feat: timeline zooms to clip region on cut-clip from Player mode

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-09-23 03:18:18 -04:00
parent f6ad41f5fd
commit 619fe59dbe
2 changed files with 29 additions and 1 deletions

View File

@@ -62,6 +62,9 @@
// Caption state for PlayerControls
let captionsEnabled = $state(true);
// Pending timeline zoom for cut-clip feature
let pendingTimelineZoom = $state<{ start: number; end: number } | null>(null);
const CONTROLS_HIDE_DELAY = 2500;
const TOOLBAR_PROXIMITY = 50;
@@ -191,6 +194,7 @@
const range = computeQuickClipRange(session.currentTime, session.duration, position);
if (!range) return;
addClip(range.start, range.end);
pendingTimelineZoom = { start: range.start, end: range.end };
setAppMode('clipper');
}
@@ -462,7 +466,10 @@
}}
></div>
<div class="timeline-pane" style="height: {timelineHeight}px">
<Timeline />
<Timeline
zoomRegion={pendingTimelineZoom}
onZoomApplied={() => { pendingTimelineZoom = null; }}
/>
</div>
</div>

View File

@@ -22,6 +22,14 @@
type ClipDragTarget = { clipId: string; edge: 'start' | 'end' };
let {
zoomRegion,
onZoomApplied,
}: {
zoomRegion?: { start: number; end: number } | null;
onZoomApplied?: () => void;
} = $props();
let canvas = $state<HTMLCanvasElement | null>(null);
let minimapCanvas = $state<HTMLCanvasElement | null>(null);
let containerEl = $state<HTMLDivElement | null>(null);
@@ -189,6 +197,19 @@
}
});
$effect(() => {
if (zoomRegion && session.duration > 0) {
const clipLen = zoomRegion.end - zoomRegion.start;
const pad = Math.max(clipLen * 0.2, 2);
const vs = Math.max(0, zoomRegion.start - pad);
const ve = Math.min(session.duration, zoomRegion.end + pad);
timelineState.visibleStart = vs;
timelineState.visibleEnd = ve;
timelineState.zoom = session.duration / (ve - vs);
onZoomApplied?.();
}
});
$effect(() => {
if (!containerEl) return;
const observer = new ResizeObserver((entries) => {