/** * TimelineContent - Основной контент Timeline * * Отображает треки, клипы и временную шкалу */ import { useEffect, useRef, useState } from "react" // Убираем ненужные иконки import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card" import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from "@/components/ui/resizable" import { useTimelineAIIntegration } from "@/features/ai-chat/hooks/use-timeline-ai-integration" import { useCurrentProject } from "@/features/app-state/hooks/use-current-project" import { useProjectSettings } from "@/features/project-settings/hooks/use-project-settings" import { useClips } from "../hooks/use-clips" import { useDragDropTimeline } from "../hooks/use-drag-drop-timeline" import { EditModeProvider } from "../hooks/use-edit-mode" import { useTimeline } from "../hooks/use-timeline" import { useTimelinePlayerSync } from "../hooks/use-timeline-player-sync" import { useTracks } from "../hooks/use-tracks" import { TimelineAIOverlay } from "./ai-analysis/timeline-ai-overlay" import { AIMarkerControls } from "./ai-markers/ai-marker-controls" import { DragDropProvider } from "./drag-drop-provider" import { EditModeSelector } from "./edit-mode-selector" import { EditModeOverlay } from "./edit-tools/edit-mode-overlay" import { SplitIndicator } from "./edit-tools/split-indicator" import { TimelineMarkersLayer } from "./markers" import { TimelineHotkeys } from "./timeline-hotkeys" import { TimelinePreviewStrip } from "./timeline-preview-strip" import { TimelineScale } from "./timeline-scale" import { SpeedRampingIndicator, TimelineSpeedRampingIntegration, TimelineSpeedRampingStatus, } from "./timeline-speed-ramping-integration" import { Track } from "./track/track" import { TrackControlsPanel } from "./track-controls-panel" import { TrackInsertionZones } from "./track-insertion-zone" export function TimelineContent() { const scrollContainerRef = useRef(null) const [scrollOffset, setScrollOffset] = useState(0) const [containerWidth, setContainerWidth] = useState(0) // Подключаем AI интеграцию const { isReady: aiReady } = useTimelineAIIntegration() // Drag and drop hook const { dragState } = useDragDropTimeline() const { project, uiState, currentTime, createProject, addSection, addTrack, updateTrack, selectTracks, seek, error, clearError, send, } = useTimeline() const { tracks, setTrackHeight } = useTracks() const { clips } = useClips() // Получаем данные реального проекта const { currentProject } = useCurrentProject() const { settings: projectSettings } = useProjectSettings() // Инициализируем синхронизацию с плеером useTimelinePlayerSync() // Создаем проект при первой загрузке, используя настройки из реального проекта useEffect(() => { if (!project && currentProject && projectSettings) { void createProject(currentProject.name, { width: projectSettings.aspectRatio.value.width, height: projectSettings.aspectRatio.value.height, frameRate: Number.parseInt(projectSettings.frameRate), }) } }, [project, currentProject, projectSettings, createProject]) // Добавляем демо секцию useEffect(() => { if (project && project.sections.length === 0) { // Добавляем секцию void addSection("Main Section", 0, 300) // 5 минут } }, [project, addSection]) // Отслеживаем размер контейнера и прокрутку useEffect(() => { const container = scrollContainerRef.current if (!container) return const handleScroll = () => { setScrollOffset(container.scrollLeft) } const handleResize = () => { setContainerWidth(container.clientWidth) } // Инициализация handleResize() // Слушатели событий container.addEventListener("scroll", handleScroll) window.addEventListener("resize", handleResize) const resizeObserver = new ResizeObserver(handleResize) resizeObserver.observe(container) return () => { container.removeEventListener("scroll", handleScroll) window.removeEventListener("resize", handleResize) resizeObserver.disconnect() } }, []) if (error) { return (
Ошибка Timeline

{error}

) } if (!project) { return (
Загрузка Timeline...

Инициализация проекта...

) } return (
{/* Edit mode overlay */} {/* Информация о проекте и режимы редактирования */}

{currentProject?.name || project.name}

{projectSettings ? `${projectSettings.aspectRatio.value.width}x${projectSettings.aspectRatio.value.height} @ ${projectSettings.frameRate}fps` : `${project.settings.resolution.width}x${project.settings.resolution.height} @ ${project.settings.fps}fps`}

{/* Edit mode selector */} {/* AI Marker Controls */}
{project.sections.length} секций {tracks.length} треков {clips.length} клипов
{/* Основная область Timeline */}
{/* Временная шкала */}
{/* Пустое место для синхронизации с TrackControlsPanel */}
Временная шкала
{/* Шкала времени */}
{/* Треки с горизонтальным разделением */} {/* Левая панель - Управление треками */} {/* Правая панель - Область треков */}
{tracks.length === 0 ? (

Треки не найдены

) : (
{/* Markers layer */} {/* AI Analysis Overlay */} {/* Split indicator */} } timeScale={uiState.timeScale} scrollX={scrollOffset} onSplit={(time, trackId) => { // Find clip at this position const track = tracks.find((t) => t.id === trackId) if (track) { const clip = track.clips.find((c) => time > c.startTime && time < c.startTime + c.duration) if (clip) { send({ type: "SPLIT_CLIP", clipId: clip.id, splitTime: time }) } } }} /> {/* Track Insertion Zones - показываем только во время drag */} t.id)} isVisible={dragState.isDragging} /> {/* Полоса превью для видео клипов */} {clips.some((clip) => { const track = tracks.find((t) => t.id === clip.trackId) return track?.type === "video" && clip.mediaFile?.path }) && (
{clips .filter((clip) => { const track = tracks.find((t) => t.id === clip.trackId) return track?.type === "video" && clip.mediaFile?.path }) .map((clip) => ( seek(clip.startTime + timestamp)} showTimestamps={false} /> ))}
)} {/* Треки */}
{tracks.map((track) => ( selectTracks([trackId])} onUpdate={(updates) => updateTrack(track.id, updates)} /> ))}
)}
) }