Files
website/src/lib/components/shell/Music.svelte
T
2026-10-31 21:17:42 -04:00

124 lines
2.5 KiB
Svelte

<script lang="ts">
import { onMount } from 'svelte';
import Icon from '@iconify/svelte';
import { musicPlayer } from '#lib/music/player.svelte';
import MusicPopover from '../music/MusicPopover.svelte';
import MusicBars from '../music/MusicBars.svelte';
let open = $state(false);
const track = $derived(musicPlayer.unavailable ? undefined : musicPlayer.currentTrack);
const muteIcon = $derived(musicPlayer.muted ? 'mdi:volume-off' : 'mdi:volume-high');
onMount(() => {
musicPlayer.start();
});
</script>
{#if track}
{#key musicPlayer.streamKey}
<audio
src={musicPlayer.streamUrl}
autoplay
preload="auto"
bind:paused={musicPlayer.paused}
bind:muted={musicPlayer.muted}
bind:volume={musicPlayer.volume}
ontimeupdate={(event) => musicPlayer.handleTimeUpdate(event.currentTarget.currentTime)}
oncanplay={() => musicPlayer.handleTrackLoaded()}
onended={() => musicPlayer.handleEnded()}
onerror={(event) => musicPlayer.handleTrackError(event.currentTarget.error)}
></audio>
{/key}
{/if}
<div class="music-widget">
{#if track}
<button
class="mute-button"
class:active={!musicPlayer.muted}
title={musicPlayer.muted ? 'Unmute music' : 'Mute music'}
onclick={() => musicPlayer.toggleMute()}
>
<Icon icon={muteIcon} width="18" />
</button>
{/if}
<button
class="track-button"
title={track ? `${track.title} - ${track.artist}` : 'Music'}
aria-expanded={open}
onclick={() => (open = !open)}
>
{#if track}
<MusicBars playing={!musicPlayer.paused} />
<span class="track-title">{track.title}</span>
{:else}
<Icon icon="mdi:music-note-off" width="16" />
{/if}
</button>
{#if open}
<MusicPopover onclose={() => (open = false)} />
{/if}
</div>
<style>
.music-widget {
position: relative;
display: flex;
align-items: center;
margin-right: 4px;
}
.mute-button,
.track-button {
display: inline-flex;
align-items: center;
height: var(--bar-height);
background: none;
border: none;
color: var(--foreground);
}
.mute-button {
padding: 0 0.35rem;
color: var(--muted);
}
.mute-button.active {
color: var(--accent);
}
.track-button {
gap: 0.35rem;
padding: 0 0.4rem;
}
.mute-button:hover,
.track-button:hover {
color: var(--accent);
}
.track-title {
max-width: 14rem;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
@media (max-width: 640px) {
.track-title {
display: none;
}
.music-widget {
margin-right: 2px;
}
.mute-button,
.track-button {
padding: 0 0.3rem;
}
}
</style>