summaryrefslogtreecommitdiff
path: root/apps/web/src/components/editor/timeline-element.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'apps/web/src/components/editor/timeline-element.tsx')
-rw-r--r--apps/web/src/components/editor/timeline-element.tsx45
1 files changed, 43 insertions, 2 deletions
diff --git a/apps/web/src/components/editor/timeline-element.tsx b/apps/web/src/components/editor/timeline-element.tsx
index 1e1674bf..ee9445f3 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";
@@ -23,7 +24,7 @@ import { useTimelineElementResize } from "@/hooks/use-timeline-element-resize";
import {
getTrackElementClasses,
TIMELINE_CONSTANTS,
-} from "@/lib/timeline-constants";
+} from "@/constants/timeline-constants";
import {
DropdownMenu,
DropdownMenuContent,
@@ -61,6 +62,7 @@ export function TimelineElement({
splitAndKeepRight,
separateAudio,
addElementToTrack,
+ replaceElementMedia,
} = useTimelineStore();
const { currentTime } = usePlaybackStore();
@@ -213,10 +215,41 @@ 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 (
- <div className="w-full h-full flex items-center justify-center">
+ <div className="w-full h-full flex items-center justify-start pl-2">
<span className="text-xs text-foreground/80 truncate">
{element.content}
</span>
@@ -306,6 +339,8 @@ export function TimelineElement({
left: `${elementLeft}px`,
width: `${elementWidth}px`,
}}
+ data-element-id={element.id}
+ data-track-id={track.id}
onMouseMove={resizing ? handleResizeMove : undefined}
onMouseUp={resizing ? handleResizeEnd : undefined}
onMouseLeave={resizing ? handleResizeEnd : undefined}
@@ -350,6 +385,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}