From 222627a18c704203301a6c0b032e34b5b6653293 Mon Sep 17 00:00:00 2001 From: Admin Date: Sun, 5 Apr 2026 17:57:44 +0500 Subject: [PATCH] =?UTF-8?q?refactor:=20clean=20up=20chapter=20reader=20UI?= =?UTF-8?q?=20=E2=80=94=20nav,=20audio,=20lang=20switcher,=20bottom=20CTA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Consolidate top nav into a single row: ← back | ← → chapter arrows | settings gear Removes the duplicate prev/next buttons that appeared at both top and bottom - Language switcher moved inline into chapter meta line (after word count); lock icons made smaller and less distracting for free users; removes the separate "Upgrade to Pro" text link - Audio player wrapped in a collapsible "Listen to this chapter" panel; auto-expands if audio is already playing for the chapter, collapsed otherwise so content is immediately visible on page load - Bottom nav redesigned: next chapter is a full-width card CTA with hover accent, previous is a small secondary text link — clear visual hierarchy - Remove floating gear button (settings now triggered from top nav settings icon) Co-Authored-By: Claude Sonnet 4.6 --- .../books/[slug]/chapters/[n]/+page.svelte | 387 ++++++++++-------- 1 file changed, 207 insertions(+), 180 deletions(-) diff --git a/ui/src/routes/books/[slug]/chapters/[n]/+page.svelte b/ui/src/routes/books/[slug]/chapters/[n]/+page.svelte index df4441e..0a2ef3e 100644 --- a/ui/src/routes/books/[slug]/chapters/[n]/+page.svelte +++ b/ui/src/routes/books/[slug]/chapters/[n]/+page.svelte @@ -286,23 +286,36 @@ const wordCount = $derived( html ? (html.replace(/<[^>]*>/g, '').match(/\S+/g)?.length ?? 0) : 0 ); + + // Audio panel: auto-open if this chapter is already loaded/playing in the store + // svelte-ignore state_referenced_locally + let audioExpanded = $state( + audioStore.slug === data.book.slug && audioStore.chapter === data.chapter.number + ); + $effect(() => { + // Expand automatically when the store starts playing this chapter + if (audioStore.slug === data.book.slug && audioStore.chapter === data.chapter.number && audioStore.isPlaying) { + audioExpanded = true; + } + }); {data.chapter.title || m.reader_chapter_n({ n: String(data.chapter.number) })} — {data.book.title} — libnovel - + {#if layout.readMode === 'scroll'}
{/if} - + {#if !layout.focusMode} -
+
+ @@ -310,148 +323,177 @@ {m.reader_back_to_chapters()} -
+ +
{#if data.prev} - ← {m.reader_chapter_n({ n: String(data.prev) })} + + + {/if} {#if data.next} - {m.reader_chapter_n({ n: String(data.next) })} → + + + {/if} + {#if settingsCtx} + + {/if}
- -
-

+ +
+

{data.chapter.title || m.reader_chapter_n({ n: String(data.chapter.number) })}

- {#if wordCount > 0} -

- {m.reader_words({ n: wordCount.toLocaleString() })} - · - ~{Math.max(1, Math.round(wordCount / 200))} min read -

- {/if} -
-{/if} - - -{#if !data.isPreview && !layout.focusMode} -
- Read in: - - - - EN - - - {#each SUPPORTED_LANGS as { code, label }} - {#if !data.isPro} - - - - - - {label} - - {:else if currentLang() === code && (translationStatus === 'pending' || translationStatus === 'running')} - - - - - - - {label} - - {:else if currentLang() === code} - - {label} - {:else} - - +
+ {#if wordCount > 0} +

+ {m.reader_words({ n: wordCount.toLocaleString() })} + · + ~{Math.max(1, Math.round(wordCount / 200))} min +

{/if} - {/each} - {#if !data.isPro} - Upgrade to Pro - {/if} + + {#if !data.isPreview} +
+ EN + {#each SUPPORTED_LANGS as { code, label }} + {#if !data.isPro} + + + + + {label} + + {:else if currentLang() === code && (translationStatus === 'pending' || translationStatus === 'running')} + + + + + + {label} + + {:else if currentLang() === code} + {label} + {:else} + + {/if} + {/each} + {#if !data.isPro} + Pro + {/if} +
+ {/if} +
{/if} - + {#if !data.isPreview && !layout.focusMode} -{#if !page.data.user} - -
-
-

{m.reader_signin_for_audio()}

-

{m.reader_signin_audio_desc()}

+ {#if !page.data.user} + +
+
+

{m.reader_signin_for_audio()}

+

{m.reader_signin_audio_desc()}

+
+ + {m.nav_sign_in()} +
- - {m.nav_sign_in()} - -
-{:else if audioProRequired} -
-
-

Daily audio limit reached

-

Free users can listen to 3 chapters per day. Upgrade to Pro for unlimited audio.

+ {:else if audioProRequired} +
+
+

Daily audio limit reached

+

Upgrade to Pro for unlimited audio.

+
+ + Upgrade +
- - Upgrade - + {:else} + +
+ + {#if audioExpanded} +
+ { audioProRequired = true; }} + /> +
+ {/if} +
+ {/if} +{:else if data.isPreview} +
+ {m.reader_preview_audio_notice()}
-{:else} - { audioProRequired = true; }} -/> -{/if} -{:else} -
- {m.reader_preview_audio_notice()} -
{/if} - + {#if fetchingContent}
@@ -465,7 +507,7 @@

{fetchError || m.reader_audio_error()}

{:else if layout.readMode === 'paginated'} - +
Prev - {pageIndex + 1} / {totalPages} -
- -

Tap left/right · Arrow keys · Space

{:else} - +
{@html html}
{/if} - + {#if !layout.focusMode} -
- {#if data.prev} - - ← {m.reader_prev_chapter()} - - {:else} - - {/if} - {#if data.next} - - {m.reader_next_chapter()} → - - {/if} -
+ -
- -
+
+ +
{/if} - + {#if layout.focusMode}
{#if data.prev} @@ -595,22 +644,8 @@
{/if} - + {#if settingsCtx} - - - - - {#if settingsPanelOpen} @@ -648,12 +683,11 @@ {#if settingsTab === 'reading'} - +

Typography

-
Font
@@ -670,7 +704,6 @@
-
Size
@@ -690,12 +723,11 @@
- +

Layout

-
Mode
@@ -713,7 +745,6 @@
-
Spacing
@@ -731,7 +762,6 @@
-
Width
@@ -749,7 +779,6 @@
-
Paragraphs
@@ -767,7 +796,6 @@
-