feat(web): responsive UI overhaul — hamburger nav, spacing scale, icon system #15

Closed
opened 2026-07-07 10:01:24 +02:00 by dominik.polakovics · 1 comment

This was generated by AI during triage.

Request

Overhaul the web UI to be properly responsive (maintainer request, design grilled interactively on 2026-07-07):

  • the navbar should show a hamburger menu on mobile
  • the cards should have well spacing — e.g. on the repo screen the running-instance title column is squeezed unreadable on phones by the chips/links/stop button
  • the stop button in the chat should be icon-only
  • the UI should work more with icons overall

Design decisions (binding, from the grilling session)

  1. Scope — polish within the existing design language (keep color/radius tokens, OS dark mode, 44px touch targets). No visual redesign.
  2. Nav pattern — hamburger menu. Bottom tab bar rejected (collides with the chat's pinned composer); priority+ nav rejected (complexity).
  3. Menu contents — mobile topbar keeps only brand · live dot · hamburger. The five section links plus username and Log out move into the menu.
  4. Menu style — full-width dropdown panel under the sticky topbar with a scrim; closes on outside tap, Esc, and navigation; trigger carries aria-expanded.
  5. Breakpoint — nav collapses below 640px; supersedes the old 560px hide-username rule.
  6. Card spacing — a tokenized spacing scale (--space-* CSS custom properties) applied consistently to card padding, list gaps, and section margins. Slightly roomier ≥640px, current density on phones.
  7. Instance row — on <640px stack into two lines: title + branch + state chips full-width on top, actions (Chat / Open / Stop) in a row below. Single line stays ≥640px.
  8. Chat stop — resting state is a 44px danger-colored stop-square icon button with an accessible name; tapping swaps in the existing textual "Confirm stop" + "Cancel" pair. Destructive confirm stays verbal.
  9. Icon source — no new dependency: vendor the ~15 needed Lucide icons (ISC license) as inline SVG paths behind a single Icon component, colored via currentColor.
  10. Icon policy — icon-only (with aria-label + title) for universal actions in tight spots: hamburger, back, close/dismiss, send, stop, external-link, and instance-row actions on mobile. Icon+text for nav menu entries, Log out, and form/action buttons.
  11. Send button — the chat composer's Send becomes an icon-only paper-plane.
  12. Nav section icons — Repos = folder, Credentials = key, Runs = play, Tokens = ticket, Settings = gear.

Agent brief follows as a comment.

> *This was generated by AI during triage.* ## Request Overhaul the web UI to be properly responsive (maintainer request, design grilled interactively on 2026-07-07): - the navbar should show a hamburger menu on mobile - the cards should have well spacing — e.g. on the repo screen the running-instance title column is squeezed unreadable on phones by the chips/links/stop button - the stop button in the chat should be icon-only - the UI should work more with icons overall ## Design decisions (binding, from the grilling session) 1. **Scope** — polish within the existing design language (keep color/radius tokens, OS dark mode, 44px touch targets). No visual redesign. 2. **Nav pattern** — hamburger menu. Bottom tab bar rejected (collides with the chat's pinned composer); priority+ nav rejected (complexity). 3. **Menu contents** — mobile topbar keeps only brand · live dot · hamburger. The five section links plus username and Log out move into the menu. 4. **Menu style** — full-width dropdown panel under the sticky topbar with a scrim; closes on outside tap, Esc, and navigation; trigger carries `aria-expanded`. 5. **Breakpoint** — nav collapses below **640px**; supersedes the old 560px hide-username rule. 6. **Card spacing** — a tokenized spacing scale (`--space-*` CSS custom properties) applied consistently to card padding, list gaps, and section margins. Slightly roomier ≥640px, current density on phones. 7. **Instance row** — on <640px stack into two lines: title + branch + state chips full-width on top, actions (Chat / Open / Stop) in a row below. Single line stays ≥640px. 8. **Chat stop** — resting state is a 44px danger-colored stop-square icon button with an accessible name; tapping swaps in the existing textual "Confirm stop" + "Cancel" pair. Destructive confirm stays verbal. 9. **Icon source** — no new dependency: vendor the ~15 needed Lucide icons (ISC license) as inline SVG paths behind a single `Icon` component, colored via `currentColor`. 10. **Icon policy** — icon-only (with `aria-label` + `title`) for universal actions in tight spots: hamburger, back, close/dismiss, send, stop, external-link, and instance-row actions on mobile. Icon+text for nav menu entries, Log out, and form/action buttons. 11. **Send button** — the chat composer's Send becomes an icon-only paper-plane. 12. **Nav section icons** — Repos = folder, Credentials = key, Runs = play, Tokens = ticket, Settings = gear. Agent brief follows as a comment.
Author
Owner

This was generated by AI during triage.

Agent Brief

Category: enhancement
Summary: Make the lab SPA responsive: collapse the topbar nav behind a hamburger below 640px, introduce a tokenized spacing scale, restack instance rows on narrow screens, and adopt a vendored inline-SVG icon system with icon-only controls in tight spots.

Current behavior:
The topbar renders brand, five text nav links (Repos · Credentials · Runs · Tokens · Settings), an SSE live dot, the username (hidden below 560px by an ad-hoc rule), and a Log out button inline at every viewport width — on phones the links crowd the bar. Spacing values (card padding, list gaps, section margins) are ad-hoc literals in the stylesheet. A repo card's instance row puts title/branch, up to three state chips, a Chat link, an Open deep-link, and a Stop button on one wrapping flex line, squeezing the title to an unreadable sliver on ~360px screens. The chat header's stop control is a text button ("Stop" → "Confirm stop" + "Cancel"), and the composer submits via a text "Send" button. The only iconography is unicode glyphs (←, ↗, ✕, ▸); there is no icon component or icon dependency.

Desired behavior:

  • Below a 640px viewport the topbar shows only brand · live dot · hamburger button. The hamburger opens a full-width dropdown panel beneath the sticky topbar, over a scrim, containing the five section links (icon + text: folder, key, play, ticket, gear), the username, and Log out. It closes on outside tap, Esc, and route navigation; the trigger has an accessible name and aria-expanded. At ≥640px the inline nav renders as today with the username visible (the 560px rule is removed).
  • A spacing scale exists as CSS custom properties (--space-*) alongside the existing color/radius tokens, and card padding, list gaps, and section margins are expressed through it — current density on phones, slightly roomier at ≥640px.
  • Below 640px an instance row stacks: first line is title + branch (+ AFK budget) at full width with its state chips; second line holds the actions (Chat, Open/connecting, Stop). At ≥640px the single-line layout is unchanged.
  • The chat header stop control rests as a 44px danger-colored stop-square icon button; activating it swaps in the existing textual "Confirm stop" + "Cancel" buttons unchanged. The composer's send action becomes an icon-only paper-plane button.
  • Icon-only controls (hamburger, back, close/dismiss, send, stop, external-link, and instance-row actions on mobile) each carry aria-label and title. Nav menu entries, Log out, and form/action buttons keep visible text next to any icon.
  • All icons render through a single Icon component containing vendored Lucide SVG paths (ISC license — keep attribution in the component header), sized via a prop and colored via currentColor so dark mode needs no extra work.

Key interfaces:

  • New Icon component — the only icon entry point; name + optional size props, inline <svg> with stroke="currentColor", no runtime dependency added to the web package.
  • The shared authenticated-page header component (brand/nav/live-dot/logout) — gains the collapse behavior and owns the open/closed menu state.
  • The instance-list row component under repo cards — gains the two-line narrow layout; its Stop flow (guarded outcome toast) must not change.
  • The chat header component and chat composer — stop and send become icon buttons; the two-phase stop confirmation logic is untouched.
  • The design-token stylesheet — new --space-* custom properties join the existing --bg/--radius-* token block; the 44px touch-target and 16px-input rules must survive.
  • Existing component tests select buttons by visible text (e.g. "Stop", "Open ↗") — icon-only controls must keep accessible names so those tests can query by role/accessible name instead.

Acceptance criteria:

  • At <640px the topbar contains only brand, live dot, and the menu button; the menu holds the five section links, username, and Log out; it closes on outside tap, Esc, and navigation, and the trigger reflects state via aria-expanded.
  • At ≥640px the full inline nav renders with username and Log out; no hamburger is present.
  • --space-* tokens exist and card padding, card-list gaps, and section margins reference them; desktop layouts show no regressions.
  • On a 360px-wide viewport, an instance row shows title and branch across the full row width with actions on their own line, and the page never scrolls horizontally.
  • The chat stop control is icon-only at rest with an accessible name, and confirming still requires the textual "Confirm stop" step.
  • The chat send control is an icon-only button with an accessible name.
  • Every icon-only control has aria-label and title; all icons render via the single Icon component; package.json gains no new dependency.
  • Icons are legible in both light and dark mode (inherit currentColor).
  • Unit tests and the Playwright suite pass, with selectors updated to query by role/accessible name where buttons became icon-only. Validate with local nix flake check (CI has no runner).

Out of scope:

  • Any visual redesign: colors, typography, radii, shadows, and the overall design language stay as they are.
  • Bottom tab bar or priority+ overflow nav (explicitly rejected in the design session).
  • Removing or weakening the two-phase stop confirmation.
  • Icon fonts or icon package dependencies.
  • Chat markdown rendering, tool-call grouping, and copy-raw (tracked separately in issue #13).
> *This was generated by AI during triage.* ## Agent Brief **Category:** enhancement **Summary:** Make the lab SPA responsive: collapse the topbar nav behind a hamburger below 640px, introduce a tokenized spacing scale, restack instance rows on narrow screens, and adopt a vendored inline-SVG icon system with icon-only controls in tight spots. **Current behavior:** The topbar renders brand, five text nav links (Repos · Credentials · Runs · Tokens · Settings), an SSE live dot, the username (hidden below 560px by an ad-hoc rule), and a Log out button inline at every viewport width — on phones the links crowd the bar. Spacing values (card padding, list gaps, section margins) are ad-hoc literals in the stylesheet. A repo card's instance row puts title/branch, up to three state chips, a Chat link, an Open deep-link, and a Stop button on one wrapping flex line, squeezing the title to an unreadable sliver on ~360px screens. The chat header's stop control is a text button ("Stop" → "Confirm stop" + "Cancel"), and the composer submits via a text "Send" button. The only iconography is unicode glyphs (←, ↗, ✕, ▸); there is no icon component or icon dependency. **Desired behavior:** - Below a 640px viewport the topbar shows only brand · live dot · hamburger button. The hamburger opens a full-width dropdown panel beneath the sticky topbar, over a scrim, containing the five section links (icon + text: folder, key, play, ticket, gear), the username, and Log out. It closes on outside tap, Esc, and route navigation; the trigger has an accessible name and `aria-expanded`. At ≥640px the inline nav renders as today with the username visible (the 560px rule is removed). - A spacing scale exists as CSS custom properties (`--space-*`) alongside the existing color/radius tokens, and card padding, list gaps, and section margins are expressed through it — current density on phones, slightly roomier at ≥640px. - Below 640px an instance row stacks: first line is title + branch (+ AFK budget) at full width with its state chips; second line holds the actions (Chat, Open/connecting, Stop). At ≥640px the single-line layout is unchanged. - The chat header stop control rests as a 44px danger-colored stop-square icon button; activating it swaps in the existing textual "Confirm stop" + "Cancel" buttons unchanged. The composer's send action becomes an icon-only paper-plane button. - Icon-only controls (hamburger, back, close/dismiss, send, stop, external-link, and instance-row actions on mobile) each carry `aria-label` and `title`. Nav menu entries, Log out, and form/action buttons keep visible text next to any icon. - All icons render through a single `Icon` component containing vendored Lucide SVG paths (ISC license — keep attribution in the component header), sized via a prop and colored via `currentColor` so dark mode needs no extra work. **Key interfaces:** - New `Icon` component — the only icon entry point; name + optional size props, inline `<svg>` with `stroke="currentColor"`, no runtime dependency added to the web package. - The shared authenticated-page header component (brand/nav/live-dot/logout) — gains the collapse behavior and owns the open/closed menu state. - The instance-list row component under repo cards — gains the two-line narrow layout; its Stop flow (guarded outcome toast) must not change. - The chat header component and chat composer — stop and send become icon buttons; the two-phase stop confirmation logic is untouched. - The design-token stylesheet — new `--space-*` custom properties join the existing `--bg`/`--radius-*` token block; the 44px touch-target and 16px-input rules must survive. - Existing component tests select buttons by visible text (e.g. "Stop", "Open ↗") — icon-only controls must keep accessible names so those tests can query by role/accessible name instead. **Acceptance criteria:** - [ ] At <640px the topbar contains only brand, live dot, and the menu button; the menu holds the five section links, username, and Log out; it closes on outside tap, Esc, and navigation, and the trigger reflects state via `aria-expanded`. - [ ] At ≥640px the full inline nav renders with username and Log out; no hamburger is present. - [ ] `--space-*` tokens exist and card padding, card-list gaps, and section margins reference them; desktop layouts show no regressions. - [ ] On a 360px-wide viewport, an instance row shows title and branch across the full row width with actions on their own line, and the page never scrolls horizontally. - [ ] The chat stop control is icon-only at rest with an accessible name, and confirming still requires the textual "Confirm stop" step. - [ ] The chat send control is an icon-only button with an accessible name. - [ ] Every icon-only control has `aria-label` and `title`; all icons render via the single `Icon` component; `package.json` gains no new dependency. - [ ] Icons are legible in both light and dark mode (inherit `currentColor`). - [ ] Unit tests and the Playwright suite pass, with selectors updated to query by role/accessible name where buttons became icon-only. Validate with local `nix flake check` (CI has no runner). **Out of scope:** - Any visual redesign: colors, typography, radii, shadows, and the overall design language stay as they are. - Bottom tab bar or priority+ overflow nav (explicitly rejected in the design session). - Removing or weakening the two-phase stop confirmation. - Icon fonts or icon package dependencies. - Chat markdown rendering, tool-call grouping, and copy-raw (tracked separately in issue #13).
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
Cloonar/coding-lab#15
No description provided.