fix: refine waveform filmstrip controls

This commit is contained in:
2026-05-19 18:16:57 +08:00
parent 818d785d14
commit f574ab4775
3 changed files with 41 additions and 34 deletions

View File

@@ -15,7 +15,7 @@
## 部署事实
- 平台VPS `76.13.31.179`Ubuntu 24.04 / Docker Compose / Coolify Traefik
- 发布状态已部署并验证2026-05-19逐句时间轴窄版面板 + 波形同框时间对齐画面胶片 + 胶片贴近波形并原位大放大 + 隐藏源视频工作区音频解析摘要卡 + 隐藏工作区顶部状态提示条 + 三字段候选生成工作流 + 折叠紧凑候选区);`https://marketing.skg.com` 已启用应用内登录页,未登录 API 返回 401认证后首页 200容器内 `/health` 返回 `ok:true`
- 发布状态已部署并验证2026-05-19逐句时间轴窄版面板 + 波形同框时间对齐画面胶片 + 胶片密度按钮上移波形顶部 + 去分隔线 + 胶片贴近波形并原位顶层大放大 + 隐藏源视频工作区音频解析摘要卡 + 隐藏工作区顶部状态提示条 + 三字段候选生成工作流 + 折叠紧凑候选区);`https://marketing.skg.com` 已启用应用内登录页,未登录 API 返回 401认证后首页 200容器内 `/health` 返回 `ok:true`
- 主站 / 前端:`https://marketing.skg.com`
- API / 后端:`https://marketing.skg.com/api`
- 代码仓库 / Gitea`https://git.kang-kang.com/kangwan/20260512-skg-tk`

File diff suppressed because one or more lines are too long

View File

@@ -2605,8 +2605,12 @@ function AudioIntakePanel({
</div>
<div className="min-w-0 space-y-2">
<div className="rounded-md border border-white/10 bg-black/32 p-2">
<div className="relative z-40 overflow-visible rounded-md border border-white/10 bg-black/32 p-2">
<div className="mb-1 flex items-center justify-end gap-3 text-[10px] text-white/40">
<FilmstripDensityControls
density={filmstripDensity}
onDensityChange={setFilmstripDensity}
/>
<div className="flex items-center gap-2 font-mono">
<span> {currentTime.toFixed(1)}s</span>
<span> {formatSeconds(timelineDuration)}</span>
@@ -2632,7 +2636,6 @@ function AudioIntakePanel({
hoverTime={waveHoverTime}
selectedTimes={frames.map((frame) => frame.timestamp)}
busyTime={filmstripBusyTime}
onDensityChange={setFilmstripDensity}
onSeek={seekTo}
onDragStart={setFilmstripDragTime}
onDragEnd={() => setFilmstripDragTime(null)}
@@ -2718,7 +2721,6 @@ function TimelineFilmstrip({
hoverTime,
selectedTimes,
busyTime,
onDensityChange,
onSeek,
onDragStart,
onDragEnd,
@@ -2731,7 +2733,6 @@ function TimelineFilmstrip({
hoverTime: number | null
selectedTimes: number[]
busyTime: number | null
onDensityChange: (density: FilmstripDensitySeconds) => void
onSeek: (time: number) => void
onDragStart: (time: number) => void
onDragEnd: () => void
@@ -2740,30 +2741,8 @@ function TimelineFilmstrip({
const hoverPct = hoverTime === null ? null : clampNumber((hoverTime / Math.max(duration, 1)) * 100, 0, 100)
return (
<div className="relative z-30 mt-1 overflow-visible pt-0.5">
<div className="mb-0.5 flex items-center justify-between gap-3">
<div className="min-w-0" />
<div className="flex shrink-0 items-center gap-1">
{FILMSTRIP_DENSITIES.map((item) => (
<button
key={item.value}
type="button"
onClick={() => onDensityChange(item.value)}
aria-label={`胶片密度:${item.detail}`}
className={`h-7 rounded-md border px-2 text-[10.5px] font-semibold transition ${
density === item.value
? "border-[#d6b36a]/70 bg-[#d6b36a]/18 text-[#f7df9a]"
: "border-white/10 bg-white/[0.035] text-white/48 hover:border-white/22 hover:text-white/72"
}`}
title={item.detail}
>
{item.label}
</button>
))}
</div>
</div>
<div className="relative h-[172px] overflow-visible border-t border-white/8">
<div className="relative z-[80] mt-1 overflow-visible pt-0.5">
<div className="relative h-[172px] overflow-visible">
{status === "loading" ? (
<div className="absolute inset-x-0 top-12 flex h-[72px] items-center justify-center gap-2 rounded-md border border-dashed border-white/12 text-[11px] text-white/40">
<Loader2 className="h-3.5 w-3.5 animate-spin" />
@@ -2775,7 +2754,6 @@ function TimelineFilmstrip({
</div>
) : frames.length ? (
<div className="absolute bottom-7 left-0 right-0 top-1 overflow-visible">
<div className="absolute inset-x-0 bottom-[58px] h-px bg-white/14" />
{hoverPct !== null && (
<div
className="pointer-events-none absolute bottom-0 top-0 z-10 w-px bg-cyan-100/55"
@@ -2802,7 +2780,7 @@ function TimelineFilmstrip({
onDragStart(frame.time)
}}
onDragEnd={onDragEnd}
className={`absolute bottom-[58px] z-20 -translate-x-1/2 ${tiltClass} origin-bottom cursor-grab transition-transform duration-150 hover:z-[90] hover:-translate-y-3 hover:rotate-0 hover:scale-[4.8] active:cursor-grabbing`}
className={`absolute bottom-[58px] z-20 -translate-x-1/2 ${tiltClass} origin-bottom cursor-grab transition-transform duration-150 will-change-transform hover:z-[9999] hover:-translate-y-3 hover:rotate-0 hover:scale-[4.8] active:cursor-grabbing`}
style={{ left: `${framePct}%` }}
title={`${frame.time.toFixed(1)}s · 拖到关键帧库才选取`}
>
@@ -2842,6 +2820,35 @@ function TimelineFilmstrip({
)
}
function FilmstripDensityControls({
density,
onDensityChange,
}: {
density: FilmstripDensitySeconds
onDensityChange: (density: FilmstripDensitySeconds) => void
}) {
return (
<div className="flex shrink-0 items-center gap-1">
{FILMSTRIP_DENSITIES.map((item) => (
<button
key={item.value}
type="button"
onClick={() => onDensityChange(item.value)}
aria-label={`胶片密度:${item.detail}`}
className={`h-6 rounded-md border px-2 text-[10.5px] font-semibold transition ${
density === item.value
? "border-[#d6b36a]/70 bg-[#d6b36a]/18 text-[#f7df9a]"
: "border-white/10 bg-white/[0.035] text-white/48 hover:border-white/22 hover:text-white/72"
}`}
title={item.detail}
>
{item.label}
</button>
))}
</div>
)
}
function SourceKeyframePicker({
job,
frames,