Sink 设计系统解析:DESIGN.md 中的 oklch 语义令牌与 shadcn-vue 组件约定
2026/9/16 18:15:44 网站建设 项目流程

Sink 设计系统解析:DESIGN.md 中的 oklch 语义令牌与 shadcn-vue 组件约定

【免费下载链接】Sink⚡ A Simple / Speedy / Secure Link Shortener with Analytics, 100% run on Cloudflare.项目地址: https://gitcode.com/GitHub_Trending/si/Sink

本文基于 Sink(一个 100% 运行在 Cloudflare 上的短链接统计工具)仓库根目录的DESIGN.md展开。该文件是 Sink 的"语义设计令牌 + 组件指引"文档,专为设计感知型 Agent 与人协作而生。读完本文,你将完整掌握 Sink 界面的颜色角色体系(含明暗两套主题)、字体与圆角令牌、刻意保持"非全局化"的布局/阴影策略,以及按钮、卡片、对话框、Tabs、侧边栏等组件的变体约定,并能对照app/assets/css/tailwind.cssapp/components/ui/**源码验证每个令牌的真实落点。

DESIGN.md 的定位:派生摘要,CSS 与组件实现是权威

DESIGN.md开头明确了自己的角色:

This file is a derived summary for design-aware agents. If it conflicts withapp/assets/css/tailwind.cssor a component underapp/components/ui/**, the CSS and UI component implementation are authoritative.

也就是说,它是从真实样式实现中派生出来的摘要文档,供 Agent 在生成 UI 时快速对齐设计规范;一旦它与 app/assets/css/tailwind.css 或 app/components/ui/ 下的组件实现冲突,以后者为准。文件由两部分组成:

  1. YAML frontmatter:机器可读的令牌声明(version: alphaname: Sinkcolorstypographyroundedcomponents),其中组件样式通过{colors.primary}这类引用串接颜色令牌;
  2. Markdown 正文:面向人的使用守则(Colors / Typography / Layout / Elevation / Shapes / Components / Interaction / Do's and Don'ts)。

这种"frontmatter 给 Agent 读、正文给人读"的双轨结构,是设计令牌文件被 LLM 直接消费的一种务实形态。

颜色令牌:以角色而非色值组织的全套体系

DESIGN.md 的核心主张是:永远按语义角色使用颜色,并且每个背景必须与其前景成对出现。前缀无修饰的令牌复现:root(浅色主题)中的语义角色,dark-*令牌则把.dark(深色主题)的对应值"拍平"成同名前缀令牌。

浅色主题(:root)令牌全集

以下值与 tailwind.css 的:root定义逐一对应:

令牌值(oklch)语义用途
background/foregroundoklch(1 0 0)/oklch(0.141 0.005 285.823)页面底色与默认正文
card/card-foreground同 background/foreground卡片容器
popover/popover-foreground同 background/foreground下拉内容、浮层
primary/primary-foregroundoklch(0.21 0.006 285.885)/oklch(0.985 0 0)近黑主色 + 近白文字
secondary/secondary-foregroundoklch(0.967 0.001 286.375)/oklch(0.21 0.006 285.885)次级按钮等
muted/muted-foregroundoklch(0.967 0.001 286.375)/oklch(0.552 0.016 285.938)弱化背景与弱文字
accent/accent-foreground与 secondary 相同悬停/激活高亮
success/success-foregroundoklch(0.55 0.16 145)/oklch(0.985 0 0)正向状态与完成指示
destructiveoklch(0.577 0.245 27.325)破坏性操作或无效状态
border/inputoklch(0.92 0.004 286.32)边框与输入框描边
ringoklch(0.705 0.015 286.067)焦点强调
chart-1chart-5oklch(0.871 0.15 154.449)oklch(0.448 0.119 151.328)的绿色递进序列仅供图表使用
sidebar系列 8 项sidebaroklch(0.985 0 0),其余见下节侧边栏专属角色

几条关键使用规则(DESIGN.md Colors 一节原文要旨):

  • 绿色 chart-1 到 chart-5 序列只给图表用,不要挪作状态色;
  • success专用于正向状态/完成指示,ring专用于焦点强调,destructive专用于破坏性或无效状态——三者在深色模式都有对应值;
  • 深浅两套主题中都要保持背景/前景成对出现,禁止混搭。

深色主题(.dark):拍平的 dark-* 令牌

DESIGN.md 用dark-前缀把.dark选择器下的值拍平成独立令牌,例如dark-background: oklch(0.141 0.005 285.823)dark-primary: oklch(0.92 0.004 286.32)。对照 tailwind.css 可以看到几个值得注意的深色主题设计决策:

  • 透明度描边dark-borderoklch(1 0 0 / 10%)dark-inputoklch(1 0 0 / 15%)——深色下用白色半透明替代实色描边,边框会随背景深浅自然变化;
  • 图表色跨主题不变dark-chart-1dark-chart-5与浅色主题完全相同,保证同一数据集在明暗主题下颜色一致;
  • 深色侧边栏主色带蓝调dark-sidebar-primary: oklch(0.488 0.243 264.376)是整张令牌表中唯一的饱和蓝紫值(浅色主题的sidebar-primary则是与 primary 相同的近黑色),这是深色模式下侧边栏强调色被单独提亮的地方。

主题切换机制本身由 Nuxt 的useColorMode驱动:app/components/SwitchTheme.vue 提供 light / dark / system 三个选项,写入colorMode.preference,而@custom-variant dark (&:is(.dark *))(tailwind.css)让所有dark:工具类响应根节点上的.darkclass。

排版与圆角:两条极简令牌

Typography 一节明确:

  • 界面文字统一使用IBM Plex SansfontFamily: "IBM Plex Sans, sans-serif");heading只是同一字族的别名,不是独立的展示字体;
  • 字号、字重、行高由各组件用本地工具类自行决定——这个文件不定义全局字阶

这一点在 tailwind.css 中得到印证:

--font-sans: 'IBM Plex Sans', sans-serif; --font-heading: var(--font-sans);

--font-heading直接指向--font-sans,"heading 是别名"这句话就是这一行 CSS 的文字版。同时 components.json 里"font": "ibm-plex-sans"记录了 shadcn-vue CLI 初始化时选定的字体。

Shapes 一节给出唯一的形状令牌:基准圆角0.625rem--radius: 0.625rem),派生圆角为:

sm = calc(var(--radius) - 4px) md = calc(var(--radius) - 2px) lg = var(--radius) xl = calc(var(--radius) + 4px)

这段公式与 tailwind.css 的@theme inline块逐字对应。DESIGN.md 还特别强调:rounded-2xlrounded-4xl这类工具类是组件的本地选择,不是全局设计令牌;"大圆角与紧凑密度共存,更大的圆角不意味着更大的控件"。

布局与层次:刻意不定义全局令牌

DESIGN.md 有两大节在"宣告克制":

  • Layout:仓库不定义全局网格、容器、断点或间距比例尺。组合界面时"跟随相邻实现";侧边栏宽度与响应式行为属于 sidebar 组件自身,不是全局布局令牌。
  • Elevation & Depth:基础表面靠语义背景、边框、ring 建立层次;对话框和浮层是否用遮罩/ring/阴影,取决于各自的组件实现——阴影是组件实现细节,不是全局层级令牌

这种"令牌最小化"策略的源码级证据同样来自 tailwind.css:@theme inline块只映射了颜色、radius、字体,没有任何--spacing网格或断点覆盖;@layer base里只做了全局border-border outline-ring/50bg-background text-foreground、细滚动条与prefers-reduced-motion降级(动画/过渡时长压到0.01ms),没有任何全局阴影变量。

组件约定:与 app/components/ui 实现一一对应

DESIGN.md 的 Components 一节逐组件列出了约定,下面结合源码逐一核对。

按钮:变体、尺寸与 data 属性

约定内容:default、outline、secondary、ghost、destructive、link 六类变体,多种文字/图标尺寸,focus/invalid ring,按下位移,禁用处理。

app/components/ui/button/Button.vue 的实现印证了"变体由 data 属性驱动"的模式:

<Primitive ><div >variant: { default: 'bg-muted', // 填充式:muted 背景 line: 'gap-1 bg-transparent' // 线性:透明背景 + 间距 }

配合 app/components/ui/tabs/TabsTrigger.vue 中通过after:伪元素绘制激活指示条、按group-data-horizontal/group-data-vertical切换横纵方向的写法,DESIGN.md 里"横向/纵向状态"的描述有了具体出处。

侧边栏:专属令牌组与"已定义未消费"的诚实声明

约定:sidebar 使用专属的 background、foreground、accent、border、ring 角色,贯穿 responsive、collapsible、floating、inset 各形态;主导航空闲时用默认形状,hover 与 active 状态都用更强的 pill 处理;次级工具是紧凑的纯图标控件,依赖原生折叠行为。

DESIGN.md 还主动声明了一条容易被忽略的事实:sidebar-primary/sidebar-primary-foreground已定义但当前这些组件并未消费。这一点可以用仓库搜索验证:sidebar-primary只出现在 tailwind.css(浅色与深色各一处定义),而 app/components/ui/sidebar/ 下的组件实际消费的是text-sidebar-foregroundring-sidebar-ringhover:bg-sidebar-accentdata-active:bg-sidebar-accent等 accent/foreground/border/ring 角色(见 SidebarMenuButtonChild.vue 与 sidebar/index.ts 的工具类组合)。设计文档与源码互相印证:令牌表为"未来的侧边栏主色"预留了槽位,但当前实现走的是 accent 高亮路线。

组件使用纪律

DESIGN.md 的最后一句组件纪律值得单独引用:复用现有 UI 组件及其变体,不要手改app/components/ui/**下的生成组件。这些组件由 components.json 描述的 shadcn-vue 配置管理——style: "reka-maia"cssVariables: truebaseColor: "zinc"、图标库lucideui别名指向@/components/ui。手改生成代码意味着下一次 CLI 同步/升级时会丢失本地修改,因此"新样式应落在业务组件(如 app/components/dashboard/)而不动 ui 层"是隐含的工作流。

交互约定

DESIGN.md Interaction 一节给出三条跨组件规则:

  1. 移动端默认保持 registry 控件尺寸,只有当上下文确实需要更大触控目标时才用更大的官方变体;
  2. 紧凑的上下文动作列表用 menu,更丰富的锚定内容用 popover——这与前文 select"触发器 + popover 内容"的分工是同一套判断;
  3. 浮层套浮层时,焦点直接进入新表面;流程结束后回到发起控件——这是标准的焦点管理约定,与 reka-ui 底层的 focus-trap 行为配合。

另外 tailwind.css 的 base 层为这条交互约定补了两个全局细节:所有可交互的role元素(button、menuitem、tab、option、switch 等)统一cursor-pointer,链接/按钮/输入统一touch-action: manipulation消除移动端双击缩放延迟。

Do's and Don'ts(原文守则)

DESIGN.md 以清单收尾,是整份规范的浓缩版:

Do

  • 使用语义颜色;
  • 在明暗两个主题中都保持背景/前景成对;
  • 复用现有组件;
  • 让 hover、focus、active、invalid、expanded、disabled 状态与相邻实现保持一致。

Don't

  • 不要发明新令牌;
  • 不要把生成出来的工具类选择(如某个rounded-2xl)升格为全局令牌;
  • 不要手改app/components/ui/**

小结与延伸阅读

Sink 的DESIGN.md展示了小型项目中一套非常克制的设计令牌实践:颜色按角色组织、oklch 统一色彩空间、明暗主题成对定义、排版与圆角各留一条令牌、布局与阴影坚决不下沉为全局。frontmatter 服务 Agent 自动化,正文服务人类协作,且全文明确自己相对于 CSS 与组件实现是"派生摘要"的从属地位。

如需深入,可按以下路径继续:

  • 令牌唯一事实来源:app/assets/css/tailwind.css
  • shadcn-vue 生成配置:components.json
  • 组件示例:Button.vue、Card.vue、tabs/index.ts、sidebar 组件目录
  • 主题切换入口:SwitchTheme.vue
  • 业务侧组件(令牌的实际消费方):app/components/dashboard/

【免费下载链接】Sink⚡ A Simple / Speedy / Secure Link Shortener with Analytics, 100% run on Cloudflare.项目地址: https://gitcode.com/GitHub_Trending/si/Sink

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

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

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

立即咨询