Files
rippr/docs/ui-redesign/UI-03-glass-component-kit.md
uhryniuk 822003ed38 UI redesign: 8 tickets from the Stitch export analysis
Same shape as docs/v3/: Goal/Context/Design/Implementation/Acceptance/Tests/Risks/Out-of-scope, written before implementing.

UI-01: persistent 4-tab shell (StatefulShellRoute) replacing the current push/pop stack rooted at Record, with a single shared background map dimmed behind every tab and no header anywhere.
UI-02: animated skeleton map for the no-cache/no-network case, since the map is now a permanent background presence rather than opt-in per screen.
UI-03: shared GlassPanel/FloatingPill/PulsingLocationMarker component kit.
UI-04: draggable, resizable HUD telemetry widgets with a Settings visibility toggle -- split out from the screen redesign itself since it's a genuinely separate piece of engineering (a small widget-layout system, not a reskin).
UI-05: Map HUD/Record screen redesign -- the design north star every other screen ticket restyles toward.
UI-06: Plan & Route Planning -- correct in principle, explicitly restyled toward UI-05 rather than copying the Stitch export's drifted styling.
UI-07: Rides History -- live dimmed map background (not the mockup's static image), search/filter, real per-ride map thumbnails, and real distinct summary stats (fixing the export's 4-identical-cards generation artifact).
UI-08: theme migration to Modern Professional Dark, superseding V3-16's safety-orange direction.

README documents the dependency order, and two categories worth keeping separate: what was named explicitly by the person commissioning this (map-on-every-tab, no header, offline skeleton, customizable HUD) versus what the mockups themselves got inconsistent (nav icon count, duplicate summary cards, wrong active-tab highlight) and should not be copied as intentional.
2026-08-23 18:25:35 -05:00

3.9 KiB

UI-03 — Shared floating-glass component kit

Depends on UI-08 (theme tokens) · Size M · Status Not started

Goal

Build once, use everywhere: the small set of visual primitives every Stitch screen reuses, so UI-04/05/06/07 compose them instead of each reinventing blur-panel styling.

Context

All four Stitch exports lean on the same handful of visual patterns repeatedly: glassmorphic panels (bg-surface/80 backdrop-blur-xl border border-white/10), a floating centered pill for a compact stat summary, and a pulsing/radar-style location marker. Building these once means every consuming screen ticket is "compose these," not "reimplement blur and border styling a fourth time."

Design

Three widgets, all pure presentation (no data-fetching, no business logic):

GlassPanel — the workhorse. BackdropFilter + ImageFilter.blur inside a ClipRRect, a translucent surface-color fill, a 1px low-opacity border. Takes a child and behaves like a styled Container. Every floating card, tooltip, and control in the redesign is one of these underneath.

FloatingPill — a GlassPanel shaped as a horizontally-centered, rounded-full capsule holding a row of labeled stat columns (see Route Planning's Distance/Est. Time/ Pins header). Takes a list of (label, value) pairs and lays them out with vertical dividers between them, matching the Stitch export exactly.

PulsingLocationMarker — the expanding-ring-plus-glow-dot from the Plan/Route Planning exports. A CustomPainter or layered AnimatedContainers driving an AnimationController in a loop (scale 0.8→1.0, opacity 0.8→0, repeating) — respect MediaQuery.disableAnimations/prefers-reduced-motion equivalent by falling back to a static dot when animations are disabled system-wide.

Implementation

  1. lib/src/ui/components/glass_panel.dart — GlassPanel, with blur radius, fill opacity, and border opacity as named constants (not magic numbers scattered per call site), sourced from UI-08's theme tokens.
  2. lib/src/ui/components/floating_pill.dart — FloatingPill, built on GlassPanel.
  3. lib/src/ui/components/pulsing_location_marker.dart — PulsingLocationMarker, wrapping its AnimationController lifecycle correctly (dispose on unmount, same discipline as RideMap's existing lifecycle observer from V3-04).
  4. Widget tests render each in isolation against both themes (if UI-08 keeps a light variant) to catch a black-on-black-style contrast regression early, the same discipline V3-16 established.

Acceptance criteria

  • GlassPanel renders a blurred, bordered, translucent container matching the Stitch reference visually
  • FloatingPill renders an arbitrary number of stat columns with dividers between them, not hardcoded to exactly three
  • PulsingLocationMarker animates continuously without leaking its AnimationController across widget rebuilds or disposal
  • Reduced-motion setting is respected by PulsingLocationMarker

Tests

  • Widget: each component renders with representative content and takes a screenshot- comparable snapshot of its structure (no golden files per V3-16's precedent — assert structure/color, not pixels)
  • Widget: PulsingLocationMarker's animation controller is disposed when the widget is removed from the tree (a flutter_test pending-timer/ticker check, mirroring the Drift stream-query keep-alive pattern already documented in widget_test.dart)

Risks

  • BackdropFilter is one of the more expensive Flutter widgets to composite; stacking several GlassPanels over a live, animating map (per UI-01/UI-02) could visibly cost frame time on lower-end devices. Worth a real-device check once UI-05 assembles them together, not just in isolation.

Out of scope

The customizable drag/resize telemetry widgets (UI-04) — those consume GlassPanel as their visual shell but the interaction logic is a separate, larger ticket.