@tfdesign/b-end 1.0.4
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/AI_READ_FIRST.md +131 -0
- package/LICENSE +21 -0
- package/README.md +353 -0
- package/package.json +67 -0
- package/scripts/check-tfds-contract.mjs +334 -0
- package/scripts/check-tfds-integration.mjs +263 -0
- package/scripts/postinstall-cursor-skill.mjs +382 -0
- package/scripts/setup.mjs +520 -0
- package/skills/tfds/CHECKLIST.md +205 -0
- package/skills/tfds/COMMON_FAILURES.md +238 -0
- package/skills/tfds/DESIGN_PRINCIPLES.md +477 -0
- package/skills/tfds/GLOBAL_DESIGN_RULES.md +636 -0
- package/skills/tfds/LAYOUT_RECIPES.md +140 -0
- package/skills/tfds/LAYOUT_RULES.md +1355 -0
- package/skills/tfds/PAGE_ARCHETYPES.md +201 -0
- package/skills/tfds/SKILL.md +188 -0
- package/skills/tfds/components.index.json +7305 -0
- package/skills/tfds/components.summary.json +1809 -0
- package/src/_b_end_runtime/components/AiSuggestionShared.jsx +166 -0
- package/src/_b_end_runtime/components/Avatar.jsx +325 -0
- package/src/_b_end_runtime/components/Avatar.tokens.js +76 -0
- package/src/_b_end_runtime/components/AvatarGridPreview.jsx +56 -0
- package/src/_b_end_runtime/components/AvatarGroup.jsx +80 -0
- package/src/_b_end_runtime/components/AvatarGroup.tokens.js +28 -0
- package/src/_b_end_runtime/components/Button.jsx +144 -0
- package/src/_b_end_runtime/components/Button.tokens.js +90 -0
- package/src/_b_end_runtime/components/Card.jsx +460 -0
- package/src/_b_end_runtime/components/Card.tokens.js +124 -0
- package/src/_b_end_runtime/components/CardPreview.jsx +51 -0
- package/src/_b_end_runtime/components/ChatBubble.jsx +384 -0
- package/src/_b_end_runtime/components/ChatBubble.tokens.js +60 -0
- package/src/_b_end_runtime/components/ChatBubblePreview.jsx +129 -0
- package/src/_b_end_runtime/components/ChatInput.jsx +1399 -0
- package/src/_b_end_runtime/components/ChatInput.tokens.js +75 -0
- package/src/_b_end_runtime/components/ChatMessage.jsx +2215 -0
- package/src/_b_end_runtime/components/ChatMessage.tokens.js +257 -0
- package/src/_b_end_runtime/components/ChatMessagePreview.jsx +388 -0
- package/src/_b_end_runtime/components/Checkbox.jsx +317 -0
- package/src/_b_end_runtime/components/Checkbox.tokens.js +59 -0
- package/src/_b_end_runtime/components/ConversationList.jsx +1264 -0
- package/src/_b_end_runtime/components/ConversationList.tokens.js +135 -0
- package/src/_b_end_runtime/components/ConversationListPreview.jsx +108 -0
- package/src/_b_end_runtime/components/CustomerServiceWorkspaceFrame.jsx +324 -0
- package/src/_b_end_runtime/components/CustomerServiceWorkspaceFrame.tokens.js +69 -0
- package/src/_b_end_runtime/components/DatePicker.jsx +739 -0
- package/src/_b_end_runtime/components/DatePicker.tokens.js +99 -0
- package/src/_b_end_runtime/components/Empty.jsx +141 -0
- package/src/_b_end_runtime/components/Empty.tokens.js +40 -0
- package/src/_b_end_runtime/components/Form.jsx +609 -0
- package/src/_b_end_runtime/components/Form.tokens.js +77 -0
- package/src/_b_end_runtime/components/FormFieldStack.jsx +123 -0
- package/src/_b_end_runtime/components/FormFieldStack.tokens.js +12 -0
- package/src/_b_end_runtime/components/FormTitle.jsx +119 -0
- package/src/_b_end_runtime/components/FormTitle.tokens.js +87 -0
- package/src/_b_end_runtime/components/FullScreenPage.jsx +97 -0
- package/src/_b_end_runtime/components/FullScreenPage.tokens.js +19 -0
- package/src/_b_end_runtime/components/Icon.jsx +172 -0
- package/src/_b_end_runtime/components/Icon.tokens.js +26 -0
- package/src/_b_end_runtime/components/IconGridPreview.jsx +277 -0
- package/src/_b_end_runtime/components/InfoDisplayPanel.jsx +620 -0
- package/src/_b_end_runtime/components/InfoDisplayPanel.tokens.js +71 -0
- package/src/_b_end_runtime/components/InfoDisplayPanelPreview.jsx +133 -0
- package/src/_b_end_runtime/components/Input.jsx +258 -0
- package/src/_b_end_runtime/components/Input.tokens.js +68 -0
- package/src/_b_end_runtime/components/InputNumber.jsx +242 -0
- package/src/_b_end_runtime/components/InputNumber.tokens.js +55 -0
- package/src/_b_end_runtime/components/Modal.jsx +155 -0
- package/src/_b_end_runtime/components/Modal.tokens.js +73 -0
- package/src/_b_end_runtime/components/NavBar.jsx +842 -0
- package/src/_b_end_runtime/components/NavBar.tokens.js +97 -0
- package/src/_b_end_runtime/components/NavBarPreview.jsx +11 -0
- package/src/_b_end_runtime/components/Radio.jsx +227 -0
- package/src/_b_end_runtime/components/Radio.tokens.js +59 -0
- package/src/_b_end_runtime/components/Select.jsx +766 -0
- package/src/_b_end_runtime/components/Select.tokens.js +99 -0
- package/src/_b_end_runtime/components/Sheet.jsx +132 -0
- package/src/_b_end_runtime/components/Sheet.tokens.js +61 -0
- package/src/_b_end_runtime/components/Slider.jsx +346 -0
- package/src/_b_end_runtime/components/Slider.tokens.js +47 -0
- package/src/_b_end_runtime/components/Switch.jsx +124 -0
- package/src/_b_end_runtime/components/Switch.tokens.js +38 -0
- package/src/_b_end_runtime/components/Table.jsx +1338 -0
- package/src/_b_end_runtime/components/Table.tokens.js +147 -0
- package/src/_b_end_runtime/components/TablePreview.jsx +599 -0
- package/src/_b_end_runtime/components/Tabs.jsx +149 -0
- package/src/_b_end_runtime/components/Tabs.tokens.js +102 -0
- package/src/_b_end_runtime/components/Tag.jsx +199 -0
- package/src/_b_end_runtime/components/Tag.tokens.js +171 -0
- package/src/_b_end_runtime/components/TagBar.jsx +1134 -0
- package/src/_b_end_runtime/components/TagBar.tokens.js +75 -0
- package/src/_b_end_runtime/components/TagGridPreview.jsx +23 -0
- package/src/_b_end_runtime/components/TagInput.jsx +382 -0
- package/src/_b_end_runtime/components/TagInput.tokens.js +52 -0
- package/src/_b_end_runtime/components/TextArea.jsx +363 -0
- package/src/_b_end_runtime/components/TextArea.tokens.js +65 -0
- package/src/_b_end_runtime/components/TimePicker.jsx +444 -0
- package/src/_b_end_runtime/components/TimePicker.tokens.js +77 -0
- package/src/_b_end_runtime/components/Toast.jsx +120 -0
- package/src/_b_end_runtime/components/Toast.tokens.js +146 -0
- package/src/_b_end_runtime/components/Tooltip.jsx +282 -0
- package/src/_b_end_runtime/components/Tooltip.tokens.js +48 -0
- package/src/_b_end_runtime/components/TooltipPreview.jsx +50 -0
- package/src/_b_end_runtime/components/Upload.jsx +455 -0
- package/src/_b_end_runtime/components/Upload.tokens.js +47 -0
- package/src/_b_end_runtime/components/avatar-assets/avatar-default.png +0 -0
- package/src/_b_end_runtime/components/avatar-group-assets/avatar-group-1.png +0 -0
- package/src/_b_end_runtime/components/avatar-group-assets/avatar-group-2.png +0 -0
- package/src/_b_end_runtime/components/avatar-group-assets/avatar-group-3.png +0 -0
- package/src/_b_end_runtime/components/avatar-group-assets/avatar-group-4.png +0 -0
- package/src/_b_end_runtime/components/avatar-group-assets/avatar-group-5.png +0 -0
- package/src/_b_end_runtime/components/empty-assets/administrator-1.svg +40 -0
- package/src/_b_end_runtime/components/empty-assets/administrator-2.svg +33 -0
- package/src/_b_end_runtime/components/empty-assets/construction.svg +33 -0
- package/src/_b_end_runtime/components/empty-assets/failure.svg +49 -0
- package/src/_b_end_runtime/components/empty-assets/idle.svg +34 -0
- package/src/_b_end_runtime/components/empty-assets/no-access.svg +36 -0
- package/src/_b_end_runtime/components/empty-assets/no-content.svg +77 -0
- package/src/_b_end_runtime/components/empty-assets/no-result.svg +61 -0
- package/src/_b_end_runtime/components/empty-assets/not-found.svg +46 -0
- package/src/_b_end_runtime/components/empty-assets/success.svg +38 -0
- package/src/_b_end_runtime/components/file-type-assets/batch-report.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/catcat.svg +21 -0
- package/src/_b_end_runtime/components/file-type-assets/code.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/conversation.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/document.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/feishu-card.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/feishu-sheet.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/feishu.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/image.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/index.js +105 -0
- package/src/_b_end_runtime/components/file-type-assets/knowledge.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/pdf.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/pe.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/strategy.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/table.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/webpage.png +0 -0
- package/src/_b_end_runtime/components/file-type-assets/xmind.png +0 -0
- package/src/_b_end_runtime/components/icons/icon-data.js +12496 -0
- package/src/_b_end_runtime/components/nav-bar-assets/bytehi-logo-mark.svg +21 -0
- package/src/_b_end_runtime/components/table-assets/avatar.png +0 -0
- package/src/_b_end_runtime/components/table-assets/button.png +0 -0
- package/src/_b_end_runtime/components/table-assets/icon-chevron-down.png +0 -0
- package/src/_b_end_runtime/components/table-cell-assets/avatar.png +0 -0
- package/src/_b_end_runtime/components/table-cell-assets/button.png +0 -0
- package/src/_b_end_runtime/components/table-cell-assets/checkbox.png +0 -0
- package/src/_b_end_runtime/components/table-cell-assets/icon-chevron-right.png +0 -0
- package/src/_b_end_runtime/components/table-cell-assets/icon.png +0 -0
- package/src/_b_end_runtime/components/table-cell-assets/semi-icons-handle.png +0 -0
- package/src/_b_end_runtime/components/table-cell-assets/semi-icons-tree-triangle-right.png +0 -0
- package/src/_b_end_runtime/components/table-cell-assets/switch.png +0 -0
- package/src/_b_end_runtime/components/tagShared.js +3 -0
- package/src/_b_end_runtime/components/team-avatar-assets/chengcheng-murphy.png +0 -0
- package/src/_b_end_runtime/components/team-avatar-assets/duan-ran.png +0 -0
- package/src/_b_end_runtime/components/team-avatar-assets/guo-zhezhi.png +0 -0
- package/src/_b_end_runtime/components/team-avatar-assets/li-siru.png +0 -0
- package/src/_b_end_runtime/components/team-avatar-assets/liu-delin.png +0 -0
- package/src/_b_end_runtime/components.js +3499 -0
- package/src/_b_end_runtime/index.js +9 -0
- package/src/_b_end_runtime/page-patterns/BasePageFramePattern.jsx +395 -0
- package/src/_b_end_runtime/page-patterns/ChatConversationPattern.jsx +989 -0
- package/src/_b_end_runtime/page-patterns/ChatHomePagePattern.jsx +281 -0
- package/src/_b_end_runtime/page-patterns/CopilotPagePattern.jsx +380 -0
- package/src/_b_end_runtime/page-patterns/CustomerServiceWorkspaceFramePattern.jsx +392 -0
- package/src/_b_end_runtime/page-patterns/IMConversationPattern.jsx +590 -0
- package/src/_b_end_runtime/page-patterns/McpManagementPage.jsx +237 -0
- package/src/_b_end_runtime/page-patterns/StrategyListPage.jsx +189 -0
- package/src/_b_end_runtime/page-patterns/TabTopBarListPage.jsx +594 -0
- package/src/_b_end_runtime/page-patterns/VariableManagementPage.jsx +87 -0
- package/src/_b_end_runtime/page-patterns/pageListShared.jsx +177 -0
- package/src/_b_end_runtime/patterns.js +428 -0
- package/src/_b_end_runtime/preview-registry.jsx +4719 -0
- package/src/_b_end_runtime/teamMembers.js +56 -0
- package/src/_b_end_runtime/tokens.js +500 -0
- package/src/index.d.ts +1073 -0
- package/src/index.js +52 -0
- package/theme.css +350 -0
|
@@ -0,0 +1,460 @@
|
|
|
1
|
+
import Avatar from './Avatar';
|
|
2
|
+
import FormTitle from './FormTitle';
|
|
3
|
+
import Icon from './Icon';
|
|
4
|
+
import Tag from './Tag';
|
|
5
|
+
import duanRanAvatar from './team-avatar-assets/duan-ran.png';
|
|
6
|
+
|
|
7
|
+
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' },
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
const DEFAULT_TAGS = ['标签', '标签'];
|
|
14
|
+
const DEFAULT_DATA_TITLE = '智能服务近7天趋势分析';
|
|
15
|
+
const DEFAULT_DATA_DESCRIPTION = '针对指定业务场景下智能服务核心指标、运行路径、渠道等进行趋势分析,并输出总结报告';
|
|
16
|
+
const DEFAULT_PRODUCT_TITLE = '海底捞门店通用双人套餐';
|
|
17
|
+
const DEFAULT_PRODUCT_DESCRIPTION = '数量 1 · ¥128.00 · 月售 2,361';
|
|
18
|
+
const DEFAULT_PRODUCT_STATUS = '已使用';
|
|
19
|
+
const DEFAULT_INFO_TITLE = '抖音 AI 创作助手';
|
|
20
|
+
const DEFAULT_INFO_DESCRIPTION = '抖音官方 AI 创作能力,支持短视频脚本、标题推荐、封面文案和热点灵感生成,帮助创作者提升内容生产效率。';
|
|
21
|
+
const DEFAULT_INFO_META = '段然';
|
|
22
|
+
const DEFAULT_INFO_BADGE = '官方能力';
|
|
23
|
+
const DEFAULT_INFO_ICON_TONE = 'pink';
|
|
24
|
+
const DEFAULT_INFO_ICON_STYLE = 'inverse';
|
|
25
|
+
const DEFAULT_INFO_BADGE_VARIANT = 'purple';
|
|
26
|
+
const DEFAULT_INFO_ICON = 'magic-wand-01-stroked';
|
|
27
|
+
const DEFAULT_INFO_META_AVATAR = duanRanAvatar;
|
|
28
|
+
const DEFAULT_INFO_LAYOUT = 'icon-right';
|
|
29
|
+
const DEFAULT_DATA_ICON_VISIBLE = 'hidden';
|
|
30
|
+
const DEFAULT_DATA_ICON_TONE = 'blue';
|
|
31
|
+
const DEFAULT_DATA_ICON_STYLE = 'inverse';
|
|
32
|
+
const DEFAULT_INFO_STATS = [
|
|
33
|
+
{ iconName: 'users-01-stroked', value: '128.6K' },
|
|
34
|
+
{ iconName: 'star-01-stroked', value: '4.9' },
|
|
35
|
+
{ iconName: 'play-circle-stroked', value: '立即体验' },
|
|
36
|
+
];
|
|
37
|
+
const DEFAULT_PRODUCT_IMAGE_SRC = `data:image/svg+xml;utf8,${encodeURIComponent(
|
|
38
|
+
"<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>"
|
|
39
|
+
)}`;
|
|
40
|
+
|
|
41
|
+
/* ── 卡片容器 ── */
|
|
42
|
+
const CARD_SURFACE = [
|
|
43
|
+
'tfds-card',
|
|
44
|
+
'group flex w-full',
|
|
45
|
+
'rounded-xl border p-5',
|
|
46
|
+
'transition-all duration-200',
|
|
47
|
+
'hover:shadow-card',
|
|
48
|
+
].join(' ');
|
|
49
|
+
|
|
50
|
+
const DATA_CARD = 'min-h-[var(--size-card-min-height)] flex-col justify-between gap-7';
|
|
51
|
+
const PRODUCT_CARD = 'min-h-[96px] flex-row items-center gap-5 [&_.tfds-tag.bg-white]:hidden';
|
|
52
|
+
const INFO_CARD = 'min-h-[148px] flex-row items-start gap-6 p-6 [&_.tfds-tag.bg-white]:hidden';
|
|
53
|
+
|
|
54
|
+
const CARD_VARIANT_CLASS = {
|
|
55
|
+
white: 'border-white bg-card-secondary hover:border-white hover:bg-surface',
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const CARD_VARIANT_STYLE = {
|
|
59
|
+
grey: {
|
|
60
|
+
backgroundColor: 'var(--color-blueGrey-100)',
|
|
61
|
+
borderColor: 'var(--color-blueGrey-300)',
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/* ── 内容区 ── */
|
|
66
|
+
const CONTENT = 'flex w-full flex-col items-start gap-4';
|
|
67
|
+
const COPY = 'flex w-full flex-col items-start gap-2';
|
|
68
|
+
const TITLE = 'm-0 w-full text-base [font-weight:var(--font-semibold)] leading-card-title text-foreground';
|
|
69
|
+
const DESCRIPTION = 'm-0 w-full text-sm font-normal leading-card-copy text-foreground-muted';
|
|
70
|
+
const DATA_TAGS = 'flex flex-wrap items-center gap-2';
|
|
71
|
+
const DATA_ICON_ROW = 'flex w-full items-start gap-5';
|
|
72
|
+
const DATA_CONTENT_INNER = 'flex min-w-0 flex-1 flex-col items-start gap-4';
|
|
73
|
+
const DATA_ICON_FRAME_BASE = 'inline-flex h-12 w-12 shrink-0 items-center justify-center rounded-xl border';
|
|
74
|
+
|
|
75
|
+
/* ── 数据行 ── */
|
|
76
|
+
const STATS = 'flex flex-wrap items-center gap-5';
|
|
77
|
+
const STAT = 'inline-flex items-center gap-2 text-xs font-normal leading-4 text-foreground-muted';
|
|
78
|
+
|
|
79
|
+
/* ── 商品卡片 ── */
|
|
80
|
+
const PRODUCT_IMAGE_FRAME = [
|
|
81
|
+
'relative h-14 w-14 shrink-0 overflow-hidden',
|
|
82
|
+
'[border-radius:var(--radius-lg)] border border-white bg-surface shadow-sm',
|
|
83
|
+
].join(' ');
|
|
84
|
+
const PRODUCT_IMAGE = 'h-full w-full object-cover';
|
|
85
|
+
const PRODUCT_BODY = 'flex h-14 min-w-0 flex-1 flex-col justify-center gap-2';
|
|
86
|
+
const PRODUCT_HEADER = 'flex min-w-0 items-start justify-between gap-3';
|
|
87
|
+
const PRODUCT_HEADER_ICON_RIGHT = 'flex min-w-0 items-center gap-2 [&>h3]:flex-initial';
|
|
88
|
+
const PRODUCT_CARD_ICON_RIGHT = 'min-h-[96px] flex-row-reverse items-center gap-5 [&_.tfds-tag.bg-white]:hidden';
|
|
89
|
+
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
|
+
const PRODUCT_DESCRIPTION = 'm-0 line-clamp-1 text-sm font-normal leading-card-copy text-foreground-muted';
|
|
91
|
+
|
|
92
|
+
/* ── 信息卡片 ── */
|
|
93
|
+
const INFO_ICON_FRAME_BASE = 'inline-flex h-12 w-12 shrink-0 items-center justify-center rounded-[var(--radius-lg)] border';
|
|
94
|
+
const INFO_ICON_TONE_CLASS = {
|
|
95
|
+
pink: 'border-pink-100 bg-pink-50 text-pink-600',
|
|
96
|
+
blue: 'border-blue-100 bg-blue-50 text-blue-600',
|
|
97
|
+
green: 'border-green-100 bg-green-50 text-green-600',
|
|
98
|
+
orange: 'border-orange-100 bg-orange-50 text-orange-600',
|
|
99
|
+
purple: 'border-purple-100 bg-purple-50 text-purple-600',
|
|
100
|
+
brand: 'border-brand-100 bg-brand-50 text-brand-600',
|
|
101
|
+
grey: 'border-blueGrey-100 bg-blueGrey-50 text-blueGrey-600',
|
|
102
|
+
};
|
|
103
|
+
const INFO_ICON_STYLE_CLASS = {
|
|
104
|
+
tone: null,
|
|
105
|
+
inverse: 'border-black bg-black text-white',
|
|
106
|
+
};
|
|
107
|
+
const INFO_BADGE_VARIANTS = new Set([
|
|
108
|
+
'brand',
|
|
109
|
+
'red',
|
|
110
|
+
'orange',
|
|
111
|
+
'yellow',
|
|
112
|
+
'green',
|
|
113
|
+
'cyan',
|
|
114
|
+
'blue',
|
|
115
|
+
'purple',
|
|
116
|
+
'pink',
|
|
117
|
+
'teal',
|
|
118
|
+
'grey',
|
|
119
|
+
'white',
|
|
120
|
+
'ai',
|
|
121
|
+
]);
|
|
122
|
+
const INFO_BODY = 'flex min-w-0 flex-1 flex-col gap-5';
|
|
123
|
+
const INFO_HEADER = 'flex min-w-0 flex-col gap-2';
|
|
124
|
+
const INFO_HEADER_INLINE = 'flex min-w-0 items-start justify-between gap-3';
|
|
125
|
+
const INFO_HEADER_ROW = 'flex min-w-0 items-center gap-2';
|
|
126
|
+
const INFO_TITLE = 'm-0 min-w-0 flex-initial line-clamp-1 text-base [font-weight:var(--font-semibold)] leading-card-title text-foreground';
|
|
127
|
+
const INFO_DESCRIPTION = 'm-0 w-full text-sm font-normal leading-5 text-foreground-muted line-clamp-2';
|
|
128
|
+
const INFO_TITLE_GROUP = [
|
|
129
|
+
'min-w-0 flex-1 gap-2',
|
|
130
|
+
'[&>div>span]:line-clamp-1 [&>div>span]:!text-base [&>div>span]:!leading-card-title',
|
|
131
|
+
'[&>span]:line-clamp-2 [&>span]:!text-xs [&>span]:!leading-5',
|
|
132
|
+
].join(' ');
|
|
133
|
+
const INFO_TITLE_GROUP_ICON_RIGHT = [
|
|
134
|
+
INFO_TITLE_GROUP,
|
|
135
|
+
'[&>div]:gap-2',
|
|
136
|
+
'[&>div]:items-center',
|
|
137
|
+
].join(' ');
|
|
138
|
+
const INFO_FOOTER = 'flex min-w-0 flex-wrap items-center justify-between gap-x-8 gap-y-3';
|
|
139
|
+
const INFO_META = 'inline-flex h-4 min-w-0 items-center gap-2 text-xs font-normal leading-4 text-foreground-muted';
|
|
140
|
+
const INFO_META_AVATAR = [
|
|
141
|
+
'[&>img]:!scale-100',
|
|
142
|
+
'[&>img]:!translate-y-0',
|
|
143
|
+
'[&>img]:!object-center',
|
|
144
|
+
].join(' ');
|
|
145
|
+
const INFO_STATS = 'flex h-4 flex-wrap items-center gap-5';
|
|
146
|
+
const INFO_STAT = [
|
|
147
|
+
'inline-flex h-4 items-center gap-2',
|
|
148
|
+
'text-xs font-normal leading-4 text-foreground-muted',
|
|
149
|
+
'[&>svg]:block [&>svg]:shrink-0',
|
|
150
|
+
].join(' ');
|
|
151
|
+
|
|
152
|
+
/* ── 底部 ── */
|
|
153
|
+
const FOOTER = 'flex w-full items-center justify-between gap-4';
|
|
154
|
+
const ACTION = [
|
|
155
|
+
'card-action inline-flex h-7 w-7 shrink-0 items-center justify-center rounded-full',
|
|
156
|
+
'border border-transparent text-foreground-muted',
|
|
157
|
+
'transition-all duration-200',
|
|
158
|
+
'hover:border-black hover:text-black',
|
|
159
|
+
'active:scale-[0.96]',
|
|
160
|
+
'focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blueGrey-300',
|
|
161
|
+
'disabled:opacity-50 disabled:cursor-not-allowed disabled:pointer-events-none',
|
|
162
|
+
'group-hover:border-black group-hover:text-black',
|
|
163
|
+
].join(' ');
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Card — 业务信息摘要卡片
|
|
167
|
+
* @prop {'data'|'product'|'info'} [type='data'] — 卡片类型:data 为数据卡片,product 为商品卡片,info 为信息卡片
|
|
168
|
+
* @prop {string} [title] — 卡片标题,商品卡片中为商品标题
|
|
169
|
+
* @prop {string} [description] — 卡片描述,商品卡片中为数量、价格等辅助信息
|
|
170
|
+
* @prop {'white'|'grey'} [color='white'] — 卡片颜色:white 为白底默认样式,grey 为 Blue Grey 灰底样式
|
|
171
|
+
* @prop {Array<{iconName: string, value: string}>|null} [stats=null] — 指标数组,建议 1-3 项
|
|
172
|
+
* @prop {string[]|null} [tags=null] — 数据卡片标签数组,建议 1-2 个短标签;商品卡片和信息卡片不渲染通用 tags
|
|
173
|
+
* @prop {string} [productStatus='已使用'] — 商品状态标签文案
|
|
174
|
+
* @prop {string} [productImageSrc] — 商品卡片左侧商品图地址
|
|
175
|
+
* @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'] — 信息卡片图标容器样式:tone 为同色系浅底,inverse 为黑底白 icon
|
|
179
|
+
* @prop {'default'|'icon-right'} [infoLayout='icon-right'] — 卡片主视觉布局:信息卡片为 default 左侧图标 / icon-right 右侧图标;商品卡片为 default 左侧商品图 / icon-right 右侧商品图
|
|
180
|
+
* @prop {'hidden'|'visible'} [dataIconVisible='hidden'] — 数据卡片是否展示右侧图标
|
|
181
|
+
* @prop {string|null} [dataIconName=null] — 数据卡片右侧图标名称;dataIconVisible=visible 时生效
|
|
182
|
+
* @prop {'pink'|'blue'|'green'|'orange'|'purple'|'brand'|'grey'} [dataIconTone='blue'] — 数据卡片右侧图标容器色系
|
|
183
|
+
* @prop {'tone'|'inverse'} [dataIconStyle='inverse'] — 数据卡片右侧图标容器样式:tone 为彩色浅底,inverse 为黑底白 icon
|
|
184
|
+
* @prop {string} [infoMetaLabel='段然'] — 信息卡片底部人名昵称
|
|
185
|
+
* @prop {string} [infoMetaBadge='官方能力'] — 信息卡片右上角徽标文案
|
|
186
|
+
* @prop {'brand'|'red'|'orange'|'yellow'|'green'|'cyan'|'blue'|'purple'|'pink'|'teal'|'grey'|'white'|'ai'|null} [infoMetaBadgeVariant=null] — 信息卡片右上角徽标颜色;黑底白标时可覆盖,彩色浅底时固定 grey
|
|
187
|
+
* @prop {string} [infoMetaAvatarSrc] — 信息卡片底部人名昵称头像
|
|
188
|
+
* @prop {string} [infoMetaAvatarAlt='用户头像'] — 信息卡片底部人名昵称头像无障碍文案
|
|
189
|
+
* @prop {Array<{iconName: string, value: string}>|null} [infoStats=null] — 信息卡片底部右侧辅助项数组
|
|
190
|
+
* @prop {function|null} [onAction=null] — 数据卡片右侧箭头操作回调
|
|
191
|
+
* @prop {string} [actionAriaLabel='查看卡片详情'] — 右侧操作按钮无障碍文案
|
|
192
|
+
* @prop {string} [className=''] — 附加类名
|
|
193
|
+
* @prop {object} [style] — 内联样式
|
|
194
|
+
*
|
|
195
|
+
* 通用 tags 仅用于数据卡片左下角;商品和信息卡片不渲染标题左侧通用标签。
|
|
196
|
+
* 卡片容器默认半透明白底,hover 后补满白底并出现业务卡片专用投影。
|
|
197
|
+
*/
|
|
198
|
+
export default function Card({
|
|
199
|
+
type = 'data',
|
|
200
|
+
title,
|
|
201
|
+
description,
|
|
202
|
+
color = 'white',
|
|
203
|
+
stats = null,
|
|
204
|
+
tags = null,
|
|
205
|
+
productStatus = DEFAULT_PRODUCT_STATUS,
|
|
206
|
+
productImageSrc,
|
|
207
|
+
productImageAlt = '商品图',
|
|
208
|
+
infoIconName = DEFAULT_INFO_ICON,
|
|
209
|
+
infoIconTone = DEFAULT_INFO_ICON_TONE,
|
|
210
|
+
infoIconStyle = DEFAULT_INFO_ICON_STYLE,
|
|
211
|
+
infoLayout = DEFAULT_INFO_LAYOUT,
|
|
212
|
+
infoMetaLabel = DEFAULT_INFO_META,
|
|
213
|
+
infoMetaBadge = DEFAULT_INFO_BADGE,
|
|
214
|
+
infoMetaBadgeVariant = null,
|
|
215
|
+
infoMetaAvatarSrc = DEFAULT_INFO_META_AVATAR,
|
|
216
|
+
infoMetaAvatarAlt = '用户头像',
|
|
217
|
+
infoStats = null,
|
|
218
|
+
dataIconVisible = DEFAULT_DATA_ICON_VISIBLE,
|
|
219
|
+
dataIconName = null,
|
|
220
|
+
dataIconTone = DEFAULT_DATA_ICON_TONE,
|
|
221
|
+
dataIconStyle = DEFAULT_DATA_ICON_STYLE,
|
|
222
|
+
onAction,
|
|
223
|
+
actionAriaLabel = '查看卡片详情',
|
|
224
|
+
className = '',
|
|
225
|
+
style,
|
|
226
|
+
}) {
|
|
227
|
+
const resolvedType = type === 'product' || type === 'info' ? type : 'data';
|
|
228
|
+
const resolvedColor = color === 'grey' ? 'grey' : 'white';
|
|
229
|
+
const resolvedTitle = title || (
|
|
230
|
+
resolvedType === 'product'
|
|
231
|
+
? DEFAULT_PRODUCT_TITLE
|
|
232
|
+
: (resolvedType === 'info' ? DEFAULT_INFO_TITLE : DEFAULT_DATA_TITLE)
|
|
233
|
+
);
|
|
234
|
+
const resolvedDescription = description || (
|
|
235
|
+
resolvedType === 'product'
|
|
236
|
+
? DEFAULT_PRODUCT_DESCRIPTION
|
|
237
|
+
: (resolvedType === 'info' ? DEFAULT_INFO_DESCRIPTION : DEFAULT_DATA_DESCRIPTION)
|
|
238
|
+
);
|
|
239
|
+
const resolvedStats = Array.isArray(stats) && stats.length > 0 ? stats : DEFAULT_STATS;
|
|
240
|
+
const resolvedTags = resolvedType === 'data'
|
|
241
|
+
? (Array.isArray(tags) && tags.length > 0 ? tags : DEFAULT_TAGS)
|
|
242
|
+
: [];
|
|
243
|
+
const resolvedInfoStats = Array.isArray(infoStats) && infoStats.length > 0 ? infoStats : DEFAULT_INFO_STATS;
|
|
244
|
+
const resolvedInfoIconTone = Object.prototype.hasOwnProperty.call(INFO_ICON_TONE_CLASS, infoIconTone)
|
|
245
|
+
? infoIconTone
|
|
246
|
+
: DEFAULT_INFO_ICON_TONE;
|
|
247
|
+
const resolvedInfoIconStyle = Object.prototype.hasOwnProperty.call(INFO_ICON_STYLE_CLASS, infoIconStyle)
|
|
248
|
+
? infoIconStyle
|
|
249
|
+
: DEFAULT_INFO_ICON_STYLE;
|
|
250
|
+
const resolvedInfoLayout = infoLayout === 'default' || infoLayout === 'icon-right'
|
|
251
|
+
? infoLayout
|
|
252
|
+
: DEFAULT_INFO_LAYOUT;
|
|
253
|
+
const resolvedInfoMetaBadgeVariant = resolvedInfoIconStyle === 'tone'
|
|
254
|
+
? 'grey'
|
|
255
|
+
: (INFO_BADGE_VARIANTS.has(infoMetaBadgeVariant) ? infoMetaBadgeVariant : DEFAULT_INFO_BADGE_VARIANT);
|
|
256
|
+
const resolvedDataIconTone = Object.prototype.hasOwnProperty.call(INFO_ICON_TONE_CLASS, dataIconTone)
|
|
257
|
+
? dataIconTone
|
|
258
|
+
: DEFAULT_DATA_ICON_TONE;
|
|
259
|
+
const resolvedDataIconStyle = Object.prototype.hasOwnProperty.call(INFO_ICON_STYLE_CLASS, dataIconStyle)
|
|
260
|
+
? dataIconStyle
|
|
261
|
+
: DEFAULT_DATA_ICON_STYLE;
|
|
262
|
+
const resolvedDataIconVisible = dataIconVisible === 'visible' ? 'visible' : DEFAULT_DATA_ICON_VISIBLE;
|
|
263
|
+
const hasDataIcon = resolvedType === 'data' && resolvedDataIconVisible === 'visible' && !!dataIconName;
|
|
264
|
+
const cardStyle = {
|
|
265
|
+
...(CARD_VARIANT_STYLE[resolvedColor] || {}),
|
|
266
|
+
...style,
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
if (resolvedType === 'product') {
|
|
270
|
+
return (
|
|
271
|
+
<article
|
|
272
|
+
className={[
|
|
273
|
+
CARD_SURFACE,
|
|
274
|
+
resolvedInfoLayout === 'icon-right' ? PRODUCT_CARD_ICON_RIGHT : PRODUCT_CARD,
|
|
275
|
+
CARD_VARIANT_CLASS[resolvedColor],
|
|
276
|
+
className,
|
|
277
|
+
].filter(Boolean).join(' ')}
|
|
278
|
+
style={cardStyle}
|
|
279
|
+
data-tfds-component="Card"
|
|
280
|
+
>
|
|
281
|
+
<div className={PRODUCT_IMAGE_FRAME}>
|
|
282
|
+
<img
|
|
283
|
+
className={PRODUCT_IMAGE}
|
|
284
|
+
src={productImageSrc || DEFAULT_PRODUCT_IMAGE_SRC}
|
|
285
|
+
alt={productImageSrc ? productImageAlt : ''}
|
|
286
|
+
aria-hidden={productImageSrc ? undefined : true}
|
|
287
|
+
/>
|
|
288
|
+
</div>
|
|
289
|
+
|
|
290
|
+
<div className={PRODUCT_BODY}>
|
|
291
|
+
<div className={resolvedInfoLayout === 'icon-right' ? PRODUCT_HEADER_ICON_RIGHT : PRODUCT_HEADER}>
|
|
292
|
+
<h3 className={PRODUCT_TITLE}>{resolvedTitle}</h3>
|
|
293
|
+
<Tag variant="green" size="l" radius="md" className="shrink-0">
|
|
294
|
+
{productStatus || DEFAULT_PRODUCT_STATUS}
|
|
295
|
+
</Tag>
|
|
296
|
+
</div>
|
|
297
|
+
<p className={PRODUCT_DESCRIPTION}>{resolvedDescription}</p>
|
|
298
|
+
</div>
|
|
299
|
+
</article>
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (resolvedType === 'info') {
|
|
304
|
+
const iconNode = (
|
|
305
|
+
<span
|
|
306
|
+
className={[
|
|
307
|
+
INFO_ICON_FRAME_BASE,
|
|
308
|
+
resolvedInfoIconStyle === 'inverse'
|
|
309
|
+
? INFO_ICON_STYLE_CLASS.inverse
|
|
310
|
+
: INFO_ICON_TONE_CLASS[resolvedInfoIconTone],
|
|
311
|
+
].join(' ')}
|
|
312
|
+
aria-hidden="true"
|
|
313
|
+
>
|
|
314
|
+
<Icon name={infoIconName || DEFAULT_INFO_ICON} size={24} />
|
|
315
|
+
</span>
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
const badgeNode = infoMetaBadge ? (
|
|
319
|
+
<Tag
|
|
320
|
+
variant={resolvedInfoMetaBadgeVariant}
|
|
321
|
+
size="l"
|
|
322
|
+
radius="md"
|
|
323
|
+
fontWeight="bold"
|
|
324
|
+
className="shrink-0 self-center"
|
|
325
|
+
>
|
|
326
|
+
{infoMetaBadge}
|
|
327
|
+
</Tag>
|
|
328
|
+
) : null;
|
|
329
|
+
|
|
330
|
+
return (
|
|
331
|
+
<article
|
|
332
|
+
className={[CARD_SURFACE, INFO_CARD, CARD_VARIANT_CLASS[resolvedColor], className].filter(Boolean).join(' ')}
|
|
333
|
+
style={cardStyle}
|
|
334
|
+
data-tfds-component="Card"
|
|
335
|
+
>
|
|
336
|
+
{resolvedInfoLayout === 'icon-right' ? null : iconNode}
|
|
337
|
+
|
|
338
|
+
<div className={INFO_BODY}>
|
|
339
|
+
{resolvedInfoLayout === 'icon-right' ? (
|
|
340
|
+
<div className={INFO_HEADER_INLINE}>
|
|
341
|
+
<FormTitle
|
|
342
|
+
variant="form"
|
|
343
|
+
title={resolvedTitle}
|
|
344
|
+
description={resolvedDescription}
|
|
345
|
+
showDescription
|
|
346
|
+
titleSuffix={badgeNode}
|
|
347
|
+
className={INFO_TITLE_GROUP_ICON_RIGHT}
|
|
348
|
+
/>
|
|
349
|
+
{iconNode}
|
|
350
|
+
</div>
|
|
351
|
+
) : (
|
|
352
|
+
<div className={INFO_HEADER}>
|
|
353
|
+
<div className={INFO_HEADER_ROW}>
|
|
354
|
+
<h3 className={INFO_TITLE}>{resolvedTitle}</h3>
|
|
355
|
+
{badgeNode}
|
|
356
|
+
</div>
|
|
357
|
+
<p className={INFO_DESCRIPTION}>{resolvedDescription}</p>
|
|
358
|
+
</div>
|
|
359
|
+
)}
|
|
360
|
+
|
|
361
|
+
<div className={INFO_FOOTER}>
|
|
362
|
+
<span className={INFO_META}>
|
|
363
|
+
<Avatar
|
|
364
|
+
type="image"
|
|
365
|
+
shape="round"
|
|
366
|
+
size="xxs"
|
|
367
|
+
src={infoMetaAvatarSrc}
|
|
368
|
+
alt={infoMetaAvatarSrc ? infoMetaAvatarAlt : `${infoMetaLabel || DEFAULT_INFO_META}头像`}
|
|
369
|
+
className={INFO_META_AVATAR}
|
|
370
|
+
/>
|
|
371
|
+
<span className="truncate">{infoMetaLabel || DEFAULT_INFO_META}</span>
|
|
372
|
+
</span>
|
|
373
|
+
|
|
374
|
+
<div className={INFO_STATS}>
|
|
375
|
+
{resolvedInfoStats.map(({ iconName, value }, index) => (
|
|
376
|
+
<span key={`${iconName}-${value}-${index}`} className={INFO_STAT}>
|
|
377
|
+
<Icon name={iconName} size={14} />
|
|
378
|
+
<span>{value}</span>
|
|
379
|
+
</span>
|
|
380
|
+
))}
|
|
381
|
+
</div>
|
|
382
|
+
</div>
|
|
383
|
+
</div>
|
|
384
|
+
</article>
|
|
385
|
+
);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
return (
|
|
389
|
+
<article
|
|
390
|
+
className={[CARD_SURFACE, DATA_CARD, CARD_VARIANT_CLASS[resolvedColor], className].filter(Boolean).join(' ')}
|
|
391
|
+
style={cardStyle}
|
|
392
|
+
data-tfds-component="Card"
|
|
393
|
+
>
|
|
394
|
+
{hasDataIcon ? (
|
|
395
|
+
<div className={DATA_ICON_ROW}>
|
|
396
|
+
<div className={DATA_CONTENT_INNER}>
|
|
397
|
+
<div className={COPY}>
|
|
398
|
+
<h3 className={TITLE}>{resolvedTitle}</h3>
|
|
399
|
+
<p className={DESCRIPTION}>{resolvedDescription}</p>
|
|
400
|
+
</div>
|
|
401
|
+
<div className={STATS}>
|
|
402
|
+
{resolvedStats.map(({ iconName, value }, index) => (
|
|
403
|
+
<span key={`${iconName}-${value}-${index}`} className={STAT}>
|
|
404
|
+
<Icon name={iconName} size={14} />
|
|
405
|
+
<span>{value}</span>
|
|
406
|
+
</span>
|
|
407
|
+
))}
|
|
408
|
+
</div>
|
|
409
|
+
</div>
|
|
410
|
+
<span
|
|
411
|
+
className={[
|
|
412
|
+
DATA_ICON_FRAME_BASE,
|
|
413
|
+
resolvedDataIconStyle === 'inverse'
|
|
414
|
+
? INFO_ICON_STYLE_CLASS.inverse
|
|
415
|
+
: INFO_ICON_TONE_CLASS[resolvedDataIconTone],
|
|
416
|
+
].join(' ')}
|
|
417
|
+
aria-hidden="true"
|
|
418
|
+
>
|
|
419
|
+
<Icon name={dataIconName} size={24} />
|
|
420
|
+
</span>
|
|
421
|
+
</div>
|
|
422
|
+
) : (
|
|
423
|
+
<div className={CONTENT}>
|
|
424
|
+
<div className={COPY}>
|
|
425
|
+
<h3 className={TITLE}>{resolvedTitle}</h3>
|
|
426
|
+
<p className={DESCRIPTION}>{resolvedDescription}</p>
|
|
427
|
+
</div>
|
|
428
|
+
|
|
429
|
+
<div className={STATS}>
|
|
430
|
+
{resolvedStats.map(({ iconName, value }, index) => (
|
|
431
|
+
<span key={`${iconName}-${value}-${index}`} className={STAT}>
|
|
432
|
+
<Icon name={iconName} size={14} />
|
|
433
|
+
<span>{value}</span>
|
|
434
|
+
</span>
|
|
435
|
+
))}
|
|
436
|
+
</div>
|
|
437
|
+
</div>
|
|
438
|
+
)}
|
|
439
|
+
|
|
440
|
+
<div className={FOOTER}>
|
|
441
|
+
<div className={DATA_TAGS}>
|
|
442
|
+
{resolvedTags.slice(0, 2).map((tag, index) => (
|
|
443
|
+
<Tag key={`${tag}-${index}`} variant="grey" size="l" radius="md" fontWeight="bold">
|
|
444
|
+
{tag}
|
|
445
|
+
</Tag>
|
|
446
|
+
))}
|
|
447
|
+
</div>
|
|
448
|
+
<button
|
|
449
|
+
type="button"
|
|
450
|
+
className={ACTION}
|
|
451
|
+
aria-label={actionAriaLabel}
|
|
452
|
+
onClick={onAction}
|
|
453
|
+
disabled={!onAction}
|
|
454
|
+
>
|
|
455
|
+
<Icon name="arrow-narrow-right-stroked" size={16} />
|
|
456
|
+
</button>
|
|
457
|
+
</div>
|
|
458
|
+
</article>
|
|
459
|
+
);
|
|
460
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
export const CARD_TOKEN_MAP = {
|
|
2
|
+
base: [],
|
|
3
|
+
标题: [
|
|
4
|
+
{ label: '颜色', cssProp: 'color', token: '--color-foreground', value: '#182230', semanticRef: 'text-primary' },
|
|
5
|
+
{ label: '字号', cssProp: 'font-size', token: '--text-base', value: '16px' },
|
|
6
|
+
{ label: '字重', cssProp: 'font-weight', token: '--font-semibold', value: '600(运行时使用 [font-weight:var(--font-semibold)])' },
|
|
7
|
+
{ label: '行高', cssProp: 'line-height', token: '--leading-card-title', value: '22px' },
|
|
8
|
+
],
|
|
9
|
+
描述: [
|
|
10
|
+
{ label: '颜色', cssProp: 'color', token: '--color-foreground-muted', value: '#667085', semanticRef: 'text-tertiary' },
|
|
11
|
+
{ label: '字号', cssProp: 'font-size', token: '--text-sm', value: '14px' },
|
|
12
|
+
{ label: '字重', cssProp: 'font-weight', token: '--font-normal', value: '400' },
|
|
13
|
+
{ label: '行高', cssProp: 'line-height', token: '--leading-card-copy', value: '21px' },
|
|
14
|
+
],
|
|
15
|
+
数据: [
|
|
16
|
+
{ label: '适用内容类型', cssProp: 'usage', value: '指标摘要 / 趋势分析 / 工具入口 / 优秀知识模版 / 优秀案例模版 / 脚本模版 / 话术模版 / 内容生成模版 / 服务 SOP 模版' },
|
|
17
|
+
{ label: '标签位置', cssProp: 'placement', value: '卡片左下角,与右侧操作按钮水平对齐' },
|
|
18
|
+
{ label: '标签组件', cssProp: 'component', value: 'Tag / variant=grey / size=l / radius=md' },
|
|
19
|
+
{ label: '文字色', cssProp: 'color', token: '--color-foreground-muted', value: '#667085', semanticRef: 'text-tertiary' },
|
|
20
|
+
{ label: '图标色', cssProp: 'color', token: '--color-foreground-muted', value: '#667085', semanticRef: 'text-tertiary' },
|
|
21
|
+
{ label: '字号', cssProp: 'font-size', token: '--text-xs', value: '12px' },
|
|
22
|
+
{ label: '图标尺寸', cssProp: 'icon-size', token: '--size-icon-14', value: '14px' },
|
|
23
|
+
{ label: '行高', cssProp: 'line-height', token: '--leading-4', value: '16px' },
|
|
24
|
+
{ label: '项间距', cssProp: 'gap', token: '--spacing-5', value: '20px' },
|
|
25
|
+
{ label: '图标显示配置', cssProp: 'prop', value: 'dataIconVisible: hidden(默认不显示) / visible(显示右侧图标)' },
|
|
26
|
+
{ label: '右侧图标容器', cssProp: 'width/height', value: '48×48px,圆角 rounded-xl / 16px(仅数据卡片)' },
|
|
27
|
+
{ label: '图标与标题区间距', cssProp: 'gap', token: '--spacing-5', value: '20px,与数据卡片 p-5 内边距一致' },
|
|
28
|
+
{ label: '图标样式配置', cssProp: 'prop', value: 'dataIconStyle: inverse(黑底白标,默认) / tone(彩色浅底)' },
|
|
29
|
+
{ label: '标签颜色规则', cssProp: 'variant', value: '数据卡片所有类型默认统一 grey,不跟随 dataIconStyle 变化' },
|
|
30
|
+
{ label: '图标色系配置', cssProp: 'prop', value: 'dataIconTone: pink / blue / green / orange / purple / brand / grey,默认 blue' },
|
|
31
|
+
{ label: '图标尺寸(右侧)', cssProp: 'icon-size', value: '24px' },
|
|
32
|
+
],
|
|
33
|
+
商品卡片: [
|
|
34
|
+
{ label: '布局模式', cssProp: 'prop', value: 'infoLayout: 图标在左(default) / 图标在右(icon-right)' },
|
|
35
|
+
{ label: '图片尺寸', cssProp: 'width/height', value: '56px' },
|
|
36
|
+
{ label: '右侧文案区高度', cssProp: 'height', value: '56px' },
|
|
37
|
+
{ label: '图片圆角', cssProp: 'border-radius', token: '--radius-lg', value: '12px' },
|
|
38
|
+
{ label: '图文间距', cssProp: 'gap', token: '--spacing-5', value: '20px,与商品卡片 p-5 内边距一致' },
|
|
39
|
+
{ label: '图标在右布局', cssProp: 'display', value: 'icon-right: 商品图移动到右侧,状态标签紧跟主标题右侧,间距 8px' },
|
|
40
|
+
{ label: '状态标签', cssProp: 'component', value: 'Tag / variant=green / size=l / radius=md' },
|
|
41
|
+
{ label: '标题字号', cssProp: 'font-size', token: '--text-base', value: '16px' },
|
|
42
|
+
{ label: '标题颜色', cssProp: 'color', token: '--color-foreground', value: '#182230', semanticRef: 'text-primary' },
|
|
43
|
+
{ label: '副标题颜色', cssProp: 'color', token: '--color-foreground-muted', value: '#667085', semanticRef: 'text-tertiary' },
|
|
44
|
+
{ label: '最小高度', cssProp: 'min-height', value: '96px' },
|
|
45
|
+
],
|
|
46
|
+
信息卡片: [
|
|
47
|
+
{ label: '布局模式', cssProp: 'prop', value: 'infoLayout: 图标在左(default) / 图标在右(icon-right)' },
|
|
48
|
+
{ label: '图标在左', cssProp: 'display', value: '左侧图标 + 右侧标题/副标题/右上徽标 + 底部辅助信息' },
|
|
49
|
+
{ label: '图标在右', cssProp: 'display', value: '左侧标题/副标题/底部辅助信息 + 最右侧图标;徽标紧跟标题右侧,间距 8px' },
|
|
50
|
+
{ label: '最小高度', cssProp: 'min-height', value: '148px' },
|
|
51
|
+
{ label: '内边距', cssProp: 'padding', token: '--spacing-6', value: '24px' },
|
|
52
|
+
{ label: '图文间距', cssProp: 'gap', token: '--spacing-6', value: '24px' },
|
|
53
|
+
{ label: '默认场景', cssProp: 'content', value: '抖音 AI 创作助手 / 官方 AI 能力' },
|
|
54
|
+
{ label: '图标组件', cssProp: 'component', value: 'Icon / 默认 magic-wand-01-stroked' },
|
|
55
|
+
{ label: '图标容器尺寸', cssProp: 'width/height', value: '48px' },
|
|
56
|
+
{ label: '图标容器圆角', cssProp: 'border-radius', token: '--radius-lg', value: '12px' },
|
|
57
|
+
{ label: '图标色系配置', cssProp: 'prop', value: 'infoIconTone: pink / blue / green / orange / purple / brand / grey' },
|
|
58
|
+
{ label: '图标样式配置', cssProp: 'prop', value: 'infoIconStyle: tone / inverse' },
|
|
59
|
+
{ label: '图标容器背景', cssProp: 'background-color', token: '--color-*-50', value: '同色系 50 token' },
|
|
60
|
+
{ label: '图标容器描边', cssProp: 'border-color', token: '--color-*-100', value: '同色系 100 token' },
|
|
61
|
+
{ label: '图标颜色', cssProp: 'color', token: '--color-*-600', value: '同色系 600 token / brand 使用 brand-600' },
|
|
62
|
+
{ label: '反色图标样式', cssProp: 'background/color', value: 'inverse: 黑背景 + 白色 icon' },
|
|
63
|
+
{ label: '图标尺寸', cssProp: 'icon-size', value: '24px' },
|
|
64
|
+
{ label: '标题组件', cssProp: 'component', value: 'FormTitle / variant=form / showDescription' },
|
|
65
|
+
{ label: '标题字号', cssProp: 'font-size', token: '--text-base', value: '16px' },
|
|
66
|
+
{ label: '标题字重', cssProp: 'font-weight', token: '--font-semibold', value: '600' },
|
|
67
|
+
{ label: '标题行高', cssProp: 'line-height', token: '--leading-5', value: '20px' },
|
|
68
|
+
{ label: '副标题字号', cssProp: 'font-size', token: '--text-xs', value: '12px' },
|
|
69
|
+
{ label: '副标题行高', cssProp: 'line-height', token: '--leading-5', value: '20px' },
|
|
70
|
+
{ label: '副标题颜色', cssProp: 'color', token: '--color-foreground-muted', value: '#667085', semanticRef: 'text-tertiary' },
|
|
71
|
+
{ label: '徽标组件', cssProp: 'component', value: 'Tag / variant 跟随 infoIconStyle / size=l / radius=md' },
|
|
72
|
+
{ label: '徽标颜色联动', cssProp: 'variant', value: 'tone: 一律 grey;inverse: 默认 purple 彩色标签,可通过 infoMetaBadgeVariant 覆盖' },
|
|
73
|
+
{ label: '彩色标签优先级', cssProp: 'variant', value: 'purple(紫色)> teal(青绿色)> blue(蓝色)> cyan(青色)> orange(橙色)' },
|
|
74
|
+
{ label: '徽标位置', cssProp: 'placement', value: '所有布局均紧跟主标题右侧' },
|
|
75
|
+
{ label: '标题与徽标间距', cssProp: 'gap', token: '--spacing-2', value: '8px(所有信息卡片布局)' },
|
|
76
|
+
{ label: '标题与徽标对齐', cssProp: 'align-items', value: '所有布局均水平排列并垂直居中对齐' },
|
|
77
|
+
{ label: '昵称头像', cssProp: 'component', value: 'Avatar / type=image / shape=round / size=xxs' },
|
|
78
|
+
{ label: '昵称头像尺寸', cssProp: 'width/height', value: '16px' },
|
|
79
|
+
{ label: '昵称头像资源', cssProp: 'asset', value: 'team-avatar-assets/duan-ran.png' },
|
|
80
|
+
{ label: '头像与昵称间距', cssProp: 'gap', token: '--spacing-2', value: '8px' },
|
|
81
|
+
{ label: '身份区行高', cssProp: 'height/line-height', token: '--leading-4', value: '16px,头像与文字垂直居中' },
|
|
82
|
+
{ label: '身份文案', cssProp: 'semantic', value: '默认“段然”,可按负责人 / 创建人 / 团队动态替换' },
|
|
83
|
+
{ label: '昵称字号', cssProp: 'font-size', token: '--text-xs', value: '12px' },
|
|
84
|
+
{ label: '辅助区指标行', cssProp: 'component-style', value: '复用数据卡片指标行样式,infoStats 支持 2-4 项动态配置' },
|
|
85
|
+
{ label: '辅助区对齐', cssProp: 'align-items', value: '整行所有头像、图标、文字高度水平居中对齐' },
|
|
86
|
+
{ label: '辅助区间距', cssProp: 'gap', token: '--spacing-5', value: '20px' },
|
|
87
|
+
{ label: '辅助项图标', cssProp: 'component', value: 'Icon / 14px' },
|
|
88
|
+
{ label: '辅助项文字', cssProp: 'font-size/font-weight', value: '12px / 400' },
|
|
89
|
+
{ label: '辅助项语义', cssProp: 'content', value: '启用量 / 评分 / 调用量 / 响应率 / 转化率 / 更新时间 / 操作入口' },
|
|
90
|
+
],
|
|
91
|
+
卡片: [
|
|
92
|
+
{ label: '白底背景', cssProp: 'background', token: '--color-card-secondary', value: 'rgba(255,255,255,0.65)', semanticRef: 'bg-card-secondary', state: 'default' },
|
|
93
|
+
{ label: '白底 Hover 背景', cssProp: 'background', token: '--color-surface', value: '#FFFFFF', semanticRef: 'bg-surface', state: 'hover' },
|
|
94
|
+
{ label: '白底描边', cssProp: 'border-color', token: '--color-white', value: '#FFFFFF' },
|
|
95
|
+
{ label: '灰底背景', cssProp: 'background', token: '--color-blueGrey-100', value: '#F9FAFB' },
|
|
96
|
+
{ label: '灰底描边', cssProp: 'border-color', token: '--color-blueGrey-300', value: '#E4E7EC' },
|
|
97
|
+
{ label: '圆角', cssProp: 'border-radius', token: '--radius-xl', value: '16px' },
|
|
98
|
+
{ label: '投影', cssProp: 'box-shadow', token: '--shadow-card', value: '0 30px 50px 0 rgba(0, 9, 36, 0.05)', state: 'hover' },
|
|
99
|
+
],
|
|
100
|
+
操作: [
|
|
101
|
+
{ label: '图标色', cssProp: 'color', token: '--color-foreground-muted', value: '#667085', semanticRef: 'text-tertiary', state: 'default' },
|
|
102
|
+
{ label: '图标色', cssProp: 'color', token: '--color-black', value: '#000000', state: 'hover' },
|
|
103
|
+
{ label: '描边色', cssProp: 'border-color', token: '--color-transparent', value: 'transparent', state: 'default' },
|
|
104
|
+
{ label: '描边色', cssProp: 'border-color', token: '--color-black', value: '#000000', state: 'hover' },
|
|
105
|
+
{ label: '尺寸', cssProp: 'width/height', token: '--spacing-7', value: '28px' },
|
|
106
|
+
{ label: '圆角', cssProp: 'border-radius', token: '--radius-full', value: '9999px' },
|
|
107
|
+
],
|
|
108
|
+
尺寸: [
|
|
109
|
+
{ label: '最小列宽', cssProp: 'min-width', token: '--size-card-width', value: '400px' },
|
|
110
|
+
{ label: '高度', cssProp: 'min-height', token: '--size-card-min-height', value: '201px' },
|
|
111
|
+
{ label: '内边距', cssProp: 'padding', token: '--spacing-5', value: '20px' },
|
|
112
|
+
{ label: '层间距', cssProp: 'gap', token: '--spacing-7', value: '28px' },
|
|
113
|
+
],
|
|
114
|
+
引用组件: [
|
|
115
|
+
{ label: '数据卡片标签', cssProp: 'component', value: 'Tag / variant=white / size=l / radius=md / 左下角' },
|
|
116
|
+
{ label: '商品状态标签', cssProp: 'component', value: 'Tag / variant=green / size=l / radius=md' },
|
|
117
|
+
{ label: '信息卡片主图标', cssProp: 'component', value: 'Icon / 同色系浅底 + 描边容器' },
|
|
118
|
+
{ label: '信息卡片标题', cssProp: 'component', value: 'FormTitle / variant=form / showDescription' },
|
|
119
|
+
{ label: '信息卡片徽标', cssProp: 'component', value: 'Tag / infoMetaBadgeVariant / size=l / radius=md' },
|
|
120
|
+
{ label: '信息卡片昵称头像', cssProp: 'component', value: 'Avatar / type=image / shape=round / size=xxs' },
|
|
121
|
+
{ label: '数据卡片图标', cssProp: 'component', value: 'Icon / users-01-stroked / message-chat-square-stroked / hearts-stroked / arrow-narrow-right-stroked' },
|
|
122
|
+
{ label: '信息卡片图标', cssProp: 'component', value: 'Icon / magic-wand-01-stroked / users-01-stroked / star-01-stroked / play-circle-stroked' },
|
|
123
|
+
],
|
|
124
|
+
};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import Card from './Card';
|
|
2
|
+
|
|
3
|
+
const CANVAS = 'flex w-full justify-center p-6';
|
|
4
|
+
|
|
5
|
+
export default function CardPreview({
|
|
6
|
+
type = 'data',
|
|
7
|
+
color = 'white',
|
|
8
|
+
infoIconTone = 'pink',
|
|
9
|
+
infoIconStyle,
|
|
10
|
+
infoMetaBadgeVariant,
|
|
11
|
+
infoLayout,
|
|
12
|
+
dataIconVisible,
|
|
13
|
+
dataIconStyle,
|
|
14
|
+
}) {
|
|
15
|
+
const isProduct = type === 'product';
|
|
16
|
+
const isInfo = type === 'info';
|
|
17
|
+
const isData = !isProduct && !isInfo;
|
|
18
|
+
const resolvedInfoIconStyle = isInfo ? (infoIconStyle || 'inverse') : infoIconStyle;
|
|
19
|
+
const resolvedInfoLayout = isInfo
|
|
20
|
+
? (infoLayout || 'icon-right')
|
|
21
|
+
: (isProduct ? (infoLayout || 'default') : infoLayout);
|
|
22
|
+
const resolvedDataIconVisible = isData ? (dataIconVisible || 'hidden') : undefined;
|
|
23
|
+
const resolvedDataIconStyle = isData ? (dataIconStyle || 'inverse') : undefined;
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<div className={CANVAS}>
|
|
27
|
+
<div className={isProduct ? 'w-full max-w-[520px]' : 'w-full'}>
|
|
28
|
+
<Card
|
|
29
|
+
type={type}
|
|
30
|
+
color={color}
|
|
31
|
+
title={isProduct ? '海底捞门店通用双人套餐' : undefined}
|
|
32
|
+
description={isProduct ? '数量 1 · ¥128.00 · 月售 2,361' : undefined}
|
|
33
|
+
tags={isProduct || isInfo ? [] : undefined}
|
|
34
|
+
productStatus={isProduct ? '已使用' : undefined}
|
|
35
|
+
infoIconTone={isInfo ? infoIconTone : undefined}
|
|
36
|
+
infoIconStyle={isInfo ? resolvedInfoIconStyle : undefined}
|
|
37
|
+
infoLayout={isProduct || isInfo ? resolvedInfoLayout : undefined}
|
|
38
|
+
infoMetaLabel={isInfo ? '段然' : undefined}
|
|
39
|
+
infoMetaBadge={isInfo ? '官方能力' : undefined}
|
|
40
|
+
infoMetaBadgeVariant={isInfo ? infoMetaBadgeVariant : undefined}
|
|
41
|
+
dataIconVisible={isData ? resolvedDataIconVisible : undefined}
|
|
42
|
+
dataIconName={isData && resolvedDataIconVisible === 'visible' ? 'edit-04-stroked' : undefined}
|
|
43
|
+
dataIconTone={isData ? 'blue' : undefined}
|
|
44
|
+
dataIconStyle={isData ? resolvedDataIconStyle : undefined}
|
|
45
|
+
actionAriaLabel={isProduct ? undefined : '查看卡片详情'}
|
|
46
|
+
onAction={isProduct ? undefined : () => {}}
|
|
47
|
+
/>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
);
|
|
51
|
+
}
|