paperclip / ui /src /pages /DesignGuide.tsx
cjovs's picture
Deploy Paperclip CN to Hugging Face Space
96e86e5
Raw
History Blame Contribute Delete
59.2 kB
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { formatDate } from "../lib/utils";
import {
BookOpen,
Bot,
Check,
ChevronDown,
CircleDot,
Command as CommandIcon,
DollarSign,
Hexagon,
History,
Inbox,
LayoutDashboard,
ListTodo,
Mail,
Plus,
Search,
Settings,
Target,
Trash2,
Upload,
User,
Zap,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import { Checkbox } from "@/components/ui/checkbox";
import { Label } from "@/components/ui/label";
import { Separator } from "@/components/ui/separator";
import { Skeleton } from "@/components/ui/skeleton";
import { Tabs, TabsList, TabsTrigger, TabsContent } from "@/components/ui/tabs";
import {
Card,
CardHeader,
CardTitle,
CardDescription,
CardContent,
CardFooter,
} from "@/components/ui/card";
import {
Dialog,
DialogTrigger,
DialogContent,
DialogHeader,
DialogTitle,
DialogDescription,
DialogFooter,
} from "@/components/ui/dialog";
import {
Tooltip,
TooltipTrigger,
TooltipContent,
} from "@/components/ui/tooltip";
import {
Select,
SelectTrigger,
SelectValue,
SelectContent,
SelectItem,
} from "@/components/ui/select";
import {
DropdownMenu,
DropdownMenuTrigger,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuCheckboxItem,
DropdownMenuShortcut,
} from "@/components/ui/dropdown-menu";
import {
Popover,
PopoverTrigger,
PopoverContent,
} from "@/components/ui/popover";
import {
Sheet,
SheetTrigger,
SheetContent,
SheetHeader,
SheetTitle,
SheetDescription,
SheetFooter,
} from "@/components/ui/sheet";
import {
Collapsible,
CollapsibleTrigger,
CollapsibleContent,
} from "@/components/ui/collapsible";
import { ScrollArea } from "@/components/ui/scroll-area";
import {
Command,
CommandInput,
CommandList,
CommandGroup,
CommandItem,
CommandEmpty,
CommandSeparator,
} from "@/components/ui/command";
import {
Breadcrumb,
BreadcrumbItem,
BreadcrumbLink,
BreadcrumbList,
BreadcrumbPage,
BreadcrumbSeparator,
} from "@/components/ui/breadcrumb";
import {
Avatar,
AvatarFallback,
AvatarGroup,
AvatarGroupCount,
} from "@/components/ui/avatar";
import { StatusBadge } from "@/components/StatusBadge";
import { StatusIcon } from "@/components/StatusIcon";
import { PriorityIcon } from "@/components/PriorityIcon";
import { agentStatusDot, agentStatusDotDefault } from "@/lib/status-colors";
import { EntityRow } from "@/components/EntityRow";
import { EmptyState } from "@/components/EmptyState";
import { MetricCard } from "@/components/MetricCard";
import { FilterBar, type FilterValue } from "@/components/FilterBar";
import { InlineEditor } from "@/components/InlineEditor";
import { PageSkeleton } from "@/components/PageSkeleton";
import { Identity } from "@/components/Identity";
import { IssueReferencePill } from "@/components/IssueReferencePill";
/* ------------------------------------------------------------------ */
/* Section wrapper */
/* ------------------------------------------------------------------ */
function Section({ title, children }: { title: string; children: React.ReactNode }) {
return (
<section className="space-y-4">
<h3 className="text-sm font-semibold text-muted-foreground uppercase tracking-wide">
{title}
</h3>
<Separator />
{children}
</section>
);
}
function SubSection({ title, children }: { title: string; children: React.ReactNode }) {
return (
<div className="space-y-3">
<h4 className="text-sm font-medium">{title}</h4>
{children}
</div>
);
}
/* ------------------------------------------------------------------ */
/* Color swatch */
/* ------------------------------------------------------------------ */
function Swatch({ name, cssVar }: { name: string; cssVar: string }) {
return (
<div className="flex items-center gap-3">
<div
className="h-8 w-8 rounded-md border border-border shrink-0"
style={{ backgroundColor: `var(${cssVar})` }}
/>
<div>
<p className="text-xs font-mono">{cssVar}</p>
<p className="text-xs text-muted-foreground">{name}</p>
</div>
</div>
);
}
/* ------------------------------------------------------------------ */
/* Page */
/* ------------------------------------------------------------------ */
export function DesignGuide() {
const { t } = useTranslation();
const td = (value: string, options?: Record<string, string | number>) =>
t(value, { defaultValue: value, ...(options ?? {}) });
const [status, setStatus] = useState("todo");
const [priority, setPriority] = useState("medium");
const [selectValue, setSelectValue] = useState("in_progress");
const [menuChecked, setMenuChecked] = useState(true);
const [collapsibleOpen, setCollapsibleOpen] = useState(false);
const [inlineText, setInlineText] = useState(() => td("Click to edit this text"));
const [inlineTitle, setInlineTitle] = useState(() => td("Editable Title"));
const [inlineDesc, setInlineDesc] = useState(
() =>
td(
"This is an editable description. Click to edit it so the textarea can auto-size without causing layout shift.",
)
);
const [filters, setFilters] = useState<FilterValue[]>([
{ key: "status", label: td("Status"), value: td("Active") },
{ key: "priority", label: td("Priority"), value: td("High") },
]);
return (
<div className="space-y-10 max-w-4xl">
{/* Page header */}
<div>
<h2 className="text-xl font-bold">{td("Design Guide")}</h2>
<p className="text-sm text-muted-foreground mt-1">
{td("A reference for the components, styles, and interaction patterns used across Paperclip CN.")}
</p>
</div>
{/* ============================================================ */}
{/* COVERAGE */}
{/* ============================================================ */}
<Section title={td("Component Coverage")}>
<p className="text-sm text-muted-foreground">
{td("Update this page whenever new UI primitives or app-level patterns ship.")}
</p>
<div className="grid gap-6 md:grid-cols-2">
<SubSection title={td("UI primitives")}>
<div className="flex flex-wrap gap-2" data-e2e-ignore-i18n="true">
{[
"avatar", "badge", "breadcrumb", "button", "card", "checkbox", "collapsible",
"command", "dialog", "dropdown-menu", "input", "label", "popover", "scroll-area",
"select", "separator", "sheet", "skeleton", "tabs", "textarea", "tooltip",
].map((name) => (
<Badge key={name} variant="outline" className="font-mono text-[10px]">
{name}
</Badge>
))}
</div>
</SubSection>
<SubSection title={td("App components")}>
<div className="flex flex-wrap gap-2" data-e2e-ignore-i18n="true">
{[
"StatusBadge", "StatusIcon", "PriorityIcon", "EntityRow", "EmptyState", "MetricCard",
"FilterBar", "InlineEditor", "PageSkeleton", "Identity", "CommentThread", "MarkdownEditor",
"PropertiesPanel", "Sidebar", "CommandPalette",
].map((name) => (
<Badge key={name} variant="ghost" className="font-mono text-[10px]">
{name}
</Badge>
))}
</div>
</SubSection>
</div>
</Section>
{/* ============================================================ */}
{/* COLORS */}
{/* ============================================================ */}
<Section title={td("Colors")}>
<SubSection title={td("Core")}>
<div className="grid grid-cols-2 md:grid-cols-3 gap-4">
<Swatch name={td("Background")} cssVar="--background" />
<Swatch name={td("Foreground")} cssVar="--foreground" />
<Swatch name={td("Card")} cssVar="--card" />
<Swatch name={td("Primary")} cssVar="--primary" />
<Swatch name={td("Primary foreground")} cssVar="--primary-foreground" />
<Swatch name={td("Secondary")} cssVar="--secondary" />
<Swatch name={td("Muted")} cssVar="--muted" />
<Swatch name={td("Muted foreground")} cssVar="--muted-foreground" />
<Swatch name={td("Accent")} cssVar="--accent" />
<Swatch name={td("Destructive")} cssVar="--destructive" />
<Swatch name={td("Border")} cssVar="--border" />
<Swatch name={td("Ring")} cssVar="--ring" />
</div>
</SubSection>
<SubSection title={td("Sidebar")}>
<div className="grid grid-cols-2 md:grid-cols-3 gap-4">
<Swatch name={td("Sidebar")} cssVar="--sidebar" />
<Swatch name={td("Sidebar border")} cssVar="--sidebar-border" />
</div>
</SubSection>
<SubSection title={td("Chart")}>
<div className="grid grid-cols-2 md:grid-cols-3 gap-4">
<Swatch name={td("Chart 1")} cssVar="--chart-1" />
<Swatch name={td("Chart 2")} cssVar="--chart-2" />
<Swatch name={td("Chart 3")} cssVar="--chart-3" />
<Swatch name={td("Chart 4")} cssVar="--chart-4" />
<Swatch name={td("Chart 5")} cssVar="--chart-5" />
</div>
</SubSection>
</Section>
{/* ============================================================ */}
{/* TYPOGRAPHY */}
{/* ============================================================ */}
<Section title={td("Typography")}>
<div className="space-y-3">
<h2 className="text-xl font-bold">{td("Page title example")}</h2>
<h2 className="text-lg font-semibold">{td("Section title example")}</h2>
<h3 className="text-sm font-semibold text-muted-foreground uppercase tracking-wide">
{td("Section heading example")}
</h3>
<p className="text-sm font-medium">{td("Card title example")}</p>
<p className="text-sm font-semibold">{td("Alternative card title example")}</p>
<p className="text-sm">{td("Body text example")}</p>
<p className="text-sm text-muted-foreground">
{td("Muted description example")}
</p>
<p className="text-xs text-muted-foreground">
{td("Tiny label example")}
</p>
<p className="text-sm font-mono text-muted-foreground">
{td("Mono identifier example")}
</p>
<p className="text-2xl font-bold">{td("Large stat example")}</p>
<p className="font-mono text-xs">{td("Log/code text example")}</p>
</div>
</Section>
{/* ============================================================ */}
{/* SPACING & RADIUS */}
{/* ============================================================ */}
<Section title={td("Radius")}>
<div className="flex items-end gap-4 flex-wrap">
{[
["sm", "var(--radius-sm)"],
["md", "var(--radius-md)"],
["lg", "var(--radius-lg)"],
["xl", "var(--radius-xl)"],
["full", "9999px"],
].map(([label, radius]) => (
<div key={label} className="flex flex-col items-center gap-1">
<div
className="h-12 w-12 bg-primary"
style={{ borderRadius: radius }}
/>
<span className="text-xs text-muted-foreground">{label}</span>
</div>
))}
</div>
</Section>
{/* ============================================================ */}
{/* BUTTONS */}
{/* ============================================================ */}
<Section title={td("Buttons")}>
<SubSection title={td("Variants")}>
<div className="flex items-center gap-2 flex-wrap">
<Button variant="default">{td("Default")}</Button>
<Button variant="secondary">{td("Secondary")}</Button>
<Button variant="outline">{td("Outline")}</Button>
<Button variant="ghost">{td("Ghost")}</Button>
<Button variant="destructive">{td("Destructive")}</Button>
<Button variant="link">{td("Link")}</Button>
</div>
</SubSection>
<SubSection title={td("Sizes")}>
<div className="flex items-center gap-2 flex-wrap">
<Button size="xs">{td("Extra Small")}</Button>
<Button size="sm">{td("Small")}</Button>
<Button size="default">{td("Default")}</Button>
<Button size="lg">{td("Large")}</Button>
</div>
</SubSection>
<SubSection title={td("Icon buttons")}>
<div className="flex items-center gap-2 flex-wrap">
<Button variant="ghost" size="icon-xs"><Search /></Button>
<Button variant="ghost" size="icon-sm"><Search /></Button>
<Button variant="outline" size="icon"><Search /></Button>
<Button variant="outline" size="icon-lg"><Search /></Button>
</div>
</SubSection>
<SubSection title={td("With icons")}>
<div className="flex items-center gap-2 flex-wrap">
<Button><Plus /> {td("New Issue")}</Button>
<Button variant="outline"><Upload /> {td("Upload")}</Button>
<Button variant="destructive"><Trash2 /> {td("Delete")}</Button>
<Button size="sm"><Plus /> {td("Add")}</Button>
</div>
</SubSection>
<SubSection title={td("States")}>
<div className="flex items-center gap-2 flex-wrap">
<Button disabled>{td("Disabled")}</Button>
<Button variant="outline" disabled>{td("Disabled Outline")}</Button>
</div>
</SubSection>
</Section>
{/* ============================================================ */}
{/* BADGES */}
{/* ============================================================ */}
<Section title={td("Badges")}>
<SubSection title={td("Variants")}>
<div className="flex items-center gap-2 flex-wrap">
<Badge variant="default">{td("Default")}</Badge>
<Badge variant="secondary">{td("Secondary")}</Badge>
<Badge variant="outline">{td("Outline")}</Badge>
<Badge variant="destructive">{td("Destructive")}</Badge>
<Badge variant="ghost">{td("Ghost")}</Badge>
</div>
</SubSection>
</Section>
{/* ============================================================ */}
{/* STATUS BADGES & ICONS */}
{/* ============================================================ */}
<Section title={td("Status System")}>
<SubSection title={td("StatusBadge (all statuses)")}>
<div className="flex items-center gap-2 flex-wrap">
{[
"active", "running", "paused", "idle", "archived", "planned",
"achieved", "completed", "failed", "timed_out", "succeeded", "error",
"pending_approval", "backlog", "todo", "in_progress", "in_review", "blocked",
"done", "terminated", "cancelled", "pending", "revision_requested",
"approved", "rejected",
].map((s) => (
<StatusBadge key={s} status={s} />
))}
</div>
</SubSection>
<SubSection title={td("StatusIcon (interactive)")}>
<div className="flex items-center gap-3 flex-wrap">
{["backlog", "todo", "in_progress", "in_review", "done", "cancelled", "blocked"].map(
(s) => (
<div key={s} className="flex items-center gap-1.5">
<StatusIcon status={s} />
<span className="text-xs text-muted-foreground">{s}</span>
</div>
)
)}
</div>
<div className="flex items-center gap-2 mt-2">
<StatusIcon status={status} onChange={setStatus} />
<span className="text-sm">
{td("Click the icon to change status (current: {{status}})", { status })}
</span>
</div>
</SubSection>
<SubSection title={td("PriorityIcon (interactive)")}>
<div className="flex items-center gap-3 flex-wrap">
{["critical", "high", "medium", "low"].map((p) => (
<div key={p} className="flex items-center gap-1.5">
<PriorityIcon priority={p} />
<span className="text-xs text-muted-foreground">{p}</span>
</div>
))}
</div>
<div className="flex items-center gap-2 mt-2">
<PriorityIcon priority={priority} onChange={setPriority} />
<span className="text-sm">
{td("Click the icon to change (current: {{priority}})", { priority })}
</span>
</div>
</SubSection>
<SubSection title={td("Agent status dots")}>
<div className="flex items-center gap-4 flex-wrap" data-e2e-ignore-i18n="true">
{(["running", "active", "paused", "error", "archived"] as const).map((label) => (
<div key={label} className="flex items-center gap-2">
<span className="relative flex h-2.5 w-2.5">
<span className={`inline-flex h-full w-full rounded-full ${agentStatusDot[label] ?? agentStatusDotDefault}`} />
</span>
<span className="text-xs text-muted-foreground">{label}</span>
</div>
))}
</div>
</SubSection>
<SubSection title={td("Run invocation badges")}>
<div className="flex items-center gap-2 flex-wrap" data-e2e-ignore-i18n="true">
{[
["timer", "bg-blue-100 text-blue-700 dark:bg-blue-900/50 dark:text-blue-300"],
["assignment", "bg-violet-100 text-violet-700 dark:bg-violet-900/50 dark:text-violet-300"],
["on_demand", "bg-cyan-100 text-cyan-700 dark:bg-cyan-900/50 dark:text-cyan-300"],
["automation", "bg-muted text-muted-foreground"],
].map(([label, cls]) => (
<span key={label} className={`rounded-full px-1.5 py-0.5 text-[10px] font-medium ${cls}`}>
{label}
</span>
))}
</div>
</SubSection>
<SubSection title="IssueReferencePill">
<p className="text-xs text-muted-foreground">
Used wherever a task is referenced — in markdown, the Related Work tab, and activity summaries.
Pass <code className="font-mono">status</code> to show the target issue&apos;s state at a glance.
Use <code className="font-mono">strikethrough</code> for &quot;removed&quot; contexts.
</p>
<div className="flex items-center gap-2 flex-wrap">
<IssueReferencePill issue={{ id: "demo-1", identifier: "PAP-123", title: "Identifier onlyno status yet" }} />
<IssueReferencePill issue={{ id: "demo-2", identifier: "PAP-456", title: "With in_progress status", status: "in_progress" }} />
<IssueReferencePill issue={{ id: "demo-3", identifier: "PAP-789", title: "Done status", status: "done" }} />
<IssueReferencePill issue={{ id: "demo-4", identifier: "PAP-101", title: "Blocked status", status: "blocked" }} />
<IssueReferencePill strikethrough issue={{ id: "demo-5", identifier: "PAP-202", title: "Removed (strikethrough)", status: "todo" }} />
</div>
</SubSection>
</Section>
{/* ============================================================ */}
{/* FORM ELEMENTS */}
{/* ============================================================ */}
<Section title={td("Form Elements")}>
<div className="grid gap-6 md:grid-cols-2">
<SubSection title={td("Input")}>
<Input placeholder={td("Default input")} />
<Input placeholder={td("Disabled input")} disabled className="mt-2" />
</SubSection>
<SubSection title={td("Textarea")}>
<Textarea placeholder={td("Write something...")} />
</SubSection>
<SubSection title={td("Checkbox & Label")}>
<div className="space-y-3">
<div className="flex items-center gap-2">
<Checkbox id="check1" defaultChecked />
<Label htmlFor="check1">{td("Checked item")}</Label>
</div>
<div className="flex items-center gap-2">
<Checkbox id="check2" />
<Label htmlFor="check2">{td("Unchecked item")}</Label>
</div>
<div className="flex items-center gap-2">
<Checkbox id="check3" disabled />
<Label htmlFor="check3">{td("Disabled item")}</Label>
</div>
</div>
</SubSection>
<SubSection title={td("Inline Editor")}>
<div className="space-y-4">
<div>
<p className="text-xs text-muted-foreground mb-1">{td("Title (single-line)")}</p>
<InlineEditor
value={inlineTitle}
onSave={setInlineTitle}
as="h2"
className="text-xl font-bold"
/>
</div>
<div>
<p className="text-xs text-muted-foreground mb-1">{td("Body text (single-line)")}</p>
<InlineEditor
value={inlineText}
onSave={setInlineText}
as="p"
className="text-sm"
/>
</div>
<div>
<p className="text-xs text-muted-foreground mb-1">{td("Description (multiline, auto-sizing)")}</p>
<InlineEditor
value={inlineDesc}
onSave={setInlineDesc}
as="p"
className="text-sm text-muted-foreground"
placeholder={td("Add a description...")}
multiline
/>
</div>
</div>
</SubSection>
</div>
</Section>
{/* ============================================================ */}
{/* SELECT */}
{/* ============================================================ */}
<Section title={td("Select")}>
<div className="grid gap-6 md:grid-cols-2">
<SubSection title={td("Default size")}>
<Select value={selectValue} onValueChange={setSelectValue}>
<SelectTrigger className="w-full">
<SelectValue placeholder={td("Select status")} />
</SelectTrigger>
<SelectContent>
<SelectItem value="backlog">{td("Backlog")}</SelectItem>
<SelectItem value="todo">{td("Todo")}</SelectItem>
<SelectItem value="in_progress">{td("In Progress")}</SelectItem>
<SelectItem value="in_review">{td("In Review")}</SelectItem>
<SelectItem value="done">{td("Done")}</SelectItem>
</SelectContent>
</Select>
<p className="text-xs text-muted-foreground">{td("Current value: {{value}}", { value: selectValue })}</p>
</SubSection>
<SubSection title={td("Small trigger")}>
<Select defaultValue="high">
<SelectTrigger size="sm" className="w-full">
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="critical">{td("Critical")}</SelectItem>
<SelectItem value="high">{td("High")}</SelectItem>
<SelectItem value="medium">{td("Medium")}</SelectItem>
<SelectItem value="low">{td("Low")}</SelectItem>
</SelectContent>
</Select>
</SubSection>
</div>
</Section>
{/* ============================================================ */}
{/* DROPDOWN MENU */}
{/* ============================================================ */}
<Section title={td("Dropdown Menu")}>
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" size="sm">
{td("Quick Actions")}
<ChevronDown className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="start" className="w-56">
<DropdownMenuItem>
<Check className="h-4 w-4" />
{td("Mark as done")}
<DropdownMenuShortcut>⌘D</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuItem>
<BookOpen className="h-4 w-4" />
{td("Open docs")}
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuCheckboxItem
checked={menuChecked}
onCheckedChange={(value) => setMenuChecked(value === true)}
>
{td("Watch issue")}
</DropdownMenuCheckboxItem>
<DropdownMenuItem variant="destructive">
<Trash2 className="h-4 w-4" />
{td("Delete issue")}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</Section>
{/* ============================================================ */}
{/* POPOVER */}
{/* ============================================================ */}
<Section title={td("Popover")}>
<Popover>
<PopoverTrigger asChild>
<Button variant="outline" size="sm">{td("Open Popover")}</Button>
</PopoverTrigger>
<PopoverContent className="space-y-2">
<p className="text-sm font-medium">{td("Agent heartbeat")}</p>
<p className="text-xs text-muted-foreground">
{td("Last run succeeded 24s ago. Next timer run in 9m.")}
</p>
<Button size="xs">{td("Wake now")}</Button>
</PopoverContent>
</Popover>
</Section>
{/* ============================================================ */}
{/* COLLAPSIBLE */}
{/* ============================================================ */}
<Section title={td("Collapsible")}>
<Collapsible open={collapsibleOpen} onOpenChange={setCollapsibleOpen} className="space-y-2">
<CollapsibleTrigger asChild>
<Button variant="outline" size="sm">
{collapsibleOpen ? td("Hide") : td("Show")} {td("advanced filters")}
</Button>
</CollapsibleTrigger>
<CollapsibleContent className="rounded-md border border-border p-3">
<div className="space-y-2">
<Label htmlFor="owner-filter">{td("Owner")}</Label>
<Input id="owner-filter" placeholder={td("Filter by agent name")} />
</div>
</CollapsibleContent>
</Collapsible>
</Section>
{/* ============================================================ */}
{/* SHEET */}
{/* ============================================================ */}
<Section title={td("Sheet")}>
<Sheet>
<SheetTrigger asChild>
<Button variant="outline" size="sm">{td("Open Side Panel")}</Button>
</SheetTrigger>
<SheetContent side="right">
<SheetHeader>
<SheetTitle>{td("Issue Properties")}</SheetTitle>
<SheetDescription>{td("Edit metadata without leaving the current page.")}</SheetDescription>
</SheetHeader>
<div className="space-y-4 px-4">
<div className="space-y-1">
<Label htmlFor="sheet-title">{td("Title")}</Label>
<Input id="sheet-title" defaultValue={td("Improve onboarding docs")} />
</div>
<div className="space-y-1">
<Label htmlFor="sheet-description">{td("Description")}</Label>
<Textarea id="sheet-description" defaultValue={td("Capture setup pitfalls and screenshots.")} />
</div>
</div>
<SheetFooter>
<Button variant="outline">{td("Cancel")}</Button>
<Button>{td("Save")}</Button>
</SheetFooter>
</SheetContent>
</Sheet>
</Section>
{/* ============================================================ */}
{/* SCROLL AREA */}
{/* ============================================================ */}
<Section title={td("Scroll Area")}>
<ScrollArea className="h-36 rounded-md border border-border">
<div className="space-y-2 p-3">
{Array.from({ length: 12 }).map((_, i) => (
<div key={i} className="rounded-md border border-border p-2 text-sm">
{td("Heartbeat run #{{index}}: completed successfully", { index: i + 1 })}
</div>
))}
</div>
</ScrollArea>
</Section>
{/* ============================================================ */}
{/* COMMAND */}
{/* ============================================================ */}
<Section title={td("Command (CMDK)")}>
<div className="rounded-md border border-border">
<Command>
<CommandInput placeholder={td("Type a command or search...")} />
<CommandList>
<CommandEmpty>{td("No results found.")}</CommandEmpty>
<CommandGroup heading={td("Pages")}>
<CommandItem>
<LayoutDashboard className="h-4 w-4" />
{td("Dashboard")}
</CommandItem>
<CommandItem>
<CircleDot className="h-4 w-4" />
{td("Issues")}
</CommandItem>
</CommandGroup>
<CommandSeparator />
<CommandGroup heading={td("Actions")}>
<CommandItem>
<CommandIcon className="h-4 w-4" />
{td("Open command palette")}
</CommandItem>
<CommandItem>
<Plus className="h-4 w-4" />
{td("Create new issue")}
</CommandItem>
</CommandGroup>
</CommandList>
</Command>
</div>
</Section>
{/* ============================================================ */}
{/* BREADCRUMB */}
{/* ============================================================ */}
<Section title={td("Breadcrumb")}>
<Breadcrumb>
<BreadcrumbList>
<BreadcrumbItem>
<BreadcrumbLink href="#">{td("Projects")}</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbLink href="#">{td("Paperclip CN App")}</BreadcrumbLink>
</BreadcrumbItem>
<BreadcrumbSeparator />
<BreadcrumbItem>
<BreadcrumbPage>{td("Issue List")}</BreadcrumbPage>
</BreadcrumbItem>
</BreadcrumbList>
</Breadcrumb>
</Section>
{/* ============================================================ */}
{/* CARDS */}
{/* ============================================================ */}
<Section title={td("Cards")}>
<SubSection title={td("Standard Card")}>
<Card>
<CardHeader>
<CardTitle>{td("Card Title")}</CardTitle>
<CardDescription>{td("Card description with supporting text.")}</CardDescription>
</CardHeader>
<CardContent>
<p className="text-sm">{td("Card content goes here. This is the main body area.")}</p>
</CardContent>
<CardFooter className="gap-2">
<Button size="sm">{td("Action")}</Button>
<Button variant="outline" size="sm">{td("Cancel")}</Button>
</CardFooter>
</Card>
</SubSection>
<SubSection title={td("Metric Cards")}>
<div className="grid md:grid-cols-2 xl:grid-cols-4 gap-4">
<MetricCard icon={Bot} value={12} label={td("Active Agents")} description={td("+3 this week")} />
<MetricCard icon={CircleDot} value={48} label={td("Open Issues")} />
<MetricCard icon={DollarSign} value="$1,234" label={td("Monthly Cost")} description={td("Under budget")} />
<MetricCard icon={Zap} value="99.9%" label={td("Uptime")} />
</div>
</SubSection>
</Section>
{/* ============================================================ */}
{/* TABS */}
{/* ============================================================ */}
<Section title={td("Tabs")}>
<SubSection title={td("Default (pill) variant")}>
<Tabs defaultValue="overview">
<TabsList>
<TabsTrigger value="overview">{td("Overview")}</TabsTrigger>
<TabsTrigger value="runs">{td("Runs")}</TabsTrigger>
<TabsTrigger value="config">{td("Config")}</TabsTrigger>
<TabsTrigger value="costs">{td("Costs")}</TabsTrigger>
</TabsList>
<TabsContent value="overview">
<p className="text-sm text-muted-foreground py-4">{td("Overview tab content.")}</p>
</TabsContent>
<TabsContent value="runs">
<p className="text-sm text-muted-foreground py-4">{td("Runs tab content.")}</p>
</TabsContent>
<TabsContent value="config">
<p className="text-sm text-muted-foreground py-4">{td("Config tab content.")}</p>
</TabsContent>
<TabsContent value="costs">
<p className="text-sm text-muted-foreground py-4">{td("Costs tab content.")}</p>
</TabsContent>
</Tabs>
</SubSection>
<SubSection title={td("Line variant")}>
<Tabs defaultValue="summary">
<TabsList variant="line">
<TabsTrigger value="summary">{td("Summary")}</TabsTrigger>
<TabsTrigger value="details">{td("Details")}</TabsTrigger>
<TabsTrigger value="comments">{td("Comments")}</TabsTrigger>
</TabsList>
<TabsContent value="summary">
<p className="text-sm text-muted-foreground py-4">{td("Summary content with underline tabs.")}</p>
</TabsContent>
<TabsContent value="details">
<p className="text-sm text-muted-foreground py-4">{td("Details content.")}</p>
</TabsContent>
<TabsContent value="comments">
<p className="text-sm text-muted-foreground py-4">{td("Comments content.")}</p>
</TabsContent>
</Tabs>
</SubSection>
</Section>
{/* ============================================================ */}
{/* ENTITY ROWS */}
{/* ============================================================ */}
<Section title={td("Entity Rows")}>
<div className="border border-border rounded-md">
<EntityRow
leading={
<>
<StatusIcon status="in_progress" />
<PriorityIcon priority="high" />
</>
}
identifier="PAP-001"
title={td("Implement authentication flow")}
subtitle={td("Assigned to Agent Alpha")}
trailing={<StatusBadge status="in_progress" />}
onClick={() => {}}
/>
<EntityRow
leading={
<>
<StatusIcon status="done" />
<PriorityIcon priority="medium" />
</>
}
identifier="PAP-002"
title={td("Set up CI/CD pipeline")}
subtitle={td("Completed 2 days ago")}
trailing={<StatusBadge status="done" />}
onClick={() => {}}
/>
<EntityRow
leading={
<>
<StatusIcon status="todo" />
<PriorityIcon priority="low" />
</>
}
identifier="PAP-003"
title={td("Write API documentation")}
trailing={<StatusBadge status="todo" />}
onClick={() => {}}
/>
<EntityRow
leading={
<>
<StatusIcon status="blocked" />
<PriorityIcon priority="critical" />
</>
}
identifier="PAP-004"
title={td("Deploy to production")}
subtitle={td("Blocked by PAP-001")}
trailing={<StatusBadge status="blocked" />}
selected
/>
</div>
</Section>
{/* ============================================================ */}
{/* FILTER BAR */}
{/* ============================================================ */}
<Section title={td("Filter Bar")}>
<FilterBar
filters={filters}
onRemove={(key) => setFilters((f) => f.filter((x) => x.key !== key))}
onClear={() => setFilters([])}
/>
{filters.length === 0 && (
<Button
variant="outline"
size="sm"
onClick={() =>
setFilters([
{ key: "status", label: "Status", value: "Active" },
{ key: "priority", label: td("Priority"), value: td("High") },
])
}
>
{td("Reset filters")}
</Button>
)}
</Section>
{/* ============================================================ */}
{/* AVATARS */}
{/* ============================================================ */}
<Section title={td("Avatars")}>
<SubSection title={td("Sizes")}>
<div className="flex items-center gap-3">
<Avatar size="sm"><AvatarFallback>SM</AvatarFallback></Avatar>
<Avatar><AvatarFallback>DF</AvatarFallback></Avatar>
<Avatar size="lg"><AvatarFallback>LG</AvatarFallback></Avatar>
</div>
</SubSection>
<SubSection title={td("Group")}>
<AvatarGroup>
<Avatar><AvatarFallback>A1</AvatarFallback></Avatar>
<Avatar><AvatarFallback>A2</AvatarFallback></Avatar>
<Avatar><AvatarFallback>A3</AvatarFallback></Avatar>
<AvatarGroupCount>+5</AvatarGroupCount>
</AvatarGroup>
</SubSection>
</Section>
{/* ============================================================ */}
{/* IDENTITY */}
{/* ============================================================ */}
<Section title={td("Identity")}>
<SubSection title={td("Sizes")}>
<div className="flex items-center gap-6" data-e2e-ignore-i18n="true">
<Identity name="Agent Alpha" size="sm" />
<Identity name="Agent Alpha" />
<Identity name="Agent Alpha" size="lg" />
</div>
</SubSection>
<SubSection title={td("Initials derivation")}>
<div className="flex flex-col gap-2" data-e2e-ignore-i18n="true">
<Identity name="CEO Agent" size="sm" />
<Identity name="Alpha" size="sm" />
<Identity name="Quality Assurance Lead" size="sm" />
</div>
</SubSection>
<SubSection title={td("Custom initials")}>
<div data-e2e-ignore-i18n="true">
<Identity name="Backend Service" initials="BS" size="sm" />
</div>
</SubSection>
</Section>
{/* ============================================================ */}
{/* TOOLTIPS */}
{/* ============================================================ */}
<Section title={td("Tooltips")}>
<div className="flex items-center gap-4">
<Tooltip>
<TooltipTrigger asChild>
<Button variant="outline" size="sm">{td("Hover me")}</Button>
</TooltipTrigger>
<TooltipContent>{td("This is a tooltip")}</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<Button variant="ghost" size="icon-sm"><Settings /></Button>
</TooltipTrigger>
<TooltipContent>{td("Settings")}</TooltipContent>
</Tooltip>
</div>
</Section>
{/* ============================================================ */}
{/* DIALOG */}
{/* ============================================================ */}
<Section title={td("Dialog")}>
<Dialog>
<DialogTrigger asChild>
<Button variant="outline">{td("Open Dialog")}</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>{td("Dialog Title")}</DialogTitle>
<DialogDescription>
{td("This is a sample dialog showing the standard layout with header, content, and footer.")}
</DialogDescription>
</DialogHeader>
<div className="space-y-3">
<div>
<Label>{td("Name")}</Label>
<Input placeholder={td("Enter a name")} className="mt-1.5" />
</div>
<div>
<Label>{td("Description")}</Label>
<Textarea placeholder={td("Describe...")} className="mt-1.5" />
</div>
</div>
<DialogFooter>
<Button variant="outline">{td("Cancel")}</Button>
<Button>{td("Save")}</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</Section>
{/* ============================================================ */}
{/* EMPTY STATE */}
{/* ============================================================ */}
<Section title={td("Empty State")}>
<div className="border border-border rounded-md">
<EmptyState
icon={Inbox}
message={td("No items to show. Create your first one to get started.")}
action={td("Create Item")}
onAction={() => {}}
/>
</div>
</Section>
{/* ============================================================ */}
{/* PROGRESS BARS */}
{/* ============================================================ */}
<Section title={td("Progress Bars (Budget)")}>
<div className="space-y-3">
{[
{ label: td("Under budget (40%)"), pct: 40, color: "bg-green-400" },
{ label: td("Warning (75%)"), pct: 75, color: "bg-yellow-400" },
{ label: td("Over budget (95%)"), pct: 95, color: "bg-red-400" },
].map(({ label, pct, color }) => (
<div key={label} className="space-y-1">
<div className="flex items-center justify-between">
<span className="text-xs text-muted-foreground">{label}</span>
<span className="text-xs font-mono">{pct}%</span>
</div>
<div className="w-full h-2 bg-muted rounded-full overflow-hidden">
<div
className={`h-full rounded-full transition-[width,background-color] duration-150 ${color}`}
style={{ width: `${pct}%` }}
/>
</div>
</div>
))}
</div>
</Section>
{/* ============================================================ */}
{/* LOG VIEWER */}
{/* ============================================================ */}
<Section title={td("Log Viewer")}>
<div className="bg-neutral-950 rounded-lg p-3 font-mono text-xs max-h-80 overflow-y-auto" data-e2e-ignore-i18n="true">
<div className="text-foreground">[12:00:01] INFO Agent started successfully</div>
<div className="text-foreground">[12:00:02] INFO Processing task PAP-001</div>
<div className="text-yellow-400">[12:00:05] WARN Rate limit approaching (80%)</div>
<div className="text-foreground">[12:00:08] INFO Task PAP-001 completed</div>
<div className="text-red-400">[12:00:12] ERROR Connection timeout to upstream service</div>
<div className="text-blue-300">[12:00:12] SYS Retrying connection in 5s...</div>
<div className="text-foreground">[12:00:17] INFO Reconnected successfully</div>
<div className="flex items-center gap-1.5">
<span className="relative flex h-1.5 w-1.5">
<span className="absolute inline-flex h-full w-full rounded-full bg-cyan-400 animate-pulse" />
<span className="inline-flex h-full w-full rounded-full bg-cyan-400" />
</span>
<span className="text-cyan-400">Live</span>
</div>
</div>
</Section>
{/* ============================================================ */}
{/* PROPERTY ROW PATTERN */}
{/* ============================================================ */}
<Section title={td("Property Row Pattern")}>
<div className="border border-border rounded-md p-4 space-y-1 max-w-sm">
<div className="flex items-center justify-between py-1.5">
<span className="text-xs text-muted-foreground">{td("Status")}</span>
<StatusBadge status="active" />
</div>
<div className="flex items-center justify-between py-1.5">
<span className="text-xs text-muted-foreground">{td("Priority")}</span>
<PriorityIcon priority="high" />
</div>
<div className="flex items-center justify-between py-1.5">
<span className="text-xs text-muted-foreground">{td("Assignee")}</span>
<div className="flex items-center gap-1.5">
<Avatar size="sm"><AvatarFallback>A</AvatarFallback></Avatar>
<span className="text-xs">Agent Alpha</span>
</div>
</div>
<div className="flex items-center justify-between py-1.5">
<span className="text-xs text-muted-foreground">{td("Created")}</span>
<span className="text-xs">{formatDate("2025-01-15")}</span>
</div>
</div>
</Section>
{/* ============================================================ */}
{/* NAVIGATION PATTERNS */}
{/* ============================================================ */}
<Section title={td("Navigation Patterns")}>
<SubSection title={td("Sidebar nav items")}>
<div className="w-60 border border-border rounded-md p-3 space-y-0.5 bg-card">
<div className="flex items-center gap-2 px-3 py-1.5 rounded-md text-sm font-medium bg-accent text-accent-foreground">
<LayoutDashboard className="h-4 w-4" />
{td("Dashboard")}
</div>
<div className="flex items-center gap-2 px-3 py-1.5 rounded-md text-sm font-medium text-muted-foreground hover:bg-accent/50 hover:text-accent-foreground cursor-pointer">
<CircleDot className="h-4 w-4" />
{td("Issues")}
<span className="ml-auto text-xs bg-primary text-primary-foreground rounded-full px-1.5 py-0.5">
12
</span>
</div>
<div className="flex items-center gap-2 px-3 py-1.5 rounded-md text-sm font-medium text-muted-foreground hover:bg-accent/50 hover:text-accent-foreground cursor-pointer">
<Bot className="h-4 w-4" />
{td("Agents")}
</div>
<div className="flex items-center gap-2 px-3 py-1.5 rounded-md text-sm font-medium text-muted-foreground hover:bg-accent/50 hover:text-accent-foreground cursor-pointer">
<Hexagon className="h-4 w-4" />
{td("Projects")}
</div>
</div>
</SubSection>
<SubSection title={td("View toggle")}>
<div className="flex items-center border border-border rounded-md w-fit">
<button className="px-3 py-1.5 text-xs font-medium bg-accent text-foreground rounded-l-md">
<ListTodo className="h-3.5 w-3.5 inline mr-1" />
{td("List")}
</button>
<button className="px-3 py-1.5 text-xs font-medium text-muted-foreground hover:bg-accent/50 rounded-r-md">
<Target className="h-3.5 w-3.5 inline mr-1" />
{td("Org")}
</button>
</div>
</SubSection>
</Section>
{/* ============================================================ */}
{/* GROUPED LIST (Issues pattern) */}
{/* ============================================================ */}
<Section title={td("Grouped List (Issues pattern)")}>
<div>
<div className="flex items-center gap-2 px-4 py-2 bg-muted/50 rounded-t-md">
<StatusIcon status="in_progress" />
<span className="text-sm font-medium">{td("In Progress")}</span>
<span className="text-xs text-muted-foreground ml-1">2</span>
</div>
<div className="border border-border rounded-b-md">
<EntityRow
leading={<PriorityIcon priority="high" />}
identifier="PAP-101"
title={td("Build agent heartbeat system")}
onClick={() => {}}
/>
<EntityRow
leading={<PriorityIcon priority="medium" />}
identifier="PAP-102"
title={td("Add cost tracking dashboard")}
onClick={() => {}}
/>
</div>
</div>
</Section>
{/* ============================================================ */}
{/* COMMENT THREAD PATTERN */}
{/* ============================================================ */}
<Section title={td("Comment Thread Pattern")}>
<div className="space-y-3 max-w-2xl">
<h3 className="text-sm font-semibold">{td("Comments (2)")}</h3>
<div className="space-y-3">
<div className="rounded-md border border-border p-3">
<div className="flex items-center justify-between mb-1">
<span className="text-xs font-medium text-muted-foreground">{td("Agent")}</span>
<span className="text-xs text-muted-foreground">{formatDate("2025-01-15")}</span>
</div>
<p className="text-sm">{td("Started working on the authentication module. Will need API keys configured.")}</p>
</div>
<div className="rounded-md border border-border p-3">
<div className="flex items-center justify-between mb-1">
<span className="text-xs font-medium text-muted-foreground">{td("Human")}</span>
<span className="text-xs text-muted-foreground">{formatDate("2025-01-16")}</span>
</div>
<p className="text-sm">{td("API keys have been added to the vault. Please proceed.")}</p>
</div>
</div>
<div className="space-y-2">
<Textarea placeholder={td("Leave a comment...")} rows={3} />
<Button size="sm">{td("Comment")}</Button>
</div>
</div>
</Section>
{/* ============================================================ */}
{/* COST TABLE PATTERN */}
{/* ============================================================ */}
<Section title={td("Cost Table Pattern")}>
<div className="border border-border rounded-lg overflow-hidden">
<table className="w-full text-xs">
<thead className="border-b border-border bg-accent/20">
<tr>
<th className="text-left px-3 py-2 font-medium text-muted-foreground">{td("Model")}</th>
<th className="text-left px-3 py-2 font-medium text-muted-foreground">{td("Tokens")}</th>
<th className="text-left px-3 py-2 font-medium text-muted-foreground">{td("Cost")}</th>
</tr>
</thead>
<tbody>
<tr className="border-b border-border">
<td className="px-3 py-2">claude-sonnet-4-20250514</td>
<td className="px-3 py-2 font-mono">1.2M</td>
<td className="px-3 py-2 font-mono">$18.00</td>
</tr>
<tr className="border-b border-border">
<td className="px-3 py-2">claude-haiku-4-20250506</td>
<td className="px-3 py-2 font-mono">500k</td>
<td className="px-3 py-2 font-mono">$1.25</td>
</tr>
<tr>
<td className="px-3 py-2 font-medium">{td("Total")}</td>
<td className="px-3 py-2 font-mono">1.7M</td>
<td className="px-3 py-2 font-mono font-medium">$19.25</td>
</tr>
</tbody>
</table>
</div>
</Section>
{/* ============================================================ */}
{/* SKELETONS */}
{/* ============================================================ */}
<Section title={td("Skeletons")}>
<SubSection title={td("Individual")}>
<div className="space-y-2">
<Skeleton className="h-4 w-48" />
<Skeleton className="h-8 w-full max-w-sm" />
<Skeleton className="h-20 w-full" />
</div>
</SubSection>
<SubSection title={td("Page Skeleton (list)")}>
<div className="border border-border rounded-md p-4">
<PageSkeleton variant="list" />
</div>
</SubSection>
<SubSection title={td("Page Skeleton (detail)")}>
<div className="border border-border rounded-md p-4">
<PageSkeleton variant="detail" />
</div>
</SubSection>
</Section>
{/* ============================================================ */}
{/* SEPARATOR */}
{/* ============================================================ */}
<Section title={td("Separator")}>
<div className="space-y-4">
<p className="text-sm text-muted-foreground">{td("Horizontal")}</p>
<Separator />
<div className="flex items-center gap-4 h-8">
<span className="text-sm">{td("Left")}</span>
<Separator orientation="vertical" />
<span className="text-sm">{td("Right")}</span>
</div>
</div>
</Section>
{/* ============================================================ */}
{/* ICON REFERENCE */}
{/* ============================================================ */}
<Section title={td("Common Icons (Lucide)")}>
<div className="grid grid-cols-4 md:grid-cols-6 gap-4" data-e2e-ignore-i18n="true">
{[
["Inbox", Inbox],
["ListTodo", ListTodo],
["CircleDot", CircleDot],
["Hexagon", Hexagon],
["Target", Target],
["LayoutDashboard", LayoutDashboard],
["Bot", Bot],
["DollarSign", DollarSign],
["History", History],
["Search", Search],
["Plus", Plus],
["Trash2", Trash2],
["Settings", Settings],
["User", User],
["Mail", Mail],
["Upload", Upload],
["Zap", Zap],
].map(([name, Icon]) => {
const LucideIcon = Icon as React.FC<{ className?: string }>;
return (
<div key={name as string} className="flex flex-col items-center gap-1.5 p-2">
<LucideIcon className="h-4 w-4 text-muted-foreground" />
<span className="text-[10px] text-muted-foreground font-mono">{name as string}</span>
</div>
);
})}
</div>
</Section>
{/* ============================================================ */}
{/* KEYBOARD SHORTCUTS */}
{/* ============================================================ */}
<Section title={td("Keyboard Shortcuts")}>
<div className="border border-border rounded-md divide-y divide-border text-sm">
{[
["Cmd+K / Ctrl+K", td("Open Command Palette")],
["C", td("New Issue (outside inputs)")],
["[", td("Toggle Sidebar")],
["]", td("Toggle Properties Panel")],
["Cmd+Enter / Ctrl+Enter", td("Submit markdown comment")],
].map(([key, desc]) => (
<div key={key} className="flex items-center justify-between px-4 py-2">
<span className="text-muted-foreground">{desc}</span>
<kbd className="px-2 py-0.5 text-xs font-mono bg-muted rounded border border-border">
{key}
</kbd>
</div>
))}
</div>
</Section>
</div>
);
}