diff --git a/app/js/Routes.js b/app/js/Routes.js index a5b247e7..a96c4fcf 100644 --- a/app/js/Routes.js +++ b/app/js/Routes.js @@ -15,7 +15,6 @@ export default ( - diff --git a/app/js/actions/user-actions.js b/app/js/actions/user-actions.js new file mode 100644 index 00000000..3d0313ef --- /dev/null +++ b/app/js/actions/user-actions.js @@ -0,0 +1,9 @@ +import Reflux from 'reflux'; + +var UserActions = Reflux.createActions([ + 'checkLoginStatus', + 'login', + 'logout' +]); + +export default UserActions; \ No newline at end of file diff --git a/app/js/pages/home-page.js b/app/js/pages/home-page.js new file mode 100644 index 00000000..7c584535 --- /dev/null +++ b/app/js/pages/home-page.js @@ -0,0 +1,13 @@ +'use strict'; + +import React from 'react/addons'; +import DocumentTitle from 'react-document-title'; + +var HomePage = React.createClass({ + + render() { + return ( + null + ); + } +}); \ No newline at end of file diff --git a/app/js/stores/user-store.js b/app/js/stores/user-store.js new file mode 100644 index 00000000..ad2f0b22 --- /dev/null +++ b/app/js/stores/user-store.js @@ -0,0 +1,21 @@ +import Reflux from 'reflux'; + +import CurrentUserActions from '../actions/CurrentUserActions'; + +var UserStore = Reflux.createStore({ + + init() { + this.user = null; + this.hasBeenChecked = false; + + this.listenTo(CurrentUserActions.checkLoginStatus, this.checkLoginStatus); + this.listenTo(CurrentUserActions.login, this.loginUser); + this.listenTo(CurrentUserActions.logout, this.logoutUser); + }, + + loginUser() { + + } +}); + +export default UserStore; \ No newline at end of file diff --git a/gulp/config.js b/gulp/config.js index 0d963a3c..3aadedd6 100644 --- a/gulp/config.js +++ b/gulp/config.js @@ -5,21 +5,21 @@ module.exports = { 'serverport': 3000, 'scripts': { - 'src': './app/js/**/*.js', + 'src': './src/**/*.js', 'dest': './build/js/' }, 'images': { - 'src': './app/images/**/*.{jpeg,jpg,png}', + 'src': './src/assets/images/**/*.{jpeg,jpg,png}', 'dest': './build/images/' }, 'styles': { - 'src': './app/styles/**/*.scss', + 'src': './src/styles/**/*.scss', 'dest': './build/css/' }, - 'sourceDir': './app/', + 'sourceDir': './src/', 'buildDir': './build/' diff --git a/gulp/index.js b/gulp/index.js index 6039b897..2ae5b73c 100644 --- a/gulp/index.js +++ b/gulp/index.js @@ -4,6 +4,8 @@ var fs = require('fs'); var onlyScripts = require('./util/script-filter'); var tasks = fs.readdirSync('./gulp/tasks/').filter(onlyScripts); +process.env.NODE_PATH = './src'; + tasks.forEach(function(task) { require('./tasks/' + task); }); \ No newline at end of file diff --git a/gulp/tasks/browserify.js b/gulp/tasks/browserify.js index 200299b6..e28b8f93 100644 --- a/gulp/tasks/browserify.js +++ b/gulp/tasks/browserify.js @@ -20,7 +20,7 @@ var config = require('../config'); function buildScript(file, watch) { var bundler = browserify({ - entries: [config.sourceDir + 'js/' + file], + entries: [config.sourceDir + 'app/' + file], debug: !global.isProd, cache: {}, packageCache: {}, diff --git a/src/app/App.js b/src/app/App.js new file mode 100644 index 00000000..e38ee444 --- /dev/null +++ b/src/app/App.js @@ -0,0 +1,18 @@ +import React from 'react/addons'; +import {ListenerMixin} from 'reflux'; +import {RouteHandler} from 'react-router'; + +var App = React.createClass({ + + render() { + return ( +
+ +
+ ); + } + +}); + +export default App; \ No newline at end of file diff --git a/src/app/Routes.js b/src/app/Routes.js new file mode 100644 index 00000000..a7b61597 --- /dev/null +++ b/src/app/Routes.js @@ -0,0 +1,21 @@ +import React from 'react/addons'; +import {Route, NotFoundRoute, DefaultRoute} from 'react-router'; + +import App from 'app/App'; +import DemoPage from 'app/demo/components-demo-page'; + +import MainLayout from 'app/main/main-layout'; +import MainHomePage from 'app/main/main-home-page'; + + +export default ( + + + + + + + + + +); \ No newline at end of file diff --git a/src/app/demo/components-demo-page.js b/src/app/demo/components-demo-page.js new file mode 100644 index 00000000..e89885d5 --- /dev/null +++ b/src/app/demo/components-demo-page.js @@ -0,0 +1,61 @@ +'use strict'; + +import React from 'react/addons'; +import {Link} from 'react-router'; +import DocumentTitle from 'react-document-title'; + +import Button from 'core-components/button.js'; +import Widget from 'core-components/widget.js'; + +var DemoPage = React.createClass({ + + propTypes: { + currentUser: React.PropTypes.object.isRequired + }, + + elements: [ + { + title: 'Primary Button', + render: ( + + ) + }, + { + title: 'Widget', + render: ( + +

Register here!

+ + +
+ ) + } + ], + + render() { + return ( + +
+ {this.renderElements()} +
+
+ ); + }, + + renderElements: function () { + return this.elements.map((element) => { + return ( +
+

+ {element.title} +

+
+ {element.render} +
+
+ ); + }); + } +}); + +export default DemoPage; \ No newline at end of file diff --git a/src/app/index.js b/src/app/index.js new file mode 100644 index 00000000..647b0627 --- /dev/null +++ b/src/app/index.js @@ -0,0 +1,13 @@ +import React from 'react/addons'; +import Router from 'react-router'; + +import routes from './Routes'; + +if ( process.env.NODE_ENV !== 'production' ) { + // Enable React devtools + window.React = React; +} + +Router.run(routes, Router.HistoryLocation, (Handler, state) => { + React.render(, document.getElementById('app')); +}); \ No newline at end of file diff --git a/src/app/main/main-home-page.js b/src/app/main/main-home-page.js new file mode 100644 index 00000000..9676605d --- /dev/null +++ b/src/app/main/main-home-page.js @@ -0,0 +1,16 @@ +import React from 'react/addons'; +import {ListenerMixin} from 'reflux'; +import {RouteHandler} from 'react-router'; + +var MainHomePage = React.createClass({ + + render() { + return ( +
+ this is the Home page +
+ ); + } +}); + +export default MainHomePage; \ No newline at end of file diff --git a/src/app/main/main-layout.js b/src/app/main/main-layout.js new file mode 100644 index 00000000..b9cef731 --- /dev/null +++ b/src/app/main/main-layout.js @@ -0,0 +1,23 @@ +import React from 'react/addons'; +import {ListenerMixin} from 'reflux'; +import {RouteHandler} from 'react-router'; + +var MainLayout = React.createClass({ + + render() { + return ( +
+ + MainHeader + + + + MainFooter + +
+ ); + } +}); + +export default MainLayout; \ No newline at end of file diff --git a/src/assets/fonts/.gitkeep b/src/assets/fonts/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/src/assets/images/.gitkeep b/src/assets/images/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/src/core-components/__tests__/button-test.js b/src/core-components/__tests__/button-test.js new file mode 100644 index 00000000..089ac4e8 --- /dev/null +++ b/src/core-components/__tests__/button-test.js @@ -0,0 +1,36 @@ +/** + * Created by ivan on 16/08/15. + */ +jest.dontMock('../button.js'); + +import React from 'react/addons'; +import Button from '../button.js'; + +var TestUtils = React.addons.TestUtils; + +describe('Button', () => { + it('should render children', () => { + var button = TestUtils.renderIntoDocument( + + ); + + expect(button.getDOMNode().textContent).toEqual('testcontent'); + }); + + it('should add passed types to class', () => { + var types = [ + 'primary' + ]; + + types.forEach((type) => { + var button = TestUtils.renderIntoDocument( + + ); + expect(button.getDOMNode().getAttribute('class')).toContain('button-' + type); + }); + }); +}); \ No newline at end of file diff --git a/src/core-components/button.js b/src/core-components/button.js new file mode 100644 index 00000000..75a5999f --- /dev/null +++ b/src/core-components/button.js @@ -0,0 +1,44 @@ +/** + * Created by ivan on 16/08/15. + */ +'use strict'; + +import React from 'react/addons'; +import classNames from 'classnames'; + +var Button = React.createClass({ + + propTypes: { + children: React.PropTypes.node, + type: React.PropTypes.oneOf([ + 'primary' + ]) + }, + + getDefaultProps() { + return { + type: 'primary' + }; + }, + + render() { + return ( + + ); + }, + + getClass() { + var classes = { + 'button': true + }; + + classes['button-' + this.props.type] = (this.props.type); + classes[this.props.className] = (this.props.className); + + return classNames(classes); + } +}); + +export default Button; \ No newline at end of file diff --git a/src/core-components/widget.js b/src/core-components/widget.js new file mode 100644 index 00000000..098bccf7 --- /dev/null +++ b/src/core-components/widget.js @@ -0,0 +1,28 @@ +import React from 'react/addons'; +import classNames from 'classnames'; + +var Widget = React.createClass({ + propTypes: { + children: React.PropTypes.node.isRequired + }, + + render() { + return ( +
+ {this.props.children} +
+ ); + }, + + getClass() { + var classes = { + 'widget': true + }; + + classes[this.props.className] = (this.props.className); + + return classNames(classes); + } +}); + +export default Widget; \ No newline at end of file diff --git a/src/index.html b/src/index.html new file mode 100644 index 00000000..6aff3455 --- /dev/null +++ b/src/index.html @@ -0,0 +1,20 @@ + + + + + + + + + App Name + + + + + +
+ + + + + \ No newline at end of file diff --git a/src/styles/_base.scss b/src/styles/_base.scss new file mode 100644 index 00000000..90c998e1 --- /dev/null +++ b/src/styles/_base.scss @@ -0,0 +1,10 @@ +* { + box-sizing: border-box; +} + +body { + font-family: Helvetica, sans-serif; + color: $font-color--dark; + background-color: $background--light; + padding: $half-space; +} \ No newline at end of file diff --git a/src/styles/_reset.scss b/src/styles/_reset.scss new file mode 100644 index 00000000..81c6f31e --- /dev/null +++ b/src/styles/_reset.scss @@ -0,0 +1,427 @@ +/*! normalize.css v3.0.2 | MIT License | git.io/normalize */ + +/** + * 1. Set default font family to sans-serif. + * 2. Prevent iOS text size adjust after orientation change, without disabling + * user zoom. + */ + +html { + font-family: sans-serif; /* 1 */ + -ms-text-size-adjust: 100%; /* 2 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +/** + * Remove default margin. + */ + +body { + margin: 0; +} + +/* HTML5 display definitions + ========================================================================== */ + +/** + * Correct `block` display not defined for any HTML5 element in IE 8/9. + * Correct `block` display not defined for `details` or `summary` in IE 10/11 + * and Firefox. + * Correct `block` display not defined for `main` in IE 11. + */ + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +menu, +nav, +section, +summary { + display: block; +} + +/** + * 1. Correct `inline-block` display not defined in IE 8/9. + * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. + */ + +audio, +canvas, +progress, +video { + display: inline-block; /* 1 */ + vertical-align: baseline; /* 2 */ +} + +/** + * Prevent modern browsers from displaying `audio` without controls. + * Remove excess height in iOS 5 devices. + */ + +audio:not([controls]) { + display: none; + height: 0; +} + +/** + * Address `[hidden]` styling not present in IE 8/9/10. + * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. + */ + +[hidden], +template { + display: none; +} + +/* Links + ========================================================================== */ + +/** + * Remove the gray background color from active links in IE 10. + */ + +a { + background-color: transparent; +} + +/** + * Improve readability when focused and also mouse hovered in all browsers. + */ + +a:active, +a:hover { + outline: 0; +} + +/* Text-level semantics + ========================================================================== */ + +/** + * Address styling not present in IE 8/9/10/11, Safari, and Chrome. + */ + +abbr[title] { + border-bottom: 1px dotted; +} + +/** + * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. + */ + +b, +strong { + font-weight: bold; +} + +/** + * Address styling not present in Safari and Chrome. + */ + +dfn { + font-style: italic; +} + +/** + * Address variable `h1` font-size and margin within `section` and `article` + * contexts in Firefox 4+, Safari, and Chrome. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/** + * Address styling not present in IE 8/9. + */ + +mark { + background: #ff0; + color: #000; +} + +/** + * Address inconsistent and variable font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` affecting `line-height` in all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Remove border when inside `a` element in IE 8/9/10. + */ + +img { + border: 0; +} + +/** + * Correct overflow not hidden in IE 9/10/11. + */ + +svg:not(:root) { + overflow: hidden; +} + +/* Grouping content + ========================================================================== */ + +/** + * Address margin not present in IE 8/9 and Safari. + */ + +figure { + margin: 1em 40px; +} + +/** + * Address differences between Firefox and other browsers. + */ + +hr { + -moz-box-sizing: content-box; + box-sizing: content-box; + height: 0; +} + +/** + * Contain overflow in all browsers. + */ + +pre { + overflow: auto; +} + +/** + * Address odd `em`-unit font size rendering in all browsers. + */ + +code, +kbd, +pre, +samp { + font-family: monospace, monospace; + font-size: 1em; +} + +/* Forms + ========================================================================== */ + +/** + * Known limitation: by default, Chrome and Safari on OS X allow very limited + * styling of `select`, unless a `border` property is set. + */ + +/** + * 1. Correct color not being inherited. + * Known issue: affects color of disabled elements. + * 2. Correct font properties not being inherited. + * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. + */ + +button, +input, +optgroup, +select, +textarea { + color: inherit; /* 1 */ + font: inherit; /* 2 */ + margin: 0; /* 3 */ +} + +/** + * Address `overflow` set to `hidden` in IE 8/9/10/11. + */ + +button { + overflow: visible; +} + +/** + * Address inconsistent `text-transform` inheritance for `button` and `select`. + * All other form control elements do not inherit `text-transform` values. + * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. + * Correct `select` style inheritance in Firefox. + */ + +button, +select { + text-transform: none; +} + +/** + * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` + * and `video` controls. + * 2. Correct inability to style clickable `input` types in iOS. + * 3. Improve usability and consistency of cursor style between image-type + * `input` and others. + */ + +button, +html input[type="button"], /* 1 */ +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; /* 2 */ + cursor: pointer; /* 3 */ +} + +/** + * Re-set default cursor for disabled elements. + */ + +button[disabled], +html input[disabled] { + cursor: default; +} + +/** + * Remove inner padding and border in Firefox 4+. + */ + +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} + +/** + * Address Firefox 4+ setting `line-height` on `input` using `!important` in + * the UA stylesheet. + */ + +input { + line-height: normal; +} + +/** + * It's recommended that you don't attempt to style these elements. + * Firefox's implementation doesn't respect box-sizing, padding, or width. + * + * 1. Address box sizing set to `content-box` in IE 8/9/10. + * 2. Remove excess padding in IE 8/9/10. + */ + +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Fix the cursor style for Chrome's increment/decrement buttons. For certain + * `font-size` values of the `input`, it causes the cursor style of the + * decrement button to change from `default` to `text`. + */ + +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Address `appearance` set to `searchfield` in Safari and Chrome. + * 2. Address `box-sizing` set to `border-box` in Safari and Chrome + * (include `-moz` to future-proof). + */ + +input[type="search"] { + -webkit-appearance: textfield; /* 1 */ + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; /* 2 */ + box-sizing: content-box; +} + +/** + * Remove inner padding and search cancel button in Safari and Chrome on OS X. + * Safari (but not Chrome) clips the cancel button when the search input has + * padding (and `textfield` appearance). + */ + +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * Define consistent border, margin, and padding. + */ + +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} + +/** + * 1. Correct `color` not being inherited in IE 8/9/10/11. + * 2. Remove padding so people aren't caught out if they zero out fieldsets. + */ + +legend { + border: 0; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Remove default vertical scrollbar in IE 8/9/10/11. + */ + +textarea { + overflow: auto; +} + +/** + * Don't inherit the `font-weight` (applied by a rule above). + * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. + */ + +optgroup { + font-weight: bold; +} + +/* Tables + ========================================================================== */ + +/** + * Remove most spacing between table cells. + */ + +table { + border-collapse: collapse; + border-spacing: 0; +} + +td, +th { + padding: 0; +} \ No newline at end of file diff --git a/src/styles/_typography.scss b/src/styles/_typography.scss new file mode 100644 index 00000000..8cc7a168 --- /dev/null +++ b/src/styles/_typography.scss @@ -0,0 +1,42 @@ +p { + margin-bottom: 1em; +} + +.heading { + margin-bottom: 0.618em; + + &.-large { + font-size: $font-size--lg; + font-weight: bold; + line-height: $half-space * 3 / 2; + } + + &.-medium { + font-size: $font-size--md; + font-weight: normal; + line-height: $half-space; + } + + &.-small { + font-size: $font-size--sm; + font-weight: bold; + line-height: $half-space * 2 / 3; + } + + &.-smallest { + font-size: $font-size--xs; + font-weight: bold; + } +} + +h1 { + @extend .heading.-large; +} + +h2 { + @extend .heading.-medium; +} + +h3 { + @extend .heading.-small; +} \ No newline at end of file diff --git a/src/styles/_vars.scss b/src/styles/_vars.scss new file mode 100644 index 00000000..937b25bb --- /dev/null +++ b/src/styles/_vars.scss @@ -0,0 +1,21 @@ +// colors +$font-color--dark: #333; +$font-color--light: #fff; +$background--light: #eee; +$background--dark: #222; +$blue: #1f8de2; +$green: #1fe27b; +$red: #e21f3f; + +$primary-red: #DD5555; + +// spacing +$full-space: 40px; +$half-space: 20px; + +// font sizing +$font-size--xs: 10px; +$font-size--sm: 12px; +$font-size--md: 16px; +$font-size--lg: 24px; +$font-size--xl: 32px; \ No newline at end of file diff --git a/src/styles/app-components/_footer.scss b/src/styles/app-components/_footer.scss new file mode 100644 index 00000000..772c1f15 --- /dev/null +++ b/src/styles/app-components/_footer.scss @@ -0,0 +1,4 @@ +footer { + height: 50px; + background: #eeeeee; +} \ No newline at end of file diff --git a/src/styles/app-components/_header.scss b/src/styles/app-components/_header.scss new file mode 100644 index 00000000..f81d4a19 --- /dev/null +++ b/src/styles/app-components/_header.scss @@ -0,0 +1,4 @@ +header { + height: 50px; + background: #eeeeee; +} \ No newline at end of file diff --git a/src/styles/core-components/_button.scss b/src/styles/core-components/_button.scss new file mode 100644 index 00000000..6fede974 --- /dev/null +++ b/src/styles/core-components/_button.scss @@ -0,0 +1,16 @@ +.button { + + &:focus { + outline: none; + } + + &-primary { + background-color: $primary-red; + border: solid transparent; + border-radius: 4px; + color: white; + height: 47px; + text-transform: uppercase; + width: 239px; + } +} \ No newline at end of file diff --git a/src/styles/core-components/_widget.scss b/src/styles/core-components/_widget.scss new file mode 100644 index 00000000..7ec67f4d --- /dev/null +++ b/src/styles/core-components/_widget.scss @@ -0,0 +1,7 @@ +.widget { + background-color: white; + border-radius: 4px; + text-align: center; + padding: 27px; + width: 324px; +} \ No newline at end of file diff --git a/src/styles/main.scss b/src/styles/main.scss new file mode 100644 index 00000000..d288a93d --- /dev/null +++ b/src/styles/main.scss @@ -0,0 +1,9 @@ +@import 'reset'; +@import 'vars'; +@import 'typography'; +@import 'base'; + +@import 'app-components/header'; +@import 'app-components/footer'; +@import 'core-components/button'; +@import 'core-components/widget'; \ No newline at end of file