refactor: refine global player visibility and active signal labels

This commit is contained in:
Carlos (Almeira) 2026-03-30 08:55:51 -05:00
parent 031e8f4523
commit 86b2e704e9
3 changed files with 25 additions and 10 deletions

View File

@ -42,7 +42,7 @@ export default async function RootLayout({
<GlobalTopBanner /> <GlobalTopBanner />
{children} {children}
</div> </div>
<GlobalPlayer /> <GlobalPlayer initialConfig={entity} />
</body> </body>
</html> </html>
); );

View File

@ -7,10 +7,10 @@ import { StreamOverlays } from './StreamOverlays';
import videojs from 'video.js'; import videojs from 'video.js';
import 'video.js/dist/video-js.css'; import 'video.js/dist/video-js.css';
export const GlobalPlayer = () => { export const GlobalPlayer = ({ initialConfig }: { initialConfig?: any }) => {
const { const {
audioUrl, isAudioPlaying, audioVolume, toggleAudio, setAudioVolume, audioUrl, isAudioPlaying, audioVolume, toggleAudio, setAudioUrl, setAudioVolume,
isVideoActive, videoUrl, videoType, setVideoActive isVideoActive, videoUrl, videoType, setVideoActive, setVideoUrl, setVideoType
} = usePlayerStore(); } = usePlayerStore();
const audioRef = useRef<HTMLAudioElement>(null); const audioRef = useRef<HTMLAudioElement>(null);
@ -19,6 +19,21 @@ export const GlobalPlayer = () => {
const [isMuted, setIsMuted] = useState(false); const [isMuted, setIsMuted] = useState(false);
const [lastVolume, setLastVolume] = useState(audioVolume); const [lastVolume, setLastVolume] = useState(audioVolume);
const [isExpanded, setIsExpanded] = useState(false); const [isExpanded, setIsExpanded] = useState(false);
const [hasHydrated, setHasHydrated] = useState(false);
// Sync from Layout Config on First Load
useEffect(() => {
if (initialConfig) {
if (initialConfig.radio_url && audioUrl === '') {
setAudioUrl(initialConfig.radio_url);
}
if (initialConfig.tv_url && videoUrl === '') {
setVideoUrl(initialConfig.tv_url);
setVideoType(initialConfig.tv_url.includes('youtube.com') || initialConfig.tv_url.includes('youtu.be') ? 'youtube' : 'm3u8');
}
}
setHasHydrated(true);
}, [initialConfig, setAudioUrl, setVideoUrl, setVideoType]);
// Sync Audio State // Sync Audio State
useEffect(() => { useEffect(() => {
@ -130,7 +145,7 @@ export const GlobalPlayer = () => {
<div className={`fixed bottom-6 left-6 z-[60] flex items-center gap-3 transition-opacity duration-500 ${isVideoActive ? 'opacity-0 pointer-events-none' : 'opacity-100'}`}> <div className={`fixed bottom-6 left-6 z-[60] flex items-center gap-3 transition-opacity duration-500 ${isVideoActive ? 'opacity-0 pointer-events-none' : 'opacity-100'}`}>
{/* ESTADO COLAPSADO */} {/* ESTADO COLAPSADO */}
{!isExpanded && (audioUrl || videoUrl) && ( {!isExpanded && (audioUrl !== '' || videoUrl !== '') && (
<button <button
onClick={() => setIsExpanded(true)} onClick={() => setIsExpanded(true)}
className="group relative h-14 px-5 bg-red-600 hover:bg-red-500 text-white rounded-full flex items-center justify-center gap-3 shadow-[0_0_20px_rgba(220,38,38,0.4)] transition-all animate-in zoom-in slide-in-from-bottom-5" className="group relative h-14 px-5 bg-red-600 hover:bg-red-500 text-white rounded-full flex items-center justify-center gap-3 shadow-[0_0_20px_rgba(220,38,38,0.4)] transition-all animate-in zoom-in slide-in-from-bottom-5"
@ -169,10 +184,10 @@ export const GlobalPlayer = () => {
<div className="flex flex-col pr-3"> <div className="flex flex-col pr-3">
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<span className={`text-[10px] font-black uppercase tracking-[0.2em] transition-colors ${isAudioPlaying ? 'text-cyan-400' : 'text-slate-500'}`}> <span className={`text-[10px] font-black uppercase tracking-[0.2em] transition-colors ${isAudioPlaying ? 'text-cyan-400' : 'text-rose-400'}`}>
{isAudioPlaying ? 'Señal Activa' : 'Radio Offline'} {isAudioPlaying ? 'Al Aire' : 'Señal en Vivo'}
</span> </span>
{isAudioPlaying && <div className="w-1.5 h-1.5 bg-red-500 rounded-full animate-pulse shadow-[0_0_8px_rgba(239,68,68,0.5)]"></div>} <div className={`w-1.5 h-1.5 rounded-full ${isAudioPlaying ? 'bg-red-500 animate-pulse shadow-[0_0_8px_rgba(239,68,68,0.5)]' : 'bg-rose-500'}`}></div>
</div> </div>
<h4 className="text-xs font-bold text-white tracking-wider font-outfit truncate max-w-[100px]">ALMEIRA RADIO</h4> <h4 className="text-xs font-bold text-white tracking-wider font-outfit truncate max-w-[100px]">ALMEIRA RADIO</h4>
</div> </div>

View File

@ -35,11 +35,11 @@ export const usePlayerStore = create<PlayerState>()(
persist( persist(
(set) => ({ (set) => ({
// Default values // Default values
audioUrl: 'https://radio.almeira.com.co/listen/almeira/radio.mp3', audioUrl: '',
isAudioPlaying: false, isAudioPlaying: false,
audioVolume: 0.8, audioVolume: 0.8,
videoUrl: 'https://tv.almeira.com.co/hls/stream.m3u8', videoUrl: '',
isVideoActive: false, isVideoActive: false,
videoVolume: 0.5, videoVolume: 0.5,
videoType: 'm3u8', videoType: 'm3u8',