This commit is contained in:
2026-07-27 16:05:44 +08:00
parent aab0b7849b
commit 21143f9ff5
6 changed files with 471 additions and 448 deletions
@@ -154,100 +154,100 @@ export function ImageCanvasAssetLibraryPanelView({
}: ImageCanvasAssetLibraryPanelViewProps) {
return (
<div className="image-canvas-editor__asset-library">
<div
ref={assetListRef}
className="image-canvas-editor__asset-list"
onPointerDown={onAssetMarqueePointerDown}
onPointerMove={onAssetMarqueePointerMove}
onPointerUp={onAssetMarqueePointerUp}
onPointerCancel={onAssetMarqueePointerUp}
>
{pinnedAssetMoveFolderId ? (
<div
className="image-canvas-editor__asset-folder-sticky-target"
aria-hidden="true"
>
<Folder className="h-4 w-4" />
<span>
<div
ref={assetListRef}
className="image-canvas-editor__asset-list"
onPointerDown={onAssetMarqueePointerDown}
onPointerMove={onAssetMarqueePointerMove}
onPointerUp={onAssetMarqueePointerUp}
onPointerCancel={onAssetMarqueePointerUp}
>
{pinnedAssetMoveFolderId ? (
<div
className="image-canvas-editor__asset-folder-sticky-target"
aria-hidden="true"
>
<Folder className="h-4 w-4" />
<span>
{assetFolders.find(
(folder) => folder.id === pinnedAssetMoveFolderId,
)?.label ?? '目标文件夹'}
</span>
</div>
) : null}
{creatingFolder ? (
<form
className="image-canvas-editor__folder-create"
onSubmit={(event) => {
event.preventDefault();
void commitNewAssetFolder();
}}
>
<PlatformTextField
aria-label="素材文件夹名称"
value={newFolderName}
autoFocus
size="xs"
density="compact"
className="image-canvas-editor__folder-create-input"
onChange={(event) => setNewFolderName(event.target.value)}
onKeyDown={(event) => {
if (event.key === 'Escape') {
event.preventDefault();
setCreatingFolder(false);
setNewFolderName('');
}
</span>
</div>
) : null}
{creatingFolder ? (
<form
className="image-canvas-editor__folder-create"
onSubmit={(event) => {
event.preventDefault();
void commitNewAssetFolder();
}}
/>
>
<PlatformTextField
aria-label="素材文件夹名称"
value={newFolderName}
autoFocus
size="xs"
density="compact"
className="image-canvas-editor__folder-create-input"
onChange={(event) => setNewFolderName(event.target.value)}
onKeyDown={(event) => {
if (event.key === 'Escape') {
event.preventDefault();
setCreatingFolder(false);
setNewFolderName('');
}
}}
/>
<EditorIconButton
type="submit"
label="保存素材文件夹"
icon={Check}
/>
<EditorIconButton
label="取消新建素材文件夹"
icon={X}
onClick={() => {
setCreatingFolder(false);
setNewFolderName('');
}}
/>
</form>
) : null}
{groupedAssets.map((folder) => (
<ImageCanvasAssetFolderSectionView
key={folder.id}
folder={folder}
assetPointerDragRef={assetPointerDragRef}
suppressAssetClickRef={suppressAssetClickRef}
isAssetSelectionMode={isAssetSelectionMode}
selectedAssetIds={selectedAssetIds}
<EditorIconButton
label="取消新建素材文件夹"
icon={X}
onClick={() => {
setCreatingFolder(false);
setNewFolderName('');
}}
/>
</form>
) : null}
{groupedAssets.map((folder) => (
<ImageCanvasAssetFolderSectionView
key={folder.id}
folder={folder}
assetPointerDragRef={assetPointerDragRef}
suppressAssetClickRef={suppressAssetClickRef}
isAssetSelectionMode={isAssetSelectionMode}
selectedAssetIds={selectedAssetIds}
visibleAssetIds={visibleAssetIds}
assetMoveDropFolderId={assetMoveDropFolderId}
renamingFolder={renamingFolder}
renamingAsset={renamingAsset}
setRenamingFolder={setRenamingFolder}
setRenamingAsset={setRenamingAsset}
setActiveUploadFolderId={setActiveUploadFolderId}
setUploadDropTarget={setUploadDropTarget}
setAssetPointerDrag={setAssetPointerDrag}
updateAssetMoveDropFolder={updateAssetMoveDropFolder}
addUploadedFiles={addUploadedFiles}
requestUpload={requestUpload}
moveAssetToFolder={moveAssetToFolder}
toggleAssetFolder={toggleAssetFolder}
startRenamingFolder={startRenamingFolder}
commitFolderRename={commitFolderRename}
deleteAssetFolder={deleteAssetFolder}
startRenamingAsset={startRenamingAsset}
commitAssetRename={commitAssetRename}
deleteUploadedAsset={deleteUploadedAsset}
submitAssetToShowcase={submitAssetToShowcase}
toggleAssetSelected={toggleAssetSelected}
addAssetLayer={addAssetLayer}
onDownloadAsset={onDownloadAsset}
/>
))}
assetMoveDropFolderId={assetMoveDropFolderId}
renamingFolder={renamingFolder}
renamingAsset={renamingAsset}
setRenamingFolder={setRenamingFolder}
setRenamingAsset={setRenamingAsset}
setActiveUploadFolderId={setActiveUploadFolderId}
setUploadDropTarget={setUploadDropTarget}
setAssetPointerDrag={setAssetPointerDrag}
updateAssetMoveDropFolder={updateAssetMoveDropFolder}
addUploadedFiles={addUploadedFiles}
requestUpload={requestUpload}
moveAssetToFolder={moveAssetToFolder}
toggleAssetFolder={toggleAssetFolder}
startRenamingFolder={startRenamingFolder}
commitFolderRename={commitFolderRename}
deleteAssetFolder={deleteAssetFolder}
startRenamingAsset={startRenamingAsset}
commitAssetRename={commitAssetRename}
deleteUploadedAsset={deleteUploadedAsset}
submitAssetToShowcase={submitAssetToShowcase}
toggleAssetSelected={toggleAssetSelected}
addAssetLayer={addAssetLayer}
onDownloadAsset={onDownloadAsset}
/>
))}
{assetMarquee ? (
<div
className="image-canvas-editor__asset-marquee"
@@ -279,9 +279,9 @@ export function ImageCanvasAssetLibraryPanelView({
<Square className="h-4 w-4" />
)}
<span className="min-w-0 truncate">
{selectedAssetIds.size > 0
{selectedAssetIds.size > 0
? `${allVisibleAssetsSelected ? '取消全选' : '全选'} · 已选 ${selectedAssetIds.size}`
: '全选'}
: '全选'}
</span>
</PlatformActionButton>
<PlatformActionButton
@@ -403,8 +403,8 @@ export function ImageCanvasAssetRowView({
event.pointerType === 'touch' || event.pointerType === 'pen'
? event.pointerType
: 'mouse';
return;
}
return;
}
if (event.button !== 0) {
return;
}
@@ -559,11 +559,11 @@ describe('ImageCanvasEditorView asset library integration', () => {
const originalCreateElement = document.createElement.bind(document);
vi.spyOn(document, 'createElement').mockImplementation(
(tagName, options) => {
const element = originalCreateElement(tagName, options);
if (tagName === 'video' || tagName === 'audio') {
createdMediaElements.push(element as HTMLMediaElement);
}
return element;
const element = originalCreateElement(tagName, options);
if (tagName === 'video' || tagName === 'audio') {
createdMediaElements.push(element as HTMLMediaElement);
}
return element;
},
);
Object.defineProperty(URL, 'createObjectURL', {
@@ -1017,13 +1017,13 @@ describe('ImageCanvasEditorView asset library integration', () => {
await waitFor(() => {
const savedLayoutWithoutDeletedLayer =
saveEditorProjectLayoutMock.mock.calls
.map((call) => call[1])
.find((layout) =>
layout.layers.every(
(item: { layerId?: unknown }) =>
item.layerId !== 'layer-generated-a',
),
);
.map((call) => call[1])
.find((layout) =>
layout.layers.every(
(item: { layerId?: unknown }) =>
item.layerId !== 'layer-generated-a',
),
);
expect(savedLayoutWithoutDeletedLayer).toBeTruthy();
});
expect(deleteEditorAssetMock).toHaveBeenCalledWith('asset-generated-a');
File diff suppressed because it is too large Load Diff
@@ -322,21 +322,21 @@ export function useImageCanvasAssetLibrary({
);
setAssetFolders(
(currentFolders) =>
replaceLocalAssetFolder({
folders: currentFolders,
assets: [],
localFolderId: folderId,
persistedFolder: folder,
}).folders,
replaceLocalAssetFolder({
folders: currentFolders,
assets: [],
localFolderId: folderId,
persistedFolder: folder,
}).folders,
);
setAssets(
(currentAssets) =>
replaceLocalAssetFolder({
folders: [],
assets: currentAssets,
localFolderId: folderId,
persistedFolder: folder,
}).assets,
replaceLocalAssetFolder({
folders: [],
assets: currentAssets,
localFolderId: folderId,
persistedFolder: folder,
}).assets,
);
setActiveUploadFolderId(folder.folderId);
} catch {
@@ -362,58 +362,58 @@ export function useImageCanvasAssetLibrary({
);
const submitAssetToShowcase = useCallback((asset: EditorAsset) => {
if (!resolveAssetShowcaseSubmissionState(asset).canSubmit) {
return;
}
const previousAsset = asset;
setAssets((currentAssets) =>
currentAssets.map((currentAsset) =>
currentAsset.id === asset.id
? {
...currentAsset,
publicShowcaseEnabled: false,
showcaseReviewStatus: 'pending',
showcaseDisplayEnabled: false,
showcaseSubmitError: undefined,
}
: currentAsset,
),
);
submitEditorAssetShowcase(asset.id)
.then((showcaseAsset) => {
setAssets((currentAssets) =>
currentAssets.map((currentAsset) =>
currentAsset.id === asset.id
? {
...currentAsset,
publicShowcaseEnabled: false,
if (!resolveAssetShowcaseSubmissionState(asset).canSubmit) {
return;
}
const previousAsset = asset;
setAssets((currentAssets) =>
currentAssets.map((currentAsset) =>
currentAsset.id === asset.id
? {
...currentAsset,
publicShowcaseEnabled: false,
showcaseReviewStatus: 'pending',
showcaseDisplayEnabled: false,
showcaseSubmitError: undefined,
}
: currentAsset,
),
);
submitEditorAssetShowcase(asset.id)
.then((showcaseAsset) => {
setAssets((currentAssets) =>
currentAssets.map((currentAsset) =>
currentAsset.id === asset.id
? {
...currentAsset,
publicShowcaseEnabled: false,
showcaseId:
showcaseAsset.showcaseId ?? showcaseAsset.resourceId,
showcaseReviewStatus: showcaseAsset.reviewStatus ?? 'pending',
showcaseDisplayEnabled: showcaseAsset.displayEnabled ?? false,
showcaseLikeCount: showcaseAsset.likeCount ?? 0,
generationCostMudPoints:
showcaseAsset.generationCostMudPoints ??
currentAsset.generationCostMudPoints,
showcaseSubmitError: undefined,
}
: currentAsset,
),
);
})
.catch((error: unknown) => {
const showcaseSubmitError = formatShowcaseSubmitError(error);
setAssets((currentAssets) =>
currentAssets.map((currentAsset) =>
currentAsset.id === asset.id
? {
...previousAsset,
showcaseSubmitError,
}
: currentAsset,
),
);
});
showcaseReviewStatus: showcaseAsset.reviewStatus ?? 'pending',
showcaseDisplayEnabled: showcaseAsset.displayEnabled ?? false,
showcaseLikeCount: showcaseAsset.likeCount ?? 0,
generationCostMudPoints:
showcaseAsset.generationCostMudPoints ??
currentAsset.generationCostMudPoints,
showcaseSubmitError: undefined,
}
: currentAsset,
),
);
})
.catch((error: unknown) => {
const showcaseSubmitError = formatShowcaseSubmitError(error);
setAssets((currentAssets) =>
currentAssets.map((currentAsset) =>
currentAsset.id === asset.id
? {
...previousAsset,
showcaseSubmitError,
}
: currentAsset,
),
);
});
}, []);
const startRenamingFolder = useCallback((folder: EditorAssetFolder) => {
@@ -454,21 +454,21 @@ export function useImageCanvasAssetLibrary({
}
setAssetFolders(
(currentFolders) =>
deleteAssetFolderLocally({
folders: currentFolders,
assets: [],
folderId: folder.id,
defaultFolderId: defaultFolder.id,
}).folders,
deleteAssetFolderLocally({
folders: currentFolders,
assets: [],
folderId: folder.id,
defaultFolderId: defaultFolder.id,
}).folders,
);
setAssets(
(currentAssets) =>
deleteAssetFolderLocally({
folders: [],
assets: currentAssets,
folderId: folder.id,
defaultFolderId: defaultFolder.id,
}).assets,
deleteAssetFolderLocally({
folders: [],
assets: currentAssets,
folderId: folder.id,
defaultFolderId: defaultFolder.id,
}).assets,
);
if (folder.persisted) {
deleteEditorAssetFolder(folder.id)
@@ -497,7 +497,7 @@ export function useImageCanvasAssetLibrary({
});
},
[],
);
);
const toggleAllAssetsSelected = useCallback((visibleAssetIds: string[]) => {
setSelectedAssetIds((currentIds) =>
@@ -580,9 +580,9 @@ export function useImageCanvasAssetLibrary({
bottom: number;
}) => {
const marqueeSelection = selectUploadedAssetsInRect({
assets,
assetTargets: readAssetHitTargets(assetListRef.current),
selectionRect,
assets,
assetTargets: readAssetHitTargets(assetListRef.current),
selectionRect,
});
setSelectedAssetIds(
new Set([...marqueeBaseSelectionRef.current, ...marqueeSelection]),