<div id="app"></div>
// Fonts
@import 'https://fonts.googleapis.com/css?family=Lato:100,300,400,700,900';

// Variables
$font: 'Lato', sans-serif;

// Colors
$red: #e50914;
$black: #221f1f;
$blackblack: #000000;
$grey: #f5f5f1;
$white: #ffffff;

// General
body {
	background: $black;
	color: $white;
	font-family: $font;
}

// Typography

h2 {
	font-size: 24px;
	font-weight: 600;
	line-height: 1.4;
	margin-bottom: 1em;
}

p {
	font-size: 15px;
	font-weight: 300;
	line-height: 1.6;
	margin-bottom: 1em;
}

////////////
// MIXINS //
////////////
@mixin generate-gradient($color,$amount) {
	background: -moz-linear-gradient(top, rgba($color,$amount) 0%, rgba($color,0) 100%); /* FF3.6-15 */
	background: -webkit-linear-gradient(top, rgba($color,$amount) 0%,rgba($color,0) 100%); /* Chrome10-25,Safari5.1-6 */
	background: linear-gradient(to bottom, rgba($color,$amount) 0%,rgba($color,0) 100%); /* W3C, IE10+, FF16+, Chrome26+, Opera12+, Safari7+ */
	filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#a6000000', endColorstr='#00000000',GradientType=0 ); /* IE6-9 */
}

////////////////
// COMPONENTS //
////////////////

// Header
.Header {
	@include generate-gradient($blackblack, 1);
	display: flex;
	padding: 40px ;
	position: fixed;
	top: 0;
	left: 0;
	width: 100vw;
	box-sizing: border-box;
	z-index: 5;
}

// Logo
.Logo {
	width: 151px;
	height: 41px;
	margin-right: 10px;
	transition: margin .125s ease;
	
	svg {
		transform: scale(.5);
		transform-origin: 0 0;
		
		path {
			fill: $red;
			transition: fill .125s ease;
		}
	}
	
	&:hover {
		cursor: pointer;
		margin-top: 2px;
		svg {
			path {
				fill: $white !important;
			}
		}
	}
}

// Navigation
.Navigation {
	ul {
		display: flex;
		height: 37px;
		align-items: center;
		padding: 0 10px;
		
		li {
			font-weight: 400;
			padding: 7px 10px;
			font-size: 14px;
			transition: background .125s ease;
			border-radius: 3px;
			
			&:hover {
				background: $red;
				cursor: pointer;
			}
		}
	}
}

// Search
.Search {
	align-items: center;
	justify-content: center;
	width: 100%;
	position: absolute;
	display: flex;
	justify-content: center;
	pointer-events: none;
	
	input {
		font-family: $font;
		font-weight: 300;
		font-size: 14px;
		height: 37px;
		width: 20%;
		background: transparent;
		color: $white;
		appearance: none;
		border: 0;
		border: 2px solid rgba($grey, .1);
		outline: none;
		border-radius: 37px;
		padding: 0 10px;
		pointer-events: all;
		transition: border .25s ease, width .125s ease .125s;
		
		&:focus {
			border: 2px solid $red;
			width: 30%;
		}
	}
}

// UserProfile
.UserProfile {
	margin-left: auto;
	
	// User
	.User {
		display: flex;
		
		.image {
			border-radius: 44px;
			margin-left: 10px;
			overflow: hidden;
			width: 44px;
			height: 44px;
			box-sizing: border-box;
			border: 3px solid transparent;
			transition: border .125s ease;
			
			img {
				width: 100%;
				display: block;
			}
		}
		
		.name {
			align-items: center;
			display: flex;
			font-size: 18px;
			font-weight: 300;
			height: 44px;
		}
		
		&:hover {
			cursor: pointer;
			.image {
				border: 3px solid $red;
			}
		}
	}
	
	// UserProfile-menu
	.UserProfile-menu {
		display: none;
	}
}

