unified-video-framework
Version:
Cross-platform video player framework supporting iOS, Android, Web, Smart TVs (Samsung/LG), Roku, and more
156 lines • 7.84 kB
JavaScript
import React, { useMemo, useRef, useEffect } from 'react';
import { DEFAULT_EPG_THEME } from '../types/EPGTypes.js';
import { generateTimeSlots, getCurrentTimePosition, formatTime } from '../utils/EPGUtils.js';
export const EPGTimelineHeader = ({ timelineStart, timelineEnd, containerWidth, currentTime = Date.now(), visibleHours = 4, slotDuration = 60, onTimeClick, scrollLeft = 0, onScroll, className = '', style = {}, theme: themeProp, }) => {
const theme = { ...DEFAULT_EPG_THEME, ...themeProp };
const headerRef = useRef(null);
const scrollContainerRef = useRef(null);
const timeSlots = useMemo(() => {
return generateTimeSlots(timelineStart, visibleHours, slotDuration);
}, [timelineStart, visibleHours, slotDuration]);
const currentTimePosition = useMemo(() => {
return getCurrentTimePosition(currentTime, timelineStart, timelineEnd, containerWidth);
}, [currentTime, timelineStart, timelineEnd, containerWidth]);
const handleTimeSlotClick = (timestamp) => {
if (onTimeClick) {
onTimeClick(timestamp);
}
};
useEffect(() => {
if (scrollContainerRef.current && scrollLeft !== undefined) {
scrollContainerRef.current.scrollLeft = scrollLeft;
}
}, [scrollLeft]);
const handleTimelineScroll = (e) => {
if (onScroll) {
onScroll(e.currentTarget.scrollLeft);
}
};
return (React.createElement("div", { ref: headerRef, className: `epg-timeline-header ${className}`, style: {
position: 'relative',
height: '60px',
borderBottom: '1px solid rgba(255, 255, 255, 0.1)',
backgroundColor: 'rgba(20, 20, 20, 0.5)',
backdropFilter: 'blur(8px)',
display: 'flex',
...style,
} },
React.createElement("div", { style: {
width: '200px',
height: '100%',
backgroundColor: 'rgba(20, 20, 20, 0.6)',
borderRight: '1px solid rgba(255, 255, 255, 0.1)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontSize: '12px',
fontWeight: '600',
color: 'rgba(255, 255, 255, 0.5)',
} }, "Channels"),
React.createElement("div", { ref: scrollContainerRef, className: "epg-timeline-scroll-container", style: {
flex: 1,
height: '100%',
overflow: 'auto',
scrollbarWidth: 'none',
msOverflowStyle: 'none',
}, onScroll: handleTimelineScroll },
React.createElement("div", { className: "epg-timeline-slots", style: {
position: 'relative',
width: `${containerWidth}px`,
height: '100%',
display: 'flex',
alignItems: 'center',
} },
timeSlots.map((slot, index) => {
const slotPosition = ((slot.timestamp - timelineStart) / (timelineEnd - timelineStart)) * containerWidth;
return (React.createElement("div", { key: slot.timestamp, className: "epg-time-slot", style: {
position: 'absolute',
left: `${slotPosition}px`,
height: '100%',
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'flex-start',
cursor: 'pointer',
paddingLeft: '8px',
minWidth: '80px',
borderLeft: index > 0 ? '1px solid #333' : 'none',
}, onClick: () => handleTimeSlotClick(slot.timestamp) },
React.createElement("div", { className: "epg-time-label", style: {
color: '#fff',
fontSize: '14px',
fontWeight: '600',
lineHeight: '1.2',
} }, slot.label),
(index === 0 || slot.hour === 0) && (React.createElement("div", { className: "epg-date-label", style: {
color: '#888',
fontSize: '11px',
lineHeight: '1.2',
marginTop: '2px',
} }, new Date(slot.timestamp).toLocaleDateString('en-US', {
weekday: 'short',
month: 'short',
day: 'numeric',
})))));
}),
currentTimePosition > 0 && (React.createElement("div", { className: "epg-current-time-indicator", style: {
position: 'absolute',
left: `${currentTimePosition}px`,
top: '0',
bottom: '0',
width: '2px',
backgroundColor: theme.primaryColor,
zIndex: 10,
pointerEvents: 'none',
} },
React.createElement("div", { style: {
position: 'absolute',
top: '8px',
left: '50%',
transform: 'translateX(-50%)',
backgroundColor: theme.primaryColor,
color: '#fff',
fontSize: '10px',
fontWeight: '600',
padding: '2px 6px',
borderRadius: '4px',
whiteSpace: 'nowrap',
boxShadow: '0 2px 4px rgba(0,0,0,0.3)',
} }, "NOW"),
React.createElement("div", { style: {
position: 'absolute',
bottom: '8px',
left: '50%',
transform: 'translateX(-50%)',
backgroundColor: theme.primaryColor,
color: '#fff',
fontSize: '10px',
fontWeight: '600',
padding: '2px 6px',
borderRadius: '4px',
whiteSpace: 'nowrap',
boxShadow: '0 2px 4px rgba(0,0,0,0.3)',
} }, formatTime(currentTime)))),
timeSlots.map((slot, index) => {
if (index === 0)
return null;
const linePosition = ((slot.timestamp - timelineStart) / (timelineEnd - timelineStart)) * containerWidth;
return (React.createElement("div", { key: `grid-${slot.timestamp}`, className: "epg-grid-line", style: {
position: 'absolute',
left: `${linePosition}px`,
top: '0',
bottom: '0',
width: '1px',
backgroundColor: 'rgba(255, 255, 255, 0.1)',
opacity: 1,
pointerEvents: 'none',
} }));
})),
React.createElement("style", null, `
.epg-timeline-scroll-container::-webkit-scrollbar {
display: none;
}
`))));
};
export default EPGTimelineHeader;
//# sourceMappingURL=EPGTimelineHeader.js.map