From b8fa19aeaac7a80ff1f2ce669a258e3471b88681 Mon Sep 17 00:00:00 2001 From: kang Date: Thu, 14 May 2026 03:15:11 +0800 Subject: [PATCH] auto-save 2026-05-14 03:14 (~2) --- .memory/worklog.json | 13 ++++++ web/components/nodes/index.tsx | 79 +++++++++------------------------- 2 files changed, 33 insertions(+), 59 deletions(-) diff --git a/.memory/worklog.json b/.memory/worklog.json index b036fee..9c3f7f0 100644 --- a/.memory/worklog.json +++ b/.memory/worklog.json @@ -3011,6 +3011,19 @@ "type": "session-heartbeat", "message": "Codex 会话活跃 · 最近命令:codex · 3 项未提交变更 · 最近提交:auto-save 2026-05-14 03:03 (~3)", "files_changed": 3 + }, + { + "ts": "2026-05-14T03:09:40+08:00", + "type": "commit", + "message": "auto-save 2026-05-14 03:09 (~3)", + "hash": "79b3f79", + "files_changed": 3 + }, + { + "ts": "2026-05-13T19:13:12Z", + "type": "session-heartbeat", + "message": "Claude 会话活跃 · 最近命令:claude · 1 项未提交变更 · 最近提交:auto-save 2026-05-14 03:09 (~3)", + "files_changed": 1 } ] } diff --git a/web/components/nodes/index.tsx b/web/components/nodes/index.tsx index 65fc598..4f78d1b 100644 --- a/web/components/nodes/index.tsx +++ b/web/components/nodes/index.tsx @@ -10,7 +10,7 @@ import { type NodeProps, useReactFlow } from "@xyflow/react" import { Link2, Upload, Download, Scissors, Image as ImageIcon, Mic, Languages, FileEdit, Film, FileVideo, Loader2, Plus, X, LayoutGrid, Pin, Maximize2, - Copy, Trash2, + Copy, Trash2, Move, PanelLeft, PanelRight, PanelBottom, } from "lucide-react" import { toast } from "sonner" import { NodeShell, type NodeStatus, type NodeKind } from "./node-shell" @@ -21,6 +21,8 @@ import { } from "@/lib/api" import { FrameLightbox } from "@/components/lightbox" +export type CanvasPanelDock = "canvas" | "left" | "right" | "bottom" + export interface NodeData { job: Job | null // 当前 active job jobs: Job[] // 所有 job 列表 @@ -31,6 +33,9 @@ export interface NodeData { expandedFrame: number | null framePanelScale?: number framePanelPinned?: boolean + videoPanelJobId?: string | null + videoPanelScale?: number + videoPanelDock?: CanvasPanelDock onSubmitUrl: (url: string) => void onUploadFile: (file: File) => void onAnalyze: () => void @@ -41,6 +46,11 @@ export interface NodeData { onFramePanelPinnedChange?: (pinned: boolean) => void onCloseExpandedFrame: () => void onAddManualFrame: (t: number) => void + onAddManualFrameForJob?: (jobId: string, t: number) => Promise | void + onOpenVideoPanel?: (jobId: string) => void + onCloseVideoPanel?: () => void + onVideoPanelScaleChange?: (scale: number) => void + onVideoPanelDockChange?: (dock: CanvasPanelDock) => void onOpenVideoLightbox: () => void onSwitchJob: (id: string) => void onJobUpdate: (j: Job) => void @@ -384,15 +394,11 @@ function DeleteConfirmDialog({ export function InputNode({ data, selected }: NodeProps<{ data: NodeData }> | any) { const d: NodeData = data const [url, setUrl] = useState("") - const [videoT, setVideoT] = useState(0) - const [addingFrame, setAddingFrame] = useState(false) - const [videoExpanded, setVideoExpanded] = useState(false) const [hoverPreviewJob, setHoverPreviewJob] = useState | null>(null) const [pinnedPreviewJob, setPinnedPreviewJob] = useState | null>(null) const [deleteJobTarget, setDeleteJobTarget] = useState(null) const rootRef = useRef(null) const fileRef = useRef(null) - const videoRef = useRef(null) const job = d.job // 点击 input 节点外的任何位置 → 取消 pin(capture 阶段,避免 ReactFlow pane 拦截) @@ -419,7 +425,7 @@ export function InputNode({ data, selected }: NodeProps<{ data: NodeData }> | an
{/* 多视频缩略图浮条 — 「+」在最左,job 按时间倒序(最新靠左高亮),统一高度 64,宽度按视频原比例,一行横滚。 浮条宽度 = 节点宽度(节点拖宽后浮条同步变宽,可见更多缩略图,少滚动)。 */} - {!videoExpanded && d.jobs.length > 0 && ( + {d.jobs.length > 0 && ( {/* + 再上传一个(放在最前面) */}
)}
- {ready ? `${j.duration.toFixed(1)}s` : "…"} + {ready ? `${(j.duration ?? 0).toFixed(1)}s` : "…"}
{d.onDeleteJob && ( @@ -515,7 +525,7 @@ export function InputNode({ data, selected }: NodeProps<{ data: NodeData }> | an {(() => { const anchor = pinnedPreviewJob ?? hoverPreviewJob - if (!anchor || videoExpanded) return null + if (!anchor) return null const previewJob = d.jobs.find((j) => j.id === anchor.id) if (!previewJob?.video_url) return null const aspectStr = previewJob.height ? `${previewJob.width}/${previewJob.height}` : "9/16" @@ -535,55 +545,6 @@ export function InputNode({ data, selected }: NodeProps<{ data: NodeData }> | an ) })()} - {/* 展开态 — 稍微放大(360 宽),含 controls + 加帧按钮,不全屏 */} - {hasVideo && job && videoExpanded && ( -
-
e.stopPropagation()} - className="relative rounded-xl overflow-hidden border border-white/25 shadow-2xl bg-black" - style={{ width: 360, animation: "drawer-in 0.18s cubic-bezier(0.32, 0.72, 0, 1)" }} - > -
-
- )} - }