diff options
| author | aashishparuvada <aashishvardhanp@gmail.com> | 2025-06-24 09:31:53 +0530 |
|---|---|---|
| committer | aashishparuvada <aashishvardhanp@gmail.com> | 2025-06-24 09:31:53 +0530 |
| commit | 073f0d89bd8ee6ccd81a3a4b3948f88816812bdf (patch) | |
| tree | db53282170fbd52dcfaa652341bd9a0ca2c6b08e | |
| parent | 9570847edd5afc8d005d4c1596eb7ce84d3fcdd1 (diff) | |
| download | opencut-073f0d89bd8ee6ccd81a3a4b3948f88816812bdf.tar.gz | |
feat:enabled-redo-functionality
| -rw-r--r-- | apps/web/src/components/editor/timeline.tsx | 17 | ||||
| -rw-r--r-- | apps/web/src/stores/timeline-store.ts | 25 |
2 files changed, 37 insertions, 5 deletions
diff --git a/apps/web/src/components/editor/timeline.tsx b/apps/web/src/components/editor/timeline.tsx index 484e1a6b..064d0dd2 100644 --- a/apps/web/src/components/editor/timeline.tsx +++ b/apps/web/src/components/editor/timeline.tsx @@ -40,7 +40,7 @@ export function Timeline() { // Timeline shows all tracks (video, audio, effects) and their clips.
// You can drag media here to add it to your project.
// Clips can be trimmed, deleted, and moved.
- const { tracks, addTrack, addClipToTrack, removeTrack, toggleTrackMute, removeClipFromTrack, moveClipToTrack, getTotalDuration, selectedClips, selectClip, deselectClip, clearSelectedClips, setSelectedClips, updateClipTrim, undo } =
+ const { tracks, addTrack, addClipToTrack, removeTrack, toggleTrackMute, removeClipFromTrack, moveClipToTrack, getTotalDuration, selectedClips, selectClip, deselectClip, clearSelectedClips, setSelectedClips, updateClipTrim, undo, redo } =
useTimelineStore();
const { mediaItems, addMediaItem } = useMediaStore();
const { currentTime, duration, seek, setDuration, isPlaying, play, pause, toggle, setSpeed, speed } = usePlaybackStore();
@@ -110,6 +110,21 @@ export function Timeline() { return () => window.removeEventListener("keydown", handleKeyDown);
}, [undo]);
+ // Keyboard event for redo (Cmd+Shift+Z or Cmd+Y)
+ useEffect(() => {
+ const handleKeyDown = (e: KeyboardEvent) => {
+ if ((e.metaKey || e.ctrlKey) && e.key === "z" && e.shiftKey) {
+ e.preventDefault();
+ redo();
+ } else if ((e.metaKey || e.ctrlKey) && e.key === "y") {
+ e.preventDefault();
+ redo();
+ }
+ };
+ window.addEventListener("keydown", handleKeyDown);
+ return () => window.removeEventListener("keydown", handleKeyDown);
+ }, [redo]);
+
// Mouse down on timeline background to start marquee
const handleTimelineMouseDown = (e: React.MouseEvent) => {
if (e.target === e.currentTarget && e.button === 0) {
diff --git a/apps/web/src/stores/timeline-store.ts b/apps/web/src/stores/timeline-store.ts index a369d574..e1474bae 100644 --- a/apps/web/src/stores/timeline-store.ts +++ b/apps/web/src/stores/timeline-store.ts @@ -21,6 +21,7 @@ export interface TimelineTrack { interface TimelineStore {
tracks: TimelineTrack[];
history: TimelineTrack[][];
+ redoStack: TimelineTrack[][];
// Multi-selection
selectedClips: { trackId: string; clipId: string }[];
@@ -57,25 +58,34 @@ interface TimelineStore { // New actions
undo: () => void;
+ redo: () => void;
pushHistory: () => void;
}
export const useTimelineStore = create<TimelineStore>((set, get) => ({
tracks: [],
history: [],
+ redoStack: [],
selectedClips: [],
pushHistory: () => {
- const { tracks, history } = get();
+ const { tracks, history, redoStack } = get();
// Deep copy tracks
- set({ history: [...history, JSON.parse(JSON.stringify(tracks))] });
+ set({
+ history: [...history, JSON.parse(JSON.stringify(tracks))],
+ redoStack: [] // Clear redo stack when new action is performed
+ });
},
undo: () => {
- const { history } = get();
+ const { history, redoStack, tracks } = get();
if (history.length === 0) return;
const prev = history[history.length - 1];
- set({ tracks: prev, history: history.slice(0, -1) });
+ set({
+ tracks: prev,
+ history: history.slice(0, -1),
+ redoStack: [...redoStack, JSON.parse(JSON.stringify(tracks))] // Add current state to redo stack
+ });
},
selectClip: (trackId, clipId, multi = false) => {
@@ -244,4 +254,11 @@ export const useTimelineStore = create<TimelineStore>((set, get) => ({ return Math.max(...trackEndTimes, 0);
},
+
+ redo: () => {
+ const { redoStack } = get();
+ if (redoStack.length === 0) return;
+ const next = redoStack[redoStack.length - 1];
+ set({ tracks: next, redoStack: redoStack.slice(0, -1) });
+ },
}));
|
