Fix #273: site header narrow widths #296

Merged
crueber merged 1 commit from fix/issue-273 into main 2026-09-10 17:13:34 +00:00
Owner

Fixes #273: the site header overflowed a 390px viewport (flex row, gap-6, nowrap — theme toggle landed at x=439, page panned sideways).

Fix (option (a) from the issue — smallest change, everything stays reachable):

  • web/src/App.jsx: brand + right cluster pinned (shrink-0); site-nav takes the leftover (min-w-0 flex-1) and scrolls internally (overflow-x-auto, whitespace-nowrap); row/nav gaps relax below sm: (gap-3, sm:gap-6 / sm:gap-4); nav gains aria-label="Site" (labelled landmark, keyboard Tab follows focus).
  • web/src/ui.css: .site-nav strip scrollbar hidden (stable single row height; touch scroll + focus-follow intact), links shrink-0. Dark + light share it (layout only).
  • Tray popover fit already held by the #278 viewport bound — pinned intact by test, not re-changed.
  • Tests: new web/test/unit/header-narrow.test.js (7 cases: responsive gaps, pinned chrome + scrolling nav, landmark + link shrink, scrollbar behavior, nav contents unchanged, 390px arithmetic, #278 bound intact); nav-api-right.test.js updated to the new nav tag shape (same assertions, #238 behavior untouched).
  • No new deps; no JS behavior change.

Verification:

  • node --test web/test/unit/*.test.js: 564/564 pass.
  • vite + esbuild build clean (0 errors); compiled CSS confirmed to contain overflow-x-auto, shrink-0, min-w-0, flex-1, whitespace-nowrap, gap-3, sm:gap-4/6, scrollbar-width:none; bundle contains the nav aria-label.
  • Narrow-viewport proof is structural (source-text pinning + 390px flex arithmetic in-test). Browser left open explicitly: shared obscura daemon blocks loopback per task instructions — not attempted. Zero console-error risk: no JS changed (classes + aria-label only).
Fixes #273: the site header overflowed a 390px viewport (flex row, gap-6, nowrap — theme toggle landed at x=439, page panned sideways). Fix (option (a) from the issue — smallest change, everything stays reachable): - web/src/App.jsx: brand + right cluster pinned (shrink-0); site-nav takes the leftover (min-w-0 flex-1) and scrolls internally (overflow-x-auto, whitespace-nowrap); row/nav gaps relax below sm: (gap-3, sm:gap-6 / sm:gap-4); nav gains aria-label="Site" (labelled landmark, keyboard Tab follows focus). - web/src/ui.css: .site-nav strip scrollbar hidden (stable single row height; touch scroll + focus-follow intact), links shrink-0. Dark + light share it (layout only). - Tray popover fit already held by the #278 viewport bound — pinned intact by test, not re-changed. - Tests: new web/test/unit/header-narrow.test.js (7 cases: responsive gaps, pinned chrome + scrolling nav, landmark + link shrink, scrollbar behavior, nav contents unchanged, 390px arithmetic, #278 bound intact); nav-api-right.test.js updated to the new nav tag shape (same assertions, #238 behavior untouched). - No new deps; no JS behavior change. Verification: - node --test web/test/unit/*.test.js: 564/564 pass. - vite + esbuild build clean (0 errors); compiled CSS confirmed to contain overflow-x-auto, shrink-0, min-w-0, flex-1, whitespace-nowrap, gap-3, sm:gap-4/6, scrollbar-width:none; bundle contains the nav aria-label. - Narrow-viewport proof is structural (source-text pinning + 390px flex arithmetic in-test). Browser left open explicitly: shared obscura daemon blocks loopback per task instructions — not attempted. Zero console-error risk: no JS changed (classes + aria-label only).
Brand + right cluster pinned (shrink-0); site-nav flexes into the
leftover (min-w-0 flex-1) and scrolls internally (overflow-x-auto,
nowrap) instead of pushing the page past 390px. Gaps relax below sm:.
Nav strip is a labelled landmark; strip scrollbar hidden (stable row
height, keyboard focus still followed). Tray popover fit already held
by the #278 viewport bound (pinned by test). No new deps.
Sign in to join this conversation.
No description provided.