{
  "$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.2.1"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "registry/default/overview-board/overview-board.tsx",
      "content": "import { forwardRef } from \"react\";\n\nimport { 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 = forwardRef<HTMLElement, OverviewCardProps>(\n  (\n    {\n      className,\n      ctaLabel,\n      description,\n      handleCtaClick,\n      heading,\n      icon,\n      metric,\n      tone = \"default\",\n      ...props\n    },\n    ref,\n  ) => (\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);\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 = forwardRef<HTMLElement, OverviewBoardProps>(\n  ({ className, eyebrow, heading, items, subtitle, ...props }, ref) => (\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);\n\nOverviewBoard.displayName = \"OverviewBoard\";\n\nexport { OverviewBoard, OverviewCard };\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:component",
  "version": "0.2.1",
  "stability": "stable"
}
