Perplexica/ui/components/Markdown/renderer/inner/CopyButton.tsx

70 lines
1.8 KiB
TypeScript
Raw Normal View History

2024-07-10 16:17:23 +08:00
import { css, cx } from "@emotion/css";
import { Copy as CopyIcon, ClipboardPaste as CopiedIcon } from "lucide-react";
import copy from "copy-to-clipboard";
import React from "react";
export enum CopyStatus {
PENDING = 0,
COPYING = 1,
COPIED = 2,
FAILED = 3,
}
2024-07-10 16:36:37 +08:00
export interface ICopyButtonProperties {
2024-07-10 16:17:23 +08:00
delay?: number;
className?: string;
calcContentForCopy: () => string;
}
2024-07-10 16:36:37 +08:00
export const CopyButton: React.FC<ICopyButtonProperties> = properties => {
const { className, delay = 1500, calcContentForCopy } = properties;
2024-07-10 16:17:23 +08:00
const [status, setStatus] = React.useState<CopyStatus>(CopyStatus.PENDING);
const disabled: boolean = status !== CopyStatus.PENDING;
const onCopy = () => {
if (status === CopyStatus.PENDING) {
setStatus(CopyStatus.COPYING);
try {
const contentForCopy: string = calcContentForCopy();
copy(contentForCopy);
setStatus(CopyStatus.COPIED);
2024-07-10 16:36:37 +08:00
} catch {
2024-07-10 16:17:23 +08:00
setStatus(CopyStatus.FAILED);
}
}
};
React.useEffect((): (() => void) | undefined => {
if (status === CopyStatus.COPIED || status === CopyStatus.FAILED) {
const timer = setTimeout(() => setStatus(CopyStatus.PENDING), delay);
return () => {
if (timer) {
clearTimeout(timer);
}
};
}
return undefined;
}, [status, delay]);
return (
<button
className={cx(
classes.copyButton,
className,
"bg-[#24A0ED] text-white disabled:text-black/50 dark:disabled:text-white/50 hover:bg-opacity-85 transition duration-100 disabled:bg-[#e0e0dc79] dark:disabled:bg-[#ececec21] rounded-full p-2",
)}
disabled={disabled}
onClick={onCopy}
>
status === CopyStatus.PENDING ? <CopyIcon size={24} /> : <CopiedIcon size={24} />
</button>
);
};
const classes = {
copyButton: css({
cursor: "pointer",
}),
};