"use client"; import { Scissors, Trash2, Copy, Search, RefreshCw, EyeOff, Eye, Volume2, VolumeX, } from "lucide-react"; import { useMediaStore } from "@/stores/media-store"; import { useTimelineStore } from "@/stores/timeline-store"; import { usePlaybackStore } from "@/stores/playback-store"; import AudioWaveform from "../audio-waveform"; import { toast } from "sonner"; import { TimelineElementProps, MediaElement } from "@/types/timeline"; import { useTimelineElementResize } from "@/hooks/use-timeline-element-resize"; import { getTrackElementClasses, TIMELINE_CONSTANTS, getTrackHeight, } from "@/constants/timeline-constants"; import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuSeparator, ContextMenuTrigger, } from "../../ui/context-menu"; import { useMediaPanelStore } from "../media-panel/store"; export function TimelineElement({ element, track, zoomLevel, isSelected, onElementMouseDown, onElementClick, }: TimelineElementProps) { const { mediaFiles } = useMediaStore(); const { dragState, copySelected, selectedElements, deleteSelected, splitSelected, toggleSelectedHidden, toggleSelectedMuted, duplicateElement, revealElementInMedia, replaceElementWithFile, getContextMenuState, } = useTimelineStore(); const { currentTime } = usePlaybackStore(); const mediaItem = element.type === "media" ? mediaFiles.find((file) => file.id === element.mediaId) : null; const hasAudio = mediaItem?.type === "audio" || mediaItem?.type === "video"; const { resizing, handleResizeStart, handleResizeMove, handleResizeEnd } = useTimelineElementResize({ element, track, zoomLevel, }); const { isMultipleSelected, isCurrentElementSelected, hasAudioElements, canSplitSelected, } = getContextMenuState(track.id, element.id); const effectiveDuration = element.duration - element.trimStart - element.trimEnd; const elementWidth = Math.max( TIMELINE_CONSTANTS.ELEMENT_MIN_WIDTH, effectiveDuration * TIMELINE_CONSTANTS.PIXELS_PER_SECOND * zoomLevel ); const isBeingDragged = dragState.elementId === element.id; const elementStartTime = isBeingDragged && dragState.isDragging ? dragState.currentTime : element.startTime; const elementLeft = elementStartTime * 50 * zoomLevel; const handleElementSplitContext = (e: React.MouseEvent) => { e.stopPropagation(); splitSelected( currentTime, isMultipleSelected && isCurrentElementSelected ? undefined : track.id, isMultipleSelected && isCurrentElementSelected ? undefined : element.id ); }; const handleElementDuplicateContext = (e: React.MouseEvent) => { e.stopPropagation(); duplicateElement(track.id, element.id); }; const handleElementCopyContext = (e: React.MouseEvent) => { e.stopPropagation(); copySelected(); }; const handleElementDeleteContext = (e: React.MouseEvent) => { e.stopPropagation(); deleteSelected( isMultipleSelected && isCurrentElementSelected ? undefined : track.id, isMultipleSelected && isCurrentElementSelected ? undefined : element.id ); }; const handleToggleElementContext = (e: React.MouseEvent) => { e.stopPropagation(); if (hasAudio && element.type === "media") { toggleSelectedMuted( isMultipleSelected && isCurrentElementSelected ? undefined : track.id, isMultipleSelected && isCurrentElementSelected ? undefined : element.id ); } else { toggleSelectedHidden( isMultipleSelected && isCurrentElementSelected ? undefined : track.id, isMultipleSelected && isCurrentElementSelected ? undefined : element.id ); } }; const handleReplaceClip = (e: React.MouseEvent) => { e.stopPropagation(); const input = document.createElement("input"); input.type = "file"; input.accept = "video/*,audio/*,image/*"; input.onchange = async (e) => { const file = (e.target as HTMLInputElement).files?.[0]; if (file) { await replaceElementWithFile(track.id, element.id, file); } }; input.click(); }; const handleRevealInMedia = (e: React.MouseEvent) => { e.stopPropagation(); revealElementInMedia(element.id); }; const renderElementContent = () => { if (element.type === "text") { return (