{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "context-cards",
  "title": "Context cards",
  "description": "Retrieved context chunks with metadata and linked source attribution.",
  "registryDependencies": [
    "https://beadkit.dev/r/ai-core.json"
  ],
  "files": [
    {
      "path": "components/ai/ContextCards.tsx",
      "content": "\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport styles from \"./ai-state.module.css\";\nimport { safeExternalHref } from \"./safeExternalHref\";\nimport { useReducedMotion } from \"./useReducedMotion\";\n\nexport interface ContextChunk {\n  id?: string;\n  title: string;\n  /** Human-readable size, for example \"290 characters\". */\n  chars?: string;\n  body: string;\n  source: string;\n  badge?: string;\n  href?: string;\n}\n\nexport interface ContextCardsProps {\n  chunks: readonly ContextChunk[];\n  label?: string;\n  totalCount?: number;\n  /** Animate retrieved chunks and defer source chips. Set false for settled output. */\n  animate?: boolean;\n  className?: string;\n}\n\nfunction SourceMark({ label }: { label: string }) {\n  return (\n    <span className=\"flex size-3.5 shrink-0 items-center justify-center rounded-[4px] bg-primary text-[7px] font-bold text-primary-foreground\">\n      {label.slice(0, 4)}\n    </span>\n  );\n}\n\nexport function ContextCards({\n  chunks,\n  label = \"All chunks\",\n  totalCount,\n  animate = true,\n  className = \"\",\n}: ContextCardsProps) {\n  const reducedMotion = useReducedMotion();\n  const [chipsShown, setChipsShown] = useState(!animate);\n\n  useEffect(() => {\n    if (!animate || reducedMotion) {\n      setChipsShown(true);\n      return;\n    }\n    setChipsShown(false);\n    const chips = window.setTimeout(() => setChipsShown(true), 700);\n    return () => window.clearTimeout(chips);\n  }, [animate, reducedMotion]);\n\n  return (\n    <div data-ai-state=\"context-cards\" className={`flex w-full max-w-md flex-col gap-2 ${className}`}>\n      <div className={`${animate ? styles.fadeIn : \"\"} flex items-center gap-2 px-0.5`}>\n        <span className=\"text-[13px] font-semibold text-foreground\">{label}</span>\n        {totalCount !== undefined ? (\n          <span className=\"bg-muted text-muted-foreground inline-flex h-5 items-center rounded-md px-1.5 text-[11.5px] font-medium tabular-nums\">\n            {totalCount}\n          </span>\n        ) : null}\n      </div>\n\n      {chunks.map((chunk, index) => {\n        const href = safeExternalHref(chunk.href);\n        const sourceContent = (\n          <>\n            {chunk.badge ? <SourceMark label={chunk.badge} /> : null}\n            <span className=\"truncate\">{chunk.source}</span>\n            {href ? (\n              <svg aria-hidden=\"true\" width=\"9\" height=\"9\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\" strokeLinejoin=\"round\">\n                <path d=\"M7 17 17 7M7 7h10v10\" />\n              </svg>\n            ) : null}\n          </>\n        );\n        const chipClass = \"bg-muted text-muted-foreground inline-flex min-h-6 max-w-full items-center gap-1.5 rounded-full px-2 text-[12px] font-medium shadow-sm transition-[opacity,transform,background-color] duration-300 hover:bg-secondary motion-reduce:transition-none\";\n\n        return (\n          <article\n            key={chunk.id ?? `${chunk.title}-${index}`}\n            className={`bg-card overflow-hidden rounded-lg shadow-sm ${animate ? styles.fadeUp : \"\"}`}\n            style={animate ? { animationDelay: `${index * 100}ms` } : undefined}\n          >\n            <div className=\"border-border flex items-center gap-2.5 border-b px-3 py-2.5\">\n              <span className=\"text-foreground flex min-w-0 items-center gap-1.5 text-[13px] font-medium\">\n                <svg aria-hidden=\"true\" width=\"11\" height=\"11\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"2.5\" strokeLinecap=\"round\"><path d=\"M4 6h16M4 12h16M4 18h10\" /></svg>\n                <span className=\"truncate\">{chunk.title}</span>\n              </span>\n              {chunk.chars ? <span className=\"text-muted-foreground ml-auto shrink-0 text-[12px] tabular-nums\">{chunk.chars}</span> : null}\n            </div>\n            <p className=\"text-muted-foreground px-3 pt-2 pb-1 text-[12.5px] leading-relaxed\">{chunk.body}</p>\n            <div className=\"px-3 pb-3\">\n              {href ? (\n                <a href={href} target=\"_blank\" rel=\"noreferrer\" tabIndex={chipsShown ? undefined : -1} aria-hidden={!chipsShown} className={chipClass} style={{ opacity: chipsShown ? 1 : 0, transform: chipsShown ? \"scale(1)\" : \"scale(0.95)\", pointerEvents: chipsShown ? \"auto\" : \"none\", transitionDelay: `${index * 80}ms` }}>\n                  {sourceContent}\n                </a>\n              ) : (\n                <span className={chipClass} aria-label={`Source: ${chunk.source}`} style={{ opacity: chipsShown ? 1 : 0, transform: chipsShown ? \"scale(1)\" : \"scale(0.95)\", transitionDelay: `${index * 80}ms` }}>\n                  {sourceContent}\n                </span>\n              )}\n            </div>\n          </article>\n        );\n      })}\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "@components/ai/ContextCards.tsx"
    }
  ],
  "type": "registry:component"
}
