Give untimed lyrics one uniform line size in service mode

This commit is contained in:
Jonathan Sykes
2026-09-24 08:34:09 +08:00
parent d64c5f2613
commit 05e85a0a3f
2 changed files with 20 additions and 3 deletions

View File

@@ -2353,8 +2353,9 @@ function updateNowPlayingActions() {
// Used by service-mode lyrics and the presenter view. Measured with a hidden // Used by service-mode lyrics and the presenter view. Measured with a hidden
// real .sl-line (same font rules) in two passes: the display font has an // real .sl-line (same font rules) in two passes: the display font has an
// optical-size axis, so glyphs get relatively WIDER as the size drops and a // optical-size axis, so glyphs get relatively WIDER as the size drops and a
// single measurement at 100px over-fits on small screens. Sets --fit per row. // single measurement at 100px over-fits on small screens. Sets --fit per row;
function fitLyricLines(list, { maxShare = 0.17, maxPx = 160 } = {}) { // with `uniform` every row gets the smallest fit, so all lines share one size.
function fitLyricLines(list, { maxShare = 0.17, maxPx = 160, uniform = false } = {}) {
if (!list) return; if (!list) return;
const rows = [...list.querySelectorAll('.sl-line')]; const rows = [...list.querySelectorAll('.sl-line')];
if (!rows.length || !list.clientWidth) return; if (!rows.length || !list.clientWidth) return;
@@ -2367,6 +2368,7 @@ function fitLyricLines(list, { maxShare = 0.17, maxPx = 160 } = {}) {
probe.style.cssText = 'position:absolute;left:0;top:0;visibility:hidden;white-space:nowrap;width:auto;padding:0;font-size:100px;transition:none'; probe.style.cssText = 'position:absolute;left:0;top:0;visibility:hidden;white-space:nowrap;width:auto;padding:0;font-size:100px;transition:none';
list.appendChild(probe); list.appendChild(probe);
const widthAt = (px) => { probe.style.fontSize = px + 'px'; return probe.getBoundingClientRect().width; }; const widthAt = (px) => { probe.style.fontSize = px + 'px'; return probe.getBoundingClientRect().width; };
const fits = [];
for (const el of rows) { for (const el of rows) {
probe.textContent = el.textContent; probe.textContent = el.textContent;
const w100 = widthAt(100); const w100 = widthAt(100);
@@ -2377,8 +2379,13 @@ function fitLyricLines(list, { maxShare = 0.17, maxPx = 160 } = {}) {
px = Math.floor(clamp(wEst ? est * (width / wEst) : est)); px = Math.floor(clamp(wEst ? est * (width / wEst) : est));
} }
el.style.setProperty('--fit', px + 'px'); el.style.setProperty('--fit', px + 'px');
fits.push(px);
} }
probe.remove(); probe.remove();
if (uniform) {
const px = Math.min(...fits);
rows.forEach((el) => el.style.setProperty('--fit', px + 'px'));
}
} }
// ============================================================================ // ============================================================================
@@ -3086,7 +3093,15 @@ const Notes = (() => {
const serviceAuto = () => data.settings.serviceLyricsAutoscroll !== false; const serviceAuto = () => data.settings.serviceLyricsAutoscroll !== false;
const sungLines = () => lines().map((l, i) => ({ ...l, i })).filter((l) => l.kind === 'line'); const sungLines = () => lines().map((l, i) => ({ ...l, i })).filter((l) => l.kind === 'line');
function applyFits() { fitLyricLines($('serviceLyricsList')); } // Plain (untimed) lyrics have no sung line to spotlight, so every line gets
// the same size — the largest at which the longest line still fits one row.
const plainLyrics = () => { const l = sungLines(); return l.length > 0 && l.every((x) => x.t === null || x.t === undefined); };
function applyFits() {
const list = $('serviceLyricsList');
const plain = plainLyrics();
list.classList.toggle('plain', plain);
fitLyricLines(list, { uniform: plain });
}
function renderServiceButtons() { function renderServiceButtons() {
const on = !!data.settings.serviceLyrics; const on = !!data.settings.serviceLyrics;

View File

@@ -3813,6 +3813,8 @@ body.remote-open { overflow: hidden; }
text-shadow: 0 0 32px var(--accent-glow); text-shadow: 0 0 32px var(--accent-glow);
} }
.sl-line.untimed { cursor: default; } .sl-line.untimed { cursor: default; }
/* Plain lyrics (no timings): one shared --fit, every line full size. */
.sl-list.plain .sl-line { font-size: var(--fit, 40px); opacity: 0.92; color: var(--text); }
.sl-empty { .sl-empty {
display: flex; flex-direction: column; gap: 10px; align-items: center; display: flex; flex-direction: column; gap: 10px; align-items: center;
font-size: clamp(22px, 4vw, 40px); font-weight: 700; color: var(--text-2); font-size: clamp(22px, 4vw, 40px); font-weight: 700; color: var(--text-2);