auto-save 2026-05-14 02:30 (+2, ~4)
This commit is contained in:
@@ -9,13 +9,11 @@ import {
|
||||
import { Toaster, toast } from "sonner"
|
||||
import { LayoutGrid } from "lucide-react"
|
||||
import {
|
||||
InputNode, KeyframeNode, AudioNode,
|
||||
StoryboardNode, VideoGenNode, ComposeNode, KeyframePanelNode,
|
||||
InputNode, VisualLabNode, AudioNode,
|
||||
ComposeNode, KeyframePanelNode,
|
||||
type NodeData,
|
||||
} from "@/components/nodes"
|
||||
import { ThemeToggle } from "@/components/theme-toggle"
|
||||
import { StoryboardBar } from "@/components/storyboard-bar"
|
||||
import { StoryboardWorkbench } from "@/components/storyboard-workbench"
|
||||
import {
|
||||
addManualFrame, analyzeJob, createJob, getJob, listJobs, uploadJob, deleteFrame, deleteGeneratedImage,
|
||||
deleteGeneratedVideo, deleteCutout, generateStoryboardVideo,
|
||||
@@ -25,10 +23,8 @@ import { VideoLightbox } from "@/components/video-lightbox"
|
||||
|
||||
const NODE_TYPES = {
|
||||
input: InputNode,
|
||||
keyframe: KeyframeNode,
|
||||
visual: VisualLabNode,
|
||||
audio: AudioNode,
|
||||
storyboard: StoryboardNode,
|
||||
videogen: VideoGenNode,
|
||||
compose: ComposeNode,
|
||||
keyframePanel: KeyframePanelNode,
|
||||
}
|
||||
@@ -36,15 +32,13 @@ const NODE_TYPES = {
|
||||
const KEYFRAME_PANEL_ID = "keyframe-detail-panel"
|
||||
|
||||
// 合并 input + download + split 为一个节点
|
||||
// 分叉:上路 input → keyframe → storyboard → videogen ↘
|
||||
// 分叉:上路 input → visual lab ↘
|
||||
// 下路 input → audio ──────────────────────────→ compose
|
||||
const LAYOUT: Array<{ id: string; type: keyof typeof NODE_TYPES; x: number; y: number; w: number }> = [
|
||||
{ id: "input", type: "input", x: 40, y: 240, w: 320 },
|
||||
{ id: "keyframe", type: "keyframe", x: 460, y: 60, w: 360 },
|
||||
{ id: "visual", type: "visual", x: 460, y: 60, w: 620 },
|
||||
{ id: "audio", type: "audio", x: 460, y: 440, w: 320 },
|
||||
{ id: "storyboard", type: "storyboard", x: 880, y: 60, w: 360 },
|
||||
{ id: "videogen", type: "videogen", x: 1260, y: 60, w: 280 },
|
||||
{ id: "compose", type: "compose", x: 1640, y: 240, w: 320 },
|
||||
{ id: "compose", type: "compose", x: 1160, y: 240, w: 320 },
|
||||
]
|
||||
|
||||
const NODE_SIZES_KEY = "skg-tk:node-sizes:v2"
|
||||
@@ -74,11 +68,9 @@ function loadNodePins(): string[] {
|
||||
}
|
||||
|
||||
const EDGES_RAW: Array<[string, string]> = [
|
||||
["input", "keyframe"],
|
||||
["input", "visual"],
|
||||
["input", "audio"],
|
||||
["keyframe", "storyboard"],
|
||||
["storyboard", "videogen"],
|
||||
["videogen", "compose"],
|
||||
["visual", "compose"],
|
||||
["audio", "compose"],
|
||||
]
|
||||
|
||||
@@ -521,9 +513,7 @@ export default function Home() {
|
||||
// 按管线列分组(顶 → 底):图层 1 输入 → 5 合成
|
||||
const COLUMNS: string[][] = [
|
||||
["input"],
|
||||
["keyframe", "audio"],
|
||||
["storyboard"],
|
||||
["videogen"],
|
||||
["visual", "audio"],
|
||||
["compose"],
|
||||
]
|
||||
const GAP_X = 80
|
||||
@@ -602,11 +592,11 @@ export default function Home() {
|
||||
|
||||
let shouldFocusNewPanel = false
|
||||
setNodes((prev) => {
|
||||
const keyframeNode = prev.find((n) => n.id === "keyframe")
|
||||
const visualNode = prev.find((n) => n.id === "visual")
|
||||
const inputNode = prev.find((n) => n.id === "input")
|
||||
const defaultPosition = {
|
||||
x: (inputNode?.position.x ?? 40) - 820,
|
||||
y: (keyframeNode?.position.y ?? 60),
|
||||
y: (visualNode?.position.y ?? 60),
|
||||
}
|
||||
const exists = prev.some((n) => n.id === KEYFRAME_PANEL_ID)
|
||||
if (exists) {
|
||||
@@ -637,7 +627,7 @@ export default function Home() {
|
||||
if (shouldFocusNewPanel) {
|
||||
window.setTimeout(() => {
|
||||
flowRef.current?.fitView?.({
|
||||
nodes: [{ id: KEYFRAME_PANEL_ID }, { id: "keyframe" }],
|
||||
nodes: [{ id: KEYFRAME_PANEL_ID }, { id: "visual" }],
|
||||
padding: 0.18,
|
||||
duration: 260,
|
||||
})
|
||||
@@ -649,11 +639,10 @@ export default function Home() {
|
||||
useEffect(() => {
|
||||
const doneOf: Record<string, boolean> = {
|
||||
input: !!job?.video_url,
|
||||
keyframe: !!job && job.frames.length > 0,
|
||||
visual: !!job && (job.frames.length > 0 || (job.generated_videos?.length ?? 0) > 0),
|
||||
asr: !!job && job.transcript.length > 0,
|
||||
translate: !!job && (job.transcript.some((s) => s.zh) ?? false),
|
||||
rewrite: !!job && (job.transcript.some((s) => s.zh) ?? false),
|
||||
storyboard: selectedFrames.size > 0,
|
||||
}
|
||||
setEdges((prev) => prev.map((e) => ({ ...e, animated: !!doneOf[e.source] })))
|
||||
}, [job, setEdges])
|
||||
|
||||
Reference in New Issue
Block a user