diff options
Diffstat (limited to 'src/lib/List/MediaRoulette.svelte')
| -rw-r--r-- | src/lib/List/MediaRoulette.svelte | 163 |
1 files changed, 82 insertions, 81 deletions
diff --git a/src/lib/List/MediaRoulette.svelte b/src/lib/List/MediaRoulette.svelte index 4b498d4f..d6e33d7a 100644 --- a/src/lib/List/MediaRoulette.svelte +++ b/src/lib/List/MediaRoulette.svelte @@ -1,85 +1,86 @@ <script lang="ts"> - import type { Media } from '$lib/Data/AniList/media'; - import ParallaxImage from '$lib/Image/ParallaxImage.svelte'; - import { outboundLink } from '$lib/Media/links'; - import settings from '$stores/settings'; - import { mediaTitle } from './mediaTitle'; - - interface Props { - media: Media[]; - type: 'anime' | 'manga'; - onClose: () => void; - spinDuration?: number; - } - - let { media, type, onClose, spinDuration = 2 }: Props = $props(); - let isSpinning = $state(false); - let selectedIndex = $state(0); - let displayIndex = $state(0); - let spinTimeout: ReturnType<typeof setTimeout> | null = $state(null); - let showResult = $state(false); - let isClosing = $state(false); - let currentMedia = $derived(media[displayIndex]); - - const startRoulette = () => { - if (media.length === 0 || isSpinning) return; - - isSpinning = true; - showResult = false; - selectedIndex = Math.floor(Math.random() * media.length); - - const startTime = Date.now(); - const durationMs = spinDuration * 1000; - const minSpeed = 50; - const maxSpeed = 350; - const slowdownStart = 0.8; - - const spin = () => { - displayIndex = (displayIndex + 1) % media.length; - - const elapsed = Date.now() - startTime; - const progress = Math.min(elapsed / durationMs, 1); - let speed = minSpeed; - - if (progress > slowdownStart) { - const slowdownProgress = (progress - slowdownStart) / (1 - slowdownStart); - - speed = minSpeed + slowdownProgress * (maxSpeed - minSpeed); - } - - if (progress >= 1 && displayIndex === selectedIndex) { - spinTimeout = null; - isSpinning = false; - showResult = true; - - return; - } - - spinTimeout = setTimeout(spin, speed); - }; - - spinTimeout = setTimeout(spin, minSpeed); - }; - - const handleClose = () => { - if (isClosing) return; - - if (spinTimeout) { - clearTimeout(spinTimeout); - - spinTimeout = null; - } - - isSpinning = false; - showResult = false; - isClosing = true; - - setTimeout(() => onClose(), 200); - }; - - const handleOverlayClick = (e: MouseEvent) => { - if (e.target === e.currentTarget) handleClose(); - }; +import type { Media } from "$lib/Data/AniList/media"; +import ParallaxImage from "$lib/Image/ParallaxImage.svelte"; +import { outboundLink } from "$lib/Media/links"; +import settings from "$stores/settings"; +import { mediaTitle } from "./mediaTitle"; + +interface Props { + media: Media[]; + type: "anime" | "manga"; + onClose: () => void; + spinDuration?: number; +} + +let { media, type, onClose, spinDuration = 2 }: Props = $props(); +let isSpinning = $state(false); +let selectedIndex = $state(0); +let displayIndex = $state(0); +let spinTimeout: ReturnType<typeof setTimeout> | null = $state(null); +let showResult = $state(false); +let isClosing = $state(false); +let currentMedia = $derived(media[displayIndex]); + +const startRoulette = () => { + if (media.length === 0 || isSpinning) return; + + isSpinning = true; + showResult = false; + selectedIndex = Math.floor(Math.random() * media.length); + + const startTime = Date.now(); + const durationMs = spinDuration * 1000; + const minSpeed = 50; + const maxSpeed = 350; + const slowdownStart = 0.8; + + const spin = () => { + displayIndex = (displayIndex + 1) % media.length; + + const elapsed = Date.now() - startTime; + const progress = Math.min(elapsed / durationMs, 1); + let speed = minSpeed; + + if (progress > slowdownStart) { + const slowdownProgress = (progress - slowdownStart) / (1 - slowdownStart); + + speed = minSpeed + slowdownProgress * (maxSpeed - minSpeed); + } + + if (progress >= 1) { + displayIndex = selectedIndex; + spinTimeout = null; + isSpinning = false; + showResult = true; + + return; + } + + spinTimeout = setTimeout(spin, speed); + }; + + spinTimeout = setTimeout(spin, minSpeed); +}; + +const handleClose = () => { + if (isClosing) return; + + if (spinTimeout) { + clearTimeout(spinTimeout); + + spinTimeout = null; + } + + isSpinning = false; + showResult = false; + isClosing = true; + + setTimeout(() => onClose(), 200); +}; + +const handleOverlayClick = (e: MouseEvent) => { + if (e.target === e.currentTarget) handleClose(); +}; </script> <svelte:window onkeydown={(e) => e.key === 'Escape' && handleClose()} /> |