feat(editor): DnD сцен в список, порядок списка и правки импорта
Можно перетащить изображения/видео в колонку сцен: создаются новые сцены с превью и названием из файла, с полноэкранным прогрессом и отчётом о пропущенных файлах. Добавлен ручной порядок сцен в списке (sceneListOrder) с сохранением в проект; перетаскивание карточек отделено от импорта файлов. Во время сортировки снова работает скролл колесом. Исправлен залипающий disabled у «+ Новая сцена» после создания сцены. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
import assert from 'node:assert/strict';
|
||||
import test from 'node:test';
|
||||
|
||||
import type { Scene, SceneId } from '../types';
|
||||
|
||||
import {
|
||||
defaultSceneListOrder,
|
||||
moveSceneInListOrder,
|
||||
prependSceneListOrder,
|
||||
reconcileSceneListOrder,
|
||||
removeFromSceneListOrder,
|
||||
} from './sceneListOrder';
|
||||
|
||||
function scene(id: string): Scene {
|
||||
return {
|
||||
id: id as SceneId,
|
||||
title: id,
|
||||
description: '',
|
||||
previewAssetId: null,
|
||||
previewThumbAssetId: null,
|
||||
previewAssetType: null,
|
||||
previewVideoAutostart: false,
|
||||
previewRotationDeg: 0,
|
||||
darkenScene: false,
|
||||
media: { videos: [], audios: [] },
|
||||
settings: { autoplayVideo: false, autoplayAudio: true, loopVideo: true, loopAudio: true },
|
||||
connections: [],
|
||||
layout: { x: 0, y: 0 },
|
||||
};
|
||||
}
|
||||
|
||||
void test('defaultSceneListOrder sorts by id timestamp newest first', () => {
|
||||
const scenes = {
|
||||
scene_a_100: scene('scene_a_100'),
|
||||
scene_b_200: scene('scene_b_200'),
|
||||
scene_c_150: scene('scene_c_150'),
|
||||
} as Record<SceneId, Scene>;
|
||||
assert.deepEqual(defaultSceneListOrder(scenes), ['scene_b_200', 'scene_c_150', 'scene_a_100']);
|
||||
});
|
||||
|
||||
void test('reconcileSceneListOrder drops missing and appends new', () => {
|
||||
const scenes = {
|
||||
a: scene('a'),
|
||||
b: scene('b'),
|
||||
c: scene('c'),
|
||||
} as Record<SceneId, Scene>;
|
||||
assert.deepEqual(reconcileSceneListOrder(scenes, ['b', 'gone', 'a'] as SceneId[]), ['b', 'a', 'c']);
|
||||
});
|
||||
|
||||
void test('moveSceneInListOrder before/after', () => {
|
||||
const order = ['a', 'b', 'c', 'd'] as SceneId[];
|
||||
assert.deepEqual(moveSceneInListOrder(order, 'd' as SceneId, 'b' as SceneId, 'before'), [
|
||||
'a',
|
||||
'd',
|
||||
'b',
|
||||
'c',
|
||||
]);
|
||||
assert.deepEqual(moveSceneInListOrder(order, 'a' as SceneId, 'c' as SceneId, 'after'), [
|
||||
'b',
|
||||
'c',
|
||||
'a',
|
||||
'd',
|
||||
]);
|
||||
assert.deepEqual(moveSceneInListOrder(order, 'b' as SceneId, 'b' as SceneId, 'before'), [
|
||||
'a',
|
||||
'b',
|
||||
'c',
|
||||
'd',
|
||||
]);
|
||||
});
|
||||
|
||||
void test('prepend and remove helpers', () => {
|
||||
const order = ['a', 'b'] as SceneId[];
|
||||
assert.deepEqual(prependSceneListOrder(order, 'c' as SceneId), ['c', 'a', 'b']);
|
||||
assert.deepEqual(prependSceneListOrder(order, 'a' as SceneId), ['a', 'b']);
|
||||
assert.deepEqual(removeFromSceneListOrder(order, 'a' as SceneId), ['b']);
|
||||
});
|
||||
Reference in New Issue
Block a user