Files
pivoine.art/layouts/partials/player.html
2025-11-29 17:51:00 +01:00

123 lines
3.8 KiB
HTML
Executable File

{{/* Persistent Audio Player */}}
<div
x-data="playerUI()"
x-show="$store.audio.currentTrack"
x-cloak
class="audio-player p-4"
role="region"
aria-label="Audio player"
>
<div class="container-wide flex items-center gap-4">
{{/* Track Info */}}
<div class="flex items-center gap-3 min-w-0 flex-1">
{{/* Cover */}}
<div
class="w-12 h-12 bg-surface-2 rounded overflow-hidden flex-shrink-0"
x-show="$store.audio.currentTrack?.image"
>
<img
:src="$store.audio.currentTrack?.image"
:alt="$store.audio.currentTrack?.title"
class="w-full h-full object-cover"
>
</div>
{{/* Title */}}
<div class="min-w-0">
<p
class="text-sm font-medium truncate"
x-text="$store.audio.currentTrack?.title || 'No track'"
></p>
<p class="text-xs text-text-muted">Valknar</p>
</div>
</div>
{{/* Controls */}}
<div class="flex items-center gap-4">
{{/* Play/Pause */}}
<button
@click="togglePlay()"
class="w-10 h-10 flex items-center justify-center rounded-full bg-accent text-surface-0 hover:scale-105 transition-transform"
:aria-label="$store.audio.isPlaying ? 'Pause' : 'Play'"
>
<svg
x-show="!$store.audio.isPlaying"
class="w-5 h-5 ml-0.5"
fill="currentColor"
viewBox="0 0 24 24"
>
<path d="M8 5v14l11-7z"/>
</svg>
<svg
x-show="$store.audio.isPlaying"
x-cloak
class="w-5 h-5"
fill="currentColor"
viewBox="0 0 24 24"
>
<path d="M6 4h4v16H6V4zm8 0h4v16h-4V4z"/>
</svg>
</button>
</div>
{{/* Progress */}}
<div class="flex-1 max-w-md hidden sm:flex items-center gap-3">
<span class="text-xs text-text-muted tabular-nums" x-text="formatTime($store.audio.progress)">0:00</span>
<input
type="range"
min="0"
:max="$store.audio.duration || 100"
:value="$store.audio.progress"
@input="seek($event.target.value)"
class="audio-player__progress flex-1"
aria-label="Seek"
>
<span class="text-xs text-text-muted tabular-nums" x-text="formatTime($store.audio.duration)">0:00</span>
</div>
{{/* Volume */}}
<div class="hidden md:flex items-center gap-2">
<button
@click="toggleMute()"
class="p-2 text-text-secondary hover:text-text-primary transition-colors"
:aria-label="$store.audio.volume === 0 ? 'Unmute' : 'Mute'"
>
<svg
x-show="$store.audio.volume > 0"
class="w-5 h-5"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.536 8.464a5 5 0 010 7.072M17.5 6.5a8 8 0 010 11M11 5L6 9H2v6h4l5 4V5z"/>
</svg>
<svg
x-show="$store.audio.volume === 0"
x-cloak
class="w-5 h-5"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5.586 15H4a1 1 0 01-1-1v-4a1 1 0 011-1h1.586l4.707-4.707C10.923 3.663 12 4.109 12 5v14c0 .891-1.077 1.337-1.707.707L5.586 15z"/>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2"/>
</svg>
</button>
<input
type="range"
min="0"
max="1"
step="0.01"
:value="$store.audio.volume"
@input="setVolume($event.target.value)"
class="w-20 audio-player__progress"
aria-label="Volume"
>
</div>
</div>
</div>
<style>
[x-cloak] { display: none !important; }
</style>