summaryrefslogtreecommitdiff
path: root/apps/web/src/components/editor/timeline-element.tsx
diff options
context:
space:
mode:
authorMaze Winther <mazewinther@gmail.com>2025-07-09 21:03:56 +0200
committerMaze Winther <mazewinther@gmail.com>2025-07-09 21:03:56 +0200
commitc02f276303e00f4d8c66d8d1c804c4af9c719afb (patch)
treeaac3a38fd5f673cc30a9bbe1aef9eb197b430c9e /apps/web/src/components/editor/timeline-element.tsx
parentdd35c91f395eacf37f96dff8c9cec2340c9bb2b1 (diff)
downloadopencut-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.tsx39
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}