拆分编辑器前端画布视图
抽出素材栏、生成器、舞台工具栏和画布世界视图 补充各拆分视图的聚焦测试 更新 TRACKING.md 记录第三十四阶段验证
This commit is contained in:
@@ -0,0 +1,257 @@
|
||||
import {
|
||||
Check,
|
||||
ChevronDown,
|
||||
ChevronRight,
|
||||
Folder,
|
||||
ImagePlus,
|
||||
PencilLine,
|
||||
Trash2,
|
||||
X,
|
||||
} from 'lucide-react';
|
||||
import type { Dispatch, SetStateAction } from 'react';
|
||||
|
||||
import { PlatformTextField } from '../common/PlatformTextField';
|
||||
import { EditorIconButton } from './ImageCanvasEditorPrimitives';
|
||||
import {
|
||||
ASSET_DRAG_MIME_TYPE,
|
||||
getDraggedAssetId,
|
||||
hasDataTransferType,
|
||||
} from './ImageCanvasEditorModel';
|
||||
import type {
|
||||
AssetPointerDragState,
|
||||
EditorAsset,
|
||||
EditorAssetFolder,
|
||||
UploadTarget,
|
||||
} from './ImageCanvasEditorTypes';
|
||||
import { ImageCanvasAssetRowView } from './ImageCanvasAssetRowView';
|
||||
import type {
|
||||
GroupedEditorAssetFolder,
|
||||
UploadFilesOptions,
|
||||
} from './ImageCanvasAssetLibraryPanelView';
|
||||
|
||||
type ImageCanvasAssetFolderSectionViewProps = {
|
||||
folder: GroupedEditorAssetFolder;
|
||||
assetPointerDragRef: { current: AssetPointerDragState | null };
|
||||
suppressAssetClickRef: { current: boolean };
|
||||
isAssetSelectionMode: boolean;
|
||||
selectedAssetIds: Set<string>;
|
||||
assetMoveDropFolderId: string | null;
|
||||
renamingFolder: { folderId: string; value: string } | null;
|
||||
renamingAsset: { assetId: string; value: string } | null;
|
||||
setRenamingFolder: Dispatch<
|
||||
SetStateAction<{ folderId: string; value: string } | null>
|
||||
>;
|
||||
setRenamingAsset: Dispatch<
|
||||
SetStateAction<{ assetId: string; value: string } | null>
|
||||
>;
|
||||
setActiveUploadFolderId: Dispatch<SetStateAction<string>>;
|
||||
setUploadDropTarget: Dispatch<SetStateAction<'canvas' | 'assets' | null>>;
|
||||
setAssetPointerDrag: Dispatch<SetStateAction<AssetPointerDragState | null>>;
|
||||
setSelectedAssetIds: Dispatch<SetStateAction<Set<string>>>;
|
||||
updateAssetMoveDropFolder: (folderId: string | null) => void;
|
||||
addUploadedFiles: (files: FileList | File[], options?: UploadFilesOptions) => void;
|
||||
requestUpload: (target: UploadTarget) => void;
|
||||
moveAssetToFolder: (assetId: string, folderId: string) => void;
|
||||
toggleAssetFolder: (folderId: string) => void;
|
||||
startRenamingFolder: (folder: EditorAssetFolder) => void;
|
||||
commitFolderRename: (folder: EditorAssetFolder) => void;
|
||||
deleteAssetFolder: (folder: EditorAssetFolder) => void;
|
||||
startRenamingAsset: (asset: EditorAsset) => void;
|
||||
commitAssetRename: (asset: EditorAsset) => void;
|
||||
deleteUploadedAsset: (asset: EditorAsset) => void;
|
||||
toggleAssetSelected: (assetId: string) => void;
|
||||
addAssetLayer: (asset: EditorAsset) => void;
|
||||
};
|
||||
|
||||
export function ImageCanvasAssetFolderSectionView({
|
||||
folder,
|
||||
assetPointerDragRef,
|
||||
suppressAssetClickRef,
|
||||
isAssetSelectionMode,
|
||||
selectedAssetIds,
|
||||
assetMoveDropFolderId,
|
||||
renamingFolder,
|
||||
renamingAsset,
|
||||
setRenamingFolder,
|
||||
setRenamingAsset,
|
||||
setActiveUploadFolderId,
|
||||
setUploadDropTarget,
|
||||
setAssetPointerDrag,
|
||||
setSelectedAssetIds,
|
||||
updateAssetMoveDropFolder,
|
||||
addUploadedFiles,
|
||||
requestUpload,
|
||||
moveAssetToFolder,
|
||||
toggleAssetFolder,
|
||||
startRenamingFolder,
|
||||
commitFolderRename,
|
||||
deleteAssetFolder,
|
||||
startRenamingAsset,
|
||||
commitAssetRename,
|
||||
deleteUploadedAsset,
|
||||
toggleAssetSelected,
|
||||
addAssetLayer,
|
||||
}: ImageCanvasAssetFolderSectionViewProps) {
|
||||
return (
|
||||
<section
|
||||
className={[
|
||||
'image-canvas-editor__asset-folder',
|
||||
assetMoveDropFolderId === folder.id
|
||||
? 'image-canvas-editor__asset-folder--move-target'
|
||||
: '',
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(' ')}
|
||||
aria-label={folder.label}
|
||||
data-asset-folder-id={folder.id}
|
||||
onDragOver={(event) => {
|
||||
if (hasDataTransferType(event.dataTransfer, ASSET_DRAG_MIME_TYPE)) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
setUploadDropTarget(null);
|
||||
updateAssetMoveDropFolder(folder.id);
|
||||
event.dataTransfer.dropEffect = 'move';
|
||||
return;
|
||||
}
|
||||
if (hasDataTransferType(event.dataTransfer, 'Files')) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
setUploadDropTarget('assets');
|
||||
event.dataTransfer.dropEffect = 'copy';
|
||||
}
|
||||
}}
|
||||
onDrop={(event) => {
|
||||
const movingAssetId = getDraggedAssetId(event.dataTransfer);
|
||||
if (movingAssetId) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
setUploadDropTarget(null);
|
||||
updateAssetMoveDropFolder(null);
|
||||
moveAssetToFolder(movingAssetId, folder.id);
|
||||
return;
|
||||
}
|
||||
if (!event.dataTransfer.files.length) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
setUploadDropTarget(null);
|
||||
updateAssetMoveDropFolder(null);
|
||||
addUploadedFiles(event.dataTransfer.files, {
|
||||
folderId: folder.id,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="image-canvas-editor__asset-folder-header"
|
||||
data-asset-folder-header-id={folder.id}
|
||||
>
|
||||
<EditorIconButton
|
||||
label={`${folder.collapsed ? '展开' : '折叠'}${folder.label}`}
|
||||
title={folder.collapsed ? '展开' : '折叠'}
|
||||
icon={folder.collapsed ? ChevronRight : ChevronDown}
|
||||
expanded={!folder.collapsed}
|
||||
onClick={() => toggleAssetFolder(folder.id)}
|
||||
/>
|
||||
<Folder className="h-4 w-4" />
|
||||
{renamingFolder?.folderId === folder.id ? (
|
||||
<PlatformTextField
|
||||
aria-label={`重命名文件夹${folder.label}`}
|
||||
value={renamingFolder.value}
|
||||
autoFocus
|
||||
size="xs"
|
||||
density="compact"
|
||||
className="image-canvas-editor__folder-rename-input"
|
||||
onChange={(event) =>
|
||||
setRenamingFolder({
|
||||
folderId: folder.id,
|
||||
value: event.target.value,
|
||||
})
|
||||
}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === 'Enter') {
|
||||
event.preventDefault();
|
||||
commitFolderRename(folder);
|
||||
}
|
||||
if (event.key === 'Escape') {
|
||||
event.preventDefault();
|
||||
setRenamingFolder(null);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<span>{folder.label}</span>
|
||||
)}
|
||||
<span>{folder.assets.length}</span>
|
||||
{renamingFolder?.folderId === folder.id ? (
|
||||
<>
|
||||
<EditorIconButton
|
||||
label={`保存文件夹${folder.label}名称`}
|
||||
title="保存"
|
||||
icon={Check}
|
||||
onClick={() => commitFolderRename(folder)}
|
||||
/>
|
||||
<EditorIconButton
|
||||
label={`取消重命名文件夹${folder.label}`}
|
||||
title="取消"
|
||||
icon={X}
|
||||
onClick={() => setRenamingFolder(null)}
|
||||
/>
|
||||
</>
|
||||
) : (
|
||||
<EditorIconButton
|
||||
label={`重命名文件夹${folder.label}`}
|
||||
title="重命名"
|
||||
icon={PencilLine}
|
||||
onClick={() => startRenamingFolder(folder)}
|
||||
/>
|
||||
)}
|
||||
{!folder.systemDefault ? (
|
||||
<EditorIconButton
|
||||
label={`删除文件夹${folder.label}`}
|
||||
title="删除"
|
||||
icon={Trash2}
|
||||
onClick={() => deleteAssetFolder(folder)}
|
||||
/>
|
||||
) : null}
|
||||
<EditorIconButton
|
||||
label={`上传到${folder.label}`}
|
||||
title="上传"
|
||||
icon={ImagePlus}
|
||||
onClick={() => {
|
||||
setActiveUploadFolderId(folder.id);
|
||||
requestUpload('asset');
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="image-canvas-editor__asset-folder-list"
|
||||
hidden={folder.collapsed}
|
||||
>
|
||||
{folder.assets.map((asset) => (
|
||||
<ImageCanvasAssetRowView
|
||||
key={asset.id}
|
||||
asset={asset}
|
||||
assetPointerDragRef={assetPointerDragRef}
|
||||
suppressAssetClickRef={suppressAssetClickRef}
|
||||
isAssetSelectionMode={isAssetSelectionMode}
|
||||
selectedAssetIds={selectedAssetIds}
|
||||
renamingAsset={renamingAsset}
|
||||
setRenamingAsset={setRenamingAsset}
|
||||
setUploadDropTarget={setUploadDropTarget}
|
||||
setAssetPointerDrag={setAssetPointerDrag}
|
||||
setSelectedAssetIds={setSelectedAssetIds}
|
||||
updateAssetMoveDropFolder={updateAssetMoveDropFolder}
|
||||
addUploadedFiles={addUploadedFiles}
|
||||
moveAssetToFolder={moveAssetToFolder}
|
||||
startRenamingAsset={startRenamingAsset}
|
||||
commitAssetRename={commitAssetRename}
|
||||
deleteUploadedAsset={deleteUploadedAsset}
|
||||
toggleAssetSelected={toggleAssetSelected}
|
||||
addAssetLayer={addAssetLayer}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user