volumebar
This commit is contained in:
parent
42a8c8122b
commit
e6beacd005
3 changed files with 188 additions and 0 deletions
21
index.html
21
index.html
|
|
@ -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>
|
||||
|
|
|
|||
83
js/ui.js
83
js/ui.js
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
84
styles.css
84
styles.css
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue