@huyooo/ai-chat-frontend-react 0.2.14 → 0.2.16

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 (76) hide show
  1. package/dist/index.css +0 -1
  2. package/dist/index.js +1 -5418
  3. package/package.json +4 -5
  4. package/dist/index.css.map +0 -1
  5. package/dist/index.js.map +0 -1
  6. package/src/adapter.ts +0 -68
  7. package/src/components/ChatPanel.tsx +0 -553
  8. package/src/components/common/ConfirmDialog.css +0 -136
  9. package/src/components/common/ConfirmDialog.tsx +0 -91
  10. package/src/components/common/CopyButton.css +0 -22
  11. package/src/components/common/CopyButton.tsx +0 -46
  12. package/src/components/common/IndexingSettings.css +0 -207
  13. package/src/components/common/IndexingSettings.tsx +0 -398
  14. package/src/components/common/SettingsPanel.css +0 -337
  15. package/src/components/common/SettingsPanel.tsx +0 -215
  16. package/src/components/common/Toast.css +0 -50
  17. package/src/components/common/Toast.tsx +0 -38
  18. package/src/components/common/ToggleSwitch.css +0 -52
  19. package/src/components/common/ToggleSwitch.tsx +0 -20
  20. package/src/components/header/ChatHeader.css +0 -285
  21. package/src/components/header/ChatHeader.tsx +0 -376
  22. package/src/components/input/AtFilePicker.css +0 -147
  23. package/src/components/input/AtFilePicker.tsx +0 -519
  24. package/src/components/input/ChatInput.css +0 -283
  25. package/src/components/input/ChatInput.tsx +0 -575
  26. package/src/components/input/DropdownSelector.css +0 -231
  27. package/src/components/input/DropdownSelector.tsx +0 -333
  28. package/src/components/input/ImagePreviewModal.css +0 -124
  29. package/src/components/input/ImagePreviewModal.tsx +0 -118
  30. package/src/components/input/at-views/AtBranchView.tsx +0 -34
  31. package/src/components/input/at-views/AtBrowserView.tsx +0 -34
  32. package/src/components/input/at-views/AtChatsView.tsx +0 -34
  33. package/src/components/input/at-views/AtDocsView.tsx +0 -34
  34. package/src/components/input/at-views/AtFilesView.tsx +0 -168
  35. package/src/components/input/at-views/AtTerminalsView.tsx +0 -34
  36. package/src/components/input/at-views/AtViewStyles.css +0 -143
  37. package/src/components/input/at-views/index.ts +0 -9
  38. package/src/components/message/ContentRenderer.css +0 -9
  39. package/src/components/message/MessageBubble.css +0 -193
  40. package/src/components/message/MessageBubble.tsx +0 -240
  41. package/src/components/message/PartsRenderer.css +0 -12
  42. package/src/components/message/PartsRenderer.tsx +0 -168
  43. package/src/components/message/WelcomeMessage.css +0 -221
  44. package/src/components/message/WelcomeMessage.tsx +0 -93
  45. package/src/components/message/parts/CollapsibleCard.css +0 -80
  46. package/src/components/message/parts/CollapsibleCard.tsx +0 -80
  47. package/src/components/message/parts/ErrorPart.css +0 -9
  48. package/src/components/message/parts/ErrorPart.tsx +0 -40
  49. package/src/components/message/parts/ImagePart.css +0 -49
  50. package/src/components/message/parts/ImagePart.tsx +0 -54
  51. package/src/components/message/parts/SearchPart.css +0 -44
  52. package/src/components/message/parts/SearchPart.tsx +0 -63
  53. package/src/components/message/parts/TextPart.css +0 -579
  54. package/src/components/message/parts/TextPart.tsx +0 -213
  55. package/src/components/message/parts/ThinkingPart.css +0 -9
  56. package/src/components/message/parts/ThinkingPart.tsx +0 -48
  57. package/src/components/message/parts/ToolCallPart.css +0 -246
  58. package/src/components/message/parts/ToolCallPart.tsx +0 -289
  59. package/src/components/message/parts/ToolResultPart.css +0 -67
  60. package/src/components/message/parts/index.ts +0 -13
  61. package/src/components/message/parts/visual-predicate.ts +0 -43
  62. package/src/components/message/parts/visual-render.ts +0 -19
  63. package/src/components/message/parts/visual.ts +0 -12
  64. package/src/components/message/welcome-types.ts +0 -46
  65. package/src/context/AutoRunConfigContext.tsx +0 -13
  66. package/src/context/ChatAdapterContext.tsx +0 -8
  67. package/src/context/ChatInputContext.tsx +0 -40
  68. package/src/context/RenderersContext.tsx +0 -35
  69. package/src/hooks/useChat.ts +0 -1569
  70. package/src/hooks/useImageUpload.ts +0 -345
  71. package/src/hooks/useVoiceInput.ts +0 -454
  72. package/src/hooks/useVoiceToTextInput.ts +0 -87
  73. package/src/index.ts +0 -151
  74. package/src/styles.css +0 -330
  75. package/src/types/index.ts +0 -196
  76. package/src/utils/fileIcon.ts +0 -49
