'use client'; import { Button } from '@/components/ui/button'; import { cn } from '@/lib/utils'; import { CheckIcon, CopyIcon } from 'lucide-react'; import type { ComponentProps, HTMLAttributes, ReactNode } from 'react'; import { createContext, useContext, useState } from 'react'; import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; import { oneDark, oneLight, } from 'react-syntax-highlighter/dist/esm/styles/prism'; type CodeBlockContextType = { code: string; }; const CodeBlockContext = createContext({ code: '', }); export type CodeBlockProps = HTMLAttributes & { code: string; language: string; showLineNumbers?: boolean; children?: ReactNode; }; export const CodeBlock = ({ code, language, showLineNumbers = false, className, children, ...props }: CodeBlockProps) => (
{code} {code} {children && (
{children}
)}
); export type CodeBlockCopyButtonProps = ComponentProps & { onCopy?: () => void; onError?: (error: Error) => void; timeout?: number; }; export const CodeBlockCopyButton = ({ onCopy, onError, timeout = 2000, children, className, ...props }: CodeBlockCopyButtonProps) => { const [isCopied, setIsCopied] = useState(false); const { code } = useContext(CodeBlockContext); const copyToClipboard = async () => { if (typeof window === 'undefined' || !navigator.clipboard.writeText) { onError?.(new Error('Clipboard API not available')); return; } try { await navigator.clipboard.writeText(code); setIsCopied(true); onCopy?.(); setTimeout(() => setIsCopied(false), timeout); } catch (error) { onError?.(error as Error); } }; const Icon = isCopied ? CheckIcon : CopyIcon; return ( ); };