diff --git a/components/audio-player/floating-player.tsx b/components/audio-player/floating-player.tsx index 0e6f97e7..b277fc8c 100644 --- a/components/audio-player/floating-player.tsx +++ b/components/audio-player/floating-player.tsx @@ -43,7 +43,7 @@ function useIsMobile() { * Auto-minimizes after `MINIMIZE_DELAY` ms of inactivity on mobile. * Call `resetTimer()` on any user interaction to restart the countdown. */ -function useMobileMinimize(isMobile: boolean, hasTrack: boolean) { +function useAutoMinimize(hasTrack: boolean) { const [minimized, setMinimized] = useState(false); const timerRef = useRef | null>(null); @@ -60,21 +60,20 @@ function useMobileMinimize(isMobile: boolean, hasTrack: boolean) { }, [clearTimer]); const resetTimer = useCallback(() => { - if (!isMobile) return; setMinimized(false); startTimer(); - }, [isMobile, startTimer]); + }, [startTimer]); - // Start timer when track begins or mobile state changes + // Start timer when track begins useEffect(() => { - if (isMobile && hasTrack) { + if (hasTrack) { startTimer(); } else { clearTimer(); setMinimized(false); } return clearTimer; - }, [isMobile, hasTrack, startTimer, clearTimer]); + }, [hasTrack, startTimer, clearTimer]); return { minimized, setMinimized, resetTimer } as const; } @@ -293,10 +292,8 @@ export function FloatingPlayer() { const playerRef = useRef(null); const [selectionToolbarVisible, setSelectionToolbarVisible] = useState(false); const isMobile = useIsMobile(); - const { minimized, setMinimized, resetTimer } = useMobileMinimize( - isMobile, - !!currentTrack, - ); + const { minimized, setMinimized, resetTimer } = + useAutoMinimize(!!currentTrack); // Watch for the selection toolbar appearing/disappearing in the DOM useEffect(() => { @@ -343,6 +340,22 @@ export function FloatingPlayer() { const iPrevious = interact(previous); const iStop = interact(stop); + // Minimize when clicking/tapping outside the player + useEffect(() => { + if (!currentTrack || minimized) return; + + function handleOutsideClick(e: PointerEvent) { + const player = playerRef.current; + if (!player) return; + if (player.contains(e.target as Node)) return; + setMinimized(true); + } + + document.addEventListener("pointerdown", handleOutsideClick); + return () => + document.removeEventListener("pointerdown", handleOutsideClick); + }, [currentTrack, minimized, setMinimized]); + // Keyboard shortcuts when player is focused const handleKeyDown = useCallback( (e: React.KeyboardEvent) => { @@ -403,7 +416,7 @@ export function FloatingPlayer() { // ── Render ── return ( - {isMobile && minimized ? ( + {minimized ? ( )} - {/* Close */} + {/* Minimize (playing) or Close (paused) */}