// Hero Image
.Hero {
	width: 100%;
	position: relative;
	background-size: cover;
	min-height: 800px;
	
	.content {
		position: relative;
		z-index: 4;
		width: 500px;
		left: 10vw;
		top: 10vw;
		
		.logo {
			max-width: 400px;
			display: block;
			position: relative;
			left: -5px;
		}
		
		p {
			width: 100%;
		}
		
		.button-wrapper {
			display: flex;
			width: 400px;
			margin-top: 30px;
			
			.Button:first-child {
				margin-right: 10px;
			}
		}
	}
	
	.overlay {
		@include generate-gradient($black, 1);
		height: 100%;
		position: absolute;
		z-index: 3;
		top: 0;
		left: 0;
		width: 100%;
		transform: rotate(180deg);
	}
}

// Button
.Button {
	background: transparent;
	display: flex;
	height: 44px;
	align-items: center;
	justify-content: center;
	text-decoration: none;
	color: $white;
	padding: 20px;
	box-sizing: border-box;
	border: 2px solid rgba($grey, .2);
	border-radius: 44px;
	font-size: 14px;
	font-weight: 600;
	transition: border .125s ease, background .125s ease;
	
	&:hover {
		border: 2px solid $grey;
	}
	
	&[data-primary='true'] {
		border: 2px solid $red;
		
		&:hover {
			background: $red;
		}
	}
}

// TitleList
.Hero ~ .TitleList:nth-child(3) {
	margin-top: -10vw;
	position: relative;
	z-index: 4;
}

// Hack for first after Hero
.TitleList {
	padding: 20px 40px;
	box-sizing: border-box;
	transition: opacity 3s ease;
	opacity: 0;
	
	.Title {
		@extend h2;
	}
	
	.titles-wrapper {
		display: flex;
		flex-wrap: wrap;
		margin: 20px 0;
		
		width: calc(100vw - 80px);
		box-sizing: border-box;
		justify-content: space-between;
		
	}
	
	// Animation
	
	&[data-loaded='true'] {
		opacity: 1;
	}
}

// Item
.Item {
	width: calc(20% - 10px);
	min-width: calc(20% - 10px);
	background-color: $blackblack;
	flex: 1 0 auto;
	background-position: center;
	background-size: 100%;
	height: 200px;
	background-repeat: no-repeat;
	overflow: hidden;
	margin-right: 10px;
	transition: background 1s ease;
	
	&:nth-child(n+6) {
		margin-top: 20px;
	}
	
	&:last-child {
		margin-right: 0;
	}
	
	.overlay {
		@include generate-gradient($blackblack, .75);
		padding: 20px;
		position: relative;
		height: 100%;
		pointer-events: none;
		opacity: 0;
		transition: opacity .125s ease;
		
		.title {
			font-size: 22px;
			font-weight: 200;
			opacity: 0;
			
			transition: opacity .25s ease;
		}
		
		.rating {
			font-size: 14px;
			opacity: 0;
			
			transition: opacity .25s ease .125s;
		}
		
		.plot {
			$lines-to-show: 3;
			font-size: 14px;
			display: -webkit-box;
			margin-top: 100px;
			font-weight: 300;
			line-height: 1.6;
			opacity: 0;
			-webkit-line-clamp: $lines-to-show;
  		-webkit-box-orient: vertical;
			overflow: hidden;
  		text-overflow: ellipsis;
			
			transition: margin .25s ease .125s, opacity .25s ease .25s;
		}
	}
	
	&:hover {
		background-size: 150%;
		
		.overlay {
			opacity: 1;
			pointer-events: all;
			
			.plot {
				margin-top: 10px;
				opacity: 1;
			}
			
			.title {
				opacity: 1;
			}
			
			.rating {
				opacity: 1;
			}
			
			.ListToggle {
				opacity: 1;
			}
		}
	}
}

// Item [ANIMATION]

