fix stupid slider
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Disc, Volume1, Volume2, VolumeX } from "@lucide/svelte";
|
import { Disc, Volume1, Volume2, VolumeX } from "@lucide/svelte";
|
||||||
import { Slider } from "$lib/components/ui/slider";
|
|
||||||
import { player } from "$lib/player/store.svelte";
|
import { player } from "$lib/player/store.svelte";
|
||||||
import Controls from "./Controls.svelte";
|
import Controls from "./Controls.svelte";
|
||||||
import { getAudioContext } from "./ctx.svelte";
|
import { getAudioContext } from "./ctx.svelte";
|
||||||
@@ -8,21 +8,13 @@
|
|||||||
import { formatTime } from "./utils";
|
import { formatTime } from "./utils";
|
||||||
|
|
||||||
const audio = getAudioContext();
|
const audio = getAudioContext();
|
||||||
|
|
||||||
function onVolume(v: number[]) {
|
|
||||||
player.setVolume(v[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleMute() {
|
|
||||||
player.toggleMute();
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="h-full flex flex-col border-l bg-background/50 backdrop-blur w-full"
|
class="h-full flex flex-col border-l bg-background/50 backdrop-blur w-full"
|
||||||
>
|
>
|
||||||
{#if player.currentTrack}
|
{#if player.currentTrack}
|
||||||
<div class="p-6 space-y-6 flex-shrink-0">
|
<div class="p-6 space-y-6 shrink-0">
|
||||||
<!-- Artwork -->
|
<!-- Artwork -->
|
||||||
<div
|
<div
|
||||||
class="aspect-square w-full relative rounded-xl overflow-hidden bg-muted flex items-center justify-center shadow-lg border"
|
class="aspect-square w-full relative rounded-xl overflow-hidden bg-muted flex items-center justify-center shadow-lg border"
|
||||||
@@ -72,7 +64,7 @@
|
|||||||
<!-- Volume -->
|
<!-- Volume -->
|
||||||
<div class="flex items-center gap-3 px-4">
|
<div class="flex items-center gap-3 px-4">
|
||||||
<button
|
<button
|
||||||
onclick={toggleMute}
|
onclick={() => player.toggleMute()}
|
||||||
class="text-muted-foreground hover:text-foreground transition-colors"
|
class="text-muted-foreground hover:text-foreground transition-colors"
|
||||||
title={player.isMuted ? "Unmute" : "Mute"}
|
title={player.isMuted ? "Unmute" : "Mute"}
|
||||||
>
|
>
|
||||||
@@ -84,12 +76,11 @@
|
|||||||
<Volume2 class="h-4 w-4" />
|
<Volume2 class="h-4 w-4" />
|
||||||
{/if}
|
{/if}
|
||||||
</button>
|
</button>
|
||||||
<Slider
|
<input
|
||||||
value={[player.isMuted ? 0 : player.volume]}
|
type="range"
|
||||||
|
bind:value={player.volume}
|
||||||
max={1}
|
max={1}
|
||||||
step={0.01}
|
step={0.05}
|
||||||
onValueChange={onVolume}
|
|
||||||
type="multiple"
|
|
||||||
class="flex-1"
|
class="flex-1"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { ChevronUp, Disc, X } from "@lucide/svelte";
|
import { Disc } from "@lucide/svelte";
|
||||||
import { Button } from "$lib/components/ui/button";
|
|
||||||
import * as Drawer from "$lib/components/ui/drawer";
|
import * as Drawer from "$lib/components/ui/drawer";
|
||||||
import { Slider } from "$lib/components/ui/slider";
|
|
||||||
import { player } from "$lib/player/store.svelte";
|
import { player } from "$lib/player/store.svelte";
|
||||||
import Controls from "./Controls.svelte";
|
import Controls from "./Controls.svelte";
|
||||||
import { getAudioContext } from "./ctx.svelte";
|
import { getAudioContext } from "./ctx.svelte";
|
||||||
@@ -11,19 +9,6 @@
|
|||||||
|
|
||||||
const audio = getAudioContext();
|
const audio = getAudioContext();
|
||||||
let open = $state(false);
|
let open = $state(false);
|
||||||
let sliderValue = $state([0]);
|
|
||||||
|
|
||||||
// Sync Audio -> Slider
|
|
||||||
$effect(() => {
|
|
||||||
if (Math.abs(sliderValue[0] - audio.currentTime) > 0.1) {
|
|
||||||
sliderValue = [audio.currentTime];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function onSeek(v: number[]) {
|
|
||||||
if (Math.abs(v[0] - audio.currentTime) < 0.1) return;
|
|
||||||
audio.seek(v[0]);
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
@@ -109,12 +94,10 @@
|
|||||||
|
|
||||||
<!-- Progress -->
|
<!-- Progress -->
|
||||||
<div class="space-y-2">
|
<div class="space-y-2">
|
||||||
<Slider
|
<input
|
||||||
bind:value={sliderValue}
|
type="range"
|
||||||
|
bind:value={audio.currentTime}
|
||||||
max={audio.duration || 100}
|
max={audio.duration || 100}
|
||||||
step={0.01}
|
|
||||||
onValueChange={onSeek}
|
|
||||||
type="multiple"
|
|
||||||
class="w-full"
|
class="w-full"
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -40,13 +40,8 @@
|
|||||||
if (track) {
|
if (track) {
|
||||||
const newSrc = track.src;
|
const newSrc = track.src;
|
||||||
const currentSrc = audioEl.currentSrc;
|
const currentSrc = audioEl.currentSrc;
|
||||||
// Create absolute URL for comparison if needed, or rely on currentSrc
|
|
||||||
// audioEl.src sets the attribute, currentSrc is the resolved URL
|
|
||||||
const newSrcAbsolute = new URL(newSrc, document.baseURI).href;
|
|
||||||
|
|
||||||
// audioEl.src sets the attribute, currentSrc is the resolved URL
|
if (currentSrc !== newSrc) {
|
||||||
|
|
||||||
if (currentSrc !== newSrcAbsolute) {
|
|
||||||
audioEl.src = newSrc;
|
audioEl.src = newSrc;
|
||||||
audioEl.play().catch((e) => {
|
audioEl.play().catch((e) => {
|
||||||
console.warn("Autoplay blocked or failed", e);
|
console.warn("Autoplay blocked or failed", e);
|
||||||
@@ -87,6 +82,8 @@
|
|||||||
bind:currentTime={audioCtx.currentTime}
|
bind:currentTime={audioCtx.currentTime}
|
||||||
bind:duration={audioCtx.duration}
|
bind:duration={audioCtx.duration}
|
||||||
bind:paused={audioCtx.paused}
|
bind:paused={audioCtx.paused}
|
||||||
|
bind:volume={player.volume}
|
||||||
|
bind:muted={player.isMuted}
|
||||||
onended={onEnded}
|
onended={onEnded}
|
||||||
class="hidden"
|
class="hidden"
|
||||||
></audio>
|
></audio>
|
||||||
|
|||||||
@@ -51,7 +51,7 @@
|
|||||||
class:active={player.currentId === track.id}
|
class:active={player.currentId === track.id}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="w-8 flex-shrink-0 text-center text-xs text-muted-foreground/60 font-mono"
|
class="w-8 shrink-0 text-center text-xs text-muted-foreground/60 font-mono"
|
||||||
>
|
>
|
||||||
{#if player.currentId === track.id}
|
{#if player.currentId === track.id}
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
import Root from "./slider.svelte";
|
|
||||||
|
|
||||||
export {
|
|
||||||
Root,
|
|
||||||
//
|
|
||||||
Root as Slider,
|
|
||||||
};
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import { Slider as SliderPrimitive } from "bits-ui";
|
|
||||||
import { cn, type WithoutChildrenOrChild } from "$lib/utils.js";
|
|
||||||
|
|
||||||
let {
|
|
||||||
ref = $bindable(null),
|
|
||||||
value = $bindable(),
|
|
||||||
orientation = "horizontal",
|
|
||||||
class: className,
|
|
||||||
...restProps
|
|
||||||
}: WithoutChildrenOrChild<SliderPrimitive.RootProps> = $props();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Discriminated Unions + Destructing (required for bindable) do not
|
|
||||||
get along, so we shut typescript up by casting `value` to `never`.
|
|
||||||
-->
|
|
||||||
<SliderPrimitive.Root
|
|
||||||
bind:ref
|
|
||||||
bind:value={value as never}
|
|
||||||
data-slot="slider"
|
|
||||||
{orientation}
|
|
||||||
class={cn(
|
|
||||||
"relative flex w-full touch-none items-center select-none data-[disabled]:opacity-50 data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-44 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col",
|
|
||||||
className
|
|
||||||
)}
|
|
||||||
{...restProps}
|
|
||||||
>
|
|
||||||
{#snippet children({ thumbs })}
|
|
||||||
<span
|
|
||||||
data-orientation={orientation}
|
|
||||||
data-slot="slider-track"
|
|
||||||
class={cn(
|
|
||||||
"bg-muted relative grow overflow-hidden rounded-full data-[orientation=horizontal]:h-1.5 data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-1.5"
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<SliderPrimitive.Range
|
|
||||||
data-slot="slider-range"
|
|
||||||
class={cn(
|
|
||||||
"bg-primary absolute data-[orientation=horizontal]:h-full data-[orientation=vertical]:w-full"
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
{#each thumbs as thumb (thumb)}
|
|
||||||
<SliderPrimitive.Thumb
|
|
||||||
data-slot="slider-thumb"
|
|
||||||
index={thumb}
|
|
||||||
class="border-primary ring-ring/50 block size-4 shrink-0 rounded-full border bg-white shadow-sm transition-[color,box-shadow] hover:ring-4 focus-visible:ring-4 focus-visible:outline-hidden disabled:pointer-events-none disabled:opacity-50"
|
|
||||||
/>
|
|
||||||
{/each}
|
|
||||||
{/snippet}
|
|
||||||
</SliderPrimitive.Root>
|
|
||||||
Reference in New Issue
Block a user