~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/pds.js

An atproto PDS in JavaScript, for Cloudflare Workers and Node

0
0
main
61 lines · 1.9 KB Raw History
import { CheckIcon, CopyIcon } from 'lucide-react';
import { useState } from 'react';
import { Button } from '#/components/atoms/button.jsx';
import { cn } from '#/lib/utils.js';

/**
 * A shell command with a copy button beside it. The command is what a reader
 * came for, so it reads in full where there is room and truncates where there
 * is not. `lines` draws several commands as one block, each on its own
 * line, and copies them joined by newlines the way a shell takes them.
 * @param {{command?: string, lines?: string[], label?: string, className?: string}} props
 */
export function CopyCommand({ command, lines, label, className }) {
  const [copied, setCopied] = useState(false);
  const text = lines ? lines.join('\n') : (command ?? '');
  const copy = async () => {
    await navigator.clipboard.writeText(text);
    setCopied(true);
    setTimeout(() => setCopied(false), 1600);
  };

  if (lines) {
    return (
      <div
        className={cn(
          'relative rounded-lg border border-border bg-muted',
          className,
        )}
      >
        <pre className="overflow-x-auto px-4 py-3 pr-14 font-mono text-[12.5px] text-foreground leading-relaxed">
          {text}
        </pre>
        <Button
          variant="outline"
          size="icon-sm"
          aria-label={label ?? 'Copy these commands'}
          onClick={copy}
          className="absolute top-2 right-2"
        >
          {copied ? <CheckIcon /> : <CopyIcon />}
        </Button>
      </div>
    );
  }

  return (
    <div className={cn('flex min-w-0 items-center gap-1.5', className)}>
      <code className="min-w-0 flex-1 truncate rounded-lg border border-border bg-muted px-2.5 py-1.5 font-mono text-[11.5px] text-muted-foreground">
        {text}
      </code>
      <Button
        variant="outline"
        size="icon-sm"
        aria-label={label ?? `Copy ${text}`}
        onClick={copy}
      >
        {copied ? <CheckIcon /> : <CopyIcon />}
      </Button>
    </div>
  );
}