From a123886ee460acd9807850f10e852c406acb85b6 Mon Sep 17 00:00:00 2001 From: Adrian Altner Date: Tue, 21 Apr 2026 03:09:37 +0200 Subject: [PATCH] Add mobile menu toggle functionality and launch configuration --- .claude/launch.json | 11 +++ src/components/Header.astro | 137 +++++++++++++++++++++++++++++++++++- 2 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 .claude/launch.json diff --git a/.claude/launch.json b/.claude/launch.json new file mode 100644 index 0000000..cc9ef50 --- /dev/null +++ b/.claude/launch.json @@ -0,0 +1,11 @@ +{ + "version": "0.0.1", + "configurations": [ + { + "name": "astro-dev", + "runtimeExecutable": "npm", + "runtimeArgs": ["run", "dev"], + "port": 4321 + } + ] +} diff --git a/src/components/Header.astro b/src/components/Header.astro index 5e6a2c8..8e28250 100644 --- a/src/components/Header.astro +++ b/src/components/Header.astro @@ -53,7 +53,7 @@ const switchHref = await resolveSwitchHref();
@@ -114,15 +119,61 @@ const switchHref = await resolveSwitchHref(); localStorage.setItem('theme', next); }); } + function wireMenuToggle() { + const btn = document.querySelector('.menu-toggle'); + const menu = document.getElementById('mobile-menu'); + const header = document.querySelector('header'); + if (!btn || !menu || !header || btn.dataset.wired) return; + btn.dataset.wired = '1'; + const nav = header.querySelector('nav'); + const mq = window.matchMedia('(max-width: 960px)'); + const syncLocation = () => { + if (mq.matches) { + if (menu.parentElement !== document.body) document.body.appendChild(menu); + } else { + if (menu.parentElement !== nav) nav!.insertBefore(menu, nav!.children[1] ?? null); + } + }; + syncLocation(); + mq.addEventListener('change', syncLocation); + const setScrollbarCompensation = (on: boolean) => { + if (on) { + const sbw = window.innerWidth - document.documentElement.clientWidth; + document.documentElement.style.setProperty('--scrollbar-width', `${sbw}px`); + } else { + document.documentElement.style.removeProperty('--scrollbar-width'); + } + }; + const close = () => { + header.classList.remove('is-menu-open'); + menu.classList.remove('is-open'); + btn.setAttribute('aria-expanded', 'false'); + setScrollbarCompensation(false); + }; + btn.addEventListener('click', () => { + const willOpen = !header.classList.contains('is-menu-open'); + if (willOpen) setScrollbarCompensation(true); + const open = header.classList.toggle('is-menu-open'); + menu.classList.toggle('is-open', open); + btn.setAttribute('aria-expanded', String(open)); + if (!open) setScrollbarCompensation(false); + }); + menu.querySelectorAll('a').forEach((a) => a.addEventListener('click', close)); + document.addEventListener('astro:after-swap', close); + } wireLangToggle(); wireThemeToggle(); + wireMenuToggle(); document.addEventListener('astro:page-load', () => { wireLangToggle(); wireThemeToggle(); + wireMenuToggle(); });