// ListToggle
.ListToggle {
	$size: 32px;
	border: 2px solid rgba($white, .2);
	width: $size;
	height: $size;
	font-size: $size / 2;
	border-radius: $size;
	overflow: hidden;
	position: absolute;
	right: 20px;
	top: 20px;
	opacity: 0;
	
	&:hover {
		border: 2px solid $white;
		div {
			top: - $size;
		}
	}
	
	&[data-toggled="true"] {
		background: $red;
		border: 2px solid $red;
		div {
			top: - $size;
		}
	}
	
	div {
		position: absolute;
		top: 0;
		left: 0;
		height: $size * 2;
		width: $size;
		transition: .125s ease;
		
		i {
			display: flex;
			align-items: center;
			justify-content: center;
			height: $size;
			width: $size;
		}
	}
}
View Compiled
/////////////////
/// COMPONENTS //
/////////////////

// Container
var App = React.createClass({
	apiKey: '87dfa1c669eea853da609d4968d294be',
	getInitialState: function() {
		return {data: []};
	},
	performSearch: function(e) {
		// stop form from submitting
		e.preventDefault();
		
		// get the value
		var val = $('.Search input').val();
		
		// Do the thing
		var requestUrl = 'https://api.themoviedb.org/3/search/multi?query=' + val + '&api_key=' + this.apiKey;
		
		$.ajax({
      url: requestUrl,
      dataType: 'json',
      cache: false,
      success: function(data) {
        this.setState({data: data});
      }.bind(this),
      error: function(xhr, status, err) {
        console.error(this.props.url, status, err.toString());
      }.bind(this)
    });
		
	},
	componentDidUpdate: function() {
	
	},
	render: function() {
		
		if(this.state.data.results) {
			console.log(this.state.data);
		}
		
		return (
			<div>
				<Header onSubmit={this.performSearch} />
				<Hero />
				<TitleList title="Top TV picks for Jack" url='discover/tv?sort_by=popularity.desc&page=1' />
				<TitleList title="Trending now" url='discover/movie?sort_by=popularity.desc&page=1' />
				<TitleList title="Most watched in Horror" url='genre/27/movies?sort_by=popularity.desc&page=1' />
				<TitleList title="Sci-Fi greats" url='genre/878/movies?sort_by=popularity.desc&page=1' />
				<TitleList title="Comedy magic" url='genre/35/movies?sort_by=popularity.desc&page=1' />
			</div>
		);
	}
});

////////////
// Header //
////////////

var Header = React.createClass({
	render: function() {
		return (
			<header className="Header">
				<Logo />
				<Navigation />
				<Search onSubmit={this.props.onSubmit} />
				<UserProfile />
			</header>
		);
	}
});

