Liquid Glass for the web: the rim refraction, light and motion of iOS 27 glass on any rounded element. React bindings and pill tabs. MIT.
| 5 | export function useCopy() { |
| 6 | const [copied, setCopied] = React.useState(false); |
| 7 | const timer = React.useRef(0); |
| 8 | React.useEffect(() => () => window.clearTimeout(timer.current), []); |
| 9 | return { |
| 10 | copied, |
| 11 | copy: (text: string) => { |
| 12 | void navigator.clipboard?.writeText(text).then(() => { |
| 13 | setCopied(true); |
| 14 | window.clearTimeout(timer.current); |
| 15 | timer.current = window.setTimeout(() => setCopied(false), 1400); |
| 16 | }); |
| 17 | }, |
| 18 | }; |
| 19 | } |
| 20 |
| 21 | export function CopyButton({ text, label = "Copy", className }: { text: string; label?: string; className?: string }) { |
| 22 | const { copied, copy } = useCopy(); |
| 23 | return ( |
| 24 | <Button variant="ghost" size="xs" className={className} onClick={() => copy(text)} aria-live="polite"> |
| 25 | {copied ? <IconCheck className="size-3.5" /> : <IconCopy className="size-3.5" />} |
| 26 | {copied ? "Copied" : label} |
| 27 | </Button> |
| 28 | ); |
| 29 | } |
| 30 |
| 31 | /** Code, monochrome, with a copy button. */ |
| 32 | export function CodeBlock({ code, className, title, wrap = false }: { code: string; className?: string; title?: string; wrap?: boolean }) { |
| 33 | return ( |
| 34 | <div className={cn("overflow-hidden rounded-xl border border-border bg-muted/40", className)}> |
| 35 | <div className="flex items-center justify-between gap-2 border-b border-border px-3 py-1.5"> |
| 36 | <span className="truncate text-xs text-muted-foreground">{title ?? ""}</span> |
| 37 | <CopyButton text={code} /> |
| 38 | </div> |
| 39 | <pre className={cn("overflow-x-auto p-4 text-[13px] leading-relaxed", wrap && "whitespace-pre-wrap")}> |
| 40 | <code className="font-mono">{code}</code> |
| 41 | </pre> |
| 42 | </div> |
| 43 | ); |
| 44 | } |
| 45 |
| 46 | /** The install command, one click to copy. */ |
| 47 | export function InstallCommand({ command, className }: { command: string; className?: string }) { |
| 48 | const { copied, copy } = useCopy(); |
| 49 | return ( |
| 50 | <Button variant="outline" size="lg" className={className} onClick={() => copy(command)} aria-label={`Copy ${command}`}> |
| 51 | <code className="font-mono">{command}</code> |
| 52 | {copied ? <IconCheck className="size-4" /> : <IconCopy className="size-4" />} |
| 53 | </Button> |
| 54 | ); |
| 55 | } |
| 56 |