auto-save 2026-05-12 20:10 (~3)
This commit is contained in:
@@ -9,7 +9,9 @@ import { NodeShell, type NodeStatus, type NodeKind } from "./node-shell"
|
||||
import { type Job, frameUrl, videoUrl } from "@/lib/api"
|
||||
|
||||
export interface NodeData {
|
||||
job: Job | null
|
||||
job: Job | null // 当前 active job
|
||||
jobs: Job[] // 所有 job 列表
|
||||
activeJobId: string | null
|
||||
submitting: boolean
|
||||
analyzing: boolean
|
||||
selectedFrames: Set<number>
|
||||
@@ -20,6 +22,7 @@ export interface NodeData {
|
||||
onExpandFrame: (idx: number) => void
|
||||
onAddManualFrame: (t: number) => void
|
||||
onOpenVideoLightbox: () => void
|
||||
onSwitchJob: (id: string) => void
|
||||
}
|
||||
|
||||
/* ---- 状态映射工具 ---- */
|
||||
@@ -79,37 +82,62 @@ export function InputNode({ data, selected }: NodeProps<{ data: NodeData }> | an
|
||||
|
||||
return (
|
||||
<div className="relative" style={{ width: 320 }}>
|
||||
{/* 视频缩略图浮于节点上方 — 跟关键帧缩略图同尺寸(小),点击稍微放大可选帧 */}
|
||||
{hasVideo && job && !videoExpanded && (
|
||||
<div className="absolute left-0 right-0 flex justify-center" style={{ bottom: "calc(100% + 12px)" }}>
|
||||
{/* 多视频缩略图浮条 — 每个 job 一张 + 末尾「+」按钮再上传 */}
|
||||
{!videoExpanded && d.jobs.length > 0 && (
|
||||
<div className="absolute left-0 right-0 flex justify-center items-end gap-1.5 flex-wrap" style={{ bottom: "calc(100% + 12px)" }}>
|
||||
{d.jobs.map((j) => {
|
||||
const isActive = j.id === d.activeJobId
|
||||
const ready = !!j.video_url
|
||||
return (
|
||||
<button
|
||||
key={j.id}
|
||||
type="button"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
if (isActive && ready) setVideoExpanded(true)
|
||||
else d.onSwitchJob(j.id)
|
||||
}}
|
||||
title={ready ? `${j.width}×${j.height} · ${j.duration.toFixed(1)}s · ${isActive ? "点击展开" : "点击切换"}` : "下载中…"}
|
||||
className={`group relative rounded-md overflow-hidden border shadow-lg transition hover:-translate-y-0.5 ${
|
||||
isActive ? "border-violet-400 ring-2 ring-violet-400/60" : "border-white/25"
|
||||
}`}
|
||||
style={{ width: 80, aspectRatio: ready ? `${j.width}/${j.height}` : "9/16" }}
|
||||
>
|
||||
{ready ? (
|
||||
<video
|
||||
src={videoUrl(j.id)}
|
||||
muted
|
||||
loop
|
||||
playsInline
|
||||
preload="metadata"
|
||||
className="block w-full h-full object-cover bg-black"
|
||||
onMouseEnter={(e) => (e.target as HTMLVideoElement).play().catch(() => {})}
|
||||
onMouseLeave={(e) => {
|
||||
const v = e.target as HTMLVideoElement
|
||||
v.pause()
|
||||
v.currentTime = 0
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<div className="w-full h-full bg-black/60 flex items-center justify-center">
|
||||
<Loader2 className="h-4 w-4 animate-spin text-white/60" />
|
||||
</div>
|
||||
)}
|
||||
<div className="absolute bottom-0.5 right-0.5 bg-black/70 text-white text-[9px] font-mono px-1 py-0.5 rounded">
|
||||
{ready ? `${j.duration.toFixed(1)}s` : "…"}
|
||||
</div>
|
||||
</button>
|
||||
)
|
||||
})}
|
||||
{/* + 再加一个 */}
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => { e.stopPropagation(); setVideoExpanded(true) }}
|
||||
title="点击展开 · 可拖时间轴选帧"
|
||||
className="group relative rounded-md overflow-hidden border border-white/30 shadow-lg hover:-translate-y-0.5 transition"
|
||||
style={{ width: 80 }}
|
||||
onClick={(e) => { e.stopPropagation(); fileRef.current?.click() }}
|
||||
title="再上传一个视频"
|
||||
className="rounded-md border border-dashed border-white/30 hover:border-white/50 bg-white/[0.04] hover:bg-white/[0.08] inline-flex items-center justify-center text-white/60 hover:text-white transition"
|
||||
style={{ width: 36, height: 64 }}
|
||||
>
|
||||
<video
|
||||
src={videoUrl(job.id)}
|
||||
muted
|
||||
loop
|
||||
playsInline
|
||||
preload="metadata"
|
||||
className="block w-full bg-black"
|
||||
style={{ aspectRatio: `${job.width}/${job.height}` }}
|
||||
onMouseEnter={(e) => {
|
||||
const v = e.target as HTMLVideoElement
|
||||
v.play().catch(() => {})
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
const v = e.target as HTMLVideoElement
|
||||
v.pause()
|
||||
v.currentTime = 0
|
||||
}}
|
||||
/>
|
||||
<div className="absolute bottom-0.5 right-0.5 bg-black/70 text-white text-[9px] font-mono px-1 py-0.5 rounded">
|
||||
{job.duration.toFixed(1)}s
|
||||
</div>
|
||||
<Plus className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user