// Logo
var Logo = React.createClass({
	render: function() {
		return (
			<div id="logo" className="Logo">
				<svg version="1.1" width="300" height="81.386726" id="svg3262">
					<g transform="translate(-384.28572,-428.81172)" id="layer1">
						<g transform="matrix(2.5445375,0,0,2.5445375,1157.1714,-1457.8678)" id="g3235">
							<path d="m -203.09972,771.41415 c 1.6425,0.15875 3.2825,0.33 4.92,0.5075 l 3.615,-8.92625 3.43625,9.74875 c 1.76375,0.22125 3.525,0.4525 5.2825,0.695 l -6.02375,-17.09625 6.02625,-14.88 -5.10375,0 -0.0525,0.0725 -3.255,8.03875 -2.8575,-8.11125 -5.03875,0 5.2025,14.7625 -6.15125,15.18875 z" id="path3015" style={{fill:'#b81d24', fillOpacity: 1, fillRule:'nonzero', stroke:'none'}} />
							<path d="m -206.91147,771.06478 0,-29.60125 -5.0375,0 0,29.18625 c 1.68125,0.12875 3.36125,0.26875 5.0375,0.415" id="path3019" style={{fill:'#b81d24', fillOpacity: 1, fillRule:'nonzero', stroke:'none'}} />
							<path d="m -244.7486,769.4089 c 1.36,0 2.7175,0.01 4.07375,0.0213 l 0,-10.875 6.05125,0 0,-4.63125 -6.05125,0 0,-7.825 6.96875,0 0,-4.63625 -12.02625,0 0,27.95 c 0.3275,0 0.655,-0.004 0.98375,-0.004" id="path3023" style={{fill:'#b81d24', fillOpacity: 1, fillRule:'nonzero', stroke:'none'}} />
							<path d="m -260.3881,769.69191 c 1.6775,-0.06 3.3575,-0.11 5.04,-0.15125 l 0,-23.44125 4.7075,0 0,-4.63625 -14.45625,0 0,4.63625 4.70875,0 0,23.5925 z" id="path3035" style={{fill:'#b81d24', fillOpacity: 1, fillRule:'nonzero', stroke:'none'}} />
							<path d="m -298.91059,772.81378 0,-17.63625 5.96375,16.92375 c 1.83375,-0.20625 3.67125,-0.4 5.5125,-0.5825 l 0,-30.055 -4.8325,0 0,18.2675 -6.43625,-18.2675 -0.2075,0 -4.8325,0 0,31.98375 0.03,0 c 1.5975,-0.22125 3.19875,-0.43125 4.8025,-0.63375" id="path3039" style={{fill:'#b81d24', fillOpacity: 1, fillRule:'nonzero', stroke:'none'}} />
							<path d="m -269.95297,746.09903 0,-4.63625 -12.0275,0 0,24.9125 0,4.6375 0,0.004 c 3.99125,-0.345 7.99625,-0.63375 12.0175,-0.86875 l 0,-0.004 0,-1.33625 0,-3.3 c -2.325,0.135 -4.645,0.29125 -6.96,0.46375 l 0,-7.415 6.05125,0 0,-4.63375 -6.05125,0 0,-7.82375 6.97,0 z" id="path3051" style={{fill:'#b81d24', fillOpacity: 1, fillRule:'nonzero', stroke:'none'}} />
							<path d="m -223.72272,765.2864 0,-23.82375 -5.05875,0 0,23.605 0,4.63625 0,0.005 c 4.02375,0.1475 8.0325,0.35375 12.0275,0.6125 l 0,-0.006 0,-1.4975 0,-3.13875 c -2.31875,-0.15 -4.64125,-0.28 -6.96875,-0.3925" id="path3055" style={{fill:'#b81d24', fillOpacity: 1, fillRule:'nonzero', stroke:'none'}} />
						</g>
					</g>
				</svg>
			</div>
		);
	}
});

// Navigation
var Navigation = React.createClass({
	render: function() {
		return (
			<div id="navigation" className="Navigation">
				<nav>
					<ul>
						<li>Browse</li>
						<li>My list</li>
						<li>Top picks</li>
						<li>Recent</li>
					</ul>
				</nav>
			</div>
		);
	}
});

// Search
var Search = React.createClass({
	render: function() {
		return (
			<form onSubmit={this.props.onSubmit} id="search" className="Search">
				<input type="search" placeholder="Search for a title..." />
			</form>
		);
	}
});

// User Profile
var UserProfile = React.createClass({
	render: function() {
		return (
			<div className="UserProfile">
				<div className="User">
					<div className="name">Jack Oliver</div>
					<div className="image"><img src="https://s3-us-west-2.amazonaws.com/s.cdpn.io/557257/profile/profile-512_1.jpg" /></div>
				</div>
				<div className="UserProfile-menu">
					<div className="UserProfileSwitch">
						<ul>
							<li>
								<div className="UserProfile-image">
									<img src="http://lorempixel.com/96/96" />
								</div>
								<div className="UserProfile-name">
									Alexander
								</div>
							</li>
							<li>
								<div className="UserProfile-image">
									<img src="http://lorempixel.com/96/96" />
								</div>
								<div className="UserProfile-name">
									Mattias
								</div>
							</li>
						</ul>
					</div>
					<div className="UserNavigation">
						<ul>
							<li>Your Account</li>
							<li>Help Center</li>
							<li>Sign out of Netflix</li>
						</ul>
					</div>
				</div>
			</div>
		);
	}
});

