From 882d06b359f5a9c4ca77b790d5f797325a2d8cd4 Mon Sep 17 00:00:00 2001 From: Cats Juice Date: Fri, 4 Jul 2025 16:00:24 +0800 Subject: [PATCH] fix(core): re-layout ai-chat-content to display preview panel (#13030) ## Summary by CodeRabbit * **New Features** * Introduced a split-view layout in the AI chat, allowing chat content and a preview panel to be displayed side-by-side. * Added responsive padding and layout adjustments for improved chat panel appearance. * **Refactor** * Simplified the chat panel by removing the previous preview panel feature and related state from the main chat component. * Updated internal logic to support the new split-view structure. * **Style** * Adjusted chat panel and workspace chat page styles for better layout consistency and responsiveness. * **Chores** * Improved code organization and import statements for maintainability. --- .../src/blocksuite/ai/chat-panel/index.ts | 32 +-------------- .../blocksuite/ai/chat-panel/split-view.ts | 3 +- .../ai-chat-content/ai-chat-content.ts | 40 ++++++++++++++++++- .../ai-tools/artifacts-preview-panel.ts | 4 +- .../desktop/pages/workspace/chat/index.css.ts | 3 -- .../desktop/pages/workspace/chat/index.tsx | 18 +++++---- 6 files changed, 56 insertions(+), 44 deletions(-) diff --git a/packages/frontend/core/src/blocksuite/ai/chat-panel/index.ts b/packages/frontend/core/src/blocksuite/ai/chat-panel/index.ts index d7c0e4fdf..7b1d4867e 100644 --- a/packages/frontend/core/src/blocksuite/ai/chat-panel/index.ts +++ b/packages/frontend/core/src/blocksuite/ai/chat-panel/index.ts @@ -13,16 +13,9 @@ import { ShadowlessElement } from '@blocksuite/affine/std'; import type { ExtensionType, Store } from '@blocksuite/affine/store'; import { CenterPeekIcon } from '@blocksuite/icons/lit'; import { type Signal, signal } from '@preact/signals-core'; -import { - css, - html, - nothing, - type PropertyValues, - type TemplateResult, -} from 'lit'; +import { css, html, nothing, type PropertyValues } from 'lit'; import { property, state } from 'lit/decorators.js'; import { keyed } from 'lit/directives/keyed.js'; -import { styleMap } from 'lit/directives/style-map.js'; import type { DocDisplayConfig, @@ -111,12 +104,6 @@ export class ChatPanel extends SignalWatcher( @state() accessor embeddingProgress: [number, number] = [0, 0]; - @state() - accessor showPreviewPanel = false; - - @state() - accessor previewPanelContent: TemplateResult<1> | null = null; - private isSidebarOpen: Signal = signal(false); private sidebarWidth: Signal = signal(undefined); @@ -269,7 +256,6 @@ export class ChatPanel extends SignalWatcher( private readonly resetPanel = () => { this.session = undefined; this.embeddingProgress = [0, 0]; - this.showPreviewPanel = false; this.hasPinned = false; }; @@ -350,12 +336,7 @@ export class ChatPanel extends SignalWatcher( return nothing; } - const width = this.sidebarWidth.value || 0; - const style = styleMap({ - padding: width > 540 ? '8px 24px 0 24px' : '8px 12px 0 12px', - }); - - const left = html`
+ return html`
${keyed( this.hasPinned ? this.session?.id : this.doc.id, html`` )}
`; - - const right = this.previewPanelContent; - - return html` - `; } } diff --git a/packages/frontend/core/src/blocksuite/ai/chat-panel/split-view.ts b/packages/frontend/core/src/blocksuite/ai/chat-panel/split-view.ts index 04ac40be6..a38821071 100644 --- a/packages/frontend/core/src/blocksuite/ai/chat-panel/split-view.ts +++ b/packages/frontend/core/src/blocksuite/ai/chat-panel/split-view.ts @@ -46,7 +46,8 @@ export class ChatPanelSplitView extends SignalWatcher( width: var(--gap); position: relative; } - .ai-chat-panel-split-view-divider[data-open='false'] { + .ai-chat-panel-split-view[data-open='false'] + .ai-chat-panel-split-view-divider { width: 0; visibility: hidden; pointer-events: none; diff --git a/packages/frontend/core/src/blocksuite/ai/components/ai-chat-content/ai-chat-content.ts b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-content/ai-chat-content.ts index 9809ac995..7149be502 100644 --- a/packages/frontend/core/src/blocksuite/ai/components/ai-chat-content/ai-chat-content.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/ai-chat-content/ai-chat-content.ts @@ -88,6 +88,27 @@ export class AIChatContent extends SignalWatcher( overflow-y: visible; } } + chat-panel-split-view { + height: 100%; + width: 100%; + container-type: inline-size; + container-name: chat-panel-split-view; + } + .chat-panel-main { + display: flex; + flex-direction: column; + justify-content: center; + height: 100%; + width: 100%; + padding: 8px 24px 0 24px; + max-width: 800px; + margin: 0 auto; + } + @container chat-panel-split-view (width < 540px) { + .chat-panel-main { + padding: 8px 12px 0 12px; + } + } `; @property({ attribute: false }) @@ -152,6 +173,12 @@ export class AIChatContent extends SignalWatcher( @state() accessor isHistoryLoading = false; + @state() + accessor showPreviewPanel = false; + + @state() + accessor previewPanelContent: TemplateResult<1> | null = null; + private readonly chatMessagesRef: Ref = createRef(); @@ -311,6 +338,8 @@ export class AIChatContent extends SignalWatcher( public reset() { this.updateContext(DEFAULT_CHAT_CONTEXT_VALUE); + this.showPreviewPanel = false; + this.previewPanelContent = null; } override connectedCallback() { @@ -349,7 +378,7 @@ export class AIChatContent extends SignalWatcher( } override render() { - return html`${this.chatTitle + const left = html`${this.chatTitle ? html`
${this.chatTitle}
` : nothing} `; + + const right = this.previewPanelContent; + + return html`${left}
`} + .right=${right} + .open=${this.showPreviewPanel} + > + `; } } diff --git a/packages/frontend/core/src/blocksuite/ai/components/ai-tools/artifacts-preview-panel.ts b/packages/frontend/core/src/blocksuite/ai/components/ai-tools/artifacts-preview-panel.ts index 694707d38..85a98477e 100644 --- a/packages/frontend/core/src/blocksuite/ai/components/ai-tools/artifacts-preview-panel.ts +++ b/packages/frontend/core/src/blocksuite/ai/components/ai-tools/artifacts-preview-panel.ts @@ -5,8 +5,10 @@ import { EmptyIcon } from '@blocksuite/icons/lit'; import { css, html, nothing, type TemplateResult } from 'lit'; import { property } from 'lit/decorators.js'; +import type { AIChatContent } from '../ai-chat-content'; + function getChatPanel(target: HTMLElement) { - return target.closest('chat-panel'); + return target.closest('ai-chat-content') as AIChatContent; } export const isPreviewPanelOpen = (target: HTMLElement) => { diff --git a/packages/frontend/core/src/desktop/pages/workspace/chat/index.css.ts b/packages/frontend/core/src/desktop/pages/workspace/chat/index.css.ts index 83b061181..d72cd8071 100644 --- a/packages/frontend/core/src/desktop/pages/workspace/chat/index.css.ts +++ b/packages/frontend/core/src/desktop/pages/workspace/chat/index.css.ts @@ -3,9 +3,6 @@ import { style } from '@vanilla-extract/css'; export const chatRoot = style({ width: '100%', height: '100%', - maxWidth: 800, - padding: '0px 16px', - margin: '0 auto', }); export const chatHeader = style({ diff --git a/packages/frontend/core/src/desktop/pages/workspace/chat/index.tsx b/packages/frontend/core/src/desktop/pages/workspace/chat/index.tsx index fb89eb7a4..f02fb9781 100644 --- a/packages/frontend/core/src/desktop/pages/workspace/chat/index.tsx +++ b/packages/frontend/core/src/desktop/pages/workspace/chat/index.tsx @@ -188,16 +188,18 @@ export const Component = () => { tool.session = currentSession; + tool.onNewSession = () => { + if (!currentSession) return; + setCurrentSession(null); + chatContent?.reset(); + }; + + tool.onTogglePin = async () => { + await togglePin(); + }; + // initial props if (!chatTool) { - tool.onNewSession = () => { - if (!currentSession) return; - setCurrentSession(null); - chatContent?.reset(); - }; - tool.onTogglePin = async () => { - await togglePin(); - }; // mount chatToolContainerRef.current.append(tool); setChatTool(tool);