auto-save 2026-05-12 18:52 (~2)
This commit is contained in:
@@ -195,6 +195,13 @@
|
||||
"message": "auto-save 2026-05-12 18:40 (~2)",
|
||||
"hash": "864781d",
|
||||
"files_changed": 2
|
||||
},
|
||||
{
|
||||
"ts": "2026-05-12T18:46:46+08:00",
|
||||
"type": "commit",
|
||||
"message": "auto-save 2026-05-12 18:46 (~3)",
|
||||
"hash": "5a914b9",
|
||||
"files_changed": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -187,43 +187,35 @@ export function Dashboard({ data }: Props) {
|
||||
<Tile tkey="compose" />
|
||||
</div>
|
||||
|
||||
{/* 展开面板 — 多卡同时展开,按 step 顺序排列 */}
|
||||
{/* 展开面板 — 单列宽度,居中,卡片竖向堆叠 */}
|
||||
{expanded.size > 0 && (
|
||||
<div className="relative mx-4 mb-3 rounded-xl border border-white/10 bg-black/30 backdrop-blur-xl overflow-hidden" style={{ maxHeight: "52vh" }}>
|
||||
<div className="flex items-center justify-between px-4 py-2 border-b border-white/8">
|
||||
<span className="text-[10px] uppercase tracking-widest text-[var(--text-faint)]">展开详情</span>
|
||||
<button
|
||||
onClick={() => setExpanded(new Set())}
|
||||
className="text-[var(--text-faint)] hover:text-[var(--text-strong)]"
|
||||
title="收起"
|
||||
<div className="flex justify-center px-4 pb-3" style={{ maxHeight: "52vh" }}>
|
||||
{TILES.filter((t) => expanded.has(t.key)).map((t) => (
|
||||
<section
|
||||
key={t.key}
|
||||
className="rounded-xl border border-white/10 bg-black/30 backdrop-blur-xl overflow-hidden flex flex-col"
|
||||
style={{ width: 360, maxHeight: "52vh" }}
|
||||
>
|
||||
<X className="h-4 w-4" />
|
||||
</button>
|
||||
</div>
|
||||
<div className="overflow-y-auto p-3 space-y-3" style={{ maxHeight: "calc(52vh - 40px)" }}>
|
||||
{TILES.filter((t) => expanded.has(t.key)).map((t) => (
|
||||
<section key={t.key} className="rounded-lg border border-white/8 overflow-hidden">
|
||||
<div className="flex items-center justify-between px-3 py-1.5" style={{ background: TYPE_GRAD[t.type] }}>
|
||||
<div className="flex items-center gap-1.5">
|
||||
<span className="text-white/70 text-[9px] font-mono">{String(t.step).padStart(2, "0")}</span>
|
||||
<span className="text-white">{t.icon}</span>
|
||||
<span className="text-[12.5px] font-semibold text-white">{t.title}</span>
|
||||
<span className="text-[10px] text-white/60 ml-2">{colSummary[t.key]}</span>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => closeTile(t.key)}
|
||||
className="text-white/70 hover:text-white"
|
||||
title="收起此卡"
|
||||
>
|
||||
<X className="h-3.5 w-3.5" />
|
||||
</button>
|
||||
<div className="flex items-center justify-between px-3 py-2" style={{ background: TYPE_GRAD[t.type] }}>
|
||||
<div className="flex items-center gap-1.5">
|
||||
<span className="text-white/70 text-[9px] font-mono">{String(t.step).padStart(2, "0")}</span>
|
||||
<span className="text-white">{t.icon}</span>
|
||||
<span className="text-[12.5px] font-semibold text-white">{t.title}</span>
|
||||
<span className="text-[10px] text-white/70 ml-2">{colSummary[t.key]}</span>
|
||||
</div>
|
||||
<div className="p-3 bg-black/20">
|
||||
{renderSection(t.key)}
|
||||
</div>
|
||||
</section>
|
||||
))}
|
||||
</div>
|
||||
<button
|
||||
onClick={() => closeTile(t.key)}
|
||||
className="text-white/70 hover:text-white"
|
||||
title="收起"
|
||||
>
|
||||
<X className="h-3.5 w-3.5" />
|
||||
</button>
|
||||
</div>
|
||||
<div className="overflow-y-auto p-3 bg-black/20">
|
||||
{renderSection(t.key)}
|
||||
</div>
|
||||
</section>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -231,7 +223,7 @@ export function Dashboard({ data }: Props) {
|
||||
|
||||
function renderSection(key: string): ReactNode {
|
||||
return (
|
||||
<>
|
||||
<div className="space-y-3">
|
||||
|
||||
{/* ---- Input ---- */}
|
||||
{key === "input" && (
|
||||
@@ -367,41 +359,45 @@ export function Dashboard({ data }: Props) {
|
||||
<div className="text-[11.5px] text-[var(--text-soft)]">候选 30 张 → pHash 去重 + 清晰度排序 → 时序分桶 → 5 张代表分镜</div>
|
||||
</KanbanCard>
|
||||
) : (
|
||||
<div className="grid grid-cols-5 gap-3">
|
||||
{job!.frames.map((f) => {
|
||||
const isSel = data.selectedFrames.has(f.index)
|
||||
return (
|
||||
<KanbanCard
|
||||
key={f.index}
|
||||
tone={isSel ? "green" : "pink"}
|
||||
tags={[`分镜 ${f.index + 1}`, `${f.timestamp.toFixed(1)}s`]}
|
||||
className={isSel ? "ring-2 ring-emerald-400/60" : ""}
|
||||
meta={
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => { e.stopPropagation(); data.onToggleFrame(f.index) }}
|
||||
className={`ml-auto text-[10.5px] px-2 py-0.5 rounded-full inline-flex items-center gap-1 ${
|
||||
isSel
|
||||
? "bg-emerald-500 text-white"
|
||||
: "bg-white/10 text-[var(--text-soft)] border border-white/15 hover:bg-white/20"
|
||||
}`}
|
||||
>
|
||||
<Check className="h-2.5 w-2.5" />
|
||||
{isSel ? "已选用" : "选用此帧"}
|
||||
</button>
|
||||
}
|
||||
>
|
||||
job!.frames.map((f) => {
|
||||
const isSel = data.selectedFrames.has(f.index)
|
||||
return (
|
||||
<KanbanCard
|
||||
key={f.index}
|
||||
tone={isSel ? "green" : "pink"}
|
||||
tags={[`分镜 ${f.index + 1}`, `${f.timestamp.toFixed(1)}s`]}
|
||||
className={isSel ? "ring-2 ring-emerald-400/60" : ""}
|
||||
meta={
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => { e.stopPropagation(); data.onExpandFrame(f.index) }}
|
||||
className="block w-full aspect-video rounded-md overflow-hidden bg-black relative"
|
||||
onClick={(e) => { e.stopPropagation(); data.onToggleFrame(f.index) }}
|
||||
className={`ml-auto text-[10.5px] px-2 py-0.5 rounded-full inline-flex items-center gap-1 ${
|
||||
isSel
|
||||
? "bg-emerald-500 text-white"
|
||||
: "bg-white/10 text-[var(--text-soft)] border border-white/15 hover:bg-white/20"
|
||||
}`}
|
||||
>
|
||||
<img src={frameUrl(job!.id, f.index)} alt={`frame ${f.index}`} className="absolute inset-0 w-full h-full object-cover" />
|
||||
<Check className="h-2.5 w-2.5" />
|
||||
{isSel ? "已选用" : "选用此帧"}
|
||||
</button>
|
||||
</KanbanCard>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => { e.stopPropagation(); data.onExpandFrame(f.index) }}
|
||||
className="block w-full rounded-md overflow-hidden bg-black"
|
||||
title="点击放大"
|
||||
>
|
||||
<img
|
||||
src={frameUrl(job!.id, f.index)}
|
||||
alt={`frame ${f.index}`}
|
||||
className="block w-full h-auto"
|
||||
style={{ objectFit: "contain" }}
|
||||
/>
|
||||
</button>
|
||||
</KanbanCard>
|
||||
)
|
||||
})
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
@@ -415,24 +411,22 @@ export function Dashboard({ data }: Props) {
|
||||
</div>
|
||||
</KanbanCard>
|
||||
) : (
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
{job!.transcript.map((s) => (
|
||||
<KanbanCard
|
||||
key={s.index}
|
||||
tone={key === "asr" ? "blue" : "cyan"}
|
||||
tags={[`段落 ${s.index + 1}`, `${s.start.toFixed(1)}s → ${s.end.toFixed(1)}s`]}
|
||||
>
|
||||
<div className="text-[12.5px] text-[var(--text-strong)] leading-snug mb-1.5">
|
||||
<span className="kanban-tag mr-1.5" style={{ padding: "1px 6px", fontSize: 9.5 }}>EN</span>
|
||||
{s.en}
|
||||
</div>
|
||||
<div className="text-[12.5px] text-[var(--text-strong)] leading-snug">
|
||||
<span className="kanban-tag mr-1.5" style={{ padding: "1px 6px", fontSize: 9.5 }}>ZH</span>
|
||||
{s.zh || <span className="text-[var(--text-faint)] italic">翻译中…</span>}
|
||||
</div>
|
||||
</KanbanCard>
|
||||
))}
|
||||
</div>
|
||||
job!.transcript.map((s) => (
|
||||
<KanbanCard
|
||||
key={s.index}
|
||||
tone={key === "asr" ? "blue" : "cyan"}
|
||||
tags={[`段落 ${s.index + 1}`, `${s.start.toFixed(1)}s → ${s.end.toFixed(1)}s`]}
|
||||
>
|
||||
<div className="text-[12.5px] text-[var(--text-strong)] leading-snug mb-1.5">
|
||||
<span className="kanban-tag mr-1.5" style={{ padding: "1px 6px", fontSize: 9.5 }}>EN</span>
|
||||
{s.en}
|
||||
</div>
|
||||
<div className="text-[12.5px] text-[var(--text-strong)] leading-snug">
|
||||
<span className="kanban-tag mr-1.5" style={{ padding: "1px 6px", fontSize: 9.5 }}>ZH</span>
|
||||
{s.zh || <span className="text-[var(--text-faint)] italic">翻译中…</span>}
|
||||
</div>
|
||||
</KanbanCard>
|
||||
))
|
||||
)
|
||||
)}
|
||||
|
||||
@@ -512,7 +506,7 @@ export function Dashboard({ data }: Props) {
|
||||
</MiniCard>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user