Files
NextEdu/docs/superpowers/specs/2026-07-04-design-tokens-refactor-design.md
SpecialX 214ebec976 refactor(design-tokens): 全量体系化重建设计令牌
Primitive + Semantic 双层令牌架构,HEX->HSL,明暗双份,@theme inline 暴露为 Tailwind 类。

- 新建 src/app/styles/tokens/ 6 个令牌文件(primitive/semantic-light/semantic-dark/lesson-preparation/tailwind-theme/index)
- globals.css 改为 @import 引入,477->258 行
- 清理 91 处 #hex 硬编码颜色 -> hsl(var(--*))
- 清理 10 处硬编码字体 -> var(--font-family-*)
- 清理 100 文件 Tailwind 任意值(Tier 1 映射/Tier 3 注释豁免)
- 清理 M3 Surface 死代码,升级 --lp-* 令牌(HEX->HSL + 暗色补全)
- 新建 ESLint 自定义规则 no-hardcoded-design-tokens(单词边界正则)
- eslint.config.mjs 新增 no-restricted-syntax 禁止 #hex + 自定义规则加载(pathToFileURL)
- 项目规则新增设计令牌规范强制章节
- 架构图 004/005 同步设计令牌体系节点
- known-issues.md 追加设计令牌问题分类(7 个规则表)

验证: tsc --noEmit 0 errors, npm run lint 0 errors/12 warnings(均为既有问题)
2026-07-05 01:03:19 +08:00

25 KiB

设计令牌专项重构 · 设计文档

创建日期:2026-07-04 状态:Draft(待用户审查) 执行方式:大爆炸式(单 PR) 关联规则:docs/architecture/004_architecture_impact_map.md.trae/rules/project_rules.md


1. 背景与目标

1.1 现状摘要

项目当前令牌散落在 src/app/globals.css(477 行)与 tailwind.config.ts(极简,无 theme.extend)。已有 5 类令牌:

  1. shadcn 标准令牌(HSL 格式,完整暗色)
  2. chart-1~5 数据可视化令牌(HSL,完整暗色)
  3. sidebar 令牌(HSL,完整暗色)
  4. --lp-* 备课编辑器令牌(HEX 格式,无暗色,未在 @theme inline 中暴露,无法 bg-lp-paper)
  5. Material Design 3 Surface 映射令牌(在 @theme inline 中,经扫描零使用,属死代码)

1.2 关键技术债

扫描结果:

问题类型 出现次数 文件数
硬编码颜色 #xxx 91 处 15 文件
硬编码字体 'Inter'/'Fraunces'/'JetBrains Mono' 8 处 2 文件
硬编码 font-size: Npx 15 处 3 文件
Tailwind 任意值 w-[Npx]/h-[Npx]/p-[Npx]/... 98 处 40 文件
缺失:font/spacing/shadow/text-size 尺度令牌
--lp-* 无暗色 / 未暴露为 Tailwind 类
M3 Surface 令牌零使用(死代码)

项目规则(.trae/rules/project_rules.md)明确禁止"任意值"和"动态拼接类名",但实际任意值已散落到 40 个文件,需要专项治理。

1.3 重构目标

  • 核心目标:全量体系化重建设计令牌,建立完整令牌契约,清理全部硬编码与任意值
  • 命名体系:双层架构(Primitive + Semantic)+ shadcn 语义扩展
  • 覆盖范围:font/size/leading/weight/radius/shadow/spacing/duration/ease/z-index 全阶梯
  • 暗色覆盖:明暗双色全面覆盖(所有令牌都有 :root.dark 双份)
  • 强制约束:ESLint 规则 + 注释豁免,防止技术债复发

2. 令牌架构

2.1 双层架构

