forked from 77media/video-flow
281 lines
11 KiB
TypeScript
281 lines
11 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from 'react';
|
|
import { motion } from 'framer-motion';
|
|
import {
|
|
DndContext,
|
|
closestCenter,
|
|
KeyboardSensor,
|
|
PointerSensor,
|
|
useSensor,
|
|
useSensors,
|
|
} from '@dnd-kit/core';
|
|
import {
|
|
arrayMove,
|
|
SortableContext,
|
|
sortableKeyboardCoordinates,
|
|
verticalListSortingStrategy,
|
|
} from '@dnd-kit/sortable';
|
|
import type { DragEndEvent } from '@dnd-kit/core';
|
|
import { ScriptMetaInfo } from '../script-overview/script-meta-info';
|
|
import { SceneFilmstrip } from '../script-overview/scene-filmstrip';
|
|
import { SceneCardList } from '../script-overview/scene-card-list';
|
|
import { FloatingToolbar } from '../script-overview/floating-toolbar';
|
|
|
|
// 场景数据结构
|
|
export interface Scene {
|
|
id: string;
|
|
name: string;
|
|
description: string;
|
|
plot: string;
|
|
dialogue: string;
|
|
narration: string;
|
|
imageUrl: string;
|
|
}
|
|
|
|
// 剧本元信息数据结构
|
|
export interface ScriptMeta {
|
|
title: string;
|
|
type: string;
|
|
genre: string;
|
|
tags: string[];
|
|
duration: string;
|
|
uploadTime: string;
|
|
}
|
|
|
|
export default function ScriptOverview() {
|
|
// Configure drag sensors
|
|
const sensors = useSensors(
|
|
useSensor(PointerSensor),
|
|
useSensor(KeyboardSensor, {
|
|
coordinateGetter: sortableKeyboardCoordinates,
|
|
})
|
|
);
|
|
|
|
// Example Data
|
|
const [scriptMeta] = useState<ScriptMeta>({
|
|
title: "Lost Stars",
|
|
type: "Short Drama",
|
|
genre: "Sci-Fi/Mystery",
|
|
tags: ["Space", "Psychology", "Future"],
|
|
duration: "20-25 minutes",
|
|
uploadTime: "2024-03-20"
|
|
});
|
|
|
|
const [scenes, setScenes] = useState<Scene[]>([
|
|
{
|
|
id: "scene-1",
|
|
name: "Space Station Interior",
|
|
description: "Main control room of the International Space Station",
|
|
plot: "Protagonist discovers an anomalous signal",
|
|
dialogue: "Captain: This signal... it's not from Earth",
|
|
narration: "In the darkness of space, a faint light blinks",
|
|
imageUrl: "https://smart-video-ai.oss-cn-beijing.aliyuncs.com/frames/d877fa43-4856-4acb-9a3b-627c28275343/frame_000007.jpg/1750507514_tmphfb431oc_000007.jpg",
|
|
},
|
|
{
|
|
id: "scene-2",
|
|
name: "Space Station Interior",
|
|
description: "Main control room of the International Space Station",
|
|
plot: "Protagonist discovers an anomalous signal",
|
|
dialogue: "Captain: This signal... it's not from Earth",
|
|
narration: "In the darkness of space, a faint light blinks",
|
|
imageUrl: "https://smart-video-ai.oss-cn-beijing.aliyuncs.com/frames/d877fa43-4856-4acb-9a3b-627c28275343/frame_000007.jpg/1750507514_tmphfb431oc_000007.jpg",
|
|
},
|
|
{
|
|
id: "scene-3",
|
|
name: "Space Station Interior",
|
|
description: "Main control room of the International Space Station",
|
|
plot: "Protagonist discovers an anomalous signal",
|
|
dialogue: "Captain: This signal... it's not from Earth",
|
|
narration: "In the darkness of space, a faint light blinks",
|
|
imageUrl: "https://smart-video-ai.oss-cn-beijing.aliyuncs.com/frames/d877fa43-4856-4acb-9a3b-627c28275343/frame_000007.jpg/1750507514_tmphfb431oc_000007.jpg",
|
|
},
|
|
{
|
|
id: "scene-5",
|
|
name: "Space Station Interior",
|
|
description: "Main control room of the International Space Station",
|
|
plot: "Protagonist discovers an anomalous signal",
|
|
dialogue: "Captain: This signal... it's not from Earth",
|
|
narration: "In the darkness of space, a faint light blinks",
|
|
imageUrl: "https://smart-video-ai.oss-cn-beijing.aliyuncs.com/frames/d877fa43-4856-4acb-9a3b-627c28275343/frame_000007.jpg/1750507514_tmphfb431oc_000007.jpg",
|
|
},
|
|
{
|
|
id: "scene-6",
|
|
name: "Space Station Interior",
|
|
description: "Main control room of the International Space Station",
|
|
plot: "Protagonist discovers an anomalous signal",
|
|
dialogue: "Captain: This signal... it's not from Earth",
|
|
narration: "In the darkness of space, a faint light blinks",
|
|
imageUrl: "https://smart-video-ai.oss-cn-beijing.aliyuncs.com/frames/d877fa43-4856-4acb-9a3b-627c28275343/frame_000007.jpg/1750507514_tmphfb431oc_000007.jpg",
|
|
},
|
|
{
|
|
id: "scene-7",
|
|
name: "Space Station Interior",
|
|
description: "Main control room of the International Space Station",
|
|
plot: "Protagonist discovers an anomalous signal",
|
|
dialogue: "Captain: This signal... it's not from Earth",
|
|
narration: "In the darkness of space, a faint light blinks",
|
|
imageUrl: "https://smart-video-ai.oss-cn-beijing.aliyuncs.com/frames/d877fa43-4856-4acb-9a3b-627c28275343/frame_000007.jpg/1750507514_tmphfb431oc_000007.jpg",
|
|
},
|
|
{
|
|
id: "scene-8",
|
|
name: "Space Station Interior",
|
|
description: "Main control room of the International Space Station",
|
|
plot: "Protagonist discovers an anomalous signal",
|
|
dialogue: "Captain: This signal... it's not from Earth",
|
|
narration: "In the darkness of space, a faint light blinks",
|
|
imageUrl: "https://smart-video-ai.oss-cn-beijing.aliyuncs.com/frames/d877fa43-4856-4acb-9a3b-627c28275343/frame_000007.jpg/1750507514_tmphfb431oc_000007.jpg",
|
|
},
|
|
{
|
|
id: "scene-9",
|
|
name: "Space Station Interior",
|
|
description: "Main control room of the International Space Station",
|
|
plot: "Protagonist discovers an anomalous signal",
|
|
dialogue: "Captain: This signal... it's not from Earth",
|
|
narration: "In the darkness of space, a faint light blinks",
|
|
imageUrl: "https://smart-video-ai.oss-cn-beijing.aliyuncs.com/frames/d877fa43-4856-4acb-9a3b-627c28275343/frame_000007.jpg/1750507514_tmphfb431oc_000007.jpg",
|
|
},
|
|
{
|
|
id: "scene-10",
|
|
name: "Space Station Interior",
|
|
description: "Main control room of the International Space Station",
|
|
plot: "Protagonist discovers an anomalous signal",
|
|
dialogue: "Captain: This signal... it's not from Earth",
|
|
narration: "In the darkness of space, a faint light blinks",
|
|
imageUrl: "https://smart-video-ai.oss-cn-beijing.aliyuncs.com/frames/d877fa43-4856-4acb-9a3b-627c28275343/frame_000007.jpg/1750507514_tmphfb431oc_000007.jpg",
|
|
},
|
|
{
|
|
id: "scene-11",
|
|
name: "Space Station Interior",
|
|
description: "Main control room of the International Space Station",
|
|
plot: "Protagonist discovers an anomalous signal",
|
|
dialogue: "Captain: This signal... it's not from Earth",
|
|
narration: "In the darkness of space, a faint light blinks",
|
|
imageUrl: "https://smart-video-ai.oss-cn-beijing.aliyuncs.com/frames/d877fa43-4856-4acb-9a3b-627c28275343/frame_000007.jpg/1750507514_tmphfb431oc_000007.jpg",
|
|
},
|
|
{
|
|
id: "scene-12",
|
|
name: "Space Station Interior",
|
|
description: "Main control room of the International Space Station",
|
|
plot: "Protagonist discovers an anomalous signal",
|
|
dialogue: "Captain: This signal... it's not from Earth",
|
|
narration: "In the darkness of space, a faint light blinks",
|
|
imageUrl: "https://smart-video-ai.oss-cn-beijing.aliyuncs.com/frames/d877fa43-4856-4acb-9a3b-627c28275343/frame_000007.jpg/1750507514_tmphfb431oc_000007.jpg",
|
|
},
|
|
{
|
|
id: "scene-13",
|
|
name: "Space Station Interior",
|
|
description: "Main control room of the International Space Station",
|
|
plot: "Protagonist discovers an anomalous signal",
|
|
dialogue: "Captain: This signal... it's not from Earth",
|
|
narration: "In the darkness of space, a faint light blinks",
|
|
imageUrl: "https://smart-video-ai.oss-cn-beijing.aliyuncs.com/frames/d877fa43-4856-4acb-9a3b-627c28275343/frame_000007.jpg/1750507514_tmphfb431oc_000007.jpg",
|
|
},
|
|
{
|
|
id: "scene-14",
|
|
name: "Space Station Interior",
|
|
description: "Main control room of the International Space Station",
|
|
plot: "Protagonist discovers an anomalous signal",
|
|
dialogue: "Captain: This signal... it's not from Earth",
|
|
narration: "In the darkness of space, a faint light blinks",
|
|
imageUrl: "https://smart-video-ai.oss-cn-beijing.aliyuncs.com/frames/d877fa43-4856-4acb-9a3b-627c28275343/frame_000007.jpg/1750507514_tmphfb431oc_000007.jpg",
|
|
}
|
|
// ... 更多场景数据
|
|
]);
|
|
|
|
const [selectedSceneId, setSelectedSceneId] = useState<string>();
|
|
|
|
// Handle scene drag and drop sorting
|
|
const handleDragEnd = (event: DragEndEvent) => {
|
|
const { active, over } = event;
|
|
|
|
if (active.id === over?.id) {
|
|
return;
|
|
}
|
|
|
|
const oldIndex = scenes.findIndex(scene => scene.id === active.id);
|
|
const newIndex = scenes.findIndex(scene => scene.id === over?.id);
|
|
|
|
if (oldIndex === -1 || newIndex === -1) {
|
|
return;
|
|
}
|
|
|
|
setScenes(arrayMove(scenes, oldIndex, newIndex));
|
|
};
|
|
|
|
// Handle scene updates
|
|
const handleSceneUpdate = (sceneId: string, updates: Partial<Scene>) => {
|
|
setScenes(scenes.map(scene =>
|
|
scene.id === sceneId ? { ...scene, ...updates } : scene
|
|
));
|
|
};
|
|
|
|
// Handle scene deletion
|
|
const handleSceneDelete = (sceneId: string) => {
|
|
setScenes(scenes.filter(scene => scene.id !== sceneId));
|
|
if (selectedSceneId === sceneId) {
|
|
setSelectedSceneId(undefined);
|
|
}
|
|
};
|
|
|
|
// Handle scene duplication
|
|
const handleSceneDuplicate = (sceneId: string) => {
|
|
const sceneToDuplicate = scenes.find(scene => scene.id === sceneId);
|
|
if (!sceneToDuplicate) return;
|
|
|
|
const newScene = {
|
|
...sceneToDuplicate,
|
|
id: `scene-${Date.now()}`,
|
|
name: `${sceneToDuplicate.name} (Copy)`
|
|
};
|
|
|
|
setScenes([...scenes, newScene]);
|
|
};
|
|
|
|
return (
|
|
<div className="h-full bg-[#0C0E11] text-white">
|
|
<div className="h-full flex">
|
|
{/* Left: Script Meta Info */}
|
|
<div className="flex-shrink-0 h-full">
|
|
<ScriptMetaInfo meta={scriptMeta} />
|
|
</div>
|
|
|
|
{/* Right: Scene Content */}
|
|
<div className="flex-grow min-w-0 h-full overflow-hidden flex flex-col">
|
|
{/* Scene Card List */}
|
|
<div className="flex-grow overflow-y-auto px-8">
|
|
<DndContext
|
|
sensors={sensors}
|
|
collisionDetection={closestCenter}
|
|
onDragEnd={handleDragEnd}
|
|
>
|
|
<SortableContext
|
|
items={scenes.map(scene => scene.id)}
|
|
strategy={verticalListSortingStrategy}
|
|
>
|
|
<SceneCardList
|
|
scenes={scenes}
|
|
selectedSceneId={selectedSceneId}
|
|
onSceneUpdate={handleSceneUpdate}
|
|
onSceneDelete={handleSceneDelete}
|
|
onSceneDuplicate={handleSceneDuplicate}
|
|
/>
|
|
</SortableContext>
|
|
</DndContext>
|
|
</div>
|
|
|
|
{/* Filmstrip Preview */}
|
|
<div className="flex-shrink-0 py-6 px-8">
|
|
<SceneFilmstrip
|
|
scenes={scenes}
|
|
selectedSceneId={selectedSceneId}
|
|
onSceneSelect={(sceneId: string) => {
|
|
setSelectedSceneId(sceneId);
|
|
}}
|
|
/>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|