50 lines
1.4 KiB
TypeScript
50 lines
1.4 KiB
TypeScript
import { useState } from 'react';
|
|
import Highlight from 'react-highlight';
|
|
import 'highlight.js/styles/atom-one-light.css';
|
|
|
|
interface CodeBlockProps {
|
|
code: string;
|
|
language?: 'json' | 'xml' | 'javascript' | 'typescript' | 'css' | 'html' | 'plaintext';
|
|
showLineNumbers?: boolean;
|
|
maxHeight?: string;
|
|
className?: string;
|
|
}
|
|
|
|
export function CodeBlock({
|
|
code,
|
|
language = 'plaintext',
|
|
showLineNumbers = false,
|
|
maxHeight = 'none',
|
|
className = '',
|
|
}: CodeBlockProps) {
|
|
const [copied, setCopied] = useState(false);
|
|
|
|
const handleCopy = async () => {
|
|
await navigator.clipboard.writeText(code);
|
|
setCopied(true);
|
|
setTimeout(() => setCopied(false), 2000);
|
|
};
|
|
|
|
return (
|
|
<div className={`relative group ${className}`}>
|
|
<div className="absolute right-2 top-2 opacity-0 group-hover:opacity-100 transition-opacity">
|
|
<button
|
|
onClick={handleCopy}
|
|
className="px-2 py-1 text-xs bg-slate-800 text-white rounded hover:bg-slate-700 transition-colors"
|
|
>
|
|
{copied ? 'Copied!' : 'Copy'}
|
|
</button>
|
|
</div>
|
|
|
|
<div
|
|
className="rounded-lg overflow-hidden border border-slate-200"
|
|
style={{ maxHeight, overflow: maxHeight !== 'none' ? 'auto' : 'visible' }}
|
|
>
|
|
<Highlight className={`language-${language} text-sm ${showLineNumbers ? 'line-numbers' : ''}`}>
|
|
{code || '// Empty'}
|
|
</Highlight>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|