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

@ -7,6 +7,7 @@ import type {
CutRange,
MuteRange,
GainRange,
SpeedRange,
TranscriptionResult,
ProjectFile,
SilenceDetectionRange,
@ -24,6 +25,7 @@ interface EditorState {
cutRanges: CutRange[];
muteRanges: MuteRange[];
gainRanges: GainRange[];
speedRanges: SpeedRange[];
globalGainDb: number;
silenceTrimGroups: SilenceTrimGroup[];
transcriptionModel: string | null;
@ -63,13 +65,17 @@ interface EditorActions {
addCutRange: (start: number, end: number, trimGroupId?: string) => void;
addMuteRange: (start: number, end: number) => void;
addGainRange: (start: number, end: number, gainDb: number) => void;
addSpeedRange: (start: number, end: number, speed: number) => void;
updateCutRange: (id: string, start: number, end: number) => void;
updateMuteRange: (id: string, start: number, end: number) => void;
updateGainRangeBounds: (id: string, start: number, end: number) => void;
updateGainRange: (id: string, gainDb: number) => void;
updateSpeedRangeBounds: (id: string, start: number, end: number) => void;
updateSpeedRange: (id: string, speed: number) => void;
removeCutRange: (id: string) => void;
removeMuteRange: (id: string) => void;
removeGainRange: (id: string) => void;
removeSpeedRange: (id: string) => void;
setGlobalGainDb: (gainDb: number) => void;
applySilenceTrimGroup: (args: {
groupId?: string;
@ -95,6 +101,7 @@ const initialState: EditorState = {
cutRanges: [],
muteRanges: [],
gainRanges: [],
speedRanges: [],
globalGainDb: 0,
silenceTrimGroups: [],
transcriptionModel: null,
@ -152,7 +159,7 @@ export const useEditorStore = create<EditorState & EditorActions>()(
setTranscriptionModel: (model) => set({ transcriptionModel: model }),
saveProject: (): ProjectFile => {
const { videoPath, words, segments, deletedRanges, cutRanges, muteRanges, gainRanges, globalGainDb, silenceTrimGroups, transcriptionModel, language, exportedAudioPath } = get();
const { videoPath, words, segments, deletedRanges, cutRanges, muteRanges, gainRanges, speedRanges, globalGainDb, silenceTrimGroups, transcriptionModel, language, exportedAudioPath } = get();
if (!videoPath) throw new Error('No video loaded');
const now = new Date().toISOString();
// Strip globalStartIndex (runtime-only field) before persisting.
@ -172,6 +179,7 @@ export const useEditorStore = create<EditorState & EditorActions>()(
cutRanges,
muteRanges,
gainRanges,
speedRanges,
globalGainDb,
silenceTrimGroups,
language,
@ -286,6 +294,17 @@ export const useEditorStore = create<EditorState & EditorActions>()(
set({ gainRanges: [...gainRanges, newRange] });
},
addSpeedRange: (start, end, speed) => {
const { speedRanges } = get();
const newRange: SpeedRange = {
id: `speed_${nextRangeId++}`,
start,
end,
speed: Math.max(0.25, Math.min(4, speed)),
};
set({ speedRanges: [...speedRanges, newRange] });
},
updateCutRange: (id, start, end) => {
const { cutRanges } = get();
set({
@ -322,6 +341,24 @@ export const useEditorStore = create<EditorState & EditorActions>()(
});
},
updateSpeedRangeBounds: (id, start, end) => {
const { speedRanges } = get();
set({
speedRanges: speedRanges.map((r) =>
r.id === id ? { ...r, start, end } : r
),
});
},
updateSpeedRange: (id, speed) => {
const { speedRanges } = get();
set({
speedRanges: speedRanges.map((r) =>
r.id === id ? { ...r, speed: Math.max(0.25, Math.min(4, speed)) } : r
),
});
},
removeCutRange: (id) => {
const { cutRanges } = get();
set({ cutRanges: cutRanges.filter((r) => r.id !== id) });
@ -337,6 +374,11 @@ export const useEditorStore = create<EditorState & EditorActions>()(
set({ gainRanges: gainRanges.filter((r) => r.id !== id) });
},
removeSpeedRange: (id) => {
const { speedRanges } = get();
set({ speedRanges: speedRanges.filter((r) => r.id !== id) });
},
setGlobalGainDb: (gainDb) => {
set({ globalGainDb: Math.max(-24, Math.min(24, gainDb)) });
},
@ -470,6 +512,7 @@ export const useEditorStore = create<EditorState & EditorActions>()(
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,