feat: simplify keyframe selection pool

This commit is contained in:
2026-05-18 15:26:23 +08:00
parent c22bee4878
commit d9b51348fe
2 changed files with 45 additions and 70 deletions

File diff suppressed because one or more lines are too long

View File

@@ -2044,77 +2044,40 @@ function SourceKeyframePicker({
</div>
</div>
<div className="grid min-h-[205px] gap-1.5 rounded-md border border-white/10 bg-black/32 p-1.5 xl:grid-cols-[minmax(0,1fr)_86px] 2xl:min-h-[260px] 2xl:grid-cols-[minmax(0,1fr)_96px]">
<div className="min-w-0">
<div className="mb-1 flex items-center justify-between gap-2">
<span className="text-[10px] text-white/34"></span>
<span className="text-[9.5px] text-white/28"></span>
</div>
<div className="grid max-h-[178px] grid-cols-[repeat(auto-fill,minmax(38px,1fr))] gap-1 overflow-y-auto pr-0.5 2xl:max-h-[232px]">
{frames.map((frame, index) => {
const selected = selectedFrames.has(frame.index)
return (
<MediaAssetTile
key={frame.index}
src={effectiveFrameUrl(job.id, frame)}
alt={`关键帧 ${index + 1}`}
label={`参考帧 ${String(index + 1).padStart(2, "0")}`}
meta={`${frame.timestamp.toFixed(1)}s`}
className="aspect-[9/16]"
objectFit="contain"
selected={selected}
title={`关键帧 ${index + 1} · ${frame.timestamp.toFixed(1)}s`}
onClick={() => onToggleFrame(frame.index)}
topLeft={<span className="rounded bg-black/72 px-1 font-mono text-[9px] text-white/70">{String(index + 1).padStart(2, "0")}</span>}
topRight={<span className="rounded-full bg-black/72 p-0.5">{selected ? <Check className="h-3 w-3 text-emerald-200" /> : <Circle className="h-3 w-3 text-white/50" />}</span>}
onDelete={onDeleteFrame ? () => onDeleteFrame(frame.index) : undefined}
deleting={deletingFrame === frame.index}
deleteLabel={`删除关键帧 ${index + 1}`}
/>
)
})}
{!frames.length && (
<div className="col-span-full flex h-[106px] items-center justify-center rounded border border-dashed border-white/12 px-2 text-center text-[10.5px] leading-snug text-white/34">
</div>
)}
</div>
<div className="min-h-[205px] rounded-md border border-white/10 bg-black/32 p-1.5 2xl:min-h-[260px]">
<div className="mb-1 flex items-center justify-between gap-2">
<span className="text-[10px] text-white/34"></span>
<span className="text-[9.5px] text-white/28"></span>
</div>
<aside className="min-w-0 rounded-md border border-emerald-300/12 bg-emerald-300/[0.035] p-1">
<div className="mb-1 flex items-center justify-between gap-1">
<span className="text-[9.5px] font-semibold text-emerald-50/70"></span>
<span className="font-mono text-[9px] text-emerald-50/55">{selectedReferenceFrames.length}</span>
</div>
{selectedReferenceFrames.length ? (
<div className="grid max-h-[168px] grid-cols-2 gap-1 overflow-y-auto pr-0.5 2xl:max-h-[222px]">
{selectedReferenceFrames.map((frame) => {
const order = frames.findIndex((item) => item.index === frame.index)
const label = order >= 0 ? String(order + 1).padStart(2, "0") : String(frame.index)
return (
<MediaAssetTile
key={frame.index}
src={effectiveFrameUrl(job.id, frame)}
alt={`已选关键帧 ${label}`}
label={`已选 ${label}`}
meta={`${frame.timestamp.toFixed(1)}s`}
className="aspect-[9/16]"
objectFit="contain"
selected
title={`点击取消选择 · ${frame.timestamp.toFixed(1)}s`}
onClick={() => onToggleFrame(frame.index)}
topLeft={<span className="rounded bg-black/72 px-1 font-mono text-[8.5px] text-emerald-100/80">{label}</span>}
topRight={<span className="rounded-full bg-black/72 p-0.5"><Check className="h-2.5 w-2.5 text-emerald-200" /></span>}
/>
)
})}
</div>
) : (
<div className="flex h-[90px] items-center justify-center rounded border border-dashed border-emerald-300/12 px-1 text-center text-[9.5px] leading-snug text-white/30">
使
<div className="grid max-h-[178px] grid-cols-[repeat(auto-fill,minmax(38px,1fr))] gap-1 overflow-y-auto pr-0.5 2xl:max-h-[232px]">
{frames.map((frame, index) => {
const selected = selectedFrames.has(frame.index)
return (
<MediaAssetTile
key={frame.index}
src={effectiveFrameUrl(job.id, frame)}
alt={`关键帧 ${index + 1}`}
label={`参考帧 ${String(index + 1).padStart(2, "0")}`}
meta={`${frame.timestamp.toFixed(1)}s`}
className="aspect-[9/16]"
objectFit="contain"
selected={selected}
title={`${selected ? "已选 · 点击取消" : "点击选择"} · 关键帧 ${index + 1} · ${frame.timestamp.toFixed(1)}s`}
onClick={() => onToggleFrame(frame.index)}
topLeft={<span className="rounded bg-black/72 px-1 font-mono text-[9px] text-white/70">{String(index + 1).padStart(2, "0")}</span>}
topRight={<span className="rounded-full bg-black/72 p-0.5">{selected ? <Check className="h-3 w-3 text-emerald-200" /> : <Circle className="h-3 w-3 text-white/50" />}</span>}
onDelete={onDeleteFrame ? () => onDeleteFrame(frame.index) : undefined}
deleting={deletingFrame === frame.index}
deleteLabel={`删除关键帧 ${index + 1}`}
/>
)
})}
{!frames.length && (
<div className="col-span-full flex h-[106px] items-center justify-center rounded border border-dashed border-white/12 px-2 text-center text-[10.5px] leading-snug text-white/34">
</div>
)}
</aside>
</div>
</div>
</div>
)