The mock pages in `src/pages/` build several UI patterns using raw CSS and inline HTML that should either be promoted into the design system or refactored to use existing components. This spec captures each deviation and its resolution to minimize rework when transitioning to the real application.
## Decision Framework
A pattern is promoted to the design system when it:
- Appears on 2+ pages with the same structure
- Is visually distinctive and would be inconsistent if reimplemented
- Will be needed by the real application
A pattern stays in the pages when it is page-specific composition or a one-off layout.
---
## 1. KpiStrip — New Composite
**Problem:** Dashboard, Routes, and AgentHealth each build a custom KPI header strip (~320 lines of duplicated layout code). Same visual structure: horizontal row of cards with colored left border, uppercase label, large value, trend indicator, subtitle, and optional sparkline.
- Trend: inline next to value, 11px. Color controlled by `trend.variant` (maps to semantic tokens). Default `'muted'`. The caller decides what color a trend should be — "↑ +12%" on error count is `'error'`, on throughput is `'success'`.
**Note:** KpiStrip builds its own card-like containers internally. It does NOT reuse the `Card` primitive because `Card` uses a top accent border while KpiStrip needs a left border. The visual surface (bg, border, radius, shadow) uses the same tokens but the layout is distinct.
**Pages to refactor:** Dashboard.tsx, Routes.tsx, AgentHealth.tsx — replace inline `KpiHeader` functions with `<KpiStrip items={[...]} />`.
---
## 2. SplitPane — New Composite
**Problem:** Admin RBAC tabs (UsersTab, GroupsTab, RolesTab) each build a custom CSS grid split-pane layout with scrollable list, detail panel, and empty state placeholder.
**Solution:** New composite `SplitPane`.
```tsx
interface SplitPaneProps {
list: ReactNode
detail: ReactNode | null // null renders empty state
emptyMessage?: string // Default: "Select an item to view details"
ratio?: '1:1' | '1:2' | '2:3' // Default: '1:2'
className?: string
}
```
**Layout:**
- CSS grid with two columns at the specified ratio
- Left panel: scrollable, `var(--bg-surface)` background, right border `var(--border-subtle)`
- Right panel: scrollable, `var(--bg-raised)` background
**Pages to refactor:** AgentInstance.tsx — replace custom log rendering with `<LogViewer entries={logs} />`.
---
## 5. StatusText — New Primitive
**Problem:** Dashboard and Routes use inline `style={{ color: 'var(--error)', fontWeight: 600 }}` for status values like "BREACH", "OK", colored percentages.
3.**Card title** — small change to existing component, unblocks Routes cleanup
4.**SplitPane** — 3 admin tabs, clean pattern
5.**LogViewer** — 1 page but important for real app
6.**AgentHealth DataTable refactor** — pure page cleanup, no DS changes
## Testing
All new components tested with Vitest + React Testing Library, co-located test files. Page refactors verified by running existing tests + visual check that pages look identical before and after.
## Barrel Exports
New components added to respective barrel exports: