chore: stage all pending work — caption styling, media server, processing modal, docs, summaries
Includes: - Extended caption styling (font, shadow, dimmed color, bg toggle) - Media server, subtitle downloader, VTT parser, processing modal - Waveform tiers, thumbnail/timeline improvements, transport controls - Hybrid download model, dependency management, clip export enhancements - 21 chat summaries, 2 implementation plans, 2 design specs Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
import SetupWizard from '$lib/components/SetupWizard.svelte';
|
||||
import PreferencesPanel from '$lib/components/PreferencesPanel.svelte';
|
||||
import ExportDialog from '$lib/components/ExportDialog.svelte';
|
||||
import ProcessingModal from '$lib/components/ProcessingModal.svelte';
|
||||
import { loadPreferences } from '$lib/stores/preferences.svelte';
|
||||
import { getSelectedClipId, removeClip } from '$lib/stores/clips.svelte';
|
||||
import { adjustShuttle, resetShuttleRate } from '$lib/transport/playback';
|
||||
@@ -21,6 +22,13 @@
|
||||
|
||||
let transportControls = $state<TransportControls | null>(null);
|
||||
|
||||
// Resizable split: timeline height in px (clip list gets the rest)
|
||||
let timelineHeight = $state(180);
|
||||
let isResizing = $state(false);
|
||||
let resizeStartY = $state(0);
|
||||
let resizeStartHeight = $state(0);
|
||||
let splitAreaEl = $state<HTMLDivElement | null>(null);
|
||||
|
||||
$effect(() => {
|
||||
loadPreferences();
|
||||
});
|
||||
@@ -36,6 +44,25 @@
|
||||
transportControls?.handleKeyAction(action);
|
||||
}
|
||||
|
||||
function handleResizeStart(e: MouseEvent) {
|
||||
e.preventDefault();
|
||||
isResizing = true;
|
||||
resizeStartY = e.clientY;
|
||||
resizeStartHeight = timelineHeight;
|
||||
}
|
||||
|
||||
function handleResizeMove(e: MouseEvent) {
|
||||
if (!isResizing || !splitAreaEl) return;
|
||||
const delta = e.clientY - resizeStartY;
|
||||
const totalHeight = splitAreaEl.clientHeight;
|
||||
const newHeight = Math.max(40, Math.min(totalHeight - 20, resizeStartHeight + delta));
|
||||
timelineHeight = newHeight;
|
||||
}
|
||||
|
||||
function handleResizeEnd() {
|
||||
isResizing = false;
|
||||
}
|
||||
|
||||
function handleGlobalKeydown(e: KeyboardEvent) {
|
||||
const target = e.target as HTMLElement;
|
||||
if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA') return;
|
||||
@@ -110,7 +137,11 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:window onkeydown={handleGlobalKeydown} />
|
||||
<svelte:window
|
||||
onkeydown={handleGlobalKeydown}
|
||||
onmousemove={handleResizeMove}
|
||||
onmouseup={handleResizeEnd}
|
||||
/>
|
||||
|
||||
{#if showSetupWizard}
|
||||
<SetupWizard onComplete={() => (showSetupWizard = false)} />
|
||||
@@ -124,6 +155,10 @@
|
||||
<ExportDialog onClose={() => (showExportDialog = false)} />
|
||||
{/if}
|
||||
|
||||
{#if session.processingStep !== 'idle' && session.processingStep !== 'done'}
|
||||
<ProcessingModal />
|
||||
{/if}
|
||||
|
||||
<div class="app-shell">
|
||||
<header class="toolbar">
|
||||
<UrlInput />
|
||||
@@ -133,8 +168,21 @@
|
||||
<main class="content">
|
||||
<VideoPlayer />
|
||||
<TransportControls bind:this={transportControls} />
|
||||
<Timeline />
|
||||
<ClipList onExport={() => (showExportDialog = true)} />
|
||||
<div class="timeline-clip-area" bind:this={splitAreaEl}>
|
||||
<div class="timeline-pane" style="height: {timelineHeight}px">
|
||||
<Timeline />
|
||||
</div>
|
||||
<div
|
||||
class="resize-handle"
|
||||
class:active={isResizing}
|
||||
role="separator"
|
||||
aria-orientation="horizontal"
|
||||
onmousedown={handleResizeStart}
|
||||
></div>
|
||||
<div class="cliplist-pane">
|
||||
<ClipList onExport={() => (showExportDialog = true)} />
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<StatusBar />
|
||||
@@ -163,6 +211,38 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.timeline-clip-area {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-shrink: 0;
|
||||
min-height: 80px;
|
||||
}
|
||||
|
||||
.timeline-pane {
|
||||
flex-shrink: 0;
|
||||
min-height: 40px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.resize-handle {
|
||||
height: 5px;
|
||||
background: var(--border, #353550);
|
||||
cursor: ns-resize;
|
||||
flex-shrink: 0;
|
||||
transition: background 0.1s;
|
||||
}
|
||||
|
||||
.resize-handle:hover,
|
||||
.resize-handle.active {
|
||||
background: var(--accent, #89b4fa);
|
||||
}
|
||||
|
||||
.cliplist-pane {
|
||||
flex: 1;
|
||||
min-height: 20px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.prefs-btn {
|
||||
font-size: 18px;
|
||||
padding: 4px 8px;
|
||||
|
||||
Reference in New Issue
Block a user