┌──────────────────────────────────────────────────────────────────┐
│  Layer 1: Primitive (Raw Tokens) — 原始色板/字号/间距/阴影         │
│  ─────────────────────────────────────────────────────────────  │
│  命名: --color-zinc-50 ~ 950                                      │
│        --color-stone-50 ~ 950                                     │
│        --color-indigo-500/600                                     │
│        --font-size-1 ~ --font-size-9                              │
│        --space-0 ~ --space-32                                     │
│        --shadow-1 ~ --shadow-6                                    │
│        --font-family-sans/serif/mono                              │
│  特征: 不直接使用,只被 Semantic 层引用                            │
│  主题: 无主题差异(色板层不区分明暗)                               │
└──────────────────────────────────────────────────────────────────┘
                                ▲ 引用
                                │
┌──────────────────────────────────────────────────────────────────┐
│  Layer 2: Semantic (Component/Context Tokens) — 语义层            │
│  ─────────────────────────────────────────────────────────────  │
│  shadcn 兼容: --background / --foreground / --primary / ...      │
│  扩展层级:   --background-elevated / --text-secondary / ...      │
│  模块命名空间: --lp-* (lesson-preparation)                       │
│  chart/sidebar: --chart-1~5 / --sidebar-*                         │
│  特征: 业务代码唯一引用入口,Tailwind 通过 @theme inline 暴露      │
│  主题: :root 与 .dark 双份定义,所有令牌都有暗色                  │
└──────────────────────────────────────────────────────────────────┘
                                ▲ 引用
                                │
┌──────────────────────────────────────────────────────────────────┐
│  Layer 3: Tailwind 类 (via @theme inline)                         │
│  ─────────────────────────────────────────────────────────────  │
│  bg-background / text-foreground / bg-primary / ...              │
│  bg-lp-paper / text-lp-inline-node-meta / ...                    │
│  font-sans / font-serif / font-mono                               │
│  text-size-2 / leading-snug / weight-semibold                    │
│  radius-md / shadow-2 / space-4 / duration-fast / z-modal        │
└──────────────────────────────────────────────────────────────────┘

2.2 核心原则

  • 业务代码 只引用 Semantic 层(直接 var(--background) 或 Tailwind 类 bg-background),禁止引用 Primitive 层
  • Primitive 层只为 Semantic 层提供"原材料",便于未来多主题切换(只改 Semantic 层映射,不动 Primitive)
  • shadcn 命名严格保留(--background/--foreground/--primary 等),shared/components/ui/* 零改动
  • --lp-* 保留命名空间(已有 9 文件使用,改名风险大),但补全暗色与 Tailwind 暴露

2.3 文件分布

当前 globals.css 477 行,补全令牌后估算 1200+ 行,超过项目规则硬性上限 1000 行。拆分为令牌专题目录:

src/app/
├─ globals.css                      # 仅保留 @import、base layer、组件硬编码样式清理后的样式
└─ styles/
   └─ tokens/
      ├─ primitive.css              # Layer 1: 原始色板/字号/间距/阴影阶梯
      ├─ semantic-light.css         # Layer 2: :root 语义令牌(明色)
      ├─ semantic-dark.css          # Layer 2: .dark 语义令牌(暗色)
      ├─ lesson-preparation.css     # --lp-* 令牌(明暗双份)
      ├─ tailwind-theme.css         # @theme inline 暴露规则
      └─ index.css                  # 汇总 @import 入口

globals.css 顶部改为:

@import "tailwindcss";
@import "./styles/tokens/index.css";
@plugin "tailwindcss-animate";
@plugin "@tailwindcss/typography";
@custom-variant dark (&:where(.dark, .dark *));

2.4 Tailwind v4 集成

tailwind.config.ts 保持极简(只 content + plugins),所有令牌通过 @theme inlinetailwind-theme.css 中暴露。


3. Primitive 层(原始阶梯)

3.1 色板(以 Zinc 为基准中性色,与现有 shadcn 一致)

/* primitive.css */
:root {
  /* Zinc 中性色板(shadcn 默认) */
  --color-zinc-50: 0 0% 99%;
  --color-zinc-100: 240 4.8% 95.9%;
  --color-zinc-200: 240 5.9% 90%;
  --color-zinc-300: 240 4.8% 83.9%;
  --color-zinc-400: 240 5% 64.9%;
  --color-zinc-500: 240 3.8% 46.1%;
  --color-zinc-600: 240 5.2% 33.9%;
  --color-zinc-700: 240 5.3% 26.1%;
  --color-zinc-800: 240 5.9% 10%;
  --color-zinc-900: 240 5.9% 3.9%;
  --color-zinc-950: 240 10% 3.9%;

  /* Stone 暖灰(用于 lp-* 纸感,与现有 --lp-paper-edge #f8f8f7 对齐) */
  --color-stone-50: 60 4.8% 95.9%;
  --color-stone-100: 60 5.1% 90%;
  --color-stone-200: 20 5.9% 90%;
  --color-stone-300: 24 5.7% 82.9%;
  --color-stone-400: 24 5.4% 63.9%;
  --color-stone-500: 25 5.1% 44.7%;
  --color-stone-600: 33 5% 39.8%;
  --color-stone-700: 30 5.2% 32.7%;
  --color-stone-800: 12 6.5% 31.4%;
  --color-stone-900: 24 10% 10%;
  --color-stone-950: 20 14.3% 4.1%;

  /* Indigo 强调色(lp-interaction 用) */
  --color-indigo-500: 238.7 83.5% 66.7%;
  --color-indigo-600: 238.6 84.5% 59.8%;
}

