diff --git a/web/app/components/explore/banner/banner-item.tsx b/web/app/components/explore/banner/banner-item.tsx index 964ab95069..af2533325a 100644 --- a/web/app/components/explore/banner/banner-item.tsx +++ b/web/app/components/explore/banner/banner-item.tsx @@ -22,9 +22,10 @@ export type BannerData = { type BannerItemProps = { banner: BannerData autoplayDelay: number + isPaused?: boolean } -export const BannerItem: FC = ({ banner, autoplayDelay }) => { +export const BannerItem: FC = ({ banner, autoplayDelay, isPaused = false }) => { const { t } = useTranslation() const { api, selectedIndex } = useCarousel() const [resetKey, setResetKey] = useState(0) @@ -102,6 +103,7 @@ export const BannerItem: FC = ({ banner, autoplayDelay }) => { isNextSlide={index === slideInfo.nextIndex} autoplayDelay={autoplayDelay} resetKey={resetKey} + isPaused={isPaused} onClick={() => handleIndicatorClick(index)} /> ))} diff --git a/web/app/components/explore/banner/banner.tsx b/web/app/components/explore/banner/banner.tsx index 331f198683..e1623e59bc 100644 --- a/web/app/components/explore/banner/banner.tsx +++ b/web/app/components/explore/banner/banner.tsx @@ -1,5 +1,5 @@ import type { FC } from 'react' -import React, { useMemo } from 'react' +import React, { useMemo, useState } from 'react' import { Carousel } from '@/app/components/base/carousel' import { useGetBanners } from '@/service/use-explore' import Loading from '../../base/loading' @@ -12,6 +12,7 @@ const MIN_LOADING_HEIGHT = 168 const Banner: FC = () => { const { locale } = useI18N() const { data: banners, isLoading, isError } = useGetBanners(locale) + const [isHovered, setIsHovered] = useState(false) const enabledBanners = useMemo( () => banners?.filter((banner: BannerData) => banner.status === 'enabled') ?? [], @@ -39,14 +40,17 @@ const Banner: FC = () => { Carousel.Plugin.Autoplay({ delay: AUTOPLAY_DELAY, stopOnInteraction: false, + stopOnMouseEnter: true, }), ]} className="rounded-2xl" + onMouseEnter={() => setIsHovered(true)} + onMouseLeave={() => setIsHovered(false)} > {enabledBanners.map((banner: BannerData) => ( - + ))} diff --git a/web/app/components/explore/banner/indicator-button.tsx b/web/app/components/explore/banner/indicator-button.tsx index 0bc5fac668..84e52d32d9 100644 --- a/web/app/components/explore/banner/indicator-button.tsx +++ b/web/app/components/explore/banner/indicator-button.tsx @@ -8,6 +8,7 @@ type IndicatorButtonProps = { isNextSlide: boolean autoplayDelay: number resetKey: number + isPaused?: boolean onClick: () => void } @@ -20,12 +21,12 @@ export const IndicatorButton: FC = ({ isNextSlide, autoplayDelay, resetKey, + isPaused = false, onClick, }) => { const [progress, setProgress] = useState(0) const [isPageVisible, setIsPageVisible] = useState(true) const frameIdRef = useRef(undefined) - const pausedTimeRef = useRef(0) const startTimeRef = useRef(0) // Listen to page visibility changes @@ -52,13 +53,12 @@ export const IndicatorButton: FC = ({ // reset and start new animation setProgress(0) startTimeRef.current = Date.now() - pausedTimeRef.current = 0 const animate = () => { - // Only continue animation when page is visible - if (!document.hidden) { + // Only continue animation when page is visible and not paused + if (!document.hidden && !isPaused) { const now = Date.now() - const elapsed = now - startTimeRef.current - pausedTimeRef.current + const elapsed = now - startTimeRef.current const newProgress = Math.min((elapsed / autoplayDelay) * PROGRESS_MAX, PROGRESS_MAX) setProgress(newProgress) @@ -69,14 +69,14 @@ export const IndicatorButton: FC = ({ frameIdRef.current = requestAnimationFrame(animate) } } - if (!document.hidden) + if (!document.hidden && !isPaused) frameIdRef.current = requestAnimationFrame(animate) return () => { if (frameIdRef.current) cancelAnimationFrame(frameIdRef.current) } - }, [isNextSlide, autoplayDelay, resetKey, isPageVisible]) + }, [isNextSlide, autoplayDelay, resetKey, isPageVisible, isPaused]) const isActive = index === selectedIndex