Queue fix + cross-client queue enhancements #112

Merged
bvandeusen merged 9 commits from dev into main 2026-07-23 08:31:34 -04:00
2 changed files with 29 additions and 3 deletions
Showing only changes of commit 723293110d - Show all commits
+5 -1
View File
@@ -35,5 +35,9 @@
transition-transform duration-200
{player.queueDrawerOpen ? 'translate-x-0' : 'translate-x-full'}"
>
<QueueList onClose={() => closeQueueDrawer()} bind:closeButtonRef={closeButton} />
<QueueList
onClose={() => closeQueueDrawer()}
active={player.queueDrawerOpen}
bind:closeButtonRef={closeButton}
/>
</aside>
+24 -2
View File
@@ -1,4 +1,5 @@
<script lang="ts">
import { untrack } from 'svelte';
import { X } from 'lucide-svelte';
import { player } from '$lib/player/store.svelte';
import QueueTrackRow from './QueueTrackRow.svelte';
@@ -8,12 +9,33 @@
// now-playing route (visible at lg+ widths) omits it.
// closeButtonRef: bind:this hook so the drawer can focus the X for
// keyboard users on open.
// active: true when the queue is on-screen (drawer open, or the always-
// visible now-playing panel). Flipping it true scrolls the now-playing
// row into view — parity with the Android queue, which opens positioned
// on the current track.
type Props = {
onClose?: () => void;
closeButtonRef?: HTMLButtonElement;
active?: boolean;
};
let { onClose, closeButtonRef = $bindable() }: Props = $props();
let { onClose, closeButtonRef = $bindable(), active = true }: Props = $props();
let scrollBody: HTMLElement | undefined = $state();
// When the queue becomes visible, center the now-playing row in view. The
// index/length are read untracked so this fires once per open (matching the
// Android queue's open-positioned behavior) rather than following the track
// as it auto-advances. Deferred a frame so the drawer's slide-in has settled.
$effect(() => {
if (!active || !scrollBody) return;
const body = scrollBody;
const index = untrack(() => player.index);
if (untrack(() => player.queue.length) === 0) return;
requestAnimationFrame(() => {
(body.children[index] as HTMLElement | undefined)?.scrollIntoView({ block: 'center' });
});
});
function totalDurationLabel(tracks: { duration_sec: number }[]): string {
const totalSec = tracks.reduce((s, tr) => s + (tr.duration_sec ?? 0), 0);
@@ -45,7 +67,7 @@
{/if}
</div>
<div class="flex-1 overflow-y-auto">
<div bind:this={scrollBody} class="flex-1 overflow-y-auto">
{#if player.queue.length === 0}
<p class="text-text-secondary text-center p-8">No tracks queued.</p>
{:else}