docs: convert website from postcss to emotion (#2068)
This commit is contained in:
parent
7b0838dfef
commit
3d474b1944
@ -1,46 +1,14 @@
|
||||
{
|
||||
presets: [
|
||||
"presets": ["babel-preset-gatsby"],
|
||||
"plugins": [
|
||||
[
|
||||
"@babel/preset-env",
|
||||
"prismjs",
|
||||
{
|
||||
loose: true,
|
||||
modules: false,
|
||||
useBuiltIns: "usage",
|
||||
shippedProposals: true,
|
||||
targets: {
|
||||
browsers: [">0.25%", "not dead"],
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
"@babel/preset-react",
|
||||
{
|
||||
useBuiltIns: true,
|
||||
pragma: "React.createElement",
|
||||
},
|
||||
],
|
||||
],
|
||||
plugins: [
|
||||
["prismjs", {
|
||||
"languages": ["javascript", "css", "markup", "yaml", "json"],
|
||||
"plugins": ["line-numbers"],
|
||||
"theme": "tomorrow",
|
||||
"css": true,
|
||||
}],
|
||||
[
|
||||
"@babel/plugin-proposal-class-properties",
|
||||
{
|
||||
loose: true,
|
||||
},
|
||||
],
|
||||
"@babel/plugin-syntax-dynamic-import",
|
||||
"babel-plugin-macros",
|
||||
[
|
||||
"@babel/plugin-transform-runtime",
|
||||
{
|
||||
helpers: true,
|
||||
regenerator: true,
|
||||
},
|
||||
],
|
||||
],
|
||||
"css": true
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
|
@ -1,11 +0,0 @@
|
||||
{
|
||||
"extends": [
|
||||
"stylelint-config-recommended"
|
||||
],
|
||||
"rules": {
|
||||
"at-rule-no-unknown": [true, {
|
||||
"ignoreAtRules": ["/^neat/"]
|
||||
}],
|
||||
"no-descending-specificity": null
|
||||
}
|
||||
}
|
@ -68,7 +68,6 @@ Then import it (assuming your project has tooling for imports):
|
||||
|
||||
```js
|
||||
import CMS from 'netlify-cms'
|
||||
|
||||
// Now the registry is available via the CMS object.
|
||||
CMS.registerPreviewTemplate('my-template', MyTemplate)
|
||||
```
|
||||
|
@ -19,11 +19,10 @@ To use it in your own project stored on GitHub or GitLab, follow these steps:
|
||||
|
||||
1. Head over to the [Netlify Identity docs](https://www.netlify.com/docs/identity) and follow the steps to get started.
|
||||
2. Add the following lines to your Netlify CMS `config.yml` file:
|
||||
|
||||
```yaml
|
||||
backend:
|
||||
name: git-gateway
|
||||
```
|
||||
```yaml
|
||||
backend:
|
||||
name: git-gateway
|
||||
```
|
||||
|
||||
### Reconnect after Changing Repository Permissions
|
||||
|
||||
@ -45,12 +44,11 @@ To enable basic GitHub authentication:
|
||||
|
||||
1. Follow the authentication provider setup steps in the [Netlify docs](https://www.netlify.com/docs/authentication-providers/#using-an-authentication-provider).
|
||||
2. Add the following lines to your Netlify CMS `config.yml` file:
|
||||
|
||||
```yaml
|
||||
backend:
|
||||
name: github
|
||||
repo: owner-name/repo-name # Path to your GitHub repository
|
||||
```
|
||||
```yaml
|
||||
backend:
|
||||
name: github
|
||||
repo: owner-name/repo-name # Path to your GitHub repository
|
||||
```
|
||||
|
||||
### Specifying a status for deploy previews
|
||||
The GitHub backend supports [deploy preview links](../deploy-preview-links). Netlify CMS checks the
|
||||
@ -58,7 +56,6 @@ The GitHub backend supports [deploy preview links](../deploy-preview-links). Net
|
||||
one that seems to represent a deploy preview. If you need to customize this behavior, you can
|
||||
specify which context to look for using `preview_context`:
|
||||
|
||||
|
||||
```yaml
|
||||
backend:
|
||||
name: github
|
||||
@ -87,11 +84,11 @@ To enable it:
|
||||
2. Follow the [Netlify docs](https://www.netlify.com/docs/authentication-providers/#using-an-authentication-provider) to add your new GitLab Application ID and Secret to your Netlify site dashboard.
|
||||
3. In your repository, add the following lines to your Netlify CMS `config.yml` file:
|
||||
|
||||
```yaml
|
||||
backend:
|
||||
name: gitlab
|
||||
repo: owner-name/repo-name # Path to your GitLab repository
|
||||
```
|
||||
```yaml
|
||||
backend:
|
||||
name: gitlab
|
||||
repo: owner-name/repo-name # Path to your GitLab repository
|
||||
```
|
||||
|
||||
### Client-Side Implicit Grant (GitLab)
|
||||
|
||||
|
@ -215,20 +215,15 @@ Assuming you have the netlify-cms package installed to your project, manual init
|
||||
```js
|
||||
// This global flag enables manual initialization.
|
||||
window.CMS_MANUAL_INIT = true
|
||||
|
||||
// Usage with import from npm package
|
||||
import CMS, { init } from 'netlify-cms'
|
||||
|
||||
// Usage with script tag
|
||||
const { CMS, initCMS: init } = window
|
||||
|
||||
/**
|
||||
* Initialize without passing in config - equivalent to just importing
|
||||
* Netlify CMS the old way.
|
||||
*/
|
||||
|
||||
init()
|
||||
|
||||
/**
|
||||
* Optionally pass in a config object. This object will be merged into
|
||||
* `config.yml` if it exists, and any portion that conflicts with
|
||||
@ -239,7 +234,6 @@ init()
|
||||
* your `config.yml` can be missing its backend property, allowing you
|
||||
* to set this property at runtime.
|
||||
*/
|
||||
|
||||
init({
|
||||
config: {
|
||||
backend: {
|
||||
@ -247,7 +241,6 @@ init({
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
/**
|
||||
* Optionally pass in a complete config object and set a flag
|
||||
* (`load_config_file: false`) to ignore the `config.yml`.
|
||||
@ -257,7 +250,6 @@ init({
|
||||
* It is not required if the `config.yml` file is missing to set
|
||||
* `load_config_file`, but will improve performance and avoid a load error.
|
||||
*/
|
||||
|
||||
init({
|
||||
config: {
|
||||
backend: {
|
||||
@ -276,7 +268,6 @@ init({
|
||||
],
|
||||
},
|
||||
})
|
||||
|
||||
// The registry works as expected, and can be used before or after init.
|
||||
CMS.registerPreviewTemplate(...);
|
||||
```
|
||||
@ -292,7 +283,6 @@ CMS.registerPreviewTemplate(...);
|
||||
*/
|
||||
import CMS from 'netlify-cms';
|
||||
import styles from '!css-loader!sass-loader!../main.scss'
|
||||
|
||||
CMS.registerPreviewStyle(styles.toString(), { raw: true })
|
||||
```
|
||||
|
||||
|
@ -17,7 +17,7 @@ You can [sign up for Cloudinary](https://cloudinary.com/users/register/free) for
|
||||
|
||||
To use the Cloudinary media library within Netlify CMS, you'll need to update your Netlify CMS configuration file with the information from your Cloudinary account:
|
||||
|
||||
```yml
|
||||
```yaml
|
||||
media_library:
|
||||
name: cloudinary
|
||||
config:
|
||||
@ -70,17 +70,17 @@ Global configuration, which is meant to affect the Cloudinary widget at all time
|
||||
as seen below, under the primary `media_library` property. Settings applied here will affect every
|
||||
instance of the Cloudinary widget.
|
||||
|
||||
```yml
|
||||
```yaml
|
||||
# global
|
||||
media_library:
|
||||
name: cloudinary
|
||||
output_filename_only: false
|
||||
config:
|
||||
default_transformations:
|
||||
- - fetch_format: auto
|
||||
width: 160
|
||||
quality: auto
|
||||
crop: scale
|
||||
- - fetch_format: auto
|
||||
width: 160
|
||||
quality: auto
|
||||
crop: scale
|
||||
```
|
||||
|
||||
#### Field configuration
|
||||
@ -89,22 +89,22 @@ Configuration can also be provided for individual fields that use the media libr
|
||||
is very similar to the global configuration, except the settings are added to an individual `field`.
|
||||
For example:
|
||||
|
||||
```yml
|
||||
```yaml
|
||||
# field
|
||||
fields: # The fields each document in this collection have
|
||||
- label: 'Cover Image'
|
||||
name: 'image'
|
||||
widget: 'image'
|
||||
required: false
|
||||
tagname: ''
|
||||
media_library:
|
||||
config:
|
||||
default_transformations:
|
||||
- - fetch_format: auto
|
||||
width: 300
|
||||
quality: auto
|
||||
crop: fill
|
||||
effect: grayscale
|
||||
- label: 'Cover Image'
|
||||
name: 'image'
|
||||
widget: 'image'
|
||||
required: false
|
||||
tagname: ''
|
||||
media_library:
|
||||
config:
|
||||
default_transformations:
|
||||
- fetch_format: auto
|
||||
width: 300
|
||||
quality: auto
|
||||
crop: fill
|
||||
effect: grayscale
|
||||
```
|
||||
|
||||
## Inserting Cloudinary URL in page templates
|
||||
@ -113,24 +113,22 @@ If you prefer to provide direction so that images are transformed in a specific
|
||||
|
||||
* Either globally or for specific fields, configure the Cloudinary extension to only output the asset filename
|
||||
|
||||
```yml
|
||||
# global
|
||||
media_library:
|
||||
name: cloudinary
|
||||
output_filename_only: true
|
||||
|
||||
# field
|
||||
media_library:
|
||||
name: cloudinary
|
||||
output_filename_only: true
|
||||
```
|
||||
```yaml
|
||||
# global
|
||||
media_library:
|
||||
name: cloudinary
|
||||
output_filename_only: true
|
||||
# field
|
||||
media_library:
|
||||
name: cloudinary
|
||||
output_filename_only: true
|
||||
```
|
||||
|
||||
* Provide a dynamic URL in the site template
|
||||
|
||||
```hbs
|
||||
{{! handlebars example }}
|
||||
|
||||
<img src="https://res.cloudinary.com/<cloud_name>/<resource_type>/<type>/<transformations>/{{image}}"/>
|
||||
```
|
||||
```handlebars
|
||||
{{! handlebars example }}
|
||||
<img src="https://res.cloudinary.com/<cloud_name>/<resource_type>/<type>/<transformations>/{{image}}"/>
|
||||
```
|
||||
|
||||
Your dynamic URL can be formed conditionally to provide any desired transformations - please see Cloudinary's [image transformation reference](https://cloudinary.com/documentation/image_transformation_reference) for available transformations.
|
||||
|
@ -9,7 +9,6 @@ Alternatively, you can specify a custom config file using a link tag:
|
||||
|
||||
```html
|
||||
<!-- Note the "type" and "rel" attribute values, which are required. -->
|
||||
|
||||
<link href="path/to/config.yml" type="text/yaml" rel="cms-config-url">
|
||||
```
|
||||
|
||||
|
@ -49,7 +49,7 @@ to a post in your repo may look like `content/blog/2018-01-new-post.md`, but the
|
||||
on your site would look more like: `/blog/2018-01-new-post/`. Here's how you would use
|
||||
`preview_path` in your configuration for this scenario:
|
||||
|
||||
```yml
|
||||
```yaml
|
||||
collections:
|
||||
- name: blog
|
||||
folder: content/blog
|
||||
@ -65,9 +65,8 @@ template, `{{slug}}` is only the url-safe [identifier
|
||||
field](../configuration-options/#identifier_field), while in the `preview_path` template, `{{slug}}`
|
||||
is the entire slug for the entry. For example:
|
||||
|
||||
```yml
|
||||
```yaml
|
||||
# for an entry created Jan 1, 2000 with identifier "My New Post!"
|
||||
|
||||
collections:
|
||||
- name: posts
|
||||
slug: {{year}}-{{month}}-{{slug}} # {{slug}} will compile to "my-new-post"
|
||||
@ -91,7 +90,6 @@ through static site generators.
|
||||
|
||||
```yaml
|
||||
# This collection's date field will be inferred because it has a field named `"date"`
|
||||
|
||||
collections:
|
||||
- name: posts
|
||||
preview_path: blog/{{year}}/{{month}}/{{title}}
|
||||
@ -99,9 +97,7 @@ collections:
|
||||
- { name: title, label: Title }
|
||||
{ name: date, label: Date, widget: date }
|
||||
{ name: body, label: Body, widget: markdown }
|
||||
|
||||
# This collection requires `path_preview_date_field` because the no obvious date field is available
|
||||
|
||||
collections:
|
||||
- name: posts
|
||||
preview_path: blog/{{year}}/{{month}}/{{title}}
|
||||
|
@ -70,7 +70,7 @@ module.exports = {
|
||||
},
|
||||
'gatsby-transformer-yaml',
|
||||
'gatsby-transformer-json',
|
||||
'gatsby-plugin-postcss',
|
||||
'gatsby-plugin-emotion',
|
||||
'gatsby-plugin-react-helmet',
|
||||
'gatsby-plugin-catch-links',
|
||||
{
|
||||
@ -80,7 +80,7 @@ module.exports = {
|
||||
},
|
||||
},
|
||||
{
|
||||
resolve: `gatsby-plugin-manifest`,
|
||||
resolve: 'gatsby-plugin-manifest',
|
||||
options: {
|
||||
name: 'NetlifyCMS',
|
||||
short_name: 'NetlifyCMS',
|
||||
|
@ -1,8 +1,8 @@
|
||||
const path = require('path');
|
||||
const { createFilePath } = require('gatsby-source-filesystem');
|
||||
|
||||
exports.createPages = async ({ graphql, boundActionCreators }) => {
|
||||
const { createPage } = boundActionCreators;
|
||||
exports.createPages = async ({ graphql, actions }) => {
|
||||
const { createPage } = actions;
|
||||
|
||||
const docPage = path.resolve('./src/templates/doc-page.js');
|
||||
const blogPost = path.resolve('./src/templates/blog-post.js');
|
||||
@ -51,8 +51,8 @@ exports.createPages = async ({ graphql, boundActionCreators }) => {
|
||||
|
||||
const pad = n => (n >= 10 ? n : `0${n}`);
|
||||
|
||||
exports.onCreateNode = ({ node, boundActionCreators, getNode }) => {
|
||||
const { createNodeField } = boundActionCreators;
|
||||
exports.onCreateNode = ({ node, actions, getNode }) => {
|
||||
const { createNodeField } = actions;
|
||||
|
||||
if (node.internal.type === 'MarkdownRemark') {
|
||||
const value = createFilePath({ node, getNode });
|
||||
|
@ -13,38 +13,38 @@
|
||||
"homepage": "https://www.netlifycms.org/",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"classnames": "^2.2.5",
|
||||
"dayjs": "^1.7.5",
|
||||
"gatsby": "next",
|
||||
"gatsby-plugin-catch-links": "next",
|
||||
"gatsby-plugin-manifest": "next",
|
||||
"gatsby-plugin-netlify-cms": "^3.0.0-rc.1",
|
||||
"gatsby-plugin-postcss": "^1.0.0",
|
||||
"gatsby-plugin-react-helmet": "next",
|
||||
"gatsby-remark-autolink-headers": "next",
|
||||
"gatsby-remark-prismjs": "next",
|
||||
"gatsby-source-filesystem": "next",
|
||||
"gatsby-transformer-json": "next",
|
||||
"gatsby-transformer-remark": "next",
|
||||
"gatsby-transformer-yaml": "next",
|
||||
"github-buttons": "git+https://github.com/ntkme/github-buttons.git",
|
||||
"lodash": "^4.17.13",
|
||||
"netlify-cms": "^2.0.11",
|
||||
"postcss-at2x": "^2.0.0",
|
||||
"postcss-cssnext": "^2.7.0",
|
||||
"postcss-neat": "^2.5.2",
|
||||
"postcss-nested": "^1.0.0",
|
||||
"postcss-simple-extend": "^1.0.0",
|
||||
"postcss-simple-vars-async": "^1.2.1",
|
||||
"prismjs": "^1.15.0",
|
||||
"react": "^16.4.2",
|
||||
"react-dom": "^16.4.2",
|
||||
"react-helmet": "^5.2.0",
|
||||
"react-markdown": "^3.3.2",
|
||||
"smooth-scroll": "^14.2.0"
|
||||
"@emotion/core": "^10.0.27",
|
||||
"@emotion/styled": "^10.0.27",
|
||||
"dayjs": "^1.8.19",
|
||||
"emotion-theming": "^10.0.27",
|
||||
"gatsby": "2.19.3",
|
||||
"gatsby-plugin-catch-links": "2.1.24",
|
||||
"gatsby-plugin-emotion": "^4.1.21",
|
||||
"gatsby-plugin-manifest": "2.2.38",
|
||||
"gatsby-plugin-netlify-cms": "^4.1.37",
|
||||
"gatsby-plugin-react-helmet": "3.1.21",
|
||||
"gatsby-remark-autolink-headers": "2.1.23",
|
||||
"gatsby-remark-prismjs": "3.3.30",
|
||||
"gatsby-source-filesystem": "2.1.46",
|
||||
"gatsby-transformer-json": "2.2.25",
|
||||
"gatsby-transformer-remark": "2.6.48",
|
||||
"gatsby-transformer-yaml": "2.2.23",
|
||||
"lodash": "^4.17.15",
|
||||
"moment": "^2.24.0",
|
||||
"netlify-cms": "^2.10.11",
|
||||
"prismjs": "^1.19.0",
|
||||
"react": "^16.12.0",
|
||||
"react-dom": "^16.12.0",
|
||||
"react-github-btn": "^1.1.1",
|
||||
"react-helmet": "^5.2.1",
|
||||
"react-markdown": "^4.3.1",
|
||||
"smooth-scroll": "^16.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-plugin-prismjs": "^1.0.2"
|
||||
"babel-plugin-prismjs": "^2.0.1",
|
||||
"babel-preset-gatsby": "^0.2.27",
|
||||
"eslint": "^6.8.0",
|
||||
"eslint-plugin-import": "^2.20.0"
|
||||
},
|
||||
"private": true
|
||||
}
|
||||
|
@ -1,19 +0,0 @@
|
||||
const neatgrid = require('postcss-neat');
|
||||
const nestedcss = require('postcss-nested');
|
||||
// const colorfunctions = require('postcss-colour-functions');
|
||||
const hdBackgrounds = require('postcss-at2x');
|
||||
const cssextend = require('postcss-simple-extend');
|
||||
const cssvars = require('postcss-simple-vars-async');
|
||||
|
||||
const styleVariables = require('./src/theme');
|
||||
|
||||
module.exports = () => ({
|
||||
plugins: [
|
||||
neatgrid(),
|
||||
nestedcss(),
|
||||
// colorfunctions(),
|
||||
hdBackgrounds(),
|
||||
cssextend(),
|
||||
cssvars({ variables: styleVariables }),
|
||||
],
|
||||
});
|
@ -5,16 +5,9 @@ import Prism from 'prismjs';
|
||||
import { BlogPostTemplate } from '../templates/blog-post';
|
||||
import { DocsTemplate } from '../templates/doc-page';
|
||||
import WidgetDoc from '../components/widget-doc';
|
||||
import Release from '../components/release';
|
||||
import WhatsNew from '../components/whats-new';
|
||||
import Notification from '../components/notification';
|
||||
import Community from '../components/community';
|
||||
import '../css/imports/hero.css';
|
||||
import '../css/imports/docs.css';
|
||||
import '../css/imports/whatsnew.css';
|
||||
import '../css/imports/header.css';
|
||||
import '../css/imports/collab.css';
|
||||
import '../css/imports/community.css';
|
||||
|
||||
const withHighlight = WrappedComponent =>
|
||||
class Highlight extends React.Component {
|
||||
@ -70,16 +63,15 @@ const WidgetDocPreview = ({ entry, widgetFor }) => (
|
||||
);
|
||||
|
||||
const ReleasePreview = ({ entry }) => (
|
||||
<WhatsNew>
|
||||
{entry.getIn(['data', 'updates']).map((release, idx) => (
|
||||
<Release
|
||||
key={idx}
|
||||
version={release.get('version')}
|
||||
date={dayjs(release.get('date')).format('MMMM D, YYYY')}
|
||||
description={release.get('description')}
|
||||
/>
|
||||
))}
|
||||
</WhatsNew>
|
||||
<WhatsNew
|
||||
updates={[
|
||||
entry.getIn(['data', 'updates']).map(release => ({
|
||||
version: release.get('version'),
|
||||
date: dayjs(release.get('date')).format('MMMM D, YYYY'),
|
||||
description: release.get('description'),
|
||||
})),
|
||||
]}
|
||||
/>
|
||||
);
|
||||
|
||||
const NotificationPreview = ({ entry }) =>
|
||||
|
34
website/src/components/button.js
Normal file
34
website/src/components/button.js
Normal file
@ -0,0 +1,34 @@
|
||||
import { css } from '@emotion/core';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import theme from '../theme';
|
||||
|
||||
// prettier-ignore
|
||||
const Button = styled.button`
|
||||
display: inline-block;
|
||||
background-image: linear-gradient(0deg, #97bf2f 14%, #c9fa4b 94%);
|
||||
color: ${theme.colors.darkGray};
|
||||
border-radius: ${theme.radii[1]};
|
||||
font-size: ${theme.fontsize[3]};
|
||||
font-weight: 700;
|
||||
padding: ${theme.space[2]} ${theme.space[3]};
|
||||
border: 2px solid ${theme.colors.darkGreen};
|
||||
cursor: pointer;
|
||||
|
||||
${p => p.block && css`
|
||||
display: block;
|
||||
width: 100%;
|
||||
`};
|
||||
|
||||
${p => p.outline && css`
|
||||
background: none;
|
||||
font-weight: 500;
|
||||
`};
|
||||
|
||||
${p => p.active && css`
|
||||
background: ${theme.colors.darkGreen};
|
||||
color: white;
|
||||
`};
|
||||
`;
|
||||
|
||||
export default Button;
|
18
website/src/components/chat-button.js
Normal file
18
website/src/components/chat-button.js
Normal file
@ -0,0 +1,18 @@
|
||||
import React from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
const ChatLink = styled.a`
|
||||
z-index: 100;
|
||||
position: fixed;
|
||||
bottom: 10px;
|
||||
right: 10px;
|
||||
cursor: pointer;
|
||||
`;
|
||||
|
||||
const ChatButton = () => (
|
||||
<ChatLink href="/chat">
|
||||
<img src="/img/slack.svg" />
|
||||
</ChatLink>
|
||||
);
|
||||
|
||||
export default ChatButton;
|
56
website/src/components/community-channels-list.js
Normal file
56
website/src/components/community-channels-list.js
Normal file
@ -0,0 +1,56 @@
|
||||
import React from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
import theme from '../theme';
|
||||
|
||||
const StyledCommunityChannelsList = styled.ul`
|
||||
margin-left: 0;
|
||||
|
||||
li {
|
||||
list-style-type: none;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
a {
|
||||
display: block;
|
||||
font-weight: inherit;
|
||||
position: relative;
|
||||
|
||||
&:focus,
|
||||
&:active,
|
||||
&:hover {
|
||||
&:before {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
&:before {
|
||||
display: none;
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 3px;
|
||||
height: 100%;
|
||||
background-color: ${theme.colors.darkGreen};
|
||||
left: -16px;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
color: ${theme.colors.gray};
|
||||
margin-bottom: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
const CommunityChannelsList = ({ channels }) => (
|
||||
<StyledCommunityChannelsList>
|
||||
{channels.map(({ title, description, url }, idx) => (
|
||||
<li key={idx}>
|
||||
<a href={url}>
|
||||
<strong>{title}</strong>
|
||||
<p>{description}</p>
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</StyledCommunityChannelsList>
|
||||
);
|
||||
|
||||
export default CommunityChannelsList;
|
32
website/src/components/container.js
Normal file
32
website/src/components/container.js
Normal file
@ -0,0 +1,32 @@
|
||||
import styled from '@emotion/styled';
|
||||
import { css } from '@emotion/core';
|
||||
|
||||
import { mq } from '../utils';
|
||||
import theme from '../theme';
|
||||
|
||||
const Container = styled.div`
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
max-width: 1280px;
|
||||
padding-left: ${theme.space[4]};
|
||||
padding-right: ${theme.space[4]};
|
||||
|
||||
${p =>
|
||||
p.size === 'sm' &&
|
||||
css`
|
||||
max-width: 800px;
|
||||
`};
|
||||
|
||||
${p =>
|
||||
p.size === 'md' &&
|
||||
css`
|
||||
max-width: 1024px;
|
||||
`};
|
||||
|
||||
${mq[3]} {
|
||||
padding-left: ${theme.space[5]};
|
||||
padding-right: ${theme.space[5]};
|
||||
}
|
||||
`;
|
||||
|
||||
export default Container;
|
@ -1,67 +1,101 @@
|
||||
import React, { Component } from 'react';
|
||||
import Link from 'gatsby-link';
|
||||
import React, { useState } from 'react';
|
||||
import { Link } from 'gatsby';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
/**
|
||||
* Manually get table of contents since tableOfContents from markdown
|
||||
* nodes have code added.
|
||||
*
|
||||
* https://github.com/gatsbyjs/gatsby/issues/5436
|
||||
*/
|
||||
class TableOfContents extends Component {
|
||||
state = {
|
||||
headings: [],
|
||||
import Button from './button';
|
||||
import TableOfContents from './table-of-contents';
|
||||
import { mq } from '../utils';
|
||||
import theme from '../theme';
|
||||
|
||||
const Menu = styled.nav`
|
||||
margin-bottom: ${theme.space[5]};
|
||||
`;
|
||||
|
||||
const MenuBtn = styled(Button)`
|
||||
${mq[1]} {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
|
||||
const MenuContent = styled.div`
|
||||
display: ${p => (p.isOpen ? 'block' : 'none')};
|
||||
background: white;
|
||||
padding: ${theme.space[3]};
|
||||
|
||||
${mq[1]} {
|
||||
display: block;
|
||||
background: transparent;
|
||||
padding: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
const MenuSection = styled.div`
|
||||
margin-bottom: ${theme.space[3]};
|
||||
`;
|
||||
|
||||
const SectionTitle = styled.h3`
|
||||
font-size: ${theme.fontsize[4]};
|
||||
margin-bottom: ${theme.space[2]};
|
||||
`;
|
||||
|
||||
const SectionList = styled.ul``;
|
||||
|
||||
const MenuItem = styled.li``;
|
||||
|
||||
const NavLink = styled(Link)`
|
||||
display: block;
|
||||
/* font-weight: $regular; */
|
||||
font-size: ${theme.fontsize[3]};
|
||||
color: ${theme.colors.gray};
|
||||
line-height: ${theme.lineHeight[1]};
|
||||
text-transform: capitalize;
|
||||
transition: color 0.2s ease;
|
||||
padding: ${theme.space[2]} 0;
|
||||
|
||||
&.active {
|
||||
color: ${theme.colors.darkGreen};
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: ${theme.colors.darkGreen};
|
||||
}
|
||||
`;
|
||||
|
||||
const DocsNav = ({ items, location }) => {
|
||||
const [isMenuOpen, setMenuOpen] = useState(false);
|
||||
|
||||
const toggleMenu = () => {
|
||||
setMenuOpen(isOpen => !isOpen);
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
const contentHeadings = document.querySelectorAll('.docs-content h2');
|
||||
|
||||
const headings = [];
|
||||
contentHeadings.forEach(h => {
|
||||
headings.push({
|
||||
id: h.id,
|
||||
text: h.innerText,
|
||||
});
|
||||
});
|
||||
|
||||
this.setState({
|
||||
headings,
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { headings } = this.state;
|
||||
return (
|
||||
<ul className="nav-subsections">
|
||||
{headings.map(h => (
|
||||
<li key={h.id}>
|
||||
<a href={`#${h.id}`} className="subnav-link">
|
||||
{h.text}
|
||||
</a>
|
||||
</li>
|
||||
return (
|
||||
<Menu>
|
||||
<MenuBtn onClick={toggleMenu} block>
|
||||
{isMenuOpen ? <span>×</span> : <span>☰</span>} {isMenuOpen ? 'Hide' : 'Show'}{' '}
|
||||
Navigation
|
||||
</MenuBtn>
|
||||
<MenuContent isOpen={isMenuOpen}>
|
||||
{items.map(item => (
|
||||
<MenuSection key={item.title}>
|
||||
<SectionTitle>{item.title}</SectionTitle>
|
||||
<SectionList>
|
||||
{item.group.edges.map(({ node }) => (
|
||||
<MenuItem key={node.fields.slug}>
|
||||
<NavLink to={node.fields.slug} activeClassName="active">
|
||||
{node.frontmatter.title}
|
||||
</NavLink>
|
||||
{location.pathname === node.fields.slug && <TableOfContents />}
|
||||
</MenuItem>
|
||||
))}
|
||||
</SectionList>
|
||||
</MenuSection>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const DocsNav = ({ items, location }) => (
|
||||
<nav className="docs-nav" id="docs-nav">
|
||||
{items.map(item => (
|
||||
<div className="docs-nav-section" key={item.title}>
|
||||
<div className="docs-nav-section-title">{item.title}</div>
|
||||
<ul className="docs-nav-section-list">
|
||||
{item.group.edges.map(({ node }) => (
|
||||
<li className="docs-nav-item" key={node.fields.slug}>
|
||||
<Link to={node.fields.slug} className="nav-link" activeClassName="active">
|
||||
{node.frontmatter.title}
|
||||
</Link>
|
||||
{location.pathname === node.fields.slug && <TableOfContents />}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
))}
|
||||
</nav>
|
||||
);
|
||||
</MenuContent>
|
||||
</Menu>
|
||||
);
|
||||
};
|
||||
|
||||
export default DocsNav;
|
||||
|
||||
export { NavLink };
|
||||
|
@ -1,35 +1,56 @@
|
||||
import React, { Component } from 'react';
|
||||
import React, { useState, useEffect, memo } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import theme from '../theme';
|
||||
import searchIcon from '../img/search.svg';
|
||||
|
||||
class DocSearch extends Component {
|
||||
state = {
|
||||
enabled: true,
|
||||
};
|
||||
componentDidMount() {
|
||||
const SearchForm = styled.form`
|
||||
> span {
|
||||
width: 100%;
|
||||
}
|
||||
`;
|
||||
|
||||
const SearchField = styled.input`
|
||||
color: white;
|
||||
font-size: ${theme.fontsize[3]};
|
||||
border-radius: ${theme.radii[1]};
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
background-image: url(${searchIcon});
|
||||
background-repeat: no-repeat;
|
||||
background-position: ${theme.space[2]} 50%;
|
||||
border: 0;
|
||||
appearance: none;
|
||||
width: 100%;
|
||||
padding: ${theme.space[2]};
|
||||
padding-left: 30px;
|
||||
outline: 0;
|
||||
`;
|
||||
|
||||
const DocSearch = () => {
|
||||
const [enabled, setEnabled] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
if (window.docsearch) {
|
||||
window.docsearch({
|
||||
apiKey: '08d03dc80862e84c70c5a1e769b13019',
|
||||
indexName: 'netlifycms',
|
||||
inputSelector: '.algolia-search',
|
||||
inputSelector: '#algolia-search',
|
||||
debug: false, // Set debug to true if you want to inspect the dropdown
|
||||
});
|
||||
} else {
|
||||
this.setState({ enabled: false });
|
||||
}
|
||||
}
|
||||
render() {
|
||||
if (!this.state.enabled) {
|
||||
return null;
|
||||
setEnabled(false);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className="utility-input">
|
||||
<img src={searchIcon} alt="" />
|
||||
<input type="search" placeholder="Search the docs" className="algolia-search" />
|
||||
</div>
|
||||
);
|
||||
if (!enabled) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export default DocSearch;
|
||||
return (
|
||||
<SearchForm>
|
||||
<SearchField type="search" placeholder="Search the docs" id="algolia-search" />
|
||||
</SearchForm>
|
||||
);
|
||||
};
|
||||
|
||||
export default memo(DocSearch);
|
||||
|
@ -1,32 +1,44 @@
|
||||
import React from 'react';
|
||||
import { css } from '@emotion/core';
|
||||
|
||||
const EditLink = ({ path }) => (
|
||||
<a
|
||||
className="edit-this-page"
|
||||
href={`https://github.com/netlify/netlify-cms/blob/master/website/content/${path}`}
|
||||
<div
|
||||
css={css`
|
||||
float: right;
|
||||
|
||||
a {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
#pencil {
|
||||
fill: #7ca511;
|
||||
}
|
||||
`}
|
||||
>
|
||||
<svg
|
||||
version="1.1"
|
||||
id="pencil"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="14px"
|
||||
height="14px"
|
||||
viewBox="0 0 512 512"
|
||||
enableBackground="new 0 0 512 512"
|
||||
xmlSpace="preserve"
|
||||
>
|
||||
<path
|
||||
d="M398.875,248.875L172.578,475.187l-22.625-22.625L376.25,226.265L398.875,248.875z M308.375,158.39L82.063,384.687
|
||||
<a href={`https://github.com/netlify/netlify-cms/blob/master/website/content/${path}`}>
|
||||
<svg
|
||||
version="1.1"
|
||||
id="pencil"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="14px"
|
||||
height="14px"
|
||||
viewBox="0 0 512 512"
|
||||
enableBackground="new 0 0 512 512"
|
||||
xmlSpace="preserve"
|
||||
>
|
||||
<path
|
||||
d="M398.875,248.875L172.578,475.187l-22.625-22.625L376.25,226.265L398.875,248.875z M308.375,158.39L82.063,384.687
|
||||
l45.266,45.25L353.625,203.64L308.375,158.39z M263.094,113.125L36.828,339.437l22.625,22.625L285.75,135.765L263.094,113.125z
|
||||
M308.375,67.875L285.719,90.5L421.5,226.265l22.625-22.625L308.375,67.875z M376.25,0L331,45.25l135.75,135.766L512,135.781
|
||||
L376.25,0z M32,453.5V480h26.5L32,453.5 M0,376.25L135.766,512H0V376.25L0,376.25z"
|
||||
/>
|
||||
</svg>{' '}
|
||||
Edit this page
|
||||
</a>
|
||||
/>
|
||||
</svg>{' '}
|
||||
Edit this page
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default EditLink;
|
||||
|
126
website/src/components/event-box.js
Normal file
126
website/src/components/event-box.js
Normal file
@ -0,0 +1,126 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import moment from 'moment';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import Markdownify from './markdownify';
|
||||
|
||||
import theme from '../theme';
|
||||
|
||||
const Root = styled.div`
|
||||
text-align: center;
|
||||
background: ${theme.colors.darkerGray};
|
||||
background-image: linear-gradient(
|
||||
-17deg,
|
||||
${theme.colors.darkerGray} 17%,
|
||||
${theme.colors.darkGray} 94%
|
||||
);
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
|
||||
padding: 24px;
|
||||
padding-top: 40px;
|
||||
max-width: 446px;
|
||||
`;
|
||||
|
||||
const Title = styled.h2`
|
||||
font-size: 36px;
|
||||
color: white;
|
||||
`;
|
||||
|
||||
const Cal = styled.div`
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.5);
|
||||
margin: 24px auto;
|
||||
max-width: 250px;
|
||||
`;
|
||||
|
||||
const Month = styled.div`
|
||||
background: ${theme.colors.green};
|
||||
color: ${theme.colors.gray};
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 4px;
|
||||
font-size: 14px;
|
||||
padding: 8px;
|
||||
`;
|
||||
|
||||
const Day = styled.div`
|
||||
font-size: 104px;
|
||||
line-height: 1.3;
|
||||
font-weight: bold;
|
||||
color: white;
|
||||
border: 1px solid ${theme.colors.gray};
|
||||
border-top: none;
|
||||
border-bottom-left-radius: 8px;
|
||||
border-bottom-right-radius: 8px;
|
||||
`;
|
||||
|
||||
const CalDates = styled.p`
|
||||
color: white;
|
||||
font-weight: bold;
|
||||
font-size: ${theme.fontsize[4]};
|
||||
margin-bottom: ${theme.space[3]};
|
||||
`;
|
||||
|
||||
const CalCta = styled.div``;
|
||||
|
||||
const EventBox = ({ title, cta }) => {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [eventDate, setEventDate] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
const eventbriteToken = 'C5PX65CJBVIXWWLNFKLO';
|
||||
const eventbriteOrganiser = '14281996019';
|
||||
|
||||
const url = `https://www.eventbriteapi.com/v3/events/search/?token=${eventbriteToken}&organizer.id=${eventbriteOrganiser}&expand=venue%27`;
|
||||
|
||||
fetch(url)
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
const eventDate = data.events[0].start.utc;
|
||||
|
||||
setEventDate(eventDate);
|
||||
setLoading(false);
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err); // eslint-disable-line no-console
|
||||
// TODO: set state to show error message
|
||||
|
||||
setLoading(false);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const eventDateMoment = moment(eventDate);
|
||||
|
||||
const offset = eventDateMoment.isDST() ? -7 : -8;
|
||||
const month = eventDateMoment.format('MMMM');
|
||||
const day = eventDateMoment.format('DD');
|
||||
const datePrefix = eventDateMoment.format('dddd, MMMM Do');
|
||||
const dateSuffix = eventDateMoment.utcOffset(offset).format('h a');
|
||||
|
||||
const ellip = <span>…</span>;
|
||||
|
||||
return (
|
||||
<Root>
|
||||
<Title>{title}</Title>
|
||||
<Cal>
|
||||
<Month>{loading ? 'loading' : month}</Month>
|
||||
<Day>{loading ? ellip : day}</Day>
|
||||
</Cal>
|
||||
<CalDates>
|
||||
{loading ? (
|
||||
ellip
|
||||
) : (
|
||||
<span>
|
||||
{datePrefix} at {dateSuffix} PT
|
||||
</span>
|
||||
)}
|
||||
</CalDates>
|
||||
<CalCta>
|
||||
<Markdownify source={cta} />
|
||||
</CalCta>
|
||||
</Root>
|
||||
);
|
||||
};
|
||||
|
||||
export default EventBox;
|
@ -1,71 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
import moment from 'moment';
|
||||
|
||||
class EventWidget extends Component {
|
||||
state = {
|
||||
loading: false,
|
||||
eventDate: '',
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
const eventbriteToken = 'C5PX65CJBVIXWWLNFKLO';
|
||||
const eventbriteOrganiser = '14281996019';
|
||||
|
||||
const url = `https://www.eventbriteapi.com/v3/events/search/?token=${eventbriteToken}&organizer.id=${eventbriteOrganiser}&expand=venue%27`;
|
||||
|
||||
this.setState({
|
||||
loading: true,
|
||||
});
|
||||
|
||||
fetch(url)
|
||||
.then(res => res.json())
|
||||
.then(data => {
|
||||
const eventDate = data.events[0].start.utc;
|
||||
|
||||
this.setState({
|
||||
loading: false,
|
||||
eventDate,
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err); // eslint-disable-line no-console
|
||||
// TODO: set state to show error message
|
||||
this.setState({
|
||||
loading: false,
|
||||
});
|
||||
});
|
||||
}
|
||||
render() {
|
||||
const { loading, eventDate } = this.state;
|
||||
|
||||
if (loading) {
|
||||
return <span>Loading...</span>;
|
||||
}
|
||||
|
||||
const eventDateMoment = moment(eventDate);
|
||||
|
||||
const offset = eventDateMoment.isDST() ? -7 : -8;
|
||||
|
||||
const month = eventDateMoment.format('MMMM');
|
||||
const day = eventDateMoment.format('DD');
|
||||
|
||||
const datePrefix = eventDateMoment.format('dddd, MMMM Do');
|
||||
const dateSuffix = eventDateMoment.utcOffset(offset).format('h a');
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="calendar">
|
||||
<div className="month">{month}</div>
|
||||
<div className="day">{day}</div>
|
||||
</div>
|
||||
<h3>
|
||||
<strong>
|
||||
{datePrefix} at {dateSuffix} PT
|
||||
</strong>
|
||||
</h3>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default EventWidget;
|
43
website/src/components/features.js
Normal file
43
website/src/components/features.js
Normal file
@ -0,0 +1,43 @@
|
||||
import React from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import Markdownify from './markdownify';
|
||||
import theme from '../theme';
|
||||
|
||||
const Box = styled.div`
|
||||
margin-bottom: ${theme.space[5]};
|
||||
|
||||
img {
|
||||
margin-bottom: ${theme.space[3]};
|
||||
margin-left: -${theme.space[2]};
|
||||
}
|
||||
`;
|
||||
|
||||
const Title = styled.h3`
|
||||
color: ${p => (p.kind === 'light' ? theme.colors.white : theme.colors.gray)};
|
||||
font-size: ${theme.fontsize[4]};
|
||||
`;
|
||||
|
||||
const Text = styled.p`
|
||||
font-size: 18px;
|
||||
a {
|
||||
font-weight: 700;
|
||||
}
|
||||
`;
|
||||
|
||||
const FeatureItem = ({ feature, description, imgpath, kind }) => (
|
||||
<Box>
|
||||
{imgpath && <img src={require(`../img/${imgpath}`)} alt="" />}
|
||||
<Title kind={kind}>
|
||||
<Markdownify source={feature} />
|
||||
</Title>
|
||||
<Text>
|
||||
<Markdownify source={description} />
|
||||
</Text>
|
||||
</Box>
|
||||
);
|
||||
|
||||
const Features = ({ items, kind }) =>
|
||||
items.map(item => <FeatureItem kind={kind} {...item} key={item.feature} />);
|
||||
|
||||
export default Features;
|
@ -1,36 +1,96 @@
|
||||
import React from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import '../css/imports/footer.css';
|
||||
import Container from './container';
|
||||
|
||||
import theme from '../theme';
|
||||
import { mq } from '../utils';
|
||||
|
||||
const Root = styled.footer`
|
||||
background: white;
|
||||
padding-top: ${theme.space[4]};
|
||||
padding-bottom: ${theme.space[5]};
|
||||
`;
|
||||
|
||||
const FooterGrid = styled.div`
|
||||
text-align: center;
|
||||
|
||||
${mq[2]} {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
text-align: left;
|
||||
}
|
||||
`;
|
||||
|
||||
const FooterButtons = styled.div`
|
||||
margin-bottom: ${theme.space[3]};
|
||||
${mq[2]} {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
const SocialButton = styled.a`
|
||||
display: inline-block;
|
||||
padding: ${theme.space[1]} ${theme.space[3]};
|
||||
background-color: ${theme.colors.lightishGray};
|
||||
color: white;
|
||||
font-weight: 700;
|
||||
font-size: ${theme.fontsize[2]};
|
||||
border-radius: ${theme.radii[1]};
|
||||
margin-right: ${theme.space[2]};
|
||||
|
||||
&:active,
|
||||
&:hover {
|
||||
background-color: ${theme.colors.darkGreen};
|
||||
}
|
||||
`;
|
||||
|
||||
const Info = styled.div`
|
||||
font-size: ${theme.fontsize[1]};
|
||||
color: ${theme.colors.gray};
|
||||
opacity: 0.5;
|
||||
|
||||
${mq[2]} {
|
||||
padding-left: ${theme.space[4]};
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: 700;
|
||||
color: ${theme.colors.gray};
|
||||
}
|
||||
`;
|
||||
|
||||
const Footer = ({ buttons }) => (
|
||||
<footer>
|
||||
<div className="contained">
|
||||
<div className="social-buttons">
|
||||
{buttons.map(btn => (
|
||||
<a href={btn.url} key={btn.url}>
|
||||
{btn.name}
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
<div className="footer-info">
|
||||
<p>
|
||||
<a
|
||||
href="https://github.com/netlify/netlify-cms/blob/master/LICENSE"
|
||||
className="text-link"
|
||||
>
|
||||
Distributed under MIT License
|
||||
</a>{' '}
|
||||
·{' '}
|
||||
<a
|
||||
href="https://github.com/netlify/netlify-cms/blob/master/CODE_OF_CONDUCT.md"
|
||||
className="text-link"
|
||||
>
|
||||
Code of Conduct
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
<Root>
|
||||
<Container>
|
||||
<FooterGrid>
|
||||
<FooterButtons>
|
||||
{buttons.map(btn => (
|
||||
<SocialButton href={btn.url} key={btn.url}>
|
||||
{btn.name}
|
||||
</SocialButton>
|
||||
))}
|
||||
</FooterButtons>
|
||||
<Info>
|
||||
<p>
|
||||
<a
|
||||
href="https://github.com/netlify/netlify-cms/blob/master/LICENSE"
|
||||
className="text-link"
|
||||
>
|
||||
Distributed under MIT License
|
||||
</a>{' '}
|
||||
·{' '}
|
||||
<a
|
||||
href="https://github.com/netlify/netlify-cms/blob/master/CODE_OF_CONDUCT.md"
|
||||
className="text-link"
|
||||
>
|
||||
Code of Conduct
|
||||
</a>
|
||||
</p>
|
||||
</Info>
|
||||
</FooterGrid>
|
||||
</Container>
|
||||
</Root>
|
||||
);
|
||||
|
||||
export default Footer;
|
||||
|
14
website/src/components/grid.js
Normal file
14
website/src/components/grid.js
Normal file
@ -0,0 +1,14 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { mq } from '../utils';
|
||||
import theme from '../theme';
|
||||
|
||||
const Grid = styled.div`
|
||||
${mq[2]} {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(${p => p.cols}, 1fr);
|
||||
grid-gap: ${theme.space[7]};
|
||||
}
|
||||
`;
|
||||
|
||||
export default Grid;
|
@ -1,88 +1,215 @@
|
||||
import React, { Component } from 'react';
|
||||
import Link from 'gatsby-link';
|
||||
import classnames from 'classnames';
|
||||
import { Location } from '@reach/router';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Link } from 'gatsby';
|
||||
import styled from '@emotion/styled';
|
||||
import { css } from '@emotion/core';
|
||||
|
||||
import GitHubButton from 'react-github-btn';
|
||||
import Container from './container';
|
||||
import Notifications from './notifications';
|
||||
import DocSearch from './docsearch';
|
||||
import GitHubButton from './github-button';
|
||||
|
||||
import logo from '../img/netlify-cms-logo.svg';
|
||||
import searchIcon from '../img/search.svg';
|
||||
|
||||
import '../css/imports/header.css';
|
||||
import theme from '../theme';
|
||||
import { mq } from '../utils';
|
||||
|
||||
class Header extends Component {
|
||||
state = {
|
||||
scrolled: false,
|
||||
};
|
||||
const StyledHeader = styled.header`
|
||||
background: ${theme.colors.darkerGray};
|
||||
padding-top: ${theme.space[3]};
|
||||
padding-bottom: ${theme.space[3]};
|
||||
transition: background 0.2s ease, padding 0.2s ease, box-shadow 0.2s ease;
|
||||
|
||||
async componentDidMount() {
|
||||
${mq[2]} {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
z-index: ${theme.zIndexes.header};
|
||||
|
||||
${p =>
|
||||
p.hasHeroBelow &&
|
||||
!p.scrolled &&
|
||||
css`
|
||||
background: #2a2c24;
|
||||
padding-top: ${theme.space[5]};
|
||||
padding-bottom: ${theme.space[5]};
|
||||
`};
|
||||
}
|
||||
`;
|
||||
|
||||
const HeaderContainer = styled(Container)`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
`;
|
||||
|
||||
const Logo = styled.div`
|
||||
flex: 1 0 50%;
|
||||
${mq[1]} {
|
||||
flex: 0 0 auto;
|
||||
margin-right: ${theme.space[5]};
|
||||
}
|
||||
`;
|
||||
|
||||
const MenuActions = styled.div`
|
||||
flex: 1 0 50%;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
${mq[1]} {
|
||||
display: none;
|
||||
}
|
||||
`;
|
||||
|
||||
const MenuBtn = styled.button`
|
||||
background: none;
|
||||
border: 0;
|
||||
color: white;
|
||||
padding: ${theme.space[3]};
|
||||
font-size: ${theme.fontsize[4]};
|
||||
line-height: 1;
|
||||
`;
|
||||
|
||||
const SearchBtn = styled(MenuBtn)``;
|
||||
|
||||
const ToggleArea = styled.div`
|
||||
display: ${p => (p.open ? 'block' : 'none')};
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
margin-top: ${theme.space[3]};
|
||||
|
||||
${mq[1]} {
|
||||
display: block;
|
||||
width: auto;
|
||||
margin-top: 0;
|
||||
}
|
||||
`;
|
||||
|
||||
const SearchBox = styled(ToggleArea)`
|
||||
${mq[1]} {
|
||||
flex: 1;
|
||||
max-width: 200px;
|
||||
margin-right: ${theme.space[3]};
|
||||
}
|
||||
`;
|
||||
|
||||
const Menu = styled(ToggleArea)`
|
||||
${mq[1]} {
|
||||
flex: 0 0 auto;
|
||||
margin-left: auto;
|
||||
}
|
||||
`;
|
||||
|
||||
const MenuList = styled.ul`
|
||||
${mq[1]} {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
`;
|
||||
|
||||
const MenuItem = styled.li`
|
||||
margin-bottom: ${theme.space[3]};
|
||||
${mq[1]} {
|
||||
margin-bottom: 0;
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-right: ${theme.space[3]};
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const NavLink = styled(Link)`
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
`;
|
||||
|
||||
const Header = ({ hasHeroBelow }) => {
|
||||
const [scrolled, setScrolled] = useState(false);
|
||||
const [isNavOpen, setNavOpen] = useState(false);
|
||||
const [isSearchOpen, setSearchOpen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
// TODO: use raf to throttle events
|
||||
window.addEventListener('scroll', this.handleScroll);
|
||||
}
|
||||
window.addEventListener('scroll', handleScroll);
|
||||
|
||||
componentWillUnmount() {
|
||||
window.removeEventListener('scroll', this.handleScroll);
|
||||
}
|
||||
return () => {
|
||||
window.removeEventListener('scroll', handleScroll);
|
||||
};
|
||||
}, []);
|
||||
|
||||
handleScroll = () => {
|
||||
const handleScroll = () => {
|
||||
const currentWindowPos = document.documentElement.scrollTop || document.body.scrollTop;
|
||||
|
||||
const scrolled = currentWindowPos > 0;
|
||||
|
||||
this.setState({
|
||||
scrolled,
|
||||
});
|
||||
setScrolled(scrolled);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { scrolled } = this.state;
|
||||
const handleMenuBtnClick = () => {
|
||||
setNavOpen(s => !s);
|
||||
setSearchOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<Location>
|
||||
{({ location }) => {
|
||||
const isDocs = location.pathname.indexOf('docs') !== -1;
|
||||
const isBlog = location.pathname.indexOf('blog') !== -1;
|
||||
const handleSearchBtnClick = () => {
|
||||
setSearchOpen(s => !s);
|
||||
setNavOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<header
|
||||
id="header"
|
||||
className={classnames({
|
||||
docs: isDocs,
|
||||
blog: isBlog,
|
||||
scrolled,
|
||||
})}
|
||||
return (
|
||||
<StyledHeader scrolled={scrolled} id="header" hasHeroBelow={hasHeroBelow}>
|
||||
<Notifications />
|
||||
<HeaderContainer>
|
||||
<Logo>
|
||||
<Link to="/">
|
||||
<img src={logo} alt="Netlify CMS logo" />
|
||||
</Link>
|
||||
</Logo>
|
||||
<MenuActions>
|
||||
<SearchBtn onClick={handleSearchBtnClick}>
|
||||
{isSearchOpen ? <span>×</span> : <img src={searchIcon} alt="search" />}
|
||||
</SearchBtn>
|
||||
<MenuBtn onClick={handleMenuBtnClick}>
|
||||
{isNavOpen ? <span>×</span> : <span>☰</span>}
|
||||
</MenuBtn>
|
||||
</MenuActions>
|
||||
<SearchBox open={isSearchOpen}>
|
||||
<DocSearch />
|
||||
</SearchBox>
|
||||
<Menu open={isNavOpen}>
|
||||
<MenuList>
|
||||
<MenuItem
|
||||
css={css`
|
||||
margin-top: 8px;
|
||||
`}
|
||||
>
|
||||
<div className="contained">
|
||||
<div className="logo-container">
|
||||
<Link to="/" className="logo">
|
||||
<img src={logo} alt="Netlify CMS" />
|
||||
</Link>
|
||||
<DocSearch />
|
||||
</div>
|
||||
<div className="nav-container">
|
||||
<span className="gh-button">
|
||||
<GitHubButton />
|
||||
</span>
|
||||
<Link className="nav-link docs-link" to="/docs/intro/">
|
||||
Docs
|
||||
</Link>
|
||||
<Link className="nav-link contributing-link" to="/docs/contributor-guide/">
|
||||
Contributing
|
||||
</Link>
|
||||
<Link className="nav-link" to="/community/">
|
||||
Community
|
||||
</Link>
|
||||
<Link className="nav-link" to="/blog/">
|
||||
Blog
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
}}
|
||||
</Location>
|
||||
);
|
||||
}
|
||||
}
|
||||
<GitHubButton
|
||||
href="https://github.com/netlify/netlify-cms"
|
||||
data-icon="octicon-star"
|
||||
data-show-count="true"
|
||||
aria-label="Star netlify/netlify-cms on GitHub"
|
||||
>
|
||||
Star
|
||||
</GitHubButton>
|
||||
</MenuItem>
|
||||
<MenuItem>
|
||||
<NavLink to="/docs/intro/">Docs</NavLink>
|
||||
</MenuItem>
|
||||
<MenuItem>
|
||||
<NavLink to="/docs/contributor-guide/">Contributing</NavLink>
|
||||
</MenuItem>
|
||||
<MenuItem>
|
||||
<NavLink to="/community/">Community</NavLink>
|
||||
</MenuItem>
|
||||
<MenuItem>
|
||||
<NavLink to="/blog/">Blog</NavLink>
|
||||
</MenuItem>
|
||||
</MenuList>
|
||||
</Menu>
|
||||
</HeaderContainer>
|
||||
</StyledHeader>
|
||||
);
|
||||
};
|
||||
|
||||
export default Header;
|
||||
|
16
website/src/components/hero-title.js
Normal file
16
website/src/components/hero-title.js
Normal file
@ -0,0 +1,16 @@
|
||||
import styled from '@emotion/styled';
|
||||
import theme from '../theme';
|
||||
import { mq } from '../utils';
|
||||
|
||||
const HeroTitle = styled.h1`
|
||||
color: ${theme.colors.green};
|
||||
font-size: ${theme.fontsize[6]};
|
||||
margin-bottom: ${theme.space[1]};
|
||||
|
||||
${mq[2]} {
|
||||
font-size: ${theme.fontsize[7]};
|
||||
margin-bottom: ${theme.space[2]};
|
||||
}
|
||||
`;
|
||||
|
||||
export default HeroTitle;
|
36
website/src/components/home-section.js
Normal file
36
website/src/components/home-section.js
Normal file
@ -0,0 +1,36 @@
|
||||
import React from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import Container from './container';
|
||||
import Page from './page';
|
||||
|
||||
import theme from '../theme';
|
||||
|
||||
const Header = styled.header`
|
||||
text-align: center;
|
||||
padding-top: ${theme.space[7]};
|
||||
padding-bottom: ${theme.space[7]};
|
||||
`;
|
||||
|
||||
const Title = styled.h2`
|
||||
font-size: ${theme.fontsize[6]};
|
||||
`;
|
||||
|
||||
const Text = styled.div`
|
||||
max-width: 710px;
|
||||
margin: 0 auto;
|
||||
`;
|
||||
|
||||
const HomeSection = ({ title, text, children, ...props }) => (
|
||||
<Page as="section" {...props}>
|
||||
<Container>
|
||||
<Header>
|
||||
<Title>{title}</Title>
|
||||
{text && <Text>{text}</Text>}
|
||||
</Header>
|
||||
{children}
|
||||
</Container>
|
||||
</Page>
|
||||
);
|
||||
|
||||
export default HomeSection;
|
@ -1,67 +1,53 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import React from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
import { graphql, StaticQuery } from 'gatsby';
|
||||
|
||||
import { ThemeProvider } from 'emotion-theming';
|
||||
import Header from './header';
|
||||
import Footer from './footer';
|
||||
import Notification from './notification';
|
||||
import GlobalStyles from '../global-styles';
|
||||
import theme from '../theme';
|
||||
|
||||
import '../css/imports/base.css';
|
||||
import '../css/imports/utilities.css';
|
||||
import '../css/imports/chat.css';
|
||||
|
||||
const Layout = ({ children }) => {
|
||||
return (
|
||||
<StaticQuery
|
||||
query={graphql`
|
||||
query layoutQuery {
|
||||
site {
|
||||
siteMetadata {
|
||||
title
|
||||
description
|
||||
}
|
||||
}
|
||||
footer: file(relativePath: { regex: "/global/" }) {
|
||||
childDataYaml {
|
||||
footer {
|
||||
buttons {
|
||||
url
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
notifs: file(relativePath: { regex: "/notifications/" }) {
|
||||
childDataYaml {
|
||||
notifications {
|
||||
published
|
||||
loud
|
||||
message
|
||||
url
|
||||
}
|
||||
}
|
||||
const LAYOUT_QUERY = graphql`
|
||||
query layoutQuery {
|
||||
site {
|
||||
siteMetadata {
|
||||
title
|
||||
description
|
||||
}
|
||||
}
|
||||
footer: file(relativePath: { regex: "/global/" }) {
|
||||
childDataYaml {
|
||||
footer {
|
||||
buttons {
|
||||
url
|
||||
name
|
||||
}
|
||||
}
|
||||
`}
|
||||
>
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const Layout = ({ hasPageHero, children }) => {
|
||||
return (
|
||||
<StaticQuery query={LAYOUT_QUERY}>
|
||||
{data => {
|
||||
const { title, description } = data.site.siteMetadata;
|
||||
const notifs = data.notifs.childDataYaml.notifications.filter(notif => notif.published);
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<ThemeProvider theme={theme}>
|
||||
<GlobalStyles />
|
||||
<Helmet defaultTitle={title} titleTemplate={`%s | ${title}`}>
|
||||
<meta name="description" content={description} />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://fonts.googleapis.com/css?family=Roboto:400,100,100italic,300,300italic,400italic,500,700,900|Roboto+Mono:400,700"
|
||||
/>
|
||||
</Helmet>
|
||||
{notifs.map((node, i) => (
|
||||
<Notification key={i} url={node.url} loud={node.loud}>
|
||||
{node.message}
|
||||
</Notification>
|
||||
))}
|
||||
<Header notifications={notifs} />
|
||||
<Header hasHeroBelow={hasPageHero} />
|
||||
{children}
|
||||
<Footer buttons={data.footer.childDataYaml.footer.buttons} />
|
||||
</Fragment>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}}
|
||||
</StaticQuery>
|
||||
|
10
website/src/components/lead.js
Normal file
10
website/src/components/lead.js
Normal file
@ -0,0 +1,10 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
const Lead = styled.p`
|
||||
font-size: 20px;
|
||||
margin-bottom: 24px;
|
||||
|
||||
${p => p.light && 'color: white;'};
|
||||
`;
|
||||
|
||||
export default Lead;
|
132
website/src/components/markdown.js
Normal file
132
website/src/components/markdown.js
Normal file
@ -0,0 +1,132 @@
|
||||
import React from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import theme from '../theme';
|
||||
|
||||
const StyledMarkdown = styled.div`
|
||||
> :first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
> :last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
line-height: ${theme.lineHeight[1]};
|
||||
margin-top: 2em;
|
||||
margin-bottom: 0.25em;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: ${theme.fontsize[6]};
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: ${theme.fontsize[5]};
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: ${theme.fontsize[4]};
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: ${theme.fontsize[3]};
|
||||
}
|
||||
|
||||
ol,
|
||||
ul {
|
||||
margin-left: ${theme.space[3]};
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: disc;
|
||||
}
|
||||
|
||||
ol {
|
||||
list-style: decimal;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul,
|
||||
p {
|
||||
font-size: 18px;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: bold;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
table {
|
||||
border: 0;
|
||||
background: #f7f7f7;
|
||||
border-radius: 4px;
|
||||
margin-top: 40px;
|
||||
margin-bottom: 40px;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
tbody tr {
|
||||
&:nth-child(odd) {
|
||||
background: #fdfdfd;
|
||||
}
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
th {
|
||||
font-weight: 700;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
td {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
iframe {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
pre {
|
||||
border-radius: ${theme.radii[2]};
|
||||
margin-bottom: ${theme.space[4]};
|
||||
margin-top: ${theme.space[4]};
|
||||
}
|
||||
|
||||
pre > code {
|
||||
font-size: ${theme.fontsize[2]};
|
||||
line-height: ${theme.lineHeight[0]};
|
||||
}
|
||||
|
||||
*:not(pre) > code {
|
||||
color: inherit;
|
||||
background: #e6e6e6;
|
||||
border-radius: 2px;
|
||||
padding: 2px 6px;
|
||||
white-space: nowrap;
|
||||
font-size: ${theme.fontsize[2]};
|
||||
}
|
||||
`;
|
||||
|
||||
const Markdown = ({ html }) => {
|
||||
return <StyledMarkdown dangerouslySetInnerHTML={{ __html: html }} />;
|
||||
};
|
||||
|
||||
export default Markdown;
|
10
website/src/components/meta-info.js
Normal file
10
website/src/components/meta-info.js
Normal file
@ -0,0 +1,10 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import theme from '../theme';
|
||||
|
||||
const MetaInfo = styled.p`
|
||||
font-size: ${theme.fontsize[2]};
|
||||
margin-bottom: ${theme.space[4]};
|
||||
`;
|
||||
|
||||
export default MetaInfo;
|
@ -1,52 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
import { Link } from 'gatsby';
|
||||
|
||||
class MobileNav extends Component {
|
||||
state = {
|
||||
isOpen: false,
|
||||
};
|
||||
toggleNav = () => {
|
||||
this.setState({
|
||||
isOpen: !this.state.isOpen,
|
||||
});
|
||||
};
|
||||
render() {
|
||||
const { items } = this.props;
|
||||
const { isOpen } = this.state;
|
||||
|
||||
return (
|
||||
<div className="mobile-docs-nav">
|
||||
<button className="btn-primary mobile-docs-nav-btn" onClick={this.toggleNav}>
|
||||
{isOpen ? <span>×</span> : <span>☰</span>} {isOpen ? 'Hide' : 'Show'}{' '}
|
||||
Navigation
|
||||
</button>
|
||||
{isOpen && (
|
||||
<nav className="mobile-docs-nav-content">
|
||||
<ul className="mobile-docs-nav-list">
|
||||
{items.map(item => (
|
||||
<li key={item.title} className="mobile-docs-nav-item">
|
||||
{item.title}
|
||||
<ul className="mobile-docs-nav-list">
|
||||
{item.group.edges.map(({ node }) => (
|
||||
<li key={node.fields.slug} className="mobile-docs-nav-item">
|
||||
<Link
|
||||
to={node.fields.slug}
|
||||
className="mobile-docs-nav-link"
|
||||
onClick={this.toggleNav}
|
||||
>
|
||||
{node.frontmatter.title}
|
||||
</Link>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</nav>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default MobileNav;
|
@ -1,10 +1,46 @@
|
||||
import React from 'react';
|
||||
import cn from 'classnames';
|
||||
import styled from '@emotion/styled';
|
||||
import { css } from '@emotion/core';
|
||||
|
||||
import theme from '../theme';
|
||||
|
||||
const Notif = styled.a`
|
||||
background-color: ${theme.colors.darkerGray};
|
||||
color: white;
|
||||
display: block;
|
||||
padding: ${theme.space[2]} ${theme.space[3]};
|
||||
text-align: center;
|
||||
|
||||
/* prettier-ignore */
|
||||
${p =>
|
||||
p.loud &&
|
||||
css`
|
||||
background-color: ${theme.colors.green};
|
||||
color: ${theme.colors.darkerGray};
|
||||
`}
|
||||
|
||||
em {
|
||||
font-style: normal;
|
||||
color: #8b8b8b;
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
sup,
|
||||
sub {
|
||||
font-size: initial;
|
||||
vertical-align: initial;
|
||||
}
|
||||
|
||||
.text-link {
|
||||
text-decoration: underline;
|
||||
color: ${theme.colors.green};
|
||||
}
|
||||
`;
|
||||
|
||||
const Notification = ({ url, loud, children }) => (
|
||||
<a href={url} className={cn('notification', { 'notification-loud': loud })}>
|
||||
<Notif href={url} loud={loud}>
|
||||
{children}
|
||||
</a>
|
||||
</Notif>
|
||||
);
|
||||
|
||||
export default Notification;
|
||||
|
34
website/src/components/notifications.js
Normal file
34
website/src/components/notifications.js
Normal file
@ -0,0 +1,34 @@
|
||||
import React from 'react';
|
||||
import { graphql, StaticQuery } from 'gatsby';
|
||||
|
||||
import Notification from './notification';
|
||||
|
||||
const NOTIFS_QUERY = graphql`
|
||||
query notifs {
|
||||
file(relativePath: { regex: "/notifications/" }) {
|
||||
childDataYaml {
|
||||
notifications {
|
||||
published
|
||||
loud
|
||||
message
|
||||
url
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const Notifications = () => (
|
||||
<StaticQuery query={NOTIFS_QUERY}>
|
||||
{data => {
|
||||
const notifs = data.file.childDataYaml.notifications.filter(notif => notif.published);
|
||||
return notifs.map((node, i) => (
|
||||
<Notification key={i} url={node.url} loud={node.loud}>
|
||||
{node.message}
|
||||
</Notification>
|
||||
));
|
||||
}}
|
||||
</StaticQuery>
|
||||
);
|
||||
|
||||
export default Notifications;
|
29
website/src/components/page-hero.js
Normal file
29
website/src/components/page-hero.js
Normal file
@ -0,0 +1,29 @@
|
||||
import React from 'react';
|
||||
import { css } from '@emotion/core';
|
||||
|
||||
import Container from './container';
|
||||
|
||||
import theme from '../theme';
|
||||
import { mq } from '../utils';
|
||||
|
||||
const PageHero = ({ children }) => (
|
||||
<section
|
||||
css={css`
|
||||
background: ${theme.colors.darkerGray};
|
||||
background-image: linear-gradient(to bottom, #2a2c24 0%, ${theme.colors.darkerGray} 20%);
|
||||
color: ${theme.colors.blueGray};
|
||||
position: relative;
|
||||
padding-top: ${theme.space[6]};
|
||||
padding-bottom: ${theme.space[6]};
|
||||
|
||||
${mq[3]} {
|
||||
padding-top: ${theme.space[6]};
|
||||
padding-bottom: ${theme.space[8]};
|
||||
}
|
||||
`}
|
||||
>
|
||||
<Container>{children}</Container>
|
||||
</section>
|
||||
);
|
||||
|
||||
export default PageHero;
|
16
website/src/components/page.js
Normal file
16
website/src/components/page.js
Normal file
@ -0,0 +1,16 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import theme from '../theme';
|
||||
import { mq } from '../utils';
|
||||
|
||||
const Page = styled.div`
|
||||
padding-top: ${theme.space[5]};
|
||||
padding-bottom: ${theme.space[5]};
|
||||
|
||||
${mq[1]} {
|
||||
padding-top: ${theme.space[6]};
|
||||
padding-bottom: ${theme.space[6]};
|
||||
}
|
||||
`;
|
||||
|
||||
export default Page;
|
@ -1,23 +1,67 @@
|
||||
import React from 'react';
|
||||
import moment from 'moment';
|
||||
import styled from '@emotion/styled';
|
||||
import { css } from '@emotion/core';
|
||||
|
||||
import Markdownify from '../components/markdownify';
|
||||
import theme from '../theme';
|
||||
|
||||
const ReleaseLink = styled.a`
|
||||
color: white;
|
||||
display: block;
|
||||
padding: ${theme.space[2]} ${theme.space[3]};
|
||||
border-radius: ${theme.radii[1]};
|
||||
height: 100%;
|
||||
&:hover {
|
||||
background: ${theme.colors.darkGray};
|
||||
}
|
||||
`;
|
||||
|
||||
const Version = styled.span`
|
||||
background: ${theme.colors.shadeBlue};
|
||||
font-size: ${theme.fontsize[1]};
|
||||
padding: 0 ${theme.space[1]};
|
||||
border-radius: ${theme.radii[1]};
|
||||
font-weight: 700;
|
||||
margin-right: ${theme.space[2]};
|
||||
color: ${theme.colors.gray};
|
||||
`;
|
||||
|
||||
const Release = ({ version, versionPrevious, date, description, url }) => {
|
||||
const displayDate = moment(date).format('MMMM D, YYYY');
|
||||
const defaultUrl = `https://github.com/netlify/netlify-cms/compare/netlify-cms@${versionPrevious}...netlify-cms@${version}`;
|
||||
|
||||
return (
|
||||
<a href={url || defaultUrl} key={version}>
|
||||
<li>
|
||||
<div className="update-metadata">
|
||||
<span className="update-version">{version}</span>
|
||||
<span className="update-date">{displayDate}</span>
|
||||
<li
|
||||
css={css`
|
||||
flex: 1;
|
||||
`}
|
||||
>
|
||||
<ReleaseLink href={url || defaultUrl}>
|
||||
<div
|
||||
css={css`
|
||||
margin-bottom: ${theme.space[1]};
|
||||
`}
|
||||
>
|
||||
<Version>{version}</Version>
|
||||
<span
|
||||
css={css`
|
||||
font-size: ${theme.fontsize[1]};
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
`}
|
||||
>
|
||||
{displayDate}
|
||||
</span>
|
||||
</div>
|
||||
<span className="update-description">
|
||||
<span
|
||||
css={css`
|
||||
font-size: ${theme.fontsize[2]};
|
||||
`}
|
||||
>
|
||||
<Markdownify source={description} />
|
||||
</span>
|
||||
</li>
|
||||
</a>
|
||||
</ReleaseLink>
|
||||
</li>
|
||||
);
|
||||
};
|
||||
|
||||
|
23
website/src/components/section-label.js
Normal file
23
website/src/components/section-label.js
Normal file
@ -0,0 +1,23 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import theme from '../theme';
|
||||
|
||||
const SectionLabel = styled.h3`
|
||||
color: ${theme.colors.gray};
|
||||
font-size: ${theme.fontsize[1]};
|
||||
font-weight: 600;
|
||||
letter-spacing: 1.5px;
|
||||
text-transform: uppercase;
|
||||
margin-bottom: ${theme.space[4]};
|
||||
|
||||
&:after {
|
||||
background: ${theme.colors.darkGreen};
|
||||
content: ' ';
|
||||
display: block;
|
||||
height: 2px;
|
||||
margin-top: 5px;
|
||||
width: ${theme.space[5]};
|
||||
}
|
||||
`;
|
||||
|
||||
export default SectionLabel;
|
22
website/src/components/sidebar-layout.js
Normal file
22
website/src/components/sidebar-layout.js
Normal file
@ -0,0 +1,22 @@
|
||||
import React from 'react';
|
||||
import { css } from '@emotion/core';
|
||||
|
||||
import Page from './page';
|
||||
import { mq } from '../utils';
|
||||
|
||||
const SidebarLayout = ({ sidebar, children }) => (
|
||||
<Page
|
||||
css={css`
|
||||
${mq[1]} {
|
||||
display: grid;
|
||||
grid-template-columns: 300px 1fr;
|
||||
grid-gap: 2rem;
|
||||
}
|
||||
`}
|
||||
>
|
||||
<div>{sidebar}</div>
|
||||
<div>{children}</div>
|
||||
</Page>
|
||||
);
|
||||
|
||||
export default SidebarLayout;
|
59
website/src/components/table-of-contents.js
Normal file
59
website/src/components/table-of-contents.js
Normal file
@ -0,0 +1,59 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import theme from '../theme';
|
||||
|
||||
const TocList = styled.ol`
|
||||
margin: ${theme.space[2]} 0;
|
||||
padding-left: ${theme.space[3]};
|
||||
border-left: 2px solid ${theme.colors.lightestGray};
|
||||
list-style-type: none;
|
||||
`;
|
||||
|
||||
const TocLink = styled.a`
|
||||
display: block;
|
||||
font-size: ${theme.fontsize[2]};
|
||||
color: ${theme.colors.gray};
|
||||
transition: color 0.2s;
|
||||
line-height: ${theme.lineHeight[1]};
|
||||
margin: ${theme.space[2]} 0;
|
||||
|
||||
&:hover {
|
||||
color: ${theme.colors.darkGreen};
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* Maually get table of contents since tableOfContents from markdown
|
||||
* nodes have code added.
|
||||
*
|
||||
* https://github.com/gatsbyjs/gatsby/issues/5436
|
||||
*/
|
||||
const TableOfContents = () => {
|
||||
const [headings, setHeadings] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
const contentHeadings = document.querySelectorAll('[data-docs-content] h2');
|
||||
const headings = [];
|
||||
contentHeadings.forEach(h => {
|
||||
headings.push({
|
||||
id: h.id,
|
||||
text: h.innerText,
|
||||
});
|
||||
});
|
||||
|
||||
setHeadings(headings);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<TocList>
|
||||
{headings.map(h => (
|
||||
<li key={h.id}>
|
||||
<TocLink href={`#${h.id}`}>{h.text}</TocLink>
|
||||
</li>
|
||||
))}
|
||||
</TocList>
|
||||
);
|
||||
};
|
||||
|
||||
export default TableOfContents;
|
@ -1,7 +1,65 @@
|
||||
import React, { Component } from 'react';
|
||||
import React, { useState } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import theme from '../theme';
|
||||
|
||||
import screenshotEditor from '../img/screenshot-editor.jpg';
|
||||
|
||||
const VideoLink = styled.a`
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
|
||||
&:hover {
|
||||
div {
|
||||
background-color: ${theme.colors.blue};
|
||||
box-shadow: 0 6px 18px 0 rgba(0, 0, 0, 0.15), 0 2px 6px 0 rgba(0, 0, 0, 0.3);
|
||||
transform: scale(1.1);
|
||||
}
|
||||
svg {
|
||||
fill: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
&:active {
|
||||
div {
|
||||
transform: scale(0.9);
|
||||
}
|
||||
}
|
||||
|
||||
img,
|
||||
iframe {
|
||||
width: 100%;
|
||||
border-radius: ${theme.radii[2]};
|
||||
box-shadow: 0 10px 30px 0 rgba(0, 0, 0, 0.15), 0 3px 9px 0 rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
`;
|
||||
|
||||
const VideoButton = styled.div`
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
margin: auto;
|
||||
color: ${theme.colors.blue};
|
||||
background-color: rgba(255, 255, 255, 0.85);
|
||||
box-shadow: 0 3px 9px 0 rgba(0, 0, 0, 0.05), 0 1px 3px 0 rgba(0, 0, 0, 0.15);
|
||||
border-radius: 100px;
|
||||
transition: 0.1s;
|
||||
|
||||
svg {
|
||||
position: absolute;
|
||||
left: 30px;
|
||||
top: 24px;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
fill: #3a69c7;
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* We should be able to import complete inline svg's rather than base64, this
|
||||
* component is a stopgap for now. Source in '../img/play.svg'.
|
||||
@ -16,45 +74,35 @@ const PlayIcon = ({ className }) => (
|
||||
</svg>
|
||||
);
|
||||
|
||||
class VideoEmbed extends Component {
|
||||
state = {
|
||||
toggled: false,
|
||||
};
|
||||
toggleVideo = () => {
|
||||
this.setState({
|
||||
toggled: true,
|
||||
});
|
||||
};
|
||||
render() {
|
||||
const { toggled } = this.state;
|
||||
const VideoEmbed = () => {
|
||||
const [toggled, setToggled] = useState(false);
|
||||
|
||||
const embedcode = (
|
||||
<iframe
|
||||
width={560}
|
||||
height={315}
|
||||
src="https://www.youtube-nocookie.com/embed/p6h-rYSVX90?rel=0&showinfo=0&autoplay=1"
|
||||
frameBorder={0}
|
||||
allow="autoplay; encrypted-media"
|
||||
allowFullScreen
|
||||
title="video_embed"
|
||||
/>
|
||||
);
|
||||
const toggleVideo = () => setToggled(true);
|
||||
|
||||
const imgPlaceholder = (
|
||||
<img src={screenshotEditor} className="responsive" alt="editor video screenshot" />
|
||||
);
|
||||
const embedcode = (
|
||||
<iframe
|
||||
title="Netlify CMS video"
|
||||
width={560}
|
||||
height={315}
|
||||
src="https://www.youtube-nocookie.com/embed/p6h-rYSVX90?rel=0&showinfo=0&autoplay=1"
|
||||
frameBorder={0}
|
||||
allow="autoplay; encrypted-media"
|
||||
allowFullScreen
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="hero-graphic" onClick={this.toggleVideo}>
|
||||
{toggled ? embedcode : imgPlaceholder}
|
||||
{!toggled && (
|
||||
<div className="hero-videolink">
|
||||
<PlayIcon className="hero-videolink-arrow" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
const imgPlaceholder = <img src={screenshotEditor} alt="Netlify CMS editor" />;
|
||||
|
||||
return (
|
||||
<VideoLink onClick={toggleVideo}>
|
||||
{toggled ? embedcode : imgPlaceholder}
|
||||
{!toggled && (
|
||||
<VideoButton>
|
||||
<PlayIcon />
|
||||
</VideoButton>
|
||||
)}
|
||||
</VideoLink>
|
||||
);
|
||||
};
|
||||
|
||||
export default VideoEmbed;
|
||||
|
@ -1,10 +1,26 @@
|
||||
import React from 'react';
|
||||
import { css } from '@emotion/core';
|
||||
|
||||
const WhatsNew = ({ children }) => (
|
||||
<section className="whatsnew">
|
||||
<div className="contained">
|
||||
<ol>{children}</ol>
|
||||
</div>
|
||||
import Container from './container';
|
||||
import Release from './release';
|
||||
import Grid from './grid';
|
||||
import theme from '../theme';
|
||||
|
||||
const WhatsNew = ({ updates }) => (
|
||||
<section
|
||||
css={css`
|
||||
background: ${theme.colors.lightishGray};
|
||||
padding-top: ${theme.space[6]};
|
||||
padding-bottom: ${theme.space[5]};
|
||||
`}
|
||||
>
|
||||
<Container>
|
||||
<Grid as="ol" cols={3}>
|
||||
{updates.slice(0, 3).map((item, idx) => (
|
||||
<Release {...item} versionPrevious={updates[idx + 1].version} key={item.version} />
|
||||
))}
|
||||
</Grid>
|
||||
</Container>
|
||||
</section>
|
||||
);
|
||||
|
||||
|
@ -1,11 +1,18 @@
|
||||
import React from 'react';
|
||||
import classnames from 'classnames';
|
||||
|
||||
const WidgetDoc = ({ visible, label, body, html }) => (
|
||||
<div className={classnames('widget', { widget_open: visible })}>
|
||||
<h3>{label}</h3>
|
||||
{body ? body : <div dangerouslySetInnerHTML={{ __html: html }} />}
|
||||
</div>
|
||||
);
|
||||
import Markdown from './markdown';
|
||||
|
||||
const WidgetDoc = ({ visible, label, body, html }) => {
|
||||
if (!visible) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h3>{label}</h3>
|
||||
<Markdown html={body || html} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default WidgetDoc;
|
||||
|
@ -1,79 +1,76 @@
|
||||
import React, { Component } from 'react';
|
||||
import classnames from 'classnames';
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import WidgetDoc from './widget-doc';
|
||||
import Button from './button';
|
||||
|
||||
import '../css/imports/widgets.css';
|
||||
import theme from '../theme';
|
||||
|
||||
class Widgets extends Component {
|
||||
state = {
|
||||
currentWidget: null,
|
||||
};
|
||||
const WidgetsNav = styled.nav`
|
||||
margin-bottom: 1rem;
|
||||
|
||||
componentDidMount() {
|
||||
const { widgets } = this.props;
|
||||
> button {
|
||||
margin-right: 8px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
`;
|
||||
|
||||
const WidgetsContent = styled.div`
|
||||
background: ${theme.colors.lightGray};
|
||||
padding: ${theme.space[3]};
|
||||
border-radius: 4px;
|
||||
`;
|
||||
|
||||
const Widgets = ({ widgets }) => {
|
||||
const [currentWidget, setWidget] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
const hash = window.location.hash ? window.location.hash.replace('#', '') : '';
|
||||
|
||||
const widgetsContainHash = widgets.edges.some(w => w.node.frontmatter.title === hash);
|
||||
|
||||
if (widgetsContainHash) {
|
||||
return this.setState({
|
||||
currentWidget: hash,
|
||||
});
|
||||
return setWidget(hash);
|
||||
}
|
||||
|
||||
this.setState({
|
||||
currentWidget: widgets.edges[0].node.frontmatter.title,
|
||||
});
|
||||
}
|
||||
setWidget(widgets.edges[0].node.frontmatter.title);
|
||||
}, []);
|
||||
|
||||
handleWidgetChange = (event, title) => {
|
||||
const handleWidgetChange = (event, title) => {
|
||||
event.preventDefault();
|
||||
this.setState(
|
||||
{
|
||||
currentWidget: title,
|
||||
},
|
||||
() => {
|
||||
window.history.pushState(null, null, `#${title}`);
|
||||
},
|
||||
);
|
||||
|
||||
setWidget(title);
|
||||
|
||||
window.history.pushState(null, null, `#${title}`);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { widgets } = this.props;
|
||||
const { currentWidget } = this.state;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<section className="widgets">
|
||||
<div className="widgets__cloud">
|
||||
{widgets.edges.map(({ node }) => {
|
||||
const { label, title } = node.frontmatter;
|
||||
return (
|
||||
<button
|
||||
key={title}
|
||||
className={classnames('widgets__item', {
|
||||
widgets__item_active: currentWidget === title,
|
||||
})}
|
||||
onClick={event => this.handleWidgetChange(event, title)}
|
||||
>
|
||||
{label}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div className="widgets__container">
|
||||
{widgets.edges.map(({ node }) => {
|
||||
const { frontmatter, html } = node;
|
||||
const { title, label } = frontmatter;
|
||||
const isVisible = currentWidget === title;
|
||||
return <WidgetDoc key={label} visible={isVisible} label={label} html={html} />;
|
||||
})}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<section>
|
||||
<WidgetsNav>
|
||||
{widgets.edges.map(({ node }) => {
|
||||
const { label, title } = node.frontmatter;
|
||||
return (
|
||||
<Button
|
||||
key={title}
|
||||
active={currentWidget === title}
|
||||
onClick={event => handleWidgetChange(event, title)}
|
||||
outline
|
||||
>
|
||||
{label}
|
||||
</Button>
|
||||
);
|
||||
})}
|
||||
</WidgetsNav>
|
||||
<WidgetsContent>
|
||||
{widgets.edges.map(({ node }) => {
|
||||
const { frontmatter, html } = node;
|
||||
const { title, label } = frontmatter;
|
||||
const isVisible = currentWidget === title;
|
||||
return <WidgetDoc key={label} visible={isVisible} label={label} html={html} />;
|
||||
})}
|
||||
</WidgetsContent>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default Widgets;
|
||||
|
@ -1,169 +0,0 @@
|
||||
@import url(
|
||||
https://fonts.googleapis.com/css?family=Roboto:400,
|
||||
100,
|
||||
100italic,
|
||||
300,
|
||||
300italic,
|
||||
400italic,
|
||||
500,
|
||||
700,
|
||||
900|Roboto+Mono:400,
|
||||
700
|
||||
);
|
||||
|
||||
body {
|
||||
background-color: $shadeBlue;
|
||||
color: $grey;
|
||||
font-family: $roboto;
|
||||
margin: 0;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
|
||||
@media screen and (min-width: $tablet) {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
.page {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight: $bold;
|
||||
font-size: 36px;
|
||||
line-height: 48px;
|
||||
margin: 0 0 $small 0;
|
||||
|
||||
@media screen and (min-width: $tablet) {
|
||||
font-size: 42px;
|
||||
line-height: 56px;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-family: $roboto;
|
||||
font-size: 36px;
|
||||
font-weight: $bold;
|
||||
color: $darkGrey;
|
||||
margin-bottom: $tiny;
|
||||
|
||||
&.subhead {
|
||||
font-weight: $regular;
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-family: $roboto;
|
||||
font-size: 18px;
|
||||
font-weight: $bold;
|
||||
line-height: 26px;
|
||||
padding-bottom: $micro;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
p,
|
||||
ul {
|
||||
font-size: 18px;
|
||||
line-height: 26px;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: $darkGreen;
|
||||
text-decoration: none;
|
||||
font-weight: $bold;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin: $tiny 0 $tiny $small;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.contained {
|
||||
margin: 0 auto;
|
||||
max-width: $display;
|
||||
padding: 0 $small;
|
||||
|
||||
@media screen and (min-width: $tablet) {
|
||||
padding: 0 $medium;
|
||||
}
|
||||
}
|
||||
|
||||
*[class^='btn-'] {
|
||||
border-radius: $borderRadius;
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
font-family: $roboto;
|
||||
font-size: $tiny;
|
||||
font-weight: $bold;
|
||||
margin: 0;
|
||||
padding: $tiny $small;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
&:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -40%;
|
||||
left: -210%;
|
||||
width: 200%;
|
||||
height: 200%;
|
||||
opacity: 0;
|
||||
transform: rotate(30deg);
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
background: linear-gradient(
|
||||
to right,
|
||||
rgba(255, 255, 255, 0.2) 0%,
|
||||
rgba(255, 255, 255, 0.2) 77%,
|
||||
rgba(255, 255, 255, 0.6) 92%,
|
||||
rgba(255, 255, 255, 0) 100%
|
||||
);
|
||||
}
|
||||
|
||||
&:hover:after {
|
||||
opacity: 1;
|
||||
left: 110%;
|
||||
transition-property: left, opacity;
|
||||
transition-duration: 0.6s, 0.1s;
|
||||
transition-timing-function: ease;
|
||||
}
|
||||
|
||||
&:active:after {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
&.small {
|
||||
padding: $micro $tiny;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-image: linear-gradient(0deg, $lightGreen 14%, $green 94%);
|
||||
color: $darkerGrey;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
border: 1px solid white;
|
||||
color: white;
|
||||
}
|
||||
|
||||
pre {
|
||||
border-radius: $borderRadius;
|
||||
line-height: 1 !important;
|
||||
}
|
||||
|
||||
/* fixes overflowing code example in widgets */
|
||||
.widget pre {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.code,
|
||||
code {
|
||||
font-family: 'Roboto Mono', monospace !important;
|
||||
font-size: 80%;
|
||||
text-transform: none;
|
||||
line-height: 1 !important;
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
.chat-button {
|
||||
z-index: 100;
|
||||
position: fixed;
|
||||
bottom: 10px;
|
||||
right: 10px;
|
||||
cursor: pointer;
|
||||
}
|
@ -1,92 +0,0 @@
|
||||
.collab,
|
||||
.community-channels {
|
||||
margin: $medium $tiny;
|
||||
|
||||
@media screen and (min-width: $mobile) {
|
||||
margin: $large auto;
|
||||
}
|
||||
}
|
||||
|
||||
.collab {
|
||||
h1 {
|
||||
margin-bottom: $small;
|
||||
text-align: center;
|
||||
|
||||
@media screen and (min-width: $mobile) {
|
||||
margin-bottom: $large;
|
||||
}
|
||||
}
|
||||
|
||||
.collab-graphic {
|
||||
@media screen and (min-width: $mobile) {
|
||||
@neat-span-columns 4;
|
||||
@neat-shift 1;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: $medium;
|
||||
|
||||
@media screen and (min-width: $mobile) {
|
||||
margin-top: 0;
|
||||
text-align: left;
|
||||
@neat-span-columns 5;
|
||||
@neat-shift 1;
|
||||
}
|
||||
|
||||
@media screen and (min-width: $tablet) {
|
||||
margin-top: $medium;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.community-channels {
|
||||
padding-bottom: $xl;
|
||||
text-align: left;
|
||||
|
||||
.section-label:not(:first-child) {
|
||||
margin-top: $large;
|
||||
}
|
||||
|
||||
a {
|
||||
color: $darkGreen;
|
||||
}
|
||||
}
|
||||
|
||||
.community-channels-list {
|
||||
margin-left: 0;
|
||||
|
||||
li {
|
||||
list-style-type: none;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
a {
|
||||
display: block;
|
||||
font-weight: inherit;
|
||||
position: relative;
|
||||
|
||||
&:focus,
|
||||
&:active,
|
||||
&:hover {
|
||||
&:before {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
&:before {
|
||||
display: none;
|
||||
content: '';
|
||||
position: absolute;
|
||||
width: 3px;
|
||||
height: 100%;
|
||||
background-color: $darkGreen;
|
||||
left: -16px;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
color: $grey;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
@ -1,57 +0,0 @@
|
||||
.communitysupport {
|
||||
@neat-row;
|
||||
background-color: white;
|
||||
padding: $large 0 $large 0;
|
||||
|
||||
@media screen and (min-width: $desktop) {
|
||||
padding: $xl 0 $large 0;
|
||||
h2 {
|
||||
text-align: center;
|
||||
margin-bottom: $large;
|
||||
}
|
||||
}
|
||||
|
||||
.community {
|
||||
@neat-span-columns 12;
|
||||
|
||||
@media screen and (min-width: $tablet) {
|
||||
@neat-span-columns 8;
|
||||
}
|
||||
@media screen and (min-width: $desktop) {
|
||||
@neat-span-columns 6;
|
||||
}
|
||||
}
|
||||
|
||||
.community-features {
|
||||
.feature {
|
||||
margin-top: $medium;
|
||||
}
|
||||
}
|
||||
|
||||
.contributors {
|
||||
@neat-span-columns 12;
|
||||
margin-top: $medium;
|
||||
|
||||
@media screen and (min-width: $tablet) {
|
||||
@neat-span-columns 10;
|
||||
}
|
||||
@media screen and (min-width: $desktop) {
|
||||
@neat-span-columns 5;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.contributor-list {
|
||||
margin-top: 4px;
|
||||
img {
|
||||
width: 32px;
|
||||
margin: 0 4px 4px 0;
|
||||
border-radius: 16px;
|
||||
transition: 0.1s;
|
||||
}
|
||||
img:hover {
|
||||
transform: scale(1.3);
|
||||
box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.25), 0 4px 12px 0 rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
.cta {
|
||||
@media screen and (min-width: $desktop) {
|
||||
position: relative;
|
||||
top: -65px;
|
||||
width: 880px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.cta-primary {
|
||||
background-color: white;
|
||||
padding: $medium $small $medium $small;
|
||||
|
||||
@media screen and (min-width: $tablet) {
|
||||
padding: $medium;
|
||||
}
|
||||
|
||||
@media screen and (min-width: $desktop) {
|
||||
padding: $small $medium $small $medium;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
box-shadow: 0 10px 30px 0 rgba(28, 30, 30, 0.1), 0 3px 9px 0 rgba(28, 30, 30, 0.15);
|
||||
border-radius: $largeBorderRadius;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 18px;
|
||||
line-height: 25px;
|
||||
color: $lightishGrey;
|
||||
margin: 0;
|
||||
|
||||
.hook {
|
||||
font-weight: $bold;
|
||||
color: $darkGrey;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
color: white;
|
||||
text-transform: uppercase;
|
||||
font-size: $tiny;
|
||||
letter-spacing: 0.5px;
|
||||
background-color: $blue;
|
||||
background-image: linear-gradient(-180deg, #4a7fdd 0%, #3a69c7 100%);
|
||||
box-shadow: 0 4px 12px 0 rgba(68, 74, 87, 0.1), 0 1px 3px 0 rgba(68, 74, 87, 0.2);
|
||||
border-radius: $borderRadius;
|
||||
padding: 12px 18px 12px 18px;
|
||||
transition: 0.2s;
|
||||
display: inline-block;
|
||||
margin-top: $tiny;
|
||||
|
||||
@media screen and (min-width: $desktop) {
|
||||
flex-shrink: 0;
|
||||
margin: 0 0 0 $small;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.05);
|
||||
box-shadow: 0 4px 12px 0 rgba(68, 74, 87, 0.2), 0 1px 3px 0 rgba(68, 74, 87, 0.4);
|
||||
}
|
||||
&:active {
|
||||
transform: scale(0.95);
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,254 +0,0 @@
|
||||
.docs.page,
|
||||
.blog.page {
|
||||
padding: 69px $tiny $xl;
|
||||
text-align: left;
|
||||
@media screen and (min-width: $mobile) {
|
||||
padding: 157px $medium $xl;
|
||||
}
|
||||
|
||||
.sidebar {
|
||||
@media screen and (min-width: $tablet) {
|
||||
@neat-span-columns 6 24;
|
||||
}
|
||||
}
|
||||
|
||||
.docs-nav {
|
||||
display: none;
|
||||
|
||||
@media screen and (min-width: $tablet) {
|
||||
display: block;
|
||||
height: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.nav-link,
|
||||
.subnav-link {
|
||||
display: block;
|
||||
font-weight: $regular;
|
||||
font-size: $tiny;
|
||||
color: $grey;
|
||||
line-height: 1.3;
|
||||
margin: 10px 0;
|
||||
text-decoration: none;
|
||||
text-transform: capitalize;
|
||||
transition: color 0.2s ease;
|
||||
|
||||
&.active {
|
||||
color: $darkGreen;
|
||||
font-weight: $bold;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: $darkGreen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.docs-nav-section {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
.docs-nav-section-list {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.docs-nav-section-title {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.nav-subsections {
|
||||
margin: $tiny 0;
|
||||
padding: 0 0 0 $tiny;
|
||||
border-left: 2px solid $lightestGrey;
|
||||
list-style-type: none;
|
||||
|
||||
li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.subnav-link {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
h1,
|
||||
h2 {
|
||||
font-size: 36px;
|
||||
line-height: 1.4em;
|
||||
|
||||
&.intro-headline {
|
||||
padding: 0 $small;
|
||||
margin-bottom: 86px;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: $small;
|
||||
}
|
||||
|
||||
h3 {
|
||||
color: $grey;
|
||||
font-size: 20px;
|
||||
margin-top: $medium;
|
||||
margin-bottom: $small;
|
||||
|
||||
&.inverse {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.meta-info {
|
||||
font-size: $tiny;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
margin: 34px 0 $medium 0;
|
||||
|
||||
th,
|
||||
td {
|
||||
padding: $micro;
|
||||
}
|
||||
|
||||
th {
|
||||
font-size: 18px;
|
||||
font-weight: $bold;
|
||||
}
|
||||
|
||||
tbody tr {
|
||||
&:nth-child(odd) {
|
||||
background: #fdfdfd;
|
||||
}
|
||||
}
|
||||
|
||||
td {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.docs-content,
|
||||
.blog-content {
|
||||
font-size: 18px;
|
||||
line-height: 28px;
|
||||
|
||||
.edit-this-page {
|
||||
float: right;
|
||||
}
|
||||
|
||||
#pencil {
|
||||
fill: #7ca511;
|
||||
}
|
||||
|
||||
@media screen and (min-width: $tablet) {
|
||||
@neat-span-columns 17 24;
|
||||
@neat-shift 1 24;
|
||||
}
|
||||
|
||||
h2:not(:first-child) {
|
||||
margin-top: $medium;
|
||||
}
|
||||
p {
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: $darkGreen;
|
||||
}
|
||||
|
||||
iframe {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
table {
|
||||
background: #f7f7f7;
|
||||
border-radius: $borderRadius;
|
||||
}
|
||||
|
||||
pre {
|
||||
margin: 30px -16px !important;
|
||||
@media (min-width: $xlarge) {
|
||||
margin-right: -120px !important;
|
||||
}
|
||||
}
|
||||
|
||||
figure {
|
||||
margin-left: 0;
|
||||
|
||||
.gatsby-highlight {
|
||||
margin-top: -20px;
|
||||
}
|
||||
}
|
||||
|
||||
figcaption {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
:not(pre) > code {
|
||||
color: inherit;
|
||||
background: $lightestGrey;
|
||||
border-radius: 2px;
|
||||
padding: 2px 6px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.blog-content h1 {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.blog-list-item h2 {
|
||||
margin: 48px 0 0;
|
||||
line-height: 36px;
|
||||
}
|
||||
|
||||
.mobile-docs-nav {
|
||||
display: block;
|
||||
position: relative;
|
||||
margin-bottom: $small;
|
||||
|
||||
@media screen and (min-width: $tablet) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.mobile-docs-nav-btn {
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.mobile-docs-nav-content {
|
||||
/* border: 1px solid $lightishGrey; */
|
||||
background-color: $lighterGrey;
|
||||
padding: $tiny;
|
||||
}
|
||||
|
||||
.mobile-docs-nav-list {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
|
||||
.mobile-docs-nav-list {
|
||||
margin-left: $small;
|
||||
}
|
||||
}
|
||||
|
||||
.mobile-docs-nav-item {
|
||||
font-weight: bold;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.mobile-docs-nav-link {
|
||||
font-size: 16px;
|
||||
display: block;
|
||||
padding: $micro;
|
||||
}
|
@ -1,52 +0,0 @@
|
||||
.editors {
|
||||
@neat-row;
|
||||
margin: $large 0 $large 0;
|
||||
|
||||
@media screen and (min-width: $desktop) {
|
||||
text-align: center;
|
||||
margin: $xxl 0 $xxl 0;
|
||||
}
|
||||
|
||||
h2,
|
||||
p {
|
||||
max-width: $desktop;
|
||||
|
||||
@media screen and (min-width: $desktop) {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
}
|
||||
|
||||
p#editor-intro {
|
||||
max-width: 710px;
|
||||
}
|
||||
|
||||
.editors-features {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: calc($large * 2);
|
||||
|
||||
@media screen and (max-width: $desktop) {
|
||||
justify-content: flex-start;
|
||||
flex-wrap: wrap;
|
||||
margin-top: $small;
|
||||
}
|
||||
|
||||
.feature {
|
||||
min-width: 260px;
|
||||
width: 320px;
|
||||
text-align: left;
|
||||
margin-right: $medium;
|
||||
|
||||
img {
|
||||
max-width: 300px;
|
||||
margin-bottom: $tiny;
|
||||
margin-left: -9px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: $desktop) {
|
||||
margin-top: $large;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
footer {
|
||||
background: white;
|
||||
padding: $medium 0 $large 0;
|
||||
text-align: center;
|
||||
|
||||
.footer-info {
|
||||
@media screen and (min-width: $tablet) {
|
||||
float: left;
|
||||
margin-right: $small;
|
||||
}
|
||||
p {
|
||||
color: $grey;
|
||||
font-family: $roboto;
|
||||
font-size: 12px;
|
||||
opacity: 0.5;
|
||||
}
|
||||
a {
|
||||
color: $grey;
|
||||
}
|
||||
}
|
||||
|
||||
.social-buttons {
|
||||
margin-bottom: $small;
|
||||
@media screen and (min-width: $tablet) {
|
||||
float: left;
|
||||
margin-right: $small;
|
||||
}
|
||||
a {
|
||||
padding: $micro $tiny $micro $tiny;
|
||||
margin-right: $micro;
|
||||
background-color: $lightishGrey;
|
||||
color: white;
|
||||
border-radius: $borderRadius;
|
||||
}
|
||||
a:hover {
|
||||
background-color: $darkGreen;
|
||||
}
|
||||
a:active {
|
||||
background-color: $darkerGreen;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,237 +0,0 @@
|
||||
.notification {
|
||||
background-color: $darkerGrey;
|
||||
box-sizing: border-box;
|
||||
color: white;
|
||||
display: block;
|
||||
padding: $tiny $small;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
z-index: 100;
|
||||
|
||||
@media screen and (min-width: $mobile) {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
em {
|
||||
font-style: normal;
|
||||
color: #8b8b8b;
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
sup,
|
||||
sub {
|
||||
font-size: initial;
|
||||
vertical-align: initial;
|
||||
}
|
||||
|
||||
.text-link {
|
||||
text-decoration: underline;
|
||||
color: $green;
|
||||
}
|
||||
|
||||
&.notification-loud {
|
||||
background-color: $green;
|
||||
color: $darkerGrey;
|
||||
}
|
||||
|
||||
+ header {
|
||||
margin-top: 100px;
|
||||
|
||||
@media screen and (min-width: 360px) {
|
||||
margin-top: 74px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 712px) {
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
+ div:before,
|
||||
+ .hero:before {
|
||||
content: '';
|
||||
display: block;
|
||||
height: 100px;
|
||||
width: 100%;
|
||||
|
||||
@media screen and (min-width: 360px) {
|
||||
height: 74px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 712px) {
|
||||
height: 50px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
header {
|
||||
background: transparent;
|
||||
box-shadow: none;
|
||||
font-family: $roboto;
|
||||
position: absolute;
|
||||
padding: $medium 0;
|
||||
text-align: center;
|
||||
transition: background 0.2s ease, padding 0.2s ease, box-shadow 0.2s ease;
|
||||
width: 100%;
|
||||
z-index: 100;
|
||||
|
||||
@media screen and (min-width: $tablet) {
|
||||
text-align: right;
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
&.scrolled {
|
||||
@media screen and (min-width: $tablet) {
|
||||
background: $darkerGrey;
|
||||
padding: $small 0;
|
||||
}
|
||||
}
|
||||
|
||||
&.docs,
|
||||
&.blog {
|
||||
background: $darkerGrey;
|
||||
padding: $small 0;
|
||||
|
||||
@media screen and (max-width: $tablet) {
|
||||
position: static;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-container {
|
||||
padding-top: $micro;
|
||||
|
||||
.nav-link {
|
||||
color: white;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
-webkit-vertical-align: middle !important;
|
||||
margin-left: $tiny;
|
||||
&:first-child {
|
||||
margin-left: 0;
|
||||
}
|
||||
&:hover {
|
||||
color: $green;
|
||||
}
|
||||
}
|
||||
|
||||
.gh-button {
|
||||
display: inline-block;
|
||||
margin-left: $small;
|
||||
vertical-align: middle;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
@media screen and (max-width: $mobile) {
|
||||
margin-top: $tiny;
|
||||
top: 0;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.algolia-search {
|
||||
margin-top: 1px;
|
||||
-webkit-margin-top: 0;
|
||||
-webkit-display: inline-block;
|
||||
vertical-align: baseline !important;
|
||||
}
|
||||
input.closed {
|
||||
display: none;
|
||||
}
|
||||
|
||||
input {
|
||||
padding: -5px 0 0 0;
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
appearance: none;
|
||||
background: none;
|
||||
color: $lightGrey;
|
||||
display: inline-block;
|
||||
font-size: $tiny;
|
||||
font-weight: $regular;
|
||||
max-width: 160px;
|
||||
-webkit-appearance: none;
|
||||
visibility: visible;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
display: inline-block;
|
||||
|
||||
~ .bar {
|
||||
&::before,
|
||||
&::after {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
|
||||
~ .button-submit {
|
||||
margin-top: -35px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.utility-input {
|
||||
display: none;
|
||||
padding: $micro;
|
||||
position: relative;
|
||||
top: -4px;
|
||||
width: auto;
|
||||
border-radius: 4px;
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
color: white;
|
||||
margin: 0 0 0 $tiny;
|
||||
padding-top: -5px;
|
||||
padding-bottom: 9px;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
transition: all 0.2s ease-in-out;
|
||||
|
||||
@media screen and (min-width: 1024px) {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
&:focus,
|
||||
&:active {
|
||||
outline-style: none;
|
||||
}
|
||||
|
||||
&::-webkit-input-placeholder,
|
||||
&:-moz-placeholder,
|
||||
&::-moz-placeholder,
|
||||
&:-ms-input-placeholder {
|
||||
font-size: $tiny;
|
||||
font-weight: $semibold;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
line-height: $small;
|
||||
}
|
||||
|
||||
img {
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.logo-container {
|
||||
@media screen and (min-width: $tablet) {
|
||||
margin-top: 10px;
|
||||
float: left;
|
||||
}
|
||||
.logo {
|
||||
display: block;
|
||||
margin: 0 auto $tiny auto;
|
||||
width: 100%;
|
||||
@media screen and (min-width: $tablet) {
|
||||
margin: -14px 20px -6px 0;
|
||||
width: initial;
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,257 +0,0 @@
|
||||
.hero {
|
||||
@neat-row;
|
||||
background: $darkerGrey;
|
||||
background-image: linear-gradient(-180deg, #2a2c24 0%, $darkerGrey 20%);
|
||||
color: $blueGrey;
|
||||
overflow: hidden;
|
||||
padding: calc($xl * 2.25) 0 0 0;
|
||||
position: relative;
|
||||
|
||||
@media screen and (min-width: $mobile) {
|
||||
padding-top: calc($xl * 1.5);
|
||||
}
|
||||
|
||||
@media screen and (min-width: $tablet) {
|
||||
padding-top: calc($xl * 1.5);
|
||||
}
|
||||
|
||||
&.landing {
|
||||
padding-bottom: 100px;
|
||||
@media screen and (min-width: $desktop) {
|
||||
padding-bottom: 200px;
|
||||
}
|
||||
}
|
||||
|
||||
.hero-copy {
|
||||
margin: $medium auto $xl auto;
|
||||
}
|
||||
|
||||
.subhead {
|
||||
display: inline-block;
|
||||
margin: $micro auto;
|
||||
font-size: 18px;
|
||||
line-height: 26px;
|
||||
|
||||
@media screen and (min-width: $desktop) {
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
strong {
|
||||
display: block;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: $green;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: white;
|
||||
}
|
||||
|
||||
h3 {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.cta-header {
|
||||
display: block;
|
||||
margin-top: $small;
|
||||
}
|
||||
.cta-header a {
|
||||
display: inline-block;
|
||||
color: white;
|
||||
text-transform: uppercase;
|
||||
font-size: $tiny;
|
||||
letter-spacing: 0.5px;
|
||||
background-color: $blue;
|
||||
background-image: linear-gradient(-180deg, #4a7fdd 0%, #3a69c7 100%);
|
||||
box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.3), 0 1px 3px 0 rgba(0, 0, 0, 0.6);
|
||||
border-radius: $borderRadius;
|
||||
padding: 10px 14px 8px 14px;
|
||||
transition: 0.2s;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.05);
|
||||
box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.5), 0 1px 3px 0 rgba(0, 0, 0, 1);
|
||||
}
|
||||
&:active {
|
||||
transform: scale(0.95);
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
.hero-features {
|
||||
@media screen and (min-width: $tablet) {
|
||||
@neat-span-columns 5;
|
||||
}
|
||||
|
||||
.feature {
|
||||
margin: 0 0 $medium 0;
|
||||
}
|
||||
}
|
||||
|
||||
.hero-graphic {
|
||||
@neat-span-columns 12;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
|
||||
@media screen and (min-width: $tablet) {
|
||||
@neat-span-columns 6;
|
||||
float: right;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
img,
|
||||
iframe {
|
||||
width: 100%;
|
||||
border-radius: $largeBorderRadius;
|
||||
box-shadow: 0 10px 30px 0 rgba(0, 0, 0, 0.15), 0 3px 9px 0 rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.hero-videolink {
|
||||
position: absolute;
|
||||
margin: auto;
|
||||
padding: 10px 0 0 10px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
color: $blue;
|
||||
background-color: rgba(255, 255, 255, 0.85);
|
||||
box-shadow: 0 3px 9px 0 rgba(0, 0, 0, 0.05), 0 1px 3px 0 rgba(0, 0, 0, 0.15);
|
||||
border-radius: 100px;
|
||||
transition: 0.1s;
|
||||
}
|
||||
.hero-videolink-arrow {
|
||||
position: absolute;
|
||||
left: 33px;
|
||||
top: 28px;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
fill: #3a69c7;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
.hero-videolink {
|
||||
background-color: $blue;
|
||||
box-shadow: 0 6px 18px 0 rgba(0, 0, 0, 0.15), 0 2px 6px 0 rgba(0, 0, 0, 0.3);
|
||||
transform: scale(1.1);
|
||||
}
|
||||
.hero-videolink-arrow {
|
||||
fill: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
&:active {
|
||||
.hero-videolink {
|
||||
transform: scale(0.9);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*COMMUNITY PAGE*/
|
||||
|
||||
&.community {
|
||||
.hero-copy {
|
||||
text-align: left;
|
||||
@media screen and (min-width: $tablet) {
|
||||
@neat-span-columns 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ctas {
|
||||
margin-bottom: $small;
|
||||
|
||||
@media screen and (min-width: $mobile) {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: $green;
|
||||
font-weight: $semibold;
|
||||
}
|
||||
}
|
||||
|
||||
.calendar-cta {
|
||||
text-align: center;
|
||||
background: $darkerGrey;
|
||||
background-image: linear-gradient(-17deg, $darkerGrey 17%, $darkGrey 94%);
|
||||
border-radius: $largeBorderRadius;
|
||||
box-shadow: 0 $micro $small rgba(0, 0, 0, 0.1);
|
||||
padding: $medium;
|
||||
box-sizing: border-box;
|
||||
|
||||
@media screen and (min-width: $tablet) {
|
||||
max-width: 446px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: $tablet) {
|
||||
@neat-span-columns 5;
|
||||
@neat-shift 1;
|
||||
display: inline-block;
|
||||
position: fixed;
|
||||
right: $medium;
|
||||
max-height: calc(100vh - ($xl * 1.5) - $medium);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 1280px) {
|
||||
right: initial;
|
||||
left: calc(50% - $large);
|
||||
}
|
||||
|
||||
.calendar {
|
||||
border-radius: $largeBorderRadius;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 $micro $small rgba(0, 0, 0, 0.5);
|
||||
margin: $small auto;
|
||||
max-width: 250px;
|
||||
|
||||
.month {
|
||||
background: $green;
|
||||
color: $grey;
|
||||
font-weight: $black;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 4px;
|
||||
font-size: $tiny;
|
||||
padding: $tiny;
|
||||
}
|
||||
|
||||
.day {
|
||||
font-size: $xl;
|
||||
font-weight: $black;
|
||||
color: white;
|
||||
border: 1px solid $grey;
|
||||
border-top: none;
|
||||
border-bottom-left-radius: $largeBorderRadius;
|
||||
border-bottom-right-radius: $largeBorderRadius;
|
||||
}
|
||||
}
|
||||
|
||||
strong {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
h2:not(:first-child) {
|
||||
font-weight: $light;
|
||||
}
|
||||
|
||||
.cal-cta {
|
||||
margin-top: $micro;
|
||||
|
||||
a {
|
||||
color: $green;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,258 +0,0 @@
|
||||
@keyframes fadeInUp {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
.centered-text {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.container {
|
||||
@neat-outer-container;
|
||||
}
|
||||
|
||||
.half,
|
||||
.third,
|
||||
.quarter {
|
||||
padding-bottom: $small;
|
||||
@neat-span-columns 12;
|
||||
|
||||
@media screen and (min-width: $tablet) {
|
||||
@neat-span-columns 6;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
&:nth-child(even) {
|
||||
@media screen and (min-width: $mobile) and (max-width: 767px) {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.third {
|
||||
@media screen and (min-width: $tablet) {
|
||||
@neat-span-columns 4;
|
||||
}
|
||||
}
|
||||
|
||||
.quarter {
|
||||
@media screen and (min-width: $tablet) {
|
||||
@neat-span-columns 3;
|
||||
}
|
||||
}
|
||||
|
||||
.clearfix {
|
||||
&:after {
|
||||
content: ' ';
|
||||
width: 100%;
|
||||
display: table;
|
||||
}
|
||||
}
|
||||
|
||||
.section-label {
|
||||
color: $grey;
|
||||
font-size: 12px;
|
||||
font-weight: $semibold;
|
||||
letter-spacing: 1.5px;
|
||||
text-transform: uppercase;
|
||||
|
||||
&:after {
|
||||
background: $darkGreen;
|
||||
content: ' ';
|
||||
display: block;
|
||||
height: 2px;
|
||||
margin-top: 5px;
|
||||
width: $small;
|
||||
}
|
||||
|
||||
&.inverse {
|
||||
color: white;
|
||||
|
||||
&.mono:after {
|
||||
background: $grey;
|
||||
}
|
||||
}
|
||||
|
||||
&.extended {
|
||||
display: inline-block;
|
||||
line-height: 1.15;
|
||||
|
||||
&:after {
|
||||
position: relative;
|
||||
height: 1px;
|
||||
left: -10000%;
|
||||
width: calc(10100%);
|
||||
z-index: -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
img.responsive {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.img-bg-hero {
|
||||
color: white;
|
||||
background-size: 100% auto;
|
||||
background-size: cover !important;
|
||||
|
||||
h1,
|
||||
h2 {
|
||||
color: white;
|
||||
font-weight: $light;
|
||||
|
||||
@media screen and (min-width: $tablet) {
|
||||
font-weight: $thin;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pagination {
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style-type: none;
|
||||
|
||||
@media screen and (min-width: $tablet) {
|
||||
@neat-span-columns 8;
|
||||
@neat-shift 2;
|
||||
}
|
||||
|
||||
li {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: inline;
|
||||
|
||||
@media screen and (min-width: $tablet) {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
&.active a,
|
||||
a[aria-label] {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
font-weight: $light;
|
||||
color: $grey;
|
||||
width: 18px;
|
||||
font-size: $tiny;
|
||||
padding: $micro;
|
||||
border-radius: 99px;
|
||||
display: none;
|
||||
|
||||
@media screen and (min-width: $tablet) {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.active a {
|
||||
color: white;
|
||||
background: $green;
|
||||
}
|
||||
|
||||
.disabled a {
|
||||
color: $lighterGrey;
|
||||
}
|
||||
}
|
||||
|
||||
.unordered-list ul {
|
||||
margin: 0 0 $small 0;
|
||||
padding: 0;
|
||||
font-size: 16px;
|
||||
line-height: 28px;
|
||||
list-style-type: none;
|
||||
list-style-position: inside;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
li span {
|
||||
position: relative;
|
||||
padding-left: $small;
|
||||
display: list-item;
|
||||
|
||||
&:before {
|
||||
content: '\2192';
|
||||
color: $green;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.numbered-list ol {
|
||||
list-style-type: decimal-leading-zero;
|
||||
margin: 32px 0 0 0;
|
||||
padding: 0 0 0 78px;
|
||||
|
||||
li {
|
||||
margin-bottom: 33px;
|
||||
font-size: 34px;
|
||||
font-weight: $bold;
|
||||
color: $grey;
|
||||
position: relative;
|
||||
|
||||
&:before,
|
||||
&:after {
|
||||
position: absolute;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
&:before {
|
||||
content: 'N';
|
||||
top: 6px;
|
||||
left: -78px;
|
||||
padding-bottom: 2px;
|
||||
border-bottom: 1px solid $green;
|
||||
padding-right: 25px;
|
||||
}
|
||||
|
||||
&:after {
|
||||
content: 'ọ';
|
||||
left: -69px;
|
||||
top: 4px;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 34px;
|
||||
margin-bottom: $tiny;
|
||||
|
||||
@media screen and (min-width: $tablet) {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
&:before {
|
||||
content: ' ';
|
||||
position: absolute;
|
||||
background: white;
|
||||
left: -19px;
|
||||
height: 10px;
|
||||
width: 10px;
|
||||
top: $small;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
font-weight: $regular;
|
||||
line-height: 28px;
|
||||
color: $lightGrey;
|
||||
}
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
.whatsnew {
|
||||
padding: $medium 0 $medium 0;
|
||||
background-color: $lightishGrey;
|
||||
color: white;
|
||||
@media screen and (min-width: $desktop) {
|
||||
margin-top: -98px;
|
||||
padding-top: 75px;
|
||||
}
|
||||
|
||||
ol {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
list-style: none;
|
||||
padding-left: 0;
|
||||
@media screen and (max-width: $desktop) {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
a {
|
||||
color: white;
|
||||
font-weight: $regular;
|
||||
min-width: 250px;
|
||||
max-width: 320px;
|
||||
margin-right: $medium;
|
||||
@media screen and (max-width: $desktop) {
|
||||
max-width: 100%;
|
||||
min-width: 100%;
|
||||
padding: 16px 0 16px 0;
|
||||
}
|
||||
}
|
||||
a:hover {
|
||||
padding: 16px 24px 16px 24px;
|
||||
margin: -16px calc($medium - 24px) -16px -24px;
|
||||
background-color: $darkGrey;
|
||||
border-radius: $borderRadius;
|
||||
@media screen and (max-width: $desktop) {
|
||||
margin: 0 -24px 0 -24px;
|
||||
}
|
||||
}
|
||||
a:active {
|
||||
background-color: $darkerGrey;
|
||||
}
|
||||
li {
|
||||
.update-metadata {
|
||||
font-size: 13px;
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
display: block;
|
||||
margin-bottom: $micro;
|
||||
.update-version {
|
||||
font-weight: $bold;
|
||||
background-color: $shadeBlue;
|
||||
color: $darkGrey;
|
||||
padding: 0 4px 0 4px;
|
||||
margin-right: 8px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
}
|
||||
.update-description {
|
||||
font-size: 15px;
|
||||
line-height: 20px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
.widgets {
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
||||
.widgets__cloud {
|
||||
margin: $micro calc(-$micro / 2);
|
||||
}
|
||||
|
||||
.widgets__item {
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
background: transparent;
|
||||
color: $darkGrey;
|
||||
border: 2px solid $darkGreen;
|
||||
border-radius: $borderRadius;
|
||||
padding: calc($micro / 2) $micro;
|
||||
margin: calc($micro / 2);
|
||||
cursor: pointer;
|
||||
transition: color 0.2s ease, background 0.2s ease;
|
||||
display: inline-block;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.widgets__item:hover,
|
||||
.widgets__item_active {
|
||||
background: $darkGreen;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.widgets__container {
|
||||
margin: 1em 0;
|
||||
background: $lightGrey;
|
||||
border-radius: $borderRadius;
|
||||
transition: height 0.15s ease;
|
||||
}
|
||||
|
||||
.widget {
|
||||
padding: 0.5em 1em;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.widget_open {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.widget_closing {
|
||||
display: block;
|
||||
animation: widgetOpacity 0.15s ease forwards reverse;
|
||||
}
|
||||
|
||||
.widget_opening {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
opacity: 0;
|
||||
animation: widgetOpacity 0.15s 0.05s ease forwards;
|
||||
}
|
||||
|
||||
@keyframes widgetOpacity {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.widget pre {
|
||||
margin-right: 0 !important;
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
|
||||
.widget h3 {
|
||||
margin-top: 0 !important;
|
||||
}
|
96
website/src/global-styles.js
Normal file
96
website/src/global-styles.js
Normal file
@ -0,0 +1,96 @@
|
||||
import React from 'react';
|
||||
import { Global, css } from '@emotion/core';
|
||||
|
||||
import theme from './theme';
|
||||
|
||||
const globalStyles = css`
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
color: ${theme.colors.gray};
|
||||
font-family: ${theme.fontFamily};
|
||||
line-height: ${theme.lineHeight[2]};
|
||||
font-size: ${theme.fontsize[3]};
|
||||
background: ${theme.colors.shadeBlue};
|
||||
margin: 0;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
ol,
|
||||
ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
line-height: ${theme.lineHeight[1]};
|
||||
margin-top: 0;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: ${theme.colors.darkGreen};
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.gitter-open-chat-button {
|
||||
&,
|
||||
&:visited {
|
||||
padding: ${theme.space[3]} ${theme.space[4]};
|
||||
font-family: ${theme.fontFamily};
|
||||
font-size: ${theme.fontsize[3]};
|
||||
letter-spacing: 0.5px;
|
||||
line-height: 1;
|
||||
color: ${theme.colors.gray};
|
||||
background-color: ${theme.colors.green};
|
||||
box-shadow: 0 2px 16px 0 rgba(68, 74, 87, 0.15), 0 1px 4px 0 rgba(68, 74, 87, 0.3);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: ${theme.colors.lightGreen};
|
||||
box-shadow: 0 2px 16px 0 rgba(68, 74, 87, 0.25), 0 1px 4px 0 rgba(68, 74, 87, 0.5);
|
||||
}
|
||||
|
||||
&:focus {
|
||||
box-shadow: 0 0 6px 3px rgba(62, 160, 127, 0.6);
|
||||
transition: none;
|
||||
}
|
||||
|
||||
&:active {
|
||||
color: ${theme.colors.lightGray};
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const GlobalStyles = () => <Global styles={globalStyles} />;
|
||||
|
||||
export default GlobalStyles;
|
@ -1,4 +1,5 @@
|
||||
import React from 'react';
|
||||
import ChatButton from './components/chat-button';
|
||||
|
||||
class HTML extends React.Component {
|
||||
render() {
|
||||
@ -24,9 +25,7 @@ class HTML extends React.Component {
|
||||
{this.props.preBodyComponents}
|
||||
<div key={'body'} id="___gatsby" dangerouslySetInnerHTML={{ __html: this.props.body }} />
|
||||
{this.props.postBodyComponents}
|
||||
<a className="chat-button" href="/chat">
|
||||
<img src="/img/slack.svg" />
|
||||
</a>
|
||||
<ChatButton />
|
||||
<script src="//unpkg.com/docsearch.js@2.4.1/dist/cdn/docsearch.min.js" />
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0" y="0" viewBox="0 0 56.966 56.966" xml:space="preserve" width="16" height="12" enable-background="new 0 0 56.966 56.966"><path d="M55.146,51.887L41.588,37.786c3.486-4.144,5.396-9.358,5.396-14.786c0-12.682-10.318-23-23-23s-23,10.318-23,23 s10.318,23,23,23c4.761,0,9.298-1.436,13.177-4.162l13.661,14.208c0.571,0.593,1.339,0.92,2.162,0.92 c0.779,0,1.518-0.297,2.079-0.837C56.255,54.982,56.293,53.08,55.146,51.887z M23.984,6c9.374,0,17,7.626,17,17s-7.626,17-17,17 s-17-7.626-17-17S14.61,6,23.984,6z" fill="#FFF"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Capa_1" x="0" y="0" viewBox="0 0 56.966 56.966" xml:space="preserve" width="16" height="12" enable-background="new 0 0 56.966 56.966"><path d="M55.146,51.887L41.588,37.786c3.486-4.144,5.396-9.358,5.396-14.786c0-12.682-10.318-23-23-23s-23,10.318-23,23 s10.318,23,23,23c4.761,0,9.298-1.436,13.177-4.162l13.661,14.208c0.571,0.593,1.339,0.92,2.162,0.92 c0.779,0,1.518-0.297,2.079-0.837C56.255,54.982,56.293,53.08,55.146,51.887z M23.984,6c9.374,0,17,7.626,17,17s-7.626,17-17,17 s-17-7.626-17-17S14.61,6,23.984,6z" fill="#fff"/></svg>
|
||||
|
Before Width: | Height: | Size: 629 B After Width: | Height: | Size: 630 B |
@ -1,34 +1,48 @@
|
||||
import React from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
import { Link, graphql } from 'gatsby';
|
||||
import { css } from '@emotion/core';
|
||||
|
||||
import Layout from '../components/layout';
|
||||
import Container from '../components/container';
|
||||
import MetaInfo from '../components/meta-info';
|
||||
import Page from '../components/page';
|
||||
import Lead from '../components/lead';
|
||||
|
||||
import theme from '../theme';
|
||||
|
||||
const Blog = ({ data }) => (
|
||||
<Layout>
|
||||
<div className="blog page">
|
||||
<Helmet>
|
||||
<title>Blog</title>
|
||||
<meta name="description" content="Recent news and updates about Netlify CMS." />
|
||||
</Helmet>
|
||||
<div className="container">
|
||||
<Helmet>
|
||||
<title>Blog</title>
|
||||
<meta name="description" content="Recent news and updates about Netlify CMS." />
|
||||
</Helmet>
|
||||
<Page>
|
||||
<Container size="sm">
|
||||
<h1>Netlify CMS Blog</h1>
|
||||
{data.allMarkdownRemark.edges.map(({ node }) => (
|
||||
<article className="blog-list-item" key={node.id}>
|
||||
<h2>
|
||||
<Link to={node.fields.slug} className="article">
|
||||
{node.frontmatter.title}
|
||||
</Link>
|
||||
<article
|
||||
key={node.id}
|
||||
css={css`
|
||||
margin-bottom: ${theme.space[5]};
|
||||
`}
|
||||
>
|
||||
<h2
|
||||
css={css`
|
||||
margin-bottom: 0;
|
||||
`}
|
||||
>
|
||||
<Link to={node.fields.slug}>{node.frontmatter.title}</Link>
|
||||
</h2>
|
||||
<p className="meta-info">
|
||||
<MetaInfo>
|
||||
by {node.frontmatter.author} on {node.frontmatter.date}
|
||||
</p>
|
||||
<p>{node.frontmatter.description}</p>
|
||||
</MetaInfo>
|
||||
<Lead>{node.frontmatter.description}</Lead>
|
||||
</article>
|
||||
))}
|
||||
{/* TODO: pagination */}
|
||||
</div>
|
||||
</div>
|
||||
</Container>
|
||||
</Page>
|
||||
</Layout>
|
||||
);
|
||||
|
||||
|
@ -1,19 +1,60 @@
|
||||
import React from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
import { graphql } from 'gatsby';
|
||||
import { css } from '@emotion/core';
|
||||
|
||||
import Layout from '../components/layout';
|
||||
import Community from '../components/community';
|
||||
import Markdownify from '../components/markdownify';
|
||||
import PageHero from '../components/page-hero';
|
||||
import HeroTitle from '../components/hero-title';
|
||||
import Lead from '../components/lead';
|
||||
import Container from '../components/container';
|
||||
import SectionLabel from '../components/section-label';
|
||||
import Page from '../components/page';
|
||||
import Grid from '../components/grid';
|
||||
import CommunityChannelsList from '../components/community-channels-list';
|
||||
|
||||
import '../css/imports/collab.css';
|
||||
import theme from '../theme';
|
||||
|
||||
const CommunityPage = ({ data }) => {
|
||||
const { title, headline, subhead, sections } = data.markdownRemark.frontmatter;
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<Layout hasPageHero>
|
||||
<Helmet title={title} />
|
||||
<Community headline={headline} subhead={subhead} sections={sections} />
|
||||
<PageHero>
|
||||
<div
|
||||
css={css`
|
||||
margin-bottom: 20px;
|
||||
`}
|
||||
>
|
||||
<HeroTitle>
|
||||
<Markdownify source={headline} />
|
||||
</HeroTitle>
|
||||
<Lead light>
|
||||
<Markdownify source={subhead} />
|
||||
</Lead>
|
||||
</div>
|
||||
</PageHero>
|
||||
|
||||
<Container>
|
||||
<Page>
|
||||
<Grid cols={2}>
|
||||
<div
|
||||
css={css`
|
||||
margin-bottom: ${theme.space[5]};
|
||||
`}
|
||||
>
|
||||
{sections.map(({ title: sectionTitle, channels }, channelIdx) => (
|
||||
<React.Fragment key={channelIdx}>
|
||||
<SectionLabel>{sectionTitle}</SectionLabel>
|
||||
<CommunityChannelsList channels={channels} />
|
||||
</React.Fragment>
|
||||
))}
|
||||
</div>
|
||||
</Grid>
|
||||
</Page>
|
||||
</Container>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
@ -1,30 +1,69 @@
|
||||
import React from 'react';
|
||||
import { graphql } from 'gatsby';
|
||||
import styled from '@emotion/styled';
|
||||
import { css } from '@emotion/core';
|
||||
|
||||
import Layout from '../components/layout';
|
||||
import Markdownify from '../components/markdownify';
|
||||
import PageHero from '../components/page-hero';
|
||||
import HeroTitle from '../components/hero-title';
|
||||
import VideoEmbed from '../components/video-embed';
|
||||
import WhatsNew from '../components/whats-new';
|
||||
import Release from '../components/release';
|
||||
import Lead from '../components/lead';
|
||||
import Features from '../components/features';
|
||||
import HomeSection from '../components/home-section';
|
||||
import Grid from '../components/grid';
|
||||
|
||||
import '../css/imports/hero.css';
|
||||
import '../css/imports/cta.css';
|
||||
import '../css/imports/whatsnew.css';
|
||||
import '../css/imports/editors.css';
|
||||
import '../css/imports/community.css';
|
||||
import theme from '../theme';
|
||||
import { mq } from '../utils';
|
||||
|
||||
const Features = ({ items }) =>
|
||||
items.map(item => (
|
||||
<div className="feature" key={item.feature}>
|
||||
{item.imgpath && <img src={require(`../img/${item.imgpath}`)} alt="" />}
|
||||
<h3>
|
||||
<Markdownify source={item.feature} />
|
||||
</h3>
|
||||
<p>
|
||||
<Markdownify source={item.description} />
|
||||
</p>
|
||||
</div>
|
||||
));
|
||||
const MarkdownButton = styled.span`
|
||||
a {
|
||||
white-space: nowrap;
|
||||
display: inline-block;
|
||||
color: white;
|
||||
text-transform: uppercase;
|
||||
font-weight: 700;
|
||||
font-size: ${theme.fontsize[3]};
|
||||
letter-spacing: 0.5px;
|
||||
line-height: ${theme.lineHeight[1]};
|
||||
background-color: ${theme.colors.blue};
|
||||
background-image: linear-gradient(-180deg, #4a7fdd 0%, #3a69c7 100%);
|
||||
box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.3), 0 1px 3px 0 rgba(0, 0, 0, 0.6);
|
||||
border-radius: ${theme.radii[1]};
|
||||
padding: ${theme.space[2]} ${theme.space[3]};
|
||||
transition: 0.2s;
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.05);
|
||||
box-shadow: 0 4px 12px 0 rgba(0, 0, 0, 0.5), 0 1px 3px 0 rgba(0, 0, 0, 1);
|
||||
}
|
||||
&:active {
|
||||
transform: scale(0.95);
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const ContribList = styled.div`
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
img {
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
border-radius: 10rem;
|
||||
margin-right: ${theme.space[1]};
|
||||
margin-bottom: ${theme.space[1]};
|
||||
transition: 0.1s;
|
||||
|
||||
&:hover {
|
||||
transform: scale(1.3);
|
||||
box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.25), 0 4px 12px 0 rgba(0, 0, 0, 0.25);
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const HomePage = ({ data }) => {
|
||||
const landing = data.landing.childDataYaml;
|
||||
@ -32,90 +71,115 @@ const HomePage = ({ data }) => {
|
||||
const contribs = data.contribs.childDataJson;
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<div className="landing page">
|
||||
<section className="landing hero">
|
||||
<div className="contained">
|
||||
<div className="hero-copy">
|
||||
<h1 className="headline">
|
||||
<Markdownify source={landing.hero.headline} />
|
||||
</h1>
|
||||
<span className="subhead">
|
||||
<Markdownify source={landing.hero.subhead} />
|
||||
</span>
|
||||
<span className="cta-header">
|
||||
<Markdownify source={landing.cta.button} />
|
||||
</span>
|
||||
</div>
|
||||
<div className="hero-features">
|
||||
<Features items={landing.hero.devfeatures} />
|
||||
</div>
|
||||
<Layout hasPageHero>
|
||||
<PageHero>
|
||||
<div
|
||||
css={css`
|
||||
margin-bottom: ${theme.space[7]};
|
||||
`}
|
||||
>
|
||||
<HeroTitle>
|
||||
<Markdownify source={landing.hero.headline} />
|
||||
</HeroTitle>
|
||||
<Lead>
|
||||
<Markdownify source={landing.hero.subhead} />
|
||||
</Lead>
|
||||
<Lead>
|
||||
<MarkdownButton>
|
||||
<Markdownify source={landing.cta.button} />
|
||||
</MarkdownButton>
|
||||
</Lead>
|
||||
</div>
|
||||
<Grid cols={2}>
|
||||
<div>
|
||||
<Features items={landing.hero.devfeatures} kind="light" />
|
||||
</div>
|
||||
<div>
|
||||
<VideoEmbed />
|
||||
</div>
|
||||
</section>
|
||||
</Grid>
|
||||
</PageHero>
|
||||
|
||||
<section className="cta">
|
||||
<div className="cta-primary">
|
||||
<p>
|
||||
<span className="hook">
|
||||
<Markdownify source={landing.cta.primaryhook} />
|
||||
</span>{' '}
|
||||
<Markdownify source={landing.cta.primary} />
|
||||
</p>
|
||||
<section
|
||||
css={css`
|
||||
background: white;
|
||||
${mq[2]} {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -75%);
|
||||
width: 880px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
`}
|
||||
>
|
||||
<div
|
||||
css={css`
|
||||
padding: ${theme.space[4]} ${theme.space[5]};
|
||||
color: ${theme.colors.lightishGray};
|
||||
${mq[2]} {
|
||||
display: flex;
|
||||
}
|
||||
`}
|
||||
>
|
||||
<Lead
|
||||
css={css`
|
||||
margin-right: 2rem;
|
||||
font-size: 18px;
|
||||
${mq[2]} {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
`}
|
||||
>
|
||||
<strong>
|
||||
<Markdownify source={landing.cta.primaryhook} />
|
||||
</strong>{' '}
|
||||
<Markdownify source={landing.cta.primary} />
|
||||
</Lead>
|
||||
<MarkdownButton>
|
||||
<Markdownify source={landing.cta.button} />
|
||||
</div>
|
||||
</section>
|
||||
</MarkdownButton>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<WhatsNew>
|
||||
{updates.updates.slice(0, 3).map((node, idx) => (
|
||||
<Release
|
||||
key={idx}
|
||||
version={node.version}
|
||||
versionPrevious={updates.updates[idx + 1].version}
|
||||
date={node.date}
|
||||
description={node.description}
|
||||
url={node.url}
|
||||
/>
|
||||
))}
|
||||
</WhatsNew>
|
||||
<WhatsNew updates={updates.updates} />
|
||||
|
||||
<section className="editors">
|
||||
<div className="contained">
|
||||
<h2>
|
||||
<Markdownify source={landing.editors.hook} />
|
||||
</h2>
|
||||
<p id="editor-intro">
|
||||
<Markdownify source={landing.editors.intro} />
|
||||
</p>
|
||||
<div className="editors-features">
|
||||
<Features items={landing.editors.features} />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<HomeSection
|
||||
title={<Markdownify source={landing.editors.hook} />}
|
||||
text={<Markdownify source={landing.editors.intro} />}
|
||||
>
|
||||
<Grid cols={3}>
|
||||
<Features items={landing.editors.features} />
|
||||
</Grid>
|
||||
</HomeSection>
|
||||
|
||||
<section className="communitysupport">
|
||||
<div className="contained">
|
||||
<h2>
|
||||
<Markdownify source={landing.community.hook} />
|
||||
</h2>
|
||||
<div className="community">
|
||||
<div className="community-features">
|
||||
<Features items={landing.community.features} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="contributors feature">
|
||||
<h3>{landing.community.contributors}</h3>
|
||||
<div className="contributor-list">
|
||||
{contribs.contributors.map(user => (
|
||||
<a href={user.profile} title={user.name} key={user.login}>
|
||||
<img src={user.avatar_url.replace('v=4', 's=32')} alt={user.login} />
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<HomeSection
|
||||
css={css`
|
||||
background: white;
|
||||
`}
|
||||
title={<Markdownify source={landing.community.hook} />}
|
||||
>
|
||||
<Grid cols={2}>
|
||||
<div>
|
||||
<Features items={landing.community.features} />
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<div>
|
||||
<h3
|
||||
css={css`
|
||||
font-size: 18px;
|
||||
`}
|
||||
>
|
||||
{landing.community.contributors}
|
||||
</h3>
|
||||
<ContribList>
|
||||
{contribs.contributors.map(user => (
|
||||
<a href={user.profile} title={user.name} key={user.login}>
|
||||
<img src={user.avatar_url.replace('v=4', 's=32')} alt={user.login} />
|
||||
</a>
|
||||
))}
|
||||
</ContribList>
|
||||
</div>
|
||||
</Grid>
|
||||
</HomeSection>
|
||||
</Layout>
|
||||
);
|
||||
};
|
||||
|
@ -2,24 +2,31 @@ import React from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
import { graphql } from 'gatsby';
|
||||
import { trimStart, trimEnd } from 'lodash';
|
||||
import { css } from '@emotion/core';
|
||||
|
||||
import TwitterMeta from '../components/twitter-meta';
|
||||
import Layout from '../components/layout';
|
||||
import Container from '../components/container';
|
||||
import Markdown from '../components/markdown';
|
||||
import MetaInfo from '../components/meta-info';
|
||||
import Page from '../components/page';
|
||||
|
||||
export const BlogPostTemplate = ({ title, author, date, body, html }) => (
|
||||
<div className="docs page">
|
||||
<div className="container">
|
||||
<article className="blog-content" id="blog-content">
|
||||
<div className="blog-post-header">
|
||||
<h1>{title}</h1>
|
||||
<p className="meta-info">
|
||||
by {author} on {date}
|
||||
</p>
|
||||
</div>
|
||||
{body ? body : <div dangerouslySetInnerHTML={{ __html: html }} />}
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
<Container size="sm">
|
||||
<Page as="article">
|
||||
<h1
|
||||
css={css`
|
||||
margin-bottom: 0;
|
||||
`}
|
||||
>
|
||||
{title}
|
||||
</h1>
|
||||
<MetaInfo>
|
||||
by {author} on {date}
|
||||
</MetaInfo>
|
||||
<Markdown html={body || html} />
|
||||
</Page>
|
||||
</Container>
|
||||
);
|
||||
|
||||
const BlogPost = ({ data }) => {
|
||||
|
@ -7,9 +7,9 @@ import Layout from '../components/layout';
|
||||
import EditLink from '../components/edit-link';
|
||||
import Widgets from '../components/widgets';
|
||||
import DocsNav from '../components/docs-nav';
|
||||
import MobileNav from '../components/mobile-nav';
|
||||
|
||||
import '../css/imports/docs.css';
|
||||
import Container from '../components/container';
|
||||
import SidebarLayout from '../components/sidebar-layout';
|
||||
import Markdown from '../components/markdown';
|
||||
|
||||
const toMenu = (menu, nav) =>
|
||||
menu.map(group => ({
|
||||
@ -17,10 +17,9 @@ const toMenu = (menu, nav) =>
|
||||
group: nav.group.find(g => g.fieldValue === group.name),
|
||||
}));
|
||||
|
||||
const DocsSidebar = ({ docsNav, location, history }) => (
|
||||
<aside id="sidebar" className="sidebar">
|
||||
const DocsSidebar = ({ docsNav, location }) => (
|
||||
<aside>
|
||||
<DocsNav items={docsNav} location={location} />
|
||||
<MobileNav items={docsNav} history={history} />
|
||||
</aside>
|
||||
);
|
||||
|
||||
@ -34,22 +33,22 @@ export const DocsTemplate = ({
|
||||
showSidebar,
|
||||
docsNav,
|
||||
location,
|
||||
history,
|
||||
}) => (
|
||||
<div className="docs detail page">
|
||||
<div className="container">
|
||||
{showSidebar && <DocsSidebar docsNav={docsNav} location={location} history={history} />}
|
||||
<article className="docs-content" id="docs-content">
|
||||
<Container size="md">
|
||||
<SidebarLayout
|
||||
sidebar={<div>{showSidebar && <DocsSidebar docsNav={docsNav} location={location} />}</div>}
|
||||
>
|
||||
<article data-docs-content>
|
||||
{editLinkPath && <EditLink path={editLinkPath} />}
|
||||
<h1>{title}</h1>
|
||||
{body ? body : <div dangerouslySetInnerHTML={{ __html: html }} />}
|
||||
<Markdown html={body || html} />
|
||||
{showWidgets && <Widgets widgets={widgets} />}
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</SidebarLayout>
|
||||
</Container>
|
||||
);
|
||||
|
||||
const DocPage = ({ data, location, history }) => {
|
||||
const DocPage = ({ data, location }) => {
|
||||
const { nav, page, widgets, menu } = data;
|
||||
|
||||
const docsNav = toMenu(menu.siteMetadata.menu.docs, nav);
|
||||
@ -66,7 +65,6 @@ const DocPage = ({ data, location, history }) => {
|
||||
widgets={widgets}
|
||||
docsNav={docsNav}
|
||||
location={location}
|
||||
history={history}
|
||||
showSidebar
|
||||
/>
|
||||
</Layout>
|
||||
|
@ -1,50 +1,37 @@
|
||||
// if you change these you must restart the server
|
||||
|
||||
module.exports = {
|
||||
// colors
|
||||
lightestGrey: '#E6E6E6',
|
||||
lighterGrey: '#F7F8F8',
|
||||
lightGrey: '#F6F6F6',
|
||||
lightishGrey: '#51555D',
|
||||
grey: '#313D3E',
|
||||
darkGrey: '#2F3132',
|
||||
darkerGrey: '#1E1F21',
|
||||
blueGrey: '#BCC2CE',
|
||||
lightGreen: '#97bf2f',
|
||||
green: '#C9FA4B',
|
||||
darkGreen: '#7CA511',
|
||||
darkerGreen: '#628013',
|
||||
shadeBlue: '#EFF0F4',
|
||||
blue: '#3A69C7',
|
||||
|
||||
// typography
|
||||
thin: 100,
|
||||
light: 300,
|
||||
regular: 400,
|
||||
semibold: 500,
|
||||
bold: 700,
|
||||
black: 900,
|
||||
|
||||
// fonts
|
||||
roboto: "'Roboto', -apple-system, BlinkMacSystemFont, Helvetica, Arial, sans-serif",
|
||||
|
||||
// padding
|
||||
micro: '8px',
|
||||
tiny: '16px',
|
||||
small: '24px',
|
||||
medium: '40px',
|
||||
large: '64px',
|
||||
xl: '104px',
|
||||
xxl: '152px',
|
||||
|
||||
// border radius
|
||||
borderRadius: '4px',
|
||||
largeBorderRadius: '8px',
|
||||
|
||||
// responsive breakpoints
|
||||
mobile: '480px',
|
||||
tablet: '768px',
|
||||
desktop: '960px',
|
||||
display: '1200px',
|
||||
xlarge: '1280px',
|
||||
colors: {
|
||||
white: '#fff',
|
||||
black: '#000',
|
||||
lightestGray: '#E6E6E6',
|
||||
lighterGray: '#F7F8F8',
|
||||
lightGray: '#F6F6F6',
|
||||
lightishGray: '#51555D',
|
||||
gray: '#313D3E',
|
||||
darkGray: '#2F3132',
|
||||
darkerGray: '#1E1F21',
|
||||
blueGray: '#BCC2CE',
|
||||
lightGreen: '#97bf2f',
|
||||
green: '#C9FA4B',
|
||||
darkGreen: '#7CA511',
|
||||
darkerGreen: '#628013',
|
||||
shadeBlue: '#EFF0F4',
|
||||
blue: '#3A69C7',
|
||||
},
|
||||
fontWeight: {
|
||||
thin: 100,
|
||||
light: 300,
|
||||
regular: 400,
|
||||
semibold: 500,
|
||||
bold: 700,
|
||||
black: 900,
|
||||
},
|
||||
fontFamily: "'Roboto', -apple-system, BlinkMacSystemFont, Helvetica, Arial, sans-serif",
|
||||
fontsize: ['10px', '12px', '14px', '16px', '18px', '24px', '32px', '42px', '64px'],
|
||||
lineHeight: [1, 1.3, 1.7],
|
||||
space: [0, '4px', '8px', '16px', '24px', '40px', '64px', '104px', '152px'],
|
||||
radii: [0, '4px', '8px'],
|
||||
breakpoints: [480, 768, 960, 1200, 1280],
|
||||
zIndexes: {
|
||||
header: 100,
|
||||
},
|
||||
};
|
||||
|
5
website/src/utils.js
Normal file
5
website/src/utils.js
Normal file
@ -0,0 +1,5 @@
|
||||
import theme from './theme';
|
||||
|
||||
export const mq = theme.breakpoints.map(bp => `@media (min-width: ${bp}px)`);
|
||||
|
||||
export const themeGet = (key, initial) => props => props.theme[key] || initial;
|
10114
website/yarn.lock
10114
website/yarn.lock
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user