说明: 仅记录 Primitive 原料,业务代码不直接引用。

3.2 字号阶梯(替代硬编码 13.5px/14px/12.5px 等)

Token 用途
--font-size-1 12px 元信息/角色标签
--font-size-2 13px inline-node body
--font-size-3 13.5px inline-node 主文(备课纸感)
--font-size-4 14px 标题/按钮
--font-size-5 16px 正文(Fraunces 16px)
--font-size-6 18px H2
--font-size-7 20px H1
--font-size-8 24px 区块标题
--font-size-9 32px 页面标题

3.3 间距阶梯(覆盖 98 处任意值)

Token 替代示例
--space-0 0
--space-0_5 0.125rem (2px) p-[2px]
--space-1 0.25rem (4px) p-[4px]
--space-1_5 0.375rem (6px) gap-[6px]
--space-2 0.5rem (8px)
--space-2_5 0.625rem (10px) p-[10px]
--space-3 0.75rem (12px)
--space-3_5 0.875rem (14px) p-[14px]
--space-4 1rem (16px)
--space-5 1.25rem (20px) m-[20px]
--space-6 1.5rem (24px)
--space-7 1.75rem (28px) w-[28px] (lp-tb-btn)
--space-8 2rem (32px)
--space-10 2.5rem (40px)
--space-12 3rem (48px)
--space-16 4rem (64px)
--space-18 4.5rem (72px) px-[72px] (lp-paper-toolbar)

3.4 阴影阶梯(替代硬编码 box-shadow)

Token 替代
--shadow-1 0 1px 2px rgba(15,15,15,0.04) shadow-xs
--shadow-2 0 1px 3px rgba(15,15,15,0.06), 0 1px 2px rgba(15,15,15,0.04) shadow-sm
--shadow-3 0 4px 6px rgba(15,15,15,0.05), 0 2px 4px rgba(15,15,15,0.04) shadow-md
--shadow-4 0 1px 2px rgba(15,15,15,0.04), 0 8px 24px rgba(15,15,15,0.04) lp-paper-shadow
--shadow-5 0 1px 2px rgba(15,15,15,0.06), 0 12px 36px rgba(15,15,15,0.08) lp-paper-shadow-active
--shadow-6 0 10px 15px rgba(15,15,15,0.1), 0 4px 6px rgba(15,15,15,0.05) shadow-xl

3.5 字体家族(替代 8 处硬编码)

