Compare commits

..

2 Commits
v2.6.7 ... push

Author SHA1 Message Date
root
1cdc7275f8 fix: homepage overlay blocker and carousel auto-advance
Some checks failed
Release / Test backend (push) Successful in 41s
Release / Check ui (push) Successful in 1m43s
Release / Docker / caddy (push) Successful in 42s
Release / Docker / backend (push) Successful in 2m31s
Release / Docker / runner (push) Successful in 2m36s
Release / Docker / ui (push) Has been cancelled
Release / Gitea Release (push) Has been cancelled
Release / Upload source maps (push) Has been cancelled
CI / Backend (push) Successful in 43s
CI / UI (push) Successful in 49s
- Add pointer-events:none to ListeningMode fly-transition wrapper div in
  +layout.svelte so the exiting animation div never blocks page interaction
- Add pointer-events:auto to ListeningMode root div so it still captures
  all touch/click events correctly despite the parent being pointer-events:none
- Rewrite carousel auto-advance using $effect + autoAdvanceSeed pattern:
  replaces the stale-closure setInterval in resetAutoAdvance() with a
  reactive $effect that owns the interval and re-starts cleanly on manual
  navigation by bumping a seed counter
2026-04-06 16:58:23 +05:00
root
9d925382b3 fix(player): register touchmove with passive:false via $effect
All checks were successful
Release / Test backend (push) Successful in 38s
Release / Check ui (push) Successful in 1m34s
Release / Docker / caddy (push) Successful in 41s
Release / Docker / backend (push) Successful in 2m36s
Release / Docker / runner (push) Successful in 2m34s
Release / Upload source maps (push) Successful in 1m35s
Release / Docker / ui (push) Successful in 3m18s
Release / Gitea Release (push) Successful in 1m27s
Svelte 5 has no |nonpassive modifier. Register the touchmove listener
manually so e.preventDefault() can suppress page scroll during the
pull-down gesture.
2026-04-06 16:32:25 +05:00
3 changed files with 30 additions and 14 deletions

View File

@@ -31,6 +31,15 @@
let isDragging = $state(false);
let dragStartY = 0;
let dragStartTime = 0;
let overlayEl = $state<HTMLDivElement | null>(null);
// Register ontouchmove with passive:false so e.preventDefault() works.
// Svelte 5 does not support the |nonpassive modifier, so we use $effect.
$effect(() => {
if (!overlayEl) return;
overlayEl.addEventListener('touchmove', onTouchMove, { passive: false });
return () => overlayEl!.removeEventListener('touchmove', onTouchMove);
});
function onTouchStart(e: TouchEvent) {
// Don't hijack touches that start inside a scrollable element
@@ -238,6 +247,7 @@
<!-- Full-screen listening mode overlay -->
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div
bind:this={overlayEl}
class="fixed inset-0 z-60 flex flex-col overflow-hidden"
style="
background: var(--color-surface);
@@ -246,9 +256,9 @@
transition: {isDragging ? 'none' : 'transform 0.32s cubic-bezier(0.32,0.72,0,1), opacity 0.32s ease'};
will-change: transform;
touch-action: pan-x;
pointer-events: auto;
"
ontouchstart={onTouchStart}
ontouchmove|nonpassive={onTouchMove}
ontouchend={onTouchEnd}
>

View File

@@ -954,7 +954,7 @@
<!-- Listening mode — mounted at root level, independent of audioStore.active,
so closing/pausing audio never tears it down and loses context. -->
{#if listeningModeOpen}
<div transition:fly={{ y: '100%', duration: 320, opacity: 1 }}>
<div transition:fly={{ y: '100%', duration: 320, opacity: 1 }} style="pointer-events: none;">
<ListeningMode
onclose={() => { listeningModeOpen = false; listeningModeChapters = false; }}
openChapters={listeningModeChapters}

View File

@@ -95,22 +95,28 @@
resetAutoAdvance();
}
let autoAdvanceTimer = $state<ReturnType<typeof setInterval> | null>(null);
function resetAutoAdvance() {
if (autoAdvanceTimer) clearInterval(autoAdvanceTimer);
if (heroBooks.length > 1) {
autoAdvanceTimer = setInterval(() => {
heroIndex = (heroIndex + 1) % heroBooks.length;
}, 6000);
}
}
// Auto-advance carousel every 6 s when there are multiple books.
// We use a $state counter as a "restart token" so the $effect can be
// re-triggered by manual navigation without reading heroIndex (which would
// cause an infinite loop when the interval itself mutates heroIndex).
let autoAdvanceSeed = $state(0);
$effect(() => {
resetAutoAdvance();
return () => { if (autoAdvanceTimer) clearInterval(autoAdvanceTimer); };
if (heroBooks.length <= 1) return;
// Subscribe to heroBooks.length and autoAdvanceSeed only — not heroIndex.
const len = heroBooks.length;
void autoAdvanceSeed; // track the seed
const id = setInterval(() => {
heroIndex = (heroIndex + 1) % len;
}, 6000);
return () => clearInterval(id);
});
function resetAutoAdvance() {
// Bump the seed to restart the interval after manual navigation.
autoAdvanceSeed++;
}
function playChapter(slug: string, chapter: number) {
audioStore.autoStartChapter = chapter;
goto(`/books/${slug}/chapters/${chapter}`);