mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-15 00:56:26 +08:00
refactor(core): simplify chat panel user message rendering (#10910)
### TL;DR Refactor style of user chat message > CLOSE AF-2323 AF-2324 AF-2325 ### What Changed * Refactor style of user message. * Refactor style of image message.
This commit is contained in:
@@ -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`<div class="message">
|
||||
${isChatMessage(item) && item.role === 'user'
|
||||
? html`<chat-panel-user-message
|
||||
.host=${this.host}
|
||||
.item=${item}
|
||||
.avatarUrl=${this.avatarUrl}
|
||||
.previewSpecBuilder=${this.previewSpecBuilder}
|
||||
></chat-panel-user-message>`
|
||||
: html`<chat-panel-assistant-message
|
||||
.host=${this.host}
|
||||
.item=${item}
|
||||
.isLast=${isLast}
|
||||
.status=${status}
|
||||
.error=${error}
|
||||
.previewSpecBuilder=${this.previewSpecBuilder}
|
||||
.getSessionId=${this.getSessionId}
|
||||
.retry=${() => this.retry()}
|
||||
></chat-panel-assistant-message>`}
|
||||
</div>`;
|
||||
return isChatMessage(item) && item.role === 'user'
|
||||
? html`<chat-panel-user-message
|
||||
.item=${item}
|
||||
></chat-panel-user-message>`
|
||||
: html`<chat-panel-assistant-message
|
||||
.host=${this.host}
|
||||
.item=${item}
|
||||
.isLast=${isLast}
|
||||
.status=${status}
|
||||
.error=${error}
|
||||
.previewSpecBuilder=${this.previewSpecBuilder}
|
||||
.getSessionId=${this.getSessionId}
|
||||
.retry=${() => this.retry()}
|
||||
></chat-panel-assistant-message>`;
|
||||
}
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -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`<div class="images">
|
||||
${repeat(
|
||||
images,
|
||||
image => image,
|
||||
image => {
|
||||
return html`<img src="${image}" />`;
|
||||
}
|
||||
)}
|
||||
</div>`
|
||||
: nothing;
|
||||
}
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor avatarUrl: string = '';
|
||||
|
||||
@property({ attribute: false })
|
||||
accessor previewSpecBuilder: any;
|
||||
|
||||
renderAvatar() {
|
||||
return html`<div class="user-info">
|
||||
<div class="avatar-container">
|
||||
${this.avatarUrl
|
||||
? html`<img .src=${this.avatarUrl} />`
|
||||
: html`<div class="avatar"></div>`}
|
||||
</div>
|
||||
You
|
||||
</div>`;
|
||||
renderText(text: string) {
|
||||
return text.length > 0
|
||||
? html`<div class="text-content">${text}</div>`
|
||||
: nothing;
|
||||
}
|
||||
|
||||
renderContent() {
|
||||
const { host, item } = this;
|
||||
const { item } = this;
|
||||
|
||||
if (isChatMessage(item)) {
|
||||
return html`<chat-text
|
||||
.host=${host}
|
||||
.attachments=${item.attachments}
|
||||
.text=${item.content}
|
||||
.state=${'finished'}
|
||||
.previewSpecBuilder=${this.previewSpecBuilder}
|
||||
></chat-text>`;
|
||||
}
|
||||
|
||||
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()}
|
||||
<div class="item-wrapper">${this.renderContent()}</div>
|
||||
`;
|
||||
return html` <div class="chat-user-message">${this.renderContent()}</div> `;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user