import { useState } from "react"; import { formatTimestamp } from "../hooks/useVideoFrames"; import type { TimelineMarker } from "../lib/api"; interface TimelineProps { currentTime: number; duration: number; currentFrame: number; totalFrames: number; fps: number; onSeekTime: (seconds: number) => void; onSeekFrame: (frame: number) => void; markers?: TimelineMarker[]; } // Linear-style markers with accent colors const MARKER_COLORS: Record = { command: "var(--status-success)", // green for terminal commands click: "var(--accent-1)", // purple for clicks file_change: "var(--status-warning)", // amber for file changes marker: "var(--accent-2)", shortcut: "var(--status-danger)", keypress: "var(--text-secondary)", mouse_scroll: "var(--accent-3)", app_focus: "var(--accent-4)", dom_navigation: "var(--accent-5)", dom_action: "var(--accent-2)", }; function Timeline({ currentTime, duration, currentFrame, totalFrames, fps, onSeekFrame, onSeekTime, markers = [], }: TimelineProps) { const [frameInput, setFrameInput] = useState(""); const [timestampInput, setTimestampInput] = useState(""); const [hoveredMarker, setHoveredMarker] = useState(null); const progress = duration > 0 ? (currentTime / duration) * 100 : 0; const handleScrub = (event: React.MouseEvent) => { if (!duration) return; const rect = event.currentTarget.getBoundingClientRect(); const percent = (event.clientX - rect.left) / rect.width; onSeekTime(Math.max(0, Math.min(duration, percent * duration))); }; const handleFrameJump = (event: React.FormEvent) => { event.preventDefault(); const targetFrame = Number(frameInput); if (!Number.isFinite(targetFrame)) return; onSeekFrame(targetFrame); setFrameInput(""); }; const handleTimestampJump = (event: React.FormEvent) => { event.preventDefault(); const targetSeconds = Number(timestampInput); if (!Number.isFinite(targetSeconds)) return; onSeekTime(targetSeconds); setTimestampInput(""); }; return ( ); } export default Timeline;