Merge branch 'react-pr' into lint-staged

This commit is contained in:
Andrey Okonetchnikov 2016-09-13 18:50:18 +02:00
commit 357bcb18cc
10 changed files with 124 additions and 68 deletions

View File

@ -4,7 +4,7 @@
"description": "Netlify CMS lets content editors work on structured content stored in git", "description": "Netlify CMS lets content editors work on structured content stored in git",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {
"start": "webpack-dev-server -d --inline --config webpack.config.js", "start": "webpack-dev-server --config webpack.config.js",
"test": "NODE_ENV=test mocha --recursive --compilers js:babel-register --require ./test/setup.js", "test": "NODE_ENV=test mocha --recursive --compilers js:babel-register --require ./test/setup.js",
"test:watch": "npm test -- --watch", "test:watch": "npm test -- --watch",
"build": "webpack --config webpack.config.js", "build": "webpack --config webpack.config.js",
@ -45,8 +45,6 @@
"eslint": "^3.5.0", "eslint": "^3.5.0",
"eslint-plugin-react": "^5.1.1", "eslint-plugin-react": "^5.1.1",
"exports-loader": "^0.6.3", "exports-loader": "^0.6.3",
"express": "^4.13.4",
"extract-text-webpack-plugin": "^1.0.1",
"file-loader": "^0.8.5", "file-loader": "^0.8.5",
"immutable": "^3.7.6", "immutable": "^3.7.6",
"imports-loader": "^0.6.5", "imports-loader": "^0.6.5",
@ -61,6 +59,7 @@
"pre-commit": "^1.1.3", "pre-commit": "^1.1.3",
"react": "^15.1.0", "react": "^15.1.0",
"react-dom": "^15.1.0", "react-dom": "^15.1.0",
"react-hot-loader": "^3.0.0-beta.2",
"react-immutable-proptypes": "^1.6.0", "react-immutable-proptypes": "^1.6.0",
"react-lazy-load": "^3.0.3", "react-lazy-load": "^3.0.3",
"react-pure-render": "^1.0.2", "react-pure-render": "^1.0.2",
@ -71,8 +70,8 @@
"redux-thunk": "^1.0.3", "redux-thunk": "^1.0.3",
"style-loader": "^0.13.0", "style-loader": "^0.13.0",
"url-loader": "^0.5.7", "url-loader": "^0.5.7",
"webpack": "^1.12.13", "webpack": "^1.13.2",
"webpack-dev-server": "^1.14.1", "webpack-dev-server": "^1.15.1",
"webpack-postcss-tools": "^1.1.1", "webpack-postcss-tools": "^1.1.1",
"whatwg-fetch": "^1.0.0" "whatwg-fetch": "^1.0.0"
}, },

View File

