diff --git a/.memory/worklog.json b/.memory/worklog.json index c4b9cb6..f68bf21 100644 --- a/.memory/worklog.json +++ b/.memory/worklog.json @@ -1197,6 +1197,13 @@ "type": "session-heartbeat", "message": "Claude 会话活跃 · 最近命令:claude · 2 项未提交变更 · 最近提交:auto-save 2026-05-13 10:05 (~3)", "files_changed": 2 + }, + { + "ts": "2026-05-13T10:11:03+08:00", + "type": "commit", + "message": "auto-save 2026-05-13 10:10 (~3)", + "hash": "7db74cf", + "files_changed": 3 } ] } diff --git a/web/app/page.tsx b/web/app/page.tsx index 8a1879a..1a1b414 100644 --- a/web/app/page.tsx +++ b/web/app/page.tsx @@ -13,7 +13,7 @@ import { type NodeData, } from "@/components/nodes" import { ThemeToggle } from "@/components/theme-toggle" -import { Dashboard } from "@/components/dashboard" +import { Dashboard, type DashboardHandle } from "@/components/dashboard" import { addManualFrame, analyzeJob, createJob, getJob, uploadJob, type Job } from "@/lib/api" import { VideoLightbox } from "@/components/video-lightbox" @@ -64,6 +64,7 @@ export default function Home() { const [selectedFrames, setSelectedFrames] = useState>(new Set()) const [expandedFrame, setExpandedFrame] = useState(null) const [videoLightboxOpen, setVideoLightboxOpen] = useState(false) + const dashboardRef = useRef(null) // 把 setJob(prev=>...) 翻译成 setJobs 里更新当前 active const setJob = useCallback((updater: Job | ((prev: Job | null) => Job | null) | null) => { @@ -225,6 +226,7 @@ export default function Home() { onOpenVideoLightbox: () => setVideoLightboxOpen(true), onSwitchJob: handleSwitchJob, onJobUpdate: setJob as any, + onOpenPanel: (key: string) => dashboardRef.current?.openPanel(key), }), [job, jobs, activeJobId, submitting, analyzing, selectedFrames, expandedFrame, handleSubmit, handleUpload, handleAnalyze, handleToggleFrame, handleAddManualFrame, handleSwitchJob, setJob]) // 用 useNodesState 让 ReactFlow 自己管位置(避免轮询时重置 drag) @@ -281,7 +283,7 @@ export default function Home() { className="relative z-10 flex-shrink-0 border-r border-white/5 bg-black/20 backdrop-blur-xl overflow-y-auto" style={{ width: 88 }} > - + {/* 右区:紧凑 DAG 节点流图(撑满剩余宽度) */} diff --git a/web/components/dashboard.tsx b/web/components/dashboard.tsx index b3c89ac..cad86ed 100644 --- a/web/components/dashboard.tsx +++ b/web/components/dashboard.tsx @@ -1,5 +1,5 @@ "use client" -import { useEffect, useRef, useState, type ReactNode } from "react" +import { forwardRef, useEffect, useImperativeHandle, useRef, useState, type ReactNode } from "react" import { createPortal } from "react-dom" import { Link2, Upload, Download, Scissors, Image as ImageIcon, @@ -77,7 +77,11 @@ interface Props { data: NodeData } -export function Dashboard({ data }: Props) { +export interface DashboardHandle { + openPanel: (key: string) => void +} + +export const Dashboard = forwardRef(function Dashboard({ data }, ref) { const { job } = data const [url, setUrl] = useState("") const [videoT, setVideoT] = useState(0) @@ -85,6 +89,9 @@ export function Dashboard({ data }: Props) { const [expanded, setExpanded] = useState>(new Set()) const [mounted, setMounted] = useState(false) useEffect(() => setMounted(true), []) + useImperativeHandle(ref, () => ({ + openPanel: (key: string) => setExpanded(new Set([key])), + }), []) const tileRefs = useRef>({}) const fileRef = useRef(null) const videoRef = useRef(null) @@ -583,7 +590,7 @@ export function Dashboard({ data }: Props) { ) } -} +}) /* ============================================================ ImageGenCard — 单张关键帧的生图卡 diff --git a/web/components/nodes/index.tsx b/web/components/nodes/index.tsx index 02d65c3..4d8c1c7 100644 --- a/web/components/nodes/index.tsx +++ b/web/components/nodes/index.tsx @@ -26,6 +26,7 @@ export interface NodeData { onOpenVideoLightbox: () => void onSwitchJob: (id: string) => void onJobUpdate: (j: Job) => void + onOpenPanel?: (key: string) => void // 控制 sidebar 哪个 drawer 展开 } /* ---- 状态映射工具 ---- */ @@ -571,8 +572,8 @@ export function ImageGenNode({ data, selected }: any) { {previews.map((p) => (