auto-save 2026-05-14 00:48 (+4, ~3)
This commit is contained in:
@@ -64,6 +64,18 @@ function loadNodeSizes(): Record<string, NodeSize> {
|
||||
}
|
||||
}
|
||||
|
||||
const NODE_PINS_KEY = "skg-tk:node-pins:v1"
|
||||
|
||||
function loadNodePins(): string[] {
|
||||
if (typeof window === "undefined") return []
|
||||
try {
|
||||
const raw = window.localStorage.getItem(NODE_PINS_KEY)
|
||||
return raw ? JSON.parse(raw) : []
|
||||
} catch {
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
const EDGES_RAW: Array<[string, string]> = [
|
||||
["input", "keyframe"],
|
||||
["input", "asr"],
|
||||
@@ -412,6 +424,16 @@ export default function Home() {
|
||||
return () => { if (pollRef.current) clearInterval(pollRef.current) }
|
||||
}, [job?.id, job?.status, job?.generated_videos?.map((v) => `${v.id}:${v.status}:${v.progress}`).join("|")])
|
||||
|
||||
const [pinnedNodes, setPinnedNodes] = useState<Set<string>>(() => new Set(loadNodePins()))
|
||||
const handleToggleNodePin = useCallback((id: string) => {
|
||||
setPinnedNodes((prev) => {
|
||||
const next = new Set(prev)
|
||||
if (next.has(id)) next.delete(id); else next.add(id)
|
||||
try { window.localStorage.setItem(NODE_PINS_KEY, JSON.stringify([...next])) } catch {}
|
||||
return next
|
||||
})
|
||||
}, [])
|
||||
|
||||
const nodeData: NodeData = useMemo(() => ({
|
||||
job,
|
||||
jobs,
|
||||
@@ -444,7 +466,9 @@ export default function Home() {
|
||||
setWorkbenchOpen(true)
|
||||
},
|
||||
onCopyImage: handleCopyImage,
|
||||
}), [job, jobs, activeJobId, submitting, analyzing, selectedFrames, expandedFrame, framePanelScale, framePanelPinned, handleSubmit, handleUpload, handleAnalyze, handleToggleFrame, handleOpenFramePanel, handleFramePanelScaleChange, handleAddManualFrame, handleSwitchJob, setJob, handleDeleteFrame, handleDeleteGenerated, handleDeleteVideo, handleCopyImage])
|
||||
pinnedNodes,
|
||||
onToggleNodePin: handleToggleNodePin,
|
||||
}), [job, jobs, activeJobId, submitting, analyzing, selectedFrames, expandedFrame, framePanelScale, framePanelPinned, handleSubmit, handleUpload, handleAnalyze, handleToggleFrame, handleOpenFramePanel, handleFramePanelScaleChange, handleAddManualFrame, handleSwitchJob, setJob, handleDeleteFrame, handleDeleteGenerated, handleDeleteVideo, handleCopyImage, pinnedNodes, handleToggleNodePin])
|
||||
|
||||
// 用 useNodesState 让 ReactFlow 自己管位置(避免轮询时重置 drag)
|
||||
const savedSizes = useMemo(() => loadNodeSizes(), [])
|
||||
@@ -453,12 +477,13 @@ export default function Home() {
|
||||
const s = savedSizes[n.id] ?? {}
|
||||
const w = s.w ?? n.w
|
||||
const h = s.h
|
||||
const isPinned = pinnedNodes.has(n.id)
|
||||
return {
|
||||
id: n.id,
|
||||
type: n.type,
|
||||
position: { x: n.x, y: n.y },
|
||||
data: nodeData,
|
||||
draggable: true,
|
||||
draggable: !isPinned,
|
||||
width: w,
|
||||
...(typeof h === "number" ? { height: h } : {}),
|
||||
style: { width: w, ...(typeof h === "number" ? { height: h } : {}) },
|
||||
@@ -466,6 +491,13 @@ export default function Home() {
|
||||
}),
|
||||
)
|
||||
|
||||
// pinned 变化时同步每个节点 draggable
|
||||
useEffect(() => {
|
||||
setNodes((prev) => prev.map((n) =>
|
||||
n.id === KEYFRAME_PANEL_ID ? n : { ...n, draggable: !pinnedNodes.has(n.id) },
|
||||
))
|
||||
}, [pinnedNodes, setNodes])
|
||||
|
||||
// 持久化每个节点宽 / 高到 localStorage(KeyframePanelNode 自己管尺寸,不写回)
|
||||
useEffect(() => {
|
||||
const sizes: Record<string, NodeSize> = {}
|
||||
|
||||
Reference in New Issue
Block a user