Header KPI strip The first row answers whether it is okay before the rest asks why. Four tiles is the ceiling worth defending; a fifth means somebody could not choose and the row stops being scannable. npx shadcn@latest add card Tokens this needs: --card, --card-foreground, --accent, --muted-foreground, --border, --ring, --direction-up, --direction-down, --direction-flat The status, chart, scale, state and direction names are an extension, not a rename. shadcn has --destructive and five --chart-* and nothing else in this territory. ──────────────────────────────────────────────────────────────────────── // KpiStrip.tsx ──────────────────────────────────────────────────────────────────────── import { Card } from "@/components/ui/card"; import { directionColor, directionGlyph, type Polarity } from "../red-green-direction/direction"; export type Tile = { label: string; /** null is a source that is down. The tile says so instead of showing the * last number it had. */ value: string | null; /** Signed change over the strip's window. `text` is the change in the unit * the label uses ("24ms", "9 pts"); `value` carries the sign. */ delta: { value: number; text: string }; polarity?: Polarity; /** What someone does differently when this moves. Required, because the * test for a place in the strip is actionability rather than importance, * and a tile that cannot answer it is a total wearing a KPI's clothes. */ action: string; }; /** Four to six reads as a row. Nine reads as a grid, and a grid has no reading * order, so the type stops at six. */ export type Row = | [Tile, Tile, Tile, Tile] | [Tile, Tile, Tile, Tile, Tile] | [Tile, Tile, Tile, Tile, Tile, Tile]; export function KpiStrip({ tiles, window, onSelect }: { tiles: Row; /** One window for the whole row. Tiles cannot be compared over different * periods, so it is a property of the strip rather than of a tile. */ window: string; onSelect?: (tile: Tile) => void; }) { return (
{/* One anatomy, every time: label, number, delta, on the same three baselines. The eye stops only where a value differs. */} {tiles.map((t) => { const polarity = t.polarity ?? "higher-is-better"; return ( ); })}

{window}

); } ──────────────────────────────────────────────────────────────────────── // demo.tsx ──────────────────────────────────────────────────────────────────────── import { KpiStrip, type Row } from "./KpiStrip"; /** Five tiles for a checkout service, each with the thing it changes. */ const TILES: Row = [ { label: "Error rate", value: "0.04%", delta: { value: -0.01, text: "0.01" }, polarity: "lower-is-better", action: "Above 0.5% the release is rolled back." }, { label: "P95", value: "312ms", delta: { value: 24, text: "24ms" }, polarity: "lower-is-better", action: "Above 400ms the on-call engineer is paged." }, { label: "Checkouts", value: "4,182", delta: { value: 3.1, text: "3.1%" }, action: "A drop of 10% against last week opens an incident." }, { label: "Queue depth", value: "7", delta: { value: -12, text: "12" }, polarity: "lower-is-better", action: "Above 50 a second worker is started." }, { label: "Budget left", value: "61%", delta: { value: -9, text: "9 pts" }, action: "Below 25% non-urgent deploys are frozen." }, ]; export default function Demo() { return {}} />; }