feat: redesign Canvas plan and reference flow

This commit is contained in:
inman
2026-09-07 10:06:38 +08:00
parent f8eee430f4
commit 1562a49ff1
18 changed files with 2141 additions and 1057 deletions

View File

@@ -36,6 +36,7 @@ export function MainLayout() {
const isProgrammingModule = activeModule === 'programming';
const isPaintingModule = activeModule === 'painting';
const isPromptMuseum = location.pathname === '/image-prompts' || location.pathname.startsWith('/image-prompts/');
const isCanvasWorkspace = location.pathname === '/image-canvas';
const isChatWorkspace = location.pathname === '/chat';
const isInitializationSafeRoute = location.pathname === '/project-config'
|| location.pathname === '/plugins'
@@ -96,6 +97,7 @@ export function MainLayout() {
integrated
workspaceLayout={isChatWorkspace}
overlay={isPaintingModule && !isPromptMuseum}
showSidebarControls={!isCanvasWorkspace}
pageTitle={isPromptMuseum ? '获取灵感' : undefined}
sidebarPeekOpen={sidebarPeekOpen}
onSidebarPeekChange={handleSidebarPeekChange}
@@ -103,11 +105,13 @@ export function MainLayout() {
{/* Below the title bar: sidebar + content */}
<div className="relative flex min-h-0 flex-1 overflow-hidden">
<Sidebar
workspaceLayout={isChatWorkspace}
sidebarPeekOpen={sidebarPeekOpen}
onSidebarPeekChange={handleSidebarPeekChange}
/>
{!isCanvasWorkspace ? (
<Sidebar
workspaceLayout={isChatWorkspace}
sidebarPeekOpen={sidebarPeekOpen}
onSidebarPeekChange={handleSidebarPeekChange}
/>
) : null}
<main
data-testid="main-content"
className={cn(

View File

@@ -24,16 +24,17 @@ type TitleBarProps = {
integrated?: boolean;
workspaceLayout?: boolean;
overlay?: boolean;
showSidebarControls?: boolean;
pageTitle?: string;
sidebarPeekOpen?: boolean;
onSidebarPeekChange?: SidebarPeekChange;
};
export function TitleBar({ integrated = false, workspaceLayout = false, overlay = false, pageTitle, sidebarPeekOpen = false, onSidebarPeekChange }: TitleBarProps) {
export function TitleBar({ integrated = false, workspaceLayout = false, overlay = false, showSidebarControls = true, pageTitle, sidebarPeekOpen = false, onSidebarPeekChange }: TitleBarProps) {
const platform = window.electron?.platform;
if (platform === 'darwin') {
return <ProductTitleBar integrated={integrated} workspaceLayout={workspaceLayout} overlay={overlay} pageTitle={pageTitle} nativeTrafficLights sidebarPeekOpen={sidebarPeekOpen} onSidebarPeekChange={onSidebarPeekChange} />;
return <ProductTitleBar integrated={integrated} workspaceLayout={workspaceLayout} overlay={overlay} showSidebarControls={showSidebarControls} pageTitle={pageTitle} nativeTrafficLights sidebarPeekOpen={sidebarPeekOpen} onSidebarPeekChange={onSidebarPeekChange} />;
}
// Linux keeps the native frame/title bar for better IME compatibility.
@@ -41,13 +42,14 @@ export function TitleBar({ integrated = false, workspaceLayout = false, overlay
return null;
}
return <WindowsTitleBar integrated={integrated} workspaceLayout={workspaceLayout} overlay={overlay} pageTitle={pageTitle} sidebarPeekOpen={sidebarPeekOpen} onSidebarPeekChange={onSidebarPeekChange} />;
return <WindowsTitleBar integrated={integrated} workspaceLayout={workspaceLayout} overlay={overlay} showSidebarControls={showSidebarControls} pageTitle={pageTitle} sidebarPeekOpen={sidebarPeekOpen} onSidebarPeekChange={onSidebarPeekChange} />;
}
function ProductTitleBar({
integrated,
workspaceLayout = false,
overlay = false,
showSidebarControls = true,
pageTitle,
children,
windowControlsWidth = 0,
@@ -58,6 +60,7 @@ function ProductTitleBar({
integrated: boolean;
workspaceLayout?: boolean;
overlay?: boolean;
showSidebarControls?: boolean;
pageTitle?: string;
children?: React.ReactNode;
windowControlsWidth?: number;
@@ -150,7 +153,7 @@ function ProductTitleBar({
integrated && !overlay && sidebarTitlebarHidden && !workspaceLayout && 'border-b border-border/80',
)}
>
{integrated ? (
{integrated && showSidebarControls ? (
<>
<div
data-testid="titlebar-sidebar-surface"
@@ -236,7 +239,7 @@ function ProductTitleBar({
);
}
function WindowsTitleBar({ integrated, workspaceLayout, overlay, pageTitle, sidebarPeekOpen, onSidebarPeekChange }: Omit<TitleBarProps, 'integrated'> & { integrated: boolean }) {
function WindowsTitleBar({ integrated, workspaceLayout, overlay, showSidebarControls, pageTitle, sidebarPeekOpen, onSidebarPeekChange }: Omit<TitleBarProps, 'integrated'> & { integrated: boolean }) {
const [maximized, setMaximized] = useState(false);
useEffect(() => {
@@ -267,6 +270,7 @@ function WindowsTitleBar({ integrated, workspaceLayout, overlay, pageTitle, side
integrated={integrated}
workspaceLayout={workspaceLayout}
overlay={overlay}
showSidebarControls={showSidebarControls}
pageTitle={pageTitle}
windowControlsWidth={WINDOWS_TITLEBAR_CONTROLS_WIDTH}
sidebarPeekOpen={sidebarPeekOpen}