'use client'; import { Volume2, VolumeX } from 'lucide-react'; import { useEffect, useState } from 'react'; import { Popover, PopoverContent, PopoverTrigger, Slider } from '@djangocfg/ui-core/components'; import { usePlayerAudio, usePlayerControls } from '../../context/selectors'; import { IconButton } from './IconButton'; // `audio.volume` is read-only on iOS Safari (controlled by hardware buttons), // so a JS slider does nothing useful there. Detect once at module load. function isIosSafari(): boolean { if (typeof navigator === 'undefined') return false; const ua = navigator.userAgent; const iOS = /iPad|iPhone|iPod/.test(ua) || (navigator.platform === 'MacIntel' && (navigator as { maxTouchPoints?: number }).maxTouchPoints! > 1); return iOS; } const HIDE_VOLUME = isIosSafari(); /** * Volume control — click-to-open Popover with a vertical ``. * * Click on the trigger toggles the popover (not mute). Mute lives as a * dedicated icon button inside the popover. This avoids the classic * Radix `` + `` collision on the same trigger: * hovering opened the tooltip, click toggled the popover — but the * tooltip's pointer-events fought the popover's outside-click logic. * One trigger, one job: open the popover; volume + mute live inside. */ export function VolumeControl() { const audio = usePlayerAudio(); const { setVolume, toggleMute } = usePlayerControls(); const [volume, setVol] = useState(audio.volume); const [muted, setMuted] = useState(audio.muted); const [isOpen, setOpen] = useState(false); useEffect(() => { const sync = () => { setVol(audio.volume); setMuted(audio.muted); }; audio.addEventListener('volumechange', sync); return () => audio.removeEventListener('volumechange', sync); }, [audio]); if (HIDE_VOLUME) { return ( { toggleMute(); setMuted(audio.muted); }} > {muted || volume === 0 ? : } ); } const Icon = muted || volume === 0 ? VolumeX : Volume2; const handleChange = (v: number) => { setVolume(v); setVol(v); if (v > 0) setMuted(false); }; return ( e.preventDefault()} > {Math.round((muted ? 0 : volume) * 100)} handleChange(v)} aria-label="Volume" className="h-32" /> ); }