fix(reader): clean chapter title display and declutter audio panel
- Strip leading digit prefix (e.g. "6Chapter 6 → Chapter 6") and content after first newline (scraped date artifacts) from chapter titles - Add "CHAPTER N" eyebrow label above the h1 for clear hierarchy - Show date_label as small muted text in the meta row - Remove double-border / mt-6 gap from standard AudioPlayer inside the chapter page's collapsible panel (was rendering two nested boxes) - Remove redundant "Audio Narration" label (toggle already says "Listen") Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1024,15 +1024,8 @@
|
||||
</div>
|
||||
{:else}
|
||||
<!-- ── Standard player ─────────────────────────────────────────────────────── -->
|
||||
<div class="mt-6 p-4 rounded-lg bg-(--color-surface-2) border border-(--color-border)">
|
||||
<div class="flex items-center justify-between gap-2 mb-3">
|
||||
<div class="flex items-center gap-2">
|
||||
<svg class="w-4 h-4 text-(--color-brand)" fill="currentColor" viewBox="0 0 24 24">
|
||||
<path d="M12 3v10.55A4 4 0 1014 17V7h4V3h-6z"/>
|
||||
</svg>
|
||||
<span class="text-sm text-(--color-text) font-medium">{m.reader_audio_narration()}</span>
|
||||
</div>
|
||||
|
||||
<div class="p-4">
|
||||
<div class="flex items-center justify-end gap-2 mb-3">
|
||||
<!-- Voice selector button -->
|
||||
{#if voices.length > 0}
|
||||
<Button
|
||||
|
||||
@@ -287,6 +287,15 @@
|
||||
html ? (html.replace(/<[^>]*>/g, '').match(/\S+/g)?.length ?? 0) : 0
|
||||
);
|
||||
|
||||
// Strip scraper artifacts from chapter titles:
|
||||
// - Leading digit(s) prefixed before "Chapter" (e.g. "6Chapter 6 : ...")
|
||||
// - Everything after the first newline (often includes a scraped date)
|
||||
const cleanTitle = $derived.by(() => {
|
||||
let t = (data.chapter.title || '').split('\n')[0].trim();
|
||||
t = t.replace(/^\d+(?=Chapter)/i, '').trim();
|
||||
return t || `Chapter ${data.chapter.number}`;
|
||||
});
|
||||
|
||||
// Audio panel: auto-open if this chapter is already loaded/playing in the store
|
||||
// svelte-ignore state_referenced_locally
|
||||
let audioExpanded = $state(
|
||||
@@ -301,7 +310,7 @@
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>{data.chapter.title || m.reader_chapter_n({ n: String(data.chapter.number) })} — {data.book.title} — libnovel</title>
|
||||
<title>{cleanTitle} — {data.book.title} — libnovel</title>
|
||||
</svelte:head>
|
||||
|
||||
<!-- Reading progress bar (scroll mode, fixed at top of viewport) -->
|
||||
@@ -364,8 +373,11 @@
|
||||
|
||||
<!-- Chapter heading + meta + language switcher -->
|
||||
<div class="mb-6">
|
||||
<p class="text-xs font-semibold text-(--color-brand) uppercase tracking-widest mb-1.5">
|
||||
{m.reader_chapter_n({ n: String(data.chapter.number) })}
|
||||
</p>
|
||||
<h1 class="text-xl font-bold text-(--color-text) leading-snug">
|
||||
{data.chapter.title || m.reader_chapter_n({ n: String(data.chapter.number) })}
|
||||
{cleanTitle}
|
||||
</h1>
|
||||
<div class="flex items-center flex-wrap gap-x-3 gap-y-1.5 mt-2">
|
||||
{#if wordCount > 0}
|
||||
@@ -375,6 +387,9 @@
|
||||
~{Math.max(1, Math.round(wordCount / 200))} min
|
||||
</p>
|
||||
{/if}
|
||||
{#if data.chapter.date_label}
|
||||
<span class="text-(--color-muted) text-xs opacity-60">{data.chapter.date_label}</span>
|
||||
{/if}
|
||||
|
||||
<!-- Language switcher (inline, compact) -->
|
||||
{#if !data.isPreview}
|
||||
@@ -483,7 +498,7 @@
|
||||
<AudioPlayer
|
||||
slug={data.book.slug}
|
||||
chapter={data.chapter.number}
|
||||
chapterTitle={data.chapter.title || m.reader_chapter_n({ n: String(data.chapter.number) })}
|
||||
chapterTitle={cleanTitle}
|
||||
bookTitle={data.book.title}
|
||||
cover={data.book.cover}
|
||||
nextChapter={data.next}
|
||||
|
||||
Reference in New Issue
Block a user