feat(ui): cohesive frontend polish — design system + per-screen refinement
Distill the UI into a single, recognizable voice: a precision instrument for one operator on one machine. Bloomberg-coded chrome, warm-paper detail surfaces, mono-heavy numerics, with one editorial serif accent for moments of weight. Design system - Three-font stack: Geist Sans (UI), Geist Mono (data), Instrument Serif (editorial display). No Inter, no system fonts. - Two surfaces: dark chrome (--background, --accent, --signal) and warm paper detail surfaces (--surface, --surface-ink*). - Inbox has its own Ticker Tape terminal palette (--tt-*). - Shared component classes: .eyebrow, .mono, .display, .surface, .surface-2, .row-hover, .nav-active, .kbd, .editorial, .hairline. - --m-* token aliases for the legacy drawer components so test- asserted class strings keep resolving to the same hue family. Drawers (Claim + Remit) - Editorial display face for totals (paid/adjustment amounts). - Color-coded money tiles: green-tinted paid card, amber-tinted adjustment card when non-zero, muted otherwise. - Tabs get accent-blue underline + CSS-driven active state. - Validation banners with proper background opacity + ring-around- dot success badge. - StateHistoryTimeline: dashed border, ring around dots, ↳ prefix for remit ids. - DiagnosesList, PartiesGrid, MatchedRemitCard, CasAdjustmentsPanel: refined typography, dashed dividers, italic descriptions, mono amounts, font-semibold totals, hover row tints. Inbox Ticker Tape - Custom RowCheckbox with sr-only input + amber accent. - Alternating row striping, hover tints, accent rail with inset shadow on selection. - Refined sparkline with glow at high values. - BulkBar: bottom-floating bar with amber count chip, larger shadow. - CandidateBreakdown: animated progress bars with amber gradient. - InboxHeader: Instrument Serif headline, mono day/date stamp, pulsing amber status dot. Dialogs & search - NewClaimDialog: editorial title, mono NPI/CPT/amount fields. - SearchBar: refined input row with mono, footer with pulsing loading indicator. - KeyboardCheatsheet: monogram icon chip, hover row states, refined eyebrow header. Primitives - StatusBadge / ClaimStateBadge: per-state dot indicators. - SelectItem: data-[highlighted]:outline tokens for keyboard a11y. - Table primitives: refined header treatment, hover/focus states. Tests + build - 354/354 tests passing across 59 files. - Vite build clean (53.84 kB CSS / 560.86 kB JS). - Eyebrow assertions updated to match the consolidated .eyebrow class (intact visual contract, abstracted class string). - Badge variant tokens updated to the polished bg-muted/80 / /0.14 opacity scale.
This commit is contained in:
+33
-22
@@ -1,27 +1,29 @@
|
||||
import { Outlet } from "react-router-dom";
|
||||
import { useIsFetching } from "@tanstack/react-query";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Sidebar } from "./Sidebar";
|
||||
import { SkipLink } from "@/components/ui/skip-link";
|
||||
import { SearchBar } from "./SearchBar";
|
||||
|
||||
/**
|
||||
* App shell. Three columns:
|
||||
* - Sidebar (240px, fixed)
|
||||
* - Top bar (sticky, lightweight utility row)
|
||||
* - Outlet (page content, max-w-[1400px] centered)
|
||||
*
|
||||
* The hairline scan element at the very top of the viewport is a 1px
|
||||
* line that slides an accent bar across the entire width whenever
|
||||
* the React Query layer has an in-flight request. The intent is to
|
||||
* surface "we're doing something" without a spinner — a moving line
|
||||
* reads as a sensor sweep, not a loading state.
|
||||
*/
|
||||
export function Layout() {
|
||||
// useIsFetching() returns the number of in-flight queries and is 0 on
|
||||
// first load (queries that have not yet fired are not counted). We use it
|
||||
// to drive a 1px hairline scan element at the very top of the layout.
|
||||
const isFetching = useIsFetching();
|
||||
const showScan = isFetching > 0;
|
||||
|
||||
return (
|
||||
<div className="relative min-h-screen z-10">
|
||||
{/* Skip link — first Tab stop, jumps past the sidebar.
|
||||
Hidden until focused (see .skip-link in index.css). */}
|
||||
<SkipLink />
|
||||
{/*
|
||||
Scan element — always in the DOM (no layout shift), 1px tall, full
|
||||
width. pointer-events-none so it never blocks clicks. The inner
|
||||
bar uses the `scan` keyframe from tailwind.config to slide a 1/3-
|
||||
width electric-blue bar across the hairline.
|
||||
*/}
|
||||
<div
|
||||
className="fixed top-0 left-0 right-0 z-50 h-px overflow-hidden pointer-events-none transition-opacity duration-200"
|
||||
style={{ opacity: showScan ? 1 : 0 }}
|
||||
@@ -38,19 +40,28 @@ export function Layout() {
|
||||
tabIndex={-1}
|
||||
className="md:pl-60 outline-none"
|
||||
>
|
||||
{/*
|
||||
Top bar — sits inside <main> so it shares the sidebar's right
|
||||
column. Sticky to the viewport top so the search chip stays
|
||||
reachable while the user scrolls long claim lists. The
|
||||
hairline + horizontal padding mirrors the main content
|
||||
container below it for visual continuity. The Sidebar's
|
||||
own header is taller and brand-marked; this is the
|
||||
lightweight "always-on utility" row.
|
||||
*/}
|
||||
<div className="sticky top-0 z-20 mx-auto max-w-[1400px] px-8 h-12 flex items-center justify-end bg-background/70 backdrop-blur-md border-b border-border/40">
|
||||
<div
|
||||
className="sticky top-0 z-20 mx-auto max-w-[1400px] px-6 lg:px-8 h-12 flex items-center justify-end gap-3 bg-background/70 backdrop-blur-md border-b border-border/40"
|
||||
data-print="hide"
|
||||
>
|
||||
{/* Tailing pill on the left edge of the top bar — a tiny
|
||||
global "system is alive" indicator. It lights up whenever
|
||||
any query is in flight, complementing the hairline scan. */}
|
||||
<div className="mr-auto flex items-center gap-2 text-[10.5px] mono uppercase tracking-[0.14em] text-muted-foreground/60">
|
||||
<span className="relative inline-flex h-1.5 w-1.5">
|
||||
<span
|
||||
className={cn(
|
||||
"absolute inline-flex h-full w-full rounded-full bg-[hsl(var(--success))] opacity-60",
|
||||
showScan && "animate-ping"
|
||||
)}
|
||||
/>
|
||||
<span className="relative inline-flex h-1.5 w-1.5 rounded-full bg-[hsl(var(--success))]" />
|
||||
</span>
|
||||
{showScan ? "Working" : "Idle"}
|
||||
</div>
|
||||
<SearchBar />
|
||||
</div>
|
||||
<div className="mx-auto max-w-[1400px] px-8 py-10">
|
||||
<div className="mx-auto max-w-[1400px] px-6 lg:px-8 py-8 lg:py-10">
|
||||
<Outlet />
|
||||
</div>
|
||||
</main>
|
||||
|
||||
Reference in New Issue
Block a user