71 lines
1.9 KiB
TypeScript
71 lines
1.9 KiB
TypeScript
import React, { useState } from 'react'
|
|
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
|
|
import { vscDarkPlus } from 'react-syntax-highlighter/dist/esm/styles/prism'
|
|
import { Copy, Check } from 'lucide-react'
|
|
|
|
interface CodeBlockProps {
|
|
language?: string
|
|
value: string
|
|
inline?: boolean
|
|
}
|
|
|
|
export const CodeBlock: React.FC<CodeBlockProps> = ({ language, value, inline }) => {
|
|
const [copied, setCopied] = useState(false)
|
|
|
|
const handleCopy = async () => {
|
|
await navigator.clipboard.writeText(value)
|
|
setCopied(true)
|
|
setTimeout(() => setCopied(false), 2000)
|
|
}
|
|
|
|
// Inline code
|
|
if (inline) {
|
|
return (
|
|
<code className="px-1.5 py-0.5 bg-zinc-800 text-blue-300 rounded text-sm font-mono">
|
|
{value}
|
|
</code>
|
|
)
|
|
}
|
|
|
|
// Block code
|
|
return (
|
|
<div className="relative group my-4">
|
|
<div className="flex items-center justify-between bg-zinc-800 px-4 py-2 rounded-t-lg border-b border-zinc-700">
|
|
<span className="text-xs text-zinc-400 font-mono">
|
|
{language || 'plaintext'}
|
|
</span>
|
|
<button
|
|
onClick={handleCopy}
|
|
className="flex items-center gap-1.5 px-2 py-1 text-xs text-zinc-400 hover:text-white hover:bg-zinc-700 rounded transition-colors"
|
|
>
|
|
{copied ? (
|
|
<>
|
|
<Check className="w-3 h-3" />
|
|
Copied!
|
|
</>
|
|
) : (
|
|
<>
|
|
<Copy className="w-3 h-3" />
|
|
Copy
|
|
</>
|
|
)}
|
|
</button>
|
|
</div>
|
|
<SyntaxHighlighter
|
|
language={language || 'plaintext'}
|
|
style={vscDarkPlus}
|
|
customStyle={{
|
|
margin: 0,
|
|
borderTopLeftRadius: 0,
|
|
borderTopRightRadius: 0,
|
|
borderBottomLeftRadius: '0.5rem',
|
|
borderBottomRightRadius: '0.5rem',
|
|
}}
|
|
showLineNumbers={value.split('\n').length > 3}
|
|
>
|
|
{value}
|
|
</SyntaxHighlighter>
|
|
</div>
|
|
)
|
|
}
|