{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "object-card",
  "type": "registry:component",
  "title": "Object Card",
  "description": "Durable object view for agents, runs, artifacts, and tasks inside the canvas.",
  "dependencies": [
    "@vllnt/ui@^0.2.1"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "registry/default/object-card/object-card.tsx",
      "content": "import { forwardRef } from \"react\";\n\nimport type { ReactNode } from \"react\";\n\nimport { cn } from \"@vllnt/ui\";\nimport { Badge } from \"@vllnt/ui\";\nimport { Button } from \"@vllnt/ui\";\n\nexport type ObjectCardMetric = {\n  label: string;\n  value: ReactNode;\n};\n\nexport type ObjectCardAction = {\n  label: string;\n  onClick?: () => void;\n};\n\nexport type ObjectCardProps = React.ComponentPropsWithoutRef<\"article\"> & {\n  actions?: ObjectCardAction[];\n  footer?: ReactNode;\n  kind?: string;\n  metrics?: ObjectCardMetric[];\n  ports?: ReactNode;\n  state?: \"blocked\" | \"complete\" | \"idle\" | \"running\";\n  summary?: string;\n  title: string;\n};\n\nconst stateClasses: Record<NonNullable<ObjectCardProps[\"state\"]>, string> = {\n  blocked:\n    \"border-amber-500/30 bg-amber-500/10 text-amber-700 dark:text-amber-300\",\n  complete:\n    \"border-emerald-500/30 bg-emerald-500/10 text-emerald-700 dark:text-emerald-300\",\n  idle: \"border-border/70 bg-muted/60 text-muted-foreground\",\n  running: \"border-sky-500/30 bg-sky-500/10 text-sky-700 dark:text-sky-300\",\n};\n\nfunction ObjectCardHeader({\n  kind,\n  ports,\n  state,\n  summary,\n  title,\n}: {\n  kind: string;\n  ports?: ReactNode;\n  state: NonNullable<ObjectCardProps[\"state\"]>;\n  summary?: string;\n  title: string;\n}) {\n  return (\n    <div className=\"flex items-start justify-between gap-3\">\n      <div className=\"space-y-2\">\n        <div className=\"flex flex-wrap items-center gap-2\">\n          <Badge\n            className=\"rounded-full border-border/60 bg-background/70 px-2.5 py-1 text-[11px] uppercase tracking-[0.2em] text-muted-foreground\"\n            variant=\"outline\"\n          >\n            {kind}\n          </Badge>\n          <span\n            className={cn(\n              \"inline-flex items-center rounded-full border px-2.5 py-1 text-xs font-medium capitalize\",\n              stateClasses[state],\n            )}\n          >\n            {state}\n          </span>\n        </div>\n        <div className=\"space-y-1\">\n          <h3 className=\"text-lg font-semibold tracking-tight text-foreground\">\n            {title}\n          </h3>\n          {summary ? (\n            <p className=\"max-w-[32ch] text-sm leading-6 text-muted-foreground\">\n              {summary}\n            </p>\n          ) : null}\n        </div>\n      </div>\n      {ports ? <div className=\"flex shrink-0 items-start\">{ports}</div> : null}\n    </div>\n  );\n}\n\nfunction ObjectCardMetrics({ metrics }: Pick<ObjectCardProps, \"metrics\">) {\n  if (!metrics?.length) {\n    return null;\n  }\n\n  return (\n    <dl className=\"grid grid-cols-2 gap-3 rounded-2xl border border-border/60 bg-background/75 p-3\">\n      {metrics.map((metric) => (\n        <div className=\"space-y-1\" key={metric.label}>\n          <dt className=\"text-[11px] uppercase tracking-[0.18em] text-muted-foreground\">\n            {metric.label}\n          </dt>\n          <dd className=\"text-sm font-medium text-foreground\">\n            {metric.value}\n          </dd>\n        </div>\n      ))}\n    </dl>\n  );\n}\n\nfunction ObjectCardActions({ actions }: Pick<ObjectCardProps, \"actions\">) {\n  if (!actions?.length) {\n    return null;\n  }\n\n  return (\n    <div className=\"flex flex-wrap gap-2\">\n      {actions.map((action) => {\n        const handleActionClick = () => {\n          action.onClick?.();\n        };\n\n        return (\n          <Button\n            className=\"rounded-full\"\n            key={action.label}\n            onClick={handleActionClick}\n            size=\"sm\"\n            type=\"button\"\n            variant=\"outline\"\n          >\n            {action.label}\n          </Button>\n        );\n      })}\n    </div>\n  );\n}\n\nconst ObjectCard = forwardRef<HTMLElement, ObjectCardProps>(\n  (\n    {\n      actions,\n      children,\n      className,\n      footer,\n      kind = \"Object\",\n      metrics = [],\n      ports,\n      state = \"idle\",\n      summary,\n      title,\n      ...props\n    },\n    ref,\n  ) => (\n    <article\n      className={cn(\n        \"group relative flex min-w-[320px] max-w-[420px] flex-col gap-4 rounded-[1.5rem] border border-border/70 bg-[linear-gradient(180deg,hsl(var(--background)),hsl(var(--muted)/0.22))] p-5 shadow-[0_24px_80px_hsl(var(--foreground)/0.08)] transition-transform duration-200 hover:-translate-y-0.5\",\n        className,\n      )}\n      data-state={state}\n      ref={ref}\n      {...props}\n    >\n      <div className=\"pointer-events-none absolute inset-x-5 top-0 h-px bg-[linear-gradient(90deg,transparent,hsl(var(--foreground)/0.22),transparent)]\" />\n      <ObjectCardHeader\n        kind={kind}\n        ports={ports}\n        state={state}\n        summary={summary}\n        title={title}\n      />\n      <ObjectCardMetrics metrics={metrics} />\n      {children ? <div className=\"space-y-3\">{children}</div> : null}\n      <ObjectCardActions actions={actions} />\n      {footer ? (\n        <div className=\"border-t border-border/60 pt-3 text-sm text-muted-foreground\">\n          {footer}\n        </div>\n      ) : null}\n    </article>\n  ),\n);\n\nObjectCard.displayName = \"ObjectCard\";\n\nexport { ObjectCard };\n",
      "type": "registry:component"
    }
  ],
  "version": "0.2.1",
  "stability": "stable"
}
