Skip to content

Commit e394ef9

Browse files
committedSep 15, 2017
add client
1 parent 0985af3 commit e394ef9

33 files changed

+63364
-0
lines changed
 

‎.eslintignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
client/.eslintignore

‎.eslintrc.json

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
client/.eslintrc.json

‎.sass-lint.yml

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
client/.sass-lint.yml

‎PULL_REQUEST_TEMPLATE

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
## Background
2+
- Include some background information about your PR
3+
4+
5+
## Changes
6+
- Include a list of changes involved in your PR
7+
- If you can add an image
8+
9+
## Test on []()

‎bin/www

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
#!/usr/bin/env node
2+
3+
/**
4+
* Module dependencies.
5+
*/
6+
7+
var app = require('../dist/app');
8+
var debug = require('debug')('server');
9+
var http = require('http');
10+
11+
debug.log = console.log.bind(console);
12+
13+
/**
14+
* Get port from environment and store in Express.
15+
*/
16+
17+
var port = normalizePort(process.env.PORT || '3000');
18+
app.set('port', port);
19+
20+
/**
21+
* Create HTTP server.
22+
*/
23+
24+
var server = http.createServer(app);
25+
26+
/**
27+
* Listen on provided port, on all network interfaces.
28+
*/
29+
30+
server.listen(port);
31+
server.on('error', onError);
32+
server.on('listening', onListening);
33+
34+
/**
35+
* Normalize a port into a number, string, or false.
36+
*/
37+
38+
function normalizePort(val) {
39+
var port = parseInt(val, 10);
40+
41+
if (isNaN(port)) {
42+
// named pipe
43+
return val;
44+
}
45+
46+
if (port >= 0) {
47+
// port number
48+
return port;
49+
}
50+
51+
return false;
52+
}
53+
54+
/**
55+
* Event listener for HTTP server "error" event.
56+
*/
57+
58+
function onError(error) {
59+
if (error.syscall !== 'listen') {
60+
throw error;
61+
}
62+
63+
var bind = typeof port === 'string'
64+
? 'Pipe ' + port
65+
: 'Port ' + port;
66+
67+
// handle specific listen errors with friendly messages
68+
switch (error.code) {
69+
case 'EACCES':
70+
console.error(bind + ' requires elevated privileges');
71+
process.exit(1);
72+
break;
73+
case 'EADDRINUSE':
74+
console.error(bind + ' is already in use');
75+
process.exit(1);
76+
break;
77+
default:
78+
throw error;
79+
}
80+
}
81+
82+
/**
83+
* Event listener for HTTP server "listening" event.
84+
*/
85+
86+
function onListening() {
87+
var addr = server.address();
88+
var bind = typeof addr === 'string'
89+
? 'pipe ' + addr
90+
: 'port ' + addr.port;
91+
console.log('Listening on ' + bind);
92+
}

‎client/.babelrc

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"presets": [
3+
"env",
4+
"es2015",
5+
"es2016",
6+
"es2017",
7+
"stage-1",
8+
"stage-2",
9+
"stage-3",
10+
"react"
11+
],
12+
"plugins": [
13+
"add-module-exports",
14+
"transform-runtime",
15+
"syntax-async-functions"
16+
]
17+
}

‎client/.eslintignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
bin
2+
.eslintrc.js
3+
gulpfile.babel.js
4+
webpack.config.babel.js

‎client/.eslintrc.json

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
{
2+
"parser": "babel-eslint",
3+
"extends": "airbnb",
4+
"parserOptions": {
5+
"ecmaVersion": 8,
6+
"sourceType": "module",
7+
"ecmaFeatures": {
8+
"jsx": true,
9+
"experimentalObjectRestSpread": true
10+
}
11+
},
12+
"env": {
13+
"es6": true,
14+
"browser": true,
15+
"node": true,
16+
"mocha": true
17+
},
18+
"plugins": [
19+
"react",
20+
"jsx-a11y",
21+
"import"
22+
],
23+
"rules": {
24+
"brace-style": ["error", "stroustrup"],
25+
"comma-dangle": ["error", "always-multiline"],
26+
"func-names": ["error", "as-needed"],
27+
"max-len": "off",
28+
"no-param-reassign": ["error", { "props": false }],
29+
"no-plusplus": "off",
30+
"no-restricted-syntax": "off",
31+
"quote-props": ["error", "consistent"],
32+
"arrow-parens": ["error", "always"],
33+
"arrow-body-style": "off",
34+
"react/prop-types": ["error", { "ignore": ["children", "className"] }],
35+
"react/require-default-props": "off",
36+
"react/jsx-no-target-blank": "error",
37+
"react/jsx-filename-extension": ["warn", { "extensions": [".js"] }],
38+
"react/jsx-closing-bracket-location": ["error", "tag-aligned"],
39+
"import/no-mutable-exports": "off",
40+
"import/no-unresolved": "off",
41+
"import/extensions": ["error", "never", { "scss": "always" }],
42+
"import/no-absolute-path": "off",
43+
"import/no-extraneous-dependencies": "off",
44+
"import/no-named-as-default": "off"
45+
}
46+
}

