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