feat(editor): DnD сцен в список, порядок списка и правки импорта
Можно перетащить изображения/видео в колонку сцен: создаются новые сцены с превью и названием из файла, с полноэкранным прогрессом и отчётом о пропущенных файлах. Добавлен ручной порядок сцен в списке (sceneListOrder) с сохранением в проект; перетаскивание карточек отделено от импорта файлов. Во время сортировки снова работает скролл колесом. Исправлен залипающий disabled у «+ Новая сцена» после создания сцены. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -8,6 +8,11 @@ import { ZipFile } from 'yazl';
|
||||
|
||||
import { isSceneGraphEdgeRejected } from '../../shared/graph/sceneGraphEdgeRules';
|
||||
import { canSetSideStoryStart, getSideStoryComponentNodeIds } from '../../shared/graph/sceneGraphLineage';
|
||||
import {
|
||||
prependSceneListOrder,
|
||||
reconcileSceneListOrder,
|
||||
removeFromSceneListOrder,
|
||||
} from '../../shared/graph/sceneListOrder';
|
||||
import {
|
||||
buildPartialExportProject,
|
||||
computeGraphImportOffsetX,
|
||||
@@ -217,6 +222,7 @@ export class ZipProjectStore {
|
||||
schemaVersion: PROJECT_SCHEMA_VERSION,
|
||||
},
|
||||
scenes: {},
|
||||
sceneListOrder: [],
|
||||
assets: {},
|
||||
campaignAudios: [],
|
||||
currentSceneId: null,
|
||||
@@ -591,7 +597,14 @@ export class ZipProjectStore {
|
||||
...(patch.layout ? { layout: { ...base.layout, ...patch.layout } } : null),
|
||||
};
|
||||
|
||||
await this.updateProject((p) => ({ ...p, scenes: { ...p.scenes, [sceneId]: next } }));
|
||||
await this.updateProject((p) => {
|
||||
const scenes = { ...p.scenes, [sceneId]: next };
|
||||
const sceneListOrder =
|
||||
existing != null
|
||||
? reconcileSceneListOrder(scenes, p.sceneListOrder)
|
||||
: prependSceneListOrder(reconcileSceneListOrder(p.scenes, p.sceneListOrder), sceneId);
|
||||
return { ...p, scenes, sceneListOrder };
|
||||
});
|
||||
return next;
|
||||
}
|
||||
|
||||
@@ -638,6 +651,10 @@ export class ZipProjectStore {
|
||||
return {
|
||||
...withGraph,
|
||||
scenes: nextScenes,
|
||||
sceneListOrder: removeFromSceneListOrder(
|
||||
reconcileSceneListOrder(withGraph.scenes, p.sceneListOrder),
|
||||
sceneId,
|
||||
),
|
||||
currentSceneId,
|
||||
};
|
||||
});
|
||||
@@ -646,6 +663,18 @@ export class ZipProjectStore {
|
||||
return latest;
|
||||
}
|
||||
|
||||
async setSceneListOrder(sceneListOrder: SceneId[]): Promise<Project> {
|
||||
const open = this.openProject;
|
||||
if (!open) throw new Error('No open project');
|
||||
await this.updateProject((p) => ({
|
||||
...p,
|
||||
sceneListOrder: reconcileSceneListOrder(p.scenes, sceneListOrder),
|
||||
}));
|
||||
const latest = this.getOpenProject();
|
||||
if (!latest) throw new Error('No open project');
|
||||
return latest;
|
||||
}
|
||||
|
||||
async updateSceneGraphNodePosition(nodeId: GraphNodeId, x: number, y: number): Promise<Project> {
|
||||
const open = this.openProject;
|
||||
if (!open) throw new Error('No open project');
|
||||
@@ -1711,6 +1740,10 @@ function normalizeProject(p: Project): Project {
|
||||
sceneGraphNodes,
|
||||
sceneGraphEdges,
|
||||
currentGraphNodeId,
|
||||
sceneListOrder: reconcileSceneListOrder(
|
||||
scenes,
|
||||
(p as { sceneListOrder?: SceneId[] }).sceneListOrder,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user