├── .babelrc ├── .codeclimate.yml ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── bin └── wooo.js ├── lib ├── argv.js ├── dependencies.js ├── files.js ├── fn.js ├── index.js └── options.js ├── package.json ├── src ├── argv.js ├── dependencies.js ├── files.js ├── fn.js ├── index.js └── options.js ├── templates ├── default │ ├── components │ │ └── Header │ │ │ ├── index.css │ │ │ └── index.js │ ├── containers │ │ ├── App.js │ │ └── Home.js │ ├── index.js │ ├── modules │ │ ├── index.js │ │ └── user.js │ ├── static │ │ ├── index.css │ │ └── normalize.css │ └── store │ │ ├── configureStore.dev.js │ │ ├── configureStore.prod.js │ │ └── index.js └── react-router-4 │ ├── components │ └── Button.js │ ├── containers │ ├── App.js │ └── Home.js │ ├── index.js │ ├── modules │ ├── index.js │ └── user.js │ ├── static │ └── css │ │ └── reboot.css │ └── store │ └── index.js └── test ├── pretest.js └── test.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "env", 5 | { 6 | "targets": { 7 | "node": "current" 8 | } 9 | } 10 | ], 11 | "stage-0" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /.codeclimate.yml: -------------------------------------------------------------------------------- 1 | engines: 2 | duplication: 3 | enabled: true 4 | config: 5 | languages: 6 | - javascript 7 | ratings: 8 | paths: 9 | - src/**/* 10 | exclude_paths: 11 | - lib/**/* 12 | - node_modules/**/* 13 | - _test_/**/* 14 | - test/**/* 15 | - templates/**/* 16 | - src/options.js 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | 39 | .test 40 | tst 41 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "node" 4 | - "6" 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Ondřej Kocián 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | # Wooo [![Build Status](https://travis-ci.org/Kocisov/wooo.svg?branch=master)](https://travis-ci.org/Kocisov/wooo) [![npm](https://img.shields.io/npm/v/redux-wooo.svg)](http://npmjs.com/redux-wooo) [![davidm](https://david-dm.org/kocisov/wooo.svg)](https://david-dm.org/kocisov/wooo) [![Code Climate](https://codeclimate.com/github/Kocisov/wooo/badges/gpa.svg)](https://codeclimate.com/github/Kocisov/wooo) 6 | > Tool that helps you add Redux to your React project without pain 7 | 8 | ## Main goal of wooo 9 | Let users write one command instead of creating 5 folders, 10+ files and installing 4 dependencies for Redux to get going. 10 | 11 | ## So, what does wooo do? 12 | **Wooo** does install required dependencies and create [template files](https://github.com/Kocisov/wooo/tree/master/templates) in specified path with: 13 | 1. One [duck](https://github.com/erikras/ducks-modular-redux) module for user login/logout 14 | 2. One stateless Component with CSS 15 | 3. React-router and react-router-redux reducer (You can choose v4 or v3 (default) template) 16 | 4. Redux store configuration for production and development by process.env.NODE_ENV check 17 | 5. One Container with connected props by connect() function 18 | 19 | **This is pretty much just fast scaffolding, not actual code! But it can be edited to be production-ready with few more lines.** 20 | 21 | ## Installation 22 | **Node version 6 or higher is required!** 23 | ```bash 24 | # with yarn 25 | $ yarn global add redux-wooo 26 | 27 | # with npm 28 | $ npm install -g redux-wooo 29 | ``` 30 | 31 | ## Usage 32 | ``` 33 | wooo [options] 34 | --help, -h Show Wooo's usage. 35 | --version, -v Show Wooo's version. 36 | --template, -t [name] Specify which template should Wooo create (templates directory) 37 | --npm, -n Use npm for installing dependencies. (Wooo uses Yarn by default) 38 | --dir, -d [path] Directory, where do you want to create files by Wooo. (Dependencies are written into package.json (yarn creates new package.json if it is not present) in current directory) 39 | ``` 40 | 41 | **Default path for files is src folder in your current location in command line!** 42 | 43 | ## Contribution 44 | If you want to add template, just fork the repo and add your template files in folder into [/template](https://github.com/Kocisov/wooo/tree/master/templates). 45 | 46 | This is not ideal and in the future Wooo will have better system for this. 47 | -------------------------------------------------------------------------------- /bin/wooo.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const wooo = require('../lib/index').default() 3 | -------------------------------------------------------------------------------- /lib/argv.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = argv; 7 | 8 | var _yargs = require('yargs'); 9 | 10 | var _yargs2 = _interopRequireDefault(_yargs); 11 | 12 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 13 | 14 | function argv() { 15 | return _yargs2.default.usage('Usage: wooo [Options]').example('wooo -d ./src/ -t react-router-4', 'Create react-router-4 template files and install its needed dependencies').alias('v', 'version').alias('d', 'dir').alias('n', 'npm').alias('t', 'template').alias('h', 'help').boolean('v').boolean('n').string('d').string('t').describe('v', 'Show version of Wooo').describe('d', 'Specify directory where Wooo should create files').describe('t', 'Specify template that Wooo should create').describe('n', 'Specify if Wooo should install dependencies with npm instead of yarn').help('h').argv; 16 | } -------------------------------------------------------------------------------- /lib/dependencies.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.install = exports.prepare = undefined; 7 | 8 | let prepare = exports.prepare = (() => { 9 | var _ref = _asyncToGenerator(function* ({ manager, template }) { 10 | const _manager = manager; 11 | 12 | const command = manager && manager === 'yarn' ? 'yarn add' : 'npm install --save'; 13 | 14 | const dependencies = ['react-redux', 'redux', 'redux-thunk']; 15 | 16 | if (template === 'react-router-4') { 17 | dependencies.push('react-router-dom', 'react-router-redux@next', 'styled-components'); 18 | } else { 19 | dependencies.push('react-router-redux', 'react-router@3.0.2'); 20 | } 21 | 22 | return { 23 | manager: _manager, 24 | command, 25 | dependencies 26 | }; 27 | }); 28 | 29 | return function prepare(_x) { 30 | return _ref.apply(this, arguments); 31 | }; 32 | })(); 33 | 34 | let install = exports.install = (() => { 35 | var _ref2 = _asyncToGenerator(function* ({ command, manager, dependencies }) { 36 | console.log((0, _fn.yellow)(`Installing dependencies with ${manager}`)); 37 | const e = yield (0, _fn.exec)(`${command} ${dependencies.join(' ')}`); 38 | return e; 39 | }); 40 | 41 | return function install(_x2) { 42 | return _ref2.apply(this, arguments); 43 | }; 44 | })(); 45 | 46 | var _fn = require('./fn'); 47 | 48 | function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } -------------------------------------------------------------------------------- /lib/files.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = createFiles; 7 | 8 | var _fsExtra = require('fs-extra'); 9 | 10 | var _path = require('path'); 11 | 12 | var _fn = require('./fn'); 13 | 14 | function createFiles({ dir, template }) { 15 | let tmplt; 16 | 17 | const ad = (0, _fsExtra.realpathSync)(process.cwd()); 18 | const p = (0, _path.resolve)(__dirname, `../templates/${template}`); 19 | 20 | const resolvedDir = (0, _path.resolve)(ad, dir); 21 | 22 | console.log((0, _fn.white)(`Wooo will create files in ${resolvedDir} directory.`)); 23 | 24 | if ((0, _fsExtra.existsSync)(p)) { 25 | tmplt = p; 26 | } else { 27 | tmplt = (0, _path.resolve)(__dirname, `../templates/default`); 28 | 29 | console.log((0, _fn.red)(`Template ${template} was not found!`)); 30 | 31 | console.log((0, _fn.yellow)(`Installing default template instead...`)); 32 | } 33 | 34 | (0, _fsExtra.copySync)(tmplt, resolvedDir); 35 | 36 | return (0, _fn.green)(`Wooo!!! Everything is done. 37 | Let's build something cool.`); 38 | } -------------------------------------------------------------------------------- /lib/fn.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.green = exports.red = exports.white = exports.yellow = exports.exec = undefined; 7 | 8 | var _child_process = require('child_process'); 9 | 10 | var _chalk = require('chalk'); 11 | 12 | var _chalk2 = _interopRequireDefault(_chalk); 13 | 14 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 15 | 16 | const exec = exports.exec = cmd => (0, _child_process.execSync)(cmd, { 17 | stdio: 'inherit' 18 | }); 19 | 20 | const yellow = exports.yellow = n => _chalk2.default.yellow(n); 21 | 22 | const white = exports.white = n => _chalk2.default.white(n); 23 | 24 | const red = exports.red = n => _chalk2.default.red(n); 25 | 26 | const green = exports.green = n => _chalk2.default.green(n); -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | require('babel-polyfill'); 8 | 9 | var _argv = require('./argv'); 10 | 11 | var _argv2 = _interopRequireDefault(_argv); 12 | 13 | var _options = require('./options'); 14 | 15 | var _options2 = _interopRequireDefault(_options); 16 | 17 | var _dependencies = require('./dependencies'); 18 | 19 | var _files = require('./files'); 20 | 21 | var _files2 = _interopRequireDefault(_files); 22 | 23 | var _clear = require('clear'); 24 | 25 | var _clear2 = _interopRequireDefault(_clear); 26 | 27 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 28 | 29 | function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } 30 | 31 | exports.default = (() => { 32 | var _ref = _asyncToGenerator(function* () { 33 | const args = yield (0, _argv2.default)(); 34 | const options = yield (0, _options2.default)(args); 35 | const prepared = yield (0, _dependencies.prepare)(options); 36 | const installed = yield (0, _dependencies.install)(prepared); 37 | const created = yield (0, _files2.default)(options); 38 | 39 | (0, _clear2.default)(); 40 | 41 | console.log(created); 42 | }); 43 | 44 | function wooo() { 45 | return _ref.apply(this, arguments); 46 | } 47 | 48 | return wooo; 49 | })(); -------------------------------------------------------------------------------- /lib/options.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _clear = require('clear'); 8 | 9 | var _clear2 = _interopRequireDefault(_clear); 10 | 11 | var _package = require('../package.json'); 12 | 13 | var _fn = require('./fn'); 14 | 15 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 16 | 17 | function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } 18 | 19 | exports.default = (() => { 20 | var _ref = _asyncToGenerator(function* (args) { 21 | let opts = { 22 | template: 'default', 23 | manager: 'yarn', 24 | dir: './src' 25 | }; 26 | 27 | if (args.version) { 28 | (0, _clear2.default)(); 29 | console.log((0, _fn.white)(`Wooo's current version is ${_package.version}.`)); 30 | process.exit(); 31 | } 32 | 33 | if (args.template && args.template.length > 0) { 34 | opts.template = args.template; 35 | } 36 | 37 | if (args.npm) { 38 | opts.manager = 'npm'; 39 | } 40 | 41 | if (args.dir && args.dir.length > 0) { 42 | opts.dir = args.dir; 43 | } 44 | 45 | return opts; 46 | }); 47 | 48 | function checkOptions(_x) { 49 | return _ref.apply(this, arguments); 50 | } 51 | 52 | return checkOptions; 53 | })(); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "redux-wooo", 3 | "version": "1.0.9", 4 | "description": "Add redux scaffolding into your folder without pain.", 5 | "main": "lib/index.js", 6 | "repository": { 7 | "url": "kocisov/wooo", 8 | "type": "git" 9 | }, 10 | "author": "kocisov ", 11 | "scripts": { 12 | "compile": "babel src -d lib", 13 | "compile:with-minify": "babel src -d lib --minified", 14 | "pretest": "node test/pretest.js -d ./_test_ -t react-router-4", 15 | "test": "mocha test/test.js" 16 | }, 17 | "bin": { 18 | "wooo": "bin/wooo.js" 19 | }, 20 | "license": "MIT", 21 | "devDependencies": { 22 | "babel-cli": "^6.24.1", 23 | "babel-core": "^6.24.1", 24 | "babel-plugin-transform-async-to-generator": "^6.24.1", 25 | "babel-preset-env": "^1.4.0", 26 | "babel-preset-stage-0": "^6.24.1", 27 | "mocha": "^4.0.1", 28 | "prettier": "^1.2.2" 29 | }, 30 | "dependencies": { 31 | "babel-polyfill": "^6.23.0", 32 | "chalk": "^2.1.0", 33 | "clear": "^0.0.1", 34 | "fs-extra": "^4.0.2", 35 | "yargs": "^9.0.1" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/argv.js: -------------------------------------------------------------------------------- 1 | import yargs from 'yargs' 2 | 3 | export default function argv() { 4 | return yargs 5 | .usage('Usage: wooo [Options]') 6 | .example( 7 | 'wooo -d ./src/ -t react-router-4', 8 | 'Create react-router-4 template files and install its needed dependencies' 9 | ) 10 | .alias('v', 'version') 11 | .alias('d', 'dir') 12 | .alias('n', 'npm') 13 | .alias('t', 'template') 14 | .alias('h', 'help') 15 | .boolean('v') 16 | .boolean('n') 17 | .string('d') 18 | .string('t') 19 | .describe('v', 'Show version of Wooo') 20 | .describe('d', 'Specify directory where Wooo should create files') 21 | .describe('t', 'Specify template that Wooo should create') 22 | .describe( 23 | 'n', 24 | 'Specify if Wooo should install dependencies with npm instead of yarn' 25 | ) 26 | .help('h').argv 27 | } 28 | -------------------------------------------------------------------------------- /src/dependencies.js: -------------------------------------------------------------------------------- 1 | import { exec, yellow } from './fn' 2 | 3 | export async function prepare({ manager, template }) { 4 | const _manager = manager 5 | 6 | const command = 7 | manager && manager === 'yarn' ? 'yarn add' : 'npm install --save' 8 | 9 | const dependencies = ['react-redux', 'redux', 'redux-thunk'] 10 | 11 | if (template === 'react-router-4') { 12 | dependencies.push( 13 | 'react-router-dom', 14 | 'react-router-redux@next', 15 | 'styled-components' 16 | ) 17 | } else { 18 | dependencies.push('react-router-redux', 'react-router@3.0.2') 19 | } 20 | 21 | return { 22 | manager: _manager, 23 | command, 24 | dependencies, 25 | } 26 | } 27 | 28 | export async function install({ command, manager, dependencies }) { 29 | console.log(yellow(`Installing dependencies with ${manager}`)) 30 | const e = await exec(`${command} ${dependencies.join(' ')}`) 31 | return e 32 | } 33 | -------------------------------------------------------------------------------- /src/files.js: -------------------------------------------------------------------------------- 1 | import { existsSync, realpathSync, copySync } from 'fs-extra' 2 | import { resolve } from 'path' 3 | import { red, green, yellow, white } from './fn' 4 | 5 | export default function createFiles({ dir, template }) { 6 | let tmplt 7 | 8 | const ad = realpathSync(process.cwd()) 9 | const p = resolve(__dirname, `../templates/${template}`) 10 | 11 | const resolvedDir = resolve(ad, dir) 12 | 13 | console.log(white(`Wooo will create files in ${resolvedDir} directory.`)) 14 | 15 | if (existsSync(p)) { 16 | tmplt = p 17 | } else { 18 | tmplt = resolve(__dirname, `../templates/default`) 19 | 20 | console.log(red(`Template ${template} was not found!`)) 21 | 22 | console.log(yellow(`Installing default template instead...`)) 23 | } 24 | 25 | copySync(tmplt, resolvedDir) 26 | 27 | return green( 28 | `Wooo!!! Everything is done. 29 | Let's build something cool.` 30 | ) 31 | } 32 | -------------------------------------------------------------------------------- /src/fn.js: -------------------------------------------------------------------------------- 1 | import { execSync } from 'child_process' 2 | import chalk from 'chalk' 3 | 4 | export const exec = (cmd) => 5 | execSync(cmd, { 6 | stdio: 'inherit', 7 | }) 8 | 9 | export const yellow = (n) => chalk.yellow(n) 10 | export const white = (n) => chalk.white(n) 11 | export const red = (n) => chalk.red(n) 12 | export const green = (n) => chalk.green(n) 13 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import 'babel-polyfill' 2 | import argv from './argv' 3 | import checkOptions from './options' 4 | import { install, prepare } from './dependencies' 5 | import createFiles from './files' 6 | import clear from 'clear' 7 | 8 | export default async function wooo() { 9 | const args = await argv() 10 | const options = await checkOptions(args) 11 | const prepared = await prepare(options) 12 | const installed = await install(prepared) 13 | const created = await createFiles(options) 14 | 15 | clear() 16 | 17 | console.log(created) 18 | } 19 | -------------------------------------------------------------------------------- /src/options.js: -------------------------------------------------------------------------------- 1 | import clear from 'clear' 2 | import { version } from '../package.json' 3 | import { white } from './fn' 4 | 5 | export default async function checkOptions(args) { 6 | let opts = { 7 | template: 'default', 8 | manager: 'yarn', 9 | dir: './src', 10 | } 11 | 12 | if (args.version) { 13 | clear() 14 | console.log(white(`Wooo's current version is ${version}.`)) 15 | process.exit() 16 | } 17 | 18 | if (args.template && args.template.length > 0) { 19 | opts.template = args.template 20 | } 21 | 22 | if (args.npm) { 23 | opts.manager = 'npm' 24 | } 25 | 26 | if (args.dir && args.dir.length > 0) { 27 | opts.dir = args.dir 28 | } 29 | 30 | return opts 31 | } 32 | -------------------------------------------------------------------------------- /templates/default/components/Header/index.css: -------------------------------------------------------------------------------- 1 | .header { 2 | align-items: center; 3 | background: #fff; 4 | display: flex; 5 | } 6 | -------------------------------------------------------------------------------- /templates/default/components/Header/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import './index.css'; 3 | 4 | export default ({ children }) => ( 5 |
6 | {children} 7 |
8 | ); 9 | -------------------------------------------------------------------------------- /templates/default/containers/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react'; 2 | import Header from '../components/Header'; 3 | 4 | export default class App extends Component { 5 | render() { 6 | return ( 7 |
8 |
9 |
10 | {this.props.children} 11 |
12 |
13 | ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /templates/default/containers/Home.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react'; 2 | import { connect } from 'react-redux'; 3 | import { fakeLogin, logout } from '../modules/user'; 4 | 5 | class Home extends PureComponent { 6 | render() { 7 | const { name, isAuthenticated } = this.props.user; 8 | const { fakeLogin, logout } = this.props; 9 | 10 | return ( 11 |
12 | {isAuthenticated 13 | ?
14 |

Hello, {name}

15 | 16 |
17 | :
18 |

Hello

19 | 20 |
} 21 |
22 | ); 23 | } 24 | } 25 | 26 | export default connect(({ user }) => ({ user }), { 27 | fakeLogin, 28 | logout 29 | })(Home); 30 | -------------------------------------------------------------------------------- /templates/default/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { render } from 'react-dom'; 3 | import { Provider } from 'react-redux'; 4 | import { syncHistoryWithStore } from 'react-router-redux'; 5 | import store from './store'; 6 | 7 | import { Router, Route, IndexRoute, browserHistory } from 'react-router'; 8 | 9 | import App from './containers/App'; 10 | import Home from './containers/Home'; 11 | 12 | import './static/normalize.css'; 13 | import './static/index.css'; 14 | 15 | const history = syncHistoryWithStore(browserHistory, store); 16 | 17 | render( 18 | 19 | 20 | 21 | 22 | {/* Your routes here */} 23 | 24 | 25 | , 26 | document.getElementById('root') 27 | ); 28 | -------------------------------------------------------------------------------- /templates/default/modules/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux'; 2 | import { routerReducer } from 'react-router-redux'; 3 | import user from './user'; 4 | 5 | export default combineReducers({ 6 | user, 7 | routing: routerReducer 8 | }); 9 | -------------------------------------------------------------------------------- /templates/default/modules/user.js: -------------------------------------------------------------------------------- 1 | const USER_LOGGED_IN = 'app/user/USER_LOGGED_IN'; 2 | const USER_LOGGED_OUT = 'app/user/USER_LOGGED_OUT'; 3 | 4 | const initialState = { 5 | avatar: null, 6 | isAuthenticated: false, 7 | name: null, 8 | points: null, 9 | rank_group: null 10 | }; 11 | 12 | export default function user(state = initialState, action) { 13 | switch (action.type) { 14 | case USER_LOGGED_IN: 15 | return { 16 | ...state, 17 | isAuthenticated: true, 18 | 19 | // spread over payload, instead of manually adding each key 20 | ...action.payload 21 | }; 22 | 23 | case USER_LOGGED_OUT: 24 | return initialState; 25 | 26 | default: 27 | return state; 28 | } 29 | } 30 | 31 | export function fakeLogin() { 32 | return dispatch => { 33 | setTimeout( 34 | () => { 35 | dispatch({ 36 | type: USER_LOGGED_IN, 37 | payload: { 38 | avatar: '//placecage.com/200/200', 39 | name: 'UserName', 40 | points: 1337, 41 | rank_group: 5 42 | } 43 | }); 44 | }, 45 | 2000 46 | ); // fake db delay 47 | }; 48 | } 49 | 50 | export function logout() { 51 | return { 52 | type: USER_LOGGED_OUT 53 | }; 54 | } 55 | -------------------------------------------------------------------------------- /templates/default/static/index.css: -------------------------------------------------------------------------------- 1 | * { 2 | box-sizing: border-box; 3 | } 4 | 5 | ::selection { 6 | background: #3a3e3e; 7 | color: #fff; 8 | text-shadow: none; 9 | } 10 | 11 | body { 12 | -webkit-font-smoothing: antialiased; 13 | font-family: sans-serif; 14 | font-size: 14px; 15 | font-weight: 300; 16 | line-height: 1.5; 17 | margin: 0; 18 | } 19 | 20 | h1, 21 | h2, 22 | h3, 23 | h4, 24 | h5, 25 | h6, 26 | ul, 27 | li, 28 | ol, 29 | p, 30 | a { 31 | margin: 0; 32 | } 33 | -------------------------------------------------------------------------------- /templates/default/static/normalize.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v6.0.0 | MIT License | github.com/necolas/normalize.css */ 2 | 3 | /* Document 4 | ========================================================================== */ 5 | 6 | /** 7 | * 1. Correct the line height in all browsers. 8 | * 2. Prevent adjustments of font size after orientation changes in 9 | * IE on Windows Phone and in iOS. 10 | */ 11 | 12 | html { 13 | line-height: 1.15; /* 1 */ 14 | -ms-text-size-adjust: 100%; /* 2 */ 15 | -webkit-text-size-adjust: 100%; /* 2 */ 16 | } 17 | 18 | /* Sections 19 | ========================================================================== */ 20 | 21 | /** 22 | * Add the correct display in IE 9-. 23 | */ 24 | 25 | article, 26 | aside, 27 | footer, 28 | header, 29 | nav, 30 | section { 31 | display: block; 32 | } 33 | 34 | /** 35 | * Correct the font size and margin on `h1` elements within `section` and 36 | * `article` contexts in Chrome, Firefox, and Safari. 37 | */ 38 | 39 | h1 { 40 | font-size: 2em; 41 | margin: 0.67em 0; 42 | } 43 | 44 | /* Grouping content 45 | ========================================================================== */ 46 | 47 | /** 48 | * Add the correct display in IE 9-. 49 | * 1. Add the correct display in IE. 50 | */ 51 | 52 | figcaption, 53 | figure, 54 | main { /* 1 */ 55 | display: block; 56 | } 57 | 58 | /** 59 | * Add the correct margin in IE 8. 60 | */ 61 | 62 | figure { 63 | margin: 1em 40px; 64 | } 65 | 66 | /** 67 | * 1. Add the correct box sizing in Firefox. 68 | * 2. Show the overflow in Edge and IE. 69 | */ 70 | 71 | hr { 72 | box-sizing: content-box; /* 1 */ 73 | height: 0; /* 1 */ 74 | overflow: visible; /* 2 */ 75 | } 76 | 77 | /** 78 | * 1. Correct the inheritance and scaling of font size in all browsers. 79 | * 2. Correct the odd `em` font sizing in all browsers. 80 | */ 81 | 82 | pre { 83 | font-family: monospace, monospace; /* 1 */ 84 | font-size: 1em; /* 2 */ 85 | } 86 | 87 | /* Text-level semantics 88 | ========================================================================== */ 89 | 90 | /** 91 | * 1. Remove the gray background on active links in IE 10. 92 | * 2. Remove gaps in links underline in iOS 8+ and Safari 8+. 93 | */ 94 | 95 | a { 96 | background-color: transparent; /* 1 */ 97 | -webkit-text-decoration-skip: objects; /* 2 */ 98 | } 99 | 100 | /** 101 | * 1. Remove the bottom border in Chrome 57- and Firefox 39-. 102 | * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. 103 | */ 104 | 105 | abbr[title] { 106 | border-bottom: none; /* 1 */ 107 | text-decoration: underline; /* 2 */ 108 | text-decoration: underline dotted; /* 2 */ 109 | } 110 | 111 | /** 112 | * Prevent the duplicate application of `bolder` by the next rule in Safari 6. 113 | */ 114 | 115 | b, 116 | strong { 117 | font-weight: inherit; 118 | } 119 | 120 | /** 121 | * Add the correct font weight in Chrome, Edge, and Safari. 122 | */ 123 | 124 | b, 125 | strong { 126 | font-weight: bolder; 127 | } 128 | 129 | /** 130 | * 1. Correct the inheritance and scaling of font size in all browsers. 131 | * 2. Correct the odd `em` font sizing in all browsers. 132 | */ 133 | 134 | code, 135 | kbd, 136 | samp { 137 | font-family: monospace, monospace; /* 1 */ 138 | font-size: 1em; /* 2 */ 139 | } 140 | 141 | /** 142 | * Add the correct font style in Android 4.3-. 143 | */ 144 | 145 | dfn { 146 | font-style: italic; 147 | } 148 | 149 | /** 150 | * Add the correct background and color in IE 9-. 151 | */ 152 | 153 | mark { 154 | background-color: #ff0; 155 | color: #000; 156 | } 157 | 158 | /** 159 | * Add the correct font size in all browsers. 160 | */ 161 | 162 | small { 163 | font-size: 80%; 164 | } 165 | 166 | /** 167 | * Prevent `sub` and `sup` elements from affecting the line height in 168 | * all browsers. 169 | */ 170 | 171 | sub, 172 | sup { 173 | font-size: 75%; 174 | line-height: 0; 175 | position: relative; 176 | vertical-align: baseline; 177 | } 178 | 179 | sub { 180 | bottom: -0.25em; 181 | } 182 | 183 | sup { 184 | top: -0.5em; 185 | } 186 | 187 | /* Embedded content 188 | ========================================================================== */ 189 | 190 | /** 191 | * Add the correct display in IE 9-. 192 | */ 193 | 194 | audio, 195 | video { 196 | display: inline-block; 197 | } 198 | 199 | /** 200 | * Add the correct display in iOS 4-7. 201 | */ 202 | 203 | audio:not([controls]) { 204 | display: none; 205 | height: 0; 206 | } 207 | 208 | /** 209 | * Remove the border on images inside links in IE 10-. 210 | */ 211 | 212 | img { 213 | border-style: none; 214 | } 215 | 216 | /** 217 | * Hide the overflow in IE. 218 | */ 219 | 220 | svg:not(:root) { 221 | overflow: hidden; 222 | } 223 | 224 | /* Forms 225 | ========================================================================== */ 226 | 227 | /** 228 | * Remove the margin in Firefox and Safari. 229 | */ 230 | 231 | button, 232 | input, 233 | optgroup, 234 | select, 235 | textarea { 236 | margin: 0; 237 | } 238 | 239 | /** 240 | * Show the overflow in IE. 241 | * 1. Show the overflow in Edge. 242 | */ 243 | 244 | button, 245 | input { /* 1 */ 246 | overflow: visible; 247 | } 248 | 249 | /** 250 | * Remove the inheritance of text transform in Edge, Firefox, and IE. 251 | * 1. Remove the inheritance of text transform in Firefox. 252 | */ 253 | 254 | button, 255 | select { /* 1 */ 256 | text-transform: none; 257 | } 258 | 259 | /** 260 | * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` 261 | * controls in Android 4. 262 | * 2. Correct the inability to style clickable types in iOS and Safari. 263 | */ 264 | 265 | button, 266 | html [type="button"], /* 1 */ 267 | [type="reset"], 268 | [type="submit"] { 269 | -webkit-appearance: button; /* 2 */ 270 | } 271 | 272 | /** 273 | * Remove the inner border and padding in Firefox. 274 | */ 275 | 276 | button::-moz-focus-inner, 277 | [type="button"]::-moz-focus-inner, 278 | [type="reset"]::-moz-focus-inner, 279 | [type="submit"]::-moz-focus-inner { 280 | border-style: none; 281 | padding: 0; 282 | } 283 | 284 | /** 285 | * Restore the focus styles unset by the previous rule. 286 | */ 287 | 288 | button:-moz-focusring, 289 | [type="button"]:-moz-focusring, 290 | [type="reset"]:-moz-focusring, 291 | [type="submit"]:-moz-focusring { 292 | outline: 1px dotted ButtonText; 293 | } 294 | 295 | /** 296 | * 1. Correct the text wrapping in Edge and IE. 297 | * 2. Correct the color inheritance from `fieldset` elements in IE. 298 | * 3. Remove the padding so developers are not caught out when they zero out 299 | * `fieldset` elements in all browsers. 300 | */ 301 | 302 | legend { 303 | box-sizing: border-box; /* 1 */ 304 | color: inherit; /* 2 */ 305 | display: table; /* 1 */ 306 | max-width: 100%; /* 1 */ 307 | padding: 0; /* 3 */ 308 | white-space: normal; /* 1 */ 309 | } 310 | 311 | /** 312 | * 1. Add the correct display in IE 9-. 313 | * 2. Add the correct vertical alignment in Chrome, Firefox, and Opera. 314 | */ 315 | 316 | progress { 317 | display: inline-block; /* 1 */ 318 | vertical-align: baseline; /* 2 */ 319 | } 320 | 321 | /** 322 | * Remove the default vertical scrollbar in IE. 323 | */ 324 | 325 | textarea { 326 | overflow: auto; 327 | } 328 | 329 | /** 330 | * 1. Add the correct box sizing in IE 10-. 331 | * 2. Remove the padding in IE 10-. 332 | */ 333 | 334 | [type="checkbox"], 335 | [type="radio"] { 336 | box-sizing: border-box; /* 1 */ 337 | padding: 0; /* 2 */ 338 | } 339 | 340 | /** 341 | * Correct the cursor style of increment and decrement buttons in Chrome. 342 | */ 343 | 344 | [type="number"]::-webkit-inner-spin-button, 345 | [type="number"]::-webkit-outer-spin-button { 346 | height: auto; 347 | } 348 | 349 | /** 350 | * 1. Correct the odd appearance in Chrome and Safari. 351 | * 2. Correct the outline style in Safari. 352 | */ 353 | 354 | [type="search"] { 355 | -webkit-appearance: textfield; /* 1 */ 356 | outline-offset: -2px; /* 2 */ 357 | } 358 | 359 | /** 360 | * Remove the inner padding and cancel buttons in Chrome and Safari on macOS. 361 | */ 362 | 363 | [type="search"]::-webkit-search-cancel-button, 364 | [type="search"]::-webkit-search-decoration { 365 | -webkit-appearance: none; 366 | } 367 | 368 | /** 369 | * 1. Correct the inability to style clickable types in iOS and Safari. 370 | * 2. Change font properties to `inherit` in Safari. 371 | */ 372 | 373 | ::-webkit-file-upload-button { 374 | -webkit-appearance: button; /* 1 */ 375 | font: inherit; /* 2 */ 376 | } 377 | 378 | /* Interactive 379 | ========================================================================== */ 380 | 381 | /* 382 | * Add the correct display in IE 9-. 383 | * 1. Add the correct display in Edge, IE, and Firefox. 384 | */ 385 | 386 | details, /* 1 */ 387 | menu { 388 | display: block; 389 | } 390 | 391 | /* 392 | * Add the correct display in all browsers. 393 | */ 394 | 395 | summary { 396 | display: list-item; 397 | } 398 | 399 | /* Scripting 400 | ========================================================================== */ 401 | 402 | /** 403 | * Add the correct display in IE 9-. 404 | */ 405 | 406 | canvas { 407 | display: inline-block; 408 | } 409 | 410 | /** 411 | * Add the correct display in IE. 412 | */ 413 | 414 | template { 415 | display: none; 416 | } 417 | 418 | /* Hidden 419 | ========================================================================== */ 420 | 421 | /** 422 | * Add the correct display in IE 10-. 423 | */ 424 | 425 | [hidden] { 426 | display: none; 427 | } 428 | -------------------------------------------------------------------------------- /templates/default/store/configureStore.dev.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware, compose } from 'redux'; 2 | import rootReducer from '../modules'; 3 | import thunk from 'redux-thunk'; 4 | 5 | const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; 6 | 7 | export default createStore( 8 | rootReducer, 9 | composeEnhancers(applyMiddleware(thunk)) 10 | ); 11 | -------------------------------------------------------------------------------- /templates/default/store/configureStore.prod.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware } from 'redux'; 2 | import rootReducer from '../modules'; 3 | import thunk from 'redux-thunk'; 4 | 5 | export default createStore(rootReducer, applyMiddleware(thunk)); 6 | -------------------------------------------------------------------------------- /templates/default/store/index.js: -------------------------------------------------------------------------------- 1 | if (process.env.NODE_ENV === 'production') { 2 | module.exports = require('./configureStore.prod'); 3 | } else { 4 | module.exports = require('./configureStore.dev'); 5 | } 6 | -------------------------------------------------------------------------------- /templates/react-router-4/components/Button.js: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components' 2 | 3 | export default styled.header` 4 | align-items: center; 5 | background: #333; 6 | color: #fff; 7 | display: flex; 8 | min-height: 40px; 9 | ` 10 | -------------------------------------------------------------------------------- /templates/react-router-4/containers/App.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { Route } from 'react-router-dom' 3 | import Home from './Home' 4 | 5 | export default class App extends Component { 6 | render() { 7 | return ( 8 |
9 | 10 |
11 | ) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /templates/react-router-4/containers/Home.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react' 2 | import { connect } from 'react-redux' 3 | import { fakeLogin, logout } from '../modules/user' 4 | 5 | class Home extends PureComponent { 6 | render() { 7 | const { name, isAuthenticated } = this.props.user 8 | const { fakeLogin, logout } = this.props 9 | 10 | return ( 11 |
12 | {isAuthenticated ? ( 13 |
14 |

Hello, {name}

15 | 16 |
17 | ) : ( 18 |
19 |

Hello

20 | 21 |
22 | )} 23 |
24 | ) 25 | } 26 | } 27 | 28 | export default connect(({ user }) => ({ user }), { 29 | fakeLogin, 30 | logout, 31 | })(Home) 32 | -------------------------------------------------------------------------------- /templates/react-router-4/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { render } from 'react-dom' 3 | import { Provider } from 'react-redux' 4 | import { ConnectedRouter as Router } from 'react-router-redux' 5 | import createHistory from 'history/createBrowserHistory' 6 | import createStore from './store' 7 | import App from './containers/App' 8 | import './static/css/reboot.css' 9 | 10 | const history = createHistory() 11 | const el = document.getElementById('root') 12 | 13 | const store = createStore(history) 14 | 15 | function r(Component) { 16 | render( 17 | 18 | 19 | 20 | 21 | , 22 | el 23 | ) 24 | } 25 | 26 | r(App) 27 | 28 | if (module.hot) { 29 | module.hot.accept('./containers/App', () => { 30 | const NextApp = require('./containers/App').default 31 | r(NextApp) 32 | }) 33 | } 34 | -------------------------------------------------------------------------------- /templates/react-router-4/modules/index.js: -------------------------------------------------------------------------------- 1 | import { combineReducers } from 'redux' 2 | import { routerReducer } from 'react-router-redux' 3 | import user from './user' 4 | 5 | export default combineReducers({ 6 | user, 7 | router: routerReducer, 8 | }) 9 | -------------------------------------------------------------------------------- /templates/react-router-4/modules/user.js: -------------------------------------------------------------------------------- 1 | const USER_LOGGED_IN = 'app/user/USER_LOGGED_IN' 2 | const USER_LOGGED_OUT = 'app/user/USER_LOGGED_OUT' 3 | 4 | const initialState = { 5 | avatar: null, 6 | isAuthenticated: false, 7 | name: null, 8 | points: null, 9 | rank_group: null, 10 | } 11 | 12 | export default function user(state = initialState, action) { 13 | switch (action.type) { 14 | case USER_LOGGED_IN: 15 | return { 16 | ...state, 17 | isAuthenticated: true, 18 | 19 | // spread over payload, instead of manually adding each key 20 | ...action.payload, 21 | } 22 | 23 | case USER_LOGGED_OUT: 24 | return initialState 25 | 26 | default: 27 | return state 28 | } 29 | } 30 | 31 | export function fakeLogin() { 32 | return dispatch => { 33 | setTimeout(() => { 34 | dispatch({ 35 | type: USER_LOGGED_IN, 36 | payload: { 37 | avatar: '//placecage.com/200/200', 38 | name: 'UserName', 39 | points: 1337, 40 | rank_group: 5, 41 | }, 42 | }) 43 | }, 2000) // fake db delay 44 | } 45 | } 46 | 47 | export function logout() { 48 | return { 49 | type: USER_LOGGED_OUT, 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /templates/react-router-4/static/css/reboot.css: -------------------------------------------------------------------------------- 1 | *, 2 | *::before, 3 | *::after { 4 | box-sizing: border-box; 5 | } 6 | 7 | html { 8 | font-family: sans-serif; 9 | line-height: 1.15; 10 | -webkit-text-size-adjust: 100%; 11 | -ms-text-size-adjust: 100%; 12 | -ms-overflow-style: scrollbar; 13 | -webkit-tap-highlight-color: transparent; 14 | } 15 | 16 | @-ms-viewport { 17 | width: device-width; 18 | } 19 | 20 | article, 21 | aside, 22 | dialog, 23 | figcaption, 24 | figure, 25 | footer, 26 | header, 27 | hgroup, 28 | main, 29 | nav, 30 | section { 31 | display: block; 32 | } 33 | 34 | body { 35 | margin: 0; 36 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 37 | 'Helvetica Neue', Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 38 | 'Segoe UI Symbol'; 39 | font-size: 1rem; 40 | font-weight: normal; 41 | line-height: 1.5; 42 | color: #212529; 43 | text-align: left; 44 | background-color: #fff; 45 | } 46 | 47 | [tabindex='-1']:focus { 48 | outline: none !important; 49 | } 50 | 51 | hr { 52 | box-sizing: content-box; 53 | height: 0; 54 | overflow: visible; 55 | } 56 | 57 | h1, 58 | h2, 59 | h3, 60 | h4, 61 | h5, 62 | h6 { 63 | margin-top: 0; 64 | margin-bottom: 0.5rem; 65 | } 66 | 67 | p { 68 | margin-top: 0; 69 | margin-bottom: 1rem; 70 | } 71 | 72 | abbr[title], 73 | abbr[data-original-title] { 74 | text-decoration: underline; 75 | -webkit-text-decoration: underline dotted; 76 | text-decoration: underline dotted; 77 | cursor: help; 78 | border-bottom: 0; 79 | } 80 | 81 | address { 82 | margin-bottom: 1rem; 83 | font-style: normal; 84 | line-height: inherit; 85 | } 86 | 87 | ol, 88 | ul, 89 | dl { 90 | margin-top: 0; 91 | margin-bottom: 1rem; 92 | } 93 | 94 | ol ol, 95 | ul ul, 96 | ol ul, 97 | ul ol { 98 | margin-bottom: 0; 99 | } 100 | 101 | dt { 102 | font-weight: bold; 103 | } 104 | 105 | dd { 106 | margin-bottom: 0.5rem; 107 | margin-left: 0; 108 | } 109 | 110 | blockquote { 111 | margin: 0 0 1rem; 112 | } 113 | 114 | dfn { 115 | font-style: italic; 116 | } 117 | 118 | b, 119 | strong { 120 | font-weight: bolder; 121 | } 122 | 123 | small { 124 | font-size: 80%; 125 | } 126 | 127 | sub, 128 | sup { 129 | position: relative; 130 | font-size: 75%; 131 | line-height: 0; 132 | vertical-align: baseline; 133 | } 134 | 135 | sub { 136 | bottom: -0.25em; 137 | } 138 | 139 | sup { 140 | top: -0.5em; 141 | } 142 | 143 | a { 144 | color: #007bff; 145 | text-decoration: none; 146 | background-color: transparent; 147 | -webkit-text-decoration-skip: objects; 148 | } 149 | 150 | a:hover { 151 | color: #0056b3; 152 | text-decoration: underline; 153 | } 154 | 155 | a:not([href]):not([tabindex]) { 156 | color: inherit; 157 | text-decoration: none; 158 | } 159 | 160 | a:not([href]):not([tabindex]):focus, 161 | a:not([href]):not([tabindex]):hover { 162 | color: inherit; 163 | text-decoration: none; 164 | } 165 | 166 | a:not([href]):not([tabindex]):focus { 167 | outline: 0; 168 | } 169 | 170 | pre, 171 | code, 172 | kbd, 173 | samp { 174 | font-family: monospace, monospace; 175 | font-size: 1em; 176 | } 177 | 178 | pre { 179 | margin-top: 0; 180 | margin-bottom: 1rem; 181 | overflow: auto; 182 | -ms-overflow-style: scrollbar; 183 | } 184 | 185 | figure { 186 | margin: 0 0 1rem; 187 | } 188 | 189 | img { 190 | vertical-align: middle; 191 | border-style: none; 192 | } 193 | 194 | svg:not(:root) { 195 | overflow: hidden; 196 | } 197 | 198 | a, 199 | area, 200 | button, 201 | [role='button'], 202 | input:not([type='range']), 203 | label, 204 | select, 205 | summary, 206 | textarea { 207 | -ms-touch-action: manipulation; 208 | touch-action: manipulation; 209 | } 210 | 211 | table { 212 | border-collapse: collapse; 213 | } 214 | 215 | caption { 216 | padding-top: 0.75rem; 217 | padding-bottom: 0.75rem; 218 | color: #868e96; 219 | text-align: left; 220 | caption-side: bottom; 221 | } 222 | 223 | th { 224 | text-align: inherit; 225 | } 226 | 227 | label { 228 | display: inline-block; 229 | margin-bottom: 0.5rem; 230 | } 231 | 232 | button { 233 | border-radius: 0; 234 | } 235 | 236 | button:focus { 237 | outline: 1px dotted; 238 | outline: 5px auto -webkit-focus-ring-color; 239 | } 240 | 241 | input, 242 | button, 243 | select, 244 | optgroup, 245 | textarea { 246 | margin: 0; 247 | font-family: inherit; 248 | font-size: inherit; 249 | line-height: inherit; 250 | } 251 | 252 | button, 253 | input { 254 | overflow: visible; 255 | } 256 | 257 | button, 258 | select { 259 | text-transform: none; 260 | } 261 | 262 | button, 263 | html [type='button'], 264 | [type='reset'], 265 | [type='submit'] { 266 | -webkit-appearance: button; 267 | } 268 | 269 | button::-moz-focus-inner, 270 | [type='button']::-moz-focus-inner, 271 | [type='reset']::-moz-focus-inner, 272 | [type='submit']::-moz-focus-inner { 273 | padding: 0; 274 | border-style: none; 275 | } 276 | 277 | input[type='radio'], 278 | input[type='checkbox'] { 279 | box-sizing: border-box; 280 | padding: 0; 281 | } 282 | 283 | input[type='date'], 284 | input[type='time'], 285 | input[type='datetime-local'], 286 | input[type='month'] { 287 | -webkit-appearance: listbox; 288 | } 289 | 290 | textarea { 291 | overflow: auto; 292 | resize: vertical; 293 | } 294 | 295 | fieldset { 296 | min-width: 0; 297 | padding: 0; 298 | margin: 0; 299 | border: 0; 300 | } 301 | 302 | legend { 303 | display: block; 304 | width: 100%; 305 | max-width: 100%; 306 | padding: 0; 307 | margin-bottom: 0.5rem; 308 | font-size: 1.5rem; 309 | line-height: inherit; 310 | color: inherit; 311 | white-space: normal; 312 | } 313 | 314 | progress { 315 | vertical-align: baseline; 316 | } 317 | 318 | [type='number']::-webkit-inner-spin-button, 319 | [type='number']::-webkit-outer-spin-button { 320 | height: auto; 321 | } 322 | 323 | [type='search'] { 324 | outline-offset: -2px; 325 | -webkit-appearance: none; 326 | } 327 | 328 | [type='search']::-webkit-search-cancel-button, 329 | [type='search']::-webkit-search-decoration { 330 | -webkit-appearance: none; 331 | } 332 | 333 | ::-webkit-file-upload-button { 334 | font: inherit; 335 | -webkit-appearance: button; 336 | } 337 | 338 | output { 339 | display: inline-block; 340 | } 341 | 342 | summary { 343 | display: list-item; 344 | } 345 | 346 | template { 347 | display: none; 348 | } 349 | 350 | [hidden] { 351 | display: none !important; 352 | } 353 | -------------------------------------------------------------------------------- /templates/react-router-4/store/index.js: -------------------------------------------------------------------------------- 1 | import { createStore, applyMiddleware, compose } from 'redux' 2 | import { routerMiddleware } from 'react-router-redux' 3 | import thunk from 'redux-thunk' 4 | import reducers from '../modules' 5 | 6 | export default history => { 7 | const composeEnhancers = 8 | window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose 9 | 10 | const middleware = [routerMiddleware(history), thunk] 11 | 12 | // add redux-devtools for development 13 | const middlewares = 14 | process.env.NODE_ENV === 'production' 15 | ? applyMiddleware(...middleware) 16 | : composeEnhancers(applyMiddleware(...middleware)) 17 | 18 | const store = createStore(reducers, middlewares) 19 | 20 | // hot module replacement for reducers 21 | if (module.hot) { 22 | module.hot.accept('../modules', () => { 23 | const nextRootReducer = require('../modules').default 24 | store.replaceReducer(nextRootReducer) 25 | }) 26 | } 27 | 28 | return store 29 | } 30 | -------------------------------------------------------------------------------- /test/pretest.js: -------------------------------------------------------------------------------- 1 | const wooo = require('../lib').default() 2 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const { resolve } = require('path') 3 | 4 | function dp(pth, done) { 5 | fs.open(pth, 'r', (err, fd) => { 6 | if (err) { 7 | return done(err) 8 | } 9 | 10 | done() 11 | }) 12 | } 13 | 14 | function resolveDir(dir) { 15 | return resolve(__dirname, dir) 16 | } 17 | 18 | describe('after running wooo', () => { 19 | describe('containers', () => { 20 | it('should created containers folder', done => { 21 | dp(resolveDir('../_test_/containers'), done) 22 | }) 23 | 24 | describe('App', () => { 25 | it('should created containers/App.js', done => { 26 | dp(resolveDir('../_test_/containers/App.js'), done) 27 | }) 28 | }) 29 | 30 | describe('Home', () => { 31 | it('should created containers/Home.js', done => { 32 | dp(resolveDir('../_test_/containers/Home.js'), done) 33 | }) 34 | }) 35 | }) 36 | 37 | describe('modules', () => { 38 | it('should created modules folder', done => { 39 | dp(resolveDir('../_test_/modules'), done) 40 | }) 41 | 42 | it('should created modules/index file', done => { 43 | dp(resolveDir('../_test_/modules/index.js'), done) 44 | }) 45 | 46 | it('should created modules/user file', done => { 47 | dp(resolveDir('../_test_/modules/user.js'), done) 48 | }) 49 | }) 50 | 51 | describe('static', () => { 52 | it('should created static folder', done => { 53 | dp(resolveDir('../_test_/static'), done) 54 | }) 55 | 56 | it('should created static/css/reboot.css file', done => { 57 | dp(resolveDir('../_test_/static/css/reboot.css'), done) 58 | }) 59 | }) 60 | 61 | describe('store', () => { 62 | it('should created store folder', done => { 63 | dp(resolveDir('../_test_/store'), done) 64 | }) 65 | 66 | it('should created store/index file', done => { 67 | dp(resolveDir('../_test_/store/index.js'), done) 68 | }) 69 | }) 70 | }) 71 | --------------------------------------------------------------------------------