{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "metric-row",
  "title": "Metric row",
  "description": "A row of headline numbers for the last 24 hours: requests, error rate, response time and sprouts serving, each with its change and an hourly sparkline.",
  "registryDependencies": [
    "https://sproutboat.com/ikada/r/theme.json",
    "https://sproutboat.com/ikada/r/chart-theme.json",
    "https://sproutboat.com/ikada/r/cn.json",
    "https://sproutboat.com/ikada/r/metric-tile.json",
    "https://sproutboat.com/ikada/r/sparkline.json"
  ],
  "files": [
    {
      "path": "registry/ikada/blocks/metric-row/metric-row.tsx",
      "content": "\"use client\";\n\n/**\n * A row of headline numbers for the last 24 hours: requests, error rate, response time and\n * sprouts serving, each with its change and an hourly sparkline. Two columns when narrow, four when wide.\n */\nimport { Sparkline } from \"@/components/ikada/sparkline\";\nimport type { ChartColorName } from \"@/components/ikada/chart-theme\";\nimport { MetricTile } from \"@/components/ikada/metric-tile\";\nimport type { MetricDelta } from \"@/components/ikada/metric-tile\";\nimport { cn } from \"@/components/ikada/lib/cn\";\n\nexport interface Metric {\n  id: string;\n  label: string;\n  /** Already formatted: \"184K\", \"0.21\". */\n  value: string;\n  /** \"%\", \"ms p50\", \"of 6\". */\n  unit?: string;\n  delta?: MetricDelta;\n  /** One line under the value. */\n  hint?: string;\n  /** Hourly values, oldest first; draws a sparkline under the tile. */\n  trend?: readonly number[];\n  trendColor?: ChartColorName;\n  /** How a hovered sparkline value reads: the number (and a unit if it has one), not the series name, which the tooltip shows once. */\n  formatTrend?: (value: number) => string;\n}\n\nexport interface MetricRowProps {\n  metrics?: Metric[];\n  /** Labels a sparkline point by its index, e.g. the hour it covers. */\n  formatPoint?: (index: number) => string;\n  className?: string;\n}\n\n/** Deterministic noise, so the sample looks real and renders the same every time. */\nfunction seeded(seed: number): () => number {\n  let s = seed;\n  return () => {\n    s = (s + 0x6d2b79f5) | 0;\n    let t = Math.imul(s ^ (s >>> 15), 1 | s);\n    t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\n    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n  };\n}\n\n/** 24 hourly values on a day curve: quiet at night, busiest mid-afternoon. */\nfunction day(peak: number, seed: number, floor = 0.18): number[] {\n  const rand = seeded(seed);\n  return Array.from({ length: 24 }, (_, h) => {\n    const curve = floor + (1 - floor) * Math.max(0, Math.sin(((h - 6) / 24) * Math.PI * 2) * 0.5 + 0.5) ** 1.6;\n    return Math.round(peak * curve * (0.85 + rand() * 0.3));\n  });\n}\n\nconst requests = day(12_400, 7);\nconst errors = requests.map((r, h) => Math.round(r * (h === 15 || h === 16 ? 0.011 : 0.0016)));\nconst latency = day(64, 11, 0.55);\n\n/** Sample data: a busy project's last 24 hours, with a short error spike after an afternoon deploy. */\nexport const sampleMetrics: Metric[] = [\n  {\n    id: \"requests\",\n    label: \"Requests\",\n    value: \"184K\",\n    delta: { value: \"12%\", direction: \"up\" },\n    hint: \"Last 24 hours\",\n    trend: requests,\n    formatTrend: (v) => v.toLocaleString(\"en\"),\n  },\n  {\n    id: \"errors\",\n    label: \"Error rate\",\n    value: \"0.21\",\n    unit: \"%\",\n    delta: { value: \"0.08 pt\", direction: \"up\", sentiment: \"bad\" },\n    hint: \"5xx responses\",\n    trend: errors,\n    trendColor: \"errors\",\n    formatTrend: (v) => String(v),\n  },\n  {\n    id: \"latency\",\n    label: \"Response time\",\n    value: \"38\",\n    unit: \"ms p50\",\n    delta: { value: \"9%\", direction: \"down\", sentiment: \"good\" },\n    hint: \"p99 212 ms\",\n    trend: latency,\n    trendColor: \"series\",\n    formatTrend: (v) => `${v} ms`,\n  },\n  {\n    id: \"serving\",\n    label: \"Sprouts serving\",\n    value: \"5\",\n    unit: \"of 6\",\n    hint: \"One paused\",\n  },\n];\n\nconst hourLabel = (i: number): string => `${String(i).padStart(2, \"0\")}:00`;\n\nexport function MetricRow({ metrics = sampleMetrics, formatPoint = hourLabel, className }: MetricRowProps) {\n  return (\n    <div className={cn(\"@container\", className)}>\n      <div className=\"grid grid-cols-1 gap-3 @xs:grid-cols-2 @4xl:grid-cols-4\">\n        {metrics.map((m) => (\n          <MetricTile\n            key={m.id}\n            className=\"justify-between\"\n            label={m.label}\n            value={m.value}\n            unit={m.unit}\n            delta={m.delta}\n            hint={m.hint}\n            sparkline={\n              m.trend ? (\n                <Sparkline\n                  data={m.trend}\n                  color={m.trendColor}\n                  aria-label={`${m.label}, per hour over the last 24 hours`}\n                  formatValue={m.formatTrend}\n                  formatPoint={formatPoint}\n                />\n              ) : undefined\n            }\n          />\n        ))}\n      </div>\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "@components/ikada/blocks/metric-row/metric-row.tsx"
    }
  ],
  "categories": [
    "dashboard"
  ],
  "type": "registry:block"
}