watchparty/client/src/musicBar/MusicBar.html
Nicolas fc2c4e551f
Some checks failed
Publier l'image Docker / test (pull_request) Failing after 4s
Publier l'image Docker / publish (pull_request) Has been skipped
Fix the music bar queue popup: broken layout on desktop, unclosable on mobile
.musicBarQueue never actually had a position set on desktop despite its
own comment saying it should float above the bar - toggling it visible
just pushed the real controls out of the way instead, growing the
fixed bottom bar upward. Mobile had position: relative with a high
z-index to at least show above the full-screen now-playing panel, but
that left it sized/placed by normal flow, overlapping the very toggle
button used to open it with no other way to close it.

Now: musicBar gets position: relative, desktop musicBarQueue floats
via position: absolute; bottom: 100% without touching the bar's own
layout, and mobile gets a proper position: fixed; inset: 0 overlay.
Also added a dedicated close button plus a click-outside-closes
listener, so closing it never again depends on where the toggle button
happens to render underneath.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 22:32:32 +02:00

79 lines
5.1 KiB
HTML

<div id="musicBarQueue" class="musicBarQueue hide">
<div class="pageHeader">
<h2>File d'attente</h2>
<button class="queueCloseBtn" id="queueCloseBtn" aria-label="Fermer la file d'attente">
<svg viewBox="0 0 24 24" width="20" height="20" aria-hidden="true">
<path d="M6 9l6 6 6-6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
</svg>
</button>
</div>
<div id="queueList" class="trackList"><p class="hint">Rien en attente.</p></div>
</div>
<!-- Mobile-only collapsed preview (see MusicBar.css's 720px breakpoint) -
#musicBarPanel below is already always visible on desktop, so this
only ever renders there. Tapping anywhere on it except the play
button opens the panel - see MusicBar.ts. -->
<div id="mobileMiniBar" class="mobileMiniBar">
<div class="mobileMiniProgress"><div id="miniProgressFill" class="mobileMiniProgressFill"></div></div>
<img id="miniTrackImage" class="mobileMiniArt" alt="" onerror="this.classList.add('noImage')" />
<div class="mobileMiniMeta">
<strong id="miniTrackName">-</strong>
<span class="hint" id="miniTrackArtist"></span>
</div>
<button class="iconBtn musicBarPlayBig" id="miniPlayPauseBtn" title="Lecture / pause" aria-label="Lecture / pause"></button>
</div>
<!-- Always in place on desktop (the bar itself, unconditionally visible
like before); a full-screen "now playing" overlay on mobile,
opened via #mobileMiniBar above and closed via #panelCloseBtn. -->
<div id="musicBarPanel" class="musicBarPanel">
<button class="linklike panelCloseBtn" id="panelCloseBtn" aria-label="Réduire">
<svg viewBox="0 0 24 24" width="20" height="20" aria-hidden="true">
<path d="M6 9l6 6 6-6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"></path>
</svg>
</button>
<!-- Click/drag to seek - see MusicBar.ts's pointerdown/move/up
handlers. No host check needed to enable this, unlike the video
player's own seek bar: a listen party has no host at all - see
MusicQueueService.seek's own comment for why that's the right
model for this, not voteSkip's majority gate. -->
<div id="trackProgress" class="musicBarProgressTrack"><div id="trackProgressFill" class="musicBarProgressFill"></div></div>
<div class="musicBarPanelTrack">
<img id="trackImage" class="musicBarImage" alt="" onerror="this.classList.add('noImage')" />
<div class="musicBarInfo">
<strong id="trackName">-</strong>
<span class="hint" id="trackArtist"></span>
</div>
<span id="trackPosition" class="hint musicBarPosition">0:00 / 0:00</span>
</div>
<div class="musicBarPanelTransport">
<button class="iconBtn" id="voteSkipBtn" title="Passer (vote)" aria-label="Passer (vote)">
<svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true"><path d="M5 5v14l10-7Z" fill="currentColor"></path><rect x="17" y="5" width="2.5" height="14" rx="1" fill="currentColor"></rect></svg>
<span id="voteBadge" class="voteBadge hide"></span>
</button>
<button class="iconBtn musicBarPlayBig" id="playPauseBtn" title="Lecture / pause" aria-label="Lecture / pause"></button>
<button class="iconBtn" id="toggleQueueBtn" title="File d'attente" aria-label="File d'attente">
<svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true"><circle cx="4.5" cy="7" r="1.3" fill="currentColor"></circle><circle cx="4.5" cy="12" r="1.3" fill="currentColor"></circle><circle cx="4.5" cy="17" r="1.3" fill="currentColor"></circle><line x1="9" y1="7" x2="20" y2="7" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"></line><line x1="9" y1="12" x2="20" y2="12" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"></line><line x1="9" y1="17" x2="20" y2="17" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"></line></svg>
</button>
</div>
<div class="musicBarPanelSide">
<div id="presenceOverlay" class="presenceOverlay musicBarPresence"></div>
<button class="iconBtn hide" id="castBtn" title="Caster sur un Chromecast" aria-label="Caster sur un Chromecast" aria-pressed="false">
<svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true">
<rect x="1" y="4" width="22" height="16" rx="2" fill="none" stroke="currentColor" stroke-width="2"></rect>
<path d="M4 15a5 5 0 0 1 5 5" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"></path>
<path d="M4 11a9 9 0 0 1 9 9" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"></path>
<circle cx="4" cy="20" r="1.5" fill="currentColor"></circle>
</svg>
</button>
<button class="iconBtn" id="leaveBtn" title="Quitter" aria-label="Quitter">
<svg viewBox="0 0 24 24" width="16" height="16" aria-hidden="true"><path d="M9 4.5H6a1.5 1.5 0 0 0-1.5 1.5v12A1.5 1.5 0 0 0 6 19.5h3" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"></path><path d="M13 8l4 4-4 4M9.5 12H20" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"></path></svg>
</button>
</div>
</div>
<audio id="barAudio"></audio>