fix(#2399): redesign match profile page for mobile version
parent
e304a42e1e
commit
234fde38bb
@ -0,0 +1,34 @@ |
|||||||
|
import { useMemo } from 'react' |
||||||
|
|
||||||
|
import { format, parseISO } from 'date-fns' |
||||||
|
|
||||||
|
import { MatchInfo } from 'requests' |
||||||
|
|
||||||
|
import { ScDate, ScDateMonth } from './styled' |
||||||
|
|
||||||
|
type Props = { |
||||||
|
profile: MatchInfo, |
||||||
|
} |
||||||
|
|
||||||
|
export const MatchDate = ({ profile }: Props) => { |
||||||
|
const { |
||||||
|
date, |
||||||
|
} = { ...profile! } |
||||||
|
|
||||||
|
const month = useMemo(() => ( |
||||||
|
format(parseISO(date), 'MMM MM,') |
||||||
|
), [date]) |
||||||
|
|
||||||
|
const hour = useMemo(() => ( |
||||||
|
format(parseISO(date), ' HH:mm') |
||||||
|
), [date]) |
||||||
|
|
||||||
|
return ( |
||||||
|
<ScDate> |
||||||
|
<ScDateMonth> |
||||||
|
{month} |
||||||
|
</ScDateMonth> |
||||||
|
{hour} |
||||||
|
</ScDate> |
||||||
|
) |
||||||
|
} |
||||||
@ -0,0 +1,10 @@ |
|||||||
|
import styled from 'styled-components' |
||||||
|
|
||||||
|
export const ScDate = styled.div` |
||||||
|
font-size: 10px; |
||||||
|
color: rgba(255, 255, 255, 0.7); |
||||||
|
` |
||||||
|
|
||||||
|
export const ScDateMonth = styled.span` |
||||||
|
font-weight: 600; |
||||||
|
` |
||||||
@ -0,0 +1,73 @@ |
|||||||
|
import { useCallback } from 'react' |
||||||
|
|
||||||
|
import { ProfileTypes } from 'config' |
||||||
|
|
||||||
|
import { getName } from 'features/Name' |
||||||
|
import { useMatchSwitchesStore } from 'features/MatchSwitches' |
||||||
|
import { useLexicsStore } from 'features/LexicsStore' |
||||||
|
|
||||||
|
import { usePageParams } from 'hooks/usePageParams' |
||||||
|
|
||||||
|
import { MatchInfo, Team } from 'requests' |
||||||
|
|
||||||
|
import { |
||||||
|
Score, |
||||||
|
ScoreWrapper, |
||||||
|
StyledLink, |
||||||
|
ScTeam, |
||||||
|
Wrapper, |
||||||
|
} from './styled' |
||||||
|
|
||||||
|
type Props = { |
||||||
|
profile: MatchInfo, |
||||||
|
teamNameLimit?: number, |
||||||
|
} |
||||||
|
|
||||||
|
export const TeamsDetails = ({ profile, teamNameLimit }: Props) => { |
||||||
|
const { sportType } = usePageParams() |
||||||
|
const { isScoreHidden } = useMatchSwitchesStore() |
||||||
|
const { suffix } = useLexicsStore() |
||||||
|
|
||||||
|
const { |
||||||
|
team1, |
||||||
|
team2, |
||||||
|
} = { ...profile! } |
||||||
|
|
||||||
|
const getTeamName = useCallback((team: Team) => { |
||||||
|
let name = getName({ nameObj: team, suffix }) |
||||||
|
if (!!teamNameLimit && name.length > teamNameLimit) name = name.substring(0, teamNameLimit).concat('...') |
||||||
|
return name |
||||||
|
}, [suffix, teamNameLimit]) |
||||||
|
|
||||||
|
return ( |
||||||
|
<Wrapper> |
||||||
|
<ScTeam> |
||||||
|
<StyledLink |
||||||
|
id={team1.id} |
||||||
|
profileType={ProfileTypes.TEAMS} |
||||||
|
sportType={sportType} |
||||||
|
> |
||||||
|
{getTeamName(team1)} |
||||||
|
</StyledLink> |
||||||
|
</ScTeam> |
||||||
|
<ScoreWrapper> |
||||||
|
<Score> |
||||||
|
{ |
||||||
|
isScoreHidden |
||||||
|
? '-' |
||||||
|
: `${team1.score} - ${team2.score}` |
||||||
|
} |
||||||
|
</Score> |
||||||
|
</ScoreWrapper> |
||||||
|
<ScTeam> |
||||||
|
<StyledLink |
||||||
|
id={team2.id} |
||||||
|
profileType={ProfileTypes.TEAMS} |
||||||
|
sportType={sportType} |
||||||
|
> |
||||||
|
{getTeamName(team2)} |
||||||
|
</StyledLink> |
||||||
|
</ScTeam> |
||||||
|
</Wrapper> |
||||||
|
) |
||||||
|
} |
||||||
@ -0,0 +1,70 @@ |
|||||||
|
import styled, { css } from 'styled-components' |
||||||
|
|
||||||
|
import { isMobileDevice } from 'config/userAgent' |
||||||
|
|
||||||
|
import { ProfileLink } from 'features/ProfileLink' |
||||||
|
import { ProfileLogo } from 'features/ProfileLogo' |
||||||
|
|
||||||
|
export const Wrapper = styled.div` |
||||||
|
display: flex; |
||||||
|
font-weight: 600; |
||||||
|
margin-bottom: 5px; |
||||||
|
` |
||||||
|
|
||||||
|
export const ScTeam = styled.div` |
||||||
|
font-size: 21px; |
||||||
|
|
||||||
|
${isMobileDevice |
||||||
|
? css` |
||||||
|
font-size: 16px; |
||||||
|
` |
||||||
|
: ''}; |
||||||
|
` |
||||||
|
|
||||||
|
export const StyledLink = styled(ProfileLink)` |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
color: white; |
||||||
|
font-size: 14px; |
||||||
|
|
||||||
|
&:hover { |
||||||
|
text-decoration: underline; |
||||||
|
} |
||||||
|
` |
||||||
|
|
||||||
|
export const ScoreWrapper = styled.div` |
||||||
|
margin: 0 10px; |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
align-items: center; |
||||||
|
` |
||||||
|
|
||||||
|
export const Score = styled.span` |
||||||
|
font-size: 14px; |
||||||
|
white-space: nowrap; |
||||||
|
` |
||||||
|
|
||||||
|
export const MatchStatus = styled.span` |
||||||
|
text-align: center; |
||||||
|
background-color: #CC0000; |
||||||
|
border-radius: 1.3px; |
||||||
|
font-weight: 600; |
||||||
|
font-size: 13px; |
||||||
|
line-height: 16px; |
||||||
|
letter-spacing: 0.05em; |
||||||
|
text-transform: uppercase; |
||||||
|
padding: 2.5px 14px; |
||||||
|
margin-top: 6px; |
||||||
|
` |
||||||
|
|
||||||
|
export const Logo = styled(ProfileLogo)` |
||||||
|
width: 41px; |
||||||
|
height: 41px; |
||||||
|
margin: 0 9px; |
||||||
|
${isMobileDevice |
||||||
|
? css` |
||||||
|
width: 30px; |
||||||
|
height: 30px; |
||||||
|
` |
||||||
|
: ''}; |
||||||
|
` |
||||||
@ -0,0 +1,28 @@ |
|||||||
|
import { MatchInfo } from 'requests' |
||||||
|
import { TournamentSubtitle } from 'features/TournamentSubtitle' |
||||||
|
|
||||||
|
import { Wrapper, WrapperTop } from './styled' |
||||||
|
|
||||||
|
import { TeamsDetails } from './components/TeamsDetails' |
||||||
|
import { MatchDate } from './components/MatchDate' |
||||||
|
import { useMatchPageStore } from '../../store' |
||||||
|
|
||||||
|
type Props = { |
||||||
|
profile: MatchInfo, |
||||||
|
} |
||||||
|
|
||||||
|
export const MatchProfileCardMobile = ({ profile }: Props) => { |
||||||
|
const { profileCardShown } = useMatchPageStore() |
||||||
|
|
||||||
|
if (!profile) return null |
||||||
|
|
||||||
|
return ( |
||||||
|
<Wrapper isHidden={!profileCardShown}> |
||||||
|
<WrapperTop> |
||||||
|
<TeamsDetails profile={profile} teamNameLimit={14} /> |
||||||
|
<MatchDate profile={profile} /> |
||||||
|
</WrapperTop> |
||||||
|
<TournamentSubtitle countryId={profile!.country_id} tournament={profile!.tournament} /> |
||||||
|
</Wrapper> |
||||||
|
) |
||||||
|
} |
||||||
@ -0,0 +1,19 @@ |
|||||||
|
import styled, { css } from 'styled-components/macro' |
||||||
|
|
||||||
|
export const Wrapper = styled.div<{isHidden?: boolean}>` |
||||||
|
transition: 0.3s linear;
|
||||||
|
padding: 0 5px; |
||||||
|
color: white; |
||||||
|
margin-bottom: 15px; |
||||||
|
|
||||||
|
${({ isHidden }) => (isHidden ? css` |
||||||
|
height: 0; |
||||||
|
opacity: 0; |
||||||
|
margin-bottom: 0; |
||||||
|
` : '')}
|
||||||
|
` |
||||||
|
|
||||||
|
export const WrapperTop = styled.div` |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
` |
||||||
@ -0,0 +1,15 @@ |
|||||||
|
import { useToggle } from 'hooks' |
||||||
|
|
||||||
|
export const useMatchPage = () => { |
||||||
|
const { |
||||||
|
close: hideProfileCard, |
||||||
|
isOpen: profileCardShown, |
||||||
|
open: showProfileCard, |
||||||
|
} = useToggle(true) |
||||||
|
|
||||||
|
return { |
||||||
|
hideProfileCard, |
||||||
|
profileCardShown, |
||||||
|
showProfileCard, |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,20 @@ |
|||||||
|
import type { ReactNode } from 'react' |
||||||
|
import { createContext, useContext } from 'react' |
||||||
|
|
||||||
|
import { useMatchPage } from '../hooks' |
||||||
|
|
||||||
|
type Context = ReturnType<typeof useMatchPage> |
||||||
|
type Props = { children: ReactNode } |
||||||
|
|
||||||
|
const MatchPageContext = createContext({} as Context) |
||||||
|
|
||||||
|
export const MatchPageStore = ({ children }: Props) => { |
||||||
|
const value = useMatchPage() |
||||||
|
return ( |
||||||
|
<MatchPageContext.Provider value={value}> |
||||||
|
{children} |
||||||
|
</MatchPageContext.Provider> |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
export const useMatchPageStore = () => useContext(MatchPageContext) |
||||||
@ -1,7 +1,14 @@ |
|||||||
import styled from 'styled-components/macro' |
import styled, { css } from 'styled-components/macro' |
||||||
|
import { isMobileDevice } from '../../../../config/userAgent' |
||||||
|
|
||||||
export const ProgressBarList = styled.div` |
export const ProgressBarList = styled.div` |
||||||
flex-grow: 1; |
flex-grow: 1; |
||||||
height: 4px; |
height: 4px; |
||||||
position: relative; |
position: relative; |
||||||
|
|
||||||
|
${isMobileDevice |
||||||
|
? css` |
||||||
|
height: 1px; |
||||||
|
` |
||||||
|
: ''} |
||||||
` |
` |
||||||
|
|||||||
@ -0,0 +1,61 @@ |
|||||||
|
import { T9n } from 'features/T9n' |
||||||
|
import { Settings } from 'features/MultiSourcePlayer/components/Settings' |
||||||
|
|
||||||
|
import { ControlsPropsExtended } from '../..' |
||||||
|
import { LiveBtn } from '../../../../styled' |
||||||
|
import { |
||||||
|
Controls, |
||||||
|
ControlsGroup, |
||||||
|
ControlsRow, |
||||||
|
Fullscreen, |
||||||
|
PlaybackTime, |
||||||
|
} from './styled' |
||||||
|
|
||||||
|
export const ControlsMobile = (controlsProps: {props: ControlsPropsExtended}) => { |
||||||
|
const { props } = controlsProps |
||||||
|
|
||||||
|
const { |
||||||
|
backToLive, |
||||||
|
controlsVisible, |
||||||
|
isFullscreen, |
||||||
|
isLive, |
||||||
|
onFullscreenClick, |
||||||
|
onQualitySelect, |
||||||
|
playBackTime, |
||||||
|
progressBarElement, |
||||||
|
selectedQuality, |
||||||
|
videoQualities, |
||||||
|
} = props |
||||||
|
|
||||||
|
return ( |
||||||
|
<Controls isFullscreen={isFullscreen}> |
||||||
|
<ControlsRow visible={controlsVisible}> |
||||||
|
<ControlsGroup> |
||||||
|
<PlaybackTime> |
||||||
|
{playBackTime} |
||||||
|
</PlaybackTime> |
||||||
|
</ControlsGroup> |
||||||
|
|
||||||
|
<ControlsGroup> |
||||||
|
{isLive && ( |
||||||
|
<LiveBtn onClick={backToLive}> |
||||||
|
<T9n t='live' /> |
||||||
|
</LiveBtn> |
||||||
|
)} |
||||||
|
<Settings |
||||||
|
onSelect={onQualitySelect} |
||||||
|
selectedQuality={selectedQuality} |
||||||
|
videoQualities={videoQualities} |
||||||
|
/> |
||||||
|
<Fullscreen |
||||||
|
onClick={onFullscreenClick} |
||||||
|
isFullscreen={isFullscreen} |
||||||
|
/> |
||||||
|
</ControlsGroup> |
||||||
|
</ControlsRow> |
||||||
|
<ControlsRow visible> |
||||||
|
{progressBarElement} |
||||||
|
</ControlsRow> |
||||||
|
</Controls> |
||||||
|
) |
||||||
|
} |
||||||
@ -0,0 +1,74 @@ |
|||||||
|
import styled from 'styled-components' |
||||||
|
|
||||||
|
import { ButtonBase, hoverStyles } from '../../../../styled' |
||||||
|
|
||||||
|
type FullscreenProps = { |
||||||
|
isFullscreen: boolean, |
||||||
|
} |
||||||
|
|
||||||
|
export const Controls = styled.div<FullscreenProps>` |
||||||
|
z-index: 50; |
||||||
|
position: absolute; |
||||||
|
width: 100%; |
||||||
|
bottom: 22px; |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
align-items: center; |
||||||
|
filter: drop-shadow(0px 4px 4px rgba(0, 0, 0, 0.25)); |
||||||
|
bottom: 0; |
||||||
|
|
||||||
|
@media (orientation: landscape){ |
||||||
|
bottom: ${({ isFullscreen }) => (isFullscreen ? '20px' : 0)}; |
||||||
|
width: 100%; |
||||||
|
left: 50%; |
||||||
|
transform: translateX(-50%); |
||||||
|
} |
||||||
|
` |
||||||
|
|
||||||
|
export const ControlsRow = styled.div` |
||||||
|
width: 100%; |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
|
||||||
|
${hoverStyles} |
||||||
|
|
||||||
|
justify-content: flex-start; |
||||||
|
|
||||||
|
:first-child { |
||||||
|
margin-bottom: 15px; |
||||||
|
padding: 0 15px; |
||||||
|
} |
||||||
|
|
||||||
|
:last-child { |
||||||
|
padding-left: 0; |
||||||
|
padding-right: 0; |
||||||
|
} |
||||||
|
` |
||||||
|
|
||||||
|
export const ControlsGroup = styled.div` |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
|
||||||
|
:last-child { |
||||||
|
margin-left: auto; |
||||||
|
} |
||||||
|
` |
||||||
|
|
||||||
|
export const Fullscreen = styled(ButtonBase)<FullscreenProps>` |
||||||
|
width: 20px; |
||||||
|
height: 18px; |
||||||
|
margin-left: 15px; |
||||||
|
background-image: ${({ isFullscreen }) => ( |
||||||
|
isFullscreen |
||||||
|
? 'url(/images/player-fullscreen-off.svg)' |
||||||
|
: 'url(/images/player-fullscreen-on.svg)' |
||||||
|
)}; |
||||||
|
` |
||||||
|
|
||||||
|
export const PlaybackTime = styled.span` |
||||||
|
font-weight: 700; |
||||||
|
color: #fff; |
||||||
|
font-size: 12px; |
||||||
|
width: 100px; |
||||||
|
white-space: nowrap; |
||||||
|
` |
||||||
@ -0,0 +1,114 @@ |
|||||||
|
import { Fragment } from 'react' |
||||||
|
|
||||||
|
import { REWIND_SECONDS } from 'features/MultiSourcePlayer/config' |
||||||
|
import { |
||||||
|
ChaptersText, |
||||||
|
Next, |
||||||
|
Prev, |
||||||
|
} from 'features/MultiSourcePlayer/styled' |
||||||
|
import { Settings } from 'features/MultiSourcePlayer/components/Settings' |
||||||
|
import { T9n } from 'features/T9n' |
||||||
|
|
||||||
|
import { ControlsPropsExtended } from '../..' |
||||||
|
import { VolumeBar } from '../../../VolumeBar' |
||||||
|
import { |
||||||
|
Backward, |
||||||
|
Controls, |
||||||
|
ControlsGroup, |
||||||
|
ControlsRow, |
||||||
|
Forward, |
||||||
|
Fullscreen, |
||||||
|
LiveBtn, |
||||||
|
PlaybackTime, |
||||||
|
PlayStop, |
||||||
|
} from '../../../../styled' |
||||||
|
|
||||||
|
export const ControlsWeb = (controlsProps: { props: ControlsPropsExtended }) => { |
||||||
|
const { props } = controlsProps |
||||||
|
const { |
||||||
|
activeChapterIndex = 0, |
||||||
|
backToLive, |
||||||
|
controlsVisible, |
||||||
|
isFirstChapterPlaying, |
||||||
|
isFullscreen, |
||||||
|
isLastChapterPlaying, |
||||||
|
isLive, |
||||||
|
isStorage, |
||||||
|
muted, |
||||||
|
numberOfChapters = 0, |
||||||
|
onFullscreenClick, |
||||||
|
onQualitySelect, |
||||||
|
onVolumeChange, |
||||||
|
onVolumeClick, |
||||||
|
playBackTime, |
||||||
|
playing, |
||||||
|
playNextChapter, |
||||||
|
playPrevChapter, |
||||||
|
progressBarElement, |
||||||
|
rewindBackward, |
||||||
|
rewindForward, |
||||||
|
selectedQuality, |
||||||
|
togglePlaying, |
||||||
|
videoQualities, |
||||||
|
volumeInPercent, |
||||||
|
} = props |
||||||
|
|
||||||
|
return ( |
||||||
|
<Controls visible={controlsVisible}> |
||||||
|
<ControlsRow> |
||||||
|
{progressBarElement} |
||||||
|
</ControlsRow> |
||||||
|
<ControlsRow> |
||||||
|
<ControlsGroup> |
||||||
|
<PlayStop |
||||||
|
playing={playing} |
||||||
|
onClickCapture={togglePlaying} |
||||||
|
/> |
||||||
|
{!isLive && !isStorage && ( |
||||||
|
<Fragment> |
||||||
|
<Prev |
||||||
|
disabled={isFirstChapterPlaying} |
||||||
|
onClick={() => playPrevChapter?.()} |
||||||
|
/> |
||||||
|
<ChaptersText> |
||||||
|
{activeChapterIndex + 1} / {numberOfChapters} |
||||||
|
</ChaptersText> |
||||||
|
<Next |
||||||
|
disabled={isLastChapterPlaying} |
||||||
|
onClick={() => playNextChapter?.()} |
||||||
|
/> |
||||||
|
</Fragment> |
||||||
|
)} |
||||||
|
<VolumeBar |
||||||
|
value={volumeInPercent} |
||||||
|
muted={muted} |
||||||
|
onChange={onVolumeChange} |
||||||
|
onClick={onVolumeClick} |
||||||
|
/> |
||||||
|
<PlaybackTime> |
||||||
|
{playBackTime} |
||||||
|
</PlaybackTime> |
||||||
|
<Backward onClick={rewindBackward}>{REWIND_SECONDS}</Backward> |
||||||
|
<Forward onClick={rewindForward}>{REWIND_SECONDS}</Forward> |
||||||
|
</ControlsGroup> |
||||||
|
|
||||||
|
<ControlsGroup> |
||||||
|
{isLive && ( |
||||||
|
<LiveBtn onClick={backToLive}> |
||||||
|
<T9n t='live' /> |
||||||
|
</LiveBtn> |
||||||
|
)} |
||||||
|
<Settings |
||||||
|
onSelect={onQualitySelect} |
||||||
|
selectedQuality={selectedQuality} |
||||||
|
videoQualities={videoQualities} |
||||||
|
/> |
||||||
|
<Fullscreen |
||||||
|
onClick={onFullscreenClick} |
||||||
|
isFullscreen={isFullscreen} |
||||||
|
/> |
||||||
|
</ControlsGroup> |
||||||
|
</ControlsRow> |
||||||
|
</Controls> |
||||||
|
) |
||||||
|
} |
||||||
@ -0,0 +1,143 @@ |
|||||||
|
import { Fragment, useMemo } from 'react' |
||||||
|
|
||||||
|
import { DebouncedFunc } from 'lodash' |
||||||
|
|
||||||
|
import { isMobileDevice } from 'config/userAgent' |
||||||
|
|
||||||
|
import { secondsToHms } from 'helpers/secondsToHms' |
||||||
|
|
||||||
|
import { ProgressBar as ProgressBarMultiSource } from 'features/MultiSourcePlayer/components/ProgressBar' |
||||||
|
import { Chapters } from 'features/MultiSourcePlayer/types' |
||||||
|
|
||||||
|
import { ControlsMobile } from './Components/ControlsMobile' |
||||||
|
import { ControlsWeb } from './Components/ControlsWeb' |
||||||
|
import { ProgressBar } from '../ProgressBar' |
||||||
|
|
||||||
|
export type ControlsProps = { |
||||||
|
activeChapterIndex?: number, |
||||||
|
allPlayedProgress?: number, |
||||||
|
backToLive?: () => void, |
||||||
|
chapters?: Chapters, |
||||||
|
controlsVisible: boolean, |
||||||
|
duration: number, |
||||||
|
isFirstChapterPlaying?: boolean, |
||||||
|
isFullscreen: boolean, |
||||||
|
isLastChapterPlaying?: boolean, |
||||||
|
isLive?: boolean, |
||||||
|
isStorage?: boolean, |
||||||
|
loadedProgress: number, |
||||||
|
muted: boolean, |
||||||
|
numberOfChapters?: number, |
||||||
|
onFullscreenClick: () => void, |
||||||
|
onProgressChange?: (progress: number, seeking: boolean) => void, |
||||||
|
onProgressChangeLive?: (progress: number) => void, |
||||||
|
onQualitySelect: (quality: string) => void, |
||||||
|
onTouchEnd: DebouncedFunc<() => void>, |
||||||
|
onTouchStart: () => void, |
||||||
|
onVolumeChange: (value: number) => void, |
||||||
|
onVolumeClick: () => void, |
||||||
|
playNextChapter?: (fromMs?: number | undefined, startOffsetMs?: number | undefined) => void, |
||||||
|
playPrevChapter?: (fromMs?: number | undefined, startOffsetMs?: number | undefined) => void, |
||||||
|
playedProgress: number, |
||||||
|
playing: boolean, |
||||||
|
rewindBackward: () => void, |
||||||
|
rewindForward: () => void, |
||||||
|
selectedQuality: string, |
||||||
|
togglePlaying: () => void, |
||||||
|
videoQualities: Array<string>, |
||||||
|
volume: number, |
||||||
|
volumeInPercent: number, |
||||||
|
} |
||||||
|
|
||||||
|
export type ControlsPropsExtended = ControlsProps & { |
||||||
|
playBackTime: string, |
||||||
|
progressBarElement: JSX.Element, |
||||||
|
} |
||||||
|
|
||||||
|
export const Controls = (props: ControlsProps) => { |
||||||
|
const { |
||||||
|
activeChapterIndex = 0, |
||||||
|
allPlayedProgress = 0, |
||||||
|
chapters, |
||||||
|
controlsVisible, |
||||||
|
duration, |
||||||
|
isLive, |
||||||
|
isStorage, |
||||||
|
loadedProgress, |
||||||
|
onProgressChange, |
||||||
|
onProgressChangeLive, |
||||||
|
onTouchEnd, |
||||||
|
onTouchStart, |
||||||
|
playedProgress, |
||||||
|
} = { ...props } |
||||||
|
|
||||||
|
const playBackTime = useMemo(() => { |
||||||
|
if (isLive || isStorage) { |
||||||
|
return secondsToHms(allPlayedProgress / 1000) |
||||||
|
} |
||||||
|
return `${secondsToHms(allPlayedProgress / 1000)} |
||||||
|
${' / '} |
||||||
|
${secondsToHms(duration / 1000)}` |
||||||
|
}, [ |
||||||
|
allPlayedProgress, |
||||||
|
duration, |
||||||
|
isLive, |
||||||
|
isStorage, |
||||||
|
]) |
||||||
|
|
||||||
|
const progressBarElement = useMemo(() => { |
||||||
|
if (isLive || isStorage) { |
||||||
|
return ( |
||||||
|
<ProgressBar |
||||||
|
duration={duration} |
||||||
|
isScrubberVisible={controlsVisible} |
||||||
|
onPlayedProgressChange={onProgressChangeLive!} |
||||||
|
playedProgress={playedProgress} |
||||||
|
loadedProgress={loadedProgress} |
||||||
|
/> |
||||||
|
) |
||||||
|
} |
||||||
|
return ( |
||||||
|
<ProgressBarMultiSource |
||||||
|
activeChapterIndex={activeChapterIndex} |
||||||
|
allPlayedProgress={allPlayedProgress} |
||||||
|
chapters={chapters} |
||||||
|
duration={duration} |
||||||
|
isScrubberVisible={controlsVisible} |
||||||
|
onTouchEnd={onTouchEnd} |
||||||
|
onTouchStart={onTouchStart} |
||||||
|
onPlayedProgressChange={onProgressChange!} |
||||||
|
playedProgress={playedProgress} |
||||||
|
loadedProgress={loadedProgress} |
||||||
|
/> |
||||||
|
) |
||||||
|
}, [ |
||||||
|
activeChapterIndex, |
||||||
|
allPlayedProgress, |
||||||
|
chapters, |
||||||
|
controlsVisible, |
||||||
|
duration, |
||||||
|
isLive, |
||||||
|
isStorage, |
||||||
|
loadedProgress, |
||||||
|
onProgressChange, |
||||||
|
onProgressChangeLive, |
||||||
|
onTouchEnd, |
||||||
|
onTouchStart, |
||||||
|
playedProgress, |
||||||
|
]) |
||||||
|
|
||||||
|
const controlsPropsExtended: ControlsPropsExtended = { |
||||||
|
...props, |
||||||
|
playBackTime, |
||||||
|
progressBarElement, |
||||||
|
} |
||||||
|
|
||||||
|
return ( |
||||||
|
<Fragment> |
||||||
|
{isMobileDevice |
||||||
|
? <ControlsMobile props={controlsPropsExtended} /> |
||||||
|
: <ControlsWeb props={controlsPropsExtended} />} |
||||||
|
</Fragment> |
||||||
|
) |
||||||
|
} |
||||||
@ -0,0 +1,50 @@ |
|||||||
|
import { SportIcon } from 'components/SportIcon/SportIcon' |
||||||
|
|
||||||
|
import { useName } from 'features/Name' |
||||||
|
import { useUserFavoritesStore } from 'features/UserFavorites/store' |
||||||
|
|
||||||
|
import { ProfileTypes, SportTypes } from 'config' |
||||||
|
|
||||||
|
import { usePageParams } from 'hooks/usePageParams' |
||||||
|
|
||||||
|
import { TournamentType } from 'requests' |
||||||
|
|
||||||
|
import { |
||||||
|
CountryFlag, |
||||||
|
FavoriteSign, |
||||||
|
NameSignWrapper, |
||||||
|
Wrapper, |
||||||
|
TournamentName, |
||||||
|
} from './styled' |
||||||
|
|
||||||
|
type Props = { |
||||||
|
countryId: number, |
||||||
|
sportType?: SportTypes, |
||||||
|
tournament: TournamentType, |
||||||
|
} |
||||||
|
|
||||||
|
export const TournamentSubtitle = ({ |
||||||
|
countryId, |
||||||
|
sportType, |
||||||
|
tournament, |
||||||
|
}: Props) => { |
||||||
|
const { isInFavorites } = useUserFavoritesStore() |
||||||
|
const { sportType: sportTypeFromUrl } = usePageParams() |
||||||
|
const tournamentName = useName(tournament) |
||||||
|
const tournamentInFavorites = isInFavorites(ProfileTypes.TOURNAMENTS, tournament.id) |
||||||
|
|
||||||
|
return ( |
||||||
|
<Wrapper> |
||||||
|
<SportIcon sport={sportType ?? sportTypeFromUrl} /> |
||||||
|
<CountryFlag src={`https://instatscout.com/images/flags/48/${countryId}.png`} /> |
||||||
|
{tournament && ( |
||||||
|
<NameSignWrapper> |
||||||
|
<TournamentName title={tournamentName}> |
||||||
|
{tournamentName} |
||||||
|
</TournamentName> |
||||||
|
{tournamentInFavorites && <FavoriteSign marginLeft={12} />} |
||||||
|
</NameSignWrapper> |
||||||
|
)} |
||||||
|
</Wrapper> |
||||||
|
) |
||||||
|
} |
||||||
@ -0,0 +1,70 @@ |
|||||||
|
import styled, { css } from 'styled-components' |
||||||
|
|
||||||
|
import { isMobileDevice } from 'config/userAgent' |
||||||
|
|
||||||
|
export const Wrapper = styled.div` |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
` |
||||||
|
|
||||||
|
export const CountryFlag = styled.img` |
||||||
|
width: 0.71rem; |
||||||
|
height: 0.75rem; |
||||||
|
margin-left: 0.567rem; |
||||||
|
object-fit: contain; |
||||||
|
object-position: bottom; |
||||||
|
${isMobileDevice |
||||||
|
? css` |
||||||
|
width: 12px; |
||||||
|
height: 8px; |
||||||
|
margin-left: 3.5px; |
||||||
|
` |
||||||
|
: ''}; |
||||||
|
` |
||||||
|
|
||||||
|
export const NameSignWrapper = styled.div` |
||||||
|
display: flex; |
||||||
|
max-width: 90%; |
||||||
|
align-items: center; |
||||||
|
` |
||||||
|
|
||||||
|
const nameStyles = css` |
||||||
|
text-overflow: ellipsis; |
||||||
|
white-space: nowrap; |
||||||
|
overflow: hidden; |
||||||
|
` |
||||||
|
|
||||||
|
export const TournamentName = styled.span` |
||||||
|
max-width: 95%; |
||||||
|
color: rgba(255, 255, 255, 0.7); |
||||||
|
font-size: 0.567rem; |
||||||
|
line-height: 0.95rem; |
||||||
|
margin-left: 0.567rem; |
||||||
|
${isMobileDevice |
||||||
|
? css` |
||||||
|
font-size: 10px; |
||||||
|
line-height: 100%; |
||||||
|
max-width: 100%; |
||||||
|
` |
||||||
|
: ''}; |
||||||
|
|
||||||
|
${nameStyles} |
||||||
|
` |
||||||
|
|
||||||
|
type FavoriteSignProps = { |
||||||
|
marginLeft?: number, |
||||||
|
} |
||||||
|
|
||||||
|
export const FavoriteSign = styled.span<FavoriteSignProps>` |
||||||
|
display: inline-block; |
||||||
|
width: 0.472rem; |
||||||
|
height: 0.472rem; |
||||||
|
margin-left: ${({ marginLeft = 9 }) => marginLeft}px; |
||||||
|
background: url('/images/sportFavStar.png') no-repeat center / 100% 100%; |
||||||
|
${isMobileDevice |
||||||
|
? css` |
||||||
|
width: 10px; |
||||||
|
height: 10px; |
||||||
|
` |
||||||
|
: ''}; |
||||||
|
` |
||||||
Loading…
Reference in new issue