From 078de28cc4d9023af04cf91eccd34020a6f50b27 Mon Sep 17 00:00:00 2001 From: Tyler Date: Fri, 19 Jun 2026 18:36:39 -0600 Subject: [PATCH] docs: add live-data UX section + aesthetic acceptance checks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace 7.6 (skeleton) with hairline + scanline-shimmer design that matches the existing precision-instrument voice (Cabinet Grotesk + Geist Mono, true-black + electric-blue, hairline chrome, radial light + grain) - Add 7.7 Live-data UX patterns: skeleton variants, EmptyState primitive, ErrorState primitive, Layout-level refetch indicator, Active filter chips, newly-streamed row highlight, status color alignment, pagination footer - Add 13.1 visual / aesthetic acceptance checks - Voice decision: stay the course — additive only, no new accent / typeface / layout primitive / light theme --- ...-19-cyclone-production-readiness-design.md | 203 +++++++++++++++++- 1 file changed, 201 insertions(+), 2 deletions(-) diff --git a/docs/superpowers/specs/2026-06-19-cyclone-production-readiness-design.md b/docs/superpowers/specs/2026-06-19-cyclone-production-readiness-design.md index 97146de..f57370c 100644 --- a/docs/superpowers/specs/2026-06-19-cyclone-production-readiness-design.md +++ b/docs/superpowers/specs/2026-06-19-cyclone-production-readiness-design.md @@ -248,7 +248,194 @@ Each page gains: `` rows during `isLoading`, an error block with "Re ### 7.6 UI primitive: `src/components/ui/skeleton.tsx` -~10 lines, shadcn-style: `
`. No new dep. +A reusable row-shaped skeleton block. Voice: hairline + a slow horizontal scanline gradient (not the generic "pulse the whole block gray" pattern). Renders three bars (id / name / amount) sized to match the typography of the row it stands in for. ~25 lines, no new dep. + +```tsx +// Sketch — not the final implementation +export function Skeleton({ className, variant = "row" }: Props) { + return ( +
+
+ {variant === "row" ? ( +
+
+
+
+
+
+
+
+ ) : null} +
+ ); +} +``` + +The `shimmer` keyframe is added to `tailwind.config.js` next to the existing `fade-in` keyframes. No external library. + +### 7.7 Live-data UX patterns + +The aesthetic is already committed (Cabinet Grotesk + Geist Mono, true-black ground, electric-blue accent, hairline chrome, radial top-right light, fine grain). This sub-project does not introduce a new accent color, a new typeface, a light theme, or a new layout primitive. The additions below are *only* the live-data UX patterns needed to make the page refactors feel as precise as the data they carry. + +#### 7.7.1 Loading — three skeleton variants + +Pages render 3–5 `Skeleton` rows (or cards, or KPI tiles) on `isLoading` so the page doesn't pop. Skeleton uses the row-shaped variant (above) inside table surfaces, the `card` variant inside the Provider grid, and the existing `.surface` + `display` text treatment for the page header (which renders immediately, not behind a skeleton). + +#### 7.7.2 Empty state + +Replace the existing generic "No claims yet." text with a consistent empty state primitive: a hairline-circle icon (1.5px stroke), an all-caps eyebrow (`text-[10.5px] font-semibold uppercase tracking-[0.18em] text-muted-foreground`), and a one-line message. The eyebrow uses the *page subject* so it reads as an instrument label: e.g., "Claims · inbox idle" / "Remittances · awaiting first 835" / "Activity · log idle" / "Providers · directory empty". No apologetic language, no illustrations. + +```tsx +function EmptyState({ eyebrow, message }: { eyebrow: string; message: string }) { + return ( +
+
+ +
+
+ {eyebrow} +
+
{message}
+
+ ); +} +``` + +`CircleDashed` from `lucide-react`. + +#### 7.7.3 Error state + +A bordered block at the top of the page content (not a full-page takeover — the user should still be able to navigate away). `border-destructive/30` on a `.surface` background; a destructive-tinted `AlertCircle` icon, the error message in `text-sm`, and a `Retry` button on the right. A sonner toast surfaces the same error at the bottom-right (existing Toaster config keeps this). Network errors get a more verbose message ("Can't reach the backend at `http://127.0.0.1:8000`. Is the FastAPI server running?"). + +```tsx +function ErrorState({ error, onRetry }: { error: Error; onRetry: () => void }) { + return ( +
+ +
+
+ Fetch failed +
+
{error.message}
+
+ +
+ ); +} +``` + +#### 7.7.4 Refetch indicator (Layout-level) + +A 1px hairline at the very top of `
` that animates in (left → right, accent color, 400ms) whenever *any* query is fetching in the background (e.g., after `invalidateQueries` post-parse). Uses `useIsFetching()` from `@tanstack/react-query`. Implemented as a fixed-position element inside `Layout.tsx`, not page-level — so every page benefits without per-page plumbing. + +```tsx +// In Layout.tsx +const isFetching = useIsFetching(); +return ( +
+ {isFetching > 0 ? ( +
+
+
+ ) : null} + +
+
+); +``` + +The `scan` keyframe is added to `tailwind.config.js`. The element is hairline-thin so it never competes with the content; the only motion on the page during a background refetch is this 1px sliver. + +#### 7.7.5 Active filter chips (Claims page) + +The existing `