//////////
// Hero //
//////////

var Hero = React.createClass({
	render: function() {
		return (
			<div id="hero" className="Hero" style={{backgroundImage: 'url(https://images.alphacoders.com/633/633643.jpg)'}}>
				<div className="content">
					<img className="logo" src="http://www.returndates.com/backgrounds/narcos.logo.png" alt="" />
					<h2>Season 2 now available</h2>
					<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Doloremque id quam sapiente unde voluptatum alias vero debitis, magnam quis quod.</p>
					<div className="button-wrapper">
						<HeroButton primary={true} text="Watch now" />
						<HeroButton primary={false} text="+ My list" />
					</div>
				</div>
				<div className="overlay"></div>
			</div>
		);
	}
})

// Hero Button
var HeroButton = React.createClass({
	render: function() {
		return (
			<a href="#" className="Button" data-primary={this.props.primary}>{this.props.text}</a>
		);
	}
})

////////////////
// Title List //
////////////////

// Title List Container

var TitleList = React.createClass({
	apiKey: '87dfa1c669eea853da609d4968d294be',
	getInitialState: function() {
		return {data: [], mounted: false};
	},
	loadContent: function() {
		var requestUrl = 'https://api.themoviedb.org/3/' + this.props.url + '&api_key=' + this.apiKey;
		
		$.ajax({
      url: requestUrl,
      dataType: 'json',
      cache: false,
      success: function(data) {
        this.setState({data: data});
				// console.log(data);
      }.bind(this),
      error: function(xhr, status, err) {
        console.error(this.props.url, status, err.toString());
      }.bind(this)
    });
	},
	componentDidMount: function() {
		this.loadContent();
		this.setState({ mounted: true });
	},
	componentWillUnmount: function() {
		this.setState({ mounted: false });
	},
	render: function() {
		if(this.state.data.results) {
			var titles = this.state.data.results.map(function(title, i) {
				if(i < 5) {

					var backDrop = 'http://image.tmdb.org/t/p/original' + title.backdrop_path;
					if(!title.name) {
						var name = title.original_title;
					} else {
						var name = title.name;
					}

					return (
						<Item key={title.id} title={name} score={title.vote_average} overview={title.overview} backdrop={backDrop} />
					);	

				}
			});	

		} else {
			var titles = '';
		}
		
		return (
			<div ref="titlecategory" className="TitleList" data-loaded={this.state.mounted}>
				<div className="Title">
					<h1>{this.props.title}</h1>
					<div className="titles-wrapper">
						{titles}
					</div>
				</div>
			</div>
		);
	}
});

// Title List Item
var Item = React.createClass({
	render: function() {
		return (
			<div className="Item" style={{backgroundImage: 'url(' + this.props.backdrop + ')'}} >
				<div className="overlay">
					<div className="title">{this.props.title}</div>
					<div className="rating">{this.props.score} / 10</div>
					<div className="plot">{this.props.overview}</div>
					<ListToggle />
				</div>
			</div>
		);
	}
});

// ListToggle
var ListToggle = React.createClass({
	getInitialState: function() {
		return({ toggled: false })
	},
	handleClick: function() {
		if(this.state.toggled === true) {
			this.setState({ toggled: false });
		} else {
			this.setState({ toggled: true });	
		}
		
	},
	render: function() {
		return (
			<div onClick={this.handleClick} data-toggled={this.state.toggled} className="ListToggle">
				<div>
					<i className="fa fa-fw fa-plus"></i>
					<i className="fa fa-fw fa-check"></i>
				</div>
			</div>
		);
	}
});



ReactDOM.render(
	<App />,
	document.getElementById('app')
);
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/react/0.14.0/react.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/react/0.14.0/react-dom.min.js
  3. https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js