Files
familysync/.planning/phases/17-ui-optimization-polish/17-CONTEXT.md
T

14 KiB
Raw Blame History

Phase 17: UI Optimization & Polish - Context

Gathered: 2026-06-17 Status: Ready for planning

## Phase Boundary

A visual-identity & polish pass for the PWA, spanning four bounded workstreams (AC from this discussion; D added from Phase 19 UAT, see Decisions §D):

  • A — Phone-layout polish. Fix the long-standing phone (≤767px) fixed-chrome overlap where the position: fixed BottomTabBar covers the New Event FAB (FAB lands on the Admin tab) and occludes the bottom of the calendar + the colour-legend chips, then sweep other small-viewport spacing / tap-target / overflow issues. CSS/layout only, no behaviour change.
  • B — Branding assets. Generate a real FamilySync logo and drop it into the already-built BrandSlot seam (apps/pwa/src/components/BrandSlot.tsx), and produce a complete favicon / PWA-icon set to replace the placeholder stubs in apps/pwa/public/ (icon-192.png 699 B, icon-512.png, apple-touch-icon.png 617 B — all generated stubs; there is currently no favicon.ico/favicon.svg and index.html links only the apple-touch icon).
  • C — Theme-token groundwork. Restructure apps/pwa/src/styles/tokens.css from its single light :root into a themeable semantic-token layer (swappable by data-theme / prefers-color-scheme). Light stays the only shipped theme — this is enabling groundwork only.
  • D — UAT-surfaced UI fixes (from Phase 19 live UAT). Wire a logout control to the existing fetchLocalLogout() (no backend), add success feedback to admin create/reset-password flows, fix dialog/popup bottom-center positioning, and rework the clunky admin navigation. See Decisions §D (D-07…D-10).

