summaryrefslogtreecommitdiff
path: root/apps/web/src/hooks
diff options
context:
space:
mode:
Diffstat (limited to 'apps/web/src/hooks')
-rw-r--r--apps/web/src/hooks/use-timeline-element-resize.ts71
1 files changed, 66 insertions, 5 deletions
diff --git a/apps/web/src/hooks/use-timeline-element-resize.ts b/apps/web/src/hooks/use-timeline-element-resize.ts
index 3882a8f8..0e409977 100644
--- a/apps/web/src/hooks/use-timeline-element-resize.ts
+++ b/apps/web/src/hooks/use-timeline-element-resize.ts
@@ -1,5 +1,6 @@
import { useState, useEffect } from "react";
import { ResizeState, TimelineElement, TimelineTrack } from "@/types/timeline";
+import { useMediaStore } from "@/stores/media-store";
interface UseTimelineElementResizeProps {
element: TimelineElement;
@@ -11,6 +12,11 @@ interface UseTimelineElementResizeProps {
trimStart: number,
trimEnd: number
) => void;
+ onUpdateDuration: (
+ trackId: string,
+ elementId: string,
+ duration: number
+ ) => void;
}
export function useTimelineElementResize({
@@ -18,8 +24,10 @@ export function useTimelineElementResize({
track,
zoomLevel,
onUpdateTrim,
+ onUpdateDuration,
}: UseTimelineElementResizeProps) {
const [resizing, setResizing] = useState<ResizeState | null>(null);
+ const { mediaItems } = useMediaStore();
// Set up document-level mouse listeners during resize (like proper drag behavior)
useEffect(() => {
@@ -60,6 +68,30 @@ export function useTimelineElementResize({
});
};
+ const canExtendElementDuration = () => {
+ // Text elements can always be extended
+ if (element.type === "text") {
+ return true;
+ }
+
+ // Media elements - check the media type
+ if (element.type === "media") {
+ const mediaItem = mediaItems.find((item) => item.id === element.mediaId);
+ if (!mediaItem) return false;
+
+ // Images can be extended (static content)
+ if (mediaItem.type === "image") {
+ return true;
+ }
+
+ // Videos and audio cannot be extended beyond their natural duration
+ // (no additional content exists)
+ return false;
+ }
+
+ return false;
+ };
+
const updateTrimFromMouseMove = (e: { clientX: number }) => {
if (!resizing) return;
@@ -68,19 +100,48 @@ export function useTimelineElementResize({
const deltaTime = deltaX / (50 * zoomLevel);
if (resizing.side === "left") {
+ // Left resize - only trim within original duration
const maxAllowed = element.duration - resizing.initialTrimEnd - 0.1;
const calculated = resizing.initialTrimStart + deltaTime;
const newTrimStart = Math.max(0, Math.min(maxAllowed, calculated));
onUpdateTrim(track.id, element.id, newTrimStart, resizing.initialTrimEnd);
} else {
- // For right resize (expanding element), allow trimEnd to go to 0 but cap at element duration
+ // Right resize - can extend duration for supported element types
const calculated = resizing.initialTrimEnd - deltaTime;
- // Prevent negative trim AND prevent trimEnd from exceeding element duration
- const maxTrimEnd = element.duration - resizing.initialTrimStart - 0.1; // Leave at least 0.1s visible
- const newTrimEnd = Math.max(0, Math.min(maxTrimEnd, calculated));
- onUpdateTrim(track.id, element.id, resizing.initialTrimStart, newTrimEnd);
+ if (calculated < 0) {
+ // We're trying to extend beyond original duration
+ if (canExtendElementDuration()) {
+ // Extend the duration instead of reducing trimEnd further
+ const extensionNeeded = Math.abs(calculated);
+ const newDuration = element.duration + extensionNeeded;
+ const newTrimEnd = 0; // Reset trimEnd to 0 since we're extending
+
+ // Update duration first, then trim
+ onUpdateDuration(track.id, element.id, newDuration);
+ onUpdateTrim(
+ track.id,
+ element.id,
+ resizing.initialTrimStart,
+ newTrimEnd
+ );
+ } else {
+ // Can't extend - just set trimEnd to 0 (maximum possible extension)
+ onUpdateTrim(track.id, element.id, resizing.initialTrimStart, 0);
+ }
+ } else {
+ // Normal trimming within original duration
+ const maxTrimEnd = element.duration - resizing.initialTrimStart - 0.1; // Leave at least 0.1s visible
+ const newTrimEnd = Math.max(0, Math.min(maxTrimEnd, calculated));
+
+ onUpdateTrim(
+ track.id,
+ element.id,
+ resizing.initialTrimStart,
+ newTrimEnd
+ );
+ }
}
};