mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-09-24 04:27:27 +08:00
feat(core): auto expand workbench sidebar when opening ai preview panel (#13058)
<!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added the ability to programmatically open and close the AI chat preview panel, with improved control over its visibility and content. * Introduced event notifications for preview panel open/close actions, enabling responsive UI updates. * **Enhancements** * Automatically adjusts the sidebar width to a minimum value when the preview panel is opened for optimal viewing. * Improved synchronization between sidebar width and external changes, ensuring a consistent user experience. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
+18
-3
@@ -174,10 +174,10 @@ export class AIChatContent extends SignalWatcher(
|
|||||||
accessor isHistoryLoading = false;
|
accessor isHistoryLoading = false;
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
accessor showPreviewPanel = false;
|
private accessor showPreviewPanel = false;
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
accessor previewPanelContent: TemplateResult<1> | null = null;
|
private accessor previewPanelContent: TemplateResult<1> | null = null;
|
||||||
|
|
||||||
private readonly chatMessagesRef: Ref<AIChatMessages> =
|
private readonly chatMessagesRef: Ref<AIChatMessages> =
|
||||||
createRef<AIChatMessages>();
|
createRef<AIChatMessages>();
|
||||||
@@ -338,8 +338,23 @@ export class AIChatContent extends SignalWatcher(
|
|||||||
|
|
||||||
public reset() {
|
public reset() {
|
||||||
this.updateContext(DEFAULT_CHAT_CONTEXT_VALUE);
|
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.showPreviewPanel = false;
|
||||||
this.previewPanelContent = null;
|
if (destroyContent) this.previewPanelContent = null;
|
||||||
|
AIProvider.slots.previewPanelOpenChange.next(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isPreviewPanelOpen() {
|
||||||
|
return this.showPreviewPanel;
|
||||||
}
|
}
|
||||||
|
|
||||||
override connectedCallback() {
|
override connectedCallback() {
|
||||||
|
|||||||
+3
-5
@@ -13,7 +13,7 @@ function getChatPanel(target: HTMLElement) {
|
|||||||
|
|
||||||
export const isPreviewPanelOpen = (target: HTMLElement) => {
|
export const isPreviewPanelOpen = (target: HTMLElement) => {
|
||||||
const chatPanel = getChatPanel(target);
|
const chatPanel = getChatPanel(target);
|
||||||
return chatPanel?.showPreviewPanel ?? false;
|
return chatPanel?.isPreviewPanelOpen ?? false;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const renderPreviewPanel = (
|
export const renderPreviewPanel = (
|
||||||
@@ -28,13 +28,11 @@ export const renderPreviewPanel = (
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
chatPanel.showPreviewPanel = true;
|
|
||||||
|
|
||||||
const preview = html`<artifact-preview-panel
|
const preview = html`<artifact-preview-panel
|
||||||
.content=${content}
|
.content=${content}
|
||||||
.controls=${controls ?? nothing}
|
.controls=${controls ?? nothing}
|
||||||
></artifact-preview-panel>`;
|
></artifact-preview-panel>`;
|
||||||
chatPanel.previewPanelContent = preview;
|
chatPanel.openPreviewPanel(preview);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const closePreviewPanel = (target: HTMLElement) => {
|
export const closePreviewPanel = (target: HTMLElement) => {
|
||||||
@@ -45,7 +43,7 @@ export const closePreviewPanel = (target: HTMLElement) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
chatPanel.showPreviewPanel = false;
|
chatPanel.closePreviewPanel();
|
||||||
};
|
};
|
||||||
|
|
||||||
export class ArtifactPreviewPanel extends WithDisposable(ShadowlessElement) {
|
export class ArtifactPreviewPanel extends WithDisposable(ShadowlessElement) {
|
||||||
|
|||||||
@@ -149,6 +149,7 @@ export class AIProvider {
|
|||||||
}>(),
|
}>(),
|
||||||
// downstream can emit this slot to notify ai presets that user info has been updated
|
// downstream can emit this slot to notify ai presets that user info has been updated
|
||||||
userInfo: new Subject<AIUserInfo | null>(),
|
userInfo: new Subject<AIUserInfo | null>(),
|
||||||
|
previewPanelOpenChange: new Subject<boolean>(),
|
||||||
/* eslint-enable rxjs/finnish */
|
/* eslint-enable rxjs/finnish */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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 type { AffineEditorContainer } from '@affine/core/blocksuite/block-suite-editor';
|
||||||
import { useAIChatConfig } from '@affine/core/components/hooks/affine/use-ai-chat-config';
|
import { useAIChatConfig } from '@affine/core/components/hooks/affine/use-ai-chat-config';
|
||||||
import { WorkspaceDialogService } from '@affine/core/modules/dialogs';
|
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 { RefNodeSlotsProvider } from '@blocksuite/affine/inlines/reference';
|
||||||
import { DocModeProvider } from '@blocksuite/affine/shared/services';
|
import { DocModeProvider } from '@blocksuite/affine/shared/services';
|
||||||
import { createSignalFromObservable } from '@blocksuite/affine/shared/utils';
|
import { createSignalFromObservable } from '@blocksuite/affine/shared/utils';
|
||||||
import { useFramework } from '@toeverything/infra';
|
import { useFramework, useService } from '@toeverything/infra';
|
||||||
import { forwardRef, useEffect, useRef } from 'react';
|
import { forwardRef, useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
import * as styles from './chat.css';
|
import * as styles from './chat.css';
|
||||||
|
|
||||||
@@ -25,6 +25,7 @@ export const EditorChatPanel = forwardRef(function EditorChatPanel(
|
|||||||
) {
|
) {
|
||||||
const chatPanelRef = useRef<ChatPanel | null>(null);
|
const chatPanelRef = useRef<ChatPanel | null>(null);
|
||||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||||
|
const workbench = useService(WorkbenchService).workbench;
|
||||||
const framework = useFramework();
|
const framework = useFramework();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -118,5 +119,25 @@ export const EditorChatPanel = forwardRef(function EditorChatPanel(
|
|||||||
playgroundConfig,
|
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 <div className={styles.root} ref={containerRef} />;
|
return <div className={styles.root} ref={containerRef} />;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -117,6 +117,7 @@ const WorkbenchSidebar = () => {
|
|||||||
const [resizing, setResizing] = useState(false);
|
const [resizing, setResizing] = useState(false);
|
||||||
|
|
||||||
const workbench = useService(WorkbenchService).workbench;
|
const workbench = useService(WorkbenchService).workbench;
|
||||||
|
const sidebarWidth = useLiveData(workbench.sidebarWidth$);
|
||||||
const [width, setWidth] = useState(workbench.sidebarWidth$.value ?? 0);
|
const [width, setWidth] = useState(workbench.sidebarWidth$.value ?? 0);
|
||||||
|
|
||||||
const views = useLiveData(workbench.views$);
|
const views = useLiveData(workbench.views$);
|
||||||
@@ -152,6 +153,11 @@ const WorkbenchSidebar = () => {
|
|||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (resizing) return;
|
||||||
|
setWidth(sidebarWidth ?? 0);
|
||||||
|
}, [resizing, sidebarWidth]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ResizePanel
|
<ResizePanel
|
||||||
floating={floating}
|
floating={floating}
|
||||||
|
|||||||
Reference in New Issue
Block a user