├── .gitignore
├── LICENSE
├── README.md
├── package.json
├── roc.setup.json
└── template
├── .editorconfig
├── .eslintignore
├── .eslintrc
├── .gitignore
├── LICENSE
├── package.json
├── public
└── favicon.png
├── roc.config.js
└── src
├── components
├── clicker
│ ├── index.js
│ └── style.scss
├── fetching
│ ├── index.js
│ └── style.scss
├── header
│ ├── index.js
│ ├── roc.png
│ └── style.scss
├── index.js
├── redux
│ ├── index.js
│ └── style.scss
├── reset.scss
├── start
│ ├── ext.png
│ ├── index.js
│ ├── index.spec.js
│ └── style.scss
└── style.scss
├── redux
├── clicker.js
├── reducers.js
└── repo.js
└── routes.js
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Verdens Gang AS
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 | # roc-template-web-app-react
2 |
3 | Template for creating a application that builds on [roc-package-web-app-react](https://github.com/rocjs/roc-package-web-app-react).
4 |
5 | ## Install
6 |
7 | `$ roc init rocjs/roc-template-web-app-react`
8 |
9 | _This repository is a default alternative in the Roc CLI and can be used directly using `$ roc init web-app-react`_.
10 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "roc-template-web-app-react",
3 | "version": "1.1.0-next.1",
4 | "description": "A simple start on a generic React web application for Roc",
5 | "author": "Verdens Gang AS",
6 | "license": "MIT",
7 | "keywords": [
8 | "roc",
9 | "roc-template",
10 | "react",
11 | "universal",
12 | "isomorphic",
13 | "redux"
14 | ]
15 | }
16 |
--------------------------------------------------------------------------------
/roc.setup.json:
--------------------------------------------------------------------------------
1 | {
2 | "prompts": {
3 | "name": {
4 | "type": "string",
5 | "required": true,
6 | "message": "Project name"
7 | },
8 | "description": {
9 | "type": "string",
10 | "required": false,
11 | "message": "Project description",
12 | "default": "A Roc project"
13 | },
14 | "author": {
15 | "type": "string",
16 | "message": "Author"
17 | },
18 | "license": {
19 | "type": "list",
20 | "choices": [{
21 | "name": "MIT"
22 | }, {
23 | "name": "UNLICENSED"
24 | }]
25 | },
26 | "port": {
27 | "type": "input",
28 | "message": "Port",
29 | "default": 3000
30 | },
31 | "title": {
32 | "type": "string",
33 | "message": "
"
34 | },
35 | "fetchExample": {
36 | "type": "confirm",
37 | "message": "Include data-fetching example?"
38 | },
39 | "reduxExample": {
40 | "type": "confirm",
41 | "message": "Include Redux example with data-fetching?"
42 | },
43 | "testJest": {
44 | "type": "confirm",
45 | "message": "Include Jest for testing?"
46 | }
47 | },
48 | "filters": {
49 | "LICENSE": "license === 'MIT'",
50 | "src/redux/**/*": "reduxExample",
51 | "src/components/redux/**/*": "reduxExample",
52 | "src/components/clicker/**/*": "reduxExample",
53 | "src/components/fetching/**/*": "fetchExample",
54 | "src/components/**/*.spec.js": "testJest"
55 | },
56 | "completionMessage": "To get started:\n\n{{#unless inPlace}} cd {{destDirName}}\n{{/unless}} npm install\n npm run dev\n\n It will open your default browser when ready.\n You can change this by setting 'dev.browsersync.options.open' to 'false' in roc.config.js"
57 | }
58 |
--------------------------------------------------------------------------------
/template/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig helps developers define and maintain consistent coding styles between different editors and IDEs.
2 | # Requires EditorConfig JetBrains Plugin - http://github.com/editorconfig/editorconfig-jetbrains
3 |
4 | # Set this file as the topmost .editorconfig
5 | # (multiple files can be used, and are applied starting from current document location)
6 | root = true
7 |
8 | # Use bracketed regexp to target specific file types or file locations
9 | [*.{js,json}]
10 |
11 | # Use hard or soft tabs ["tab", "space"]
12 | indent_style = space
13 |
14 | # Size of a single indent [an integer, "tab"]
15 | indent_size = tab
16 |
17 | # Number of columns representing a tab character [an integer]
18 | tab_width = 2
19 |
20 | # Line breaks representation ["lf", "cr", "crlf"]
21 | end_of_line = lf
22 |
23 | # ["latin1", "utf-8", "utf-16be", "utf-16le"]
24 | charset = utf-8
25 |
26 | # Remove any whitespace characters preceding newline characters ["true", "false"]
27 | trim_trailing_whitespace = true
28 |
29 | # Ensure file ends with a newline when saving ["true", "false"]
30 | insert_final_newline = true
31 |
--------------------------------------------------------------------------------
/template/.eslintignore:
--------------------------------------------------------------------------------
1 | build
2 |
--------------------------------------------------------------------------------
/template/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "airbnb",
4 | "roc"
5 | ],
6 | "parser": "babel-eslint",
7 | "rules": {
8 | "react/jsx-filename-extension": 0
9 | }{{#if testJest}},
10 | "env": {
11 | "jest": true
12 | }
13 | {{/if}}
14 | }
15 |
--------------------------------------------------------------------------------
/template/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | build
3 | node_modules
4 |
--------------------------------------------------------------------------------
/template/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 {{ author }}
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 |
--------------------------------------------------------------------------------
/template/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "{{ name }}",
3 | "version": "1.0.0",
4 | "description": "{{ description }}",
5 | "author": "{{ author }}",
6 | "license": "{{ license }}",
7 | {{#if_eq license "UNLICENSED"}}
8 | "private": true,
9 | {{/if_eq}}
10 | "scripts": {
11 | "build": "roc build",
12 | "dev": "roc dev",
13 | "lint": "eslint .",
14 | "start": "roc start"{{#if testJest}},
15 | "test": "roc test"
16 | {{/if}}
17 | },
18 | "dependencies": {
19 | {{#if fetchExample}}
20 | "isomorphic-fetch": "^2.2.1",
21 | {{else if reduxExample}}
22 | "isomorphic-fetch": "^2.2.1",
23 | {{/if}}
24 | "roc-package-web-app-react": "^1.0.0-beta.16"
25 | },
26 | "devDependencies": {
27 | "babel-eslint": "^7.1.0",
28 | "eslint": "^3.6.0",
29 | "eslint-config-airbnb": "^12.0.0",
30 | "eslint-config-roc": "^0.1.0",
31 | "eslint-plugin-import": "^1.16.0",
32 | "eslint-plugin-jsx-a11y": "^2.2.2",
33 | "eslint-plugin-react": "^6.3.0",
34 | "roc-package-web-app-react-dev": "^1.0.0-beta.16",
35 | "roc-plugin-style-sass": "1.0.0-beta.5"{{#if testJest}},
36 | "roc-plugin-test-jest": "^1.0.0-beta.3"
37 | {{/if}}
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/template/public/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rocjs/roc-template-web-app-react/f831bc6230e6b8ec43561b0f56729f14c56d5882/template/public/favicon.png
--------------------------------------------------------------------------------
/template/roc.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | settings: {
3 | runtime: {
4 | applicationName: '{{ title }}',
5 | port: {{ port }},
6 | serve: ['public', 'build/client'],
7 | favicon: 'favicon.png',
8 | {{#if fetchExample}}
9 | // fetch settings (these are the defaults)
10 | fetch: {
11 | server: ['fetch'], // hook used by server for fetching
12 | client: {
13 | beforeTransition: ['fetch'], // hook used by client for fetching that block route transitions
14 | afterTransition: ['defer', 'deferDone'], // hook used by client for fetching that does not block route transitions
15 | parallel: false, // if we should start non-blocking fetches in parallel with blocking ones
16 | },
17 | },
18 | {{/if}}
19 | },
20 | build: {
21 | {{#if reduxExample}}
22 | reducers: 'src/redux/reducers.js',
23 | {{/if}}
24 | routes: 'src/routes.js',
25 | },
26 | dev: {
27 | browsersync: {
28 | options: {
29 | open: true,
30 | },
31 | },
32 | },
33 | },
34 | };
35 |
--------------------------------------------------------------------------------
/template/src/components/clicker/index.js:
--------------------------------------------------------------------------------
1 | import PropTypes from 'prop-types';
2 | import React from 'react';
3 | import { bindActionCreators } from 'redux';
4 | import { connect } from 'react-redux';
5 |
6 | import { click } from '../../redux/clicker';
7 |
8 | import styles from './style.scss';
9 |
10 | function mapStateToProps(state) {
11 | return {
12 | clicker: state.clicker,
13 | };
14 | }
15 |
16 | function mapDispatchToProps(dispatch) {
17 | return bindActionCreators({ click }, dispatch);
18 | }
19 |
20 | /* decorate our component to make it redux state aware using react-redux */
21 | @connect(mapStateToProps, mapDispatchToProps)
22 | export default class Clicker extends React.Component {
23 | static defaultProps = {
24 | clicker: 0,
25 | }
26 |
27 | static propTypes = {
28 | clicker: PropTypes.number.isRequired,
29 | click: PropTypes.func.isRequired,
30 | }
31 |
32 | render() {
33 | return (
34 |
35 |
Counter: { this.props.clicker }
36 |
this.props.click(1)}>
37 | +1
38 |
39 |
this.props.click(-1)}>
40 | -1
41 |
42 |
43 | );
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/template/src/components/clicker/style.scss:
--------------------------------------------------------------------------------
1 | .main {
2 | margin: 15px 0 15px 0;
3 | }
4 |
--------------------------------------------------------------------------------
/template/src/components/fetching/index.js:
--------------------------------------------------------------------------------
1 | // React Hot Reload does not support stateless function components as of now
2 | /* eslint-disable react/prefer-stateless-function, react/no-multi-comp */
3 | import React, { Component } from 'react';
4 | import { provideHooks } from 'redial';
5 | import fetch from 'isomorphic-fetch';
6 |
7 | import styles from './style.scss';
8 |
9 | /* functions that promise to fetch json data from GitHub API */
10 | function fetchRocRepos() {
11 | return fetch('https://api.github.com/users/rocjs/repos')
12 | .then(response => response.json());
13 | }
14 |
15 | function fetchRocStargazers() {
16 | return fetch('https://api.github.com/repos/rocjs/roc')
17 | .then(response => response.json());
18 | }
19 |
20 | /* components for simple presentation */
21 | class RepoList extends Component {
22 | static propTypes = {
23 | display: React.PropTypes.number,
24 | loading: React.PropTypes.bool,
25 | repo: React.PropTypes.arrayOf(React.PropTypes.object),
26 | };
27 |
28 | static defaultProps = {
29 | display: 5,
30 | repoItems: [],
31 | loading: true,
32 | };
33 |
34 | render() {
35 | if (this.props.loading) {
36 | return Loading... ;
37 | }
38 |
39 | let repoItemsToDisplay = [];
40 |
41 | if (this.props.repo.length > 0) {
42 | repoItemsToDisplay = this.props.repo
43 | .filter((repo, index) => index < this.props.display)
44 | .map(repo => {repo.name} );
45 | }
46 |
47 | return ;
48 | }
49 | }
50 |
51 | class RocStargazers extends Component {
52 | static propTypes = {
53 | loading: React.PropTypes.bool,
54 | stars: React.PropTypes.number,
55 | }
56 |
57 | static defaultProps = {
58 | stars: 0,
59 | loading: true,
60 | };
61 |
62 | render() {
63 | if (this.props.loading) {
64 | return Loading... ;
65 | }
66 |
67 | return {this.props.stars} ;
68 | }
69 | }
70 |
71 | class FetchButton extends Component {
72 | static propTypes = {
73 | fetch: React.PropTypes.func,
74 | }
75 |
76 | render() {
77 | return Refetch ;
78 | }
79 | }
80 |
81 | /* enhance our component with data fetching abilities */
82 | @provideHooks({
83 | // by default, fetch is run on both server and client side
84 | fetch: ({ force, getProps, setProps }) => {
85 | const alreadyFetched = !!getProps().fetch;
86 |
87 | if (force || !alreadyFetched) {
88 | return fetchRocRepos()
89 | .then((json) => {
90 | setProps({
91 | repo: json,
92 | });
93 | });
94 | }
95 |
96 | return Promise.resolve();
97 | },
98 | // by default, defer only runs on the client side
99 | defer: ({ setProps }) => fetchRocStargazers()
100 | .then((json) => {
101 | setProps({
102 | stars: json.stargazers_count,
103 | });
104 | }),
105 | })
106 | /* this decorated component is mapped to /fetching/ in routes.js */
107 | export default class Fetching extends Component {
108 | static propTypes = {
109 | loading: React.PropTypes.bool,
110 | afterTransitionLoading: React.PropTypes.bool,
111 | reload: React.PropTypes.func,
112 | repo: React.PropTypes.arrayOf(React.PropTypes.object),
113 | stars: React.PropTypes.number,
114 | }
115 |
116 | static defaultProps = {
117 | repo: [],
118 | stars: 0,
119 | };
120 |
121 | render() {
122 | return (
123 |
124 |
Data fetching examples
125 |
126 | We recommend the use of these built-in facilities for data-fetching
127 | connected to your route components.
128 |
129 |
This gives you powerful data fetching that works on both the server and the client
130 |
131 |
Universal fetch data (server and client)
132 |
Top 5 Rocjs repositories
133 |
134 |
135 |
Clientside fetch data
136 |
Number of stargazers of rocjs/roc
137 |
138 |
139 |
Refetch all data
140 |
141 |
142 | );
143 | }
144 | }
145 | /* eslint-enablereact/prefer-stateless-function, react/no-multi-comp */
146 |
--------------------------------------------------------------------------------
/template/src/components/fetching/style.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rocjs/roc-template-web-app-react/f831bc6230e6b8ec43561b0f56729f14c56d5882/template/src/components/fetching/style.scss
--------------------------------------------------------------------------------
/template/src/components/header/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { IndexLink{{#if fetchExample }}, Link{{else if reduxExample}}, Link{{/if}} } from 'react-router';
3 |
4 | import logo from './roc.png';
5 | import styles from './style.scss';
6 |
7 | export default () =>
8 | (
9 |
10 |
11 |
12 |
17 | Start
18 |
19 |
20 | {{#if_eq fetchExample true}}
21 |
22 |
27 | Data-fetch
28 |
29 |
30 | {{/if_eq}}
31 | {{#if_eq reduxExample true}}
32 |
33 |
38 | Redux
39 |
40 |
41 | {{/if_eq}}
42 |
43 |
44 |
45 | )
46 | ;
47 |
--------------------------------------------------------------------------------
/template/src/components/header/roc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rocjs/roc-template-web-app-react/f831bc6230e6b8ec43561b0f56729f14c56d5882/template/src/components/header/roc.png
--------------------------------------------------------------------------------
/template/src/components/header/style.scss:
--------------------------------------------------------------------------------
1 | $bright: #fff;
2 | $light: #5f7a91;
3 | $dark: #254763;
4 |
5 | .header {
6 | background: $light;
7 | overflow: auto;
8 | text-align: center;
9 | }
10 |
11 | .menu {
12 | margin: 0 auto 0 auto;
13 |
14 | li {
15 | display: inline-block;
16 | {{#if fetchExample}}
17 | {{#if reduxExample}}
18 | width: 33.3%;
19 | {{else}}
20 | width: 50%;
21 | {{/if}}
22 | {{else}}
23 | {{#if reduxExample}}
24 | width: 50%;
25 | {{else}}
26 | width: 100%;
27 | {{/if}}
28 | {{/if}}
29 | height: 40px;
30 | line-height: 40px;
31 | margin: 0 0 0 0;
32 | }
33 |
34 | li:nth-child(2) {
35 | border-left: 1px solid $bright;
36 | border-right: 1px solid $bright;
37 | }
38 | }
39 |
40 | .item {
41 | display: block;
42 | background: $dark;
43 | border-bottom: 1px solid $bright;
44 | text-transform: uppercase;
45 |
46 | &:hover {
47 | background: $bright;
48 | color: $dark;
49 | border-bottom: none;
50 | }
51 | }
52 |
53 | .active {
54 | background: $bright;
55 | color: $dark;
56 | border-bottom: none;
57 | }
58 |
59 | .logo {
60 | width: 200px;
61 | margin: 20px 0 20px 0;
62 | }
63 |
--------------------------------------------------------------------------------
/template/src/components/index.js:
--------------------------------------------------------------------------------
1 | // React Hot Reload does not support stateless function components as of now
2 | /* eslint-disable react/prefer-stateless-function */
3 | import PropTypes from 'prop-types';
4 | import React, { Component } from 'react';
5 | import Helmet from 'react-helmet';
6 |
7 | import Header from './header';
8 | import styles from './style.scss';
9 |
10 | export default class App extends Component {
11 | static propTypes = {
12 | children: PropTypes.node.isRequired,
13 | }
14 |
15 | render() {
16 | return (
17 |
18 |
23 |
24 |
25 |
26 | { this.props.children }
27 |
28 |
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/template/src/components/redux/index.js:
--------------------------------------------------------------------------------
1 | // React Hot Reload does not support stateless function components as of now
2 | /* eslint-disable react/prefer-stateless-function */
3 | import React, { Component } from 'react';
4 | import { connect } from 'react-redux';
5 | import { provideHooks } from 'redial';
6 | import isoFetch from 'isomorphic-fetch';
7 |
8 | import Clicker from '../../components/clicker';
9 | import { repoFetchBegin, repoFetchSuccess, repoFetchFail } from '../../redux/repo';
10 | import styles from './style.scss';
11 |
12 | const repoApiUrl = 'http://api.github.com/repos/rocjs/roc';
13 |
14 | function fetchRocStargazers() {
15 | return isoFetch(repoApiUrl)
16 | .then(response => response.json());
17 | }
18 |
19 | @provideHooks({
20 | // by default, fetch is run on both server and client side
21 | fetch: ({ dispatch }) => {
22 | // dispatch that fetch has started
23 | dispatch(repoFetchBegin(repoApiUrl));
24 |
25 | // this "thunk" is compatible with a redux middleware that allows async actions
26 | // https://www.npmjs.com/package/redux-thunk
27 | const fetchThunk = (thunkDispatch) => {
28 | fetchRocStargazers().then((json) => {
29 | thunkDispatch(repoFetchSuccess(repoApiUrl, json));
30 | }).catch((err) => {
31 | thunkDispatch(repoFetchFail(repoApiUrl, err));
32 | });
33 | };
34 |
35 | // dispatch the thunk that will later dispatch a success of failure action depending on outcome
36 | return dispatch(fetchThunk);
37 | },
38 | })
39 | @connect(state => ({
40 | stargazers: state.repo.stargazers,
41 | }))
42 | export default class Redux extends Component {
43 | static propTypes = {
44 | stargazers: React.PropTypes.number,
45 | }
46 |
47 | render() {
48 | const { stargazers } = this.props;
49 |
50 | return (
51 |
52 |
Redux demo
53 |
54 | Roc takes care of all boilerplate required to set up Redux.
55 | Clicker (components/clicker/index.js) is a simple example-component that
56 | demonstrates how to connect your components to Redux.
57 |
58 |
59 |
60 |
61 |
62 | You can of course also do your data-fetching by dispatching a
63 | Redux action to do so! We have included a simple demo of this below.
64 |
65 |
Number of stargazers (fetched using Redux): { stargazers }
66 |
67 | );
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/template/src/components/redux/style.scss:
--------------------------------------------------------------------------------
1 | .main {
2 | strong {
3 | font-weight: bold;
4 | }
5 | p {
6 | margin-bottom: 20px;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/template/src/components/reset.scss:
--------------------------------------------------------------------------------
1 | /* http://meyerweb.com/eric/tools/css/reset/
2 | v2.0 | 20110126
3 | License: none (public domain)
4 | */
5 | html, body, div, span, applet, object, iframe,
6 | h1, h2, h3, h4, h5, h6, p, blockquote, pre,
7 | a, abbr, acronym, address, big, cite, code,
8 | del, dfn, em, img, ins, kbd, q, s, samp,
9 | small, strike, strong, sub, sup, tt, var,
10 | b, u, i, center,
11 | dl, dt, dd, ol, ul, li,
12 | fieldset, form, label, legend,
13 | table, caption, tbody, tfoot, thead, tr, th, td,
14 | article, aside, canvas, details, embed,
15 | figure, figcaption, footer, header, hgroup,
16 | menu, nav, output, ruby, section, summary,
17 | time, mark, audio, video {
18 | margin: 0;
19 | padding: 0;
20 | border: 0;
21 | font-size: 100%;
22 | font: inherit;
23 | vertical-align: baseline;
24 | }
25 | /* HTML5 display-role reset for older browsers */
26 | article, aside, details, figcaption, figure,
27 | footer, header, hgroup, menu, nav, section {
28 | display: block;
29 | }
30 | body {
31 | line-height: 1;
32 | }
33 | ol, ul {
34 | list-style: none;
35 | }
36 | blockquote, q {
37 | quotes: none;
38 | }
39 | blockquote:before, blockquote:after,
40 | q:before, q:after {
41 | content: '';
42 | content: none;
43 | }
44 | table {
45 | border-collapse: collapse;
46 | border-spacing: 0;
47 | }
48 |
--------------------------------------------------------------------------------
/template/src/components/start/ext.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rocjs/roc-template-web-app-react/f831bc6230e6b8ec43561b0f56729f14c56d5882/template/src/components/start/ext.png
--------------------------------------------------------------------------------
/template/src/components/start/index.js:
--------------------------------------------------------------------------------
1 | // React Hot Reload does not support stateless function components as of now
2 | /* eslint-disable react/prefer-stateless-function */
3 | import React, { Component } from 'react';
4 |
5 | import ext from './ext.png';
6 | import styles from './style.scss';
7 |
8 | export default class Start extends Component {
9 | render() {
10 | return (
11 |
12 |
Get started
13 |
14 | Open src/components/start.js in your favourite editor
15 | to make changes to this page.
16 |
17 |
src/routes.js maps routes to your components.
18 |
19 |
Docs
20 |
21 | Run roc docs in your project to generate updated docs for this Roc project.
22 |
23 |
24 |
Learn more
25 |
26 |
27 | Documentation for Roc on Github
28 |
29 |
30 | );
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/template/src/components/start/index.spec.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import renderer from 'react-test-renderer';
3 |
4 | import Start from './index';
5 |
6 | jest.mock('./ext.png', () => {});
7 | jest.mock('./style.scss', () => ({ default: {} }));
8 |
9 | it('renders start correctly', () => {
10 | const tree = renderer.create(
11 | ,
12 | ).toJSON();
13 |
14 | expect(tree).toMatchSnapshot();
15 | });
16 |
--------------------------------------------------------------------------------
/template/src/components/start/style.scss:
--------------------------------------------------------------------------------
1 | .main {
2 | text-align: center;
3 |
4 | a {
5 | color: #000;
6 | }
7 |
8 | span {
9 | background: #eee;
10 | padding: 2px;
11 | }
12 | }
13 |
14 | .ext {
15 | width: 250px;
16 | }
17 |
--------------------------------------------------------------------------------
/template/src/components/style.scss:
--------------------------------------------------------------------------------
1 | @import "reset";
2 |
3 | $bright: #fff;
4 | $light: #5f7a91;
5 | $dark: #254763;
6 |
7 | body {
8 | background: $bright;
9 | color: $dark;
10 | font-family: sans-serif;
11 | font-size: 14px;
12 | line-height: 22px;
13 | }
14 |
15 | a {
16 | color: #fff;
17 | text-decoration: none;
18 | }
19 |
20 | h1 {
21 | font-size: 32px;
22 | line-height: 80px;
23 | }
24 |
25 | h2 {
26 | font-size: 26px;
27 | line-height: 52px;
28 | }
29 |
30 | h3 {
31 | font-size: 22px;
32 | line-height: 30px;
33 | }
34 |
35 | button {
36 | padding: 4px;
37 | }
38 |
39 | .main {
40 | background: #fff;
41 | padding: 15px;
42 | max-width: 750px;
43 | margin: 0 auto 0 auto;
44 | }
45 |
--------------------------------------------------------------------------------
/template/src/redux/clicker.js:
--------------------------------------------------------------------------------
1 | const CLICKED = 'CLICKED';
2 |
3 | export default function clicker(state = 0, action = { increment: 1 }) {
4 | if (action.type === CLICKED) {
5 | return state + action.increment;
6 | }
7 |
8 | return state;
9 | }
10 |
11 | export function click(increment) {
12 | return { type: CLICKED, increment };
13 | }
14 |
--------------------------------------------------------------------------------
/template/src/redux/reducers.js:
--------------------------------------------------------------------------------
1 | export clicker from './clicker';
2 | export repo from './repo';
3 |
--------------------------------------------------------------------------------
/template/src/redux/repo.js:
--------------------------------------------------------------------------------
1 | const FETCH_REPO_REQUEST = 'FETCH_REPO_REQUEST';
2 | const FETCH_REPO_SUCCESS = 'FETCH_REPO_SUCCESS';
3 | const FETCH_REPO_FAIL = 'FETCH_REPO_FAIL';
4 |
5 | const defaultState = {
6 | loading: false,
7 | error: false,
8 | stargazers: undefined,
9 | };
10 |
11 | export default function repoFetch(state = defaultState, action) {
12 | if (action.type === FETCH_REPO_REQUEST) {
13 | return {
14 | loading: true,
15 | endpoint: action.payload.endpoint,
16 | error: false,
17 | stargazers: undefined,
18 | };
19 | }
20 |
21 | if (action.type === FETCH_REPO_SUCCESS) {
22 | return {
23 | loading: false,
24 | error: false,
25 | endpoint: action.payload.endpoint,
26 | stargazers: action.payload.data.stargazers_count,
27 | };
28 | }
29 |
30 | if (action.type === FETCH_REPO_FAIL) {
31 | return {
32 | loading: false,
33 | error: action.payload.error,
34 | endpoint: action.payload.endpoint,
35 | stargazers: undefined,
36 | };
37 | }
38 |
39 | return state;
40 | }
41 |
42 | export function repoFetchBegin(url) {
43 | return {
44 | type: FETCH_REPO_REQUEST,
45 | payload: {
46 | endpoint: url,
47 | },
48 | };
49 | }
50 |
51 | export function repoFetchSuccess(url, json) {
52 | return {
53 | type: FETCH_REPO_SUCCESS,
54 | payload: {
55 | endpoint: url,
56 | data: json,
57 | },
58 | };
59 | }
60 |
61 | export function repoFetchFail(url, err) {
62 | return {
63 | type: FETCH_REPO_FAIL,
64 | payload: {
65 | error: err,
66 | endpoint: url,
67 | },
68 | };
69 | }
70 |
--------------------------------------------------------------------------------
/template/src/routes.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Route, IndexRoute } from 'react-router';
3 |
4 | import App from './components';
5 | import Start from './components/start';
6 | {{#if_eq fetchExample true}}
7 | import Fetching from './components/fetching';
8 | {{/if_eq}}
9 | {{#if_eq reduxExample true}}
10 | import Redux from './components/redux';
11 | {{/if_eq}}
12 |
13 | export default () => (
14 |
15 |
16 | {{#if_eq fetchExample true}}
17 |
18 | {{/if_eq}}
19 | {{#if_eq reduxExample true}}
20 |
21 | {{/if_eq}}
22 |
23 | );
24 |
--------------------------------------------------------------------------------