openxiangda 1.0.27 → 1.0.29

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.
@@ -1,492 +1,222 @@
1
- # OpenXiangda 样式体系参考
2
-
3
- > 本文档面向 AI Agent,约束代码页面/表单/工作流自定义节点的样式编写规范。**严禁硬编码颜色、间距、圆角、字号、阴影**,统一通过三层变量体系消费设计 Token。
4
-
5
- ---
6
-
7
- ## 1. 样式体系总览
8
-
9
- ### 1.1 三层结构
10
-
11
- ```
12
- ┌──────────────────────────────────────────────────────────────┐
13
- Layer 3: Tailwind Utilities (原子类层) │
14
- │ 语义化类名 → 引用 CSS Variables │
15
- │ 例: text-primary, bg-container, gap-form, rounded-form │
16
- └──────────────────────────────────────────────────────────────┘
17
-
18
- │ 引用
19
-
20
- ┌──────────────────────────────────────────────────────────────┐
21
- │ Layer 2: AntD Theme Token (组件库层) │
22
- │ ConfigProvider.theme.token 映射到 CSS Variables │
23
- │ 例: colorPrimary: var(--sy-color-primary) │
24
- └──────────────────────────────────────────────────────────────┘
25
-
26
- 映射
27
-
28
- ┌──────────────────────────────────────────────────────────────┐
29
- │ Layer 1: CSS Variables (基础层 / Single Source of Truth) │
30
- │ --sy-color-*, --sy-spacing-*, --sy-radius-*, --sy-shadow-* │
31
- │ 定义在 :root 与 .sy-app-workspace │
32
- └──────────────────────────────────────────────────────────────┘
33
- ```
34
-
35
- **核心原则**:所有视觉 Token 来源于 Layer 1 的 CSS Variables;AntD 与 Tailwind 都只是 Layer 1 的消费者。
36
-
37
- ### 1.2 为什么不使用 Shadow DOM
38
-
39
- | 维度 | Shadow DOM | CSS Namespace(当前方案)|
40
- |---|---|---|
41
- | antd 弹层(Modal/Drawer/Select 下拉/DatePicker)| **失效** —— 默认挂载到 `document.body`,逃出 Shadow 边界后丢失样式 | **正常** —— 通过 `getPopupContainer` 挂载到 `.sy-app-workspace` 内 |
42
- | 全局样式继承 | 完全隔离,需重写所有基础样式 | 受控隔离,通过命名空间避免冲突 |
43
- | 调试体验 | DevTools 跨边界困难 | 与普通 DOM 一致 |
44
- | 主题切换 | 必须穿透 Shadow Root | 直接覆盖 `.sy-app-workspace` 上的 CSS 变量 |
45
-
46
- **结论**:Shadow DOM 与 antd 的 Portal 弹层机制不兼容;改用 `.sy-app-workspace` 命名空间方案。
47
-
48
- ### 1.3 CSS Namespace 隔离原理
49
-
50
- - 应用根节点统一加 `class="sy-app-workspace"`。
51
- - 所有自定义样式(Tailwind、业务 CSS)通过 `.sy-app-workspace` 前缀限定作用域。
52
- - AntD CSS-in-JS 通过 `ConfigProvider.theme.cssVar.prefix = 'sy-ant'` 输出独立变量名,避免与宿主页面碰撞。
53
- - 弹层容器通过 `getPopupContainer={() => document.querySelector('.sy-app-workspace')}` 锚定到命名空间内部。
54
-
55
- ---
56
-
57
- ## 2. Layer 1:CSS Variables 设计 Token
58
-
59
- > 唯一真源(Single Source of Truth)。**所有变量同时挂载在 `:root` 与 `.sy-app-workspace`**,前者用于全局可用,后者保证命名空间生效时不依赖根选择器。
60
-
61
- ```css
62
- :root, .sy-app-workspace {
63
- /* ───── 品牌色 ───── */
64
- --sy-color-primary: #1677ff;
65
- --sy-color-primary-hover: #4096ff;
66
- --sy-color-primary-active: #0958d9;
67
- --sy-color-success: #52c41a;
68
- --sy-color-warning: #faad14;
69
- --sy-color-error: #ff4d4f;
70
-
71
- /* ───── 文本 ───── */
72
- --sy-color-text: rgba(0, 0, 0, 0.88);
73
- --sy-color-text-secondary: rgba(0, 0, 0, 0.65);
74
- --sy-color-text-tertiary: rgba(0, 0, 0, 0.45);
75
- --sy-color-text-disabled: rgba(0, 0, 0, 0.25);
76
-
77
- /* ───── 背景 ───── */
78
- --sy-color-bg-container: #ffffff;
79
- --sy-color-bg-layout: #f5f5f5;
80
- --sy-color-bg-elevated: #ffffff;
81
-
82
- /* ───── 边框 ───── */
83
- --sy-color-border: #d9d9d9;
84
- --sy-color-border-secondary: #f0f0f0;
85
-
86
- /* ───── 间距 ───── */
87
- --sy-spacing-xs: 4px;
88
- --sy-spacing-sm: 8px;
89
- --sy-spacing-md: 16px;
90
- --sy-spacing-lg: 24px;
91
- --sy-spacing-xl: 32px;
92
-
93
- /* ───── 圆角 ───── */
94
- --sy-radius-sm: 4px;
95
- --sy-radius-md: 6px;
96
- --sy-radius-lg: 8px;
97
-
98
- /* ───── 字体 ───── */
99
- --sy-font-size-sm: 12px;
100
- --sy-font-size-base: 14px;
101
- --sy-font-size-lg: 16px;
102
- --sy-font-size-xl: 20px;
103
- --sy-font-size-2xl: 24px;
104
-
105
- /* ───── 阴影 ───── */
106
- --sy-shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.03), 0 1px 6px -1px rgba(0, 0, 0, 0.02);
107
- --sy-shadow-md: 0 6px 16px rgba(0, 0, 0, 0.08), 0 3px 6px -4px rgba(0, 0, 0, 0.12);
108
- --sy-shadow-lg: 0 12px 40px rgba(0, 0, 0, 0.12);
109
-
110
- /* ───── 表单特定 ───── */
111
- --sy-form-gap: 16px;
112
- --sy-form-padding: 24px;
113
- --sy-form-field-height: 32px;
114
- }
115
- ```
116
-
117
- ### 2.1 Token 速查表
118
-
119
- | 类别 | 变量 | 默认值 | 用途 |
120
- |---|---|---|---|
121
- | 品牌 | `--sy-color-primary` | `#1677ff` | 主按钮、主色链接、激活态 |
122
- | 品牌 | `--sy-color-primary-hover` | `#4096ff` | 主色 hover |
123
- | 品牌 | `--sy-color-primary-active` | `#0958d9` | 主色 active/pressed |
124
- | 状态 | `--sy-color-success` | `#52c41a` | 成功/通过 |
125
- | 状态 | `--sy-color-warning` | `#faad14` | 警示 |
126
- | 状态 | `--sy-color-error` | `#ff4d4f` | 错误/危险操作 |
127
- | 文本 | `--sy-color-text` | `rgba(0,0,0,.88)` | 主文本 |
128
- | 文本 | `--sy-color-text-secondary` | `rgba(0,0,0,.65)` | 次文本 |
129
- | 文本 | `--sy-color-text-tertiary` | `rgba(0,0,0,.45)` | 提示/占位 |
130
- | 文本 | `--sy-color-text-disabled` | `rgba(0,0,0,.25)` | 禁用 |
131
- | 背景 | `--sy-color-bg-container` | `#ffffff` | 卡片/输入框 |
132
- | 背景 | `--sy-color-bg-layout` | `#f5f5f5` | 页面底色 |
133
- | 背景 | `--sy-color-bg-elevated` | `#ffffff` | 浮层/抽屉 |
134
- | 边框 | `--sy-color-border` | `#d9d9d9` | 实体边框 |
135
- | 边框 | `--sy-color-border-secondary` | `#f0f0f0` | 分隔线 |
136
- | 间距 | `--sy-spacing-{xs\|sm\|md\|lg\|xl}` | 4/8/16/24/32 | 通用间距 |
137
- | 圆角 | `--sy-radius-{sm\|md\|lg}` | 4/6/8 | 通用圆角 |
138
- | 字号 | `--sy-font-size-{sm\|base\|lg\|xl\|2xl}` | 12/14/16/20/24 | 字号阶梯 |
139
- | 阴影 | `--sy-shadow-{sm\|md\|lg}` | 见上 | 卡片/浮层阴影 |
140
- | 表单 | `--sy-form-gap` | `16px` | 表单字段间距 |
141
- | 表单 | `--sy-form-padding` | `24px` | 表单容器内边距 |
142
- | 表单 | `--sy-form-field-height` | `32px` | 输入框高度 |
143
-
144
- ---
145
-
146
- ## 3. Layer 2:AntD Theme Token 映射
147
-
148
- 通过 `ConfigProvider` 让 antd 组件读取 CSS 变量,实现"改变量即改主题"。
149
-
150
- ```tsx
151
- import { ConfigProvider } from 'antd';
152
-
153
- export function AppThemeProvider({ children }: { children: React.ReactNode }) {
154
- return (
155
- <ConfigProvider
156
- // 让弹层挂载到命名空间容器内(关键:保证 CSS 变量可达)
157
- getPopupContainer={() =>
158
- (document.querySelector('.sy-app-workspace') as HTMLElement) ?? document.body
159
- }
160
- theme={{
161
- cssVar: { prefix: 'sy-ant' }, // 输出 --sy-ant-* 变量,避免冲突
162
- hashed: false, // 与 cssVar 配合,禁用 hash
163
- token: {
164
- // 颜色
165
- colorPrimary: 'var(--sy-color-primary)',
166
- colorSuccess: 'var(--sy-color-success)',
167
- colorWarning: 'var(--sy-color-warning)',
168
- colorError: 'var(--sy-color-error)',
169
- colorText: 'var(--sy-color-text)',
170
- colorTextSecondary: 'var(--sy-color-text-secondary)',
171
- colorTextTertiary: 'var(--sy-color-text-tertiary)',
172
- colorTextDisabled: 'var(--sy-color-text-disabled)',
173
- colorBgContainer: 'var(--sy-color-bg-container)',
174
- colorBgLayout: 'var(--sy-color-bg-layout)',
175
- colorBgElevated: 'var(--sy-color-bg-elevated)',
176
- colorBorder: 'var(--sy-color-border)',
177
- colorBorderSecondary: 'var(--sy-color-border-secondary)',
178
-
179
- // 度量(antd token 不支持 var(),需用数值;通过 components 精细控制时再用 var)
180
- borderRadius: 6,
181
- borderRadiusLG: 8,
182
- borderRadiusSM: 4,
183
- fontSize: 14,
184
- controlHeight: 32,
185
- },
186
- components: {
187
- Form: { itemMarginBottom: 16 },
188
- Card: { paddingLG: 24 },
189
- },
190
- }}
191
- >
192
- {children}
193
- </ConfigProvider>
194
- );
195
- }
196
- ```
197
-
198
- > **注意**:antd token 中数值类(borderRadius/fontSize/controlHeight)需直接写数值,与 Layer 1 的 `--sy-radius-md`/`--sy-font-size-base`/`--sy-form-field-height` 保持同步即可。
199
-
200
- ---
201
-
202
- ## 4. Layer 3:Tailwind 语义化工具类
203
-
204
- `tailwind-preset.ts` 基于 CSS Variables 扩展语义化类,**优先使用语义类**而非数值类。
205
-
206
- ### 4.1 颜色类
207
-
208
- | Tailwind | 等价 CSS | 场景 |
209
- |---|---|---|
210
- | `text-primary` | `color: var(--sy-color-primary)` | 主色文本/链接 |
211
- | `text-success` | `color: var(--sy-color-success)` | 成功文本 |
212
- | `text-warning` | `color: var(--sy-color-warning)` | 警示文本 |
213
- | `text-error` | `color: var(--sy-color-error)` | 错误文本 |
214
- | `text-default` | `color: var(--sy-color-text)` | 主文本 |
215
- | `text-secondary` | `color: var(--sy-color-text-secondary)` | 次文本 |
216
- | `text-tertiary` | `color: var(--sy-color-text-tertiary)` | 提示文本 |
217
- | `text-disabled` | `color: var(--sy-color-text-disabled)` | 禁用文本 |
218
- | `bg-container` | `background: var(--sy-color-bg-container)` | 卡片底 |
219
- | `bg-layout` | `background: var(--sy-color-bg-layout)` | 页面底 |
220
- | `bg-elevated` | `background: var(--sy-color-bg-elevated)` | 浮层底 |
221
- | `border-default` | `border-color: var(--sy-color-border)` | 边框 |
222
- | `border-secondary` | `border-color: var(--sy-color-border-secondary)` | 分隔 |
223
-
224
- ### 4.2 间距 / 布局类
225
-
226
- | Tailwind 类 | 等价 CSS |
227
- |---|---|
228
- | `gap-form` | `gap: var(--sy-form-gap)` |
229
- | `p-form` | `padding: var(--sy-form-padding)` |
230
- | `px-form` / `py-form` | `padding-inline / padding-block: var(--sy-form-padding)` |
231
- | `space-y-form > * + *` | `margin-top: var(--sy-form-gap)` |
232
- | `h-field` | `height: var(--sy-form-field-height)` |
233
-
234
- ### 4.3 圆角 / 阴影 / 字号
235
-
236
- | Tailwind 类 | 等价 CSS |
237
- |---|---|
238
- | `rounded-form` | `border-radius: var(--sy-radius-md)` |
239
- | `rounded-card` | `border-radius: var(--sy-radius-lg)` |
240
- | `rounded-pill` | `border-radius: var(--sy-radius-sm)` |
241
- | `shadow-card` | `box-shadow: var(--sy-shadow-md)` |
242
- | `shadow-popover` | `box-shadow: var(--sy-shadow-lg)` |
243
- | `shadow-subtle` | `box-shadow: var(--sy-shadow-sm)` |
244
- | `text-sm-sy` | `font-size: var(--sy-font-size-sm)` |
245
- | `text-base-sy` | `font-size: var(--sy-font-size-base)` |
246
- | `text-lg-sy` | `font-size: var(--sy-font-size-lg)` |
247
- | `text-xl-sy` | `font-size: var(--sy-font-size-xl)` |
248
- | `text-2xl-sy` | `font-size: var(--sy-font-size-2xl)` |
249
-
250
- > 通用 Tailwind 数值类(如 `p-4`、`text-sm`)仍可使用,但**当存在语义类时优先用语义类**。
251
-
252
- ---
253
-
254
- ## 5. 禁止规则(AI Agent 必须遵守)
255
-
256
- | # | 规则 | 反例 | 正例 |
257
- |---|---|---|---|
258
- | 1 | **禁止硬编码颜色** | `color: #333`、`className="bg-[#1677ff]"` | `text-default`、`bg-container` 或 `var(--sy-color-primary)` |
259
- | 2 | **禁止硬编码间距** | `padding: 16px`、`className="p-[24px]"` | `p-form`、`var(--sy-spacing-md)` |
260
- | 3 | **禁止用数值类替代语义类** | `className="rounded-md gap-4"`(用于表单时)| `className="rounded-form gap-form"` |
261
- | 4 | **禁止内联颜色/间距** | `<div style={{ color: '#1677ff', padding: 16 }}>` | `<div className="text-primary p-form">` |
262
- | 5 | **禁止绕过 ConfigProvider 直接覆盖 antd 类名** | `.ant-btn { background: red }` | 通过 `theme.token.colorPrimary` 或自定义类组合 |
263
- | 6 | **禁止 antd 弹层挂到 body** | 默认行为 | 通过 `getPopupContainer` 锚定到 `.sy-app-workspace` |
264
- | 7 | **禁止在样式中假设白色/黑色背景** | `color: #fff`(在深色主题失效)| `text-default`,让 Token 决定 |
265
-
266
- ---
267
-
268
- ## 6. 正确示例 vs 错误示例
269
-
270
- ### 示例 1:主操作按钮的容器
271
-
272
- ```tsx
273
- // ❌ 错误:硬编码颜色 + 硬编码间距
274
- <div style={{ background: '#fff', padding: 24, borderRadius: 6 }}>
275
- <button style={{ background: '#1677ff', color: '#fff' }}>提交</button>
276
- </div>
277
-
278
- // ✅ 正确:语义类 + antd 组件
279
- <div className="bg-container p-form rounded-form">
280
- <Button type="primary">提交</Button>
281
- </div>
282
- ```
283
-
284
- ### 示例 2:表单字段布局
285
-
286
- ```tsx
287
- // ❌ 错误:随意数值类
288
- <div className="flex flex-col gap-[16px] p-[24px]">
289
- <Input className="h-[32px]" />
290
- <Input className="h-[32px]" />
291
- </div>
292
-
293
- // ✅ 正确:表单语义类
294
- <div className="flex flex-col gap-form p-form">
295
- <Input />
296
- <Input />
297
- </div>
298
- ```
299
-
300
- ### 示例 3:状态文案
301
-
302
- ```tsx
303
- // ❌ 错误:直接写颜色值
304
- <span style={{ color: '#52c41a' }}>已通过</span>
305
- <span style={{ color: '#ff4d4f' }}>已驳回</span>
306
-
307
- // ✅ 正确:状态语义类
308
- <span className="text-success">已通过</span>
309
- <span className="text-error">已驳回</span>
310
- ```
311
-
312
- ### 示例 4:卡片容器
313
-
314
- ```tsx
315
- // ❌ 错误:阴影硬编码
316
- <div style={{
317
- background: '#fff',
318
- boxShadow: '0 6px 16px rgba(0,0,0,0.08)',
319
- borderRadius: 8
320
- }}>...</div>
321
-
322
- // ✅ 正确:语义类
323
- <div className="bg-container shadow-card rounded-card">...</div>
324
- ```
325
-
326
- ### 示例 5:次要文本 + 提示
327
-
328
- ```tsx
329
- // ❌ 错误:rgba 硬编码
330
- <p style={{ color: 'rgba(0,0,0,0.65)', fontSize: 12 }}>提示信息</p>
331
-
332
- // ✅ 正确:层级语义
333
- <p className="text-secondary text-sm-sy">提示信息</p>
334
- ```
335
-
336
- ### 示例 6:自定义代码节点的 CSS(局部样式表)
337
-
338
- ```css
339
- /* ❌ 错误 */
340
- .my-node-card {
341
- background: #ffffff;
342
- border: 1px solid #d9d9d9;
343
- padding: 16px;
344
- }
345
-
346
- /* ✅ 正确 */
347
- .sy-app-workspace .my-node-card {
348
- background: var(--sy-color-bg-container);
349
- border: 1px solid var(--sy-color-border);
350
- padding: var(--sy-spacing-md);
351
- border-radius: var(--sy-radius-md);
352
- }
353
- ```
354
-
355
- ---
356
-
357
- ## 7. 自定义主题
358
-
359
- ### 7.1 全局主题切换
360
-
361
- 直接覆盖 `.sy-app-workspace` 上的 CSS 变量即可,**无需重新构建**:
362
-
363
- ```css
364
- /* 应用 A —— 默认蓝 */
365
- .sy-app-workspace.theme-default {
366
- --sy-color-primary: #1677ff;
367
- --sy-color-primary-hover: #4096ff;
368
- --sy-color-primary-active: #0958d9;
369
- }
370
-
371
- /* 应用 B —— 品牌绿 */
372
- .sy-app-workspace.theme-brand-green {
373
- --sy-color-primary: #00b96b;
374
- --sy-color-primary-hover: #2fd58a;
375
- --sy-color-primary-active: #008a4f;
376
- }
377
-
378
- /* 应用 C —— 暗色 */
379
- .sy-app-workspace.theme-dark {
380
- --sy-color-text: rgba(255, 255, 255, 0.88);
381
- --sy-color-text-secondary: rgba(255, 255, 255, 0.65);
382
- --sy-color-bg-container: #1f1f1f;
383
- --sy-color-bg-layout: #141414;
384
- --sy-color-border: #424242;
385
- }
386
- ```
387
-
388
- ```tsx
389
- // 运行时切换
390
- document.querySelector('.sy-app-workspace')?.classList.toggle('theme-dark');
391
- ```
392
-
393
- 由于 antd token 与 Tailwind 语义类都引用相同 CSS 变量,**变量一改,三层全变**。
394
-
395
- ### 7.2 单应用差异化
396
-
397
- 不同应用可在自身 workspace 入口注入差异化变量:
398
-
399
- ```tsx
400
- // app-workspace.config.ts(应用级)
401
- export default {
402
- theme: {
403
- '--sy-color-primary': '#722ed1',
404
- '--sy-radius-md': '10px',
405
- }
406
- };
407
- ```
408
-
409
- 入口处将 `theme` 对象 inline 到根容器 `style` 上即可。
410
-
411
- ---
412
-
413
- ## 8. CSS Namespace 下的特殊注意事项
414
-
415
- ### 8.1 根容器要求
416
-
417
- ```tsx
418
- // 应用入口必须包裹 .sy-app-workspace
419
- <div className="sy-app-workspace">
420
- <AppThemeProvider>
421
- <YourApp />
422
- </AppThemeProvider>
423
- </div>
424
- ```
425
-
426
- ### 8.2 Tailwind 配置(关键)
427
-
428
- `tailwind.config.cjs` 中:
429
-
430
- ```js
431
- module.exports = {
432
- important: '.sy-app-workspace', // 所有 Tailwind 工具类都受命名空间限定
433
- corePlugins: {
434
- preflight: false, // 避免污染宿主页面
435
- },
436
- content: ['./src/**/*.{ts,tsx}'],
437
- presets: [require('./tailwind-preset')],
438
- };
439
- ```
440
-
441
- `important: '.sy-app-workspace'` 让所有原子类输出形如 `.sy-app-workspace .text-primary { ... }`,自动隔离。
442
-
443
- ### 8.3 antd 弹层挂载
444
-
445
- 任何 `Modal` / `Drawer` / `Select` / `DatePicker` / `Tooltip` 等组件,**必须**通过 `ConfigProvider.getPopupContainer` 或局部 `getPopupContainer` 锚定到命名空间容器:
446
-
447
- ```tsx
448
- <ConfigProvider
449
- getPopupContainer={() =>
450
- (document.querySelector('.sy-app-workspace') as HTMLElement) ?? document.body
451
- }
452
- >
453
- ...
454
- </ConfigProvider>
455
- ```
456
-
457
- 否则弹层会挂到 `document.body`,导致 CSS 变量无法继承、Tailwind 工具类失效。
458
-
459
- ### 8.4 第三方组件库
460
-
461
- 引入第三方组件时,若其样式依赖全局 reset,需在 `.sy-app-workspace` 内手动补齐;不要依赖 Tailwind preflight。
462
-
463
- ### 8.5 字体与基础样式
464
-
465
- 基础 `font-family` / `line-height` 应在 `.sy-app-workspace` 上设置一次,避免逐组件重复:
466
-
467
- ```css
468
- .sy-app-workspace {
469
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC',
470
- 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;
471
- font-size: var(--sy-font-size-base);
472
- color: var(--sy-color-text);
473
- line-height: 1.5715;
474
- }
475
- ```
476
-
477
- ---
478
-
479
- ## 速查 Cheatsheet
480
-
481
- | 想做什么 | 用什么 |
482
- |---|---|
483
- | 主色按钮 | `<Button type="primary">` |
484
- | 主色文本 | `className="text-primary"` |
485
- | 卡片容器 | `className="bg-container shadow-card rounded-card p-form"` |
486
- | 表单纵向布局 | `className="flex flex-col gap-form"` |
487
- | 错误状态文本 | `className="text-error"` |
488
- | 次要说明文本 | `className="text-secondary text-sm-sy"` |
489
- | 浮层背景 | `className="bg-elevated shadow-popover"` |
490
- | 分隔线 | `className="border-t border-secondary"` |
491
- | 切换主题 | 改 `.sy-app-workspace` 的 CSS 变量 |
492
- | 弹层挂载 | `getPopupContainer` 指向 `.sy-app-workspace` |
1
+ # OpenXiangda 样式体系参考
2
+
3
+ > 面向 AI Agent 的代码页、表单页和自定义节点样式基线。默认直接使用 Tailwind 原生工具类和 Tailwind 任意值;平台 token 是兼容能力和平台组件内部能力,不是业务页面的强制范式。
4
+
5
+ ---
6
+
7
+ ## 1. 默认规则
8
+
9
+ 1. **业务页面默认写原生 Tailwind**:优先使用 `bg-white`、`border`、`border-slate-200`、`text-slate-600`、`shadow-sm`、`rounded-lg`、`p-4`、`gap-4`、`grid-cols-[240px_1fr]` 这类 Tailwind 原生类和任意值。
10
+ 2. **不要强制平台 token**:不要把 `bg-container`、`text-secondary`、`rounded-form`、`shadow-card` 当默认示例或默认范式。历史项目或平台组件需要时可以兼容使用,但新业务页面不推荐主动依赖。
11
+ 3. **不要直接套 shadcn token**:`bg-card`、`text-muted-foreground`、`text-foreground`、`bg-background` 等不是 Tailwind 原生类。除非项目已经在 `tailwind.config.cjs` 明确配置这些 token,否则必须改成 Tailwind 原生类或任意值。
12
+ 4. **保留 OpenXiangda 隔离能力**:Tailwind 仍通过 `.sy-app-workspace` namespace 输出,workspace 仍扫描 `openxiangda` 包内容,平台组件 safelist 仍保留。
13
+ 5. **CSS 作用域要收敛**:页面级 CSS 写在 `styles.css`,选择器限定在 `.sy-app-workspace` 或页面根类下,避免污染宿主平台。
14
+
15
+ ---
16
+
17
+ ## 2. 推荐写法
18
+
19
+ ### 2.1 页面容器
20
+
21
+ ```tsx
22
+ export function DashboardPage() {
23
+ return (
24
+ <main className="min-h-screen bg-slate-50 px-6 py-5 text-slate-900">
25
+ <section className="rounded-lg border border-slate-200 bg-white p-5 shadow-sm">
26
+ <h1 className="text-xl font-semibold">排队预约</h1>
27
+ <p className="mt-1 text-sm text-slate-600">查看排队申请、安排上机时间、处理冲突。</p>
28
+ </section>
29
+ </main>
30
+ );
31
+ }
32
+ ```
33
+
34
+ ### 2.2 卡片和状态
35
+
36
+ ```tsx
37
+ <div className="rounded-lg border border-slate-200 bg-white p-4 shadow-sm">
38
+ <div className="text-sm text-slate-500">待分配</div>
39
+ <div className="mt-2 text-2xl font-semibold text-amber-700">2</div>
40
+ </div>
41
+
42
+ <span className="inline-flex rounded-full bg-emerald-50 px-2 py-0.5 text-xs font-medium text-emerald-700">
43
+ 已完成
44
+ </span>
45
+ ```
46
+
47
+ ### 2.3 精确布局和品牌色
48
+
49
+ ```tsx
50
+ <div className="grid min-h-[calc(100vh-64px)] grid-cols-[280px_1fr] gap-5">
51
+ <aside className="border-r border-slate-200 bg-white" />
52
+ <section className="bg-[#f7fafc] p-6" />
53
+ </div>
54
+
55
+ <button className="rounded-md bg-[#1677ff] px-4 py-2 text-sm font-medium text-white hover:bg-[#0958d9]">
56
+ 提交
57
+ </button>
58
+ ```
59
+
60
+ ### 2.4 局部 CSS
61
+
62
+ ```css
63
+ .sy-app-workspace .queue-booking-page {
64
+ min-height: 100%;
65
+ background: #f8fafc;
66
+ }
67
+
68
+ .sy-app-workspace .queue-booking-page__calendar-grid {
69
+ display: grid;
70
+ grid-template-columns: repeat(7, minmax(120px, 1fr));
71
+ gap: 12px;
72
+ }
73
+ ```
74
+
75
+ ---
76
+
77
+ ## 3. Tailwind 配置要求
78
+
79
+ OpenXiangda workspace 的 `tailwind.config.cjs` 必须保留:
80
+
81
+ ```js
82
+ const openxiangdaPath = require("node:path");
83
+ const openxiangdaPresetModule = require("openxiangda/tailwind-preset");
84
+ const openxiangdaPreset =
85
+ openxiangdaPresetModule.default ?? openxiangdaPresetModule;
86
+
87
+ function resolveOpenXiangdaContent() {
88
+ try {
89
+ const packagePath = require.resolve("openxiangda");
90
+ const distDir = openxiangdaPath.dirname(packagePath);
91
+ return [openxiangdaPath.join(distDir, "..", "**/*.{js,mjs,cjs}")];
92
+ } catch {
93
+ return [];
94
+ }
95
+ }
96
+
97
+ const openxiangdaContent = resolveOpenXiangdaContent();
98
+
99
+ module.exports = {
100
+ content: [
101
+ "./index.html",
102
+ "./src/**/*.{js,ts,jsx,tsx}",
103
+ ...openxiangdaContent,
104
+ ],
105
+ blocklist: ["[-:T]", "[-:TZ.]"],
106
+ presets: [openxiangdaPreset],
107
+ theme: {
108
+ extend: {},
109
+ },
110
+ plugins: [],
111
+ };
112
+ ```
113
+
114
+ 这个配置的作用:
115
+
116
+ - `openxiangdaPreset` 保留 `.sy-app-workspace` namespace、平台组件 safelist 和平台组件需要的工具类。
117
+ - `...openxiangdaContent` 确保平台组件内部 class 会被 Tailwind 扫描到。
118
+ - `blocklist` 避免 Tailwind 误生成日期字符串相关的异常类。
119
+
120
+ 不要为了“更自由”移除这些平台构建能力;自由写 Tailwind 原生类和保留构建隔离能力并不冲突。
121
+
122
+ ---
123
+
124
+ ## 4. 入口 CSS 要求
125
+
126
+ `src/index.css` 默认只需要 Tailwind 指令和少量基础样式:
127
+
128
+ ```css
129
+ @layer tailwind-base {
130
+ @tailwind base;
131
+ }
132
+
133
+ @tailwind components;
134
+ @tailwind utilities;
135
+
136
+ * {
137
+ box-sizing: border-box;
138
+ }
139
+
140
+ body {
141
+ margin: 0;
142
+ min-width: 320px;
143
+ background: #f8fafc;
144
+ color: #0f172a;
145
+ font-family:
146
+ -apple-system,
147
+ BlinkMacSystemFont,
148
+ "Segoe UI",
149
+ sans-serif;
150
+ }
151
+
152
+ #root {
153
+ min-height: 100dvh;
154
+ }
155
+ ```
156
+
157
+ `openxiangda/styles/tokens.css` 不再是新业务页面的默认依赖。旧项目已经引入时可以保留,或在确实需要平台 CSS 变量统一主题时手动引入。
158
+
159
+ ---
160
+
161
+ ## 5. Ant Design 和弹层
162
+
163
+ PC 控件优先用 `antd`,移动端控件优先用 `antd-mobile`。弹层必须挂到当前页面容器或 `.sy-app-workspace` 内,避免宿主平台污染或滚动容器裁切:
164
+
165
+ ```tsx
166
+ <ConfigProvider
167
+ getPopupContainer={(trigger) =>
168
+ trigger?.closest('.sy-app-workspace') ??
169
+ (document.querySelector('.sy-app-workspace') as HTMLElement) ??
170
+ document.body
171
+ }
172
+ >
173
+ <App />
174
+ </ConfigProvider>
175
+ ```
176
+
177
+ 局部组件也可以使用 `getPopupContainer={(trigger) => trigger.parentElement ?? document.body}`。不要无作用域覆盖 `.ant-select-selector`、`.ant-modal` 等私有 class;确实需要覆盖时限定在页面根类下。
178
+
179
+ ---
180
+
181
+ ## 6. 平台 Token 兼容说明
182
+
183
+ OpenXiangda 仍保留部分平台语义类和 CSS 变量,主要用于:
184
+
185
+ - 平台标准表单、数据管理列表、审批时间线等组件内部样式。
186
+ - 老项目兼容。
187
+ - 多应用统一主题或深度主题定制。
188
+
189
+ 常见兼容类包括 `text-primary`、`text-secondary`、`bg-container`、`bg-layout`、`border-secondary`、`rounded-form`、`shadow-card` 等。AI 编写新业务页面时不要默认使用这些类;除非用户明确要求跟随平台变量主题,或当前项目已有一致的 token 体系。
190
+
191
+ 如果需要统一主题,推荐把主题限制在 `.sy-app-workspace` 或应用根类下:
192
+
193
+ ```css
194
+ .sy-app-workspace.theme-brand {
195
+ --sy-color-primary: #0f766e;
196
+ --sy-radius-md: 8px;
197
+ }
198
+ ```
199
+
200
+ ---
201
+
202
+ ## 7. 构建期提醒
203
+
204
+ OpenXiangda 构建会扫描源码里的 shadcn token 类。如果发现 `bg-card`、`text-muted-foreground`、`text-foreground` 等类,但项目没有显式配置对应 token,会输出 warning。
205
+
206
+ 收到 warning 时优先修正为:
207
+
208
+ - Tailwind 原生类:`bg-white border border-slate-200 text-slate-600`
209
+ - Tailwind 任意值:`bg-[#1677ff] text-[13px] grid-cols-[240px_1fr]`
210
+ - 或在 `tailwind.config.cjs` 中显式配置这些 shadcn token
211
+
212
+ warning 不会阻断构建,但它通常意味着页面会出现“颜色、边框、文本层级异常”的视觉问题。
213
+
214
+ ---
215
+
216
+ ## 8. 提交前检查
217
+
218
+ - [ ] 页面样式默认使用 Tailwind 原生类和任意值,而不是平台 token 类?
219
+ - [ ] 没有使用未配置的 shadcn token 类,例如 `bg-card`、`text-muted-foreground`、`text-foreground`?
220
+ - [ ] `tailwind.config.cjs` 保留 OpenXiangda preset、content 扫描和 blocklist?
221
+ - [ ] 业务 CSS 限定在 `.sy-app-workspace` 或页面根类下?
222
+ - [ ] antd / antd-mobile 弹层设置了合适的挂载容器?