Comp AI CRM 前端样式规范:shadcn/ui 语义化 Styling Customization 实战指南
2026/9/24 15:32:57 网站建设 项目流程
  • 后端
  • 前端
  • CRM
  • 人工智能
  • AI Agent

【免费下载链接】crm

Comp AI CRM is an open source, CRM designed for AI agents. Agentic-first CRM.

项目地址:https://gitcode.com/gh_mirrors/crm48/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正反示例,可直接作为代码评审的检查清单:

  1. 语义色(Semantic colors)
  2. 状态/指示器不得使用原始颜色值
  3. 优先使用内置变体(Built-in variants first)
  4. className仅用于布局
  5. 禁止space-x-*/space-y-*
  6. 等宽高优先size-*
  7. 优先truncate简写
  8. 禁止手动dark:颜色覆盖
  9. 条件类统一使用cn()
  10. 浮层组件禁止手动z-index
  11. 使用shimmer/scroll-fade工具类而非自定义动画

二、先理解机制:CSS 变量 → Tailwind 工具类 → 组件

在展开规则前,先看支撑这些规则的主题机制(详见 customization.md),它遵循三层链路:

  1. CSS 变量定义在:root(亮色)与.dark(暗色)中;
  2. Tailwind 将变量映射为工具类,如bg-primarytext-muted-foreground
  3. 组件消费这些工具类——改一个变量,所有引用它的组件同步变化

在 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定义了defaultsecondarydestructiveoutlineghostlinkmonotoken共 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 的实现,Buttoncva变体覆盖了defaultoutlineoutline-ghostsecondaryghostdestructivecontrastlink八种,尺寸涵盖xs/sm/default/lg/xl/icon/icon-xs/icon-sm/icon-lg,绝大多数视觉需求都应先在此列表中寻找答案。

3.4 className 仅用于布局

className只允许承担max-w-mdmx-automt-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>

当确实需要自定义组件外观时,按以下优先级依次尝试:

  1. 内置变体——variant="outline"variant="destructive"等;
  2. 语义色 token——bg-primarytext-muted-foreground
  3. 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-4flex flex-col gap-4space-x-2flex 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,本质是clsxtailwind-merge的组合:前者负责条件合并,后者负责智能去重冲突类——例如同时传入p-2p-4时只保留后者,从而保证调用方传入的类能安全覆盖组件默认类。

3.10 浮层组件禁止手动 z-index

DialogSheetDrawerAlertDialogDropdownMenuPopoverTooltipHoverCard等浮层组件自带层级管理,永远不要追加z-50z-[999]。手动堆叠 z-index 会破坏组件自身的层叠上下文,导致弹层被错误遮挡。若确有层级需求,应优先调整 DOM 结构或在主题层解决。

3.11 用 shimmer / scroll-fade 工具类替代自定义动画

实时"思考中…"或加载文字闪烁效果,直接使用shimmer工具类;滚动容器边缘渐隐使用scroll-fade(含轴向变体scroll-fade-xscroll-fade-b),不要手写@keyframesbg-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-themesThemeProvider

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-lgvar(--radius)rounded-mdcalc(var(--radius) - 2px)。Comp AI CRM 中--radius: 5px(globals.css),并在@theme inline中派生出--radius-sm: 4px--radius-lg: 8px--radius-xl: 12px等梯度。

组件级定制按四档优先级递进:

  1. 内置变体
<Button variant="outline" size="sm">Click</Button>
  1. className 传布局类
<Card className="mx-auto max-w-md">...</Card>
  1. 新增 cva 变体(编辑组件源码):
// components/ui/button.tsx warning: "bg-warning text-warning-foreground hover:bg-warning/90",
  1. 包装组件:将 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-backgroundtext-foreground等语义 token,无bg-blue-500类原始色;
  • 状态指示(涨跌、在线、错误)使用 Badge 变体或text-destructive,无text-green-500类原始色;
  • Button 等组件优先查variant/size表,无手搓边框+悬停背景的组合类;
  • className中只有布局类(max-w-*mx-automt-*),无颜色/排版覆盖;
  • 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.

项目地址:https://gitcode.com/gh_mirrors/crm48/crm
点击查看免费下载

相关推荐

上一篇:如何用MoocDownloader高效下载中国大学MOOC课程:离线学习的终极解决方案
下一篇:深度解析:Windows内核级硬件信息欺骗技术的3种实现机制

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询