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