@teamix-evo/skills 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/README.md +18 -8
  2. package/_template/SKILL.md.hbs +14 -1
  3. package/manifest.json +79 -6
  4. package/package.json +7 -3
  5. package/src/teamix-evo-code-opentrek/SKILL.md +92 -0
  6. package/src/teamix-evo-code-opentrek/api-layering.md +225 -0
  7. package/src/teamix-evo-code-opentrek/checklist.md +173 -0
  8. package/src/teamix-evo-code-opentrek/error-and-loading.md +269 -0
  9. package/src/teamix-evo-code-opentrek/file-structure.md +273 -0
  10. package/src/teamix-evo-code-opentrek/forms-and-validation.md +220 -0
  11. package/src/teamix-evo-code-opentrek/reuse-first.md +130 -0
  12. package/src/teamix-evo-code-opentrek/routing-and-codesplit.md +298 -0
  13. package/src/teamix-evo-code-opentrek/testing.md +313 -0
  14. package/src/teamix-evo-code-uni-manager/SKILL.md +95 -0
  15. package/src/teamix-evo-code-uni-manager/api-layering.md +370 -0
  16. package/src/teamix-evo-code-uni-manager/checklist.md +193 -0
  17. package/src/teamix-evo-code-uni-manager/error-and-loading.md +389 -0
  18. package/src/teamix-evo-code-uni-manager/file-structure.md +339 -0
  19. package/src/teamix-evo-code-uni-manager/forms-and-validation.md +459 -0
  20. package/src/teamix-evo-code-uni-manager/reuse-first.md +188 -0
  21. package/src/teamix-evo-code-uni-manager/routing-and-codesplit.md +450 -0
  22. package/src/teamix-evo-code-uni-manager/testing.md +396 -0
  23. package/src/teamix-evo-design-opentrek/SKILL.md +71 -0
  24. package/src/teamix-evo-design-opentrek/boundaries.md +513 -0
  25. package/src/teamix-evo-design-opentrek/brand.md +154 -0
  26. package/src/teamix-evo-design-opentrek/checklist.md +83 -0
  27. package/src/teamix-evo-design-opentrek/components.md +245 -0
  28. package/src/teamix-evo-design-opentrek/flows.md +51 -0
  29. package/src/teamix-evo-design-opentrek/foundations.md +271 -0
  30. package/src/teamix-evo-design-opentrek/generation-flow.md +185 -0
  31. package/src/teamix-evo-design-opentrek/patterns/dashboard.md +31 -0
  32. package/src/teamix-evo-design-opentrek/patterns/detail-page.md +202 -0
  33. package/src/teamix-evo-design-opentrek/patterns/form-page.md +289 -0
  34. package/src/teamix-evo-design-opentrek/patterns/list-page.md +334 -0
  35. package/src/teamix-evo-design-opentrek/patterns/page-types.md +154 -0
  36. package/src/teamix-evo-design-opentrek/philosophy.md +96 -0
  37. package/src/teamix-evo-design-opentrek/rules/README.md +39 -0
  38. package/src/teamix-evo-design-opentrek/rules/boundaries.rules.json +391 -0
  39. package/src/teamix-evo-design-uni-manager/SKILL.md +73 -0
  40. package/src/teamix-evo-design-uni-manager/boundaries.md +564 -0
  41. package/src/teamix-evo-design-uni-manager/brand.md +202 -0
  42. package/src/teamix-evo-design-uni-manager/checklist.md +115 -0
  43. package/src/teamix-evo-design-uni-manager/components.md +254 -0
  44. package/src/teamix-evo-design-uni-manager/flows.md +63 -0
  45. package/src/teamix-evo-design-uni-manager/foundations.md +258 -0
  46. package/src/teamix-evo-design-uni-manager/generation-flow.md +194 -0
  47. package/src/teamix-evo-design-uni-manager/patterns/dashboard.md +95 -0
  48. package/src/teamix-evo-design-uni-manager/patterns/detail-page.md +224 -0
  49. package/src/teamix-evo-design-uni-manager/patterns/form-page.md +329 -0
  50. package/src/teamix-evo-design-uni-manager/patterns/list-page.md +356 -0
  51. package/src/teamix-evo-design-uni-manager/patterns/page-types.md +165 -0
  52. package/src/teamix-evo-design-uni-manager/philosophy.md +106 -0
  53. package/src/teamix-evo-design-uni-manager/rules/README.md +49 -0
  54. package/src/teamix-evo-design-uni-manager/rules/boundaries.rules.json +418 -0
  55. package/src/teamix-evo-manage/SKILL.md +281 -0
  56. package/skills/teamix-evo-manage/SKILL.md +0 -138
