{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "codeblock",
  "type": "registry:component",
  "title": "Code Block",
  "description": "Easy Code Block Component",
  "dependencies": [
    "shiki"
  ],
  "registryDependencies": [
    "tooltip"
  ],
  "files": [
    {
      "path": "components/chatcn/ai/codeblock.tsx",
      "content": "\"use client\";\nimport type { BundledLanguage } from \"shiki\";\nimport { codeToHtml } from \"shiki\";\nimport { Copy01Icon, Tick01Icon, File01Icon } from \"@hugeicons/core-free-icons\";\nimport { HugeiconsIcon } from \"@hugeicons/react\";\nimport Image from \"next/image\";\nimport {\n  useState,\n  useEffect,\n  useCallback,\n  createContext,\n  useContext,\n} from \"react\";\nimport {\n  Tooltip,\n  TooltipTrigger,\n  TooltipContent,\n} from \"@/components/ui/tooltip\";\nimport { cn } from \"@/lib/utils\";\n\ntype CodeBlockContextType = {\n  code: string;\n};\n\nconst CodeBlockContext = createContext<CodeBlockContextType>({\n  code: \"\",\n});\n\nfunction useCodeBlockContext() {\n  const ctx = useContext(CodeBlockContext);\n  if (!ctx) {\n    throw Error(\"useCodeBlockContext must be used within a CodeBlock\");\n  }\n  return ctx;\n}\n\ntype CodeBlockCopyButtonProps = {\n  className?: string;\n};\n\nexport function CodeBlockCopyButton({ className }: CodeBlockCopyButtonProps) {\n  const { code } = useCodeBlockContext();\n  const [copied, setCopied] = useState(false);\n\n  const handleCopy = async () => {\n    await navigator.clipboard.writeText(code);\n    setCopied(true);\n    setTimeout(() => setCopied(false), 2000);\n  };\n\n  return (\n    <Tooltip>\n      <TooltipTrigger\n        className={cn(\"p-1 rounded-md hover:bg-muted transition\", className)}\n        onClick={handleCopy}\n      >\n        {copied ? (\n          <HugeiconsIcon icon={Tick01Icon} size={18} />\n        ) : (\n          <HugeiconsIcon icon={Copy01Icon} size={18} />\n        )}\n      </TooltipTrigger>\n      <TooltipContent>\n        <p>{copied ? \"Copied!\" : \"Copy to Clipboard\"}</p>\n      </TooltipContent>\n    </Tooltip>\n  );\n}\n\ntype CodeBlockTitleProps = {\n  children: string;\n  lang?: string;\n  className?: string;\n};\n\nexport function CodeBlockTitle({\n  children,\n  lang,\n  className,\n}: CodeBlockTitleProps) {\n  const iconUrl = lang\n    ? `https://cdn.jsdelivr.net/gh/devicons/devicon@latest/icons/${lang}/${lang}-original.svg`\n    : null;\n\n  return (\n    <div\n      className={cn(\n        \"flex items-center gap-2.5 px-4 py-3 border-b bg-muted/30 text-sm text-muted-foreground font-mono\",\n        className\n      )}\n    >\n      {iconUrl ? (\n        <Image\n          src={iconUrl}\n          alt=\"\"\n          width={16}\n          height={16}\n          className=\"size-4 shrink-0\"\n        />\n      ) : (\n        <HugeiconsIcon\n          icon={File01Icon}\n          size={16}\n          className=\"text-muted-foreground shrink-0\"\n        />\n      )}\n      <span className=\"truncate font-semibold flex-1\">{children}</span>\n      <CodeBlockCopyButton />\n    </div>\n  );\n}\n\ntype CodeBlockContentProps = {\n  className?: string;\n};\n\nexport function CodeBlockContent({ className }: CodeBlockContentProps) {\n  const { code } = useCodeBlockContext();\n\n  return (\n    <div\n      className={cn(\n        \"w-full overflow-x-auto text-sm md:text-base [&>pre]:px-4 [&>pre]:py-4\",\n        className\n      )}\n    >\n      <pre className=\"bg-background text-foreground\">\n        <code>\n          {code.split(\"\\n\").map((line, i) => (\n            <span key={i} className=\"line\">\n              {line}\n              {\"\\n\"}\n            </span>\n          ))}\n        </code>\n      </pre>\n    </div>\n  );\n}\n\ntype CodeBlockProps = {\n  children?: React.ReactNode;\n  code?: string;\n  lang: BundledLanguage;\n  height?: string;\n  className?: string;\n  highlight?: { start: number; end: number };\n  theme?: string;\n};\n\nexport function CodeBlock({\n  children,\n  code,\n  theme = \"github-dark-default\",\n  lang,\n  height = \"600\",\n  className,\n  highlight,\n}: CodeBlockProps) {\n  const [html, setHtml] = useState<string | null>(null);\n\n  const codeContent = code ?? (typeof children === \"string\" ? children : \"\");\n  const hasCompoundChildren = children && typeof children !== \"string\";\n\n  const generateHtml = useCallback(async () => {\n    if (!codeContent) {\n      setHtml(\"<pre><code></code></pre>\");\n      return;\n    }\n    const out = await codeToHtml(codeContent, {\n      lang,\n      theme,\n      colorReplacements: {\n        \"#0d1117\": \"var(--background)\",\n        \"#ffffff\": \"var(--background)\",\n      },\n      decorations: highlight\n        ? [\n            {\n              start: { line: highlight.start - 1, character: 0 },\n              end: { line: highlight.end, character: 0 },\n              properties: { class: \"bg-muted inline-block\" },\n            },\n          ]\n        : [],\n    });\n    setHtml(out);\n  }, [codeContent, lang, theme, highlight]);\n\n  useEffect(() => {\n    generateHtml();\n  }, [generateHtml]);\n\n  return (\n    <CodeBlockContext.Provider value={{ code: codeContent }}>\n      <div\n        className={cn(\n          \"relative rounded-xl md:text-xl overflow-auto border shadow-md bg-background w-full max-w-full shrink\",\n          className\n        )}\n        style={{ height: \"100%\", maxHeight: `${height}px` }}\n      >\n        {hasCompoundChildren ? (\n          <>\n            {children}\n            {html == null ? (\n              <CodeBlockContent />\n            ) : (\n              <div\n                className=\"w-full overflow-x-auto md:text-base text-sm [&>pre]:px-4 [&>pre]:py-4\"\n                dangerouslySetInnerHTML={{ __html: html }}\n              />\n            )}\n          </>\n        ) : (\n          <>\n            <div className=\"sticky top-5 flex justify-end -mt-8 mr-5 z-10\">\n              <CodeBlockCopyButton />\n            </div>\n            {html == null ? (\n              <CodeBlockContent />\n            ) : (\n              <div\n                className=\"w-full overflow-x-auto md:text-base text-sm [&>pre]:px-4 [&>pre]:py-4\"\n                dangerouslySetInnerHTML={{ __html: html }}\n              />\n            )}\n          </>\n        )}\n      </div>\n    </CodeBlockContext.Provider>\n  );\n}\n",
      "type": "registry:component"
    }
  ]
}