Files
2026-07-13 12:49:11 +08:00

110 lines
2.8 KiB
Markdown

# Component Patterns
## Card Structure
Standard grouping pattern: `Card > CardHeader + CardContent`.
```tsx
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
<Card>
<CardHeader>
<CardTitle className="text-sm font-medium">Section Title</CardTitle>
</CardHeader>
<CardContent>
{/* content */}
</CardContent>
</Card>
```
## KPI / Stat Cards — Use py-0
Stat grid cards use `py-0` so vertical rhythm is controlled by the parent grid, not the card itself.
```tsx
// CORRECT
<Card className="relative overflow-hidden">
<CardContent className="px-4 py-0">
<div className="absolute top-0 left-0 h-full w-1 bg-emerald-500" />
<p className="text-muted-foreground text-sm">Active Agents</p>
<p className="mt-1 text-2xl font-bold text-emerald-700">4</p>
</CardContent>
</Card>
// WRONG — default py-6 causes excessive padding in stat grids
<Card>
<CardContent className="p-4">
```
## Sidebar Navigation
Width: `w-64` (256px). Background: `bg-muted/30`. Right border: `border-r`.
```tsx
<aside className="bg-muted/30 flex h-full w-64 flex-col border-r">
<div className="flex items-center gap-2.5 border-b px-5 py-4">
<div className="flex h-8 w-8 items-center justify-center rounded-lg bg-orange-600">
<Bot className="h-4 w-4 text-white" />
</div>
<span className="text-sm font-semibold">App Name</span>
</div>
<nav className="flex-1 space-y-0.5 p-3">
{NAV_ITEMS.map((item) => (
<button
key={item.label}
className={`flex w-full items-center gap-3 rounded-md px-3 py-2 text-sm font-medium transition-colors ${
item.active
? "bg-background text-foreground shadow-sm"
: "text-muted-foreground hover:bg-background/60 hover:text-foreground"
}`}
>
<item.icon className="h-4 w-4" />
{item.label}
</button>
))}
</nav>
</aside>
```
## ScrollArea for Overflow
Any list that can overflow must use `ScrollArea` (not `overflow-y-auto` directly).
```tsx
import { ScrollArea } from "@/components/ui/scroll-area"
<ScrollArea className="flex-1">
<div className="space-y-2 p-4">
{items.map((item) => <Item key={item.id} {...item} />)}
</div>
</ScrollArea>
```
## Status Badge with Dot
```tsx
<div className="inline-flex items-center gap-1.5 rounded-full border px-2 py-0.5 text-xs font-medium bg-emerald-50 text-emerald-700 border-emerald-200">
<span className="h-1.5 w-1.5 rounded-full bg-emerald-500" />
Active
</div>
```
## Avatar Fallback Colors
Use orange tones for user/agent avatars:
```tsx
<AvatarFallback className="bg-orange-100 text-xs font-semibold text-orange-700">
JD
</AvatarFallback>
```
## Action Buttons in Tables
Small ghost buttons for row actions:
```tsx
<Button variant="ghost" size="sm" className="h-6 px-2 text-xs">
<Eye className="mr-1 h-3 w-3" />
View
</Button>
```