fix(#2399): redesign match profile page for mobile version

keep-around/f8f8ce5f5085edde7169b2bf4c778be264fcc9b4
Rakov Roman 4 years ago
parent e304a42e1e
commit 234fde38bb
  1. 5
      src/config/clients/facr.tsx
  2. 4
      src/config/clients/instat.tsx
  3. 5
      src/config/clients/lff.tsx
  4. 1
      src/config/clients/types.tsx
  5. 7
      src/features/Common/Tabs/index.tsx
  6. 24
      src/features/MatchCard/CardFrontside/index.tsx
  7. 37
      src/features/MatchCard/styled.tsx
  8. 5
      src/features/MatchPage/components/FinishedMatch/index.tsx
  9. 4
      src/features/MatchPage/components/LiveMatch/index.tsx
  10. 34
      src/features/MatchPage/components/MatchProfileCardMobile/components/MatchDate/index.tsx
  11. 10
      src/features/MatchPage/components/MatchProfileCardMobile/components/MatchDate/styled.tsx
  12. 73
      src/features/MatchPage/components/MatchProfileCardMobile/components/TeamsDetails/index.tsx
  13. 70
      src/features/MatchPage/components/MatchProfileCardMobile/components/TeamsDetails/styled.tsx
  14. 28
      src/features/MatchPage/components/MatchProfileCardMobile/index.tsx
  15. 19
      src/features/MatchPage/components/MatchProfileCardMobile/styled.tsx
  16. 15
      src/features/MatchPage/hooks/index.tsx
  17. 58
      src/features/MatchPage/index.tsx
  18. 20
      src/features/MatchPage/store/index.tsx
  19. 5
      src/features/MatchPage/styled.tsx
  20. 16
      src/features/MatchSidePlaylists/components/TabEvents/styled.tsx
  21. 43
      src/features/MatchSidePlaylists/index.tsx
  22. 40
      src/features/MatchSidePlaylists/styled.tsx
  23. 9
      src/features/Menu/styled.tsx
  24. 15
      src/features/MultiSourcePlayer/components/ProgressBar/index.tsx
  25. 9
      src/features/MultiSourcePlayer/components/ProgressBar/styled.tsx
  26. 3
      src/features/MultiSourcePlayer/hooks/index.tsx
  27. 138
      src/features/MultiSourcePlayer/index.tsx
  28. 3
      src/features/ProfileHeader/index.tsx
  29. 27
      src/features/ProfileHeader/styled.tsx
  30. 2
      src/features/Search/styled.tsx
  31. 61
      src/features/StreamPlayer/components/Controls/Components/ControlsMobile/index.tsx
  32. 74
      src/features/StreamPlayer/components/Controls/Components/ControlsMobile/styled.tsx
  33. 114
      src/features/StreamPlayer/components/Controls/Components/ControlsWeb/index.tsx
  34. 143
      src/features/StreamPlayer/components/Controls/index.tsx
  35. 10
      src/features/StreamPlayer/components/ProgressBar/index.tsx
  36. 28
      src/features/StreamPlayer/components/ProgressBar/styled.tsx
  37. 10
      src/features/StreamPlayer/components/TimeTooltip/styled.tsx
  38. 102
      src/features/StreamPlayer/index.tsx
  39. 54
      src/features/StreamPlayer/styled.tsx
  40. 50
      src/features/TournamentSubtitle/index.tsx
  41. 70
      src/features/TournamentSubtitle/styled.tsx

@ -46,6 +46,11 @@ export const facr: ClientConfig = {
matchLogoHeight: 2.6,
matchLogoTopMargin: 0.9,
matchLogoWidth: 3.4,
matchPageMobileHeaderLogo: css`
width: 35px;
height: 25px;
top: 2px;
`,
mobileHeaderLogo: css`
width: 48px;
height: 37px;

@ -24,6 +24,10 @@ export const instat: ClientConfig = {
logoWidth: 6.37,
matchLogoHeight: 1.465,
matchLogoWidth: 6.37,
matchPageMobileHeaderLogo: css`
width: 65px;
height: 15px;
`,
mobileHeaderLogo: css`
width: 84px;
height: 20px;

@ -27,6 +27,11 @@ export const lff: ClientConfig = {
logoWidth: 6,
matchLogoHeight: 2.5,
matchLogoWidth: 2.5,
matchPageMobileHeaderLogo: css`
width: 24px;
height: 24px;
top: 0;
`,
mobileHeaderLogo: css`
width: 42px;
height: 42px;

@ -39,6 +39,7 @@ export type ClientConfig = {
matchLogoHeight?: number,
matchLogoTopMargin?: number,
matchLogoWidth?: number,
matchPageMobileHeaderLogo?: StyledCss,
mobileHeaderLogo?: StyledCss,
userAccountLogo?: StyledCss,
},

@ -68,10 +68,7 @@ export const Tab = styled.button.attrs(({ selected }: TabProps) => ({
}
${isMobileDevice
? css`
font-size: 10px;
@media (orientation: landscape){
font-size: 9px;
}
font-size: 14px;
`
: ''};
@ -98,7 +95,7 @@ export const TabsGroup = styled.div.attrs({
${isMobileDevice
? css`
height: 28px;
height: 32px;
`
: ''};
`

@ -6,12 +6,12 @@ import getUnixTime from 'date-fns/getUnixTime'
import { ProfileTypes, PAGES } from 'config'
import type { Match } from 'features/Matches'
import { SportIcon } from 'components/SportIcon/SportIcon'
import { useMatchSwitchesStore } from 'features/MatchSwitches'
import { useName } from 'features/Name'
import { T9n } from 'features/T9n'
import { MatchAccess } from 'features/Matches/helpers/getMatchClickAction'
import { useUserFavoritesStore } from 'features/UserFavorites/store'
import { TournamentSubtitle } from 'features/TournamentSubtitle'
import { NoAccessMessage } from '../NoAccessMessage'
import {
@ -28,12 +28,9 @@ import {
TeamName,
Teams,
Time,
TournamentName,
TeamLogos,
TeamLogo,
BuyMatchBadge,
CountryFlag,
SecondaryInfo,
FavoriteSign,
NameSignWrapper,
HoverFrame,
@ -57,6 +54,7 @@ export const CardFrontside = ({
const location = useLocation()
const {
access,
countryId,
date,
formattedDate,
live,
@ -78,7 +76,6 @@ export const CardFrontside = ({
isInFuture
|| isScoreHidden
) || (live && !isScoreHidden)
const tournamentInFavorites = isInFavorites(ProfileTypes.TOURNAMENTS, tournament.id)
const team1InFavorites = isInFavorites(ProfileTypes.TEAMS, team1.id)
const team2InFavorites = isInFavorites(ProfileTypes.TEAMS, team2.id)
@ -157,18 +154,11 @@ export const CardFrontside = ({
{showScore && <Score>{team2.score}</Score>}
</Team>
</Teams>
<SecondaryInfo>
<SportIcon sport={sportType} />
<CountryFlag src={`https://instatscout.com/images/flags/48/${match.countryId}.png`} />
{tournament && (
<NameSignWrapper>
<TournamentName title={tournamentName}>
{tournamentName}
</TournamentName>
{tournamentInFavorites && <FavoriteSign marginLeft={12} />}
</NameSignWrapper>
)}
</SecondaryInfo>
<TournamentSubtitle
sportType={sportType}
countryId={countryId}
tournament={tournament}
/>
</Info>
</CardWrapper>
</CardWrapperOuter>

@ -153,26 +153,6 @@ export const Info = styled.div`
: ''};
`
export const SecondaryInfo = 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;
`
: ''};
`
type FavoriteSignProps = {
marginLeft?: number,
}
@ -198,23 +178,6 @@ const nameStyles = css`
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}
`
export const Teams = styled.div`
margin-bottom: 0.567rem;
${isMobileDevice

@ -8,6 +8,8 @@ import type { MatchInfo } from 'requests/getMatchInfo'
import { MatchSidePlaylists } from 'features/MatchSidePlaylists'
import { MultiSourcePlayer } from 'features/MultiSourcePlayer'
import { isMobileDevice } from 'config/userAgent'
import { SettingsPopup } from '../SettingsPopup'
import { useFinishedMatch } from './hooks'
@ -15,6 +17,7 @@ import { Container } from '../../styled'
import { Modal } from './styled'
import { TournamentData } from '../../types'
import { MatchDescription } from '../MatchDescription'
import { MatchProfileCardMobile } from '../MatchProfileCardMobile'
type Props = {
events: Events,
@ -59,12 +62,14 @@ export const FinishedMatch = ({
<MultiSourcePlayer
chapters={chapters}
onPlayingChange={onPlayingChange}
profile={profile}
/>
<MatchDescription
profile={profile}
/>
</Fragment>
)}
{isMobileDevice ? <MatchProfileCardMobile profile={profile} /> : null}
</Container>
<MatchSidePlaylists

@ -7,10 +7,13 @@ import { StreamPlayer } from 'features/StreamPlayer'
import { YoutubePlayer } from 'features/StreamPlayer/components/YoutubePlayer'
import { MatchSidePlaylists } from 'features/MatchSidePlaylists'
import { isMobileDevice } from 'config/userAgent'
import { Container } from '../../styled'
import { useLiveMatch } from './hooks'
import { TournamentData } from '../../types'
import { MatchProfileCardMobile } from '../MatchProfileCardMobile'
type Props = {
events: Events,
@ -45,6 +48,7 @@ export const LiveMatch = ({
resumeFrom={resume}
url={streamUrl}
/>
{isMobileDevice ? <MatchProfileCardMobile profile={profile} /> : null}
</Container>
<MatchSidePlaylists

@ -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,
}
}

@ -11,6 +11,7 @@ import {
import { FavoritesActions } from 'requests'
import { ProfileTypes } from 'config'
import { isMobileDevice } from 'config/userAgent'
import { usePageLogger } from 'hooks/usePageLogger'
import { usePageParams } from 'hooks/usePageParams'
@ -21,6 +22,7 @@ import { FinishedMatch } from './components/FinishedMatch'
import { LiveMatch } from './components/LiveMatch'
import { useMatchProfile } from './hooks/useMatchProfile'
import { Wrapper } from './styled'
import { MatchPageStore } from './store'
const MatchPage = () => {
usePageLogger()
@ -70,32 +72,36 @@ const MatchPage = () => {
}
return (
<PageWrapper>
<ProfileHeader color='#2B2A28' height={4.5}>
<MatchProfileCard profile={profile} />
</ProfileHeader>
<Main>
<UserFavorites />
<SubscriptionGuard matchProfile={profile}>
<Wrapper>
{playFromOTT && (
<LiveMatch
events={events}
profile={profile}
tournamentData={tournamentData}
/>
)}
{playFromScout && (
<FinishedMatch
events={events}
profile={profile}
tournamentData={tournamentData}
/>
)}
</Wrapper>
</SubscriptionGuard>
</Main>
</PageWrapper>
<MatchPageStore>
<PageWrapper>
<ProfileHeader color='#2B2A28' height={4.5}>
{isMobileDevice ? null : <MatchProfileCard profile={profile} />}
</ProfileHeader>
<Main>
<UserFavorites />
<SubscriptionGuard matchProfile={profile}>
<Wrapper>
{playFromOTT && (
<LiveMatch
events={events}
profile={profile}
tournamentData={tournamentData}
/>
)}
{playFromScout && (
<FinishedMatch
events={events}
profile={profile}
tournamentData={tournamentData}
/>
)}
</Wrapper>
</SubscriptionGuard>
</Main>
</PageWrapper>
</MatchPageStore>
)
}

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

@ -17,11 +17,8 @@ export const Wrapper = styled.div`
${isMobileDevice
? css`
@media (max-width: 750px) {
/* padding-top: 50px; */
}
@media screen and (orientation: landscape) {
padding-top: 55px;
padding-top: 20px;
flex-direction: row;
justify-content: space-between;
margin-left: 10px;

@ -147,6 +147,16 @@ export const Tab = styled(TabBase)`
:first-child {
margin-right: 15px;
}
${isMobileDevice
? css`
font-size: 14px;
@media (orientation: portrait) {
width: 120px;
}
`
: ''}
`
export const LikeToggle = styled.img`
@ -156,6 +166,12 @@ export const LikeToggle = styled.img`
width: 15px;
height: 15px;
cursor: pointer;
${isMobileDevice
? css`
right: 20px;
`
: ''};
`
export const BlockTitle = styled(BlockTitleBase)`

@ -1,3 +1,5 @@
import { useRef } from 'react'
import type { Events, MatchInfo } from 'requests'
import type {
@ -8,12 +10,19 @@ import type {
import { Tab, TabsGroup } from 'features/Common'
import { T9n } from 'features/T9n'
import { useEventListener } from 'hooks'
import { useMatchPageStore } from 'features/MatchPage/store'
import { isIOS } from 'config/userAgent'
import { Tabs } from './config'
import { TabEvents } from './components/TabEvents'
import { TabWatch } from './components/TabWatch'
import { TabVideo } from './components/TabVideo'
import { useMatchSidePlaylists } from './hooks'
import {
BackToTopBtn,
Wrapper,
TabsWrapper,
Container,
@ -54,8 +63,33 @@ export const MatchSidePlaylists = ({
tournamentData,
})
const {
hideProfileCard,
profileCardShown,
showProfileCard,
} = useMatchPageStore()
const TabPane = tabPanes[selectedTab]
const containerRef = useRef<HTMLDivElement | null>(null)
useEventListener({
callback: () => {
const screenLandscape = isIOS ? window.orientation : window.screen.orientation.type
const yOffset = isIOS
? containerRef.current?.offsetTop
: containerRef.current?.scrollTop
const isScreenLandscape = isIOS
? (screenLandscape === 90 || screenLandscape === -90)
: (screenLandscape === 'landscape-primary' || screenLandscape === 'landscape-secondary')
if (yOffset && yOffset > 10 && !isScreenLandscape) hideProfileCard()
if (yOffset && yOffset < 10) showProfileCard()
},
event: isIOS ? 'touchmove' : 'scroll',
target: containerRef,
})
return (
<Wrapper>
<TabsWrapper>
@ -85,8 +119,15 @@ export const MatchSidePlaylists = ({
</Tab>
) : null}
</TabsGroup>
<BackToTopBtn
hidden={profileCardShown}
onClick={() => {
containerRef.current?.scrollTo(0, 0)
showProfileCard()
}}
/>
</TabsWrapper>
<Container forVideoTab={selectedTab === Tabs.VIDEO}>
<Container forVideoTab={selectedTab === Tabs.VIDEO} ref={containerRef}>
<TabPane
tournamentData={tournamentData}
events={events}

@ -21,6 +21,13 @@ ${isMobileDevice
export const TabsWrapper = styled.div`
padding-left: 14px;
padding-right: 18px;
position: relative;
${isMobileDevice
? css`
padding: 0 5px;
`
: ''};
`
type TContainer = {
@ -43,6 +50,9 @@ export const Container = styled.div<TContainer>`
${isMobileDevice
? css`
padding: 0 5px;
overflow-y: auto;
@media (max-width: 750px){
width: 100%;
}
@ -118,11 +128,6 @@ export const Title = styled.span`
overflow: hidden;
white-space: nowrap;
text-overflow:ellipsis;
@media ${devices.mobile} {
font-size: 16px;
padding-right: 5px;
}
`
export const BlockTitle = styled.span`
@ -133,3 +138,28 @@ export const BlockTitle = styled.span`
color: rgba(255, 255, 255, 0.5);
text-transform: uppercase;
`
export const BackToTopBtn = styled.div`
position: absolute;
left: 50%;
bottom: -100%;
background: rgba(0, 0, 0, 0.5);
border-radius: 0px 0 20px 20px;
width: 37px;
height: 34px;
z-index: 1;
cursor: pointer;
transform: translate(-50%, 6%);
:after {
content: '';
width: 10px;
height: 10px;
position: absolute;
border-left: 2px solid rgb(255, 255, 255);
border-top: 2px solid rgb(255, 255, 255);
top: 50%;
left: 50%;
transform: translate(-50%, -50%) rotate(45deg);
}
`

@ -50,17 +50,12 @@ export const Icon = styled.div<IconProps>`
opacity: 0.8;
${isMobileDevice
? css`
height: 13px;
height: 14px;
width: 14px;
background-size: contain;
/* margin: 0 4px; */
:only-child {
margin: 0 4px;
}
@media screen and (orientation: landscape){
width: 21px;
height: 21px;
}
`
: ''};

@ -7,8 +7,13 @@ import type { Props } from './hooks'
import { useProgressBar } from './hooks'
import { ProgressBarList } from './styled'
export const ProgressBar = (props: Props) => {
export interface ProgressBarProps extends Props {
isScrubberVisible?: boolean,
}
export const ProgressBar = (props: ProgressBarProps) => {
const {
isScrubberVisible,
onPlayedProgressChange,
onTouchEnd,
onTouchStart,
@ -29,9 +34,11 @@ export const ProgressBar = (props: Props) => {
return (
<ProgressBarList ref={progressBarRef}>
<Chapters chapters={calculatedChapters} />
<Scrubber style={{ left: `${playedProgressInPercent}%` }}>
<TimeTooltip time={time} />
</Scrubber>
{isScrubberVisible === false ? null : (
<Scrubber style={{ left: `${playedProgressInPercent}%` }}>
<TimeTooltip time={time} />
</Scrubber>
)}
</ProgressBarList>
)
}

@ -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`
flex-grow: 1;
height: 4px;
position: relative;
${isMobileDevice
? css`
height: 1px;
`
: ''}
`

@ -14,6 +14,8 @@ import { useNoNetworkPopupStore } from 'features/NoNetworkPopup'
import { useEventListener, useObjectState } from 'hooks'
import { MatchInfo } from 'requests'
import { useProgressChangeHandler } from './useProgressChangeHandler'
import { usePlayingHandlers } from './usePlayingHandlers'
import { useVideoQuality } from './useVideoQuality'
@ -43,6 +45,7 @@ export type Props = {
chapters: Chapters,
onError?: () => void,
onPlayingChange: (playing: boolean) => void,
profile: MatchInfo,
}
export const useMultiSourcePlayer = ({

@ -1,39 +1,28 @@
import { Loader } from 'features/Loader'
import { VolumeBar } from 'features/StreamPlayer/components/VolumeBar'
import {
PlayerWrapper,
Controls,
ControlsRow,
ControlsGroup,
CenterControls,
PlayStop,
Fullscreen,
LoaderWrapper,
Backward,
Forward,
PlaybackTime,
ControlsGradient,
TeamsDetailsWrapper,
} from 'features/StreamPlayer/styled'
import { VideoPlayer } from 'features/VideoPlayer'
import { secondsToHms } from 'helpers'
import { Controls } from 'features/StreamPlayer/components/Controls'
import { Name } from 'features/Name'
import { isMobileDevice } from 'config/userAgent'
import { HOUR_IN_MILLISECONDS, REWIND_SECONDS } from './config'
import { ProgressBar } from './components/ProgressBar'
import { Settings } from './components/Settings'
import type { Props } from './hooks'
import { useMultiSourcePlayer } from './hooks'
import { Players } from './types'
import {
ChaptersText,
Next,
Prev,
} from './styled'
import { REWIND_SECONDS } from './config'
export const MultiSourcePlayer = (props: Props) => {
const { profile } = props
const {
activeChapterIndex,
activePlayer,
@ -83,7 +72,6 @@ export const MultiSourcePlayer = (props: Props) => {
volumeInPercent,
wrapperRef,
} = useMultiSourcePlayer(props)
const firstPlayerActive = activePlayer === Players.PLAYER1
return (
@ -136,6 +124,15 @@ export const MultiSourcePlayer = (props: Props) => {
onError={onError}
onReady={onReady}
/>
{isMobileDevice && isFullscreen && controlsVisible && profile && (
<TeamsDetailsWrapper>
<Name nameObj={profile.team1} />
{` ${profile.team1.score}-${profile.team2.score} `}
<Name nameObj={profile.team2} />
</TeamsDetailsWrapper>
)}
{ready && (
<CenterControls playing={playing}>
<Backward size='lg' onClick={rewindBackward}>{REWIND_SECONDS}</Backward>
@ -148,79 +145,38 @@ export const MultiSourcePlayer = (props: Props) => {
<Forward size='lg' onClick={rewindForward}>{REWIND_SECONDS}</Forward>
</CenterControls>
)}
<Controls visible={controlsVisible}>
<ControlsRow>
<ProgressBar
activeChapterIndex={activeChapterIndex}
allPlayedProgress={allPlayedProgress}
duration={duration}
chapters={chapters}
onTouchEnd={onTouchEnd}
onTouchStart={onTouchStart}
onPlayedProgressChange={onProgressChange}
playedProgress={playedProgress}
loadedProgress={loadedProgress}
/>
</ControlsRow>
<ControlsRow>
<ControlsGroup>
<PlayStop
playing={playing}
onClickCapture={togglePlaying}
/>
<Prev
disabled={isFirstChapterPlaying}
onClick={() => playPrevChapter()}
/>
<ChaptersText>
{activeChapterIndex + 1} / {numberOfChapters}
</ChaptersText>
<Next
disabled={isLastChapterPlaying}
onClick={() => playNextChapter()}
/>
{
!isMobileDevice && (
<VolumeBar
value={volumeInPercent}
muted={muted}
onChange={onVolumeChange}
onClick={onVolumeClick}
/>
)
}
<PlaybackTime width={duration > HOUR_IN_MILLISECONDS ? 150 : 130}>
{secondsToHms(allPlayedProgress / 1000)}
{' / '}
{secondsToHms(duration / 1000)}
</PlaybackTime>
<Backward
onClick={rewindBackward}
isHidden={isMobileDevice}
>{REWIND_SECONDS}
</Backward>
<Forward
onClick={rewindForward}
isHidden={isMobileDevice}
>{REWIND_SECONDS}
</Forward>
</ControlsGroup>
<ControlsGroup>
<Settings
onSelect={onQualitySelect}
selectedQuality={selectedQuality}
videoQualities={videoQualities}
/>
<Fullscreen
onClick={onFullscreenClick}
isFullscreen={isFullscreen}
/>
</ControlsGroup>
</ControlsRow>
</Controls>
<ControlsGradient />
<Controls
activeChapterIndex={activeChapterIndex}
allPlayedProgress={allPlayedProgress}
chapters={chapters}
controlsVisible={controlsVisible}
duration={duration}
isFirstChapterPlaying={isFirstChapterPlaying}
isFullscreen={isFullscreen}
isLastChapterPlaying={isLastChapterPlaying}
loadedProgress={loadedProgress}
muted={muted}
numberOfChapters={numberOfChapters}
onFullscreenClick={onFullscreenClick}
onProgressChange={onProgressChange}
onQualitySelect={onQualitySelect}
onTouchEnd={onTouchEnd}
onTouchStart={onTouchStart}
onVolumeChange={onVolumeChange}
onVolumeClick={onVolumeClick}
playNextChapter={playNextChapter}
playPrevChapter={playPrevChapter}
playedProgress={playedProgress}
playing={playing}
rewindBackward={rewindBackward}
rewindForward={rewindForward}
selectedQuality={selectedQuality}
togglePlaying={togglePlaying}
videoQualities={videoQualities}
volume={volume}
volumeInPercent={volumeInPercent}
/>
<ControlsGradient isVisible={controlsVisible} />
</PlayerWrapper>
)
}

@ -76,14 +76,13 @@ export const ProfileHeader = ({
{children}
<Position right={0.71}>
<Position top={isMobileDevice ? client.styles.logoTop : undefined} right={0.71}>
<HeaderGroup>
{!isMobileDevice ? <ScoreSwitch /> : null}
<Menu />
</HeaderGroup>
</Position>
</HeaderStyled>
{isMobileDevice ? <ScoreSwitch /> : null}
</Fragment>
)
}

@ -64,7 +64,7 @@ export const HeaderStyled = styled.header<HeaderProps>`
${isMobileDevice
? css`
height: 124px;
height: 40px;
padding: 8px;
`
: ''}
@ -93,18 +93,29 @@ export const HeaderLogo = styled(Logo)`
${({ isMatchPage }) => (isMatchPage ? css`
width: ${client.styles.matchLogoWidth}rem;
height: ${client.styles.matchLogoHeight}rem;
` : '')}
${isMobileDevice ? css`
${client.styles.mobileHeaderLogo}
@media (max-width: 450px){
${isMobileDevice ? css`
left: 48vw;
top: 5px;
transform: translateX(-50%);
position: absolute;
}
` : ''}
${client.styles.matchPageMobileHeaderLogo}
` : ''}
` : css`
${isMobileDevice ? css`
${client.styles.mobileHeaderLogo}
@media (max-width: 450px){
left: 48vw;
top: 5px;
transform: translateX(-50%);
position: absolute;
}
` : ''}
`)}
`
type PositionProps = {

@ -92,7 +92,7 @@ export const Form = styled.form<FormProps>`
box-shadow: none;
${isMobileDevice
? css`
height: 32px;
height: 28px;
padding-right: 5px;
`
: ''};

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

@ -12,6 +12,7 @@ import {
type Props = {
duration: number,
isScrubberVisible?: boolean,
loadedProgress: number,
onPlayedProgressChange: (progress: number) => void,
playedProgress: number,
@ -19,6 +20,7 @@ type Props = {
export const ProgressBar = ({
duration,
isScrubberVisible,
loadedProgress,
onPlayedProgressChange,
playedProgress,
@ -31,9 +33,11 @@ export const ProgressBar = ({
<ProgressBarList ref={progressBarRef}>
<LoadedProgress style={{ width: `${loadedFraction}%` }} />
<PlayedProgress style={{ width: `${playedFraction}%` }} />
<Scrubber style={{ left: `${playedFraction}%` }}>
<TimeTooltip time={secondsToHms(playedProgress / 1000)} />
</Scrubber>
{isScrubberVisible === false ? null : (
<Scrubber style={{ left: `${playedFraction}%` }}>
<TimeTooltip time={secondsToHms(playedProgress / 1000)} />
</Scrubber>
)}
</ProgressBarList>
)
}

@ -1,7 +1,6 @@
import styled from 'styled-components/macro'
import { devices } from 'config/devices'
import styled, { css } from 'styled-components/macro'
import { isMobileDevice } from 'config/userAgent'
import { Wrapper } from '../TimeTooltip/styled'
export const ProgressBarList = styled.div`
@ -10,6 +9,12 @@ export const ProgressBarList = styled.div`
position: relative;
background-color: rgba(255, 255, 255, 0.3);
cursor: pointer;
${isMobileDevice
? css`
height: 1px;
`
: ''}
`
export const LoadedProgress = styled.div`
@ -24,6 +29,12 @@ export const PlayedProgress = styled.div`
z-index: 2;
background-color: #CC0000;
height: 100%;
${isMobileDevice
? css`
background-color: #FFFFFF;
`
: ''}
`
export const Scrubber = styled.div`
@ -43,8 +54,11 @@ export const Scrubber = styled.div`
visibility: visible;
}
@media ${devices.mobile} {
width: 14px;
height: 14px;
}
${isMobileDevice
? css`
width: 14px;
height: 14px;
background-color: #FFFFFF;
`
: ''}
`

@ -1,4 +1,6 @@
import styled from 'styled-components/macro'
import styled, { css } from 'styled-components/macro'
import { isMobileDevice } from 'config/userAgent'
export const Wrapper = styled.div`
visibility: hidden;
@ -31,4 +33,10 @@ export const Time = styled.span`
font-weight: bold;
font-size: 16px;
line-height: 20px;
${isMobileDevice
? css`
color: #FFFFFF;
`
: ''}
`

@ -1,31 +1,23 @@
import { T9n } from 'features/T9n'
import { Loader } from 'features/Loader'
import { REWIND_SECONDS } from 'features/MultiSourcePlayer/config'
import { Settings } from 'features/MultiSourcePlayer/components/Settings'
import { VideoPlayer } from 'features/VideoPlayer'
import { Name } from 'features/Name'
import { secondsToHms } from 'helpers'
import { VolumeBar } from './components/VolumeBar'
import { ProgressBar } from './components/ProgressBar'
import { isMobileDevice } from 'config/userAgent'
import {
PlayerWrapper,
Controls,
ControlsRow,
ControlsGroup,
CenterControls,
PlayStop,
Fullscreen,
LoaderWrapper,
ControlsGradient,
CenterControls,
Backward,
PlayStop,
Forward,
PlaybackTime,
ControlsGradient,
LiveBtn,
TeamsDetailsWrapper,
} from './styled'
import type { Props } from './hooks'
import { useVideoPlayer } from './hooks'
import { Controls } from './components/Controls'
export const StreamPlayer = (props: Props) => {
const { profile, url } = props
@ -102,6 +94,15 @@ export const StreamPlayer = (props: Props) => {
onError={onError}
crossOrigin='use-credentials'
/>
{isMobileDevice && isFullscreen && controlsVisible && profile && (
<TeamsDetailsWrapper>
<Name nameObj={profile.team1} />
{` ${profile.team1.score}-${profile.team2.score} `}
<Name nameObj={profile.team2} />
</TeamsDetailsWrapper>
)}
{ready && (
<CenterControls playing={playing}>
<Backward size='lg' onClick={rewindBackward}>
@ -119,49 +120,34 @@ export const StreamPlayer = (props: Props) => {
</CenterControls>
)}
<Controls visible={controlsVisible}>
<ControlsRow>
<ProgressBar
duration={duration}
onPlayedProgressChange={onProgressChange}
playedProgress={playedProgress}
loadedProgress={loadedProgress}
/>
</ControlsRow>
<ControlsRow>
<ControlsGroup>
<PlayStop onClickCapture={togglePlaying} playing={playing} />
<VolumeBar
value={volumeInPercent}
muted={muted}
onChange={onVolumeChange}
onClick={onVolumeClick}
/>
<PlaybackTime>{secondsToHms(playedProgress / 1000)}</PlaybackTime>
<Backward onClick={rewindBackward}>{REWIND_SECONDS}</Backward>
<Forward onClick={rewindForward}>{REWIND_SECONDS}</Forward>
</ControlsGroup>
<ControlsGroup>
{
profile?.live && (
<LiveBtn onClick={backToLive}>
<T9n t='live' />
</LiveBtn>
)
}
<Settings
onSelect={onQualitySelect}
selectedQuality={selectedQuality}
videoQualities={videoQualities}
/>
<Fullscreen
onClick={onFullscreenClick}
isFullscreen={isFullscreen}
/>
</ControlsGroup>
</ControlsRow>
</Controls>
<ControlsGradient />
<Controls
allPlayedProgress={playedProgress}
backToLive={backToLive}
controlsVisible={controlsVisible}
duration={duration}
isFullscreen={isFullscreen}
isLive={profile?.live}
isStorage={profile?.storage}
loadedProgress={loadedProgress}
muted={muted}
onFullscreenClick={onFullscreenClick}
onProgressChangeLive={onProgressChange}
onQualitySelect={onQualitySelect}
onTouchEnd={onTouchEnd}
onTouchStart={onTouchStart}
onVolumeChange={onVolumeChange}
onVolumeClick={onVolumeClick}
playedProgress={playedProgress}
playing={playing}
rewindBackward={rewindBackward}
rewindForward={rewindForward}
selectedQuality={selectedQuality}
togglePlaying={togglePlaying}
videoQualities={videoQualities}
volume={volume}
volumeInPercent={volumeInPercent}
/>
<ControlsGradient isVisible={controlsVisible} />
</PlayerWrapper>
)
}

@ -1,21 +1,29 @@
import styled, { css } from 'styled-components/macro'
import styled, { css } from 'styled-components'
import { isMobileDevice } from 'config/userAgent'
export const ControlsGradient = styled.div`
export const ControlsGradient = styled.div<{ isVisible?: boolean }>`
background-image: url(/images/player-controls-gradient.png);
bottom: 0;
position: absolute;
width: 100%;
pointer-events: none;
height: 145px;
${({ isVisible }) => (isMobileDevice
? css`
height: 100%;
background: ${(isVisible
? 'linear-gradient(0deg, rgba(0,0,0,0.7) 0%, rgba(255,255,255,0) 25%, rgba(255,255,255,0) 75%, rgba(0,0,0,0.7) 100%)'
: 'initial')}
` : '')}
`
type HoverStylesProps = {
visible: boolean,
}
const hoverStyles = css<HoverStylesProps>`
export const hoverStyles = css<HoverStylesProps>`
transition: opacity 0.3s ease-in-out;
${({ visible }) => (visible
? css`opacity: 1;`
@ -115,6 +123,7 @@ export const PlayerWrapper = styled.div<PlayStopProps>`
${isMobileDevice
? css`
min-height: auto;
margin-bottom: 15px;
`
: ''};
`
@ -144,7 +153,7 @@ export const ButtonBase = styled.button`
const sizes = {
lg: 92,
sm: 24,
sm: 29,
}
type PlayStopProps = {
@ -169,8 +178,8 @@ export const PlayStop = styled(ButtonBase)<PlayStopProps>`
${isMobileDevice
? css`
width: 20%;
height: 60%;
width: ${sizes.sm}px;
height: ${sizes.sm}px;
margin-right: 0;
padding: 0;
`
@ -241,26 +250,24 @@ export const Backward = styled(ButtonBase)<ButtonProps>`
${isMobileDevice
? css`
width: 15%;
font-size: 14px;
margin-right: 6px;
width: ${rewindButtonSizes.sides.sm}px;
height: ${rewindButtonSizes.sides.sm}px;
font-size: ${rewindButtonSizes.fontSizes.sm}px;
`
: ''};
`
export const Forward = styled(Backward)`
background-image: url(/images/player-forward.svg);
margin-left: 10px;
margin-right: 0;
`
type PlaybackTimeProps = {
width?: number,
}
export const PlaybackTime = styled.span<PlaybackTimeProps>`
width: ${({ width = 130 }) => `${width}px`};
export const PlaybackTime = styled.span`
font-weight: 600;
font-size: 16px;
color: #fff;
margin-right: 10px;
${isMobileDevice
? css`
@ -292,7 +299,7 @@ export const CenterControls = styled.div<CenterControlsProps>`
pointer-events: ${({ playing }) => (playing ? 'none' : 'auto')};
${isMobileDevice
? css`
width: 70%;
width: 135px;
`
: ''};
`
@ -307,12 +314,13 @@ export const LiveBtn = styled(ButtonBase)`
padding: 4.5px 8px;
background-color: #CC0000;
border-radius: 1.3px;
`
${isMobileDevice
? css`
@media (max-width: 650px) {
margin-right: 7px;
}
`
: ''};
export const TeamsDetailsWrapper = styled.div`
position: absolute;
top: 20px;
left: 15px;
font-size: 16px;
color: #FFFFFF;
z-index: 50;
`

@ -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…
Cancel
Save