Canonical source for all UI rules in this project. Do not duplicate these rules in CLAUDE.md or AGENTS.md.
Applies to all UI changes in:
src/components/**src/pages/**src/App.css
- Semantic color tokens in
src/App.css(:root,.dark,@theme inline) are the source of truth. - Do not hardcode raw colors in components (
#...,rgb(...),hsl(...),bg-[#...]) except ANSI stream text in terminal output. - Always use semantic classes/tokens:
bg-background,text-foregroundbg-card,text-card-foregroundborder-border,text-muted-foregroundtext-success,text-warning,text-info
- Sidebar must use dedicated tokens:
bg-sidebar,text-sidebar-foreground,border-sidebar-border,ring-sidebar-ring
- H1 (page title):
text-xl font-semibold text-foreground - H2 (section heading):
text-lg font-semibold text-foreground - H3 (card title):
font-semibold text-foregroundorfont-medium text-foreground - Body:
text-sm text-foreground - Caption/meta:
text-xs text-muted-foreground - Code/terminal:
font-mono text-sm
- Global border radius:
--radius: 0.75rem - Page padding:
p-6 - Card padding:
p-4→p-6 - Section gap:
space-y-6→space-y-8 - Grid gap:
gap-4 - Sidebar width: expanded
w-64, collapsedw-[60px] - Header height: prefer
h-16
- Prefer shadcn/ui primitives:
- Installed:
Avatar,Badge,Button,Card,Dialog,Input,Progress,RadioGroup,Select,Separator,Sheet,Switch,Tabs,Textarea,Tooltip - Install on demand:
Checkbox,Skeleton,DropdownMenu,ScrollArea
- Installed:
- Card states:
- Hover:
hover:border-primary/30 hover:shadow-md transition-all - Active:
border-primary shadow-md
- Hover:
- View toggle should use segmented control:
- Wrapper:
rounded-lg border bg-muted/50 p-0.5 - Active segment:
bg-background text-foreground shadow-sm
- Wrapper:
- Active / Done / Merged →
bg-success/10 text-success - In Progress / Paused / Todo →
bg-warning/10 text-warning - Backlog →
bg-muted text-muted-foreground - High priority →
bg-destructive/10 text-destructive - Medium priority →
bg-warning/10 text-warning - Low priority →
bg-success/10 text-success
- Terminal background target:
hsl(240 10% 4%)(tokenized; avoid raw color hardcoding in JSX wrappers). - xterm theme colors should come from semantic tokens.
- Mandatory:
terminal.dispose()on unmount- lazy mount when tab is hidden
- buffered output streaming
- Theme flow:
ThemeProvider+useTheme()+localStoragepersistence. - Icon system:
lucide-react, standard sizeh-4 w-4toh-5 w-5.
- No new raw color literals in changed UI files
- Typography classes follow the scale (H1/H2/H3/body/caption)
- Spacing/radius follow the system (
p-6,gap-4,--radius) - Status badges follow semantic mapping
- Theme behavior works in both light and dark modes
- No new hardcoded user-facing strings (follow i18n rules)