Merge pull request #45 from zzstoatzz/feat/player-improvements

feat: improve player UI cosmetics

authored by zzstoatzz.io and committed by GitHub f8eec832 29052593

Changed files
+60 -17
frontend
src
lib
components
+60 -17
frontend/src/lib/components/Player.svelte
··· 6 let formattedCurrentTime = $derived(formatTime(player.currentTime)); 7 let formattedDuration = $derived(formatTime(player.duration)); 8 9 // volume state indicators 10 let volumeState = $derived.by(() => { 11 if (player.volume === 0) return 'muted'; ··· 93 <div class="player-title" class:scrolling={player.currentTrack.title.length > 30}> 94 <span>{player.currentTrack.title}</span> 95 </div> 96 - <a href="/u/{player.currentTrack.artist_handle}" class="player-artist-link"> 97 - {player.currentTrack.artist} 98 - </a> 99 </div> 100 101 <div class="player-controls"> ··· 124 min="0" 125 max={player.duration || 0} 126 bind:value={player.currentTime} 127 /> 128 <span class="time">{formattedDuration}</span> 129 </div> ··· 218 } 219 } 220 221 - .player-artist-link { 222 color: #909090; 223 font-size: 0.9rem; 224 text-decoration: none; 225 - display: block; 226 transition: color 0.2s; 227 - white-space: nowrap; 228 - overflow: hidden; 229 - text-overflow: ellipsis; 230 } 231 232 .player-artist-link:hover { 233 color: var(--accent); 234 } 235 236 .player-controls { 237 flex: 1; 238 display: flex; ··· 324 cursor: pointer; 325 } 326 327 - input[type="range"]::-webkit-slider-track { 328 - background: #333; 329 height: 4px; 330 border-radius: 2px; 331 } ··· 342 } 343 344 input[type="range"]::-webkit-slider-thumb:hover { 345 - background: #8ab3ff; 346 transform: scale(1.2); 347 - box-shadow: 0 0 0 4px rgba(106, 159, 255, 0.2); 348 } 349 350 input[type="range"].muted::-webkit-slider-thumb { ··· 353 354 input[type="range"].max::-webkit-slider-thumb { 355 background: var(--accent); 356 - box-shadow: 0 0 0 4px rgba(106, 159, 255, 0.3); 357 } 358 359 input[type="range"]::-moz-range-track { 360 - background: #333; 361 height: 4px; 362 border-radius: 2px; 363 } ··· 372 } 373 374 input[type="range"]::-moz-range-thumb:hover { 375 - background: #8ab3ff; 376 transform: scale(1.2); 377 - box-shadow: 0 0 0 4px rgba(106, 159, 255, 0.2); 378 } 379 380 input[type="range"].muted::-moz-range-thumb { ··· 383 384 input[type="range"].max::-moz-range-thumb { 385 background: var(--accent); 386 - box-shadow: 0 0 0 4px rgba(106, 159, 255, 0.3); 387 } 388 389 @media (max-width: 768px) {
··· 6 let formattedCurrentTime = $derived(formatTime(player.currentTime)); 7 let formattedDuration = $derived(formatTime(player.duration)); 8 9 + // compute progress percentage for seek bar styling 10 + let progressPercent = $derived.by(() => { 11 + if (!player.duration || player.duration === 0) return 0; 12 + return (player.currentTime / player.duration) * 100; 13 + }); 14 + 15 // volume state indicators 16 let volumeState = $derived.by(() => { 17 if (player.volume === 0) return 'muted'; ··· 99 <div class="player-title" class:scrolling={player.currentTrack.title.length > 30}> 100 <span>{player.currentTrack.title}</span> 101 </div> 102 + <div class="player-metadata"> 103 + <a href="/u/{player.currentTrack.artist_handle}" class="player-artist-link"> 104 + {player.currentTrack.artist} 105 + </a> 106 + {#if player.currentTrack.album} 107 + <span class="metadata-separator">•</span> 108 + <span class="player-album">{player.currentTrack.album}</span> 109 + {/if} 110 + </div> 111 </div> 112 113 <div class="player-controls"> ··· 136 min="0" 137 max={player.duration || 0} 138 bind:value={player.currentTime} 139 + style="--progress: {progressPercent}%" 140 /> 141 <span class="time">{formattedDuration}</span> 142 </div> ··· 231 } 232 } 233 234 + .player-metadata { 235 + display: flex; 236 + align-items: center; 237 + gap: 0.5rem; 238 color: #909090; 239 font-size: 0.9rem; 240 + white-space: nowrap; 241 + overflow: hidden; 242 + } 243 + 244 + .player-artist-link { 245 + color: #909090; 246 text-decoration: none; 247 transition: color 0.2s; 248 + flex-shrink: 0; 249 } 250 251 .player-artist-link:hover { 252 color: var(--accent); 253 } 254 255 + .metadata-separator { 256 + color: #606060; 257 + flex-shrink: 0; 258 + } 259 + 260 + .player-album { 261 + color: #808080; 262 + overflow: hidden; 263 + text-overflow: ellipsis; 264 + white-space: nowrap; 265 + } 266 + 267 .player-controls { 268 flex: 1; 269 display: flex; ··· 355 cursor: pointer; 356 } 357 358 + input[type="range"]::-webkit-slider-runnable-track { 359 + background: linear-gradient( 360 + to right, 361 + color-mix(in srgb, var(--accent) 60%, transparent) 0%, 362 + color-mix(in srgb, var(--accent) 60%, transparent) var(--progress, 0%), 363 + color-mix(in srgb, var(--accent) 20%, transparent) var(--progress, 0%), 364 + color-mix(in srgb, var(--accent) 20%, transparent) 100% 365 + ); 366 height: 4px; 367 border-radius: 2px; 368 } ··· 379 } 380 381 input[type="range"]::-webkit-slider-thumb:hover { 382 + background: var(--accent-hover); 383 transform: scale(1.2); 384 + box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 20%, transparent); 385 } 386 387 input[type="range"].muted::-webkit-slider-thumb { ··· 390 391 input[type="range"].max::-webkit-slider-thumb { 392 background: var(--accent); 393 + box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 30%, transparent); 394 } 395 396 input[type="range"]::-moz-range-track { 397 + background: color-mix(in srgb, var(--accent) 20%, transparent); 398 + height: 4px; 399 + border-radius: 2px; 400 + } 401 + 402 + input[type="range"]::-moz-range-progress { 403 + background: color-mix(in srgb, var(--accent) 60%, transparent); 404 height: 4px; 405 border-radius: 2px; 406 } ··· 415 } 416 417 input[type="range"]::-moz-range-thumb:hover { 418 + background: var(--accent-hover); 419 transform: scale(1.2); 420 + box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 20%, transparent); 421 } 422 423 input[type="range"].muted::-moz-range-thumb { ··· 426 427 input[type="range"].max::-moz-range-thumb { 428 background: var(--accent); 429 + box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 30%, transparent); 430 } 431 432 @media (max-width: 768px) {