UI improvements, moved file name and moved buttons left

This commit is contained in:
2026-04-15 19:54:39 -06:00
parent 7479acd3ee
commit b7a795f986
9 changed files with 500 additions and 70 deletions

View File

@ -21,6 +21,7 @@ import {
Scissors,
VolumeX,
SlidersHorizontal,
Gauge,
FilePlus2,
RefreshCw,
Grid3x3,
@ -40,6 +41,7 @@ export default function App() {
cutRanges,
muteRanges,
gainRanges,
speedRanges,
globalGainDb,
silenceTrimGroups,
transcriptionModel,
@ -55,14 +57,18 @@ export default function App() {
addCutRange,
addMuteRange,
addGainRange,
addSpeedRange,
} = useEditorStore();
const [activePanel, setActivePanel] = useState<Panel>(null);
const [whisperModel, setWhisperModel] = useState('base');
useEffect(() => { if (transcriptionModel) setWhisperModel(transcriptionModel); }, [transcriptionModel]);
const [cutMode, setCutMode] = useState(false);
const [muteMode, setMuteMode] = useState(false);
const [gainMode, setGainMode] = useState(false);
const [gainModeDb, setGainModeDb] = useState(3);
const [speedMode, setSpeedMode] = useState(false);
const [speedModeValue, setSpeedModeValue] = useState(1.25);
const [showReprocessConfirm, setShowReprocessConfirm] = useState(false);
const [showUnsavedPrompt, setShowUnsavedPrompt] = useState(false);
const [pendingProceedAction, setPendingProceedAction] = useState<(() => Promise<void>) | null>(null);
@ -79,6 +85,7 @@ export default function App() {
cutRanges,
muteRanges,
gainRanges,
speedRanges,
globalGainDb,
silenceTrimGroups,
transcriptionModel,
@ -93,6 +100,7 @@ export default function App() {
cutRanges,
muteRanges,
gainRanges,
speedRanges,
globalGainDb,
silenceTrimGroups,
transcriptionModel,
@ -112,6 +120,7 @@ export default function App() {
cutRanges: data.cutRanges || [],
muteRanges: data.muteRanges || [],
gainRanges: data.gainRanges || [],
speedRanges: data.speedRanges || [],
globalGainDb: typeof data.globalGainDb === 'number' ? data.globalGainDb : 0,
silenceTrimGroups: data.silenceTrimGroups || [],
transcriptionModel: data.transcriptionModel ?? null,
@ -138,6 +147,7 @@ export default function App() {
setCutMode(false);
setMuteMode(false);
setGainMode(false);
setSpeedMode(false);
}
};
@ -217,6 +227,7 @@ export default function App() {
setCutMode(false);
setMuteMode(false);
setGainMode(false);
setSpeedMode(false);
});
};
@ -315,6 +326,7 @@ export default function App() {
setCutMode(!cutMode);
setMuteMode(false); // Exit mute mode
setGainMode(false); // Exit gain mode
setSpeedMode(false); // Exit speed mode
}
};
@ -330,6 +342,7 @@ export default function App() {
setMuteMode(!muteMode);
setCutMode(false); // Exit cut mode
setGainMode(false); // Exit gain mode
setSpeedMode(false); // Exit speed mode
}
};
@ -343,6 +356,21 @@ export default function App() {
setGainMode(!gainMode);
setCutMode(false);
setMuteMode(false);
setSpeedMode(false);
}
};
const handleSpeed = () => {
if (selectedWordIndices.length > 0) {
const sorted = [...selectedWordIndices].sort((a, b) => a - b);
const startTime = words[sorted[0]].start;
const endTime = words[sorted[sorted.length - 1]].end;
addSpeedRange(startTime, endTime, speedModeValue);
} else {
setSpeedMode(!speedMode);
setCutMode(false);
setMuteMode(false);
setGainMode(false);
}
};
@ -413,19 +441,8 @@ export default function App() {
return (
<div className="h-screen flex flex-col bg-editor-bg overflow-hidden">
{/* Top bar */}
<header className="h-12 flex items-center justify-between px-4 border-b border-editor-border shrink-0">
<div className="flex items-center gap-3">
<Film className="w-5 h-5 text-editor-accent" />
<span className="text-sm font-medium truncate max-w-[300px]">
{videoPath.split(/[\\/]/).pop()}
</span>
{transcriptionModel && (
<span className="px-2 py-0.5 rounded border border-editor-border bg-editor-surface text-[10px] uppercase tracking-wide text-editor-text-muted">
Model: {transcriptionModel}
</span>
)}
</div>
<div className="flex items-center gap-2">
<header className="h-12 flex items-center px-4 border-b border-editor-border shrink-0">
<div className="flex items-center gap-0.5">
<ToolbarButton
icon={<FilePlus2 className="w-4 h-4" />}
label="New"
@ -477,6 +494,24 @@ export default function App() {
title="Gain dB for new gain zones"
/>
</div>
<div className="flex items-center gap-1">
<ToolbarButton
icon={<Gauge className="w-4 h-4" />}
label="Speed Zone"
onClick={handleSpeed}
active={speedMode}
/>
<input
type="number"
min={0.25}
max={4}
step={0.05}
value={speedModeValue}
onChange={(e) => setSpeedModeValue(Math.max(0.25, Math.min(4, Number(e.target.value) || 1)))}
className="w-16 px-1.5 py-1 text-xs bg-editor-surface border border-editor-border rounded text-editor-text focus:outline-none focus:border-editor-accent"
title="Playback rate for new speed zones"
/>
</div>
<ToolbarButton
icon={<Grid3x3 className="w-4 h-4" />}
label="Zones"
@ -495,7 +530,7 @@ export default function App() {
<select
value={whisperModel}
onChange={(e) => setWhisperModel(e.target.value)}
className="bg-transparent text-xs text-editor-text focus:outline-none"
className="bg-editor-surface text-xs text-editor-text focus:outline-none [color-scheme:dark]"
title="Transcription model"
>
<optgroup label="Multilingual">
@ -521,7 +556,7 @@ export default function App() {
onClick={handleReprocessProject}
disabled={isTranscribing || !videoPath}
title="Reprocess transcript with selected model"
className="flex items-center gap-1 px-2 py-1 rounded text-xs text-editor-text-muted hover:text-editor-text hover:bg-editor-bg disabled:opacity-40 disabled:cursor-not-allowed"
className="flex items-center gap-1 px-2 py-1 rounded text-xs text-editor-text hover:bg-editor-bg disabled:opacity-40 disabled:cursor-not-allowed"
>
<RefreshCw className={`w-3 h-3 ${isTranscribing ? 'animate-spin' : ''}`} />
Reprocess
@ -562,6 +597,16 @@ export default function App() {
{/* Transcript */}
<div className="w-1/2 border-l border-editor-border flex flex-col min-h-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">
<span className="text-xs font-medium truncate text-editor-text">{videoPath.split(/[\/]/).pop()}</span>
{transcriptionModel && (
<span className="px-1.5 py-0.5 rounded border border-editor-border bg-editor-surface text-[10px] uppercase tracking-wide text-editor-text-muted shrink-0">
{transcriptionModel}
</span>
)}
</div>
)}
{isTranscribing ? (
<div className="flex-1 flex flex-col items-center justify-center gap-5">
{/* Animated waveform */}
@ -588,6 +633,8 @@ export default function App() {
muteMode={muteMode}
gainMode={gainMode}
gainModeDb={gainModeDb}
speedMode={speedMode}
speedModeValue={speedModeValue}
/>
) : (
<div className="flex-1 flex items-center justify-center text-editor-text-muted text-sm">
@ -599,7 +646,14 @@ export default function App() {
{/* Waveform timeline */}
<div className="h-32 border-t border-editor-border shrink-0">
<WaveformTimeline cutMode={cutMode} muteMode={muteMode} gainMode={gainMode} gainModeDb={gainModeDb} />
<WaveformTimeline
cutMode={cutMode}
muteMode={muteMode}
gainMode={gainMode}
gainModeDb={gainModeDb}
speedMode={speedMode}
speedModeValue={speedModeValue}
/>
</div>
</div>