Skip to content

Commit

Permalink
feat(videodetail): add cinema and jwplayer
Browse files Browse the repository at this point in the history
  • Loading branch information
royschut committed May 30, 2021
1 parent a1302d2 commit 0397ac3
Show file tree
Hide file tree
Showing 16 changed files with 443 additions and 162 deletions.
18 changes: 16 additions & 2 deletions src/components/Button/Button.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

color: var(--highlight-color, white);
font-family: theme.$body-alt-font-family;
font-size: 16px;
line-height: 18px;
text-align: center;
text-decoration: none;

Expand All @@ -20,7 +22,12 @@
border-radius: 4px;

cursor: pointer;
transition: background 0.1s ease, transform 0.1s ease;
transition: background-color 0.1s ease, transform 0.1s ease;

> svg {
height: 18px;
width: 18px;
}

&.fullWidth {
width: 100%;
Expand Down Expand Up @@ -61,5 +68,12 @@
}
}
.startIcon {
margin-right: 13px;
margin-right: 11px;
height: 100%;
display: flex;
align-items: center;
> svg {
height: 20px;
width: 20px;
}
}
5 changes: 3 additions & 2 deletions src/components/DynamicBlur/DynamicBlur.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
position: fixed;
height: 100vh;
width: 100vw;
background-position: center;
background-position: center center;
background-size: cover;
background-repeat: no-repeat;
box-sizing: border-box;
filter: blur(30px);
z-index: -1;
z-index: -2;
opacity: 0;
}
136 changes: 99 additions & 37 deletions src/components/Video/Video.module.scss
Original file line number Diff line number Diff line change
@@ -1,52 +1,112 @@
@use '../../styles/variables';
@use '../../styles/theme';
@use '../../styles/mixins/responsive';

