Sidebar drawer ends above the bottom nav so Audio-only is reachable; landscape lyrics (orientation lock, CSS rotation on iOS) in the stage and watch party

This commit is contained in:
Jonathan Sykes
2026-10-15 19:24:26 +08:00
parent ca042ccbe3
commit 23097918e9
5 changed files with 60 additions and 4 deletions

View File

@@ -4635,11 +4635,42 @@ const Notes = (() => {
function setStageLyrics(on) {
data.settings.stageLyrics = !!on;
persist();
if (!on) setLandscape(false);
renderStage(true);
}
// Landscape lyrics (sing-alongs on a phone): lock the real orientation where
// the browser allows it (Android, after fullscreen); iOS can't lock, so the
// view is rotated in CSS while the phone is held upright.
const landOn = () => !!$('stageLyrics')?.classList.contains('landscape');
async function setLandscape(on) {
const box = $('stageLyrics'); if (!box || on === landOn()) return;
// The player stage is its own stacking context; lift the view to <body> so
// it covers the party panel and nav, and put it back on exit.
if (on) { setLandscape.home = setLandscape.home || { parent: box.parentNode, next: box.nextSibling }; document.body.append(box); }
else if (setLandscape.home) { setLandscape.home.parent.insertBefore(box, setLandscape.home.next); setLandscape.home = null; }
box.classList.toggle('landscape', !!on);
document.body.classList.toggle('lyrics-landscape', !!on);
const b = $('stageLyricsLand');
if (b) { b.setAttribute('aria-pressed', String(!!on)); b.textContent = on ? '↺ Exit landscape' : '↻ Landscape'; }
try {
if (on && document.documentElement.requestFullscreen && screen.orientation?.lock) {
if (!document.fullscreenElement) await document.documentElement.requestFullscreen({ navigationUI: 'hide' });
await screen.orientation.lock('landscape');
} else if (!on) {
try { screen.orientation?.unlock?.(); } catch { /* not locked */ }
if (document.fullscreenElement) await document.exitFullscreen();
}
} catch { /* no lock (iOS, desktop): the CSS rotation covers it */ }
renderStage(true);
setTimeout(() => renderStage(true), 400); // after the rotation settles
if (typeof Party !== 'undefined' && Party.renderLyricsToggle) Party.renderLyricsToggle();
}
document.addEventListener('fullscreenchange', () => { if (!document.fullscreenElement && landOn() && screen.orientation?.type?.startsWith('portrait')) setLandscape(false); });
if ($('stageLyricsOff')) {
$('stageLyricsOff').addEventListener('click', () => setStageLyrics(false));
$('stageLyricsLand').addEventListener('click', () => setLandscape(!landOn()));
$('stageLyricsAuto').addEventListener('click', () => {
data.settings.stageLyricsAutoscroll = !stageAuto();
persist();
@@ -4870,7 +4901,7 @@ const Notes = (() => {
return {
load, tick, addBookmark, addNote, handleSyncKey, serviceRefresh, refreshFlags: () => { sv.flagsKey = ''; renderServiceButtons(); setPanelFlagMode(sv.panelFlag && flagsEnabled()); paintFlags(); loadFlags(); },
stageLyrics: { render: renderStage, set: setStageLyrics, on: stageOn },
stageLyrics: { render: renderStage, set: setStageLyrics, on: stageOn, landscape: setLandscape, landscapeOn: landOn },
jumpChapter,
openChapterPicker,
repeatSection: () => { const cs = chapters().filter(c => c.t <= now()).sort((a, b) => a.t - b.t); Player.seek(abA ?? cs.at(-1)?.t ?? 0); },