fix(canvas): compact workspace toolbar

This commit is contained in:
inman
2026-09-07 15:53:49 +08:00
parent 0619327fbe
commit e98603435d
4 changed files with 21 additions and 71 deletions

View File

@@ -5,7 +5,6 @@ import { DesignPlanHistory } from './DesignPlanHistory';
export function DesignHistoryRail({ workspace }: { workspace: DesignWorkspace | null }) {
const taskCount = workspace?.tasks.length ?? 0;
const resultCount = workspace?.assets.filter((asset) => asset.generationTaskId).length ?? 0;
const platform = window.electron?.platform;
return (
@@ -17,22 +16,14 @@ export function DesignHistoryRail({ workspace }: { workspace: DesignWorkspace |
<header
data-testid="image-workspace-history-header"
className={cn(
'flex h-16 shrink-0 items-center border-b border-border/70 px-4',
'flex h-12 shrink-0 items-center border-b border-border/70 px-4',
platform === 'darwin' && 'pr-[116px]',
platform === 'win32' && 'items-end pb-1.5 pr-[156px]',
platform === 'win32' && 'pr-[244px]',
)}
>
<div className="min-w-0">
<div className="flex items-center gap-2">
<Images className="h-4 w-4 shrink-0 text-brand" aria-hidden="true" />
<h2 className="truncate text-sm font-semibold text-foreground">历史作品</h2>
</div>
<p className={cn(
'mt-1 truncate text-[11px] tabular-nums text-muted-foreground',
platform === 'win32' && 'hidden',
)}>
{taskCount > 0 ? `${taskCount} 次制作 · ${resultCount} 个结果` : '当前设计项目的制作记录'}
</p>
<div className="flex min-w-0 items-center gap-2">
<Images className="h-4 w-4 shrink-0 text-brand" aria-hidden="true" />
<h2 className="truncate text-sm font-semibold text-foreground">历史作品</h2>
</div>
</header>

View File

@@ -1,6 +1,5 @@
import { useEffect, useState } from 'react';
import {
Cloud,
CloudOff,
PanelLeft,
Plus,
@@ -23,8 +22,6 @@ import { useImageWorkspaceStore } from '@/stores/image-workspace';
import { DesignConversationPane } from './DesignConversationPane';
import { DesignHistoryRail } from './DesignHistoryRail';
import { DesignWorksRail } from './DesignWorksRail';
import { hasActiveCreationPlan } from './plan-lifecycle';
import { projectYouthCreationCard } from './youth-form-projection';
function useDesktopLayout(): boolean {
const [desktop, setDesktop] = useState(() => (
@@ -49,7 +46,7 @@ function LoadingWorkspace() {
return (
<div className="flex h-full min-h-0 bg-background" aria-label="正在加载 AI 设计">
<div className="flex min-w-0 flex-1 flex-col">
<div className="h-16 animate-pulse border-b border-border/60 bg-surface-subtle/60" />
<div className="h-12 animate-pulse border-b border-border/60 bg-surface-subtle/60" />
<div className="min-h-0 flex-1 space-y-4 bg-surface-subtle/35 p-6">
<div className="h-16 animate-pulse rounded-2xl bg-surface-subtle" />
<div className="ml-auto h-20 w-4/5 animate-pulse rounded-2xl bg-brand/[0.07]" />
@@ -57,7 +54,7 @@ function LoadingWorkspace() {
</div>
</div>
<div className="hidden h-full w-[320px] shrink-0 flex-col border-l border-border/70 bg-background lg:flex xl:w-[340px]">
<div className="h-16 animate-pulse border-b border-border/60 bg-surface-subtle/45" />
<div className="h-12 animate-pulse border-b border-border/60 bg-surface-subtle/45" />
<div className="space-y-3 p-3">
{[0, 1, 2].map((item) => (
<div key={item} className="h-16 animate-pulse rounded-xl bg-surface-subtle" />
@@ -111,7 +108,6 @@ export function ImageCanvas() {
const status = useImageWorkspaceStore((state) => state.status);
const bootstrap = useImageWorkspaceStore((state) => state.bootstrap);
const workspace = useImageWorkspaceStore((state) => state.workspace);
const eventState = useImageWorkspaceStore((state) => state.eventState);
const error = useImageWorkspaceStore((state) => state.error);
const quoteBlockers = useImageWorkspaceStore((state) => state.quoteBlockers);
const load = useImageWorkspaceStore((state) => state.load);
@@ -150,23 +146,7 @@ export function ImageCanvas() {
if (!workspace && status !== 'ready') return <LoadingWorkspace />;
const streamHealthy = eventState === 'connected';
const generationAvailable = bootstrap?.capabilities.generation !== false;
const readiness = workspace
? workspace.form.activeQuotes.some((quote) => quote.status === 'offered')
? '制作方案已准备好,确认前仍可修改'
: hasActiveCreationPlan(workspace)
? '想法已整理清楚,可以检查制作方案'
: projectYouthCreationCard(workspace, { quoteBlockers }).readinessMessage
: '从一个新作品开始';
const updatedAt = workspace
? new Date(workspace.workspace.updatedAt).toLocaleString([], {
month: 'numeric',
day: 'numeric',
hour: '2-digit',
minute: '2-digit',
})
: null;
const platform = window.electron?.platform;
const openCreate = () => {
if (!desktopLayout) setWorksOpen(true);
@@ -179,7 +159,7 @@ export function ImageCanvas() {
<div data-testid="image-workspace" className="flex h-full min-h-0 overflow-hidden bg-background font-sans">
<div className="flex min-w-0 flex-1 flex-col">
<header data-testid="image-workspace-header" className={cn(
'flex h-16 shrink-0 items-center gap-4 border-b border-border/70 bg-background py-2',
'flex h-12 shrink-0 items-center gap-3 border-b border-border/70 bg-background',
platform === 'darwin'
? 'pl-4 pr-[116px] sm:pl-5'
: platform === 'win32'
@@ -193,36 +173,8 @@ export function ImageCanvas() {
{workspace?.workspace.title ?? 'Makelore Canvas'}
</h1>
</div>
<p className="mt-1 truncate text-xs text-muted-foreground">
{updatedAt ? `${readiness} · 更新于 ${updatedAt}` : readiness}
</p>
</div>
<div
className={cn(
'hidden items-center gap-1.5 rounded-lg px-2.5 py-1.5 text-xs sm:flex',
streamHealthy ? 'bg-brand/[0.055] text-brand' : 'bg-surface-subtle text-muted-foreground',
)}
title={streamHealthy ? '已经连接' : '正在重新连接,你的内容不会丢失'}
>
{streamHealthy ? <Cloud className="h-3.5 w-3.5" /> : <CloudOff className="h-3.5 w-3.5" />}
{streamHealthy ? '实时同步' : '恢复连接'}
</div>
{workspace && (
<Button
type="button"
variant="ghost"
size="icon"
className="h-9 w-9 rounded-lg"
aria-label="刷新作品"
title="刷新"
onClick={() => void refreshWorkspace()}
>
<RefreshCw className="h-4 w-4" />
</Button>
)}
{!desktopLayout && (
<Button
type="button"