.video {
padding: 50px;
color: white;
padding: 56px 56px;
color: var(--primary-color);
font-family: var(--body-font-family);
font-weight: 400;
text-shadow: 0px 2px 4px rgba(0, 0, 0, 0.14), 0px 3px 4px rgba(0, 0, 0, 0.12), 0px 1px 5px rgba(0, 0, 0, 0.2);

@include responsive.tablet-only() {
padding: 24px;
}
@include responsive.mobile-only() {
padding: 16px;
}
}
.main {
display: flex;
position: relative;
}
.info {
width: 50%;
max-width: 450px;
@include responsive.tablet-only() {
max-width: 350px;
}
@include responsive.mobile-only() {
width: 100%;
padding-top: 225px;
}
}
.title {
font-weight: 900;
font-size: larger;
margin: 20px 0px;
font-size: 34px;
font-weight: 700;
line-height: 36px;
letter-spacing: 0.25px;
margin: 8px 0px;
}
.meta {
margin: 20px 0px;
> ul {
padding-inline-start: 0px;
display: flex;
> li {
margin-right: 30px;
line-height: 18px;
font-size: 16px;
letter-spacing: 0.15px;
margin-bottom: 8px;
}
.description {
font-size: 18px;
line-height: 20px;
letter-spacing: 0.5px;
margin-bottom: 24px;
}
.playButton {
justify-content: center;
margin-bottom: 8px;
}
.otherButtons {
display: flex;
justify-content: center;
> button {
margin-right: 8px;
width: 33%;
}
> button:last-child {
margin-right: 0px;
}
@include responsive.mobile-only() {
flex-wrap: wrap;
> button:first-child {
margin-bottom: 8px;
margin-right: 0px;
width: 100%;
}
> li:first-child {
list-style-type: none;
> button:not(:first-child) {
flex: 1;
}
}
}
.buttons {
margin: 20px 0px;
> button {
margin-right: 20px;
}
.poster {
position: absolute;
background-size: cover;
background-repeat: no-repeat;
background-position: center center;
top: 0;
right: 0;
z-index: -1;
}
.banner {
width: 50%;
position: relative;
opacity: 0.7;
> img {
width: 100%;
.posterNormal {
width: 720px;
height: 405px;
border-radius: 4px;
mask-image: linear-gradient(-90deg, rgba(0, 0, 0, 1) 90%, rgba(0, 0, 0, 0) 100%);
-webkit-mask-image: linear-gradient(-90deg, rgba(0, 0, 0, 1) 90%, rgba(0, 0, 0, 0) 100%);

@include responsive.tablet-only() {
width: 600px;
height: 338px;
}
&:hover {
cursor: pointer;
opacity: 1;
@include responsive.mobile-only() {
width: 100vw;
mask-image: radial-gradient(farthest-corner at 80% 20%, rgba(0, 0, 0, 1) 40%, rgba(0, 0, 0, 0) 60%);
-webkit-mask-image: radial-gradient(farthest-corner at 80% 20%, rgba(0, 0, 0, 1) 40%, rgba(0, 0, 0, 0) 60%);
}
}
.posterFading {
width: 1280px;
height: 640px;
mask-image: radial-gradient(farthest-corner at 80% 20%, rgba(0, 0, 0, 1) 40%, rgba(0, 0, 0, 0) 60%);
-webkit-mask-image: radial-gradient(farthest-corner at 80% 20%, rgba(0, 0, 0, 1) 40%, rgba(0, 0, 0, 0) 60%);
}
.playIcon {
position: absolute;
left: calc(50% - 35px);
Expand Down Expand Up @@ -74,18 +134,20 @@
background-position: center;
opacity: 0.7;
}
.playerInfo {
.player {
position: absolute;
left: 0;
top: 0;
margin: 50px;
width: 100vw;
height: 100vh;
}
.playerContent {
position: absolute;
top: 0;
margin: 30px 62px;
max-width: 50%;
display: flex;

> h2 {
font-size: x-large;
}
}
.backButton {
padding: 10px;
font-size: x-large;
.playerInfo {
margin: 0px 30px;
}
93 changes: 55 additions & 38 deletions src/components/Video/Video.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import React from 'react';
import type { PlaylistItem } from 'types/playlist';
import classNames from 'classnames';

import Cinema from '../../containers/Cinema/Cinema';
import useBreakpoint, { Breakpoint } from '../../hooks/useBreakpoint';
import Favorite from '../../icons/Favorite';
import PlayTrailer from '../../icons/PlayTrailer';
import Share from '../../icons/Share';
import ArrowLeft from '../../icons/ArrowLeft';
import Play from '../../icons/Play';
import Button from '../Button/Button';
import IconButton from '../IconButton/IconButton';

Expand All @@ -11,59 +19,68 @@ type Props = {
play: boolean;
startPlay: () => void;
goBack: () => void;
posterFading: boolean;
relatedShelf?: JSX.Element;
};

const Video: React.FC<Props> = ({ item, play, startPlay, goBack }: Props) => {
const fullYear: number = new Date(item.pubdate).getFullYear();
const duration: string = `${Math.floor(item.duration / 60)}h ${item.duration % 60}m`;
const Video: React.FC<Props> = ({ item, play, startPlay, goBack, posterFading, relatedShelf }: Props) => {
const posterImage = item.image.replace('720', '1280'); // Todo: 1280 should be sent from API
const breakpoint = useBreakpoint();
const isMobile = breakpoint === Breakpoint.xs;

const metaData = [];
if (item.pubdate) metaData.push(new Date(item.pubdate).getFullYear());
if (item.duration) metaData.push(`${Math.floor(item.duration / 60)}h ${item.duration % 60}m`);
if (item.genre) metaData.push(item.genre);
if (item.rating) metaData.push(item.rating);
const metaString = metaData.join(' • ');

//todo: image based on screen res, etc (like Home)
//todo: breakpoints not same as css (so info padding-top acts too soon)
//todo: description enlarger

return (
<div className={styles.video}>
<div className={styles.main}>
<div className={styles.info}>
<h2 className={styles.title}>{item.title}</h2>
<div className={styles.meta}>
<ul>
<li>{fullYear}</li>
<li>{duration}</li>
<li>{item.genre}</li>
<li>{item.rating}</li>
</ul>
<div className={styles.meta}>{metaString}</div>
{!isMobile && <div className={styles.description}>{item.description}</div>}
<div className={styles.playButton}>
<Button
color="secondary"
label={'Start watching'}
startIcon={<Play />}
onClick={startPlay}
active={play}
fullWidth
/>
</div>
<div className={styles.description}>{item.description}</div>
<div className={styles.buttons}>
<Button label={'Favorite'} onClick={() => null} active />
<Button label={'Trailer'} onClick={() => null} active />
<Button label={'Share'} onClick={() => null} active />
<div className={styles.otherButtons}>
<Button label={'Trailer'} startIcon={<PlayTrailer />} onClick={() => null} />
<Button label={'Favorite'} startIcon={<Favorite />} onClick={() => null} />
<Button label={'Share'} startIcon={<Share />} onClick={() => null} />
</div>
</div>
<div className={styles.banner} onClick={startPlay}>
<img src={item.image} />
<div className={styles.playIcon}>&#9658;</div>
</div>
</div>
<div className={styles.other}>
<h3>Resting shelf</h3>
<div
className={classNames(styles.poster, posterFading ? styles.posterFading : styles.posterNormal)}
style={{ backgroundImage: `url('${posterImage}')` }}
/>
</div>
{!!relatedShelf && <div className={styles.other}>{relatedShelf}</div>}
{play && (
<div className={styles.playerContainer}>
<div className={styles.background} style={{ backgroundImage: `url('${item.image}')` }} />
<div className={styles.player}></div>
<div className={styles.playerInfo}>
<div className={styles.backButton}>
<IconButton aria-label="Back" onClick={goBack}>
<p>&#8592;</p>
</IconButton>
</div>
<div>
<div className={styles.player}>
<Cinema item={item} />
</div>
<div className={styles.playerContent}>
<IconButton aria-label="Back" onClick={goBack}>
<ArrowLeft />
</IconButton>
<div className={styles.playerInfo}>
<h2 className={styles.title}>{item.title}</h2>
<div className={styles.meta}>
<ul>
<li>{fullYear}</li>
<li>{duration}</li>
<li>{item.genre}</li>
<li>{item.rating}</li>
</ul>
</div>
<div className={styles.meta}>{metaString}</div>
<div className={styles.description}>{item.description}</div>
</div>
</div>
Expand Down
Loading

0 comments on commit 0397ac3

Please sign in to comment.