Files
joelhooks__joelclaw/apps/web/components/copy-button.tsx
2026-02-27 14:55:43 -08:00

76 lines
1.8 KiB
TypeScript

"use client";
import { useCallback, useState } from "react";
export function CopyButton({ text }: { text: string }) {
const [copied, setCopied] = useState(false);
const copy = useCallback(() => {
navigator.clipboard.writeText(text).then(() => {
setCopied(true);
setTimeout(() => setCopied(false), 2000);
});
}, [text]);
return (
<button
onClick={copy}
className="shrink-0 text-neutral-600 hover:text-neutral-400 transition-colors cursor-pointer"
aria-label="Copy to clipboard"
title="Copy to clipboard"
>
{copied ? (
<svg
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<polyline points="20 6 9 17 4 12" />
</svg>
) : (
<svg
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<rect x="9" y="9" width="13" height="13" rx="2" ry="2" />
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" />
</svg>
)}
</button>
);
}
export function CodeBlock({
children,
className,
}: {
children: string;
className?: string;
}) {
return (
<pre
className={`flex items-center gap-3 text-xs text-neutral-400 bg-neutral-900/50 border border-neutral-800 rounded-lg px-3 py-2 overflow-x-auto ${className ?? ""}`}
>
<code className="flex-1 min-w-0">{children}</code>
<CopyButton text={children.trim()} />
</pre>
);
}
export function CodeBlockCopyButton({ text }: { text: string }) {
return (
<CopyButton text={text.trim()} />
);
}