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:
+22
-31
@@ -2,6 +2,7 @@ import { Building2, MapPin, Phone } from "lucide-react";
|
||||
import { Skeleton } from "@/components/ui/skeleton";
|
||||
import { EmptyState } from "@/components/ui/empty-state";
|
||||
import { ErrorState } from "@/components/ui/error-state";
|
||||
import { PageHeader } from "@/components/PageHeader";
|
||||
import { useProviders } from "@/hooks/useProviders";
|
||||
import { fmt } from "@/lib/format";
|
||||
|
||||
@@ -10,18 +11,12 @@ export function Providers() {
|
||||
const items = data?.items ?? [];
|
||||
|
||||
return (
|
||||
<div className="space-y-6 md:space-y-8 animate-fade-in">
|
||||
<header>
|
||||
<div className="text-[10.5px] font-semibold uppercase tracking-[0.18em] text-muted-foreground mb-2 flex items-center gap-2">
|
||||
<span className="inline-block h-px w-6 bg-border" />
|
||||
Providers
|
||||
</div>
|
||||
<h1 className="text-[22px] sm:text-[26px] font-semibold tracking-tight">Provider directory</h1>
|
||||
<p className="text-muted-foreground mt-1.5 text-[14px]">
|
||||
NPIs registered with the clearinghouse for 837P submission and 835
|
||||
remittance retrieval.
|
||||
</p>
|
||||
</header>
|
||||
<div className="space-y-6 lg:space-y-8 animate-fade-in">
|
||||
<PageHeader
|
||||
eyebrow="Providers"
|
||||
title={<>Provider <span className="display italic text-muted-foreground">directory</span></>}
|
||||
subtitle="NPIs registered with the clearinghouse for 837P submission and 835 remittance retrieval."
|
||||
/>
|
||||
|
||||
{isError ? (
|
||||
<ErrorState
|
||||
@@ -45,53 +40,49 @@ export function Providers() {
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid gap-4 md:grid-cols-2 xl:grid-cols-3">
|
||||
<div className="grid gap-3.5 md:grid-cols-2 xl:grid-cols-3">
|
||||
{items.map((p) => (
|
||||
<article
|
||||
key={p.npi}
|
||||
className="surface rounded-xl p-4 sm:p-6 flex flex-col gap-4 hover:bg-muted/20 transition-colors"
|
||||
className="group surface-2 rounded-xl p-5 flex flex-col gap-4 transition-colors hover:bg-muted/20 cursor-default"
|
||||
>
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="h-10 w-10 rounded-lg bg-muted/60 flex items-center justify-center text-foreground">
|
||||
<Building2 className="h-5 w-5" strokeWidth={1.5} />
|
||||
<div className="h-10 w-10 rounded-md bg-muted/60 ring-1 ring-inset ring-border/40 flex items-center justify-center text-foreground">
|
||||
<Building2 className="h-4 w-4" strokeWidth={1.5} />
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<h3 className="text-[15px] font-semibold tracking-tight">
|
||||
<h3 className="display text-[15px] text-foreground tracking-tight">
|
||||
{p.name}
|
||||
</h3>
|
||||
<p className="text-[11px] text-muted-foreground num mt-0.5">
|
||||
<p className="mono text-[10.5px] text-muted-foreground mt-0.5">
|
||||
NPI {p.npi} · TIN {p.taxId}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5 text-[13px] text-muted-foreground">
|
||||
<div className="flex items-center gap-2">
|
||||
<MapPin className="h-3.5 w-3.5" strokeWidth={1.75} />
|
||||
<div className="space-y-1.5 text-[12.5px] text-muted-foreground">
|
||||
<div className="flex items-start gap-2">
|
||||
<MapPin className="h-3.5 w-3.5 mt-0.5 shrink-0" strokeWidth={1.75} />
|
||||
<span>
|
||||
{p.address}, {p.city}, {p.state} {p.zip}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Phone className="h-3.5 w-3.5" strokeWidth={1.75} />
|
||||
<span className="num">{p.phone}</span>
|
||||
<span className="mono">{p.phone}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4 pt-4 border-t border-border/40">
|
||||
<div className="grid grid-cols-2 gap-4 pt-4 border-t border-border/30">
|
||||
<div>
|
||||
<div className="text-[11px] uppercase tracking-wider text-muted-foreground">
|
||||
Claims
|
||||
</div>
|
||||
<div className="display text-[20px] leading-none mt-1.5">
|
||||
<div className="eyebrow">Claims</div>
|
||||
<div className="display mono text-[20px] leading-none mt-2">
|
||||
{fmt.num(p.claimCount)}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-[11px] uppercase tracking-wider text-muted-foreground">
|
||||
Outstanding AR
|
||||
</div>
|
||||
<div className="display text-[20px] leading-none mt-1.5">
|
||||
<div className="eyebrow">Outstanding AR</div>
|
||||
<div className="display mono text-[20px] leading-none mt-2">
|
||||
{fmt.usd(p.outstandingAr)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user