Convert the two TODO items into append-mode phases (Protocol B): 18_nav_hamburger (TODO L3) and 19_ups_events_expandable (TODO L4), numbered after the existing todo phases. TODO.md is cleared to an empty list; its items now live in .agents/phases/todo/. LLM-Generated: true
4.6 KiB
Phase 18 — Collapse the nav bar into a hamburger
Source: TODO.md L3 — "The nav bar needs to collapse into a hamburger like brain of reese does"
Story: n/a
Context: the seven mastheads that carry the tab nav — src/dashboards/web/pages/{index,system,disks,llm,ups,settings,certs}.html (each has nav class="tabs" aria-label="Dashboards" with the five dashboard links; login.html deliberately has no tabs — it renders only the brand link and the theme toggle, and stays untouched), src/dashboards/web/static/app.js (Dash.initChrome(), called from the one DOMContentLoaded at line 786 — the themeButton/clock/nav-status blocks there are the per-element if (element) no-op pattern this phase's binding follows), src/dashboards/web/static/dash.css (.masthead at line 95 — position: sticky; z-index: 40; height: var(--header-h), nav.tabs at line 131, the existing @media (max-width: 640px) block at line 286, the prefers-reduced-motion block at line 938), and the reference implementation the TODO names — brain_of_reese (sibling repo, read-only): frontend/assets/header.js lines 326–366 (the phase-46 binding: #nav-toggle shown ≤640px, setNavMenu(open) funnel, close on link click / Esc with focus return / matchMedia resize-back). Pinned test neighbours: tests/test_api.py::test_the_disks_tab_is_in_the_masthead_of_every_page (line 3837) and the served-page orphan-id audit in tests/test_auth_api.py (line 1654)
Objective
On viewports ≤640px the masthead's five tab links collapse into a dropdown opened by a hamburger button, mirroring brain of reese's phase-46 behaviour: one shared binding in app.js (a no-op on any page without the elements — /login), the inline nav hidden and the dropdown absolutely positioned under the sticky masthead, and the desktop masthead byte-identical in behaviour above the breakpoint. The masthead-right cluster stays visible on phones; only the tab nav collapses.
Dependencies
- — (none; builds on the shipped masthead,
initChrome, and the 640px media block)
Tasks
01_hamburger_markup.md— the#nav-togglebutton and thenavid, identical across the seven tabbed pages, absent from/login02_dropdown_css.md— the ≤640px block: toggle visible, inline tabs hidden,.is-opendropdown under the masthead, two-row masthead03_toggle_binding.md— theinitChromebinding: toggle +aria-expanded, close on link click / Esc / resize-back04_tests_and_verification.md— the pins (present on all seven, absent on/login, CSS and binding), the orphan-idaudit, and the narrow-viewport browser verification with screenshots
Testing & Quality
- Unit/integration:
tests/test_api.py— the served-page pins (see task 04); the existing masthead/tab pins (test_the_disks_tab_is_in_the_masthead_of_every_page,test_every_page_links_to_both_admin_pages) and thetests/test_auth_api.pyorphan-idaudit pass untouched — the newids are referenced byaria-controls, the stylesheet, andapp.js, so the audit must still clear - Coverage: >90% on new/modified code (the phase is markup + CSS + one small JS binding; the coverage gate applies to the changed Python test files)
- The gate (
bash .agents/validate.sh) includesnode --checkofweb/static— the modifiedapp.jsmust pass it
Documentation & Consistency
- The final pass reviews
README.mdandAGENTS.mdin full against the project as it stands after this phase — fixing every inconsistency found, including pre-existing ones not caused by this phase. - AGENTS.md's
UI conventionssection gains the masthead-collapsing convention (the 640px breakpoint, the toggle's identity, the close paths, and that/logincarries no toggle) so a future masthead edit knows the contract. The README's page table is unchanged — the nav is the same five links at every width.
Completion Criteria
- at ≤640px: the tab links are hidden, the hamburger is visible, and clicking it opens a dropdown containing the five links; above 640px the desktop masthead is unchanged
- the dropdown closes on link click, on Esc (focus returns to the button), and on resize back above 640px;
aria-expandedtracks the state uv run pytestgreen, coverage not down,ruff+pyrightcleanbash .agents/validate.shgreen (includingnode --checkof the modifiedapp.js)- narrow-viewport screenshots (closed, open, and one desktop no-regression shot) in
data/logs/against the running dev server (invariant 10) - no behavior change in completed work: the desktop masthead and every page render identically at widths >640px