Mobile: settings sidebar pushes nav items off-screen (not stacked/chipped on narrow widths) #276

Closed
opened 2026-09-10 11:19:50 +00:00 by crueber · 3 comments
Owner

What's wrong

At a phone viewport (390×844), the repo settings page renders its sidebar as a fixed-width column that pushes nav items past the right edge of the screen: measured LI.side-nav-item right:570 (180px off-screen). The settings sections (Scheduled tasks, Push policy, Access, …) are unreachable by sight; the page scrolls sideways to reach them, and the content pane is squeezed below.

Measured evidence

settings page at 390px: side-nav LI right:570 (off-canvas), page docW 531 vs 390

Root cause (code evidence)

  • web/src/pages/Settings.jsx (nav shell built at :770-836) renders the sidebar (side-nav list) and content in a two-column arrangement whose narrow-screen behavior keeps the sidebar inline rather than stacking or converting to a horizontal chip/bar. The sidebar items (~183px wide) sit alongside the content column, overflowing.

Fix direction

  • Below a breakpoint (sm:), stack the settings nav as a horizontally scrollable chip/bar above the content (the standard settings-on-mobile pattern), or collapse it into a select. The nav model is already headless (web/src/lib/settingsNav.js), so the layout change is contained to the shell markup.
  • Acceptance: at 390px all settings nav entries are visible/reachable without page-level horizontal scroll; scrollWidth === clientWidth; the active tab is obvious.
## What's wrong At a phone viewport (390×844), the repo **settings** page renders its sidebar as a fixed-width column that pushes nav items past the right edge of the screen: measured `LI.side-nav-item right:570` (180px off-screen). The settings sections (Scheduled tasks, Push policy, Access, …) are unreachable by sight; the page scrolls sideways to reach them, and the content pane is squeezed below. ## Measured evidence ``` settings page at 390px: side-nav LI right:570 (off-canvas), page docW 531 vs 390 ``` ## Root cause (code evidence) - `web/src/pages/Settings.jsx` (nav shell built at :770-836) renders the sidebar (`side-nav` list) and content in a two-column arrangement whose narrow-screen behavior keeps the sidebar inline rather than stacking or converting to a horizontal chip/bar. The sidebar items (~183px wide) sit alongside the content column, overflowing. ## Fix direction - Below a breakpoint (`sm:`), stack the settings nav as a horizontally scrollable chip/bar above the content (the standard settings-on-mobile pattern), or collapse it into a select. The nav model is already headless (`web/src/lib/settingsNav.js`), so the layout change is contained to the shell markup. - Acceptance: at 390px all settings nav entries are visible/reachable without page-level horizontal scroll; `scrollWidth === clientWidth`; the active tab is obvious.
Author
Owner

Fixed by PR #284 (#284): settings nav stacks as full-width chip bars below sm:. Measured on the live page at 390px — sections 358px stacked, bars scroll internally, shell+content contribute zero page-level overflow (shellOnly=390 with shared chrome hidden). Remaining page docW 552 is the repo tab bar (#274) + site-header cluster (#273), left to those issues. node --test 548/548, vite build green, no new deps.

Fixed by PR #284 (https://git.packden.us/crueber/walhub/pulls/284): settings nav stacks as full-width chip bars below sm:. Measured on the live page at 390px — sections 358px stacked, bars scroll internally, shell+content contribute zero page-level overflow (shellOnly=390 with shared chrome hidden). Remaining page docW 552 is the repo tab bar (#274) + site-header cluster (#273), left to those issues. node --test 548/548, vite build green, no new deps.
Author
Owner

Review of PR #284 (fix/issue-276) — independent verification in fresh scratch worktree (removed afterward; main worktree untouched, still clean on main).

