Move secondary player controls into a More controls sheet

This commit is contained in:
Claude
2026-10-01 20:58:15 +00:00
parent 88f878b8eb
commit 9f313f61af
3 changed files with 91 additions and 39 deletions

View File

@@ -2526,6 +2526,65 @@ async function offerPeerDownload(videoObj) {
}
// "More controls" sheet for the player deck. Toggles drive the original (hidden)
// buttons; speed and quality are mirrored selects that write back to the real
// ones. Rows marked `stay` keep the sheet open so A then B can be set in a row.
function openMoreControls() {
const toggles = [
['abABtn', '🅰', 'Loop start (A)', true],
['abBBtn', '🅱', 'Loop end (B)', true],
['abClearBtn', '↺', 'Clear A-B loop', true],
['rememberPosBtn', '📍', 'Remember position', true],
['sleepTimerBtn', '⏱', 'Sleep timer', false],
['transitionBtn', '↦', 'Between songs', true],
['eqBtn', '🎚', 'Equalizer', false],
['pipBtn', '⧉', 'Picture-in-picture', false],
];
const selects = [['speedSelect', '⏩', 'Speed'], ['qualitySelect', '🎞', 'Quality']];
const list = document.createElement('div');
list.className = 'more-list';
const draw = () => {
list.innerHTML = '';
for (const [id, icon, title] of selects) {
const src = $(id);
if (!src || !src.options.length) continue;
const row = document.createElement('label');
row.className = 'more-row';
row.innerHTML = '<span class="more-ico"></span><span class="more-txt"><b></b></span>';
row.querySelector('.more-ico').textContent = icon;
row.querySelector('b').textContent = title;
const sel = document.createElement('select');
sel.className = 'more-sel';
sel.innerHTML = src.innerHTML;
sel.value = src.value;
sel.onchange = () => { src.value = sel.value; src.dispatchEvent(new Event('change', { bubbles: true })); };
row.appendChild(sel);
list.appendChild(row);
}
for (const [id, icon, title, stay] of toggles) {
const src = $(id);
if (!src || src.classList.contains('hidden') || src.hidden) continue;
const on = src.classList.contains('active') || src.classList.contains('sleep-active');
const row = document.createElement('button');
row.type = 'button';
row.className = 'more-row' + (on ? ' on' : '');
row.innerHTML = '<span class="more-ico"></span><span class="more-txt"><b></b><small></small></span><span class="more-go">' + (on ? '●' : '›') + '</span>';
row.querySelector('.more-ico').textContent = icon;
row.querySelector('b').textContent = title;
row.querySelector('small').textContent = String(src.title || '').replace(/\s*\[[A-Za-z]\]\s*$/, '');
row.onclick = () => {
if (stay) { src.click(); setTimeout(draw, 60); return; }
closeModal();
setTimeout(() => src.click(), 0);
};
list.appendChild(row);
}
};
draw();
showModal('More controls', list, [{ label: 'Done', onClick: closeModal }]);
}
// "More actions" sheet: the everyday four stay on the page, the rest live here.
// Each row drives the original (hidden) button, so handlers and the hidden /
// disabled state those buttons already manage keep working.
@@ -3790,21 +3849,6 @@ const Notes = (() => {
};
})();
// ---- Player deck tabs: Sound & view (default) / Practice ----
(function deckTabs() {
const tabs = document.querySelectorAll('.dk-tab');
if (!tabs.length) return;
let cur = 'sound';
try { cur = localStorage.getItem('ytpDeckTab') === 'practice' ? 'practice' : 'sound'; } catch { /* default */ }
const show = (name) => {
tabs.forEach((t) => { const on = t.dataset.dk === name; t.classList.toggle('active', on); t.setAttribute('aria-selected', String(on)); });
document.querySelectorAll('.dk-group').forEach((g) => g.classList.toggle('hidden', g.dataset.dk !== name));
try { localStorage.setItem('ytpDeckTab', name); } catch { /* private mode */ }
};
tabs.forEach((t) => t.addEventListener('click', () => show(t.dataset.dk)));
show(cur);
})();
// ============================================================================
// Phone remote (server/remote.js relays both ends over /ws/remote)
// ============================================================================
@@ -9382,6 +9426,7 @@ document.querySelectorAll('.chip').forEach((c) => {
}
});
if ($('moreBtn')) $('moreBtn').addEventListener('click', openMoreActions);
if ($('ctlMoreBtn')) $('ctlMoreBtn').addEventListener('click', openMoreControls);
if ($('exportBtn')) $('exportBtn').addEventListener('click', () => { if (current && current.meta) exportToDevice(current.meta); });
els.addPlaylistBtn.addEventListener('click', () => {
if (current && current.meta) openCardMenu(current.meta);

View File

@@ -181,18 +181,20 @@
<button id="muteBtn" class="ctrl" title="Mute" aria-label="Mute">🔊</button>
<input id="volume" type="range" min="0" max="1" step="0.01" value="1" aria-label="Volume" />
</div>
<div class="dk-tabs" role="tablist" aria-label="More controls">
<button class="dk-tab" data-dk="sound" role="tab" type="button">Sound &amp; view</button>
<button class="dk-tab" data-dk="practice" role="tab" type="button">Practice</button>
<div class="dk-quick">
<button id="loopBtn" class="ctrl" title="Loop current video (L)">🔂</button>
<button id="fsBtn" class="ctrl" title="Fullscreen">⛶</button>
<button id="ctlMoreBtn" class="dk-more" type="button" aria-haspopup="dialog"><span>⋯ More controls</span><small>Speed · Quality · A-B · Sleep</small></button>
</div>
<div class="deck-groups">
<div class="dk-group" data-dk="practice">
<div class="dk-tiles">
<div id="dkMoreHost" hidden>
<button id="abABtn" class="ctrl ab-ctrl" title="Set A-B loop start [A]">A</button>
<button id="abBBtn" class="ctrl ab-ctrl" title="Set A-B loop end [B]">B</button>
<button id="abClearBtn" class="ctrl ab-ctrl hidden" title="Clear A-B loop">↺</button>
<button id="rememberPosBtn" class="ctrl" title="Remember playback position for this song (per playlist)">📍</button>
<button id="loopBtn" class="ctrl" title="Loop current video (L)">🔂</button>
<button id="sleepTimerBtn" class="ctrl" title="Sleep timer">⏱</button>
<button id="transitionBtn" class="ctrl" title="Between songs in a playlist: Normal — click to change">↦</button>
<button id="eqBtn" class="ctrl" title="Equalizer (E)">🎚</button>
<button id="pipBtn" class="ctrl hidden" title="Picture-in-picture (I)">⧉</button>
<label class="sel dk-sel">
<span>Speed</span>
<select id="speedSelect">
@@ -204,23 +206,12 @@
<option value="2">2×</option>
</select>
</label>
</div>
</div>
<div class="dk-group" data-dk="sound">
<div class="dk-tiles">
<button id="sleepTimerBtn" class="ctrl" title="Sleep timer">⏱</button>
<button id="transitionBtn" class="ctrl" title="Between songs in a playlist: Normal — click to change">↦</button>
<button id="eqBtn" class="ctrl" title="Equalizer (E)">🎚</button>
<button id="pipBtn" class="ctrl hidden" title="Picture-in-picture (I)">⧉</button>
<button id="fsBtn" class="ctrl" title="Fullscreen">⛶</button>
<label class="sel dk-sel">
<span>Quality</span>
<select id="qualitySelect"></select>
</label>
</div>
</div>
</div>
</div>
<div id="sleepStatus" class="sleep-status hidden">
<span id="sleepCountdown" class="sleep-countdown"></span>

View File

@@ -447,3 +447,19 @@
.more-go { color: var(--text-dim); font-size: 22px; }
.more-row.danger b { color: #ff8a80; }
.more-row.danger .more-ico { background: rgba(255, 75, 50, 0.16); }
/* ---- Deck: quick row + More controls ---- */
#controls #dkMoreHost { display: none; }
#controls .dk-quick { display: flex; gap: 8px; align-items: stretch; }
#controls .dk-quick .ctrl { flex: 0 0 56px; width: 56px; height: 56px; border-radius: 16px; font-size: 20px; }
#controls .dk-more {
flex: 1; min-width: 0; padding: 6px 14px; text-align: left; cursor: pointer;
display: flex; flex-direction: column; justify-content: center; gap: 2px;
border-radius: 16px; border: 1px solid var(--line); background: transparent; color: var(--text);
}
#controls .dk-more span { font: 700 14px var(--ui); }
#controls .dk-more small { font: 400 11.5px var(--ui); color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#controls .dk-more:hover { border-color: var(--accent); }
.more-row.on .more-go { color: var(--accent-bright); }
.more-row.on { border-color: color-mix(in srgb, var(--accent) 55%, transparent); }
.more-sel { margin-left: auto; min-width: 96px; height: 38px; padding: 0 8px; border-radius: 10px; border: 1px solid var(--line); background: var(--bg-1); color: var(--text); font: 700 14px var(--mono); }