diff --git a/src/features/Common/Image/index.tsx b/src/features/Common/Image/index.tsx index a9d3591c..310aa9a4 100644 --- a/src/features/Common/Image/index.tsx +++ b/src/features/Common/Image/index.tsx @@ -37,7 +37,6 @@ export const Image = ({ onError={onError} onLoad={onLoad} title={title} - loading='lazy' /> ) } diff --git a/src/features/HeaderFilters/store/hooks/index.tsx b/src/features/HeaderFilters/store/hooks/index.tsx index be3255a2..46ea69d9 100644 --- a/src/features/HeaderFilters/store/hooks/index.tsx +++ b/src/features/HeaderFilters/store/hooks/index.tsx @@ -31,7 +31,7 @@ export const useFilters = () => { }) const sportList = getLocalStorageItem(querieKeys.sportsList) - const [selectedMode, setSelectedMode] = useState(isMobileDevice ? Tabs.WEEK : Tabs.TIMELINE) + const [selectedMode, setSelectedMode] = useState(Tabs.WEEK) const [selectedMonthModeDate, setSelectedMonthModeDate] = useState(startOfMonth(new Date())) const isMonthMode = selectedMode === Tabs.MONTH const isTimelineMode = selectedMode === Tabs.TIMELINE && !isMobileDevice diff --git a/src/features/MatchesSlider/hooks.tsx b/src/features/MatchesSlider/hooks.tsx index 6b293dcd..a7dbcdb4 100644 --- a/src/features/MatchesSlider/hooks.tsx +++ b/src/features/MatchesSlider/hooks.tsx @@ -9,11 +9,9 @@ import { import throttle from 'lodash/throttle' -import { MATCH_CARD_WIDTH, MATCH_CARD_GAP } from 'features/MatchCard/config' - import type { Match } from 'helpers' -const MATCHES_TO_SCROLL = 12 +const MATCHES_TO_SCROLL = 3 const SCROLLING_DELAY = 350 @@ -24,6 +22,8 @@ export const useMatchesSlider = (matches: Array) => { const [showRightArrow, setShowRigthArrow] = useState(false) const [isLeftArrowDisabled, setIsLeftArrowDisabled] = useState(false) const [isRightArrowDisabled, setIsRightArrowDisabled] = useState(false) + const [sliderLiWidth, setSliderLiWidth] = useState(0) + const [sliderLiGap, setSliderLiGap] = useState(0) useEffect(() => { const { @@ -70,21 +70,32 @@ export const useMatchesSlider = (matches: Array) => { setShowRigthArrow(false) } + useEffect(() => { + const liFirst = slidesRef.current?.querySelectorAll('li')[0]?.getBoundingClientRect() + const liWidth = liFirst?.width + const liFirstLeft = liFirst?.left + const liSecondLeft = slidesRef.current?.querySelectorAll('li')[1]?.getBoundingClientRect().left + if (liWidth && liFirstLeft && liSecondLeft) { + setSliderLiWidth(liWidth) + setSliderLiGap(liSecondLeft - liFirstLeft - liWidth) + } + }, []) + const slideLeft = useMemo(() => throttle(() => { slidesRef.current!.scrollBy({ behavior: 'smooth', - left: -((MATCH_CARD_WIDTH + MATCH_CARD_GAP) * MATCHES_TO_SCROLL), + left: -((sliderLiWidth + sliderLiGap) * MATCHES_TO_SCROLL), top: 0, }) - }, SCROLLING_DELAY), []) + }, SCROLLING_DELAY), [sliderLiGap, sliderLiWidth]) const slideRight = useMemo(() => throttle(() => { slidesRef.current!.scrollBy({ behavior: 'smooth', - left: (MATCH_CARD_WIDTH + MATCH_CARD_GAP) * MATCHES_TO_SCROLL, + left: ((sliderLiWidth + sliderLiGap) * MATCHES_TO_SCROLL), top: 0, }) - }, SCROLLING_DELAY), []) + }, SCROLLING_DELAY), [sliderLiGap, sliderLiWidth]) return { isLeftArrowDisabled, diff --git a/src/features/MatchesSlider/index.tsx b/src/features/MatchesSlider/index.tsx index 5ab29c86..f6fb397d 100644 --- a/src/features/MatchesSlider/index.tsx +++ b/src/features/MatchesSlider/index.tsx @@ -16,10 +16,13 @@ import { } from './styled' type MatchesSliderProps = { + cardSize?: number, matches: Array, } -export const MatchesSlider = ({ matches }: MatchesSliderProps) => { +const PADDING_PARENT = 10 + +export const MatchesSlider = ({ cardSize, matches }: MatchesSliderProps) => { const { isLeftArrowDisabled, isRightArrowDisabled, @@ -36,15 +39,16 @@ export const MatchesSlider = ({ matches }: MatchesSliderProps) => { const scrollToMatchByIndex = (index: number) => { const match = slidesRef.current!.querySelectorAll('li')[index] const offsetLeftCount = match.offsetLeft - const PADDING_PARENT = 10 const offsetLeft = offsetLeftCount - PADDING_PARENT - slidesRef.current!.scrollBy({ - // @ts-ignore - behavior: 'instant', - left: offsetLeft, - }) + setTimeout(() => { + slidesRef.current!.scrollBy({ + // @ts-ignore + behavior: 'instant', + left: offsetLeft, + }) + }, 0) } // скролл к лайв матчам или сегодняшней дате @@ -63,12 +67,16 @@ export const MatchesSlider = ({ matches }: MatchesSliderProps) => { const slidesRefClientWidth = slidesRef.current!.clientWidth const slidesRefScrollWidth = slidesRef.current!.scrollWidth - slidesRef.current!.scrollBy({ + + setTimeout(() => { + slidesRef.current!.scrollBy({ // @ts-ignore - behavior: 'instant', - left: slidesRefScrollWidth - slidesRefClientWidth, - }) - // eslint-disable-next-line react-hooks/exhaustive-deps + behavior: 'instant', + left: slidesRefScrollWidth - slidesRefClientWidth + PADDING_PARENT, + }) + }, 0) + + // eslint-disable-next-line react-hooks/exhaustive-deps }, []) if (isEmpty(matches)) return null @@ -90,7 +98,11 @@ export const MatchesSlider = ({ matches }: MatchesSliderProps) => { /> )} - + {map(matches, (match) => ( ` display: flex; scroll-behavior: smooth; overflow-x: auto; gap: 0.9rem; padding: 10px 10px 10px 7px; - + &::-webkit-scrollbar { display: none; } @@ -26,37 +28,13 @@ export const Slides = styled.ul` ${CardWrapper} { position: relative; - height: 12.9rem; - width: 12.9rem; + height: ${({ size }) => (size ? `${size}px` : '12.9rem')}; + width: ${({ size }) => (size ? `${size}px` : '12.9rem')}; + transition: scale 0.2s; &:hover { scale: 1.04; } - - @media screen and (min-width: 1920px) { - height: 13.8rem; - width: 13.8rem; - } - - @media screen and (max-width: 1920px) { - height: 13.4rem; - width: 13.4rem; - } - - @media screen and (max-width: 1600px) { - height: 13rem; - width: 13rem; - } - - @media screen and (max-width: 1440px) { - height: 12.8rem; - width: 12.8rem; - } - - @media screen and (max-width: 1280px) { - height: 12.6rem; - width: 12.6rem; - } } ` @@ -99,13 +77,13 @@ export const ArrowButton = styled.button` z-index: 3; top: 50%; transform: translate(-50%, -50%); - left: ${({ direction }) => (direction === 'left' ? '1.6rem' : 'calc(100% - 1.6rem)')}; + left: ${({ direction }) => (direction === 'left' ? '1.6rem' : 'calc(100% - 2.3rem)')}; &:hover { ${({ direction, disabled }) => (!disabled ? css` width: 3rem; height: 3rem; - left: ${direction === 'left' ? '2rem' : 'calc(100% - 2rem)'}; + left: ${direction === 'left' ? '2rem' : 'calc(100% - 2.8rem)'}; ${Arrow} { width: 1.5rem; diff --git a/src/features/MatchesTimeline/index.tsx b/src/features/MatchesTimeline/index.tsx index c522ec17..8df1603c 100644 --- a/src/features/MatchesTimeline/index.tsx +++ b/src/features/MatchesTimeline/index.tsx @@ -1,10 +1,13 @@ import { useCallback, useEffect, + useLayoutEffect, useRef, useState, } from 'react' +import isEmpty from 'lodash/isEmpty' + import { MatchesSlider } from 'features/MatchesSlider' import { TimelineTournamentList, useTimeline } from 'features/MatchesTimeline/hooks' import { InfiniteScroll } from 'features/InfiniteScroll' @@ -24,6 +27,10 @@ import { } from './styled' const TOURNAMENT_LIMIT = 10 +const MATCH_COUNT = 6 +const PADDING = 30 +const GAP_COUNT = 5 +const SLIDER_ITEM_GAP = 0.9 // rem export const MatchesTimeline = () => { const { @@ -36,6 +43,25 @@ export const MatchesTimeline = () => { const pageRef = useRef(0) const isLastPageRef = useRef(false) + const wrapperRef = useRef(null) + + const [cardSize, setCardSize] = useState(0) + + // вычисляем размеры плитки + useLayoutEffect(() => { + const offsetWidth = wrapperRef.current?.offsetWidth + const ulItemGapFromRem = SLIDER_ITEM_GAP * parseFloat( + getComputedStyle(document.documentElement).fontSize, + ) + + if (offsetWidth) { + const size = Math.round( + ((offsetWidth - (ulItemGapFromRem * GAP_COUNT) - PADDING) / MATCH_COUNT), + ) + + setCardSize(size) + } + }, []) const getTournaments = useCallback(() => tournamentList.slice( pageRef.current * TOURNAMENT_LIMIT, @@ -66,20 +92,23 @@ export const MatchesTimeline = () => { } }, [getTournaments, tournamentList]) - if (isTimelineFetching) { - return ... - } - return ( - - {onlineUpcomingMatches.length > 0 && ( + + {isTimelineFetching && ...} + {(!isEmpty(onlineUpcomingMatches)) && ( - + LIVE & UPCOMING - + )} @@ -99,14 +128,20 @@ export const MatchesTimeline = () => { /> - + - + ))} diff --git a/src/features/MatchesTimeline/styled.tsx b/src/features/MatchesTimeline/styled.tsx index ac6a399d..8a63b8db 100644 --- a/src/features/MatchesTimeline/styled.tsx +++ b/src/features/MatchesTimeline/styled.tsx @@ -12,12 +12,12 @@ export const RowWrapper = styled.div`` export const Content = styled.div` display: flex; - gap: 10px; -` + ` export const Tournament = styled.div<{ gradientColor?: string, isOnlineUpcoming?: boolean, + size?: number, }>` ${({ gradientColor }) => (gradientColor ? css`background: linear-gradient(187deg, ${gradientColor} -4.49%, #000000 68.29%), #000000;` @@ -29,10 +29,10 @@ export const Tournament = styled.div<{ `} position: relative; - height: 12.9rem; - width: 12.9rem; + height: ${({ size }) => (size ? `${size}px` : '12.9rem')}; + width: ${({ size }) => (size ? `${size}px` : '12.9rem')}; flex-shrink: 0; - margin: 10px 0; + margin: 10px 0.93rem 10px 0px; display: flex; align-items: center; justify-content: center; @@ -42,31 +42,6 @@ export const Tournament = styled.div<{ color: #FFFFFF; text-align: start; padding: 10px; - - @media screen and (min-width: 1920px) { - height: 13.8rem; - width: 13.8rem; - } - - @media screen and (max-width: 1920px) { - height: 13.4rem; - width: 13.4rem; - } - - @media screen and (max-width: 1600px) { - height: 13rem; - width: 13rem; - } - - @media screen and (max-width: 1440px) { - height: 12.8rem; - width: 12.8rem; - } - - @media screen and (max-width: 1280px) { - height: 12.6rem; - width: 12.6rem; - } ` export const TournamentLogo = styled(ProfileLogo)`