Move the request-pause/resume buttons off the subtitle zone
All checks were successful
Publier l'image Docker / test (push) Successful in 22s
Publier l'image Docker / publish (push) Successful in 8s

Asked for directly: .requestToolbar (the non-host's "Demander une
pause"/"Demander une reprise" buttons) shared .bottomOverlay's
centered-bottom column with the request banner and the follower
notice - which is also exactly where a native <track> subtitle
renders. Real, clickable buttons sitting there for the whole session
is a worse problem than the banner (transient, 4s) or the notice
(static text) occasionally doing the same.

Pulled #requestToolbar out of .bottomOverlay into its own sibling
block in Player.html, positioned independently in the bottom-right
corner instead (position: absolute; right: 16px; bottom: 20px), and
stacked as a column (align-items: flex-end) rather than a row so the
two pill buttons never fight a narrow phone screen for width side by
side. .bottomOverlay itself is untouched - still centered-bottom,
still just the banner and the notice.

Verified against the real bundle (mocked-fetch + real dist, this
session's standing harness) as a follower at both desktop and phone
width: the two buttons render bottom-right, clear of the (still
centered) follower notice, at both widths. Client typecheck/build
clean. docs/architecture.md updated.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Nicolas 2026-09-14 23:08:28 +02:00
parent 8718175bae
commit 8c9852d854
4 changed files with 63 additions and 15 deletions

View file

@ -139,7 +139,12 @@
comment, and docs/architecture.md for the exact bug this avoided: a comment, and docs/architecture.md for the exact bug this avoided: a
<p>'s default margin silently throwing off a hand-picked bottom offset <p>'s default margin silently throwing off a hand-picked bottom offset
on the element above it - not repeatable once nothing is positioned on the element above it - not repeatable once nothing is positioned
independently any more). */ independently any more). Centered on purpose - this is exactly where
a native <track> subtitle renders too, but both children here are
passive text (a transient banner, a static notice), not something a
viewer needs to click through subtitle text to reach - unlike
.requestToolbar below, which used to live in this same column and
was moved out for exactly that reason. */
.bottomOverlay { .bottomOverlay {
position: absolute; position: absolute;
bottom: 20px; bottom: 20px;
@ -174,10 +179,25 @@
Player.ts's requestPauseBtn/requestResumeBtn. Pill buttons matching Player.ts's requestPauseBtn/requestResumeBtn. Pill buttons matching
the banner/notice's own dark-overlay look above, not the plain-text the banner/notice's own dark-overlay look above, not the plain-text
.linklike used in the (opaque) top action bar - this sits directly on .linklike used in the (opaque) top action bar - this sits directly on
top of the video image, same as the rest of .bottomOverlay. */ top of the video image, same as .bottomOverlay.
Its own bottom-RIGHT corner, independently of .bottomOverlay -
deliberately not centered-bottom any more (see .bottomOverlay's own
comment): that's also where a native <track> subtitle renders, and
these are real buttons someone needs to read and click, not passive
text a subtitle could just as easily sit behind. Stacked as a column
(not a row, unlike the old centered layout) so two pill buttons next
to each other never has to fight a narrow phone screen for width -
each just takes however much it needs, right-aligned under the other. */
.requestToolbar { .requestToolbar {
position: absolute;
right: 16px;
bottom: 20px;
z-index: 6;
display: flex; display: flex;
flex-direction: column;
align-items: flex-end;
gap: 8px; gap: 8px;
max-width: calc(50% - 16px);
} }
.requestBtn { .requestBtn {
@ -186,6 +206,7 @@
padding: 8px 14px; padding: 8px 14px;
border-radius: 20px; border-radius: 20px;
font-size: 12.5px; font-size: 12.5px;
white-space: nowrap; /* keeps the pill shape even in .requestToolbar's own narrow corner on a phone-width screen */
} }
.requestBtn:hover { background: rgba(0, 0, 0, .8); } .requestBtn:hover { background: rgba(0, 0, 0, .8); }

View file

@ -31,16 +31,21 @@
<!-- Stacked as one column (same reasoning as .topOverlay's own <!-- Stacked as one column (same reasoning as .topOverlay's own
actionBar+presenceOverlay grouping - see Player.css) so the actionBar+presenceOverlay grouping - see Player.css) so the
transient banner, the passive notice and the request toolbar transient banner and the passive notice always sit in the right
always sit in the right order relative to each other regardless order relative to each other regardless of which is visible at a
of which are visible at a given moment, instead of each guessing given moment, instead of each guessing a fixed pixel offset from
a fixed pixel offset from the bottom edge. --> the bottom edge. The request toolbar (the actual buttons) used to
live here too, third in this same column - moved out to its own
bottom-right corner instead (see .requestToolbar in Player.css):
centered-bottom is also where a native <track> subtitle renders,
and the buttons sat right on top of it. -->
<div class="bottomOverlay"> <div class="bottomOverlay">
<div id="requestBanner" class="requestBanner hide"></div> <div id="requestBanner" class="requestBanner hide"></div>
<p id="followerNotice" class="followerNotice hide">L'hôte contrôle la lecture.</p> <p id="followerNotice" class="followerNotice hide">L'hôte contrôle la lecture.</p>
</div>
<div id="requestToolbar" class="requestToolbar hide"> <div id="requestToolbar" class="requestToolbar hide">
<button id="requestPauseBtn" class="requestBtn">Demander une pause</button> <button id="requestPauseBtn" class="requestBtn">Demander une pause</button>
<button id="requestResumeBtn" class="requestBtn">Demander une reprise</button> <button id="requestResumeBtn" class="requestBtn">Demander une reprise</button>
</div> </div>
</div>
</div> </div>

View file

@ -636,11 +636,14 @@ function renderVideoPlayer(root: HTMLElement, partyId: string, party: PartyPubli
showRequestBanner(msg.userId, msg.userName, 'une reprise'); showRequestBanner(msg.userId, msg.userName, 'une reprise');
} }
// The toolbar itself - see .bottomOverlay/.requestToolbar in Player.css // The toolbar itself - see .requestToolbar in Player.css for why this
// for why this replaced the old "click your own avatar" affordance. // replaced the old "click your own avatar" affordance, and for why it
// Each button has its own client-side cooldown (mirroring the server's // sits in its own bottom-right corner rather than centered-bottom like
// own independent per-request throttle in SocketGateway) purely so a // .bottomOverlay next to it (that's also where a native <track>
// rapid double-click doesn't even bother emitting the second request. // subtitle renders). Each button has its own client-side cooldown
// (mirroring the server's own independent per-request throttle in
// SocketGateway) purely so a rapid double-click doesn't even bother
// emitting the second request.
requestPauseBtn.addEventListener('click', () => { requestPauseBtn.addEventListener('click', () => {
const now = Date.now(); const now = Date.now();
if (now < pauseRequestCooldownUntil || !conn) return; if (now < pauseRequestCooldownUntil || !conn) return;

View file

@ -409,6 +409,25 @@ button's own client-side cooldown collapses a rapid double-click to one
`requestResume` emission; a pushed `resumeRequested` shows the banner `requestResume` emission; a pushed `resumeRequested` shows the banner
with the right text and highlights the right avatar. with the right text and highlights the right avatar.
**Much later still: moved the toolbar off the subtitle zone.** Asked
for directly - `.requestToolbar` shared `.bottomOverlay`'s centered
column with the banner/follower-notice above, which is also exactly
where a native `<track>` subtitle renders (see "Player track
selection" below): real, clickable buttons sitting on top of subtitle
text, for the whole session, is a worse problem than a transient
banner or static notice occasionally doing the same. Pulled `#request
Toolbar` out into its own sibling block in `Player.html`, positioned
independently in the bottom-right corner (`position: absolute; right:
16px; bottom: 20px`) and stacked as a column instead of a row (`align-
items: flex-end`) so two pill buttons never have to fight a narrow
phone screen for width side by side. `.bottomOverlay` itself is
untouched - still centered-bottom, still just the banner and the
notice, neither of which is something a viewer needs to click through
subtitle text to reach. Verified against the real bundle at both
desktop and phone width: the two buttons render bottom-right,
non-overlapping with the (still centered) follower notice, in both
widths.
## Player track selection: forcing our pick onto Emby's own negotiation ## Player track selection: forcing our pick onto Emby's own negotiation
First real-world bug report once someone actually watched something end to First real-world bug report once someone actually watched something end to