@ -4,6 +4,9 @@
vertical-align: top; vertical-align: top;
text-align: center; text-align: center;
width: 28%; width: 28%;
& h2 {
font-size: 16px;
}
} }
.column:not(:last-child) { .column:not(:last-child) {

View File

@ -13,7 +13,7 @@ export default class UnpublishedListing extends React.Component {
if (!column) { if (!column) {
return entries.entrySeq().map(([currColumn, currEntries]) => ( return entries.entrySeq().map(([currColumn, currEntries]) => (
<div key={currColumn} className={styles.column}> <div key={currColumn} className={styles.column}>
<h3>{statusDescriptions.get(currColumn)}</h3> <h2>{statusDescriptions.get(currColumn)}</h2>
{this.renderColumns(currEntries, currColumn)} {this.renderColumns(currEntries, currColumn)}
</div> </div>
)); ));
@ -22,7 +22,7 @@ export default class UnpublishedListing extends React.Component {
{entries.map(entry => { {entries.map(entry => {
// Look for an "author" field. Fallback to username on backend implementation; // Look for an "author" field. Fallback to username on backend implementation;
const author = entry.getIn(['data', 'author'], entry.getIn(['metaData', 'user'])); const author = entry.getIn(['data', 'author'], entry.getIn(['metaData', 'user']));
const timeStamp = moment(entry.getIn(['metaData', 'timeStamp'])).formate('llll'); const timeStamp = moment(entry.getIn(['metaData', 'timeStamp'])).format('llll');
const link = `/editorialworkflow/${entry.getIn(['metaData', 'collection'])}/${entry.getIn(['metaData', 'status'])}/${entry.get('slug')}`; const link = `/editorialworkflow/${entry.getIn(['metaData', 'collection'])}/${entry.getIn(['metaData', 'status'])}/${entry.get('slug')}`;
return ( return (
<Card key={entry.get('slug')} className={styles.card}> <Card key={entry.get('slug')} className={styles.card}>
@ -41,6 +41,7 @@ export default class UnpublishedListing extends React.Component {
return ( return (
<div> <div>
<h1>Editorial Workflow</h1>
{columns} {columns}
</div> </div>
); );

View File

@ -6,6 +6,7 @@ import { selectUnpublishedEntries } from '../../reducers';
import { EDITORIAL_WORKFLOW, status } from '../../constants/publishModes'; import { EDITORIAL_WORKFLOW, status } from '../../constants/publishModes';
import UnpublishedListing from '../../components/UnpublishedListing'; import UnpublishedListing from '../../components/UnpublishedListing';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import styles from '../CollectionPage.css';
export default function CollectionPageHOC(CollectionPage) { export default function CollectionPageHOC(CollectionPage) {
class CollectionPageHOC extends CollectionPage { class CollectionPageHOC extends CollectionPage {
@ -23,7 +24,7 @@ export default function CollectionPageHOC(CollectionPage) {
if (!isEditorialWorkflow) return super.render(); if (!isEditorialWorkflow) return super.render();
return ( return (
<div> <div className={styles.alignable}>
<UnpublishedListing entries={unpublishedEntries}/> <UnpublishedListing entries={unpublishedEntries}/>
{super.render()} {super.render()}
</div> </div>

View File

@ -3,8 +3,9 @@ html {
-ms-text-size-adjust: 100%; -ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%; -webkit-text-size-adjust: 100%;
margin: 0; margin: 0;
font-family: Roboto,"Helvetica Neue",HelveticaNeue,Helvetica,Arial,sans-serif; font-family: Roboto, "Helvetica Neue", HelveticaNeue, Helvetica, Arial, sans-serif;
} }
*, *:before, *:after { *, *:before, *:after {
box-sizing: inherit; box-sizing: inherit;
} }
@ -13,15 +14,15 @@ body {
font-family: 'Roboto', sans-serif; font-family: 'Roboto', sans-serif;
height: 100%; height: 100%;
background-color: #f2f5f4; background-color: #f2f5f4;
color:#7c8382; color: #7c8382;
margin: 0; margin: 0;
} }
header { header {
background-color: #272e30; background-color: #272e30;
box-shadow: 0 1px 2px 0 rgba(0,0,0,0.22); box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.22);
height: 54px; height: 54px;
border-bottom:2px solid #3ab7a5; border-bottom: 2px solid #3ab7a5;
position: fixed; position: fixed;
width: 100%; width: 100%;
z-index: 999; z-index: 999;
@ -35,7 +36,7 @@ h1, h2, h3, h4, h5, h6, p {
margin: 0; margin: 0;
} }
h1{ h1 {
color: #3ab7a5; color: #3ab7a5;
border-bottom: 1px solid #3ab7a5; border-bottom: 1px solid #3ab7a5;
margin: 30px auto 25px; margin: 30px auto 25px;
@ -43,15 +44,16 @@ h1{
font-size: 25px; font-size: 25px;
} }
header input{ header input {
margin-bottom:0; margin-bottom: 0;
} }
button{
button {
border: 1px solid #3ab7a5; border: 1px solid #3ab7a5;
padding: 3px 20px; padding: 3px 20px;
font-size: 12px; font-size: 12px;
line-height: 18px; line-height: 18px;
background-color:#fff; background-color: #fff;
cursor: pointer; cursor: pointer;
} }
@ -120,7 +122,7 @@ button{
margin-top: 1px; margin-top: 1px;
z-index: 99999 !important; z-index: 99999 !important;
background: #fff; background: #fff;
box-shadow: 0 1px 3px rgba(0,0,0,.1); box-shadow: 0 1px 3px rgba(0, 0, 0, .1);
border: 1px solid #f9f9f9; border: 1px solid #f9f9f9;
} }
& .rdtOpen .rdtPicker { & .rdtOpen .rdtPicker {

View File

@ -1,31 +1,33 @@
import React from 'react'; import React from 'react';
import { render } from 'react-dom'; import { render } from 'react-dom';
import { Provider } from 'react-redux'; import { AppContainer } from 'react-hot-loader'
import { Router } from 'react-router'; import Root from './root'
import registry from './lib/registry'; import registry from './lib/registry';
import configureStore from './store/configureStore';
import routes from './routing/routes';
import history, { syncHistory } from './routing/history';
import 'file?name=index.html!../example/index.html'; import 'file?name=index.html!../example/index.html';
import './index.css'; import './index.css';
const store = configureStore(); // Create mount element dynamically
// Create an enhanced history that syncs navigation events with the store
syncHistory(store);
const el = document.createElement('div'); const el = document.createElement('div');
el.id = 'root'; el.id = 'root';
document.body.appendChild(el); document.body.appendChild(el);
render(( render((
<Provider store={store}> <AppContainer>
<Router history={history}> <Root />
{routes} </AppContainer>
</Router>
</Provider>
), el); ), el);
if (module.hot) {
module.hot.accept('./root', () => {
const NextRoot = require('./root').default;
render((
<AppContainer>
<NextRoot />
</AppContainer>
), el);
});
}
window.CMS = {}; window.CMS = {};
console.log('reg: ', registry); console.log('reg: ', registry);
for (const method in registry) { for (const method in registry) {

View File

@ -0,0 +1,8 @@
import { combineReducers } from 'redux';
import { routerReducer } from 'react-router-redux';
import reducers from '.';
export default combineReducers({
...reducers,
routing: routerReducer
});

21
src/root.js Normal file
View File

@ -0,0 +1,21 @@
import React from 'react';
import { Provider } from 'react-redux';
import { Router } from 'react-router';
import routes from './routing/routes';
import history, { syncHistory } from './routing/history';
import configureStore from './store/configureStore';
const store = configureStore();
// Create an enhanced history that syncs navigation events with the store
syncHistory(store);
const Root = () => (
<Provider store={store}>
<Router history={history}>
{routes}
</Router>
</Provider>
);
export default Root;

View File

@ -1,18 +1,20 @@
import { createStore, applyMiddleware, combineReducers, compose } from 'redux'; import { createStore, applyMiddleware, compose } from 'redux';
import thunkMiddleware from 'redux-thunk'; import thunkMiddleware from 'redux-thunk';
import { routerReducer } from 'react-router-redux'; import reducer from '../reducers/combinedReducer';
import reducers from '../reducers';
const reducer = combineReducers({ export default function configureStore(initialState) {
...reducers, const store = createStore(reducer, initialState, compose(
routing: routerReducer
});
const createStoreWithMiddleware = compose(
applyMiddleware(thunkMiddleware), applyMiddleware(thunkMiddleware),
window.devToolsExtension ? window.devToolsExtension() : (f) => f window.devToolsExtension ? window.devToolsExtension() : f => f
)(createStore); ));
export default (initialState) => ( if (module.hot) {
createStoreWithMiddleware(reducer, initialState) // Enable Webpack hot module replacement for reducers
); module.hot.accept('../reducers/combinedReducer', () => {
const nextReducer = require('../reducers/combinedReducer') // eslint-disable-line
store.replaceReducer(nextReducer);
});
}
return store;
}

View File

@ -1,8 +1,10 @@
/* global module, __dirname, require */ /* global module, __dirname, require */
var webpack = require('webpack'); var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var path = require('path'); var path = require('path');
const HOST = 'localhost';
const PORT = '8080';
module.exports = { module.exports = {
module: { module: {
loaders: [ loaders: [
@ -13,7 +15,7 @@ module.exports = {
{ test: /\.json$/, loader: 'json-loader' }, { test: /\.json$/, loader: 'json-loader' },
{ {
test: /\.css$/, test: /\.css$/,
loader: ExtractTextPlugin.extract('style', 'css?modules&importLoaders=1&&localIdentName=cms__[name]__[local]!postcss'), loader: 'style!css?modules&importLoaders=1&&localIdentName=cms__[name]__[local]!postcss',
}, },
{ {
loader: 'babel', loader: 'babel',
@ -22,7 +24,13 @@ module.exports = {
query: { query: {
cacheDirectory: true, cacheDirectory: true,
presets: ['react', 'es2015'], presets: ['react', 'es2015'],
plugins: ['transform-class-properties', 'transform-object-assign', 'transform-object-rest-spread', 'lodash'] plugins: [
'transform-class-properties',
'transform-object-assign',
'transform-object-rest-spread',
'lodash',
'react-hot-loader/babel'
]
} }
} }
] ]
@ -34,7 +42,9 @@ module.exports = {
], ],
plugins: [ plugins: [
new ExtractTextPlugin('cms.css', { allChunks: true }), new webpack.optimize.OccurenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
new webpack.ProvidePlugin({ new webpack.ProvidePlugin({
'fetch': 'imports?this=>global!exports?global.fetch!whatwg-fetch' 'fetch': 'imports?this=>global!exports?global.fetch!whatwg-fetch'
}) })
@ -42,16 +52,23 @@ module.exports = {
context: path.join(__dirname, 'src'), context: path.join(__dirname, 'src'),
entry: { entry: {
cms: './index', cms: [
'webpack/hot/dev-server',
`webpack-dev-server/client?http://${HOST}:${PORT}/`,
'react-hot-loader/patch',
'./index'
],
}, },
output: { output: {
path: path.join(__dirname, 'dist'), path: path.join(__dirname, 'dist'),
filename: '[name].js' filename: '[name].js',
publicPath: `http://${HOST}:${PORT}/`,
}, },
externals: [/^vendor\/.+\.js$/], externals: [/^vendor\/.+\.js$/],
devServer: { devServer: {
hot: true,
contentBase: 'example/', contentBase: 'example/',
historyApiFallback: true, historyApiFallback: true,
devTool: 'source-map' devTool: 'cheap-module-source-map'
}, },
}; };