Admin portrait: top bar clears the notch, bottom bar's last tab stops inside the edge, song cards with stacked full-width actions
This commit is contained in:
@@ -412,17 +412,44 @@
|
||||
.tabs .tab { flex: none; }
|
||||
}
|
||||
.nav { display: none; }
|
||||
.song-info { min-width: 0; flex: 1; }
|
||||
.song-actions { display: flex; flex-wrap: wrap; gap: 8px; }
|
||||
.song-edit { display: none; }
|
||||
.m-only { display: none; }
|
||||
@media (max-width: 760px) {
|
||||
.tabs, .top .desk-only { display: none; }
|
||||
.top .brand { min-width: 0; overflow: hidden; text-overflow: ellipsis; }
|
||||
.top .back-app, .top #logoutBtn { padding-inline: 10px; flex: none; }
|
||||
.top { padding: 10px 14px; }
|
||||
.top { padding: calc(10px + env(safe-area-inset-top, 0px)) calc(14px + env(safe-area-inset-right, 0px)) 10px calc(14px + env(safe-area-inset-left, 0px)); }
|
||||
.deck { top: calc(54px + env(safe-area-inset-top, 0px)); }
|
||||
|
||||
/* Song cards: what it is on top, every action full width beneath it. */
|
||||
#songList { display: grid; gap: 12px; }
|
||||
.song-row { display: grid; gap: 14px; padding: 16px; border-radius: 16px; border: 0; background: var(--bg-2); }
|
||||
.song-row:hover { border-color: transparent; }
|
||||
.song-open { display: grid; grid-template-columns: minmax(0, 1fr); gap: 8px; min-height: 0; flex-basis: auto; }
|
||||
.song-row b { font-size: 17px; line-height: 1.3; white-space: normal; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
|
||||
.song-row small { display: block; margin-top: 2px; font-size: 14px; color: var(--text-2); }
|
||||
.song-row .st { justify-self: start; font-size: 12px; padding: 4px 10px; }
|
||||
.song-actions { display: grid; grid-template-columns: 1fr; gap: 8px; }
|
||||
.song-actions .btn { width: 100%; min-height: 46px; justify-content: center; font-size: 15px; margin: 0; }
|
||||
.song-edit { display: inline-flex; }
|
||||
.m-only { display: inline; } .d-only { display: none; }
|
||||
|
||||
.nav {
|
||||
position: fixed; left: 0; right: 0; bottom: 0; z-index: 50; display: flex; gap: 4px;
|
||||
height: calc(var(--nav-h) + var(--safe)); padding: 6px 6px var(--safe); overflow-x: auto; overflow-y: hidden;
|
||||
overscroll-behavior-x: contain; -webkit-overflow-scrolling: touch; scrollbar-width: thin;
|
||||
overscroll-behavior-x: contain; -webkit-overflow-scrolling: touch; scrollbar-width: none;
|
||||
scroll-snap-type: x proximity; scroll-padding-inline: 6px;
|
||||
padding-left: calc(6px + env(safe-area-inset-left, 0px)); padding-right: calc(6px + env(safe-area-inset-right, 0px));
|
||||
background: var(--bg-1); border-top: 1px solid var(--line-2);
|
||||
}
|
||||
.nav::-webkit-scrollbar { display: none; }
|
||||
/* A flex row drops its end padding when it scrolls; this spacer keeps the
|
||||
last tab clear of the right edge. */
|
||||
.nav::after { content: ""; flex: 0 0 6px; }
|
||||
.nav .tab { scroll-snap-align: start; }
|
||||
.nav .tab:last-of-type { scroll-snap-align: end; }
|
||||
.nav .tab { flex: 0 0 68px; min-width: 68px; min-height: 44px; flex-direction: column; justify-content: center; gap: 3px; height: auto; padding: 4px 3px; font-size: 10px; line-height: 1.05; text-align: center; white-space: normal; border-radius: 12px; }
|
||||
.nav .tab .badge { position: absolute; top: 2px; left: 55%; }
|
||||
.steps { grid-template-columns: 1fr; }
|
||||
@@ -1628,10 +1655,13 @@
|
||||
const q = $('songFilter').value.trim().toLowerCase();
|
||||
const rows = SONGS.filter((r) => !q || (r.title + ' ' + (r.sub || '')).toLowerCase().includes(q));
|
||||
$('songList').innerHTML = rows.length ? rows.map((r) => `<div class="song-row"><button type="button" class="song-open" data-open="${esc(r.id)}">
|
||||
<span style="min-width:0;flex:1"><b>${esc(r.title)}</b><small>${esc(r.sub || '')}</small></span>
|
||||
<span class="song-info"><b>${esc(r.title)}</b><small>${esc(r.sub || '')}</small></span>
|
||||
<span class="st ${r.lines > 0 ? 'has' : ''}">${r.lines > 0 ? `${r.lines} lines` : r.lines === 0 ? 'no lyrics' : 'open'}</span></button>
|
||||
${r.sourceUrl ? `<a class="btn sm" href="${esc(r.sourceUrl)}" target="_blank" rel="noopener">Source</a><button type="button" class="btn sm" data-redownload="${esc(r.id)}">Re-download from source</button>` : ''}
|
||||
<button type="button" class="btn sm whisper-request" data-whisper="${esc(r.id)}" aria-label="Transcribe ${esc(r.title)} with Whisper">Whisper</button></div>`).join('')
|
||||
<div class="song-actions">
|
||||
<button type="button" class="btn sm pri song-edit" data-open="${esc(r.id)}">${r.lines > 0 ? 'Edit lyrics' : 'Add lyrics'}</button>
|
||||
<button type="button" class="btn sm whisper-request" data-whisper="${esc(r.id)}" aria-label="Transcribe ${esc(r.title)} with Whisper">Whisper</button>
|
||||
${r.sourceUrl ? `<button type="button" class="btn sm" data-redownload="${esc(r.id)}">Re-download from source</button><a class="btn sm" href="${esc(r.sourceUrl)}" target="_blank" rel="noopener"><span class="d-only">Source</span><span class="m-only">Open source page</span></a>` : ''}
|
||||
</div></div>`).join('')
|
||||
: '<div class="muted" style="padding:10px">Nothing matches — paste a link above to open any YouTube song.</div>';
|
||||
paintWhisper();
|
||||
}
|
||||
@@ -1790,7 +1820,7 @@
|
||||
document.querySelectorAll('[data-whisper]').forEach(btn => {
|
||||
const job = whisperJobs.get(btn.dataset.whisper);
|
||||
btn.disabled = whisperStarting.has(btn.dataset.whisper) || activeWhisper(job);
|
||||
btn.textContent = job?.status === 'running' ? 'Transcribing…' : job?.status === 'queued' ? 'Queued' : 'Whisper';
|
||||
btn.textContent = job?.status === 'running' ? 'Transcribing…' : job?.status === 'queued' ? 'Queued' : (matchMedia('(max-width: 760px)').matches ? 'Transcribe with Whisper' : 'Whisper');
|
||||
});
|
||||
const job = whisperJobs.get(LE.id);
|
||||
$('whisperBtn').disabled = whisperStarting.has(LE.id) || activeWhisper(job);
|
||||
|
||||
Reference in New Issue
Block a user