2026-09-21 10:45:53 -04:00
|
|
|
|
<script lang="ts">
|
|
|
|
|
|
import UrlInput from '$lib/components/UrlInput.svelte';
|
|
|
|
|
|
import VideoPlayer from '$lib/components/VideoPlayer.svelte';
|
|
|
|
|
|
import TransportControls from '$lib/components/TransportControls.svelte';
|
|
|
|
|
|
import Timeline from '$lib/components/Timeline.svelte';
|
|
|
|
|
|
import ClipList from '$lib/components/ClipList.svelte';
|
|
|
|
|
|
import StatusBar from '$lib/components/StatusBar.svelte';
|
2026-09-21 10:50:24 -04:00
|
|
|
|
import SetupWizard from '$lib/components/SetupWizard.svelte';
|
2026-09-21 10:54:42 -04:00
|
|
|
|
import PreferencesPanel from '$lib/components/PreferencesPanel.svelte';
|
2026-09-21 11:20:32 -04:00
|
|
|
|
import ExportDialog from '$lib/components/ExportDialog.svelte';
|
2026-09-22 12:40:32 -04:00
|
|
|
|
import AboutDialog from '$lib/components/AboutDialog.svelte';
|
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>
2026-09-22 10:48:16 -04:00
|
|
|
|
import ProcessingModal from '$lib/components/ProcessingModal.svelte';
|
2026-09-22 16:49:35 -04:00
|
|
|
|
import { loadPreferences, preferences, setClipListPosition, setClipListWidth } from '$lib/stores/preferences.svelte';
|
2026-09-21 11:08:16 -04:00
|
|
|
|
import { getSelectedClipId, removeClip } from '$lib/stores/clips.svelte';
|
2026-09-21 11:25:28 -04:00
|
|
|
|
import { adjustShuttle, resetShuttleRate } from '$lib/transport/playback';
|
|
|
|
|
|
import { session } from '$lib/stores/videoSession.svelte';
|
2026-09-22 16:16:00 -04:00
|
|
|
|
import { listen } from '@tauri-apps/api/event';
|
2026-09-21 11:08:16 -04:00
|
|
|
|
import type { TransportKeyAction } from '$lib/transport/playback';
|
2026-09-21 10:50:24 -04:00
|
|
|
|
|
|
|
|
|
|
let showSetupWizard = $state(true);
|
2026-09-21 10:54:42 -04:00
|
|
|
|
let showPreferences = $state(false);
|
2026-09-21 11:08:16 -04:00
|
|
|
|
let showExportDialog = $state(false);
|
2026-09-22 12:40:32 -04:00
|
|
|
|
let showAboutDialog = $state(false);
|
2026-09-21 11:08:16 -04:00
|
|
|
|
let shuttleRate = $state(1);
|
|
|
|
|
|
|
|
|
|
|
|
let transportControls = $state<TransportControls | null>(null);
|
2026-09-21 10:54:42 -04:00
|
|
|
|
|
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>
2026-09-22 10:48:16 -04:00
|
|
|
|
// 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);
|
|
|
|
|
|
|
2026-09-22 16:49:35 -04:00
|
|
|
|
let isSidebarResizing = $state(false);
|
|
|
|
|
|
let sidebarResizeStartX = $state(0);
|
|
|
|
|
|
let sidebarResizeStartWidth = $state(0);
|
|
|
|
|
|
let windowWidth = $state(window.innerWidth);
|
|
|
|
|
|
|
2026-09-22 17:30:47 -04:00
|
|
|
|
let isLeft = $derived(preferences.clipListPosition === 'left');
|
|
|
|
|
|
|
2026-09-21 10:54:42 -04:00
|
|
|
|
$effect(() => {
|
|
|
|
|
|
loadPreferences();
|
|
|
|
|
|
});
|
2026-09-21 11:08:16 -04:00
|
|
|
|
|
2026-09-22 16:16:00 -04:00
|
|
|
|
// Listen for native macOS menu "About" action
|
|
|
|
|
|
$effect(() => {
|
|
|
|
|
|
const unlisten = listen('open-about', () => {
|
|
|
|
|
|
showAboutDialog = true;
|
|
|
|
|
|
});
|
|
|
|
|
|
return () => { unlisten.then((fn) => fn()); };
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2026-09-21 11:25:28 -04:00
|
|
|
|
$effect(() => {
|
|
|
|
|
|
if (session.status === 'resolving') {
|
|
|
|
|
|
shuttleRate = 1;
|
|
|
|
|
|
resetShuttleRate();
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
2026-09-21 11:08:16 -04:00
|
|
|
|
function dispatchTransport(action: TransportKeyAction) {
|
|
|
|
|
|
transportControls?.handleKeyAction(action);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
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>
2026-09-22 10:48:16 -04:00
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-22 16:49:35 -04:00
|
|
|
|
function toggleClipListPosition() {
|
|
|
|
|
|
const next = preferences.clipListPosition === 'bottom' ? 'left' : 'bottom';
|
|
|
|
|
|
setClipListPosition(next);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function handleSidebarResizeStart(e: MouseEvent) {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
isSidebarResizing = true;
|
|
|
|
|
|
sidebarResizeStartX = e.clientX;
|
|
|
|
|
|
sidebarResizeStartWidth = preferences.clipListWidth;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function handleSidebarResizeMove(e: MouseEvent) {
|
|
|
|
|
|
if (!isSidebarResizing) return;
|
|
|
|
|
|
const delta = e.clientX - sidebarResizeStartX;
|
|
|
|
|
|
const maxWidth = Math.round(windowWidth * 0.4);
|
2026-09-22 16:50:57 -04:00
|
|
|
|
const minWidth = Math.min(150, maxWidth);
|
|
|
|
|
|
const newWidth = Math.max(minWidth, Math.min(maxWidth, sidebarResizeStartWidth + delta));
|
2026-09-22 16:49:35 -04:00
|
|
|
|
preferences.clipListWidth = newWidth;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function handleSidebarResizeEnd() {
|
|
|
|
|
|
if (isSidebarResizing) {
|
|
|
|
|
|
isSidebarResizing = false;
|
|
|
|
|
|
setClipListWidth(preferences.clipListWidth);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-21 11:08:16 -04:00
|
|
|
|
function handleGlobalKeydown(e: KeyboardEvent) {
|
|
|
|
|
|
const target = e.target as HTMLElement;
|
|
|
|
|
|
if (target.tagName === 'INPUT' || target.tagName === 'TEXTAREA') return;
|
|
|
|
|
|
|
|
|
|
|
|
switch (e.key) {
|
|
|
|
|
|
case ' ':
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
dispatchTransport('play-pause');
|
|
|
|
|
|
break;
|
|
|
|
|
|
case ',':
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
dispatchTransport(e.shiftKey ? 'keyframe-back' : 'frame-back');
|
|
|
|
|
|
break;
|
|
|
|
|
|
case '.':
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
dispatchTransport(e.shiftKey ? 'keyframe-forward' : 'frame-forward');
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'ArrowLeft':
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
dispatchTransport(e.shiftKey ? 'seek-back-1' : 'seek-back-5');
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'ArrowRight':
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
dispatchTransport(e.shiftKey ? 'seek-forward-1' : 'seek-forward-5');
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'i':
|
|
|
|
|
|
case 'I':
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
dispatchTransport('mark-in');
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'o':
|
|
|
|
|
|
case 'O':
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
dispatchTransport('mark-out');
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'j':
|
|
|
|
|
|
case 'J':
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
shuttleRate = adjustShuttle(-1, shuttleRate);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'k':
|
|
|
|
|
|
case 'K':
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
dispatchTransport('play-pause');
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'l':
|
|
|
|
|
|
case 'L':
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
shuttleRate = adjustShuttle(1, shuttleRate);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'Delete':
|
|
|
|
|
|
case 'Backspace': {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
const selectedId = getSelectedClipId();
|
|
|
|
|
|
if (selectedId) removeClip(selectedId);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
case 'a':
|
|
|
|
|
|
if (e.metaKey) {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
|
|
|
|
|
case 'e':
|
|
|
|
|
|
if (e.metaKey) {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
showExportDialog = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
2026-09-22 12:40:32 -04:00
|
|
|
|
case '/':
|
|
|
|
|
|
if (e.metaKey) {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
showAboutDialog = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
break;
|
2026-09-21 11:08:16 -04:00
|
|
|
|
default:
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-09-21 10:45:53 -04:00
|
|
|
|
</script>
|
|
|
|
|
|
|
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>
2026-09-22 10:48:16 -04:00
|
|
|
|
<svelte:window
|
|
|
|
|
|
onkeydown={handleGlobalKeydown}
|
2026-09-22 16:49:35 -04:00
|
|
|
|
onmousemove={(e) => {
|
|
|
|
|
|
handleResizeMove(e);
|
|
|
|
|
|
handleSidebarResizeMove(e);
|
|
|
|
|
|
}}
|
|
|
|
|
|
onmouseup={() => {
|
|
|
|
|
|
handleResizeEnd();
|
|
|
|
|
|
handleSidebarResizeEnd();
|
|
|
|
|
|
}}
|
|
|
|
|
|
onresize={() => {
|
|
|
|
|
|
windowWidth = window.innerWidth;
|
|
|
|
|
|
}}
|
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>
2026-09-22 10:48:16 -04:00
|
|
|
|
/>
|
2026-09-21 11:08:16 -04:00
|
|
|
|
|
2026-09-21 10:50:24 -04:00
|
|
|
|
{#if showSetupWizard}
|
|
|
|
|
|
<SetupWizard onComplete={() => (showSetupWizard = false)} />
|
|
|
|
|
|
{/if}
|
|
|
|
|
|
|
2026-09-21 10:54:42 -04:00
|
|
|
|
{#if showPreferences}
|
|
|
|
|
|
<PreferencesPanel onClose={() => (showPreferences = false)} />
|
|
|
|
|
|
{/if}
|
|
|
|
|
|
|
2026-09-21 11:20:32 -04:00
|
|
|
|
{#if showExportDialog}
|
|
|
|
|
|
<ExportDialog onClose={() => (showExportDialog = false)} />
|
|
|
|
|
|
{/if}
|
|
|
|
|
|
|
2026-09-22 12:40:32 -04:00
|
|
|
|
{#if showAboutDialog}
|
|
|
|
|
|
<AboutDialog onClose={() => (showAboutDialog = false)} />
|
|
|
|
|
|
{/if}
|
|
|
|
|
|
|
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>
2026-09-22 10:48:16 -04:00
|
|
|
|
{#if session.processingStep !== 'idle' && session.processingStep !== 'done'}
|
|
|
|
|
|
<ProcessingModal />
|
|
|
|
|
|
{/if}
|
|
|
|
|
|
|
2026-09-21 10:45:53 -04:00
|
|
|
|
<div class="app-shell">
|
|
|
|
|
|
<header class="toolbar">
|
|
|
|
|
|
<UrlInput />
|
2026-09-22 16:49:35 -04:00
|
|
|
|
<button
|
|
|
|
|
|
class="layout-btn"
|
|
|
|
|
|
onclick={toggleClipListPosition}
|
|
|
|
|
|
title={preferences.clipListPosition === 'bottom'
|
|
|
|
|
|
? 'Move clip list to sidebar'
|
|
|
|
|
|
: 'Move clip list to bottom'}
|
|
|
|
|
|
>
|
|
|
|
|
|
{preferences.clipListPosition === 'bottom' ? '⬒' : '⬓'}
|
|
|
|
|
|
</button>
|
2026-09-22 12:40:32 -04:00
|
|
|
|
<button class="about-btn" onclick={() => (showAboutDialog = true)} title="About">ℹ</button>
|
2026-09-21 10:54:42 -04:00
|
|
|
|
<button class="prefs-btn" onclick={() => (showPreferences = true)} title="Preferences">⚙</button>
|
2026-09-21 10:45:53 -04:00
|
|
|
|
</header>
|
|
|
|
|
|
|
2026-09-22 17:30:47 -04:00
|
|
|
|
<main class="content" class:layout-left={isLeft} style:--sidebar-width="{preferences.clipListWidth}px">
|
|
|
|
|
|
<!-- Sidebar clip list: visible only in left mode -->
|
|
|
|
|
|
<div class="sidebar-area" class:hidden={!isLeft}>
|
|
|
|
|
|
<ClipList onExport={() => (showExportDialog = true)} position="left" />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div
|
|
|
|
|
|
class="sidebar-handle"
|
|
|
|
|
|
class:hidden={!isLeft}
|
|
|
|
|
|
class:active={isSidebarResizing}
|
|
|
|
|
|
role="slider"
|
|
|
|
|
|
aria-orientation="vertical"
|
|
|
|
|
|
aria-label="Resize clip list sidebar"
|
|
|
|
|
|
aria-valuenow={preferences.clipListWidth}
|
|
|
|
|
|
aria-valuemin={150}
|
|
|
|
|
|
aria-valuemax={Math.round(windowWidth * 0.4)}
|
|
|
|
|
|
tabindex="0"
|
|
|
|
|
|
onmousedown={handleSidebarResizeStart}
|
|
|
|
|
|
onkeydown={(e) => {
|
|
|
|
|
|
const maxWidth = Math.round(windowWidth * 0.4);
|
|
|
|
|
|
const minWidth = Math.min(150, maxWidth);
|
|
|
|
|
|
if (e.key === 'ArrowRight') {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
setClipListWidth(
|
|
|
|
|
|
Math.max(minWidth, Math.min(maxWidth, preferences.clipListWidth + 10)),
|
|
|
|
|
|
);
|
|
|
|
|
|
} else if (e.key === 'ArrowLeft') {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
setClipListWidth(
|
|
|
|
|
|
Math.max(minWidth, Math.min(maxWidth, preferences.clipListWidth - 10)),
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
}}
|
|
|
|
|
|
></div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Video + Transport: always rendered, never destroyed -->
|
|
|
|
|
|
<div class="video-area">
|
2026-09-22 16:49:35 -04:00
|
|
|
|
<VideoPlayer />
|
|
|
|
|
|
<TransportControls bind:this={transportControls} />
|
2026-09-22 17:30:47 -04:00
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Timeline section: always full width -->
|
|
|
|
|
|
<div class="lower-section" bind:this={splitAreaEl}>
|
|
|
|
|
|
<div
|
|
|
|
|
|
class="resize-handle"
|
|
|
|
|
|
class:active={isResizing}
|
|
|
|
|
|
role="slider"
|
|
|
|
|
|
aria-orientation="horizontal"
|
|
|
|
|
|
aria-label="Resize timeline"
|
|
|
|
|
|
aria-valuenow={timelineHeight}
|
|
|
|
|
|
aria-valuemin={40}
|
|
|
|
|
|
aria-valuemax={500}
|
|
|
|
|
|
tabindex="0"
|
|
|
|
|
|
onmousedown={handleResizeStart}
|
|
|
|
|
|
onkeydown={(e) => {
|
|
|
|
|
|
if (e.key === 'ArrowDown') {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
timelineHeight = Math.min(500, timelineHeight + 10);
|
|
|
|
|
|
} else if (e.key === 'ArrowUp') {
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
|
timelineHeight = Math.max(40, timelineHeight - 10);
|
|
|
|
|
|
}
|
|
|
|
|
|
}}
|
|
|
|
|
|
></div>
|
|
|
|
|
|
<div class="timeline-pane" style="height: {timelineHeight}px">
|
|
|
|
|
|
<Timeline />
|
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>
2026-09-22 10:48:16 -04:00
|
|
|
|
</div>
|
2026-09-22 17:30:47 -04:00
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- Bottom clip list: visible only in bottom mode -->
|
|
|
|
|
|
<div class="bottom-cliplist" class:hidden={isLeft}>
|
|
|
|
|
|
<ClipList onExport={() => (showExportDialog = true)} />
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</main>
|
2026-09-21 10:45:53 -04:00
|
|
|
|
|
2026-09-22 12:40:32 -04:00
|
|
|
|
<StatusBar onOpenAbout={() => (showAboutDialog = true)} />
|
2026-09-21 10:45:53 -04:00
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<style>
|
|
|
|
|
|
.app-shell {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
height: 100vh;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.toolbar {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
padding: 8px 12px;
|
|
|
|
|
|
background: var(--bg-secondary);
|
|
|
|
|
|
border-bottom: 1px solid var(--border);
|
|
|
|
|
|
gap: 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-22 17:30:47 -04:00
|
|
|
|
/* --- Grid layout: bottom mode (default) --- */
|
2026-09-21 10:45:53 -04:00
|
|
|
|
.content {
|
|
|
|
|
|
flex: 1;
|
2026-09-22 17:30:47 -04:00
|
|
|
|
display: grid;
|
|
|
|
|
|
grid-template-areas:
|
|
|
|
|
|
"video"
|
|
|
|
|
|
"lower"
|
|
|
|
|
|
"bottom-clips";
|
|
|
|
|
|
grid-template-columns: 1fr;
|
|
|
|
|
|
grid-template-rows: 1fr auto auto;
|
2026-09-21 10:45:53 -04:00
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
}
|
2026-09-21 10:54:42 -04:00
|
|
|
|
|
2026-09-22 17:30:47 -04:00
|
|
|
|
.video-area {
|
|
|
|
|
|
grid-area: video;
|
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>
2026-09-22 10:48:16 -04:00
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
2026-09-22 17:30:47 -04:00
|
|
|
|
min-height: 0;
|
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>
2026-09-22 10:48:16 -04:00
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-22 17:30:47 -04:00
|
|
|
|
.lower-section {
|
|
|
|
|
|
grid-area: lower;
|
2026-09-22 16:49:35 -04:00
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
2026-09-22 17:30:47 -04:00
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
min-height: 80px;
|
2026-09-22 16:49:35 -04:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-22 17:30:47 -04:00
|
|
|
|
.bottom-cliplist {
|
|
|
|
|
|
grid-area: bottom-clips;
|
|
|
|
|
|
min-height: 20px;
|
2026-09-22 16:49:35 -04:00
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-22 17:30:47 -04:00
|
|
|
|
/* Sidebar elements hidden in bottom mode */
|
|
|
|
|
|
.sidebar-area {
|
|
|
|
|
|
grid-area: sidebar;
|
2026-09-22 16:49:35 -04:00
|
|
|
|
overflow-y: auto;
|
|
|
|
|
|
overflow-x: hidden;
|
|
|
|
|
|
border-right: 1px solid var(--border);
|
|
|
|
|
|
background: var(--bg-secondary);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-22 17:30:47 -04:00
|
|
|
|
.sidebar-handle {
|
|
|
|
|
|
grid-area: handle;
|
2026-09-22 16:49:35 -04:00
|
|
|
|
width: 5px;
|
|
|
|
|
|
background: var(--border);
|
|
|
|
|
|
cursor: ew-resize;
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
transition: background 0.1s;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-22 17:30:47 -04:00
|
|
|
|
.sidebar-handle:hover,
|
|
|
|
|
|
.sidebar-handle.active {
|
2026-09-22 16:49:35 -04:00
|
|
|
|
background: var(--accent);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-22 17:30:47 -04:00
|
|
|
|
.hidden {
|
|
|
|
|
|
display: none !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* --- Grid layout: left mode --- */
|
|
|
|
|
|
.content.layout-left {
|
|
|
|
|
|
grid-template-areas:
|
|
|
|
|
|
"sidebar handle video"
|
|
|
|
|
|
"lower lower lower"
|
|
|
|
|
|
"bottom-clips bottom-clips bottom-clips";
|
|
|
|
|
|
grid-template-columns: var(--sidebar-width, 220px) 5px 1fr;
|
|
|
|
|
|
grid-template-rows: 1fr auto 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.timeline-pane {
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
min-height: 40px;
|
2026-09-22 16:49:35 -04:00
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-22 17:30:47 -04:00
|
|
|
|
.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);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-22 16:49:35 -04:00
|
|
|
|
.layout-btn {
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
padding: 4px 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-22 12:40:32 -04:00
|
|
|
|
.about-btn {
|
|
|
|
|
|
font-size: 16px;
|
|
|
|
|
|
padding: 4px 8px;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-09-21 10:54:42 -04:00
|
|
|
|
.prefs-btn {
|
|
|
|
|
|
font-size: 18px;
|
|
|
|
|
|
padding: 4px 8px;
|
|
|
|
|
|
}
|
2026-09-21 10:45:53 -04:00
|
|
|
|
</style>
|