Step 7: UI foundation #3
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
packages/ui tokens and primitives per docs/UI.md, app shell, editable sidebar (in memory), inbox panel, account and version, Dashboard with honest empty states, svelte-sonner.
Step 7 in docs/PLAN.md. Done when: merged to dev, browser-verified
Started step 7 UI foundation on branch
ui-foundation, base headfac2890c93276e645d6ba439ff2291ba93f0eec4.Scope:
packages/uitokens/primitives/tests,packages/webapp shell/sidebar/inbox/dashboard/routes/sonner, browser verification and initial-route gzip measurement. Required UI skills and docs loaded before implementation.Fast gate completed on
ui-foundationat the current implementation head.Verbatim output:
The UI package tests cover the non-chart/table primitives' accessible roles/names and interaction behavior; the web package still passes its existing health tests.
UI foundation findings worth keeping:
$state is not definedfromnavigation.ts: Svelte runes require the.svelte.tsmodule treatment. The store now lives innavigation.svelte.ts, and the web Vite resolver recognizes that extension.container-typeto intrinsic inline controls madeStatusDotcollapse to zero width under size containment. Containment remains on block/layout primitives; intrinsic controls stay content-sized.UI foundation finished on branch
ui-foundation.Head:
fb63985Final
scripts/verify fastoutput:Final
scripts/verify browseroutput:Initial dashboard route JS is 54,121 bytes gzip, measured as the sum of the gzip-9 sizes of the JS assets referenced by
packages/web/build/index.html.Screenshots:
/mnt/hdd/infraternal/artifacts/ui-foundation/desktop-light.png/mnt/hdd/infraternal/artifacts/ui-foundation/desktop-dark.png/mnt/hdd/infraternal/artifacts/ui-foundation/mobile-light.png/mnt/hdd/infraternal/artifacts/ui-foundation/mobile-dark.pngAdditional verification: the 1024×900 icon-rail spot check reported
rail: true,overflow: false,triggerFits: true, and no browser errors.Build job
ui-foundation(gpt-5.6-luna/max) finished. Author's report:Review started: independent UI foundation review in detached worktree at
fb63985ab8; base dev ata9961a2198. Scope is read-only review of git diff dev...HEAD plus production-browser verification.Review findings recorded so far (all reproduced on release binary
fb63985): HIGH: at 1024x768/768x1024 the icon rail hides dashboard/group labels and exposes unnamed links/buttons in the accessibility tree; HIGH: entering Edit sidebar in the rail hides item/group actions while rename/create controls clip past the 68px rail (screenshots /mnt/hdd/infraternal/artifacts/ui-review/light-normal-1024x768-edit.png and light-normal-768x1024-edit.png); HIGH: mobile Navigation aria-modal has no focus trap—after 18 Tab presses focus reaches BODY, Skip to content, header controls outside the drawer; HIGH: account-menu Sign out leaves URL/menu unchanged and emits no action. Further primitive/motion findings are in progress.ISSUE UPDATE kayg/infraternal#3\nreview of: ui-foundation @ fb63985ab8c53c0a320aee1c05af5711f66bdd0d\nverdict: merge after fixes\n\ngates:\nPASS fast: JavaScript dependencies\nPASS fast: build web app\nPASS fast: cargo fmt --check\nPASS fast: cargo clippy\nPASS fast: cargo test\nPASS fast: svelte-check\nPASS fast: UI package svelte-check\nPASS fast: Vitest\nPASS fast: UI package Vitest\nPASS fast: OpenAPI and TypeScript client drift\nPASS browser: JavaScript dependencies\nPASS browser: install Chromium and system dependencies\nPASS browser: build web app\nPASS browser: build release binary\nPASS browser: Playwright against release server\n\nscreenshots: /mnt/hdd/infraternal/artifacts/ui-review/\n\nfindings:\n1. [HIGH][Accessibility] The icon rail hides Dashboard/group labels without supplying accessible names; the 1024px accessibility snapshot exposes unnamed links/buttons (packages/web/src/lib/shell/Sidebar.svelte:77-97,217).\n2. [HIGH][Layout] Edit sidebar at 1024x768 and 768x1024 hides item/group actions while rename/create controls clip past the 68px rail (Sidebar.svelte:98-112,122-147,216-223); evidence: light-normal-1024x768-edit.png and light-normal-768x1024-edit.png.\n3. [HIGH][Accessibility] The custom mobile aria-modal has no focus trap; after 19 Tabs focus is BODY/outside and Escape does not close it (packages/web/src/lib/shell/AppShell.svelte:115,120-125).\n4. [HIGH][Accessibility/Security] Account-menu Sign out is a visible no-op: click leaves the URL/menu unchanged and emits no toast (packages/web/src/lib/shell/Sidebar.svelte:158-162).\n5. [HIGH][Accessibility] Popover opens a role=dialog panel without moving focus into it, so its Escape handler is unreachable when content is non-focusable (packages/ui/src/lib/Popover.svelte:22-29); the test only asserts open text (primitives.test.ts:62-64).\n6. [HIGH][Accessibility] Field makes the label target optional and never associates hint/error IDs or aria-invalid/aria-describedby with the child control (packages/ui/src/lib/Field.svelte:7-24).\n7. [MEDIUM][Layout] AppShell responsive hide rules lose to IconButton scoped display: hamburger and rail-toggle render at every width; rail-toggle is a no-op on mobile and squeezes/truncates the 320px breadcrumb (AppShell.svelte:95,103,150,158-162; screenshots light-normal-1440x900-dashboard.png and light-normal-320x640-dashboard.png).\n8. [MEDIUM][Accessibility] Menu button omits ArrowDown/ArrowUp opening behavior required by its role; focused Account + ArrowDown leaves the menu closed (packages/ui/src/lib/Menu.svelte:36-42).\n9. [MEDIUM][Accessibility] SPA navigation does not move focus to the new heading or close transient menu state; Profile navigation leaves focus on BODY with the Account menu still visible (AppShell.svelte:40-53, Sidebar.svelte:160-161).\n10. [MEDIUM][Color] Manual theme switching changes data-theme but Toaster remains theme=system; in a light OS context, the dark app produced a white toast (AppShell.svelte:71-76, Toaster.svelte:8; light-manual-dark-toast.png).\n11. [MEDIUM][UI/Performance] svelte-sonner default toast transition animates height and box-shadow in addition to transform/opacity (Toaster.svelte:8; computed normal-motion transition: transform 0.4s, opacity 0.4s, height 0.4s, box-shadow 0.2s), contrary to the UI motion contract.\n12. [MEDIUM][UI/Accessibility] Touch hover states are not gated and active scale also runs during keyboard Space activation (Sidebar.svelte:189, Menu.svelte:52, AppShell.svelte:147, Button.svelte:57, IconButton.svelte:55; keyboard computed transform matrix was 0.96).\n13. [MEDIUM][Accessibility] Tooltip puts aria-describedby on a non-focusable wrapper instead of the wrapped control, so the tooltip description is not reliably announced (packages/ui/src/lib/Tooltip.svelte:9-11).\n14. [MEDIUM][Reuse] Dashboard and PlaceholderPage duplicate page-intro/eyebrow/lede styling instead of extending a shared primitive (packages/web/src/routes/+page.svelte:67-82, packages/web/src/lib/PlaceholderPage.svelte:24-28).\n15. [MEDIUM][Typography] The Inter token is declared but no font face/import is shipped; on this Debian VM fc-match Inter resolves to WenQuanYi Zen Hei (packages/ui/src/tokens.css:19-20).
Independent Playwright route matrix against target/release/infraternal: 14 routes x 5 viewports (1440x900, 1024x768, 768x1024, 390x844, 320x640) x 4 passes (light/dark, reduce/no-preference); result { routes: 14, viewports: 5, passes: 4, failures: [] }. Focused probes additionally recorded unnamed rail controls, 0 Move Hosts button at 1024/768 edit mode, drawer focus escape after 19 Tabs, Sign out no-op, white manual-dark toast, and 56,418 gzip bytes for the 10 initial JS responses (under the 120 KB budget; author claim 54,121 not reproduced).
Orchestrator: review accepted (15 findings). Fix job
ui-fixlaunched with all of them plus 7 visual findings from the orchestrator: duplicated status captions, a green dot claiming health on a zero count, unlabeled header chevrons, placeholder-looking empty-state icons, eyebrow labels on every section, marketing intro copy, and a dead "Add host" primary action.Started UI foundation review fixes on branch
ui-foundationat basefb63985ab8c53c0a320aee1c05af5711f66bdd0d.Scope: fix every finding from the independent review plus the seven orchestrator visual findings, add the requested browser checks, verify with
scripts/verify fastandscripts/verify browser, capture the required screenshots, and report route JS/font byte sizes.Recon at
fb63985confirms the review repros in source and artifacts: rail CSS sets labels/edit actions todisplay:none; the mobile drawer only listens on its container and has no Tab loop; Popover never focuses its panel; Field only forwards an optional callerfor; Tooltip describes its wrapper; Menu handles arrows only after opening; Sonner istheme="system"and shipsheight/box-shadowtransitions; the dashboard duplicates status copy, shows a green zero Inbox state, keeps dead host actions, eyebrows, marketing copy and dash empty marks. The account menu also exposes a no-op Sign out before auth exists. Fixing these at the shared primitive/shell seams keeps behavior reusable and avoids route-specific patches.ISSUE UPDATE kayg/infraternal#3
branch: ui-foundation
base:
fb63985head:
2007c16fixed:
rules applied: emil-design-eng; better-ui; better-layout; better-typography; better-colors; better-accessibility; better-writing; better-interface.
gates:
PASS fast: JavaScript dependencies
PASS fast: build web app
PASS fast: cargo fmt --check
PASS fast: cargo clippy
PASS fast: cargo test
PASS fast: svelte-check
PASS fast: UI package svelte-check
PASS fast: Vitest
PASS fast: UI package Vitest
PASS fast: OpenAPI and TypeScript client drift
PASS browser: JavaScript dependencies
PASS browser: install Chromium and system dependencies
PASS browser: build web app
PASS browser: build release binary
PASS browser: Playwright against release server
initial route JS gzip: 57309 bytes; fonts: 302728 bytes shipped WOFF2
screenshots:
open problems: none
Fix job
ui-fixfinished at2007c16: all 22 findings addressed, gates green, initial JS 57,309 B gzip, fonts 302,728 B WOFF2 (likely full charset; measured in verify). Verify jobui-verifyrunning.Verification started: worktree /mnt/hdd/infraternal/.worktrees/ui-review, requested detached head
2007c16(ui-foundation), fix range fb63985..2007c16. Verification-only job; no tracked-file edits or commits. Required UI skills and repo docs loaded; gates and Playwright evidence will be recorded here.ISSUE UPDATE kayg/infraternal#3
verify of: ui-foundation @
2007c16verdict: merge
gates:
Targeted production-browser verification: 20 contexts (1440×900, 1024×768, 768×1024, 390×844, 320×640 × light/dark × reduced-motion on/off), 20 screenshots, 0 page errors, 0 console errors, no horizontal overflow or visible text overlap.
findings:
fonts on first load: 88,660 bytes,
inter-latin-wght-normal.Dx4kXJAl.woff248,256 bytes +jetbrains-mono-latin-wght-normal.B9CIFXIH.woff240,404 bytes. This is Latin-only normal-weight WOFF2, not the full character set. The installed Fontsource 5.3.0 normal-weight shard totals are Inter 218,512 + JetBrains Mono 86,244 = 304,756 bytes; Latin + Latin Extended would be Inter 133,324 + JetBrains Mono 55,600 = 188,924 bytes. The 302,728-byte fix estimate is not the first-load network figure and is approximately the all-normal-shard total with the 2,028-byte JetBrains Mono Cyrillic-ext shard omitted.metrics: initial route JS gzip 56,704 bytes (within the 120 KiB budget).
artifacts:
/mnt/hdd/infraternal/artifacts/ui-verify/evidence.jsonand the 20*.pngscreenshots in that directory.blocks-merge: none
later: none
Verify job
ui-verify(gpt-5.6-luna/max): merge. All 22 findings verified fixed; first-load fonts 88,660 B (Latin shards only). Merged to dev. Step 7 done.