Out of scope (explicitly deferred this discussion, 2026-06-17):

  • Shipped dark theme + light/dark/system toggle → backlog 999.20 (Phase 17's token groundwork is the enabling seam).
  • Broader "modern styling" visual refresh (contemporary restyle of login/calendar/event-form/lists/admin) → backlog 999.21, flagged for a future milestone — a redesign track, not a polish phase.

This stays a focused polish + branding + groundwork pass, not a redesign.

## Implementation Decisions

A — Phone-layout polish

  • D-01: Fix the seed defect (BottomTabBar overlapping the FAB + colour legend) AND run a bounded small-viewport sweep — the Phase 7 layout.spec.ts assertions (tap targets ≥44px, no horizontal overflow, critical elements in-viewport, accessible names) are the checklist; fix what they flag across phone routes. Bounded and checklist-driven, not a free-form audit.
  • D-02: Fix technique and regression-guard mechanism are the researcher's call (deferred from discussion). Inputs the researcher must weigh: the ROADMAP/todo fix sketch (lift FAB to bottom: calc(56px + env(safe-area-inset-bottom,0px) + var(--space-6)) + matching content padding-bottom, OR shrink the 100dvh column by the bar height) vs. a single shared --bottom-chrome-h token consumed by both the FAB offset and the content padding (single source of truth). Researcher also decides whether to add a permanent overlap assertion to layout.spec.ts (FAB/legend must not intersect the BottomTabBar rect on phone profiles) vs. playwright-cli manual verification only. Default lean if evidence is neutral: shared token + add the CI assertion (hardest to regress), but this is the researcher's decision to make on the merits.

B — Branding assets

  • D-03: Logo + full icon set are AI-generated in-phase (option 2a). Claude generates the logo and the complete icon/favicon set from the brief below, wires them in (BrandSlot <img>, apps/pwa/public/ files, index.html <link>s, and the vite-plugin-pwa manifest icons[] in apps/pwa/vite.config.ts), and the user approves the result before it's final. No external designer / user-supplied art.
  • D-04: Deliver a complete icon set, not just a logo: favicon.ico + favicon.svg, icon-192.png, icon-512.png, a proper maskable 512 (the current manifest reuses the non-maskable 512 as maskable — a real maskable needs safe-zone padding), and apple-touch-icon.png (180×180). Update index.html (add the missing <link rel="icon">s; theme-color currently #4A90D9) and the vite.config.ts manifest to reference them.
  • D-05: Drive the logo through the existing BrandSlot seam contract — swap the placeholder <div> for an <img> and override the --brand-logo-* tokens — without changing LoginPage layout (the seam was built in Phase 19 precisely to isolate this). Keep the accessibility shape: <h1> carries the app name, logo image is decorative (alt="" / aria-hidden), no layout shift.

C — Theme-token groundwork

  • D-06: Restructure tokens.css into a themeable layer (semantic tokens resolvable per theme via data-theme/prefers-color-scheme) — groundwork only (option 3a). Do NOT author dark palette values, wire prefers-color-scheme to actually flip, or add a toggle this phase. Light remains the sole shipped theme. Keep the existing invariant: no hard-coded hex/px in component files — all values stay in tokens.css. The restructure must leave the Schedule-X --sx-color-* overrides (bottom of tokens.css) working unchanged.

D — UAT-surfaced UI findings (from Phase 19 live UAT, 2026-06-17)

Surfaced by the operator during the Phase 19 local-auth UAT and routed here by operator decision — these are UI concerns, not Phase 19 auth blockers. Phase 19 ships functionally complete; Phase 17 owns the UI. (Recorded in .planning/phases/19-local-auth-no-oidc-mode/19-UAT.md as F-01…F-04.)

  • D-07 (F-02) — Wire a logout control into the UI. Logout is fully plumbed but unreachable: the endpoint POST/GET /api/auth/local/logout works (200, clears cookie — BL-02 verified live) and fetchLocalLogout() exists at apps/pwa/src/api/client.ts:127, but no component calls it (zero logout buttons in apps/pwa/src). Add a logout control (likely in SettingsSheet.tsx and/or AppNav) that calls the existing client function + redirects to /login. No backend work — UI wiring only. (Slightly beyond pure "polish" — it's a small new control; planner should size it.)
  • D-08 (F-01) — Add success feedback to admin local-account actions. Admin create-member and reset-password both succeed (verified at DB/login level in UAT) but show no success toast/confirmation, leaving the operator unsure it worked. Add success feedback to those admin flows (AdminPage.tsx).
  • D-09 (F-03) — Fix dialog/popup positioning. Popups/sheets render bottom-center instead of properly centered. Fits the fixed-chrome/sheet-positioning sweep already in workstream A; likely the same dialog/sheet CSS (SettingsSheet.tsx and shared dialog styles). Verify across phone + desktop via playwright-cli.
  • D-10 (F-04) — Rework the clunky admin navigation. Admin UI navigation reads as clunky and needs a rework. Larger UX item than the others — planner should decide whether it fits this phase's "polish" budget or warrants its own slice. (AdminPage.tsx, admin nav/tab surface.)

Claude's Discretion

  • D-02 (fix technique + regression guard) is explicitly delegated to the researcher/planner.
  • Exact small-viewport issues surfaced by the layout.spec sweep (D-01) — fix as found, within the no-behaviour-change boundary.
  • Logo visual execution within the brand brief (see Specific Ideas) — subject to user approval at the checkpoint.

Folded Todos

  • 2026-06-13-pwa-phone-bottombar-overlap.md (area: pwa-ui, resolves_phase: 17) — the phase's seed defect. Phone-layout fixed BottomTabBar overlaps the New Event FAB + colour legend at ≤767px. Reproduced 2026-06-13 via playwright-cli at 390×844 (FAB over Admin tab; "Dev User" legend clipped) vs 1280×800 (no overlap). Long-standing (BottomTabBar dates to Phase 04), not a Phase 10 regression. This is workstream A's anchor — its files: list (App.tsx, BottomTabBar.tsx, CalendarShell.tsx) is the fix surface.

<canonical_refs>

Canonical References

Downstream agents MUST read these before planning or implementing.

Phase scope & seed defect

  • .planning/ROADMAP.md §"Phase 17: UI Optimization & Polish" — goal, three-workstream scope, scope boundary, seed-defect detail + CSS fix sketch.
  • .planning/todos/pending/2026-06-13-pwa-phone-bottombar-overlap.md — the folded seed-defect todo (repro, fix sketch, affected files).
  • .planning/ROADMAP.md §"Phase 999.20" / §"Phase 999.21" — the deferred dark-mode and styling-refresh backlog items (what is explicitly NOT in this phase).

A — Phone layout (fix surface)

  • apps/pwa/src/App.tsxwindow.matchMedia('(max-width: 767px)') phone breakpoint + contentStyle (currently reserves no padding-bottom for the fixed bar).
  • apps/pwa/src/components/BottomTabBar.tsxposition: fixed; height: calc(56px + env(safe-area-inset-bottom)); z-index: 200.
  • apps/pwa/src/components/CalendarShell.tsx — the "New Event" FAB (position: fixed; bottom: var(--space-6); right: var(--space-6)).
  • apps/pwa/e2e/layout.spec.ts — Phase 7 quality-bar assertions (UI-SPEC Rules 14: ≥44px tap targets, no overflow, in-viewport, accessible names); the sweep checklist AND the home for any new overlap regression assertion.
  • apps/pwa/playwright.config.tsiphone (iPhone 14/WebKit 390×844), pixel (Pixel 7/Chromium 412×915), desktop (Desktop Chrome 1280×720) profiles to verify across.

B — Branding

  • apps/pwa/src/components/BrandSlot.tsx — the Phase-17 branding seam; header documents the --brand-logo-* token contract and the swap-div-for-<img> plan.
  • .planning/phases/19-local-auth-no-oidc-mode/19-UI-SPEC.md §Brand Slot — the seam's design contract (referenced by BrandSlot.tsx).
  • apps/pwa/public/apple-touch-icon.png, icon-192.png, icon-512.png (placeholder stubs to replace).
  • apps/pwa/index.html — current <link rel="apple-touch-icon"> + theme-color meta (no <link rel="icon"> yet).
  • apps/pwa/vite.config.ts §VitePWA({ manifest: { icons: [...] } }) (lines ~2941) — PWA manifest icon list to update (incl. the improper maskable reuse).

C — Theming

  • apps/pwa/src/styles/tokens.css — the single light :root token system to restructure into a themeable layer (note the Schedule-X --sx-color-* overrides at the bottom and the --brand-logo-* defaults). </canonical_refs>

<code_context>

Existing Code Insights

Reusable Assets

  • BrandSlot seam (apps/pwa/src/components/BrandSlot.tsx): purpose-built in Phase 19 to absorb the real logo with zero LoginPage layout change — swap the placeholder div for an <img> and set --brand-logo-*. The branding workstream is wiring, not new architecture.
  • layout.spec.ts + 3 Playwright profiles (Phase 7/14): a ready, CI-wired structural quality bar (tap targets / overflow / in-viewport / a11y names) — doubles as the sweep checklist (D-01) and the natural home for a regression guard (D-02).
  • CSS custom-property token system (tokens.css): everything is already a variable with "no hard-coded hex/px in components" enforced — the themeable-layer restructure (D-06) builds on an already-favourable structure rather than fighting inline values.
  • vite-plugin-pwa manifest (vite.config.ts): the icon set is declared in one place; replacing stubs = update files in public/ + the manifest icons[] + index.html links.

Established Patterns

  • Phone/desktop split at 767/768px via matchMedia in App.tsx; phone uses top AppNav (PhoneNav <header>) + fixed BottomTabBar (sole <nav aria-label="Main navigation">), desktop uses a sidebar with no bottom bar. Fixes must be phone-scoped and not touch desktop geometry.
  • Safe-area awareness: BottomTabBar already uses env(safe-area-inset-bottom); any FAB-lift / content-padding fix must compose with the same inset (notched-device correctness).
  • Accessibility invariants the layout fix must preserve: single nav landmark on mobile, ≥44px tap targets, no horizontal overflow (the very assertions in layout.spec.ts).

Integration Points

  • FAB offset (CalendarShell.tsx) ↔ bar height (BottomTabBar.tsx) ↔ content padding (App.tsx) — D-02's "shared --bottom-chrome-h token" option would make these three agree via one source of truth.
  • Logo image ↔ --brand-logo-* tokens (tokens.css) ↔ BrandSlotLoginPage.
  • Icon files (public/) ↔ index.html links ↔ vite.config.ts PWA manifest — all three must reference the same regenerated asset set. </code_context>
## Specific Ideas

Logo / brand brief (user, 2026-06-17):

  • FamilySync is the brand — family-oriented, the name is the identity.
  • Caricature-family vibes — a warm, characterful family feel (not a cold/corporate geometric mark).
  • Warm tones.
  • Rounded corners / rounded shapes.
  • Overall it should "make you feel comfortable and at home."

This brief drives the AI-generated logo + icon set (D-03/D-04). Present generated options at a user-approval checkpoint before finalizing; the warm/rounded/at-home direction is the acceptance lens. Note the current theme-color is #4A90D9 (cool blue) and --color-shared-family is rose #f25c7a — the warm-tone brief may motivate revisiting the brand/theme accent during the token-groundwork work (keep within light-theme scope).

## Deferred Ideas
  • Shipped dark theme + light/dark/system toggle — captured as backlog 999.20 (PWA dark mode / theming). Phase 17 ships the enabling token groundwork only.
  • Modern visual styling refresh (contemporary restyle across high-visibility surfaces) — captured as backlog 999.21, flagged for a future milestone (redesign risk; own track).

Reviewed Todos (not folded)

  • 2026-06-10-gitea-ci-regression-and-docker-publish.md — surfaced as a weak keyword match (score 0.6) but is CI/tooling work already shipped in Phase 8/14; unrelated to this UI phase. Not folded.

Phase: 17-ui-optimization-polish Context gathered: 2026-06-17