fix: make whole clip draggable

This commit is contained in:
Maze Winther
2025-06-25 21:22:08 +02:00
parent 2775ac427d
commit 926aebe004

View File

@ -1254,8 +1254,24 @@ function TimelineTrackContent({
const [justFinishedDrag, setJustFinishedDrag] = useState(false); const [justFinishedDrag, setJustFinishedDrag] = useState(false);
const handleClipMouseDown = (e: React.MouseEvent, clip: any) => { const handleClipMouseDown = (e: React.MouseEvent, clip: any) => {
// Handle selection first
if (!justFinishedDrag) {
const isSelected = selectedClips.some(
(c) => c.trackId === track.id && c.clipId === clip.id
);
if (e.metaKey || e.ctrlKey || e.shiftKey) {
// Multi-selection mode: toggle the clip
selectClip(track.id, clip.id, true);
} else if (!isSelected) {
// If clip is not selected, select it (replacing other selections)
selectClip(track.id, clip.id, false);
}
// Note: Don't deselect if already selected, as user might want to drag
}
// Calculate the offset from the left edge of the clip to where the user clicked // Calculate the offset from the left edge of the clip to where the user clicked
const clipElement = e.currentTarget.parentElement as HTMLElement; const clipElement = e.currentTarget as HTMLElement;
const clipRect = clipElement.getBoundingClientRect(); const clipRect = clipElement.getBoundingClientRect();
const clickOffsetX = e.clientX - clipRect.left; const clickOffsetX = e.clientX - clipRect.left;
const clickOffsetTime = clickOffsetX / (50 * zoomLevel); const clickOffsetTime = clickOffsetX / (50 * zoomLevel);
@ -1773,8 +1789,9 @@ function TimelineTrackContent({
return ( return (
<div <div
key={clip.id} key={clip.id}
className={`timeline-clip absolute h-full border ${getTrackColor(track.type)} flex items-center py-3 min-w-[80px] overflow-hidden group hover:shadow-lg ${isSelected ? "ring-2 ring-blue-500 z-10" : ""} ${isBeingDragged ? "shadow-lg z-20" : ""}`} className={`timeline-clip absolute h-full border ${getTrackColor(track.type)} flex items-center py-3 min-w-[80px] overflow-hidden group hover:shadow-lg ${isSelected ? "ring-2 ring-blue-500 z-10" : ""} ${isBeingDragged ? "shadow-lg z-20" : ""} ${isBeingDragged ? "cursor-grabbing" : "cursor-grab"}`}
style={{ width: `${clipWidth}px`, left: `${clipLeft}px` }} style={{ width: `${clipWidth}px`, left: `${clipLeft}px` }}
onMouseDown={(e) => handleClipMouseDown(e, clip)}
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
@ -1789,19 +1806,14 @@ function TimelineTrackContent({
return; // Don't handle selection when closing context menu return; // Don't handle selection when closing context menu
} }
// Only handle deselection here (selection is handled in mouseDown)
const isSelected = selectedClips.some( const isSelected = selectedClips.some(
(c) => c.trackId === track.id && c.clipId === clip.id (c) => c.trackId === track.id && c.clipId === clip.id
); );
if (e.metaKey || e.ctrlKey || e.shiftKey) { if (isSelected && !e.metaKey && !e.ctrlKey && !e.shiftKey) {
// Multi-selection mode: toggle the clip // If clip is already selected and no modifier keys, deselect it
selectClip(track.id, clip.id, true);
} else if (isSelected) {
// If clip is already selected, deselect it
deselectClip(track.id, clip.id); deselectClip(track.id, clip.id);
} else {
// If clip is not selected, select it (replacing other selections)
selectClip(track.id, clip.id, false);
} }
}} }}
tabIndex={0} tabIndex={0}
@ -1820,13 +1832,13 @@ function TimelineTrackContent({
{/* Left trim handle */} {/* Left trim handle */}
<div <div
className={`absolute left-0 top-0 bottom-0 w-2 cursor-w-resize transition-opacity bg-blue-500/50 hover:bg-blue-500 ${isSelected ? "opacity-100" : "opacity-0"}`} className={`absolute left-0 top-0 bottom-0 w-2 cursor-w-resize transition-opacity bg-blue-500/50 hover:bg-blue-500 ${isSelected ? "opacity-100" : "opacity-0"}`}
onMouseDown={(e) => handleResizeStart(e, clip.id, "left")} onMouseDown={(e) => {
e.stopPropagation(); // Prevent triggering clip drag
handleResizeStart(e, clip.id, "left");
}}
/> />
{/* Clip content */} {/* Clip content */}
<div <div className="flex-1 relative">
className={`flex-1 relative ${isBeingDragged ? "cursor-grabbing" : "cursor-grab"}`}
onMouseDown={(e) => handleClipMouseDown(e, clip)}
>
{renderClipContent(clip)} {renderClipContent(clip)}
{/* Clip options menu */} {/* Clip options menu */}
<div className="absolute top-1 right-1 z-10"> <div className="absolute top-1 right-1 z-10">
@ -1835,11 +1847,15 @@ function TimelineTrackContent({
size="icon" size="icon"
className="opacity-0 group-hover:opacity-100 transition-opacity" className="opacity-0 group-hover:opacity-100 transition-opacity"
onClick={() => setClipMenuOpen(clip.id)} onClick={() => setClipMenuOpen(clip.id)}
onMouseDown={(e) => e.stopPropagation()}
> >
<MoreVertical className="h-4 w-4" /> <MoreVertical className="h-4 w-4" />
</Button> </Button>
{clipMenuOpen === clip.id && ( {clipMenuOpen === clip.id && (
<div className="absolute right-0 mt-2 w-32 bg-white border rounded shadow z-50"> <div
className="absolute right-0 mt-2 w-32 bg-white border rounded shadow z-50"
onMouseDown={(e) => e.stopPropagation()}
>
<button <button
className="flex items-center w-full px-3 py-2 text-sm hover:bg-muted/30" className="flex items-center w-full px-3 py-2 text-sm hover:bg-muted/30"
onClick={() => { onClick={() => {
@ -1862,7 +1878,10 @@ function TimelineTrackContent({
{/* Right trim handle */} {/* Right trim handle */}
<div <div
className={`absolute right-0 top-0 bottom-0 w-2 cursor-e-resize transition-opacity bg-blue-500/50 hover:bg-blue-500 ${isSelected ? "opacity-100" : "opacity-0"}`} className={`absolute right-0 top-0 bottom-0 w-2 cursor-e-resize transition-opacity bg-blue-500/50 hover:bg-blue-500 ${isSelected ? "opacity-100" : "opacity-0"}`}
onMouseDown={(e) => handleResizeStart(e, clip.id, "right")} onMouseDown={(e) => {
e.stopPropagation(); // Prevent triggering clip drag
handleResizeStart(e, clip.id, "right");
}}
/> />
</div> </div>
); );