Merge pull request #130 from entozoon/master

Simple react-based display page for the list
This commit is contained in:
Nikolaos Kamarinakis 2017-08-29 15:48:23 +03:00 committed by GitHub
commit 62b3cd926d
10 changed files with 6444 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
node_modules

View File

@ -13,6 +13,8 @@ Check out my [blog](https://nikolaskama.me/) and follow me on [Twitter](https://
## Contents
## [View the sortable version](https://k4m4.github.io/movies-for-hackers/)
- [Movies For Hackers](#movies-for-hackers)
- [Thrillers/Drama](#thrillers--drama)
- [Science Fiction/Fantasy](#science-fiction--fantasy)

1
dist/css/app.css vendored Normal file
View File

@ -0,0 +1 @@
body{font-size:calc(10px + .5vw);padding:0 0 30px;font-family:Play,sans-serif;background:#000;color:#47c101}.container-fluid{max-width:1440px;overflow:auto}h1,h2,h3{color:#ba4ee4}h2{font-size:20px}a{color:#df3968}a:hover{color:#fff}th{position:relative;text-transform:capitalize;background:#052c36;color:#15afd9}.react-bs-table{border:1px solid #052c36;border-radius:2px;margin:0}.react-bs-table table td,.react-bs-table table th{white-space:normal;word-break:break-word}.table>tbody>tr>td,.table>tbody>tr>th,.table>tfoot>tr>td,.table>tfoot>tr>th,.table>thead>tr>td,.table>thead>tr>th{border-color:#052c36;padding:1px calc(0px + 1vw)}.table>tbody>tr>th,.table>tfoot>tr>th,.table>thead>tr>th{padding-right:20px}.table-hover>tbody>tr:hover{background:#060f00}td:nth-child(1),th:nth-child(1){width:50%}td:nth-child(2),th:nth-child(2){width:22%}td:nth-child(3),th:nth-child(3){width:14%}td:nth-child(4),th:nth-child(4){width:14%}.order{position:absolute;top:1px;right:3px}

1
dist/js/app.js vendored Normal file
View File

@ -0,0 +1 @@
"use strict";function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function _possibleConstructorReturn(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function _inherits(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var _createClass=function(){function e(e,t){for(var o=0;o<t.length;o++){var n=t[o];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}return function(t,o,n){return o&&e(t.prototype,o),n&&e(t,n),t}}(),client=new XMLHttpRequest,objectifyMarkdownNotWomen=new marked.Renderer,moviesCollection,movies,cellCounter=0,lastHeading="",headers=["movie","genre","year","rating"],parseNowt=function(e,t){return e},parseTheImdb=function(e,t){if(null!=e)return e.replace("/10","")},Table=function(e){function t(e){_classCallCheck(this,t);var o=_possibleConstructorReturn(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e));return o.movies=e.movies,o.columns=[],headers.map(function(e,t){var n=0==t,r="rating"==e;o.columns.push(React.createElement(TableHeaderColumn,{key:t,isKey:n,dataFormat:r?parseTheImdb:parseNowt,dataField:e,dataSort:!0},e))}),o}return _inherits(t,e),_createClass(t,[{key:"render",value:function(){return React.createElement(BootstrapTable,{data:this.movies,hover:!0},this.columns)}}]),t}(React.Component);objectifyMarkdownNotWomen.heading=function(e,t){lastHeading=e},objectifyMarkdownNotWomen.tablerow=function(e){cellCounter=0,movies.push({})},objectifyMarkdownNotWomen.tablecell=function(e,t){movies[movies.length-1][headers[cellCounter]]=e,cellCounter++},objectifyMarkdownNotWomen.table=function(e,t){movies[0][headers[0]].toLowerCase()==headers[0]&&movies.splice(0,1),null==movies[movies.length-1][headers[0]]&&movies.pop(),moviesCollection.push({heading:lastHeading,movies:movies}),movies=[{}]},client.open("GET",window.location.href+"README.md"),client.onreadystatechange=function(e){document.getElementById("root").innerHTML="",moviesCollection=[],movies=[{}],marked(client.responseText,{renderer:objectifyMarkdownNotWomen},function(){if(null!=moviesCollection[0]){console.log(moviesCollection);var e=[];moviesCollection.map(function(t,o){e.push(React.createElement("div",{key:o},React.createElement("h2",null,t.heading),React.createElement(Table,{movies:t.movies})))}),ReactDOM.render(React.createElement("div",null,e),document.getElementById("root"))}})},client.send();

29
index.html Normal file
View File

@ -0,0 +1,29 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Movies for Hackers</title>
<meta name="description" content="movies-for-hackers - 🎬 A curated list of movies every hacker &amp; cyberpunk must watch.">
<meta name="viewport" content="initial-scale=0.75"/>
<link href="https://fonts.googleapis.com/css?family=Play" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"/>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/react-bootstrap-table/3.0.0/react-bootstrap-table-all.min.css"/>
<link rel="stylesheet" type="text/css" href="dist/css/app.css"/>
</head>
<body>
<div class="container-fluid">
<h1>Movies For Hackers</h1>
<p>Every aspiring hacker &amp; cyberpunk must watch these movies - drawing directly from the impressive <a href="https://github.com/k4m4/movies-for-hackers">curated list</a> from <a href="https://github.com/k4m4">Nikolaos Kamarinakis</a></p>
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.1/react-dom.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-bootstrap-table/3.0.0/react-bootstrap-table.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.6/marked.min.js"></script>
<script src="dist/js/app.js"></script>
</div>
</body>
</html>

22
lapisconfig.json Normal file
View File

@ -0,0 +1,22 @@
{
"css": [
{
"watch": [
"src/scss/**/*.scss"
],
"src": "src/scss/app.scss",
"dest": "./dist/css",
"filename": "app.css"
}
],
"js": [
{
"watch": [
"src/js/**/*.js"
],
"src": "src/js/app.js",
"dest": "dist/js",
"filename": "app.js"
}
]
}

6136
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

6
package.json Normal file
View File

@ -0,0 +1,6 @@
{
"dependencies": {
"babel-preset-react": "^6.23.0",
"lapis-compiler": "^1.5.7"
}
}

146
src/js/app.js Normal file
View File

@ -0,0 +1,146 @@
/**
* Vars
*/
var client = new XMLHttpRequest(),
objectifyMarkdownNotWomen = new marked.Renderer(),
moviesCollection,
movies,
cellCounter = 0,
lastHeading = '',
headers = ['movie', 'genre', 'year', 'rating'];
/**
* React Table Component
* Using https://github.com/AllenFang/react-bootstrap-table
*/
const parseNowt = (cell, row) => {
return cell;
};
const parseTheImdb = (cell, row) => {
// Make it like 7.1 rather than 7.1/10, we all know what it's out of.
if (cell != null) {
return cell.replace('/10', '');
}
};
class Table extends React.Component {
// Runs on init
constructor(props) {
// pass props to the base constructor:
super(props);
this.movies = props.movies;
this.columns = [];
// Create table headers (the rest is all handled by the plugin)
headers.map((header, i) => {
let isFirstItem = i == 0,
parseImdb = header == 'rating';
this.columns.push(
<TableHeaderColumn
key={i}
isKey={isFirstItem}
dataFormat={parseImdb ? parseTheImdb : parseNowt}
dataField={header}
dataSort={true}
>
{header}
</TableHeaderColumn>
);
});
}
// Runs on render
render() {
return (
<BootstrapTable data={this.movies} hover={true}>
{this.columns}
</BootstrapTable>
);
}
}
/**
* Custom renderer for Marked plugin
* Turning the parsed markdown into an array of objects
*/
objectifyMarkdownNotWomen.heading = function(heading, level) {
lastHeading = heading;
};
objectifyMarkdownNotWomen.tablerow = function(content) {
cellCounter = 0;
movies.push({});
};
objectifyMarkdownNotWomen.tablecell = function(content, flags) {
movies[movies.length - 1][headers[cellCounter]] = content;
cellCounter++;
};
objectifyMarkdownNotWomen.table = function(header, body) {
// Test if the first movie object is actually just the headers (which it will be)
if (movies[0][headers[0]].toLowerCase() == headers[0]) {
movies.splice(0, 1);
}
// Similarly, test if the very last movie object is empty and pop it
if (movies[movies.length - 1][headers[0]] == null) {
movies.pop();
}
// Add movies to collection
moviesCollection.push({
heading: lastHeading,
movies: movies
});
movies = [{}];
};
// Ajax the markdown file with all movie data
client.open('GET', window.location.href + 'README.md');
client.onreadystatechange = function(e) {
// Wipe movies, collections and content as this'll run a bunch of times
document.getElementById('root').innerHTML = '';
moviesCollection = [];
movies = [{}];
/*
// Test markdown:
marked("## Thrillers / Drama\n\n| MOVIE | GENRE | YEAR | RATING |\n|--------------------------------------------------------------------------------------------|---------------------------|------|--------|\n| [WarGames: The Dead Code](http://www.imdb.com/title/tt0865957/) | Thriller/Drama | 2008 | 4.5/10 |\n| [WarGames](http://www.imdb.com/title/tt0086567/) | Thriller/Drama | 1983 | 7.1/10 |\n| [Hackers](http://www.imdb.com/title/tt0113243/) | Crime/Drama | 1995 | 6.2/10 |\n\n## Science Fiction / Fantasy\n\n| MOVIE | GENRE | YEAR | RATING |\n|--------------------------------------------------------------------------------------------|---------------------------|------|--------|\n| [The Matrix](http://www.imdb.com/title/tt0133093/) | Fantasy/Action | 1999 | 8.7/10 |\n| [The Lawnmower Man](http://www.imdb.com/title/tt0104692/) | Fantasy/Action | 1992 | 5.4/10 |", {
*/
marked(
client.responseText,
{
renderer: objectifyMarkdownNotWomen
},
function() {
if (moviesCollection[0] == null) {
return;
}
console.log(moviesCollection);
//document.body.innerHTML = JSON.stringify(moviesCollection);
// Create JSX for tables of each set of movies in moviesCollection
var moviesCollectionJSX = [];
moviesCollection.map((movies, i) => {
moviesCollectionJSX.push(
<div key={i}>
<h2>
{movies.heading}
</h2>
<Table movies={movies.movies} />
</div>
);
});
ReactDOM.render(
<div>
{moviesCollectionJSX}
</div>,
document.getElementById('root')
);
}
);
};
client.send();

100
src/scss/app.scss Normal file
View File

@ -0,0 +1,100 @@
$brand-primary: #ba4ee4;
$brand-secondary: #47c101;
$brand-tertiary: #15afd9;
$headings-color: $brand-primary;
$link-color: #df3968;
$border-color: adjust-color($brand-tertiary, $lightness: -35%);
body {
font-size: calc(10px + .5vw);
padding: 0 0 30px;
font-family: 'Play', sans-serif;
background: black;
color: $brand-secondary;
}
.container-fluid {
max-width: 1440px;
overflow: auto;
}
h1,
h2,
h3 {
color: $headings-color;
}
h2 {
font-size: 20px;
}
a {
color: $link-color;
&:hover {
color: white;
}
}
th {
position: relative;
text-transform: capitalize;
background: $border-color;
color: $brand-tertiary;
}
.react-bs-table {
border: 1px solid $border-color;
border-radius: 2px;
margin: 0;
&,
& table {
// We can't do this because, unbelievably, the <th> elements are in a separate table :( // table-layout: auto;
}
table {
td,
th {
// Override some bananas styles
// Why did they think nowrap was a smart idea? Fuck mobiles, right?
white-space: normal;
word-break: break-word;
}
}
}
.table {
// Cells
> thead,
> tbody,
> tfoot {
> tr {
> th,
> td {
border-color: $border-color;
padding: 1px calc(0px + 1vw);
}
> th {
padding-right: 20px;
}
}
}
}
.table-hover {
> tbody {
> tr:hover {
background: adjust-color($brand-secondary, $lightness: -35%);
}
}
}
// Quick solution to the forced table-layout: fixed
th,
td {
&:nth-child(1) {
width: 50%;
}
&:nth-child(2) {
width: 22%;
}
&:nth-child(3) {
width: 14%;
}
&:nth-child(4) {
width: 14%;
}
}
.order {
position: absolute;
top: 1px;
right: 3px;
}