Files
2026-07-13 12:28:53 +08:00

83 lines
2.9 KiB
TypeScript

'use client';
import posthog from 'posthog-js';
import { useState } from 'react';
export function CopyCommand({ command, size = 'lg' }: { command: string; size?: 'lg' | 'md' }) {
const [copied, setCopied] = useState(false);
const onCopy = async () => {
try {
await navigator.clipboard.writeText(command);
setCopied(true);
setTimeout(() => setCopied(false), 1500);
posthog.capture('command_copied', { command });
} catch {
/* ignore */
}
};
const height = size === 'lg' ? 'h-[48px] sm:h-[52px]' : 'h-10';
const pad = size === 'lg' ? 'px-4 sm:px-5' : 'px-4';
const text = size === 'lg' ? 'text-[13px] sm:text-[15px]' : 'text-[13px]';
return (
<button
type="button"
onClick={onCopy}
style={{
boxShadow:
'0 0 0 1px color-mix(in oklab, var(--color-accent) 15%, transparent), 0 20px 80px -20px color-mix(in oklab, var(--color-accent) 35%, transparent)',
}}
className={`group relative inline-flex items-center gap-3 ${height} ${pad} rounded-[6px] border border-[color:var(--color-accent)]/40 bg-[color:var(--color-panel)] text-[color:var(--color-text)] font-[family-name:var(--font-mono)] ${text} hover:border-[color:var(--color-accent)] transition`}
>
<span aria-hidden className="text-[color:var(--color-accent)]">
$
</span>
<span className="tracking-[-0.01em]">{command}</span>
<span
aria-hidden
className="ml-1 inline-flex items-center gap-1.5 text-[color:var(--color-muted)] group-hover:text-[color:var(--color-accent)] transition-colors"
>
<span className="h-4 w-px bg-[color:var(--color-rule)]" />
<span className="relative inline-flex h-[14px] w-[14px] items-center justify-center">
<CopyGlyph
className={`absolute inset-0 transition-opacity duration-200 ${copied ? 'opacity-0' : 'opacity-100'}`}
/>
<CheckGlyph
className={`absolute inset-0 text-[color:var(--color-mint)] transition-opacity duration-200 ${copied ? 'opacity-100' : 'opacity-0'}`}
/>
</span>
</span>
</button>
);
}
function CopyGlyph({ className }: { className?: string }) {
return (
<svg aria-hidden width="14" height="14" viewBox="0 0 24 24" fill="none" className={className}>
<rect x="7" y="7" width="12" height="13" rx="2" stroke="currentColor" strokeWidth="1.5" />
<path
d="M5 15H4a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v1"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
/>
</svg>
);
}
function CheckGlyph({ className }: { className?: string }) {
return (
<svg aria-hidden width="14" height="14" viewBox="0 0 24 24" fill="none" className={className}>
<path
d="M5 12.5 10 17.5 19 7.5"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
}