diff --git a/desktop/src/components/chat/AssistantMessage.tsx b/desktop/src/components/chat/AssistantMessage.tsx index 4c7f0d89..65ac2a74 100644 --- a/desktop/src/components/chat/AssistantMessage.tsx +++ b/desktop/src/components/chat/AssistantMessage.tsx @@ -9,8 +9,11 @@ type Props = { export function AssistantMessage({ content, isStreaming }: Props) { return ( -
-
+
+
{!isStreaming && } @@ -18,12 +21,13 @@ export function AssistantMessage({ content, isStreaming }: Props) { )}
-
- + +
) } diff --git a/desktop/src/components/chat/MessageActionBar.tsx b/desktop/src/components/chat/MessageActionBar.tsx index 00c941d8..34070cae 100644 --- a/desktop/src/components/chat/MessageActionBar.tsx +++ b/desktop/src/components/chat/MessageActionBar.tsx @@ -5,6 +5,7 @@ type Props = { copyLabel: string onRewind?: () => void rewindLabel?: string + align?: 'start' | 'end' } export function MessageActionBar({ @@ -12,6 +13,7 @@ export function MessageActionBar({ copyLabel, onRewind, rewindLabel = 'Rewind to here', + align = 'start', }: Props) { const hasCopy = Boolean(copyText?.trim()) const hasRewind = Boolean(onRewind) @@ -19,7 +21,13 @@ export function MessageActionBar({ if (!hasCopy && !hasRewind) return null return ( -
+
{hasRewind && (
diff --git a/desktop/src/components/chat/MessageList.test.tsx b/desktop/src/components/chat/MessageList.test.tsx index 09e8866d..9e46d5c8 100644 --- a/desktop/src/components/chat/MessageList.test.tsx +++ b/desktop/src/components/chat/MessageList.test.tsx @@ -338,6 +338,43 @@ describe('MessageList nested tool calls', () => { ) }) + it('keeps user actions anchored to the right bubble and assistant actions to the left bubble', () => { + useChatStore.setState({ + sessions: { + [ACTIVE_TAB]: makeSessionState({ + messages: [ + { + id: 'user-1', + type: 'user_text', + content: '请把这条 prompt 放在右侧', + timestamp: 1, + }, + { + id: 'assistant-1', + type: 'assistant_text', + content: '这条回复应该停在左侧。', + timestamp: 2, + }, + ], + }), + }, + }) + + render() + + const userShell = screen.getByText('请把这条 prompt 放在右侧').closest('[data-message-shell="user"]') + const assistantShell = screen.getByText('这条回复应该停在左侧。').closest('[data-message-shell="assistant"]') + const userActions = screen.getByRole('button', { name: 'Copy prompt' }).closest('[data-message-actions]') + const assistantActions = screen.getByRole('button', { name: 'Copy reply' }).closest('[data-message-actions]') + + expect(userShell).toBeTruthy() + expect(userShell?.className).toContain('items-end') + expect(assistantShell).toBeTruthy() + expect(assistantShell?.className).toContain('items-start') + expect(userActions?.getAttribute('data-align')).toBe('end') + expect(assistantActions?.getAttribute('data-align')).toBe('start') + }) + it('opens a rewind preview modal for user messages', async () => { vi.spyOn(sessionsApi, 'rewind').mockResolvedValue({ target: { diff --git a/desktop/src/components/chat/UserMessage.tsx b/desktop/src/components/chat/UserMessage.tsx index 58b7f98e..729ed489 100644 --- a/desktop/src/components/chat/UserMessage.tsx +++ b/desktop/src/components/chat/UserMessage.tsx @@ -13,8 +13,11 @@ export function UserMessage({ content, attachments, onRewind, rewindLabel }: Pro const hasText = content.trim().length > 0 return ( -
-
+
+
{attachments && attachments.length > 0 && ( )} @@ -27,16 +30,17 @@ export function UserMessage({ content, attachments, onRewind, rewindLabel }: Pro {content}
)} -
- {hasText && ( - - )} + {hasText && ( + + )} +
) } diff --git a/desktop/src/components/plugins/PluginList.tsx b/desktop/src/components/plugins/PluginList.tsx index 273a44bd..7d8df76a 100644 --- a/desktop/src/components/plugins/PluginList.tsx +++ b/desktop/src/components/plugins/PluginList.tsx @@ -102,7 +102,7 @@ export function PluginList() { return (
-
+
{t('settings.plugins.browserEyebrow')} @@ -129,8 +129,8 @@ export function PluginList() { )}
-
-
+
+
-
- - @@ -316,12 +326,14 @@ function SummaryCard({ icon: string }) { return ( -
-
+
+
{icon} - {label} + + {label} +
-
+
{value}