volumebar

This commit is contained in:
EduardPrigoana 2026-02-01 19:13:14 +02:00
parent 42a8c8122b
commit e6beacd005
3 changed files with 188 additions and 0 deletions

View file

@ -299,6 +299,27 @@
</svg>
</button>
</div>
<div class="fullscreen-volume-container">
<button id="fs-volume-btn" class="fs-volume-btn" title="Mute">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"></polygon>
<path d="M15.54 8.46a5 5 0 0 1 0 7.07"></path>
</svg>
</button>
<div id="fs-volume-bar" class="fs-volume-bar">
<div id="fs-volume-fill" class="fs-volume-fill"></div>
</div>
</div>
</div>
</div>
</div>

View file

@ -5,6 +5,8 @@ import {
SVG_DOWNLOAD,
SVG_MENU,
SVG_HEART,
SVG_VOLUME,
SVG_MUTE,
formatTime,
createPlaceholder,
trackDataStore,
@ -900,6 +902,87 @@ export class UIRenderer {
'<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m17 2 4 4-4 4"/><path d="M3 11v-1a4 4 0 0 1 4-4h14"/><path d="m7 22-4-4 4-4"/><path d="M21 13v1a4 4 0 0 1-4 4H3"/><path d="M11 10h1v4"/></svg>';
}
// Fullscreen volume controls
const fsVolumeBtn = document.getElementById('fs-volume-btn');
const fsVolumeBar = document.getElementById('fs-volume-bar');
const fsVolumeFill = document.getElementById('fs-volume-fill');
if (fsVolumeBtn && fsVolumeBar && fsVolumeFill) {
const updateFsVolumeUI = () => {
const { muted } = audioPlayer;
const volume = this.player.userVolume;
fsVolumeBtn.innerHTML = muted || volume === 0 ? SVG_MUTE : SVG_VOLUME;
fsVolumeBtn.classList.toggle('muted', muted || volume === 0);
const effectiveVolume = muted ? 0 : volume * 100;
fsVolumeFill.style.setProperty('--fs-volume-level', `${effectiveVolume}%`);
fsVolumeFill.style.width = `${effectiveVolume}%`;
};
fsVolumeBtn.onclick = () => {
audioPlayer.muted = !audioPlayer.muted;
localStorage.setItem('muted', audioPlayer.muted);
updateFsVolumeUI();
};
const setFsVolume = (e) => {
const rect = fsVolumeBar.getBoundingClientRect();
const position = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width));
const newVolume = position;
this.player.setVolume(newVolume);
if (audioPlayer.muted && newVolume > 0) {
audioPlayer.muted = false;
localStorage.setItem('muted', false);
}
updateFsVolumeUI();
};
let isAdjustingFsVolume = false;
fsVolumeBar.addEventListener('mousedown', (e) => {
isAdjustingFsVolume = true;
setFsVolume(e);
});
fsVolumeBar.addEventListener(
'touchstart',
(e) => {
e.preventDefault();
isAdjustingFsVolume = true;
const touch = e.touches[0];
setFsVolume({ clientX: touch.clientX });
},
{ passive: false }
);
document.addEventListener('mousemove', (e) => {
if (isAdjustingFsVolume) {
setFsVolume(e);
}
});
document.addEventListener(
'touchmove',
(e) => {
if (isAdjustingFsVolume) {
const touch = e.touches[0];
setFsVolume({ clientX: touch.clientX });
}
},
{ passive: false }
);
document.addEventListener('mouseup', () => {
isAdjustingFsVolume = false;
});
document.addEventListener('touchend', () => {
isAdjustingFsVolume = false;
});
audioPlayer.addEventListener('volumechange', updateFsVolumeUI);
updateFsVolumeUI();
}
const update = () => {
if (document.getElementById('fullscreen-cover-overlay').style.display === 'none') return;

View file

@ -2230,6 +2230,90 @@ input:checked + .slider::before {
color: var(--primary);
}
.fullscreen-volume-container {
display: flex;
align-items: center;
justify-content: center;
gap: 1rem;
margin-top: 1rem;
}
.fs-volume-btn {
background: transparent;
border: none;
color: var(--foreground);
cursor: pointer;
padding: 0.5rem;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s ease;
width: 40px;
height: 40px;
}
.fs-volume-btn:hover {
background: rgb(255, 255, 255, 0.1);
transform: scale(1.1);
}
.fs-volume-btn.muted {
color: var(--muted-foreground);
}
.fs-volume-bar {
width: 150px;
height: 6px;
background-color: rgb(255, 255, 255, 0.2);
border-radius: 3px;
cursor: pointer;
position: relative;
transition: height 0.2s ease;
}
.fs-volume-bar:hover {
height: 8px;
}
.fs-volume-fill {
height: 100%;
background-color: var(--foreground);
border-radius: 3px;
width: var(--fs-volume-level, 70%);
transition: width 0.1s ease;
position: relative;
pointer-events: none;
}
.fs-volume-bar:hover .fs-volume-fill {
background-color: var(--highlight);
}
.fs-volume-bar:hover .fs-volume-fill::after,
.fs-volume-bar:active .fs-volume-fill::after {
content: '';
position: absolute;
right: -6px;
top: 50%;
transform: translateY(-50%);
width: 12px;
height: 12px;
background-color: var(--highlight);
border-radius: 50%;
box-shadow: 0 2px 4px rgb(0, 0, 0, 0.3);
}
@media (max-width: 768px) {
.fullscreen-volume-container {
gap: 0.75rem;
}
.fs-volume-bar {
width: 120px;
}
}
.fullscreen-actions {
display: flex;
gap: 1rem;