import { useEffect } from "react"; import { useLocation } from "react-router-dom"; import { usePlayer } from "@/lib/usePlayer"; import { useLang } from "@/lib/useLang"; import { dict } from "@/lib/i18n"; import { VISIBLE_PATHS, PATH_PLAYLISTS } from "@/lib/playlist"; // --------------------------------------------------------------------------- // 시간 포맷 // --------------------------------------------------------------------------- function fmtTime(sec: number): string { if (!isFinite(sec) || sec < 0) return "0:00"; const m = Math.floor(sec / 60); const s = Math.floor(sec % 60); return `${m}:${s.toString().padStart(2, "0")}`; } // --------------------------------------------------------------------------- // 아이콘 // --------------------------------------------------------------------------- function IconPrev() { return ( ); } function IconNext() { return ( ); } function IconPlay() { return ( ); } function IconPause() { return ( ); } function IconMusic() { return ( ); } function IconVolume({ level }: { level: number }) { if (level === 0) { return ( ); } if (level < 0.5) { return ( ); } return ( ); } // --------------------------------------------------------------------------- // 접기/펼치기 탭 (바 상단 중앙에 고정) // --------------------------------------------------------------------------- function CollapseTab({ minimized, onToggle, }: { minimized: boolean; onToggle: () => void; }) { return ( ); } // --------------------------------------------------------------------------- // MusicBar // --------------------------------------------------------------------------- export default function MusicBar() { const lang = useLang(); const t = dict(lang); const { pathname } = useLocation(); const { currentTrack, isPlaying, progress, currentTime, duration, volume, muted, userClosed, hasTrack, toggle, next, prev, seek, setVolume, toggleMute, close, open, loadPlaylist, } = usePlayer(); // 경로가 바뀌면 해당 경로의 플레이리스트 로드, 없으면 초기화 useEffect(() => { const tracks = PATH_PLAYLISTS[pathname]; loadPlaylist(tracks ?? []); }, [pathname, loadPlaylist]); if (!hasTrack) return null; if (VISIBLE_PATHS.length > 0) { const visible = VISIBLE_PATHS.some( (p: string) => pathname === p || pathname.startsWith(p) ); if (!visible) return null; } const handleProgressClick = (e: React.MouseEvent) => { const rect = e.currentTarget.getBoundingClientRect(); seek(Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width))); }; const handleVolumeClick = (e: React.MouseEvent) => { const rect = e.currentTarget.getBoundingClientRect(); setVolume((e.clientX - rect.left) / rect.width); }; const handleVolumeDrag = (e: React.PointerEvent) => { const el = e.currentTarget; el.setPointerCapture(e.pointerId); const update = (ev: PointerEvent) => { const rect = el.getBoundingClientRect(); setVolume(Math.max(0, Math.min(1, (ev.clientX - rect.left) / rect.width))); }; const stop = () => { window.removeEventListener("pointermove", update); window.removeEventListener("pointerup", stop); }; window.addEventListener("pointermove", update); window.addEventListener("pointerup", stop); }; const displayVolume = muted ? 0 : volume; /* ── 최소화 상태: 우측 하단 고정 pill (썸네일 + 재생/정지) ── */ if (userClosed) { return (
{/* 썸네일 — 클릭 시 펼치기 */}
{currentTrack?.cover ? ( {currentTrack.title} ) : ( )}
{/* 재생/일시정지 */}
); } return (
<> {/* 모바일 진행선 (seekbar 대신, md 이상에선 숨김) */}
{/* 전체 레이아웃 */}
{/* ── 좌: 썸네일 + 곡 정보 ── */}
{currentTrack?.cover ? ( {currentTrack.title} ) : ( )}

{currentTrack?.title ?? "—"}

{currentTrack?.artist ?? ""}

{/* ── 중: 재생 컨트롤 (모바일 포함 전체 표시) ── */}
{/* ── 우: seekbar(데스크톱만) + 볼륨(전체) ── */}
{/* seekbar — 데스크톱만 */} {fmtTime(currentTime)}
{fmtTime(duration)} {/* 볼륨 — 모바일 포함 전체 표시 */}
); }