auto-save 2026-05-12 23:55 (~2)
This commit is contained in:
@@ -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
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user