What I checked (Settings.jsx shell + ui.css comment + 12_web_ui.md entry; settingsNav.js untouched, package.json untouched):

  • Breakpoints (Settings.jsx:1122-1160): below sm: inner wrapper flex-col so both sections stack full-width above content — fixes the ~230px squeeze. sm-lg: sm:flex-row side-by-side (standard flex-1 + min-w-0, danger single-chip flex-none — fits). lg+: lg:block + lg:sticky/lg:top-4 + nav lg:w-56 classic sidebar preserved. Correct.
  • No content hidden: both uls keep overflow-x-auto below lg with li flex-none chips (Settings.jsx:1077,1133,1147), so bars scroll internally; lg: switches to flex-col/overflow-visible full list. Headings are short nowrap strings — no overflow risk at any width.
  • Shell contributes no page-level overflow: nav + both sections + content div all carry min-w-0; no fixed widths below lg. The residual docW>390 attribution to #274 (repo tab bar) + #273 (site header) is plausible — both are separate chrome components outside this shell, and the PR's shellOnly=390 measurement supports it.
  • Nav model untouched: lib/settingsNav.js not in diff; select()/hashchange deep-link code and SETTINGS/DANGER_GROUP wiring unchanged. Active tab (aria-current=page + side-nav-item selected style) and danger tone classes unchanged. Keyboard: native buttons, DOM-order tab flow preserved. Danger section equivalent (single Danger Zone chip, same styling).
  • Deps/themes: no package.json change, no new imports — law 1 holds. Only responsive-layout classes changed, theme-agnostic — dark+light ship together. Laws 7/8 N/A (no tasks, no new seams). Law 12: doc decision appended in the same commit, follows the established FIXED-entry pattern; claims match the diff.

Verification (scratch worktree @ c9c0c00; node_modules satisfied via read-only symlink to main's install, no copies/edits):

  • node --test web/test/unit/*.test.js: 548/548 pass, 0 fail.
  • vite build + esbuild SDK bundle: both exit 0 (only the pre-existing >500kB chunk-size warning).
  • No browser run per review instructions (node tests + class reasoning only); author's per-tab/per-theme browser measurements taken as stated.

No fixes needed — nothing to push. MERGE RECOMMENDATION: ready to merge.

Review of PR #284 (fix/issue-276) — independent verification in fresh scratch worktree (removed afterward; main worktree untouched, still clean on main). What I checked (Settings.jsx shell + ui.css comment + 12_web_ui.md entry; settingsNav.js untouched, package.json untouched): - Breakpoints (Settings.jsx:1122-1160): below sm: inner wrapper flex-col so both sections stack full-width above content — fixes the ~230px squeeze. sm-lg: sm:flex-row side-by-side (standard flex-1 + min-w-0, danger single-chip flex-none — fits). lg+: lg:block + lg:sticky/lg:top-4 + nav lg:w-56 classic sidebar preserved. Correct. - No content hidden: both uls keep overflow-x-auto below lg with li flex-none chips (Settings.jsx:1077,1133,1147), so bars scroll internally; lg: switches to flex-col/overflow-visible full list. Headings are short nowrap strings — no overflow risk at any width. - Shell contributes no page-level overflow: nav + both sections + content div all carry min-w-0; no fixed widths below lg. The residual docW>390 attribution to #274 (repo tab bar) + #273 (site header) is plausible — both are separate chrome components outside this shell, and the PR's shellOnly=390 measurement supports it. - Nav model untouched: lib/settingsNav.js not in diff; select()/hashchange deep-link code and SETTINGS/DANGER_GROUP wiring unchanged. Active tab (aria-current=page + side-nav-item selected style) and danger tone classes unchanged. Keyboard: native buttons, DOM-order tab flow preserved. Danger section equivalent (single Danger Zone chip, same styling). - Deps/themes: no package.json change, no new imports — law 1 holds. Only responsive-layout classes changed, theme-agnostic — dark+light ship together. Laws 7/8 N/A (no tasks, no new seams). Law 12: doc decision appended in the same commit, follows the established FIXED-entry pattern; claims match the diff. Verification (scratch worktree @ c9c0c00; node_modules satisfied via read-only symlink to main's install, no copies/edits): - node --test web/test/unit/*.test.js: 548/548 pass, 0 fail. - vite build + esbuild SDK bundle: both exit 0 (only the pre-existing >500kB chunk-size warning). - No browser run per review instructions (node tests + class reasoning only); author's per-tab/per-theme browser measurements taken as stated. No fixes needed — nothing to push. MERGE RECOMMENDATION: ready to merge.
Author
Owner

Fixed by PR #284 (review clean; breakpoints + no-overflow verified; 548/548), merged. Closing.

Fixed by PR #284 (review clean; breakpoints + no-overflow verified; 548/548), merged. Closing.
crueber added this to the v1 milestone 2026-09-10 22:27:08 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
crueber/walhub#276
No description provided.