"use client" import type { ComponentProps, HTMLAttributes, KeyboardEvent, MouseEvent, } from "react" import { useCallback, useEffect, useRef, useState } from "react" import { CheckIcon, CopyIcon, FileIcon, GitCommitIcon, MinusIcon, PlusIcon, } from "lucide-react" import { Avatar, AvatarFallback } from "@/components/ui/avatar" import { Button } from "@/components/ui/button" import { Collapsible, CollapsibleContent, CollapsibleTrigger, } from "@/components/ui/collapsible" import { cn } from "@/lib/utils" export type CommitProps = ComponentProps export const Commit = ({ className, children, ...props }: CommitProps) => ( {children} ) export type CommitHeaderProps = ComponentProps export const CommitHeader = ({ className, children, ...props }: CommitHeaderProps) => (
{children}
) export type CommitHashProps = HTMLAttributes export const CommitHash = ({ className, children, ...props }: CommitHashProps) => ( {children} ) export type CommitMessageProps = HTMLAttributes export const CommitMessage = ({ className, children, ...props }: CommitMessageProps) => ( {children} ) export type CommitMetadataProps = HTMLAttributes export const CommitMetadata = ({ className, children, ...props }: CommitMetadataProps) => (
{children}
) export type CommitSeparatorProps = HTMLAttributes export const CommitSeparator = ({ className, children, ...props }: CommitSeparatorProps) => ( {children ?? "•"} ) export type CommitInfoProps = HTMLAttributes export const CommitInfo = ({ className, children, ...props }: CommitInfoProps) => (
{children}
) export type CommitAuthorProps = HTMLAttributes export const CommitAuthor = ({ className, children, ...props }: CommitAuthorProps) => (
{children}
) export type CommitAuthorAvatarProps = ComponentProps & { initials: string } export const CommitAuthorAvatar = ({ initials, className, ...props }: CommitAuthorAvatarProps) => ( {initials} ) export type CommitTimestampProps = HTMLAttributes & { date: Date } export const CommitTimestamp = ({ date, className, children, ...props }: CommitTimestampProps) => { const formatted = date.toLocaleDateString(undefined, { day: "numeric", month: "short", year: "numeric", }) return ( ) } export type CommitActionsProps = HTMLAttributes const handleActionsClick = (e: MouseEvent) => e.stopPropagation() const handleActionsKeyDown = (e: KeyboardEvent) => e.stopPropagation() export const CommitActions = ({ className, children, ...props }: CommitActionsProps) => (
{children}
) export type CommitCopyButtonProps = ComponentProps & { hash: string onCopy?: () => void onError?: (error: Error) => void timeout?: number } export const CommitCopyButton = ({ hash, onCopy, onError, timeout = 2000, children, className, ...props }: CommitCopyButtonProps) => { const [isCopied, setIsCopied] = useState(false) const timeoutRef = useRef(0) const copyToClipboard = useCallback(async () => { if (typeof window === "undefined" || !navigator?.clipboard?.writeText) { onError?.(new Error("Clipboard API not available")) return } try { if (!isCopied) { await navigator.clipboard.writeText(hash) setIsCopied(true) onCopy?.() timeoutRef.current = window.setTimeout( () => setIsCopied(false), timeout ) } } catch (error) { onError?.(error as Error) } }, [hash, onCopy, onError, timeout, isCopied]) useEffect( () => () => { window.clearTimeout(timeoutRef.current) }, [] ) const Icon = isCopied ? CheckIcon : CopyIcon return ( ) } export type CommitContentProps = ComponentProps export const CommitContent = ({ className, children, ...props }: CommitContentProps) => ( {children} ) export type CommitFilesProps = HTMLAttributes export const CommitFiles = ({ className, children, ...props }: CommitFilesProps) => (
{children}
) export type CommitFileProps = HTMLAttributes export const CommitFile = ({ className, children, ...props }: CommitFileProps) => (
{children}
) export type CommitFileInfoProps = HTMLAttributes export const CommitFileInfo = ({ className, children, ...props }: CommitFileInfoProps) => (
{children}
) const fileStatusStyles = { added: "text-green-600 dark:text-green-400", deleted: "text-red-600 dark:text-red-400", modified: "text-yellow-600 dark:text-yellow-400", renamed: "text-blue-600 dark:text-blue-400", } const fileStatusLabels = { added: "A", deleted: "D", modified: "M", renamed: "R", } export type CommitFileStatusProps = HTMLAttributes & { status: "added" | "modified" | "deleted" | "renamed" } export const CommitFileStatus = ({ status, className, children, ...props }: CommitFileStatusProps) => ( {children ?? fileStatusLabels[status]} ) export type CommitFileIconProps = ComponentProps export const CommitFileIcon = ({ className, ...props }: CommitFileIconProps) => ( ) export type CommitFilePathProps = HTMLAttributes export const CommitFilePath = ({ className, children, ...props }: CommitFilePathProps) => ( {children} ) export type CommitFileChangesProps = HTMLAttributes export const CommitFileChanges = ({ className, children, ...props }: CommitFileChangesProps) => (
{children}
) export type CommitFileAdditionsProps = HTMLAttributes & { count: number } export const CommitFileAdditions = ({ count, className, children, ...props }: CommitFileAdditionsProps) => { if (count <= 0) { return null } return ( {children ?? ( <> {count} )} ) } export type CommitFileDeletionsProps = HTMLAttributes & { count: number } export const CommitFileDeletions = ({ count, className, children, ...props }: CommitFileDeletionsProps) => { if (count <= 0) { return null } return ( {children ?? ( <> {count} )} ) }