@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.
Files changed (176) hide show
  1. package/AI_READ_FIRST.md +131 -0
  2. package/LICENSE +21 -0
  3. package/README.md +353 -0
  4. package/package.json +67 -0
  5. package/scripts/check-tfds-contract.mjs +334 -0
  6. package/scripts/check-tfds-integration.mjs +263 -0
  7. package/scripts/postinstall-cursor-skill.mjs +382 -0
  8. package/scripts/setup.mjs +520 -0
  9. package/skills/tfds/CHECKLIST.md +205 -0
  10. package/skills/tfds/COMMON_FAILURES.md +238 -0
  11. package/skills/tfds/DESIGN_PRINCIPLES.md +477 -0
  12. package/skills/tfds/GLOBAL_DESIGN_RULES.md +636 -0
  13. package/skills/tfds/LAYOUT_RECIPES.md +140 -0
  14. package/skills/tfds/LAYOUT_RULES.md +1355 -0
  15. package/skills/tfds/PAGE_ARCHETYPES.md +201 -0
  16. package/skills/tfds/SKILL.md +188 -0
  17. package/skills/tfds/components.index.json +7305 -0
  18. package/skills/tfds/components.summary.json +1809 -0
  19. package/src/_b_end_runtime/components/AiSuggestionShared.jsx +166 -0
  20. package/src/_b_end_runtime/components/Avatar.jsx +325 -0
  21. package/src/_b_end_runtime/components/Avatar.tokens.js +76 -0
  22. package/src/_b_end_runtime/components/AvatarGridPreview.jsx +56 -0
  23. package/src/_b_end_runtime/components/AvatarGroup.jsx +80 -0
  24. package/src/_b_end_runtime/components/AvatarGroup.tokens.js +28 -0
  25. package/src/_b_end_runtime/components/Button.jsx +144 -0
  26. package/src/_b_end_runtime/components/Button.tokens.js +90 -0
  27. package/src/_b_end_runtime/components/Card.jsx +460 -0
  28. package/src/_b_end_runtime/components/Card.tokens.js +124 -0
  29. package/src/_b_end_runtime/components/CardPreview.jsx +51 -0
  30. package/src/_b_end_runtime/components/ChatBubble.jsx +384 -0
  31. package/src/_b_end_runtime/components/ChatBubble.tokens.js +60 -0
  32. package/src/_b_end_runtime/components/ChatBubblePreview.jsx +129 -0
  33. package/src/_b_end_runtime/components/ChatInput.jsx +1399 -0
  34. package/src/_b_end_runtime/components/ChatInput.tokens.js +75 -0
  35. package/src/_b_end_runtime/components/ChatMessage.jsx +2215 -0
  36. package/src/_b_end_runtime/components/ChatMessage.tokens.js +257 -0
  37. package/src/_b_end_runtime/components/ChatMessagePreview.jsx +388 -0
  38. package/src/_b_end_runtime/components/Checkbox.jsx +317 -0
  39. package/src/_b_end_runtime/components/Checkbox.tokens.js +59 -0
  40. package/src/_b_end_runtime/components/ConversationList.jsx +1264 -0
  41. package/src/_b_end_runtime/components/ConversationList.tokens.js +135 -0
  42. package/src/_b_end_runtime/components/ConversationListPreview.jsx +108 -0
  43. package/src/_b_end_runtime/components/CustomerServiceWorkspaceFrame.jsx +324 -0
  44. package/src/_b_end_runtime/components/CustomerServiceWorkspaceFrame.tokens.js +69 -0
  45. package/src/_b_end_runtime/components/DatePicker.jsx +739 -0
  46. package/src/_b_end_runtime/components/DatePicker.tokens.js +99 -0
  47. package/src/_b_end_runtime/components/Empty.jsx +141 -0
  48. package/src/_b_end_runtime/components/Empty.tokens.js +40 -0
  49. package/src/_b_end_runtime/components/Form.jsx +609 -0
  50. package/src/_b_end_runtime/components/Form.tokens.js +77 -0
  51. package/src/_b_end_runtime/components/FormFieldStack.jsx +123 -0
  52. package/src/_b_end_runtime/components/FormFieldStack.tokens.js +12 -0
  53. package/src/_b_end_runtime/components/FormTitle.jsx +119 -0
  54. package/src/_b_end_runtime/components/FormTitle.tokens.js +87 -0
  55. package/src/_b_end_runtime/components/FullScreenPage.jsx +97 -0
  56. package/src/_b_end_runtime/components/FullScreenPage.tokens.js +19 -0
  57. package/src/_b_end_runtime/components/Icon.jsx +172 -0
  58. package/src/_b_end_runtime/components/Icon.tokens.js +26 -0
  59. package/src/_b_end_runtime/components/IconGridPreview.jsx +277 -0
  60. package/src/_b_end_runtime/components/InfoDisplayPanel.jsx +620 -0
  61. package/src/_b_end_runtime/components/InfoDisplayPanel.tokens.js +71 -0
  62. package/src/_b_end_runtime/components/InfoDisplayPanelPreview.jsx +133 -0
  63. package/src/_b_end_runtime/components/Input.jsx +258 -0
  64. package/src/_b_end_runtime/components/Input.tokens.js +68 -0
  65. package/src/_b_end_runtime/components/InputNumber.jsx +242 -0
  66. package/src/_b_end_runtime/components/InputNumber.tokens.js +55 -0
  67. package/src/_b_end_runtime/components/Modal.jsx +155 -0
  68. package/src/_b_end_runtime/components/Modal.tokens.js +73 -0
  69. package/src/_b_end_runtime/components/NavBar.jsx +842 -0
  70. package/src/_b_end_runtime/components/NavBar.tokens.js +97 -0
  71. package/src/_b_end_runtime/components/NavBarPreview.jsx +11 -0
  72. package/src/_b_end_runtime/components/Radio.jsx +227 -0
  73. package/src/_b_end_runtime/components/Radio.tokens.js +59 -0
  74. package/src/_b_end_runtime/components/Select.jsx +766 -0
  75. package/src/_b_end_runtime/components/Select.tokens.js +99 -0
  76. package/src/_b_end_runtime/components/Sheet.jsx +132 -0
  77. package/src/_b_end_runtime/components/Sheet.tokens.js +61 -0
  78. package/src/_b_end_runtime/components/Slider.jsx +346 -0
  79. package/src/_b_end_runtime/components/Slider.tokens.js +47 -0
  80. package/src/_b_end_runtime/components/Switch.jsx +124 -0
  81. package/src/_b_end_runtime/components/Switch.tokens.js +38 -0
  82. package/src/_b_end_runtime/components/Table.jsx +1338 -0
  83. package/src/_b_end_runtime/components/Table.tokens.js +147 -0
  84. package/src/_b_end_runtime/components/TablePreview.jsx +599 -0
  85. package/src/_b_end_runtime/components/Tabs.jsx +149 -0
  86. package/src/_b_end_runtime/components/Tabs.tokens.js +102 -0
  87. package/src/_b_end_runtime/components/Tag.jsx +199 -0
  88. package/src/_b_end_runtime/components/Tag.tokens.js +171 -0
  89. package/src/_b_end_runtime/components/TagBar.jsx +1134 -0
  90. package/src/_b_end_runtime/components/TagBar.tokens.js +75 -0
  91. package/src/_b_end_runtime/components/TagGridPreview.jsx +23 -0
  92. package/src/_b_end_runtime/components/TagInput.jsx +382 -0
  93. package/src/_b_end_runtime/components/TagInput.tokens.js +52 -0
  94. package/src/_b_end_runtime/components/TextArea.jsx +363 -0
  95. package/src/_b_end_runtime/components/TextArea.tokens.js +65 -0
  96. package/src/_b_end_runtime/components/TimePicker.jsx +444 -0
  97. package/src/_b_end_runtime/components/TimePicker.tokens.js +77 -0
  98. package/src/_b_end_runtime/components/Toast.jsx +120 -0
  99. package/src/_b_end_runtime/components/Toast.tokens.js +146 -0
  100. package/src/_b_end_runtime/components/Tooltip.jsx +282 -0
  101. package/src/_b_end_runtime/components/Tooltip.tokens.js +48 -0
  102. package/src/_b_end_runtime/components/TooltipPreview.jsx +50 -0
  103. package/src/_b_end_runtime/components/Upload.jsx +455 -0
  104. package/src/_b_end_runtime/components/Upload.tokens.js +47 -0
  105. package/src/_b_end_runtime/components/avatar-assets/avatar-default.png +0 -0
  106. package/src/_b_end_runtime/components/avatar-group-assets/avatar-group-1.png +0 -0
  107. package/src/_b_end_runtime/components/avatar-group-assets/avatar-group-2.png +0 -0
  108. package/src/_b_end_runtime/components/avatar-group-assets/avatar-group-3.png +0 -0
  109. package/src/_b_end_runtime/components/avatar-group-assets/avatar-group-4.png +0 -0
  110. package/src/_b_end_runtime/components/avatar-group-assets/avatar-group-5.png +0 -0
  111. package/src/_b_end_runtime/components/empty-assets/administrator-1.svg +40 -0
  112. package/src/_b_end_runtime/components/empty-assets/administrator-2.svg +33 -0
  113. package/src/_b_end_runtime/components/empty-assets/construction.svg +33 -0
  114. package/src/_b_end_runtime/components/empty-assets/failure.svg +49 -0
  115. package/src/_b_end_runtime/components/empty-assets/idle.svg +34 -0
  116. package/src/_b_end_runtime/components/empty-assets/no-access.svg +36 -0
  117. package/src/_b_end_runtime/components/empty-assets/no-content.svg +77 -0
  118. package/src/_b_end_runtime/components/empty-assets/no-result.svg +61 -0
  119. package/src/_b_end_runtime/components/empty-assets/not-found.svg +46 -0
  120. package/src/_b_end_runtime/components/empty-assets/success.svg +38 -0
  121. package/src/_b_end_runtime/components/file-type-assets/batch-report.png +0 -0
  122. package/src/_b_end_runtime/components/file-type-assets/catcat.svg +21 -0
  123. package/src/_b_end_runtime/components/file-type-assets/code.png +0 -0
  124. package/src/_b_end_runtime/components/file-type-assets/conversation.png +0 -0
  125. package/src/_b_end_runtime/components/file-type-assets/document.png +0 -0
  126. package/src/_b_end_runtime/components/file-type-assets/feishu-card.png +0 -0
  127. package/src/_b_end_runtime/components/file-type-assets/feishu-sheet.png +0 -0
  128. package/src/_b_end_runtime/components/file-type-assets/feishu.png +0 -0
  129. package/src/_b_end_runtime/components/file-type-assets/image.png +0 -0
  130. package/src/_b_end_runtime/components/file-type-assets/index.js +105 -0
  131. package/src/_b_end_runtime/components/file-type-assets/knowledge.png +0 -0
  132. package/src/_b_end_runtime/components/file-type-assets/pdf.png +0 -0
  133. package/src/_b_end_runtime/components/file-type-assets/pe.png +0 -0
  134. package/src/_b_end_runtime/components/file-type-assets/strategy.png +0 -0
  135. package/src/_b_end_runtime/components/file-type-assets/table.png +0 -0
  136. package/src/_b_end_runtime/components/file-type-assets/webpage.png +0 -0
  137. package/src/_b_end_runtime/components/file-type-assets/xmind.png +0 -0
  138. package/src/_b_end_runtime/components/icons/icon-data.js +12496 -0
  139. package/src/_b_end_runtime/components/nav-bar-assets/bytehi-logo-mark.svg +21 -0
  140. package/src/_b_end_runtime/components/table-assets/avatar.png +0 -0
  141. package/src/_b_end_runtime/components/table-assets/button.png +0 -0
  142. package/src/_b_end_runtime/components/table-assets/icon-chevron-down.png +0 -0
  143. package/src/_b_end_runtime/components/table-cell-assets/avatar.png +0 -0
  144. package/src/_b_end_runtime/components/table-cell-assets/button.png +0 -0
  145. package/src/_b_end_runtime/components/table-cell-assets/checkbox.png +0 -0
  146. package/src/_b_end_runtime/components/table-cell-assets/icon-chevron-right.png +0 -0
  147. package/src/_b_end_runtime/components/table-cell-assets/icon.png +0 -0
  148. package/src/_b_end_runtime/components/table-cell-assets/semi-icons-handle.png +0 -0
  149. package/src/_b_end_runtime/components/table-cell-assets/semi-icons-tree-triangle-right.png +0 -0
  150. package/src/_b_end_runtime/components/table-cell-assets/switch.png +0 -0
  151. package/src/_b_end_runtime/components/tagShared.js +3 -0
  152. package/src/_b_end_runtime/components/team-avatar-assets/chengcheng-murphy.png +0 -0
  153. package/src/_b_end_runtime/components/team-avatar-assets/duan-ran.png +0 -0
  154. package/src/_b_end_runtime/components/team-avatar-assets/guo-zhezhi.png +0 -0
  155. package/src/_b_end_runtime/components/team-avatar-assets/li-siru.png +0 -0
  156. package/src/_b_end_runtime/components/team-avatar-assets/liu-delin.png +0 -0
  157. package/src/_b_end_runtime/components.js +3499 -0
  158. package/src/_b_end_runtime/index.js +9 -0
  159. package/src/_b_end_runtime/page-patterns/BasePageFramePattern.jsx +395 -0
  160. package/src/_b_end_runtime/page-patterns/ChatConversationPattern.jsx +989 -0
  161. package/src/_b_end_runtime/page-patterns/ChatHomePagePattern.jsx +281 -0
  162. package/src/_b_end_runtime/page-patterns/CopilotPagePattern.jsx +380 -0
  163. package/src/_b_end_runtime/page-patterns/CustomerServiceWorkspaceFramePattern.jsx +392 -0
  164. package/src/_b_end_runtime/page-patterns/IMConversationPattern.jsx +590 -0
  165. package/src/_b_end_runtime/page-patterns/McpManagementPage.jsx +237 -0
  166. package/src/_b_end_runtime/page-patterns/StrategyListPage.jsx +189 -0
  167. package/src/_b_end_runtime/page-patterns/TabTopBarListPage.jsx +594 -0
  168. package/src/_b_end_runtime/page-patterns/VariableManagementPage.jsx +87 -0
  169. package/src/_b_end_runtime/page-patterns/pageListShared.jsx +177 -0
  170. package/src/_b_end_runtime/patterns.js +428 -0
  171. package/src/_b_end_runtime/preview-registry.jsx +4719 -0
  172. package/src/_b_end_runtime/teamMembers.js +56 -0
  173. package/src/_b_end_runtime/tokens.js +500 -0
  174. package/src/index.d.ts +1073 -0
  175. package/src/index.js +52 -0
  176. package/theme.css +350 -0