Token 用途
--font-family-sans 'Inter', system-ui, sans-serif UI 元素
--font-family-serif 'Fraunces', Georgia, serif 主文/备课纸感
--font-family-mono 'JetBrains Mono', monospace 角色标签

4. Semantic 层(shadcn 扩展 + lp-* 升级 + M3 清理)

4.1 shadcn 标准令牌(零改动,确保 ui/ 兼容)

--background/--foreground/--card/--popover/--primary/--secondary/--muted/--accent/--destructive/--border/--input/--ring/--radius 全部保留现有 HSL 值,:root.dark 双份定义不变。

4.2 语义层扩展(新增层级)

Token 明色 HSL 暗色 HSL 用途
--background-elevated 0 0% 100% 240 6% 10% 浮层/card-on-card
--background-sunken 240 4.8% 95.9% 240 6% 8% 凹陷区/inset
--text-primary = --foreground = --foreground 主文
--text-secondary 240 3.8% 46.1% 240 5% 64.9% 副文(= muted-foreground)
--text-tertiary 240 4% 65% 240 5% 50% 占位/元信息
--border-strong 240 5.9% 70% 240 5% 40% 强调边框
--border-subtle 240 5.9% 95% 240 5% 18% 弱边框

说明: --text-secondary 等是 --muted-foreground 的语义别名,业务代码优先用语义名。

4.3 chart-1~5 / sidebar 令牌(零改动)

保留现有 HSL 值,:root.dark 双份定义不变。

4.4 --lp-* 令牌升级(HEX→HSL + 暗色 + Tailwind 暴露)

明色(:root):

Token 旧 HEX 新 HSL 说明
--lp-paper #fefefe 0 0% 99.6% 纸面
--lp-paper-edge #f8f8f7 60 9% 97% 纸边(对齐 stone-100)
--lp-paper-shadow (box-shadow) = --shadow-4 引用 阴影令牌化
--lp-paper-shadow-active (box-shadow) = --shadow-5 引用 阴影令牌化
--lp-anchor-range rgba(28,25,23,0.08) 20 14.3% 4.1% / 0.08 引用 stone-950
--lp-anchor-range-active rgba(28,25,23,0.16) 20 14.3% 4.1% / 0.16
--lp-anchor-point #1c1917 20 14.3% 4.1% = stone-950
--lp-inline-node-border #d6d3d1 30 5.7% 82.9% = stone-300
--lp-inline-node-text #44403c 24 5.4% 26.9% ≈ stone-700 微调
--lp-inline-node-meta #a8a29e 30 5% 64.9% = stone-400
--lp-interaction #6366f1 238.6 84.5% 59.8% = indigo-600

12 个 --lp-dot- 节点色点*: 全部映射到 zinc/stone 色板对应值,统一为 HSL。

暗色(.dark): 全部补齐。例如:

  • --lp-paper: 240 6% 10%(暗背景纸面)
  • --lp-paper-edge: 240 6% 8%
  • --lp-anchor-point: 0 0% 98%(反相)
  • --lp-interaction: 238.7 83.5% 66.7%(= indigo-500,暗色微亮)

4.5 M3 Surface 映射令牌清理

globals.css:185-198 中的 M3 令牌零使用(已扫描确认),全部删除:

  • --color-surface / --color-on-surface / --color-on-surface-variant
  • --color-surface-container-lowest/low/high/highest
  • --color-outline-variant / --color-outline
  • --color-error / --color-tertiary / --color-tertiary-container

4.6 globals.css 硬编码样式令牌化

