import type { VariantProps } from "class-variance-authority"; import { Check, Copy } from "lucide-react"; import { type HTMLProps, type ReactNode, useCallback, useEffect, useState } from "react"; import CopyToClipboard from "react-copy-to-clipboard"; import { useTranslation } from "react-i18next"; import { PrismLight as SyntaxHighlighter } from "react-syntax-highlighter"; import java from "react-syntax-highlighter/dist/esm/languages/prism/java"; import materialDark from "react-syntax-highlighter/dist/esm/styles/prism/material-dark"; import { toast } from "sonner"; import { Button, type buttonVariants } from "@/components/ui/button"; import { cn } from "@/lib/utils"; SyntaxHighlighter.registerLanguage("java", java); interface CopyButtonProps extends React.ComponentProps<"button"> { value: string; src?: string; } export function CopyButton({ value, }: Readonly>) { const [hasCopied, setHasCopied] = useState(false); const { t } = useTranslation(["common"]); useEffect(() => { if (hasCopied) { const timer = setTimeout(() => { setHasCopied(false); }, 1000); return () => clearTimeout(timer); } }, [hasCopied]); const handleCopy = useCallback(() => { if (!hasCopied) { setHasCopied(true); toast.success(t("copySuccess"), { duration: 1000 }); } }, [hasCopied, t]); return ( ); } export default function CodeViewer({ code, header, button, language, height, showLineNumbers = true, wrapLongLines = true, }: Readonly) { const lineProps: lineTagPropsFunction | HTMLProps | undefined = wrapLongLines ? { style: { overflowWrap: "break-word", whiteSpace: "pre-wrap" } } : undefined; return (
{header}
{button}
{code}
); } interface CodeViewerProps { code: string; language: string; header?: ReactNode; button?: ReactNode; height?: string | number; showLineNumbers?: boolean; wrapLongLines?: boolean; lineProps?: (lineNumber: number) => React.HTMLProps; }