Move secondary player controls into a More controls sheet
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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 & 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>
|
||||
|
||||
@@ -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); }
|
||||
|
||||
Reference in New Issue
Block a user