import { FC, useEffect, useState } from 'react'; import { FaBroadcastTower, FaChevronDown, FaPlay, FaStop } from 'react-icons/fa'; import { LocalizeText } from '../../api'; import { LayoutImage } from '../../common'; import { RadioStation, useRadio } from '../../hooks'; const RADIO_STYLES = ` .radio-widget { font-feature-settings: "tnum"; } .radio-eq { display: flex; align-items: flex-end; gap: 2px; height: 12px; } .radio-eq span { width: 3px; height: 30%; border-radius: 2px; background: #38bdf8; opacity: .55; } .radio-eq.is-live span { opacity: 1; animation: radioEq .9s ease-in-out infinite; } .radio-eq span:nth-child(2) { animation-delay: .18s; } .radio-eq span:nth-child(3) { animation-delay: .36s; } .radio-eq span:nth-child(4) { animation-delay: .12s; } @keyframes radioEq { 0%, 100% { height: 22%; } 50% { height: 100%; } } .radio-scroll::-webkit-scrollbar { width: 6px; } .radio-scroll::-webkit-scrollbar-thumb { background: rgba(255,255,255,.18); border-radius: 3px; } .radio-scroll::-webkit-scrollbar-track { background: transparent; } .radio-vol { accent-color: #38bdf8; } `; // Compact, polished top-left radio widget. Shows the selected station with a // dropdown (3 visible, scrolls if more) to switch. Nudged down so it clears the // CMS top bar most hotels render there. export const RadioView: FC<{}> = () => { const { stations, currentId, isPlaying, volume, loadError, play, stop, setVolume } = useRadio(); const [ open, setOpen ] = useState(false); const [ selectedId, setSelectedId ] = useState(null); useEffect(() => { if(!selectedId && stations.length) setSelectedId(stations[0].id); }, [ stations, selectedId ]); const selected: RadioStation | null = stations.find(s => s.id === selectedId) ?? stations[0] ?? null; const selectedPlaying = !!selected && (currentId === selected.id) && isPlaying; const onPlayToggle = () => { if(!selected) return; if(selectedPlaying) stop(); else play(selected); }; const onPick = (station: RadioStation) => { setSelectedId(station.id); setOpen(false); play(station); }; return (
{ LocalizeText('radio.title') }
{ selected ? selected.name : LocalizeText('radio.title') }
{ selectedPlaying && { LocalizeText('radio.live') } } { selected?.genre && { selected.genre } }
{ selectedPlaying &&
🔊 setVolume(e.target.valueAsNumber) } className="radio-vol h-1 grow cursor-pointer" />
} { open &&
{ loadError &&
{ LocalizeText('radio.error') }
} { !loadError && !stations.length &&
{ LocalizeText('radio.empty') }
} { /* ~3 rows tall, scrolls when there are more */ }
{ stations.map(station => { const isActive = station.id === selectedId; const playingThis = (currentId === station.id) && isPlaying; return (
onPick(station) } className={ `flex cursor-pointer items-center gap-2.5 rounded-lg px-2 py-1.5 transition-colors ${ isActive ? 'bg-sky-500/15 ring-1 ring-sky-400/40' : 'hover:bg-white/8' }` }> { station.logo ? :
{ playingThis ? : }
}
{ station.name }
{ station.genre &&
{ station.genre }
}
{ playingThis &&
}
); }) }
}
); };