grok2api / frontend /src /shared /components /copy-button.tsx
fromozuzhouzzz
Deploy grok2api v3.0.11 to HF Spaces
f1dd159
Raw
History Blame Contribute Delete
1.95 kB
import { Check, Copy } from "lucide-react";
import { useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
import { copyToClipboard } from "@/shared/clipboard";
import { cn } from "@/shared/lib/cn";
export function CopyButton({
value,
className,
disabled,
copyLabel,
onCopied,
onError,
}: {
value: string;
className?: string;
disabled?: boolean;
copyLabel?: string;
onCopied?: () => void;
onError?: (error: unknown) => void;
}) {
const { t } = useTranslation();
const [copiedValue, setCopiedValue] = useState<string | null>(null);
const resetTimerRef = useRef<number | null>(null);
useEffect(() => () => {
if (resetTimerRef.current !== null) window.clearTimeout(resetTimerRef.current);
}, []);
async function handleClick() {
const ok = await copyToClipboard(value);
if (ok) {
if (resetTimerRef.current !== null) window.clearTimeout(resetTimerRef.current);
setCopiedValue(value);
resetTimerRef.current = window.setTimeout(() => {
setCopiedValue(null);
resetTimerRef.current = null;
}, 1500);
onCopied?.();
} else {
const message = t("common.copyFailed");
toast.error(message);
onError?.(new Error(message));
}
}
const copied = copiedValue === value;
const label = copied ? t("common.copied") : copyLabel ?? t("common.copy");
return (
<Tooltip>
<TooltipTrigger asChild>
<Button type="button" variant="ghost" size="icon" className={cn("size-7 shrink-0 text-muted-foreground", className)} aria-label={label} disabled={disabled} onClick={handleClick}>
{copied ? <Check /> : <Copy />}
</Button>
</TooltipTrigger>
<TooltipContent>{label}</TooltipContent>
</Tooltip>
);
}