add support for dropdown

This commit is contained in:
chark1es 2025-02-08 06:01:29 -08:00
parent 45153c2fbd
commit fe187034c8

View file

@ -5,150 +5,252 @@ import pages from "../../data/pages.json";
---
<div class="w-full">
<div
class="flex justify-between items-center bg-ieee-black my-[1%] mx-[2.5%] py-[0.5%] px-[1%] rounded-full md:border-[0.1vw]"
>
<a href="/" class="hover:opacity-60 duration-300">
<Image
class="w-[15vw] md:block hidden"
src={whiteLogoHorizontal}
alt="IEEE UCSD Logo"
/>
<Image
class="w-[40vw] md:hidden block"
src={whiteLogoHorizontal}
alt="IEEE UCSD Logo"
/>
</a>
<!-- Desktop Navigation -->
<div class="hidden md:flex md:w-[55%] md:justify-between">
{
pages.map((page) => (
<a
href={page.path}
class={`uppercase rounded-full duration-300 px-[1.5vw] py-[0.2vw] text-[1.2vw] text-nowrap
${
page.name === "Online Store"
? "bg-ieee-yellow text-black hover:opacity-70"
: "text-white border-white hover:opacity-50 border-[0.1vw] font-light"
}`}
>
{page.name}
</a>
))
}
</div>
<!-- Mobile Hamburger/Close Button -->
<button
id="menu-btn"
class="md:hidden text-white p-2 flex justify-center items-center focus:outline-none relative z-[60] scale-150"
aria-label="Toggle menu"
>
<!-- Hamburger Icon -->
<svg
class="w-6 h-6 menu-icon"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M4 6h16M4 12h16M4 18h16"></path>
</svg>
<!-- Close Icon -->
<svg
class="w-6 h-6 close-icon hidden"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 18L18 6M6 6l12 12"></path>
</svg>
</button>
</div>
<!-- Mobile Menu -->
<div
id="mobile-menu"
class="fixed inset-0 z-[51] hidden xl:hidden motion-safe:transition-transform motion-safe:duration-300 translate-x-full"
>
<div
class="flex flex-col items-center min-h-screen justify-center bg-black py-20 px-4 space-y-8"
class="flex justify-between items-center bg-ieee-black my-[1%] mx-[2.5%] py-[0.5%] px-[1%] rounded-full md:border-[0.1vw]"
>
{
pages.map((page) => (
<a
href={page.path}
class={`block py-4 px-12 text-center rounded-[3rem] motion-safe:transition-colors motion-safe:duration-200 uppercase font-bold text-2xl w-full max-w-md
${
page.name === "Online Store"
? "bg-[#f3c135] text-black border-[#f3c135] hover:bg-[#dba923] hover:border-[#dba923]"
: "text-white hover:text-gray-300 border-white border-2"
}`}
>
{page.name}
</a>
))
}
<a href="/" class="hover:opacity-60 duration-300">
<Image
class="w-[15vw] md:block hidden"
src={whiteLogoHorizontal}
alt="IEEE UCSD Logo"
/>
<Image
class="w-[40vw] md:hidden block"
src={whiteLogoHorizontal}
alt="IEEE UCSD Logo"
/>
</a>
<!-- Desktop Navigation -->
<div class="hidden md:flex md:w-[55%] md:justify-between">
{
pages.map((page) =>
page.subpages ? (
<div class="relative group">
<a
href={page.path}
class="uppercase rounded-full duration-300 px-[1.5vw] py-[0.2vw] text-[1.2vw] text-nowrap text-white border-white hover:opacity-50 border-[0.1vw] font-light inline-block"
>
{page.name}
</a>
<div class="absolute left-1/2 transform -translate-x-1/2 top-full pt-2 w-64 z-50">
<div class="rounded-lg bg-ieee-black border border-white shadow-lg hidden group-hover:block animate-fade-down animate-duration-200 animate-ease-in-out">
{page.subpages.map((subpage) => (
<a
href={subpage.path}
class="block px-6 py-3 text-white hover:bg-gray-700 text-[1vw] first:rounded-t-lg last:rounded-b-lg text-center whitespace-nowrap transition-colors duration-200"
>
{subpage.name}
</a>
))}
</div>
</div>
</div>
) : (
<a
href={page.path}
class={`uppercase rounded-full duration-300 px-[1.5vw] py-[0.2vw] text-[1.2vw] text-nowrap
${
page.name === "Online Store"
? "bg-ieee-yellow text-black hover:opacity-70"
: "text-white border-white hover:opacity-50 border-[0.1vw] font-light"
}`}
>
{page.name}
</a>
)
)
}
</div>
<!-- Mobile Hamburger/Close Button -->
<button
id="menu-btn"
class="md:hidden text-white p-2 flex justify-center items-center focus:outline-none relative z-[60] scale-150"
aria-label="Toggle menu"
>
<!-- Hamburger Icon -->
<svg
class="w-6 h-6 menu-icon"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M4 6h16M4 12h16M4 18h16"></path>
</svg>
<!-- Close Icon -->
<svg
class="w-6 h-6 close-icon hidden"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 18L18 6M6 6l12 12"></path>
</svg>
</button>
</div>
<!-- Mobile Menu -->
<div
id="mobile-menu"
class="fixed inset-0 z-[51] hidden xl:hidden motion-safe:transition-transform motion-safe:duration-300 translate-x-full bg-black"
>
<div
class="flex flex-col items-center min-h-screen w-full justify-center py-20 px-4 space-y-6 overflow-y-auto"
>
{
pages.map((page) =>
page.subpages ? (
<div class="w-full max-w-md space-y-4">
<div class="flex gap-2">
<a
href={page.path}
class="flex-1 block py-4 px-12 text-center rounded-[3rem] motion-safe:transition-colors motion-safe:duration-200 uppercase font-bold text-2xl text-white hover:text-gray-300 border-white border-2"
>
{page.name}
</a>
<button
class="mobile-dropdown-toggle py-4 px-6 text-center rounded-[3rem] motion-safe:transition-all motion-safe:duration-200 uppercase font-bold text-2xl text-white hover:text-gray-300 border-white border-2 flex items-center justify-center"
aria-expanded="false"
>
<svg
class="w-6 h-6 transform transition-transform duration-200 dropdown-icon"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M19 9l-7 7-7-7"
/>
</svg>
</button>
</div>
<div class="mobile-dropdown-content hidden mt-2 space-y-2 pl-4">
{page.subpages.map((subpage) => (
<a
href={subpage.path}
class="block py-3 px-8 text-center rounded-[2rem] motion-safe:transition-all motion-safe:duration-200 uppercase font-medium text-lg w-full text-white hover:text-gray-300 border-white border bg-[#111111] hover:bg-[#222222]"
>
{subpage.name}
</a>
))}
</div>
</div>
) : (
<a
href={page.path}
class={`block py-4 px-12 text-center rounded-[3rem] motion-safe:transition-colors motion-safe:duration-200 uppercase font-bold text-2xl w-full max-w-md
${
page.name === "Online Store"
? "bg-[#f3c135] text-black border-[#f3c135] hover:bg-[#dba923] hover:border-[#dba923]"
: "text-white hover:text-gray-300 border-white border-2"
}`}
>
{page.name}
</a>
)
)
}
</div>
</div>
</div>
</div>
<style>
#mobile-menu.show {
@apply translate-x-0;
}
#mobile-menu.show {
@apply translate-x-0;
}
.mobile-dropdown-content {
max-height: 0;
transition: max-height 0.3s ease-out;
}
.mobile-dropdown-content.show {
max-height: 500px;
transition: max-height 0.5s ease-in;
}
.dropdown-icon.rotated {
transform: rotate(180deg);
}
</style>
<script>
const menuBtn = document.getElementById("menu-btn");
const mobileMenu = document.getElementById("mobile-menu");
const menuIcon = document.querySelector(".menu-icon");
const closeIcon = document.querySelector(".close-icon");
const menuBtn = document.getElementById("menu-btn");
const mobileMenu = document.getElementById("mobile-menu");
const menuIcon = document.querySelector(".menu-icon");
const closeIcon = document.querySelector(".close-icon");
const dropdownToggles = document.querySelectorAll(
".mobile-dropdown-toggle"
);
function toggleMenu(show: boolean) {
if (show) {
mobileMenu?.classList.remove("hidden");
menuIcon?.classList.add("hidden");
closeIcon?.classList.remove("hidden");
document.body.style.overflow = "hidden";
function toggleMenu(show: boolean) {
if (show) {
mobileMenu?.classList.remove("hidden");
menuIcon?.classList.add("hidden");
closeIcon?.classList.remove("hidden");
document.body.style.overflow = "hidden";
setTimeout(() => {
mobileMenu?.classList.add("show");
}, 10);
} else {
mobileMenu?.classList.remove("show");
menuIcon?.classList.remove("hidden");
closeIcon?.classList.add("hidden");
document.body.style.overflow = "";
setTimeout(() => {
mobileMenu?.classList.add("show");
}, 10);
} else {
mobileMenu?.classList.remove("show");
menuIcon?.classList.remove("hidden");
closeIcon?.classList.add("hidden");
document.body.style.overflow = "";
setTimeout(() => {
mobileMenu?.classList.add("hidden");
}, 100);
setTimeout(() => {
mobileMenu?.classList.add("hidden");
}, 300);
}
}
}
menuBtn?.addEventListener("click", () => {
const isMenuHidden = mobileMenu?.classList.contains("hidden") ?? true;
toggleMenu(isMenuHidden);
});
menuBtn?.addEventListener("click", () => {
const isMenuHidden = mobileMenu?.classList.contains("hidden") ?? true;
toggleMenu(isMenuHidden);
});
// Close menu when clicking outside
document.addEventListener("click", (e) => {
if (
!mobileMenu?.contains(e.target as Node) &&
!menuBtn?.contains(e.target as Node) &&
!mobileMenu?.classList.contains("hidden")
) {
toggleMenu(false);
}
});
// Handle dropdown toggles
dropdownToggles.forEach((toggle) => {
toggle.addEventListener("click", (e) => {
e.stopPropagation();
const content = toggle.parentElement
?.nextElementSibling as HTMLElement;
const icon = toggle.querySelector(".dropdown-icon");
// Toggle aria-expanded
const isExpanded = toggle.getAttribute("aria-expanded") === "true";
toggle.setAttribute("aria-expanded", (!isExpanded).toString());
// Toggle content visibility
if (content) {
content.classList.toggle("hidden");
content.classList.toggle("show");
icon?.classList.toggle("rotated");
}
});
});
// Close menu when clicking outside
document.addEventListener("click", (e) => {
if (
!mobileMenu?.contains(e.target as Node) &&
!menuBtn?.contains(e.target as Node) &&
!mobileMenu?.classList.contains("hidden")
) {
toggleMenu(false);
}
});
</script>