fix(#720): timeline tile size

test-c
Rakov 2 years ago
parent c0d06f8ef9
commit 42623654bb
  1. 1
      src/features/Common/Image/index.tsx
  2. 2
      src/features/HeaderFilters/store/hooks/index.tsx
  3. 25
      src/features/MatchesSlider/hooks.tsx
  4. 38
      src/features/MatchesSlider/index.tsx
  5. 38
      src/features/MatchesSlider/styled.tsx
  6. 55
      src/features/MatchesTimeline/index.tsx
  7. 35
      src/features/MatchesTimeline/styled.tsx

@ -37,7 +37,6 @@ export const Image = ({
onError={onError}
onLoad={onLoad}
title={title}
loading='lazy'
/>
)
}

@ -31,7 +31,7 @@ export const useFilters = () => {
})
const sportList = getLocalStorageItem(querieKeys.sportsList)
const [selectedMode, setSelectedMode] = useState<Tabs>(isMobileDevice ? Tabs.WEEK : Tabs.TIMELINE)
const [selectedMode, setSelectedMode] = useState<Tabs>(Tabs.WEEK)
const [selectedMonthModeDate, setSelectedMonthModeDate] = useState(startOfMonth(new Date()))
const isMonthMode = selectedMode === Tabs.MONTH
const isTimelineMode = selectedMode === Tabs.TIMELINE && !isMobileDevice

@ -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<Match>) => {
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<Match>) => {
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,

@ -16,10 +16,13 @@ import {
} from './styled'
type MatchesSliderProps = {
cardSize?: number,
matches: Array<Match>,
}
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) => {
/>
</ArrowButton>
)}
<Slides ref={slidesRef} onScroll={onScroll}>
<Slides
ref={slidesRef}
onScroll={onScroll}
size={cardSize}
>
{map(matches, (match) => (
<MatchCard
match={match}

@ -8,7 +8,9 @@ export const Wrapper = styled.div`
padding-right: 5px;
`
export const Slides = styled.ul`
export const Slides = styled.ul<{
size?: number,
}>`
display: flex;
scroll-behavior: smooth;
overflow-x: auto;
@ -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<ArrowProps>`
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;

@ -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<HTMLDivElement>(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 <Loading><T9n t='loading' />...</Loading>
}
return (
<InfiniteScroll fullPageScroll onFetchMore={getMoreTournaments}>
<Wrapper>
{onlineUpcomingMatches.length > 0 && (
<Wrapper ref={wrapperRef}>
{isTimelineFetching && <Loading><T9n t='loading' />...</Loading>}
{(!isEmpty(onlineUpcomingMatches)) && (
<RowWrapper>
<Content>
<Tournament isOnlineUpcoming>
<Tournament
size={cardSize}
isOnlineUpcoming
>
LIVE & UPCOMING
</Tournament>
<MatchesSlider matches={onlineUpcomingMatches} />
<MatchesSlider
cardSize={cardSize}
matches={onlineUpcomingMatches}
/>
</Content>
</RowWrapper>
)}
@ -99,14 +128,20 @@ export const MatchesTimeline = () => {
/>
</TournamentSubtitleWrapper>
<Content>
<Tournament gradientColor={tournament.color}>
<Tournament
size={cardSize}
gradientColor={tournament.color}
>
<TournamentLogo
id={tournament_id}
profileType={ProfileTypes.TOURNAMENTS}
sportType={sport_id}
/>
</Tournament>
<MatchesSlider matches={matches} />
<MatchesSlider
cardSize={cardSize}
matches={matches}
/>
</Content>
</RowWrapper>
))}

@ -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)`

Loading…
Cancel
Save