|
|
<template> |
|
|
<div class="desktop-sidebar hidden-mobile"> |
|
|
|
|
|
<div class="sidebar-header"> |
|
|
<div class="app-logo"> |
|
|
<i class="fas fa-music"></i> |
|
|
</div> |
|
|
<div class="app-title">云音乐</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<nav class="sidebar-nav"> |
|
|
<router-link |
|
|
v-for="item in navItems" |
|
|
:key="item.name" |
|
|
:to="item.path" |
|
|
class="nav-item" |
|
|
:class="{ active: currentRoute === item.name }" |
|
|
@click="handleNavClick(item)" |
|
|
> |
|
|
<i :class="item.icon" class="nav-icon"></i> |
|
|
<span class="nav-label">{{ item.label }}</span> |
|
|
<div class="nav-indicator" v-if="currentRoute === item.name"></div> |
|
|
</router-link> |
|
|
</nav> |
|
|
|
|
|
|
|
|
<div class="sidebar-player" v-if="currentSong"> |
|
|
|
|
|
<div class="current-song" @click="openFullPlayer"> |
|
|
<div class="song-cover"> |
|
|
<img |
|
|
:src="currentCoverUrl || defaultCover" |
|
|
:alt="currentSong.name" |
|
|
class="cover-image" |
|
|
@error="handleImageError" |
|
|
/> |
|
|
<div class="play-overlay" @click.stop="togglePlay"> |
|
|
<i :class="isPlaying ? 'fas fa-pause' : 'fas fa-play'"></i> |
|
|
</div> |
|
|
</div> |
|
|
<div class="song-details"> |
|
|
<div class="song-name" :title="currentSong.name">{{ currentSong.name }}</div> |
|
|
<div class="song-artist" :title="formattedArtist">{{ formattedArtist }}</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="player-controls"> |
|
|
<button class="control-btn" @click="playPrevious" title="上一首"> |
|
|
<i class="fas fa-step-backward"></i> |
|
|
</button> |
|
|
<button class="control-btn play-btn" @click="togglePlay" :title="isPlaying ? '暂停' : '播放'"> |
|
|
<i :class="isPlaying ? 'fas fa-pause' : 'fas fa-play'"></i> |
|
|
</button> |
|
|
<button class="control-btn" @click="playNext" title="下一首"> |
|
|
<i class="fas fa-step-forward"></i> |
|
|
</button> |
|
|
<button class="control-btn" @click="openFullPlayer" title="打开播放器"> |
|
|
<i class="fas fa-expand"></i> |
|
|
</button> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="progress-container"> |
|
|
<div class="progress-background" @click="handleProgressClick" ref="progressRef"> |
|
|
<div |
|
|
class="progress-fill" |
|
|
:style="{ width: `${progress}%` }" |
|
|
></div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="volume-control"> |
|
|
<button class="volume-btn" @click="toggleMute"> |
|
|
<i :class="volumeIcon"></i> |
|
|
</button> |
|
|
<input |
|
|
type="range" |
|
|
min="0" |
|
|
max="100" |
|
|
:value="volume" |
|
|
@input="handleVolumeChange" |
|
|
class="volume-slider" |
|
|
/> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="sidebar-stats" v-if="!currentSong"> |
|
|
<div class="stats-item"> |
|
|
<i class="fas fa-music"></i> |
|
|
<div class="stats-info"> |
|
|
<div class="stats-label">暂无播放</div> |
|
|
<div class="stats-value">选择音乐开始播放</div> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="sidebar-actions"> |
|
|
<button class="action-btn" @click="toggleTheme" :title="isDarkTheme ? '切换到亮色主题' : '切换到暗色主题'"> |
|
|
<i :class="isDarkTheme ? 'fas fa-sun' : 'fas fa-moon'"></i> |
|
|
</button> |
|
|
<button class="action-btn" @click="openSettings" title="设置"> |
|
|
<i class="fas fa-cog"></i> |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</template> |
|
|
|
|
|
<script setup> |
|
|
import { computed, ref, watch } from 'vue' |
|
|
import { useRoute, useRouter } from 'vue-router' |
|
|
import { usePlayerStore } from '@/stores/player' |
|
|
import { usePlayQueueStore } from '@/stores/playqueue' |
|
|
import { useSettingsStore } from '@/stores/settings' |
|
|
import { utils } from '@/services/musicApi' |
|
|
|
|
|
const route = useRoute() |
|
|
const router = useRouter() |
|
|
const playerStore = usePlayerStore() |
|
|
const playQueueStore = usePlayQueueStore() |
|
|
const settingsStore = useSettingsStore() |
|
|
|
|
|
|
|
|
const currentCoverUrl = ref('') |
|
|
const isMuted = ref(false) |
|
|
const lastVolume = ref(80) |
|
|
const progressRef = ref(null) |
|
|
|
|
|
|
|
|
const navItems = [ |
|
|
{ |
|
|
name: 'Home', |
|
|
path: '/home', |
|
|
label: '首页', |
|
|
icon: 'fas fa-home' |
|
|
}, |
|
|
{ |
|
|
name: 'Favorites', |
|
|
path: '/favorites', |
|
|
label: '我喜欢', |
|
|
icon: 'fas fa-heart' |
|
|
}, |
|
|
{ |
|
|
name: 'Playlists', |
|
|
path: '/playlists', |
|
|
label: '歌单', |
|
|
icon: 'fas fa-music' |
|
|
}, |
|
|
{ |
|
|
name: 'PlayQueue', |
|
|
path: '/play-queue', |
|
|
label: '播放列表', |
|
|
icon: 'fas fa-list' |
|
|
}, |
|
|
{ |
|
|
name: 'History', |
|
|
path: '/history', |
|
|
label: '播放历史', |
|
|
icon: 'fas fa-history' |
|
|
} |
|
|
] |
|
|
|
|
|
|
|
|
const currentRoute = computed(() => route.name) |
|
|
const currentSong = computed(() => playerStore.currentSong) |
|
|
const isPlaying = computed(() => playerStore.isPlaying) |
|
|
const progress = computed(() => playerStore.progress) |
|
|
const volume = computed(() => playerStore.volume || 80) |
|
|
const isDarkTheme = computed(() => settingsStore.settings.theme === 'dark') |
|
|
|
|
|
const formattedArtist = computed(() => { |
|
|
if (!currentSong.value?.artist) return '' |
|
|
return utils.formatArtist(currentSong.value.artist) |
|
|
}) |
|
|
|
|
|
|
|
|
const defaultCover = computed(() => { |
|
|
return 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNjQiIHZpZXdCb3g9IjAgMCA2NCA2NCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjY0IiBoZWlnaHQ9IjY0IiBmaWxsPSJyZ2JhKDI1NSwyNTUsMjU1LDAuMSkiIHJ4PSI4Ii8+CjxwYXRoIGQ9Ik0zMiAyMEw0MCAzMkgzNlY0NEgyOFYzMkgyNEwzMiAyMFoiIGZpbGw9InJnYmEoMjU1LDI1NSwyNTUsMC4zKSIvPgo8L3N2Zz4K' |
|
|
}) |
|
|
|
|
|
|
|
|
const volumeIcon = computed(() => { |
|
|
if (isMuted.value || volume.value === 0) { |
|
|
return 'fas fa-volume-mute' |
|
|
} else if (volume.value < 30) { |
|
|
return 'fas fa-volume-off' |
|
|
} else if (volume.value < 70) { |
|
|
return 'fas fa-volume-down' |
|
|
} else { |
|
|
return 'fas fa-volume-up' |
|
|
} |
|
|
}) |
|
|
|
|
|
|
|
|
const handleNavClick = (item) => { |
|
|
console.log('导航到:', item.label) |
|
|
} |
|
|
|
|
|
|
|
|
const togglePlay = () => { |
|
|
|
|
|
window.dispatchEvent(new CustomEvent('sidebarTogglePlay')) |
|
|
} |
|
|
|
|
|
const playPrevious = () => { |
|
|
const prevSong = playQueueStore.playPrevious() |
|
|
if (prevSong) { |
|
|
|
|
|
playerStore.setCurrentTime(0) |
|
|
playerStore.playSong(prevSong) |
|
|
} |
|
|
} |
|
|
|
|
|
const playNext = () => { |
|
|
const nextSong = playQueueStore.playNext() |
|
|
if (nextSong) { |
|
|
|
|
|
playerStore.setCurrentTime(0) |
|
|
playerStore.playSong(nextSong) |
|
|
} |
|
|
} |
|
|
|
|
|
const openFullPlayer = () => { |
|
|
if (currentSong.value) { |
|
|
router.push('/player') |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
const handleProgressClick = (event) => { |
|
|
if (!progressRef.value || !playerStore.duration) return |
|
|
|
|
|
const rect = progressRef.value.getBoundingClientRect() |
|
|
const percent = (event.clientX - rect.left) / rect.width |
|
|
const newTime = percent * playerStore.duration |
|
|
|
|
|
playerStore.seekTo(newTime) |
|
|
} |
|
|
|
|
|
|
|
|
const toggleMute = () => { |
|
|
if (isMuted.value) { |
|
|
playerStore.setVolume(lastVolume.value) |
|
|
isMuted.value = false |
|
|
} else { |
|
|
lastVolume.value = volume.value |
|
|
playerStore.setVolume(0) |
|
|
isMuted.value = true |
|
|
} |
|
|
} |
|
|
|
|
|
const handleVolumeChange = (event) => { |
|
|
const newVolume = parseInt(event.target.value) |
|
|
playerStore.setVolume(newVolume) |
|
|
isMuted.value = newVolume === 0 |
|
|
} |
|
|
|
|
|
|
|
|
const handleImageError = () => { |
|
|
currentCoverUrl.value = defaultCover.value |
|
|
} |
|
|
|
|
|
|
|
|
const loadAlbumCover = async () => { |
|
|
if (!currentSong.value) { |
|
|
currentCoverUrl.value = defaultCover.value |
|
|
return |
|
|
} |
|
|
|
|
|
try { |
|
|
const coverUrlResult = await playerStore.getAlbumCover(currentSong.value, 300) |
|
|
if (coverUrlResult) { |
|
|
currentCoverUrl.value = coverUrlResult |
|
|
} else { |
|
|
currentCoverUrl.value = defaultCover.value |
|
|
} |
|
|
} catch (error) { |
|
|
console.error('加载侧边栏封面失败:', error) |
|
|
currentCoverUrl.value = defaultCover.value |
|
|
} |
|
|
} |
|
|
|
|
|
const toggleTheme = () => { |
|
|
const newTheme = isDarkTheme.value ? 'light' : 'dark' |
|
|
settingsStore.updateSetting('theme', newTheme) |
|
|
settingsStore.applyTheme(newTheme) |
|
|
} |
|
|
|
|
|
const openSettings = () => { |
|
|
router.push('/settings') |
|
|
} |
|
|
|
|
|
|
|
|
watch(currentSong, (newSong) => { |
|
|
if (newSong) { |
|
|
loadAlbumCover() |
|
|
} else { |
|
|
currentCoverUrl.value = defaultCover.value |
|
|
} |
|
|
}, { immediate: true }) |
|
|
</script> |
|
|
|
|
|
<style scoped> |
|
|
.desktop-sidebar { |
|
|
width: 280px; |
|
|
height: 100vh; |
|
|
background: var(--bg-card); |
|
|
border-right: 1px solid var(--border-light); |
|
|
display: flex; |
|
|
flex-direction: column; |
|
|
position: fixed; |
|
|
left: 0; |
|
|
top: 0; |
|
|
z-index: 100; |
|
|
backdrop-filter: blur(20px); |
|
|
} |
|
|
|
|
|
|
|
|
.sidebar-header { |
|
|
display: flex; |
|
|
align-items: center; |
|
|
gap: 12px; |
|
|
padding: 24px 20px; |
|
|
border-bottom: 1px solid var(--border-lighter); |
|
|
} |
|
|
|
|
|
.app-logo { |
|
|
width: 40px; |
|
|
height: 40px; |
|
|
background: linear-gradient(135deg, var(--primary-color), var(--primary-color-hover)); |
|
|
border-radius: 12px; |
|
|
display: flex; |
|
|
align-items: center; |
|
|
justify-content: center; |
|
|
color: white; |
|
|
font-size: 18px; |
|
|
box-shadow: 0 4px 12px var(--glow-color); |
|
|
} |
|
|
|
|
|
.app-title { |
|
|
font-size: 20px; |
|
|
font-weight: 700; |
|
|
color: var(--text-primary); |
|
|
} |
|
|
|
|
|
|
|
|
.sidebar-nav { |
|
|
flex: 1; |
|
|
padding: 16px 0; |
|
|
overflow-y: auto; |
|
|
} |
|
|
|
|
|
.nav-item { |
|
|
display: flex; |
|
|
align-items: center; |
|
|
gap: 12px; |
|
|
padding: 16px 20px; |
|
|
text-decoration: none; |
|
|
color: var(--text-secondary); |
|
|
transition: all var(--transition-fast); |
|
|
position: relative; |
|
|
margin: 0 12px; |
|
|
border-radius: 12px; |
|
|
} |
|
|
|
|
|
.nav-item:hover { |
|
|
background: var(--overlay-lighter); |
|
|
color: var(--text-primary); |
|
|
transform: translateX(4px); |
|
|
} |
|
|
|
|
|
.nav-item.active { |
|
|
background: linear-gradient(135deg, var(--primary-color), var(--primary-color-hover)); |
|
|
color: white; |
|
|
box-shadow: 0 4px 12px var(--glow-color); |
|
|
} |
|
|
|
|
|
.nav-item.active .nav-icon { |
|
|
color: white; |
|
|
} |
|
|
|
|
|
.nav-icon { |
|
|
font-size: 18px; |
|
|
width: 20px; |
|
|
text-align: center; |
|
|
transition: var(--transition-fast); |
|
|
} |
|
|
|
|
|
.nav-label { |
|
|
font-size: 16px; |
|
|
font-weight: 500; |
|
|
} |
|
|
|
|
|
.nav-indicator { |
|
|
position: absolute; |
|
|
right: 0; |
|
|
top: 50%; |
|
|
transform: translateY(-50%); |
|
|
width: 4px; |
|
|
height: 20px; |
|
|
background: white; |
|
|
border-radius: 2px; |
|
|
opacity: 0.8; |
|
|
} |
|
|
|
|
|
|
|
|
.sidebar-stats { |
|
|
padding: 16px 20px; |
|
|
border-top: 1px solid var(--border-lighter); |
|
|
border-bottom: 1px solid var(--border-lighter); |
|
|
} |
|
|
|
|
|
.stats-item { |
|
|
display: flex; |
|
|
align-items: center; |
|
|
gap: 12px; |
|
|
padding: 12px 0; |
|
|
} |
|
|
|
|
|
.stats-item i { |
|
|
font-size: 16px; |
|
|
color: var(--primary-color); |
|
|
width: 20px; |
|
|
text-align: center; |
|
|
} |
|
|
|
|
|
.stats-info { |
|
|
flex: 1; |
|
|
min-width: 0; |
|
|
} |
|
|
|
|
|
.stats-label { |
|
|
font-size: 12px; |
|
|
color: var(--text-tertiary); |
|
|
margin-bottom: 2px; |
|
|
} |
|
|
|
|
|
.stats-value { |
|
|
font-size: 14px; |
|
|
font-weight: 600; |
|
|
color: var(--text-primary); |
|
|
white-space: nowrap; |
|
|
overflow: hidden; |
|
|
text-overflow: ellipsis; |
|
|
} |
|
|
|
|
|
|
|
|
.sidebar-actions { |
|
|
display: flex; |
|
|
gap: 8px; |
|
|
padding: 16px 20px; |
|
|
} |
|
|
|
|
|
.action-btn { |
|
|
flex: 1; |
|
|
height: 40px; |
|
|
border: none; |
|
|
background: var(--overlay-lighter); |
|
|
color: var(--text-secondary); |
|
|
border-radius: 10px; |
|
|
cursor: pointer; |
|
|
display: flex; |
|
|
align-items: center; |
|
|
justify-content: center; |
|
|
font-size: 16px; |
|
|
transition: var(--transition-fast); |
|
|
} |
|
|
|
|
|
.action-btn:hover { |
|
|
background: var(--overlay-light); |
|
|
color: var(--text-primary); |
|
|
transform: scale(1.05); |
|
|
} |
|
|
|
|
|
|
|
|
.sidebar-nav::-webkit-scrollbar { |
|
|
width: 4px; |
|
|
} |
|
|
|
|
|
.sidebar-nav::-webkit-scrollbar-track { |
|
|
background: transparent; |
|
|
} |
|
|
|
|
|
.sidebar-nav::-webkit-scrollbar-thumb { |
|
|
background: rgba(255, 255, 255, 0.2); |
|
|
border-radius: 2px; |
|
|
} |
|
|
|
|
|
.sidebar-nav::-webkit-scrollbar-thumb:hover { |
|
|
background: rgba(255, 255, 255, 0.4); |
|
|
} |
|
|
|
|
|
|
|
|
[data-theme="dark"] .sidebar-nav::-webkit-scrollbar-thumb { |
|
|
background: rgba(255, 255, 255, 0.1); |
|
|
} |
|
|
|
|
|
[data-theme="dark"] .sidebar-nav::-webkit-scrollbar-thumb:hover { |
|
|
background: rgba(255, 255, 255, 0.2); |
|
|
} |
|
|
|
|
|
|
|
|
.sidebar-player { |
|
|
padding: 20px; |
|
|
border-top: 1px solid var(--border-lighter); |
|
|
border-bottom: 1px solid var(--border-lighter); |
|
|
background: var(--overlay-lighter); |
|
|
backdrop-filter: blur(10px); |
|
|
} |
|
|
|
|
|
.current-song { |
|
|
display: flex; |
|
|
align-items: center; |
|
|
gap: 12px; |
|
|
margin-bottom: 16px; |
|
|
cursor: pointer; |
|
|
transition: var(--transition-fast); |
|
|
border-radius: 8px; |
|
|
padding: 4px; |
|
|
} |
|
|
|
|
|
.current-song:hover { |
|
|
background: var(--overlay-lighter); |
|
|
transform: scale(1.02); |
|
|
} |
|
|
|
|
|
.song-cover { |
|
|
position: relative; |
|
|
width: 48px; |
|
|
height: 48px; |
|
|
border-radius: 8px; |
|
|
overflow: hidden; |
|
|
flex-shrink: 0; |
|
|
} |
|
|
|
|
|
.cover-image { |
|
|
width: 100%; |
|
|
height: 100%; |
|
|
object-fit: cover; |
|
|
} |
|
|
|
|
|
.play-overlay { |
|
|
position: absolute; |
|
|
top: 0; |
|
|
left: 0; |
|
|
right: 0; |
|
|
bottom: 0; |
|
|
background: rgba(0, 0, 0, 0.5); |
|
|
display: flex; |
|
|
align-items: center; |
|
|
justify-content: center; |
|
|
opacity: 0; |
|
|
transition: var(--transition-fast); |
|
|
cursor: pointer; |
|
|
} |
|
|
|
|
|
.song-cover:hover .play-overlay { |
|
|
opacity: 1; |
|
|
} |
|
|
|
|
|
.play-overlay i { |
|
|
color: white; |
|
|
font-size: 14px; |
|
|
} |
|
|
|
|
|
.song-details { |
|
|
flex: 1; |
|
|
min-width: 0; |
|
|
} |
|
|
|
|
|
.song-name { |
|
|
font-size: 14px; |
|
|
font-weight: 600; |
|
|
color: var(--text-primary); |
|
|
margin-bottom: 2px; |
|
|
white-space: nowrap; |
|
|
overflow: hidden; |
|
|
text-overflow: ellipsis; |
|
|
} |
|
|
|
|
|
.song-artist { |
|
|
font-size: 12px; |
|
|
color: var(--text-secondary); |
|
|
white-space: nowrap; |
|
|
overflow: hidden; |
|
|
text-overflow: ellipsis; |
|
|
} |
|
|
|
|
|
|
|
|
.player-controls { |
|
|
display: flex; |
|
|
align-items: center; |
|
|
justify-content: center; |
|
|
gap: 8px; |
|
|
margin-bottom: 16px; |
|
|
} |
|
|
|
|
|
.control-btn { |
|
|
width: 32px; |
|
|
height: 32px; |
|
|
border-radius: 50%; |
|
|
background: var(--overlay-light); |
|
|
border: 1px solid var(--border-light); |
|
|
color: var(--text-secondary); |
|
|
cursor: pointer; |
|
|
display: flex; |
|
|
align-items: center; |
|
|
justify-content: center; |
|
|
font-size: 12px; |
|
|
transition: var(--transition-fast); |
|
|
} |
|
|
|
|
|
.control-btn:hover { |
|
|
background: var(--overlay-light); |
|
|
color: var(--text-primary); |
|
|
transform: scale(1.1); |
|
|
} |
|
|
|
|
|
.control-btn.play-btn { |
|
|
width: 36px; |
|
|
height: 36px; |
|
|
font-size: 14px; |
|
|
background: var(--primary-color); |
|
|
color: white; |
|
|
border-color: var(--primary-color); |
|
|
} |
|
|
|
|
|
.control-btn.play-btn:hover { |
|
|
background: var(--primary-color-hover); |
|
|
border-color: var(--primary-color-hover); |
|
|
box-shadow: 0 0 12px var(--glow-color); |
|
|
} |
|
|
|
|
|
|
|
|
.progress-container { |
|
|
margin-bottom: 16px; |
|
|
} |
|
|
|
|
|
.progress-background { |
|
|
height: 4px; |
|
|
background: var(--border-light); |
|
|
border-radius: 2px; |
|
|
cursor: pointer; |
|
|
position: relative; |
|
|
transition: var(--transition-fast); |
|
|
} |
|
|
|
|
|
.progress-background:hover { |
|
|
height: 6px; |
|
|
transform: scaleY(1.2); |
|
|
} |
|
|
|
|
|
.progress-fill { |
|
|
height: 100%; |
|
|
background: var(--primary-color); |
|
|
border-radius: 2px; |
|
|
transition: width 0.1s ease; |
|
|
position: relative; |
|
|
} |
|
|
|
|
|
.progress-fill::after { |
|
|
content: ''; |
|
|
position: absolute; |
|
|
right: -2px; |
|
|
top: 50%; |
|
|
transform: translateY(-50%); |
|
|
width: 8px; |
|
|
height: 8px; |
|
|
background: var(--primary-color); |
|
|
border-radius: 50%; |
|
|
opacity: 0; |
|
|
transition: var(--transition-fast); |
|
|
} |
|
|
|
|
|
.progress-background:hover .progress-fill::after { |
|
|
opacity: 1; |
|
|
} |
|
|
|
|
|
|
|
|
.volume-control { |
|
|
display: flex; |
|
|
align-items: center; |
|
|
gap: 12px; |
|
|
} |
|
|
|
|
|
.volume-btn { |
|
|
width: 28px; |
|
|
height: 28px; |
|
|
border-radius: 50%; |
|
|
background: var(--overlay-lighter); |
|
|
border: none; |
|
|
color: var(--text-secondary); |
|
|
cursor: pointer; |
|
|
display: flex; |
|
|
align-items: center; |
|
|
justify-content: center; |
|
|
font-size: 10px; |
|
|
transition: var(--transition-fast); |
|
|
flex-shrink: 0; |
|
|
} |
|
|
|
|
|
.volume-btn:hover { |
|
|
background: var(--overlay-light); |
|
|
color: var(--text-primary); |
|
|
} |
|
|
|
|
|
.volume-slider { |
|
|
flex: 1; |
|
|
height: 3px; |
|
|
background: var(--border-light); |
|
|
border-radius: 2px; |
|
|
outline: none; |
|
|
appearance: none; |
|
|
cursor: pointer; |
|
|
transition: var(--transition-fast); |
|
|
} |
|
|
|
|
|
.volume-slider::-webkit-slider-thumb { |
|
|
appearance: none; |
|
|
width: 12px; |
|
|
height: 12px; |
|
|
border-radius: 50%; |
|
|
background: var(--primary-color); |
|
|
cursor: pointer; |
|
|
border: 2px solid white; |
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); |
|
|
transition: var(--transition-fast); |
|
|
} |
|
|
|
|
|
.volume-slider::-webkit-slider-thumb:hover { |
|
|
transform: scale(1.2); |
|
|
} |
|
|
|
|
|
.volume-slider::-moz-range-thumb { |
|
|
width: 12px; |
|
|
height: 12px; |
|
|
border-radius: 50%; |
|
|
background: var(--primary-color); |
|
|
cursor: pointer; |
|
|
border: 2px solid white; |
|
|
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); |
|
|
transition: var(--transition-fast); |
|
|
} |
|
|
|
|
|
|
|
|
@media (max-width: 1023px) { |
|
|
.desktop-sidebar { |
|
|
display: none; |
|
|
} |
|
|
} |
|
|
</style> |