44 lines
1.7 KiB
TypeScript
44 lines
1.7 KiB
TypeScript
'use client';
|
|
|
|
import { useState } from 'react';
|
|
import { Check, Copy } from 'lucide-react';
|
|
import { Button } from '@/components/ui/button';
|
|
import { cn } from '@/lib/utils';
|
|
|
|
export function CodeBlock({ code, language, title }: { code: string; language?: string; title?: string }) {
|
|
const [copied, setCopied] = useState(false);
|
|
|
|
async function copy() {
|
|
await navigator.clipboard.writeText(code);
|
|
setCopied(true);
|
|
setTimeout(() => setCopied(false), 2000);
|
|
}
|
|
|
|
return (
|
|
<div className="group relative my-4 overflow-hidden rounded-xl border border-zinc-200 dark:border-zinc-800">
|
|
{(title || language) && (
|
|
<div className="flex items-center justify-between border-b border-zinc-200 bg-zinc-50 px-4 py-2 text-xs text-zinc-500 dark:border-zinc-800 dark:bg-zinc-900">
|
|
<span>{title ?? language}</span>
|
|
<Button variant="ghost" size="sm" className="h-7 px-2 opacity-0 group-hover:opacity-100" onClick={copy}>
|
|
{copied ? <Check className="h-3.5 w-3.5" /> : <Copy className="h-3.5 w-3.5" />}
|
|
{copied ? 'Скопировано' : 'Копировать'}
|
|
</Button>
|
|
</div>
|
|
)}
|
|
<pre className={cn('overflow-x-auto bg-zinc-950 p-4 text-sm leading-relaxed text-zinc-50', !title && !language && 'rounded-xl')}>
|
|
<code>{code}</code>
|
|
</pre>
|
|
{!title && !language && (
|
|
<Button
|
|
variant="ghost"
|
|
size="sm"
|
|
className="absolute right-2 top-2 h-7 bg-zinc-900/80 px-2 text-zinc-300 opacity-0 group-hover:opacity-100"
|
|
onClick={copy}
|
|
>
|
|
{copied ? <Check className="h-3.5 w-3.5" /> : <Copy className="h-3.5 w-3.5" />}
|
|
</Button>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|