diff options
| author | Maze Winther <mazewinther@gmail.com> | 2025-07-09 21:03:56 +0200 |
|---|---|---|
| committer | Maze Winther <mazewinther@gmail.com> | 2025-07-09 21:03:56 +0200 |
| commit | c02f276303e00f4d8c66d8d1c804c4af9c719afb (patch) | |
| tree | aac3a38fd5f673cc30a9bbe1aef9eb197b430c9e /apps/web/src/components/editor/timeline-element.tsx | |
| parent | dd35c91f395eacf37f96dff8c9cec2340c9bb2b1 (diff) | |
| download | opencut-c02f276303e00f4d8c66d8d1c804c4af9c719afb.tar.gz | |
refactor: fresh properties panel
Diffstat (limited to 'apps/web/src/components/editor/timeline-element.tsx')
| -rw-r--r-- | apps/web/src/components/editor/timeline-element.tsx | 39 |
1 files changed, 39 insertions, 0 deletions
diff --git a/apps/web/src/components/editor/timeline-element.tsx b/apps/web/src/components/editor/timeline-element.tsx index 1e1674bf..c1c8b12b 100644 --- a/apps/web/src/components/editor/timeline-element.tsx +++ b/apps/web/src/components/editor/timeline-element.tsx @@ -12,6 +12,7 @@ import { ChevronLeft, Type, Copy, + RefreshCw, } from "lucide-react"; import { useMediaStore } from "@/stores/media-store"; import { useTimelineStore } from "@/stores/timeline-store"; @@ -61,6 +62,7 @@ export function TimelineElement({ splitAndKeepRight, separateAudio, addElementToTrack, + replaceElementMedia, } = useTimelineStore(); const { currentTime } = usePlaybackStore(); @@ -213,6 +215,37 @@ export function TimelineElement({ removeElementFromTrack(track.id, element.id); }; + const handleReplaceClip = () => { + if (element.type !== "media") { + toast.error("Replace is only available for media clips"); + return; + } + + // Create a file input to select replacement media + const input = document.createElement("input"); + input.type = "file"; + input.accept = "video/*,audio/*,image/*"; + input.onchange = async (e) => { + const file = (e.target as HTMLInputElement).files?.[0]; + if (!file) return; + + try { + const success = await replaceElementMedia(track.id, element.id, file); + if (success) { + toast.success("Clip replaced successfully"); + } else { + toast.error("Failed to replace clip"); + } + } catch (error) { + toast.error("Failed to replace clip"); + console.log( + JSON.stringify({ error: "Failed to replace clip", details: error }) + ); + } + }; + input.click(); + }; + const renderElementContent = () => { if (element.type === "text") { return ( @@ -350,6 +383,12 @@ export function TimelineElement({ <Copy className="h-4 w-4 mr-2" /> Duplicate {element.type === "text" ? "text" : "clip"} </ContextMenuItem> + {element.type === "media" && ( + <ContextMenuItem onClick={handleReplaceClip}> + <RefreshCw className="h-4 w-4 mr-2" /> + Replace clip + </ContextMenuItem> + )} <ContextMenuSeparator /> <ContextMenuItem onClick={handleElementDeleteContext} |
