improved chapters/markers

This commit is contained in:
2026-05-05 12:29:25 -06:00
parent 21e4255325
commit cde635a660
5 changed files with 410 additions and 20 deletions

View File

@ -1,4 +1,4 @@
import { useEffect, useState, useMemo } from 'react';
import { useEffect, useState, useMemo, useCallback, useRef } from 'react';
import { useEditorStore } from './store/editorStore';
import VideoPlayer from './components/VideoPlayer';
import TranscriptEditor from './components/TranscriptEditor';
@ -68,6 +68,54 @@ export default function App() {
const [activePanel, setActivePanel] = useState<Panel>(null);
const [projectName, setProjectName] = useState<string | null>(null);
const [splitRatio, setSplitRatio] = useState(() => {
try { return Number(localStorage.getItem('talkedit:splitRatio')) || 0.5; } catch { return 0.5; }
});
const splitRef = useRef<HTMLDivElement>(null);
const isDraggingSplit = useRef(false);
const startSplitDrag = useCallback((e: React.MouseEvent) => {
e.preventDefault();
isDraggingSplit.current = true;
const container = splitRef.current?.parentElement;
if (!container) return;
const rect = container.getBoundingClientRect();
const onMove = (me: MouseEvent) => {
if (!isDraggingSplit.current) return;
const pct = (me.clientX - rect.left) / rect.width;
const clamped = Math.max(0.15, Math.min(0.85, pct));
setSplitRatio(clamped);
localStorage.setItem('talkedit:splitRatio', String(clamped));
};
const onUp = () => { isDraggingSplit.current = false; window.removeEventListener('mousemove', onMove); window.removeEventListener('mouseup', onUp); };
window.addEventListener('mousemove', onMove);
window.addEventListener('mouseup', onUp);
}, []);
// Draggable right sidebar
const [sidebarWidth, setSidebarWidth] = useState(() => {
try { return Number(localStorage.getItem('talkedit:sidebarWidth')) || 320; } catch { return 320; }
});
const isDraggingSidebar = useRef(false);
const startSidebarDrag = useCallback((e: React.MouseEvent) => {
e.preventDefault();
isDraggingSidebar.current = true;
const container = document.querySelector('.main-content') as HTMLElement;
if (!container) return;
const rect = container.getBoundingClientRect();
const onMove = (me: MouseEvent) => {
if (!isDraggingSidebar.current) return;
const w = rect.right - me.clientX;
const clamped = Math.max(180, Math.min(600, w));
setSidebarWidth(clamped);
localStorage.setItem('talkedit:sidebarWidth', String(clamped));
};
const onUp = () => { isDraggingSidebar.current = false; window.removeEventListener('mousemove', onMove); window.removeEventListener('mouseup', onUp); };
window.addEventListener('mousemove', onMove);
window.addEventListener('mouseup', onUp);
}, []);
const [whisperModel, setWhisperModel] = useState('base');
useEffect(() => { if (transcriptionModel) setWhisperModel(transcriptionModel); }, [transcriptionModel]);
const [cutMode, setCutMode] = useState(false);
@ -666,17 +714,24 @@ export default function App() {
</header>
{/* Main content */}
<div className="flex-1 flex overflow-hidden">
<div className="main-content flex-1 flex overflow-hidden">
{/* Left: video + transcript */}
<div className="flex-1 flex flex-col min-w-0">
<div className="flex-1 flex min-h-0">
<div ref={splitRef} className="flex-1 flex min-h-0" style={{ position: 'relative' }}>
{/* Video player */}
<div className="w-1/2 p-3 flex items-center justify-center bg-black/20">
<div className="p-3 flex items-center justify-center bg-black/20 overflow-hidden" style={{ width: `${splitRatio * 100}%`, minWidth: 0 }}>
<VideoPlayer />
</div>
{/* Draggable divider */}
<div
className="w-1 shrink-0 bg-editor-border cursor-col-resize hover:bg-editor-accent/50 active:bg-editor-accent transition-colors relative z-10"
style={{ cursor: isDraggingSplit.current ? 'col-resize' : 'col-resize' }}
onMouseDown={startSplitDrag}
/>
{/* Transcript */}
<div className="w-1/2 border-l border-editor-border flex flex-col min-h-0">
<div className="border-l border-editor-border flex flex-col min-h-0" style={{ width: `${(1 - splitRatio) * 100}%`, minWidth: 0 }}>
{videoPath && (
<div className="flex items-center gap-2 px-3 py-1.5 border-b border-editor-border shrink-0 bg-editor-surface/50">
{projectName && (
@ -745,7 +800,13 @@ export default function App() {
{/* Right panel (AI / Export / Settings) */}
{activePanel && (
<div className="w-80 border-l border-editor-border overflow-y-auto shrink-0">
<div className="flex shrink-0">
{/* Draggable sidebar divider */}
<div
className="w-1 shrink-0 bg-editor-border cursor-col-resize hover:bg-editor-accent/50 active:bg-editor-accent transition-colors relative z-10"
onMouseDown={startSidebarDrag}
/>
<div className="overflow-y-auto" style={{ width: sidebarWidth }}>
{activePanel === 'zones' && (
<ZoneEditor />
)}
@ -755,7 +816,8 @@ export default function App() {
{activePanel === 'export' && <ExportDialog />}
{activePanel === 'settings' && <SettingsPanel />}
</div>
)}
</div>
)}
</div>
{import.meta.env.DEV && <DevPanel />}