feat(web): responsive UI overhaul — hamburger nav, spacing scale, icon system (ADR-0019) #16

Merged
dominik.polakovics merged 1 commit from feat/responsive-ui-overhaul into main 2026-07-07 11:23:21 +02:00

Summary

Phone-first responsive overhaul of the operator SPA (issue #15), within the existing design language — no colour/type/radius redesign. Pure frontend/CSS: no schema, seam, API, SSE, or migration change, and no new npm dependency. Recorded as ADR-0019.

Closes #15.

What changed

  • Icon system — one Icon component vendoring 15 Lucide glyphs as inline SVG (ISC, currentColor, aria-hidden); the ADR-0018 copy/check SVGs fold in so it is the single source.
  • Hamburger nav — below 640px the topbar is brand · live dot · hamburger; the five section links (folder/key/play/ticket/gear), username, and Log out move into a full-width dropdown over a scrim that closes on outside tap, Esc, and navigation (including the already-active link). Inline nav + username restored at ≥640px; the old 560px hide-username rule is removed.
  • Spacing scale — a tokenized --space-* scale on card padding, list gaps, and section margins; roomier at ≥640px, current density on phones.
  • Instance rows — stack into two lines below 640px (title/branch/chips, then icon-only Chat/Open/Stop); single line unchanged at ≥640px; no horizontal scroll at 360px.
  • Chat controls — the header Stop (resting) and composer Send become icon-only buttons with accessible names; the two-phase stop confirm is unchanged.
  • Component tests query the now-icon-only controls by accessible name.

Also fixes a pre-existing prettier violation in lib/toolGroups.test.ts that the format:check gate surfaced (CI has no runner to have caught it).

Validation

  • nix flake checkall checks passed (web build + eslint + prettier + 366 vitest; Go; golangci-lint; nixos-module).
  • Rendered the icon set and both breakpoints (360px / 900px) headless: icons legible in light + dark; two-line mobile row with no horizontal scroll; desktop shows the inline nav with no hamburger.

That visual pass caught a bug the unit suite + review both missed: the desktop hamburger-hide rule tied .icon-btn on specificity and lost on source order, so the hamburger stayed visible at ≥640px — fixed by scoping it .topbar .nav-toggle. (jsdom applies no CSS, so this class of breakpoint bug is invisible to vitest.)

🤖 Generated with Claude Code

https://claude.ai/code/session_01NP2Ai6CBkYY7Fj1fujtRDD

## Summary Phone-first responsive overhaul of the operator SPA (issue #15), within the existing design language — no colour/type/radius redesign. Pure frontend/CSS: no schema, seam, API, SSE, or migration change, and **no new npm dependency**. Recorded as ADR-0019. Closes #15. ## What changed - **Icon system** — one `Icon` component vendoring 15 Lucide glyphs as inline SVG (ISC, `currentColor`, `aria-hidden`); the ADR-0018 copy/check SVGs fold in so it is the single source. - **Hamburger nav** — below 640px the topbar is brand · live dot · hamburger; the five section links (folder/key/play/ticket/gear), username, and Log out move into a full-width dropdown over a scrim that closes on outside tap, `Esc`, and navigation (including the already-active link). Inline nav + username restored at ≥640px; the old 560px hide-username rule is removed. - **Spacing scale** — a tokenized `--space-*` scale on card padding, list gaps, and section margins; roomier at ≥640px, current density on phones. - **Instance rows** — stack into two lines below 640px (title/branch/chips, then icon-only Chat/Open/Stop); single line unchanged at ≥640px; no horizontal scroll at 360px. - **Chat controls** — the header Stop (resting) and composer Send become icon-only buttons with accessible names; the two-phase stop confirm is unchanged. - Component tests query the now-icon-only controls by accessible name. Also fixes a pre-existing prettier violation in `lib/toolGroups.test.ts` that the `format:check` gate surfaced (CI has no runner to have caught it). ## Validation - `nix flake check` — **all checks passed** (web build + eslint + prettier + 366 vitest; Go; golangci-lint; nixos-module). - Rendered the icon set and both breakpoints (360px / 900px) headless: icons legible in light + dark; two-line mobile row with no horizontal scroll; desktop shows the inline nav with **no** hamburger. That visual pass caught a bug the unit suite + review both missed: the desktop hamburger-hide rule tied `.icon-btn` on specificity and lost on source order, so the hamburger stayed visible at ≥640px — fixed by scoping it `.topbar .nav-toggle`. (jsdom applies no CSS, so this class of breakpoint bug is invisible to vitest.) 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01NP2Ai6CBkYY7Fj1fujtRDD
feat(web): responsive UI overhaul — hamburger nav, spacing scale, icon system (ADR-0019)
Some checks failed
ci / flake-check (pull_request) Has been cancelled
4d520d5eb8
Closes #15.

Phone-first chrome for the operator SPA, within the existing design language
(no colour/type/radius redesign). Pure frontend/CSS: no schema, seam, API, SSE,
or migration change, and no new npm dependency.

- Single Icon component: 15 vendored Lucide glyphs as inline SVG (ISC,
  currentColor, aria-hidden); folds in the ADR-0018 copy/check icons.
- Topbar collapses below 640px to brand · live dot · hamburger; the five
  section links, username, and Log out move into a full-width dropdown over a
  scrim that closes on outside tap, Esc, and navigation (incl. the active
  link). Inline nav with username restored at >=640; the old 560px rule is gone.
- Tokenized --space-* scale on card padding, list gaps, and section margins;
  roomier at >=640, current density on phones.
- Instance rows stack into two lines below 640px (title/branch/chips, then
  icon-only Chat/Open/Stop); single line unchanged at >=640; no horizontal
  scroll at 360px.
- Chat header Stop (resting) and composer Send become icon-only controls with
  accessible names; the two-phase stop confirm is unchanged.
- Tests query the icon-only controls by accessible name.

Also fixes a pre-existing prettier violation in lib/toolGroups.test.ts,
surfaced by the format:check gate (CI has no runner to have caught it).

Validated with `nix flake check` (all checks passed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NP2Ai6CBkYY7Fj1fujtRDD
Author
Owner

This was generated by AI while landing a PR.

Landing audit — PR #16 — verdict: PASS

Verification signal relied on: local nix flake check (this repo's CI ci / flake-check has no nix-label runner and stays pending, so it never vouches). Ran the full gate locally — all checks passed: web build + eslint + prettier + vitest, Go, golangci-lint, and the nixos-module eval.

What was checked

  • Gate: nix flake checkall checks passed! (exit 0). This is a real build of the web/Go/module derivations, not eval-only.
  • Conventions: title feat(web): … is valid Conventional Commits; body carries a working Closes #15, so the merge auto-closes the issue. Head is feat/responsive-ui-overhaul (a manual PR, not an afk/<N> run).
  • Mergeable: ✔ no conflict with main.
  • Diff review (11 files, +772/−119): pure frontend/CSS + ADR-0019 + test updates — no schema, seam, API, SSE, Go, or Nix-derivation src/hash change.
    • New components/Icon.tsx consolidates all inline SVG (15 vendored Lucide glyphs + the ADR-0018 copy/check icons) behind one aria-hidden component; accessible names stay on the enclosing controls.
    • Every icon-only control (hamburger, back, dismiss, send, stop, open) carries both aria-label and title; tests were updated to query by accessible name.
    • Confirmed the .topbar .nav-toggle (0,2,0) specificity scope that out-specifies .icon-btn (0,1,0) — the exact desktop-hamburger-visible bug the ADR documents.

No blockers. Awaiting explicit free-text merge go-ahead before merging.

> *This was generated by AI while landing a PR.* **Landing audit — PR #16 — verdict: PASS** **Verification signal relied on:** local `nix flake check` (this repo's CI `ci / flake-check` has no `nix`-label runner and stays pending, so it never vouches). Ran the full gate locally — **all checks passed**: web build + eslint + prettier + vitest, Go, golangci-lint, and the nixos-module eval. **What was checked** - **Gate:** `nix flake check` → `all checks passed!` (exit 0). This is a real build of the web/Go/module derivations, not eval-only. - **Conventions:** title `feat(web): …` is valid Conventional Commits; body carries a working `Closes #15`, so the merge auto-closes the issue. Head is `feat/responsive-ui-overhaul` (a manual PR, not an `afk/<N>` run). - **Mergeable:** ✔ no conflict with `main`. - **Diff review (11 files, +772/−119):** pure frontend/CSS + ADR-0019 + test updates — no schema, seam, API, SSE, Go, or Nix-derivation `src`/hash change. - New `components/Icon.tsx` consolidates all inline SVG (15 vendored Lucide glyphs + the ADR-0018 copy/check icons) behind one `aria-hidden` component; accessible names stay on the enclosing controls. - Every icon-only control (hamburger, back, dismiss, send, stop, open) carries both `aria-label` and `title`; tests were updated to query by accessible name. - Confirmed the `.topbar .nav-toggle` (0,2,0) specificity scope that out-specifies `.icon-btn` (0,1,0) — the exact desktop-hamburger-visible bug the ADR documents. No blockers. Awaiting explicit free-text merge go-ahead before merging.
Sign in to join this conversation.
No reviewers
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
Cloonar/coding-lab!16
No description provided.