diff --git a/frontend/src/components/NowPlayingPanel.tsx b/frontend/src/components/NowPlayingPanel.tsx index 2b29d60..9702f0a 100644 --- a/frontend/src/components/NowPlayingPanel.tsx +++ b/frontend/src/components/NowPlayingPanel.tsx @@ -7,6 +7,7 @@ import { Artwork } from './Artwork'; import { ArtistLinks } from './ArtistLinks'; import { TrackRow, formatDuration } from './TrackRow'; import { albumService } from '../services/albumService'; +import { useTransport } from '../hooks/useTransport'; export function NowPlayingPanel({ onClose }: { onClose: () => void }) { const panelRef = useRef(null); @@ -34,7 +35,8 @@ export function NowPlayingPanel({ onClose }: { onClose: () => void }) { previous?.focus(); }; }, []); - const { currentTrack, queue, isPlaying, position, duration, play, pause, next, prev, setPosition } = usePlaybackStore(); + const { currentTrack, queue, isPlaying, position, duration } = usePlaybackStore(); + const transport = useTransport(); const currentIdx = currentTrack ? queue.findIndex((t) => t.id === currentTrack.id) : -1; const upNext = currentIdx >= 0 ? queue.slice(currentIdx + 1) : queue; @@ -56,17 +58,21 @@ export function NowPlayingPanel({ onClose }: { onClose: () => void }) { + {/* The artwork below is capped against viewport height, not just width. + At full width on a phone the square alone is taller than the space + between the top bar and the transport, which pushed Up Next — the + reason the panel opens — entirely off the screen. */}
{currentTrack?.album_id ? ( + className="group mx-auto block aspect-square w-full max-w-[min(100%,34vh)] rounded-xl overflow-hidden relative shadow-lg shadow-black/40" title="Go to album">
) : ( -
+
)} @@ -90,7 +96,7 @@ export function NowPlayingPanel({ onClose }: { onClose: () => void }) { setPosition(Number(e.target.value))} + onChange={(e) => transport.seek(Number(e.target.value))} disabled={!currentTrack || duration <= 0} className="w-full cursor-pointer" /> @@ -101,15 +107,16 @@ export function NowPlayingPanel({ onClose }: { onClose: () => void }) {
- + - +
diff --git a/frontend/src/components/PlaybackBar.tsx b/frontend/src/components/PlaybackBar.tsx index 5b63289..4afadfc 100644 --- a/frontend/src/components/PlaybackBar.tsx +++ b/frontend/src/components/PlaybackBar.tsx @@ -6,7 +6,7 @@ import { Artwork } from './Artwork'; import { ArtistLinks } from './ArtistLinks'; import { formatDuration } from './TrackRow'; import { DevicePicker } from './DevicePicker'; -import { usePlaybackSyncContext } from './PlaybackSyncProvider'; +import { useTransport } from '../hooks/useTransport'; interface PlaybackBarProps { queueOpen: boolean; @@ -16,20 +16,9 @@ interface PlaybackBarProps { } export function PlaybackBar({ queueOpen, lyricsOpen, onToggleQueue, onToggleLyrics }: PlaybackBarProps) { - const { currentTrack, isPlaying, position, duration, volume, shuffle, repeat, play, pause, next, prev, setPosition, setVolume, toggleShuffle, cycleRepeat } = usePlaybackStore(); + const { currentTrack, isPlaying, position, duration, volume, shuffle, repeat, setVolume, toggleShuffle, cycleRepeat } = usePlaybackStore(); const dislikeTrack = useDislikeTrack(); - const { hasRemoteOwner, sendCommand } = usePlaybackSyncContext(); - - // While another device holds the audio, the transport is a remote: the press - // travels to that device instead of starting a second stream here. - const remote = { - play: () => (hasRemoteOwner ? void sendCommand({ type: 'play' }) : play()), - pause: () => (hasRemoteOwner ? void sendCommand({ type: 'pause' }) : pause()), - next: () => (hasRemoteOwner ? void sendCommand({ type: 'next' }) : next()), - prev: () => (hasRemoteOwner ? void sendCommand({ type: 'prev' }) : prev()), - seek: (seconds: number) => - hasRemoteOwner ? void sendCommand({ type: 'seek', position: seconds }) : setPosition(seconds), - }; + const transport = useTransport(); const handleDislike = () => { if (!currentTrack) return; @@ -94,18 +83,18 @@ export function PlaybackBar({ queueOpen, lyricsOpen, onToggleQueue, onToggleLyri > - -