auto-save 2026-05-13 19:28 (~4)
This commit is contained in:
@@ -3,7 +3,7 @@ import { useEffect, useRef, useState } from "react"
|
||||
import { type NodeProps } from "@xyflow/react"
|
||||
import {
|
||||
Link2, Upload, Download, Scissors, Image as ImageIcon,
|
||||
Mic, Languages, FileEdit, Film, FileVideo, Loader2, Plus, X, LayoutGrid,
|
||||
Mic, Languages, FileEdit, Film, FileVideo, Loader2, Plus, X, LayoutGrid, Pin,
|
||||
} from "lucide-react"
|
||||
import { NodeShell, type NodeStatus, type NodeKind } from "./node-shell"
|
||||
import { type Job, type ImageRef, effectiveFrameUrl, videoUrl, hasCutout, representativeCutoutUrl } from "@/lib/api"
|
||||
@@ -17,12 +17,16 @@ export interface NodeData {
|
||||
analyzing: boolean
|
||||
selectedFrames: Set<number>
|
||||
expandedFrame: number | null
|
||||
framePanelScale?: number
|
||||
framePanelPinned?: boolean
|
||||
onSubmitUrl: (url: string) => void
|
||||
onUploadFile: (file: File) => void
|
||||
onAnalyze: () => void
|
||||
onToggleFrame: (idx: number) => void
|
||||
onExpandFrame: (idx: number) => void
|
||||
onOpenFramePanel?: (idx: number) => void // 打开/找回画布内关键帧详情面板
|
||||
onFramePanelScaleChange?: (scale: number) => void
|
||||
onFramePanelPinnedChange?: (pinned: boolean) => void
|
||||
onCloseExpandedFrame: () => void
|
||||
onAddManualFrame: (t: number) => void
|
||||
onOpenVideoLightbox: () => void
|
||||
@@ -511,12 +515,21 @@ export function KeyframePanelNode({ data }: any) {
|
||||
const d: NodeData = data
|
||||
if (!d.job || d.expandedFrame === null) return null
|
||||
const active = d.job.frames.find((f) => f.index === d.expandedFrame)
|
||||
const scale = d.framePanelScale ?? 1
|
||||
const pinned = d.framePanelPinned ?? false
|
||||
const panelWidth = Math.round(760 * scale)
|
||||
const panelHeight = Math.round(746 * scale)
|
||||
const bodyHeight = Math.max(520, panelHeight - 27)
|
||||
const setScale = (next: number) => {
|
||||
const clamped = Math.max(0.75, Math.min(1.35, Number(next.toFixed(2))))
|
||||
d.onFramePanelScaleChange?.(clamped)
|
||||
}
|
||||
return (
|
||||
<div
|
||||
className="rounded-2xl border border-white/15 bg-black/70 shadow-2xl overflow-hidden"
|
||||
style={{ width: 760, height: 746, boxShadow: "0 30px 80px -20px rgba(0,0,0,0.75), 0 0 0 1px rgba(255,255,255,0.05)" }}
|
||||
style={{ width: panelWidth, height: panelHeight, boxShadow: "0 30px 80px -20px rgba(0,0,0,0.75), 0 0 0 1px rgba(255,255,255,0.05)" }}
|
||||
>
|
||||
<div className="keyframe-panel-drag flex h-7 cursor-move items-center justify-between bg-gradient-to-r from-orange-500 to-red-500 px-3 text-white">
|
||||
<div className={`keyframe-panel-drag flex h-7 items-center justify-between bg-gradient-to-r from-orange-500 to-red-500 px-3 text-white ${pinned ? "cursor-default" : "cursor-move"}`}>
|
||||
<div className="flex min-w-0 items-center gap-2">
|
||||
<ImageIcon className="h-3.5 w-3.5 shrink-0" />
|
||||
<span className="truncate text-[12px] font-semibold">关键帧详情 · 元素提取</span>
|
||||
@@ -524,8 +537,46 @@ export function KeyframePanelNode({ data }: any) {
|
||||
{active ? `分镜 ${active.index + 1} · ${active.timestamp.toFixed(2)}s` : "未选分镜"}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-[10px] text-white/60">拖动标题栏移动 · 再点缩略图可找回</span>
|
||||
<div className="flex items-center gap-1.5">
|
||||
<span className="mr-1 text-[10px] text-white/60">
|
||||
{pinned ? "已钉住 · 切图不移动" : "拖动标题栏移动 · 可钉住"}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => { e.stopPropagation(); d.onFramePanelPinnedChange?.(!pinned) }}
|
||||
className={`nodrag h-5 w-5 rounded inline-flex items-center justify-center transition ${
|
||||
pinned
|
||||
? "bg-white text-orange-600 shadow"
|
||||
: "bg-white/10 text-white/85 hover:bg-white/20 hover:text-white"
|
||||
}`}
|
||||
title={pinned ? "取消钉住,允许拖动" : "钉住面板,防止被拖动"}
|
||||
>
|
||||
<Pin className="h-3 w-3" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => { e.stopPropagation(); setScale(scale - 0.1) }}
|
||||
className="nodrag h-5 w-5 rounded bg-white/10 text-white/85 hover:bg-white/20 hover:text-white inline-flex items-center justify-center text-[13px] leading-none"
|
||||
title="缩小面板"
|
||||
>
|
||||
-
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => { e.stopPropagation(); setScale(1) }}
|
||||
className="nodrag h-5 min-w-9 rounded bg-white/10 px-1.5 text-[10px] font-mono text-white/80 hover:bg-white/20 hover:text-white inline-flex items-center justify-center"
|
||||
title="重置为 100%"
|
||||
>
|
||||
{Math.round(scale * 100)}%
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => { e.stopPropagation(); setScale(scale + 0.1) }}
|
||||
className="nodrag h-5 w-5 rounded bg-white/10 text-white/85 hover:bg-white/20 hover:text-white inline-flex items-center justify-center text-[13px] leading-none"
|
||||
title="放大面板"
|
||||
>
|
||||
+
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => { e.stopPropagation(); d.onCloseExpandedFrame() }}
|
||||
@@ -536,7 +587,7 @@ export function KeyframePanelNode({ data }: any) {
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="nodrag nowheel h-[719px]" onWheel={(e) => e.stopPropagation()}>
|
||||
<div className="nodrag nowheel" style={{ height: bodyHeight }} onWheel={(e) => e.stopPropagation()}>
|
||||
<FrameLightbox
|
||||
embedded
|
||||
jobId={d.job.id}
|
||||
|
||||
Reference in New Issue
Block a user