@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,277 @@
1
+ /**
2
+ * IconGridPreview — 图标库网格预览组件
3
+ *
4
+ * 按分类折叠展示所有图标,每个图标一个卡片,下方显示名称。
5
+ * 点击图标可选择复制「组件代码」或「SVG 代码」。
6
+ */
7
+
8
+ import { useMemo, useState } from 'react';
9
+ import { ChevronDown, ChevronRight, Check } from 'lucide-react';
10
+ import { ICON_CATEGORIES, ICON_MAP } from './icons/icon-data';
11
+ import Icon from './Icon';
12
+ import Input from './Input';
13
+
14
+ function normalizeIconEntry(entry) {
15
+ if (Array.isArray(entry)) {
16
+ return {
17
+ viewBox: '0 0 24 24',
18
+ defs: [],
19
+ shapes: entry,
20
+ contentTransform: '',
21
+ };
22
+ }
23
+
24
+ return {
25
+ viewBox: entry?.viewBox || '0 0 24 24',
26
+ defs: entry?.defs || [],
27
+ shapes: entry?.shapes || [],
28
+ contentTransform: entry?.contentTransform || '',
29
+ };
30
+ }
31
+
32
+ function buildSvgString(name) {
33
+ const entry = ICON_MAP[name];
34
+ if (!entry) return '';
35
+
36
+ const { viewBox, defs, shapes, contentTransform } = normalizeIconEntry(entry);
37
+ const defsBlock = defs.length
38
+ ? [
39
+ ' <defs>',
40
+ ...defs.map((def) => {
41
+ if (def.type !== 'linearGradient') return '';
42
+
43
+ const stops = def.stops.map((stop) => {
44
+ let attrs = `offset="${stop.offset}" stop-color="${stop.stopColor}"`;
45
+ if (stop.stopOpacity !== undefined) attrs += ` stop-opacity="${stop.stopOpacity}"`;
46
+ return ` <stop ${attrs}/>`;
47
+ }).join('\n');
48
+
49
+ return ` <linearGradient id="${def.id}" x1="${def.x1}" y1="${def.y1}" x2="${def.x2}" y2="${def.y2}" gradientUnits="${def.gradientUnits}">\n${stops}\n </linearGradient>`;
50
+ }).filter(Boolean),
51
+ ' </defs>',
52
+ ].join('\n')
53
+ : '';
54
+
55
+ const inner = shapes.map((shape) => {
56
+ if (shape.type === 'ellipse') {
57
+ const transformAttr = shape.transform ? ` transform="${shape.transform}"` : '';
58
+ return ` <ellipse cx="${shape.cx}" cy="${shape.cy}" rx="${shape.rx}" ry="${shape.ry}" fill="${shape.fill || 'currentColor'}"${transformAttr}/>`;
59
+ }
60
+
61
+ if (shape.type === 'rect') {
62
+ let attrs = `x="${shape.x}" y="${shape.y}" width="${shape.width}" height="${shape.height}"`;
63
+ if (shape.rx !== undefined) attrs += ` rx="${shape.rx}"`;
64
+ if (shape.ry !== undefined) attrs += ` ry="${shape.ry}"`;
65
+ attrs += ` fill="${shape.fill || 'currentColor'}"`;
66
+ if (shape.stroke) attrs += ` stroke="${shape.strokeColor || 'currentColor'}" stroke-width="${shape.strokeWidth || '2'}"`;
67
+ if (shape.transform) attrs += ` transform="${shape.transform}"`;
68
+ return ` <rect ${attrs}/>`;
69
+ }
70
+
71
+ if (shape.stroke) {
72
+ let attrs = `d="${shape.d}" fill="none" stroke="${shape.strokeColor || 'currentColor'}" stroke-width="${shape.strokeWidth || '2'}" stroke-linecap="${shape.strokeLinecap || 'round'}" stroke-linejoin="${shape.strokeLinejoin || 'round'}"`;
73
+ if (shape.transform) attrs += ` transform="${shape.transform}"`;
74
+ return ` <path ${attrs}/>`;
75
+ }
76
+
77
+ let attrs = `d="${shape.d}" fill="${shape.fill || 'currentColor'}"`;
78
+ if (shape.fillRule) attrs += ` fill-rule="${shape.fillRule}"`;
79
+ if (shape.clipRule) attrs += ` clip-rule="${shape.clipRule}"`;
80
+ if (shape.transform) attrs += ` transform="${shape.transform}"`;
81
+ return ` <path ${attrs}/>`;
82
+ }).join('\n');
83
+
84
+ const body = contentTransform
85
+ ? ` <g transform="${contentTransform}">\n${inner}\n </g>`
86
+ : inner;
87
+ const blocks = [defsBlock, body].filter(Boolean).join('\n');
88
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="${viewBox}" preserveAspectRatio="xMidYMid meet" fill="none">\n${blocks}\n</svg>`;
89
+ }
90
+
91
+ export default function IconGridPreview() {
92
+ const [collapsed, setCollapsed] = useState({});
93
+ const [copiedName, setCopiedName] = useState(null);
94
+ const [copiedType, setCopiedType] = useState(null); // 'jsx' | 'svg'
95
+ const [searchValue, setSearchValue] = useState('');
96
+
97
+ const keyword = searchValue.trim().toLowerCase();
98
+ const filteredCategories = useMemo(() => {
99
+ if (!keyword) return ICON_CATEGORIES;
100
+
101
+ return ICON_CATEGORIES.map((category) => ({
102
+ ...category,
103
+ icons: (category.icons || []).filter((icon) => {
104
+ const haystacks = [icon.name, icon.label].filter(Boolean).map((text) => String(text).toLowerCase());
105
+ return haystacks.some((text) => text.includes(keyword));
106
+ }),
107
+ })).filter((category) => category.icons.length > 0);
108
+ }, [keyword]);
109
+
110
+ const toggle = (id) =>
111
+ setCollapsed(prev => ({ ...prev, [id]: !prev[id] }));
112
+
113
+ const handleCopy = (name, type) => {
114
+ const text = type === 'svg'
115
+ ? buildSvgString(name)
116
+ : `<Icon name="${name}" />`;
117
+ navigator.clipboard.writeText(text);
118
+ setCopiedName(name);
119
+ setCopiedType(type);
120
+ setTimeout(() => { setCopiedName(null); setCopiedType(null); }, 1500);
121
+ };
122
+
123
+ return (
124
+ <div style={{ width: '100%', padding: '0', boxSizing: 'border-box' }}>
125
+ <div style={{ marginBottom: 20, maxWidth: 320 }}>
126
+ <Input
127
+ value={searchValue}
128
+ onChange={(event) => setSearchValue(event.target.value)}
129
+ allowClear
130
+ placeholder="搜索 icon 名称"
131
+ prefix={<Icon name="search-lg-stroked" size="sm" color="#667085" aria-hidden="true" />}
132
+ />
133
+ </div>
134
+
135
+ {filteredCategories.length === 0 ? (
136
+ <div
137
+ style={{
138
+ display: 'flex',
139
+ minHeight: 200,
140
+ alignItems: 'center',
141
+ justifyContent: 'center',
142
+ borderRadius: 12,
143
+ border: '1px dashed rgba(45,66,107,0.12)',
144
+ background: '#FCFCFD',
145
+ color: '#98A2B3',
146
+ fontSize: 13,
147
+ }}
148
+ >
149
+ 未找到匹配的 icon 名称
150
+ </div>
151
+ ) : filteredCategories.map(cat => {
152
+ const isCollapsed = keyword ? false : collapsed[cat.id];
153
+ return (
154
+ <div key={cat.id} style={{ marginBottom: 20 }}>
155
+ <button
156
+ onClick={() => toggle(cat.id)}
157
+ style={{
158
+ display: 'flex', alignItems: 'center', gap: 6,
159
+ background: 'none', border: 'none', cursor: 'pointer',
160
+ padding: '4px 0', marginBottom: 12, width: '100%',
161
+ }}
162
+ >
163
+ {isCollapsed
164
+ ? <ChevronRight size={14} style={{ color: '#667085' }} />
165
+ : <ChevronDown size={14} style={{ color: '#667085' }} />
166
+ }
167
+ <span style={{ fontSize: 13, fontWeight: 600, color: '#344054' }}>
168
+ {cat.label}
169
+ </span>
170
+ <span style={{ fontSize: 12, color: '#98A2B3' }}>
171
+ ({cat.icons.length})
172
+ </span>
173
+ </button>
174
+
175
+ {!isCollapsed && (
176
+ <div style={{
177
+ display: 'grid',
178
+ gridTemplateColumns: 'repeat(auto-fill, minmax(80px, 1fr))',
179
+ gap: 8,
180
+ }}>
181
+ {cat.icons.map(ic => {
182
+ const isActive = copiedName === ic.name;
183
+ const fallbackName = ic.name
184
+ .replace(/-stroked$/, '')
185
+ .replace(/-/g, ' ');
186
+ const displayName = ic.label || fallbackName;
187
+ return (
188
+ <div
189
+ key={ic.name}
190
+ title={ic.name}
191
+ style={{
192
+ display: 'flex', flexDirection: 'column',
193
+ alignItems: 'center', justifyContent: 'center',
194
+ gap: 6, padding: '12px 4px 8px',
195
+ borderRadius: 8,
196
+ border: '1px solid rgba(45,66,107,0.06)',
197
+ background: isActive ? '#EAFAF6' : '#FFFFFF',
198
+ cursor: 'pointer',
199
+ transition: 'all 0.15s ease',
200
+ position: 'relative',
201
+ }}
202
+ onMouseEnter={e => {
203
+ if (!isActive) e.currentTarget.style.background = '#F9FAFB';
204
+ e.currentTarget.style.borderColor = '#E4E7EC';
205
+ }}
206
+ onMouseLeave={e => {
207
+ if (!isActive) e.currentTarget.style.background = '#FFFFFF';
208
+ e.currentTarget.style.borderColor = 'rgba(45,66,107,0.06)';
209
+ }}
210
+ >
211
+ {isActive ? (
212
+ <>
213
+ <Check size={18} style={{ color: '#56D3BC' }} />
214
+ <span style={{ fontSize: 10, color: '#56D3BC', textAlign: 'center', lineHeight: '13px' }}>
215
+ {copiedType === 'svg' ? 'SVG 已复制' : '组件已复制'}
216
+ </span>
217
+ </>
218
+ ) : (
219
+ <>
220
+ <Icon name={ic.name} size="lg" color="#344054" />
221
+ <span style={{
222
+ fontSize: 10, color: '#98A2B3',
223
+ textAlign: 'center', lineHeight: '13px',
224
+ maxWidth: '100%', overflow: 'hidden',
225
+ textOverflow: 'ellipsis', whiteSpace: 'nowrap',
226
+ padding: '0 2px',
227
+ }}>
228
+ {displayName}
229
+ </span>
230
+ {/* 悬浮时显示两个复制按钮 */}
231
+ <div
232
+ className="icon-card-actions"
233
+ style={{
234
+ position: 'absolute', inset: 0,
235
+ display: 'flex', flexDirection: 'column',
236
+ alignItems: 'center', justifyContent: 'center',
237
+ gap: 4, borderRadius: 8,
238
+ background: 'rgba(255,255,255,0.95)',
239
+ opacity: 0, transition: 'opacity 0.15s ease',
240
+ }}
241
+ onMouseEnter={e => { e.currentTarget.style.opacity = '1'; }}
242
+ onMouseLeave={e => { e.currentTarget.style.opacity = '0'; }}
243
+ >
244
+ <button
245
+ onClick={(e) => { e.stopPropagation(); handleCopy(ic.name, 'jsx'); }}
246
+ style={{
247
+ fontSize: 11, color: '#344054', background: '#F2F4F7',
248
+ border: 'none', borderRadius: 4, padding: '3px 8px',
249
+ cursor: 'pointer', whiteSpace: 'nowrap',
250
+ }}
251
+ >
252
+ 复制组件
253
+ </button>
254
+ <button
255
+ onClick={(e) => { e.stopPropagation(); handleCopy(ic.name, 'svg'); }}
256
+ style={{
257
+ fontSize: 11, color: '#344054', background: '#F2F4F7',
258
+ border: 'none', borderRadius: 4, padding: '3px 8px',
259
+ cursor: 'pointer', whiteSpace: 'nowrap',
260
+ }}
261
+ >
262
+ 复制 SVG
263
+ </button>
264
+ </div>
265
+ </>
266
+ )}
267
+ </div>
268
+ );
269
+ })}
270
+ </div>
271
+ )}
272
+ </div>
273
+ );
274
+ })}
275
+ </div>
276
+ );
277
+ }