{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "card-stat",
  "title": "Stat card",
  "description": "Styled card: the Stat set. 5 decorative card variations (MetricCard, TrendCard, SparklineCard, CompareCard, IconStatCard) on the ai2 token system, driven by CSS token transitions and sized sm to xl. Part of the free styled layer.",
  "dependencies": [
    "lucide-react@^1.23.0"
  ],
  "registryDependencies": [
    "@ai2/tokens"
  ],
  "files": [
    {
      "path": "registry/ai2/styled/card-stat.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport { Activity, ArrowDownRight, ArrowUpRight } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\n\n/* Stat card family: 5 cards showing a metric or KPI. The figures are fixed placeholder data (no randomness and no time source), and the sparkline is drawn as an inline SVG polyline from a deterministic series. Colour comes ONLY from semantic tokens, transparency through color-mix. size = the padding plus radius scale (the same as card-styled). */\n\nexport type StyledSize = \"sm\" | \"md\" | \"lg\" | \"xl\"\n\nconst radii: Record<StyledSize, string> = {\n  sm: \"rounded-lg\",\n  md: \"rounded-xl\",\n  lg: \"rounded-2xl\",\n  xl: \"rounded-2xl\",\n}\n\nconst pads: Record<StyledSize, string> = {\n  sm: \"p-4\",\n  md: \"p-5\",\n  lg: \"p-6\",\n  xl: \"p-8\",\n}\n\nconst values: Record<StyledSize, string> = {\n  sm: \"text-xl\",\n  md: \"text-2xl\",\n  lg: \"text-3xl\",\n  xl: \"text-4xl\",\n}\n\ntype Props = React.ComponentProps<\"div\"> & { size?: StyledSize }\n\nconst shell = \"relative w-56 border border-border bg-card text-card-foreground\"\n\nconst label = \"text-xs font-medium uppercase tracking-wide text-muted-foreground\"\n\n/* Sabit, deterministik seri. Rastgelelik yok. */\nconst series = [8, 14, 11, 18, 16, 24, 21, 30, 27, 36]\n\n/* Seriyi 100x32 viewBox icinde polyline noktalarina cevirir. */\nfunction toPoints(data: number[]) {\n  const min = Math.min(...data)\n  const max = Math.max(...data)\n  const span = max - min || 1\n  return data\n    .map((v, i) => {\n      const x = (i / (data.length - 1)) * 100\n      const y = 30 - ((v - min) / span) * 26\n      return `${x.toFixed(2)},${y.toFixed(2)}`\n    })\n    .join(\" \")\n}\n\n/* Metric: label plus a large value plus a short description. The base of the family. */\nexport function MetricCard({ className, size = \"md\", children, ...props }: Props) {\n  return (\n    <div\n      data-slot=\"styled-card\"\n      className={cn(shell, radii[size], pads[size], className)}\n      {...props}\n    >\n      {children ?? (\n        <div className=\"flex flex-col gap-1\">\n          <span className={label}>Metric label</span>\n          <span className={cn(\"font-semibold tabular-nums text-foreground\", values[size])}>\n            1,248\n          </span>\n          <span className=\"text-xs text-muted-foreground\">Placeholder value</span>\n        </div>\n      )}\n    </div>\n  )\n}\n\n/* Trend: value plus a direction badge. Up uses the success token, down the danger one. */\nexport function TrendCard({ className, size = \"md\", children, ...props }: Props) {\n  return (\n    <div\n      data-slot=\"styled-card\"\n      className={cn(shell, radii[size], pads[size], className)}\n      {...props}\n    >\n      {children ?? (\n        <div className=\"flex flex-col gap-2\">\n          <span className={label}>Trend label</span>\n          <div className=\"flex items-baseline gap-2\">\n            <span className={cn(\"font-semibold tabular-nums text-foreground\", values[size])}>\n              4,096\n            </span>\n            <span className=\"inline-flex items-center gap-0.5 rounded-full bg-success-soft px-2 py-0.5 text-xs font-medium text-success-soft-foreground [&>svg]:size-3 [&>i]:text-xs [&>i]:leading-none\">\n              <ArrowUpRight />\n              12.4%\n            </span>\n          </div>\n          <span className=\"inline-flex items-center gap-1 text-xs text-muted-foreground [&>svg]:size-3 [&>i]:text-xs [&>i]:leading-none\">\n            <ArrowDownRight />\n            Compared with the previous period\n          </span>\n        </div>\n      )}\n    </div>\n  )\n}\n\n/* Sparkline: value plus an inline SVG polyline drawn from a fixed series. */\nexport function SparklineCard({ className, size = \"md\", children, ...props }: Props) {\n  const points = React.useMemo(() => toPoints(series), [])\n  return (\n    <div\n      data-slot=\"styled-card\"\n      className={cn(shell, radii[size], pads[size], className)}\n      {...props}\n    >\n      {children ?? (\n        <div className=\"flex flex-col gap-3\">\n          <div className=\"flex flex-col gap-1\">\n            <span className={label}>Sparkline label</span>\n            <span className={cn(\"font-semibold tabular-nums text-foreground\", values[size])}>\n              862\n            </span>\n          </div>\n          <svg\n            aria-hidden=\"true\"\n            viewBox=\"0 0 100 32\"\n            preserveAspectRatio=\"none\"\n            className=\"h-10 w-full\"\n          >\n            <polygon\n              points={`0,32 ${points} 100,32`}\n              className=\"fill-[color-mix(in_oklab,var(--color-primary)_16%,transparent)]\"\n            />\n            <polyline\n              points={points}\n              fill=\"none\"\n              className=\"stroke-primary\"\n              strokeWidth=\"2\"\n              strokeLinecap=\"round\"\n              strokeLinejoin=\"round\"\n              vectorEffect=\"non-scaling-stroke\"\n            />\n          </svg>\n        </div>\n      )}\n    </div>\n  )\n}\n\n/* Compare: iki metrik yan yana, ortada token ayirici. */\nexport function CompareCard({ className, size = \"md\", children, ...props }: Props) {\n  return (\n    <div\n      data-slot=\"styled-card\"\n      className={cn(shell, \"w-64\", radii[size], pads[size], className)}\n      {...props}\n    >\n      {children ?? (\n        <div className=\"flex items-stretch gap-4\">\n          <div className=\"flex flex-1 flex-col gap-1\">\n            <span className={label}>This period</span>\n            <span className={cn(\"font-semibold tabular-nums text-foreground\", values[size])}>\n              720\n            </span>\n          </div>\n          <span aria-hidden=\"true\" className=\"w-px shrink-0 bg-border\" />\n          <div className=\"flex flex-1 flex-col gap-1\">\n            <span className={label}>Last period</span>\n            <span\n              className={cn(\"font-semibold tabular-nums text-muted-foreground\", values[size])}\n            >\n              640\n            </span>\n          </div>\n        </div>\n      )}\n    </div>\n  )\n}\n\n/* IconStat: a token icon square on the left, label plus value on the right. */\nexport function IconStatCard({ className, size = \"md\", children, ...props }: Props) {\n  return (\n    <div\n      data-slot=\"styled-card\"\n      className={cn(shell, radii[size], pads[size], className)}\n      {...props}\n    >\n      {children ?? (\n        <div className=\"flex items-center gap-3\">\n          <span\n            aria-hidden=\"true\"\n            className=\"flex size-10 shrink-0 items-center justify-center rounded-lg bg-info-soft text-info-soft-foreground [&>svg]:size-5 [&>i]:text-xl [&>i]:leading-none\"\n          >\n            <Activity />\n          </span>\n          <div className=\"flex flex-col gap-0.5\">\n            <span className={label}>Icon stat</span>\n            <span className={cn(\"font-semibold tabular-nums text-foreground\", values[size])}>\n              312\n            </span>\n          </div>\n        </div>\n      )}\n    </div>\n  )\n}\n",
      "type": "registry:component",
      "target": "components/ui/card-stat.tsx"
    }
  ],
  "categories": [
    "styled",
    "card"
  ],
  "type": "registry:component"
}