diff --git a/packages/frontend/core/src/blocksuite/ai/chat-panel/chat-panel-messages.ts b/packages/frontend/core/src/blocksuite/ai/chat-panel/chat-panel-messages.ts
index 6ccd8f1d26..1e642c0bd0 100644
--- a/packages/frontend/core/src/blocksuite/ai/chat-panel/chat-panel-messages.ts
+++ b/packages/frontend/core/src/blocksuite/ai/chat-panel/chat-panel-messages.ts
@@ -114,10 +114,6 @@ export class ChatPanelMessages extends WithDisposable(ShadowlessElement) {
white-space: nowrap;
}
- .message {
- display: contents;
- }
-
.down-indicator {
position: absolute;
left: 50%;
@@ -249,25 +245,20 @@ export class ChatPanelMessages extends WithDisposable(ShadowlessElement) {
(_, index) => index,
(item, index) => {
const isLast = index === filteredItems.length - 1;
- return html`
- ${isChatMessage(item) && item.role === 'user'
- ? html``
- : html` this.retry()}
- >`}
-
`;
+ return isChatMessage(item) && item.role === 'user'
+ ? html``
+ : html` this.retry()}
+ >`;
}
)}
diff --git a/packages/frontend/core/src/blocksuite/ai/chat-panel/chat-panel-user-message.ts b/packages/frontend/core/src/blocksuite/ai/chat-panel/chat-panel-user-message.ts
index 784a93d6c4..8715bd9041 100644
--- a/packages/frontend/core/src/blocksuite/ai/chat-panel/chat-panel-user-message.ts
+++ b/packages/frontend/core/src/blocksuite/ai/chat-panel/chat-panel-user-message.ts
@@ -1,77 +1,100 @@
-import type { EditorHost } from '@blocksuite/affine/block-std';
import { ShadowlessElement } from '@blocksuite/affine/block-std';
import { WithDisposable } from '@blocksuite/affine/global/lit';
import { css, html, nothing } from 'lit';
import { property } from 'lit/decorators.js';
+import { repeat } from 'lit/directives/repeat.js';
-import { type ChatItem, isChatMessage } from './chat-context';
+import { type ChatMessage } from './chat-context';
export class ChatPanelUserMessage extends WithDisposable(ShadowlessElement) {
static override styles = css`
- .avatar-container {
- width: 24px;
- height: 24px;
- }
+ .chat-user-message {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-end;
- .avatar {
- width: 100%;
- height: 100%;
- border-radius: 50%;
- background-color: var(--affine-primary-color);
- }
+ .images {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: nowrap;
+ gap: 8px;
+ margin-bottom: 8px;
+ max-width: 100%;
+ overflow-x: auto;
+ padding: 4px;
+ scrollbar-width: auto;
+ }
- .avatar-container img {
- width: 100%;
- height: 100%;
- border-radius: 50%;
- object-fit: cover;
+ .images::-webkit-scrollbar {
+ height: 4px;
+ }
+
+ .images::-webkit-scrollbar-thumb {
+ background-color: var(--affine-border-color);
+ border-radius: 4px;
+ }
+
+ .images::-webkit-scrollbar-track {
+ background: transparent;
+ }
+
+ img {
+ max-width: 180px;
+ max-height: 264px;
+ object-fit: cover;
+ border-radius: 8px;
+ flex-shrink: 0;
+ }
+
+ .text-content {
+ display: inline-block;
+ text-align: left;
+ max-width: 800px;
+ max-height: 500px;
+ overflow-y: auto;
+ background: var(--affine-v2-aI-userTextBackground);
+ border-radius: 8px;
+ padding: 12px;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+ }
}
`;
@property({ attribute: false })
- accessor host!: EditorHost;
+ accessor item!: ChatMessage;
- @property({ attribute: false })
- accessor item!: ChatItem;
+ renderImages(images: string[]) {
+ return images.length > 0
+ ? html`
+ ${repeat(
+ images,
+ image => image,
+ image => {
+ return html`

`;
+ }
+ )}
+
`
+ : nothing;
+ }
- @property({ attribute: false })
- accessor avatarUrl: string = '';
-
- @property({ attribute: false })
- accessor previewSpecBuilder: any;
-
- renderAvatar() {
- return html`
-
- ${this.avatarUrl
- ? html`
![]()
`
- : html`
`}
-
- You
-
`;
+ renderText(text: string) {
+ return text.length > 0
+ ? html`${text}
`
+ : nothing;
}
renderContent() {
- const { host, item } = this;
+ const { item } = this;
- if (isChatMessage(item)) {
- return html``;
- }
-
- return nothing;
+ const imagesRendered = item.attachments
+ ? this.renderImages(item.attachments)
+ : nothing;
+ return html` ${imagesRendered} ${this.renderText(item.content)} `;
}
protected override render() {
- return html`
- ${this.renderAvatar()}
- ${this.renderContent()}
- `;
+ return html` ${this.renderContent()}
`;
}
}
diff --git a/tests/affine-cloud-copilot/e2e/copilot.spec.ts b/tests/affine-cloud-copilot/e2e/copilot.spec.ts
index 086771cd5f..f7b24b6fb2 100644
--- a/tests/affine-cloud-copilot/e2e/copilot.spec.ts
+++ b/tests/affine-cloud-copilot/e2e/copilot.spec.ts
@@ -106,13 +106,25 @@ const clearChat = async (page: Page) => {
const collectHistory = async (page: Page) => {
const chatPanel = await page.waitForSelector('.chat-panel-messages');
return Promise.all(
- Array.from(await chatPanel.$$('.message')).map(async m => ({
- name: await m.$('.user-info').then(i => i?.innerText()),
- content: await m
- .$('chat-text')
- .then(t => t?.$('editor-host'))
- .then(e => e?.innerText()),
- }))
+ Array.from(
+ await chatPanel.$$('chat-panel-user-message,chat-panel-assistant-message')
+ ).map(async m => {
+ const isAssistant = await m.evaluate(
+ el => el.tagName === 'CHAT-PANEL-ASSISTANT-MESSAGE'
+ );
+ return isAssistant
+ ? {
+ name: await m.$('.user-info').then(i => i?.innerText()),
+ content: await m
+ .$('chat-text')
+ .then(t => t?.$('editor-host'))
+ .then(e => e?.innerText()),
+ }
+ : {
+ name: 'You',
+ content: await m.$('.text-content').then(i => i?.innerText()),
+ };
+ })
);
};
@@ -123,12 +135,17 @@ const collectChat = async (page: Page) => {
return [];
}
// wait ai response
- await page.waitForSelector('.chat-panel-messages .message chat-copy-more', {
- timeout: ONE_MINUTE,
- });
+ await page.waitForSelector(
+ '.chat-panel-messages chat-panel-assistant-message chat-copy-more',
+ {
+ timeout: ONE_MINUTE,
+ }
+ );
await page.waitForTimeout(200);
- const lastMessage = await chatPanel.$$('.message').then(m => m[m.length - 1]);
- await lastMessage.waitForSelector('chat-copy-more');
+ await page
+ .locator('.chat-panel-messages > chat-panel-assistant-message')
+ .last()
+ .locator('chat-copy-more');
await page.waitForTimeout(200);
return collectHistory(page);
};