拆分图片画布顶部栏视图

新增 ImageCanvasTopbarView 承载返回项目入口和项目标题区域

新增顶栏视图测试覆盖重命名和导出入口

精简 ImageCanvasEditorView 的顶部栏 JSX

更新图片画布拆分计划和 TRACKING 验证记录
This commit is contained in:
2026-06-17 13:48:48 +08:00
parent 1c92db19c1
commit a319d2ae0d
6 changed files with 325 additions and 108 deletions

View File

@@ -0,0 +1,149 @@
import { Check, ChevronLeft, Download, Pencil, X } from 'lucide-react';
import { PlatformStatusMessage } from '../common/PlatformStatusMessage';
import { PlatformTextField } from '../common/PlatformTextField';
import { EditorIconButton } from './ImageCanvasEditorPrimitives';
import type { CanvasLayer } from './ImageCanvasEditorTypes';
import type { AssetExportStatus } from './useImageCanvasAssetExportWorkflow';
type ImageCanvasTopbarViewProps = {
projectId: string | null;
projectTitle: string;
projectRenameValue: string;
isRenamingProject: boolean;
isProjectRenameSaving: boolean;
projectRenameError: string | null;
layers: CanvasLayer[];
assetExportStatus: AssetExportStatus | null;
isExportingAssets: boolean;
setProjectRenameValue: (value: string) => void;
startProjectRename: () => void;
cancelProjectRename: () => void;
submitProjectRename: (projectId: string | null) => void;
resetProjectRenameError: () => void;
exportCanvasAssets: () => void | Promise<void>;
};
export function ImageCanvasTopbarView({
projectId,
projectTitle,
projectRenameValue,
isRenamingProject,
isProjectRenameSaving,
projectRenameError,
layers,
assetExportStatus,
isExportingAssets,
setProjectRenameValue,
startProjectRename,
cancelProjectRename,
submitProjectRename,
resetProjectRenameError,
exportCanvasAssets,
}: ImageCanvasTopbarViewProps) {
const hasExportableLayer = layers.some(
(layer) => layer.src.trim().length > 0,
);
return (
<div className="image-canvas-editor__topbar">
<a
className="image-canvas-editor__project-back-button"
href="/project"
aria-label="返回项目页面"
title="返回项目"
>
<ChevronLeft className="h-4 w-4" aria-hidden="true" />
</a>
<div className="image-canvas-editor__title-block">
{isRenamingProject ? (
<form
className="image-canvas-editor__project-title-form"
onSubmit={(event) => {
event.preventDefault();
submitProjectRename(projectId);
}}
>
<PlatformTextField
aria-label="项目名称"
value={projectRenameValue}
autoFocus
disabled={isProjectRenameSaving}
className="image-canvas-editor__project-title-input"
onChange={(event) => {
setProjectRenameValue(event.target.value);
resetProjectRenameError();
}}
onKeyDown={(event) => {
if (event.key === 'Escape') {
event.preventDefault();
cancelProjectRename();
}
}}
/>
<EditorIconButton
type="submit"
label="保存项目名称"
title="保存"
icon={Check}
disabled={isProjectRenameSaving}
/>
<EditorIconButton
label="取消修改项目名称"
title="取消"
icon={X}
disabled={isProjectRenameSaving}
onClick={cancelProjectRename}
/>
{projectRenameError ? (
<span
className="image-canvas-editor__project-title-error"
role="alert"
>
{projectRenameError}
</span>
) : null}
</form>
) : (
<div className="image-canvas-editor__project-title-row">
<button
type="button"
className="image-canvas-editor__project-title-button"
onDoubleClick={startProjectRename}
aria-label={`编辑项目名称${projectTitle}`}
>
<h1>{projectTitle}</h1>
</button>
<EditorIconButton
className="image-canvas-editor__project-rename-button"
label="编辑项目名称"
title="编辑项目名称"
icon={Pencil}
onClick={startProjectRename}
/>
</div>
)}
<span></span>
</div>
<div className="image-canvas-editor__topbar-actions">
<EditorIconButton
label="下载画布素材"
title="下载画布素材"
icon={Download}
disabled={isExportingAssets || !hasExportableLayer}
onClick={() => void exportCanvasAssets()}
/>
{assetExportStatus ? (
<PlatformStatusMessage
tone={assetExportStatus.tone}
surface="platform"
size="xs"
role={assetExportStatus.tone === 'error' ? 'alert' : 'status'}
>
{assetExportStatus.message}
</PlatformStatusMessage>
) : null}
</div>
</div>
);
}