diff --git a/DESIGN.md b/DESIGN.md index cc9ee66..3f0fcf4 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -34,8 +34,15 @@ Primitives: `apps/web/components/status/status-badges.tsx` and `apps/web/types/s ## Components -- `CompanyOsShell` application chrome -- Metric tiles, empty/error/skeleton states +- `CompanyOsShell` application chrome: grouped sidebar with an active-row + indicator, and a top bar carrying organisation context, search (⌘K), + approvals bell, theme, and the signed-in actor +- `Panel` / `PanelLink` titled dashboard containers +- Metric tiles (value, measured 24h delta, seven-day sparkline), + empty/error/skeleton states +- `Progress` ratio bar and `components/os/charts.tsx` (sparkline, hourly run + activity lines, work-status donut) — chart colour comes from tokens and is + always paired with a legend label - Approval cards in Governance Inbox - Work item tables and board mode - Agent roster / dossier (existing agents views) @@ -54,5 +61,8 @@ never as a chat bubble product. ## Data rules - Server-backed queries and mutations only for authoritative state +- Trends, sparklines, rates, and chart series are computed from stored rows; + a tile with no history shows no trend rather than a decorative arrow, and a + count and the series beneath it must measure the same window - Theme preference may use localStorage; operational state must not - Fixture adapters must be labelled `source: fixture` in UI and types diff --git a/apps/web/components/os/charts.tsx b/apps/web/components/os/charts.tsx new file mode 100644 index 0000000..85dd5e1 --- /dev/null +++ b/apps/web/components/os/charts.tsx @@ -0,0 +1,323 @@ +"use client"; + +import { useId } from "react"; +import { + CartesianGrid, + Cell, + Line, + LineChart, + Pie, + PieChart, + ResponsiveContainer, + Tooltip, + XAxis, + YAxis, +} from "recharts"; +import { cn } from "@/lib/utils"; + +/** + * Charts read their colours from the token layer so dark and light stay in + * step, and every series is also labelled in the legend — colour alone never + * carries meaning. + */ +export const SERIES_COLOURS = { + completed: "var(--color-success)", + running: "var(--color-info)", + failed: "var(--color-error)", + cancelled: "var(--color-faint)", + accent: "var(--color-accent)", + agent: "var(--color-agent)", + warning: "var(--color-warning)", +} as const; + +function TooltipCard({ + title, + rows, +}: { + title: string; + rows: Array<{ label: string; value: string; colour: string }>; +}) { + return ( +
{title}
+| Time | + {seriesKeys.map((series) => ( ++ {series.label} + | + ))} +
|---|---|
| {point.axis} | + {seriesKeys.map((series) => ( +{point[series.key]} | + ))} +
+ {total} +
+{totalLabel}
+