diff --git a/.gitignore b/.gitignore index 93db56d9bc..573ee573bc 100644 --- a/.gitignore +++ b/.gitignore @@ -34,6 +34,7 @@ reports test/e2e/drivers/* package-lock.json +yarn.lock # Website dependencies website/.cache diff --git a/website/.eslintrc.js b/website/.eslintrc.js new file mode 100644 index 0000000000..6e7e4c1409 --- /dev/null +++ b/website/.eslintrc.js @@ -0,0 +1,43 @@ +module.exports = { + parser: 'babel-eslint', + env: { + browser: true, + es6: true, + node: true, + jest: true + }, + plugins: ['react', 'jest'], + rules: { + curly: ['error', 'multi-line'], + 'no-shadow': 'warn', + 'no-trailing-spaces': 'error', + 'no-undef': 'error', + 'no-underscore-dangle': 'error', + 'no-unused-expressions': 'error', + 'no-unused-vars': [ + 'error', + { + args: 'after-used', + ignoreRestSiblings: true, + vars: 'all', + }, + ], + 'object-curly-spacing': ['error', 'always'], + quotes: ['error', 'single', 'avoid-escape'], + 'react/jsx-boolean-value': 'warn', + 'react/jsx-no-undef': 'error', + 'react/jsx-uses-vars': 'error', + 'react/jsx-wrap-multilines': 'warn', + 'react/no-did-mount-set-state': 'warn', + 'react/no-did-update-set-state': 'warn', + 'react/no-unknown-property': 'warn', + 'react/react-in-jsx-scope': 'error', + 'react/self-closing-comp': 'warn', + 'react/sort-prop-types': 'warn', + 'react/react-in-jsx-scope': 'off', + semi: 'error', + strict: 'off', + 'quote-props': 'off', + }, + "extends": ["plugin:jest/recommended"] +}; diff --git a/website/components/Container.js b/website/components/Container.js index 08d94b3790..1cdd7e13bf 100644 --- a/website/components/Container.js +++ b/website/components/Container.js @@ -6,12 +6,13 @@ const styles = { boxSizing: 'border-box', marginLeft: 'auto', marginRight: 'auto', - paddingLeft: '1em', - paddingRight: '1em', + paddingLeft: '2rem', + paddingRight: '2rem', + position: 'relative', [theme.breakpoint.mediumUp]: { - paddingLeft: '2em', - paddingRight: '2em', + paddingLeft: '2rem', + paddingRight: '2rem', }, }, }; diff --git a/website/components/GithubButton.js b/website/components/GithubButton.js new file mode 100644 index 0000000000..3a3f7a1927 --- /dev/null +++ b/website/components/GithubButton.js @@ -0,0 +1,89 @@ +import React from 'react'; + +type Props = { count: number, repo: string }; + +const StarButton = ({ count, repo }: Props) => ( +
+ + + Star + + 0 ? 1 : 0, + 'padding': '0.3125rem 0.625rem', + 'position': 'relative', + 'textDecoration': 'none', + 'transition': 'opacity 200ms', + + '&:before': { + border: '4px solid transparent', + borderRightColor: 'white', + content: ' ', + height: 0, + left: -8, + top: '50%', + marginTop: -4, + position: 'absolute', + width: 0, + }, + }} + href={`${repo}/stargazers`} + target="_blank"> + {count && count.toLocaleString()} + +
+); + +export default StarButton; diff --git a/website/components/Header.js b/website/components/Header.js new file mode 100644 index 0000000000..ebb8be3d1d --- /dev/null +++ b/website/components/Header.js @@ -0,0 +1,177 @@ +import React, { Component } from 'react'; +import { compose } from 'glamor'; +import fetch from 'unfetch'; +import Link from 'gatsby-link'; +import GithubButton from './GithubButton'; +import logo from '../images/logo-inverted.svg'; +import theme from '../theme'; + +const apiUrl = 'https://api.github.com/repos/keystonejs/keystone'; + +export default class Header extends Component { + state = { stars: 0 }; + + componentDidMount () { + this.getStarCount(); + } + + getStarCount = () => { + fetch(apiUrl) + .then(res => res.json()) + .then(data => { + const stars = data.stargazers_count; + this.setState({ stars }); + }) + .catch(err => { + console.error('Error retrieving data', err); + }); + }; + render () { + return ( +
+
+ KeystoneJS + KeystoneJS +
+ +
+ +
+
+ ); + } +} + +const styles = { + navBar: { + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + color: 'white', + height: '3rem', + [theme.breakpoint.smallOnly]: { + flexWrap: 'wrap', + height: 'auto', + }, + }, + navBarSide: { + height: '3rem', + display: 'flex', + alignItems: 'center', + position: 'absolute', + top: 0, + }, + navBarSideLeft: { + left: 0, + [theme.breakpoint.mediumDown]: { + left: '2rem', + }, + }, + navBarSideRight: { + right: 0, + [theme.breakpoint.mediumDown]: { + right: '2rem', + }, + }, + navBarCenter: { + flex: 1, + listStyle: 'none', + margin: 0, + padding: 0, + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + + [theme.breakpoint.smallOnly]: { + height: '3.75rem', + alignItems: 'flex-start', + marginTop: '4rem', + flexWrap: 'noWrap', + overflowX: 'scroll', + overflowY: 'hidden', + marginLeft: '-2rem', + marginRight: '-2rem', + padding: '0 2rem', + justifyContent: 'flex-start', + webkitOverflowScrolling: 'touch', + }, + }, + navItem: { + margin: '0 0.625em', + padding: 0, + lineHeight: 1.4, + + [theme.breakpoint.smallOnly]: { + margin: '0 1.25rem 0 0', + fontSize: '1.15rem', + }, + }, + navItemLink: { + color: 'inherit', + opacity: 0.75, + textDecoration: 'none', + whiteSpace: 'noWrap', + ':hover': { + opacity: 1, + }, + }, + logo: { + height: '3rem', + margin: '0 1rem 0 0', + }, + logoText: { + fontSize: '1.3em', + }, +}; diff --git a/website/components/Navbar/Item.js b/website/components/Navbar/Item.js index 8124e2dd00..b6cfe0aacb 100644 --- a/website/components/Navbar/Item.js +++ b/website/components/Navbar/Item.js @@ -1,20 +1,21 @@ import React, { PropTypes } from 'react'; import Link from 'gatsby-link'; -export default function Item ({ depth, title, url }) { +export default function Item ({ title, url, isActive, depth }) { return ( -
  • - - {title} - -
  • + + {title} + ); -}; +} Item.propTypes = { depth: PropTypes.number.isRequired, @@ -24,18 +25,11 @@ Item.propTypes = { /* eslint quote-props: ["error", "as-needed"] */ const styles = { - // item - item: { - fontWeight: 300, - margin: '0 0 2px', - // marginLeft: '20px', - }, link: { - // borderBottomRightRadius: 3, - // borderTopRightRadius: 3, + display: 'flex', + alignItems: 'center', color: 'white', - display: 'block', - padding: `0.5em 1rem`, + padding: '0.3125rem 1rem', textDecoration: 'none', transition: 'opacity 100ms', @@ -43,13 +37,25 @@ const styles = { backgroundColor: 'rgba(255, 255, 255, 0.1)', }, }, - link__active: { + linkActive: { backgroundColor: 'rgba(0, 0, 0, 0.15)', - opacity: 1, + fontWeight: '600', + ':hover': { + backgroundColor: 'rgba(0, 0, 0, 0.15)', + }, }, - // depth - link__2: { - paddingLeft: '2rem', + depth__1: { + fontSize: '1rem', + marginLeft: '1.875rem', + marginTop: '0.3125rem', + }, + depth__2: { + fontSize: '0.85rem', + marginLeft: '2.875rem', + borderLeft: '2px solid rgba(255,255,255,0.2)', + }, + depth__2__active: { + borderColor: 'rgba(255,255,255,0.8)', }, }; diff --git a/website/components/Navbar/Menu.js b/website/components/Navbar/Menu.js index cf74bd3420..c36ec65392 100644 --- a/website/components/Navbar/Menu.js +++ b/website/components/Navbar/Menu.js @@ -1,9 +1,11 @@ -import React from 'react'; +import React, { Component } from 'react'; import { makeSection } from './utils'; import { api, documentation, gettingStarted, guides } from '../../data/navigation'; const sections = [gettingStarted, guides, documentation, api]; -export default function Menu () { - return ; +export default class Menu extends Component { + render () { + return ; + } }; diff --git a/website/components/Navbar/index.js b/website/components/Navbar/index.js index 9865be9bb9..e6f6afb35a 100644 --- a/website/components/Navbar/index.js +++ b/website/components/Navbar/index.js @@ -11,9 +11,6 @@ import theme from '../../theme'; import { itemsShape } from './utils'; import Menu from './Menu'; -import { api, documentation, gettingStarted, guides } from '../../data/navigation'; - -const sections = [gettingStarted, guides, documentation, api]; class Navbar extends Component { constructor (props) { @@ -52,7 +49,6 @@ class Navbar extends Component { GitHub - */}
    {sections.map(s => ( @@ -60,6 +56,7 @@ class Navbar extends Component { ))}
    + */}
    - +
    ); diff --git a/website/components/Navbar/utils/makeSection.js b/website/components/Navbar/utils/makeSection.js index 7c50def171..3d600fb5b2 100644 --- a/website/components/Navbar/utils/makeSection.js +++ b/website/components/Navbar/utils/makeSection.js @@ -1,56 +1,75 @@ import React from 'react'; +import Link from 'gatsby-link'; import Item from '../Item'; -export default function makeSection (currentPath, layer, depth) { +export default function makeSection (currentPath, layer, pathname) { return layer.map((section, idx) => { - const sectionStyles = depth === 1 ? styles.section : styles.subsection; + const locationArray = pathname.split('/'); + const currentSection = locationArray[locationArray.length - 1]; - return ( - + // Sections + return ( +
    + + {section.section} + + {locationArray[1] === section.slug.split('/')[1] && menuItems} +
    ); }); -}; +} const styles = { - menu: { - listStyle: 'none', - margin: 0, - // paddingRight: '1em', - }, - menu_depth_1: {}, - menu_depth_2: {}, - - section: { - fontSize: '1.7em', - margin: '1.8em 0 0.5em', - opacity: 0.6, - padding: `0 1rem`, - textTransform: 'uppercase', - }, - subsection: { - fontSize: '1.3em', - margin: '1em 0 0.2em', - opacity: 0.6, - padding: `0 1rem 0 2rem`, + sectionTitle: { + display: 'block', + color: 'white', + fontSize: '1rem', textTransform: 'uppercase', + fontWeight: '600', + textDecoration: 'none', + padding: '0.625rem 1.875rem', }, }; diff --git a/website/components/TwitterButton.js b/website/components/TwitterButton.js new file mode 100644 index 0000000000..58071de2ae --- /dev/null +++ b/website/components/TwitterButton.js @@ -0,0 +1,41 @@ +import React from 'react'; + +const TwitterButton = ({ href }) => ( +
    + + + Follow KeystoneJS + +
    +); + +export default TwitterButton; diff --git a/website/data/navigation.js b/website/data/navigation.js index 763fc91b4f..205be59708 100644 --- a/website/data/navigation.js +++ b/website/data/navigation.js @@ -1,5 +1,5 @@ export const gettingStarted = { - section: 'Starting', + section: 'Get started', slug: '/getting-started', items: [{ label: 'Getting Started', @@ -68,7 +68,7 @@ export const documentation = { slug: '/database-options', }, { label: 'Admin UI Option', - slug: '/server-options', + slug: '/admin-ui-options', }], }, { section: 'Database', diff --git a/website/gatsby-config.js b/website/gatsby-config.js index 91a824c49c..37d78fb5fe 100644 --- a/website/gatsby-config.js +++ b/website/gatsby-config.js @@ -5,26 +5,26 @@ module.exports = { plugins: [ 'gatsby-plugin-react-helmet', 'gatsby-plugin-glamor', + 'gatsby-transformer-remark', { - resolve: `gatsby-source-filesystem`, + resolve: 'gatsby-source-filesystem', options: { - name: `docs`, + name: 'docs', path: `${__dirname}/../docs`, }, }, { - resolve: `gatsby-source-filesystem`, + resolve: 'gatsby-source-filesystem', options: { - name: `fields`, + name: 'fields', path: `${__dirname}/../fields/types`, }, }, - 'gatsby-transformer-remark', { - resolve: `gatsby-plugin-typography`, - options: { - pathToConfigModule: `utils/typography`, - }, - }, + resolve: 'gatsby-plugin-typography', + options: { + pathToConfigModule: 'utils/typography', + }, + }, ], }; diff --git a/website/package.json b/website/package.json index 1364441fd5..e76a55f1c6 100644 --- a/website/package.json +++ b/website/package.json @@ -11,6 +11,7 @@ "gatsby-link": "^1.6.40", "gatsby-plugin-glamor": "^1.6.13", "gatsby-plugin-react-helmet": "^2.0.10", + "gatsby-plugin-twitter": "^1.0.20", "gatsby-plugin-typography": "^1.7.18", "gatsby-source-filesystem": "^1.5.31", "gatsby-transformer-remark": "^1.7.40", @@ -20,10 +21,12 @@ "react-helmet": "^5.2.0", "react-icons": "^2.2.7", "react-tweet-embed": "^1.1.0", + "react-twitter-widgets": "^1.7.1", "typeface-roboto": "^0.0.54", "typography": "^0.16.17", "typography-breakpoint-constants": "^0.15.10", - "typography-plugin-code": "^0.16.11" + "typography-plugin-code": "^0.16.11", + "unfetch": "^3.0.0" }, "keywords": [ "gatsby" @@ -35,5 +38,11 @@ "format": "prettier --write 'src/**/*.js'", "test": "echo \"Error: no test specified\" && exit 1" }, - "devDependencies": {} + "devDependencies": { + "babel-eslint": "^8.2.3", + "eslint": "^4.19.1", + "eslint-plugin-jest": "^21.17.0", + "eslint-plugin-react": "^7.9.1", + "prettier": "^1.13.4" + } } diff --git a/website/src/html.js b/website/src/html.js new file mode 100644 index 0000000000..0e1d0a6800 --- /dev/null +++ b/website/src/html.js @@ -0,0 +1,47 @@ +import React from 'react'; + +let stylesStr; +if (process.env.NODE_ENV === 'production') { + try { + stylesStr = require('!raw-loader!../public/styles.css'); + } catch (e) { + console.log(e); + } +} + +module.exports = class HTML extends React.Component { + render () { + let css; + if (process.env.NODE_ENV === 'production') { + css = ( +