@tfdesign/b-end 1.0.16 → 1.0.18

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tfdesign/b-end",
3
- "version": "1.0.16",
3
+ "version": "1.0.18",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "TFDS B-end React components + Tailwind v4 theme.css; self-contained npm install (no monorepo clone required).",
@@ -51,7 +51,7 @@
51
51
  - Playground、会话、多面板页没有错误地整页滚动。
52
52
  - 双栏 / 三栏布局中固定侧 `shrink-0`,主内容 `flex-1 min-w-0`。
53
53
  - **横向并列大卡工作区**(如双白卡 / 左筛选 + 右主表):辅助侧默认具备宽度拖拽(`resizable` + `minWidth` / `maxWidth` / `overflow-visible`),主卡 `flex-1 min-w-0`;对照 `LAYOUT_RULES.md` §3.2 / `McpManagementPage`。
54
- - 白卡距浏览器边缘约 16px,卡与卡之间约 8px。
54
+ - 白卡距浏览器边缘约 16px;**纵向叠放**的板块(白卡 ↔ 白卡 / 白卡 ↔ Header / 白卡 ↔ KPI / 白卡 ↔ Tabs / 白卡 ↔ 筛选行)默认 16px (`gap-4`);**横向并列**的同行多白卡分栏 / 多面板 Playground 默认 8px (`gap-2`)
55
55
  - 白卡内部 padding 使用 24px,未误用到页面外框。
56
56
  - PageMetaBar / 白卡 Header / 筛选栏 / 卡片网格已按 `LAYOUT_RECIPES.md` 对齐:左侧标题 `min-w-0 flex-1`,右侧操作 `shrink-0 flex-wrap gap-2`;筛选栏固定宽而非全宽;卡片网格使用 `auto-fit/minmax`。
57
57
  - 表单正文宽度已按 `GLOBAL_DESIGN_RULES.md` §3.1 对齐:页面主表单、白卡表单、抽屉 / 弹窗正文表单、侧栏详情表单中的 `Input` / `Select` / `TextArea` / `InputNumber` / `DatePicker` / `TimePicker` / `TagInput` 均撑满字段列,并且左右边界一致。
@@ -71,6 +71,124 @@
71
71
  - 用语义色当背景大面积铺设(除非 Toast/Alert,已有组件)
72
72
  - 状态徽标手写:`<span className="bg-red-100 text-red-600">失败</span>` ❌ → 必须 `<Tag variant="danger">失败</Tag>` ✅
73
73
 
