Player: shuffle + repeat on the mini-player (parity with modal)
The sidebar mini-player had prev/play/next/stop/expand but not the two set-and-forget controls you reach for without opening the full view. Added shuffle + repeat (3-mode, with a repeat-one badge) to the mini-controls. State stays in sync both ways: handleNpShuffle/handleNpRepeat now call a shared syncShuffleRepeatUI() that reflects state onto BOTH the modal and mini buttons, so toggling in either place updates the other. Mini buttons reuse the same handlers. Accent-active styling via --accent-light-rgb. JS clean; CSS balance consistent with HEAD.
This commit is contained in:
parent
1e514693f1
commit
ab2b5c64f4
3 changed files with 76 additions and 6 deletions
|
|
@ -8066,6 +8066,9 @@
|
|||
<div class="artist-name" id="artist-name">Unknown Artist</div>
|
||||
</div>
|
||||
<div class="mini-player-controls">
|
||||
<button class="mini-toggle-btn" id="mini-shuffle-btn" title="Shuffle">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="13" height="13"><polyline points="16 3 21 3 21 8"/><line x1="4" y1="20" x2="21" y2="3"/><polyline points="21 16 21 21 16 21"/><line x1="15" y1="15" x2="21" y2="21"/><line x1="4" y1="4" x2="9" y2="9"/></svg>
|
||||
</button>
|
||||
<button class="mini-nav-btn" id="mini-prev-btn" title="Previous" disabled>
|
||||
<svg viewBox="0 0 24 24" fill="currentColor" width="14" height="14"><path d="M6 6h2v12H6zm3.5 6l8.5 6V6z"/></svg>
|
||||
</button>
|
||||
|
|
@ -8076,6 +8079,10 @@
|
|||
<button class="mini-nav-btn" id="mini-next-btn" title="Next" disabled>
|
||||
<svg viewBox="0 0 24 24" fill="currentColor" width="14" height="14"><path d="M6 18l8.5-6L6 6v12zM16 6v12h2V6h-2z"/></svg>
|
||||
</button>
|
||||
<button class="mini-toggle-btn" id="mini-repeat-btn" title="Repeat">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="13" height="13"><polyline points="17 1 21 5 17 9"/><path d="M3 11V9a4 4 0 0 1 4-4h14"/><polyline points="7 23 3 19 7 15"/><path d="M21 13v2a4 4 0 0 1-4 4H3"/></svg>
|
||||
<span class="mini-repeat-one" id="mini-repeat-one-badge" style="display:none">1</span>
|
||||
</button>
|
||||
<button class="stop-button" id="stop-button" disabled>
|
||||
<svg viewBox="0 0 24 24" fill="currentColor" width="10" height="10"><rect x="6" y="6" width="12" height="12" rx="1.5"/></svg>
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -61,6 +61,12 @@ function initializeMediaPlayer() {
|
|||
if (miniPrevBtn) miniPrevBtn.addEventListener('click', (e) => { e.stopPropagation(); playPreviousInQueue(); });
|
||||
if (miniNextBtn) miniNextBtn.addEventListener('click', (e) => { e.stopPropagation(); playNextInQueue(); });
|
||||
|
||||
// Mini shuffle / repeat — share the modal handlers (which now sync both UIs)
|
||||
const miniShuffleBtn = document.getElementById('mini-shuffle-btn');
|
||||
const miniRepeatBtn = document.getElementById('mini-repeat-btn');
|
||||
if (miniShuffleBtn) miniShuffleBtn.addEventListener('click', (e) => { e.stopPropagation(); handleNpShuffle(); });
|
||||
if (miniRepeatBtn) miniRepeatBtn.addEventListener('click', (e) => { e.stopPropagation(); handleNpRepeat(); });
|
||||
|
||||
// Restore a previously-saved queue (does not auto-play)
|
||||
npRestoreQueue();
|
||||
}
|
||||
|
|
@ -2064,15 +2070,32 @@ function updateNpMuteIcon() {
|
|||
if (muteBtn) muteBtn.classList.toggle('muted', npMuted);
|
||||
}
|
||||
|
||||
// Reflect shuffle/repeat state on BOTH the modal and mini-player buttons.
|
||||
function syncShuffleRepeatUI() {
|
||||
const npShuffle = document.getElementById('np-shuffle-btn');
|
||||
const miniShuffle = document.getElementById('mini-shuffle-btn');
|
||||
if (npShuffle) npShuffle.classList.toggle('active', npShuffleOn);
|
||||
if (miniShuffle) miniShuffle.classList.toggle('active', npShuffleOn);
|
||||
|
||||
const repeatOn = npRepeatMode !== 'off';
|
||||
const repeatOne = npRepeatMode === 'one';
|
||||
const npRepeat = document.getElementById('np-repeat-btn');
|
||||
const miniRepeat = document.getElementById('mini-repeat-btn');
|
||||
if (npRepeat) npRepeat.classList.toggle('active', repeatOn);
|
||||
if (miniRepeat) miniRepeat.classList.toggle('active', repeatOn);
|
||||
const npBadge = document.getElementById('np-repeat-one-badge');
|
||||
const miniBadge = document.getElementById('mini-repeat-one-badge');
|
||||
if (npBadge) npBadge.classList.toggle('hidden', !repeatOne);
|
||||
if (miniBadge) miniBadge.style.display = repeatOne ? '' : 'none';
|
||||
}
|
||||
|
||||
function handleNpShuffle() {
|
||||
npShuffleOn = !npShuffleOn;
|
||||
const btn = document.getElementById('np-shuffle-btn');
|
||||
if (btn) btn.classList.toggle('active', npShuffleOn);
|
||||
syncShuffleRepeatUI();
|
||||
updateNpPrevNextButtons();
|
||||
}
|
||||
|
||||
function handleNpRepeat() {
|
||||
const badge = document.getElementById('np-repeat-one-badge');
|
||||
if (npRepeatMode === 'off') {
|
||||
npRepeatMode = 'all';
|
||||
if (audioPlayer) audioPlayer.loop = false;
|
||||
|
|
@ -2083,9 +2106,7 @@ function handleNpRepeat() {
|
|||
npRepeatMode = 'off';
|
||||
if (audioPlayer) audioPlayer.loop = false;
|
||||
}
|
||||
const btn = document.getElementById('np-repeat-btn');
|
||||
if (btn) btn.classList.toggle('active', npRepeatMode !== 'off');
|
||||
if (badge) badge.classList.toggle('hidden', npRepeatMode !== 'one');
|
||||
syncShuffleRepeatUI();
|
||||
updateNpPrevNextButtons();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -693,6 +693,48 @@ body {
|
|||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
/* Mini shuffle / repeat toggle buttons (parity with the modal). Smaller than
|
||||
nav buttons; accent when active; repeat-one shows a tiny badge. */
|
||||
.mini-toggle-btn {
|
||||
position: relative;
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
border-radius: 50%;
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: rgba(255, 255, 255, 0.38);
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: color 0.18s ease, background 0.18s ease;
|
||||
padding: 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.mini-toggle-btn:hover {
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
.mini-toggle-btn.active {
|
||||
color: rgb(var(--accent-light-rgb));
|
||||
}
|
||||
.mini-repeat-one {
|
||||
position: absolute;
|
||||
bottom: -1px;
|
||||
right: -1px;
|
||||
font-size: 8px;
|
||||
font-weight: 800;
|
||||
line-height: 1;
|
||||
background: rgb(var(--accent-light-rgb));
|
||||
color: #06140b;
|
||||
border-radius: 50%;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* Controls cluster in the mini player */
|
||||
.mini-player-controls {
|
||||
display: flex;
|
||||
|
|
|
|||
Loading…
Reference in a new issue