- 后端
- 前端
- CRM
- 人工智能
- AI Agent
【免费下载链接】crm
Comp AI CRM is an open source, CRM designed for AI agents. Agentic-first CRM.
本文以 Comp AI CRM 仓库内.agents/skills/shadcn/rules/styling.md样式规范为核心骨架,系统讲解基于 shadcn/ui 的语义化样式体系:如何用语义色代替原始 Tailwind 颜色、如何优先使用内置变体、如何用cn()合并条件类,以及如何通过 CSS 变量完成主题定制与暗色模式切换。读完本文,你将掌握一套可直接落地的组件样式开发与定制规范,并能在 packages/ui 的真实组件(Button、Badge、MessageScroller、Attachment 等)中找到对应实现证据。
一、规范定位:这是项目必须遵守的样式规则
styling.md是 Comp AI CRM 的 shadcn skill 中始终强制生效(always enforced)的规则文件,与之并列的还有 rules/forms.md(表单)、rules/composition.md(组件结构)等。该文件为 Tailwind 类名与 shadcn/ui 组件的使用划定边界,核心思想是:
组件的外观由语义化 token 与内置变体负责,
className只负责布局。
这一思想贯穿下列 11 条规则,每条都配套Incorrect / Correct正反示例,可直接作为代码评审的检查清单:
- 语义色(Semantic colors)
- 状态/指示器不得使用原始颜色值
- 优先使用内置变体(Built-in variants first)
className仅用于布局- 禁止
space-x-*/space-y-* - 等宽高优先
size-* - 优先
truncate简写 - 禁止手动
dark:颜色覆盖 - 条件类统一使用
cn() - 浮层组件禁止手动
z-index - 使用
shimmer/scroll-fade工具类而非自定义动画
二、先理解机制:CSS 变量 → Tailwind 工具类 → 组件
在展开规则前,先看支撑这些规则的主题机制(详见 customization.md),它遵循三层链路:
- CSS 变量定义在
:root(亮色)与.dark(暗色)中; - Tailwind 将变量映射为工具类,如
bg-primary、text-muted-foreground; - 组件消费这些工具类——改一个变量,所有引用它的组件同步变化。
在 Comp AI CRM 中,这套变量集中定义在 packages/ui/src/styles/globals.css,首部通过@import "tailwindcss"、@import "tw-animate-css"与@import "shadcn/tailwind.css"引入基础,并用@custom-variant dark (&:is(.dark *))声明基于类的暗色模式。变量与 Tailwind 工具类的映射通过@theme inline块完成,例如:
@theme inline { --color-primary: var(--primary); --color-primary-foreground: var(--primary-foreground); --color-muted-foreground: var(--muted-foreground); /* ... */ }项目还额外注册了--color-success、--color-warning、--color-info、--color-tag、--color-overlay等扩展语义色,供业务组件直接使用(见 globals.css)。这一事实说明:项目需要的新颜色应先考虑补充语义变量,而不是在 JSX 里硬编码色值。
三、核心规则逐条解析(正反示例)
3.1 语义色优先
错误写法(直接使用 Tailwind 调色板):
<div className="bg-blue-500 text-white"> <p className="text-gray-600">Secondary text</p> </div>正确写法(使用语义 token):
<div className="bg-primary text-primary-foreground"> <p className="text-muted-foreground">Secondary text</p> </div>语义 token 在亮/暗两种主题下自动适配,而bg-blue-500在暗色主题中不会有任何响应。
3.2 状态/指示器禁止使用原始颜色值
上涨、下跌、启用、错误等状态色,应使用 Badge 变体、text-destructive等语义 token,或新增自定义 CSS 变量——不要直接写text-emerald-600这类原始色:
错误写法:
<span className="text-emerald-600">+20.1%</span> <span className="text-green-500">Active</span> <span className="text-red-600">-3.2%</span>正确写法:
<Badge variant="secondary">+20.1%</Badge> <Badge>Active</Badge> <span className="text-destructive">-3.2%</span>如果缺少表示成功/正向的语义 token,规范给出两条出路:使用 Badge 变体,或与用户确认后向主题新增自定义 CSS 变量(步骤见第六节)。在 Comp AI CRM 中,Badge 组件已通过cva定义了default、secondary、destructive、outline、ghost、link、mono、token共 8 个变体(见 packages/ui/src/components/badge.tsx),其中destructive变体内部使用bg-destructive/10 text-destructive的语义组合,正是指示器的标准姿势。
3.3 优先使用内置变体
不要用一堆工具类手搓出本来就有变体的效果:
错误写法:
<Button className="border border-input bg-transparent hover:bg-accent"> Click me </Button>正确写法:
<Button variant="outline">Click me</Button>查看仓库中 packages/ui/src/components/button.tsx 的实现,Button的cva变体覆盖了default、outline、outline-ghost、secondary、ghost、destructive、contrast、link八种,尺寸涵盖xs/sm/default/lg/xl/icon/icon-xs/icon-sm/icon-lg,绝大多数视觉需求都应先在此列表中寻找答案。
3.4 className 仅用于布局
className只允许承担max-w-md、mx-auto、mt-4这类布局职责,禁止用它覆盖组件的颜色或排版:
错误写法:
<Card className="bg-blue-100 text-blue-900 font-bold"> <CardContent>Dashboard</CardContent> </Card>正确写法:
<Card className="max-w-md mx-auto"> <CardContent>Dashboard</CardContent> </Card>当确实需要自定义组件外观时,按以下优先级依次尝试:
- 内置变体——
variant="outline"、variant="destructive"等; - 语义色 token——
bg-primary、text-muted-foreground; - CSS 变量—— 在全局 CSS 文件中定义自定义颜色(参见 customization.md)。
3.5 禁止 space-x-* / space-y-*
space-*依赖相邻兄弟选择器,与子元素margin冲突且不可组合,统一改用 flex 布局 +gap-*:
<div className="flex flex-col gap-4"> <Input /> <Input /> <Button>Submit</Button> </div>换算关系:space-y-4→flex flex-col gap-4;space-x-2→flex gap-2。
3.6 等宽高等高时优先 size-*
当宽度与高度相等时,用size-10而非w-10 h-10,适用于图标、头像、骨架屏等。在 Button 实现中可以看到,size-*已内嵌于组件基类(如[&_svg:not([class*='size-'])]:size-4),图标统一由size-*控制,正是这条规则的落地(button.tsx)。
3.7 优先 truncate 简写
truncate等价于overflow-hidden text-ellipsis whitespace-nowrap三件套,永远写简写:
<span className="truncate">A very long file name that must be ellipsized…</span>仓库中 packages/ui/src/components/attachment.tsx 对附件标题的处理正是"block max-w-full min-w-0 truncate font-medium"的组合。
3.8 禁止手动 dark: 颜色覆盖
语义 token 已经通过 CSS 变量自动处理亮/暗两套主题,不要再写bg-white dark:bg-gray-950:
错误写法:
<div className="bg-white dark:bg-gray-950">...</div>正确写法:
<div className="bg-background text-foreground">...</div>暗色模式下,--background从#ffffff自动切换为#0f0f0f、--foreground从#171717切换为#f5f5f5(见 globals.css),无需任何组件改动。
3.9 条件类统一使用 cn()
项目提供cn()工具函数用于合并/条件类名,禁止在 className 字符串里手写模板字面量三元:
错误写法:
<div className={`flex items-center ${isActive ? "bg-primary text-primary-foreground" : "bg-muted"}`}>正确写法:
import { cn } from "@crm/ui/lib/utils" <div className={cn("flex items-center", isActive ? "bg-primary text-primary-foreground" : "bg-muted")}>cn()的实现位于 packages/ui/src/lib/utils.ts,本质是clsx与tailwind-merge的组合:前者负责条件合并,后者负责智能去重冲突类——例如同时传入p-2与p-4时只保留后者,从而保证调用方传入的类能安全覆盖组件默认类。
3.10 浮层组件禁止手动 z-index
Dialog、Sheet、Drawer、AlertDialog、DropdownMenu、Popover、Tooltip、HoverCard等浮层组件自带层级管理,永远不要追加z-50或z-[999]。手动堆叠 z-index 会破坏组件自身的层叠上下文,导致弹层被错误遮挡。若确有层级需求,应优先调整 DOM 结构或在主题层解决。
3.11 用 shimmer / scroll-fade 工具类替代自定义动画
实时"思考中…"或加载文字闪烁效果,直接使用shimmer工具类;滚动容器边缘渐隐使用scroll-fade(含轴向变体scroll-fade-x、scroll-fade-b),不要手写@keyframes、bg-clip-text渐变扫光或 mask 渐变。
错误写法(手搓动画):
<span className="animate-pulse bg-gradient-to-r from-muted-foreground/40 via-foreground/70 to-muted-foreground/40 bg-clip-text text-transparent [animation:shimmer_1.6s_infinite]"> Thinking… </span>正确写法(使用工具类):
<span className="shimmer">Thinking…</span>这些工具类在项目内已大量内置使用:
- packages/ui/src/components/attachment.tsx:附件处于
uploading/processing状态时,标题自动应用shimmer动画; - packages/ui/src/components/message-scroller.tsx:
MessageScroller的滚动视口使用scroll-fade-b在底部做边缘渐隐; - 配套规范 rules/chat.md 明确要求"思考中"指示器使用
shimmer工具类而非自定义 keyframes,其 eval 校验项也写入了"no custom shimmer keyframes"的硬性要求(见.agents/skills/shadcn/evals/evals.json)。
复用现成工具类的好处:动效参数全局统一、天然适配prefers-reduced-motion、减少无意义的样式膨胀。
四、主题定制:改变量即可全局换肤
规则之外,掌握主题定制能力才能让语义 token 真正为我所用(完整步骤见 customization.md)。
4.1 颜色变量体系(name / name-foreground 约定)
每个颜色遵循name/name-foreground命名约定:基础变量用于背景,-foreground用于该背景上的文字/图标。常用变量一览:
| 变量 | 用途 |
|---|---|
--background/--foreground | 页面背景与默认文字 |
--card/--card-foreground | 卡片表面 |
--primary/--primary-foreground | 主按钮与主要操作 |
--secondary/--secondary-foreground | 次级操作 |
--muted/--muted-foreground | 弱化/禁用状态 |
--accent/--accent-foreground | 悬停与强调状态 |
--destructive/--destructive-foreground | 错误与破坏性操作 |
--border | 默认边框色 |
--input | 表单输入边框 |
--ring | 焦点环颜色 |
--chart-1~--chart-5 | 图表/数据可视化 |
--sidebar-* | 侧边栏专属色 |
--surface/--surface-foreground | 次级表面 |
在 globals.css 中可以看到 Comp AI CRM 的实际取值:主色--primary: #006b4f(品牌绿)、破坏色--destructive: #ae2e24、焦点环--ring: #006b4f,并额外扩展了--success、--warning、--info、--severity-*、--code-*、--tag等业务语义变量。
4.2 OKLCH 色彩空间
规范推荐的变量格式为 OKLCH:--primary: oklch(0.205 0 0),三个值分别表示亮度(0–1)、色度(0 为灰色)与色相(0–360)。OKLCH 相比 HEX/RGB 在明度感知上更均匀,便于人工推导亮暗两套变量。注意 Comp AI CRM 的globals.css同时混用了 HEX(如#006b4f)与 OKLCH(如--success: oklch(0.55 0.13 150)),二者均可正常消费。
4.3 暗色模式接入
采用 class 策略:在根元素上切换.dark类。Next.js 项目使用next-themes的ThemeProvider:
import { ThemeProvider } from "next-themes" <ThemeProvider attribute="class" defaultTheme="system" enableSystem> {children} </ThemeProvider>仓库的 packages/ui/src/styles/globals.css 中.dark块重新定义了全部变量(如--background: #0f0f0f、--ring: #40be96),配合@custom-variant dark即可在任意位置使用dark:变体。
4.4 应用预设主题与直接改变量
# 从 ui.shadcn.com 应用预设代码 npx shadcn@latest apply --preset a2r6bw # 位置参数简写 npx shadcn@latest apply a2r6bw # 切换到命名预设并覆盖已有组件 npx shadcn@latest apply --preset nova # 保留现有组件、仅应用预设 npx shadcn@latest init --preset nova --force --no-reinstall # 使用自定义主题 URL npx shadcn@latest apply --preset "https://ui.shadcn.com/init?base=radix&style=nova&theme=blue&..."也可以直接编辑globals.css中的 CSS 变量实现换肤。
4.5 添加自定义颜色(Tailwind v4 / v3)
新增颜色时,必须写入npx shadcn@latest info显示的tailwindCssFile(通常即globals.css),不要新建 CSS 文件。三步走:
/* 1. 在全局 CSS 中定义变量 */ :root { --warning: oklch(0.84 0.16 84); --warning-foreground: oklch(0.28 0.07 46); } .dark { --warning: oklch(0.41 0.11 46); --warning-foreground: oklch(0.99 0.02 95); }/* 2a. Tailwind v4:通过 @theme inline 注册 */ @theme inline { --color-warning: var(--warning); --color-warning-foreground: var(--warning-foreground); }若tailwindVersion为"v3"(用npx shadcn@latest info确认),则在tailwind.config.js中注册:
module.exports = { theme: { extend: { colors: { warning: "oklch(var(--warning) / <alpha-value>)", "warning-foreground": "oklch(var(--warning-foreground) / <alpha-value>)", }, }, }, }// 3. 在组件中使用 <div className="bg-warning text-warning-foreground">Warning</div>4.6 圆角与组件级定制
--radius全局控制圆角:rounded-lg取var(--radius),rounded-md取calc(var(--radius) - 2px)。Comp AI CRM 中--radius: 5px(globals.css),并在@theme inline中派生出--radius-sm: 4px、--radius-lg: 8px、--radius-xl: 12px等梯度。
组件级定制按四档优先级递进:
- 内置变体:
<Button variant="outline" size="sm">Click</Button>- className 传布局类:
<Card className="mx-auto max-w-md">...</Card>- 新增 cva 变体(编辑组件源码):
// components/ui/button.tsx warning: "bg-warning text-warning-foreground hover:bg-warning/90",- 包装组件:将 shadcn/ui 原语组合为高层组件:
export function ConfirmDialog({ title, description, onConfirm, children }) { return ( <AlertDialog> <AlertDialogTrigger asChild>{children}</AlertDialogTrigger> <AlertDialogContent> <AlertDialogHeader> <AlertDialogTitle>{title}</AlertDialogTitle> <AlertDialogDescription>{description}</AlertDialogDescription> </AlertDialogHeader> <AlertDialogFooter> <AlertDialogCancel>Cancel</AlertDialogCancel> <AlertDialogAction onClick={onConfirm}>Confirm</AlertDialogAction> </AlertDialogFooter> </AlertDialogContent> </AlertDialog> ) }五、组件升级与变更审查
shadcn 组件以源码形式存在于项目中,升级前先做差异审查:
# 查看某个组件相对最新注册表是否有差异 npx shadcn@latest add button --diff # 预演:只列出会受影响的所有文件 npx shadcn@latest add button --dry-run # 查看单个文件的差异 npx shadcn@latest add button --diff button.tsx--dry-run与--diff组合可以在真正写入前精确预览变更范围,配合 SKILL.md 中描述的智能合并(smart merge)工作流使用。
六、落地实践与验收清单
在 Comp AI CRM 中,这套规范由 shadcn skill(见 .agents/skills/shadcn/SKILL.md)驱动,对 Agent 生成代码与人工评审同样生效。最终验收可以对照这份清单逐条过:
- 页面/组件背景与文字全部使用
bg-background、text-foreground等语义 token,无bg-blue-500类原始色; - 状态指示(涨跌、在线、错误)使用 Badge 变体或
text-destructive,无text-green-500类原始色; - Button 等组件优先查
variant/size表,无手搓边框+悬停背景的组合类; className中只有布局类(max-w-*、mx-auto、mt-*),无颜色/排版覆盖;- 无
space-x-*/space-y-*,全部为flex gap-*; - 等宽高元素使用
size-*,无w-10 h-10; - 溢出省略统一
truncate; - 无
dark:bg-*、dark:text-*手动覆盖; - 条件类均通过
cn()合并(@crm/ui/lib/utils),无模板字符串三元; - Dialog/Sheet/Popover 等浮层无手动
z-*; - "思考中…"等效果使用
shimmer,滚动边缘渐隐使用scroll-fade-*,无自定义@keyframes。
遵循上述规则后,你的组件将天然获得主题一致、亮暗自适应、动效统一、升级无痛四重保障——这正是 Comp AI CRM 全站 UI(见 packages/ui/src/components 下 70+ 组件)能够保持视觉一致性的底层原因。
- 后端
- 前端
- CRM
- 人工智能
- AI Agent
【免费下载链接】crm
Comp AI CRM is an open source, CRM designed for AI agents. Agentic-first CRM.
相关推荐
Comp AI CRM 中的 AI Elements:基于 shadcn/ui 的 AI 聊天界面组件库实战指南
Comp AI CRM 中的 AI Elements:基于 shadcn/ui 的 AI 聊天界面组件库实战指南 本指南围绕 Comp AI CRM 仓库中锁定
后端前端CRM人工智能AI Agentinbox-zero 前端 UI 组件与样式开发指南:基于 Shadcn UI、Radix UI 与 Tailwind 的组件规范实践
inbox zero 前端 UI 组件与样式开发指南:基于 Shadcn UI、Radix UI 与 Tailwind 的组件规范实践 本文是 inbox ze
人工智能AI 应用后端前端gVisor 与 Knative 集成:让 Kubernetes 上的 Serverless 工作负载运行在 gVisor 沙箱中
gVisor 与 Knative 集成:让 Kubernetes 上的 Serverless 工作负载运行在 gVisor 沙箱中 本文基于 gVisor 仓库
后端前端CRM人工智能AI Agent
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考