From 39ad0d6c11c0955e0971f50510147d5d761ab1c2 Mon Sep 17 00:00:00 2001 From: Admin Date: Fri, 6 Mar 2026 19:46:47 +0500 Subject: [PATCH] Add cover thumbnail and chapter list drawer to audio mini-bar - Store cover and chapters array in audioStore (populated by AudioPlayer on startPlayback) - Page server returns full chapters list on normal path; empty array on preview - Mini-bar: replace arrow link with book cover thumbnail (fallback book icon) - Mini-bar track info area is now a button that toggles a chapter list drawer - Chapter drawer slides up above the mini-bar, lists all chapters with current one highlighted --- ui/src/lib/audio.svelte.ts | 6 ++ ui/src/lib/components/AudioPlayer.svelte | 5 ++ ui/src/routes/+layout.svelte | 74 +++++++++++++++++-- .../books/[slug]/chapters/[n]/+page.server.ts | 2 + .../books/[slug]/chapters/[n]/+page.svelte | 1 + 5 files changed, 80 insertions(+), 8 deletions(-) diff --git a/ui/src/lib/audio.svelte.ts b/ui/src/lib/audio.svelte.ts index 9020d22..de4f9a0 100644 --- a/ui/src/lib/audio.svelte.ts +++ b/ui/src/lib/audio.svelte.ts @@ -44,6 +44,12 @@ class AudioStore { voice = $state('af_bella'); speed = $state(1.0); + /** Cover image URL for the currently loaded book. */ + cover = $state(''); + + /** Full chapter list for the currently loaded book (number + title). */ + chapters = $state<{ number: number; title: string }[]>([]); + // ── Loading/generation state ──────────────────────────────────────────── status = $state('idle'); audioUrl = $state(''); diff --git a/ui/src/lib/components/AudioPlayer.svelte b/ui/src/lib/components/AudioPlayer.svelte index c664696..f8416bf 100644 --- a/ui/src/lib/components/AudioPlayer.svelte +++ b/ui/src/lib/components/AudioPlayer.svelte @@ -59,6 +59,8 @@ cover?: string; /** Next chapter number, or null/undefined if this is the last chapter. */ nextChapter?: number | null; + /** Full chapter list for the book (number + title). Written into the store. */ + chapters?: { number: number; title: string }[]; /** List of available voices from the Kokoro API. */ voices?: string[]; } @@ -70,6 +72,7 @@ bookTitle = '', cover = '', nextChapter = null, + chapters = [], voices = [] }: Props = $props(); @@ -405,6 +408,8 @@ audioStore.chapter = chapter; audioStore.chapterTitle = chapterTitle; audioStore.bookTitle = bookTitle; + audioStore.cover = cover; + audioStore.chapters = chapters; // Update OS media session (lock screen / notification center). setMediaSession(); diff --git a/ui/src/routes/+layout.svelte b/ui/src/routes/+layout.svelte index dd3b076..d773fcf 100644 --- a/ui/src/routes/+layout.svelte +++ b/ui/src/routes/+layout.svelte @@ -11,6 +11,9 @@ // Mobile nav drawer state let menuOpen = $state(false); + // Chapter list drawer state for the mini-player + let chapterDrawerOpen = $state(false); + // The single