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 ( -
-
- Home -
- -
-
-

^ This is a Link Component => It will apply automatically an active class on the `a` element

-
-
-

These are NavLink Components => The `active` class will be applied to the 'li' wrappers ^

-
-
- -
-
+
+ + Home + +
+ +
+ +
+

^ This is a Link Component => It will apply automatically an active class on the `a` element

+
+ +
+

These are NavLink Components => The `active` class will be applied to the 'li' wrappers ^

+
+ +
+ +
); } } +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 ( -