From 64535ee9dce5f1a7b03a30a6f58282ce24b0cda7 Mon Sep 17 00:00:00 2001 From: Fuwn Date: Tue, 19 May 2026 00:54:11 +0000 Subject: feat(nav): float header as a corner hamburger under 800px Below 800px the inline header overflows the viewport. Strips card chrome from .header itself and floats it position:fixed at top:1.25rem/right :1.25rem so it does not consume a horizontal band. The 44x44 toggle button carries the desktop banner's exact card recipe (--base0011 glass, shadow-card-emphasized + 5px --base02 ring, blur, 8px radius), and the open panel mirrors it as a separately-positioned card below. Menu closes on route navigation and Escape. Header stays visible while the menu is open so a scroll-driven hide does not chop the open sheet mid-interaction. Profile-avatar anchor and the bullet separator are hidden in the mobile menu (avatar is redundant alongside the Profile dropdown; separator reads as line noise vertically). --- src/routes/+layout.svelte | 132 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 130 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 0cfde36d..a7a03066 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -54,6 +54,7 @@ let previousScrollPosition = 0; let notificationInterval: ReturnType | undefined = undefined; let lenis: Lenis | undefined = undefined; +let isMenuOpen = false; addMessages("en", english as unknown as LocaleDictionary); addMessages("ja", japanese as unknown as LocaleDictionary); @@ -87,6 +88,8 @@ $: way = data.url.includes("/user") ? 200 : -200; +$: if ($navigating) isMenuOpen = false; + const handleScroll = () => { const currentScrollPosition = window.scrollY; @@ -214,6 +217,8 @@ $: { + { if (e.key === 'Escape' && isMenuOpen) isMenuOpen = false; }} /> +
-
-
+
+ + +