@tfdesign/b-end 1.0.8 → 1.0.9
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 +1 -1
- package/skills/tfds/components.index.json +138 -37
- package/skills/tfds/components.summary.json +22 -22
- package/src/_b_end_runtime/components/Card.jsx +218 -45
- package/src/_b_end_runtime/components/Card.tokens.js +37 -10
- package/src/_b_end_runtime/components/CardPreview.jsx +9 -3
- package/src/_b_end_runtime/components/NavBar.jsx +17 -13
- package/src/_b_end_runtime/components/NavBar.tokens.js +2 -2
- package/src/_b_end_runtime/components.js +61 -34
- package/src/_b_end_runtime/page-patterns/BasePageFramePattern.jsx +4 -5
- package/src/_b_end_runtime/patterns.js +6 -3
- package/src/_b_end_runtime/preview-registry.jsx +50 -11
- package/src/index.d.ts +14 -4
|
@@ -2,12 +2,13 @@ import Avatar from './Avatar';
|
|
|
2
2
|
import FormTitle from './FormTitle';
|
|
3
3
|
import Icon from './Icon';
|
|
4
4
|
import Tag from './Tag';
|
|
5
|
+
import Tooltip from './Tooltip';
|
|
5
6
|
import duanRanAvatar from './team-avatar-assets/duan-ran.png';
|
|
6
7
|
|
|
7
8
|
const DEFAULT_STATS = [
|
|
8
|
-
{ iconName: 'users-01-stroked', value: '1,289' },
|
|
9
|
-
{ iconName: 'message-chat-square-stroked', value: '1,289' },
|
|
10
|
-
{ iconName: 'hearts-stroked', value: '276' },
|
|
9
|
+
{ iconName: 'users-01-stroked', value: '1,289', tooltip: '近 7 天触达用户数' },
|
|
10
|
+
{ iconName: 'message-chat-square-stroked', value: '1,289', tooltip: '近 7 天累计会话量' },
|
|
11
|
+
{ iconName: 'hearts-stroked', value: '276', tooltip: '近 7 天收藏或点赞次数' },
|
|
11
12
|
];
|
|
12
13
|
|
|
13
14
|
const DEFAULT_TAGS = ['标签', '标签'];
|
|
@@ -29,10 +30,15 @@ const DEFAULT_INFO_LAYOUT = 'icon-right';
|
|
|
29
30
|
const DEFAULT_DATA_ICON_VISIBLE = 'hidden';
|
|
30
31
|
const DEFAULT_DATA_ICON_TONE = 'blue';
|
|
31
32
|
const DEFAULT_DATA_ICON_STYLE = 'inverse';
|
|
33
|
+
const DEFAULT_ANIMATED_TITLE = '智能策略生成';
|
|
34
|
+
const DEFAULT_ANIMATED_DESCRIPTION = '基于业务目标、历史数据和运营规则,自动生成可执行策略建议。';
|
|
35
|
+
const DEFAULT_ANIMATED_ICON = 'magic-wand-01-stroked';
|
|
36
|
+
const DEFAULT_ANIMATED_BADGE = 'AI 推荐';
|
|
37
|
+
const DEFAULT_ANIMATED_ACTION_TEXT = '立即体验';
|
|
32
38
|
const DEFAULT_INFO_STATS = [
|
|
33
|
-
{ iconName: 'users-01-stroked', value: '128.6K' },
|
|
34
|
-
{ iconName: 'star-01-stroked', value: '4.9' },
|
|
35
|
-
{ iconName: '
|
|
39
|
+
{ iconName: 'users-01-stroked', value: '128.6K', tooltip: '累计启用该能力的创作者数量' },
|
|
40
|
+
{ iconName: 'star-01-stroked', value: '4.9', tooltip: '用户综合评分,满分 5 分' },
|
|
41
|
+
{ iconName: 'check-circle-stroked', value: '98.6%', tooltip: '近 30 天内容生成任务成功完成率' },
|
|
36
42
|
];
|
|
37
43
|
const DEFAULT_PRODUCT_IMAGE_SRC = `data:image/svg+xml;utf8,${encodeURIComponent(
|
|
38
44
|
"<svg xmlns='http://www.w3.org/2000/svg' width='96' height='96' viewBox='0 0 96 96'><defs><linearGradient id='g' x1='0' y1='0' x2='1' y2='1'><stop offset='0%' stop-color='#2B90D9'/><stop offset='100%' stop-color='#0A355A'/></linearGradient></defs><rect width='96' height='96' fill='url(#g)'/><circle cx='72' cy='24' r='10' fill='rgba(255,255,255,0.28)'/><path d='M0 66C13 52 25 49 38 56C50 62 59 60 69 51C76 45 85 43 96 45V96H0Z' fill='rgba(255,255,255,0.24)'/></svg>"
|
|
@@ -76,6 +82,38 @@ const DATA_ICON_FRAME_BASE = 'inline-flex h-12 w-12 shrink-0 items-center justif
|
|
|
76
82
|
const STATS = 'flex flex-wrap items-center gap-5';
|
|
77
83
|
const STAT = 'inline-flex items-center gap-2 text-xs font-normal leading-4 text-foreground-muted';
|
|
78
84
|
|
|
85
|
+
function renderMetricItem({ iconName, value, tooltip, description }, index, className = STAT) {
|
|
86
|
+
const statTooltip = tooltip || description;
|
|
87
|
+
const statNode = (
|
|
88
|
+
<span
|
|
89
|
+
className={className}
|
|
90
|
+
tabIndex={statTooltip ? 0 : undefined}
|
|
91
|
+
>
|
|
92
|
+
<Icon name={iconName} size={14} />
|
|
93
|
+
<span>{value}</span>
|
|
94
|
+
</span>
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
if (!statTooltip) {
|
|
98
|
+
return (
|
|
99
|
+
<span key={`${iconName}-${value}-${index}`}>
|
|
100
|
+
{statNode}
|
|
101
|
+
</span>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return (
|
|
106
|
+
<Tooltip
|
|
107
|
+
key={`${iconName}-${value}-${index}`}
|
|
108
|
+
content={statTooltip}
|
|
109
|
+
placement="top"
|
|
110
|
+
triggerClassName="inline-flex"
|
|
111
|
+
>
|
|
112
|
+
{statNode}
|
|
113
|
+
</Tooltip>
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
79
117
|
/* ── 商品卡片 ── */
|
|
80
118
|
const PRODUCT_IMAGE_FRAME = [
|
|
81
119
|
'relative h-14 w-14 shrink-0 overflow-hidden',
|
|
@@ -89,7 +127,7 @@ const PRODUCT_CARD_ICON_RIGHT = 'min-h-[96px] flex-row-reverse items-center gap-
|
|
|
89
127
|
const PRODUCT_TITLE = 'm-0 line-clamp-1 min-w-0 flex-1 text-base [font-weight:var(--font-semibold)] leading-card-title text-foreground';
|
|
90
128
|
const PRODUCT_DESCRIPTION = 'm-0 line-clamp-1 text-sm font-normal leading-card-copy text-foreground-muted';
|
|
91
129
|
|
|
92
|
-
/* ── 信息卡片 ── */
|
|
130
|
+
/* ── 信息卡片1 ── */
|
|
93
131
|
const INFO_ICON_FRAME_BASE = 'inline-flex h-12 w-12 shrink-0 items-center justify-center rounded-[var(--radius-lg)] border';
|
|
94
132
|
const INFO_ICON_TONE_CLASS = {
|
|
95
133
|
pink: 'border-pink-100 bg-pink-50 text-pink-600',
|
|
@@ -98,7 +136,22 @@ const INFO_ICON_TONE_CLASS = {
|
|
|
98
136
|
orange: 'border-orange-100 bg-orange-50 text-orange-600',
|
|
99
137
|
purple: 'border-purple-100 bg-purple-50 text-purple-600',
|
|
100
138
|
brand: 'border-brand-100 bg-brand-50 text-brand-600',
|
|
101
|
-
grey: 'border-
|
|
139
|
+
grey: 'border-border-default bg-fill text-blueGrey-600',
|
|
140
|
+
};
|
|
141
|
+
const INFO_ICON_TONE_HOVER_CLASS = [
|
|
142
|
+
'transition-colors duration-200',
|
|
143
|
+
'group-hover:bg-[var(--tfds-card-info-icon-hover-bg)]',
|
|
144
|
+
'group-hover:border-transparent',
|
|
145
|
+
'group-hover:text-white',
|
|
146
|
+
].join(' ');
|
|
147
|
+
const INFO_ICON_TONE_HOVER_STYLE = {
|
|
148
|
+
pink: { '--tfds-card-info-icon-hover-bg': 'var(--color-pink-500)' },
|
|
149
|
+
blue: { '--tfds-card-info-icon-hover-bg': 'var(--color-blue-500)' },
|
|
150
|
+
green: { '--tfds-card-info-icon-hover-bg': 'var(--color-green-500)' },
|
|
151
|
+
orange: { '--tfds-card-info-icon-hover-bg': 'var(--color-orange-500)' },
|
|
152
|
+
purple: { '--tfds-card-info-icon-hover-bg': 'var(--color-purple-500)' },
|
|
153
|
+
brand: { '--tfds-card-info-icon-hover-bg': 'var(--color-brand-500)' },
|
|
154
|
+
grey: { '--tfds-card-info-icon-hover-bg': 'var(--color-black)' },
|
|
102
155
|
};
|
|
103
156
|
const INFO_ICON_STYLE_CLASS = {
|
|
104
157
|
tone: null,
|
|
@@ -149,6 +202,70 @@ const INFO_STAT = [
|
|
|
149
202
|
'[&>svg]:block [&>svg]:shrink-0',
|
|
150
203
|
].join(' ');
|
|
151
204
|
|
|
205
|
+
/* ── 信息卡片2 ── */
|
|
206
|
+
const ANIMATED_CARD = [
|
|
207
|
+
'relative min-h-[180px] flex-col overflow-hidden p-6',
|
|
208
|
+
'focus-within:outline-2 focus-within:outline-offset-2 focus-within:outline-blueGrey-300',
|
|
209
|
+
].join(' ');
|
|
210
|
+
const ANIMATED_CONTENT = 'relative z-10 flex min-h-0 flex-1 flex-col justify-between gap-5';
|
|
211
|
+
const ANIMATED_HEADER = 'flex items-start gap-4';
|
|
212
|
+
const ANIMATED_ICON_FRAME = [
|
|
213
|
+
'inline-flex h-12 w-12 shrink-0 items-center justify-center rounded-[var(--radius-lg)] border',
|
|
214
|
+
'transition-colors duration-200',
|
|
215
|
+
'group-hover:[--tfds-card-animated-icon-bg:var(--tfds-card-animated-icon-hover-bg)]',
|
|
216
|
+
'group-hover:[--tfds-card-animated-icon-border:transparent]',
|
|
217
|
+
'group-hover:[--tfds-card-animated-icon-color:var(--color-white)]',
|
|
218
|
+
].join(' ');
|
|
219
|
+
const ANIMATED_COPY = 'flex min-w-0 flex-col gap-2';
|
|
220
|
+
const ANIMATED_TITLE = 'm-0 line-clamp-1 text-base [font-weight:var(--font-semibold)] leading-card-title text-foreground';
|
|
221
|
+
const ANIMATED_DESCRIPTION = 'm-0 line-clamp-2 text-sm font-normal leading-card-copy text-foreground-muted';
|
|
222
|
+
const ANIMATED_SLOT = 'text-sm leading-card-copy text-foreground-secondary';
|
|
223
|
+
const ANIMATED_FOOTER = 'flex items-center justify-between gap-4';
|
|
224
|
+
const ANIMATED_TONE_STYLE = {
|
|
225
|
+
brand: {
|
|
226
|
+
'--tfds-card-animated-accent': 'var(--color-brand-600)',
|
|
227
|
+
'--tfds-card-animated-icon-bg': 'var(--color-brand-50)',
|
|
228
|
+
'--tfds-card-animated-icon-border': 'var(--color-brand-100)',
|
|
229
|
+
'--tfds-card-animated-icon-color': 'var(--color-brand-700)',
|
|
230
|
+
'--tfds-card-animated-icon-hover-bg': 'var(--color-brand-500)',
|
|
231
|
+
},
|
|
232
|
+
blue: {
|
|
233
|
+
'--tfds-card-animated-accent': 'var(--color-blue-600)',
|
|
234
|
+
'--tfds-card-animated-icon-bg': 'var(--color-blue-50)',
|
|
235
|
+
'--tfds-card-animated-icon-border': 'var(--color-blue-100)',
|
|
236
|
+
'--tfds-card-animated-icon-color': 'var(--color-blue-700)',
|
|
237
|
+
'--tfds-card-animated-icon-hover-bg': 'var(--color-blue-500)',
|
|
238
|
+
},
|
|
239
|
+
purple: {
|
|
240
|
+
'--tfds-card-animated-accent': 'var(--color-purple-600)',
|
|
241
|
+
'--tfds-card-animated-icon-bg': 'var(--color-purple-50)',
|
|
242
|
+
'--tfds-card-animated-icon-border': 'var(--color-purple-100)',
|
|
243
|
+
'--tfds-card-animated-icon-color': 'var(--color-purple-700)',
|
|
244
|
+
'--tfds-card-animated-icon-hover-bg': 'var(--color-purple-500)',
|
|
245
|
+
},
|
|
246
|
+
green: {
|
|
247
|
+
'--tfds-card-animated-accent': 'var(--color-green-600)',
|
|
248
|
+
'--tfds-card-animated-icon-bg': 'var(--color-green-50)',
|
|
249
|
+
'--tfds-card-animated-icon-border': 'var(--color-green-100)',
|
|
250
|
+
'--tfds-card-animated-icon-color': 'var(--color-green-700)',
|
|
251
|
+
'--tfds-card-animated-icon-hover-bg': 'var(--color-green-500)',
|
|
252
|
+
},
|
|
253
|
+
orange: {
|
|
254
|
+
'--tfds-card-animated-accent': 'var(--color-orange-600)',
|
|
255
|
+
'--tfds-card-animated-icon-bg': 'var(--color-orange-50)',
|
|
256
|
+
'--tfds-card-animated-icon-border': 'var(--color-orange-100)',
|
|
257
|
+
'--tfds-card-animated-icon-color': 'var(--color-orange-700)',
|
|
258
|
+
'--tfds-card-animated-icon-hover-bg': 'var(--color-orange-500)',
|
|
259
|
+
},
|
|
260
|
+
grey: {
|
|
261
|
+
'--tfds-card-animated-accent': 'var(--color-blueGrey-700)',
|
|
262
|
+
'--tfds-card-animated-icon-bg': 'var(--color-fill)',
|
|
263
|
+
'--tfds-card-animated-icon-border': 'var(--color-border-default)',
|
|
264
|
+
'--tfds-card-animated-icon-color': 'var(--color-blueGrey-700)',
|
|
265
|
+
'--tfds-card-animated-icon-hover-bg': 'var(--color-black)',
|
|
266
|
+
},
|
|
267
|
+
};
|
|
268
|
+
|
|
152
269
|
/* ── 底部 ── */
|
|
153
270
|
const FOOTER = 'flex w-full items-center justify-between gap-4';
|
|
154
271
|
const ACTION = [
|
|
@@ -164,35 +281,39 @@ const ACTION = [
|
|
|
164
281
|
|
|
165
282
|
/**
|
|
166
283
|
* Card — 业务信息摘要卡片
|
|
167
|
-
* @prop {'data'|'product'|'info'} [type='data'] — 卡片类型:data 为数据卡片,product 为商品卡片,info 为信息卡片
|
|
284
|
+
* @prop {'data'|'product'|'info'|'info2'|'animated'} [type='data'] — 卡片类型:data 为数据卡片,product 为商品卡片,info 为信息卡片1,info2 为信息卡片2;animated 为旧版兼容别名
|
|
168
285
|
* @prop {string} [title] — 卡片标题,商品卡片中为商品标题
|
|
169
286
|
* @prop {string} [description] — 卡片描述,商品卡片中为数量、价格等辅助信息
|
|
170
287
|
* @prop {'white'|'grey'} [color='white'] — 卡片颜色:white 为白底默认样式,grey 为 Blue Grey 灰底样式
|
|
171
|
-
* @prop {Array<{iconName: string, value: string}>|null} [stats=null] —
|
|
172
|
-
* @prop {string[]|null} [tags=null] — 数据卡片标签数组,建议 1-2
|
|
288
|
+
* @prop {Array<{iconName: string, value: string, tooltip?: string}>|null} [stats=null] — 数据卡片指标数组,最多展示 3 项;tooltip 用于 hover/focus 展示详细说明
|
|
289
|
+
* @prop {string[]|null} [tags=null] — 数据卡片标签数组,建议 1-2 个短标签;商品卡片和信息卡片1不渲染通用 tags
|
|
173
290
|
* @prop {string} [productStatus='已使用'] — 商品状态标签文案
|
|
174
291
|
* @prop {string} [productImageSrc] — 商品卡片左侧商品图地址
|
|
175
292
|
* @prop {string} [productImageAlt='商品图'] — 商品图无障碍文案
|
|
176
|
-
* @prop {string} [infoIconName='magic-wand-01-stroked'] —
|
|
177
|
-
* @prop {'pink'|'blue'|'green'|'orange'|'purple'|'brand'|'grey'} [infoIconTone='pink'] —
|
|
178
|
-
* @prop {'tone'|'inverse'} [infoIconStyle='inverse'] —
|
|
179
|
-
* @prop {'default'|'icon-right'} [infoLayout='icon-right'] —
|
|
293
|
+
* @prop {string} [infoIconName='magic-wand-01-stroked'] — 信息卡片1左侧图标名称
|
|
294
|
+
* @prop {'pink'|'blue'|'green'|'orange'|'purple'|'brand'|'grey'} [infoIconTone='pink'] — 信息卡片1左侧图标色系
|
|
295
|
+
* @prop {'tone'|'inverse'} [infoIconStyle='inverse'] — 信息卡片1图标容器样式:tone 为同色系浅底,inverse 为黑底白 icon
|
|
296
|
+
* @prop {'default'|'icon-right'} [infoLayout='icon-right'] — 卡片主视觉布局:信息卡片1为 default 左侧图标 / icon-right 右侧图标;商品卡片为 default 左侧商品图 / icon-right 右侧商品图
|
|
180
297
|
* @prop {'hidden'|'visible'} [dataIconVisible='hidden'] — 数据卡片是否展示右侧图标
|
|
181
298
|
* @prop {string|null} [dataIconName=null] — 数据卡片右侧图标名称;dataIconVisible=visible 时生效
|
|
182
299
|
* @prop {'pink'|'blue'|'green'|'orange'|'purple'|'brand'|'grey'} [dataIconTone='blue'] — 数据卡片右侧图标容器色系
|
|
183
300
|
* @prop {'tone'|'inverse'} [dataIconStyle='inverse'] — 数据卡片右侧图标容器样式:tone 为彩色浅底,inverse 为黑底白 icon
|
|
184
|
-
* @prop {
|
|
185
|
-
* @prop {string} [
|
|
186
|
-
* @prop {
|
|
187
|
-
* @prop {string} [
|
|
188
|
-
* @prop {string} [
|
|
189
|
-
* @prop {
|
|
301
|
+
* @prop {'brand'|'blue'|'purple'|'green'|'orange'|'grey'} [animatedTone='grey'] — 信息卡片2图标色系
|
|
302
|
+
* @prop {string|null} [animatedIconName='magic-wand-01-stroked'] — 信息卡片2左上角图标
|
|
303
|
+
* @prop {string|null} [animatedBadge='AI 推荐'] — 信息卡片2左下角徽标
|
|
304
|
+
* @prop {string|null} [animatedActionText='立即体验'] — 信息卡片2底部右侧操作文案
|
|
305
|
+
* @prop {string} [infoMetaLabel='段然'] — 信息卡片1底部人名昵称
|
|
306
|
+
* @prop {string} [infoMetaBadge='官方能力'] — 信息卡片1右上角徽标文案
|
|
307
|
+
* @prop {'brand'|'red'|'orange'|'yellow'|'green'|'cyan'|'blue'|'purple'|'pink'|'teal'|'grey'|'white'|'ai'|null} [infoMetaBadgeVariant=null] — 信息卡片1右上角徽标颜色;黑底白标时可覆盖,彩色浅底时固定 grey
|
|
308
|
+
* @prop {string} [infoMetaAvatarSrc] — 信息卡片1底部人名昵称头像
|
|
309
|
+
* @prop {string} [infoMetaAvatarAlt='用户头像'] — 信息卡片1底部人名昵称头像无障碍文案
|
|
310
|
+
* @prop {Array<{iconName: string, value: string, tooltip?: string}>|null} [infoStats=null] — 信息卡片1底部右侧辅助项数组,最多展示 3 项;tooltip 用于 hover/focus 展示详细说明
|
|
190
311
|
* @prop {function|null} [onAction=null] — 数据卡片右侧箭头操作回调
|
|
191
312
|
* @prop {string} [actionAriaLabel='查看卡片详情'] — 右侧操作按钮无障碍文案
|
|
192
313
|
* @prop {string} [className=''] — 附加类名
|
|
193
314
|
* @prop {object} [style] — 内联样式
|
|
194
315
|
*
|
|
195
|
-
* 通用 tags
|
|
316
|
+
* 通用 tags 仅用于数据卡片左下角;商品和信息卡片1不渲染标题左侧通用标签。
|
|
196
317
|
* 卡片容器默认半透明白底,hover 后补满白底并出现业务卡片专用投影。
|
|
197
318
|
*/
|
|
198
319
|
export default function Card({
|
|
@@ -219,28 +340,35 @@ export default function Card({
|
|
|
219
340
|
dataIconName = null,
|
|
220
341
|
dataIconTone = DEFAULT_DATA_ICON_TONE,
|
|
221
342
|
dataIconStyle = DEFAULT_DATA_ICON_STYLE,
|
|
343
|
+
animatedTone = 'grey',
|
|
344
|
+
animatedIconName = DEFAULT_ANIMATED_ICON,
|
|
345
|
+
animatedBadge = DEFAULT_ANIMATED_BADGE,
|
|
346
|
+
animatedActionText = DEFAULT_ANIMATED_ACTION_TEXT,
|
|
347
|
+
children,
|
|
222
348
|
onAction,
|
|
223
349
|
actionAriaLabel = '查看卡片详情',
|
|
224
350
|
className = '',
|
|
225
351
|
style,
|
|
226
352
|
}) {
|
|
227
|
-
const resolvedType = type === 'product' || type === 'info'
|
|
353
|
+
const resolvedType = type === 'product' || type === 'info'
|
|
354
|
+
? type
|
|
355
|
+
: (type === 'info2' || type === 'animated' ? 'info2' : 'data');
|
|
228
356
|
const resolvedColor = color === 'grey' ? 'grey' : 'white';
|
|
229
357
|
const resolvedTitle = title || (
|
|
230
358
|
resolvedType === 'product'
|
|
231
359
|
? DEFAULT_PRODUCT_TITLE
|
|
232
|
-
: (resolvedType === 'info' ? DEFAULT_INFO_TITLE : DEFAULT_DATA_TITLE)
|
|
360
|
+
: (resolvedType === 'info' ? DEFAULT_INFO_TITLE : (resolvedType === 'info2' ? DEFAULT_ANIMATED_TITLE : DEFAULT_DATA_TITLE))
|
|
233
361
|
);
|
|
234
362
|
const resolvedDescription = description || (
|
|
235
363
|
resolvedType === 'product'
|
|
236
364
|
? DEFAULT_PRODUCT_DESCRIPTION
|
|
237
|
-
: (resolvedType === 'info' ? DEFAULT_INFO_DESCRIPTION : DEFAULT_DATA_DESCRIPTION)
|
|
365
|
+
: (resolvedType === 'info' ? DEFAULT_INFO_DESCRIPTION : (resolvedType === 'info2' ? DEFAULT_ANIMATED_DESCRIPTION : DEFAULT_DATA_DESCRIPTION))
|
|
238
366
|
);
|
|
239
|
-
const resolvedStats = Array.isArray(stats) && stats.length > 0 ? stats : DEFAULT_STATS;
|
|
367
|
+
const resolvedStats = (Array.isArray(stats) && stats.length > 0 ? stats : DEFAULT_STATS).slice(0, 3);
|
|
240
368
|
const resolvedTags = resolvedType === 'data'
|
|
241
369
|
? (Array.isArray(tags) && tags.length > 0 ? tags : DEFAULT_TAGS)
|
|
242
370
|
: [];
|
|
243
|
-
const resolvedInfoStats = Array.isArray(infoStats) && infoStats.length > 0 ? infoStats : DEFAULT_INFO_STATS;
|
|
371
|
+
const resolvedInfoStats = (Array.isArray(infoStats) && infoStats.length > 0 ? infoStats : DEFAULT_INFO_STATS).slice(0, 3);
|
|
244
372
|
const resolvedInfoIconTone = Object.prototype.hasOwnProperty.call(INFO_ICON_TONE_CLASS, infoIconTone)
|
|
245
373
|
? infoIconTone
|
|
246
374
|
: DEFAULT_INFO_ICON_TONE;
|
|
@@ -261,8 +389,13 @@ export default function Card({
|
|
|
261
389
|
: DEFAULT_DATA_ICON_STYLE;
|
|
262
390
|
const resolvedDataIconVisible = dataIconVisible === 'visible' ? 'visible' : DEFAULT_DATA_ICON_VISIBLE;
|
|
263
391
|
const hasDataIcon = resolvedType === 'data' && resolvedDataIconVisible === 'visible' && !!dataIconName;
|
|
392
|
+
const resolvedAnimatedTone = Object.prototype.hasOwnProperty.call(ANIMATED_TONE_STYLE, animatedTone)
|
|
393
|
+
? animatedTone
|
|
394
|
+
: 'grey';
|
|
264
395
|
const cardStyle = {
|
|
265
396
|
...(CARD_VARIANT_STYLE[resolvedColor] || {}),
|
|
397
|
+
...(resolvedType === 'info' && resolvedInfoIconStyle === 'tone' ? INFO_ICON_TONE_HOVER_STYLE[resolvedInfoIconTone] : {}),
|
|
398
|
+
...(resolvedType === 'info2' ? ANIMATED_TONE_STYLE[resolvedAnimatedTone] : {}),
|
|
266
399
|
...style,
|
|
267
400
|
};
|
|
268
401
|
|
|
@@ -308,6 +441,7 @@ export default function Card({
|
|
|
308
441
|
resolvedInfoIconStyle === 'inverse'
|
|
309
442
|
? INFO_ICON_STYLE_CLASS.inverse
|
|
310
443
|
: INFO_ICON_TONE_CLASS[resolvedInfoIconTone],
|
|
444
|
+
resolvedInfoIconStyle === 'tone' ? INFO_ICON_TONE_HOVER_CLASS : null,
|
|
311
445
|
].join(' ')}
|
|
312
446
|
aria-hidden="true"
|
|
313
447
|
>
|
|
@@ -372,13 +506,62 @@ export default function Card({
|
|
|
372
506
|
</span>
|
|
373
507
|
|
|
374
508
|
<div className={INFO_STATS}>
|
|
375
|
-
{resolvedInfoStats.map((
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
509
|
+
{resolvedInfoStats.map((stat, index) => renderMetricItem(stat, index, INFO_STAT))}
|
|
510
|
+
</div>
|
|
511
|
+
</div>
|
|
512
|
+
</div>
|
|
513
|
+
</article>
|
|
514
|
+
);
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
if (resolvedType === 'info2') {
|
|
518
|
+
return (
|
|
519
|
+
<article
|
|
520
|
+
className={[CARD_SURFACE, ANIMATED_CARD, CARD_VARIANT_CLASS[resolvedColor], className].filter(Boolean).join(' ')}
|
|
521
|
+
style={cardStyle}
|
|
522
|
+
data-tfds-component="Card"
|
|
523
|
+
>
|
|
524
|
+
<div className={ANIMATED_CONTENT}>
|
|
525
|
+
<div className={ANIMATED_HEADER}>
|
|
526
|
+
{animatedIconName ? (
|
|
527
|
+
<span
|
|
528
|
+
className={ANIMATED_ICON_FRAME}
|
|
529
|
+
style={{
|
|
530
|
+
backgroundColor: 'var(--tfds-card-animated-icon-bg)',
|
|
531
|
+
borderColor: 'var(--tfds-card-animated-icon-border)',
|
|
532
|
+
color: 'var(--tfds-card-animated-icon-color)',
|
|
533
|
+
}}
|
|
534
|
+
aria-hidden="true"
|
|
535
|
+
>
|
|
536
|
+
<Icon name={animatedIconName} size={24} />
|
|
537
|
+
</span>
|
|
538
|
+
) : null}
|
|
539
|
+
</div>
|
|
540
|
+
|
|
541
|
+
<div className={ANIMATED_COPY}>
|
|
542
|
+
<h3 className={ANIMATED_TITLE}>{resolvedTitle}</h3>
|
|
543
|
+
<p className={ANIMATED_DESCRIPTION}>{resolvedDescription}</p>
|
|
544
|
+
</div>
|
|
545
|
+
|
|
546
|
+
<div className={ANIMATED_FOOTER}>
|
|
547
|
+
<div className={ANIMATED_SLOT}>
|
|
548
|
+
{animatedBadge ? (
|
|
549
|
+
<Tag variant="white" size="l" radius="md" fontWeight="regular">
|
|
550
|
+
{animatedBadge}
|
|
551
|
+
</Tag>
|
|
552
|
+
) : children}
|
|
381
553
|
</div>
|
|
554
|
+
{animatedActionText ? (
|
|
555
|
+
<button
|
|
556
|
+
type="button"
|
|
557
|
+
className={ACTION}
|
|
558
|
+
aria-label={animatedActionText || actionAriaLabel}
|
|
559
|
+
onClick={onAction}
|
|
560
|
+
disabled={!onAction}
|
|
561
|
+
>
|
|
562
|
+
<Icon name="arrow-narrow-right-stroked" size={16} />
|
|
563
|
+
</button>
|
|
564
|
+
) : null}
|
|
382
565
|
</div>
|
|
383
566
|
</div>
|
|
384
567
|
</article>
|
|
@@ -399,12 +582,7 @@ export default function Card({
|
|
|
399
582
|
<p className={DESCRIPTION}>{resolvedDescription}</p>
|
|
400
583
|
</div>
|
|
401
584
|
<div className={STATS}>
|
|
402
|
-
{resolvedStats.map((
|
|
403
|
-
<span key={`${iconName}-${value}-${index}`} className={STAT}>
|
|
404
|
-
<Icon name={iconName} size={14} />
|
|
405
|
-
<span>{value}</span>
|
|
406
|
-
</span>
|
|
407
|
-
))}
|
|
585
|
+
{resolvedStats.map((stat, index) => renderMetricItem(stat, index))}
|
|
408
586
|
</div>
|
|
409
587
|
</div>
|
|
410
588
|
<span
|
|
@@ -427,12 +605,7 @@ export default function Card({
|
|
|
427
605
|
</div>
|
|
428
606
|
|
|
429
607
|
<div className={STATS}>
|
|
430
|
-
{resolvedStats.map((
|
|
431
|
-
<span key={`${iconName}-${value}-${index}`} className={STAT}>
|
|
432
|
-
<Icon name={iconName} size={14} />
|
|
433
|
-
<span>{value}</span>
|
|
434
|
-
</span>
|
|
435
|
-
))}
|
|
608
|
+
{resolvedStats.map((stat, index) => renderMetricItem(stat, index))}
|
|
436
609
|
</div>
|
|
437
610
|
</div>
|
|
438
611
|
)}
|
|
@@ -22,6 +22,8 @@ export const CARD_TOKEN_MAP = {
|
|
|
22
22
|
{ label: '图标尺寸', cssProp: 'icon-size', token: '--size-icon-14', value: '14px' },
|
|
23
23
|
{ label: '行高', cssProp: 'line-height', token: '--leading-4', value: '16px' },
|
|
24
24
|
{ label: '项间距', cssProp: 'gap', token: '--spacing-5', value: '20px' },
|
|
25
|
+
{ label: '数据项数量', cssProp: 'content', value: 'stats 最多展示 3 项动态数据,超出运行时截断' },
|
|
26
|
+
{ label: '数据项结构', cssProp: 'prop', value: 'stats: Array<{ iconName, value, tooltip? }>;tooltip 用于 hover/focus 展示详细说明' },
|
|
25
27
|
{ label: '图标显示配置', cssProp: 'prop', value: 'dataIconVisible: hidden(默认不显示) / visible(显示右侧图标)' },
|
|
26
28
|
{ label: '右侧图标容器', cssProp: 'width/height', value: '48×48px,圆角 rounded-xl / 16px(仅数据卡片)' },
|
|
27
29
|
{ label: '图标与标题区间距', cssProp: 'gap', token: '--spacing-5', value: '20px,与数据卡片 p-5 内边距一致' },
|
|
@@ -43,7 +45,7 @@ export const CARD_TOKEN_MAP = {
|
|
|
43
45
|
{ label: '副标题颜色', cssProp: 'color', token: '--color-foreground-muted', value: '#667085', semanticRef: 'text-tertiary' },
|
|
44
46
|
{ label: '最小高度', cssProp: 'min-height', value: '96px' },
|
|
45
47
|
],
|
|
46
|
-
|
|
48
|
+
信息卡片1: [
|
|
47
49
|
{ label: '布局模式', cssProp: 'prop', value: 'infoLayout: 图标在左(default) / 图标在右(icon-right)' },
|
|
48
50
|
{ label: '图标在左', cssProp: 'display', value: '左侧图标 + 右侧标题/副标题/右上徽标 + 底部辅助信息' },
|
|
49
51
|
{ label: '图标在右', cssProp: 'display', value: '左侧标题/副标题/底部辅助信息 + 最右侧图标;徽标紧跟标题右侧,间距 8px' },
|
|
@@ -56,9 +58,14 @@ export const CARD_TOKEN_MAP = {
|
|
|
56
58
|
{ label: '图标容器圆角', cssProp: 'border-radius', token: '--radius-lg', value: '12px' },
|
|
57
59
|
{ label: '图标色系配置', cssProp: 'prop', value: 'infoIconTone: pink / blue / green / orange / purple / brand / grey' },
|
|
58
60
|
{ label: '图标样式配置', cssProp: 'prop', value: 'infoIconStyle: tone / inverse' },
|
|
59
|
-
{ label: '图标容器背景', cssProp: 'background-color', token: '--color-*-50', value: '
|
|
60
|
-
{ label: '
|
|
61
|
+
{ label: '图标容器背景', cssProp: 'background-color', token: '--color-*-50', value: '彩色系使用同色系 50 token;grey 使用 fill-default' },
|
|
62
|
+
{ label: 'Grey 图标背景', cssProp: 'background-color', token: '--color-fill', value: 'rgba(83, 96, 143, 0.07)', semanticRef: 'fill-default' },
|
|
63
|
+
{ label: '图标容器描边', cssProp: 'border-color', token: '--color-*-100', value: '彩色系使用同色系 100 token;grey 使用 border-default' },
|
|
64
|
+
{ label: 'Grey 图标描边', cssProp: 'border-color', token: '--color-border-default', value: '#E4E7EC', semanticRef: 'border-default' },
|
|
61
65
|
{ label: '图标颜色', cssProp: 'color', token: '--color-*-600', value: '同色系 600 token / brand 使用 brand-600' },
|
|
66
|
+
{ label: '彩色浅底 Hover 背景', cssProp: 'background-color', token: '--color-*-500 / --color-black', value: 'infoIconStyle=tone 时,hover 自动使用当前 infoIconTone 对应 500 token;grey 单独使用 --color-black' },
|
|
67
|
+
{ label: '彩色浅底 Hover 颜色', cssProp: 'color', token: '--color-white', value: '#FFFFFF' },
|
|
68
|
+
{ label: '彩色浅底 Hover 描边', cssProp: 'border-color', token: 'transparent', value: 'hover 时不显示描边色' },
|
|
62
69
|
{ label: '反色图标样式', cssProp: 'background/color', value: 'inverse: 黑背景 + 白色 icon' },
|
|
63
70
|
{ label: '图标尺寸', cssProp: 'icon-size', value: '24px' },
|
|
64
71
|
{ label: '标题组件', cssProp: 'component', value: 'FormTitle / variant=form / showDescription' },
|
|
@@ -72,7 +79,7 @@ export const CARD_TOKEN_MAP = {
|
|
|
72
79
|
{ label: '徽标颜色联动', cssProp: 'variant', value: 'tone: 一律 grey;inverse: 默认 purple 彩色标签,可通过 infoMetaBadgeVariant 覆盖' },
|
|
73
80
|
{ label: '彩色标签优先级', cssProp: 'variant', value: 'purple(紫色)> teal(青绿色)> blue(蓝色)> cyan(青色)> orange(橙色)' },
|
|
74
81
|
{ label: '徽标位置', cssProp: 'placement', value: '所有布局均紧跟主标题右侧' },
|
|
75
|
-
{ label: '标题与徽标间距', cssProp: 'gap', token: '--spacing-2', value: '8px
|
|
82
|
+
{ label: '标题与徽标间距', cssProp: 'gap', token: '--spacing-2', value: '8px(所有信息卡片1布局)' },
|
|
76
83
|
{ label: '标题与徽标对齐', cssProp: 'align-items', value: '所有布局均水平排列并垂直居中对齐' },
|
|
77
84
|
{ label: '昵称头像', cssProp: 'component', value: 'Avatar / type=image / shape=round / size=xxs' },
|
|
78
85
|
{ label: '昵称头像尺寸', cssProp: 'width/height', value: '16px' },
|
|
@@ -81,13 +88,33 @@ export const CARD_TOKEN_MAP = {
|
|
|
81
88
|
{ label: '身份区行高', cssProp: 'height/line-height', token: '--leading-4', value: '16px,头像与文字垂直居中' },
|
|
82
89
|
{ label: '身份文案', cssProp: 'semantic', value: '默认“段然”,可按负责人 / 创建人 / 团队动态替换' },
|
|
83
90
|
{ label: '昵称字号', cssProp: 'font-size', token: '--text-xs', value: '12px' },
|
|
84
|
-
{ label: '辅助区指标行', cssProp: 'component-style', value: '复用数据卡片指标行样式,infoStats
|
|
91
|
+
{ label: '辅助区指标行', cssProp: 'component-style', value: '复用数据卡片指标行样式,infoStats 最多展示 3 项动态数据' },
|
|
85
92
|
{ label: '辅助区对齐', cssProp: 'align-items', value: '整行所有头像、图标、文字高度水平居中对齐' },
|
|
86
93
|
{ label: '辅助区间距', cssProp: 'gap', token: '--spacing-5', value: '20px' },
|
|
87
94
|
{ label: '辅助项图标', cssProp: 'component', value: 'Icon / 14px' },
|
|
88
95
|
{ label: '辅助项文字', cssProp: 'font-size/font-weight', value: '12px / 400' },
|
|
96
|
+
{ label: '辅助项结构', cssProp: 'prop', value: 'infoStats: Array<{ iconName, value, tooltip? }>;tooltip 用于 hover/focus 展示详细说明' },
|
|
89
97
|
{ label: '辅助项语义', cssProp: 'content', value: '启用量 / 评分 / 调用量 / 响应率 / 转化率 / 更新时间 / 操作入口' },
|
|
90
98
|
],
|
|
99
|
+
信息卡片2: [
|
|
100
|
+
{ label: '适用场景', cssProp: 'usage', value: 'AI 能力推荐 / 重点工具入口 / 配置向导 / 首页推荐能力;单页建议最多 1-2 张' },
|
|
101
|
+
{ label: '结构', cssProp: 'layout', value: '左上图标 + 标题/描述 + 左下角徽标 + 右下角圆形箭头操作入口' },
|
|
102
|
+
{ label: '背景与描边', cssProp: 'background/border', value: '完全复用 Card color=white / grey 的背景、描边和 hover 投影规则' },
|
|
103
|
+
{ label: '交互', cssProp: 'motion', value: '无柔光、无流动动画、无特殊 hover 位移;仅保留普通 Card hover 投影' },
|
|
104
|
+
{ label: '图标色系配置', cssProp: 'prop', value: 'animatedTone: brand / blue / purple / green / orange / grey,默认 grey;仅影响左上图标容器;grey 背景使用 fill-default,描边使用 border-default' },
|
|
105
|
+
{ label: '图标容器', cssProp: 'width/height', value: '48px × 48px' },
|
|
106
|
+
{ label: '图标圆角', cssProp: 'border-radius', token: '--radius-lg', value: '12px' },
|
|
107
|
+
{ label: '图标 Hover 背景', cssProp: 'background-color', token: '--color-*-500 / --color-black', value: 'hover 自动使用当前 animatedTone 对应 500 token;grey 单独使用 --color-black' },
|
|
108
|
+
{ label: '图标 Hover 颜色', cssProp: 'color', token: '--color-white', value: '#FFFFFF' },
|
|
109
|
+
{ label: '图标 Hover 描边', cssProp: 'border-color', token: 'transparent', value: 'hover 时不显示描边色' },
|
|
110
|
+
{ label: '标题字号', cssProp: 'font-size', token: '--text-base', value: '16px' },
|
|
111
|
+
{ label: '标题字重', cssProp: 'font-weight', token: '--font-semibold', value: '600' },
|
|
112
|
+
{ label: '描述行数', cssProp: 'line-clamp', value: '最多 2 行' },
|
|
113
|
+
{ label: '徽标位置', cssProp: 'placement', value: '左下角,与标题左边界对齐,并与右下角圆形箭头操作入口同一行垂直居中' },
|
|
114
|
+
{ label: '徽标样式', cssProp: 'component-style', value: 'Tag variant="white" / fontWeight="regular" / size=l / radius=md' },
|
|
115
|
+
{ label: '操作按钮', cssProp: 'component-style', value: '复用数据卡片 ACTION:28px 圆形箭头按钮 / hover 黑色描边与黑色箭头 / active 缩放;无 onAction 时禁用' },
|
|
116
|
+
{ label: '操作文案', cssProp: 'a11y-label', value: 'animatedActionText 作为圆形箭头按钮语义文案,不直接渲染为文字按钮' },
|
|
117
|
+
],
|
|
91
118
|
卡片: [
|
|
92
119
|
{ label: '白底背景', cssProp: 'background', token: '--color-card-secondary', value: 'rgba(255,255,255,0.65)', semanticRef: 'bg-card-secondary', state: 'default' },
|
|
93
120
|
{ label: '白底 Hover 背景', cssProp: 'background', token: '--color-surface', value: '#FFFFFF', semanticRef: 'bg-surface', state: 'hover' },
|
|
@@ -114,11 +141,11 @@ export const CARD_TOKEN_MAP = {
|
|
|
114
141
|
引用组件: [
|
|
115
142
|
{ label: '数据卡片标签', cssProp: 'component', value: 'Tag / variant=white / size=l / radius=md / 左下角' },
|
|
116
143
|
{ label: '商品状态标签', cssProp: 'component', value: 'Tag / variant=green / size=l / radius=md' },
|
|
117
|
-
{ label: '
|
|
118
|
-
{ label: '
|
|
119
|
-
{ label: '
|
|
120
|
-
{ label: '
|
|
144
|
+
{ label: '信息卡片1主图标', cssProp: 'component', value: 'Icon / 同色系浅底 + 描边容器' },
|
|
145
|
+
{ label: '信息卡片1标题', cssProp: 'component', value: 'FormTitle / variant=form / showDescription' },
|
|
146
|
+
{ label: '信息卡片1徽标', cssProp: 'component', value: 'Tag / infoMetaBadgeVariant / size=l / radius=md' },
|
|
147
|
+
{ label: '信息卡片1昵称头像', cssProp: 'component', value: 'Avatar / type=image / shape=round / size=xxs' },
|
|
121
148
|
{ label: '数据卡片图标', cssProp: 'component', value: 'Icon / users-01-stroked / message-chat-square-stroked / hearts-stroked / arrow-narrow-right-stroked' },
|
|
122
|
-
{ label: '
|
|
149
|
+
{ label: '信息卡片1图标', cssProp: 'component', value: 'Icon / magic-wand-01-stroked / users-01-stroked / star-01-stroked / check-circle-stroked' },
|
|
123
150
|
],
|
|
124
151
|
};
|
|
@@ -11,10 +11,12 @@ export default function CardPreview({
|
|
|
11
11
|
infoLayout,
|
|
12
12
|
dataIconVisible,
|
|
13
13
|
dataIconStyle,
|
|
14
|
+
animatedTone,
|
|
14
15
|
}) {
|
|
15
16
|
const isProduct = type === 'product';
|
|
16
17
|
const isInfo = type === 'info';
|
|
17
|
-
const
|
|
18
|
+
const isInfo2 = type === 'info2' || type === 'animated';
|
|
19
|
+
const isData = !isProduct && !isInfo && !isInfo2;
|
|
18
20
|
const resolvedInfoIconStyle = isInfo ? (infoIconStyle || 'inverse') : infoIconStyle;
|
|
19
21
|
const resolvedInfoLayout = isInfo
|
|
20
22
|
? (infoLayout || 'icon-right')
|
|
@@ -28,8 +30,8 @@ export default function CardPreview({
|
|
|
28
30
|
<Card
|
|
29
31
|
type={type}
|
|
30
32
|
color={color}
|
|
31
|
-
title={isProduct ? '海底捞门店通用双人套餐' : undefined}
|
|
32
|
-
description={isProduct ? '数量 1 · ¥128.00 · 月售 2,361' : undefined}
|
|
33
|
+
title={isProduct ? '海底捞门店通用双人套餐' : (isInfo2 ? '智能策略生成' : undefined)}
|
|
34
|
+
description={isProduct ? '数量 1 · ¥128.00 · 月售 2,361' : (isInfo2 ? '基于业务目标、历史数据和运营规则,自动生成可执行策略建议。' : undefined)}
|
|
33
35
|
tags={isProduct || isInfo ? [] : undefined}
|
|
34
36
|
productStatus={isProduct ? '已使用' : undefined}
|
|
35
37
|
infoIconTone={isInfo ? infoIconTone : undefined}
|
|
@@ -42,6 +44,10 @@ export default function CardPreview({
|
|
|
42
44
|
dataIconName={isData && resolvedDataIconVisible === 'visible' ? 'edit-04-stroked' : undefined}
|
|
43
45
|
dataIconTone={isData ? 'blue' : undefined}
|
|
44
46
|
dataIconStyle={isData ? resolvedDataIconStyle : undefined}
|
|
47
|
+
animatedTone={isInfo2 ? (animatedTone || 'grey') : undefined}
|
|
48
|
+
animatedIconName={isInfo2 ? 'magic-wand-01-stroked' : undefined}
|
|
49
|
+
animatedBadge={isInfo2 ? 'AI 推荐' : undefined}
|
|
50
|
+
animatedActionText={isInfo2 ? '立即体验' : undefined}
|
|
45
51
|
actionAriaLabel={isProduct ? undefined : '查看卡片详情'}
|
|
46
52
|
onAction={isProduct ? undefined : () => {}}
|
|
47
53
|
/>
|
|
@@ -18,8 +18,8 @@ import { getTeamMemberByName } from '../teamMembers';
|
|
|
18
18
|
* @prop {string|null} currentAppId — 当前业务入口 id(受控)
|
|
19
19
|
* @prop {string|null} [defaultAppId=null] — 非受控初始业务入口 id
|
|
20
20
|
* @prop {(appId: string, meta: { app: {id: string, label: string, iconSrc?: string} | null }) => void} [onAppChange=null] — 业务入口切换回调
|
|
21
|
-
* @prop {string} [moduleLabel='平台首页'] — OLA
|
|
22
|
-
* @prop {boolean} [activeModule=true] —
|
|
21
|
+
* @prop {string} [moduleLabel='平台首页'] — OLA 首页导航文案;未传 navItems 时用于生成默认 navItems[0]
|
|
22
|
+
* @prop {boolean} [activeModule=true] — 兼容旧 API;未传 selectedItemId / defaultSelectedItemId / activeNavId 时默认选中首页
|
|
23
23
|
* @prop {Array<{id: string, label: string, iconName: string, active?: boolean}>|null} [navItems=null] — 主导航项
|
|
24
24
|
* @prop {string|null} [activeNavId=null] — 当前激活的主导航 id
|
|
25
25
|
* @prop {string|null} [activeUtilityId=null] — 当前激活的底部工具按钮 id
|
|
@@ -27,7 +27,7 @@ import { getTeamMemberByName } from '../teamMembers';
|
|
|
27
27
|
* @prop {string|null} [defaultSelectedItemId=null] — 非受控模式下的初始选中菜单 id
|
|
28
28
|
* @prop {boolean} [showUtilityActions=false] — 是否显示底部操作按钮;OLA 下控制铃铛/设置,ByteHi 下控制操作指南/消息
|
|
29
29
|
* @prop {Array<{id: string, label: string, iconName: string}>|null} [utilityItems=null] — 底部工具按钮;OLA / ByteHi 都支持自定义
|
|
30
|
-
* @prop {(itemId: string, meta: { section: '
|
|
30
|
+
* @prop {(itemId: string, meta: { section: 'nav'|'utility'|'status', item: object|null }) => void} [onSelect=null] — 菜单点击回调
|
|
31
31
|
* @prop {'image'|'robot'|'fallback'} [avatarType='image'] — 底部头像类型
|
|
32
32
|
* @prop {string|null} [avatarSrc=null] — 自定义头像地址
|
|
33
33
|
* @prop {string} [avatarAlt='当前用户头像'] — 头像替代文本
|
|
@@ -36,6 +36,7 @@ import { getTeamMemberByName } from '../teamMembers';
|
|
|
36
36
|
*/
|
|
37
37
|
|
|
38
38
|
const DEFAULT_OLA_NAV_ITEMS = [
|
|
39
|
+
{ id: 'home', label: '平台首页', iconName: 'home-smile-stroked' },
|
|
39
40
|
{ id: 'strategy', label: '策略管理', iconName: 'if-stroked' },
|
|
40
41
|
{ id: 'knowledge', label: '知识与案例', iconName: 'book-open-01-stroked' },
|
|
41
42
|
{ id: 'tools', label: '工具管理', iconName: 'tool-01-stroked' },
|
|
@@ -257,14 +258,25 @@ function resolveInitialSelectedKey({
|
|
|
257
258
|
if (defaultSelectedItemId) return defaultSelectedItemId;
|
|
258
259
|
if (activeUtilityId && utilityItems.some((item) => item.id === activeUtilityId)) return activeUtilityId;
|
|
259
260
|
if (activeNavId) return activeNavId;
|
|
260
|
-
if (platform === 'ola' && activeModule) return 'module';
|
|
261
261
|
const explicitNav = navItems.find((item) => item.active);
|
|
262
262
|
if (explicitNav) return explicitNav.id;
|
|
263
263
|
const explicitUtility = utilityItems.find((item) => item.active);
|
|
264
264
|
if (explicitUtility) return explicitUtility.id;
|
|
265
|
+
if (platform === 'ola' && activeModule) return navItems[0]?.id ?? 'home';
|
|
265
266
|
return platform === 'bytehi' ? navItems[0]?.id ?? null : null;
|
|
266
267
|
}
|
|
267
268
|
|
|
269
|
+
function getDefaultOlaNavItems(moduleLabel, moduleIconName) {
|
|
270
|
+
return DEFAULT_OLA_NAV_ITEMS.map((item, index) => {
|
|
271
|
+
if (index !== 0) return item;
|
|
272
|
+
return {
|
|
273
|
+
...item,
|
|
274
|
+
label: moduleLabel || item.label,
|
|
275
|
+
iconName: moduleIconName || item.iconName,
|
|
276
|
+
};
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
|
|
268
280
|
function getResolvedOlaAppBusinesses(appBusinesses, appLabel) {
|
|
269
281
|
const fallbackBusinesses = TAGBAR_SAMPLE_BUSINESSES.map((item, index) => ({
|
|
270
282
|
...item,
|
|
@@ -547,7 +559,7 @@ export default function NavBar({
|
|
|
547
559
|
const resolvedPlatform = platform === 'bytehi' ? 'bytehi' : (platform === 'ola' ? 'ola' : (inferredPlatform || 'ola'));
|
|
548
560
|
const resolvedNavItems = Array.isArray(navItems) && navItems.length > 0
|
|
549
561
|
? navItems
|
|
550
|
-
: (resolvedPlatform === 'bytehi' ? DEFAULT_BYTEHI_NAV_ITEMS :
|
|
562
|
+
: (resolvedPlatform === 'bytehi' ? DEFAULT_BYTEHI_NAV_ITEMS : getDefaultOlaNavItems(moduleLabel, moduleIconName));
|
|
551
563
|
const resolvedAppBusinesses = getResolvedOlaAppBusinesses(appBusinesses, appLabel);
|
|
552
564
|
const resolvedUtilityItems = showUtilityActions
|
|
553
565
|
? (Array.isArray(utilityItems) && utilityItems.length > 0
|
|
@@ -785,14 +797,6 @@ export default function NavBar({
|
|
|
785
797
|
</div>
|
|
786
798
|
|
|
787
799
|
<div className={OLA_MAIN_NAV}>
|
|
788
|
-
<OlaNavButton
|
|
789
|
-
iconName={moduleIconName}
|
|
790
|
-
label={moduleLabel}
|
|
791
|
-
tone={selectedKey === 'module' ? 'active' : 'default'}
|
|
792
|
-
ariaLabel={`${moduleLabel}模块`}
|
|
793
|
-
current={selectedKey === 'module'}
|
|
794
|
-
onClick={() => handleSelect('module', 'module', null)}
|
|
795
|
-
/>
|
|
796
800
|
{resolvedNavItems.map((item) => {
|
|
797
801
|
const isActive = selectedKey ? item.id === selectedKey : Boolean(item.active);
|
|
798
802
|
return (
|
|
@@ -16,8 +16,8 @@ export const NAVBAR_TOKEN_MAP = {
|
|
|
16
16
|
{ label: '下拉选项间距', cssProp: 'gap', token: '--spacing-1', value: '4px', state: 'dropdown' },
|
|
17
17
|
],
|
|
18
18
|
模块: [
|
|
19
|
-
{ label: '菜单身份', cssProp: 'semantics', value: '
|
|
20
|
-
{ label: '首页默认', cssProp: 'state', value: 'AI 新生成页面或明确为首页时,默认 selectedItemId="
|
|
19
|
+
{ label: '菜单身份', cssProp: 'semantics', value: '平台首页统一作为 navItems[0],默认 id="home",不是单独的 module 按钮' },
|
|
20
|
+
{ label: '首页默认', cssProp: 'state', value: 'AI 新生成页面或明确为首页时,默认 selectedItemId="home"' },
|
|
21
21
|
{ label: '默认色', cssProp: 'color', token: '--color-foreground-muted', value: '#667085', semanticRef: 'text-tertiary', state: 'default' },
|
|
22
22
|
{ label: '激活色', cssProp: 'color', token: '--color-foreground', value: '#182230', semanticRef: 'text-primary', state: 'active' },
|
|
23
23
|
{ label: '图标色', cssProp: 'color', token: '--color-brand-500', value: '#56D3BC', state: 'active' },
|