62 lines
1.9 KiB
JavaScript
62 lines
1.9 KiB
JavaScript
export function initNav() {
|
|
const header = document.querySelector('[data-header]');
|
|
if (!header) return;
|
|
const root = document.documentElement;
|
|
const toggle = header.querySelector('[data-menu-toggle]');
|
|
const nav = header.querySelector('[data-nav]');
|
|
const label = toggle.querySelector('.menu-toggle__label');
|
|
const outside = [document.querySelector('main'), document.querySelector('.site-footer')];
|
|
|
|
let lastY = scrollY;
|
|
let ticking = false;
|
|
|
|
function onScroll() {
|
|
const y = scrollY;
|
|
header.classList.toggle('is-scrolled', y > 24);
|
|
if (!root.classList.contains('menu-open')) {
|
|
// hide while scrolling down, come back as soon as the user scrolls up
|
|
if (y > lastY + 4 && y > 240) header.classList.add('is-hidden');
|
|
else if (y < lastY - 4 || y <= 240) header.classList.remove('is-hidden');
|
|
}
|
|
lastY = y;
|
|
ticking = false;
|
|
}
|
|
|
|
addEventListener(
|
|
'scroll',
|
|
() => {
|
|
if (!ticking) requestAnimationFrame(onScroll);
|
|
ticking = true;
|
|
},
|
|
{ passive: true },
|
|
);
|
|
onScroll();
|
|
|
|
header.addEventListener('focusin', () => header.classList.remove('is-hidden'));
|
|
|
|
function setOpen(open) {
|
|
toggle.setAttribute('aria-expanded', String(open));
|
|
root.classList.toggle('menu-open', open);
|
|
label.textContent = open ? label.dataset.labelClose : label.dataset.labelOpen;
|
|
for (const element of outside) if (element) element.inert = open;
|
|
if (open) header.classList.remove('is-hidden');
|
|
}
|
|
|
|
toggle.addEventListener('click', () => setOpen(toggle.getAttribute('aria-expanded') !== 'true'));
|
|
|
|
nav.addEventListener('click', (event) => {
|
|
if (event.target.closest('a')) setOpen(false);
|
|
});
|
|
|
|
document.addEventListener('keydown', (event) => {
|
|
if (event.key === 'Escape' && root.classList.contains('menu-open')) {
|
|
setOpen(false);
|
|
toggle.focus();
|
|
}
|
|
});
|
|
|
|
matchMedia('(min-width: 48em)').addEventListener('change', (event) => {
|
|
if (event.matches) setOpen(false);
|
|
});
|
|
}
|