import { AlertCircle, AlertTriangle, Bookmark, CheckSquare, Download, FolderOpen, PlayCircle, RefreshCw, StickyNote, Trash2, } from "lucide-react" import React, { useCallback, useEffect, useRef, useState } from "react" import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuTrigger } from "@/components/ui/context-menu" import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip" import { cn } from "@/lib/utils" import { ExtendedTimelineMarker, MarkerColors, MarkerType } from "../../types/markers" interface TimelineMarkerProps { marker: ExtendedTimelineMarker timeScale: number isSelected: boolean onDrag?: (markerId: string, newTime: number) => void onClick?: (markerId: string) => void onDelete?: (markerId: string) => void } const markerIcons: Record = { chapter: , section: , note: , export: , todo: , sync: , cue: , important: , warning: , } export function TimelineMarker({ marker, timeScale, isSelected, onDrag, onClick, onDelete }: TimelineMarkerProps) { const [isDragging, setIsDragging] = useState(false) const [dragStartX, setDragStartX] = useState(0) const [dragStartTime, setDragStartTime] = useState(0) const markerRef = useRef(null) const markerType = marker.type! const markerColor = MarkerColors[markerType] || "#6b7280" const markerIcon = markerIcons[markerType] || // Начало перетаскивания const handleMouseDown = useCallback( (e: React.MouseEvent) => { if (marker.isLocked) return e.preventDefault() e.stopPropagation() setIsDragging(true) setDragStartX(e.clientX) setDragStartTime(marker.time) }, [marker.isLocked, marker.time], ) // Перетаскивание const handleMouseMove = useCallback( (e: MouseEvent) => { if (!isDragging || !onDrag) return const deltaX = e.clientX - dragStartX const deltaTime = deltaX / timeScale const newTime = dragStartTime + deltaTime onDrag(marker.id, newTime) }, [isDragging, dragStartX, dragStartTime, timeScale, marker.id, onDrag], ) // Окончание перетаскивания const handleMouseUp = useCallback(() => { setIsDragging(false) }, []) // Глобальные обработчики событий для перетаскивания useEffect(() => { if (isDragging) { document.addEventListener("mousemove", handleMouseMove) document.addEventListener("mouseup", handleMouseUp) return () => { document.removeEventListener("mousemove", handleMouseMove) document.removeEventListener("mouseup", handleMouseUp) } } }, [isDragging, handleMouseMove, handleMouseUp]) // Обработка клика const handleClick = useCallback( (e: React.MouseEvent) => { if (onClick && !isDragging) { e.stopPropagation() onClick(marker.id) } }, [onClick, marker.id, isDragging], ) // Форматирование времени const formatTime = (time: number) => { const minutes = Math.floor(time / 60) const seconds = Math.floor(time % 60) const frames = Math.floor((time % 1) * 30) // Предполагаем 30 fps return `${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}.${frames.toString().padStart(2, "0")}` } return (
{/* Треугольник маркера */} {/* Иконка маркера */}
{markerIcon}
{/* Флаг для маркеров с длительностью */} {marker.duration && marker.duration > 0 && (
)}
{marker.name}
{formatTime(marker.time)}
{marker.description &&
{marker.description}
}
onClick?.(marker.id)}>Go to Marker onDelete?.(marker.id)} className="text-destructive"> Delete Marker ) }