auto-save 2026-05-12 23:55 (~2)

This commit is contained in:
2026-05-12 23:55:21 +08:00
parent 25a1e636e1
commit fd4c78f697
2 changed files with 21 additions and 10 deletions

View File

@@ -489,6 +489,13 @@
"message": "auto-save 2026-05-12 23:44 (~2)", "message": "auto-save 2026-05-12 23:44 (~2)",
"hash": "494d990", "hash": "494d990",
"files_changed": 2 "files_changed": 2
},
{
"ts": "2026-05-12T23:49:50+08:00",
"type": "commit",
"message": "auto-save 2026-05-12 23:49 (~2)",
"hash": "25a1e63",
"files_changed": 2
} }
] ]
} }

View File

@@ -27,9 +27,10 @@ export function FrameLightbox({ jobId, frames, activeIndex, selected, onClose, o
const onKey = (e: KeyboardEvent) => { const onKey = (e: KeyboardEvent) => {
const inField = ["INPUT", "TEXTAREA"].includes((e.target as HTMLElement).tagName) const inField = ["INPUT", "TEXTAREA"].includes((e.target as HTMLElement).tagName)
if (e.key === "Escape") onClose() if (e.key === "Escape") onClose()
if (!inField) { if (!inField && activeIndex !== null) {
if (e.key === "ArrowLeft" && activeIndex > 0) onChange(activeIndex - 1) const pos = frames.findIndex((x) => x.index === activeIndex)
if (e.key === "ArrowRight" && activeIndex < frames.length - 1) onChange(activeIndex + 1) if (e.key === "ArrowLeft" && pos > 0) onChange(frames[pos - 1].index)
if (e.key === "ArrowRight" && pos < frames.length - 1) onChange(frames[pos + 1].index)
if (e.key === " " || e.key === "Enter") { if (e.key === " " || e.key === "Enter") {
e.preventDefault() e.preventDefault()
onToggleSelect(activeIndex) onToggleSelect(activeIndex)
@@ -40,8 +41,11 @@ export function FrameLightbox({ jobId, frames, activeIndex, selected, onClose, o
return () => window.removeEventListener("keydown", onKey) return () => window.removeEventListener("keydown", onKey)
}, [activeIndex, frames.length, onClose, onChange, onToggleSelect]) }, [activeIndex, frames.length, onClose, onChange, onToggleSelect])
if (activeIndex === null || !frames[activeIndex] || !mounted) return null // activeIndex 是 KeyFrame.index 稳定 ID而 frames 数组按 timestamp 排序——必须用 find 不能用 [index]
const f = frames[activeIndex] const f = activeIndex !== null ? frames.find((x) => x.index === activeIndex) : undefined
const arrayPos = f ? frames.findIndex((x) => x.index === f.index) : -1
if (activeIndex === null || !f || !mounted) return null
const isSelected = selected.has(f.index) const isSelected = selected.has(f.index)
const desc = f.description const desc = f.description
@@ -79,21 +83,21 @@ export function FrameLightbox({ jobId, frames, activeIndex, selected, onClose, o
<div className="flex items-center justify-between px-4 py-2 border-b border-white/10 bg-white/[0.03]"> <div className="flex items-center justify-between px-4 py-2 border-b border-white/10 bg-white/[0.03]">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<button <button
onClick={(e) => { e.stopPropagation(); if (activeIndex > 0) onChange(activeIndex - 1) }} onClick={(e) => { e.stopPropagation(); if (arrayPos > 0) onChange(frames[arrayPos - 1].index) }}
disabled={activeIndex === 0} disabled={arrayPos <= 0}
className="h-7 w-7 rounded-md bg-white/10 hover:bg-white/20 text-white inline-flex items-center justify-center disabled:opacity-30 disabled:cursor-not-allowed" className="h-7 w-7 rounded-md bg-white/10 hover:bg-white/20 text-white inline-flex items-center justify-center disabled:opacity-30 disabled:cursor-not-allowed"
> >
<ChevronLeft className="h-4 w-4" /> <ChevronLeft className="h-4 w-4" />
</button> </button>
<button <button
onClick={(e) => { e.stopPropagation(); if (activeIndex < frames.length - 1) onChange(activeIndex + 1) }} onClick={(e) => { e.stopPropagation(); if (arrayPos < frames.length - 1) onChange(frames[arrayPos + 1].index) }}
disabled={activeIndex >= frames.length - 1} disabled={arrayPos >= frames.length - 1}
className="h-7 w-7 rounded-md bg-white/10 hover:bg-white/20 text-white inline-flex items-center justify-center disabled:opacity-30 disabled:cursor-not-allowed" className="h-7 w-7 rounded-md bg-white/10 hover:bg-white/20 text-white inline-flex items-center justify-center disabled:opacity-30 disabled:cursor-not-allowed"
> >
<ChevronRight className="h-4 w-4" /> <ChevronRight className="h-4 w-4" />
</button> </button>
<span className="text-[11px] font-mono text-white/70 ml-1"> <span className="text-[11px] font-mono text-white/70 ml-1">
{String(f.index + 1).padStart(2, "0")} / {String(frames.length).padStart(2, "0")} {String(arrayPos + 1).padStart(2, "0")} / {String(frames.length).padStart(2, "0")}
<span className="mx-1.5 text-white/30">·</span> <span className="mx-1.5 text-white/30">·</span>
<span className="text-white/60">{f.timestamp.toFixed(2)}s</span> <span className="text-white/60">{f.timestamp.toFixed(2)}s</span>
</span> </span>