diff --git a/src/components/Header.astro b/src/components/Header.astro index 3469d893c..c0cb272d5 100644 --- a/src/components/Header.astro +++ b/src/components/Header.astro @@ -18,18 +18,14 @@ const activeMenus = NAV_MENUS.map((menu) => ({ })) .filter((section) => section.items.length > 0), })).filter((menu) => !menu.sections || menu.sections.length > 0); + +// ── Layout constants (matching CSS) ── --- @@ -577,136 +608,72 @@ const activeMenus = NAV_MENUS.map((menu) => ({ const navbar = document.getElementById("navbar"); if (!navbar) return; - const navbarEl: HTMLElement = navbar; - - // ── Mobile hamburger ── - const toggle = navbar.querySelector(".nav-toggle") as HTMLElement | null; - const navLinks = navbar.querySelector(".nav-links") as HTMLElement | null; + // ── Mobile hamburger toggle ── + const toggle = navbar.querySelector(".nav-toggle"); + const navLinks = navbar.querySelector(".nav-links"); if (toggle && navLinks) { - const toggleEl = toggle; - const navLinksEl = navLinks; - function closeMenu() { - navLinksEl.classList.remove("open"); - toggleEl.classList.remove("active"); - toggleEl.setAttribute("aria-expanded", "false"); + function closeMenuMob() { + navLinks.classList.remove("open"); + toggle.classList.remove("active"); + toggle.setAttribute("aria-expanded", "false"); document.body.style.overflow = ""; - toggleEl.focus(); + toggle.focus(); + navLinks + .querySelectorAll(".has-dropdown.open") + .forEach(function (item) { + item.classList.remove("open"); + }); } - - function openMenu() { - navLinksEl.classList.add("open"); - toggleEl.classList.add("active"); - toggleEl.setAttribute("aria-expanded", "true"); + function openMenuMob() { + navLinks.classList.add("open"); + toggle.classList.add("active"); + toggle.setAttribute("aria-expanded", "true"); document.body.style.overflow = "hidden"; - navbarEl.classList.remove("nav-hidden"); + navbar.classList.remove("nav-hidden"); } - - toggleEl.addEventListener("click", function (e) { + toggle.addEventListener("click", function (e) { e.stopPropagation(); - if (navLinksEl.classList.contains("open")) { - closeMenu(); + if (navLinks.classList.contains("open")) { + closeMenuMob(); } else { - openMenu(); + openMenuMob(); } }); - // Dropdown toggle on mobile - navLinksEl - .querySelectorAll(".nav-item.has-dropdown > a") - .forEach(function (link) { - link.addEventListener("click", function (e) { + // Mobile accordion — tap trigger to expand sub-items + navLinks + .querySelectorAll(".has-dropdown > .mn-trigger") + .forEach(function (btn) { + btn.addEventListener("click", function (e) { if (window.innerWidth <= 900) { e.preventDefault(); - const item = link.closest(".nav-item") as HTMLElement | null; + const item = btn.closest(".has-dropdown"); if (!item) return; - navLinksEl - .querySelectorAll(".nav-item.open") + navLinks + .querySelectorAll(".has-dropdown.open") .forEach(function (other) { if (other !== item) other.classList.remove("open"); }); item.classList.toggle("open"); } }); - - // Keyboard support for desktop dropdowns - link.addEventListener("keydown", function (e: Event) { - const ke = e as KeyboardEvent; - if (window.innerWidth <= 900) return; - if (ke.key === "Enter" || ke.key === " ") { - e.preventDefault(); - var item = link.closest(".nav-item") as HTMLElement | null; - if (!item) return; - const isOpen = item.classList.contains("dropdown-open"); - navLinksEl - .querySelectorAll(".nav-item.dropdown-open") - .forEach(function (other) { - other.classList.remove("dropdown-open"); - const otherLink = other.querySelector(":scope > a"); - if (otherLink) - otherLink.setAttribute("aria-expanded", "false"); - }); - if (!isOpen) { - item.classList.add("dropdown-open"); - link.setAttribute("aria-expanded", "true"); - const firstLink = item.querySelector( - ".nav-dropdown li a", - ) as HTMLElement | null; - if (firstLink) firstLink.focus(); - } - } else if (ke.key === "Escape") { - var item = link.closest(".nav-item") as HTMLElement | null; - if (item) item.classList.remove("dropdown-open"); - link.setAttribute("aria-expanded", "false"); - } - }); - }); - - // Escape key inside dropdowns - navLinksEl - .querySelectorAll(".nav-dropdown li a") - .forEach(function (ddLink) { - ddLink.addEventListener("keydown", function (e: Event) { - const ke = e as KeyboardEvent; - if (ke.key === "Escape") { - const item = ddLink.closest( - ".nav-item.has-dropdown", - ) as HTMLElement | null; - if (item) item.classList.remove("dropdown-open"); - const trigger = item - ? (item.querySelector(":scope > a") as HTMLElement | null) - : null; - if (trigger) { - trigger.setAttribute("aria-expanded", "false"); - trigger.focus(); - } - } - }); }); - // Close menu when clicking a sub-link (mobile) - - // Close menu when clicking a sub-link (mobile) - navLinksEl - .querySelectorAll(".nav-dropdown li a") + // Close mobile menu on sub-link click + navLinks + .querySelectorAll(".mn-mobile-sub .mn-link") .forEach(function (link) { link.addEventListener("click", function () { if (window.innerWidth <= 900) { - closeMenu(); - navLinksEl - .querySelectorAll(".nav-item.open") - .forEach(function (item) { - item.classList.remove("open"); - }); + closeMenuMob(); } }); }); - // Close menu on backdrop click - navLinksEl.addEventListener("click", function (e) { - if (e.target === navLinksEl && window.innerWidth <= 900) { - closeMenu(); - } + // Close mobile menu on backdrop click + navLinks.addEventListener("click", function (e) { + if (e.target === navLinks && window.innerWidth <= 900) closeMenuMob(); }); } @@ -717,52 +684,40 @@ const activeMenus = NAV_MENUS.map((menu) => ({ let isVisible = true; function updateNavbar() { - const rawScrollPos = - window.pageYOffset || document.documentElement.scrollTop; - const currentScrollPos = Math.max(0, rawScrollPos); - - if (rawScrollPos <= 0 || currentScrollPos <= 50) { + const raw = window.pageYOffset || document.documentElement.scrollTop; + const cur = Math.max(0, raw); + if (raw <= 0 || cur <= 50) { if (!isVisible) { - navbarEl.style.transform = "translateY(0)"; + navbar.style.transform = "translateY(0)"; isVisible = true; } - prevScrollPos = currentScrollPos; + prevScrollPos = cur; ticking = false; return; } - - const documentHeight = document.documentElement.scrollHeight; - const windowHeight = window.innerHeight; - - if (currentScrollPos + windowHeight >= documentHeight - 50) { + const dh = document.documentElement.scrollHeight, + wh = window.innerHeight; + if (cur + wh >= dh - 50) { if (!isVisible) { - navbarEl.style.transform = "translateY(0)"; + navbar.style.transform = "translateY(0)"; isVisible = true; } - prevScrollPos = currentScrollPos; + prevScrollPos = cur; ticking = false; return; } - - const scrollDiff = Math.abs(currentScrollPos - prevScrollPos); - if (scrollDiff < 3) { + if (Math.abs(cur - prevScrollPos) < 3) { ticking = false; return; } - - if (prevScrollPos > currentScrollPos && !isVisible) { - navbarEl.style.transform = "translateY(0)"; + if (prevScrollPos > cur && !isVisible) { + navbar.style.transform = "translateY(0)"; isVisible = true; - } else if ( - prevScrollPos < currentScrollPos && - isVisible && - currentScrollPos > 100 - ) { - navbarEl.style.transform = "translateY(-100%)"; + } else if (prevScrollPos < cur && isVisible && cur > 100) { + navbar.style.transform = "translateY(-100%)"; isVisible = false; } - - prevScrollPos = currentScrollPos; + prevScrollPos = cur; ticking = false; } @@ -772,23 +727,22 @@ const activeMenus = NAV_MENUS.map((menu) => ({ ticking = true; } } - window.addEventListener("scroll", requestTick, { passive: true }); - let bounceCheckTimeout: any = null; + let bounceCheck = null; window.addEventListener( "scroll", function () { - if (bounceCheckTimeout) clearTimeout(bounceCheckTimeout); - bounceCheckTimeout = setTimeout(function () { - const finalScrollPos = Math.max( + if (bounceCheck) clearTimeout(bounceCheck); + bounceCheck = setTimeout(function () { + const finalScroll = Math.max( 0, window.pageYOffset || document.documentElement.scrollTop, ); - if (finalScrollPos <= 50 && !isVisible) { - navbarEl.style.transform = "translateY(0)"; + if (finalScroll <= 50 && !isVisible) { + navbar.style.transform = "translateY(0)"; isVisible = true; - prevScrollPos = finalScrollPos; + prevScrollPos = finalScroll; } }, 150); }, @@ -797,14 +751,14 @@ const activeMenus = NAV_MENUS.map((menu) => ({ document.addEventListener("visibilitychange", function () { if (!document.hidden) { - const currentScrollPos = Math.max( + const cur = Math.max( 0, window.pageYOffset || document.documentElement.scrollTop, ); - if (currentScrollPos <= 50) { - navbarEl.style.transform = "translateY(0)"; + if (cur <= 50) { + navbar.style.transform = "translateY(0)"; isVisible = true; - prevScrollPos = currentScrollPos; + prevScrollPos = cur; } } }); diff --git a/src/data/nav.ts b/src/data/nav.ts index 654b36f64..285bf6e5c 100644 --- a/src/data/nav.ts +++ b/src/data/nav.ts @@ -46,7 +46,7 @@ const L = { rustSummit: { label: "Rust Summit", url: "/rust-summit" }, packagingSummit: { label: "Packaging Summit", url: "/packaging-summit" }, communityOrganisersSummit: { - label: "Community Organisers Summit", + label: "Organisers Summit", url: "/community-organisers-summit", },