Ott 701 videos panel (#278)
* feat: 🎸 OTT-701-videos-panel add side panel * feat: 🎸 OTT-701 add some styles * feat: 🎸 OTT-701 delete // * feat: 🎸 #701 hook deleted * fix(701): reset route state on mount * feat: 🎸 OTT-701 fix comments * feat: 🎸 OTT-701 fix names * fix: renamed dropdown * fix: renamed dropdown back * feat: 🎸 OTT-701 fix height * feat: 🎸 OTT-701 undo changes for isClickable * feat: 🎸 OTT-701 fix comments Co-authored-by: Zoia <zizi2405@yandex.ru> Co-authored-by: Mirlan <m.maksitaliev@gmail.com>keep-around/af30b88d367751c9e05a735e4a0467a96238ef47
parent
537a38a79a
commit
c167d2dd77
@ -0,0 +1,53 @@ |
|||||||
|
import { ReactNode } from 'react' |
||||||
|
|
||||||
|
import { useToggle } from 'hooks' |
||||||
|
import { T9n } from 'features/T9n' |
||||||
|
|
||||||
|
import { |
||||||
|
Amount, |
||||||
|
Arrows, |
||||||
|
DropdownButton, |
||||||
|
Title, |
||||||
|
SectionWrapper, |
||||||
|
Wrapper, |
||||||
|
} from './styled' |
||||||
|
|
||||||
|
type Props = { |
||||||
|
children: ReactNode, |
||||||
|
itemsCount: number, |
||||||
|
title?: string | number, |
||||||
|
} |
||||||
|
|
||||||
|
export const DropdownSection = (props: Props) => { |
||||||
|
const { |
||||||
|
isOpen, |
||||||
|
toggle, |
||||||
|
} = useToggle() |
||||||
|
|
||||||
|
const { |
||||||
|
children, |
||||||
|
itemsCount, |
||||||
|
title, |
||||||
|
} = props |
||||||
|
if (!title) return null |
||||||
|
|
||||||
|
return ( |
||||||
|
<Wrapper> |
||||||
|
<DropdownButton |
||||||
|
active={isOpen} |
||||||
|
onClick={toggle} |
||||||
|
> |
||||||
|
<Title> |
||||||
|
<T9n t={title} /> |
||||||
|
</Title> |
||||||
|
<Amount> |
||||||
|
{itemsCount} |
||||||
|
</Amount> |
||||||
|
<Arrows active={isOpen} /> |
||||||
|
</DropdownButton> |
||||||
|
<SectionWrapper active={isOpen}> |
||||||
|
{children} |
||||||
|
</SectionWrapper> |
||||||
|
</Wrapper> |
||||||
|
) |
||||||
|
} |
||||||
@ -0,0 +1,78 @@ |
|||||||
|
import styled from 'styled-components/macro' |
||||||
|
|
||||||
|
type Props = { |
||||||
|
active?: boolean, |
||||||
|
} |
||||||
|
|
||||||
|
export const Wrapper = styled.div` |
||||||
|
margin-bottom: 10px; |
||||||
|
` |
||||||
|
|
||||||
|
export const Item = styled.li` |
||||||
|
margin-top: 15px; |
||||||
|
width: 100%; |
||||||
|
height: 50px; |
||||||
|
` |
||||||
|
|
||||||
|
export const SectionWrapper = styled.div<Props>` |
||||||
|
overflow: hidden; |
||||||
|
transition: .3s; |
||||||
|
|
||||||
|
${({ active }) => ( |
||||||
|
active |
||||||
|
? 'height: auto;' |
||||||
|
: 'height: 0;' |
||||||
|
)} |
||||||
|
` |
||||||
|
|
||||||
|
export const DropdownButton = styled.button<Props>` |
||||||
|
position: relative; |
||||||
|
height: 100%; |
||||||
|
width: 100%; |
||||||
|
padding-right: 40px; |
||||||
|
padding-left: 0px; |
||||||
|
outline: none; |
||||||
|
border: none; |
||||||
|
border-radius: 2px; |
||||||
|
display: flex; |
||||||
|
justify-content: space-between; |
||||||
|
align-items: center; |
||||||
|
background-color: transparent; |
||||||
|
font-weight: 600; |
||||||
|
font-size: 18px; |
||||||
|
cursor: pointer; |
||||||
|
` |
||||||
|
|
||||||
|
export const Arrows = styled.span<Props>` |
||||||
|
position: absolute; |
||||||
|
right: 19px; |
||||||
|
display: inline-block; |
||||||
|
width: 12px; |
||||||
|
height: 12px; |
||||||
|
background-repeat: no-repeat; |
||||||
|
background-position: center; |
||||||
|
|
||||||
|
${({ active }) => ( |
||||||
|
active |
||||||
|
? 'background-image: url(/images/arrowUp.svg);' |
||||||
|
: 'background-image: url(/images/arrowDown.svg);' |
||||||
|
)} |
||||||
|
` |
||||||
|
|
||||||
|
export const Title = styled.span` |
||||||
|
font-weight: 500; |
||||||
|
font-size: 20px; |
||||||
|
line-height: 45px; |
||||||
|
letter-spacing: 0.03em; |
||||||
|
text-align: start; |
||||||
|
color: #ffffff; |
||||||
|
text-transform: uppercase; |
||||||
|
` |
||||||
|
|
||||||
|
export const Amount = styled.span` |
||||||
|
font-weight: 300; |
||||||
|
font-size: 20px; |
||||||
|
line-height: 50px; |
||||||
|
letter-spacing: 0.03em; |
||||||
|
color: #ffffff; |
||||||
|
` |
||||||
@ -0,0 +1,63 @@ |
|||||||
|
import { ReactNode } from 'react' |
||||||
|
|
||||||
|
import styled, { css } from 'styled-components/macro' |
||||||
|
|
||||||
|
import { Button, Title } from '../../styled' |
||||||
|
|
||||||
|
type InterviewProps = { |
||||||
|
overlength?: boolean, |
||||||
|
} |
||||||
|
|
||||||
|
const InterviewTitle = styled(Title)<InterviewProps>` |
||||||
|
white-space: normal; |
||||||
|
text-align: start; |
||||||
|
display: -webkit-box; |
||||||
|
-webkit-line-clamp: 3; |
||||||
|
-webkit-box-orient: vertical; |
||||||
|
|
||||||
|
${({ overlength }) => ( |
||||||
|
overlength |
||||||
|
? css` |
||||||
|
font-size: 18px; |
||||||
|
line-height: 26px; |
||||||
|
` |
||||||
|
: css` |
||||||
|
font-size: 20px; |
||||||
|
line-height: 50px; |
||||||
|
` |
||||||
|
)} |
||||||
|
` |
||||||
|
|
||||||
|
const InterviewButton = styled(Button)<InterviewProps>` |
||||||
|
${({ overlength }) => ( |
||||||
|
overlength |
||||||
|
? 'padding: 16px 25px;' |
||||||
|
: 'padding: 0px 25px;' |
||||||
|
)} |
||||||
|
` |
||||||
|
|
||||||
|
type Props = { |
||||||
|
active?: boolean, |
||||||
|
children: ReactNode, |
||||||
|
onClick: () => void, |
||||||
|
overlength?: boolean, |
||||||
|
} |
||||||
|
|
||||||
|
export const InterviewPlayButton = ({ |
||||||
|
active, |
||||||
|
children, |
||||||
|
onClick, |
||||||
|
overlength, |
||||||
|
}: Props) => ( |
||||||
|
<InterviewButton |
||||||
|
onClick={onClick} |
||||||
|
active={active} |
||||||
|
overlength={overlength} |
||||||
|
> |
||||||
|
<InterviewTitle |
||||||
|
overlength={overlength} |
||||||
|
> |
||||||
|
{children} |
||||||
|
</InterviewTitle> |
||||||
|
</InterviewButton> |
||||||
|
) |
||||||
@ -0,0 +1,45 @@ |
|||||||
|
import styled from 'styled-components/macro' |
||||||
|
|
||||||
|
import map from 'lodash/map' |
||||||
|
|
||||||
|
import type { MatchPlaylistOptions, PlaylistOption } from 'features/MatchPage/types' |
||||||
|
|
||||||
|
import { T9n } from 'features/T9n' |
||||||
|
import { isEqual } from 'features/MatchSidePlaylists' |
||||||
|
|
||||||
|
import { PlayButton } from '../PlayButton' |
||||||
|
import { Item } from '../../styled' |
||||||
|
|
||||||
|
type Props = { |
||||||
|
onSelect: (selectedMathPlaylist: PlaylistOption) => void, |
||||||
|
playlists?: MatchPlaylistOptions, |
||||||
|
selectedMathPlaylist?: PlaylistOption, |
||||||
|
} |
||||||
|
|
||||||
|
const List = styled.ul`` |
||||||
|
|
||||||
|
export const MatchPlaylists = (props: Props) => { |
||||||
|
const { |
||||||
|
onSelect, |
||||||
|
playlists, |
||||||
|
selectedMathPlaylist, |
||||||
|
} = props |
||||||
|
|
||||||
|
return ( |
||||||
|
<List> |
||||||
|
{ |
||||||
|
map(playlists, (playlist) => ( |
||||||
|
<Item key={playlist.id}> |
||||||
|
<PlayButton |
||||||
|
duration={playlist.duration} |
||||||
|
active={isEqual(playlist, selectedMathPlaylist)} |
||||||
|
onClick={() => onSelect(playlist)} |
||||||
|
> |
||||||
|
<T9n t={playlist.lexic} /> |
||||||
|
</PlayButton> |
||||||
|
</Item> |
||||||
|
)) |
||||||
|
} |
||||||
|
</List> |
||||||
|
) |
||||||
|
} |
||||||
@ -0,0 +1,37 @@ |
|||||||
|
import { ReactNode } from 'react' |
||||||
|
|
||||||
|
import styled from 'styled-components/macro' |
||||||
|
|
||||||
|
import { secondsToHms } from 'helpers' |
||||||
|
|
||||||
|
import { Button, Title } from '../../styled' |
||||||
|
|
||||||
|
type Props = { |
||||||
|
active?: boolean, |
||||||
|
children: ReactNode, |
||||||
|
duration?: number, |
||||||
|
onClick: () => void, |
||||||
|
} |
||||||
|
|
||||||
|
const Duration = styled(Title)` |
||||||
|
font-weight: 300; |
||||||
|
font-size: 16px; |
||||||
|
letter-spacing: 0.05em; |
||||||
|
` |
||||||
|
|
||||||
|
export const PlayButton = ({ |
||||||
|
active, |
||||||
|
children, |
||||||
|
duration, |
||||||
|
onClick, |
||||||
|
}: Props) => ( |
||||||
|
<Button |
||||||
|
onClick={onClick} |
||||||
|
active={active} |
||||||
|
> |
||||||
|
<Title> |
||||||
|
{children} |
||||||
|
</Title> |
||||||
|
{duration && <Duration>{secondsToHms(duration)}</Duration>} |
||||||
|
</Button> |
||||||
|
) |
||||||
@ -0,0 +1,69 @@ |
|||||||
|
import styled from 'styled-components/macro' |
||||||
|
|
||||||
|
import map from 'lodash/map' |
||||||
|
|
||||||
|
import type { Team } from 'requests' |
||||||
|
import type { PlaylistOption } from 'features/MatchPage/types' |
||||||
|
|
||||||
|
import { Name } from 'features/Name' |
||||||
|
import { isEqual } from 'features/MatchSidePlaylists' |
||||||
|
|
||||||
|
import { PlayButton } from '../PlayButton' |
||||||
|
import { Item } from '../DropdownSection/styled' |
||||||
|
|
||||||
|
type Props = { |
||||||
|
onSelect: (selectedMathPlaylist: PlaylistOption) => void, |
||||||
|
players: Array<PlaylistOption>, |
||||||
|
selectedMathPlaylist?: PlaylistOption, |
||||||
|
teamName?: Team, |
||||||
|
} |
||||||
|
|
||||||
|
const Wrapper = styled.div` |
||||||
|
margin-bottom: 15px; |
||||||
|
` |
||||||
|
|
||||||
|
const List = styled.ul`` |
||||||
|
|
||||||
|
const PlayersItem = styled(Item)` |
||||||
|
margin-top: 10px |
||||||
|
` |
||||||
|
const Title = styled.span` |
||||||
|
font-weight: 300; |
||||||
|
font-size: 16px; |
||||||
|
line-height: 20px; |
||||||
|
letter-spacing: 0.03em; |
||||||
|
color: #ffffff; |
||||||
|
` |
||||||
|
|
||||||
|
export const PlayersPlaylists = (props: Props) => { |
||||||
|
const { |
||||||
|
onSelect, |
||||||
|
players, |
||||||
|
selectedMathPlaylist, |
||||||
|
teamName, |
||||||
|
} = props |
||||||
|
|
||||||
|
if (!selectedMathPlaylist || !teamName) return null |
||||||
|
|
||||||
|
return ( |
||||||
|
<Wrapper> |
||||||
|
<Title> |
||||||
|
<Name nameObj={teamName} /> |
||||||
|
</Title> |
||||||
|
<List> |
||||||
|
{ |
||||||
|
map(players, (player) => ( |
||||||
|
<PlayersItem key={player.id}> |
||||||
|
<PlayButton |
||||||
|
onClick={() => onSelect(player)} |
||||||
|
active={isEqual(player, selectedMathPlaylist)} |
||||||
|
> |
||||||
|
<Name nameObj={player} /> |
||||||
|
</PlayButton> |
||||||
|
</PlayersItem> |
||||||
|
)) |
||||||
|
} |
||||||
|
</List> |
||||||
|
</Wrapper> |
||||||
|
) |
||||||
|
} |
||||||
@ -0,0 +1,53 @@ |
|||||||
|
import map from 'lodash/map' |
||||||
|
import size from 'lodash/size' |
||||||
|
|
||||||
|
import styled from 'styled-components/macro' |
||||||
|
|
||||||
|
import type { InterviewPlaylistOptions, PlaylistOption } from 'features/MatchPage/types' |
||||||
|
|
||||||
|
import { isEqual } from 'features/MatchSidePlaylists' |
||||||
|
import { Name } from 'features/Name' |
||||||
|
|
||||||
|
import { InterviewPlayButton } from '../InterviewButton' |
||||||
|
|
||||||
|
type Props = { |
||||||
|
interviews: InterviewPlaylistOptions, |
||||||
|
onSelect: (selectedMathPlaylist: PlaylistOption) => void, |
||||||
|
selectedMathPlaylist?: PlaylistOption, |
||||||
|
} |
||||||
|
|
||||||
|
const List = styled.ul`` |
||||||
|
|
||||||
|
const InterviewItem = styled.li` |
||||||
|
min-height: 50px; |
||||||
|
margin-bottom: 10px; |
||||||
|
width: 100%; |
||||||
|
` |
||||||
|
|
||||||
|
export const SideInterviews = (props: Props) => { |
||||||
|
const { |
||||||
|
interviews, |
||||||
|
onSelect, |
||||||
|
selectedMathPlaylist, |
||||||
|
} = props |
||||||
|
return ( |
||||||
|
<List> |
||||||
|
{ |
||||||
|
map(interviews, (interview) => { |
||||||
|
const overLength = (size(interview.name_eng) > 16 || size(interview.name_rus) > 16) |
||||||
|
return ( |
||||||
|
<InterviewItem key={interview.id}> |
||||||
|
<InterviewPlayButton |
||||||
|
active={isEqual(interview, selectedMathPlaylist)} |
||||||
|
onClick={() => onSelect(interview)} |
||||||
|
overlength={overLength} |
||||||
|
> |
||||||
|
<Name nameObj={interview} /> |
||||||
|
</InterviewPlayButton> |
||||||
|
</InterviewItem> |
||||||
|
) |
||||||
|
}) |
||||||
|
} |
||||||
|
</List> |
||||||
|
) |
||||||
|
} |
||||||
@ -1,12 +1,79 @@ |
|||||||
import React from 'react' |
import size from 'lodash/size' |
||||||
|
|
||||||
import styled from 'styled-components/macro' |
import type { PlaylistOption, Playlists } from 'features/MatchPage/types' |
||||||
|
import type { MatchInfo } from 'requests' |
||||||
|
|
||||||
const Wrapper = styled.div` |
import { DropdownSection } from './components/DropdownSection' |
||||||
width: 288px; |
import { MatchPlaylists } from './components/MatchPlaylists' |
||||||
height: 100px; |
import { SideInterviews } from './components/SideInterviews' |
||||||
margin-top: 42px; |
import { PlayersPlaylists } from './components/PlayersPlaylists' |
||||||
margin-left: 14px; |
|
||||||
` |
|
||||||
|
|
||||||
export const MatchSidePlaylists = () => <Wrapper /> |
import { |
||||||
|
Container, |
||||||
|
DropdownWrapper, |
||||||
|
List, |
||||||
|
Wrapper, |
||||||
|
} from './styled' |
||||||
|
|
||||||
|
type Props = { |
||||||
|
onSelect: (option: PlaylistOption) => void, |
||||||
|
playlists: Playlists, |
||||||
|
profile: MatchInfo, |
||||||
|
selectedPlaylist?: PlaylistOption, |
||||||
|
} |
||||||
|
|
||||||
|
export const isEqual = (target: PlaylistOption, selected?: PlaylistOption) => ( |
||||||
|
target.id === selected?.id && target.type === selected.type |
||||||
|
) |
||||||
|
|
||||||
|
export const MatchSidePlaylists = ({ |
||||||
|
onSelect, |
||||||
|
playlists, |
||||||
|
profile, |
||||||
|
selectedPlaylist, |
||||||
|
}: Props) => { |
||||||
|
const playersCount = size(playlists.players.team1) + size(playlists.players.team2) |
||||||
|
|
||||||
|
return ( |
||||||
|
<Wrapper> |
||||||
|
<Container> |
||||||
|
<MatchPlaylists |
||||||
|
playlists={playlists.match} |
||||||
|
selectedMathPlaylist={selectedPlaylist} |
||||||
|
onSelect={onSelect} |
||||||
|
/> |
||||||
|
<DropdownWrapper> |
||||||
|
<DropdownSection |
||||||
|
itemsCount={size(playlists.interview)} |
||||||
|
title={playlists.lexics?.interview} |
||||||
|
> |
||||||
|
<SideInterviews |
||||||
|
interviews={playlists.interview} |
||||||
|
selectedMathPlaylist={selectedPlaylist} |
||||||
|
onSelect={onSelect} |
||||||
|
/> |
||||||
|
</DropdownSection> |
||||||
|
<DropdownSection |
||||||
|
itemsCount={playersCount} |
||||||
|
title={playlists.lexics?.players} |
||||||
|
> |
||||||
|
<List> |
||||||
|
<PlayersPlaylists |
||||||
|
teamName={profile?.team1} |
||||||
|
players={playlists.players.team1} |
||||||
|
selectedMathPlaylist={selectedPlaylist} |
||||||
|
onSelect={onSelect} |
||||||
|
/> |
||||||
|
<PlayersPlaylists |
||||||
|
teamName={profile?.team2} |
||||||
|
players={playlists.players.team2} |
||||||
|
selectedMathPlaylist={selectedPlaylist} |
||||||
|
onSelect={onSelect} |
||||||
|
/> |
||||||
|
</List> |
||||||
|
</DropdownSection> |
||||||
|
</DropdownWrapper> |
||||||
|
</Container> |
||||||
|
</Wrapper> |
||||||
|
) |
||||||
|
} |
||||||
|
|||||||
@ -0,0 +1,62 @@ |
|||||||
|
import styled, { css } from 'styled-components/macro' |
||||||
|
|
||||||
|
import { customScrollbar } from 'features/Common' |
||||||
|
import { buttonStyles } from 'features/MatchPopup/components/PlaylistButton' |
||||||
|
|
||||||
|
export const Wrapper = styled.div` |
||||||
|
margin-top: 42px;
|
||||||
|
max-height: 86vh; |
||||||
|
overflow-y: scroll; |
||||||
|
${customScrollbar} |
||||||
|
` |
||||||
|
|
||||||
|
export const Container = styled.div` |
||||||
|
width: 288px; |
||||||
|
margin-left: 14px; |
||||||
|
margin-right: 14px; |
||||||
|
` |
||||||
|
|
||||||
|
export const DropdownWrapper = styled.div` |
||||||
|
padding-top: 10px; |
||||||
|
` |
||||||
|
|
||||||
|
export const List = styled.div`` |
||||||
|
|
||||||
|
type ButtonProps = { |
||||||
|
active?: boolean, |
||||||
|
} |
||||||
|
|
||||||
|
export const Button = styled.button<ButtonProps>` |
||||||
|
${buttonStyles} |
||||||
|
|
||||||
|
min-height: 50px; |
||||||
|
outline: none; |
||||||
|
|
||||||
|
${({ active }) => ( |
||||||
|
active |
||||||
|
? css` |
||||||
|
background-color: #294FC4; |
||||||
|
&:hover { |
||||||
|
background-color: #0c3ccc; |
||||||
|
} |
||||||
|
` |
||||||
|
: '' |
||||||
|
)} |
||||||
|
` |
||||||
|
|
||||||
|
export const Item = styled.li` |
||||||
|
margin-bottom: 10px; |
||||||
|
width: 100%; |
||||||
|
height: 50px; |
||||||
|
` |
||||||
|
|
||||||
|
export const Title = styled.span` |
||||||
|
font-weight: 500; |
||||||
|
font-size: 20px; |
||||||
|
line-height: 50px; |
||||||
|
letter-spacing: 0.05em; |
||||||
|
color: #ffffff; |
||||||
|
overflow: hidden; |
||||||
|
white-space: nowrap; |
||||||
|
text-overflow:ellipsis; |
||||||
|
` |
||||||
Loading…
Reference in new issue