From 725d84152c7f2190c064cf2f4aab9af2c6ba0a80 Mon Sep 17 00:00:00 2001 From: Max Ostapenko <1611259+max-ostapenko@users.noreply.github.com> Date: Sun, 4 Oct 2026 21:50:04 +0200 Subject: [PATCH 1/4] fix(docs): resolve duplicate mobile burger menu and delegate popover toggle Signed-off-by: Max Ostapenko <1611259+max-ostapenko@users.noreply.github.com> --- src/components/docs/Header.astro | 34 ++++++++++++++++++++++++++------ src/styles/starlight-custom.css | 15 ++++++++++++++ 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/components/docs/Header.astro b/src/components/docs/Header.astro index 3dee7ac0..b39e33b7 100644 --- a/src/components/docs/Header.astro +++ b/src/components/docs/Header.astro @@ -26,12 +26,16 @@ import SiteHeader from '../Header.astro'; border-bottom: none !important; } /* Visually hide Starlight's default circular menu button; header hamburger controls it */ + .sl-menu-button, starlight-menu-button { position: absolute !important; opacity: 0 !important; pointer-events: none !important; width: 0 !important; height: 0 !important; + padding: 0 !important; + margin: 0 !important; + border: 0 !important; overflow: hidden !important; } @@ -60,6 +64,7 @@ import SiteHeader from '../Header.astro'; const hamburger = document.querySelector('.ha-docs-header .hamburger'); const mobileNav = document.querySelector('.ha-docs-header nav#mobile'); const desktopNav = document.querySelector('.ha-docs-header nav#desktop'); + const sidebar = document.getElementById('starlight__sidebar'); // Populate mobile nav with desktop links if empty if (mobileNav && desktopNav && !mobileNav.hasChildNodes()) { @@ -72,12 +77,15 @@ import SiteHeader from '../Header.astro'; if (hamburger && !hamburger.hasAttribute('data-initialized')) { hamburger.setAttribute('data-initialized', 'true'); hamburger.addEventListener('click', () => { - const starlightBtn = document.querySelector('starlight-menu-button button') as HTMLButtonElement | null; + const starlightBtn = document.querySelector('.sl-menu-button, starlight-menu-button button'); if (starlightBtn) { // On pages with Starlight sidebar drawer, delegate toggle to Starlight starlightBtn.click(); - const expanded = starlightBtn.getAttribute('aria-expanded'); - hamburger.setAttribute('aria-expanded', expanded || 'false'); + const isExpanded = sidebar ? sidebar.matches(':popover-open') : (starlightBtn.getAttribute('aria-expanded') === 'true'); + hamburger.setAttribute('aria-expanded', String(isExpanded)); + } else if (sidebar && typeof (sidebar as any).togglePopover === 'function') { + (sidebar as any).togglePopover(); + hamburger.setAttribute('aria-expanded', String(sidebar.matches(':popover-open'))); } else if (mobileNav) { // On splash pages without sidebar drawer, toggle nav#mobile const isExpanded = mobileNav.classList.toggle('active'); @@ -85,6 +93,18 @@ import SiteHeader from '../Header.astro'; } }); } + + // Keep hamburger aria-expanded synchronized with sidebar popover toggle events + if (sidebar && !sidebar.hasAttribute('data-toggle-listener')) { + sidebar.setAttribute('data-toggle-listener', 'true'); + sidebar.addEventListener('toggle', ((e: Event) => { + const customEvent = e as CustomEvent & { newState?: string }; + const isOpen = customEvent.newState ? customEvent.newState === 'open' : sidebar.matches(':popover-open'); + if (hamburger) { + hamburger.setAttribute('aria-expanded', String(isOpen)); + } + }) as EventListener); + } } // Close mobile nav when clicking outside @@ -113,10 +133,12 @@ import SiteHeader from '../Header.astro'; // Keep hamburger aria-expanded synchronized if Starlight's menu changes const observer = new MutationObserver(() => { - const isExpanded = document.body.hasAttribute('data-mobile-menu-expanded'); + const sidebar = document.getElementById('starlight__sidebar'); + const isExpanded = document.body.hasAttribute('data-mobile-menu-expanded') || + (sidebar ? sidebar.matches(':popover-open') : false); const hamburger = document.querySelector('.ha-docs-header .hamburger'); - const starlightBtn = document.querySelector('starlight-menu-button button'); - if (hamburger && starlightBtn) { + const starlightBtn = document.querySelector('.sl-menu-button, starlight-menu-button button'); + if (hamburger && (starlightBtn || sidebar)) { hamburger.setAttribute('aria-expanded', String(isExpanded)); } }); diff --git a/src/styles/starlight-custom.css b/src/styles/starlight-custom.css index 621e5753..fa9a8c97 100644 --- a/src/styles/starlight-custom.css +++ b/src/styles/starlight-custom.css @@ -68,3 +68,18 @@ starlight-theme-select { display: none !important; } + +/* Visually hide Starlight's default circular menu button; header hamburger controls it */ +.sl-menu-button, +starlight-menu-button { + position: absolute !important; + opacity: 0 !important; + pointer-events: none !important; + width: 0 !important; + height: 0 !important; + padding: 0 !important; + margin: 0 !important; + border: 0 !important; + overflow: hidden !important; +} + From e1843ac47e2d66dd62a820add446d0b37e454d39 Mon Sep 17 00:00:00 2001 From: Max Ostapenko <1611259+max-ostapenko@users.noreply.github.com> Date: Sun, 4 Oct 2026 21:56:18 +0200 Subject: [PATCH 2/4] refactor(docs): remove obsolete starlight-menu-button selectors and observer Signed-off-by: Max Ostapenko <1611259+max-ostapenko@users.noreply.github.com> --- src/components/docs/Header.astro | 18 ++---------------- src/styles/starlight-custom.css | 3 +-- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/src/components/docs/Header.astro b/src/components/docs/Header.astro index b39e33b7..37026544 100644 --- a/src/components/docs/Header.astro +++ b/src/components/docs/Header.astro @@ -26,8 +26,7 @@ import SiteHeader from '../Header.astro'; border-bottom: none !important; } /* Visually hide Starlight's default circular menu button; header hamburger controls it */ - .sl-menu-button, - starlight-menu-button { + .sl-menu-button { position: absolute !important; opacity: 0 !important; pointer-events: none !important; @@ -77,7 +76,7 @@ import SiteHeader from '../Header.astro'; if (hamburger && !hamburger.hasAttribute('data-initialized')) { hamburger.setAttribute('data-initialized', 'true'); hamburger.addEventListener('click', () => { - const starlightBtn = document.querySelector('.sl-menu-button, starlight-menu-button button'); + const starlightBtn = document.querySelector('.sl-menu-button'); if (starlightBtn) { // On pages with Starlight sidebar drawer, delegate toggle to Starlight starlightBtn.click(); @@ -131,19 +130,6 @@ import SiteHeader from '../Header.astro'; } }); - // Keep hamburger aria-expanded synchronized if Starlight's menu changes - const observer = new MutationObserver(() => { - const sidebar = document.getElementById('starlight__sidebar'); - const isExpanded = document.body.hasAttribute('data-mobile-menu-expanded') || - (sidebar ? sidebar.matches(':popover-open') : false); - const hamburger = document.querySelector('.ha-docs-header .hamburger'); - const starlightBtn = document.querySelector('.sl-menu-button, starlight-menu-button button'); - if (hamburger && (starlightBtn || sidebar)) { - hamburger.setAttribute('aria-expanded', String(isExpanded)); - } - }); - observer.observe(document.body, { attributes: true, attributeFilter: ['data-mobile-menu-expanded'] }); - setupDocsMobileMenu(); document.addEventListener('astro:page-load', setupDocsMobileMenu); diff --git a/src/styles/starlight-custom.css b/src/styles/starlight-custom.css index fa9a8c97..2889248e 100644 --- a/src/styles/starlight-custom.css +++ b/src/styles/starlight-custom.css @@ -70,8 +70,7 @@ starlight-theme-select { } /* Visually hide Starlight's default circular menu button; header hamburger controls it */ -.sl-menu-button, -starlight-menu-button { +.sl-menu-button { position: absolute !important; opacity: 0 !important; pointer-events: none !important; From 7a617301086268b4d4ce1bd58ce58a7b04451cd3 Mon Sep 17 00:00:00 2001 From: Max Ostapenko <1611259+max-ostapenko@users.noreply.github.com> Date: Sun, 4 Oct 2026 22:06:15 +0200 Subject: [PATCH 3/4] refactor(docs): override MobileMenuToggle component instead of hiding with CSS Signed-off-by: Max Ostapenko <1611259+max-ostapenko@users.noreply.github.com> --- astro.config.mjs | 1 + src/components/docs/Header.astro | 21 ++------------------- src/styles/starlight-custom.css | 20 +++++++++----------- 3 files changed, 12 insertions(+), 30 deletions(-) diff --git a/astro.config.mjs b/astro.config.mjs index 9e701b1d..85e0db8d 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -32,6 +32,7 @@ export default defineConfig({ Sidebar: './src/components/docs/Sidebar.astro', ThemeProvider: './src/components/docs/ThemeProvider.astro', ThemeSelect: './src/components/docs/EmptyComponent.astro', + MobileMenuToggle: './src/components/docs/EmptyComponent.astro', }, sidebar: [ { diff --git a/src/components/docs/Header.astro b/src/components/docs/Header.astro index 37026544..92404ecb 100644 --- a/src/components/docs/Header.astro +++ b/src/components/docs/Header.astro @@ -25,18 +25,6 @@ import SiteHeader from '../Header.astro'; padding: 0 !important; border-bottom: none !important; } - /* Visually hide Starlight's default circular menu button; header hamburger controls it */ - .sl-menu-button { - position: absolute !important; - opacity: 0 !important; - pointer-events: none !important; - width: 0 !important; - height: 0 !important; - padding: 0 !important; - margin: 0 !important; - border: 0 !important; - overflow: hidden !important; - }