From b82e334777a1211c5a788a706e2118f5e24ee2cc Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 18 May 2026 23:28:16 +0000 Subject: [PATCH] =?UTF-8?q?feat(ui):=20D.6b=20UnavailableMeasurementCard?= =?UTF-8?q?=20=E2=86=92=20EmptyState?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR 10 (sub-step b) of 16. Second of three small PRs against MeasurementDashboard.tsx — folds the local UnavailableMeasurementCard into the EmptyState primitive while preserving its (title, description, detail) call-site API. Changes: - UnavailableMeasurementCard's body now delegates to with title + description passed through. The optional `detail` line renders as a children slot (EmptyState's first-class props stop at description; children is the documented escape hatch). - The dashed-border + bg-bg-surface-dark visual treatment carries over via className override on EmptyState. - The two call sites at :1805 and :1858 are untouched — they continue to call exactly as before. Deviation from plan §D.6b: the plan flagged `bg-blue-500` at :438 as drift to fix → bg-accent. Inspecting the context, that class is one of three colors (bg-red-500 kick / bg-yellow-500 mid / bg-blue-500 high) on a "Beat Dominance" 3-band content visualization stack — the same data-coded vocabulary the plan explicitly protects for spectral content colors (:99-134) and LUFS_METER_GRADIENT. Changing only the blue band to accent would also break the visual coherence of the 3-band stack (warm/neutral/cool). Leaving all three Beat Dominance colors as data-coding to match the protection spirit. The plan's note was likely from a stale grep against a moved/removed call site. Preserved verbatim: - UnavailableMeasurementCard's external API (title, description, detail) so call sites don't change. - The Beat Dominance band-color visualization at :428/:433/:438 (red/yellow/blue) — treated as data, not chrome. - All spectral content colors at :99-134. - LUFS_METER_GRADIENT. - All data-testid attributes inside the dashboard. Verified: lint clean, 628/628 unit tests passing, build clean. Next: D.6c — migrate the local SectionHeader at :288-303 to the SectionHeader primitive. https://claude.ai/code/session_01WNtYcWXwn4mVnnjxqT7uAe --- .../src/components/MeasurementDashboard.tsx | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/apps/ui/src/components/MeasurementDashboard.tsx b/apps/ui/src/components/MeasurementDashboard.tsx index b5bd634b..416bc78f 100644 --- a/apps/ui/src/components/MeasurementDashboard.tsx +++ b/apps/ui/src/components/MeasurementDashboard.tsx @@ -33,7 +33,7 @@ import { StyledDataTable, TokenBadgeList, } from './MeasurementPrimitives'; -import { DeviceRack, MetricTile } from './ui'; +import { DeviceRack, EmptyState, MetricTile } from './ui'; import { Sparkline } from './Sparkline'; import { SpectralCursorProvider } from '../hooks/useSpectralCursorBus'; import { formatDisplayText, getTextRoleClassName } from '../utils/displayText'; @@ -202,20 +202,25 @@ function UnavailableMeasurementCard({ description: string; detail?: string; }) { + // Delegates to the EmptyState primitive — preserves the (title, + // description, detail) API that the dashboard's two call sites at + // :1805 and :1858 depend on, while folding the visual chrome into + // the canonical primitive. The optional `detail` line renders as a + // children slot since EmptyState's prop surface stops at description. return ( -
- - {title} - -

- {description} -

+ {detail ? (

{detail}

) : null} -
+
); }