feat: scroll active chapter into view when chapter drawer opens
All checks were successful
Release / Check ui (push) Successful in 40s
Release / Test backend (push) Successful in 43s
Release / Docker / caddy (push) Successful in 51s
Release / Docker / ui (push) Successful in 2m30s
Release / Docker / runner (push) Successful in 3m26s
Release / Docker / backend (push) Successful in 4m3s
Release / Gitea Release (push) Successful in 12s

When the mini-player chapter drawer is opened, the current chapter is
now immediately scrolled into the center of the list instead of always
starting from the top. Uses a Svelte action (setIfActive) to track the
active chapter element and a $effect to call scrollIntoView on open.
This commit is contained in:
Admin
2026-04-02 20:44:12 +05:00
parent 8e611840d1
commit e9c3426fbe

View File

@@ -33,6 +33,21 @@
// Chapter list drawer state for the mini-player
let chapterDrawerOpen = $state(false);
let activeChapterEl = $state<HTMLElement | null>(null);
function setIfActive(node: HTMLElement, isActive: boolean) {
if (isActive) activeChapterEl = node;
return {
update(nowActive: boolean) { if (nowActive) activeChapterEl = node; },
destroy() { if (activeChapterEl === node) activeChapterEl = null; }
};
}
$effect(() => {
if (chapterDrawerOpen && activeChapterEl) {
activeChapterEl.scrollIntoView({ block: 'center' });
}
});
// The single <audio> element that persists across navigations.
// AudioPlayer components in chapter pages control it via audioStore.
@@ -314,15 +329,6 @@
>
{m.nav_catalogue()}
</a>
<a
href="https://feedback.libnovel.cc"
target="_blank"
rel="noopener noreferrer"
class="hidden sm:block text-sm transition-colors text-(--color-muted) hover:text-(--color-text)"
>
{m.nav_feedback()}
</a>
<div class="ml-auto flex items-center gap-2">
<!-- Theme dropdown (desktop) -->
<div class="hidden sm:block relative">
@@ -423,6 +429,18 @@
{m.nav_admin_panel()}
</a>
{/if}
<a
href="https://feedback.libnovel.cc"
target="_blank"
rel="noopener noreferrer"
onclick={() => { userMenuOpen = false; }}
class="flex items-center justify-between gap-2 px-3 py-2 text-sm text-(--color-muted) hover:text-(--color-text) hover:bg-(--color-surface-3) transition-colors"
>
{m.nav_feedback()}
<svg class="w-3 h-3 shrink-0 opacity-50" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
</svg>
</a>
<div class="my-1 border-t border-(--color-border)/60"></div>
<form method="POST" action="/logout">
<button type="submit" class="w-full text-left px-3 py-2 text-sm text-(--color-danger) hover:bg-(--color-surface-3) transition-colors">
@@ -503,9 +521,12 @@
target="_blank"
rel="noopener noreferrer"
onclick={() => (menuOpen = false)}
class="px-3 py-2.5 rounded-lg text-sm font-medium transition-colors text-(--color-muted) hover:bg-(--color-surface-2) hover:text-(--color-text)"
class="px-3 py-2.5 rounded-lg text-sm font-medium transition-colors text-(--color-muted) hover:bg-(--color-surface-2) hover:text-(--color-text) flex items-center justify-between"
>
{m.nav_feedback()}
{m.nav_feedback()}
<svg class="w-3.5 h-3.5 opacity-50" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
</svg>
</a>
<a
href="/profile"
@@ -678,6 +699,7 @@
</div>
{#each audioStore.chapters as ch (ch.number)}
<a
use:setIfActive={ch.number === audioStore.chapter}
href="/books/{audioStore.slug}/chapters/{ch.number}"
onclick={() => (chapterDrawerOpen = false)}
class="flex items-center gap-2 py-2 text-xs transition-colors hover:text-(--color-text) {ch.number === audioStore.chapter