TypeScript 97.4%
SQL 1%
JavaScript 0.9%
CSS 0.6%
1"use client";2import * as React from "react";3import { Check, Copy } from "lucide-react";4import { cn } from "@/lib/utils";5import { Button } from "./button";67export function Skeleton({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {8 return <div className={cn("shimmer rounded-md", className)} {...props} />;9}1011export function Card({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {12 return <div className={cn("rounded-xl border border-border bg-bg-elevated", className)} {...props} />;13}1415export function CardHeader({ title, description, action, className }: { title: React.ReactNode; description?: React.ReactNode; action?: React.ReactNode; className?: string }) {16 return (17 <div className={cn("flex items-start justify-between gap-4 px-5 pt-5 pb-3", className)}>18 <div className="min-w-0">19 <h3 className="text-[15px] font-semibold leading-6 tracking-tight">{title}</h3>20 {description ? <p className="mt-0.5 text-[13px] text-fg-muted">{description}</p> : null}21 </div>22 {action}23 </div>24 );25}2627export function CardBody({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) {28 return <div className={cn("px-5 pb-5", className)} {...props} />;29}3031export function Divider({ className }: { className?: string }) {32 return <hr className={cn("border-border", className)} />;33}3435export function EmptyState({ icon, title, description, action, className }: { icon?: React.ReactNode; title: string; description?: string; action?: React.ReactNode; className?: string }) {36 return (37 <div className={cn("flex flex-col items-center justify-center rounded-xl border border-dashed border-border px-6 py-12 text-center", className)}>38 {icon ? <div className="mb-3 flex size-10 items-center justify-center rounded-lg bg-bg-muted text-fg-muted [&_svg]:size-5">{icon}</div> : null}39 <p className="text-sm font-medium">{title}</p>40 {description ? <p className="mt-1 max-w-sm text-[13px] text-fg-muted">{description}</p> : null}41 {action ? <div className="mt-4">{action}</div> : null}42 </div>43 );44}4546export function CopyButton({ value, className, size = "icon-sm", label = "Copy" }: { value: string; className?: string; size?: "icon-sm" | "icon" | "xs" | "sm"; label?: string }) {47 const [copied, setCopied] = React.useState(false);48 return (49 <Button50 variant="ghost"51 size={size}52 className={className}53 aria-label={label}54 onClick={async () => {55 try {56 await navigator.clipboard.writeText(value);57 setCopied(true);58 setTimeout(() => setCopied(false), 1400);59 } catch {60 /* ignore */61 }62 }}63 >64 {copied ? <Check className="text-success" /> : <Copy />}65 {size === "xs" || size === "sm" ? <span>{copied ? "Copied" : label}</span> : null}66 </Button>67 );68}6970export function PageHeader({ title, description, actions, className }: { title: React.ReactNode; description?: React.ReactNode; actions?: React.ReactNode; className?: string }) {71 return (72 <div className={cn("flex flex-col gap-3 sm:flex-row sm:items-end sm:justify-between", className)}>73 <div className="min-w-0">74 <h1 className="text-xl font-semibold tracking-tight sm:text-2xl">{title}</h1>75 {description ? <p className="mt-1 text-sm text-fg-muted">{description}</p> : null}76 </div>77 {actions ? <div className="flex shrink-0 items-center gap-2">{actions}</div> : null}78 </div>79 );80}8182export function Stat({ label, value, hint, className }: { label: string; value: React.ReactNode; hint?: React.ReactNode; className?: string }) {83 return (84 <div className={cn("rounded-xl border border-border bg-bg-elevated px-4 py-3.5", className)}>85 <p className="text-[12px] font-medium text-fg-muted">{label}</p>86 <p className="mt-1 text-xl font-semibold tabular-nums tracking-tight">{value}</p>87 {hint ? <p className="mt-0.5 text-xs text-fg-subtle">{hint}</p> : null}88 </div>89 );90}9192export function Kbd({ children, className }: { children: React.ReactNode; className?: string }) {93 return <kbd className={cn("kbd", className)}>{children}</kbd>;94}9596export function Spinner({ className }: { className?: string }) {97 return (98 <svg className={cn("size-4 animate-spin text-fg-muted", className)} viewBox="0 0 24 24" fill="none" aria-hidden>99 <circle cx="12" cy="12" r="9" stroke="currentColor" strokeOpacity="0.25" strokeWidth="3" />100 <path d="M21 12a9 9 0 0 0-9-9" stroke="currentColor" strokeWidth="3" strokeLinecap="round" />101 </svg>102 );103}104105/** Marks a control whose feature is not implemented yet. Never ship a silent placeholder button. */106export function ComingSoon({ className }: { className?: string }) {107 return <span className={cn("inline-flex items-center rounded-full border border-dashed border-border-strong px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide text-fg-subtle", className)}>Coming soon</span>;108}109