headplane/app/components/Code.tsx

51 lines
1.3 KiB
TypeScript
Raw Normal View History

2025-02-01 18:11:33 -05:00
import { Check, Copy } from 'lucide-react';
import { HTMLProps } from 'react';
2025-01-28 17:46:16 -05:00
import cn from '~/utils/cn';
2025-01-28 16:04:42 -05:00
import toast from '~/utils/toast';
2024-11-20 18:01:20 -05:00
2025-02-01 18:11:33 -05:00
export interface CodeProps extends HTMLProps<HTMLSpanElement> {
2024-12-31 10:30:14 +05:30
isCopyable?: boolean;
2025-02-01 18:11:33 -05:00
children: string | string[];
2024-11-20 18:01:20 -05:00
}
2025-02-01 18:11:33 -05:00
export default function Code({ isCopyable, children, className }: CodeProps) {
return (
2025-02-01 18:11:33 -05:00
<code
className={cn(
'bg-headplane-100 dark:bg-headplane-800 px-1 py-0.5 font-mono',
2025-05-29 09:45:47 -04:00
'rounded-lg focus-within:outline-hidden focus-within:ring-2',
2025-02-04 11:39:17 -05:00
isCopyable && 'relative pr-7',
2025-02-01 18:11:33 -05:00
className,
)}
>
2025-02-04 11:39:17 -05:00
{children}
{isCopyable && (
2024-11-20 18:01:20 -05:00
<button
2025-01-28 16:04:42 -05:00
type="button"
2025-02-04 11:39:17 -05:00
className="bottom-0 right-0 absolute"
2025-02-01 18:11:33 -05:00
onClick={async (event) => {
const text = Array.isArray(children) ? children.join('') : children;
2025-02-01 18:11:33 -05:00
const svgs = event.currentTarget.querySelectorAll('svg');
for (const svg of svgs) {
svg.toggleAttribute('data-copied', true);
}
2025-02-01 18:11:33 -05:00
await navigator.clipboard.writeText(text);
2024-12-31 10:30:14 +05:30
toast('Copied to clipboard');
2025-02-01 18:11:33 -05:00
setTimeout(() => {
for (const svg of svgs) {
svg.toggleAttribute('data-copied', false);
}
}, 1000);
2024-11-20 18:01:20 -05:00
}}
>
2025-05-29 09:45:47 -04:00
<Check className="h-4.5 w-4.5 p-1 hidden data-copied:block" />
<Copy className="h-4.5 w-4.5 p-1 block data-copied:hidden" />
2024-11-20 18:01:20 -05:00
</button>
2025-02-01 18:11:33 -05:00
)}
</code>
2024-12-31 10:30:14 +05:30
);
}