Paperclip Design Guide 是 Paperclip 项目的 UI 设计系统指南,用于构建一致、可复用的前端组件。它面向需要创建新 UI 组件、修改现有组件或添加新设计模式的开发者。
用途
该指南为 Paperclip 的界面提供统一的设计语言和实现规范。Paperclip 的 UI 被定位为专业级控制平面——信息密集、键盘驱动、默认深色主题。指南建议始终与 frontend-design(视觉打磨)和 web-design-guidelines(Web 最佳实践)配合使用。
设计原则
- 密集但可扫描:在不点击展开的情况下呈现最大信息量,用留白分隔而非填充。
- 键盘优先:提供全局快捷键(Cmd+K、C、[、]),高级用户很少使用鼠标。
- 上下文而非模态:优先内联编辑而非对话框,优先下拉菜单而非页面跳转。
- 默认深色主题:使用中性灰(OKLCH),而非纯黑;强调色仅用于状态/优先级;文本是主要视觉元素。
- 组件驱动:优先使用可复用组件来承载样式约定,在合适的抽象层级构建——不过于细碎,也不过于庞大。
技术栈
- React 19 + TypeScript + Vite
- Tailwind CSS v4,使用 CSS 变量(OKLCH 色彩空间)
- shadcn/ui(new-york 风格,neutral 基础色,启用 CSS 变量)
- Radix UI 原语(无障碍、焦点管理)
- Lucide React 图标(导航 16px,内联 14px)
- class-variance-authority(CVA)用于组件变体
- clsx + tailwind-merge,通过 cn() 工具函数使用
- 配置:ui/components.json(别名:@/components、@/components/ui、@/lib、@/hooks)
设计令牌
所有令牌在 ui/src/index.css 中定义为 CSS 变量,明暗主题均使用 OKLCH。
颜色:使用语义化令牌名,禁止使用原始颜色值。包括 --background / --foreground(页面背景与主文本)、--card / --card-foreground(卡片表面)、--primary / --primary-foreground(主要操作、强调)、--secondary / --secondary-foreground(次要表面)、--muted / --muted-foreground(弱化文本、标签)、--accent / --accent-foreground(悬停状态、活动导航项)、--destructive(破坏性操作)、--border(所有边框)、--ring(焦点环)、--sidebar-*(侧边栏专用变体)、--chart-1 至 --chart-5(数据可视化)。
圆角:单一 --radius 变量(0.625rem)及派生尺寸:rounded-sm(小输入框、胶囊)、rounded-md(按钮、输入框、小组件)、rounded-lg(卡片、对话框)、rounded-xl(卡片容器、大组件)、rounded-full(徽章、头像、状态点)。
阴影:最小化阴影,仅 shadow-xs(轮廓按钮)和 shadow-sm(卡片),不使用重阴影。
排版规范
使用以下精确模式,不要自创:页面标题 text-xl font-bold;区块标题 text-lg font-semibold;区块小标题 text-sm font-semibold text-muted-foreground uppercase tracking-wide;卡片标题 text-sm font-medium 或 text-sm font-semibold;正文 text-sm;弱化文本 text-sm text-muted-foreground;微小标签 text-xs text-muted-foreground;等宽标识 text-xs font-mono text-muted-foreground;大号统计 text-2xl font-bold;代码/日志 font-mono text-xs。
状态与优先级系统
状态颜色在所有实体中保持一致,定义于 StatusBadge.tsx 和 StatusIcon.tsx:active、achieved、completed、succeeded、approved、done 使用绿色;running 使用青色;paused 使用橙色;idle、pending 使用黄色;failed、error、rejected、blocked 使用红色;archived、planned、backlog、cancelled 使用中性灰;todo 使用蓝色;in_progress 使用靛蓝;in_review 使用紫色。
优先级图标定义于 PriorityIcon.tsx:critical(红色/AlertTriangle)、high(橙色/ArrowUp)、medium(黄色/Minus)、low(蓝色/ArrowDown)。
代理状态点:内联彩色圆点,running(青色,animate-pulse)、active(绿色)、paused(黄色)、error(红色)、offline(中性)。
组件层级
分为三层:shadcn/ui 原语(ui/src/components/ui/)——Button、Card、Input、Badge、Dialog、Tabs 等,不要直接修改,通过组合扩展;自定义复合组件(ui/src/components/)——StatusBadge、EntityRow、MetricCard 等,承载 Paperclip 特定设计语言;页面组件(ui/src/pages/)——将原语和复合组件组合成完整视图。完整组件清单见 references/component-index.md。
创建新组件的时机:同一视觉模式出现在 2 处以上;模式具有交互行为(状态变化、内联编辑);模式编码了领域逻辑(状态颜色、优先级图标)。不要为以下情况创建组件:单页面专用的一次性布局;简单的 className 组合(直接使用 Tailwind);不增加语义价值的薄包装。
组合模式
指南描述了组件如何协同工作,包括:带状态与优先级的实体行(EntityRow,leading 槽位始终先 StatusIcon 后 PriorityIcon,trailing 槽位为 StatusBadge 或时间戳);分组列表(状态标题 + 实体行);属性行(键值对,标签始终为 text-xs text-muted-foreground,值在右侧);指标卡片网格(响应式网格);进度条(按阈值着色:绿色 <60%,黄色 60-85%,红色 >85%);评论线程;成本表格;日志查看器(bg-neutral-950 容器,按级别着色:默认 foreground、WARN 黄色、ERROR 红色、SYS 蓝色,流式传输时显示实时指示点)。
交互模式
悬停状态:实体行 hover:bg-accent/50;导航项 hover:bg-accent/50 hover:text-accent-foreground;活动导航 bg-accent text-accent-foreground。焦点:focus-visible:ring-ring focus-visible:ring-[3px]。禁用:disabled:opacity-50 disabled:pointer-events-none。内联编辑:使用 InlineEditor 组件,点击文本编辑,Enter 保存,Escape 取消。弹出选择器:StatusIcon 和 PriorityIcon 使用 Radix Popover 进行内联选择。
布局系统
三区布局定义于 Layout.tsx:侧边栏(w-60,可折叠,包含 CompanySwitcher + SidebarSections);主内容区(flex-1,可滚动);属性面板(w-80,详情视图显示,列表隐藏)。
/design-guide 页面
位置:ui/src/pages/DesignGuide.tsx,路由:/design-guide。这是应用中每个组件和模式的实时展示,是外观的真相来源。规则:添加新的可复用组件时必须添加到设计指南页面,展示所有变体、尺寸和状态;修改现有组件 API 时更新其设计指南部分;添加新组合模式时添加演示部分;遵循现有结构(Section 包裹,SubSection 分组);保持区块逻辑顺序:基础(颜色、排版)优先,然后是原语、复合组件、模式。
文件约定
shadcn 原语:ui/src/components/ui/{component}.tsx(小写、kebab-case);自定义组件:ui/src/components/{ComponentName}.tsx(PascalCase);页面:ui/src/pages/{PageName}.tsx(PascalCase);工具:ui/src/lib/{name}.ts;Hooks:ui/src/hooks/{useName}.ts;API 模块:ui/src/api/{entity}.ts;上下文提供者:ui/src/context/{Name}Context.tsx。所有组件使用 @/lib/utils 的 cn() 合并 className,有多个视觉变体时使用 CVA 定义变体。
常见错误
使用原始 hex/rgb 颜色而非 CSS 变量令牌;创建临时排版样式而非使用既定比例;硬编码状态颜色而非使用 StatusBadge/StatusIcon;在已有可复用组件时构建一次性样式元素;添加组件而不更新设计指南页面;使用 shadow-md 或更重阴影(仅保留 xs、sm);使用 rounded-2xl 或更大(最大 rounded-xl,胶囊除外);忘记深色模式(始终使用语义令牌,不硬编码明暗值)。