1
0

install-command.tsx 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
  1. 'use client';
  2. import { useState } from 'react';
  3. import { Check, Copy } from 'lucide-react';
  4. import { cn } from '@/lib/cn';
  5. export function InstallCommand({
  6. command,
  7. className,
  8. copyLabel = 'Copy install command',
  9. copiedLabel = 'Copied',
  10. }: {
  11. command: string;
  12. className?: string;
  13. copyLabel?: string;
  14. copiedLabel?: string;
  15. }) {
  16. const [copied, setCopied] = useState(false);
  17. async function copy() {
  18. try {
  19. await navigator.clipboard.writeText(command);
  20. setCopied(true);
  21. setTimeout(() => setCopied(false), 2000);
  22. } catch {
  23. // Clipboard unavailable (insecure context) — silently ignore.
  24. }
  25. }
  26. return (
  27. <div
  28. className={cn(
  29. 'flex items-center gap-3 rounded-xl border bg-fd-card py-2.5 pe-2 ps-4 text-sm shadow-sm',
  30. className,
  31. )}
  32. >
  33. <span className="select-none font-mono text-fd-muted-foreground">$</span>
  34. {/* Commands are always LTR, even on RTL pages. */}
  35. <code dir="ltr" className="flex-1 overflow-x-auto whitespace-nowrap text-start font-mono">
  36. {command}
  37. </code>
  38. <button
  39. type="button"
  40. onClick={copy}
  41. aria-label={copied ? copiedLabel : copyLabel}
  42. className="inline-flex size-8 shrink-0 items-center justify-center rounded-lg text-fd-muted-foreground transition-colors hover:bg-fd-accent hover:text-fd-accent-foreground focus-visible:outline-2 focus-visible:outline-fd-ring"
  43. >
  44. {copied ? (
  45. <Check className="size-4 text-brand" aria-hidden />
  46. ) : (
  47. <Copy className="size-4" aria-hidden />
  48. )}
  49. </button>
  50. </div>
  51. );
  52. }