@@ -1,285 +0,0 @@
1
- /**
2
- * ChatHeader 组件样式
3
- */
4
-
5
- .chat-header {
6
- display: flex;
7
- align-items: center;
8
- height: 48px;
9
- padding: 0 12px;
10
- background: var(--chat-header-bg, #1e1e1e);
11
- border-bottom: 1px solid var(--chat-border, #333);
12
- flex-shrink: 0;
13
- }
14
-
15
- .tabs-container {
16
- display: flex;
17
- align-items: center;
18
- gap: 4px;
19
- flex: 1;
20
- overflow-x: auto;
21
- padding-right: 8px;
22
- }
23
-
24
- .tabs-container::-webkit-scrollbar {
25
- display: none;
26
- }
27
-
28
- .tab-item {
29
- position: relative;
30
- display: flex;
31
- align-items: center;
32
- padding: 4px 8px;
33
- background: transparent;
34
- border: none;
35
- border-radius: 4px;
36
- color: var(--chat-text-muted, #888);
37
- font-size: 14px;
38
- font-weight: 500;
39
- cursor: pointer;
40
- transition: all 0.15s;
41
- white-space: nowrap;
42
- max-width: 120px;
43
- flex-shrink: 0;
44
- }
45
-
46
- .tab-item:hover {
47
- color: var(--chat-text, #ccc);
48
- }
49
-
50
- .tab-item.active {
51
- background: var(--chat-muted, #3c3c3c);
52
- color: var(--chat-text, #fff);
53
- }
54
-
55
- .tab-title {
56
- overflow: hidden;
57
- text-overflow: ellipsis;
58
- white-space: nowrap;
59
- }
60
-
61
- .tab-close {
62
- position: absolute;
63
- right: 0;
64
- top: 0;
65
- bottom: 0;
66
- display: flex;
67
- align-items: center;
68
- justify-content: center;
69
- width: 32px;
70
- padding: 0;
71
- padding-left: 8px;
72
- background: linear-gradient(to right, transparent, var(--chat-bg, #1e1e1e) 50%);
73
- border: none;
74
- border-radius: 0 4px 4px 0;
75
- color: var(--chat-text-muted, #666);
76
- cursor: pointer;
77
- transition: all 0.15s;
78
- opacity: 0;
79
- }
80
-
81
- .tab-item:hover .tab-close {
82
- opacity: 1;
83
- }
84
-
85
- .tab-item.active .tab-close {
86
- background: linear-gradient(to right, transparent, var(--chat-muted, #3c3c3c) 50%);
87
- }
88
-
89
- .tab-close:hover {
90
- color: var(--chat-text, #fff);
91
- }
92
-
93
- .header-actions {
94
- display: flex;
95
- align-items: center;
96
- gap: 2px;
97
- flex-shrink: 0;
98
- }
99
-
100
- .header-actions .icon-btn {
101
- display: flex;
102
- align-items: center;
103
- justify-content: center;
104
- width: 24px;
105
- height: 24px;
106
- padding: 0;
107
- background: transparent;
108
- border: none;
109
- border-radius: 4px;
110
- color: var(--chat-text-muted, #888);
111
- cursor: pointer;
112
- transition: all 0.15s;
113
- }
114
-
115
- .header-actions .icon-btn:hover,
116
- .header-actions .icon-btn.active {
117
- color: var(--chat-text, #fff);
118
- }
119
-
120
- .header-actions .icon-btn.small {
121
- width: 20px;
122
- height: 20px;
123
- }
124
-
125
- .dropdown-container {
126
- position: relative;
127
- }
128
-
129
- .dropdown-panel {
130
- position: absolute;
131
- top: 100%;
132
- right: 0;
133
- margin-top: 4px;
134
- background: var(--chat-dropdown-bg, #252526);
135
- border: 1px solid rgba(255, 255, 255, 0.1);
136
- border-radius: 8px;
137
- box-shadow: 0 4px 16px rgba(0, 0, 0, 0.4);
138
- z-index: 100;
139
- overflow: hidden;
140
- }
141
-
142
- .history-panel {
143
- width: 360px;
144
- }
145
-
146
- .more-panel {
147
- width: 200px;
148
- padding: 4px;
149
- display: flex;
150
- flex-direction: column;
151
- gap: 2px;
152
- }
153
-
154
- .panel-header {
155
- display: flex;
156
- align-items: center;
157
- justify-content: space-between;
158
- padding: 10px 12px;
159
- border-bottom: 1px solid var(--chat-border, #333);
160
- font-size: 14px;
161
- font-weight: 500;
162
- color: var(--chat-text-muted, #888);
163
- }
164
-
165
- .panel-content {
166
- max-height: 400px;
167
- overflow-y: auto;
168
- }
169
-
170
- /* 日期分组标签 */
171
- .history-group-label {
172
- padding: 8px 12px 4px;
173
- font-size: 14px;
174
- font-weight: 500;
175
- color: var(--chat-text-muted, #666);
176
- }
177
-
178
- .history-group-label:not(:first-child) {
179
- border-top: 1px solid var(--chat-border, #333);
180
- margin-top: 4px;
181
- padding-top: 12px;
182
- }
183
-
184
- .history-item {
185
- display: flex;
186
- align-items: center;
187
- gap: 4px;
188
- padding: 6px 12px;
189
- cursor: pointer;
190
- transition: background 0.15s;
191
- }
192
-
193
- .history-item:hover {
194
- background: rgba(255, 255, 255, 0.08);
195
- }
196
-
197
- .history-item.active {
198
- background: rgba(255, 255, 255, 0.1);
199
- }
200
-
201
- .history-title {
202
- flex: 1;
203
- font-size: 14px;
204
- color: var(--chat-text, #ccc);
205
- overflow: hidden;
206
- text-overflow: ellipsis;
207
- white-space: nowrap;
208
- }
209
-
210
- .history-time {
211
- font-size: 14px;
212
- color: var(--chat-text-muted, #666);
213
- flex-shrink: 0;
214
- margin-right: 10px;
215
- }
216
-
217
- .history-actions {
218
- display: flex;
219
- align-items: center;
220
- gap: 2px;
221
- flex-shrink: 0;
222
- opacity: 0;
223
- transition: opacity 0.15s;
224
- }
225
-
226
- .history-item:hover .history-actions {
227
- opacity: 1;
228
- }
229
-
230
- .history-action-btn {
231
- display: flex;
232
- align-items: center;
233
- justify-content: center;
234
- width: 28px;
235
- height: 28px;
236
- padding: 0;
237
- background: transparent;
238
- border: none;
239
- border-radius: 6px;
240
- color: var(--chat-text-muted, #666);
241
- cursor: pointer;
242
- transition: all 0.15s;
243
- }
244
-
245
- .history-action-btn:hover {
246
- color: var(--chat-text, #fff);
247
- }
248
-
249
- .history-action-btn.delete:hover {
250
- color: var(--chat-destructive, #ef4444);
251
- }
252
-
253
- .empty-state {
254
- padding: 20px;
255
- text-align: center;
256
- font-size: 14px;
257
- color: var(--chat-text-muted, #666);
258
- }
259
-
260
- .menu-item {
261
- display: flex;
262
- align-items: center;
263
- gap: 8px;
264
- width: 100%;
265
- padding: 8px 10px;
266
- border: none;
267
- background: transparent;
268
- border-radius: 4px;
269
- font-size: 14px;
270
- color: var(--chat-text-muted, #999);
271
- cursor: pointer;
272
- transition: all 0.15s;
273
- text-align: left;
274
- }
275
-
276
- .menu-item:hover {
277
- background: rgba(255, 255, 255, 0.08);
278
- color: var(--chat-text, #ccc);
279
- }
280
-
281
- .menu-divider {
282
- height: 1px;
283
- background: var(--chat-border, #333);
284
- margin: 4px 0;
285
- }
@@ -1,376 +0,0 @@
1
- /**
2
- * ChatHeader Component
3
- * 与 Vue 版本 ChatHeader.vue 保持一致
4
- */
5
-
6
- import { useState, useRef, useEffect, useCallback, type FC } from 'react'
7
- import './ChatHeader.css'
8
- import { Icon } from '@iconify/react'
9
- import type { SessionRecord } from '../../types'
10
-
11
- interface ChatHeaderProps {
12
- /** 当前会话列表 */
13
- sessions: SessionRecord[]
14
- /** 当前会话 ID */
15
- currentSessionId?: string | null
16
- /** 是否显示关闭按钮 */
17
- showClose?: boolean
18
- /** 创建新会话 */
19
- onNewSession?: () => void
20
- /** 切换会话 */
21
- onSwitchSession?: (sessionId: string) => void
22
- /** 删除会话 */
23
- onDeleteSession?: (sessionId: string) => void
24
- /** 隐藏/显示会话(在 tab 栏关闭但不删除) */
25
- onHideSession?: (sessionId: string, hidden: boolean) => void
26
- /** 关闭面板 */
27
- onClose?: () => void
28
- /** 清空所有对话 */
29
- onClearAll?: () => void
30
- /** 关闭其他对话 */
31
- onCloseOthers?: () => void
32
- /** 导出对话 */
33
- onExport?: () => void
34
- /** 复制请求 ID */
35
- onCopyId?: () => void
36
- /** 反馈 */
37
- onFeedback?: () => void
38
- /** Agent 设置 */
39
- onSettings?: () => void
40
- }
41
-
42
- /** 获取日期分组标签 */
43
- function getDateGroupLabel(date: Date | string): string {
44
- const d = new Date(date)
45
- const now = new Date()
46
-
47
- // 重置时间部分,只比较日期
48
- const today = new Date(now.getFullYear(), now.getMonth(), now.getDate())
49
- const target = new Date(d.getFullYear(), d.getMonth(), d.getDate())
50
- const diff = today.getTime() - target.getTime()
51
- const days = Math.floor(diff / (1000 * 60 * 60 * 24))
52
-
53
- if (days === 0) return '今天'
54
- if (days === 1) return '昨天'
55
-
56
- // 其他显示具体日期
57
- const month = d.getMonth() + 1
58
- const day = d.getDate()
59
- return `${month}月${day}日`
60
- }
61
-
62
- /** 格式化时间(HH:mm) */
63
- function formatTime(date: Date | string): string {
64
- const d = new Date(date)
65
- const hours = String(d.getHours()).padStart(2, '0')
66
- const minutes = String(d.getMinutes()).padStart(2, '0')
67
- return `${hours}:${minutes}`
68
- }
69
-
70
- /** 按日期分组会话 */
71
- interface SessionGroup {
72
- label: string
73
- sessions: SessionRecord[]
74
- }
75
-
76
- function groupSessionsByDate(sessions: SessionRecord[]): SessionGroup[] {
77
- const groups = new Map<string, SessionRecord[]>()
78
-
79
- for (const session of sessions) {
80
- const label = getDateGroupLabel(session.updatedAt)
81
- const group = groups.get(label)
82
- if (group) {
83
- group.push(session)
84
- } else {
85
- groups.set(label, [session])
86
- }
87
- }
88
-
89
- return Array.from(groups.entries()).map(([label, groupSessions]) => ({
90
- label,
91
- sessions: groupSessions,
92
- }))
93
- }
94
-
95
- /** 获取显示标题 */
96
- function getDisplayTitle(title: string): string {
97
- return title === '新对话' ? 'New Chat' : title
98
- }
99
-
100
- export const ChatHeader: FC<ChatHeaderProps> = ({
101
- sessions,
102
- currentSessionId,
103
- showClose = false,
104
- onNewSession,
105
- onSwitchSession,
106
- onDeleteSession,
107
- onHideSession,
108
- onClose,
109
- onClearAll,
110
- onCloseOthers,
111
- onExport,
112
- onCopyId,
113
- onFeedback,
114
- onSettings,
115
- }) => {
116
- const [historyOpen, setHistoryOpen] = useState(false)
117
- const [moreMenuOpen, setMoreMenuOpen] = useState(false)
118
-
119
- const historyRef = useRef<HTMLDivElement>(null)
120
- const moreMenuRef = useRef<HTMLDivElement>(null)
121
-
122
- // 可见的会话(使用 sessions 的 hidden 字段)
123
- const visibleSessions = sessions.filter((s) => !s.hidden)
124
-
125
- // 点击外部关闭菜单
126
- useEffect(() => {
127
- const handleClickOutside = (event: MouseEvent) => {
128
- const target = event.target as HTMLElement
129
- if (historyRef.current && !historyRef.current.contains(target)) {
130
- setHistoryOpen(false)
131
- }
132
- if (moreMenuRef.current && !moreMenuRef.current.contains(target)) {
133
- setMoreMenuOpen(false)
134
- }
135
- }
136
-
137
- document.addEventListener('click', handleClickOutside)
138
- return () => document.removeEventListener('click', handleClickOutside)
139
- }, [])
140
-
141
- // 切换历史面板
142
- const toggleHistory = useCallback(() => {
143
- setHistoryOpen((prev) => !prev)
144
- setMoreMenuOpen(false)
145
- }, [])
146
-
147
- // 切换更多菜单
148
- const toggleMore = useCallback(() => {
149
- setMoreMenuOpen((prev) => !prev)
150
- setHistoryOpen(false)
151
- }, [])
152
-
153
- // 从历史新建
154
- const handleNewFromHistory = useCallback(() => {
155
- onNewSession?.()
156
- setHistoryOpen(false)
157
- }, [onNewSession])
158
-
159
- // 选择历史
160
- const handleSelectHistory = useCallback(
161
- (sessionId: string) => {
162
- const session = sessions.find((s) => s.id === sessionId)
163
- // 如果被隐藏了,恢复显示
164
- if (session?.hidden) {
165
- onHideSession?.(sessionId, false)
166
- }
167
- onSwitchSession?.(sessionId)
168
- setHistoryOpen(false)
169
- },
170
- [sessions, onSwitchSession, onHideSession]
171
- )
172
-
173
- // 隐藏 tab(触发回调由父组件持久化到数据库)
174
- const handleHideTab = useCallback(
175
- (sessionId: string, e: React.MouseEvent) => {
176
- e.stopPropagation()
177
- onHideSession?.(sessionId, true)
178
- if (sessionId === currentSessionId) {
179
- const remaining = sessions.filter((s) => s.id !== sessionId && !s.hidden)
180
- if (remaining.length > 0) {
181
- onSwitchSession?.(remaining[0].id)
182
- } else {
183
- // 最后一个 tab 被关闭,创建新会话
184
- onNewSession?.()
185
- }
186
- }
187
- },
188
- [currentSessionId, sessions, onSwitchSession, onNewSession, onHideSession]
189
- )
190
-
191
- // 删除会话
192
- const handleDeleteSession = (sessionId: string, e: React.MouseEvent) => {
193
- e.stopPropagation()
194
- onDeleteSession?.(sessionId)
195
- }
196
-
197
- // 菜单操作
198
- const handleMenuAction = (action: string) => {
199
- setMoreMenuOpen(false)
200
- switch (action) {
201
- case 'clear-all':
202
- onClearAll?.()
203
- break
204
- case 'close-others':
205
- onCloseOthers?.()
206
- break
207
- case 'export':
208
- onExport?.()
209
- break
210
- case 'copy-id':
211
- onCopyId?.()
212
- break
213
- case 'feedback':
214
- onFeedback?.()
215
- break
216
- case 'settings':
217
- onSettings?.()
218
- break
219
- }
220
- }
221
-
222
- return (
223
- <div className="chat-header">
224
- {/* 左侧:Tabs 可滚动区域 */}
225
- <div className="tabs-container">
226
- {visibleSessions.length === 0 ? (
227
- <span className="tab-item active">New Chat</span>
228
- ) : (
229
- visibleSessions.map((session) => {
230
- const isActive = session.id === currentSessionId
231
- return (
232
- <div
233
- key={session.id}
234
- className={`tab-item${isActive ? ' active' : ''}`}
235
- onClick={() => onSwitchSession?.(session.id)}
236
- title={session.title}
237
- >
238
- <span className="tab-title">{getDisplayTitle(session.title)}</span>
239
- <button
240
- className="tab-close"
241
- onClick={(e) => handleHideTab(session.id, e)}
242
- title="关闭标签"
243
- >
244
- <Icon icon="lucide:x" width={18} />
245
- </button>
246
- </div>
247
- )
248
- })
249
- )}
250
- </div>
251
-
252
- {/* 右侧:操作按钮 */}
253
- <div className="header-actions">
254
- {/* 新建会话 */}
255
- <button className="icon-btn" onClick={onNewSession} title="新建对话">
256
- <Icon icon="lucide:plus" width={18} />
257
- </button>
258
-
259
- {/* 历史记录 */}
260
- <div ref={historyRef} className="dropdown-container">
261
- <button
262
- className={`icon-btn${historyOpen ? ' active' : ''}`}
263
- onClick={(e) => {
264
- e.stopPropagation()
265
- toggleHistory()
266
- }}
267
- title="历史记录"
268
- >
269
- <Icon icon="lucide:clock" width={18} />
270
- </button>
271
-
272
- {/* 历史记录面板 */}
273
- {historyOpen && (
274
- <div className="dropdown-panel history-panel">
275
- <div className="panel-header">
276
- <span>历史记录</span>
277
- <button className="icon-btn small" title="新建对话" onClick={handleNewFromHistory}>
278
- <Icon icon="lucide:plus" width={18} />
279
- </button>
280
- </div>
281
- <div className="panel-content chat-scrollbar">
282
- {sessions.length === 0 ? (
283
- <div className="empty-state">暂无历史对话</div>
284
- ) : (
285
- groupSessionsByDate(sessions).map((group) => (
286
- <div key={group.label}>
287
- <div className="history-group-label">{group.label}</div>
288
- {group.sessions.map((session) => {
289
- const isCurrent = session.id === currentSessionId
290
- return (
291
- <div
292
- key={session.id}
293
- className={`history-item${isCurrent ? ' active' : ''}`}
294
- onClick={() => handleSelectHistory(session.id)}
295
- >
296
- <span className="history-title">{session.title}</span>
297
- <span className="history-time">{formatTime(session.updatedAt)}</span>
298
- <button
299
- className="history-action-btn delete"
300
- title="删除"
301
- onClick={(e) => handleDeleteSession(session.id, e)}
302
- >
303
- <Icon icon="lucide:trash-2" width={18} />
304
- </button>
305
- </div>
306
- )
307
- })}
308
- </div>
309
- ))
310
- )}
311
- </div>
312
- </div>
313
- )}
314
- </div>
315
-
316
- {/* 更多选项 */}
317
- <div ref={moreMenuRef} className="dropdown-container">
318
- <button
319
- className={`icon-btn${moreMenuOpen ? ' active' : ''}`}
320
- onClick={(e) => {
321
- e.stopPropagation()
322
- toggleMore()
323
- }}
324
- title="更多选项"
325
- >
326
- <Icon icon="lucide:more-horizontal" width={18} />
327
- </button>
328
-
329
- {/* 更多选项菜单 */}
330
- {moreMenuOpen && (
331
- <div className="dropdown-panel more-panel">
332
- <button className="menu-item" onClick={() => handleMenuAction('clear-all')}>
333
- <Icon icon="lucide:trash-2" width={18} />
334
- <span>清空所有对话</span>
335
- </button>
336
- <button className="menu-item" onClick={() => handleMenuAction('close-others')}>
337
- <Icon icon="lucide:x-circle" width={18} />
338
- <span>关闭其他对话</span>
339
- </button>
340
- <div className="menu-divider" />
341
- <button className="menu-item" onClick={() => handleMenuAction('export')}>
342
- <Icon icon="lucide:download" width={18} />
343
- <span>导出对话</span>
344
- </button>
345
- <button className="menu-item" onClick={() => handleMenuAction('copy-id')}>
346
- <Icon icon="lucide:copy" width={18} />
347
- <span>复制请求 ID</span>
348
- </button>
349
- <div className="menu-divider" />
350
- <button className="menu-item" onClick={() => handleMenuAction('feedback')}>
351
- <Icon icon="lucide:message-square" width={18} />
352
- <span>反馈</span>
353
- </button>
354
- <button className="menu-item" onClick={() => handleMenuAction('settings')}>
355
- <Icon icon="lucide:settings" width={18} />
356
- <span>Agent 设置</span>
357
- </button>
358
- </div>
359
- )}
360
- </div>
361
-
362
- {/* 关闭按钮 */}
363
- {showClose && (
364
- <button className="icon-btn" onClick={onClose} title="关闭">
365
- <Icon icon="lucide:x" width={18} />
366
- </button>
367
- )}
368
-
369
- {/* 设置按钮 */}
370
- <button className="icon-btn" onClick={onSettings} title="设置">
371
- <Icon icon="lucide:settings" width={18} />
372
- </button>
373
- </div>
374
- </div>
375
- )
376
- }