"use client"; import { Button } from "../../ui/button"; import { MoreVertical, Scissors, Trash2 } from "lucide-react"; import { useMediaStore } from "@/stores/media-store"; import { useTimelineStore, type TimelineTrack } from "@/stores/timeline-store"; import { usePlaybackStore } from "@/stores/playback-store"; import { type TimelineClip } from "@/types/timeline"; import { useState } from "react"; interface TimelineClipProps { clip: TimelineClip; track: TimelineTrack; zoomLevel: number; isSelected: boolean; onResizeStart: ( e: React.MouseEvent, clipId: string, side: "left" | "right" ) => void; onClipDragStart: (e: React.DragEvent, clip: any) => void; onClipDragEnd: (e: React.DragEvent) => void; onSelect: (e: React.MouseEvent) => void; onContextMenu: (e: React.MouseEvent) => void; getTrackColor: (type: string) => string; } export function TimelineClip({ clip, track, zoomLevel, isSelected, onResizeStart, onClipDragStart, onClipDragEnd, onSelect, onContextMenu, getTrackColor, }: TimelineClipProps) { const { mediaItems } = useMediaStore(); const { addClipToTrack, updateClipTrim, removeClipFromTrack } = useTimelineStore(); const { currentTime } = usePlaybackStore(); const [clipMenuOpen, setClipMenuOpen] = useState(null); const effectiveDuration = clip.duration - clip.trimStart - clip.trimEnd; const clipWidth = Math.max(80, effectiveDuration * 50 * zoomLevel); const clipLeft = clip.startTime * 50 * zoomLevel; const renderClipContent = (clip: TimelineClip) => { const mediaItem = mediaItems.find((item) => item.id === clip.mediaId); if (!mediaItem) { return ( {clip.name} ); } if (mediaItem.type === "image") { return (
{mediaItem.name}
); } if (mediaItem.type === "video" && mediaItem.thumbnailUrl) { return (
{mediaItem.name}
{clip.name}
); } // Fallback for audio or videos without thumbnails return ( {clip.name} ); }; const handleSplitClip = (clip: TimelineClip) => { // Use current playback time as split point const splitTime = currentTime; // Only split if splitTime is within the clip's effective range const effectiveStart = clip.startTime; const effectiveEnd = clip.startTime + (clip.duration - clip.trimStart - clip.trimEnd); if (splitTime <= effectiveStart || splitTime >= effectiveEnd) return; const firstDuration = splitTime - effectiveStart; const secondDuration = effectiveEnd - splitTime; // First part: adjust original clip updateClipTrim( track.id, clip.id, clip.trimStart, clip.trimEnd + secondDuration ); // Second part: add new clip after split addClipToTrack(track.id, { mediaId: clip.mediaId, name: clip.name + " (cut)", duration: clip.duration, startTime: splitTime, trimStart: clip.trimStart + firstDuration, trimEnd: clip.trimEnd, }); }; const handleDeleteClip = (clipId: string) => { removeClipFromTrack(track.id, clipId); }; return (
{/* Left trim handle */}
onResizeStart(e, clip.id, "left")} /> {/* Clip content */}
onClipDragStart(e, clip)} onDragEnd={onClipDragEnd} > {renderClipContent(clip)} {/* Clip options menu */}
{clipMenuOpen === clip.id && (
)}
{/* Right trim handle */}
onResizeStart(e, clip.id, "right")} />
); }