refactor: use KpiStrip and StatusText in Dashboard page
Replace StatCard loop with KpiStrip composite, map KpiMetric mock data to KpiItem interface. Remove unused .healthStrip CSS class. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -7,14 +7,6 @@
|
|||||||
background: var(--bg-body);
|
background: var(--bg-body);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Health strip */
|
|
||||||
.healthStrip {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(5, 1fr);
|
|
||||||
gap: 10px;
|
|
||||||
margin-bottom: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Filter bar spacing */
|
/* Filter bar spacing */
|
||||||
.filterBar {
|
.filterBar {
|
||||||
margin-bottom: 16px;
|
margin-bottom: 16px;
|
||||||
|
|||||||
@@ -15,9 +15,10 @@ import { ShortcutsBar } from '../../design-system/composites/ShortcutsBar/Shortc
|
|||||||
import { ProcessorTimeline } from '../../design-system/composites/ProcessorTimeline/ProcessorTimeline'
|
import { ProcessorTimeline } from '../../design-system/composites/ProcessorTimeline/ProcessorTimeline'
|
||||||
import { RouteFlow } from '../../design-system/composites/RouteFlow/RouteFlow'
|
import { RouteFlow } from '../../design-system/composites/RouteFlow/RouteFlow'
|
||||||
import type { RouteNode } from '../../design-system/composites/RouteFlow/RouteFlow'
|
import type { RouteNode } from '../../design-system/composites/RouteFlow/RouteFlow'
|
||||||
|
import { KpiStrip } from '../../design-system/composites/KpiStrip/KpiStrip'
|
||||||
|
import type { KpiItem } from '../../design-system/composites/KpiStrip/KpiStrip'
|
||||||
|
|
||||||
// Primitives
|
// Primitives
|
||||||
import { StatCard } from '../../design-system/primitives/StatCard/StatCard'
|
|
||||||
import { StatusDot } from '../../design-system/primitives/StatusDot/StatusDot'
|
import { StatusDot } from '../../design-system/primitives/StatusDot/StatusDot'
|
||||||
import { MonoText } from '../../design-system/primitives/MonoText/MonoText'
|
import { MonoText } from '../../design-system/primitives/MonoText/MonoText'
|
||||||
import { Badge } from '../../design-system/primitives/Badge/Badge'
|
import { Badge } from '../../design-system/primitives/Badge/Badge'
|
||||||
@@ -27,12 +28,44 @@ import { useGlobalFilters } from '../../design-system/providers/GlobalFilterProv
|
|||||||
|
|
||||||
// Mock data
|
// Mock data
|
||||||
import { exchanges, type Exchange } from '../../mocks/exchanges'
|
import { exchanges, type Exchange } from '../../mocks/exchanges'
|
||||||
import { kpiMetrics } from '../../mocks/metrics'
|
import { kpiMetrics, type KpiMetric } from '../../mocks/metrics'
|
||||||
import { SIDEBAR_APPS, buildRouteToAppMap } from '../../mocks/sidebar'
|
import { SIDEBAR_APPS, buildRouteToAppMap } from '../../mocks/sidebar'
|
||||||
|
|
||||||
// Route → Application lookup
|
// Route → Application lookup
|
||||||
const ROUTE_TO_APP = buildRouteToAppMap()
|
const ROUTE_TO_APP = buildRouteToAppMap()
|
||||||
|
|
||||||
|
// ─── KPI mapping ─────────────────────────────────────────────────────────────
|
||||||
|
const ACCENT_TO_COLOR: Record<KpiMetric['accent'], string> = {
|
||||||
|
amber: 'var(--amber)',
|
||||||
|
success: 'var(--success)',
|
||||||
|
error: 'var(--error)',
|
||||||
|
running: 'var(--running)',
|
||||||
|
warning: 'var(--warning)',
|
||||||
|
}
|
||||||
|
|
||||||
|
const TREND_ICONS: Record<KpiMetric['trend'], string> = {
|
||||||
|
up: '\u2191',
|
||||||
|
down: '\u2193',
|
||||||
|
neutral: '\u2192',
|
||||||
|
}
|
||||||
|
|
||||||
|
function sentimentToVariant(sentiment: KpiMetric['trendSentiment']): 'success' | 'error' | 'muted' {
|
||||||
|
switch (sentiment) {
|
||||||
|
case 'good': return 'success'
|
||||||
|
case 'bad': return 'error'
|
||||||
|
case 'neutral': return 'muted'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const kpiItems: KpiItem[] = kpiMetrics.map((m) => ({
|
||||||
|
label: m.label,
|
||||||
|
value: m.unit ? `${m.value} ${m.unit}` : m.value,
|
||||||
|
trend: { label: `${TREND_ICONS[m.trend]} ${m.trendValue}`, variant: sentimentToVariant(m.trendSentiment) },
|
||||||
|
subtitle: m.detail,
|
||||||
|
sparkline: m.sparkline,
|
||||||
|
borderColor: ACCENT_TO_COLOR[m.accent],
|
||||||
|
}))
|
||||||
|
|
||||||
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
||||||
function formatDuration(ms: number): string {
|
function formatDuration(ms: number): string {
|
||||||
if (ms >= 60_000) return `${(ms / 1000).toFixed(0)}s`
|
if (ms >= 60_000) return `${(ms / 1000).toFixed(0)}s`
|
||||||
@@ -370,20 +403,7 @@ export function Dashboard() {
|
|||||||
<div className={styles.content}>
|
<div className={styles.content}>
|
||||||
|
|
||||||
{/* Health strip */}
|
{/* Health strip */}
|
||||||
<div className={styles.healthStrip}>
|
<KpiStrip items={kpiItems} />
|
||||||
{kpiMetrics.map((kpi, i) => (
|
|
||||||
<StatCard
|
|
||||||
key={i}
|
|
||||||
label={kpi.label}
|
|
||||||
value={kpi.value}
|
|
||||||
detail={kpi.detail}
|
|
||||||
trend={kpi.trend}
|
|
||||||
trendValue={kpi.trendValue}
|
|
||||||
accent={kpi.accent}
|
|
||||||
sparkline={kpi.sparkline}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Exchanges table */}
|
{/* Exchanges table */}
|
||||||
<div className={styles.tableSection}>
|
<div className={styles.tableSection}>
|
||||||
|
|||||||
Reference in New Issue
Block a user