merge: ui/mobile-responsive — Dashboard/Providers/Upload/Reconciliation breakpoints

This commit is contained in:
Tyler
2026-06-20 16:59:31 -06:00
4 changed files with 33 additions and 29 deletions
+5 -5
View File
@@ -108,7 +108,7 @@ export function Dashboard() {
const sectionBase = kpiBase + kpiStep * 5 + 60; // after the last KPI
return (
<div className="space-y-10">
<div className="space-y-6 md:space-y-10">
{/* Hero */}
<header
className="relative animate-fade-in overflow-hidden"
@@ -129,13 +129,13 @@ export function Dashboard() {
{fmt.usd(kpis.billed)}
</div>
<div className="relative z-10 flex items-end justify-between gap-6 flex-wrap">
<div>
<div className="relative z-10 flex items-end justify-between gap-4 sm:gap-6 flex-wrap">
<div className="min-w-0">
<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" />
Today · {fmt.date(new Date().toISOString())}
</div>
<h1 className="text-[28px] leading-[1.15] font-semibold tracking-tight">
<h1 className="text-[22px] sm:text-[28px] leading-[1.15] font-semibold tracking-tight">
Good morning, Jordan.
</h1>
<p className="text-muted-foreground mt-1.5 max-w-xl text-[14px] leading-relaxed">
@@ -157,7 +157,7 @@ export function Dashboard() {
{/* KPIs — every card carries a trend. */}
<section
aria-label="Key performance indicators"
className="grid gap-4 grid-cols-2 lg:grid-cols-5"
className="grid gap-4 grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-5"
>
<KpiCard
label="Claims"
+3 -3
View File
@@ -10,13 +10,13 @@ export function Providers() {
const items = data?.items ?? [];
return (
<div className="space-y-8 animate-fade-in">
<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] font-semibold tracking-tight">Provider directory</h1>
<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.
@@ -49,7 +49,7 @@ export function Providers() {
{items.map((p) => (
<article
key={p.npi}
className="surface rounded-xl p-6 flex flex-col gap-4 hover:bg-muted/20 transition-colors"
className="surface rounded-xl p-4 sm:p-6 flex flex-col gap-4 hover:bg-muted/20 transition-colors"
>
<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">
+16 -14
View File
@@ -27,17 +27,17 @@ export function ReconciliationPage() {
if (unmatched.isLoading) {
return (
<div className="space-y-8 animate-fade-in">
<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" />
Reconciliation
</div>
<h1 className="text-[22px] font-semibold tracking-tight">
<h1 className="text-[22px] sm:text-[26px] font-semibold tracking-tight">
Manual pairing
</h1>
</header>
<div className="grid grid-cols-2 gap-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
<Skeleton variant="default" height={320} />
<Skeleton variant="default" height={320} />
</div>
@@ -51,13 +51,13 @@ export function ReconciliationPage() {
? unmatched.error.message
: String(unmatched.error);
return (
<div className="space-y-8 animate-fade-in">
<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" />
Reconciliation
</div>
<h1 className="text-[22px] font-semibold tracking-tight">
<h1 className="text-[22px] sm:text-[26px] font-semibold tracking-tight">
Manual pairing
</h1>
</header>
@@ -78,13 +78,13 @@ export function ReconciliationPage() {
if (empty) {
return (
<div className="space-y-8 animate-fade-in">
<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" />
Reconciliation
</div>
<h1 className="text-[22px] font-semibold tracking-tight">
<h1 className="text-[22px] sm:text-[26px] font-semibold tracking-tight">
Manual pairing
</h1>
</header>
@@ -125,13 +125,13 @@ export function ReconciliationPage() {
};
return (
<div className="space-y-8 animate-fade-in">
<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" />
Reconciliation
</div>
<h1 className="text-[22px] font-semibold tracking-tight">
<h1 className="text-[22px] sm:text-[26px] font-semibold tracking-tight">
Manual pairing
</h1>
<p className="text-muted-foreground mt-1.5 text-[14px]">
@@ -139,7 +139,7 @@ export function ReconciliationPage() {
</p>
</header>
<div className="grid grid-cols-2 gap-4">
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{/* Claims column */}
<div className="surface rounded-xl border border-border/60 p-4 space-y-2">
<h2 className="text-[10.5px] font-semibold uppercase tracking-[0.18em] text-muted-foreground">
@@ -155,7 +155,7 @@ export function ReconciliationPage() {
onClick={() => setSelectedClaim(c.id)}
aria-pressed={active}
className={cn(
"w-full text-left p-3 rounded-md border transition-colors",
"w-full text-left p-3 min-h-[44px] rounded-md border transition-colors",
active
? "border-accent bg-accent/5"
: "border-border/60 hover:border-border"
@@ -190,7 +190,7 @@ export function ReconciliationPage() {
onClick={() => setSelectedRemit(r.id)}
aria-pressed={active}
className={cn(
"w-full text-left p-3 rounded-md border transition-colors",
"w-full text-left p-3 min-h-[44px] rounded-md border transition-colors",
active
? "border-accent bg-accent/5"
: "border-border/60 hover:border-border"
@@ -215,10 +215,11 @@ export function ReconciliationPage() {
</div>
</div>
<div className="flex items-center gap-2">
<div className="flex items-center gap-2 flex-wrap">
<Button
onClick={handleMatch}
disabled={!selectedClaim || !selectedRemit || match.isPending}
className="min-h-[44px] sm:min-h-0"
>
<GitMerge className="h-3.5 w-3.5 mr-1.5" />
Match selected
@@ -227,12 +228,13 @@ export function ReconciliationPage() {
variant="outline"
onClick={handleClear}
disabled={(!selectedClaim && !selectedRemit) || match.isPending}
className="min-h-[44px] sm:min-h-0"
>
<X className="h-3.5 w-3.5 mr-1.5" />
Clear selection
</Button>
{selectedClaim || selectedRemit ? (
<span className="text-xs text-muted-foreground ml-2">
<span className="text-xs text-muted-foreground sm:ml-2 basis-full sm:basis-auto">
{selectedClaim ? `Claim ${selectedClaim}` : "No claim"}
{" · "}
{selectedRemit ? `Remit ${selectedRemit}` : "No remit"}
+9 -7
View File
@@ -233,7 +233,7 @@ function ClaimCard837({ claim }: { claim: ClaimOutput }) {
<div className="text-[10.5px] font-semibold uppercase tracking-[0.18em] text-muted-foreground mb-1.5">
Service lines
</div>
<div className="rounded-md border border-border/40 overflow-hidden">
<div className="rounded-md border border-border/40 overflow-x-auto">
<table className="w-full text-[12px]">
<thead className="bg-muted/30">
<tr className="text-left text-muted-foreground">
@@ -403,7 +403,7 @@ function ClaimCard835({ claim }: { claim: ClaimPayment }) {
<div className="text-[10.5px] font-semibold uppercase tracking-[0.18em] text-muted-foreground mb-1.5">
Service payments
</div>
<div className="rounded-md border border-border/40 overflow-hidden">
<div className="rounded-md border border-border/40 overflow-x-auto">
<table className="w-full text-[12px]">
<thead className="bg-muted/30">
<tr className="text-left text-muted-foreground">
@@ -584,13 +584,13 @@ export function Upload() {
}
return (
<div className="space-y-8 animate-fade-in">
<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" />
Upload · EDI parser
</div>
<h1 className="text-[22px] font-semibold tracking-tight">
<h1 className="text-[22px] sm:text-[26px] font-semibold tracking-tight">
Parse an X12 file
</h1>
<p className="text-muted-foreground mt-1.5 text-[14px] max-w-2xl">
@@ -665,7 +665,7 @@ export function Upload() {
if (e.key === "Enter" || e.key === " ") inputRef.current?.click();
}}
className={cn(
"relative flex flex-col items-center justify-center gap-2 rounded-lg border border-dashed border-border/60 bg-muted/20 px-6 py-8 cursor-pointer transition-colors",
"relative flex flex-col items-center justify-center gap-2 rounded-lg border border-dashed border-border/60 bg-muted/20 px-6 py-10 sm:py-8 min-h-[140px] sm:min-h-[120px] cursor-pointer transition-colors",
"hover:bg-muted/30 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
)}
>
@@ -704,7 +704,7 @@ export function Upload() {
/>
</div>
<div className="flex items-center justify-between gap-3">
<div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
<div className="text-[12px] text-muted-foreground">
{api.isConfigured ? (
<span className="inline-flex items-center gap-1.5">
@@ -721,12 +721,13 @@ export function Upload() {
</span>
)}
</div>
<div className="flex items-center gap-2">
<div className="flex items-center gap-2 flex-wrap">
{file ? (
<Button
variant="ghost"
onClick={() => pickFile(null)}
disabled={running}
className="min-h-[44px] sm:min-h-0"
>
Clear
</Button>
@@ -734,6 +735,7 @@ export function Upload() {
<Button
onClick={onParse}
disabled={!file || running}
className="min-h-[44px] sm:min-h-0"
>
{running ? (
<>