diff --git a/README.md b/README.md index 28d2c5a26..2c60d5a07 100644 --- a/README.md +++ b/README.md @@ -24,16 +24,18 @@ ├── /docs/ # Documentation files ├── /node_modules/ # Node.js-based dev tools and utilities ├── /src/ # The source code of the application +│ ├── /actions/ # Action methods that allow to trigger a dispatch to stores │ ├── /assets/ # Static files which don't require pre-processing -│ ├── /data/ # Data access layer and models -│ ├── /common/ # Utility classes etc. +│ ├── /constants/ # Enumerations used in action methods and stores │ ├── /components/ # React components. E.g. Navbar.jsx │ ├── /images/ # Graphics (.png, .jpg, .svg etc.) │ ├── /layouts/ # Layouts for web pages │ ├── /pages/ # Web pages. E.g. Profile.jsx (or .html, .jade etc.) │ ├── /services/ # Services and business logic +│ ├── /stores/ # Stores contain the application state and logic │ ├── /styles/ # LESS style sheets (or SASS/SCSS, Stylus etc.) -│ └── /app.jsx # Entry point of your web application +│ ├── /App.jsx # Entry point of your web application +│ └── /AppDispatcher.js # The central hub that manages all data flow ├── /test/ # Unit, integration and load tests │ ├── /e2e/ # End-to-end tests │ └── /unit/ # Unit tests diff --git a/config/webpack.js b/config/webpack.js index a1a84f3e9..0190aa292 100644 --- a/config/webpack.js +++ b/config/webpack.js @@ -73,7 +73,7 @@ module.exports = function (release) { loader: 'url-loader?limit=10000&mimetype=image/png' }, { - test: /\.jsx$/, + test: /\.(js|jsx)$/, loader: 'jsx-loader?harmony' } ] diff --git a/gulpfile.js b/gulpfile.js index da540e194..70a40965c 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -77,10 +77,10 @@ gulp.task('images', function () { src.images = 'src/images/**'; return gulp.src(src.images) .pipe($.changed(DEST + '/images')) - .pipe($.cache($.imagemin({ + .pipe($.imagemin({ progressive: true, interlaced: true - }))) + })) .pipe(gulp.dest(DEST + '/images')) .pipe($.size({title: 'images'})); }); diff --git a/package.json b/package.json index 933720927..1c7619e74 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,9 @@ "license": "MIT", "dependencies": { "bootstrap": "^3.2.0", - "react": "^0.11.2", - "react-router": "^0.7.0" + "director": "^1.2.3", + "flux": "^2.0.1", + "react": "^0.11.2" }, "devDependencies": { "browser-sync": "^1.5.1", diff --git a/src/App.jsx b/src/App.jsx index caeed4c83..12eb035e8 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,21 +1,33 @@ -/** - * @jsx React.DOM - */ - 'use strict'; var React = require('react'); -var {Routes, Route} = require('react-router'); +var {Router} = require('director'); +var AppDispatcher = require('./AppDispatcher'); +var ActionTypes = require('./constants/ActionTypes'); // Export React so the dev tools can find it (window !== window.top ? window.top : window).React = React; -React.renderComponent( - - - - - - , - document.body -); +function render(component) { + React.renderComponent(component(), document.body); +} + +var routes = { + '/': () => render(require('./pages/Home.jsx')), + '/privacy': () => render(require('./pages/Privacy.jsx')) +}; + +var router = new Router(routes).configure({html5history: true}).init(); + +AppDispatcher.register(function(payload) { + + var action = payload.action; + + switch (action.actionType) { + case ActionTypes.SET_CURRENT_ROUTE: + router.setRoute(action.route); + break; + } + + return true; // No errors. Needed by promise in Dispatcher. +}); diff --git a/src/AppDispatcher.js b/src/AppDispatcher.js new file mode 100644 index 000000000..afd07794b --- /dev/null +++ b/src/AppDispatcher.js @@ -0,0 +1,39 @@ +/* + * A singleton that operates as the central hub for application updates. + */ + +'use strict'; + +var {Dispatcher} = require('flux'); +var PayloadSources = require('./constants/PayloadSources'); +var copyProperties = require('react/lib/copyProperties'); + +var AppDispatcher = copyProperties(new Dispatcher(), { + + /** + * @param {object} action The details of the action, including the action's + * type and additional data coming from the server. + */ + handleServerAction: function(action) { + var payload = { + source: PayloadSources.SERVER_ACTION, + action: action + }; + this.dispatch(payload); + }, + + /** + * @param {object} action The details of the action, including the action's + * type and additional data coming from the view. + */ + handleViewAction: function(action) { + var payload = { + source: PayloadSources.VIEW_ACTION, + action: action + }; + this.dispatch(payload); + } + +}); + +module.exports = AppDispatcher; diff --git a/src/actions/RouteActions.js b/src/actions/RouteActions.js new file mode 100644 index 000000000..1c63b55e8 --- /dev/null +++ b/src/actions/RouteActions.js @@ -0,0 +1,21 @@ +'use strict'; + +var AppDispatcher = require('../AppDispatcher'); +var ActionTypes = require('../constants/ActionTypes'); + +var AppActions = { + + /** + * Set the current route. + * @param {string} route Supply a route value, such as `todos/completed`. + */ + setRoute: function(route) { + AppDispatcher.handleViewAction({ + actionType: ActionTypes.SET_CURRENT_ROUTE, + route: route + }); + } + +}; + +module.exports = AppActions; diff --git a/src/components/Link.jsx b/src/components/Link.jsx new file mode 100644 index 000000000..d32c7faf6 --- /dev/null +++ b/src/components/Link.jsx @@ -0,0 +1,30 @@ +/** + * @jsx React.DOM + */ + +'use strict'; + +var React = require('react'); +var RouteActions = require('../actions/RouteActions'); + +var Link = React.createClass({ + propTypes: { + to: React.PropTypes.string.isRequired, + children: React.PropTypes.component.isRequired + }, + render() { + this.props.href = + this.props.to && this.props.to.lastIndexOf('/', 0) === 0 ? + this.props.to : '/' + this.props.to; + + return this.transferPropsTo( + {this.props.children} + ); + }, + handleClick(e) { + e.preventDefault(); + RouteActions.setRoute(this.props.to); + } +}); + +module.exports = Link; diff --git a/src/components/Navbar.jsx b/src/components/Navbar.jsx index bdfbf832c..476c6e2e5 100644 --- a/src/components/Navbar.jsx +++ b/src/components/Navbar.jsx @@ -5,14 +5,14 @@ 'use strict'; var React = require('react'); -var {Link} = require('react-router'); +var Link = require('./Link.jsx'); var Navbar = React.createClass({ render() { return (
- + React {' Facebook React Starter Kit'} diff --git a/src/components/NavbarSpec.jsx b/src/components/NavbarSpec.jsx index d23be36cc..d98a27dfe 100644 --- a/src/components/NavbarSpec.jsx +++ b/src/components/NavbarSpec.jsx @@ -5,7 +5,7 @@ describe('Navbar', () => { beforeEach(() => { Navbar = require('./Navbar.jsx'); - component = new Navbar(); + component = Navbar(); }); it('should create a new instance of Navbar', () => { diff --git a/src/constants/ActionTypes.js b/src/constants/ActionTypes.js new file mode 100644 index 000000000..a9ab79a5a --- /dev/null +++ b/src/constants/ActionTypes.js @@ -0,0 +1,6 @@ +module.exports = { + + // Route action types + SET_CURRENT_ROUTE: 'SET_CURRENT_ROUTE' + +}; diff --git a/src/constants/PayloadSources.js b/src/constants/PayloadSources.js new file mode 100644 index 000000000..03232773a --- /dev/null +++ b/src/constants/PayloadSources.js @@ -0,0 +1,4 @@ +module.exports = { + VIEW_ACTION: 'VIEW_ACTION', + SERVER_ACTION: 'SERVER_ACTION' +}; diff --git a/src/layouts/Default.jsx b/src/layouts/Default.jsx index 2d073a17d..aba730164 100644 --- a/src/layouts/Default.jsx +++ b/src/layouts/Default.jsx @@ -5,7 +5,7 @@ 'use strict'; var React = require('react'); -var {Link} = require('react-router'); +var Link = require('../components/Link.jsx'); var Navbar = require('../components/Navbar.jsx'); var DefaultLayout = React.createClass({ @@ -19,13 +19,13 @@ var DefaultLayout = React.createClass({

Complex web apps made easy

- + {this.props.children}

{' © KriaSoft • '} - Home {' • '} - Privacy + Home{' • '} + Privacy

diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx index c989f9dec..6d8bbe609 100644 --- a/src/pages/Home.jsx +++ b/src/pages/Home.jsx @@ -5,40 +5,43 @@ 'use strict'; var React = require('react'); +var Layout = require('../layouts/Default.jsx'); var HomePage = React.createClass({ render() { return ( -
-
-
-

Runtime Components

-
-
React
-
A JavaScript library for building user interfaces, developed by Facebook
-
React-Router
-
A complete routing library for React
-
Bootstrap
-
CSS framework for developing responsive, mobile first interfaces
-
-
-
-

Development Tools

-
-
Gulp
-
JavaScript streaming build system and task automation
-
Webpack
-
Compiles front-end source code into modules / bundles
-
BrowserSync
-
A lightweight HTTP server for development
-
-
-
-

Fork me on GitHub

-

github.com/kriasoft/react-starter-kit

+ +
+
+
+

Runtime Components

+
+
React
+
A JavaScript library for building user interfaces, developed by Facebook
+
React-Router
+
A complete routing library for React
+
Bootstrap
+
CSS framework for developing responsive, mobile first interfaces
+
+
+
+

Development Tools

+
+
Gulp
+
JavaScript streaming build system and task automation
+
Webpack
+
Compiles front-end source code into modules / bundles
+
BrowserSync
+
A lightweight HTTP server for development
+
+
+
+

Fork me on GitHub

+

github.com/kriasoft/react-starter-kit

+
-
+ ); } }); diff --git a/src/pages/Privacy.jsx b/src/pages/Privacy.jsx index 743b4e51b..f28c4d0c2 100644 --- a/src/pages/Privacy.jsx +++ b/src/pages/Privacy.jsx @@ -5,53 +5,56 @@ 'use strict'; var React = require('react'); +var Layout = require('../layouts/Default.jsx'); var PrivacyPage = React.createClass({ render() { return ( -
-

Privacy Policy

-

- Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean consequat tortor fermentum mi - fermentum dignissim. Nullam vel ipsum ut ligula elementum lobortis. Maecenas aliquam, massa laoreet - lacinia pretium, nisi urna venenatis tortor, nec imperdiet tellus libero efficitur metus. Fusce - semper posuere ligula, et facilisis metus bibendum interdum. Mauris at mauris sit amet sem pharetra - commodo a eu leo. Nam at est non risus cursus maximus. Nam feugiat augue libero, id consectetur - tortor bibendum non. Quisque nec fringilla lorem. Nullam efficitur vulputate mauris, nec maximus leo - dignissim id. -

-

- In hac habitasse platea dictumst. Duis sagittis dui ac ex suscipit maximus. Morbi pellentesque - venenatis felis sed convallis. Nulla varius, nibh vitae placerat tempus, mauris sem elementum ipsum, - eget sollicitudin nisl est vel purus. Fusce malesuada odio velit, non cursus leo fermentum id. Cras - pharetra sodales fringilla. Etiam quis est a dolor egestas pellentesque. Maecenas non scelerisque - purus, congue cursus arcu. Donec vel dapibus mi. Mauris maximus posuere placerat. Sed et libero eu - nibh tristique mollis a eget lectus. Donec interdum augue sollicitudin vehicula hendrerit. Vivamus - justo orci, molestie ac sollicitudin ac, lobortis at tellus. Etiam rhoncus ullamcorper risus eu - tempor. Sed porttitor, neque ac efficitur gravida, arcu lacus pharetra dui, in consequat elit tellus - auctor nulla. Donec placerat elementum diam, vitae imperdiet lectus luctus at. -

-

- Nullam eu feugiat mi. Quisque nec tristique nisl, dignissim dictum leo. Nam non quam nisi. Donec - rutrum turpis ac diam blandit, id pulvinar mauris suscipit. Pellentesque tincidunt libero ultricies - risus iaculis, sit amet consequat velit blandit. Fusce quis varius nulla. Nullam nisi nisi, suscipit - ut magna quis, feugiat porta nibh. Sed id enim lectus. Suspendisse elementum justo sapien, sit amet - consequat orci accumsan et. Aliquam ornare ullamcorper sem sed finibus. Nullam ac lacus pulvinar, - egestas felis ut, accumsan est. -

-

- Pellentesque sagittis vehicula sem quis luctus. Proin sodales magna in lorem hendrerit aliquam. - Integer eu varius orci. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere - cubilia Curae; Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia - Curae; Ut at mauris nibh. Suspendisse maximus ac eros at vestibulum. -

-

- Interdum et malesuada fames ac ante ipsum primis in faucibus. Quisque egestas tortor et dui - consequat faucibus. Nunc vitae odio ornare, venenatis ligula a, vulputate nisl. Aenean congue varius - ex, sit amet bibendum odio posuere at. Nulla facilisi. In finibus, nulla vitae tincidunt ornare, - sapien nulla fermentum mauris, sed consectetur tortor arcu eget arcu. Vestibulum vel quam enim. -

-
+ +
+

Privacy Policy

+

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean consequat tortor fermentum mi + fermentum dignissim. Nullam vel ipsum ut ligula elementum lobortis. Maecenas aliquam, massa laoreet + lacinia pretium, nisi urna venenatis tortor, nec imperdiet tellus libero efficitur metus. Fusce + semper posuere ligula, et facilisis metus bibendum interdum. Mauris at mauris sit amet sem pharetra + commodo a eu leo. Nam at est non risus cursus maximus. Nam feugiat augue libero, id consectetur + tortor bibendum non. Quisque nec fringilla lorem. Nullam efficitur vulputate mauris, nec maximus leo + dignissim id. +

+

+ In hac habitasse platea dictumst. Duis sagittis dui ac ex suscipit maximus. Morbi pellentesque + venenatis felis sed convallis. Nulla varius, nibh vitae placerat tempus, mauris sem elementum ipsum, + eget sollicitudin nisl est vel purus. Fusce malesuada odio velit, non cursus leo fermentum id. Cras + pharetra sodales fringilla. Etiam quis est a dolor egestas pellentesque. Maecenas non scelerisque + purus, congue cursus arcu. Donec vel dapibus mi. Mauris maximus posuere placerat. Sed et libero eu + nibh tristique mollis a eget lectus. Donec interdum augue sollicitudin vehicula hendrerit. Vivamus + justo orci, molestie ac sollicitudin ac, lobortis at tellus. Etiam rhoncus ullamcorper risus eu + tempor. Sed porttitor, neque ac efficitur gravida, arcu lacus pharetra dui, in consequat elit tellus + auctor nulla. Donec placerat elementum diam, vitae imperdiet lectus luctus at. +

+

+ Nullam eu feugiat mi. Quisque nec tristique nisl, dignissim dictum leo. Nam non quam nisi. Donec + rutrum turpis ac diam blandit, id pulvinar mauris suscipit. Pellentesque tincidunt libero ultricies + risus iaculis, sit amet consequat velit blandit. Fusce quis varius nulla. Nullam nisi nisi, suscipit + ut magna quis, feugiat porta nibh. Sed id enim lectus. Suspendisse elementum justo sapien, sit amet + consequat orci accumsan et. Aliquam ornare ullamcorper sem sed finibus. Nullam ac lacus pulvinar, + egestas felis ut, accumsan est. +

+

+ Pellentesque sagittis vehicula sem quis luctus. Proin sodales magna in lorem hendrerit aliquam. + Integer eu varius orci. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere + cubilia Curae; Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia + Curae; Ut at mauris nibh. Suspendisse maximus ac eros at vestibulum. +

+

+ Interdum et malesuada fames ac ante ipsum primis in faucibus. Quisque egestas tortor et dui + consequat faucibus. Nunc vitae odio ornare, venenatis ligula a, vulputate nisl. Aenean congue varius + ex, sit amet bibendum odio posuere at. Nulla facilisi. In finibus, nulla vitae tincidunt ornare, + sapien nulla fermentum mauris, sed consectetur tortor arcu eget arcu. Vestibulum vel quam enim. +

+
+
); } });