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 7149be502c..8343ef1db6 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 @@ -174,10 +174,10 @@ export class AIChatContent extends SignalWatcher( accessor isHistoryLoading = false; @state() - accessor showPreviewPanel = false; + private accessor showPreviewPanel = false; @state() - accessor previewPanelContent: TemplateResult<1> | null = null; + private accessor previewPanelContent: TemplateResult<1> | null = null; private readonly chatMessagesRef: Ref = createRef(); @@ -338,8 +338,23 @@ export class AIChatContent extends SignalWatcher( public reset() { this.updateContext(DEFAULT_CHAT_CONTEXT_VALUE); + this.closePreviewPanel(true); + } + + public openPreviewPanel(content?: TemplateResult<1>) { + this.showPreviewPanel = true; + if (content) this.previewPanelContent = content; + AIProvider.slots.previewPanelOpenChange.next(true); + } + + public closePreviewPanel(destroyContent: boolean = false) { this.showPreviewPanel = false; - this.previewPanelContent = null; + if (destroyContent) this.previewPanelContent = null; + AIProvider.slots.previewPanelOpenChange.next(false); + } + + public get isPreviewPanelOpen() { + return this.showPreviewPanel; } override connectedCallback() { 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 85a98477ea..34eb72e7e3 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 @@ -13,7 +13,7 @@ function getChatPanel(target: HTMLElement) { export const isPreviewPanelOpen = (target: HTMLElement) => { const chatPanel = getChatPanel(target); - return chatPanel?.showPreviewPanel ?? false; + return chatPanel?.isPreviewPanelOpen ?? false; }; export const renderPreviewPanel = ( @@ -28,13 +28,11 @@ export const renderPreviewPanel = ( return; } - chatPanel.showPreviewPanel = true; - const preview = html``; - chatPanel.previewPanelContent = preview; + chatPanel.openPreviewPanel(preview); }; export const closePreviewPanel = (target: HTMLElement) => { @@ -45,7 +43,7 @@ export const closePreviewPanel = (target: HTMLElement) => { return; } - chatPanel.showPreviewPanel = false; + chatPanel.closePreviewPanel(); }; export class ArtifactPreviewPanel extends WithDisposable(ShadowlessElement) { diff --git a/packages/frontend/core/src/blocksuite/ai/provider/ai-provider.ts b/packages/frontend/core/src/blocksuite/ai/provider/ai-provider.ts index c2d81ebec3..7fbf899a3a 100644 --- a/packages/frontend/core/src/blocksuite/ai/provider/ai-provider.ts +++ b/packages/frontend/core/src/blocksuite/ai/provider/ai-provider.ts @@ -149,6 +149,7 @@ export class AIProvider { }>(), // downstream can emit this slot to notify ai presets that user info has been updated userInfo: new Subject(), + previewPanelOpenChange: new Subject(), /* eslint-enable rxjs/finnish */ }; diff --git a/packages/frontend/core/src/desktop/pages/workspace/detail-page/tabs/chat.tsx b/packages/frontend/core/src/desktop/pages/workspace/detail-page/tabs/chat.tsx index 31460e9f81..d6def17689 100644 --- a/packages/frontend/core/src/desktop/pages/workspace/detail-page/tabs/chat.tsx +++ b/packages/frontend/core/src/desktop/pages/workspace/detail-page/tabs/chat.tsx @@ -1,4 +1,4 @@ -import { ChatPanel } from '@affine/core/blocksuite/ai'; +import { AIProvider, ChatPanel } from '@affine/core/blocksuite/ai'; import type { AffineEditorContainer } from '@affine/core/blocksuite/block-suite-editor'; import { useAIChatConfig } from '@affine/core/components/hooks/affine/use-ai-chat-config'; import { WorkspaceDialogService } from '@affine/core/modules/dialogs'; @@ -8,8 +8,8 @@ import { ViewExtensionManagerIdentifier } from '@blocksuite/affine/ext-loader'; import { RefNodeSlotsProvider } from '@blocksuite/affine/inlines/reference'; import { DocModeProvider } from '@blocksuite/affine/shared/services'; import { createSignalFromObservable } from '@blocksuite/affine/shared/utils'; -import { useFramework } from '@toeverything/infra'; -import { forwardRef, useEffect, useRef } from 'react'; +import { useFramework, useService } from '@toeverything/infra'; +import { forwardRef, useEffect, useRef, useState } from 'react'; import * as styles from './chat.css'; @@ -25,6 +25,7 @@ export const EditorChatPanel = forwardRef(function EditorChatPanel( ) { const chatPanelRef = useRef(null); const containerRef = useRef(null); + const workbench = useService(WorkbenchService).workbench; const framework = useFramework(); useEffect(() => { @@ -118,5 +119,25 @@ export const EditorChatPanel = forwardRef(function EditorChatPanel( playgroundConfig, ]); + const [autoResized, setAutoResized] = useState(false); + useEffect(() => { + // after auto expanded first time, do not auto expand again(even if user manually resized) + if (autoResized) return; + const subscription = AIProvider.slots.previewPanelOpenChange.subscribe( + open => { + if (!open) return; + const sidebarWidth = workbench.sidebarWidth$.value; + const MIN_SIDEBAR_WIDTH = 1080; + if (!sidebarWidth || sidebarWidth < MIN_SIDEBAR_WIDTH) { + workbench.setSidebarWidth(MIN_SIDEBAR_WIDTH); + setAutoResized(true); + } + } + ); + return () => { + subscription.unsubscribe(); + }; + }, [autoResized, workbench]); + return
; }); diff --git a/packages/frontend/core/src/modules/workbench/view/workbench-root.tsx b/packages/frontend/core/src/modules/workbench/view/workbench-root.tsx index 10de067cdd..f828cc2fcb 100644 --- a/packages/frontend/core/src/modules/workbench/view/workbench-root.tsx +++ b/packages/frontend/core/src/modules/workbench/view/workbench-root.tsx @@ -117,6 +117,7 @@ const WorkbenchSidebar = () => { const [resizing, setResizing] = useState(false); const workbench = useService(WorkbenchService).workbench; + const sidebarWidth = useLiveData(workbench.sidebarWidth$); const [width, setWidth] = useState(workbench.sidebarWidth$.value ?? 0); const views = useLiveData(workbench.views$); @@ -152,6 +153,11 @@ const WorkbenchSidebar = () => { }; }, []); + useEffect(() => { + if (resizing) return; + setWidth(sidebarWidth ?? 0); + }, [resizing, sidebarWidth]); + return (