fix(home): restart the hero banner timer on a manual change
🏗️ Build and Test JellyTau / Run Tests (push) Failing after 14m18s
🏗️ Build and Test JellyTau / Android Compile Check (push) Skipped
Publish Documentation / Build & publish docs to gitea-pages (push) Successful in 5m31s
Traceability Validation / Check Requirement Traces (push) Successful in 17s
Build & Release / Run Tests (push) Failing after 14m7s
Build & Release / Build Linux (push) Skipped
Build & Release / Build Windows (push) Skipped
Build & Release / Build Android (push) Skipped
Build & Release / Create Release (push) Skipped
🏗️ Build and Test JellyTau / Run Tests (push) Failing after 14m18s
🏗️ Build and Test JellyTau / Android Compile Check (push) Skipped
Publish Documentation / Build & publish docs to gitea-pages (push) Successful in 5m31s
Traceability Validation / Check Requirement Traces (push) Successful in 17s
Build & Release / Run Tests (push) Failing after 14m7s
Build & Release / Build Linux (push) Skipped
Build & Release / Build Windows (push) Skipped
Build & Release / Build Android (push) Skipped
Build & Release / Create Release (push) Skipped
The rotation interval was installed once when the banner mounted and never touched again, so a swipe, arrow or dot tap inherited whatever was left of the running countdown — swiping 5.5s into a 6s interval moved the banner on half a second later. The timer moves into heroRotation.ts as a small restartable object so it can be unit-tested, and every manual navigation path restarts it from that moment. Verified red-first: with restart() reverted to leave a running timer alone, the regression test fails. Release 0.9.1.
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
import { goto } from "$app/navigation";
|
||||
import type { MediaItem } from "$lib/api/types";
|
||||
import CachedImage from "$lib/components/common/CachedImage.svelte";
|
||||
import { createRotationTimer, type RotationTimer } from "./heroRotation";
|
||||
|
||||
interface Props {
|
||||
items: MediaItem[];
|
||||
@@ -13,7 +14,7 @@
|
||||
let { items, autoRotate = true, interval = 6000 }: Props = $props();
|
||||
|
||||
let currentIndex = $state(0);
|
||||
let intervalId: number | null = null;
|
||||
let rotation: RotationTimer | null = null;
|
||||
|
||||
// Touch/swipe state
|
||||
let touchStartX = $state(0);
|
||||
@@ -70,8 +71,22 @@
|
||||
currentIndex = (currentIndex - 1 + items.length) % items.length;
|
||||
}
|
||||
|
||||
// Manual navigation (swipe, arrows, dots) restarts the countdown, so the
|
||||
// banner always waits a full interval after the last change instead of
|
||||
// firing whatever was left of the previous one.
|
||||
function showNext() {
|
||||
next();
|
||||
rotation?.restart();
|
||||
}
|
||||
|
||||
function showPrev() {
|
||||
prev();
|
||||
rotation?.restart();
|
||||
}
|
||||
|
||||
function goToIndex(idx: number) {
|
||||
currentIndex = idx;
|
||||
rotation?.restart();
|
||||
}
|
||||
|
||||
// Touch/swipe handlers
|
||||
@@ -96,10 +111,10 @@
|
||||
if (Math.abs(diff) > swipeThreshold) {
|
||||
if (diff > 0) {
|
||||
// Swiped left - go to next
|
||||
next();
|
||||
showNext();
|
||||
} else {
|
||||
// Swiped right - go to previous
|
||||
prev();
|
||||
showPrev();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,9 +125,12 @@
|
||||
// Auto-rotate logic
|
||||
$effect(() => {
|
||||
if (autoRotate && items.length > 1) {
|
||||
intervalId = window.setInterval(next, interval);
|
||||
const timer = createRotationTimer(interval, next);
|
||||
rotation = timer;
|
||||
timer.restart();
|
||||
return () => {
|
||||
if (intervalId) clearInterval(intervalId);
|
||||
timer.stop();
|
||||
rotation = null;
|
||||
};
|
||||
}
|
||||
});
|
||||
@@ -219,7 +237,7 @@
|
||||
|
||||
<!-- Swipe Indicators (Desktop hover) -->
|
||||
<button
|
||||
onclick={prev}
|
||||
onclick={showPrev}
|
||||
class="absolute left-4 top-1/2 transform -translate-y-1/2 w-12 h-12 bg-black/40 backdrop-blur-sm rounded-full items-center justify-center transition-opacity opacity-0 group-hover:opacity-100 hover:bg-black/60 hidden md:flex"
|
||||
aria-label="Previous item"
|
||||
>
|
||||
@@ -229,7 +247,7 @@
|
||||
</button>
|
||||
|
||||
<button
|
||||
onclick={next}
|
||||
onclick={showNext}
|
||||
class="absolute right-4 top-1/2 transform -translate-y-1/2 w-12 h-12 bg-black/40 backdrop-blur-sm rounded-full items-center justify-center transition-opacity opacity-0 group-hover:opacity-100 hover:bg-black/60 hidden md:flex"
|
||||
aria-label="Next item"
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user