feat(ui): expand design guide with new component sections
Add Select, Dropdown Menu, Popover, Collapsible, Sheet, Scroll Area, Command (CMDK), and Breadcrumb sections. Update status badge list and keyboard shortcuts reference. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,11 @@
|
|||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import {
|
import {
|
||||||
|
BookOpen,
|
||||||
Bot,
|
Bot,
|
||||||
|
Check,
|
||||||
|
ChevronDown,
|
||||||
CircleDot,
|
CircleDot,
|
||||||
|
Command as CommandIcon,
|
||||||
DollarSign,
|
DollarSign,
|
||||||
Hexagon,
|
Hexagon,
|
||||||
History,
|
History,
|
||||||
@@ -49,6 +53,54 @@ import {
|
|||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
TooltipContent,
|
TooltipContent,
|
||||||
} from "@/components/ui/tooltip";
|
} 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 {
|
||||||
|
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 {
|
import {
|
||||||
Avatar,
|
Avatar,
|
||||||
AvatarFallback,
|
AvatarFallback,
|
||||||
@@ -117,6 +169,9 @@ function Swatch({ name, cssVar }: { name: string; cssVar: string }) {
|
|||||||
export function DesignGuide() {
|
export function DesignGuide() {
|
||||||
const [status, setStatus] = useState("todo");
|
const [status, setStatus] = useState("todo");
|
||||||
const [priority, setPriority] = useState("medium");
|
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("Click to edit this text");
|
const [inlineText, setInlineText] = useState("Click to edit this text");
|
||||||
const [inlineTitle, setInlineTitle] = useState("Editable Title");
|
const [inlineTitle, setInlineTitle] = useState("Editable Title");
|
||||||
const [inlineDesc, setInlineDesc] = useState(
|
const [inlineDesc, setInlineDesc] = useState(
|
||||||
@@ -137,6 +192,43 @@ export function DesignGuide() {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* ============================================================ */}
|
||||||
|
{/* COVERAGE */}
|
||||||
|
{/* ============================================================ */}
|
||||||
|
<Section title="Component Coverage">
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
This page should be updated when new UI primitives or app-level patterns ship.
|
||||||
|
</p>
|
||||||
|
<div className="grid gap-6 md:grid-cols-2">
|
||||||
|
<SubSection title="UI primitives">
|
||||||
|
<div className="flex flex-wrap gap-2">
|
||||||
|
{[
|
||||||
|
"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="App components">
|
||||||
|
<div className="flex flex-wrap gap-2">
|
||||||
|
{[
|
||||||
|
"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 */}
|
{/* COLORS */}
|
||||||
{/* ============================================================ */}
|
{/* ============================================================ */}
|
||||||
@@ -299,9 +391,10 @@ export function DesignGuide() {
|
|||||||
<div className="flex items-center gap-2 flex-wrap">
|
<div className="flex items-center gap-2 flex-wrap">
|
||||||
{[
|
{[
|
||||||
"active", "running", "paused", "idle", "archived", "planned",
|
"active", "running", "paused", "idle", "archived", "planned",
|
||||||
"achieved", "completed", "failed", "succeeded", "error", "backlog",
|
"achieved", "completed", "failed", "timed_out", "succeeded", "error",
|
||||||
"todo", "in_progress", "in_review", "blocked", "done",
|
"pending_approval", "backlog", "todo", "in_progress", "in_review", "blocked",
|
||||||
"cancelled", "pending", "approved", "rejected",
|
"done", "terminated", "cancelled", "pending", "revision_requested",
|
||||||
|
"approved", "rejected",
|
||||||
].map((s) => (
|
].map((s) => (
|
||||||
<StatusBadge key={s} status={s} />
|
<StatusBadge key={s} status={s} />
|
||||||
))}
|
))}
|
||||||
@@ -365,7 +458,7 @@ export function DesignGuide() {
|
|||||||
["timer", "bg-blue-900/50 text-blue-300"],
|
["timer", "bg-blue-900/50 text-blue-300"],
|
||||||
["assignment", "bg-violet-900/50 text-violet-300"],
|
["assignment", "bg-violet-900/50 text-violet-300"],
|
||||||
["on_demand", "bg-cyan-900/50 text-cyan-300"],
|
["on_demand", "bg-cyan-900/50 text-cyan-300"],
|
||||||
["webhook", "bg-neutral-800 text-neutral-400"],
|
["automation", "bg-neutral-800 text-neutral-400"],
|
||||||
].map(([label, cls]) => (
|
].map(([label, cls]) => (
|
||||||
<span key={label} className={`rounded-full px-1.5 py-0.5 text-[10px] font-medium ${cls}`}>
|
<span key={label} className={`rounded-full px-1.5 py-0.5 text-[10px] font-medium ${cls}`}>
|
||||||
{label}
|
{label}
|
||||||
@@ -442,6 +535,217 @@ export function DesignGuide() {
|
|||||||
</div>
|
</div>
|
||||||
</Section>
|
</Section>
|
||||||
|
|
||||||
|
{/* ============================================================ */}
|
||||||
|
{/* SELECT */}
|
||||||
|
{/* ============================================================ */}
|
||||||
|
<Section title="Select">
|
||||||
|
<div className="grid gap-6 md:grid-cols-2">
|
||||||
|
<SubSection title="Default size">
|
||||||
|
<Select value={selectValue} onValueChange={setSelectValue}>
|
||||||
|
<SelectTrigger className="w-full">
|
||||||
|
<SelectValue placeholder="Select status" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="backlog">Backlog</SelectItem>
|
||||||
|
<SelectItem value="todo">Todo</SelectItem>
|
||||||
|
<SelectItem value="in_progress">In Progress</SelectItem>
|
||||||
|
<SelectItem value="in_review">In Review</SelectItem>
|
||||||
|
<SelectItem value="done">Done</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
<p className="text-xs text-muted-foreground">Current value: {selectValue}</p>
|
||||||
|
</SubSection>
|
||||||
|
<SubSection title="Small trigger">
|
||||||
|
<Select defaultValue="high">
|
||||||
|
<SelectTrigger size="sm" className="w-full">
|
||||||
|
<SelectValue />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="critical">Critical</SelectItem>
|
||||||
|
<SelectItem value="high">High</SelectItem>
|
||||||
|
<SelectItem value="medium">Medium</SelectItem>
|
||||||
|
<SelectItem value="low">Low</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</SubSection>
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* ============================================================ */}
|
||||||
|
{/* DROPDOWN MENU */}
|
||||||
|
{/* ============================================================ */}
|
||||||
|
<Section title="Dropdown Menu">
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger asChild>
|
||||||
|
<Button variant="outline" size="sm">
|
||||||
|
Quick Actions
|
||||||
|
<ChevronDown className="h-4 w-4" />
|
||||||
|
</Button>
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent align="start" className="w-56">
|
||||||
|
<DropdownMenuItem>
|
||||||
|
<Check className="h-4 w-4" />
|
||||||
|
Mark as done
|
||||||
|
<DropdownMenuShortcut>⌘D</DropdownMenuShortcut>
|
||||||
|
</DropdownMenuItem>
|
||||||
|
<DropdownMenuItem>
|
||||||
|
<BookOpen className="h-4 w-4" />
|
||||||
|
Open docs
|
||||||
|
</DropdownMenuItem>
|
||||||
|
<DropdownMenuSeparator />
|
||||||
|
<DropdownMenuCheckboxItem
|
||||||
|
checked={menuChecked}
|
||||||
|
onCheckedChange={(value) => setMenuChecked(value === true)}
|
||||||
|
>
|
||||||
|
Watch issue
|
||||||
|
</DropdownMenuCheckboxItem>
|
||||||
|
<DropdownMenuItem variant="destructive">
|
||||||
|
<Trash2 className="h-4 w-4" />
|
||||||
|
Delete issue
|
||||||
|
</DropdownMenuItem>
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* ============================================================ */}
|
||||||
|
{/* POPOVER */}
|
||||||
|
{/* ============================================================ */}
|
||||||
|
<Section title="Popover">
|
||||||
|
<Popover>
|
||||||
|
<PopoverTrigger asChild>
|
||||||
|
<Button variant="outline" size="sm">Open Popover</Button>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent className="space-y-2">
|
||||||
|
<p className="text-sm font-medium">Agent heartbeat</p>
|
||||||
|
<p className="text-xs text-muted-foreground">
|
||||||
|
Last run succeeded 24s ago. Next timer run in 9m.
|
||||||
|
</p>
|
||||||
|
<Button size="xs">Wake now</Button>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* ============================================================ */}
|
||||||
|
{/* COLLAPSIBLE */}
|
||||||
|
{/* ============================================================ */}
|
||||||
|
<Section title="Collapsible">
|
||||||
|
<Collapsible open={collapsibleOpen} onOpenChange={setCollapsibleOpen} className="space-y-2">
|
||||||
|
<CollapsibleTrigger asChild>
|
||||||
|
<Button variant="outline" size="sm">
|
||||||
|
{collapsibleOpen ? "Hide" : "Show"} advanced filters
|
||||||
|
</Button>
|
||||||
|
</CollapsibleTrigger>
|
||||||
|
<CollapsibleContent className="rounded-md border border-border p-3">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label htmlFor="owner-filter">Owner</Label>
|
||||||
|
<Input id="owner-filter" placeholder="Filter by agent name" />
|
||||||
|
</div>
|
||||||
|
</CollapsibleContent>
|
||||||
|
</Collapsible>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* ============================================================ */}
|
||||||
|
{/* SHEET */}
|
||||||
|
{/* ============================================================ */}
|
||||||
|
<Section title="Sheet">
|
||||||
|
<Sheet>
|
||||||
|
<SheetTrigger asChild>
|
||||||
|
<Button variant="outline" size="sm">Open Side Panel</Button>
|
||||||
|
</SheetTrigger>
|
||||||
|
<SheetContent side="right">
|
||||||
|
<SheetHeader>
|
||||||
|
<SheetTitle>Issue Properties</SheetTitle>
|
||||||
|
<SheetDescription>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">Title</Label>
|
||||||
|
<Input id="sheet-title" defaultValue="Improve onboarding docs" />
|
||||||
|
</div>
|
||||||
|
<div className="space-y-1">
|
||||||
|
<Label htmlFor="sheet-description">Description</Label>
|
||||||
|
<Textarea id="sheet-description" defaultValue="Capture setup pitfalls and screenshots." />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<SheetFooter>
|
||||||
|
<Button variant="outline">Cancel</Button>
|
||||||
|
<Button>Save</Button>
|
||||||
|
</SheetFooter>
|
||||||
|
</SheetContent>
|
||||||
|
</Sheet>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* ============================================================ */}
|
||||||
|
{/* SCROLL AREA */}
|
||||||
|
{/* ============================================================ */}
|
||||||
|
<Section title="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">
|
||||||
|
Heartbeat run #{i + 1}: completed successfully
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</ScrollArea>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* ============================================================ */}
|
||||||
|
{/* COMMAND */}
|
||||||
|
{/* ============================================================ */}
|
||||||
|
<Section title="Command (CMDK)">
|
||||||
|
<div className="rounded-md border border-border">
|
||||||
|
<Command>
|
||||||
|
<CommandInput placeholder="Type a command or search..." />
|
||||||
|
<CommandList>
|
||||||
|
<CommandEmpty>No results found.</CommandEmpty>
|
||||||
|
<CommandGroup heading="Pages">
|
||||||
|
<CommandItem>
|
||||||
|
<LayoutDashboard className="h-4 w-4" />
|
||||||
|
Dashboard
|
||||||
|
</CommandItem>
|
||||||
|
<CommandItem>
|
||||||
|
<CircleDot className="h-4 w-4" />
|
||||||
|
Issues
|
||||||
|
</CommandItem>
|
||||||
|
</CommandGroup>
|
||||||
|
<CommandSeparator />
|
||||||
|
<CommandGroup heading="Actions">
|
||||||
|
<CommandItem>
|
||||||
|
<CommandIcon className="h-4 w-4" />
|
||||||
|
Open command palette
|
||||||
|
</CommandItem>
|
||||||
|
<CommandItem>
|
||||||
|
<Plus className="h-4 w-4" />
|
||||||
|
Create new issue
|
||||||
|
</CommandItem>
|
||||||
|
</CommandGroup>
|
||||||
|
</CommandList>
|
||||||
|
</Command>
|
||||||
|
</div>
|
||||||
|
</Section>
|
||||||
|
|
||||||
|
{/* ============================================================ */}
|
||||||
|
{/* BREADCRUMB */}
|
||||||
|
{/* ============================================================ */}
|
||||||
|
<Section title="Breadcrumb">
|
||||||
|
<Breadcrumb>
|
||||||
|
<BreadcrumbList>
|
||||||
|
<BreadcrumbItem>
|
||||||
|
<BreadcrumbLink href="#">Projects</BreadcrumbLink>
|
||||||
|
</BreadcrumbItem>
|
||||||
|
<BreadcrumbSeparator />
|
||||||
|
<BreadcrumbItem>
|
||||||
|
<BreadcrumbLink href="#">Paperclip App</BreadcrumbLink>
|
||||||
|
</BreadcrumbItem>
|
||||||
|
<BreadcrumbSeparator />
|
||||||
|
<BreadcrumbItem>
|
||||||
|
<BreadcrumbPage>Issue List</BreadcrumbPage>
|
||||||
|
</BreadcrumbItem>
|
||||||
|
</BreadcrumbList>
|
||||||
|
</Breadcrumb>
|
||||||
|
</Section>
|
||||||
|
|
||||||
{/* ============================================================ */}
|
{/* ============================================================ */}
|
||||||
{/* CARDS */}
|
{/* CARDS */}
|
||||||
{/* ============================================================ */}
|
{/* ============================================================ */}
|
||||||
@@ -1009,7 +1313,8 @@ export function DesignGuide() {
|
|||||||
["C", "New Issue (outside inputs)"],
|
["C", "New Issue (outside inputs)"],
|
||||||
["[", "Toggle Sidebar"],
|
["[", "Toggle Sidebar"],
|
||||||
["]", "Toggle Properties Panel"],
|
["]", "Toggle Properties Panel"],
|
||||||
["Cmd+Enter", "Submit current dialog"],
|
["Cmd+1..9 / Ctrl+1..9", "Switch Company (by rail order)"],
|
||||||
|
["Cmd+Enter / Ctrl+Enter", "Submit markdown comment"],
|
||||||
].map(([key, desc]) => (
|
].map(([key, desc]) => (
|
||||||
<div key={key} className="flex items-center justify-between px-4 py-2">
|
<div key={key} className="flex items-center justify-between px-4 py-2">
|
||||||
<span className="text-muted-foreground">{desc}</span>
|
<span className="text-muted-foreground">{desc}</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user