diff --git a/webui/static/media-player.js b/webui/static/media-player.js index 6eb0c586..93c99952 100644 --- a/webui/static/media-player.js +++ b/webui/static/media-player.js @@ -1038,8 +1038,21 @@ function _npLyricsRenderSynced(lines) { } content.innerHTML = lines.map((line, idx) => { const safe = (line.text || '').replace(/[&<>"']/g, c => ({'&':'&','<':'<','>':'>','"':'"',"'":'''}[c])) || ' '; - return `
${safe}
`; + return `
${safe}
`; }).join(''); + + // Click a line → seek playback to its timestamp (synced lyrics only). + content.querySelectorAll('.np-lyrics-line').forEach(el => { + el.addEventListener('click', () => { + const idx = Number(el.dataset.idx); + const line = _npLyricsState.lines[idx]; + if (!line || !audioPlayer || !isFinite(line.time)) return; + try { + audioPlayer.currentTime = line.time; + if (audioPlayer.paused) audioPlayer.play().catch(() => {}); + } catch (_) {} + }); + }); } function _npLyricsRenderPlain(text) { diff --git a/webui/static/style.css b/webui/static/style.css index ee2e0184..06260e8a 100644 --- a/webui/static/style.css +++ b/webui/static/style.css @@ -48702,9 +48702,11 @@ textarea.enhanced-meta-field-input { .np-queue-item.active .np-queue-item-title { color: rgb(var(--accent-light-rgb)) !important; } .np-radio-btn.active, .np-queue-toggle.active { color: rgb(var(--accent-light-rgb)) !important; } -/* ── Close button + lyrics active line ── */ +/* ── Close button + lyrics (active line + click-to-seek affordance) ── */ .np-close-btn:hover { color: #fff !important; background: rgba(255,255,255,0.1) !important; } .np-lyrics-line.active { color: rgb(var(--accent-light-rgb)) !important; font-weight: 700 !important; } +.np-lyrics-line { cursor: pointer; border-radius: 6px; transition: background 0.12s, color 0.12s; } +.np-lyrics-line:hover { background: rgba(var(--accent-rgb),0.10); color: rgb(var(--accent-light-rgb)); } /* ── Crafted entrance: controls stagger-fade in when modal opens ── (Art container is intentionally excluded — its transform is reserved for the