unified-video-framework
Version:
Cross-platform video player framework supporting iOS, Android, Web, Smart TVs (Samsung/LG), Roku, and more
233 lines • 11.3 kB
JavaScript
import React, { useState, useCallback } from 'react';
import { DEFAULT_EPG_THEME } from '../types/EPGTypes.js';
import { hexToRgba } from '../utils/ColorUtils.js';
export const EPGNavigationControls = ({ onNavigate, onTimeRangeChange, canNavigateLeft = true, canNavigateRight = true, currentTime = Date.now(), timelineStart, timelineEnd, visibleHours = 4, className = '', style = {}, theme: themeProp, }) => {
const theme = { ...DEFAULT_EPG_THEME, ...themeProp };
const [isNavigating, setIsNavigating] = useState(false);
const handleNavigate = useCallback(async (direction) => {
if (isNavigating)
return;
setIsNavigating(true);
try {
await onNavigate(direction);
}
finally {
setTimeout(() => setIsNavigating(false), 300);
}
}, [onNavigate, isNavigating]);
const handleTimeRangeChange = useCallback((hours) => {
if (onTimeRangeChange) {
onTimeRangeChange(hours);
}
}, [onTimeRangeChange]);
const getTimeRangeDisplay = () => {
if (!timelineStart || !timelineEnd)
return '';
const startDate = new Date(timelineStart);
const endDate = new Date(timelineEnd);
const today = new Date();
if (startDate.toDateString() === today.toDateString()) {
return `Today, ${startDate.toLocaleTimeString('en-US', {
hour: 'numeric',
minute: '2-digit',
hour12: true
})} - ${endDate.toLocaleTimeString('en-US', {
hour: 'numeric',
minute: '2-digit',
hour12: true
})}`;
}
return `${startDate.toLocaleDateString('en-US', {
weekday: 'short',
month: 'short',
day: 'numeric'
})}, ${startDate.toLocaleTimeString('en-US', {
hour: 'numeric',
hour12: true
})} - ${endDate.toLocaleTimeString('en-US', {
hour: 'numeric',
hour12: true
})}`;
};
return (React.createElement("div", { className: `epg-navigation-controls ${className}`, style: {
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
padding: '16px 70px 16px 24px',
backgroundColor: 'rgba(20, 20, 20, 0.7)',
borderBottom: '1px solid rgba(255, 255, 255, 0.1)',
height: '70px',
backdropFilter: 'blur(10px)',
...style,
} },
React.createElement("div", { className: "epg-time-range-display" },
React.createElement("div", { style: {
color: '#fff',
fontSize: '16px',
fontWeight: '600',
lineHeight: '1.2',
} }, getTimeRangeDisplay()),
timelineStart && timelineEnd && (React.createElement("div", { style: {
color: '#888',
fontSize: '12px',
lineHeight: '1.2',
marginTop: '2px',
} },
visibleHours,
" hour",
visibleHours !== 1 ? 's' : '',
" view"))),
React.createElement("div", { className: "epg-navigation-buttons", style: {
display: 'flex',
alignItems: 'center',
gap: '8px',
} },
React.createElement("button", { className: "epg-nav-button epg-nav-left", disabled: !canNavigateLeft || isNavigating, onClick: () => handleNavigate('left'), style: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: '48px',
height: '48px',
borderRadius: '8px',
border: '1px solid rgba(255, 255, 255, 0.2)',
backgroundColor: canNavigateLeft && !isNavigating ? hexToRgba(theme.selectionColor, 0.2) : 'rgba(255, 255, 255, 0.05)',
color: canNavigateLeft && !isNavigating ? '#fff' : 'rgba(255, 255, 255, 0.4)',
cursor: canNavigateLeft && !isNavigating ? 'pointer' : 'not-allowed',
transition: 'all 200ms ease',
fontSize: '18px',
fontWeight: '600',
}, onMouseEnter: (e) => {
if (canNavigateLeft && !isNavigating) {
e.currentTarget.style.backgroundColor = '#3a3a3a';
}
}, onMouseLeave: (e) => {
if (canNavigateLeft && !isNavigating) {
e.currentTarget.style.backgroundColor = '#2a2a2a';
}
} }, "\u25C0"),
React.createElement("button", { className: "epg-nav-button epg-nav-today", disabled: isNavigating, onClick: () => handleNavigate('today'), style: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
height: '48px',
padding: '0 24px',
borderRadius: '8px',
border: 'none',
backgroundColor: !isNavigating ? theme.primaryColor : hexToRgba(theme.primaryColor, 0.6),
color: '#fff',
cursor: !isNavigating ? 'pointer' : 'not-allowed',
transition: 'all 200ms ease',
fontSize: '16px',
fontWeight: '700',
whiteSpace: 'nowrap',
boxShadow: !isNavigating ? `0 4px 12px ${hexToRgba(theme.primaryColor, 0.3)}` : 'none',
}, onMouseEnter: (e) => {
if (!isNavigating) {
e.currentTarget.style.backgroundColor = '#ff8555';
}
}, onMouseLeave: (e) => {
if (!isNavigating) {
e.currentTarget.style.backgroundColor = theme.primaryColor;
}
} }, isNavigating ? '...' : 'NOW'),
React.createElement("button", { className: "epg-nav-button epg-nav-right", disabled: !canNavigateRight || isNavigating, onClick: () => handleNavigate('right'), style: {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
width: '48px',
height: '48px',
borderRadius: '8px',
border: '1px solid rgba(255, 255, 255, 0.2)',
backgroundColor: canNavigateRight && !isNavigating ? hexToRgba(theme.selectionColor, 0.2) : 'rgba(255, 255, 255, 0.05)',
color: canNavigateRight && !isNavigating ? '#fff' : 'rgba(255, 255, 255, 0.4)',
cursor: canNavigateRight && !isNavigating ? 'pointer' : 'not-allowed',
transition: 'all 200ms ease',
fontSize: '18px',
fontWeight: '600',
}, onMouseEnter: (e) => {
if (canNavigateRight && !isNavigating) {
e.currentTarget.style.backgroundColor = '#3a3a3a';
}
}, onMouseLeave: (e) => {
if (canNavigateRight && !isNavigating) {
e.currentTarget.style.backgroundColor = '#2a2a2a';
}
} }, "\u25B6")),
React.createElement("div", { className: "epg-view-options", style: {
display: 'flex',
alignItems: 'center',
gap: '12px',
} },
onTimeRangeChange && (React.createElement("div", { className: "epg-time-range-selector", style: {
display: 'flex',
alignItems: 'center',
gap: '8px',
padding: '6px 12px',
backgroundColor: hexToRgba(theme.primaryColor, 0.1),
border: `1px solid ${hexToRgba(theme.primaryColor, 0.3)}`,
borderRadius: '6px',
transition: 'all 0.2s ease',
position: 'relative',
} },
React.createElement("label", { style: {
color: theme.primaryColor,
fontSize: '11px',
fontWeight: '600',
textTransform: 'uppercase',
letterSpacing: '0.5px',
whiteSpace: 'nowrap',
} }, "Time Range"),
React.createElement("select", { value: visibleHours, onChange: (e) => handleTimeRangeChange(Number(e.target.value)), style: {
backgroundColor: '#1a1a1a',
color: '#fff',
border: '1px solid #555',
borderRadius: '4px',
padding: '6px 8px',
fontSize: '13px',
fontWeight: '500',
cursor: 'pointer',
outline: 'none',
minWidth: '90px',
transition: 'all 0.2s ease',
}, onMouseEnter: (e) => {
e.currentTarget.style.borderColor = theme.primaryColor;
e.currentTarget.style.backgroundColor = '#222';
}, onMouseLeave: (e) => {
e.currentTarget.style.borderColor = '#555';
e.currentTarget.style.backgroundColor = '#1a1a1a';
} },
React.createElement("option", { value: 2 }, "2 hours"),
React.createElement("option", { value: 4 }, "4 hours"),
React.createElement("option", { value: 6 }, "6 hours"),
React.createElement("option", { value: 8 }, "8 hours"),
React.createElement("option", { value: 12 }, "12 hours"),
React.createElement("option", { value: 24 }, "24 hours")))),
React.createElement("div", { className: "epg-current-time-badge", style: {
display: 'flex',
alignItems: 'center',
gap: '4px',
color: theme.primaryColor,
fontSize: '12px',
fontWeight: '600',
} },
React.createElement("div", { style: {
width: '6px',
height: '6px',
borderRadius: '50%',
backgroundColor: theme.primaryColor,
animation: 'pulse 2s infinite',
} }),
new Date(currentTime).toLocaleTimeString('en-US', {
hour: 'numeric',
minute: '2-digit',
hour12: true,
}))),
React.createElement("style", null, `
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
`)));
};
export default EPGNavigationControls;
//# sourceMappingURL=EPGNavigationControls.js.map