Add movie list with react
This commit is contained in:
parent
4e0faabf06
commit
b20400b30f
@ -6,6 +6,7 @@ import webpack from 'webpack-stream';
|
|||||||
import webpackConfig from './webpack.config.babel';
|
import webpackConfig from './webpack.config.babel';
|
||||||
|
|
||||||
const paths = {
|
const paths = {
|
||||||
|
allSrcJs: 'src/**/*.js?(x)',
|
||||||
jsSrc: 'src/public/js/app.js',
|
jsSrc: 'src/public/js/app.js',
|
||||||
jsDistDir: 'build/public/js',
|
jsDistDir: 'build/public/js',
|
||||||
lessSrc: 'src/public/less/app.less',
|
lessSrc: 'src/public/less/app.less',
|
||||||
@ -17,8 +18,8 @@ const paths = {
|
|||||||
fontDest: 'build/public/fonts',
|
fontDest: 'build/public/fonts',
|
||||||
imgSrc: 'src/public/img/*',
|
imgSrc: 'src/public/img/*',
|
||||||
imgDest: 'build/public/img/',
|
imgDest: 'build/public/img/',
|
||||||
goTemplatesSrc: 'src/templates/**/*.tmpl',
|
htmlSrc: 'src/public/index.html',
|
||||||
goTemplatesDest: 'build/templates/',
|
htmlDest: 'build/public/',
|
||||||
gulpFile: 'gulpfile.babel.js',
|
gulpFile: 'gulpfile.babel.js',
|
||||||
webpackFile: 'webpack.config.babel.js',
|
webpackFile: 'webpack.config.babel.js',
|
||||||
};
|
};
|
||||||
@ -41,23 +42,24 @@ gulp.task('images', () =>
|
|||||||
.pipe(gulp.dest(paths.imgDest))
|
.pipe(gulp.dest(paths.imgDest))
|
||||||
);
|
);
|
||||||
|
|
||||||
gulp.task('go-templates', () =>
|
gulp.task('html', () =>
|
||||||
gulp.src(paths.goTemplatesSrc)
|
gulp.src(paths.htmlSrc)
|
||||||
.pipe(gulp.dest(paths.goTemplatesDest))
|
.pipe(gulp.dest(paths.htmlDest))
|
||||||
);
|
);
|
||||||
|
|
||||||
gulp.task('main', ['less', 'fonts', 'images'], () =>
|
gulp.task('js', () =>
|
||||||
gulp.src(paths.jsSrc)
|
gulp.src(paths.jsSrc)
|
||||||
.pipe(webpack(webpackConfig))
|
.pipe(webpack(webpackConfig))
|
||||||
.pipe(gulp.dest(paths.jsDistDir))
|
.pipe(gulp.dest(paths.jsDistDir))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
gulp.task('main', ['less', 'fonts', 'images', 'html', 'js'])
|
||||||
|
|
||||||
gulp.task('watch', () => {
|
gulp.task('watch', () => {
|
||||||
gulp.watch(paths.jsSrc, ['main']);
|
gulp.watch(paths.allSrcJs, ['js']);
|
||||||
gulp.watch(paths.gulpFile, ['main']);
|
|
||||||
gulp.watch(paths.lessSrc, ['less']);
|
gulp.watch(paths.lessSrc, ['less']);
|
||||||
gulp.watch(paths.imgSrc, ['images']);
|
gulp.watch(paths.imgSrc, ['images']);
|
||||||
gulp.watch(paths.goTemplatesSrc, ['go-templates']);
|
gulp.watch(paths.htmlSrc, ['html']);
|
||||||
});
|
});
|
||||||
|
|
||||||
gulp.task('default', ['watch', 'main']);
|
gulp.task('default', ['watch', 'main']);
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
"react-dom": "^15.3.2"
|
"react-dom": "^15.3.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"axios": "^0.15.2",
|
||||||
"babel": "^6.5.2",
|
"babel": "^6.5.2",
|
||||||
"babel-loader": "^6.2.7",
|
"babel-loader": "^6.2.7",
|
||||||
"babel-preset-latest": "^6.16.0",
|
"babel-preset-latest": "^6.16.0",
|
||||||
|
16
src/public/index.html
Normal file
16
src/public/index.html
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<title>Canape</title>
|
||||||
|
|
||||||
|
<link href="/css/app.css" rel="stylesheet">
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="app"></div>
|
||||||
|
<script src="/js/app.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -1,32 +1,26 @@
|
|||||||
require('jquery');
|
import React from 'react'
|
||||||
|
import ReactDOM from 'react-dom'
|
||||||
|
import NavBar from './navbar.jsx'
|
||||||
|
import MovieList from './movie-list.jsx'
|
||||||
|
|
||||||
if($('#movie-library').length >0 ){
|
class App extends React.Component {
|
||||||
listSelector();
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="navbar navbar-inverse navbar-fixed-top">
|
||||||
|
<NavBar />
|
||||||
|
</div>
|
||||||
|
<div className="container-fluid">
|
||||||
|
<div className="container">
|
||||||
|
<MovieList />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Help select elements form the list views
|
ReactDOM.render(
|
||||||
function listSelector() {
|
<App />,
|
||||||
let $first = $(".thumbnail").first();
|
document.getElementById('app')
|
||||||
$first.addClass('thumbnail-selected');
|
);
|
||||||
|
|
||||||
// Get the detail
|
|
||||||
var $detail = $("#"+$first.data("imdbid")+"-detail" );
|
|
||||||
// Show it
|
|
||||||
$detail.removeClass("hidden");
|
|
||||||
$detail.addClass("show");
|
|
||||||
|
|
||||||
$(".thumbnail").click(function(e) {
|
|
||||||
e.preventDefault();
|
|
||||||
// Hide previous details
|
|
||||||
$(".movie-detail.show" ).addClass("hidden").removeClass("show");
|
|
||||||
|
|
||||||
// Change border on selected item
|
|
||||||
$('.thumbnail-selected').removeClass('thumbnail-selected');
|
|
||||||
$(this).addClass('thumbnail-selected');
|
|
||||||
|
|
||||||
// Get the detail
|
|
||||||
var $detail = $("#"+$(this).data("imdbid")+"-detail" );
|
|
||||||
// Show it
|
|
||||||
$detail.removeClass("hidden").addClass("show");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
107
src/public/js/movie-list.jsx
Normal file
107
src/public/js/movie-list.jsx
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import axios from 'axios'
|
||||||
|
|
||||||
|
function MoviePosters(props) {
|
||||||
|
const movies = props.movies;
|
||||||
|
return (
|
||||||
|
<div className="col-xs-5 col-md-8">
|
||||||
|
<div className="row">
|
||||||
|
{movies.map((movie, index) =>
|
||||||
|
<MoviePoster
|
||||||
|
data={movie}
|
||||||
|
key={movie.ID}
|
||||||
|
onClick={ (e) => props.onClick(e, index) }
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function MoviePoster(props) {
|
||||||
|
const imgUrl = '/img/movies/' + props.data.imdb_id +'.jpg';
|
||||||
|
const selected = props.data.selected ? ' thumbnail-selected' : '';
|
||||||
|
const imgClass = 'thumbnail' + selected;
|
||||||
|
return (
|
||||||
|
<div className="col-xs-12 col-md-3">
|
||||||
|
<a className={imgClass}>
|
||||||
|
<img src={imgUrl} onClick={props.onClick}/>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function MovieDetails(props) {
|
||||||
|
return (
|
||||||
|
<div className="col-xs-7 col-md-4">
|
||||||
|
<div className="movie-detail affix">
|
||||||
|
<h1 className="hidden-xs">{props.data.title}</h1>
|
||||||
|
<h3 className="visible-xs">{props.data.title}</h3>
|
||||||
|
<p>
|
||||||
|
<i className="fa fa-clock-o"></i>
|
||||||
|
{props.data.runtime} min
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<i className="fa fa-star-o"></i>
|
||||||
|
{props.data.rating} <small>({props.data.votes} counts)</small>
|
||||||
|
</p>
|
||||||
|
<p className="movie-plot">{props.data.plot}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class MovieList extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
movies: [],
|
||||||
|
currentMovie: {},
|
||||||
|
};
|
||||||
|
this.handleClick = this.handleClick.bind(this);
|
||||||
|
}
|
||||||
|
handleClick(e,i) {
|
||||||
|
e.preventDefault();
|
||||||
|
let movies = this.state.movies.slice();
|
||||||
|
this.setMovies(movies, i);
|
||||||
|
}
|
||||||
|
setMovies(movies, index) {
|
||||||
|
let currentMovie = {};
|
||||||
|
movies.map(function(movie) {
|
||||||
|
movie.selected = false;
|
||||||
|
return {movie: movie};
|
||||||
|
});
|
||||||
|
if (!index && movies.length) {
|
||||||
|
index = 0;
|
||||||
|
currentMovie = movies[0];
|
||||||
|
}
|
||||||
|
if (index !== null) {
|
||||||
|
currentMovie = movies[index];
|
||||||
|
movies[index].selected = true;
|
||||||
|
}
|
||||||
|
this.setState({
|
||||||
|
movies: movies,
|
||||||
|
currentMovie: currentMovie,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
componentDidMount() {
|
||||||
|
var _this = this;
|
||||||
|
this.serverRequest =
|
||||||
|
axios
|
||||||
|
.get("/movies/explore/popular")
|
||||||
|
.then(function(result) {
|
||||||
|
_this.setMovies(result.data.Data.movies);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
componentWillUnmount() {
|
||||||
|
this.serverRequest.abort();
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="row" id="movie-library">
|
||||||
|
<MoviePosters movies={this.state.movies} onClick={this.handleClick}/>
|
||||||
|
<MovieDetails data={this.state.currentMovie} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
22
src/public/js/navbar.jsx
Normal file
22
src/public/js/navbar.jsx
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
export default class NavBar extends React.Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div className="container-fluid">
|
||||||
|
<div className="navbar-header">
|
||||||
|
<button type="button" className="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
|
||||||
|
<span className="sr-only">Toggle navigation</span>
|
||||||
|
<span className="icon-bar"></span>
|
||||||
|
<span className="icon-bar"></span>
|
||||||
|
<span className="icon-bar"></span>
|
||||||
|
</button>
|
||||||
|
<a className="navbar-brand" href="#">Canape</a>
|
||||||
|
</div>
|
||||||
|
<div className="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
|
||||||
|
<ul className="nav navbar-nav"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
15
yarn.lock
15
yarn.lock
@ -159,6 +159,12 @@ aws4@^1.2.1:
|
|||||||
version "1.5.0"
|
version "1.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.5.0.tgz#0a29ffb79c31c9e712eeb087e8e7a64b4a56d755"
|
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.5.0.tgz#0a29ffb79c31c9e712eeb087e8e7a64b4a56d755"
|
||||||
|
|
||||||
|
axios:
|
||||||
|
version "0.15.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/axios/-/axios-0.15.2.tgz#496f50980b2ce1ad2e195af93c2d03b4d035e90d"
|
||||||
|
dependencies:
|
||||||
|
follow-redirects "0.0.7"
|
||||||
|
|
||||||
babel-code-frame@^6.16.0:
|
babel-code-frame@^6.16.0:
|
||||||
version "6.16.0"
|
version "6.16.0"
|
||||||
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.16.0.tgz#f90e60da0862909d3ce098733b5d3987c97cb8de"
|
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.16.0.tgz#f90e60da0862909d3ce098733b5d3987c97cb8de"
|
||||||
@ -1207,6 +1213,13 @@ flagged-respawn@^0.3.2:
|
|||||||
version "0.3.2"
|
version "0.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/flagged-respawn/-/flagged-respawn-0.3.2.tgz#ff191eddcd7088a675b2610fffc976be9b8074b5"
|
resolved "https://registry.yarnpkg.com/flagged-respawn/-/flagged-respawn-0.3.2.tgz#ff191eddcd7088a675b2610fffc976be9b8074b5"
|
||||||
|
|
||||||
|
follow-redirects@0.0.7:
|
||||||
|
version "0.0.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-0.0.7.tgz#34b90bab2a911aa347571da90f22bd36ecd8a919"
|
||||||
|
dependencies:
|
||||||
|
debug "^2.2.0"
|
||||||
|
stream-consume "^0.1.0"
|
||||||
|
|
||||||
font-awesome@^4.7.0:
|
font-awesome@^4.7.0:
|
||||||
version "4.7.0"
|
version "4.7.0"
|
||||||
resolved "https://registry.yarnpkg.com/font-awesome/-/font-awesome-4.7.0.tgz#8fa8cf0411a1a31afd07b06d2902bb9fc815a133"
|
resolved "https://registry.yarnpkg.com/font-awesome/-/font-awesome-4.7.0.tgz#8fa8cf0411a1a31afd07b06d2902bb9fc815a133"
|
||||||
@ -2827,7 +2840,7 @@ stream-browserify@^1.0.0:
|
|||||||
inherits "~2.0.1"
|
inherits "~2.0.1"
|
||||||
readable-stream "^1.0.27-1"
|
readable-stream "^1.0.27-1"
|
||||||
|
|
||||||
stream-consume@~0.1.0:
|
stream-consume@^0.1.0, stream-consume@~0.1.0:
|
||||||
version "0.1.0"
|
version "0.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/stream-consume/-/stream-consume-0.1.0.tgz#a41ead1a6d6081ceb79f65b061901b6d8f3d1d0f"
|
resolved "https://registry.yarnpkg.com/stream-consume/-/stream-consume-0.1.0.tgz#a41ead1a6d6081ceb79f65b061901b6d8f3d1d0f"
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user