File size: 2,057 Bytes
3b6afc0 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
import React, { useRef, useState, RefObject } from 'react';
import { Clipboard, CheckMark } from '~/components';
import { InfoIcon } from 'lucide-react';
import { cn } from '~/utils/';
interface CodeBarProps {
lang: string;
codeRef: RefObject<HTMLElement>;
plugin?: boolean;
}
const CodeBar: React.FC<CodeBarProps> = React.memo(({ lang, codeRef, plugin = null }) => {
const [isCopied, setIsCopied] = useState(false);
return (
<div className="relative flex items-center rounded-tl-md rounded-tr-md bg-gray-800 px-4 py-2 font-sans text-xs text-gray-200">
<span className="">{lang}</span>
{plugin ? (
<InfoIcon className="ml-auto flex h-4 w-4 gap-2 text-white/50" />
) : (
<button
className="ml-auto flex gap-2"
onClick={async () => {
const codeString = codeRef.current?.textContent;
if (codeString) {
navigator.clipboard.writeText(codeString).then(() => {
setIsCopied(true);
setTimeout(() => setIsCopied(false), 3000);
});
}
}}
>
{isCopied ? (
<>
<CheckMark />
Copied!
</>
) : (
<>
<Clipboard />
Copy code
</>
)}
</button>
)}
</div>
);
});
interface CodeBlockProps {
lang: string;
codeChildren: string;
classProp?: string;
plugin?: boolean;
}
const CodeBlock: React.FC<CodeBlockProps> = ({
lang,
codeChildren,
classProp = '',
plugin = null,
}) => {
const codeRef = useRef<HTMLElement>(null);
const language = plugin ? 'json' : lang;
return (
<div className="rounded-md bg-black">
<CodeBar lang={lang} codeRef={codeRef} plugin={!!plugin} />
<div className={cn(classProp, 'overflow-y-auto p-4')}>
<code ref={codeRef} className={`hljs !whitespace-pre language-${language}`}>
{codeChildren}
</code>
</div>
</div>
);
};
export default CodeBlock;
|