format
This commit is contained in:
@@ -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]),
|
||||
|
||||
+32
-9
@@ -16,10 +16,16 @@ function readPlatformThemeCss() {
|
||||
|
||||
function getCssBlock(source: string, selector: string) {
|
||||
const selectorIndex = source.indexOf(selector);
|
||||
expect(selectorIndex, `${selector} should exist in src/index.css`).toBeGreaterThanOrEqual(0);
|
||||
expect(
|
||||
selectorIndex,
|
||||
`${selector} should exist in src/index.css`,
|
||||
).toBeGreaterThanOrEqual(0);
|
||||
|
||||
const openBraceIndex = source.indexOf('{', selectorIndex);
|
||||
expect(openBraceIndex, `${selector} should open a CSS block`).toBeGreaterThanOrEqual(0);
|
||||
expect(
|
||||
openBraceIndex,
|
||||
`${selector} should open a CSS block`,
|
||||
).toBeGreaterThanOrEqual(0);
|
||||
|
||||
let depth = 0;
|
||||
for (let index = openBraceIndex; index < source.length; index += 1) {
|
||||
@@ -111,7 +117,9 @@ describe('index stylesheet unread dots', () => {
|
||||
);
|
||||
|
||||
expect(generatingBlock).toContain('cursor: progress;');
|
||||
expect(generatingScanBlock).toContain('animation: image-canvas-generation-scan');
|
||||
expect(generatingScanBlock).toContain(
|
||||
'animation: image-canvas-generation-scan',
|
||||
);
|
||||
expect(iconBlock).toContain('background: linear-gradient(');
|
||||
expect(iconDecorationBlock).toContain('width: 42%;');
|
||||
expect(css).not.toContain(
|
||||
@@ -129,11 +137,16 @@ describe('index stylesheet unread dots', () => {
|
||||
css,
|
||||
'.project-gallery__canvas-cover-loading::before,\n.image-canvas-editor__layer-image-loading::before',
|
||||
);
|
||||
const keyframesBlock = getCssBlock(css, '@keyframes image-canvas-generation-scan');
|
||||
const keyframesBlock = getCssBlock(
|
||||
css,
|
||||
'@keyframes image-canvas-generation-scan',
|
||||
);
|
||||
|
||||
expect(loadingBlock).toContain('overflow: hidden;');
|
||||
expect(loadingBlock).toContain('background: rgba(226, 232, 240, 0.72);');
|
||||
expect(loadingBlock).not.toContain('animation: image-canvas-generation-scan');
|
||||
expect(loadingBlock).not.toContain(
|
||||
'animation: image-canvas-generation-scan',
|
||||
);
|
||||
|
||||
expect(shimmerBlock).toContain('left: -64%;');
|
||||
expect(shimmerBlock).toContain('width: 64%;');
|
||||
@@ -215,7 +228,9 @@ describe('index stylesheet unread dots', () => {
|
||||
);
|
||||
expect(platformShellBlock).toContain('--platform-layout-viewport-height');
|
||||
expect(platformShellBlock).not.toContain('translate3d');
|
||||
expect(platformShellBlock).not.toContain('--platform-keyboard-focus-offset');
|
||||
expect(platformShellBlock).not.toContain(
|
||||
'--platform-keyboard-focus-offset',
|
||||
);
|
||||
});
|
||||
|
||||
it('uses warm brown tokens for draft unread markers instead of red literals', () => {
|
||||
@@ -248,7 +263,9 @@ describe('index stylesheet unread dots', () => {
|
||||
const css = readIndexCss();
|
||||
const themeCss = readPlatformThemeCss();
|
||||
const titleRuleIndex = css.indexOf('.selection-hero-brand__title');
|
||||
const platformThemeRuleIndex = css.indexOf('.platform-theme,\n.platform-theme *');
|
||||
const platformThemeRuleIndex = css.indexOf(
|
||||
'.platform-theme,\n.platform-theme *',
|
||||
);
|
||||
|
||||
expect(titleRuleIndex).toBeGreaterThanOrEqual(0);
|
||||
expect(platformThemeRuleIndex).toBeGreaterThan(titleRuleIndex);
|
||||
@@ -313,7 +330,10 @@ describe('index stylesheet draft mobile cards', () => {
|
||||
|
||||
const draftPanelSelector =
|
||||
'#platform-tab-panel-saves,\n #platform-tab-panel-saves *';
|
||||
const draftPanelSelectorIndex = css.indexOf(draftPanelSelector, mobileQueryIndex);
|
||||
const draftPanelSelectorIndex = css.indexOf(
|
||||
draftPanelSelector,
|
||||
mobileQueryIndex,
|
||||
);
|
||||
expect(draftPanelSelectorIndex).toBeGreaterThanOrEqual(0);
|
||||
|
||||
const draftPanelBlock = getCssBlock(css, draftPanelSelector);
|
||||
@@ -323,7 +343,10 @@ describe('index stylesheet draft mobile cards', () => {
|
||||
|
||||
const editableSelector =
|
||||
"#platform-tab-panel-saves :is(input, textarea, [contenteditable='true'])";
|
||||
const editableSelectorIndex = css.indexOf(editableSelector, mobileQueryIndex);
|
||||
const editableSelectorIndex = css.indexOf(
|
||||
editableSelector,
|
||||
mobileQueryIndex,
|
||||
);
|
||||
expect(editableSelectorIndex).toBeGreaterThanOrEqual(0);
|
||||
|
||||
const editableBlock = getCssBlock(css, editableSelector);
|
||||
|
||||
Reference in New Issue
Block a user