@@ -0,0 +1,73 @@
1
+ ---
2
+ name: teamix-evo-design-uni-manager
3
+ description: |
4
+ Apply Uni-Manager design system rules (philosophy, patterns, page-types, brand tone/voice, visual foundations) when AI generates or reviews a full UI screen / page in a Uni-Manager-variant project (专有云 / 混合云 / 云管平台 / hybrid cloud console).
5
+ TRIGGER when: user asks to "新建 / 优化 / 重构 一个页面"、"做一个列表页 / 详情页 / 表单页 / 仪表盘 / 控制台首页"、"create / review / refactor a page、screen、dashboard、console、admin template"; intent involves layout structure, page-level information density, or multi-component composition for hybrid-cloud / multi-tenant / multi-region scenarios; file write under `src/pages/**` or `src/templates/**`.
6
+ SKIP: single-component edits like "加个按钮"、"改 input 的 label"; pure tokens/theme overrides; pure code refactor with no visual change; teamix-evo lifecycle commands (defer to teamix-evo-manage).
7
+ Coordinates with: teamix-evo-code-uni-manager (run alongside when the screen also creates new files).
8
+ ---
9
+
10
+ # teamix-evo-design-uni-manager
11
+
12
+ > Uni-Manager 设计体系 — 面向 **专有云 / 混合云 / 多租户管控平台** 的现代设计语言。
13
+ > 高信息密度、强一致性、可枚举可审计;视觉以 hybridcloud 蓝(B50 #0064C8)+ 锐利圆角(2px / 4px)为锚。
14
+ >
15
+ > 本技能是 **完整自包含** 的 Uni-Manager 设计规则(非 overlay over OpenTrek)。
16
+ > Token 具体值请参照 `@teamix-evo/tokens/variants/uni-manager/theme.css` 中的 CSS 变量,组件详细 API 通过 MCP `get_component_meta` 按需查询。
17
+
18
+ <!-- teamix-evo:managed:start id="core" -->
19
+
20
+ ## 意图路由
21
+
22
+ 收到页面相关请求时,按意图分流:
23
+
24
+ | 意图 | 识别关键词 | 执行路径 |
25
+ | -------- | ----------------------------------------------------------------- | ------------------------------------------- |
26
+ | **生成** | "生成" / "创建" / "新建" / "设计一个" / "做一个" / "起一个控制台" | → generation-flow.md 六步流程 |
27
+ | **翻新** | "改造" / "升级" / "翻新" / "对齐规范" / "重新生成" | → generation-flow.md §翻新路径 |
28
+ | **验证** | "检查" / "验证" / "评估" / "是否符合规范" | → checklist.md 逐项对照 |
29
+ | **查询** | "token" / "色值" / "间距" / "组件尺寸" / "圆角" | → foundations.md(MCP `tokens_*` 工具规划中) |
30
+
31
+ ## 三阶段 Dispatch
32
+
33
+ ```
34
+ 阶段 ① 确定页面类型
35
+ → 读 patterns/page-types.md 决策树(含 Console Home / 一致性三件套)
36
+ → 读 components.md 确认组件集(含 um-topbar 实物归属)
37
+
38
+ 阶段 ② 匹配子类型 + 布局
39
+ - List / Detail / Form → patterns/{list|detail|form}-page.md
40
+ - Dashboard / Console → patterns/dashboard.md
41
+ - Dialog/Sheet/Drawer → 视为复合组件(非页面);走 components.md §3.1 选型
42
+ + boundaries.md F8 / F9 / S7 / C2 / FF1-FF4 + UM1-UM3
43
+ → 读 patterns/page-types.md §6 确认页间流转
44
+ → 涉及租户/项目/区域切换、跨云资源旅程时读 flows.md(A 资源查找 / B 创建 / C 异常 / D 批量 / E 上下文切换)
45
+
46
+ 阶段 ③ 生成代码
47
+ → 读 foundations.md (hybridcloud Token 约束 — 锐利圆角 / B50 / 8 档间距)
48
+ → 读 boundaries.md (硬规则 38 + UM1~UM3 专有云增量)
49
+ → MCP get_component_meta(id) 查组件 Props
50
+ → 对照 checklist.md 自检(含 doc 15/16/20 一致性自检)
51
+ ```
52
+
53
+ ## 文件索引
54
+
55
+ | 文件 | 职责 |
56
+ | ------------------------------------------------------------ | ---------------------------------------------------------------------------- |
57
+ | [philosophy.md](./philosophy.md) | 设计哲学 + 四大原则 + 方法论(专有云一致性) |
58
+ | [generation-flow.md](./generation-flow.md) | AI 六步生成/翻新/验证流程 |
59
+ | [boundaries.md](./boundaries.md) | 硬约束:F/FF/S/C/I + UM 共 41+ 条规则([ERROR]/[WARN]) |
60
+ | [checklist.md](./checklist.md) | 12+ 项自检清单(含 hybridcloud 圆角 / 一致性三件套) |
61
+ | [foundations.md](./foundations.md) | hybridcloud Token 用法 + 排版 + 8 档间距 + 色彩 + 锐利圆角 + 4 级阴影 + 动效 |
62
+ | [components.md](./components.md) | 组件选型决策树 + 双层架构索引 + 组合规则(um-topbar 实物归属) |
63
+ | [patterns/page-types.md](./patterns/page-types.md) | 5 种页面类型 + Console Home + 一致性三件套 |
64
+ | [patterns/list-page.md](./patterns/list-page.md) | 列表页模式(多租户 / 多区域筛选) |
65
+ | [patterns/detail-page.md](./patterns/detail-page.md) | 详情页模式(资源详情 / 跨云资源关联) |
66
+ | [patterns/form-page.md](./patterns/form-page.md) | 表单页模式(含 wizard / Drawer 内联表单) |
67
+ | [patterns/dashboard.md](./patterns/dashboard.md) | Dashboard / Console Home(StatCard / Chart 标准结构) |
68
+ | [flows.md](./flows.md) | 5 条核心用户旅程 + 上下文切换(租户/项目/区域) |
69
+ | [brand.md](./brand.md) | Uni-Manager 品牌调性 + 文案语气 + 正反例(B50 + 锐利风) |
70
+ | [rules/README.md](./rules/README.md) | boundaries.md ↔ eslint-config 元数据桥说明 |
71
+ | [rules/boundaries.rules.json](./rules/boundaries.rules.json) | 41+ 条规则的结构化索引 |
72
+
73
+ <!-- teamix-evo:managed:end -->
@@ -0,0 +1,564 @@
1
+ # 硬约束 · Boundaries
2
+
3
+ > 本文件列出所有"AI 生成页面 / 组件代码时**不能做什么**"的硬规则。共 41 条规则分 6 组:
4
+ >
5
+ > - **F1-F10**:禁止项(视觉与 token 层面)
6
+ > - **FF1-FF4**:表单专属硬约束(错误信息、必填、状态色块、Card 嵌套)
7
+ > - **S1-S8**:样式规则(className 写法)
8
+ > - **C1-C12**:组件结构规则(shadcn/ui 复合组件用法)
9
+ > - **I1-I4**:图标规则
10
+ > - **UM1-UM3**:Uni-Manager 专有云一致性硬约束(v0.1+,见 ADR 0030)
11
+ >
12
+ > 严重等级:`ERROR` 必须修复,`WARN` 建议修复。
13
+ >
14
+ > **本文件是硬规则的唯一真值**。其他 skill 文件(patterns / components / brand / philosophy)遇到规则引用一律 `[boundaries.md X#]` inline 链接,不复述。
15
+
16
+ ---
17
+
18
+ ## F1-F10 · 禁止项
19
+
20
+ ### [ERROR] F1 · 禁止硬编码色值
21
+
22
+ ```diff
23
+ - <div style={{ color: '#0064C8' }}>...</div>
24
+ - <div className="text-[#0064C8]">...</div>
25
+ + <div className="text-primary">...</div>
26
+ ```
27
+
28
+ 使用 CSS 变量引用,参照 [foundations.md](./foundations.md) §色彩。
29
+
30
+ > 检查: eslint `teamix-evo/no-color-literal` (JSX/TSX 字符串) · stylelint `teamix-evo/no-color-literal` (CSS 声明)
31
+
32
+ ### [ERROR] F2 · 禁止硬编码尺寸
33
+
34
+ ```diff
35
+ - <input className="h-8 text-xs" />
36
+ + <Input /> {/* 组件已封装 token */}
37
+ ```
38
+
39
+ 不要绕过组件用 Tailwind 任意值(`h-[32px]` / `text-[12px]`)覆盖默认尺寸。
40
+
41
+ > 例外:`*-[var(--xxx)]` 形式(CSS 变量包裹的任意值)允许使用,因为变量本身就是 token。详见 [F7]。
42
+ >
43
+ > 检查: eslint `teamix-evo/no-arbitrary-tw-value` (Tailwind className) · stylelint `teamix-evo/no-hardcoded-dimension` (CSS gap/padding/margin/width/height/font-size 等)
44
+
45
+ ### [ERROR] F3 · 禁止按组件新增重复语义变量
46
+
47
+ 新增 CSS 变量前**必须**先检索 `tokens/variants/uni-manager/theme.css`:
48
+
49
+ - 已有语义匹配的变量 → 直接复用
50
+ - 完全没有可对应变量 → 才允许新增(提交前过 architect subagent 评审)
51
+
52
+ > 检查: 无 lint (人工评审 / architect subagent)
53
+
54
+ ### [ERROR] F4 · 禁止页头添加底色或下边框 · scope: PageHeader
55
+
56
+ ```diff
57
+ - <PageHeader className="bg-card border-b">
58
+ + <PageHeader> {/* 透明无底色 */}
59
+ ```
60
+
61
+ > 检查: 无 lint (人工评审 / Storybook visual diff)
62
+
63
+ ### [ERROR] F5 · outline 按钮禁止使用 border-input · scope: Button
64
+
65
+ ```diff
66
+ - <Button variant="outline" className="border-input">
67
+ + <Button variant="outline"> {/* 默认已使用 border-gray-line */}
68
+ ```
69
+
70
+ > 检查: 无 lint (人工评审 / Button.stories visual diff)
71
+
72
+ ### [ERROR] F6 · 禁止直接写 `font-size: 12px`
73
+
74
+ 使用 token:`text-xs` / `text-sm` / `text-base`,或 CSS 变量 `var(--input-font-size)`。
75
+
76
+ > 检查: stylelint `teamix-evo/no-hardcoded-dimension` (CSS `font-size`) · eslint `teamix-evo/no-arbitrary-tw-value` (Tailwind `text-[12px]`)
77
+
78
+ ### [ERROR] F7 · 语义间距必须走 CSS 变量
79
+
80
+ ```diff
81
+ - <div className="grid gap-4">
82
+ + <div className="grid gap-[var(--card-gap)]">
83
+ ```
84
+
85
+ 适用范围:
86
+
87
+ - **必须用变量**:Card、Tabs、Form、Section 等"具备语义间距"的容器 —— 用 `gap-[var(--card-gap)]` / `gap-[var(--form-gap)]`。
88
+ - **允许用 token 类**:列表、网格、表单内一般行间距等通用容器允许 8 档刻度(`gap-2/4/6` 等已映射 token 的预设类)。
89
+ - **禁止用裸数字任意值**:`gap-[16px]` / `gap-[1rem]` 是 [F2] 禁止的硬编码,永远不允许。
90
+
91
+ 判定关键:`*-[var(--xxx)]` 形态走 token、合规;`*-[16px]` 形态硬编码、违规。
92
+
93
+ > 检查: eslint `teamix-evo/no-arbitrary-tw-value` · stylelint `teamix-evo/no-hardcoded-dimension`
94
+
95
+ ### [ERROR] F8 · 禁止在 DialogTitle 中加图标 · scope: Dialog
96
+
97
+ ```diff
98
+ - <DialogTitle><AlertIcon /> 永久删除</DialogTitle>
99
+ + <DialogTitle>永久删除</DialogTitle>
100
+ ```
101
+
102
+ 标题区只放纯文字。如需视觉提醒,用 `variant="destructive"` 或 DialogDescription 表达。
103
+
104
+ > 检查: 无 lint (人工评审,可由 reviewer subagent 抽检 Dialog 用法)
105
+
106
+ ### [ERROR] F9 · 弹窗确定按钮禁止加 disabled 禁用态 · scope: Dialog
107
+
108
+ ```diff
109
+ - <Button type="submit" disabled={!isValid}>提交</Button>
110
+ + <Button type="submit">提交</Button>
111
+ {/* 始终可点击,校验后通过 inline error / Toast 反馈 */}
112
+ ```
113
+
114
+ 理由:禁用态切断了"为什么不能提交"的反馈链路,改用 inline error 显式说明。
115
+
116
+ > 检查: 无 lint (UX 评审 / scenario-instantiator subagent)
117
+
118
+ ### [WARN] F10 · hover 时禁止将 boxShadow 设为 undefined · scope: HoverCard
119
+
120
+ 切换 box-shadow 必须保留初始值 + 通过 animation 过渡,否则会引发布局抖动。
121
+
122
+ > 检查: 无 lint (Storybook hover 交互验证)
123
+
124
+ ---
125
+
126
+ ## FF1-FF4 · 表单专属硬约束
127
+
128
+ > 来自源仓 `teamix-evo-design/src/form-page.json` 的表单反模式。
129
+ > 注:DialogTitle 不加图标 与 提交按钮不可 disabled 已分别由 [F8] / [F9] 覆盖,本节只收录无重叠的 4 条。
130
+
131
+ ### [ERROR] FF1 · 禁止用色块表达表单状态 · scope: Form
132
+
133
+ ```diff
134
+ - <div className="bg-red-50 border-red-300 p-3">用户名已存在</div>
135
+ + <div className="text-destructive text-sm">用户名已存在</div>
136
+ + {/* 或 */}
137
+ + <Alert variant="destructive">...</Alert>
138
+ ```
139
+
140
+ 表单字段错误用 `text-destructive` 文字 + 图标前缀;页面级错误用 `<Alert>`;不要为单字段错误造彩色块。
141
+
142
+ > 检查: eslint `teamix-evo/no-raw-color-scale` (拦截 `bg-red-50`) · 模式识别需评审
143
+
144
+ ### [WARN] FF2 · Card 不嵌套 Card · scope: Form
145
+
146
+ ```diff
147
+ - <Card>
148
+ - <Card>
149
+ - <FieldGroup>...</FieldGroup>
150
+ - </Card>
151
+ - </Card>
152
+ + <Card>
153
+ + <FieldGroup>...</FieldGroup>
154
+ + <Separator />
155
+ + <FieldGroup>...</FieldGroup>
156
+ + </Card>
157
+ ```
158
+
159
+ 白卡是表单页的**单例容器**。分区表单确需嵌入子 Card 时,子 Card 必须有明确边框/阴影差异,且仅限**分区表单**用例(form-page.md §2.3)。
160
+
161
+ > 检查: 无 lint (人工评审 / reviewer subagent)
162
+
163
+ ### [ERROR] FF3 · 错误信息禁止暴露技术栈痕迹 · scope: Form
164
+
165
+ ```diff
166
+ - <FormMessage>POST /api/users failed: 500 Internal Server Error (stacktrace: ...)</FormMessage>
167
+ - <FormMessage>ERR_DUPLICATE_KEY: violates unique constraint "users_email_key"</FormMessage>
168
+ + <FormMessage>该邮箱已被注册,请换一个或<a>登录</a></FormMessage>
169
+ ```
170
+
171
+ 不允许:HTTP status code、stack trace、SQL 错误片段、ORM 异常名。要给的是**用户能采取的下一步行动**。
172
+
173
+ > 检查: 无 lint (评审 / scenario-instantiator subagent)
174
+
175
+ ### [WARN] FF4 · 必填用红色 `*` 星号,放标签后空格 · scope: Form
176
+
177
+ ```diff
178
+ - <FormLabel>用户名 (required)</FormLabel>
179
+ - <FormLabel>用户名*</FormLabel>
180
+ + <FormLabel required>用户名</FormLabel>
181
+ + {/* 由组件内置渲染 `<span className="text-destructive ml-1">*</span>` */}
182
+ ```
183
+
184
+ 不要 "(required)" / "(必填)" 文本;不要把 `*` 紧贴标签。
185
+
186
+ > 检查: 无 lint (代码评审)
187
+
188
+ ---
189
+
190
+ ## S1-S8 · 样式规则
191
+
192
+ ### [ERROR] S1 · className 仅用于布局,不用于覆盖组件颜色 / 字体
193
+
194
+ ```diff
195
+ - <Button className="bg-blue-100 text-blue-900 font-bold">提交</Button>
196
+ + <Button>提交</Button>
197
+ - <Card className="text-red-500">...</Card>
198
+ + <Card><CardContent className="max-w-md mx-auto">...</CardContent></Card>
199
+ ```
200
+
201
+ className 只允许写**布局相关**类(`flex` / `grid` / `gap-*` / `max-w-*` / `mx-auto`)。
202
+
203
+ > 检查: eslint `teamix-evo/no-color-literal` + `no-raw-color-scale` 拦截显式颜色覆盖;其余命名覆盖需评审。
204
+
205
+ ### [ERROR] S2 · 不用 `space-x-*` / `space-y-*`,改用 `flex + gap-*`
206
+
207
+ ```diff
208
+ - <div className="space-y-4">
209
+ + <div className="flex flex-col gap-4">
210
+ ```
211
+
212
+ > 检查: eslint `teamix-evo/prefer-gap-over-space`
213
+
214
+ ### [WARN] S3 · 等宽高用 `size-*`,不用 `w-* h-*`
215
+
216
+ ```diff
217
+ - <div className="w-10 h-10">
218
+ + <div className="size-10">
219
+ ```
220
+
221
+ > 检查: 无 lint (代码风格评审)
222
+
223
+ ### [WARN] S4 · 用 `truncate` 简写文本截断
224
+
225
+ ```diff
226
+ - <span className="overflow-hidden text-ellipsis whitespace-nowrap">
227
+ + <span className="truncate">
228
+ ```
229
+
230
+ > 检查: 无 lint (代码风格评审)
231
+
232
+ ### [ERROR] S5 · 不用手动 `dark:` 颜色覆盖,用语义 token
233
+
234
+ ```diff
235
+ - <div className="bg-white dark:bg-gray-950 text-black dark:text-white">
236
+ + <div className="bg-background text-foreground">
237
+ ```
238
+
239
+ CSS 变量已在 dark 模式下自动切换(uni-manager `theme.css` 内置)。
240
+
241
+ > 检查: eslint `teamix-evo/no-manual-dark-classnames`
242
+
243
+ ### [ERROR] S6 · 用 `cn()` 处理条件类名,不用模板字符串三元
244
+
245
+ ```diff
246
+ - className={`flex ${isActive ? 'bg-primary' : 'bg-muted'}`}
247
+ + className={cn('flex', isActive ? 'bg-primary text-primary-foreground' : 'bg-muted')}
248
+ ```
249
+
250
+ > 检查: 无 lint (代码评审 / 后续可加 ESLint 规则)
251
+
252
+ ### [ERROR] S7 · overlay 组件不手动设置 z-index
253
+
254
+ ```diff
255
+ - <Dialog><DialogContent className="z-50">
256
+ + <Dialog><DialogContent>
257
+ ```
258
+
259
+ 适用:`Dialog / Sheet / Drawer / Popover / Tooltip / DropdownMenu / HoverCard`。
260
+
261
+ > 检查: 无 lint (运行时 / 评审)
262
+
263
+ ### [ERROR] S8 · 不用原始色值表示状态
264
+
265
+ ```diff
266
+ - <span className="text-emerald-600">运行中</span>
267
+ + <Badge variant="success">运行中</Badge>
268
+
269
+ - <span className="text-red-500">异常</span>
270
+ + <Badge variant="destructive">异常</Badge>
271
+ ```
272
+
273
+ > 检查: eslint `teamix-evo/no-raw-color-scale`
274
+
275
+ ---
276
+
277
+ ## C1-C12 · 组件结构规则
278
+
279
+ ### [ERROR] C1 · Item 必须在 Group 内
280
+
281
+ 适用:`SelectItem / DropdownMenuItem / CommandItem / MenubarItem / ContextMenuItem`
282
+
283
+ ```diff
284
+ - <SelectContent>
285
+ - <SelectItem value="a">Apple</SelectItem>
286
+ - </SelectContent>
287
+ + <SelectContent>
288
+ + <SelectGroup>
289
+ + <SelectItem value="a">Apple</SelectItem>
290
+ + </SelectGroup>
291
+ + </SelectContent>
292
+ ```
293
+
294
+ | Item | Group |
295
+ | ---------------------------------------- | ------------------- |
296
+ | `SelectItem` / `SelectLabel` | `SelectGroup` |
297
+ | `DropdownMenuItem` / `DropdownMenuLabel` | `DropdownMenuGroup` |
298
+ | `CommandItem` | `CommandGroup` |
299
+ | `MenubarItem` | `MenubarGroup` |
300
+ | `ContextMenuItem` | `ContextMenuGroup` |
301
+
302
+ > 检查: 无 lint (后续可加 ESLint JSX 结构规则)
303
+
304
+ ### [ERROR] C2 · Dialog / Sheet / Drawer 必须有 Title
305
+
306
+ ```diff
307
+ - <DialogContent>...</DialogContent>
308
+ + <DialogContent>
309
+ + <DialogHeader>
310
+ + <DialogTitle>编辑配置</DialogTitle>
311
+ + <DialogDescription>修改资源参数</DialogDescription>
312
+ + </DialogHeader>
313
+ + ...
314
+ + </DialogContent>
315
+ ```
316
+
317
+ 无障碍要求。如视觉上不需要标题,用 `<VisuallyHidden>` 或 sr-only 包裹但保留语义。
318
+
319
+ > 检查: eslint `teamix-evo/dialog-must-have-title`
320
+
321
+ ### [WARN] C3 · Card 用完整结构
322
+
323
+ ```diff
324
+ - <Card><CardContent>标题 + 内容 + 操作</CardContent></Card>
325
+ + <Card>
326
+ + <CardHeader>
327
+ + <CardTitle>团队成员</CardTitle>
328
+ + <CardDescription>管理团队访问权限</CardDescription>
329
+ + </CardHeader>
330
+ + <CardContent>...</CardContent>
331
+ + <CardFooter><Button>邀请</Button></CardFooter>
332
+ + </Card>
333
+ ```
334
+
335
+ ### [ERROR] C4 · Button 用 Spinner + disabled 组合表达 loading
336
+
337
+ ```diff
338
+ - <Button isPending>保存中...</Button>
339
+ + <Button disabled><Spinner data-icon="inline-start" /> 保存中...</Button>
340
+ ```
341
+
342
+ 或直接用 `<Button loading>`。
343
+
344
+ ### [ERROR] C5 · TabsTrigger 必须在 TabsList 内
345
+
346
+ ```diff
347
+ - <Tabs><TabsTrigger value="a">账户</TabsTrigger></Tabs>
348
+ + <Tabs defaultValue="account">
349
+ + <TabsList>
350
+ + <TabsTrigger value="account">账户</TabsTrigger>
351
+ + </TabsList>
352
+ + <TabsContent value="account">...</TabsContent>
353
+ + </Tabs>
354
+ ```
355
+
356
+ ### [WARN] C6 · Avatar 必须有 AvatarFallback
357
+
358
+ ```diff
359
+ - <Avatar><AvatarImage src="/avatar.png" /></Avatar>
360
+ + <Avatar>
361
+ + <AvatarImage src="/avatar.png" alt="User" />
362
+ + <AvatarFallback>JD</AvatarFallback>
363
+ + </Avatar>
364
+ ```
365
+
366
+ ### [WARN] C7 · 提示用 Alert,不用自定义 div
367
+
368
+ ```diff
369
+ - <div className="border border-red-500 p-4">Warning...</div>
370
+ + <Alert variant="destructive">
371
+ + <AlertTitle>警告</AlertTitle>
372
+ + <AlertDescription>需要关注的内容</AlertDescription>
373
+ + </Alert>
374
+ ```
375
+
376
+ ### [WARN] C8 · 空状态用 Empty 组件
377
+
378
+ ```diff
379
+ - <div className="flex flex-col items-center p-8">
380
+ - <p>暂无数据</p>
381
+ - <Button>创建</Button>
382
+ - </div>
383
+ + <Empty>
384
+ + <EmptyHeader>
385
+ + <EmptyTitle>暂无实例</EmptyTitle>
386
+ + <EmptyDescription>创建第一个实例以开始</EmptyDescription>
387
+ + </EmptyHeader>
388
+ + <EmptyContent><Button>创建实例</Button></EmptyContent>
389
+ + </Empty>
390
+ ```
391
+
392
+ ### [WARN] C9 · Toast 用 sonner
393
+
394
+ ```diff
395
+ - alert("Changes saved");
396
+ + import { toast } from "sonner";
397
+ + toast.success("已保存修改");
398
+ ```
399
+
400
+ ### [WARN] C10 · 分隔线用 Separator
401
+
402
+ ```diff
403
+ - <hr />
404
+ - <div className="border-t" />
405
+ + <Separator />
406
+ ```
407
+
408
+ ### [WARN] C11 · 加载占位用 Skeleton
409
+
410
+ ```diff
411
+ - <div className="animate-pulse bg-gray-200 h-4 w-3/4" />
412
+ + <Skeleton className="h-4 w-3/4" />
413
+ ```
414
+
415
+ ### [WARN] C12 · 标签 / 状态用 Badge
416
+
417
+ ```diff
418
+ - <span className="rounded-full bg-green-100 text-green-800">运行中</span>
419
+ + <Badge variant="success">运行中</Badge>
420
+ ```
421
+
422
+ ---
423
+
424
+ ## I1-I4 · 图标规则
425
+
426
+ ### [ERROR] I1 · 按钮内图标用 data-icon 属性定位
427
+
428
+ ```diff
429
+ - <Button><SearchIcon className="mr-2 size-4" /> 搜索</Button>
430
+ + <Button><SearchIcon data-icon="inline-start" /> 搜索</Button>
431
+ + <Button>下一步 <ArrowRightIcon data-icon="inline-end" /></Button>
432
+ ```
433
+
434
+ ### [ERROR] I2 · 组件内图标不设尺寸类
435
+
436
+ 适用:`Button` / `DropdownMenuItem` / `Alert` / `Sidebar*`
437
+
438
+ ```diff
439
+ - <Button><SettingsIcon className="mr-2 size-4" /></Button>
440
+ + <Button><SettingsIcon /></Button>
441
+ ```
442
+
443
+ ### [ERROR] I3 · 图标作为组件对象传递
444
+
445
+ ```diff
446
+ - const iconMap = { check: CheckIcon };
447
+ - <StatusBadge icon="check" />
448
+ + function StatusBadge({ icon: Icon }) { return <Icon /> }
449
+ + <StatusBadge icon={CheckIcon} />
450
+ ```
451
+
452
+ ### [ERROR] I4 · 按项目配置的 iconLibrary 导入
453
+
454
+ `@teamix-evo/ui` Uni-Manager 变体默认使用 `lucide-react`。如项目切换图标库,遵循 `tokens.overrides.css` 中的 `--icon-library` 配置。
455
+
456
+ > 检查: eslint `teamix-evo/icon-from-lucide`
457
+
458
+ ---
459
+
460
+ ## UM1-UM3 · Uni-Manager 专有云一致性硬约束
461
+
462
+ > 来自 ADR 0030 / Teamix-UI 规范 doc 15-16-20。这三条是 uni-manager 区别于 opentrek 的核心硬约束,与"一致性是云管平台生命线"的哲学主张呼应(philosophy.md §1)。
463
+
464
+ ### [ERROR] UM1 · 全局 topbar 必须使用 um-topbar 实物 · scope: uni-manager
465
+
466
+ ```diff
467
+ - export default function Layout() {
468
+ - return (
469
+ - <>
470
+ - <header className="flex justify-between p-4 border-b">
471
+ - <Logo /> <UserMenu />
472
+ - </header>
473
+ - <main>{children}</main>
474
+ - </>
475
+ - );
476
+ - }
477
+ + import { UmTopbar } from '@teamix-evo/biz-ui/uni-manager';
478
+ + export default function Layout() {
479
+ + return (
480
+ + <>
481
+ + <UmTopbar />
482
+ + <main>{children}</main>
483
+ + </>
484
+ + );
485
+ + }
486
+ ```
487
+
488
+ 理由:um-topbar 内置 ContextSwitcher(租户/项目/区域)+ Logo + 用户菜单 + 全局通知,是 uni-manager "一致性三件套"之一(brand.md §3.2)。自建 topbar 会破坏跨页面一致性,并丢失 ContextSwitcher 全局可达性(违反 flows.md §1.E 上下文切换旅程)。
489
+
490
+ > 检查: 无 lint (代码评审 / reviewer subagent 抽检 Layout 组件)
491
+
492
+ ### [ERROR] UM2 · PageHeader 必须保持一致性结构 · scope: uni-manager
493
+
494
+ ```diff
495
+ - <div className="flex justify-between mb-4">
496
+ - <h1 className="text-3xl font-bold">实例列表</h1>
497
+ - <div><Button>新建</Button></div>
498
+ - </div>
499
+ + <PageHeader
500
+ + title="实例列表"
501
+ + breadcrumb={[{ label: '云资源' }, { label: '实例' }]}
502
+ + actions={<Button>创建实例</Button>}
503
+ + />
504
+ ```
505
+
506
+ 铁律(与 OpenTrek 共享,但 uni-manager 强化):
507
+
508
+ - 标题字号统一 `text-2xl`(24px),不允许业务页用 `text-3xl` 自我突出
509
+ - 面包屑紧贴标题左侧,操作按钮组统一靠右
510
+ - L1 页面用 `title` 模式(仅标题);L2 页面用 `breadcrumb` 模式
511
+ - 不允许在 PageHeader 内部添加底色 / 下边框(与 F4 一致)
512
+
513
+ > 检查: 无 lint (代码评审 / Storybook visual diff)
514
+
515
+ ### [ERROR] UM3 · 跨云资源列表必须标注 cloud-provider · scope: uni-manager
516
+
517
+ ```diff
518
+ - <DataTable
519
+ - columns={[
520
+ - { key: 'id', title: '实例 ID' },
521
+ - { key: 'region', title: '区域' },
522
+ - { key: 'status', title: '状态' },
523
+ - ]}
524
+ - />
525
+ + <DataTable
526
+ + columns={[
527
+ + { key: 'id', title: '实例 ID', render: (v) => <Mono copyable>{v}</Mono> },
528
+ + { key: 'cloud', title: '所属云', render: (v) => <CloudBadge provider={v} /> },
529
+ + { key: 'region', title: '区域' },
530
+ + { key: 'status', title: '状态', render: (v) => <Badge variant={v} /> },
531
+ + ]}
532
+ + />
533
+ ```
534
+
535
+ 理由:uni-manager 默认场景就是多云,列表中混合阿里云 / 腾讯云 / AWS / 私有 IDC 资源是常态。不标注归属会让用户产生"这是哪朵云的实例"的认知断裂。
536
+
537
+ 例外:明确单云场景(如 `tenant.cloudProviders.length === 1`)可去除该列,但 FilterBar 中仍需保留 cloud 筛选项。
538
+
539
+ > 检查: 无 lint (人工评审 / scenario-instantiator subagent)
540
+
541
+ ---
542
+
543
+ ## Overlay 组件选型表
544
+
545
+ | 场景 | 组件 |
546
+ | ---------------------- | ----------------------------------- |
547
+ | 需要输入的任务 | `Dialog` |
548
+ | 危险操作确认 | `AlertDialog variant="destructive"` |
549
+ | 侧面板(详情 / 筛选) | `Sheet` |
550
+ | 移动端底部面板 | `Drawer` |
551
+ | 悬浮信息(hover 触发) | `HoverCard` |
552
+ | 点击弹出小内容 | `Popover` |
553
+
554
+ ---
555
+
556
+ ## 自定义优先级
557
+
558
+ 需要差异化样式时按以下优先级:
559
+
560
+ 1. **优先**:内置 `variant`(如 `variant="outline"` / `variant="destructive"`)
561
+ 2. **其次**:语义 token(如 `bg-primary` / `text-muted-foreground`)
562
+ 3. **最后**:CSS 变量覆盖(在 `tokens.overrides.css` 中定义)
563
+
564
+ **严禁**:直接 className 覆盖颜色 / 字号 / 尺寸(违反 S1)。