fix: improve element dragging (can drag outside timeline without it breaking)
This commit is contained in:
@ -8,6 +8,13 @@ import { useTimelineStore } from "@/stores/timeline-store";
|
|||||||
import { Textarea } from "../ui/textarea";
|
import { Textarea } from "../ui/textarea";
|
||||||
import { MediaElement, TextElement } from "@/types/timeline";
|
import { MediaElement, TextElement } from "@/types/timeline";
|
||||||
import { useMediaStore } from "@/stores/media-store";
|
import { useMediaStore } from "@/stores/media-store";
|
||||||
|
import {
|
||||||
|
Select,
|
||||||
|
SelectContent,
|
||||||
|
SelectTrigger,
|
||||||
|
SelectValue,
|
||||||
|
SelectItem,
|
||||||
|
} from "../ui/select";
|
||||||
|
|
||||||
export function PropertiesPanel() {
|
export function PropertiesPanel() {
|
||||||
const { activeProject } = useProjectStore();
|
const { activeProject } = useProjectStore();
|
||||||
@ -31,7 +38,7 @@ export function PropertiesPanel() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const TextProperties = (element: TextElement, trackId: string) => (
|
const TextProperties = (element: TextElement, trackId: string) => (
|
||||||
<div className="space-y-4 p-5">
|
<div className="space-y-6 p-5">
|
||||||
<Textarea
|
<Textarea
|
||||||
placeholder="Name"
|
placeholder="Name"
|
||||||
defaultValue={element.content}
|
defaultValue={element.content}
|
||||||
@ -40,6 +47,19 @@ export function PropertiesPanel() {
|
|||||||
updateTextElement(trackId, element.id, { content: e.target.value })
|
updateTextElement(trackId, element.id, { content: e.target.value })
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
<div className="flex items-center justify-between gap-6">
|
||||||
|
<Label className="text-xs">Font</Label>
|
||||||
|
<Select>
|
||||||
|
<SelectTrigger className="w-full text-xs">
|
||||||
|
<SelectValue placeholder="Select a font" />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectItem value="Arial">Arial</SelectItem>
|
||||||
|
<SelectItem value="Helvetica">Helvetica</SelectItem>
|
||||||
|
<SelectItem value="Times New Roman">Times New Roman</SelectItem>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -88,19 +88,30 @@ export function TimelineTrackContent({
|
|||||||
const handleMouseUp = (e: MouseEvent) => {
|
const handleMouseUp = (e: MouseEvent) => {
|
||||||
if (!dragState.elementId || !dragState.trackId) return;
|
if (!dragState.elementId || !dragState.trackId) return;
|
||||||
|
|
||||||
// Check if the mouse is actually over this track
|
// If this track initiated the drag, we should handle the mouse up regardless of where it occurs
|
||||||
|
const isTrackThatStartedDrag = dragState.trackId === track.id;
|
||||||
|
|
||||||
const timelineRect = timelineRef.current?.getBoundingClientRect();
|
const timelineRect = timelineRef.current?.getBoundingClientRect();
|
||||||
if (!timelineRect) return;
|
if (!timelineRect) {
|
||||||
|
if (isTrackThatStartedDrag) {
|
||||||
|
updateElementStartTime(
|
||||||
|
track.id,
|
||||||
|
dragState.elementId,
|
||||||
|
dragState.currentTime
|
||||||
|
);
|
||||||
|
endDragAction();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const isMouseOverThisTrack =
|
const isMouseOverThisTrack =
|
||||||
e.clientY >= timelineRect.top && e.clientY <= timelineRect.bottom;
|
e.clientY >= timelineRect.top && e.clientY <= timelineRect.bottom;
|
||||||
|
|
||||||
// Only handle if mouse is over this track
|
if (!isMouseOverThisTrack && !isTrackThatStartedDrag) return;
|
||||||
if (!isMouseOverThisTrack) return;
|
|
||||||
|
|
||||||
const finalTime = dragState.currentTime;
|
const finalTime = dragState.currentTime;
|
||||||
|
|
||||||
// Check for overlaps and update position
|
if (isMouseOverThisTrack) {
|
||||||
const sourceTrack = tracks.find((t) => t.id === dragState.trackId);
|
const sourceTrack = tracks.find((t) => t.id === dragState.trackId);
|
||||||
const movingElement = sourceTrack?.elements.find(
|
const movingElement = sourceTrack?.elements.find(
|
||||||
(c) => c.id === dragState.elementId
|
(c) => c.id === dragState.elementId
|
||||||
@ -140,13 +151,52 @@ export function TimelineTrackContent({
|
|||||||
dragState.elementId
|
dragState.elementId
|
||||||
);
|
);
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
updateElementStartTime(track.id, dragState.elementId!, finalTime);
|
updateElementStartTime(
|
||||||
|
track.id,
|
||||||
|
dragState.elementId!,
|
||||||
|
finalTime
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (isTrackThatStartedDrag) {
|
||||||
|
// Mouse is not over this track, but this track started the drag
|
||||||
|
// This means user released over ruler/outside - update position within same track
|
||||||
|
const sourceTrack = tracks.find((t) => t.id === dragState.trackId);
|
||||||
|
const movingElement = sourceTrack?.elements.find(
|
||||||
|
(c) => c.id === dragState.elementId
|
||||||
|
);
|
||||||
|
|
||||||
|
if (movingElement) {
|
||||||
|
const movingElementDuration =
|
||||||
|
movingElement.duration -
|
||||||
|
movingElement.trimStart -
|
||||||
|
movingElement.trimEnd;
|
||||||
|
const movingElementEnd = finalTime + movingElementDuration;
|
||||||
|
|
||||||
|
const hasOverlap = track.elements.some((existingElement) => {
|
||||||
|
if (existingElement.id === dragState.elementId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const existingStart = existingElement.startTime;
|
||||||
|
const existingEnd =
|
||||||
|
existingElement.startTime +
|
||||||
|
(existingElement.duration -
|
||||||
|
existingElement.trimStart -
|
||||||
|
existingElement.trimEnd);
|
||||||
|
return finalTime < existingEnd && movingElementEnd > existingStart;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!hasOverlap) {
|
||||||
|
updateElementStartTime(track.id, dragState.elementId, finalTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isTrackThatStartedDrag) {
|
||||||
endDragAction();
|
endDragAction();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
document.addEventListener("mousemove", handleMouseMove);
|
document.addEventListener("mousemove", handleMouseMove);
|
||||||
|
Reference in New Issue
Block a user