@@ -0,0 +1,166 @@
1
+ import { useState } from 'react';
2
+ import Tooltip from './Tooltip';
3
+
4
+ export const AI_REFRESH_CLASS = [
5
+ 'inline-flex items-center justify-center shrink-0 size-[var(--spacing-4)]',
6
+ 'rounded-full cursor-pointer',
7
+ 'text-foreground-muted hover:text-foreground-secondary',
8
+ 'opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 group-data-[open=true]:opacity-100 transition-opacity duration-150',
9
+ 'bg-transparent border-none p-0',
10
+ 'transition-colors duration-150',
11
+ ].join(' ');
12
+
13
+ export const AI_REFRESH_VISIBLE_CLASS = [
14
+ 'inline-flex items-center justify-center shrink-0 size-[var(--spacing-4)]',
15
+ 'rounded-full cursor-pointer',
16
+ 'text-foreground-muted hover:text-foreground-secondary',
17
+ 'opacity-100',
18
+ 'bg-transparent border-none p-0',
19
+ 'transition-colors duration-150',
20
+ ].join(' ');
21
+
22
+ export const AI_REFRESH_TOOLTIP_TRIGGER_CLASS = 'inline-flex shrink-0 items-center justify-center';
23
+
24
+ export const SUGGESTION_LIST_CLASS = [
25
+ 'inline-flex w-full flex-col rounded-md p-1 gap-0.5',
26
+ 'transition-opacity duration-150',
27
+ ].join(' ');
28
+
29
+ export const SUGGESTION_ITEM_CLASS = [
30
+ 'inline-flex w-full rounded-[6px] px-3 py-1',
31
+ 'text-left text-sm leading-5 text-foreground-secondary',
32
+ 'transition-opacity duration-150',
33
+ 'disabled:cursor-not-allowed',
34
+ ].join(' ');
35
+
36
+ export const AI_SUGGESTION_LIST_STYLE = {
37
+ background: 'var(--gradient-ai-fill-1)',
38
+ };
39
+
40
+ export const AI_SUGGESTION_ITEM_STYLE = {
41
+ background: 'transparent',
42
+ };
43
+
44
+ export const AI_SUGGESTION_ITEM_HOVER_STYLE = {
45
+ background: 'var(--gradient-ai-fill-2)',
46
+ };
47
+
48
+ export function rotateList(list, offset = 1) {
49
+ if (!Array.isArray(list) || list.length === 0) return [];
50
+ const safeOffset = ((offset % list.length) + list.length) % list.length;
51
+ if (safeOffset === 0) return [...list];
52
+ return [...list.slice(safeOffset), ...list.slice(0, safeOffset)];
53
+ }
54
+
55
+ function normalizeTextSuggestionGroup(items) {
56
+ const seen = new Set();
57
+ return (Array.isArray(items) ? items : [])
58
+ .map((item) => (typeof item === 'string' ? item.trim() : ''))
59
+ .filter((item) => {
60
+ if (!item || seen.has(item)) return false;
61
+ seen.add(item);
62
+ return true;
63
+ });
64
+ }
65
+
66
+ export function buildSuggestionGroupsFromFlatList(items, fallbackGroups = []) {
67
+ const baseGroup = normalizeTextSuggestionGroup(items);
68
+ if (baseGroup.length === 0) return [];
69
+ const serialized = new Set();
70
+ const groups = [];
71
+
72
+ const pushGroup = (group) => {
73
+ const normalized = normalizeTextSuggestionGroup(group);
74
+ if (normalized.length === 0) return;
75
+ const key = JSON.stringify(normalized);
76
+ if (serialized.has(key)) return;
77
+ serialized.add(key);
78
+ groups.push(normalized);
79
+ };
80
+
81
+ pushGroup(baseGroup);
82
+
83
+ if (baseGroup.length > 1) {
84
+ for (let offset = 1; offset < baseGroup.length; offset += 1) {
85
+ pushGroup(rotateList(baseGroup, offset));
86
+ }
87
+ pushGroup([...baseGroup].reverse());
88
+ }
89
+
90
+ fallbackGroups.forEach(pushGroup);
91
+ return groups;
92
+ }
93
+
94
+ const AI_REFRESH_ICON_MASK = `url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='black' fill-rule='evenodd' clip-rule='evenodd' d='M1 12C1 6.47715 5.47715 2 11 2C13.7624 2 16.2648 3.12139 18.0735 4.93138C18.7132 5.57146 19.3981 6.36248 20 7.09444V4C20 3.44772 20.4477 3 21 3C21.5523 3 22 3.44772 22 4V10C22 10.5523 21.5523 11 21 11H15C14.4477 11 14 10.5523 14 10C14 9.44772 14.4477 9 15 9H18.9692C18.277 8.13128 17.4165 7.10335 16.6588 6.34511C15.2098 4.89514 13.2104 4 11 4C6.58172 4 3 7.58172 3 12C3 16.4183 6.58172 20 11 20C14.6457 20 17.7243 17.5605 18.6874 14.2227C18.8406 13.6921 19.3948 13.3861 19.9255 13.5392C20.4561 13.6923 20.7622 14.2466 20.609 14.7773C19.4055 18.9481 15.5605 22 11 22C5.47715 22 1 17.5228 1 12Z'/%3E%3C/svg%3E")`;
95
+ const AI_REFRESH_ICON_STYLE = {
96
+ width: '16px',
97
+ height: '16px',
98
+ display: 'block',
99
+ flexShrink: 0,
100
+ backgroundImage: 'var(--gradient-ai-fill-3)',
101
+ maskImage: AI_REFRESH_ICON_MASK,
102
+ maskRepeat: 'no-repeat',
103
+ maskPosition: 'center',
104
+ maskSize: 'contain',
105
+ WebkitMaskImage: AI_REFRESH_ICON_MASK,
106
+ WebkitMaskRepeat: 'no-repeat',
107
+ WebkitMaskPosition: 'center',
108
+ WebkitMaskSize: 'contain',
109
+ };
110
+
111
+ export function AiRefreshGradientIcon() {
112
+ return <span aria-hidden="true" style={AI_REFRESH_ICON_STYLE} />;
113
+ }
114
+
115
+ export function AiRefreshButton({ onClick, ariaLabel = '刷新推荐', className = AI_REFRESH_CLASS }) {
116
+ return (
117
+ <Tooltip content="刷新推荐" placement="top" triggerClassName={AI_REFRESH_TOOLTIP_TRIGGER_CLASS}>
118
+ <button
119
+ type="button"
120
+ className={className}
121
+ onClick={onClick}
122
+ aria-label={ariaLabel}
123
+ >
124
+ <AiRefreshGradientIcon />
125
+ </button>
126
+ </Tooltip>
127
+ );
128
+ }
129
+
130
+ export default function AiSuggestionPanel({
131
+ suggestions,
132
+ onSelect,
133
+ getSuggestionKey,
134
+ getSuggestionLabel,
135
+ getSuggestionAriaLabel,
136
+ }) {
137
+ const [hoveredSuggestionIndex, setHoveredSuggestionIndex] = useState(-1);
138
+
139
+ if (!Array.isArray(suggestions) || suggestions.length === 0) return null;
140
+
141
+ return (
142
+ <div className={SUGGESTION_LIST_CLASS} style={AI_SUGGESTION_LIST_STYLE}>
143
+ {suggestions.map((suggestion, index) => {
144
+ const key = getSuggestionKey?.(suggestion, index) ?? `${getSuggestionLabel?.(suggestion) || index}-${index}`;
145
+ const label = getSuggestionLabel?.(suggestion) ?? '';
146
+ const ariaLabel = getSuggestionAriaLabel?.(suggestion, index) ?? `采纳 AI 推荐内容 ${index + 1}`;
147
+ return (
148
+ <button
149
+ key={key}
150
+ type="button"
151
+ className={`${SUGGESTION_ITEM_CLASS} ${hoveredSuggestionIndex === index ? 'items-start' : 'items-center'}`}
152
+ style={hoveredSuggestionIndex === index ? AI_SUGGESTION_ITEM_HOVER_STYLE : AI_SUGGESTION_ITEM_STYLE}
153
+ onClick={() => onSelect?.(suggestion)}
154
+ onMouseEnter={() => setHoveredSuggestionIndex(index)}
155
+ onMouseLeave={() => setHoveredSuggestionIndex(-1)}
156
+ aria-label={ariaLabel}
157
+ >
158
+ <span className={hoveredSuggestionIndex === index ? 'block w-full whitespace-normal break-words' : 'block w-full truncate'}>
159
+ {label}
160
+ </span>
161
+ </button>
162
+ );
163
+ })}
164
+ </div>
165
+ );
166
+ }
@@ -0,0 +1,325 @@
1
+ import { useEffect, useState } from 'react';
2
+ import defaultAvatarSrc from './avatar-assets/avatar-default.png';
3
+ import Icon from './Icon';
4
+ import { getRandomTeamAvatarSrc } from '../teamMembers';
5
+
6
+ /**
7
+ * Avatar — B端基础头像组件(Tailwind 内联)
8
+ *
9
+ * 对齐 Figma Avatar 组件集,覆盖 2 种形状、6 档尺寸、6 种内容类型。
10
+ * 图片态在未传 src 或加载失败时会优先回退到本地成员头像素材,再兜底到内置默认头像;英文态 / 中文态可通过 label 覆盖默认示例文案。
11
+ *
12
+ * **何时用**:表格/会话/导航里标识「单个」用户、机器人或 AI;需要字母/中文占位或兜底轮廓时。
13
+ * **不用**:多人交叠缩略氛围 → 用 `AvatarGroup`;纯功能符号 → 用 `Icon`;可配置人数的成员列表 → 列表 + 多个 `Avatar`。
14
+ *
15
+ * @prop {'round'|'rect'} [shape='round'] — 头像形状,round 为圆形,rect 为 3px 圆角方形
16
+ * @prop {'xxs'|'mini'|'xs'|'s'|'default'|'m'} [size='default'] — 尺寸档位,对应 16 / 20 / 24 / 32 / 40 / 48px
17
+ * @prop {'image'|'eng'|'ch'|'fallback'|'robot'|'ai'} [type='image'] — 内容类型:图片 / 英文 / 中文 / 兜底 / 机器人 / AI头像
18
+ * @prop {string|null} [src=null] — 图片地址,仅 image 态生效;不传时默认随机使用本地成员头像图片素材
19
+ * @prop {string|null} [label=null] — 文本头像内容,仅 eng / ch 态生效
20
+ * @prop {string} [alt='头像'] — 图片替代文本,仅 image 态生效
21
+ * @prop {string} [className=''] — 自定义类名
22
+ * @prop {React.CSSProperties|undefined} [style=undefined] — 自定义内联样式
23
+ */
24
+
25
+ /* ── 基础容器 ── */
26
+ const BASE = [
27
+ 'relative inline-flex shrink-0 items-center justify-center overflow-hidden align-middle select-none',
28
+ '[font-family:inherit]',
29
+ ].join(' ');
30
+
31
+ /* ── 形状 → 圆角 ── */
32
+ const SHAPE_CLASS = {
33
+ round: 'rounded-full',
34
+ rect: 'rounded-avatar',
35
+ };
36
+
37
+ /* ── 尺寸 → 边长 ── */
38
+ const SIZE_CLASS = {
39
+ xxs: 'size-4',
40
+ mini: 'size-5',
41
+ xs: 'size-6',
42
+ s: 'size-8',
43
+ default: 'size-10',
44
+ m: 'size-12',
45
+ };
46
+
47
+ /* ── 类型 → 背景 / 文字色 ── */
48
+ const TYPE_CLASS = {
49
+ image: 'bg-grey-100',
50
+ eng: 'bg-grey-300 text-white',
51
+ ch: 'text-white',
52
+ fallback: 'bg-grey-100 text-grey-200',
53
+ robot: 'bg-robot-500',
54
+ ai: '',
55
+ };
56
+
57
+ /* ── 中文态在不同形状下的底色 ── */
58
+ const CHINESE_SHAPE_CLASS = {
59
+ round: 'bg-brand-500',
60
+ rect: 'bg-brand-500',
61
+ };
62
+
63
+ /* ── 图片态 → 保持原图完整,仅由容器尺寸与圆角决定头像形态 ── */
64
+ const IMAGE_CLASS = {
65
+ xxs: '',
66
+ mini: '',
67
+ xs: '',
68
+ s: '',
69
+ default: '',
70
+ m: '',
71
+ };
72
+
73
+ /* ── 文本态 → 字号 / 行高 ── */
74
+ const TEXT_CLASS = {
75
+ xxs: 'text-xs leading-4 [font-weight:var(--font-semibold)]',
76
+ mini: 'text-xs leading-4 [font-weight:var(--font-semibold)]',
77
+ xs: 'text-xs leading-4 [font-weight:var(--font-semibold)]',
78
+ s: 'text-lg leading-6 [font-weight:var(--font-semibold)]',
79
+ default: 'text-lg leading-6 [font-weight:var(--font-semibold)]',
80
+ m: 'text-xl leading-[28px] [font-weight:var(--font-semibold)]',
81
+ };
82
+
83
+ /* ── 兜底态 → 图形尺寸 ── */
84
+ const FALLBACK_ICON_CLASS = {
85
+ xxs: 'size-[10px]',
86
+ mini: 'size-[12px]',
87
+ xs: 'size-[14px]',
88
+ s: 'size-[18px]',
89
+ default: 'size-[22px]',
90
+ m: 'size-[26px]',
91
+ };
92
+
93
+ /* ── 机器人态 → 设计稿 SVG 在完整画布内自带留白,直接铺满容器即可 ── */
94
+ const ROBOT_ICON_CLASS = 'block size-full';
95
+
96
+ /* ── AI态 → 参考图中的居中留白比例 ── */
97
+ const AI_ICON_WRAP_CLASS = {
98
+ xxs: 'w-[62%] max-w-[10px]',
99
+ mini: 'w-[60%] max-w-[12px]',
100
+ xs: 'w-[58%] max-w-[14px]',
101
+ s: 'w-[56%] max-w-[18px]',
102
+ default: 'w-[54%] max-w-[22px]',
103
+ m: 'w-[52%] max-w-[26px]',
104
+ };
105
+ const AI_BACKGROUND_LAYER = 'pointer-events-none absolute inset-px rounded-[inherit]';
106
+ const IMAGE_STROKE_LAYER = 'pointer-events-none absolute inset-0 z-10 rounded-[inherit] shadow-[inset_0_0_0_1px_var(--color-fill)]';
107
+ const AI_CONTENT_LAYER = 'relative z-10 inline-flex items-center justify-center';
108
+
109
+ /* ── 默认示例文案(对齐 Figma) ── */
110
+ const DEFAULT_LABEL = {
111
+ eng: {
112
+ xxs: 'T',
113
+ mini: 'T',
114
+ xs: 'T',
115
+ s: 'TF',
116
+ default: 'TF',
117
+ m: 'TF',
118
+ },
119
+ ch: {
120
+ xxs: '体',
121
+ mini: '体',
122
+ xs: '体',
123
+ s: '体',
124
+ default: '体服',
125
+ m: '体服',
126
+ },
127
+ };
128
+
129
+ /* ── 图片层 ── */
130
+ const IMAGE = [
131
+ 'absolute inset-0 size-full object-contain object-center',
132
+ 'pointer-events-none select-none',
133
+ ].join(' ');
134
+
135
+ function FallbackGlyph({ className }) {
136
+ return (
137
+ <svg
138
+ viewBox="0 0 64 64"
139
+ aria-hidden="true"
140
+ className={['block', className].filter(Boolean).join(' ')}
141
+ xmlns="http://www.w3.org/2000/svg">
142
+ <g transform="translate(0 -4)">
143
+ <path
144
+ fill="currentColor"
145
+ d="M32 10c7.18 0 13 5.82 13 13s-5.82 13-13 13-13-5.82-13-13 5.82-13 13-13Zm0 32c13.81 0 25 7.16 25 16v4H7v-4c0-8.84 11.19-16 25-16Z"
146
+ />
147
+ </g>
148
+ </svg>
149
+ );
150
+ }
151
+
152
+ function RobotGlyph({ className }) {
153
+ return (
154
+ <svg
155
+ viewBox="0 0 48 48"
156
+ aria-hidden="true"
157
+ className={className}
158
+ fill="none"
159
+ xmlns="http://www.w3.org/2000/svg"
160
+ >
161
+ <path
162
+ className="fill-robot-50"
163
+ d="M24.0002 38.4398C12.2509 38.4787 7.57003 32.0143 7.50041 25.1558V25.1445C7.49622 24.5517 7.52425 23.959 7.58437 23.3692C7.66218 22.6321 7.75532 21.9092 7.86897 21.2038C8.9194 14.6084 11.4697 9.56512 14.2064 10.3647C14.2402 10.3739 14.276 10.3862 14.3088 10.3985C14.8371 10.5736 15.435 10.9309 16.0605 11.4029H16.0677C17.6669 12.6079 19.4545 14.549 20.765 16.0858C21.0629 16.4329 21.3352 16.7605 21.5758 17.0543L21.5932 17.0758C22.1135 17.7007 22.8584 18.0963 23.6674 18.1774C24.1788 18.2337 24.6961 18.1628 25.1735 17.9712C25.6509 17.7795 26.0736 17.4731 26.4041 17.0789C26.4111 17.0722 26.4177 17.0651 26.4236 17.0574C28.1723 14.9207 31.6143 10.9995 33.795 10.3637C36.8235 9.47912 39.6308 15.752 40.4171 23.3661C41.1911 30.8451 36.7661 38.4807 24.0002 38.4398Z"
164
+ />
165
+ <path
166
+ className="fill-robot-900"
167
+ d="M20.5989 29.1987C20.5913 29.534 20.4785 29.8585 20.2764 30.1263C19.9391 30.575 19.4646 30.9013 18.925 31.0559C17.764 31.4112 16.604 30.9873 16.3337 30.1078C16.0634 29.2284 16.7914 28.2271 17.9524 27.8718C18.6946 27.6456 19.4349 27.7377 19.9437 28.0623C20.2294 28.2341 20.4427 28.5042 20.5436 28.8219C20.5809 28.944 20.5995 29.071 20.5989 29.1987Z"
168
+ />
169
+ <path
170
+ className="fill-robot-900"
171
+ d="M21.8426 27.2135C21.8291 27.2588 21.8068 27.3011 21.7769 27.3378C21.747 27.3745 21.7102 27.405 21.6685 27.4275C21.6269 27.4499 21.5812 27.4639 21.5341 27.4686C21.487 27.4734 21.4394 27.4688 21.3941 27.4551L20.5996 27.2176V29.1403C20.5915 29.5086 20.4675 29.8651 20.2454 30.159H20.2403C20.193 30.1591 20.1462 30.1499 20.1024 30.1319C20.0587 30.1139 20.019 30.0875 19.9855 30.0541C19.952 30.0207 19.9255 29.981 19.9074 29.9374C19.8892 29.8937 19.8799 29.8469 19.8799 29.7996V26.7282C19.88 26.6722 19.8932 26.617 19.9184 26.5671C19.9436 26.5171 19.9803 26.4738 20.0253 26.4405C20.0703 26.4066 20.1227 26.3838 20.1782 26.3738C20.2337 26.3639 20.2907 26.3671 20.3447 26.3832L21.6009 26.7609C21.6468 26.7744 21.6894 26.7969 21.7265 26.827C21.7635 26.8571 21.7942 26.8944 21.8167 26.9365C21.8392 26.9786 21.8531 27.0248 21.8575 27.0724C21.8619 27.1199 21.8569 27.1679 21.8426 27.2135Z"
172
+ />
173
+ <path
174
+ className="fill-robot-900"
175
+ d="M32.3822 29.1987C32.3745 29.534 32.2617 29.8585 32.0596 30.1263C31.7223 30.575 31.2478 30.9013 30.7082 31.0559C29.5472 31.4112 28.3872 30.9873 28.1169 30.1078C27.8466 29.2284 28.5746 28.2271 29.7356 27.8718C30.4778 27.6456 31.2181 27.7377 31.7269 28.0623C32.0124 28.2344 32.2256 28.5043 32.3269 28.8219C32.3641 28.944 32.3827 29.071 32.3822 29.1987Z"
176
+ />
177
+ <path
178
+ className="fill-robot-900"
179
+ d="M33.604 27.2688C33.563 27.3463 33.496 27.407 33.4148 27.4401C33.3335 27.4732 33.2432 27.4767 33.1596 27.45L32.4215 27.2288C32.417 27.2276 32.4123 27.2274 32.4077 27.2282C32.4031 27.2291 32.3988 27.2309 32.3951 27.2337C32.3913 27.2365 32.3883 27.24 32.3861 27.2442C32.3839 27.2483 32.3827 27.2528 32.3826 27.2575V29.1403C32.3744 29.5086 32.2505 29.8651 32.0284 30.159C31.9811 30.1591 31.9342 30.1499 31.8905 30.1319C31.8468 30.1139 31.8071 30.0875 31.7736 30.0541C31.7401 30.0207 31.7135 29.981 31.6954 29.9374C31.6773 29.8937 31.668 29.8469 31.668 29.7996V26.7282C31.668 26.6722 31.6812 26.617 31.7065 26.5671C31.7317 26.5171 31.7683 26.4738 31.8133 26.4405C31.8584 26.4066 31.9108 26.3838 31.9662 26.3738C32.0217 26.3639 32.0788 26.3671 32.1328 26.3832L33.389 26.7609C33.4393 26.7763 33.4856 26.8025 33.5247 26.8376C33.5638 26.8728 33.5947 26.9162 33.6152 26.9646C33.6357 27.013 33.6453 27.0654 33.6434 27.1179C33.6415 27.1705 33.628 27.222 33.604 27.2688Z"
180
+ />
181
+ <path
182
+ className="stroke-robot-900"
183
+ d="M24.4765 31.7734C24.4765 32.401 23.8847 32.9099 23.1547 32.9099C22.4248 32.9099 21.833 32.398 21.833 31.7734"
184
+ strokeWidth="0.454199"
185
+ strokeLinecap="round"
186
+ strokeLinejoin="round"
187
+ />
188
+ <path
189
+ className="stroke-robot-900"
190
+ d="M27.12 31.7734C27.12 32.401 26.5283 32.9099 25.7983 32.9099C25.0683 32.9099 24.4766 32.398 24.4766 31.7734"
191
+ strokeWidth="0.454199"
192
+ strokeLinecap="round"
193
+ strokeLinejoin="round"
194
+ />
195
+ <path
196
+ className="fill-robot-900"
197
+ d="M25.7196 30.2304C25.3315 29.6683 24.6855 29.9713 24.4623 30.1116C24.2401 29.9713 23.5255 29.7103 23.2061 30.2304C22.6604 31.118 24.1818 31.9217 24.4551 31.9637H24.4705C24.7439 31.9217 26.3113 31.0873 25.7196 30.2304Z"
198
+ />
199
+ <path
200
+ className="fill-robot-100"
201
+ d="M13.7053 20.1578C13.4614 20.2941 13.186 20.3639 12.9066 20.3603C12.6272 20.3567 12.3536 20.2798 12.1133 20.1373C11.873 19.9947 11.6744 19.7916 11.5373 19.5481C11.4002 19.3046 11.3294 19.0294 11.3321 18.75C11.3608 16.0502 12.2986 12.7167 13.6449 12.7188C15.239 12.7188 16.744 14.7009 18.1016 16.2734C18.2807 16.4788 18.403 16.7273 18.4566 16.9945C18.5102 17.2616 18.4931 17.5381 18.4071 17.7966C18.321 18.0551 18.169 18.2867 17.9661 18.4685C17.7631 18.6502 17.5162 18.7759 17.2498 18.833C16.012 19.1062 14.8188 19.5521 13.7053 20.1578Z"
202
+ />
203
+ <path
204
+ className="fill-robot-100"
205
+ d="M34.3964 20.1568C34.6403 20.2934 34.9158 20.3634 35.1954 20.36C35.4749 20.3565 35.7486 20.2796 35.9891 20.137C36.2296 19.9944 36.4283 19.7912 36.5655 19.5476C36.7027 19.304 36.7734 19.0286 36.7706 18.7491C36.7419 16.0503 35.757 12.7157 34.4578 12.7178C32.8627 12.7178 31.3587 14.7009 30.0011 16.2735C29.8233 16.4788 29.702 16.7268 29.6491 16.9932C29.5962 17.2596 29.6136 17.5352 29.6995 17.7929C29.7855 18.0505 29.937 18.2814 30.1393 18.4627C30.3415 18.644 30.5875 18.7695 30.853 18.8269C32.0905 19.1024 33.2832 19.5501 34.3964 20.1568Z"
206
+ />
207
+ <path
208
+ className="fill-white"
209
+ d="M29.1824 29.7046C29.3097 29.7033 29.4314 29.6522 29.5215 29.5623C29.6116 29.4724 29.663 29.3507 29.6646 29.2234C29.6625 29.0962 29.611 28.9748 29.521 28.8848C29.431 28.7948 29.3096 28.7433 29.1824 28.7412C29.0551 28.7428 28.9334 28.7942 28.8435 28.8843C28.7536 28.9744 28.7025 29.0961 28.7012 29.2234C28.7033 29.3504 28.7546 29.4716 28.8444 29.5614C28.9342 29.6511 29.0554 29.7025 29.1824 29.7046Z"
210
+ />
211
+ <path
212
+ className="fill-white"
213
+ d="M17.6277 29.44C17.7552 29.4386 17.877 29.3874 17.9672 29.2973C18.0573 29.2071 18.1086 29.0852 18.1099 28.9578C18.1078 28.8306 18.0563 28.7093 17.9663 28.6195C17.8763 28.5297 17.7548 28.4784 17.6277 28.4766C17.5005 28.4779 17.3788 28.529 17.2889 28.619C17.1989 28.7089 17.1478 28.8305 17.1465 28.9578C17.1486 29.0848 17.1999 29.2061 17.2897 29.2961C17.3794 29.386 17.5006 29.4376 17.6277 29.44Z"
214
+ />
215
+ </svg>
216
+ );
217
+ }
218
+
219
+ export default function Avatar({
220
+ shape = 'round',
221
+ size = 'default',
222
+ type = 'image',
223
+ src = null,
224
+ label = null,
225
+ alt = '头像',
226
+ className = '',
227
+ style,
228
+ ...rest
229
+ }) {
230
+ const resolvedShape = Object.prototype.hasOwnProperty.call(SHAPE_CLASS, shape) ? shape : 'round';
231
+ const resolvedSize = SIZE_CLASS[size] ? size : 'default';
232
+ const resolvedType = Object.prototype.hasOwnProperty.call(TYPE_CLASS, type) ? type : 'image';
233
+ const [fallbackImageSrc] = useState(() => getRandomTeamAvatarSrc() || defaultAvatarSrc);
234
+ const [imageSrc, setImageSrc] = useState(src || fallbackImageSrc);
235
+
236
+ useEffect(() => {
237
+ setImageSrc(src || fallbackImageSrc);
238
+ }, [fallbackImageSrc, src]);
239
+
240
+ const defaultLabel = DEFAULT_LABEL[resolvedType]?.[resolvedSize] ?? '';
241
+ const resolvedLabel = resolvedType === 'eng'
242
+ ? (label || defaultLabel).toUpperCase()
243
+ : (label || defaultLabel);
244
+ const mergedStyle = {
245
+ ...(resolvedType === 'ai' ? { background: 'var(--gradient-ai-fill-2)' } : null),
246
+ ...style,
247
+ };
248
+
249
+ const cls = [
250
+ BASE,
251
+ SIZE_CLASS[resolvedSize],
252
+ SHAPE_CLASS[resolvedShape],
253
+ TYPE_CLASS[resolvedType],
254
+ resolvedType === 'ch' ? CHINESE_SHAPE_CLASS[resolvedShape] : '',
255
+ className,
256
+ ].filter(Boolean).join(' ');
257
+ const content = {
258
+ image: (
259
+ <img
260
+ alt={alt}
261
+ src={imageSrc}
262
+ className={[IMAGE, IMAGE_CLASS[resolvedSize]].join(' ')}
263
+ draggable="false"
264
+ onError={() => {
265
+ if (imageSrc !== fallbackImageSrc) {
266
+ setImageSrc(fallbackImageSrc);
267
+ } else if (imageSrc !== defaultAvatarSrc) {
268
+ setImageSrc(defaultAvatarSrc);
269
+ }
270
+ }}
271
+ />
272
+ ),
273
+ eng: (
274
+ <span
275
+ className={[
276
+ 'block max-w-[90%] overflow-hidden text-ellipsis whitespace-nowrap uppercase',
277
+ TEXT_CLASS[resolvedSize],
278
+ ].join(' ')}
279
+ >
280
+ {resolvedLabel}
281
+ </span>
282
+ ),
283
+ ch: (
284
+ <span
285
+ className={[
286
+ 'block max-w-[90%] overflow-hidden text-ellipsis whitespace-nowrap',
287
+ TEXT_CLASS[resolvedSize],
288
+ ].join(' ')}
289
+ >
290
+ {resolvedLabel}
291
+ </span>
292
+ ),
293
+ fallback: <FallbackGlyph className={FALLBACK_ICON_CLASS[resolvedSize]} />,
294
+ robot: <RobotGlyph className={ROBOT_ICON_CLASS} />,
295
+ ai: (
296
+ <span className={[AI_CONTENT_LAYER, AI_ICON_WRAP_CLASS[resolvedSize]].join(' ')}>
297
+ <Icon
298
+ name="hiai-logo"
299
+ size="xl"
300
+ className="size-full"
301
+ aria-hidden="true"
302
+ />
303
+ </span>
304
+ ),
305
+ }[resolvedType];
306
+
307
+ return (
308
+ <span className={[`tfds-avatar`, cls].filter(Boolean).join(' ')} style={mergedStyle} {...rest} data-tfds-component="Avatar">
309
+ {resolvedType === 'image' ? (
310
+ <span
311
+ aria-hidden="true"
312
+ className={IMAGE_STROKE_LAYER}
313
+ />
314
+ ) : null}
315
+ {resolvedType === 'ai' ? (
316
+ <span
317
+ aria-hidden="true"
318
+ className={AI_BACKGROUND_LAYER}
319
+ style={{ background: 'var(--gradient-ai-fill-1)' }}
320
+ />
321
+ ) : null}
322
+ {content}
323
+ </span>
324
+ );
325
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Avatar — TOKEN_MAP(供平台属性面板展示)
3
+ *
4
+ * 分组顺序:容器 → 类型 → 图片 → 尺寸
5
+ */
6
+ export const AVATAR_TOKEN_MAP = {
7
+ base: [],
8
+ 外框: [
9
+ { label: '裁切', cssProp: 'overflow', value: 'hidden' },
10
+ { label: '圆角', cssProp: 'border-radius', token: '--radius-full', value: '9999px', state: 'round' },
11
+ { label: '圆角', cssProp: 'border-radius', token: '--radius-avatar', value: '3px', state: 'rect' },
12
+ ],
13
+ 图片层: [
14
+ { label: '适配', cssProp: 'object-fit', value: 'cover' },
15
+ { label: '定位', cssProp: 'object-position', value: 'center top' },
16
+ ],
17
+ 英文态: [
18
+ { label: '背景色', cssProp: 'background', token: '--color-grey-300', value: '#A7A8B0' },
19
+ { label: '文字色', cssProp: 'color', token: '--color-white', value: '#FFFFFF', semanticRef: 'text-inverse' },
20
+ { label: '字重', cssProp: 'font-weight', token: '--font-semibold', value: '600(运行时使用 [font-weight:var(--font-semibold)])' },
21
+ ],
22
+ 中文态: [
23
+ { label: '圆形底色', cssProp: 'background', token: '--color-brand-500', value: '#56D3BC', semanticRef: 'status-primary', state: 'round' },
24
+ { label: '方形底色', cssProp: 'background', token: '--color-orange-500', value: '#FA8B14', semanticRef: 'status-warning', state: 'rect' },
25
+ { label: '文字色', cssProp: 'color', token: '--color-white', value: '#FFFFFF', semanticRef: 'text-inverse' },
26
+ { label: '字重', cssProp: 'font-weight', token: '--font-semibold', value: '600(运行时使用 [font-weight:var(--font-semibold)])' },
27
+ ],
28
+ 兜底态: [
29
+ { label: '背景色', cssProp: 'background', token: '--color-grey-100', value: '#E6E7EA' },
30
+ { label: '图形色', cssProp: 'color', token: '--color-grey-200', value: '#C6C7CD' },
31
+ ],
32
+ 机器人态: [
33
+ { label: '背景色', cssProp: 'background', token: '--color-robot-500', value: '#24B9D9' },
34
+ { label: '图形主色', cssProp: 'fill', token: '--color-robot-50', value: '#FCFCFC' },
35
+ { label: '耳朵底色', cssProp: 'fill', token: '--color-robot-100', value: '#EDEDED' },
36
+ { label: '五官色', cssProp: 'fill / stroke', token: '--color-robot-900', value: '#000000' },
37
+ { label: '高光色', cssProp: 'fill', token: '--color-white', value: '#FFFFFF' },
38
+ ],
39
+ AI头像态: [
40
+ { label: '背景色', cssProp: 'background', token: '--gradient-ai-fill-1', value: '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%)' },
41
+ { label: '图形来源', cssProp: 'component', value: 'Icon / hiai-logo' },
42
+ { label: '图形颜色', cssProp: '—', value: '使用图标内置渐变与高光,不额外覆写 color' },
43
+ ],
44
+ sizes: {
45
+ xxs: [
46
+ { label: '边长', cssProp: 'width / height', token: '--spacing-4', value: '16px' },
47
+ { label: '字体', cssProp: 'font-size', token: '--text-xs', value: '12px' },
48
+ { label: '行高', cssProp: 'line-height', token: '--spacing-4', value: '16px' },
49
+ ],
50
+ mini: [
51
+ { label: '边长', cssProp: 'width / height', token: '--spacing-5', value: '20px' },
52
+ { label: '字体', cssProp: 'font-size', token: '--text-xs', value: '12px' },
53
+ { label: '行高', cssProp: 'line-height', token: '--spacing-4', value: '16px' },
54
+ ],
55
+ xs: [
56
+ { label: '边长', cssProp: 'width / height', token: '--spacing-6', value: '24px' },
57
+ { label: '字体', cssProp: 'font-size', token: '--text-xs', value: '12px' },
58
+ { label: '行高', cssProp: 'line-height', token: '--spacing-4', value: '16px' },
59
+ ],
60
+ s: [
61
+ { label: '边长', cssProp: 'width / height', token: '--spacing-8', value: '32px' },
62
+ { label: '字体', cssProp: 'font-size', token: '--text-lg', value: '18px' },
63
+ { label: '行高', cssProp: 'line-height', token: '--spacing-6', value: '24px' },
64
+ ],
65
+ default: [
66
+ { label: '边长', cssProp: 'width / height', token: '--spacing-10', value: '40px' },
67
+ { label: '字体', cssProp: 'font-size', token: '--text-lg', value: '18px' },
68
+ { label: '行高', cssProp: 'line-height', token: '--spacing-6', value: '24px' },
69
+ ],
70
+ m: [
71
+ { label: '边长', cssProp: 'width / height', token: '--spacing-12', value: '48px' },
72
+ { label: '字体', cssProp: 'font-size', token: '--text-xl', value: '20px' },
73
+ { label: '行高', cssProp: 'line-height', value: '28px' },
74
+ ],
75
+ },
76
+ };
@@ -0,0 +1,56 @@
1
+ import Avatar from './Avatar';
2
+ import { getTeamMemberByName } from '../teamMembers';
3
+
4
+ const MATRIX_SIZES = ['xxs', 'mini', 'xs', 's', 'default', 'm'];
5
+ const SCENE_TYPES = ['image', 'eng', 'ch', 'fallback', 'robot', 'ai'];
6
+ const SCENE_FILTERS = ['all', ...SCENE_TYPES];
7
+ const PREVIEW_IMAGE_MEMBER = getTeamMemberByName('程程murphy');
8
+
9
+ function AvatarSection({ shape, rows }) {
10
+ return (
11
+ <div className="flex flex-col gap-8">
12
+ {rows.map((rowType) => (
13
+ <div key={`${shape}-${rowType}`} className="flex items-end gap-5">
14
+ {MATRIX_SIZES.map((rowSize) => (
15
+ <Avatar
16
+ key={`${shape}-${rowType}-${rowSize}`}
17
+ shape={shape}
18
+ size={rowSize}
19
+ type={rowType}
20
+ src={rowType === 'image' ? PREVIEW_IMAGE_MEMBER?.avatarSrc : undefined}
21
+ alt={rowType === 'image' ? PREVIEW_IMAGE_MEMBER?.name || '程程头像' : undefined}
22
+ />
23
+ ))}
24
+ </div>
25
+ ))}
26
+ </div>
27
+ );
28
+ }
29
+
30
+ export default function AvatarGridPreview({
31
+ previewMode = 'matrix',
32
+ shape = 'round',
33
+ size = 'default',
34
+ type = 'image',
35
+ }) {
36
+ const resolvedShape = shape === 'rect' ? 'rect' : 'round';
37
+ const resolvedType = SCENE_FILTERS.includes(type) ? type : 'all';
38
+ const matrixRows = resolvedType === 'all' ? SCENE_TYPES : [resolvedType];
39
+ const singleType = resolvedType === 'all' ? 'image' : resolvedType;
40
+
41
+ if (previewMode === 'single') {
42
+ return (
43
+ <Avatar
44
+ shape={resolvedShape}
45
+ size={size}
46
+ type={singleType}
47
+ src={singleType === 'image' ? PREVIEW_IMAGE_MEMBER?.avatarSrc : undefined}
48
+ alt={singleType === 'image' ? PREVIEW_IMAGE_MEMBER?.name || '程程头像' : undefined}
49
+ />
50
+ );
51
+ }
52
+
53
+ return (
54
+ <AvatarSection shape={resolvedShape} rows={matrixRows} />
55
+ );
56
+ }