From f7fac352a5b23f535c53435e5c8f2dc901e433a7 Mon Sep 17 00:00:00 2001 From: Fam Zheng Date: Sun, 10 May 2026 15:39:30 +0100 Subject: [PATCH] =?UTF-8?q?music(player):=20=E5=8A=A0=E9=9F=B3=E9=87=8F?= =?UTF-8?q?=E6=9D=A1=20+=20=E9=9D=99=E9=9F=B3=E6=8C=89=E9=92=AE=EF=BC=88lo?= =?UTF-8?q?calStorage=20=E6=8C=81=E4=B9=85=E5=8C=96=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/music/frontend/src/views/PlayerView.vue | 78 ++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/apps/music/frontend/src/views/PlayerView.vue b/apps/music/frontend/src/views/PlayerView.vue index 899fcdf..131fe69 100644 --- a/apps/music/frontend/src/views/PlayerView.vue +++ b/apps/music/frontend/src/views/PlayerView.vue @@ -230,6 +230,20 @@
{{ fmtTime(duration) }} + + @@ -336,6 +350,37 @@ const activeTagName = ref(null) const search = ref('') const sortMode = ref(localStorage.getItem('music.sort') || 'name') const repeatOne = ref(false) +const volume = ref(parseFloat(localStorage.getItem('music.vol') || '1')) +const muted = ref(localStorage.getItem('music.muted') === '1') + +const volIcon = computed(() => { + if (muted.value || volume.value === 0) return '🔇' + if (volume.value < 0.34) return '🔈' + if (volume.value < 0.67) return '🔉' + return '🔊' +}) + +function applyVolume() { + if (audioEl.value) { + audioEl.value.volume = volume.value + audioEl.value.muted = muted.value + } +} + +function onVolumeInput(e) { + const v = parseInt(e.target.value, 10) / 100 + volume.value = isNaN(v) ? 0 : Math.max(0, Math.min(1, v)) + if (volume.value > 0 && muted.value) muted.value = false + localStorage.setItem('music.vol', String(volume.value)) + localStorage.setItem('music.muted', muted.value ? '1' : '0') + applyVolume() +} + +function toggleMute() { + muted.value = !muted.value + localStorage.setItem('music.muted', muted.value ? '1' : '0') + applyVolume() +} const audioEl = ref(null) const lyricsBoxEl = ref(null) @@ -650,6 +695,7 @@ function onTimeUpdate(e) { function onLoaded(e) { duration.value = e.target.duration || 0 + applyVolume() } function onEnded() { @@ -1364,6 +1410,38 @@ onBeforeUnmount(() => { text-align: center; } +.vol-icon { font-size: 16px; width: 32px; height: 32px; } +.vol-slider { + -webkit-appearance: none; + appearance: none; + width: 90px; + height: 4px; + background: var(--border); + border-radius: 2px; + cursor: pointer; +} +.vol-slider:focus { outline: none; } +.vol-slider::-webkit-slider-thumb { + -webkit-appearance: none; + appearance: none; + width: 12px; + height: 12px; + background: var(--accent-strong); + border-radius: 50%; + cursor: pointer; +} +.vol-slider::-moz-range-thumb { + width: 12px; + height: 12px; + background: var(--accent-strong); + border: none; + border-radius: 50%; + cursor: pointer; +} +@media (max-width: 768px) { + .vol-slider { width: 60px; } +} + /* Chat sidebar */ .chat { width: 320px;