UNPKG

unified-video-framework

Version:

Cross-platform video player framework supporting iOS, Android, Web, Smart TVs (Samsung/LG), Roku, and more

101 lines 4.57 kB
import React, { useMemo } from 'react'; import { SEGMENT_COLORS } from '../../chapters/types/ChapterTypes.js'; export const ChapterProgress = ({ chapters, progress = 0, buffered = 0, showMarkers = true, markerColors = {}, onMarkerClick, onProgressClick, className = '', style = {}, interactive = true }) => { const markers = useMemo(() => { if (!chapters || !showMarkers) return []; const colors = { ...SEGMENT_COLORS, ...markerColors }; return chapters.segments .filter(segment => segment.type !== 'content') .map(segment => ({ segment, position: (segment.startTime / chapters.duration) * 100, color: colors[segment.type] || '#ffffff', label: segment.title || segment.type })) .sort((a, b) => a.position - b.position); }, [chapters, showMarkers, markerColors]); const handleProgressClick = (event) => { if (!interactive || !onProgressClick) return; const rect = event.currentTarget.getBoundingClientRect(); const x = event.clientX - rect.left; const percentage = (x / rect.width) * 100; onProgressClick(Math.max(0, Math.min(100, percentage))); }; const handleMarkerClick = (event, segment) => { event.stopPropagation(); onMarkerClick?.(segment); }; const progressClasses = [ 'uvf-chapter-progress', interactive ? 'interactive' : '', className ].filter(Boolean).join(' '); return (React.createElement("div", { className: progressClasses, style: { position: 'relative', width: '100%', height: '4px', backgroundColor: 'rgba(255, 255, 255, 0.2)', borderRadius: '2px', cursor: interactive ? 'pointer' : 'default', ...style }, onClick: handleProgressClick }, React.createElement("div", { className: "uvf-chapter-progress-buffered", style: { position: 'absolute', top: 0, left: 0, height: '100%', width: `${Math.max(0, Math.min(100, buffered))}%`, backgroundColor: 'rgba(255, 255, 255, 0.4)', borderRadius: 'inherit', transition: 'width 0.3s ease' } }), React.createElement("div", { className: "uvf-chapter-progress-current", style: { position: 'absolute', top: 0, left: 0, height: '100%', width: `${Math.max(0, Math.min(100, progress))}%`, background: 'linear-gradient(90deg, var(--uvf-accent-1, #ff5722) 0%, var(--uvf-accent-2, #ff8a50) 100%)', borderRadius: 'inherit', transition: 'width 0.1s ease' } }), markers.map((marker, index) => (React.createElement("div", { key: `${marker.segment.id}-${index}`, className: `uvf-chapter-progress-marker uvf-marker-${marker.segment.type}`, style: { position: 'absolute', top: '50%', left: `${marker.position}%`, width: '3px', height: '150%', backgroundColor: marker.color, transform: 'translate(-50%, -50%)', cursor: 'pointer', borderRadius: '1px', zIndex: 10, transition: 'all 0.2s ease' }, title: `${marker.label} (${formatTime(marker.segment.startTime)})`, onClick: (e) => handleMarkerClick(e, marker.segment), onMouseEnter: (e) => { const element = e.currentTarget; element.style.width = '4px'; element.style.height = '200%'; element.style.boxShadow = `0 0 8px ${marker.color}`; }, onMouseLeave: (e) => { const element = e.currentTarget; element.style.width = '3px'; element.style.height = '150%'; element.style.boxShadow = 'none'; } }))))); }; function formatTime(seconds) { if (!seconds || isNaN(seconds)) return '0:00'; const hours = Math.floor(seconds / 3600); const minutes = Math.floor((seconds % 3600) / 60); const secs = Math.floor(seconds % 60); if (hours > 0) { return `${hours}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`; } else { return `${minutes}:${secs.toString().padStart(2, '0')}`; } } //# sourceMappingURL=ChapterProgress.js.map