commit c92ea26d9ff9f377335aad5c9acad320dda32a51 parent af4afbd6e0e62c117f6a735b25832767f1dcc153 Author: Konstantin Tarkus <hello@tarkus.me> Date: Mon, 4 May 2015 00:29:40 +0300 Remove Bootstrap; refactor server-side rendering & data API Diffstat:
64 files changed, 905 insertions(+), 649 deletions(-)
diff --git a/README.md b/README.md @@ -12,7 +12,7 @@ > it to quickly bootstrap your web application projects. All the parts of this > project template are easily replaceable. -**Demo**: http://reactjs.kriasoft.com +**Demo**: http://demo.reactstarterkit.com ### Documentation @@ -26,26 +26,26 @@ ├── /docs/ # Documentation files for the project ├── /node_modules/ # 3rd-party libraries and utilities ├── /src/ # The source code of the application +│ ├── /api/ # REST API / Relay endpoints │ ├── /actions/ # Action creators that allow to trigger a dispatch to stores │ ├── /assets/ # Static files which are copied to ./build on compile │ ├── /components/ # React components -│ ├── /constants/ # Enumerations used in action creators and stores -│ ├── /content/ # Website content (plain HTML or Markdown, Jade, you name it) +│ ├── /content/ # Static content (plain HTML or Markdown, Jade, you name it) │ ├── /core/ # Core components (Flux dispatcher, base classes, utilities) │ ├── /stores/ # Stores contain the application state and logic -│ ├── /styles/ # CSS styles (deprecated, put CSS into components' folders) │ ├── /templates/ # HTML templates for server-side rendering, emails etc. │ ├── /app.js # Client-side startup script │ └── /server.js # Server-side startup script │── gulpfile.js # Configuration file for automated builds │── package.json # The list of 3rd party libraries and utilities -│── preprocessor.js # ES6 transpiler settings for Jest +│── preprocessor.js # ES6 transpiler settings for Jest └── webpack.config.js # Webpack configuration for bundling and optimization ``` ### Getting Started -Just [clone](github-windows://openRepo/https://github.com/kriasoft/react-starter-kit) or [fork](https://github.com/kriasoft/react-starter-kit/fork) the repo and start hacking: +Just [clone](github-windows://openRepo/https://github.com/kriasoft/react-starter-kit) or +[fork](https://github.com/kriasoft/react-starter-kit/fork) the repo and start hacking: ```shell $ git clone -o react-starter-kit https://github.com/kriasoft/react-starter-kit.git MyApp diff --git a/gulpfile.js b/gulpfile.js @@ -1,6 +1,6 @@ /* * React.js Starter Kit - * Copyright (c) 2014 Konstantin Tarkus (@koistya), KriaSoft LLC. + * Copyright (c) Konstantin Tarkus (@koistya), KriaSoft LLC * * This source code is licensed under the MIT license found in the * LICENSE.txt file in the root directory of this source tree. @@ -18,20 +18,6 @@ var runSequence = require('run-sequence'); var webpack = require('webpack'); var argv = require('minimist')(process.argv.slice(2)); -// Settings -var RELEASE = !!argv.release; // Minimize and optimize during a build? -var AUTOPREFIXER_BROWSERS = [ // https://github.com/ai/autoprefixer - 'ie >= 10', - 'ie_mob >= 10', - 'ff >= 30', - 'chrome >= 34', - 'safari >= 7', - 'opera >= 23', - 'ios >= 7', - 'android >= 4.4', - 'bb >= 10' -]; - var src = {}; var watch = false; var browserSync; @@ -64,23 +50,6 @@ gulp.task('assets', function() { .pipe($.size({title: 'assets'})); }); -// CSS style sheets -gulp.task('styles', function() { - src.styles = 'src/styles/**/*.{css,less}'; - return gulp.src('src/styles/bootstrap.less') - .pipe($.plumber()) - .pipe($.less({ - sourceMap: !RELEASE, - sourceMapBasepath: __dirname - })) - .on('error', console.error.bind(console)) - .pipe($.autoprefixer({browsers: AUTOPREFIXER_BROWSERS})) - .pipe($.csscomb()) - .pipe($.if(RELEASE, $.minifyCss())) - .pipe(gulp.dest('build/css')) - .pipe($.size({title: 'styles'})); -}); - // Bundle gulp.task('bundle', function(cb) { var started = false; @@ -111,7 +80,7 @@ gulp.task('bundle', function(cb) { // Build the app from source code gulp.task('build', ['clean'], function(cb) { - runSequence(['vendor', 'assets', 'styles', 'bundle'], cb); + runSequence(['vendor', 'assets', 'bundle'], cb); }); // Build and start watching for modifications @@ -119,7 +88,6 @@ gulp.task('build:watch', function(cb) { watch = true; runSequence('build', function() { gulp.watch(src.assets, ['assets']); - gulp.watch(src.styles, ['styles']); cb(); }); }); diff --git a/package.json b/package.json @@ -10,24 +10,26 @@ "npm": ">= 2.1" }, "dependencies": { - "babel": "5.1.13", - "bootstrap": "3.3.4", + "babel": "5.2.6", + "classnames": "2.0.0", "eventemitter3": "1.0.1", "express": "4.12.3", "fastclick": "1.0.6", "flux": "2.0.3", "front-matter": "1.0.0", "jade": "1.9.2", - "lodash": "3.7.0", + "lodash": "3.8.0", + "normalize.css": "3.0.3", "react": "0.13.2", + "source-map-support": "^0.2.10", "superagent": "1.2.0" }, "devDependencies": { "autoprefixer-loader": "^1.2.0", - "babel-core": "^5.1.13", + "babel-core": "^5.2.6", "babel-eslint": "^3.0.1", "babel-loader": "^5.0.0", - "browser-sync": "^2.6.5", + "browser-sync": "^2.6.9", "css-loader": "^0.12.0", "del": "^1.1.1", "eslint": "^0.20.0", @@ -35,21 +37,10 @@ "eslint-plugin-react": "^2.2.0", "git-push": "^0.1.1", "gulp": "^3.8.11", - "gulp-autoprefixer": "^2.2.0", - "gulp-cache": "^0.2.9", "gulp-changed": "^1.2.1", - "gulp-csscomb": "^3.0.3", - "gulp-htmlmin": "^1.1.1", "gulp-if": "^1.2.5", - "gulp-imagemin": "^2.2.1", - "gulp-jsbeautifier": "^0.0.8", - "gulp-less": "^3.0.3", "gulp-load-plugins": "^0.10.0", - "gulp-minify-css": "^1.1.0", - "gulp-plumber": "^1.0.0", "gulp-rename": "^1.2.2", - "gulp-render": "^0.2.2", - "gulp-replace": "^0.5.3", "gulp-size": "^1.2.1", "gulp-util": "^3.0.4", "jest-cli": "^0.4.0", @@ -58,12 +49,10 @@ "minimist": "^1.1.1", "protractor": "^2.0.0", "psi": "^1.0.6", - "react-tools": "^0.13.2", "run-sequence": "^1.1.0", "style-loader": "^0.12.1", "url-loader": "^0.5.5", - "webpack": "^1.8.10", - "webpack-dev-server": "^1.8.2" + "webpack": "^1.8.11" }, "jest": { "rootDir": "./src", @@ -74,7 +63,8 @@ }, "scripts": { "start": "node server.js", - "test": "eslint src gulpfile.js webpack.config.js && jest", + "lint": "eslint src", + "test": "eslint src && jest", "preupdate-webdriver": "npm install", "update-webdriver": "webdriver-manager update" } diff --git a/preprocessor.js b/preprocessor.js @@ -1,3 +1,11 @@ +/* + * React.js Starter Kit + * Copyright (c) Konstantin Tarkus (@koistya), KriaSoft LLC + * + * This source code is licensed under the MIT license found in the + * LICENSE.txt file in the root directory of this source tree. + */ + 'use strict'; var babel = require('babel-core'); diff --git a/src/actions/AppActions.js b/src/actions/AppActions.js @@ -1,15 +1,9 @@ -/* - * React.js Starter Kit - * Copyright (c) 2014 Konstantin Tarkus (@koistya), KriaSoft LLC. - * - * This source code is licensed under the MIT license found in the - * LICENSE.txt file in the root directory of this source tree. - */ +/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */ -import Dispatcher from '../core/Dispatcher'; -import ActionTypes from '../constants/ActionTypes'; -import ExecutionEnvironment from 'react/lib/ExecutionEnvironment'; import http from 'superagent'; +import ExecutionEnvironment from 'react/lib/ExecutionEnvironment'; +import Dispatcher from '../core/Dispatcher'; +import { ActionTypes } from '../core/Constants'; export default { @@ -22,26 +16,26 @@ export default { } } - Dispatcher.handleViewAction({ - actionType: ActionTypes.CHANGE_LOCATION, + Dispatcher.dispatch({ + type: ActionTypes.CHANGE_LOCATION, path }); }, loadPage(path, cb) { - Dispatcher.handleViewAction({ - actionType: ActionTypes.LOAD_PAGE, + Dispatcher.dispatch({ + type: ActionTypes.GET_PAGE, path }); - http.get('/api/page' + path) + http.get('/api/query?path=' + encodeURI(path)) .accept('application/json') .end((err, res) => { - Dispatcher.handleServerAction({ - actionType: ActionTypes.LOAD_PAGE, + Dispatcher.dispatch({ + type: ActionTypes.RECEIVE_PAGE, path, err, - page: res.body + page: res ? res.body : null }); if (cb) { cb(); diff --git a/src/api/query.js b/src/api/query.js @@ -0,0 +1,28 @@ +/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */ + +import db from '../core/Database'; + +function query(server) { + server.get('/api/query', async (req, res, next) => { + try { + let path = req.query.path; + + if (!path) { + res.status(400).send({error: `The 'path' query parameter cannot be empty.`}); + } + + let page = await db.getPage(path); + + if (page) { + res.status(200).send(page); + } else { + res.status(404).send({error: `The page '${path}' is not found.`}); + } + } catch (err) { + next(err); + } + }); +} + +export default query; + diff --git a/src/app.js b/src/app.js @@ -1,20 +1,13 @@ -/* - * React.js Starter Kit - * Copyright (c) 2014 Konstantin Tarkus (@koistya), KriaSoft LLC. - * - * This source code is licensed under the MIT license found in the - * LICENSE.txt file in the root directory of this source tree. - */ +/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */ import 'babel/polyfill'; - -import React from 'react/addons'; +import React from 'react'; import FastClick from 'fastclick'; import emptyFunction from 'react/lib/emptyFunction'; import App from './components/App'; import Dispatcher from './core/Dispatcher'; import AppActions from './actions/AppActions'; -import ActionTypes from './constants/ActionTypes'; +import { ActionTypes } from './core/Constants'; let path = decodeURI(window.location.pathname); let setMetaTag = (name, content) => { @@ -44,9 +37,9 @@ function run() { React.render(element, document.body); // Update `Application.path` prop when `window.location` is changed - Dispatcher.register((payload) => { - if (payload.action.actionType === ActionTypes.CHANGE_LOCATION) { - element = React.cloneElement(element, {path: payload.action.path}); + Dispatcher.register((action) => { + if (action.type === ActionTypes.CHANGE_LOCATION) { + element = React.cloneElement(element, {path: action.path}); React.render(element, document.body); } }); diff --git a/src/components/App/App.js b/src/components/App/App.js @@ -1,21 +1,21 @@ -/* - * React.js Starter Kit - * Copyright (c) 2014 Konstantin Tarkus (@koistya), KriaSoft LLC. - * - * This source code is licensed under the MIT license found in the - * LICENSE.txt file in the root directory of this source tree. - */ +/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */ import './App.less'; import React, { PropTypes } from 'react'; -import invariant from 'react/lib/invariant'; import AppActions from '../../actions/AppActions'; import AppStore from '../../stores/AppStore'; -import Navbar from '../Navbar'; +import Header from '../Header'; import ContentPage from '../ContentPage'; +import ContactPage from '../ContactPage'; +import LoginPage from '../LoginPage'; +import RegisterPage from '../RegisterPage'; import NotFoundPage from '../NotFoundPage'; +import Feedback from '../Feedback'; +import Footer from '../Footer'; import setViewport from './setViewport'; +const pages = { ContentPage, ContactPage, LoginPage, RegisterPage, NotFoundPage }; + class App { static propTypes = { @@ -42,41 +42,41 @@ class App { } render() { - var page = AppStore.getPage(this.props.path); - invariant(page !== undefined, 'Failed to load page content.'); - this.props.onSetTitle(page.title); - - if (page.type === 'notfound') { - this.props.onPageNotFound(); - return React.createElement(NotFoundPage, page); + switch (this.props.path) { + + case '/contact': + this.props.onSetTitle(ContactPage.title); + this.component = <ContactPage />; + break; + + case '/login': + this.props.onSetTitle(LoginPage.title); + this.component = <LoginPage />; + break; + + case '/register': + this.props.onSetTitle(RegisterPage.title); + this.component = <RegisterPage />; + break; + + default: + let page = AppStore.getPage(this.props.path); + if (page) { + this.props.onSetTitle(page.title); + this.component = React.createElement(pages[page.component], page); + } else { + this.props.onSetTitle(NotFoundPage.title); + this.props.onPageNotFound(); + this.component = <NotFoundPage />; + } } return ( - <div className="App"> - <Navbar /> - { - this.props.path === '/' ? - <div className="jumbotron"> - <div className="container text-center"> - <h1>React</h1> - <p>Complex web apps made easy</p> - </div> - </div> : - <div className="container"> - <h2>{page.title}</h2> - </div> - } - <ContentPage className="container" {...page} /> - <div className="navbar-footer"> - <div className="container"> - <p className="text-muted"> - <span>© Your Company</span> - <span><a href="/">Home</a></span> - <span><a href="/privacy">Privacy</a></span> - <span>{'Viewport: ' + this.props.viewport.width + 'x' + this.props.viewport.height}</span> - </p> - </div> - </div> + <div> + <Header /> + {this.component} + <Feedback /> + <Footer viewport={this.props.viewport} /> </div> ); } diff --git a/src/components/App/App.less b/src/components/App/App.less @@ -1,9 +1,167 @@ +/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */ + +@import '../variables.less'; +@import (less) '../../../node_modules/normalize.css/normalize.css'; + +// +// Base styles +// ----------------------------------------------------------------------------- + +html { + color: #222; + font-weight: 100; + font-size: 1em; // ~16px; + font-family: @font-family-base; + line-height: 1.375; // ~22px +} + /* - * React.js Starter Kit - * Copyright (c) 2014 Konstantin Tarkus (@koistya), KriaSoft LLC. + * Remove text-shadow in selection highlight: + * https://twitter.com/miketaylr/status/12228805301 * - * This source code is licensed under the MIT license found in the - * LICENSE.txt file in the root directory of this source tree. + * These selection rule sets have to be separate. + * Customize the background color to match your design. + */ + +::-moz-selection { + background: #b3d4fc; + text-shadow: none; +} + +::selection { + background: #b3d4fc; + text-shadow: none; +} + +/* + * A better looking default horizontal rule */ -.App {} +hr { + display: block; + height: 1px; + border: 0; + border-top: 1px solid #ccc; + margin: 1em 0; + padding: 0; +} + +/* + * Remove the gap between audio, canvas, iframes, + * images, videos and the bottom of their containers: + * https://github.com/h5bp/html5-boilerplate/issues/440 + */ + +audio, +canvas, +iframe, +img, +svg, +video { + vertical-align: middle; +} + +/* + * Remove default fieldset styles. + */ + +fieldset { + border: 0; + margin: 0; + padding: 0; +} + +/* + * Allow only vertical resizing of textareas. + */ + +textarea { + resize: vertical; +} + +// +// Browser upgrade prompt +// ----------------------------------------------------------------------------- + +.browserupgrade { + margin: 0.2em 0; + background: #ccc; + color: #000; + padding: 0.2em 0; +} + +// +// Print styles +// Inlined to avoid the additional HTTP request: +// http://www.phpied.com/delay-loading-your-print-css/ +// ----------------------------------------------------------------------------- + +@media print { + *, + *:before, + *:after { + background: transparent !important; + color: #000 !important; /* Black prints faster: http://www.sanbeiji.com/archives/953 */ + box-shadow: none !important; + text-shadow: none !important; + } + + a, + a:visited { + text-decoration: underline; + } + + a[href]:after { + content: " (" attr(href) ")"; + } + + abbr[title]:after { + content: " (" attr(title) ")"; + } + + /* + * Don't show links that are fragment identifiers, + * or use the `javascript:` pseudo protocol + */ + + a[href^="#"]:after, + a[href^="javascript:"]:after { + content: ""; + } + + pre, + blockquote { + border: 1px solid #999; + page-break-inside: avoid; + } + + /* + * Printing Tables: + * http://css-discuss.incutio.com/wiki/Printing_Tables + */ + + thead { + display: table-header-group; + } + + tr, + img { + page-break-inside: avoid; + } + + img { + max-width: 100% !important; + } + + p, + h2, + h3 { + orphans: 3; + widows: 3; + } + + h2, + h3 { + page-break-after: avoid; + } +} diff --git a/src/components/App/setViewport.js b/src/components/App/setViewport.js @@ -1,10 +1,4 @@ -/* - * React.js Starter Kit - * Copyright (c) 2014 Konstantin Tarkus (@koistya), KriaSoft LLC. - * - * This source code is licensed under the MIT license found in the - * LICENSE.txt file in the root directory of this source tree. - */ +/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */ import React, { Component } from 'react'; // eslint-disable-line no-unused-vars import { canUseDOM } from 'react/lib/ExecutionEnvironment'; diff --git a/src/components/ContactPage/ContactPage.js b/src/components/ContactPage/ContactPage.js @@ -0,0 +1,23 @@ +/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */ + +import React from 'react'; // eslint-disable-line no-unused-vars +import './ContactPage.less'; + +class ContactPage { + + static title = 'Contact Us'; + + render() { + return ( + <div className="ContactPage"> + <div className="ContactPage-container"> + <h1>{ContactPage.title}</h1> + <p>...</p> + </div> + </div> + ); + } + +} + +export default ContactPage; diff --git a/src/components/ContactPage/ContactPage.less b/src/components/ContactPage/ContactPage.less @@ -0,0 +1,11 @@ +/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */ + +@import '../variables.less'; + +.ContactPage { + &-container { + margin: 0 auto; + padding: 0 0 40px; + max-width: @max-content-width; + } +} diff --git a/src/components/ContactPage/package.json b/src/components/ContactPage/package.json @@ -0,0 +1,6 @@ +{ + "name": "ContactPage", + "version": "0.0.0", + "private": true, + "main": "./ContactPage.js" +} diff --git a/src/components/ContentPage/ContentPage.js b/src/components/ContentPage/ContentPage.js @@ -1,26 +1,25 @@ -/* - * React.js Starter Kit - * Copyright (c) 2014 Konstantin Tarkus (@koistya), KriaSoft LLC. - * - * This source code is licensed under the MIT license found in the - * LICENSE.txt file in the root directory of this source tree. - */ +/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */ -import './ContentPage.less'; import React, { PropTypes } from 'react'; // eslint-disable-line no-unused-vars +import './ContentPage.less'; class ContentPage { static propTypes = { - body: PropTypes.string.isRequired + path: PropTypes.string.isRequired, + content: PropTypes.string.isRequired }; render() { - var { className, body, other } = this.props; - return ( - <div className={'ContentPage ' + className} - dangerouslySetInnerHTML={{__html: body}} {...other} /> + <div className="ContentPage"> + <div className="ContentPage-container"> + { + this.props.path === '/' ? null : <h1>{this.props.title}</h1> + } + <div dangerouslySetInnerHTML={{__html: this.props.content || ''}} /> + </div> + </div> ); } diff --git a/src/components/ContentPage/ContentPage.less b/src/components/ContentPage/ContentPage.less @@ -1,9 +1,11 @@ -/* - * React.js Starter Kit - * Copyright (c) 2014 Konstantin Tarkus (@koistya), KriaSoft LLC. - * - * This source code is licensed under the MIT license found in the - * LICENSE.txt file in the root directory of this source tree. - */ +/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */ -.ContentPage {} +@import '../variables.less'; + +.ContentPage { + &-container { + margin: 0 auto; + padding: 0 0 40px; + max-width: @max-content-width; + } +} diff --git a/src/components/Feedback/Feedback.js b/src/components/Feedback/Feedback.js @@ -0,0 +1,22 @@ +/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */ + +import React from 'react'; // eslint-disable-line no-unused-vars +import './Feedback.less'; + +class Feedback { + + render() { + return ( + <div className="Feedback"> + <div className="Feedback-container"> + <a className="Feedback-link" href="https://gitter.im/kriasoft/react-starter-kit">Ask a question</a> + <span className="Feedback-spacer">|</span> + <a className="Feedback-link" href="https://github.com/kriasoft/react-starter-kit/issues/new">Report an issue</a> + </div> + </div> + ); + } + +} + +export default Feedback; diff --git a/src/components/Feedback/Feedback.less b/src/components/Feedback/Feedback.less @@ -0,0 +1,35 @@ +/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */ + +@import '../variables.less'; + +.Feedback { + background: #f5f5f5; + color: #333; + + &-container { + margin: 0 auto; + padding: 20px 8px; + max-width: @max-content-width; + text-align: center; + font-size: 1.5em; // ~24px + } + + &-link { + &, + &:active, + &:hover, + &:visited { + color: #333; + text-decoration: none; + } + + &:hover { + text-decoration: underline; + } + } + + &-spacer { + padding-right: 15px; + padding-left: 15px; + } +} diff --git a/src/components/Feedback/package.json b/src/components/Feedback/package.json @@ -0,0 +1,6 @@ +{ + "name": "Feedback", + "version": "0.0.0", + "private": true, + "main": "./Feedback.js" +} diff --git a/src/components/Footer/Footer.js b/src/components/Footer/Footer.js @@ -0,0 +1,27 @@ +/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */ + +import React, { PropTypes } from 'react'; // eslint-disable-line no-unused-vars +import './Footer.less'; + +class Footer { + + static propTypes = { + viewport: PropTypes.object.isRequired + }; + + render() { + return ( + <div className="Footer"> + <div className="Footer-container"> + <span className="Footer-text">© Your Company</span> + <a className="Footer-link" href="/">Home</a> + <a className="Footer-link" href="/privacy">Privacy</a> + <span className="Footer-text Footer-text--muted">| {'Viewport: ' + this.props.viewport.width + 'x' + this.props.viewport.height}</span> + </div> + </div> + ); + } + +} + +export default Footer; diff --git a/src/components/Footer/Footer.less b/src/components/Footer/Footer.less @@ -0,0 +1,42 @@ +/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */ + +@import '../variables.less'; + +.Footer { + background: #333; + color: #fff; + + &-container { + margin: 0 auto; + padding: 20px 15px; + max-width: @max-content-width; + text-align: center; + } + + &-text { + color: rgba(255, 255, 255, .5); + + &--muted { + color: rgba(255, 255, 255, .3); + } + } + + &-text, + &-link { + padding: 2px 5px; + font-size: 1em; + } + + &-link { + &, + &:active, + &:visited { + color: rgba(255, 255, 255, .6); + text-decoration: none; + } + + &:hover { + color: rgba(255, 255, 255, 1); + } + } +} diff --git a/src/components/Footer/package.json b/src/components/Footer/package.json @@ -0,0 +1,6 @@ +{ + "name": "Footer", + "version": "0.0.0", + "private": true, + "main": "./Footer.js" +} diff --git a/src/components/Header/Header.js b/src/components/Header/Header.js @@ -0,0 +1,29 @@ +/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */ + +import React from 'react'; // eslint-disable-line no-unused-vars +import './Header.less'; +import Navigation from '../Navigation'; + +class Header { + + render() { + return ( + <div className="Header"> + <div className="Header-container"> + <a className="Header-brand" href="/"> + <img cassName="Header-brandImg" src={require('./logo-small.png')} width="38" height="38" alt="React" /> + <span className="Header-brandTxt">Your Company</span> + </a> + <Navigation className="Header-nav" /> + <div className="Header-banner"> + <h1 className="Header-bannerTitle">React</h1> + <p className="Header-bannerDesc">Complex web apps made easy</p> + </div> + </div> + </div> + ); + } + +} + +export default Header; diff --git a/src/components/Header/Header.less b/src/components/Header/Header.less @@ -0,0 +1,54 @@ +/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */ + +@import '../variables.less'; + +@brand-color: #61dafb; + +.Header { + background: #373277; + color: #fff; + + &-container { + margin: 0 auto; + padding: 20px 0; + max-width: @max-content-width; + } + + &-brand { + color: lighten(@brand-color, 10%); + text-decoration: none; + font-size: 1.75em; // ~28px + } + + &-brandImg { + + } + + &-brandTxt { + margin-left: 10px; + } + + &-nav { + float: right; + margin-top: 6px; + } + + &-banner { + text-align: center; + } + + &-bannerTitle { + margin: 0; + padding: 0; + font-weight: normal; + font-size: 4em; + line-height: 1em; + } + + &-bannerDesc { + padding: 0; + color: rgba(255, 255, 255, .5); + font-size: 1.25em; + margion: 0; + } +} diff --git a/src/components/Navbar/logo-small.png b/src/components/Header/logo-small.png Binary files differ. diff --git a/src/components/Navbar/logo-small@2x.png b/src/components/Header/logo-small@2x.png Binary files differ. diff --git a/src/components/Header/package.json b/src/components/Header/package.json @@ -0,0 +1,6 @@ +{ + "name": "Header", + "version": "0.0.0", + "private": true, + "main": "./Header.js" +} diff --git a/src/components/HomePage/HomePage.js b/src/components/HomePage/HomePage.js @@ -1,27 +0,0 @@ -/* - * React.js Starter Kit - * Copyright (c) 2014 Konstantin Tarkus (@koistya), KriaSoft LLC. - * - * This source code is licensed under the MIT license found in the - * LICENSE.txt file in the root directory of this source tree. - */ - -import './HomePage.less'; -import React, { PropTypes } from 'react'; // eslint-disable-line no-unused-vars - -class HomePage { - - static propTypes = { - body: PropTypes.string.isRequired - }; - - render() { - return ( - <div className="ContentPage" - dangerouslySetInnerHTML={{__html: this.props.body}} /> - ); - } - -} - -export default HomePage; diff --git a/src/components/HomePage/HomePage.less b/src/components/HomePage/HomePage.less @@ -1,9 +0,0 @@ -/* - * React.js Starter Kit - * Copyright (c) 2014 Konstantin Tarkus (@koistya), KriaSoft LLC. - * - * This source code is licensed under the MIT license found in the - * LICENSE.txt file in the root directory of this source tree. - */ - -.HomePage {} diff --git a/src/components/HomePage/package.json b/src/components/HomePage/package.json @@ -1,6 +0,0 @@ -{ - "name": "HomePage", - "version": "0.0.0", - "private": true, - "main": "./HomePage.js" -} diff --git a/src/components/LoginPage/LoginPage.js b/src/components/LoginPage/LoginPage.js @@ -0,0 +1,23 @@ +/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */ + +import React from 'react'; // eslint-disable-line no-unused-vars +import './LoginPage.less'; + +class LoginPage { + + static title = 'Log In'; + + render() { + return ( + <div className="LoginPage"> + <div className="LoginPage-container"> + <h1>{LoginPage.title}</h1> + <p>...</p> + </div> + </div> + ); + } + +} + +export default LoginPage; diff --git a/src/components/LoginPage/LoginPage.less b/src/components/LoginPage/LoginPage.less @@ -0,0 +1,11 @@ +/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */ + +@import '../variables.less'; + +.LoginPage { + &-container { + margin: 0 auto; + padding: 0 0 40px; + max-width: @max-content-width; + } +} diff --git a/src/components/LoginPage/package.json b/src/components/LoginPage/package.json @@ -0,0 +1,6 @@ +{ + "name": "LoginPage", + "version": "0.0.0", + "private": true, + "main": "./LoginPage.js" +} diff --git a/src/components/Navbar/Navbar.js b/src/components/Navbar/Navbar.js @@ -1,28 +0,0 @@ -/* - * React.js Starter Kit - * Copyright (c) 2014 Konstantin Tarkus (@koistya), KriaSoft LLC. - * - * This source code is licensed under the MIT license found in the - * LICENSE.txt file in the root directory of this source tree. - */ - -import React from 'react'; // eslint-disable-line no-unused-vars - -class Navbar { - - render() { - return ( - <div className="navbar-top" role="navigation"> - <div className="container"> - <a className="navbar-brand row" href="/"> - <img src={require('./logo-small.png')} width="38" height="38" alt="React" /> - <span>React.js Starter Kit</span> - </a> - </div> - </div> - ); - } - -} - -export default Navbar; diff --git a/src/components/Navbar/__tests__/Navbar-test.js b/src/components/Navbar/__tests__/Navbar-test.js @@ -1,26 +0,0 @@ -/* - * React.js Starter Kit - * Copyright (c) 2014 Konstantin Tarkus (@koistya), KriaSoft LLC. - * - * This source code is licensed under the MIT license found in the - * LICENSE.txt file in the root directory of this source tree. - */ - -/* global jest, describe, it, expect */ - -jest.dontMock('../Navbar'); - -describe('Navbar', function() { - - it('sets class name', function() { - var React = require('react/addons'); - var TestUtils = React.addons.TestUtils; - - var Navbar = require('../Navbar'); - var Component = TestUtils.renderIntoDocument(React.createElement(Navbar)); - - var element = TestUtils.findRenderedDOMComponentWithClass(Component, 'navbar-top'); - expect(element).toBeDefined(); - }); - -}); diff --git a/src/components/Navbar/package.json b/src/components/Navbar/package.json @@ -1,6 +0,0 @@ -{ - "name": "Navbar", - "version": "0.0.0", - "private": true, - "main": "./Navbar.js" -} diff --git a/src/components/Navigation/Navigation.js b/src/components/Navigation/Navigation.js @@ -0,0 +1,24 @@ +/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */ + +import React from 'react'; // eslint-disable-line no-unused-vars +import cx from 'classnames'; +import './Navigation.less'; + +class Navigation { + + render() { + return ( + <div className={cx(this.props.className, 'Navigation')} role="navigation"> + <a className="Navigation-link" href="/about">About</a> + <a className="Navigation-link" href="/contact">Contact</a> + <span className="Navigation-spacer"> | </span> + <a className="Navigation-link" href="/login">Log in</a> + <span className="Navigation-spacer">or</span> + <a className="Navigation-link Navigation-link--highlight" href="/register">Sign up</a> + </div> + ); + } + +} + +export default Navigation; diff --git a/src/components/Navigation/Navigation.less b/src/components/Navigation/Navigation.less @@ -0,0 +1,37 @@ +/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */ + +.Navigation { + + &-link { + display: inline-block; + padding: 3px 8px; + text-decoration: none; + font-size: 1.125em; // ~18px + + &, + &:active, + &:visited { + color: rgba(255, 255, 255, .6); + } + + &:hover { + color: rgba(255, 255, 255, 1); + } + + &--highlight { + margin-right: 8px; + margin-left: 8px; + border-radius: 3px; + background: rgba(0, 0, 0, .15); + color: #fff; + + &:hover { + background: rgba(0, 0, 0, .3); + } + } + } + + &-spacer { + color: rgba(255, 255, 255, .3); + } +} diff --git a/src/components/Navigation/package.json b/src/components/Navigation/package.json @@ -0,0 +1,6 @@ +{ + "name": "Navigation", + "version": "0.0.0", + "private": true, + "main": "./Navigation.js" +} diff --git a/src/components/NotFoundPage/NotFoundPage.js b/src/components/NotFoundPage/NotFoundPage.js @@ -1,16 +1,12 @@ -/* - * React.js Starter Kit - * Copyright (c) 2014 Konstantin Tarkus (@koistya), KriaSoft LLC. - * - * This source code is licensed under the MIT license found in the - * LICENSE.txt file in the root directory of this source tree. - */ +/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */ //import './NotFoundPage.less'; import React from 'react'; // eslint-disable-line no-unused-vars class NotFoundPage { + static title = 'Page Not Found'; + render() { return ( <div> diff --git a/src/components/NotFoundPage/NotFoundPage.less b/src/components/NotFoundPage/NotFoundPage.less @@ -1,35 +1,29 @@ -/* - * React.js Starter Kit - * Copyright (c) 2014 Konstantin Tarkus (@koistya), KriaSoft LLC. - * - * This source code is licensed under the MIT license found in the - * LICENSE.txt file in the root directory of this source tree. - */ +/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */ * { - line-height: 1.2; margin: 0; + line-height: 1.2; } html { - color: #888; display: table; - font-family: sans-serif; + width: 100%; height: 100%; + color: #888; text-align: center; - width: 100%; + font-family: sans-serif; } body { display: table-cell; - vertical-align: middle; margin: 2em auto; + vertical-align: middle; } h1 { color: #555; - font-size: 2em; font-weight: 400; + font-size: 2em; } p { diff --git a/src/components/RegisterPage/RegisterPage.js b/src/components/RegisterPage/RegisterPage.js @@ -0,0 +1,23 @@ +/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */ + +import React from 'react'; // eslint-disable-line no-unused-vars +import './RegisterPage.less'; + +class RegisterPage { + + static title = 'Sign Up'; + + render() { + return ( + <div className="RegisterPage"> + <div className="RegisterPage-container"> + <h1>{RegisterPage.title}</h1> + <p>...</p> + </div> + </div> + ); + } + +} + +export default RegisterPage; diff --git a/src/components/RegisterPage/RegisterPage.less b/src/components/RegisterPage/RegisterPage.less @@ -0,0 +1,11 @@ +/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */ + +@import '../variables.less'; + +.RegisterPage { + &-container { + margin: 0 auto; + padding: 0 0 40px; + max-width: @max-content-width; + } +} diff --git a/src/components/RegisterPage/package.json b/src/components/RegisterPage/package.json @@ -0,0 +1,6 @@ +{ + "name": "RegisterPage", + "version": "0.0.0", + "private": true, + "main": "./RegisterPage.js" +} diff --git a/src/components/TextBox/TextBox.js b/src/components/TextBox/TextBox.js @@ -1,10 +1,4 @@ -/* - * React.js Starter Kit - * Copyright (c) 2014 Konstantin Tarkus (@koistya), KriaSoft LLC. - * - * This source code is licensed under the MIT license found in the - * LICENSE.txt file in the root directory of this source tree. - */ +/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */ import './TextBox.less'; import React, { PropTypes } from 'react'; // eslint-disable-line no-unused-vars diff --git a/src/components/TextBox/TextBox.less b/src/components/TextBox/TextBox.less @@ -1,10 +1,5 @@ -/* - * React.js Starter Kit - * Copyright (c) 2014 Konstantin Tarkus (@koistya), KriaSoft LLC. - * - * This source code is licensed under the MIT license found in the - * LICENSE.txt file in the root directory of this source tree. - */ +/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */ -.TextBox {} -.TextBox-input {} +.TextBox { + &-input {} +} diff --git a/src/components/variables.less b/src/components/variables.less @@ -0,0 +1,41 @@ +/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */ + +// +// Colors +// ----------------------------------------------------------------------------- + +@white-base: hsl(255, 255, 255); + +@gray-base: hsl(0, 0, 0); +@gray-darker: lighten(@gray-base, 13.5%); // #222 +@gray-dark: lighten(@gray-base, 25%); // #404040 +@gray: lighten(@gray-base, 33.5%); // #555 +@gray-light: lighten(@gray-base, 46.7%); // #777 +@gray-lighter: lighten(@gray-base, 93.5%); // #eee + +// +// Typography +// ----------------------------------------------------------------------------- + +@font-family-base: 'Segoe UI', 'HelveticaNeue-Light', sans-serif; + +// +// Layout +// ----------------------------------------------------------------------------- + +@max-content-width: 1000px; + +// +// Media queries breakpoints +// ----------------------------------------------------------------------------- + +@screen-xs-min: 480px; // Extra small screen / phone +@screen-sm-min: 768px; // Small screen / tablet +@screen-md-min: 992px; // Medium screen / desktop +@screen-lg-min: 1200px; // Large screen / wide desktop + +// +// Animations +// ----------------------------------------------------------------------------- + +@animation-swift-out: .45s cubic-bezier(0.3, 1, 0.4, 1) 0s; diff --git a/src/constants/ActionTypes.js b/src/constants/ActionTypes.js @@ -1,18 +0,0 @@ -/* - * React.js Starter Kit - * Copyright (c) 2014 Konstantin Tarkus (@koistya), KriaSoft LLC. - * - * This source code is licensed under the MIT license found in the - * LICENSE.txt file in the root directory of this source tree. - */ - -import keyMirror from 'react/lib/keyMirror'; - -export default keyMirror({ - - LOAD_PAGE: null, - LOAD_PAGE_SUCCESS: null, - LOAD_PAGE_ERROR: null, - CHANGE_LOCATION: null - -}); diff --git a/src/constants/PayloadSources.js b/src/constants/PayloadSources.js @@ -1,16 +0,0 @@ -/* - * React.js Starter Kit - * Copyright (c) 2014 Konstantin Tarkus (@koistya), KriaSoft LLC. - * - * This source code is licensed under the MIT license found in the - * LICENSE.txt file in the root directory of this source tree. - */ - -import keyMirror from 'react/lib/keyMirror'; - -export default keyMirror({ - - VIEW_ACTION: null, - SERVER_ACTION: null - -}); diff --git a/src/content/about.jade b/src/content/about.jade @@ -1,5 +1,6 @@ --- -title: About +title: About Us +component: ContentPage --- p. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean consequat diff --git a/src/content/index.jade b/src/content/index.jade @@ -1,5 +1,6 @@ --- title: React.js Starter Kit +component: ContentPage --- div.row div.col-sm-4 diff --git a/src/content/privacy.jade b/src/content/privacy.jade @@ -1,5 +1,6 @@ --- title: Privacy Policy +component: ContentPage --- mixin breadcrumb ol.breadcrumb diff --git a/src/core/Constants.js b/src/core/Constants.js @@ -0,0 +1,13 @@ +/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */ + +import keyMirror from 'react/lib/keyMirror'; + +export default { + + ActionTypes: keyMirror({ + GET_PAGE: null, + RECEIVE_PAGE: null, + CHANGE_LOCATION: null + }) + +}; diff --git a/src/core/Database.js b/src/core/Database.js @@ -0,0 +1,52 @@ +/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */ + +import fs from 'fs'; +import path from 'path'; +import jade from 'jade'; +import fm from 'front-matter'; +import Dispatcher from './Dispatcher'; +import { ActionTypes } from './Constants'; + +// A folder with Jade/Markdown/HTML content pages +const CONTENT_DIR = path.join(__dirname, './content'); + +// Check if that directory exists, print an error message if not +fs.exists(CONTENT_DIR, (exists) => { + if (!exists) { + console.error(`Error: Directory '${CONTENT_DIR}' does not exist.`); + } +}); + +// Extract 'front matter' metadata and generate HTML +function parseJade(uri, jadeContent) { + let content = fm(jadeContent); + let html = jade.render(content.body, null, ' '); + let page = Object.assign({path: uri, content: html}, content.attributes); + return page; +} + +export default { + + getPage: (uri) => { + // Read page content from a Jade file + return new Promise((resolve) => { + let fileName = path.join(CONTENT_DIR, (uri === '/' ? '/index' : uri) + '.jade'); + fs.readFile(fileName, {encoding: 'utf8'}, (err, data) => { + if (err) { + fileName = path.join(CONTENT_DIR, uri + '/index.jade'); + fs.readFile(fileName, {encoding: 'utf8'}, (err2, data2) => { + resolve(err2 ? null : parseJade(uri, data2)); + }); + } + resolve(parseJade(uri, data)); + }); + }).then((page) => { + Dispatcher.dispatch({ + type: ActionTypes.RECEIVE_PAGE, + page: page}); + return Promise.resolve(page); + }); + } + +}; + diff --git a/src/core/Dispatcher.js b/src/core/Dispatcher.js @@ -1,45 +1,5 @@ -/* - * React.js Starter Kit - * Copyright (c) 2014 Konstantin Tarkus (@koistya), KriaSoft LLC. - * - * This source code is licensed under the MIT license found in the - * LICENSE.txt file in the root directory of this source tree. - */ +/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */ -import Flux from 'flux'; -import PayloadSources from '../constants/PayloadSources'; -import assign from 'react/lib/Object.assign'; +import { Dispatcher } from 'flux'; -/** - * A singleton that operates as the central hub for application updates. - * For more information visit https://facebook.github.io/flux/ - */ -let Dispatcher = assign(new Flux.Dispatcher(), { - - /** - * @param {object} action The details of the action, including the action's - * type and additional data coming from the server. - */ - handleServerAction(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(action) { - var payload = { - source: PayloadSources.VIEW_ACTION, - action: action - }; - this.dispatch(payload); - } - -}); - -export default Dispatcher; +export default new Dispatcher(); diff --git a/src/server.js b/src/server.js @@ -1,94 +1,66 @@ -/* - * React.js Starter Kit - * Copyright (c) 2014 Konstantin Tarkus (@koistya), KriaSoft LLC. - * - * This source code is licensed under the MIT license found in the - * LICENSE.txt file in the root directory of this source tree. - */ +/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */ +require('source-map-support').install(); + +import 'babel/polyfill'; import _ from 'lodash'; import fs from 'fs'; import path from 'path'; import express from 'express'; import React from 'react'; -import Dispatcher from './core/Dispatcher'; -import ActionTypes from './constants/ActionTypes'; -import AppStore from './stores/AppStore'; +import './core/Dispatcher'; +import './stores/AppStore'; +import db from './core/Database'; +import App from './components/App'; -var server = express(); +const server = express(); server.set('port', (process.env.PORT || 5000)); server.use(express.static(path.join(__dirname))); // -// Page API +// Register API middleware // ----------------------------------------------------------------------------- -server.get('/api/page/*', function(req, res) { - var urlPath = req.path.substr(9); - var page = AppStore.getPage(urlPath); - res.send(page); -}); +require('./api/query')(server); // -// Server-side rendering +// Register server-side rendering middleware // ----------------------------------------------------------------------------- // The top-level React component + HTML template for it -var App = React.createFactory(require('./components/App')); -var templateFile = path.join(__dirname, 'templates/index.html'); -var template = _.template(fs.readFileSync(templateFile, 'utf8')); +const templateFile = path.join(__dirname, 'templates/index.html'); +const template = _.template(fs.readFileSync(templateFile, 'utf8')); + +server.get('*', async (req, res, next) => { + try { + let uri = req.path; + let notFound = false; + let data = {description: ''}; + let app = <App + path={req.path} + onSetTitle={(title) => { data.title = title; }} + onSetMeta={(name, content) => { data[name] = content; }} + onPageNotFound={() => { notFound = true; }} />; + + await db.getPage(uri); + data.body = React.renderToString(app); -server.get('*', function(req, res) { - var data = {description: ''}; - var app = new App({ - path: req.path, - onSetTitle: function(title) { data.title = title; }, - onSetMeta: function(name, content) { data[name] = content; }, - onPageNotFound: function() { res.status(404); } - }); - data.body = React.renderToString(app); - var html = template(data); - res.send(html); + if (notFound) { + res.status(404).send(); + } else { + let html = template(data); + res.send(html); + } + } catch (err) { + next(err); + } }); -// Load pages from the `/src/content/` folder into the AppStore -(function() { - var assign = require('react/lib/Object.assign'); - var fm = require('front-matter'); - var jade = require('jade'); - var sourceDir = path.join(__dirname, './content'); - var getFiles = function(dir) { - var pages = []; - fs.readdirSync(dir).forEach(function(file) { - var stat = fs.statSync(path.join(dir, file)); - if (stat && stat.isDirectory()) { - pages = pages.concat(getFiles(file)); - } else { - // Convert the file to a Page object - var filename = path.join(dir, file); - var url = filename. - substr(sourceDir.length, filename.length - sourceDir.length - 5) - .replace('\\', '/'); - if (url.indexOf('/index', url.length - 6) !== -1) { - url = url.substr(0, url.length - (url.length > 6 ? 6 : 5)); - } - var source = fs.readFileSync(filename, 'utf8'); - var content = fm(source); - var html = jade.render(content.body, null, ' '); - var page = assign({}, {path: url, body: html}, content.attributes); - Dispatcher.handleServerAction({ - actionType: ActionTypes.LOAD_PAGE, - path: url, - page: page - }); - } - }); - return pages; - }; - return getFiles(sourceDir); -})(); +// +// Launch the server +// ----------------------------------------------------------------------------- -server.listen(server.get('port'), function() { +server.listen(server.get('port'), () => { if (process.send) { process.send('online'); } else { diff --git a/src/stores/AppStore.js b/src/stores/AppStore.js @@ -1,28 +1,15 @@ -/* - * React.js Starter Kit - * Copyright (c) 2014 Konstantin Tarkus (@koistya), KriaSoft LLC. - * - * This source code is licensed under the MIT license found in the - * LICENSE.txt file in the root directory of this source tree. - */ +/*! React Starter Kit | MIT License | http://www.reactstarterkit.com/ */ -import Dispatcher from '../core/Dispatcher'; -import ActionTypes from '../constants/ActionTypes'; -import PayloadSources from '../constants/PayloadSources'; import EventEmitter from 'eventemitter3'; -import assign from 'react/lib/Object.assign'; +import Dispatcher from '../core/Dispatcher'; +import { ActionTypes } from '../core/Constants.js'; -var CHANGE_EVENT = 'change'; +const CHANGE_EVENT = 'change'; var pages = {}; var loading = false; -if (__SERVER__) { - pages['/'] = {title: 'Home Page'}; - pages['/privacy'] = {title: 'Privacy Policy'}; -} - -var AppStore = assign({}, EventEmitter.prototype, { +var AppStore = Object.assign({}, EventEmitter.prototype, { isLoading() { return loading; @@ -35,10 +22,7 @@ var AppStore = assign({}, EventEmitter.prototype, { * @returns {*} Page data. */ getPage(path) { - return path in pages ? pages[path] : { - title: 'Page Not Found', - type: 'notfound' - }; + return path in pages ? pages[path] : null; }, /** @@ -70,26 +54,25 @@ var AppStore = assign({}, EventEmitter.prototype, { }); -AppStore.dispatcherToken = Dispatcher.register((payload) => { - var action = payload.action; +AppStore.dispatchToken = Dispatcher.register((action) => { - switch (action.actionType) { + switch (action.type) { - case ActionTypes.LOAD_PAGE: - if (action.source === PayloadSources.VIEW_ACTION) { - loading = true; - } else { - loading = false; - if (!action.err) { - pages[action.path] = action.page; - } + case ActionTypes.GET_PAGE: + loading = true; + AppStore.emitChange(); + break; + + case ActionTypes.RECEIVE_PAGE: + loading = false; + if (!action.err) { + pages[action.page.path] = action.page; } AppStore.emitChange(); break; default: // Do nothing - } }); diff --git a/src/styles/bootstrap.less b/src/styles/bootstrap.less @@ -1,54 +0,0 @@ -// ============================================================================= -// Bootstrap CSS + Custom styles and overrides -// ============================================================================= - -// Core variables and mixins -@import "variables.less"; -@import "mixins.less"; - -// Reset and dependencies -@import "../../node_modules/bootstrap/less/normalize.less"; -@import "../../node_modules/bootstrap/less/print.less"; -@import "../../node_modules/bootstrap/less/glyphicons.less"; - -// Core CSS -@import "../../node_modules/bootstrap/less/scaffolding.less"; -@import "../../node_modules/bootstrap/less/type.less"; -@import "../../node_modules/bootstrap/less/code.less"; -@import "../../node_modules/bootstrap/less/grid.less"; -@import "../../node_modules/bootstrap/less/tables.less"; -@import "../../node_modules/bootstrap/less/forms.less"; -@import "../../node_modules/bootstrap/less/buttons.less"; - -// Components -@import "../../node_modules/bootstrap/less/component-animations.less"; -@import "../../node_modules/bootstrap/less/dropdowns.less"; -@import "../../node_modules/bootstrap/less/button-groups.less"; -@import "../../node_modules/bootstrap/less/input-groups.less"; -@import "../../node_modules/bootstrap/less/navs.less"; -@import "navbar.less"; -@import "../../node_modules/bootstrap/less/breadcrumbs.less"; -@import "../../node_modules/bootstrap/less/pagination.less"; -@import "../../node_modules/bootstrap/less/pager.less"; -@import "../../node_modules/bootstrap/less/labels.less"; -@import "../../node_modules/bootstrap/less/badges.less"; -@import "jumbotron.less"; -@import "../../node_modules/bootstrap/less/thumbnails.less"; -@import "../../node_modules/bootstrap/less/alerts.less"; -@import "../../node_modules/bootstrap/less/progress-bars.less"; -@import "../../node_modules/bootstrap/less/media.less"; -@import "../../node_modules/bootstrap/less/list-group.less"; -@import "../../node_modules/bootstrap/less/panels.less"; -@import "../../node_modules/bootstrap/less/responsive-embed.less"; -@import "../../node_modules/bootstrap/less/wells.less"; -@import "../../node_modules/bootstrap/less/close.less"; - -// Components w/ JavaScript -@import "../../node_modules/bootstrap/less/modals.less"; -@import "../../node_modules/bootstrap/less/tooltip.less"; -@import "../../node_modules/bootstrap/less/popovers.less"; -@import "../../node_modules/bootstrap/less/carousel.less"; - -// Utility classes -@import "utilities.less"; -@import "../../node_modules/bootstrap/less/responsive-utilities.less"; diff --git a/src/styles/jumbotron.less b/src/styles/jumbotron.less @@ -1,12 +0,0 @@ -// ============================================================================= -// Jumbotron -// ============================================================================= - -@import "../../node_modules/bootstrap/less/jumbotron.less"; - -.jumbotron { - p { - text-transform: uppercase; - letter-spacing: 1px; - } -} diff --git a/src/styles/mixins.less b/src/styles/mixins.less @@ -1,5 +0,0 @@ -// ============================================================================= -// Mixins -// ============================================================================= - -@import "../../node_modules/bootstrap/less/mixins.less"; diff --git a/src/styles/navbar.less b/src/styles/navbar.less @@ -1,48 +0,0 @@ -// ============================================================================= -// Navigation Bar -// ============================================================================= - -@import "../../node_modules/bootstrap/less/navbar.less"; - -body { - padding: @navbar-height 0; - overflow-y: scroll; -} - -.navbar-top { - &:extend(.navbar); - &:extend(.navbar-inverse); - &:extend(.navbar-fixed-top); -} - -.navbar-brand { - padding-top: 8px; - padding-bottom: 8px; - color: #00d8ff !important; - font-size: 24px; - - img { - margin-right: 10px; - display: inline; - } -} - -// -// Navigation Footer -// ----------------------------------------------------------------------------- - -.navbar-footer { - &:extend(.navbar); - &:extend(.navbar-fixed-bottom); - - background-color: darken(@body-bg, 2%); - - .text-muted { - margin-top: 1em; - - span + span:before { - content: "\2022\00a0"; // Unicode space added since inline-block means non-collapsing white-space - padding: 0 3px 0 7px; - } - } -} diff --git a/src/styles/utilities.less b/src/styles/utilities.less @@ -1,16 +0,0 @@ -// ============================================================================= -// Utility classes -// ============================================================================= - -@import "../../node_modules/bootstrap/less/utilities.less"; - -// -// Browser upgrade prompt -// ----------------------------------------------------------------------------- - -.browserupgrade { - margin: 0.2em 0; - background: #ccc; - color: #000; - padding: 0.2em 0; -} diff --git a/src/styles/variables.less b/src/styles/variables.less @@ -1,25 +0,0 @@ -// ============================================================================= -// Variables -// ============================================================================= - -@import "../../node_modules/bootstrap/less/variables.less"; - -// -// Scaffolding -// ----------------------------------------------------------------------------- - -// Background color for `<body>` -@body-bg: #f9f9f9; -// Global text color on `<body>` -@text-color: #484848; -// Global textual link color -@link-color: #c05b4d; - -// -// Jumbotron -// ----------------------------------------------------------------------------- - -@jumbotron-heading-color: #61DAFB; -@jumbotron-color: #E9E9E9; -@jumbotron-bg: #2d2d2d; -@jumbotron-font-size: @font-size-base; diff --git a/src/templates/index.html b/src/templates/index.html @@ -6,9 +6,7 @@ <title><%- title %></title> <meta name="description" content="<%- description %>"> <meta name="viewport" content="width=device-width, initial-scale=1"> - <link rel="apple-touch-icon" href="apple-touch-icon.png"> - <link rel="stylesheet" href="/css/bootstrap.css"> <script src="/app.js"></script> </head> <body> diff --git a/webpack.config.js b/webpack.config.js @@ -1,6 +1,9 @@ -/*! - * Facebook React Starter Kit | https://github.com/kriasoft/react-starter-kit - * Copyright (c) KriaSoft, LLC. All rights reserved. See LICENSE.txt +/* + * React.js Starter Kit + * Copyright (c) Konstantin Tarkus (@koistya), KriaSoft LLC + * + * This source code is licensed under the MIT license found in the + * LICENSE.txt file in the root directory of this source tree. */ 'use strict';