{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "code-comparison",
  "type": "registry:ui",
  "title": "Code Comparison",
  "description": "A component which compares two code snippets.",
  "dependencies": [
    "shiki",
    "next-themes"
  ],
  "files": [
    {
      "path": "registry/magicui/code-comparison.tsx",
      "content": "\"use client\"\n\nimport { useEffect, useMemo, useState } from \"react\"\nimport {\n  transformerNotationDiff,\n  transformerNotationFocus,\n} from \"@shikijs/transformers\"\nimport { FileIcon } from \"lucide-react\"\nimport { useTheme } from \"next-themes\"\n\nimport { cn } from \"@/lib/utils\"\n\ninterface CodeComparisonProps {\n  beforeCode: string\n  afterCode: string\n  language: string\n  filename: string\n  lightTheme: string\n  darkTheme: string\n  highlightColor?: string\n}\n\nexport function CodeComparison({\n  beforeCode,\n  afterCode,\n  language,\n  filename,\n  lightTheme,\n  darkTheme,\n  highlightColor = \"#ff3333\",\n}: CodeComparisonProps) {\n  const { theme, systemTheme } = useTheme()\n  const [highlightedBefore, setHighlightedBefore] = useState(\"\")\n  const [highlightedAfter, setHighlightedAfter] = useState(\"\")\n  const [hasLeftFocus, setHasLeftFocus] = useState(false)\n  const [hasRightFocus, setHasRightFocus] = useState(false)\n\n  const selectedTheme = useMemo(() => {\n    const currentTheme = theme === \"system\" ? systemTheme : theme\n    return currentTheme === \"dark\" ? darkTheme : lightTheme\n  }, [theme, systemTheme, darkTheme, lightTheme])\n\n  useEffect(() => {\n    if (highlightedBefore || highlightedAfter) {\n      setHasLeftFocus(highlightedBefore.includes('class=\"line focused\"'))\n      setHasRightFocus(highlightedAfter.includes('class=\"line focused\"'))\n    }\n  }, [highlightedBefore, highlightedAfter])\n\n  useEffect(() => {\n    async function highlightCode() {\n      try {\n        const { codeToHtml } = await import(\"shiki\")\n        const { transformerNotationHighlight } =\n          await import(\"@shikijs/transformers\")\n\n        const before = await codeToHtml(beforeCode, {\n          lang: language,\n          theme: selectedTheme,\n          transformers: [\n            transformerNotationHighlight({ matchAlgorithm: \"v3\" }),\n            transformerNotationDiff({ matchAlgorithm: \"v3\" }),\n            transformerNotationFocus({ matchAlgorithm: \"v3\" }),\n          ],\n        })\n        const after = await codeToHtml(afterCode, {\n          lang: language,\n          theme: selectedTheme,\n          transformers: [\n            transformerNotationHighlight({ matchAlgorithm: \"v3\" }),\n            transformerNotationDiff({ matchAlgorithm: \"v3\" }),\n            transformerNotationFocus({ matchAlgorithm: \"v3\" }),\n          ],\n        })\n        setHighlightedBefore(before)\n        setHighlightedAfter(after)\n      } catch (error) {\n        console.error(\"Error highlighting code:\", error)\n        setHighlightedBefore(`<pre>${beforeCode}</pre>`)\n        setHighlightedAfter(`<pre>${afterCode}</pre>`)\n      }\n    }\n    highlightCode()\n  }, [beforeCode, afterCode, language, selectedTheme])\n\n  const renderCode = (code: string, highlighted: string) => {\n    if (highlighted) {\n      return (\n        <div\n          style={{ \"--highlight-color\": highlightColor } as React.CSSProperties}\n          className={cn(\n            \"bg-background h-full w-full overflow-auto font-mono text-xs\",\n            \"[&>pre]:h-full [&>pre]:w-screen! [&>pre]:py-2\",\n            \"[&>pre>code]:inline-block! [&>pre>code]:w-full!\",\n            \"[&>pre>code>span]:inline-block! [&>pre>code>span]:w-full [&>pre>code>span]:px-4 [&>pre>code>span]:py-0.5\",\n            \"[&>pre>code>.highlighted]:inline-block [&>pre>code>.highlighted]:w-full [&>pre>code>.highlighted]:bg-(--highlight-color)!\",\n            \"group-hover/left:[&>pre>code>:not(.focused)]:opacity-100! group-hover/left:[&>pre>code>:not(.focused)]:blur-none!\",\n            \"group-hover/right:[&>pre>code>:not(.focused)]:opacity-100! group-hover/right:[&>pre>code>:not(.focused)]:blur-none!\",\n            \"[&>pre>code>.add]:bg-[rgba(16,185,129,.16)] [&>pre>code>.remove]:bg-[rgba(244,63,94,.16)]\",\n            \"group-hover/left:[&>pre>code>:not(.focused)]:transition-all group-hover/left:[&>pre>code>:not(.focused)]:duration-300\",\n            \"group-hover/right:[&>pre>code>:not(.focused)]:transition-all group-hover/right:[&>pre>code>:not(.focused)]:duration-300\"\n          )}\n          dangerouslySetInnerHTML={{ __html: highlighted }}\n        />\n      )\n    } else {\n      return (\n        <pre className=\"bg-background text-foreground h-full overflow-auto p-4 font-mono text-xs break-all\">\n          {code}\n        </pre>\n      )\n    }\n  }\n\n  return (\n    <div className=\"mx-auto w-full max-w-5xl\">\n      <div className=\"group border-border relative w-full overflow-hidden rounded-md border\">\n        <div className=\"relative grid md:grid-cols-2\">\n          <div\n            className={cn(\n              \"leftside group/left border-primary/20 md:border-r\",\n              hasLeftFocus &&\n                \"[&>div>pre>code>:not(.focused)]:opacity-50! [&>div>pre>code>:not(.focused)]:blur-[0.095rem]!\",\n              \"[&>div>pre>code>:not(.focused)]:transition-all [&>div>pre>code>:not(.focused)]:duration-300\"\n            )}\n          >\n            <div className=\"border-primary/20 bg-accent text-foreground flex items-center border-b p-2 text-sm\">\n              <FileIcon className=\"mr-2 h-4 w-4\" />\n              {filename}\n              <span className=\"ml-auto hidden md:block\">before</span>\n            </div>\n            {renderCode(beforeCode, highlightedBefore)}\n          </div>\n          <div\n            className={cn(\n              \"rightside group/right border-primary/20 border-t md:border-t-0\",\n              hasRightFocus &&\n                \"[&>div>pre>code>:not(.focused)]:opacity-50! [&>div>pre>code>:not(.focused)]:blur-[0.095rem]!\",\n              \"[&>div>pre>code>:not(.focused)]:transition-all [&>div>pre>code>:not(.focused)]:duration-300\"\n            )}\n          >\n            <div className=\"border-primary/20 bg-accent text-foreground flex items-center border-b p-2 text-sm\">\n              <FileIcon className=\"mr-2 h-4 w-4\" />\n              {filename}\n              <span className=\"ml-auto hidden md:block\">after</span>\n            </div>\n            {renderCode(afterCode, highlightedAfter)}\n          </div>\n        </div>\n        <div className=\"border-primary/20 bg-accent text-foreground absolute top-1/2 left-1/2 hidden h-8 w-8 -translate-x-1/2 -translate-y-1/2 items-center justify-center rounded-md border text-xs md:flex\">\n          VS\n        </div>\n      </div>\n    </div>\n  )\n}\n",
      "type": "registry:ui"
    }
  ]
}