UNPKG

unified-video-framework

Version:

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

178 lines 9.28 kB
import React, { useEffect, useState } from 'react'; function formatCount(n) { if (!n) return '0'; if (n >= 1000000) return (n / 1000000).toFixed(1).replace(/\.0$/, '') + 'M'; if (n >= 1000) return (n / 1000).toFixed(1).replace(/\.0$/, '') + 'K'; return String(n); } function getCountLabel(n, singular, plural) { return n === 1 ? singular : plural; } function formatDate(value) { if (!value) return null; const date = value instanceof Date ? value : new Date(value); if (Number.isNaN(date.getTime())) { const raw = String(value).trim(); if (!raw) return null; return { monthDay: raw, year: '' }; } return { monthDay: date.toLocaleDateString(undefined, { month: 'short', day: 'numeric' }), year: String(date.getFullYear()), }; } export const PortraitDescriptionPanel = ({ video, isOpen, onClose, desktopInline = false, }) => { const isMobile = typeof window !== 'undefined' && window.innerWidth < 768; const transitionMs = 240; const [shouldRender, setShouldRender] = useState(isOpen); useEffect(() => { if (isOpen) { setShouldRender(true); return; } const timer = window.setTimeout(() => setShouldRender(false), transitionMs); return () => window.clearTimeout(timer); }, [isOpen]); useEffect(() => { if (!isOpen) return; const handleEscape = (e) => { if (e.key === 'Escape') onClose(); }; window.addEventListener('keydown', handleEscape); return () => window.removeEventListener('keydown', handleEscape); }, [isOpen, onClose]); if (!shouldRender) return null; const panelDate = formatDate(video.publishDate ?? video.timestamp); return (React.createElement(React.Fragment, null, isMobile && !desktopInline && (React.createElement("div", { onClick: onClose, style: { position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.5)', zIndex: 100, opacity: isOpen ? 1 : 0, transition: `opacity ${transitionMs}ms cubic-bezier(0.22, 1, 0.36, 1)`, pointerEvents: isOpen ? 'auto' : 'none', } })), React.createElement("div", { "data-uvf-description-panel": true, style: { position: 'fixed', ...(isMobile ? { left: 0, right: 0, bottom: 0, top: 'auto', maxHeight: '85vh', borderTopLeftRadius: 16, borderTopRightRadius: 16, transform: isOpen ? 'translateY(0)' : 'translateY(100%)', } : { ...(desktopInline ? { position: 'relative', top: 'auto', right: 'auto', bottom: 'auto', width: '100%', maxWidth: '100%', height: 'calc(100% - 24px)', margin: '12px 0', borderRadius: 14, transform: 'none', } : { top: 14, right: 96, bottom: 14, width: '100%', maxWidth: 500, borderRadius: 14, transform: isOpen ? 'translateX(0)' : 'translateX(calc(100% + 20px))', }), }), background: '#202124', zIndex: 101, display: 'flex', flexDirection: 'column', transition: desktopInline ? 'none' : `transform ${transitionMs}ms cubic-bezier(0.22, 1, 0.36, 1), opacity ${transitionMs}ms ease`, opacity: desktopInline ? 1 : (isOpen ? 1 : 0), boxShadow: isMobile ? '0 -4px 20px rgba(0,0,0,0.5)' : '-8px 0 28px rgba(0,0,0,0.55)', border: isMobile ? 'none' : '1px solid rgba(255,255,255,0.18)', overflow: 'hidden', } }, isMobile && (React.createElement("div", { style: { display: 'flex', justifyContent: 'center', padding: '12px 0 8px 0', cursor: 'grab' } }, React.createElement("div", { style: { width: 36, height: 4, borderRadius: 2, background: 'rgba(255,255,255,0.3)' } }))), React.createElement("div", { style: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: isMobile ? '10px 18px 14px 18px' : '14px 20px', borderBottom: '1px solid rgba(255,255,255,0.1)', background: 'rgba(0,0,0,0.18)', } }, React.createElement("h2", { style: { margin: 0, fontSize: isMobile ? 24 : 16, fontWeight: 700, color: '#fff', lineHeight: 1.2, letterSpacing: 0, } }, "Description"), React.createElement("button", { onClick: onClose, style: { background: 'none', border: 'none', color: '#fff', cursor: 'pointer', padding: 6, display: 'flex', alignItems: 'center', justifyContent: 'center', WebkitTapHighlightColor: 'transparent', }, "aria-label": "Close" }, React.createElement("svg", { width: "22", height: "22", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2" }, React.createElement("line", { x1: "18", y1: "6", x2: "6", y2: "18" }), React.createElement("line", { x1: "6", y1: "6", x2: "18", y2: "18" })))), React.createElement("div", { "data-uvf-description-scroll": true, style: { flex: 1, overflowY: 'auto', padding: isMobile ? '16px 18px 22px 18px' : '16px 20px 20px 20px', marginTop: isMobile ? 4 : 6, marginBottom: isMobile ? 8 : 10, } }, React.createElement("div", { style: { color: 'rgba(255,255,255,0.92)', fontSize: isMobile ? 18 : 13, lineHeight: isMobile ? 1.35 : 1.4, fontWeight: isMobile ? 600 : 600, whiteSpace: 'pre-wrap', wordBreak: 'break-word', marginTop: isMobile ? 6 : 10, marginBottom: isMobile ? 18 : 16, minHeight: isMobile ? undefined : 42, } }, video.description || video.title || 'No description available.'), React.createElement("div", { style: { borderTop: '1px solid rgba(255,255,255,0.16)', margin: '0 0 16px 0' } }), React.createElement("div", { style: { display: 'grid', gridTemplateColumns: 'repeat(3, minmax(0, 1fr))', gap: 6, alignItems: 'start', } }, React.createElement("div", { style: { textAlign: 'center' } }, React.createElement("div", { style: { color: '#fff', fontSize: isMobile ? 30 : 22, lineHeight: 1.1, fontWeight: 700 } }, formatCount(video.likes)), React.createElement("div", { style: { color: 'rgba(255,255,255,0.72)', fontSize: isMobile ? 15 : 11, marginTop: 2 } }, getCountLabel(video.likes, 'Like', 'Likes'))), React.createElement("div", { style: { textAlign: 'center' } }, React.createElement("div", { style: { color: '#fff', fontSize: isMobile ? 30 : 22, lineHeight: 1.1, fontWeight: 700 } }, video.views != null ? formatCount(video.views) : '0'), React.createElement("div", { style: { color: 'rgba(255,255,255,0.72)', fontSize: isMobile ? 15 : 11, marginTop: 2 } }, getCountLabel(video.views, 'View', 'Views'))), React.createElement("div", { style: { textAlign: 'center' } }, React.createElement("div", { style: { color: '#fff', fontSize: isMobile ? 30 : 22, lineHeight: 1.1, fontWeight: 700 } }, panelDate?.monthDay || '-'), React.createElement("div", { style: { color: 'rgba(255,255,255,0.72)', fontSize: isMobile ? 15 : 11, marginTop: 2 } }, panelDate?.year || ''))))))); }; //# sourceMappingURL=PortraitDescriptionPanel.js.map