ff-stream-web

git clone git://archive.git.mtrnord.blog/MTRNord/ff-stream-web.git
Log | Files | Refs | README | LICENSE

commit 543d650b7873fbc193aabd6e2a09a1c5123d543e
parent 3c3e18ec571a88a2f8430b4a2bacecf720f14b03
Author: Vladimir Kutepov <frenzzy.man@gmail.com>
Date:   Thu, 10 Nov 2016 21:29:13 +0400

Use class components everywhere and optimize React code automatically (#961)

Now you do not need to repeatedly rewrite your [class components to stateless functional components](https://facebook.github.io/react/docs/components-and-props.html#functional-and-class-components) and back. Just always use `class` inherited from `React.Component` or `React.PureComponent` and [transform-react-pure-class-to-function](https://github.com/thejameskyle/babel-react-optimize) plugin will automatically optimize React code by making pure classes into functions in release mode.
Diffstat:
Mpackage.json | 7+++----
Msrc/components/Feedback/Feedback.js | 32+++++++++++++++++---------------
Msrc/components/Footer/Footer.js | 32+++++++++++++++++---------------
Msrc/components/Header/Header.js | 30++++++++++++++++--------------
Msrc/components/Html.js | 79+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Msrc/components/Layout/Layout.js | 28+++++++++++++++-------------
Msrc/components/Link/Link.js | 6++----
Msrc/components/Navigation/Navigation.js | 32+++++++++++++++++---------------
Msrc/routes/admin/Admin.js | 30++++++++++++++++--------------
Msrc/routes/contact/Contact.js | 30++++++++++++++++--------------
Msrc/routes/content/Content.js | 35+++++++++++++++++++----------------
Msrc/routes/error/ErrorPage.js | 35+++++++++++++++++++----------------
Msrc/routes/home/Home.js | 58++++++++++++++++++++++++++++++----------------------------
Msrc/routes/login/Login.js | 202++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/routes/notFound/NotFound.js | 30++++++++++++++++--------------
Msrc/routes/register/Register.js | 28++++++++++++++++------------
Mtools/webpack.config.js | 23+++++++++--------------
17 files changed, 371 insertions(+), 346 deletions(-)

diff --git a/package.json b/package.json @@ -46,12 +46,10 @@ "babel-eslint": "^7.1.0", "babel-loader": "^6.2.7", "babel-plugin-rewire": "^1.0.0", - "babel-plugin-transform-react-constant-elements": "^6.9.1", - "babel-plugin-transform-react-inline-elements": "^6.8.0", - "babel-plugin-transform-react-remove-prop-types": "^0.2.10", "babel-plugin-transform-runtime": "^6.15.0", "babel-preset-latest": "^6.16.0", "babel-preset-react": "^6.16.0", + "babel-preset-react-optimize": "^1.0.1", "babel-preset-stage-0": "^6.16.0", "babel-register": "^6.18.0", "babel-template": "^6.16.0", @@ -146,7 +144,8 @@ "react/forbid-prop-types": "off", "react/jsx-filename-extension": "off", "react/no-danger": "off", - "react/no-unused-prop-types": "off" + "react/no-unused-prop-types": "off", + "react/prefer-stateless-function": "off" } }, "stylelint": { diff --git a/src/components/Feedback/Feedback.js b/src/components/Feedback/Feedback.js @@ -11,22 +11,24 @@ import React from 'react'; import withStyles from 'isomorphic-style-loader/lib/withStyles'; import s from './Feedback.css'; -function Feedback() { - return ( - <div className={s.root}> - <div className={s.container}> - <a - className={s.link} - href="https://gitter.im/kriasoft/react-starter-kit" - >Ask a question</a> - <span className={s.spacer}>|</span> - <a - className={s.link} - href="https://github.com/kriasoft/react-starter-kit/issues/new" - >Report an issue</a> +class Feedback extends React.Component { + render() { + return ( + <div className={s.root}> + <div className={s.container}> + <a + className={s.link} + href="https://gitter.im/kriasoft/react-starter-kit" + >Ask a question</a> + <span className={s.spacer}>|</span> + <a + className={s.link} + href="https://github.com/kriasoft/react-starter-kit/issues/new" + >Report an issue</a> + </div> </div> - </div> - ); + ); + } } export default withStyles(s)(Feedback); diff --git a/src/components/Footer/Footer.js b/src/components/Footer/Footer.js @@ -12,22 +12,24 @@ import withStyles from 'isomorphic-style-loader/lib/withStyles'; import s from './Footer.css'; import Link from '../Link'; -function Footer() { - return ( - <div className={s.root}> - <div className={s.container}> - <span className={s.text}>© Your Company</span> - <span className={s.spacer}>·</span> - <Link className={s.link} to="/">Home</Link> - <span className={s.spacer}>·</span> - <Link className={s.link} to="/admin">Admin</Link> - <span className={s.spacer}>·</span> - <Link className={s.link} to="/privacy">Privacy</Link> - <span className={s.spacer}>·</span> - <Link className={s.link} to="/not-found">Not Found</Link> +class Footer extends React.Component { + render() { + return ( + <div className={s.root}> + <div className={s.container}> + <span className={s.text}>© Your Company</span> + <span className={s.spacer}>·</span> + <Link className={s.link} to="/">Home</Link> + <span className={s.spacer}>·</span> + <Link className={s.link} to="/admin">Admin</Link> + <span className={s.spacer}>·</span> + <Link className={s.link} to="/privacy">Privacy</Link> + <span className={s.spacer}>·</span> + <Link className={s.link} to="/not-found">Not Found</Link> + </div> </div> - </div> - ); + ); + } } export default withStyles(s)(Footer); diff --git a/src/components/Header/Header.js b/src/components/Header/Header.js @@ -14,22 +14,24 @@ import Link from '../Link'; import Navigation from '../Navigation'; import logoUrl from './logo-small.png'; -function Header() { - return ( - <div className={s.root}> - <div className={s.container}> - <Navigation className={s.nav} /> - <Link className={s.brand} to="/"> - <img src={logoUrl} width="38" height="38" alt="React" /> - <span className={s.brandTxt}>Your Company</span> - </Link> - <div className={s.banner}> - <h1 className={s.bannerTitle}>React</h1> - <p className={s.bannerDesc}>Complex web apps made easy</p> +class Header extends React.Component { + render() { + return ( + <div className={s.root}> + <div className={s.container}> + <Navigation className={s.nav} /> + <Link className={s.brand} to="/"> + <img src={logoUrl} width="38" height="38" alt="React" /> + <span className={s.brandTxt}>Your Company</span> + </Link> + <div className={s.banner}> + <h1 className={s.bannerTitle}>React</h1> + <p className={s.bannerDesc}>Complex web apps made easy</p> + </div> </div> </div> - </div> - ); + ); + } } export default withStyles(s)(Header); diff --git a/src/components/Html.js b/src/components/Html.js @@ -10,44 +10,47 @@ import React, { PropTypes } from 'react'; import { analytics } from '../config'; -function Html({ title, description, style, script, chunk, children }) { - return ( - <html className="no-js" lang="en"> - <head> - <meta charSet="utf-8" /> - <meta httpEquiv="x-ua-compatible" content="ie=edge" /> - <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" /> - {style && <style id="css" dangerouslySetInnerHTML={{ __html: style }} />} - </head> - <body> - <div id="app" dangerouslySetInnerHTML={{ __html: children }} /> - {script && <script src={script} />} - {chunk && <script src={chunk} />} - {analytics.google.trackingId && - <script - dangerouslySetInnerHTML={{ __html: - 'window.ga=function(){ga.q.push(arguments)};ga.q=[];ga.l=+new Date;' + - `ga('create','${analytics.google.trackingId}','auto');ga('send','pageview')` }} - /> - } - {analytics.google.trackingId && - <script src="https://www.google-analytics.com/analytics.js" async defer /> - } - </body> - </html> - ); -} +class Html extends React.Component { + static propTypes = { + title: PropTypes.string.isRequired, + description: PropTypes.string.isRequired, + style: PropTypes.string, + script: PropTypes.string, + chunk: PropTypes.string, + children: PropTypes.string, + }; -Html.propTypes = { - title: PropTypes.string.isRequired, - description: PropTypes.string.isRequired, - style: PropTypes.string, - script: PropTypes.string, - chunk: PropTypes.string, - children: PropTypes.string, -}; + render() { + const { title, description, style, script, chunk, children } = this.props; + return ( + <html className="no-js" lang="en"> + <head> + <meta charSet="utf-8" /> + <meta httpEquiv="x-ua-compatible" content="ie=edge" /> + <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" /> + {style && <style id="css" dangerouslySetInnerHTML={{ __html: style }} />} + </head> + <body> + <div id="app" dangerouslySetInnerHTML={{ __html: children }} /> + {script && <script src={script} />} + {chunk && <script src={chunk} />} + {analytics.google.trackingId && + <script + dangerouslySetInnerHTML={{ __html: + 'window.ga=function(){ga.q.push(arguments)};ga.q=[];ga.l=+new Date;' + + `ga('create','${analytics.google.trackingId}','auto');ga('send','pageview')` }} + /> + } + {analytics.google.trackingId && + <script src="https://www.google-analytics.com/analytics.js" async defer /> + } + </body> + </html> + ); + } +} export default Html; diff --git a/src/components/Layout/Layout.js b/src/components/Layout/Layout.js @@ -14,19 +14,21 @@ import Header from '../Header'; import Feedback from '../Feedback'; import Footer from '../Footer'; -function Layout({ children }) { - return ( - <div> - <Header /> - {children} - <Feedback /> - <Footer /> - </div> - ); -} +class Layout extends React.Component { + static propTypes = { + children: PropTypes.node.isRequired, + }; -Layout.propTypes = { - children: PropTypes.node.isRequired, -}; + render() { + return ( + <div> + <Header /> + {this.props.children} + <Feedback /> + <Footer /> + </div> + ); + } +} export default withStyles(s)(Layout); diff --git a/src/components/Link/Link.js b/src/components/Link/Link.js @@ -7,7 +7,7 @@ * LICENSE.txt file in the root directory of this source tree. */ -import React, { Component, PropTypes } from 'react'; +import React, { PropTypes } from 'react'; import history from '../../core/history'; function isLeftClickEvent(event) { @@ -18,8 +18,7 @@ function isModifiedEvent(event) { return !!(event.metaKey || event.altKey || event.ctrlKey || event.shiftKey); } -class Link extends Component { - +class Link extends React.Component { static propTypes = { to: PropTypes.string.isRequired, children: PropTypes.node, @@ -47,7 +46,6 @@ class Link extends Component { const { to, children, ...props } = this.props; return <a href={to} {...props} onClick={this.handleClick}>{children}</a>; } - } export default Link; diff --git a/src/components/Navigation/Navigation.js b/src/components/Navigation/Navigation.js @@ -13,21 +13,23 @@ import withStyles from 'isomorphic-style-loader/lib/withStyles'; import s from './Navigation.css'; import Link from '../Link'; -function Navigation({ className }) { - return ( - <div className={cx(s.root, className)} role="navigation"> - <Link className={s.link} to="/about">About</Link> - <Link className={s.link} to="/contact">Contact</Link> - <span className={s.spacer}> | </span> - <Link className={s.link} to="/login">Log in</Link> - <span className={s.spacer}>or</span> - <Link className={cx(s.link, s.highlight)} to="/register">Sign up</Link> - </div> - ); -} +class Navigation extends React.Component { + static propTypes = { + className: PropTypes.string, + }; -Navigation.propTypes = { - className: PropTypes.string, -}; + render() { + return ( + <div className={cx(s.root, this.props.className)} role="navigation"> + <Link className={s.link} to="/about">About</Link> + <Link className={s.link} to="/contact">Contact</Link> + <span className={s.spacer}> | </span> + <Link className={s.link} to="/login">Log in</Link> + <span className={s.spacer}>or</span> + <Link className={cx(s.link, s.highlight)} to="/register">Sign up</Link> + </div> + ); + } +} export default withStyles(s)(Navigation); diff --git a/src/routes/admin/Admin.js b/src/routes/admin/Admin.js @@ -12,21 +12,23 @@ import withStyles from 'isomorphic-style-loader/lib/withStyles'; import Layout from '../../components/Layout'; import s from './Admin.css'; -function Admin({ title }) { - return ( - <Layout> - <div className={s.root}> - <div className={s.container}> - <h1>{title}</h1> - <p>...</p> +class Admin extends React.Component { + static propTypes = { + title: PropTypes.string.isRequired, + }; + + render() { + return ( + <Layout> + <div className={s.root}> + <div className={s.container}> + <h1>{this.props.title}</h1> + <p>...</p> + </div> </div> - </div> - </Layout> - ); + </Layout> + ); + } } -Admin.propTypes = { - title: PropTypes.string.isRequired, -}; - export default withStyles(s)(Admin); diff --git a/src/routes/contact/Contact.js b/src/routes/contact/Contact.js @@ -12,21 +12,23 @@ import withStyles from 'isomorphic-style-loader/lib/withStyles'; import Layout from '../../components/Layout'; import s from './Contact.css'; -function Contact({ title }) { - return ( - <Layout> - <div className={s.root}> - <div className={s.container}> - <h1>{title}</h1> - <p>...</p> +class Contact extends React.Component { + static propTypes = { + title: PropTypes.string.isRequired, + }; + + render() { + return ( + <Layout> + <div className={s.root}> + <div className={s.container}> + <h1>{this.props.title}</h1> + <p>...</p> + </div> </div> - </div> - </Layout> - ); + </Layout> + ); + } } -Contact.propTypes = { - title: PropTypes.string.isRequired, -}; - export default withStyles(s)(Contact); diff --git a/src/routes/content/Content.js b/src/routes/content/Content.js @@ -12,23 +12,26 @@ import withStyles from 'isomorphic-style-loader/lib/withStyles'; import Layout from '../../components/Layout'; import s from './Content.css'; -function Content({ path, title, content }) { - return ( - <Layout> - <div className={s.root}> - <div className={s.container}> - {title && path !== '/' && <h1>{title}</h1>} - <div dangerouslySetInnerHTML={{ __html: content }} /> +class Content extends React.Component { + static propTypes = { + path: PropTypes.string.isRequired, + content: PropTypes.string.isRequired, + title: PropTypes.string, + }; + + render() { + const { path, title, content } = this.props; + return ( + <Layout> + <div className={s.root}> + <div className={s.container}> + {title && path !== '/' && <h1>{title}</h1>} + <div dangerouslySetInnerHTML={{ __html: content }} /> + </div> </div> - </div> - </Layout> - ); + </Layout> + ); + } } -Content.propTypes = { - path: PropTypes.string.isRequired, - content: PropTypes.string.isRequired, - title: PropTypes.string, -}; - export default withStyles(s)(Content); diff --git a/src/routes/error/ErrorPage.js b/src/routes/error/ErrorPage.js @@ -11,28 +11,31 @@ import React, { PropTypes } from 'react'; import withStyles from 'isomorphic-style-loader/lib/withStyles'; import s from './ErrorPage.css'; -function ErrorPage({ error }) { - if (process.env.NODE_ENV !== 'production') { +class ErrorPage extends React.Component { + static propTypes = { + error: PropTypes.object.isRequired, + }; + + render() { + if (process.env.NODE_ENV !== 'production') { + const { error } = this.props; + return ( + <div> + <h1>{error.name}</h1> + <p>{error.message}</p> + <pre>{error.stack}</pre> + </div> + ); + } + return ( <div> - <h1>{error.name}</h1> - <p>{error.message}</p> - <pre>{error.stack}</pre> + <h1>Error</h1> + <p>Sorry, a critical error occurred on this page.</p> </div> ); } - - return ( - <div> - <h1>Error</h1> - <p>Sorry, a critical error occurred on this page.</p> - </div> - ); } -ErrorPage.propTypes = { - error: PropTypes.object.isRequired, -}; - export { ErrorPage as ErrorPageWithoutStyle }; export default withStyles(s)(ErrorPage); diff --git a/src/routes/home/Home.js b/src/routes/home/Home.js @@ -12,35 +12,37 @@ import withStyles from 'isomorphic-style-loader/lib/withStyles'; import Layout from '../../components/Layout'; import s from './Home.css'; -function Home({ news }) { - return ( - <Layout> - <div className={s.root}> - <div className={s.container}> - <h1 className={s.title}>React.js News</h1> - <ul className={s.news}> - {news.map((item, index) => ( - <li key={index} className={s.newsItem}> - <a href={item.link} className={s.newsTitle}>{item.title}</a> - <span - className={s.newsDesc} - dangerouslySetInnerHTML={{ __html: item.contentSnippet }} - /> - </li> - ))} - </ul> +class Home extends React.Component { + static propTypes = { + news: PropTypes.arrayOf(PropTypes.shape({ + title: PropTypes.string.isRequired, + link: PropTypes.string.isRequired, + contentSnippet: PropTypes.string, + })).isRequired, + }; + + render() { + return ( + <Layout> + <div className={s.root}> + <div className={s.container}> + <h1 className={s.title}>React.js News</h1> + <ul className={s.news}> + {this.props.news.map((item, index) => ( + <li key={index} className={s.newsItem}> + <a href={item.link} className={s.newsTitle}>{item.title}</a> + <span + className={s.newsDesc} + dangerouslySetInnerHTML={{ __html: item.contentSnippet }} + /> + </li> + ))} + </ul> + </div> </div> - </div> - </Layout> - ); + </Layout> + ); + } } -Home.propTypes = { - news: PropTypes.arrayOf(PropTypes.shape({ - title: PropTypes.string.isRequired, - link: PropTypes.string.isRequired, - contentSnippet: PropTypes.string, - })).isRequired, -}; - export default withStyles(s)(Home); diff --git a/src/routes/login/Login.js b/src/routes/login/Login.js @@ -12,113 +12,115 @@ import withStyles from 'isomorphic-style-loader/lib/withStyles'; import Layout from '../../components/Layout'; import s from './Login.css'; -function Login({ title }) { - return ( - <Layout> - <div className={s.root}> - <div className={s.container}> - <h1>{title}</h1> - <p className={s.lead}>Log in with your username or company email address.</p> - <div className={s.formGroup}> - <a className={s.facebook} href="/login/facebook"> - <svg - className={s.icon} - width="30" - height="30" - viewBox="0 0 30 30" - xmlns="http://www.w3.org/2000/svg" - > - <path - d="M22 16l1-5h-5V7c0-1.544.784-2 3-2h2V0h-4c-4.072 0-7 2.435-7 7v4H7v5h5v14h6V16h4z" - /> - </svg> - <span>Log in with Facebook</span> - </a> - </div> - <div className={s.formGroup}> - <a className={s.google} href="/login/google"> - <svg - className={s.icon} - width="30" - height="30" - viewBox="0 0 30 30" - xmlns="http://www.w3.org/2000/svg" - > - <path - d={'M30 13h-4V9h-2v4h-4v2h4v4h2v-4h4m-15 2s-2-1.15-2-2c0 0-.5-1.828 1-3 ' + - '1.537-1.2 3-3.035 3-5 0-2.336-1.046-5-3-6h3l2.387-1H10C5.835 0 2 3.345 2 7c0 ' + - '3.735 2.85 6.56 7.086 6.56.295 0 .58-.006.86-.025-.273.526-.47 1.12-.47 1.735 ' + - '0 1.037.817 2.042 1.523 2.73H9c-5.16 0-9 2.593-9 6 0 3.355 4.87 6 10.03 6 5.882 ' + - '0 9.97-3 9.97-7 0-2.69-2.545-4.264-5-6zm-4-4c-2.395 0-5.587-2.857-6-6C4.587 ' + - '3.856 6.607.93 9 1c2.394.07 4.603 2.908 5.017 6.052C14.43 10.195 13 13 11 ' + - '13zm-1 15c-3.566 0-7-1.29-7-4 0-2.658 3.434-5.038 7-5 .832.01 2 0 2 0 1 0 ' + - '2.88.88 4 2 1 1 1 2.674 1 3 0 3-1.986 4-7 4z'} - /> - </svg> - <span>Log in with Google</span> - </a> - </div> - <div className={s.formGroup}> - <a className={s.twitter} href="/login/twitter"> - <svg - className={s.icon} - width="30" - height="30" - viewBox="0 0 30 30" - xmlns="http://www.w3.org/2000/svg" - > - <path - d={'M30 6.708c-1.105.49-2.756 1.143-4 1.292 1.273-.762 2.54-2.56 ' + - '3-4-.97.577-2.087 1.355-3.227 1.773L25 5c-1.12-1.197-2.23-2-4-2-3.398 0-6 ' + - '2.602-6 6 0 .4.047.7.11.956L15 10C9 10 5.034 8.724 2 5c-.53.908-1 1.872-1 ' + - '3 0 2.136 1.348 3.894 3 5-1.01-.033-2.17-.542-3-1 0 2.98 4.186 6.432 7 7-1 ' + - '1-4.623.074-5 0 .784 2.447 3.31 3.95 6 4-2.105 1.648-4.647 2.51-7.53 2.51-.5 ' + - '0-.988-.03-1.47-.084C2.723 27.17 6.523 28 10 28c11.322 0 17-8.867 17-17 ' + - '0-.268.008-.736 0-1 1.2-.868 2.172-2.058 3-3.292z'} - /> - </svg> - <span>Log in with Twitter</span> - </a> - </div> - <strong className={s.lineThrough}>OR</strong> - <form method="post"> +class Login extends React.Component { + static propTypes = { + title: PropTypes.string.isRequired, + }; + + render() { + return ( + <Layout> + <div className={s.root}> + <div className={s.container}> + <h1>{this.props.title}</h1> + <p className={s.lead}>Log in with your username or company email address.</p> <div className={s.formGroup}> - <label className={s.label} htmlFor="usernameOrEmail"> - Username or email address: - </label> - <input - className={s.input} - id="usernameOrEmail" - type="text" - name="usernameOrEmail" - autoFocus - /> + <a className={s.facebook} href="/login/facebook"> + <svg + className={s.icon} + width="30" + height="30" + viewBox="0 0 30 30" + xmlns="http://www.w3.org/2000/svg" + > + <path + d="M22 16l1-5h-5V7c0-1.544.784-2 3-2h2V0h-4c-4.072 0-7 2.435-7 7v4H7v5h5v14h6V16h4z" + /> + </svg> + <span>Log in with Facebook</span> + </a> </div> <div className={s.formGroup}> - <label className={s.label} htmlFor="password"> - Password: - </label> - <input - className={s.input} - id="password" - type="password" - name="password" - /> + <a className={s.google} href="/login/google"> + <svg + className={s.icon} + width="30" + height="30" + viewBox="0 0 30 30" + xmlns="http://www.w3.org/2000/svg" + > + <path + d={'M30 13h-4V9h-2v4h-4v2h4v4h2v-4h4m-15 2s-2-1.15-2-2c0 0-.5-1.828 1-3 ' + + '1.537-1.2 3-3.035 3-5 0-2.336-1.046-5-3-6h3l2.387-1H10C5.835 0 2 3.345 2 7c0 ' + + '3.735 2.85 6.56 7.086 6.56.295 0 .58-.006.86-.025-.273.526-.47 1.12-.47 1.735 ' + + '0 1.037.817 2.042 1.523 2.73H9c-5.16 0-9 2.593-9 6 0 3.355 4.87 6 10.03 6 5.882 ' + + '0 9.97-3 9.97-7 0-2.69-2.545-4.264-5-6zm-4-4c-2.395 0-5.587-2.857-6-6C4.587 ' + + '3.856 6.607.93 9 1c2.394.07 4.603 2.908 5.017 6.052C14.43 10.195 13 13 11 ' + + '13zm-1 15c-3.566 0-7-1.29-7-4 0-2.658 3.434-5.038 7-5 .832.01 2 0 2 0 1 0 ' + + '2.88.88 4 2 1 1 1 2.674 1 3 0 3-1.986 4-7 4z'} + /> + </svg> + <span>Log in with Google</span> + </a> </div> <div className={s.formGroup}> - <button className={s.button} type="submit"> - Log in - </button> + <a className={s.twitter} href="/login/twitter"> + <svg + className={s.icon} + width="30" + height="30" + viewBox="0 0 30 30" + xmlns="http://www.w3.org/2000/svg" + > + <path + d={'M30 6.708c-1.105.49-2.756 1.143-4 1.292 1.273-.762 2.54-2.56 ' + + '3-4-.97.577-2.087 1.355-3.227 1.773L25 5c-1.12-1.197-2.23-2-4-2-3.398 0-6 ' + + '2.602-6 6 0 .4.047.7.11.956L15 10C9 10 5.034 8.724 2 5c-.53.908-1 1.872-1 ' + + '3 0 2.136 1.348 3.894 3 5-1.01-.033-2.17-.542-3-1 0 2.98 4.186 6.432 7 7-1 ' + + '1-4.623.074-5 0 .784 2.447 3.31 3.95 6 4-2.105 1.648-4.647 2.51-7.53 2.51-.5 ' + + '0-.988-.03-1.47-.084C2.723 27.17 6.523 28 10 28c11.322 0 17-8.867 17-17 ' + + '0-.268.008-.736 0-1 1.2-.868 2.172-2.058 3-3.292z'} + /> + </svg> + <span>Log in with Twitter</span> + </a> </div> - </form> + <strong className={s.lineThrough}>OR</strong> + <form method="post"> + <div className={s.formGroup}> + <label className={s.label} htmlFor="usernameOrEmail"> + Username or email address: + </label> + <input + className={s.input} + id="usernameOrEmail" + type="text" + name="usernameOrEmail" + autoFocus + /> + </div> + <div className={s.formGroup}> + <label className={s.label} htmlFor="password"> + Password: + </label> + <input + className={s.input} + id="password" + type="password" + name="password" + /> + </div> + <div className={s.formGroup}> + <button className={s.button} type="submit"> + Log in + </button> + </div> + </form> + </div> </div> - </div> - </Layout> - ); + </Layout> + ); + } } -Login.propTypes = { - title: PropTypes.string.isRequired, -}; - export default withStyles(s)(Login); diff --git a/src/routes/notFound/NotFound.js b/src/routes/notFound/NotFound.js @@ -12,21 +12,23 @@ import withStyles from 'isomorphic-style-loader/lib/withStyles'; import Layout from '../../components/Layout'; import s from './NotFound.css'; -function NotFound({ title }) { - return ( - <Layout full={false}> - <div className={s.root}> - <div className={s.container}> - <h1>{title}</h1> - <p>Sorry, the page you were trying to view does not exist.</p> +class NotFound extends React.Component { + static propTypes = { + title: PropTypes.string.isRequired, + }; + + render() { + return ( + <Layout full={false}> + <div className={s.root}> + <div className={s.container}> + <h1>{this.props.title}</h1> + <p>Sorry, the page you were trying to view does not exist.</p> + </div> </div> - </div> - </Layout> - ); + </Layout> + ); + } } -NotFound.propTypes = { - title: PropTypes.string.isRequired, -}; - export default withStyles(s)(NotFound); diff --git a/src/routes/register/Register.js b/src/routes/register/Register.js @@ -12,19 +12,23 @@ import withStyles from 'isomorphic-style-loader/lib/withStyles'; import Layout from '../../components/Layout'; import s from './Register.css'; -function Register({ title }) { - return ( - <Layout> - <div className={s.root}> - <div className={s.container}> - <h1>{title}</h1> - <p>...</p> +class Register extends React.Component { + static propTypes = { + title: PropTypes.string.isRequired, + }; + + render() { + return ( + <Layout> + <div className={s.root}> + <div className={s.container}> + <h1>{this.props.title}</h1> + <p>...</p> + </div> </div> - </div> - </Layout> - ); + </Layout> + ); + } } -Register.propTypes = { title: PropTypes.string.isRequired }; - export default withStyles(s)(Register); diff --git a/tools/webpack.config.js b/tools/webpack.config.js @@ -44,38 +44,33 @@ const config = { // https://babeljs.io/docs/usage/options/ babelrc: false, presets: [ - // JSX, Flow - // https://github.com/babel/babel/tree/master/packages/babel-preset-react - 'react', // Latest stable ECMAScript features // https://github.com/babel/babel/tree/master/packages/babel-preset-latest 'latest', // Experimental ECMAScript proposals // https://github.com/babel/babel/tree/master/packages/babel-preset-stage-0 'stage-0', + // JSX, Flow + // https://github.com/babel/babel/tree/master/packages/babel-preset-react + 'react', + ...isDebug ? [] : [ + // Optimize React code for the production build + // https://github.com/thejameskyle/babel-react-optimize + 'react-optimize', + ], ], plugins: [ // Externalise references to helpers and builtins, // automatically polyfilling your code without polluting globals. // https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-runtime 'transform-runtime', - ...isDebug ? [ + ...!isDebug ? [] : [ // Adds component stack to warning messages // https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-react-jsx-source 'transform-react-jsx-source', // Adds __self attribute to JSX which React will use for some warnings // https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-react-jsx-self 'transform-react-jsx-self', - ] : [ - // Remove unnecessary React propTypes from the production build - // https://github.com/oliviertassinari/babel-plugin-transform-react-remove-prop-types - 'transform-react-remove-prop-types', - // Treat React JSX elements as value types and hoist them to the highest scope - // https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-react-constant-elements - 'transform-react-constant-elements', - // Turn JSX elements into exploded React objects - // https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-react-inline-elements - 'transform-react-inline-elements', ], ], },