74
+ ### 1.4 渐变色 Token(AI / 智能能力专用)
75
+
76
+ 渐变色是 TFDS 中表达 AI 能力的专属视觉语言,用来提示“智能推荐、自动生成、智能分析、AI 辅助、自动化洞察”等能力。它不是普通装饰色,不能为了丰富画面而随意使用。生成自定义区块时,必须优先使用 `var(--gradient-*)` 变量,禁止重新手写相似 `linear-gradient(...)`。
77
+
78
+ #### 1.4.1 使用原则
79
+
80
+ - **语义先行**:只有内容、入口或状态明确与 AI / 智能能力相关时,才能使用 AI 渐变。
81
+ - **层级递进**:背景用 `ai-fill-1`,边界用 `ai-fill-2`,图标和局部高强调元素用 `ai-fill-3`,AI 文字统一用 `ai-fill-text`。
82
+ - **弱背景、强点缀**:大面积区域只能使用低感知的 `ai-fill-1`;高饱和的 `ai-fill-3` 只能用于小面积图形。
83
+ - **内容可读**:正文、表单、表格、日志、代码等高密度内容区不得铺高饱和渐变;文字必须保持足够对比度。
84
+ - **一致调用**:所有 AI 渐变必须通过 token 调用,避免出现相似但不一致的自定义渐变。
85
+
86
+ #### 1.4.2 Token 语义表
87
+
88
+ | Token | CSS 变量 | UX 语义 | 视觉强度 | 适用场景 | 禁用场景 |
89
+ | --- | --- | --- | --- | --- | --- |
90
+ | dark | `var(--gradient-dark)` | AI 深色品牌氛围层 | 强 | 深色 AI Hero、AI 封面、智能能力主视觉、深色空状态 | 普通业务卡片、密集表单、表格背景、浅色页面的局部小容器 |
91
+ | ai-fill-1 | `var(--gradient-ai-fill-1)` | AI 弱感知背景层 | 弱 | AI 类背景色、AI 推荐卡片背景、AI 提示区、智能建议列表、生成中结果容器、AI Tag 底色 | 边框、图标、文字、主按钮、大面积页面底色之外的非 AI 区块 |
92
+ | ai-fill-2 | `var(--gradient-ai-fill-2)` | AI 轻量边界层 | 中弱 | AI 类浅色边框、卡片渐变描边、AI 区块 hover 边缘高光、输入框 AI 能力边界 | 大面积背景、文字颜色、图标填充、强行动按钮 |
93
+ | ai-fill-3 | `var(--gradient-ai-fill-3)` | AI 高强调元素层 | 强 | AI 相关图标、小圆点、头像光点、按钮内小图形、生成/刷新图标、激活态小元素 | 大面积背景、表单/表格容器、长文本背景、普通装饰插画 |
94
+ | ai-fill-text | `var(--gradient-ai-fill-text)` | AI 文字强调层 | 中强 | 所有 AI 色文字字体颜色:AI 标识、AI 推荐、智能生成、自动分析、AI 能力标题或短强调文案 | 普通标题、普通链接、正文段落、非 AI 文案、长段落文字 |
95
+
96
+ #### 1.4.3 渐变值定义
97
+
98
+ | Token | CSS 定义 |
99
+ | --- | --- |
100
+ | dark | `linear-gradient(74deg, rgba(134,255,197,0.4) 1.5%, transparent 50%), linear-gradient(250deg, rgba(255,158,44,0.28) 11%, transparent 52%), linear-gradient(101deg, #34423B 14%, #16141F 104%)` |
101
+ | ai-fill-1 | `linear-gradient(90deg, rgba(230, 247, 244, 1) 0%, rgba(239, 246, 255, 1) 55%, rgba(243, 245, 255, 1) 90%, rgba(252, 243, 255, 1) 100%)` |
102
+ | ai-fill-2 | `linear-gradient(-45deg, rgba(254, 224, 253, 1) 0%, rgba(233, 218, 255, 1) 25%, rgba(213, 225, 255, 1) 48%, rgba(213, 243, 248, 1) 83%, rgba(213, 247, 242, 1) 100%)` |
103
+ | ai-fill-3 | `linear-gradient(-45deg, rgba(255, 153, 248, 1) 0%, rgba(181, 131, 255, 1) 25%, rgba(114, 156, 255, 1) 48%, rgba(117, 218, 231, 1) 83%, rgba(115, 230, 204, 1) 100%)` |
104
+ | ai-fill-text | `linear-gradient(135deg, rgba(22, 218, 203, 1) 0%, rgba(49, 134, 212, 1) 20%, rgba(111, 88, 227, 1) 70%, rgba(231, 116, 221, 1) 100%)` |
105
+
106
+ #### 1.4.4 推荐组合
107
+
108
+ - **AI 推荐卡片**:`ai-fill-1` 做背景,`ai-fill-2` 做 1px 渐变边框,标题中的“AI 推荐”用 `ai-fill-text`。
109
+ - **AI 输入能力入口**:普通输入框保持白底,AI 状态或 hover 边界可用 `ai-fill-2`,右侧 AI 图标用 `ai-fill-3`。
110
+ - **AI 状态标签**:Tag 背景优先使用 `ai-fill-1`,短文案可使用 `ai-fill-text`,不要把整个 Tag 做成高饱和 `ai-fill-3`。
111
+ - **AI 图标按钮**:按钮容器仍遵循 Button 组件规范,按钮内小图标或光点可用 `ai-fill-3`。
112
+ - **AI 深色主视觉**:只有 Hero、封面、空状态主视觉可使用 `dark`,并配合白色或反色文字。
113
+
114
+ #### 1.4.5 标准示例
115
+
116
+ **AI 背景色(ai-fill-1)**:
117
+
118
+ ```jsx
119
+ <div
120
+ style={{
121
+ background: 'var(--gradient-ai-fill-1)',
122
+ borderRadius: 'var(--radius-lg)',
123
+ }}
124
+ >
125
+ AI 推荐内容
126
+ </div>
127
+ ```
128
+
129
+ **AI 浅色边框(ai-fill-2)**:
130
+
131
+ ```jsx
132
+ <div
133
+ style={{
134
+ border: '1px solid transparent',
135
+ background:
136
+ 'linear-gradient(var(--color-surface), var(--color-surface)) padding-box, var(--gradient-ai-fill-2) border-box',
137
+ borderRadius: 'var(--radius-lg)',
138
+ }}
139
+ >
140
+ AI 辅助卡片
141
+ </div>
142
+ ```
143
+
144
+ **AI 图标 / 小元素(ai-fill-3)**:
145
+
146
+ ```jsx
147
+ <span
148
+ aria-hidden
149
+ style={{
150
+ display: 'inline-block',
151
+ width: 16,
152
+ height: 16,
153
+ background: 'var(--gradient-ai-fill-3)',
154
+ borderRadius: 'var(--radius-full)',
155
+ }}
156
+ />
157
+ ```
158
+
159
+ **AI 文字字体颜色(ai-fill-text)**:
160
+
161
+ ```jsx
162
+ <span
163
+ style={{
164
+ background: 'var(--gradient-ai-fill-text)',
165
+ WebkitBackgroundClip: 'text',
166
+ backgroundClip: 'text',
167
+ WebkitTextFillColor: 'transparent',
168
+ }}
169
+ >
170
+ AI 推荐
171
+ </span>
172
+ ```
173
+
174
+ #### 1.4.6 反例与修正
175
+
176
+ | ❌ Bad | ✅ Good |
177
+ | --- | --- |
178
+ | `<div style={{ background: 'var(--gradient-ai-fill-3)' }}>表格</div>` | 表格保持 `var(--color-surface)`,仅 AI 入口图标使用 `var(--gradient-ai-fill-3)` |
179
+ | `<span style={{ color: 'var(--gradient-ai-fill-text)' }}>AI 推荐</span>` | 使用 `background: var(--gradient-ai-fill-text)` + `backgroundClip: 'text'` |
180
+ | `<div style={{ background: 'linear-gradient(90deg, #E6F7F4, #FCF3FF)' }}>` | `<div style={{ background: 'var(--gradient-ai-fill-1)' }}>` |
181
+ | 普通业务标题使用 `ai-fill-text` | 只有 AI 相关短文案使用 `ai-fill-text`,普通标题用 `var(--color-foreground)` |
182
+ | 卡片背景和图标都用 `ai-fill-3` | 卡片背景用 `ai-fill-1`,图标小面积用 `ai-fill-3` |
183
+
184
+ ⛔ **禁止**:
185
+
186
+ - ❌ 自己硬写 `linear-gradient(...)` 复刻 AI 渐变;应改用 `var(--gradient-ai-fill-*)` 或 `var(--gradient-dark)`。
187
+ - ❌ 把 AI 渐变当普通装饰色铺满密集内容区(表格、表单、日志、代码、长文本编辑器)。
188
+ - ❌ 用 `ai-fill-3` 做大面积背景;它只适合图标、按钮图形、激活态小元素。
189
+ - ❌ 用普通 `color: var(--gradient-ai-fill-text)` 设置文字渐变;必须配合 `backgroundClip: 'text'` 与 `WebkitTextFillColor: 'transparent'`。
190
+ - ❌ 为非 AI 场景使用 AI 渐变,避免用户误解该模块具备智能能力。
191
+
74
192
  ---
75
193
 
76
194
  ## 2. 字体 Token
