Merge branch 'OpenCut-app:main' into main

This commit is contained in:
Kesku 2025-06-23 20:29:13 +09:00 committed by GitHub
commit 723bc584da
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 10 additions and 86 deletions

View File

@ -20,12 +20,10 @@ import {
TooltipTrigger,
TooltipProvider,
} from "../ui/tooltip";
import { DragOverlay } from "../ui/drag-overlay";
import { useTimelineStore, type TimelineTrack } from "@/stores/timeline-store";
import { useMediaStore } from "@/stores/media-store";
import { usePlaybackStore } from "@/stores/playback-store";
import { processMediaFiles } from "@/lib/media-processing";
import { ImageTimelineTreatment } from "@/components/ui/image-timeline-treatment";
import { toast } from "sonner";
import { useState, useRef, useEffect } from "react";
@ -64,7 +62,7 @@ export function Timeline() {
const handleDragEnter = (e: React.DragEvent) => {
// When something is dragged over the timeline, show overlay
e.preventDefault();
// Don't show overlay for timeline clips or other internal drags
// Don't show overlay for timeline clips - they're handled by tracks
if (e.dataTransfer.types.includes("application/x-timeline-clip")) {
return;
}
@ -81,7 +79,7 @@ export function Timeline() {
const handleDragLeave = (e: React.DragEvent) => {
e.preventDefault();
// Don't update state for timeline clips
// Don't update state for timeline clips - they're handled by tracks
if (e.dataTransfer.types.includes("application/x-timeline-clip")) {
return;
}
@ -98,6 +96,12 @@ export function Timeline() {
setIsDragOver(false);
dragCounterRef.current = 0;
// Ignore timeline clip drags - they're handled by track-specific handlers
const hasTimelineClip = e.dataTransfer.types.includes("application/x-timeline-clip");
if (hasTimelineClip) {
return;
}
const mediaItemData = e.dataTransfer.getData("application/x-media-item");
if (mediaItemData) {
// Handle media item drops by creating new tracks
@ -903,6 +907,7 @@ function TimelineTrackContent({
const handleTrackDrop = (e: React.DragEvent) => {
e.preventDefault();
e.stopPropagation();
// Reset all drag states
dragCounterRef.current = 0;
@ -985,7 +990,6 @@ function TimelineTrackContent({
updateClipStartTime(track.id, clipId, snappedTime);
} else {
// Moving to different track
console.log('Moving clip from', fromTrackId, 'to', track.id);
moveClipToTrack(fromTrackId, track.id, clipId);
requestAnimationFrame(() => {
updateClipStartTime(track.id, clipId, snappedTime);
@ -1295,87 +1299,7 @@ function TimelineTrackContent({
)}
</>
)}
</div>
</div>
);
}
// Custom context menu for track actions
function TrackContextMenu({
x,
y,
track,
onClose,
onSplit,
onMute,
onDelete,
}: {
x: number;
y: number;
track: any;
onClose: () => void;
onSplit: () => void;
onMute: () => void;
onDelete: () => void;
}) {
// Small, modern, visually appealing popup
return (
<div
className="fixed z-50 min-w-[140px] bg-white border border-muted rounded-lg shadow-lg py-1 text-sm animate-fade-in text-black"
style={{ left: x + 4, top: y + 4 }}
onContextMenu={(e) => e.preventDefault()}
>
{/* Split option */}
<button
className="flex items-center w-full px-3 py-2 hover:bg-muted/20 transition-colors"
onClick={onSplit}
>
<span className="mr-2">
<MoreVertical className="h-4 w-4" />
</span>
Split at Playhead
</button>
{/* Mute/Unmute option */}
<button
className="flex items-center w-full px-3 py-2 hover:bg-muted/20 transition-colors"
onClick={onMute}
>
<span className="mr-2">
{track.muted ? (
<VolumeX className="h-4 w-4" />
) : (
<Volume2 className="h-4 w-4" />
)}
</span>
{track.muted ? "Unmute Track" : "Mute Track"}
</button>
{/* Delete option */}
<button
className="flex items-center w-full px-3 py-2 text-red-600 hover:bg-red-50 transition-colors"
onClick={onDelete}
>
<span className="mr-2">
<Trash2 className="h-4 w-4" />
</span>
Delete Track
</button>
</div>
);
}
}