‎client/.sass-lint.yml

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
files:
2+
include:
3+
- 'client/**/*.s+(a|c)ss'
4+
exclude:
5+
- 'node_modules/**'
6+
options:
7+
formatter: stylish
8+
rules:
9+
class-name-format:
10+
- 2
11+
- convention: camelcase
12+
force-pseudo-nesting: 0
13+
hex-length: 0
14+
no-color-literals:
15+
- 2
16+
- allow-rgba: true
17+
property-sort-order: 0

‎client/.yarnrc

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
registry "https://registry.npmjs.org/"

‎client/app/components/App.js

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import React from 'react';
2+
3+
/*
4+
If we look in index.js under the 'app' folder, we see that App is nested here:
5+
6+
<Route path="/" component={App}>
7+
<IndexRoute component={PostList} />
8+
<Route path="post/:id" component={PostInformation} />
9+
</Route>
10+
11+
The <Route /> component acts as wrapper around the actual 'App' component, which in turn renders its
12+
children (IndexRoute, Route).
13+
14+
In this case, App is a FUNCTIONAL COMPONENT that takes in a prop (children) and renders its children within a div.
15+
Anything passed in-between opening and closing tags of a React component gets passed to its props as 'children'.
16+
*/
17+
18+
function App({ children }) {
19+
return (
20+
<div>
21+
{children}
22+
</div>
23+
);
24+
}
25+
26+
export default App;

‎client/app/createStore.js

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { createStore, applyMiddleware, compose } from 'redux';
2+
import thunk from 'redux-thunk';
3+
import { routerMiddleware, syncHistoryWithStore } from 'react-router-redux';
4+
import { browserHistory } from 'react-router';
5+
6+
import rootReducer from './rootReducer';
7+
8+
const store = createStore(
9+
rootReducer,
10+
/*
11+
compose(...middleware) is where we inject our middlewares (think middleman for your Redux data)
12+
into our dataflow.
13+
14+
The first thing we're passing is the 'Thunk Middleware', which allows us to dispatch asynchronous actions.
15+
This helps us the most when we're gathering data from an API. For more details into what a thunk is, check out
16+
the following: https://github.com/gaearon/redux-thunk
17+
18+
The second is react-router-redux, which syncs our browser history with our redux store.
19+
20+
The third is Redux Devtools, which is an EXTREMELY POWERFUL extension for debugging React/Redux applications.
21+
It allows you to monitor the state of your redux store and 'time-travel' between dispatched actions.
22+
This way, I can see the exact affect that each action has on the store.
23+
*/
24+
compose(
25+
applyMiddleware(thunk),
26+
applyMiddleware(routerMiddleware(browserHistory)),
27+
process.env.NODE_ENV !== 'production' && typeof window === 'object' && typeof window.devToolsExtension !== 'undefined' ? window.devToolsExtension() : (f) => f
28+
)
29+
);
30+
31+
const history = syncHistoryWithStore(browserHistory, store);
32+
33+
export { store, history };

‎client/app/index.js

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import React from 'react';
2+
import ReactDOM from 'react-dom';
3+
import { Router, Route, IndexRoute } from 'react-router';
4+
import { Provider } from 'react-redux';
5+
6+
import PostList from 'post/scenes/PostList';
7+
import PostInformation from 'post/scenes/PostInformation';
8+
import App from './components/App';
9+
10+
import { store, history } from './createStore';
11+
12+
/*
13+
All redux applications are wrapped around a <Provider />, which can be thought of as a container object
14+
holding the entire Redux store.
15+
16+
Next, we have our actual <Router /> component which will dynamically match the route path to its matching component.
17+
For example, if we had 'www.reddit.com/post/12345', it would get matched to <Route path="post/:id" component={PostInformation} />
18+
with 12345 being passed in as a match parameter (which we will extract in the PostInformation.js component).
19+
20+
However, if our route doesn't match post/:id, then it will default to the IndexRoute.
21+
22+
NOTE: We are using React-Router 3, not React-Router 4. Don't use 4. It's bad. \s
23+
*/
24+
ReactDOM.render(
25+
<Provider store={store}>
26+
<Router history={history}>
27+
<Route path="/" component={App}>
28+
<IndexRoute component={PostList} />
29+
<Route path="post/:id" component={PostInformation} />
30+
</Route>
31+
</Router>
32+
</Provider>,
33+
document.getElementById('root')
34+
);

‎client/app/rootReducer.js

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { combineReducers } from 'redux';
2+
import { routerReducer as routing } from 'react-router-redux';
3+
4+
import post from 'post/reducer';
5+
6+
export default combineReducers({ post, routing });

‎client/index.html

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>React Redux App</title>
5+
</head>
6+
<body>
7+
<div id="root"></div>
8+
</body>
9+
<script src="/js/bundle.js"></script>
10+
</html>

0 commit comments

Comments
 (0)
Please sign in to comment.