{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "overview-board",
  "title": "Overview Board",
  "description": "Grid of overview cards for at-a-glance dashboards — a row of headline metrics with consistent spacing and tone.",
  "dependencies": [
    "@vllnt/ui@^0.3.0"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "registry/default/overview-board/overview-board.tsx",
      "content": "import { AlertCircle, ArrowRight, Inbox, ListTodo, Siren } from \"lucide-react\";\nimport type { ReactNode } from \"react\";\n\nimport { cn } from \"@vllnt/ui\";\nimport { Button } from \"@vllnt/ui\";\n\nexport type OverviewCardTone = \"danger\" | \"default\" | \"warning\";\n\nexport type OverviewCardProps = React.ComponentPropsWithoutRef<\"section\"> & {\n  ctaLabel?: ReactNode;\n  description: ReactNode;\n  handleCtaClick?: () => void;\n  heading: ReactNode;\n  icon?: ReactNode;\n  metric: ReactNode;\n  tone?: OverviewCardTone;\n};\n\nconst toneClassNames: Record<OverviewCardTone, string> = {\n  danger: \"border-red-500/30 bg-red-500/8\",\n  default: \"border-border/70 bg-background/80\",\n  warning: \"border-amber-500/30 bg-amber-500/8\",\n};\n\nconst toneAccentClassNames: Record<OverviewCardTone, string> = {\n  danger: \"text-red-600 dark:text-red-300\",\n  default: \"text-primary\",\n  warning: \"text-amber-600 dark:text-amber-300\",\n};\n\nconst OverviewCard = ({\n  className,\n  ctaLabel,\n  description,\n  handleCtaClick,\n  heading,\n  icon,\n  metric,\n  ref,\n  tone = \"default\",\n  ...props\n}: OverviewCardProps & { ref?: React.Ref<HTMLElement> }) => (\n  <section\n    className={cn(\n      \"flex min-h-[172px] flex-col gap-4 rounded-2xl border p-5 shadow-[0_8px_30px_oklch(var(--foreground)/0.06)] backdrop-blur-xl\",\n      toneClassNames[tone],\n      className,\n    )}\n    ref={ref}\n    {...props}\n  >\n    <div className=\"flex items-start justify-between gap-3\">\n      <div className=\"space-y-2\">\n        <div className=\"text-[11px] font-medium uppercase tracking-[0.24em] text-muted-foreground\">\n          {heading}\n        </div>\n        <div className=\"text-3xl font-semibold tracking-tight text-foreground\">\n          {metric}\n        </div>\n      </div>\n      <div\n        className={cn(\n          \"flex size-10 items-center justify-center rounded-xl bg-background/80\",\n          toneAccentClassNames[tone],\n        )}\n      >\n        {icon}\n      </div>\n    </div>\n    <p className=\"text-sm leading-6 text-muted-foreground\">{description}</p>\n    {ctaLabel ? (\n      <div>\n        <Button\n          onClick={handleCtaClick}\n          size=\"sm\"\n          type=\"button\"\n          variant=\"ghost\"\n        >\n          {ctaLabel}\n          <ArrowRight className=\"size-4\" />\n        </Button>\n      </div>\n    ) : null}\n  </section>\n);\n\nOverviewCard.displayName = \"OverviewCard\";\n\nexport type OverviewBoardItem = {\n  ctaLabel?: ReactNode;\n  description: ReactNode;\n  handleCtaClick?: () => void;\n  heading: ReactNode;\n  icon?: ReactNode;\n  id: string;\n  metric: ReactNode;\n  tone?: OverviewCardTone;\n};\n\nexport type OverviewBoardProps = React.ComponentPropsWithoutRef<\"section\"> & {\n  eyebrow?: ReactNode;\n  heading: ReactNode;\n  items: OverviewBoardItem[];\n  subtitle?: ReactNode;\n};\n\nfunction getDefaultIcon(heading: ReactNode) {\n  if (typeof heading !== \"string\") {\n    return <Inbox className=\"size-5\" />;\n  }\n\n  if (heading.toLowerCase().includes(\"error\")) {\n    return <AlertCircle className=\"size-5\" />;\n  }\n\n  if (heading.toLowerCase().includes(\"action\")) {\n    return <ListTodo className=\"size-5\" />;\n  }\n\n  if (heading.toLowerCase().includes(\"run\")) {\n    return <Siren className=\"size-5\" />;\n  }\n\n  return <Inbox className=\"size-5\" />;\n}\n\nconst OverviewBoard = ({\n  className,\n  eyebrow,\n  heading,\n  items,\n  ref,\n  subtitle,\n  ...props\n}: OverviewBoardProps & { ref?: React.Ref<HTMLElement> }) => (\n  <section\n    className={cn(\"mx-auto flex w-full max-w-6xl flex-col gap-6\", className)}\n    ref={ref}\n    {...props}\n  >\n    <div className=\"space-y-3\">\n      {eyebrow ? (\n        <div className=\"text-[11px] font-medium uppercase tracking-[0.28em] text-muted-foreground\">\n          {eyebrow}\n        </div>\n      ) : null}\n      <div className=\"space-y-2\">\n        <h2 className=\"text-3xl font-semibold tracking-tight text-foreground\">\n          {heading}\n        </h2>\n        {subtitle ? (\n          <p className=\"max-w-3xl text-sm leading-6 text-muted-foreground\">\n            {subtitle}\n          </p>\n        ) : null}\n      </div>\n    </div>\n    <div className=\"grid gap-4 md:grid-cols-2 xl:grid-cols-3\">\n      {items.map((item) => {\n        const handleCtaClick = item.handleCtaClick;\n\n        return (\n          <OverviewCard\n            ctaLabel={item.ctaLabel}\n            description={item.description}\n            handleCtaClick={handleCtaClick}\n            heading={item.heading}\n            icon={item.icon ?? getDefaultIcon(item.heading)}\n            key={item.id}\n            metric={item.metric}\n            tone={item.tone}\n          />\n        );\n      })}\n    </div>\n  </section>\n);\n\nOverviewBoard.displayName = \"OverviewBoard\";\n\nexport { OverviewBoard, OverviewCard };\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:component",
  "version": "0.3.0",
  "stability": "stable"
}
