diff --git a/.memory/worklog.json b/.memory/worklog.json index 8acf697..b0bead0 100644 --- a/.memory/worklog.json +++ b/.memory/worklog.json @@ -1602,6 +1602,13 @@ "type": "session-heartbeat", "message": "Claude 会话活跃 · 最近命令:claude · 3 项未提交变更 · 最近提交:auto-save 2026-05-13 13:42 (+1, ~4)", "files_changed": 3 + }, + { + "ts": "2026-05-13T13:48:39+08:00", + "type": "commit", + "message": "auto-save 2026-05-13 13:48 (~3)", + "hash": "2d297ec", + "files_changed": 3 } ] } diff --git a/web/app/page.tsx b/web/app/page.tsx index 4c6c945..4e7b146 100644 --- a/web/app/page.tsx +++ b/web/app/page.tsx @@ -15,6 +15,7 @@ import { import { ThemeToggle } from "@/components/theme-toggle" import { Dashboard, type DashboardHandle } from "@/components/dashboard" import { StoryboardBar } from "@/components/storyboard-bar" +import { StoryboardEditor } from "@/components/storyboard-editor" import { addManualFrame, analyzeJob, createJob, getJob, uploadJob, deleteFrame, deleteGeneratedImage, type Job } from "@/lib/api" import { VideoLightbox } from "@/components/video-lightbox" @@ -65,6 +66,7 @@ export default function Home() { const [selectedFrames, setSelectedFrames] = useState>(new Set()) const [expandedFrame, setExpandedFrame] = useState(null) const [videoLightboxOpen, setVideoLightboxOpen] = useState(false) + const [storyboardFrame, setStoryboardFrame] = useState(null) const dashboardRef = useRef(null) // 把 setJob(prev=>...) 翻译成 setJobs 里更新当前 active @@ -259,6 +261,7 @@ export default function Home() { onOpenPanel: (key: string) => dashboardRef.current?.openPanel(key), onDeleteFrame: handleDeleteFrame, onDeleteGenerated: handleDeleteGenerated, + onOpenStoryboard: (idx: number) => setStoryboardFrame(idx), }), [job, jobs, activeJobId, submitting, analyzing, selectedFrames, expandedFrame, handleSubmit, handleUpload, handleAnalyze, handleToggleFrame, handleAddManualFrame, handleSwitchJob, setJob, handleDeleteFrame, handleDeleteGenerated]) // 用 useNodesState 让 ReactFlow 自己管位置(避免轮询时重置 drag) @@ -323,7 +326,7 @@ export default function Home() {
setVideoLightboxOpen(false)} onAddFrame={handleAddManualFrame} /> + + {/* 分镜头编排专属面板 — imagegen 节点 / storyboard bar 缩略图点击进入 */} + setStoryboardFrame(null)} + /> ) diff --git a/web/components/nodes/index.tsx b/web/components/nodes/index.tsx index ae66e66..fe71caf 100644 --- a/web/components/nodes/index.tsx +++ b/web/components/nodes/index.tsx @@ -29,6 +29,7 @@ export interface NodeData { onOpenPanel?: (key: string) => void // 控制 sidebar 哪个 drawer 展开 onDeleteFrame?: (idx: number) => void // 删整张关键帧 onDeleteGenerated?: (frameIdx: number, genId: string) => void // 删单张生成图 + onOpenStoryboard?: (frameIdx: number) => void // 打开分镜头编排专属面板 } /* ---- 状态映射工具 ---- */ diff --git a/web/components/storyboard-bar.tsx b/web/components/storyboard-bar.tsx index 60eb625..fb29f74 100644 --- a/web/components/storyboard-bar.tsx +++ b/web/components/storyboard-bar.tsx @@ -7,10 +7,10 @@ import { type Job, type KeyFrame, effectiveFrameUrl } from "@/lib/api" interface Props { job: Job | null selectedFrames: Set - onExpandFrame: (idx: number) => void + onOpenStoryboard: (idx: number) => void } -export function StoryboardBar({ job, selectedFrames, onExpandFrame }: Props) { +export function StoryboardBar({ job, selectedFrames, onOpenStoryboard }: Props) { const [collapsed, setCollapsed] = useState(false) const [mounted, setMounted] = useState(false) useEffect(() => setMounted(true), []) @@ -71,7 +71,7 @@ export function StoryboardBar({ job, selectedFrames, onExpandFrame }: Props) { +
+ + {/* 主体 — 左大图 + 右素材 / 操作 */} +
+ {/* 左:分镜大图 */} +
+ {`frame +
+ {frame.cleaned_applied ? "✨ 已清洗版本" : "原图"} +
+
+ + {/* 右:元素 + Phase 2 操作占位 */} +
+
+
+ + 该分镜的元素清单 + + · {elementsWithCutout.length}/{elements.length} 已裁切 + +
+ {elements.length === 0 ? ( +
+ 暂无元素 · 到关键帧节点画框提取后会出现在这里 +
+ ) : ( +
+ {elements.map((e) => ( +
+
+ {e.cutout_id ? ( + {e.name_zh} + ) : ( +
+ +
+ )} +
+
{e.name_zh}
+
{e.name_en || "(无英文)"}
+
+ ))} +
+ )} +
+ + {/* 编排操作占位(Phase 2) */} +
+
+ + 编排操作 · Phase 2 待实施 +
+
+ + + +
+
+ 这些功能稍后填入。当前先用关键帧节点的「清洗 + 提取」准备好素材。 +
+
+
+
+ + {/* 底部 */} +
+ ESC 关闭 +
+ + , + document.body, + ) +}