diff --git a/.jshintrc b/.jshintrc
deleted file mode 100644
index 2b6f469..0000000
--- a/.jshintrc
+++ /dev/null
@@ -1,3 +0,0 @@
-{
- "esversion": 6
-}
diff --git a/README.md b/README.md
index 333db29..52c716b 100644
--- a/README.md
+++ b/README.md
@@ -1,26 +1,13 @@
-# react-webpack-babel-simple-starter
-Simple React Webpack Babel Starter Kit
+# react-mobx-router5-example
+
+This is a simple setup example for the [react-mobx-router5](https://github.com/LeonardoGentile/react-mobx-router5) project.
-Tired of complicated starters with 200MB of dependencies which are hard to understand and modify?
+### Install and Run
-Try this is a simple [React](https://facebook.github.io/react/), [Webpack](http://webpack.github.io/) and [Babel](https://babeljs.io/) application with nothing else in it.
-
-This is a fork of [react-webpack-babel-simple-starter](https://github.com/alicoding/react-webpack-babel)
-
-### What's in it?
-
-* Simple src/app.jsx and src/app.scss (local module css).
-* Webpack configuration for development (with hot reloading) and production (with minification).
-* CSS module loading, so you can include your css by ```import styles from './path/to.css';```.
-* Both js(x) and css hot loaded during development.
-
-### To run
-
-* You'll need to have [git](https://git-scm.com/) and [node](https://nodejs.org/en/) installed in your system.
-* Fork and clone the project:
+* Fork, clone, or download the project:
```
-git clone https://github.com/alicoding/react-webpack-babel.git
+git clone https://github.com/LeonardoGentile/react-mobx-router5-example.git
```
* Then install the dependencies:
@@ -37,63 +24,46 @@ npm start
Open the web browser to `http://localhost:8888/`
-### To build the production package
-
-```
-npm run build
-```
-
-### Nginx Config
+### Routes and Nodes
+
+The project uses this routes configuration:
+
+```javascript
+export default [
+ { name: 'home', path: '/', component: Home},
+ { name: 'login', path: '/login', component: Login},
+ { name: 'index', path: '/index/:id', component: Index},
+ { name: 'section', path: '/section', component: Sections, children: [
+ // Sections
+ { name: 'home', path: '/home', component: Home },
+ { name: 'login', path: '/login', component: Login },
+ { name: 'index', path: '/index/:id', component: Index },
+ { name: 'subsection', path: '/subsection', component: SubSections, children: [
+ // Subsections
+ { name: 'home', path: '/home', component: Home },
+ { name: 'login', path: '/login', component: Login },
+ { name: 'index', path: '/index/:id', component: Index }
+ ]}
+ ]}
+];
-Here is an example Nginx config:
-```
-server {
- # ... root and other options
-
- gzip on;
- gzip_http_version 1.1;
- gzip_types text/plain text/css text/xml application/javascript image/svg+xml;
-
- location / {
- try_files $uri $uri/ /index.html;
- }
-
- location ~ \.html?$ {
- expires 1d;
- }
-
- location ~ \.(svg|ttf|js|css|svgz|eot|otf|woff|jpg|jpeg|gif|png|ico)$ {
- access_log off;
- log_not_found off;
- expires max;
- }
-}
```
-### Eslint
-There is a .eslint.yaml config for eslint ready with React plugin.
-To use it, you need to install additional dependencies though:
+That means that the nodes of this app are:
-```
-npm install --save-dev eslint eslint-plugin-react
-```
+ - `''` the root node, see the `Main` component
+ - `'section'`, see the `Sections` component
+ - `'section.subsection'`, see the `Subsections` component
+
+All this components should be wrapped with `routeNode` HOC.
+Notice that `routeNode` HOC injects an `activeRoute` (non-observable) and (mobx-router5) `routerStore` props to the wrapped component.
-To do the actual linting, run:
+Each one of these uses in turn the `RouteView` component, resposnsible to select and render the various
+subcomponent.
+Notice that a `RouteView` component injects a `route` prop (in this case the non-observable `activeRoute` that was injected into the routeNode components) to the newly created component.
-```
-npm run lint
-```
+The better way to learn about [react-mobx-router5](https://github.com/LeonardoGentile/react-mobx-router5) is to view the source code and play around with this example.
-### Notes on importing css styles
-* styles having /src/ in their absolute path are considered part of the application and exported as local css modules.
-* other styles are considered global styles used by many components and are included in the css bundle directly.
+If you have any trouble or doubt please open an issue either here or on [react-mobx-router5](https://github.com/LeonardoGentile/react-mobx-router5) repo.
-### Contribute
-Please contribute to the project if you know how to make it better, including this README :)
-### Personal Setup
-On the personal Setup branch I've added some tools and extra funcitonalities to better suit my needs.
-- [babel-plugin-react-html-attrs](https://github.com/insin/babel-plugin-react-html-attrs) Transforms JSX `class` attributes into `className` and `for` attributes into `htmlFor`, allowing you to copy and paste HTML into your React components without having to manually edit these particular attributes each time.
-- Personal `.editorconfig` setup
-- Re-added `bootstrap` (it was stripped in the original project)
-- [react-router](https://github.com/ReactTraining/react-router) basic setup
diff --git a/package.json b/package.json
index f99dd9e..addb43c 100644
--- a/package.json
+++ b/package.json
@@ -51,7 +51,8 @@
"webpack": "2.3.2",
"webpack-cleanup-plugin": "^0.4.2",
"webpack-dashboard": "^0.3.0",
- "webpack-dev-server": "2.4.2"
+ "webpack-dev-server": "2.4.2",
+ "prop-types": "latest"
},
"scripts": {
"build": "webpack --config webpack.production.config.js --progress --profile --colors",
diff --git a/postcss.config.js b/postcss.config.js
index 0e1dcad..1ee17dd 100644
--- a/postcss.config.js
+++ b/postcss.config.js
@@ -12,8 +12,8 @@ const AUTOPREFIXER_BROWSERS = [
module.exports = {
plugins: [
require('autoprefixer')({ browsers: AUTOPREFIXER_BROWSERS }),
- require('lost')
+ // require('lost')
]
-}
+};
diff --git a/src/app.jsx b/src/app.jsx
index ddc39fa..88b0e99 100644
--- a/src/app.jsx
+++ b/src/app.jsx
@@ -14,17 +14,17 @@ import './styles/base/_commons.sass';
const router = createRouter(true);
-// Provider will add your router instance in context.
-const wrappedApp = (
+// Provider will add your pass the stores instances using context
+const App = (
-
+
);
// Render the entire app when the router starts
router.start((err, state) => {
ReactDOM.render(
- wrappedApp,
+ App,
document.getElementById('app')
);
});
diff --git a/src/components/Index/Index.jsx b/src/components/Index/Index.jsx
index 9bfa480..7e2881f 100644
--- a/src/components/Index/Index.jsx
+++ b/src/components/Index/Index.jsx
@@ -1,4 +1,5 @@
import React from 'react';
+import PropTypes from 'prop-types';
import {observer, inject} from 'mobx-react';
import styles from './Index.sass';
@@ -16,7 +17,7 @@ class Index extends React.Component {
tabStore.setActiveTab(id);
}
- // Triggered when a component will be scheduled to re-render because data it observes has changed.
+ // Triggered when a component will be scheduled to re-render because data it observes has changed (because @observer)
// This makes it easy to trace renders back to the action that caused the rendering.
componentWillReact() {
console.debug("I will re-render, since the todo has changed!");
@@ -55,4 +56,9 @@ class Index extends React.Component {
}
}
+Index.PropTypes = {
+ tabStore: PropTypes.object, // injected
+ route: PropTypes.object // injected by RouteView (non-observable)
+};
+
export default Index;
diff --git a/src/components/Layout/Footer/Footer.jsx b/src/components/Layout/Footer/Footer.jsx
index 70c6209..bb1ee70 100644
--- a/src/components/Layout/Footer/Footer.jsx
+++ b/src/components/Layout/Footer/Footer.jsx
@@ -1,4 +1,5 @@
import React from 'react';
+import PropTypes from 'prop-types';
import {withRoute, Link} from "react-mobx-router5";
import styles from './Footer.sass';
@@ -13,9 +14,22 @@ function AnotherElement(props) {
);
}
+
+AnotherElement.propTypes = {
+ // These are injected by withRoute
+ routerStore: PropTypes.object,
+ route: PropTypes.object,
+ isActive: PropTypes.bool,
+ className: PropTypes.string,
+ // This is passed to the wrapper for computing isActive and className
+ routeName: PropTypes.string,
+};
+
const AnotherComponentWithRoute = withRoute(AnotherElement);
+
+
class Footer extends React.Component {
constructor(props) {
super(props);
@@ -41,7 +55,13 @@ class Footer extends React.Component {
}
}
-
+Footer.propTypes = {
+ // These are injected by withRoute
+ routerStore: PropTypes.object,
+ route: PropTypes.object,
+ isActive: PropTypes.bool,
+ className: PropTypes.string
+};
export default withRoute(Footer);
diff --git a/src/components/Layout/Header/Header.jsx b/src/components/Layout/Header/Header.jsx
index d06d47f..32fd52c 100644
--- a/src/components/Layout/Header/Header.jsx
+++ b/src/components/Layout/Header/Header.jsx
@@ -1,10 +1,10 @@
import React from 'react';
+import PropTypes from 'prop-types';
import {inject} from 'mobx-react';
+import {Link} from "react-mobx-router5";
import NavMenu from './NavMenu/NavMenu';
import * as styles from './Header.sass';
-import {Link} from "react-mobx-router5";
-
@inject('routerStore')
class Header extends React.Component {
@@ -12,29 +12,35 @@ class Header extends React.Component {
render() {
const routerStore = this.props.routerStore;
return (
-
+
);
}
}
+Header.propTypes = {
+ routerStore: PropTypes.object // injected
+};
// will passe the router trough context
export default Header;
diff --git a/src/components/Layout/Header/Header.sass b/src/components/Layout/Header/Header.sass
index e9ce4f3..2fbe719 100644
--- a/src/components/Layout/Header/Header.sass
+++ b/src/components/Layout/Header/Header.sass
@@ -1,14 +1,18 @@
+.header
+ +container
+ +clearfix
+ position: relative
+ height: 100%
-$headerHeight: 126px
+.home-link
+ +simple-nav-link
+ text-decoration: none
-.headerContainer
- position: relative // so we can use absolute inside it
- z-index: $zindex_headerContainer
- height: $headerHeight
- // ****
- background: $red
- border-bottom: 2px solid $red-dark
- border-top: 2px solid $red-dark
+.nav-container
+ position: absolute
+ top: 0
+ right: 0
+ z-index: $zindex_navAccount
.explanation-home
position: absolute
@@ -20,18 +24,3 @@ $headerHeight: 126px
top: 90px
right: 10px
-.header
- +container
- +clearfix
- position: relative
- height: 100%
-
-.navContainer
- position: absolute
- top: 0
- right: 0
- z-index: $zindex_navAccount
-
-.home-link
- +simple-nav-link
- text-decoration: none
diff --git a/src/components/Layout/Header/NavMenu/NavMenu.jsx b/src/components/Layout/Header/NavMenu/NavMenu.jsx
index 077c904..352876c 100644
--- a/src/components/Layout/Header/NavMenu/NavMenu.jsx
+++ b/src/components/Layout/Header/NavMenu/NavMenu.jsx
@@ -1,50 +1,56 @@
import React from "react";
-import { inject, observer } from "mobx-react";
-import { BaseLink, Link, NavLink } from "react-mobx-router5";
+import PropTypes from 'prop-types';
+import {inject, observer} from "mobx-react";
+import {NavLink} from "react-mobx-router5";
import * as styles from "./NavMenu.sass";
import {} from 'react-mobx-router5';
-function LoggedInMenu(props) {
- const links = [
- { routeName: 'index',
- routeParams: {id: 1},
- linkName: 'index'
- },
- { routeName: 'section.home',
- routeParams: {},
- linkName: 'Section/Home'
- },
- { routeName: 'section.subsection.home',
- routeParams: {},
- linkName: 'Section/SubSection/home'
- },
- { routeName: 'section.subsection.login',
- routeParams: {},
- linkName: 'login/logout'
- }
- ];
+const links = [
+ {
+ routeName: 'index',
+ routeParams: {id: 1},
+ linkName: 'index'
+ },
+ {
+ routeName: 'section.home',
+ routeParams: {},
+ linkName: 'Section/Home'
+ },
+ {
+ routeName: 'section.subsection.home',
+ routeParams: {},
+ linkName: 'Section/SubSection/home'
+ },
+ {
+ routeName: 'section.subsection.login',
+ routeParams: {},
+ linkName: 'login/logout'
+ }
+];
- const Navs = links.map((item, index) => {
- return (
-
- {item.linkName}
- );
- });
+const NavLinks = links.map((item, index) => {
+ return (
+
+ {item.linkName}
+ );
+});
+
+
+function LoggedInMenu(props) {
return (
-
- { Navs }
+
);
}
-
function LoggedOutMenu(props) {
return (
-
+
login
@@ -53,28 +59,19 @@ function LoggedOutMenu(props) {
}
-@inject('routerStore', 'userStore')
+@inject('userStore')
@observer
class NavMenu extends React.Component {
- constructor(props) {
- super(props);
- this._showLogin = this._showLogin.bind(this);
- }
-
- _showLogin(e) {
- e.preventDefault();
- e.stopPropagation();
- e.nativeEvent.stopImmediatePropagation();
- console.log("hello");
- }
-
render() {
-
const isLoggedIn = this.props.userStore.isLoggedIn;
return (
isLoggedIn ? : );
}
}
+NavMenu.propTypes = {
+ userStore: PropTypes.object // injected
+};
+
export default NavMenu;
diff --git a/src/components/Layout/Header/NavMenu/NavMenu.sass b/src/components/Layout/Header/NavMenu/NavMenu.sass
index d8caef5..86672d2 100644
--- a/src/components/Layout/Header/NavMenu/NavMenu.sass
+++ b/src/components/Layout/Header/NavMenu/NavMenu.sass
@@ -1,11 +1,11 @@
-.nav
+.nav-menu
+clearfix
+horizontal-list
> li
background: $red-dark2
margin-left: 2px
- //border-left: $red-light2 solid 1px
+
// on the the li, not on the `a`
&:global(.active)
background: $green
diff --git a/src/components/Layout/Layout.jsx b/src/components/Layout/Layout.jsx
index 5552ba1..c6df306 100644
--- a/src/components/Layout/Layout.jsx
+++ b/src/components/Layout/Layout.jsx
@@ -1,10 +1,8 @@
import React from 'react';
import Header from './Header/Header';
-import Main from '../Main/Main';
+import Main from '../../nodecomponents/Main/Main';
import Footer from './Footer/Footer';
-
-
import styles from './Layout.sass';
class Layout extends React.Component {
@@ -19,7 +17,9 @@ class Layout extends React.Component {
-
+
+
+
diff --git a/src/components/Layout/Layout.sass b/src/components/Layout/Layout.sass
index efc6c65..62e058e 100644
--- a/src/components/Layout/Layout.sass
+++ b/src/components/Layout/Layout.sass
@@ -1,4 +1,3 @@
-
.body-loader
display: none
@@ -8,12 +7,20 @@ body
line-height: 20px
width: 100%
+.headerContainer
+ position: relative // so we can use absolute inside it
+ z-index: $zindex_headerContainer
+ height: $headerHeight
+ // ****
+ background: $red
+ border-bottom: 2px solid $red-dark
+ border-top: 2px solid $red-dark
+
.main-container
+container
+clearfix
margin-top: 25px
-
.footer-container
border-top: 1px dashed grey
margin-top: 25px
diff --git a/src/create-router5.js b/src/create-router5.js
index c6c44a2..be610e6 100644
--- a/src/create-router5.js
+++ b/src/create-router5.js
@@ -3,9 +3,8 @@ import loggerPlugin from 'router5/plugins/logger';
import browserPlugin from 'router5/plugins/browser';
import {mobxPlugin} from 'mobx-router5';
-import routerStore from './stores/RouterStore';
import routes from './routes';
-
+import routerStore from './stores/RouterStore';
const routerOptions = {
defaultRoute: 'home',
@@ -15,7 +14,7 @@ const routerOptions = {
// I can import the default module with whatever name I want (ex. `createRouter`)
export default function configureRouter() {
const router = createRouter(routes, routerOptions)
- // Plugins
+ // Plugins
.usePlugin(browserPlugin({useHash: true}))
.usePlugin(mobxPlugin(routerStore))
.usePlugin(loggerPlugin);
diff --git a/src/components/Main/Main.jsx b/src/nodecomponents/Main/Main.jsx
similarity index 60%
rename from src/components/Main/Main.jsx
rename to src/nodecomponents/Main/Main.jsx
index cf64020..9ebbec0 100644
--- a/src/components/Main/Main.jsx
+++ b/src/nodecomponents/Main/Main.jsx
@@ -3,22 +3,21 @@ import PropTypes from 'prop-types';
import {routeNode, RouteView} from "react-mobx-router5";
import routes from "../../routes";
-const routeNodeName = '';
+const routeNodeName = ''; // '' because root node
class Main extends React.Component {
render() {
const {activeRoute} = this.props;
- return ;
+ // This will inject 'route' to the selected child component
+ return ;
}
}
// Both injected by routeNode
Main.propTypes = {
- activeRoute: PropTypes.object.isRequired, // non-observable. plain js obj
- routerStore: PropTypes.object.isRequired
+ activeRoute: PropTypes.object, // non-observable. plain js obj
+ routerStore: PropTypes.object
};
-
-// higher-order component to wrap a route node component.
-// '' if root node
+// HOC to wrap a route node components
export default routeNode(routeNodeName)(Main);
diff --git a/src/components/Sections/Sections.jsx b/src/nodecomponents/Sections/Sections.jsx
similarity index 95%
rename from src/components/Sections/Sections.jsx
rename to src/nodecomponents/Sections/Sections.jsx
index 44c753d..d7ade61 100644
--- a/src/components/Sections/Sections.jsx
+++ b/src/nodecomponents/Sections/Sections.jsx
@@ -8,7 +8,7 @@ const routeNodeName = 'section';
class Sections extends React.Component {
render() {
const {activeRoute} = this.props;
- return ;
+ return ;
}
}
diff --git a/src/components/SubSections/SubSections.jsx b/src/nodecomponents/SubSections/SubSections.jsx
similarity index 95%
rename from src/components/SubSections/SubSections.jsx
rename to src/nodecomponents/SubSections/SubSections.jsx
index 2559400..b9c2c07 100644
--- a/src/components/SubSections/SubSections.jsx
+++ b/src/nodecomponents/SubSections/SubSections.jsx
@@ -8,7 +8,7 @@ const routeNodeName = 'section.subsection';
class SubSections extends React.Component {
render() {
const {activeRoute} = this.props;
- return ;
+ return ;
}
}
diff --git a/src/routes.js b/src/routes.js
index d43a0f1..50ad503 100644
--- a/src/routes.js
+++ b/src/routes.js
@@ -1,8 +1,9 @@
import {Home} from './components/Home';
import {Index} from './components/Index';
import {Login} from './components/Login';
-import Sections from './components/Sections/Sections';
-import SubSections from './components/SubSections/SubSections';
+// Route Nodes
+import Sections from './nodecomponents/Sections/Sections';
+import SubSections from './nodecomponents/SubSections/SubSections';
export default [
diff --git a/src/services/api.js b/src/services/api.js
deleted file mode 100644
index 70b786d..0000000
--- a/src/services/api.js
+++ /dev/null
@@ -1 +0,0 @@
-// TODO
diff --git a/src/stores/RouterStore.js b/src/stores/RouterStore.js
index c42da8d..4bc228d 100644
--- a/src/stores/RouterStore.js
+++ b/src/stores/RouterStore.js
@@ -1,6 +1,6 @@
import {RouterStore} from 'mobx-router5';
-// I instantiate it here because we could add something to the class before invoking new
+// I instantiate it here because I could add something to the class before invoking new
const routerStore = new RouterStore();
export default routerStore;
diff --git a/src/stores/TabStore.js b/src/stores/TabStore.js
index 438d1b2..b5b7ed8 100644
--- a/src/stores/TabStore.js
+++ b/src/stores/TabStore.js
@@ -1,14 +1,9 @@
-import { observable, computed, autorun, action } from 'mobx';
+import {observable, computed, action} from 'mobx';
-// Mobx Observable Store
+// A Mobx Store
class TabStore {
- constructor() {
- // Autorun runs every time the store changes
- // In reality what I want is to run a react .render() whenever something changes
- autorun(() => console.log("Active Tab: " + this.activeTab));
- }
-
+ // Observable properties
@observable activeTab = null;
@observable tabs = [];
@@ -16,33 +11,28 @@ class TabStore {
return this.tabs.length;
}
-
- // ===========
- // = Methods =
- // ===========
+ // Helper methods
_addTab = (id) => {
const found = this.tabs.find(function(item, index, array) {
return item.id === id
});
+
+ // Add element if not already in the array
if (!found) {
this.tabs.push({
id: id,
});
}
- else {
- console.log("Element already in array");
- }
};
+ // Actions
@action setActiveTab = (id) => {
- this.activeTab = id;
this._addTab(id);
+ this.activeTab = id;
};
-
}
-
const tabStore = new TabStore();
export default tabStore;
diff --git a/src/styles/abstracts/_variables.sass b/src/styles/abstracts/_variables.sass
index 001a5d7..83ba5b2 100644
--- a/src/styles/abstracts/_variables.sass
+++ b/src/styles/abstracts/_variables.sass
@@ -1,4 +1,5 @@
$width: 960px
+$headerHeight: 126px
// Colors
$red: #87000D