diff --git a/docs/superpowers/specs/2026-03-18-design-system-design.md b/docs/superpowers/specs/2026-03-18-design-system-design.md index 643200e..de96396 100644 --- a/docs/superpowers/specs/2026-03-18-design-system-design.md +++ b/docs/superpowers/specs/2026-03-18-design-system-design.md @@ -67,23 +67,44 @@ Brand: --amber, --amber-light, --amber-bg, --amber-deep Status: --success, --success-bg, --success-border --warning, --warning-bg, --warning-border --error, --error-bg, --error-border - --info (--running), --info-bg, --info-border + --running, --running-bg, --running-border Typography: --font-body, --font-mono Spacing: --radius-sm (5px), --radius-md (8px), --radius-lg (12px) Shadows: --shadow-sm, --shadow-md, --shadow-lg, --shadow-card +Chart: --chart-1 through --chart-8 (amber, olive, teal, burnt orange, + deep amber, sage, terracotta, gold) — used for multi-series + charts and sparklines ``` -Light theme values are taken directly from `mock-v2-light.html` `:root` block. Dark theme values will be derived with inverted lightness and reduced saturation (the existing `mock-v2-dark.html` is considered "too colorful" — dark theme should be more muted). +**Semantic color naming convention:** Components use semantic variant names that map to tokens: +- `primary` → `--amber` tokens +- `success` → `--success` tokens +- `warning` → `--warning` tokens +- `error` → `--error` tokens +- `running` → `--running` tokens (teal, for in-progress/active states) + +This convention applies to all components with color/accent props (Card, Badge, StatusDot, FilterPill, InfoCallout, etc.). No mixing of token-level names (`teal`, `green`) with semantic names. + +Light theme values are taken directly from `mock-v2-light.html` `:root` block. + +**Dark theme strategy:** The existing `mock-v2-dark.html` is considered "too colorful" and will not be used as-is. The dark theme will be a muted redesign that: +- Reuses the same token names as light (no separate `--bg-deep` / `--bg-base`) +- Inverts lightness and reduces saturation +- Drops glow tokens (`--amber-glow`, `--success-glow`, etc.) — these are not canonical +- Uses the same `--radius-sm: 5px` value (the dark mock's 6px was unintentional) +- All dark overrides go in a single `[data-theme="dark"]` block remapping the same variable names ### 3.2 Deterministic Color Hashing A `hashColor(name: string)` utility generates consistent HSL colors from any string: -1. Compute SHA-256 of the input name -2. Extract first 2 bytes → map to hue (0-360) +1. Compute FNV-1a hash of the input name (synchronous, fast, good distribution) +2. Take hash modulo 360 → hue angle 3. Light theme: `hsl(hue, 45%, 92%)` background, `hsl(hue, 55%, 35%)` text 4. Dark theme: `hsl(hue, 35%, 20%)` background, `hsl(hue, 45%, 75%)` text +FNV-1a is chosen over SHA-256 because it is synchronous (no `crypto.subtle` async), lightweight (~10 lines), and provides sufficient distribution for color bucketing. + Used by `Badge` and `Avatar` components when no explicit color variant is provided. ### 3.3 Theme Switching @@ -112,6 +133,8 @@ src/ │ │ ├── Button/ │ │ ├── Card/ │ │ ├── Checkbox/ +│ │ ├── CodeBlock/ +│ │ ├── Collapsible/ │ │ ├── DateTimePicker/ │ │ ├── DateRangePicker/ │ │ ├── EmptyState/ @@ -122,6 +145,7 @@ src/ │ │ ├── MonoText/ │ │ ├── Select/ │ │ ├── SectionHeader/ +│ │ ├── Sparkline/ │ │ ├── Spinner/ │ │ ├── StatCard/ │ │ ├── StatusDot/ @@ -130,14 +154,20 @@ src/ │ │ ├── Tooltip/ │ │ └── index.ts # Barrel export │ ├── composites/ +│ │ ├── AreaChart/ +│ │ ├── BarChart/ │ │ ├── Breadcrumb/ │ │ ├── CommandPalette/ │ │ ├── DataTable/ │ │ ├── DetailPanel/ │ │ ├── Dropdown/ +│ │ ├── EventFeed/ │ │ ├── FilterBar/ +│ │ ├── LineChart/ │ │ ├── MenuItem/ │ │ ├── Modal/ +│ │ ├── ProcessorTimeline/ +│ │ ├── ShortcutsBar/ │ │ ├── Tabs/ │ │ └── index.ts │ ├── layout/ @@ -187,7 +217,7 @@ All CSS custom properties for both themes. Light values sourced from `mock-v2-li #### `hashColor.ts` - `hashColor(name: string): { bg: string; text: string; border: string }` - Returns CSS color strings appropriate for current theme -- Uses SHA-256 → hue mapping (see Section 3.2) +- Uses a synchronous hash (FNV-1a) for hue mapping — SHA-256 is asynchronous in browsers and overkill for color bucketing (see Section 3.2) ### 5.2 Primitives @@ -200,8 +230,8 @@ All CSS custom properties for both themes. Light values sourced from `mock-v2-li #### Badge - Inline label pill - Variants: `filled` (solid bg + text from hash), `outlined` (transparent bg, colored border), `dashed` (dashed border, for inherited/transitive items) -- Color: auto from `hashColor(label)` or explicit `variant` for status badges (`success`, `warning`, `error`, `info`) -- Props: `label: string`, `variant?: 'filled' | 'outlined' | 'dashed'`, `color?: 'success' | 'warning' | 'error' | 'info' | 'auto'` +- Color: auto from `hashColor(label)` or explicit semantic color for status badges +- Props: `label: string`, `variant?: 'filled' | 'outlined' | 'dashed'`, `color?: 'success' | 'warning' | 'error' | 'running' | 'auto'` - Optional `onRemove` for dismissible badges #### Button @@ -214,20 +244,21 @@ All CSS custom properties for both themes. Light values sourced from `mock-v2-li - Subtle border (`--border-subtle`) + shadow (`--shadow-card`) - Border radius `--radius-md` - Optional top accent stripe (colored 2px bar) -- Props: `accent?: 'amber' | 'green' | 'error' | 'teal' | 'warning'`, `children` +- Props: `accent?: 'primary' | 'success' | 'error' | 'running' | 'warning'`, `children` #### Checkbox - Styled checkbox with warm focus ring - Props: standard input[checkbox] props + `label?: string` #### DateTimePicker -- Date + time input with calendar dropdown -- Warm styling consistent with Input component -- Props: `value`, `onChange`, `min?`, `max?` +- Initial implementation: styled native `` matching the Input component's warm styling (focus ring, border, background) +- Custom calendar dropdown is a future enhancement +- Props: `value: string`, `onChange`, `min?: string`, `max?: string` #### DateRangePicker -- Start + end datetime selection -- Built-in presets: "Last 1h", "Last 6h", "Today", "This shift", "Last 24h", "Last 7d", "Custom" +- Start + end datetime selection using two DateTimePicker inputs +- Built-in presets bar: "Last 1h", "Last 6h", "Today", "This shift", "Last 24h", "Last 7d", "Custom" +- Presets are FilterPill-style chips above the inputs; clicking a preset auto-fills both values - Props: `value: { start: Date; end: Date }`, `onChange`, `presets?: Preset[]` #### EmptyState @@ -238,12 +269,12 @@ All CSS custom properties for both themes. Light values sourced from `mock-v2-li #### FilterPill - Selectable pill with optional color dot + count - States: default, hover, active (amber bg), active-colored (status-specific bg) -- Props: `label: string`, `count?: number`, `active?: boolean`, `color?: 'green' | 'error' | 'teal'`, `onClick` +- Props: `label: string`, `count?: number`, `active?: boolean`, `color?: 'success' | 'error' | 'running'`, `onClick` #### InfoCallout - Block with left accent border (3px, amber by default) - Light background -- Props: `children`, `variant?: 'info' | 'warning' | 'error'` +- Props: `children`, `variant?: 'running' | 'warning' | 'error'` #### Input - Text input with warm focus ring (`--amber` border, `--amber-bg` shadow) @@ -276,13 +307,13 @@ All CSS custom properties for both themes. Light values sourced from `mock-v2-li #### StatCard - KPI display card extending Card - Top accent stripe, label, large mono value, trend indicator, detail line -- Props: `label: string`, `value: string | number`, `unit?: string`, `trend?: { direction: 'up' | 'down' | 'flat'; value: string; sentiment: 'good' | 'bad' | 'neutral' }`, `detail?: string`, `accent?: string` +- Props: `label: string`, `value: string | number`, `unit?: string`, `trend?: { direction: 'up' | 'down' | 'flat'; value: string; sentiment: 'good' | 'bad' | 'neutral' }`, `detail?: ReactNode`, `accent?: 'primary' | 'success' | 'error' | 'running' | 'warning'`, `sparkline?: number[]` #### StatusDot - 6-7px colored circle -- Variants: `live` (green + pulse), `stale` (amber), `dead` (gray), `success` (green), `warning` (orange), `error` (red), `info` (teal) +- Variants: `live` (green + pulse), `stale` (amber), `dead` (gray), `success` (green), `warning` (orange), `error` (red), `running` (teal) - Optional pulse animation (enabled by default for `live`) -- Props: `variant: 'live' | 'stale' | 'dead' | 'success' | 'warning' | 'error' | 'info'`, `pulse?: boolean` +- Props: `variant: 'live' | 'stale' | 'dead' | 'success' | 'warning' | 'error' | 'running'`, `pulse?: boolean` #### Tag - Removable pill with x dismiss button @@ -296,7 +327,28 @@ All CSS custom properties for both themes. Light values sourced from `mock-v2-li #### Tooltip - Hover-triggered info popup - Positions: top, bottom, left, right -- Props: `content: ReactNode`, `position?: string`, `children` (trigger element) +- Props: `content: ReactNode`, `position?: 'top' | 'bottom' | 'left' | 'right'`, `children` (trigger element) + +#### CodeBlock +- Monospace preformatted text display for JSON, XML, stack traces +- Inset background (`--bg-inset`), rounded corners +- Optional line numbers (left gutter) +- Optional copy-to-clipboard button (top-right) +- Auto-detects and pretty-prints JSON +- Match highlighting support (bold amber for search matches) +- Props: `content: string`, `language?: 'json' | 'xml' | 'text'`, `lineNumbers?: boolean`, `copyable?: boolean`, `highlights?: string[]`, `maxHeight?: string` + +#### Collapsible +- Expandable/collapsible section with toggle trigger +- Animated height transition +- Props: `open?: boolean`, `onToggle?: () => void`, `title: ReactNode`, `children`, `defaultOpen?: boolean` + +#### Sparkline +- Inline SVG mini-chart (polyline) +- Renders a small trend line from an array of numbers +- Sizes: fits within its container (typical: 60x20px in table cells, 80x24px in stat cards) +- Color inherits from parent or explicit prop +- Props: `data: number[]`, `color?: string`, `width?: number`, `height?: number`, `strokeWidth?: number` ### 5.3 Composites @@ -315,7 +367,23 @@ All CSS custom properties for both themes. Light values sourced from `mock-v2-li - Match highlighting (bold amber) in result text - Keyboard navigation: arrows to navigate, enter to open, tab to filter, esc to close - Bottom bar with keyboard shortcut hints -- Props: `open: boolean`, `onClose`, `onSelect: (result) => void`, `data: SearchResult[]` +- Props: `open: boolean`, `onClose`, `onSelect: (result: SearchResult) => void`, `data: SearchResult[]` +- `SearchResult` interface: + ```ts + type SearchCategory = 'execution' | 'route' | 'exchange' | 'agent' + interface SearchResult { + id: string + category: SearchCategory + title: string // e.g., route name "content-based-routing" + badges: Badge[] // status badges (Completed, Failed, etc.) + meta: string // correlation ID, duration, context line + timestamp?: string // relative time ("2s ago") + icon?: ReactNode + expandedContent?: string // JSON preview for inline expansion + matchRanges?: [number, number][] // highlight ranges in title/meta + } + ``` +- Scoped filter tags narrow the search by category or field (e.g., `route: order` filters to routes matching "order"); removing a tag widens the search back #### DataTable - Sortable columns (click header to sort, indicator arrow) @@ -324,7 +392,9 @@ All CSS custom properties for both themes. Light values sourced from `mock-v2-li - Optional left accent border on rows (e.g., red for failed) - Inline content below row (e.g., error preview) - Column types: text, mono, badge, status, duration, timestamp -- Props: `columns: Column[]`, `data: T[]`, `onRowClick?`, `selectedId?`, `sortable?: boolean` +- Client-side pagination with configurable page size (default 25, options: 10/25/50/100) +- Pagination bar at bottom: page info ("1-25 of 3,241"), page size selector, prev/next buttons +- Props: `columns: Column[]`, `data: T[]`, `onRowClick?`, `selectedId?`, `sortable?: boolean`, `pageSize?: number`, `pageSizeOptions?: number[]` #### DetailPanel - Sliding panel from the right (400px width) @@ -363,6 +433,40 @@ All CSS custom properties for both themes. Light values sourced from `mock-v2-li - Underline active indicator - Props: `tabs: { label: string; count?: number; value: string }[]`, `active: string`, `onChange` +#### AreaChart / LineChart +- SVG-based time-series charts, no external charting libraries +- Features: grid lines, axis labels, optional SLA threshold line (dashed, labeled), legend +- Multiple series support using `--chart-1` through `--chart-8` tokens +- Hover tooltip showing values at cursor position +- AreaChart fills below the line; LineChart is lines only +- Props: `series: { label: string; data: { x: number | Date; y: number }[]; color?: string }[]`, `xLabel?: string`, `yLabel?: string`, `threshold?: { value: number; label: string }`, `height?: number` + +#### BarChart +- SVG vertical bar chart for categorical or time-bucketed data +- Stacked or grouped mode +- Same token-based coloring as AreaChart/LineChart +- Props: `series: { label: string; data: { x: string; y: number }[]; color?: string }[]`, `stacked?: boolean`, `height?: number` + +#### ProcessorTimeline +- Gantt-style horizontal bar timeline for exchange processor steps +- Each bar: processor name (left label), colored bar (green=ok, amber=slow, red=fail), duration label (right) +- Bar width proportional to duration relative to total execution time +- Clickable bars (select processor) +- Props: `processors: { name: string; type: string; durationMs: number; status: 'ok' | 'slow' | 'fail'; startMs: number }[]`, `totalMs: number`, `onProcessorClick?` + +#### EventFeed +- Scrolling list of real-time events +- Each item: icon (by severity), text content, relative timestamp +- Auto-scrolls to newest (with "pause" on manual scroll) +- Category filtering (error, warning, info, success) +- Props: `events: { id: string; severity: 'error' | 'warning' | 'info' | 'success'; message: string; timestamp: Date }[]`, `maxItems?: number` + +#### ShortcutsBar +- Fixed-position bar at bottom-right of viewport +- Displays keyboard shortcut hints as a horizontal list +- Each hint: `KeyboardHint` + description text +- Props: `shortcuts: { keys: string; label: string }[]` + ### 5.4 Layout #### AppShell