{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "ai-commit",
  "title": "AI: Commit",
  "description": "A commit summary with metadata, changed files and an optional details panel.",
  "dependencies": [
    "@untitledui/icons@^0.0.23"
  ],
  "registryDependencies": [
    "@nx-ui/utils",
    "@nx-ui/avatar",
    "@nx-ui/button",
    "@nx-ui/collapsible"
  ],
  "files": [
    {
      "path": "components/ai/commit.tsx",
      "content": "// Ported from vercel/ai-elements@6a9d5b1822ffb10bba4bd97175f01edd7d8651cd.\n\"use client\";\n\nimport { Avatar, AvatarFallback } from \"@/components/ui/avatar\";\nimport { Button } from \"@/components/ui/button\";\nimport {\n  Collapsible,\n  CollapsibleContent,\n  CollapsibleTrigger,\n} from \"@/components/ui/collapsible\";\nimport { cn } from \"@/lib/utils\";\nimport {\n  Check as CheckIcon,\n  Copy01 as CopyIcon,\n  File01 as FileIcon,\n  GitCommit as GitCommitIcon,\n  Minus as MinusIcon,\n  Plus as PlusIcon,\n} from \"@untitledui/icons\";\nimport type { ComponentProps, HTMLAttributes } from \"react\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\nexport type CommitProps = ComponentProps<typeof Collapsible>;\n\nexport const Commit = ({ className, children, ...props }: CommitProps) => (\n  <Collapsible\n    className={cn(\"rounded-lg border bg-background\", className)}\n    {...props}\n  >\n    {children}\n  </Collapsible>\n);\n\nexport type CommitHeaderProps = ComponentProps<typeof CollapsibleTrigger>;\n\nexport const CommitHeader = ({\n  className,\n  children,\n  ...props\n}: CommitHeaderProps) => (\n  <CollapsibleTrigger\n    {...props}\n    render={<button type=\"button\" />}\n    className={cn(\n      \"group flex w-full cursor-pointer items-center justify-between gap-4 p-3 text-left transition-colors hover:opacity-80\",\n      className\n    )}\n  >\n    {children}\n  </CollapsibleTrigger>\n);\n\nexport type CommitHashProps = HTMLAttributes<HTMLSpanElement>;\n\nexport const CommitHash = ({\n  className,\n  children,\n  ...props\n}: CommitHashProps) => (\n  <span className={cn(\"font-mono text-xs\", className)} {...props}>\n    <GitCommitIcon className=\"mr-1 inline-block size-3\" />\n    {children}\n  </span>\n);\n\nexport type CommitMessageProps = HTMLAttributes<HTMLSpanElement>;\n\nexport const CommitMessage = ({\n  className,\n  children,\n  ...props\n}: CommitMessageProps) => (\n  <span className={cn(\"font-medium text-sm\", className)} {...props}>\n    {children}\n  </span>\n);\n\nexport type CommitMetadataProps = HTMLAttributes<HTMLDivElement>;\n\nexport const CommitMetadata = ({\n  className,\n  children,\n  ...props\n}: CommitMetadataProps) => (\n  <div\n    className={cn(\n      \"flex items-center gap-2 text-muted-foreground text-xs\",\n      className\n    )}\n    {...props}\n  >\n    {children}\n  </div>\n);\n\nexport type CommitSeparatorProps = HTMLAttributes<HTMLSpanElement>;\n\nexport const CommitSeparator = ({\n  className,\n  children,\n  ...props\n}: CommitSeparatorProps) => (\n  <span className={className} {...props}>\n    {children ?? \"•\"}\n  </span>\n);\n\nexport type CommitInfoProps = HTMLAttributes<HTMLDivElement>;\n\nexport const CommitInfo = ({\n  className,\n  children,\n  ...props\n}: CommitInfoProps) => (\n  <div className={cn(\"flex flex-1 flex-col\", className)} {...props}>\n    {children}\n  </div>\n);\n\nexport type CommitAuthorProps = HTMLAttributes<HTMLDivElement>;\n\nexport const CommitAuthor = ({\n  className,\n  children,\n  ...props\n}: CommitAuthorProps) => (\n  <div className={cn(\"flex items-center\", className)} {...props}>\n    {children}\n  </div>\n);\n\nexport type CommitAuthorAvatarProps = ComponentProps<typeof Avatar> & {\n  initials: string;\n};\n\nexport const CommitAuthorAvatar = ({\n  initials,\n  className,\n  ...props\n}: CommitAuthorAvatarProps) => (\n  <Avatar className={cn(\"size-8\", className)} {...props}>\n    <AvatarFallback className=\"text-xs\">{initials}</AvatarFallback>\n  </Avatar>\n);\n\nexport type CommitTimestampProps = HTMLAttributes<HTMLTimeElement> & {\n  date: Date;\n};\n\nconst relativeTimeFormat = new Intl.RelativeTimeFormat(\"en\", {\n  numeric: \"auto\",\n});\n\nconst formatRelativeDate = (date: Date) => {\n  const days = Math.round(\n    (date.getTime() - Date.now()) / (1000 * 60 * 60 * 24)\n  );\n  return relativeTimeFormat.format(days, \"day\");\n};\n\nexport const CommitTimestamp = ({\n  date,\n  className,\n  children,\n  ...props\n}: CommitTimestampProps) => {\n  const [formatted, setFormatted] = useState(\"\");\n\n  const updateFormatted = useCallback(() => {\n    setFormatted(formatRelativeDate(date));\n  }, [date]);\n\n  useEffect(() => {\n    updateFormatted();\n  }, [updateFormatted]);\n\n  return (\n    <time\n      className={cn(\"text-xs\", className)}\n      dateTime={date.toISOString()}\n      {...props}\n    >\n      {children ?? formatted}\n    </time>\n  );\n};\n\nexport type CommitActionsProps = HTMLAttributes<HTMLDivElement>;\n\nconst handleActionsClick = (e: React.MouseEvent) => e.stopPropagation();\nconst handleActionsKeyDown = (e: React.KeyboardEvent) => e.stopPropagation();\n\nexport const CommitActions = ({\n  className,\n  children,\n  ...props\n}: CommitActionsProps) => (\n  <div\n    className={cn(\"flex items-center gap-1\", className)}\n    onClick={handleActionsClick}\n    onKeyDown={handleActionsKeyDown}\n    role=\"group\"\n    {...props}\n  >\n    {children}\n  </div>\n);\n\nexport type CommitCopyButtonProps = ComponentProps<typeof Button> & {\n  hash: string;\n  onCopy?: () => void;\n  onError?: (error: Error) => void;\n  timeout?: number;\n};\n\nexport const CommitCopyButton = ({\n  hash,\n  onCopy,\n  onError,\n  timeout = 2000,\n  children,\n  className,\n  \"aria-label\": ariaLabel,\n  ...props\n}: CommitCopyButtonProps) => {\n  const [isCopied, setIsCopied] = useState(false);\n  const timeoutRef = useRef<number>(0);\n\n  const copyToClipboard = useCallback(async () => {\n    if (typeof window === \"undefined\" || !navigator?.clipboard?.writeText) {\n      onError?.(new Error(\"Clipboard API not available\"));\n      return;\n    }\n\n    try {\n      if (!isCopied) {\n        await navigator.clipboard.writeText(hash);\n        setIsCopied(true);\n        onCopy?.();\n        timeoutRef.current = window.setTimeout(\n          () => setIsCopied(false),\n          timeout\n        );\n      }\n    } catch (error) {\n      onError?.(error as Error);\n    }\n  }, [hash, onCopy, onError, timeout, isCopied]);\n\n  useEffect(\n    () => () => {\n      window.clearTimeout(timeoutRef.current);\n    },\n    []\n  );\n\n  const Icon = isCopied ? CheckIcon : CopyIcon;\n\n  return (\n    <Button\n      className={cn(\"size-7 shrink-0\", className)}\n      onClick={copyToClipboard}\n      size=\"icon\"\n      variant=\"ghost\"\n      {...props}\n      aria-label={ariaLabel ?? \"Copy commit hash\"}\n    >\n      {children ?? <Icon size={14} />}\n    </Button>\n  );\n};\n\nexport type CommitContentProps = ComponentProps<typeof CollapsibleContent>;\n\nexport const CommitContent = ({\n  className,\n  children,\n  ...props\n}: CommitContentProps) => (\n  <CollapsibleContent className={cn(\"border-t p-3\", className)} {...props}>\n    {children}\n  </CollapsibleContent>\n);\n\nexport type CommitFilesProps = HTMLAttributes<HTMLDivElement>;\n\nexport const CommitFiles = ({\n  className,\n  children,\n  ...props\n}: CommitFilesProps) => (\n  <div className={cn(\"space-y-1\", className)} {...props}>\n    {children}\n  </div>\n);\n\nexport type CommitFileProps = HTMLAttributes<HTMLDivElement>;\n\nexport const CommitFile = ({\n  className,\n  children,\n  ...props\n}: CommitFileProps) => (\n  <div\n    className={cn(\n      \"flex items-center justify-between gap-2 rounded px-2 py-1 text-sm hover:bg-muted/50\",\n      className\n    )}\n    {...props}\n  >\n    {children}\n  </div>\n);\n\nexport type CommitFileInfoProps = HTMLAttributes<HTMLDivElement>;\n\nexport const CommitFileInfo = ({\n  className,\n  children,\n  ...props\n}: CommitFileInfoProps) => (\n  <div className={cn(\"flex min-w-0 items-center gap-2\", className)} {...props}>\n    {children}\n  </div>\n);\n\nconst fileStatusStyles = {\n  added: \"text-green-600 dark:text-green-400\",\n  deleted: \"text-red-600 dark:text-red-400\",\n  modified: \"text-yellow-600 dark:text-yellow-400\",\n  renamed: \"text-blue-600 dark:text-blue-400\",\n};\n\nconst fileStatusLabels = {\n  added: \"A\",\n  deleted: \"D\",\n  modified: \"M\",\n  renamed: \"R\",\n};\n\nexport type CommitFileStatusProps = HTMLAttributes<HTMLSpanElement> & {\n  status: \"added\" | \"modified\" | \"deleted\" | \"renamed\";\n};\n\nexport const CommitFileStatus = ({\n  status,\n  className,\n  children,\n  ...props\n}: CommitFileStatusProps) => (\n  <span\n    className={cn(\n      \"font-medium font-mono text-xs\",\n      fileStatusStyles[status],\n      className\n    )}\n    {...props}\n  >\n    {children ?? fileStatusLabels[status]}\n  </span>\n);\n\nexport type CommitFileIconProps = ComponentProps<typeof FileIcon>;\n\nexport const CommitFileIcon = ({\n  className,\n  ...props\n}: CommitFileIconProps) => (\n  <FileIcon\n    className={cn(\"size-3.5 shrink-0 text-muted-foreground\", className)}\n    {...props}\n  />\n);\n\nexport type CommitFilePathProps = HTMLAttributes<HTMLSpanElement>;\n\nexport const CommitFilePath = ({\n  className,\n  children,\n  ...props\n}: CommitFilePathProps) => (\n  <span className={cn(\"truncate font-mono text-xs\", className)} {...props}>\n    {children}\n  </span>\n);\n\nexport type CommitFileChangesProps = HTMLAttributes<HTMLDivElement>;\n\nexport const CommitFileChanges = ({\n  className,\n  children,\n  ...props\n}: CommitFileChangesProps) => (\n  <div\n    className={cn(\n      \"flex shrink-0 items-center gap-1 font-mono text-xs\",\n      className\n    )}\n    {...props}\n  >\n    {children}\n  </div>\n);\n\nexport type CommitFileAdditionsProps = HTMLAttributes<HTMLSpanElement> & {\n  count: number;\n};\n\nexport const CommitFileAdditions = ({\n  count,\n  className,\n  children,\n  ...props\n}: CommitFileAdditionsProps) => {\n  if (count <= 0) {\n    return null;\n  }\n\n  return (\n    <span\n      className={cn(\"text-green-600 dark:text-green-400\", className)}\n      {...props}\n    >\n      {children ?? (\n        <>\n          <PlusIcon className=\"inline-block size-3\" />\n          {count}\n        </>\n      )}\n    </span>\n  );\n};\n\nexport type CommitFileDeletionsProps = HTMLAttributes<HTMLSpanElement> & {\n  count: number;\n};\n\nexport const CommitFileDeletions = ({\n  count,\n  className,\n  children,\n  ...props\n}: CommitFileDeletionsProps) => {\n  if (count <= 0) {\n    return null;\n  }\n\n  return (\n    <span\n      className={cn(\"text-red-600 dark:text-red-400\", className)}\n      {...props}\n    >\n      {children ?? (\n        <>\n          <MinusIcon className=\"inline-block size-3\" />\n          {count}\n        </>\n      )}\n    </span>\n  );\n};\n",
      "type": "registry:ui",
      "target": "components/ai/commit.tsx"
    }
  ],
  "type": "registry:ui"
}