硬编码 令牌化后
.lp-tb-btn { width: 28px; ... font-family: 'Inter'; font-size: 13px; color: var(--foreground) } width: var(--space-7); font-family: var(--font-family-sans); font-size: var(--font-size-2); color: hsl(var(--foreground))
.lp-inline-node { font-family: 'Inter'; font-size: 13.5px; ... border-left: 2px solid var(--lp-inline-node-border); color: var(--lp-inline-node-text) } 全部用令牌引用
.lp-qa-role.teacher { color: #1c1917 } color: hsl(var(--lp-anchor-point))
.lp-qa-role.student { color: #6b7280 } color: hsl(var(--color-zinc-500))
.lp-inline-node-title { color: #1a1a1a } color: hsl(var(--lp-anchor-point))
.lp-inline-node-body { color: #404040 } color: hsl(var(--lp-inline-node-text))
.lp-qa-content { color: #404040 } 同上
.lp-qa-prompt { color: #525252 } color: hsl(var(--color-zinc-600))
.range-anchor { background-color: var(--node-color, #1976d2) } fallback 改为 hsl(var(--lp-interaction))

5. 尺度令牌补齐清单

5.1 圆角阶梯

Token Tailwind 类
--radius-sm calc(var(--radius) - 4px) rounded-sm
--radius-md calc(var(--radius) - 2px) rounded-md
--radius-lg var(--radius) = 0.5rem rounded-lg
--radius-xl calc(var(--radius) + 4px) rounded-xl
--radius-2xl calc(var(--radius) + 8px) rounded-2xl
--radius-full 9999px rounded-full

5.2 行高与字重

Token
--leading-tight 1.2
--leading-snug 1.35
--leading-normal 1.5
--leading-relaxed 1.65
--leading-loose 1.8
--weight-regular 400
--weight-medium 500
--weight-semibold 600
--weight-bold 700

5.3 动效与 z-index

Token Tailwind 类
--duration-fast 150ms duration-fast
--duration-normal 200ms duration-normal
--duration-slow 300ms duration-slow
--ease-in cubic-bezier(0.4, 0, 1, 1) ease-in
--ease-out cubic-bezier(0, 0, 0.2, 1) ease-out
--ease-in-out cubic-bezier(0.4, 0, 0.2, 1) ease-in-out
--z-dropdown 1000 z-dropdown
--z-sticky 1100 z-sticky
--z-modal 1300 z-modal
--z-popover 1400 z-popover
--z-toast 1500 z-toast

6. 硬编码清理映射表(分级)

6.1 91 处 #hex 颜色 — 按文件分类

文件 处数 清理策略
app/globals.css 32 全部令牌化(见 4.6 节)
app/manifest.ts 2 保留(theme_color 元数据,需字面量),加注释 // arbitrary-value: PWA manifest requires literal hex
app/layout.tsx 2 检查后令牌化或注释
shared/components/ui/chart.tsx 5 令牌化(用 --chart-1~5)
modules/notifications/channels/email-channel.ts 7 保留(邮件 HTML 内联样式需字面量),加注释
modules/textbooks/components/knowledge-graph.tsx 10 令牌化(用 --chart-* 或新增 --graph-node-*)
modules/textbooks/components/force-graph.tsx 17 同上
modules/lesson-preparation/components/paper-editor/* ~6 令牌化(用 --lp-*)
modules/attendance/components/attendance-grade-correlation-card.tsx 3 令牌化(用 --chart-*)
modules/classes/components/my-classes-grid.tsx 2 令牌化
modules/lesson-preparation/components/version-diff-view.tsx 1 令牌化(用 --lp-* 或新增 --diff-add/--diff-remove)

新增语义令牌:

  • --diff-add / --diff-add-bg(版本对比新增)
  • --diff-remove / --diff-remove-bg(版本对比删除)
  • --graph-node-1 ~ --graph-node-6(知识图谱节点色)

6.2 8 处硬编码 font-family — 全部令牌化

文件 处数 令牌化
app/globals.css 7 var(--font-family-sans) / var(--font-family-serif) / var(--font-family-mono)
modules/lesson-preparation/components/paper-editor/textbook-tiptap-editor.tsx 1 同上

6.3 15 处硬编码 font-size — 全部令牌化

文件 处数 令牌化
app/globals.css 13 var(--font-size-N)
modules/notifications/channels/email-channel.ts 1 保留(邮件 HTML),加注释
modules/lesson-preparation/components/paper-editor/textbook-tiptap-editor.tsx 1 var(--font-size-N)

6.4 98 处 Tailwind 任意值 — 分级清理

Tier 1 — 直接映射 Tailwind 默认阶梯(约 40 处):

  • w-[28px]w-7(28px ≈ 1.75rem,但 w-7 = 1.75rem ✓)
  • gap-[6px]gap-1.5(6px = 0.375rem,gap-1.5 ✓)
  • p-[10px] → 需新增 --space-2_5(10px = 0.625rem)
  • text-[13px]text-size-2(13px = --font-size-2)

Tier 2 — 新增间距令牌后引用(约 30 处):

  • w-[72px]w-space-18(--space-18 = 4.5rem)
  • h-[16px]h-space-4(--space-4 = 1rem)
  • p-[20px]p-space-5(--space-5 = 1.25rem)

Tier 3 — 注释豁免(约 28 处):

  • 图表 SVG 尺寸(如 w-[400px] 在 chart 容器)→ 加注释 // arbitrary-value: chart canvas fixed size
  • 邮件 HTML 内联样式
  • loading.tsx 占位骨架特殊尺寸

ESLint 规则: tailwindcss/no-arbitrary-value: error,允许通过 // eslint-disable-next-line + 注释理由豁免。


7. 强制约束机制

7.1 ESLint 规则新增

新增依赖: eslint-plugin-tailwindcss(需验证与 Tailwind v4 兼容性,若不兼容则自定义规则)

eslint.config.mjs 新增规则:

{
  // 禁止 Tailwind 任意值(允许 eslint-disable + 注释豁免)
  'tailwindcss/no-arbitrary-value': 'error',
  // 禁止 TSX/CSS 中硬编码颜色字面量(白名单:globals.css primitive 定义、email-channel.ts、manifest.ts)
  'no-restricted-syntax': [
    'error',
    {
      selector: "Literal[value=/#[0-9a-fA-F]{3,8}/]",
      message: '禁止硬编码 hex 颜色,使用设计令牌 var(--*) 或 Tailwind 类 bg-*',
    },
  ],
}

自定义规则文件: eslint-rules/no-hardcoded-design-tokens.js

  • 检测 TSX/TS 中 'Inter'/'Fraunces'/'JetBrains Mono' 字面量
  • 检测 font-family: CSS 属性中的字面量字体名
  • 检测 font-size: Npx 硬编码
  • 白名单:globals.cssstyles/tokens/*.cssemail-channel.tsmanifest.ts

7.2 项目规则更新

.trae/rules/project_rules.md "Tailwind 规范"章节新增:

### 设计令牌规范(强制)

- **禁止硬编码颜色**: TSX/TS/CSS 中不得出现 `#hex` 颜色字面量,统一使用 `var(--*)` 或 Tailwind 类
- **禁止硬编码字体**: 不得出现 `'Inter'`/`'Fraunces'`/`'JetBrains Mono'` 字面量,使用 `var(--font-family-sans/serif/mono)`
- **禁止硬编码字号**: 不得出现 `font-size: Npx`,使用 `var(--font-size-1~9)`
- **禁止 Tailwind 任意值**: 不得使用 `w-[Npx]`/`h-[Npx]`/`p-[Npx]` 等,映射到 `--space-*` 或 Tailwind 默认阶梯
- **豁免场景**(需 `// arbitrary-value: <reason>` 注释):
  - PWA manifest(`app/manifest.ts`)
  - 邮件 HTML 内联样式(`email-channel.ts`)
  - 图表 SVG 固定画布尺寸
  - loading.tsx 占位骨架
- **令牌文件分布**: `src/app/styles/tokens/`(primitive/semantic-light/semantic-dark/lesson-preparation/tailwind-theme)
- **改令牌必同步图**: 修改令牌定义后,同步更新 `docs/architecture/004``005`

7.3 Lint 命令不变

npm run lintnpx tsc --noEmit 保持零错误零警告。


8. 验证策略与架构图同步

8.1 验证清单

验证项 命令/方法 通过标准
TypeScript npx tsc --noEmit 零错误
ESLint npm run lint 零错误零警告
视觉回归 npm run test:visual 快照无差异(或更新后人工确认)
备课编辑器视觉 手动检查 teacher/lesson-plans/[id]/edit 纸感、inline-node、师生对话样式无变化
暗色模式 切换暗色主题 所有页面可读,无对比度问题
shadcn ui 组件 抽查 button/card/dialog/table 零回归

8.2 架构图同步(项目规则强制)

修改完成后,同步更新:

文档 同步内容
docs/architecture/004_architecture_impact_map.md 新增"设计令牌体系"章节(双层架构图、文件分布、令牌分类)
docs/architecture/005_architecture_data.json modules.shared.exports 新增 design-tokens 节点;dependencyMatrix 新增令牌依赖关系
docs/troubleshooting/known-issues.md 新增"设计令牌"问题分类,记录 Tailwind v4 + ESLint 兼容性、HEX→HSL 转换、任意值豁免规则

8.3 大爆炸式执行顺序(单 PR 内)

  1. 创建 src/app/styles/tokens/ 6 个文件(primitive/semantic-light/semantic-dark/lesson-preparation/tailwind-theme/index)
  2. globals.css 改为 @import 引入,删除已迁移内容
  3. globals.css 中剩余硬编码样式令牌化(lp-tb-btn/lp-inline-node/lp-qa-*)
  4. 全局扫描替换:91 处 #hex → 令牌引用(按 6.1 表)
  5. 全局扫描替换:8 处 font-family + 15 处 font-size → 令牌引用(按 6.2/6.3 表)
  6. 全局扫描替换:98 处任意值 → Tier 1/2/3 分级处理(按 6.4 表)
  7. ESLint 规则新增 + 自定义规则文件
  8. 项目规则文档更新
  9. 架构图同步(004/005)
  10. docs/troubleshooting/known-issues.md 更新
  11. npm run lint + npx tsc --noEmit + npm run test:visual 验证
  12. 单次 commit:refactor(design-tokens): 全量体系化重建设计令牌

9. 风险与缓解

风险 缓解
Tailwind v4 + eslint-plugin-tailwindcss 兼容性未知 实施时先验证,不兼容则自定义 AST 规则
大爆炸式改动 50+ 文件,review 困难 严格按 8.3 执行顺序,每步独立验证;视觉回归测试保障
--lp-* HEX→HSL 转换可能有色差 视觉回归测试 + 手动备课编辑器检查
98 处任意值分级清理可能遗漏 Tier 3 注释豁免需明确理由,ESLint 规则锁定
暗色补全可能对比度不足 暗色模式手动抽查所有页面
shadcn ui 组件理论零改动但需验证 抽查 button/card/dialog/table 4 个核心组件

10. 范围与非目标

10.1 范围内

  • 令牌底座重建(Primitive + Semantic 双层)
  • 尺度令牌补齐(font/size/leading/weight/radius/shadow/spacing/duration/ease/z-index)
  • --lp-* 升级(HEX→HSL + 暗色 + Tailwind 暴露)
  • M3 Surface 死代码清理
  • 91 处硬编码颜色清理
  • 8 处硬编码 font-family 清理
  • 15 处硬编码 font-size 清理
  • 98 处 Tailwind 任意值清理
  • ESLint 强制约束规则
  • 项目规则文档更新
  • 架构图同步(004/005)
  • known-issues.md 更新

10.2 范围外(非目标)

  • 第三主题(如 high-contrast、paper 纸感)预留 — YAGNI
  • shared/components/ui/* shadcn 组件内部样式改动 — 理论零改动,仅验证
  • cn() 工具函数修改 — 不变
  • tailwind.config.ts 内容扩展 — 保持极简
  • 设计令牌文档站(Storybook 等)— 不在本期范围
  • 多主题切换架构 — 仅明暗双色