@@ -173,9 +291,9 @@ B 端主路径的**标题与密集区强调文案**默认以 **600(`--font-sem
173
291
  | `--spacing-0` | 0px | `gap-0` | 无间距 |
174
292
  | `--spacing-0_5` | 2px | `gap-0.5` | 极紧凑(图标内部、徽标) |
175
293
  | `--spacing-1` | 4px | `gap-1` | 单行 Tag 之间、icon-text 间距 |
176
- | `--spacing-2` | 8px | `gap-2` | **同组元素默认值**、白卡之间 |
294
+ | `--spacing-2` | 8px | `gap-2` | **同组元素默认值**、横向并列白卡之间 |
177
295
  | `--spacing-3` | 12px | `gap-3` | 跨小组件间(按钮组合) |
178
- | `--spacing-4` | 16px | `gap-4` | **表单字段之间**、卡内行块 |
296
+ | `--spacing-4` | 16px | `gap-4` | **表单字段之间**、卡内行块、**纵向叠放板块之间(白卡 ↔ 白卡 / 白卡 ↔ Header / 白卡 ↔ KPI / 白卡 ↔ Tabs / 白卡 ↔ 筛选行)** |
179
297
  | `--spacing-5` | 20px | `gap-5` | 中等分区 |
180
298
  | `--spacing-6` | 24px | `gap-6` / `p-6` | **白卡内 padding 默认值**、Section 之间 |
181
299
  | `--spacing-7` | 28px | `gap-7` | 较大分区(少用) |
@@ -188,13 +306,14 @@ B 端主路径的**标题与密集区强调文案**默认以 **600(`--font-sem
188
306
  ⛔ **禁止任意值**:`p-[14px]`、`gap-[7px]`、`space-y-[18px]`、`mt-[10px]`。
189
307
  ✅ **取整数档**:设计稿 14px → 向上取 16px (`gap-4`),11px → 取 12px (`gap-3`)。
190
308
 
191
- **白卡分区间距黄金组合**(三层各自固定,不可混用):
309
+ **白卡分区间距黄金组合**(按"横向并列 / 纵向叠放"区分,绝不可混用):
192
310
 
193
311
 
194
312
  | 位置 | 值 | Tailwind | 用法 |
195
313
  | ----------------- | ----------- | ----------------- | --------------------------------- |
196
314
  | 灰底框架(main)→ 白卡外边缘 | **16px** | `p-4` | `main` 容器的 padding,白卡距浏览器边缘 16px |
197
- | 白卡白卡 之间 | **8px** | `gap-2` | `main` 容器的 `gap-2` |
315
+ | **横向并列**:白卡白卡(同行多白卡分栏 / 多面板 Playground) | **8px** | `gap-2` | 父容器 `flex-row` 时使用,仅同组协作场景 |
316
+ | **纵向叠放**:白卡 ↔ 白卡 / 白卡 ↔ 其他板块组件(Header / Pill Tabs / 筛选行 / KPI 区 / 段落区)| **16px** | `gap-4` | 父容器 `flex-col` 时使用;上下两个独立 UI 板块默认 16px |
198
317
  | 白卡边缘 → 卡内内容 | **24px** | `p-6` | 写在白卡 div 内部的 padding |
199
318
  | 白卡内分区之间 | 16px 或 24px | `gap-4` / `gap-6` | 白卡内 section 之间 |
200
319
  | 表单字段之间 | 16px | `gap-4` | |
@@ -30,7 +30,7 @@
30
30
 
31
31
  | Recipe id | 触发场景 | 首选模板 | 背景 / 容器 | 典型组件 | 禁止项 |
32
32
  | --- | --- | --- | --- | --- | --- |
33
- | `base-management` | 筛选、搜索、浏览一批结构化对象、批量操作、查看详情 | `BasePageFramePattern` + 列表示例 | `main p-4 gap-2` 灰底框架 + 一张或多张白色 `WorkSurface` | `NavBar`、`FormTitle`、`FilterBar` 组合、`Table`、`TagBar`、`Tag` | 把页面 header 包白卡;`main p-2/px-6/px-8`;`max-w-* mx-auto` |
33
+ | `base-management` | 筛选、搜索、浏览一批结构化对象、批量操作、查看详情 | `BasePageFramePattern` + 列表示例 | `main p-4 gap-4` 灰底框架(纵向板块叠放)+ 一张或多张白色 `WorkSurface`;横向并列分栏内部用 `gap-2` | `NavBar`、`FormTitle`、`FilterBar` 组合、`Table`、`TagBar`、`Tag` | 把页面 header 包白卡;`main p-2/px-6/px-8`;`max-w-* mx-auto`;纵向板块叠放误用 `gap-2` |
34
34
  | `chat-home` | 用户尚未进入上下文,第一步是输入需求 / 搜索助手 / 从模板开始 | `ChatHomePagePattern` | 右侧内容区直接保持 `var(--color-blueGrey-200)`,Hero / ChatInput / Tabs / 搜索 / 卡片网格直接坐灰底 | `NavBar`、`ChatInput`、`Tabs size="sm"`、`Input`、`Card color="white"` | 整块右侧首页内容外包 `bg-surface rounded-*`;模板卡用 `color="grey"` |
35
35
  | `chat-conversation` | 已在 AI 任务里持续追问、看执行流和产物 | `ChatConversationPattern` | 浅灰会话工作区,消息流和底部输入各自固定职责 | `ChatMessage`、`ChatInput`、`Button`、产物卡 | 用 `ChatBubble` 手搓 AI 消息;让底部输入随消息滚走 |
36
36
  | `copilot-workbench` | 对象 / 产物 / 编辑器是主角,AI 只是侧助 | `CopilotPagePattern` | 页面 header 直接坐灰底,主工作区进入白色 `WorkSurface`,AI 面板按辅助区处理 | `FormTitle`、`Tabs`、`ChatInput`、`TextArea/Input/Select`、产物区 | 做成纯聊天页;AI 侧栏抢主工作区宽度;整页滚动破坏对照 |
@@ -60,7 +60,8 @@
60
60
  | 层级 | 固定值 | 写法 | 说明 |
61
61
  | --- | --- | --- | --- |
62
62
  | 灰底框架到白卡 | 16px | `main p-4` | 页面外框间距,禁止 `p-2/px-6/px-8` |
63
- | 白卡之间 | 8px | `gap-2` | 并列 / 上下多白卡间距 |
63
+ | 纵向叠放的上下板块 | 16px | `gap-4` | **白卡 ↔ 白卡 / 白卡 ↔ 其他板块组件**(`flex-col` 默认值);包括左侧标签栏到右侧主内容、上方数据卡片到下方对话流列表等所有纵向并列板块 |
64
+ | 横向并列的左右分栏 | 8px | `gap-2` | 仅用于 `flex-row` 同行多白卡分栏 / 多面板 Playground |
64
65
  | 白卡内部 padding | 24px | `p-6` 或 `px-6 py-4 + px-6 pb-6` | 只用于白卡内部 |
65
66
  | 白卡内区块间 | 16px / 24px | `gap-4` / `gap-6` | 筛选区到表格默认 16px,较大 section 用 24px |
66
67
  | 同组控件 | 8px | `gap-2` | 按钮组、Tag 组、图标文字 |
@@ -133,6 +134,8 @@
133
134
 
134
135
  - `ChatInput` + 模板 `Card` 网格 + 外层 `bg-surface rounded`:入口页被大白卡包住,拆掉外层白卡。
135
136
  - `main` 上出现 `p-2` / `p-6` / `p-8` / `px-6` / `px-8`:外框间距错误,改 `p-4`。
137
+ - `main` / 纵向板块栈出现 `flex-col gap-2`:上下板块挤压(白卡 ↔ 白卡 / 白卡 ↔ 其他组件应为 16px),改 `gap-4`。
138
+ - 左侧 `aside` 到右侧主内容 / 上方数据卡片到下方对话流列表间距小于 16px:违反"上下板块默认 16px",改 `gap-4`。
136
139
  - `max-w-* mx-auto` 包住主工作区:页面被居中收窄,删除。
137
140
  - `Tabs size="md"` 出现在白卡、筛选区、卡片内、Playground 内:改 `size="sm"`,除非是平台顶部一级导航。
138
141
  - 筛选栏内 `Input className="w-full"`:大概率误用正文表单规则,改固定宽。
@@ -198,28 +198,43 @@ prompt editor / prompt workspace / runtime / run result /
198
198
  ## 1.2 灰底框架间距铁律(高频误用 · 与白卡内 padding 严格区分)
199
199
 
200
200
  > **B 端最高频的宽度问题**:AI 把"白卡内 padding(24px)"当成"外框间距"用,导致卡片距浏览器边缘 24px 甚至更多,左右两侧出现大空白。
201
+ >
202
+ > **第二高频问题**:把"横向并列卡间距(8px)"误用到"上下板块叠放"上,导致 KPI 区紧贴下方列表卡、筛选行紧贴 Tabs,节奏过紧、缺少呼吸。
201
203
 
202
- ### 三层间距金字塔(只允许这三个值,不允许其他)
204
+ ### 三层间距金字塔(按"横向并列 / 纵向叠放"区分)
203
205
 
204
206
  ```
205
- ┌──────────────────────────────────────────────────────────┐
207
+ ┌────────────────────────────────────────────────────────────┐
206
208
  │ 浏览器可视区(灰底,background: var(--color-blueGrey-200)) │
207
- │ ←── main wrapper: p-4(16px)——————————————————————
208
- │ │ ┌──────────┐ ←─ gap-28px)→ ┌──────────┐
209
- │ │ │ │ │ 白 卡 │ │
210
- │ │ │ p-6 p-6 │ │
211
- │ │ │ (24px内边距) (24px内边距)
212
- │ │ └──────────┘ └──────────┘
213
- ←── main wrapper: p-4(16px)——————————————————————
214
- └──────────────────────────────────────────────────────────┘
209
+ │ ←── main wrapper: p-4(16px)—————————————————————————
210
+ │ │ ┌─ 板块 AKPI 区 / 工作区 / 列表卡)────────────────┐
211
+ │ │ │ ┌──────────┐ ←─ gap-2(8px)→ ┌──────────┐ │ │
212
+ │ │ │ │ 白 卡 横向并列 8px 白 卡
213
+ │ │ │ └──────────┘ └──────────┘
214
+ │ │ └────────────────────────────────────────────────┘
215
+ │ ↕ 上下叠放 gap-4(16px
216
+ │ │ ┌─ 板块 B(列表 / 表格 / 详情)─────────────────────┐ │
217
+ │ │ │ ┌────────────────────────────────────────────┐ │ │
218
+ │ │ │ │ 白卡(p-6 卡内 24px) │ │ │
219
+ │ │ │ └────────────────────────────────────────────┘ │ │
220
+ │ │ └────────────────────────────────────────────────┘ │
221
+ │ ←── main wrapper: p-4(16px)————————————————————————— │
222
+ └────────────────────────────────────────────────────────────┘
215
223
  ```
216
224
 
217
225
 
218
- | 位置 | 值 | Tailwind | 含义 |
219
- | ----------- | -------- | ------------------- | ----------------------------- |
220
- | 灰底框架 → 白卡边缘 | **16px** | `p-4` / `px-4 py-4` | main 容器的 padding,白卡距浏览器边 16px |
221
- | 白卡白卡 之间 | **8px** | `gap-2` | 多卡并列时的间距 |
222
- | 白卡边缘 卡内内容 | **24px** | `p-6` | 白卡内部 padding,仅写在白卡 div |
226
+ | 位置 | 值 | Tailwind | 含义 |
227
+ | -------------------------- | -------- | ------------------- | -------------------------------------- |
228
+ | 灰底框架 → 白卡边缘 | **16px** | `p-4` / `px-4 py-4` | main 容器的 padding,白卡距浏览器边 16px |
229
+ | **横向并列**:白卡白卡(同一工作区组内) | **8px** | `gap-2` | 双白卡分栏 / 多面板 Playground 横向相邻;属于"同组协作"语义 |
230
+ | **纵向叠放**:白卡 白卡 / 白卡 ↔ 其他板块组件(页面 header / Pill Tabs / 筛选行 / KPI 区 / 段落区)| **16px** | `gap-4` | 上下两个独立 UI 板块默认 16px;不只对白卡,所有"块级板块"上下排列都按此节奏 |
231
+ | 白卡边缘 → 卡内内容 | **24px** | `p-6` | 白卡内部 padding,仅写在白卡 div 上 |
232
+
233
+ ⚠️ **判别口诀**:
234
+
235
+ - `flex-row` 父容器的子项 → 同组协作 → `gap-2`
236
+ - `flex-col` 父容器的子项(含 main、aside 子面板纵向叠放、灰底纵向板块栈)→ 跨板块呼吸 → `gap-4`
237
+ - 唯一例外:白卡**内部**多个子区块上下排(卡内层级),按 [§3.5 / §6.x] 的 `gap-4 / gap-6` 走,本节只管"灰底框架级"间距
223
238
 
224
239
 
225
240
  ⛔ **禁止混淆(图同款误用)**:
@@ -237,11 +252,17 @@ prompt editor / prompt workspace / runtime / run result /
237
252
  ✅ **正确骨架(必须照此写)**:
238
253
 
239
254
  ```jsx
240
- {/* main:p-4 撑出 16px 灰底框架,gap-2 是白卡之间的间距 */}
241
- <main className="flex-1 min-h-0 flex flex-col p-4 gap-2 overflow-hidden w-full">
242
- <header className="shrink-0 ...">...</header> {/* 页面 header,直接坐灰底 */}
255
+ {/* main:p-4 撑出 16px 灰底框架;纵向叠放统一 gap-4(16px) */}
256
+ <main className="flex-1 min-h-0 flex flex-col p-4 gap-4 overflow-hidden w-full">
257
+ <header className="shrink-0 ...">...</header> {/* 页面 header,直接坐灰底;与下方板块间距 16px */}
258
+
259
+ {/* 板块 A:横向双白卡分栏(同组工作区) → 横向 gap-2(8px) */}
260
+ <section className="shrink-0 flex flex-row gap-2 min-w-0">
261
+ <div className="shrink-0 w-[260px] ..." style={{ background: 'var(--color-surface)' }}>...</div>
262
+ <div className="flex-1 min-w-0 ..." style={{ background: 'var(--color-surface)' }}>...</div>
263
+ </section>
243
264
 
244
- {/* 白卡:不加 margin,flex-1 撑满剩余空间,内部 p-6 */}
265
+ {/* 板块 B:单白卡 与板块 A 上下叠放,自动按 main 的 gap-4 间隔 16px */}
245
266
  <section
246
267
  className="flex-1 min-h-0 flex flex-col overflow-hidden"
247
268
  style={{ background: 'var(--color-surface)', borderRadius: 'var(--radius-lg)' }}
@@ -252,12 +273,14 @@ prompt editor / prompt workspace / runtime / run result /
252
273
  </main>
253
274
  ```
254
275
 
255
- ⚠️ **宽度自检**:在生成完整页面后,检查代码中所有 `main` / `section` / 最外层白卡 div:
276
+ ⚠️ **宽度 + 间距自检**:在生成完整页面后,检查代码中所有 `main` / `section` / 最外层白卡 div:
256
277
 
257
278
  1. `main` 上的 padding 值**只能是 `p-4`(或 `px-4 pb-4`)**,不是 `p-2` / `p-6` / `p-8` / `px-[Npx]`
258
279
  2. `main` 内**不允许**再套 `max-w-*` / `mx-auto` 的居中容器
259
- 3. 横向白卡 div 之间**只靠 `gap-2`**,白卡自身*不加 `mx-` 外边距**
260
- 4. 所有横向 `flex` 父容器补 `min-w-0`,纵向补 `min-h-0`——缺失会让某一层被内容撑开而不撑满
280
+ 3. **纵向叠放**(`flex-col` 父容器、main 直系子项、白卡 + KPI 区 + 筛选行 + Tab 栏 + header 上下排)→ **统一 `gap-4`(16px)**
281
+ 4. **横向并列**(`flex-row` 父容器,双白卡分栏 / 多面板 Playground 横向相邻)→ **统一 `gap-2`(8px)**
282
+ 5. 白卡自身**不加 `mx-` / `my-` 外边距**,间距统一交给父容器的 `gap-*`
283
+ 6. 所有横向 `flex` 父容器补 `min-w-0`,纵向补 `min-h-0`——缺失会让某一层被内容撑开而不撑满
261
284
 
262
285
  ---
263
286
 
@@ -288,7 +311,7 @@ prompt editor / prompt workspace / runtime / run result /
288
311
  <div className="h-dvh w-full ..." style={{ background: 'var(--color-blueGrey-200)' }}>
289
312
  <Topbar /> {/* 全局产品级顶导,独立组件,不在本节讨论 */}
290
313
 
291
- <main className="flex-1 min-h-0 flex flex-col p-4 gap-2 overflow-hidden">
314
+ <main className="flex-1 min-h-0 flex flex-col p-4 gap-4 overflow-hidden">
292
315
  {/* ✅ 页面 header:直接坐灰底,无白卡背景 */}
293
316
  <header className="shrink-0 px-2 pt-2 pb-1 flex items-start justify-between gap-3">
294
317
  <div className="flex items-center gap-3 min-w-0">
@@ -559,7 +582,7 @@ const [leftCardWidth, setLeftCardWidth] = useState(260);
559
582
  </section>
560
583
 
561
584
  {/* 面板 2:默认支持拖拽调宽;上下两个子面板独立滚 */}
562
- <aside className="shrink-0 flex flex-col gap-2 overflow-visible" style={{ width: `${sidePanelWidth}px` }}>
585
+ <aside className="shrink-0 flex flex-col gap-4 overflow-visible" style={{ width: `${sidePanelWidth}px` }}>
563
586
  {/* 子面板 A:高度由内容决定 → shrink-0 */}
564
587
  <div
565
588
  className="shrink-0 flex flex-col overflow-hidden"
@@ -973,7 +996,7 @@ const [leftCardWidth, setLeftCardWidth] = useState(260);
973
996
  | 密集内容弱对比 | 表格 / 表单 / 代码 / 日志放在渐变或透明背景上,文字发虚 | 改回稳定白底、组件指定代码背景或灰底 Card;AI 渐变只用于 AI 语义内容,不用于编辑和数据密集区 |
974
997
  | 整页有外圈圆角 | 灰底没贴浏览器边 | 移除根容器 `rounded` 与 `border` |
975
998
  | Playground 多面板整页滚 | 调参数得滚下去看结果 / 写 prompt 得滚回去看输入 | 按 § 3.4 / § 12.7 改造:根容器 `h-dvh + overflow-hidden`、main `overflow-hidden`、面板正文 `flex-1 min-h-0 overflow-y-auto` |
976
- | 子面板互相挤压(A 撑死 B) | 上下两块卡片其中一块完全看不见 / 高度不对 | 父 `flex-col gap-2`;定高块 `shrink-0`,弹性块 `flex-1 min-h-0` + 内部 `overflow-y-auto` |
999
+ | 子面板互相挤压(A 撑死 B) | 上下两块卡片其中一块完全看不见 / 高度不对 | 父 `flex-col gap-4`(纵向叠放 16px);定高块 `shrink-0`,弹性块 `flex-1 min-h-0` + 内部 `overflow-y-auto` |
977
1000
  | 面板标题被挤变形 | 内容多时面板 header 被挤压成单行 / 标题被压缩 | 面板 header 永远 `shrink-0`,标题区 `min-w-[120px] flex-1`,操作区 `shrink-0 flex-wrap`,面板正文 `flex-1 min-h-0 overflow-y-auto` |
978
1001
  | 标题竖排 / 逐字换行 | “原始信息只读”变成一字一行,或出现 `writing-mode` / `break-all` | 按 §3.4.1:删除窄宽度和竖排样式,标题使用 `<FormTitle />` 横排;窄面板 `showDescription={false}`,右侧 Tabs/按钮换行或移入正文 |
979
1002
  | TextArea 不撑满卡片 | System Prompt 只占 3-5 行,下方大片空白,长文本滚动不在控件内 | 主编辑区按 §3.5:header `shrink-0`,body `flex-1 min-h-0 overflow-hidden`,TextArea 写 `fillHeight resize="none" className="flex-1 min-h-0 w-full"` |
@@ -997,7 +1020,7 @@ const [leftCardWidth, setLeftCardWidth] = useState(260);
997
1020
  >
998
1021
  <Topbar />
999
1022
 
1000
- <main className="flex-1 min-h-0 flex flex-col p-4 gap-2 overflow-hidden">
1023
+ <main className="flex-1 min-h-0 flex flex-col p-4 gap-4 overflow-hidden">
1001
1024
  {/* 单一白卡 */}
1002
1025
  <div
1003
1026
  className="flex-1 min-h-0 flex flex-col overflow-hidden"
@@ -1143,7 +1166,7 @@ const [leftCardWidth, setLeftCardWidth] = useState(260);
1143
1166
  <Topbar />
1144
1167
 
1145
1168
  <main className="flex-1 min-h-0 overflow-y-auto">
1146
- <div className="flex flex-col gap-2 p-4">
1169
+ <div className="flex flex-col gap-4 p-4">
1147
1170
 
1148
1171
  {/* KPI 区:自适应网格 */}
1149
1172
  <section
@@ -1248,7 +1271,7 @@ const [leftCardWidth, setLeftCardWidth] = useState(260);
1248
1271
  </header>
1249
1272
 
1250
1273
  {/* 中部主内容 */}
1251
- <main className="flex-1 min-h-0 flex flex-col p-4 gap-2 overflow-hidden">
1274
+ <main className="flex-1 min-h-0 flex flex-col p-4 gap-4 overflow-hidden">
1252
1275
  {/* 这里嵌套 § 12.1 / 12.2 / 12.4 任意骨架 */}
1253
1276
  </main>
1254
1277
  </div>
@@ -1335,7 +1358,7 @@ const [leftCardWidth, setLeftCardWidth] = useState(260);
1335
1358
  </section>
1336
1359
 
1337
1360
  {/* ── 右栏:上下两个子面板 ── */}
1338
- <aside className="shrink-0 w-[360px] flex flex-col gap-2 overflow-hidden">
1361
+ <aside className="shrink-0 w-[360px] flex flex-col gap-4 overflow-hidden">
1339
1362
  {/* 上:Model Settings — 高度跟随表单内容(shrink-0) */}
1340
1363
  <div
1341
1364
  className="shrink-0 flex flex-col overflow-hidden"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "system": "b-end",
3
3
  "skill": "tfds",
4
- "generatedAt": "2026-05-13T13:51:39.617Z",
4
+ "generatedAt": "2026-05-14T12:28:55.593Z",
5
5
  "summary": "B 端 COMPONENTS 37 条 + 列表页模板 4 + PATTERNS 6;import 一律来自 @tfdesign/b-end。",
6
6
  "components": [
7
7
  {
@@ -467,6 +467,7 @@
467
467
  "【头像素材来源】所有人像类头像默认优先使用包内本地成员头像素材(team-avatar-assets:李思儒 / 程程murphy / 刘德琳 / 段然 / 郭泽智,可随机或按数据 seed 取用);Avatar 图片态未传 src 时会自动随机使用本地成员头像。生成 IM、ChatBubble、NavBar、Table avatar/avatarText、ConversationList 等头像场景时,禁止使用 pravatar/Unsplash/placeholder/随机外链头像;只有业务真实接口已返回用户头像 URL 时才传远程 src。",
468
468
  "【平台默认】NavBar 默认一律使用 platform=\"ola\" 的 OLA 类型菜单栏结构。这里的 OLA 指导航结构类型,不代表顶部品牌文案必须固定显示为“OLA”;图中的“OLA”仅为模板示意。",
469
469
  "【品牌文案】brandName 是顶部平台名称展示入口,必须根据真实页面类型动态传入对应平台名称,例如“体验服务”“抖音体验与服务”“服务治理”等;不要把“OLA”当成所有页面固定品牌名。只有在缺少真实平台名称的组件预览或模板占位中,才允许继续显示 OLA。",
470
+ "【品牌大小写】顶部品牌文案必须保留业务传入的 brandName 原始大小写,不做 uppercase / lowercase / capitalize 等强制转换;允许中文、英文大小写、中英混排和产品专有写法(如 Ola AI、dataPilot、TFDesign)。",
470
471
  "【ByteHi 限定】platform=\"bytehi\" 仅限明确提到“客服工作台”相关页面场景时使用,例如“客服工作台首页”“在线客服工作台”“客服工作台会话页”。普通客服、服务、体验、治理、策略、知识、工具、洞察等页面都不要自动切换 ByteHi,仍默认使用 OLA 类型菜单栏。",
471
472
  "【提示词】未显式传 platform 时,默认使用 OLA;只有 prompt / promptText 明确包含“客服工作台”时才默认使用 ByteHi。显式传 platform 时以显式值为准,但 AI 生成页面时不得在非客服工作台场景主动传 platform=\"bytehi\"。",
472
473
  "【站点级骨架】`NavBar` 是平台级站点导航锚点,不是普通内容区组件。只要页面使用 `NavBar`,一级骨架默认必须是左侧固定导航 + 右侧弹性主工作区的横向 app shell;`NavBar` 永远默认位于页面最左侧",
@@ -496,6 +497,10 @@
496
497
  "label": "真实平台名称",
497
498
  "code": "<NavBar brandName=\"体验服务\" selectedItemId=\"home\" onSelect={(nextId) => setCurrentNavId(nextId)} />"
498
499
  },
500
+ {
501
+ "label": "保留平台英文大小写",
502
+ "code": "<NavBar brandName=\"Ola AI\" />"
503
+ },
499
504
  {
500
505
  "label": "业务方切换",
501
506
  "code": "<NavBar appBusinesses={[{ id: \"douyin-community\", label: \"抖音社区\", iconSrc: \"icon-logo-douyin\" }, { id: \"douyin-local-services\", label: \"抖音生活服务\", iconSrc: \"icon-logo-douyin\" }, { id: \"douyin-ecommerce\", label: \"抖音电商\", iconSrc: \"icon-logo-douyin\" }]} />"
@@ -4189,9 +4194,10 @@
4189
4194
  "【选型·与 Radio】选项 ≤5 且表单内需并排展示全部文案 → Radio;选项多、需占位窄、或选项会动态增长 → Select",
4190
4195
  "【选型·与 Checkbox】同一字段要选多个离散值 → CheckboxGroup 或 Select mode=tag;仅单个开/关语义 → Switch 或单个 Checkbox",
4191
4196
  "【数据】options 为 { value, label, disabled? };value 与 option.value 用字符串比较",
4192
- "【TagSelect】mode=\"tag\" 属于 Select 的标签选择分类,不新增独立基础组件;触发器内已选项、+N 折叠项、下拉项都必须复用 Tag 组件",
4197
+ "【TagSelect】mode=\"tag\" 属于 Select 的标签选择分类,不新增独立基础组件;触发器内已选项与 +N 折叠项必须复用 Tag 组件,但下拉面板必须使用标准多选列表项(左侧文案 + 右侧 check),不要把下拉项渲染成一列 Tag",
4193
4198
  "【TagSelect 规格】Tag 默认颜色与尺寸跟 TagInput 保持一致,不单独暴露颜色或尺寸配置;如需特殊颜色可在单个 option.variant 上覆盖",
4194
- "【TagSelect 交互】mode=\"tag\" 时 value/defaultValue 为数组;点击下拉标签多选/取消,触发器内标签可关闭,宽度不足时折叠为 +N 并用白底 Tooltip 展示隐藏标签",
4199
+ "【TagSelect 交互】mode=\"tag\" 时 value/defaultValue 为数组;点击下拉选项多选/取消且面板保持打开,触发器内标签可关闭,宽度不足时折叠为 +N 并用白底 Tooltip 展示隐藏标签",
4200
+ "【TagSelect 选中态】多选下拉项用整行热区承载点击,已选项使用品牌浅底 + 品牌色文字 + 右侧 check;hover 仅使用浅灰底,避免与 selected 混淆;禁用项降低透明度且不可点",
4195
4201
  "【AI推荐】仅 mode=\"default\" 支持 `aiSuggestion` / `aiSuggestions`;推荐区展示在 Select 触发器下方,视觉样式、关闭逻辑、hover 展开和刷新交互与 Input 的 AI 推荐保持一致",
4196
4202
  "【AI推荐默认触发】当需求、字段说明或页面描述中出现“AI推荐”“智能推荐”“推荐回复”“刷新推荐”“智能建议”“推荐文案”“建议填写”“推荐选项”等语义时,Select 默认应展示 AI 推荐区,而不是只渲染普通下拉态。",
4197
4203
  "【AI推荐默认形态】命中上述语义后,AI 推荐区固定展示在 Select 组件下方,推荐内容应贴合页面场景,并优先给出适合当前任务的推荐选项或推荐分类。",
@@ -4219,7 +4225,7 @@
4219
4225
  },
4220
4226
  {
4221
4227
  "label": "标签选择",
4222
- "code": "<Select mode=\"tag\" defaultValue={[\"a\", \"b\"]} options={[{ value: \"a\", label: \"标签\", variant: \"grey\" }, { value: \"b\", label: \"标签\", variant: \"grey\" }]} />"
4228
+ "code": "<Select mode=\"tag\" defaultValue={[\"brand\", \"risk\"]} options={[{ value: \"brand\", label: \"品牌连锁\", variant: \"grey\" }, { value: \"risk\", label: \"风险预警\", variant: \"grey\" }]} />"
4223
4229
  },
4224
4230
  {
4225
4231
  "label": "默认选中",
@@ -4271,7 +4277,7 @@
4271
4277
  },
4272
4278
  {
4273
4279
  "label": "✅ Good(多选用 mode=\"tag\")",
4274
- "code": "<Select mode=\"tag\" defaultValue={[\"a\", \"b\"]} options={[{ value: \"a\", label: \"标签 A\" }, { value: \"b\", label: \"标签 B\" }]} />"
4280
+ "code": "<Select mode=\"tag\" defaultValue={[\"brand\", \"risk\"]} options={[{ value: \"brand\", label: \"品牌连锁\" }, { value: \"risk\", label: \"风险预警\" }]} />"
4275
4281
  }
4276
4282
  ],
4277
4283
  "keywords": [
@@ -6338,8 +6344,9 @@
6338
6344
  "【选型·vs Button】Filter 只用于筛选条件选择/收起/清除;普通动作(提交、取消、导出、新建)仍使用 Button。",
6339
6345
  "【尺寸】固定高度 36px(--size-control-md),左右内距 12px(--spacing-3,对齐 Select md),内容 gap 8px(--spacing-2);不要随意压缩为 24px 或 32px,以保证和 B 端 Input/Select 默认高度对齐。",
6340
6346
  "【文字】label 使用 semibold 600,value 使用 normal 400;文案建议 label 2-6 字、value 1-8 字,过长值应在业务层截断或改用 Tooltip。",
6341
- "【下拉多选】传入 options 后点击胶囊展开下拉面板;支持 selectedValues 受控、defaultValue 非受控、onChange(nextValues) 回调;点击外部或 Escape 关闭。",
6342
- "【值展示】未显式传 value 时,单选中展示选项 label,多选中展示“已选 N 项”;显式 value 优先用于自定义展示。",
6347
+ "【下拉单/多选】传入 options 后点击胶囊展开下拉面板;通过 `multiple` 切换:默认 `multiple={true}` 多选(行尾 checkbox 方框,可同时勾多项);`multiple={false}` 单选(行尾 ✓,点击即提交并自动关闭面板,再次点击已选项可反选清空)。两种模式都支持 selectedValues 受控、defaultValue 非受控、onChange 回调;点击外部或 Escape 关闭。",
6348
+ "【受控/回调签名】多选:selectedValues 传数组,onChange 返回数组;单选:selectedValues 可传单值或单元素数组,onChange 返回单值(清空时返回 null)。defaultValue 同样支持单值/数组两种形态。",
6349
+ "【值展示】未显式传 value 时,单选/多选选中 1 项都展示该项 label,多选选中 ≥2 项展示“已选 N 项”,单选始终最多 1 项 label;显式 value 优先用于自定义展示。",
6343
6350
  "【状态】selected=true 使用品牌浅底 + 品牌描边 + 品牌文字;filled=true 使用中性填充底;disabled=true 使用禁用文字与禁用底,且不可点击。",
6344
6351
  "【图标】无选中值时显示 12px 下拉箭头;closable=true 或已选中且未禁用时显示 16px 清除按钮(视觉与 Select 清除入口一致),点击清空多选值、关闭下拉并触发 onClear,不触发展开。",
6345
6352
  "【语义结构】外层使用 role=\"combobox/button\" 的 div 触发器,避免清除 button 嵌套在 button 内;不要改回 button 包 button 的非法 DOM。",
@@ -6352,17 +6359,29 @@
6352
6359
  "code": "<Filter label=\"筛选项\" />"
6353
6360
  },
6354
6361
  {
6355
- "label": "多选下拉",
6362
+ "label": "多选下拉(默认)",
6356
6363
  "code": "<Filter label=\"筛选项\" options={[{ label: \"选项一\", value: \"1\" }, { label: \"选项二\", value: \"2\" }]} />"
6357
6364
  },
6358
6365
  {
6359
- "label": "默认已选",
6366
+ "label": "单选下拉",
6367
+ "code": "<Filter label=\"状态\" multiple={false} options={[{ label: \"全部\", value: \"all\" }, { label: \"进行中\", value: \"running\" }, { label: \"已完成\", value: \"done\" }]} />"
6368
+ },
6369
+ {
6370
+ "label": "默认已选(多选)",
6360
6371
  "code": "<Filter label=\"筛选项\" options={options} defaultValue={[\"1\"]} />"
6361
6372
  },
6373
+ {
6374
+ "label": "默认已选(单选)",
6375
+ "code": "<Filter label=\"状态\" multiple={false} options={options} defaultValue=\"running\" />"
6376
+ },
6362
6377
  {
6363
6378
  "label": "受控多选",
6364
6379
  "code": "<Filter label=\"筛选项\" options={options} selectedValues={values} onChange={setValues} />"
6365
6380
  },
6381
+ {
6382
+ "label": "受控单选",
6383
+ "code": "<Filter label=\"状态\" multiple={false} options={options} selectedValues={current} onChange={setCurrent} />"
6384
+ },
6366
6385
  {
6367
6386
  "label": "选中态",
6368
6387
  "code": "<Filter label=\"筛选项\" options={options} defaultValue={[\"1\"]} selected />"
@@ -6415,6 +6434,11 @@
6415
6434
  "清除筛选",
6416
6435
  "下拉筛选",
6417
6436
  "多选筛选",
6437
+ "单选筛选",
6438
+ "single select filter",
6439
+ "multi select filter",
6440
+ "multiple",
6441
+ "multiple={false}",
6418
6442
  "selected filter",
6419
6443
  "span rounded-full border",
6420
6444
  "手搓筛选",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "system": "b-end",
3
3
  "skill": "tfds",
4
- "generatedAt": "2026-05-13T13:51:39.617Z",
4
+ "generatedAt": "2026-05-14T12:28:55.593Z",
5
5
  "purpose": "轻量组件与页面模板目录。AI 先读本文件做选型;确定命中组件后,再到 components.index.json 按 id 读取 props / rules / examples。",
6
6
  "counts": {
7
7
  "total": 47,
@@ -180,8 +180,8 @@
180
180
  "手搓侧栏",
181
181
  "自制 sidebar"
182
182
  ],
183
- "ruleCount": 23,
184
- "exampleCount": 21,
183
+ "ruleCount": 24,
184
+ "exampleCount": 22,
185
185
  "hasCode": false,
186
186
  "detailRef": "components.index.json#nav-bar"
187
187
  },
@@ -795,7 +795,7 @@
795
795
  "filter",
796
796
  "城市选择"
797
797
  ],
798
- "ruleCount": 26,
798
+ "ruleCount": 27,
799
799
  "exampleCount": 15,
800
800
  "hasCode": false,
801
801
  "detailRef": "components.index.json#select"
@@ -1311,13 +1311,15 @@
1311
1311
  "清除筛选",
1312
1312
  "下拉筛选",
1313
1313
  "多选筛选",
1314
- "selected filter",
1315
- "span rounded-full border",
1316
- "手搓筛选",
1317
- "自制筛选 chip"
1314
+ "单选筛选",
1315
+ "single select filter",
1316
+ "multi select filter",
1317
+ "multiple",
1318
+ "multiple={false}",
1319
+ "selected filter"
1318
1320
  ],
1319
- "ruleCount": 13,
1320
- "exampleCount": 12,
1321
+ "ruleCount": 14,
1322
+ "exampleCount": 15,
1321
1323
  "hasCode": false,
1322
1324
  "detailRef": "components.index.json#filter"
1323
1325
  },