Address spec review: fix all blockers and flags
- Standardize semantic color naming (running, not info/teal) - Add chart tokens (--chart-1 through --chart-8) - Document dark theme strategy (same token names, muted redesign) - Switch hashColor from SHA-256 to synchronous FNV-1a - Add missing components: CodeBlock, Collapsible, Sparkline, AreaChart, LineChart, BarChart, ProcessorTimeline, EventFeed, ShortcutsBar - Define SearchResult interface for CommandPalette - Add DataTable pagination spec - Expand DateTimePicker/DateRangePicker specifications - Fix Tooltip position type to union - Standardize Card/StatCard accent props to semantic names Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -67,23 +67,44 @@ Brand: --amber, --amber-light, --amber-bg, --amber-deep
|
|||||||
Status: --success, --success-bg, --success-border
|
Status: --success, --success-bg, --success-border
|
||||||
--warning, --warning-bg, --warning-border
|
--warning, --warning-bg, --warning-border
|
||||||
--error, --error-bg, --error-border
|
--error, --error-bg, --error-border
|
||||||
--info (--running), --info-bg, --info-border
|
--running, --running-bg, --running-border
|
||||||
Typography: --font-body, --font-mono
|
Typography: --font-body, --font-mono
|
||||||
Spacing: --radius-sm (5px), --radius-md (8px), --radius-lg (12px)
|
Spacing: --radius-sm (5px), --radius-md (8px), --radius-lg (12px)
|
||||||
Shadows: --shadow-sm, --shadow-md, --shadow-lg, --shadow-card
|
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
|
### 3.2 Deterministic Color Hashing
|
||||||
|
|
||||||
A `hashColor(name: string)` utility generates consistent HSL colors from any string:
|
A `hashColor(name: string)` utility generates consistent HSL colors from any string:
|
||||||
|
|
||||||
1. Compute SHA-256 of the input name
|
1. Compute FNV-1a hash of the input name (synchronous, fast, good distribution)
|
||||||
2. Extract first 2 bytes → map to hue (0-360)
|
2. Take hash modulo 360 → hue angle
|
||||||
3. Light theme: `hsl(hue, 45%, 92%)` background, `hsl(hue, 55%, 35%)` text
|
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
|
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.
|
Used by `Badge` and `Avatar` components when no explicit color variant is provided.
|
||||||
|
|
||||||
### 3.3 Theme Switching
|
### 3.3 Theme Switching
|
||||||
@@ -112,6 +133,8 @@ src/
|
|||||||
│ │ ├── Button/
|
│ │ ├── Button/
|
||||||
│ │ ├── Card/
|
│ │ ├── Card/
|
||||||
│ │ ├── Checkbox/
|
│ │ ├── Checkbox/
|
||||||
|
│ │ ├── CodeBlock/
|
||||||
|
│ │ ├── Collapsible/
|
||||||
│ │ ├── DateTimePicker/
|
│ │ ├── DateTimePicker/
|
||||||
│ │ ├── DateRangePicker/
|
│ │ ├── DateRangePicker/
|
||||||
│ │ ├── EmptyState/
|
│ │ ├── EmptyState/
|
||||||
@@ -122,6 +145,7 @@ src/
|
|||||||
│ │ ├── MonoText/
|
│ │ ├── MonoText/
|
||||||
│ │ ├── Select/
|
│ │ ├── Select/
|
||||||
│ │ ├── SectionHeader/
|
│ │ ├── SectionHeader/
|
||||||
|
│ │ ├── Sparkline/
|
||||||
│ │ ├── Spinner/
|
│ │ ├── Spinner/
|
||||||
│ │ ├── StatCard/
|
│ │ ├── StatCard/
|
||||||
│ │ ├── StatusDot/
|
│ │ ├── StatusDot/
|
||||||
@@ -130,14 +154,20 @@ src/
|
|||||||
│ │ ├── Tooltip/
|
│ │ ├── Tooltip/
|
||||||
│ │ └── index.ts # Barrel export
|
│ │ └── index.ts # Barrel export
|
||||||
│ ├── composites/
|
│ ├── composites/
|
||||||
|
│ │ ├── AreaChart/
|
||||||
|
│ │ ├── BarChart/
|
||||||
│ │ ├── Breadcrumb/
|
│ │ ├── Breadcrumb/
|
||||||
│ │ ├── CommandPalette/
|
│ │ ├── CommandPalette/
|
||||||
│ │ ├── DataTable/
|
│ │ ├── DataTable/
|
||||||
│ │ ├── DetailPanel/
|
│ │ ├── DetailPanel/
|
||||||
│ │ ├── Dropdown/
|
│ │ ├── Dropdown/
|
||||||
|
│ │ ├── EventFeed/
|
||||||
│ │ ├── FilterBar/
|
│ │ ├── FilterBar/
|
||||||
|
│ │ ├── LineChart/
|
||||||
│ │ ├── MenuItem/
|
│ │ ├── MenuItem/
|
||||||
│ │ ├── Modal/
|
│ │ ├── Modal/
|
||||||
|
│ │ ├── ProcessorTimeline/
|
||||||
|
│ │ ├── ShortcutsBar/
|
||||||
│ │ ├── Tabs/
|
│ │ ├── Tabs/
|
||||||
│ │ └── index.ts
|
│ │ └── index.ts
|
||||||
│ ├── layout/
|
│ ├── layout/
|
||||||
@@ -187,7 +217,7 @@ All CSS custom properties for both themes. Light values sourced from `mock-v2-li
|
|||||||
#### `hashColor.ts`
|
#### `hashColor.ts`
|
||||||
- `hashColor(name: string): { bg: string; text: string; border: string }`
|
- `hashColor(name: string): { bg: string; text: string; border: string }`
|
||||||
- Returns CSS color strings appropriate for current theme
|
- 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
|
### 5.2 Primitives
|
||||||
|
|
||||||
@@ -200,8 +230,8 @@ All CSS custom properties for both themes. Light values sourced from `mock-v2-li
|
|||||||
#### Badge
|
#### Badge
|
||||||
- Inline label pill
|
- Inline label pill
|
||||||
- Variants: `filled` (solid bg + text from hash), `outlined` (transparent bg, colored border), `dashed` (dashed border, for inherited/transitive items)
|
- 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`)
|
- Color: auto from `hashColor(label)` or explicit semantic color for status badges
|
||||||
- Props: `label: string`, `variant?: 'filled' | 'outlined' | 'dashed'`, `color?: 'success' | 'warning' | 'error' | 'info' | 'auto'`
|
- Props: `label: string`, `variant?: 'filled' | 'outlined' | 'dashed'`, `color?: 'success' | 'warning' | 'error' | 'running' | 'auto'`
|
||||||
- Optional `onRemove` for dismissible badges
|
- Optional `onRemove` for dismissible badges
|
||||||
|
|
||||||
#### Button
|
#### 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`)
|
- Subtle border (`--border-subtle`) + shadow (`--shadow-card`)
|
||||||
- Border radius `--radius-md`
|
- Border radius `--radius-md`
|
||||||
- Optional top accent stripe (colored 2px bar)
|
- Optional top accent stripe (colored 2px bar)
|
||||||
- Props: `accent?: 'amber' | 'green' | 'error' | 'teal' | 'warning'`, `children`
|
- Props: `accent?: 'primary' | 'success' | 'error' | 'running' | 'warning'`, `children`
|
||||||
|
|
||||||
#### Checkbox
|
#### Checkbox
|
||||||
- Styled checkbox with warm focus ring
|
- Styled checkbox with warm focus ring
|
||||||
- Props: standard input[checkbox] props + `label?: string`
|
- Props: standard input[checkbox] props + `label?: string`
|
||||||
|
|
||||||
#### DateTimePicker
|
#### DateTimePicker
|
||||||
- Date + time input with calendar dropdown
|
- Initial implementation: styled native `<input type="datetime-local">` matching the Input component's warm styling (focus ring, border, background)
|
||||||
- Warm styling consistent with Input component
|
- Custom calendar dropdown is a future enhancement
|
||||||
- Props: `value`, `onChange`, `min?`, `max?`
|
- Props: `value: string`, `onChange`, `min?: string`, `max?: string`
|
||||||
|
|
||||||
#### DateRangePicker
|
#### DateRangePicker
|
||||||
- Start + end datetime selection
|
- Start + end datetime selection using two DateTimePicker inputs
|
||||||
- Built-in presets: "Last 1h", "Last 6h", "Today", "This shift", "Last 24h", "Last 7d", "Custom"
|
- 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[]`
|
- Props: `value: { start: Date; end: Date }`, `onChange`, `presets?: Preset[]`
|
||||||
|
|
||||||
#### EmptyState
|
#### EmptyState
|
||||||
@@ -238,12 +269,12 @@ All CSS custom properties for both themes. Light values sourced from `mock-v2-li
|
|||||||
#### FilterPill
|
#### FilterPill
|
||||||
- Selectable pill with optional color dot + count
|
- Selectable pill with optional color dot + count
|
||||||
- States: default, hover, active (amber bg), active-colored (status-specific bg)
|
- 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
|
#### InfoCallout
|
||||||
- Block with left accent border (3px, amber by default)
|
- Block with left accent border (3px, amber by default)
|
||||||
- Light background
|
- Light background
|
||||||
- Props: `children`, `variant?: 'info' | 'warning' | 'error'`
|
- Props: `children`, `variant?: 'running' | 'warning' | 'error'`
|
||||||
|
|
||||||
#### Input
|
#### Input
|
||||||
- Text input with warm focus ring (`--amber` border, `--amber-bg` shadow)
|
- 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
|
#### StatCard
|
||||||
- KPI display card extending Card
|
- KPI display card extending Card
|
||||||
- Top accent stripe, label, large mono value, trend indicator, detail line
|
- 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
|
#### StatusDot
|
||||||
- 6-7px colored circle
|
- 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`)
|
- 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
|
#### Tag
|
||||||
- Removable pill with x dismiss button
|
- 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
|
#### Tooltip
|
||||||
- Hover-triggered info popup
|
- Hover-triggered info popup
|
||||||
- Positions: top, bottom, left, right
|
- 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
|
### 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
|
- Match highlighting (bold amber) in result text
|
||||||
- Keyboard navigation: arrows to navigate, enter to open, tab to filter, esc to close
|
- Keyboard navigation: arrows to navigate, enter to open, tab to filter, esc to close
|
||||||
- Bottom bar with keyboard shortcut hints
|
- 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
|
#### DataTable
|
||||||
- Sortable columns (click header to sort, indicator arrow)
|
- 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)
|
- Optional left accent border on rows (e.g., red for failed)
|
||||||
- Inline content below row (e.g., error preview)
|
- Inline content below row (e.g., error preview)
|
||||||
- Column types: text, mono, badge, status, duration, timestamp
|
- 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
|
#### DetailPanel
|
||||||
- Sliding panel from the right (400px width)
|
- 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
|
- Underline active indicator
|
||||||
- Props: `tabs: { label: string; count?: number; value: string }[]`, `active: string`, `onChange`
|
- 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
|
### 5.4 Layout
|
||||||
|
|
||||||
#### AppShell
|
#### AppShell
|
||||||
|
|||||||
Reference in New Issue
Block a user