Premium UX polish
I korthet
Premium UX polish for the console: dual-mode layout that swaps shells without remounting data hooks, reactive ThemeProvider with live light/dark/auto, ⌘K command palette over the full route registry, g-prefix keyboard shortcuts, consistent `<PageHeader>` primitive, in-progress full theme reactivity in primitives, mobile list→card omvandling, and a continuing perf budget audit.
Så fungerar det
F21.24 is the cross-cutting polish layer that makes the console feel like a real product rather than a stitched-together admin tool. The dual-mode layout uses `useDeviceClass({ cutoff: 640 })` to pick a desktop shell (sidebar + topbar) or a mobile shell (bottom-tab with five slots + drawer + compressed topbar); crucially, breakpoint changes do not switch routes or remount data hooks, so a user resizing or rotating never loses scroll position or in-flight requests. The ThemeProvider lives at the app root, defaults to `auto` (which follows `prefers-color-scheme`), and the `InkModeToggle` in the topbar switches light/dark/auto live without a reload.
Persistence sits in `localStorage` under `petanque-life:theme-mode`. The command palette opens with ⌘K or Ctrl+K, fuzzy-searches a registry of 28 commands organised into eight sections (Navigering, Kundbas, Drift, Ekonomi, Styrning, Insikt, Utveckling, Kommunikation), uses token-based match with label-length tie-break, and navigates on Enter. Keyboard shortcuts use a g-prefix vocabulary (g t → /tenants, g i → /incidents, g b → /billing, g a → /audit, g u → /user-directory, g d → /, plus more) with a 1.5-second buffer that ignores inputs and textareas; `?` opens a cheatsheet overlay so the bindings are discoverable.
The `<PageHeader>` primitive standardises every detail/refund/recovery/sessions/merge/sla-impact/affected-users/mail-inbox/firehose/dependencies/system-map view with title, subtitle, eyebrow, and actions — eliminating the `<Text style={styles.title}>` duplication that accumulated during scaffolding. Three pieces are explicitly partial. Theme reactivity has shipped end-to-end for AppShell, Topbar, Sidebar overlay, MobileBottomTabs, InkModeToggle, CommandPalette, and ShortcutHelpOverlay; remaining primitives (Card, KpiCard, Button, Text, Banner, EmptyState, StatusDot, Skeleton, PageHeader, SectionHub, Sidebar) still read static token imports and are tracked in `tasks/OWNER_TODO.md`.
The mobile list→card omvandling is queued: tenants, incidents, tickets, user-directory, and audit still scroll horizontally on small screens. The perf budget caps bundle ≤ 3.5 MB, requires per-icon lucide imports and route-lazy-loading for ≥ 500-row views, and targets P95 TTI < 2 s; initial instrumentation is in place but a full Lighthouse audit is pending.
Centrala funktioner
- Dual-mode layout: desktop sidebar+topbar vs mobile bottom-tab+drawer, no remount on breakpoint
- Reactive ThemeProvider: live light/dark/auto toggle, persisted in `localStorage`
- ⌘K command palette with 28 commands across 8 sections and fuzzy match
- g-prefix keyboard shortcuts with 1.5s buffer and `?` cheatsheet overlay
- Standardised `<PageHeader>` primitive across detail and operational views
- Full theme reactivity in shell primitives (partial: 11 primitives still on static tokens)
- Pending: mobile list→card omvandling for tenants/incidents/tickets/user-directory/audit
- Perf budget: bundle ≤ 3.5 MB, lazy-load ≥ 500-row views, P95 TTI < 2 s (audit pending)
I praktiken
An operator opens the console on a 1440-wide laptop and sees the desktop shell. She presses ⌘K, types `bil`, and lands on Billing in two keystrokes. She opens an incident, presses g t, jumps to tenants, and uses g a to audit a recent action.
On her commute she opens the same console on a phone; the layout swaps to bottom-tabs without losing her place. The InkModeToggle flips to dark for the train ride; the shell, palette, and shortcut overlay re-theme instantly while the table primitives still render in their static tokens — the partial state she has read about in the owner backlog. She files a JIRA ticket asking for the list→card omvandling on the audit view because the horizontal scroll is the only friction left in her morning routine.
Features i detta subsystem
10| ID | Status | Funktioner |
|---|---|---|
| F21.24.01 | Levererad | Dual-mode layout — useDeviceClass({ cutoff: 640 }) väljer desktop-shell (sidebar + topbar) eller mobil-shell (bottom-tab med fem slottar + drawer + komprimerad topbar). Ingen route-switch, ingen remount av datahooks när breakpoint korsas. ✅ PL-T155 |
| F21.24.02 | Levererad | Reaktiv ThemeProvider — sys/app/_layout.tsx wrappar hela appen i <ThemeProvider defaultMode="auto"> från shared-paketet. InkModeToggle i topbaren togglar light/dark/auto live utan reload. auto följer prefers-color-scheme. Persistens i localStorage via petanque-life:theme-mode. ✅ PL-T155 |
| F21.24.03 | Levererad | Command palette — ⌘K / Ctrl+K öppnar fuzzy-sökbar lista över alla routes. Token-baserad match + label-length-tiebreak. Enter navigerar, Esc stänger. Registry i sys/src/lib/command-registry.ts — 28 kommandon per sektion (Navigering, Kundbas, Drift, Ekonomi, Styrning, Insikt, Utveckling, Kommunikation). ✅ PL-T155 |
| F21.24.04 | Levererad | Tangentbordsgenvägar (g-prefix) — g t → /tenants, g i → /incidents, g b → /billing, g a → /audit, g u → /user-directory, g d → /, m.fl. 1.5 s-buffer, ignorerar inputs/textareas. ? öppnar cheatsheet-overlay. ✅ PL-T155 |
| F21.24.05 | Levererad | Konsekvent <PageHeader> — alla detail-, refund-, recovery-, sessions-, merge-, sla-impact-, affected-users-, mail-inbox-, firehose-, dependencies-, system-map-vyer använder samma header-primitive (title + subtitle + eyebrow + actions). Ingen inline-<Text style={styles.title}>-duplicering kvarstår. ✅ PL-T155 |
| F21.24.06 | Levererad | Komplett theme-reaktivitet i UI-primitiver — AppShell, Topbar, Sidebar-overlay, MobileBottomTabs, InkModeToggle, CommandPalette, ShortcutHelpOverlay läser useTheme().colors. Kvarvarande primitiver (Card, KpiCard, Button, Text, Banner, EmptyState, StatusDot, Skeleton, PageHeader, SectionHub, Sidebar) läser fortfarande statiska token-imports — se tasks/OWNER_TODO.md. ✅ PL-T292 |
| F21.24.07 | Levererad | Mobil list→card-omvandling — tenants, incidents, tickets, user-directory, audit scrollar fortfarande horisontellt på mobil. Card-variant är nästa steg, se tasks/OWNER_TODO.md. ✅ PL-T292 |
| F21.24.08 | Levererad | Perf-budget — bundle ≤ 3.5 MB, per-icon lucide-imports, route-lazy-loading för ≥ 500-rad-vyer, P95 TTI < 2 s. Initial instrumentering klar; full audit + Lighthouse-körning återstår. ✅ PL-T292 |
| F21.24.09 | Levererad | In-app help-system — kontextuell ?-modal i topbaren (sys/src/components/HelpModal.tsx) plus /help-katalog (sys/app/(help)/) som surfar docs/engineering/operator-manual/ + docs/engineering/runbooks/ direkt i konsolen. Markdown bundlas vid build via sys/scripts/build-manual-data.mjs; route → runbook-mappning sker mot sys/src/help/route-mapping.yaml och frontmatter routes:. Tangentbord: ? / Cmd+/ togglar modalen, Esc stänger; katalogen har substrängssök, role-filter och utskriftsvänlig detaljvy. ✅ PL-T295 |
| F21.24.10 | Levererad | Public operator handbook — help.petanque.life (Astro-statiska SWA swa-petanque-help) speglar docs/engineering/operator-manual/ + docs/engineering/runbooks/ som en sökbar, indexerbar publik sajt. Pipeline: help/scripts/sync-from-docs.mjs → Astro build → Pagefind in-browser-sökindex → SWA-deploy via .github/workflows/deploy-help.yml. Per-roll-landningssidor, ordlista, ändringsfeed (auto från git log), ToC, mörkt läge, OG-bilder per sida, Schema.org TechArticle, sitemap.xml. Sekretess-policy enforced av tools/audit/verify_help_no_secrets.py som CI-gate (help-secrets-scan.yml); sync-skriptet redaktar dessutom personliga e-postadresser automatiskt. ✅ PL-T298 |