convert website from hugo to gatsby (#1369)
70
website/src/components/docs-nav.js
Normal file
@ -0,0 +1,70 @@
|
||||
import React, { Component } from 'react';
|
||||
import Link from 'gatsby-link';
|
||||
|
||||
/**
|
||||
* Maually 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: []
|
||||
};
|
||||
|
||||
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>
|
||||
))}
|
||||
</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>
|
||||
);
|
||||
|
||||
export default DocsNav;
|
39
website/src/components/docsearch.js
Normal file
@ -0,0 +1,39 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import searchIcon from '../img/search.svg';
|
||||
|
||||
class DocSearch extends Component {
|
||||
state = {
|
||||
enabled: true
|
||||
};
|
||||
componentDidMount() {
|
||||
if (window.docsearch) {
|
||||
window.docsearch({
|
||||
apiKey: '08d03dc80862e84c70c5a1e769b13019',
|
||||
indexName: 'netlifycms',
|
||||
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;
|
||||
}
|
||||
|
||||
return (
|
||||
<a className="utility-input">
|
||||
<img src={searchIcon} />
|
||||
<input
|
||||
type="search"
|
||||
placeholder="Search the docs"
|
||||
className="algolia-search"
|
||||
/>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default DocSearch;
|
30
website/src/components/edit-link.js
Normal file
@ -0,0 +1,30 @@
|
||||
import React from 'react';
|
||||
|
||||
const EditLink = ({ path }) => (
|
||||
<a
|
||||
className="edit-this-page"
|
||||
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>
|
||||
);
|
||||
|
||||
export default EditLink;
|
71
website/src/components/event-widget.js
Normal file
@ -0,0 +1,71 @@
|
||||
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);
|
||||
// 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;
|
36
website/src/components/footer.js
Normal file
@ -0,0 +1,36 @@
|
||||
import React from 'react';
|
||||
|
||||
import '../css/imports/footer.css';
|
||||
|
||||
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>
|
||||
);
|
||||
|
||||
export default Footer;
|
94
website/src/components/header.js
Normal file
@ -0,0 +1,94 @@
|
||||
import React, { Component } from 'react';
|
||||
import Link from 'gatsby-link';
|
||||
import classnames from 'classnames';
|
||||
|
||||
import DocSearch from './docsearch';
|
||||
|
||||
import logo from '../img/netlify-cms-logo.svg';
|
||||
|
||||
import '../css/imports/header.css';
|
||||
|
||||
class Header extends Component {
|
||||
state = {
|
||||
scrolled: false
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
// TODO: use raf to throttle events
|
||||
window.addEventListener('scroll', this.handleScroll);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
window.removeEventListener('scroll', this.handleScroll);
|
||||
}
|
||||
|
||||
handleScroll = event => {
|
||||
const currentWindowPos =
|
||||
document.documentElement.scrollTop || document.body.scrollTop;
|
||||
|
||||
const scrolled = currentWindowPos > 0;
|
||||
|
||||
this.setState({
|
||||
scrolled
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { location } = this.props;
|
||||
const { scrolled } = this.state;
|
||||
|
||||
const isDocs = location.pathname.indexOf('docs') !== -1;
|
||||
const isBlog = location.pathname.indexOf('blog') !== -1;
|
||||
|
||||
return (
|
||||
<header
|
||||
id="header"
|
||||
className={classnames({
|
||||
docs: isDocs,
|
||||
blog: isBlog,
|
||||
scrolled
|
||||
})}
|
||||
>
|
||||
<div className="contained">
|
||||
<div className="logo-container">
|
||||
<Link to="/" className="logo">
|
||||
<img src={logo} />
|
||||
</Link>
|
||||
{isDocs && <DocSearch />}
|
||||
</div>
|
||||
<div className="nav-container">
|
||||
<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>
|
||||
<span className="gh-button">
|
||||
<a
|
||||
id="ghstars"
|
||||
className="github-button"
|
||||
href="https://github.com/netlify/netlify-cms"
|
||||
data-icon="octicon-star"
|
||||
data-show-count="true"
|
||||
aria-label="Star netlify/netlify-cms on GitHub"
|
||||
>
|
||||
Star
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Header;
|
11
website/src/components/markdownify.js
Normal file
@ -0,0 +1,11 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import Markdown from 'react-markdown';
|
||||
|
||||
const Markdownify = ({ source }) => (
|
||||
<Markdown
|
||||
source={source}
|
||||
renderers={{ root: Fragment, paragraph: Fragment }}
|
||||
/>
|
||||
);
|
||||
|
||||
export default Markdownify;
|
32
website/src/components/mobile-nav.js
Normal file
@ -0,0 +1,32 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
class MobileNav extends Component {
|
||||
handleChange = event => {
|
||||
this.props.history.push(event.target.value);
|
||||
};
|
||||
render() {
|
||||
const { items } = this.props;
|
||||
|
||||
return (
|
||||
<div className="mobile docs-nav">
|
||||
<select className="btn-primary" onChange={this.handleChange}>
|
||||
<option>Select A Topic</option>
|
||||
{items.map(item => (
|
||||
<optgroup label={item.title} key={item.title}>
|
||||
{item.group.edges.map(({ node }) => (
|
||||
<option
|
||||
value={node.fields.slug}
|
||||
key={node.fields.slug}
|
||||
className="nav-link">
|
||||
{node.frontmatter.title}
|
||||
</option>
|
||||
))}
|
||||
</optgroup>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default MobileNav;
|
41
website/src/components/video-embed.js
Normal file
@ -0,0 +1,41 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import screenshotEditor from '../img/screenshot-editor.jpg';
|
||||
|
||||
class VideoEmbed extends Component {
|
||||
state = {
|
||||
toggled: false
|
||||
};
|
||||
toggleVideo = event => {
|
||||
this.setState({
|
||||
toggled: true
|
||||
});
|
||||
};
|
||||
render() {
|
||||
const { toggled } = this.state;
|
||||
|
||||
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
|
||||
/>
|
||||
);
|
||||
|
||||
const imgPlaceholder = (
|
||||
<img src={screenshotEditor} className="responsive" />
|
||||
);
|
||||
|
||||
return (
|
||||
<a className="hero-graphic" onClick={this.toggleVideo}>
|
||||
{toggled ? embedcode : imgPlaceholder}
|
||||
{!toggled && <div className="hero-videolink">▶</div>}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default VideoEmbed;
|
90
website/src/components/widgets.js
Normal file
@ -0,0 +1,90 @@
|
||||
import React, { Component } from 'react';
|
||||
import classnames from 'classnames';
|
||||
|
||||
import '../css/imports/widgets.css';
|
||||
|
||||
class Widgets extends Component {
|
||||
state = {
|
||||
currentWidget: null
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
const { widgets } = this.props;
|
||||
|
||||
const hash = window.location.hash
|
||||
? window.location.hash.replace('#', '')
|
||||
: '';
|
||||
|
||||
const widgetsContainHash = widgets.edges.some(
|
||||
w => w.node.frontmatter.target === hash
|
||||
);
|
||||
|
||||
if (widgetsContainHash) {
|
||||
return this.setState({
|
||||
currentWidget: hash
|
||||
});
|
||||
}
|
||||
|
||||
this.setState({
|
||||
currentWidget: widgets.edges[0].node.frontmatter.target
|
||||
});
|
||||
}
|
||||
|
||||
handleWidgetChange = (event, target) => {
|
||||
event.preventDefault();
|
||||
this.setState(
|
||||
{
|
||||
currentWidget: target
|
||||
},
|
||||
() => {
|
||||
history.pushState(null, null, `#${target}`);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { widgets } = this.props;
|
||||
const { currentWidget } = this.state;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<section className="widgets">
|
||||
<div className="widgets__cloud">
|
||||
{widgets.edges.map(({ node }) => {
|
||||
const { label, target } = node.frontmatter;
|
||||
return (
|
||||
<button
|
||||
key={target}
|
||||
className={classnames('widgets__item', {
|
||||
widgets__item_active: currentWidget === target
|
||||
})}
|
||||
onClick={event => this.handleWidgetChange(event, target)}
|
||||
>
|
||||
{label}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div className="widgets__container">
|
||||
{widgets.edges.map(({ node }) => {
|
||||
const { label, target } = node.frontmatter;
|
||||
return (
|
||||
<div
|
||||
key={label}
|
||||
className={classnames('widget', {
|
||||
widget_open: currentWidget === target
|
||||
})}
|
||||
>
|
||||
<h3>{label}</h3>
|
||||
<div dangerouslySetInnerHTML={{ __html: node.html }} />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Widgets;
|
@ -145,6 +145,12 @@ pre {
|
||||
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;
|
||||
|
@ -202,7 +202,6 @@
|
||||
h2:not(:first-child) {
|
||||
margin-top: $medium;
|
||||
}
|
||||
|
||||
p {
|
||||
line-height: 1.7;
|
||||
}
|
||||
@ -226,18 +225,13 @@
|
||||
border-radius: $borderRadius;
|
||||
}
|
||||
|
||||
code {
|
||||
:not(pre) > code {
|
||||
color: inherit;
|
||||
background: $lightestGrey;
|
||||
border-radius: 2px;
|
||||
padding: 2px 6px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
pre > code {
|
||||
background: initial;
|
||||
padding: initial;
|
||||
white-space: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
.blog-content h1 {
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
em {
|
||||
font-style: normal;
|
||||
color: #8B8B8B;
|
||||
color: #8b8b8b;
|
||||
padding: 0 8px;
|
||||
}
|
||||
|
||||
@ -71,7 +71,7 @@ header {
|
||||
position: absolute;
|
||||
padding: $medium 0;
|
||||
text-align: center;
|
||||
transition: background .2s ease, padding .2s ease, box-shadow .2s ease;
|
||||
transition: background 0.2s ease, padding 0.2s ease, box-shadow 0.2s ease;
|
||||
width: 100%;
|
||||
z-index: 100;
|
||||
|
||||
@ -102,14 +102,12 @@ header {
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
/*.utility-input {
|
||||
@media screen and (max-width: 767px) {
|
||||
display: block;
|
||||
height: $small;
|
||||
margin: $tiny 0 0 0;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 487px) and (max-width: 767px) {
|
||||
margin-top: 32px;
|
||||
}
|
||||
@ -131,7 +129,8 @@ header {
|
||||
}
|
||||
}
|
||||
|
||||
.nav-link + iframe {
|
||||
.gh-button {
|
||||
display: inline-block;
|
||||
margin-left: $small;
|
||||
vertical-align: middle;
|
||||
@media screen and (max-width: $mobile) {
|
||||
@ -184,7 +183,6 @@ header {
|
||||
margin-top: -35px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.utility-input {
|
||||
@ -194,7 +192,7 @@ header {
|
||||
top: -4px;
|
||||
width: auto;
|
||||
border-radius: 4px;
|
||||
background-color: rgba(255,255,255,0.1);
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
color: white;
|
||||
margin: 0 0 0 $tiny;
|
||||
padding-top: -5px;
|
||||
@ -204,7 +202,7 @@ header {
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
transition: all .2s ease-in-out;
|
||||
transition: all 0.2s ease-in-out;
|
||||
|
||||
@media screen and (min-width: 1024px) {
|
||||
display: inline;
|
||||
@ -218,13 +216,17 @@ header {
|
||||
&::-webkit-input-placeholder,
|
||||
&:-moz-placeholder,
|
||||
&::-moz-placeholder,
|
||||
&:-ms-input-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 {
|
||||
|
@ -1,65 +1,71 @@
|
||||
.widgets {
|
||||
margin: 2rem 0;
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
||||
.widgets__cloud {
|
||||
margin: $micro calc(-$micro / 2);
|
||||
margin: $micro calc(-$micro / 2);
|
||||
}
|
||||
|
||||
.widgets__item {
|
||||
color: $darkGrey;
|
||||
border: 2px solid $darkGreen;
|
||||
border-radius: $borderRadius;
|
||||
padding: calc($micro /2) $micro;
|
||||
margin: calc($micro / 2);
|
||||
cursor: pointer;
|
||||
transition: color .2s ease, background .2s ease;
|
||||
display: inline-block;
|
||||
font-weight: normal;
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
line-height: inherit;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
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__item:hover,
|
||||
.widgets__item_active {
|
||||
background: $darkGreen;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.widgets__container {
|
||||
margin: 1em 0;
|
||||
background: $lightGrey;
|
||||
border-radius: $borderRadius;
|
||||
transition: height .15s ease;
|
||||
margin: 1em 0;
|
||||
background: $lightGrey;
|
||||
border-radius: $borderRadius;
|
||||
transition: height 0.15s ease;
|
||||
}
|
||||
|
||||
.widget {
|
||||
padding: .5em 1em;
|
||||
display: none;
|
||||
padding: 0.5em 1em;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.widget_open {
|
||||
display: block;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.widget_closing {
|
||||
display: block;
|
||||
animation: widgetOpacity .15s ease forwards reverse;
|
||||
display: block;
|
||||
animation: widgetOpacity 0.15s ease forwards reverse;
|
||||
}
|
||||
|
||||
.widget_opening {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
opacity: 0;
|
||||
animation: widgetOpacity .15s .05s ease forwards;
|
||||
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
|
||||
}
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
.widget pre {
|
||||
@ -68,5 +74,5 @@
|
||||
}
|
||||
|
||||
.widget h3 {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
@ -1,13 +0,0 @@
|
||||
@import "imports/base.css";
|
||||
@import "imports/utilities.css";
|
||||
@import "imports/header.css";
|
||||
@import "imports/hero.css";
|
||||
@import "imports/cta.css";
|
||||
@import "imports/whatsnew.css";
|
||||
@import "imports/editors.css";
|
||||
@import "imports/community.css";
|
||||
@import "imports/collab.css";
|
||||
@import "imports/docs.css";
|
||||
@import "imports/widgets.css";
|
||||
@import "imports/footer.css";
|
||||
@import "imports/gitter.css";
|
86
website/src/html.js
Normal file
@ -0,0 +1,86 @@
|
||||
import React from 'react';
|
||||
import Gitter from 'react-sidecar';
|
||||
|
||||
let stylesStr;
|
||||
if (process.env.NODE_ENV === `production`) {
|
||||
try {
|
||||
stylesStr = require('!raw-loader!../public/styles.css');
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
const JS_NPM_URLS = [
|
||||
'https://buttons.github.io/buttons.js',
|
||||
'//unpkg.com/docsearch.js@2.4.1/dist/cdn/docsearch.min.js'
|
||||
];
|
||||
|
||||
module.exports = class HTML extends React.Component {
|
||||
render() {
|
||||
let css;
|
||||
if (process.env.NODE_ENV === 'production') {
|
||||
css = (
|
||||
<style
|
||||
id="gatsby-inlined-css"
|
||||
dangerouslySetInnerHTML={{ __html: stylesStr }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const js = JS_NPM_URLS.map(src => <script key={src} src={src} />);
|
||||
|
||||
return (
|
||||
<html {...this.props.htmlAttributes}>
|
||||
<head>
|
||||
<meta charSet="utf-8" />
|
||||
<meta httpEquiv="x-ua-compatible" content="ie=edge" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1.0"
|
||||
/>
|
||||
<link
|
||||
rel="apple-touch-icon"
|
||||
sizes="180x180"
|
||||
href="/img/favicon/apple-touch-icon.png"
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
href="/img/favicon/favicon-32x32.png"
|
||||
sizes="32x32"
|
||||
/>
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
href="/img/favicon/favicon-16x16.png"
|
||||
sizes="16x16"
|
||||
/>
|
||||
<link
|
||||
rel="mask-icon"
|
||||
href="/img/favicon/safari-pinned-tab.svg"
|
||||
color="#96cf05"
|
||||
/>
|
||||
<meta name="apple-mobile-web-app-title" content="NetlifyCMS" />
|
||||
<meta name="application-name" content="NetlifyCMS" />
|
||||
{this.props.headComponents}
|
||||
{css}
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://unpkg.com/docsearch.js@2.5.2/dist/cdn/docsearch.min.css"
|
||||
/>
|
||||
</head>
|
||||
<body {...this.props.bodyAttributes}>
|
||||
{this.props.preBodyComponents}
|
||||
<div
|
||||
key={'body'}
|
||||
id="___gatsby"
|
||||
dangerouslySetInnerHTML={{ __html: this.props.body }}
|
||||
/>
|
||||
{this.props.postBodyComponents}
|
||||
<Gitter room="netlify/NetlifyCMS" />
|
||||
{js}
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
};
|
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 56 KiB |
Before Width: | Height: | Size: 6.1 KiB |
@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<browserconfig>
|
||||
<msapplication>
|
||||
<tile>
|
||||
<square150x150logo src="/mstile-150x150.png"/>
|
||||
<TileColor>#222222</TileColor>
|
||||
</tile>
|
||||
</msapplication>
|
||||
</browserconfig>
|
Before Width: | Height: | Size: 560 B |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 15 KiB |
@ -1,18 +0,0 @@
|
||||
{
|
||||
"name": "NetlifyCMS",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"theme_color": "#ffffff",
|
||||
"background_color": "#ffffff",
|
||||
"display": "standalone"
|
||||
}
|
Before Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 4.5 KiB |
Before Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 9.8 KiB |
Before Width: | Height: | Size: 3.1 KiB |
@ -1,98 +0,0 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="16.000000pt" height="16.000000pt" viewBox="0 0 16.000000 16.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<metadata>
|
||||
Created by potrace 1.11, written by Peter Selinger 2001-2013
|
||||
</metadata>
|
||||
<g transform="translate(0.000000,16.000000) scale(0.002286,-0.002286)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M2750 6290 c-393 -390 -712 -711 -710 -714 3 -2 196 -85 430 -184
|
||||
234 -99 447 -189 473 -201 49 -21 49 -21 76 -2 74 53 141 66 299 58 33 -2 33
|
||||
-2 318 438 156 242 288 447 294 455 15 22 145 223 153 237 4 6 -113 131 -298
|
||||
315 -168 166 -309 304 -313 305 -4 1 -329 -317 -722 -707z"/>
|
||||
<path d="M4193 6162 c-23 -37 -92 -143 -152 -237 -60 -93 -200 -311 -311 -483
|
||||
-111 -172 -204 -321 -207 -331 -3 -11 2 -30 11 -42 8 -13 22 -51 30 -83 9 -32
|
||||
17 -60 19 -62 3 -4 76 -35 227 -99 69 -29 275 -116 459 -194 183 -78 339 -140
|
||||
345 -137 70 35 110 64 111 81 1 11 5 36 8 55 4 19 9 53 12 75 3 22 8 51 10 65
|
||||
3 14 7 39 9 55 3 17 14 86 25 155 12 69 23 143 27 165 3 22 7 51 10 65 5 32
|
||||
33 204 40 250 3 19 10 55 14 80 6 31 5 50 -3 60 -20 24 -627 625 -635 627 -4
|
||||
1 -26 -28 -49 -65z"/>
|
||||
<path d="M1495 5040 c-209 -209 -379 -383 -378 -388 2 -7 418 -619 440 -647 4
|
||||
-5 20 -28 35 -50 15 -22 103 -152 197 -289 l170 -248 109 -2 108 -1 88 135
|
||||
c48 74 109 169 136 210 26 41 167 259 313 485 l264 409 -33 49 c-19 27 -41 73
|
||||
-50 103 -15 52 -21 144 -11 161 11 17 -10 31 -108 73 -55 23 -279 118 -497
|
||||
211 -218 93 -398 169 -400 169 -2 0 -174 -171 -383 -380z"/>
|
||||
<path d="M5066 5373 c-7 -37 -66 -399 -72 -440 -2 -18 -11 -72 -19 -120 -9
|
||||
-49 -18 -104 -21 -123 -3 -19 -7 -46 -9 -60 -17 -105 -20 -93 38 -137 l53 -39
|
||||
43 18 c24 10 57 25 75 33 17 7 119 51 226 95 107 45 209 88 225 95 17 8 52 23
|
||||
79 35 l50 22 -327 324 c-180 178 -329 324 -331 324 -2 0 -7 -12 -10 -27z"/>
|
||||
<path d="M3491 4679 c-67 -81 -156 -122 -270 -123 l-63 -1 -234 -360 c-129
|
||||
-198 -238 -367 -242 -375 -4 -8 -41 -67 -82 -130 -202 -308 -234 -359 -227
|
||||
-367 5 -4 191 70 342 138 33 14 333 142 1165 496 58 25 119 51 135 58 17 7
|
||||
127 55 245 105 118 50 218 94 221 98 4 4 9 26 12 49 l5 41 -77 33 c-42 18
|
||||
-101 43 -131 57 -30 13 -93 40 -140 59 -47 19 -206 86 -353 149 -148 63 -269
|
||||
114 -270 114 -1 0 -17 -19 -36 -41z"/>
|
||||
<path d="M5755 4534 c-71 -31 -215 -92 -320 -136 -264 -112 -285 -122 -282
|
||||
-131 1 -5 93 -47 202 -93 110 -46 209 -88 220 -94 11 -5 81 -34 155 -66 74
|
||||
-31 149 -62 165 -69 17 -8 75 -32 130 -55 55 -23 114 -47 130 -55 204 -91 822
|
||||
-345 834 -343 11 3 -59 78 -209 227 -124 122 -371 368 -551 547 -179 178 -329
|
||||
324 -335 324 -5 0 -67 -26 -139 -56z"/>
|
||||
<path d="M720 4279 c-454 -445 -720 -713 -712 -720 4 -3 99 -25 212 -48 243
|
||||
-50 814 -169 850 -177 35 -8 61 -13 95 -20 17 -2 46 -9 65 -14 19 -5 50 -12
|
||||
68 -15 18 -3 65 -12 105 -21 39 -8 81 -17 92 -19 11 -3 52 -11 90 -19 116 -25
|
||||
109 -26 153 33 l41 54 -43 61 c-23 34 -130 187 -236 341 -428 620 -447 648
|
||||
-459 662 -6 7 -16 24 -23 38 -6 14 -14 25 -17 25 -4 0 -15 14 -24 30 -10 17
|
||||
-21 30 -25 30 -4 0 -109 -99 -232 -221z"/>
|
||||
<path d="M5030 4045 c-31 -33 -94 -70 -147 -85 -49 -15 -48 -13 -68 -155 -4
|
||||
-22 -8 -47 -10 -55 -2 -8 -7 -35 -10 -60 -3 -25 -10 -67 -15 -95 -5 -27 -11
|
||||
-66 -14 -85 -3 -19 -12 -75 -20 -125 -21 -124 -65 -392 -72 -439 -3 -21 -7
|
||||
-46 -9 -55 -19 -102 -19 -98 24 -147 26 -29 47 -68 58 -103 9 -31 21 -61 27
|
||||
-67 6 -6 58 -21 116 -32 58 -11 193 -39 300 -62 107 -22 209 -43 225 -46 17
|
||||
-3 46 -9 65 -14 29 -7 102 -23 215 -46 11 -2 31 -6 45 -9 14 -3 43 -8 65 -11
|
||||
l40 -5 490 487 490 487 -45 19 c-25 11 -209 89 -410 174 -201 85 -374 158
|
||||
-385 163 -11 5 -41 18 -67 30 -26 12 -50 21 -53 21 -2 0 -28 11 -57 24 -77 35
|
||||
-744 316 -751 316 -2 0 -14 -11 -27 -25z"/>
|
||||
<path d="M4465 3985 c-128 -56 -140 -61 -325 -140 -85 -36 -168 -72 -185 -79
|
||||
-16 -8 -75 -33 -130 -56 -154 -65 -1196 -509 -1230 -524 -16 -8 -54 -24 -82
|
||||
-36 -48 -20 -53 -25 -53 -54 0 -17 4 -36 8 -43 6 -10 143 -43 272 -67 14 -2
|
||||
81 -16 150 -31 69 -14 136 -29 150 -31 60 -12 221 -45 290 -59 243 -51 408
|
||||
-85 430 -89 14 -3 34 -7 45 -9 11 -3 103 -22 204 -43 l184 -37 19 24 c56 73
|
||||
132 123 200 131 35 5 38 9 44 50 3 18 14 87 25 153 23 141 26 157 34 210 3 23
|
||||
8 52 10 65 3 14 10 54 15 90 18 111 51 314 55 340 3 14 12 73 21 133 16 102
|
||||
16 108 -1 127 -24 27 -35 25 -150 -25z"/>
|
||||
<path d="M138 3305 c-8 -9 652 -660 665 -657 7 2 172 71 367 154 195 83 374
|
||||
158 398 167 23 9 42 22 42 28 0 7 -3 13 -7 14 -13 1 -39 6 -266 53 -120 25
|
||||
-228 48 -240 50 -66 13 -186 38 -217 46 -19 5 -48 11 -65 14 -50 9 -86 16
|
||||
-180 36 -49 11 -101 22 -115 24 -14 3 -101 21 -195 40 -186 39 -179 38 -187
|
||||
31z"/>
|
||||
<path d="M2406 2816 c-17 -27 -25 -13 106 -201 30 -44 111 -161 180 -260 68
|
||||
-99 140 -202 159 -230 19 -27 86 -124 149 -215 63 -91 274 -397 470 -680 196
|
||||
-283 387 -560 425 -615 38 -55 70 -102 72 -105 2 -2 28 20 58 50 46 46 56 62
|
||||
60 100 3 25 7 52 10 60 2 8 7 35 10 60 3 25 12 81 20 125 7 44 16 100 20 125
|
||||
3 25 10 68 15 95 5 28 12 68 15 90 3 23 8 52 10 65 3 14 8 43 11 65 2 22 18
|
||||
117 34 210 15 94 31 186 34 205 22 145 77 478 80 493 3 12 -7 23 -34 37 -47
|
||||
24 -103 89 -127 146 -21 51 -13 48 -218 88 -157 32 -251 51 -350 72 -42 9
|
||||
-121 26 -145 30 -14 2 -56 11 -95 20 -65 14 -136 29 -195 40 -14 3 -59 12
|
||||
-100 20 -41 9 -138 29 -215 44 -77 16 -205 43 -285 59 -80 17 -148 31 -151 31
|
||||
-4 0 -14 -11 -23 -24z"/>
|
||||
<path d="M1420 2684 c-162 -69 -330 -140 -372 -157 -43 -18 -78 -37 -78 -42 0
|
||||
-16 360 -366 370 -360 4 3 35 49 69 102 34 54 113 177 176 273 169 259 168
|
||||
256 149 286 -9 13 -17 24 -18 24 0 0 -134 -57 -296 -126z"/>
|
||||
<path d="M2185 2642 c-43 -16 -193 -21 -237 -8 -25 7 -29 3 -85 -83 -32 -51
|
||||
-89 -140 -128 -200 -38 -59 -86 -132 -104 -162 -19 -30 -59 -90 -88 -135 -29
|
||||
-45 -53 -86 -53 -91 0 -10 424 -435 940 -943 113 -111 388 -383 611 -606 224
|
||||
-222 412 -405 418 -406 6 -2 89 75 185 171 l175 174 -22 32 c-12 18 -50 73
|
||||
-83 122 -34 48 -116 167 -182 263 -66 96 -135 195 -152 220 -38 54 -241 348
|
||||
-351 510 -44 63 -93 135 -110 160 -18 25 -176 254 -352 510 -175 256 -324 470
|
||||
-331 476 -8 8 -22 6 -51 -4z"/>
|
||||
<path d="M4683 2343 c-9 -13 -40 -38 -68 -54 l-52 -29 -22 -133 c-11 -72 -23
|
||||
-143 -25 -157 -6 -32 -37 -228 -41 -255 -2 -11 -26 -157 -53 -325 -28 -168
|
||||
-53 -323 -56 -345 -4 -22 -11 -68 -17 -103 -12 -67 -8 -83 14 -61 419 410
|
||||
1287 1276 1287 1284 0 6 -73 25 -162 43 -90 19 -172 35 -183 38 -11 2 -54 11
|
||||
-95 19 -41 8 -86 18 -100 21 -14 3 -36 7 -50 10 -14 3 -88 18 -165 34 -210 43
|
||||
-193 42 -212 13z"/>
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 6.2 KiB |
@ -1,135 +0,0 @@
|
||||
// Sticky Nav Functionality in Vanilla JS
|
||||
|
||||
var header = $("#header");
|
||||
|
||||
if ($('.landing.page, .community.page').length) {
|
||||
window.onscroll = function() {
|
||||
|
||||
var currentWindowPos = document.documentElement.scrollTop || document.body.scrollTop;
|
||||
|
||||
if (currentWindowPos > 0) {
|
||||
header.addClass('scrolled');
|
||||
} else {
|
||||
header.removeClass('scrolled');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Auto Indexing Docs Nav
|
||||
|
||||
var indexDocsSubsections = function() {
|
||||
if ($('.docs.page').length) {
|
||||
|
||||
if ($('#docs-content h2').length > 1) {
|
||||
$('<ul class="nav-subsections" id="nav-subsections"></ul>').insertAfter($('#docs-nav .nav-link.active'));
|
||||
|
||||
$('#docs-content h2').each(function() {
|
||||
var sectionTitle = $(this).html(),
|
||||
anchor = $(this).attr("id");
|
||||
|
||||
$('#nav-subsections').append('<li><a class="subnav-link for-' + anchor + '" href="#' + anchor + '">' + sectionTitle + '</a></li>');
|
||||
|
||||
});
|
||||
|
||||
$.localScroll({
|
||||
offset: -120,
|
||||
duration:200,
|
||||
hash:true
|
||||
});
|
||||
}
|
||||
|
||||
$(window).on('scroll', function(){
|
||||
window.requestAnimationFrame(scrollHandler);
|
||||
|
||||
function scrollHandler() {
|
||||
var scrollTop = $(window).scrollTop(),
|
||||
windowHeight = $(window).height(),
|
||||
first = false,
|
||||
allSubnavLinks = $("#docs-nav .subnav-link");
|
||||
|
||||
$("#docs-content h2").each( function() {
|
||||
var offset = $(this).offset(),
|
||||
thisLink = '.for-' + $(this).attr("id");
|
||||
|
||||
if (scrollTop <= offset.top && ($(this).height() + offset.top) < (scrollTop + windowHeight) && first == false) {
|
||||
allSubnavLinks.removeClass('active');
|
||||
$(thisLink).addClass('active');
|
||||
first=true;
|
||||
} else {
|
||||
first=false;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
indexDocsSubsections();
|
||||
|
||||
var docsMobileMenu = function() {
|
||||
if ($('.docs.page').length) {
|
||||
|
||||
$("#mobile-docs-nav").change(function() {
|
||||
window.location = $(this).find("option:selected").val();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
docsMobileMenu();
|
||||
|
||||
// search
|
||||
$('#search-button').click(function() {
|
||||
console.log("clicked")
|
||||
$('.search-icon').toggleClass('active');
|
||||
$('.algolia-search').toggleClass('closed');
|
||||
});
|
||||
|
||||
|
||||
// eventbrite info
|
||||
var eventInfoLoad = function() {
|
||||
if ($('.community.page').length) {
|
||||
var eventRequest = new XMLHttpRequest;
|
||||
var eventbriteToken = 'C5PX65CJBVIXWWLNFKLO';
|
||||
var eventbriteOrganiser = '14281996019';
|
||||
eventRequest.open('GET', 'https://www.eventbriteapi.com/v3/events/search/?token=' + eventbriteToken + '&organizer.id=' + eventbriteOrganiser + '&expand=venue%27', true);
|
||||
|
||||
eventRequest.onload = function() {
|
||||
if (eventRequest.status >= 200 && eventRequest.status < 400) {
|
||||
// Success!
|
||||
var data = JSON.parse(eventRequest.responseText);
|
||||
var upcomingDate = data.events[0].start.utc;
|
||||
updateDate(upcomingDate);
|
||||
} else {
|
||||
var upcomingDate = "0000-00-00T00:00:00Z";
|
||||
updateDate(upcomingDate);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
eventRequest.onerror = function() {
|
||||
alert('The event info could not be loaded at this time, please try again later.');
|
||||
};
|
||||
|
||||
function updateDate(eventDate) {
|
||||
const eventDateMoment = moment(eventDate);
|
||||
const offset = eventDateMoment.isDST() ? -7 : -8;
|
||||
$('.month').append(eventDateMoment.format('MMMM'));
|
||||
$('.day').append(eventDateMoment.format('DD'));
|
||||
$('.calendar-cta h3 strong:first-child()').append(eventDateMoment.format('dddd, MMMM Do'));
|
||||
$('.calendar-cta h3 strong:last-child()').append(`${eventDateMoment.utcOffset(offset).format('h a')} PT`);
|
||||
}
|
||||
|
||||
eventRequest.send();
|
||||
}
|
||||
}
|
||||
|
||||
eventInfoLoad();
|
||||
|
||||
|
||||
// Load inline YouTube video
|
||||
var 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></iframe>';
|
||||
|
||||
$('.hero-graphic').click(function() {
|
||||
$('.hero-graphic img').replaceWith(embedcode);
|
||||
$('.hero-videolink').remove();
|
||||
});
|
66
website/src/layouts/index.js
Normal file
@ -0,0 +1,66 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
import classnames from 'classnames';
|
||||
|
||||
import Header from '../components/header';
|
||||
import Footer from '../components/footer';
|
||||
|
||||
import '../css/imports/base.css';
|
||||
import '../css/imports/utilities.css';
|
||||
import '../css/imports/gitter.css';
|
||||
|
||||
const Layout = ({ data, location, children }) => {
|
||||
const { title, description } = data.site.siteMetadata;
|
||||
const notifs = data.notifs.notifications.filter(notif => notif.published);
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<Helmet defaultTitle={title} titleTemplate={`%s | ${title}`}>
|
||||
<meta name="description" content={description} />
|
||||
</Helmet>
|
||||
{notifs.map((node, i) => (
|
||||
<a
|
||||
key={i}
|
||||
href={node.url}
|
||||
className={classnames('notification', {
|
||||
'notification-loud': node.loud
|
||||
})}
|
||||
>
|
||||
{node.message}
|
||||
</a>
|
||||
))}
|
||||
<Header location={location} notifications={notifs} />
|
||||
{children()}
|
||||
<Footer buttons={data.dataYaml.footer.buttons} />
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export const pageQuery = graphql`
|
||||
query layoutQuery {
|
||||
site {
|
||||
siteMetadata {
|
||||
title
|
||||
description
|
||||
}
|
||||
}
|
||||
dataYaml(id: { regex: "/global/" }) {
|
||||
footer {
|
||||
buttons {
|
||||
url
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
notifs: dataYaml(id: { regex: "/notifications/" }) {
|
||||
notifications {
|
||||
published
|
||||
loud
|
||||
message
|
||||
url
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default Layout;
|
58
website/src/pages/blog.js
Normal file
@ -0,0 +1,58 @@
|
||||
import React from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
import Link from 'gatsby-link';
|
||||
|
||||
const Blog = ({ data }) => (
|
||||
<div className="blog page">
|
||||
<Helmet>
|
||||
<title>Blog</title>
|
||||
<meta
|
||||
name="description"
|
||||
content="Recent news and updates about Netlify CMS."
|
||||
/>
|
||||
</Helmet>
|
||||
<div className="container">
|
||||
<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>
|
||||
</h2>
|
||||
<p className="meta-info">
|
||||
by {node.frontmatter.author} on {node.frontmatter.date}
|
||||
</p>
|
||||
<p>{node.frontmatter.description}</p>
|
||||
</article>
|
||||
))}
|
||||
{/* TODO: pagination */}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
export default Blog;
|
||||
|
||||
export const pageQuery = graphql`
|
||||
query blogList {
|
||||
allMarkdownRemark(
|
||||
filter: { fields: { slug: { regex: "/blog/" } } }
|
||||
sort: { order: DESC, fields: [fields___date] }
|
||||
) {
|
||||
edges {
|
||||
node {
|
||||
id
|
||||
frontmatter {
|
||||
title
|
||||
description
|
||||
author
|
||||
date(formatString: "MMMM D, YYYY")
|
||||
}
|
||||
fields {
|
||||
slug
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
87
website/src/pages/community.js
Normal file
@ -0,0 +1,87 @@
|
||||
import React, { Component } from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
import Markdown from 'react-markdown';
|
||||
|
||||
import EventWidget from '../components/event-widget';
|
||||
import Markdownify from '../components/markdownify';
|
||||
|
||||
import '../css/imports/collab.css';
|
||||
|
||||
const CommunityPage = ({ data }) => {
|
||||
const {
|
||||
title,
|
||||
headline,
|
||||
subhead,
|
||||
primarycta,
|
||||
upcomingevent,
|
||||
howitworks,
|
||||
howtojoin
|
||||
} = data.markdownRemark.frontmatter;
|
||||
|
||||
return (
|
||||
<div className="community page">
|
||||
<Helmet title={title} />
|
||||
<section className="community hero">
|
||||
<div className="contained">
|
||||
<div className="hero-copy">
|
||||
<h1 className="headline">
|
||||
<Markdownify source={headline} />
|
||||
</h1>
|
||||
<h2 className="subhead">
|
||||
<Markdownify source={subhead} />
|
||||
</h2>
|
||||
<h3 className="ctas">
|
||||
<ul>
|
||||
<li>
|
||||
<Markdownify source={primarycta} />
|
||||
</li>
|
||||
</ul>
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<div className="calendar-cta">
|
||||
<h2>{upcomingevent.hook}</h2>
|
||||
<EventWidget />
|
||||
<div className="cal-cta">
|
||||
<Markdownify source={primarycta} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="how-it-works clearfix">
|
||||
<div className="contained">
|
||||
<div className="half">
|
||||
<h4 className="section-label">How it works</h4>
|
||||
<p>
|
||||
<Markdown source={howitworks} />
|
||||
</p>
|
||||
<h4 className="section-label">How to join</h4>
|
||||
<p>
|
||||
<Markdown source={howtojoin} />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const pageQuery = graphql`
|
||||
query communityPage {
|
||||
markdownRemark(id: { regex: "/community/" }) {
|
||||
frontmatter {
|
||||
headline
|
||||
subhead
|
||||
primarycta
|
||||
upcomingevent {
|
||||
hook
|
||||
}
|
||||
howitworks
|
||||
howtojoin
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default CommunityPage;
|
188
website/src/pages/index.js
Normal file
@ -0,0 +1,188 @@
|
||||
import React, { Component, Fragment } from 'react';
|
||||
import moment from 'moment';
|
||||
|
||||
import Markdownify from '../components/markdownify';
|
||||
import VideoEmbed from '../components/video-embed';
|
||||
|
||||
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';
|
||||
|
||||
const Features = ({ items }) => (
|
||||
<Fragment>
|
||||
{items.map(item => (
|
||||
<div className="feature" key={item.feature}>
|
||||
{item.imgpath && <img src={require(`../img/${item.imgpath}`)} />}
|
||||
<h3>
|
||||
<Markdownify source={item.feature} />
|
||||
</h3>
|
||||
<p>
|
||||
<Markdownify source={item.description} />
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</Fragment>
|
||||
);
|
||||
|
||||
const HomePage = ({ data }) => {
|
||||
const { landing, updates, contribs } = data;
|
||||
|
||||
return (
|
||||
<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>
|
||||
<VideoEmbed />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="cta">
|
||||
<div className="cta-primary">
|
||||
<p>
|
||||
<span className="hook">
|
||||
<Markdownify source={landing.cta.primaryhook} />
|
||||
</span>{' '}
|
||||
<Markdownify source={landing.cta.primary} />
|
||||
</p>
|
||||
<Markdownify source={landing.cta.button} />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section className="whatsnew">
|
||||
<div className="contained">
|
||||
<ol>
|
||||
{updates.updates.slice(0, 3).map(node => (
|
||||
<a
|
||||
href={`https://github.com/netlify/netlify-cms/releases/tag/${
|
||||
node.version
|
||||
}`}
|
||||
key={node.version}
|
||||
>
|
||||
<li>
|
||||
<div className="update-metadata">
|
||||
<span className="update-version">{node.version}</span>
|
||||
<span className="update-date">
|
||||
{moment(node.date).format('MMMM D, YYYY')}
|
||||
</span>
|
||||
</div>
|
||||
<span className="update-description">
|
||||
<Markdownify source={node.description} />
|
||||
</span>
|
||||
</li>
|
||||
</a>
|
||||
))}
|
||||
</ol>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<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>
|
||||
|
||||
<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>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const pageQuery = graphql`
|
||||
query homeQuery {
|
||||
updates: dataYaml(id: { regex: "/updates/" }) {
|
||||
updates {
|
||||
date
|
||||
description
|
||||
version
|
||||
}
|
||||
}
|
||||
landing: dataYaml(id: { regex: "/landing/" }) {
|
||||
hero {
|
||||
headline
|
||||
subhead
|
||||
devfeatures {
|
||||
feature
|
||||
description
|
||||
}
|
||||
}
|
||||
cta {
|
||||
primary
|
||||
primaryhook
|
||||
button
|
||||
}
|
||||
editors {
|
||||
hook
|
||||
intro
|
||||
features {
|
||||
feature
|
||||
imgpath
|
||||
description
|
||||
}
|
||||
}
|
||||
community {
|
||||
hook
|
||||
features {
|
||||
feature
|
||||
description
|
||||
}
|
||||
contributors
|
||||
}
|
||||
}
|
||||
contribs: dataJson(id: { regex: "/contributors/" }) {
|
||||
contributors {
|
||||
name
|
||||
profile
|
||||
avatar_url
|
||||
login
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default HomePage;
|
46
website/src/templates/blog-post.js
Normal file
@ -0,0 +1,46 @@
|
||||
import React from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
|
||||
const BlogPost = ({ data }) => {
|
||||
const { html, frontmatter } = data.markdownRemark;
|
||||
const { author, title, date, description, meta_description } = frontmatter;
|
||||
|
||||
const desc = meta_description || description;
|
||||
|
||||
return (
|
||||
<div className="docs page">
|
||||
<Helmet>
|
||||
<title>{title}</title>
|
||||
{desc && <meta name="description" content={desc} />}
|
||||
</Helmet>
|
||||
<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>
|
||||
<div dangerouslySetInnerHTML={{ __html: html }} />
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default BlogPost;
|
||||
|
||||
export const pageQuery = graphql`
|
||||
query blogPost($slug: String!) {
|
||||
markdownRemark(fields: { slug: { eq: $slug } }) {
|
||||
frontmatter {
|
||||
title
|
||||
description
|
||||
# meta_description
|
||||
date(formatString: "MMMM D, YYYY")
|
||||
author
|
||||
}
|
||||
html
|
||||
}
|
||||
}
|
||||
`;
|
108
website/src/templates/doc-page.js
Normal file
@ -0,0 +1,108 @@
|
||||
import React from 'react';
|
||||
import Helmet from 'react-helmet';
|
||||
import { matchPath } from 'react-router-dom';
|
||||
|
||||
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/lib/prism.css';
|
||||
import '../css/imports/docs.css';
|
||||
|
||||
const toMenu = (menu, nav) =>
|
||||
menu.map(group => ({
|
||||
title: group.title,
|
||||
group: nav.group.find(g => g.fieldValue === group.name)
|
||||
}));
|
||||
|
||||
const DocPage = ({ data, location, history }) => {
|
||||
const { nav, page, widgets, menu } = data;
|
||||
|
||||
const docsNav = toMenu(menu.siteMetadata.menu.docs, nav);
|
||||
const showWidgets = matchPath(location.pathname, { path: '/docs/widgets' });
|
||||
|
||||
return (
|
||||
<div className="docs detail page">
|
||||
<Helmet title={page.frontmatter.title} />
|
||||
<div className="container">
|
||||
<aside id="sidebar" className="sidebar">
|
||||
<DocsNav items={docsNav} location={location} />
|
||||
<MobileNav items={docsNav} history={history} />
|
||||
</aside>
|
||||
<article className="docs-content" id="docs-content">
|
||||
<EditLink path={page.fields.path} />
|
||||
<h1>{page.frontmatter.title}</h1>
|
||||
<div dangerouslySetInnerHTML={{ __html: page.html }} />
|
||||
{showWidgets && <Widgets widgets={widgets} />}
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const pageQuery = graphql`
|
||||
query docPage($slug: String!) {
|
||||
page: markdownRemark(fields: { slug: { eq: $slug } }) {
|
||||
fields {
|
||||
path
|
||||
}
|
||||
frontmatter {
|
||||
title
|
||||
}
|
||||
html
|
||||
}
|
||||
nav: allMarkdownRemark(
|
||||
sort: { fields: [frontmatter___weight], order: ASC }
|
||||
filter: {
|
||||
frontmatter: { title: { ne: null }, group: { ne: null } }
|
||||
fields: { slug: { regex: "/docs/" } }
|
||||
}
|
||||
) {
|
||||
group(field: frontmatter___group) {
|
||||
fieldValue
|
||||
edges {
|
||||
node {
|
||||
fields {
|
||||
slug
|
||||
}
|
||||
frontmatter {
|
||||
title
|
||||
group
|
||||
}
|
||||
tableOfContents
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
menu: site {
|
||||
siteMetadata {
|
||||
menu {
|
||||
docs {
|
||||
name
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
widgets: allMarkdownRemark(
|
||||
sort: { fields: [frontmatter___label], order: ASC }
|
||||
filter: {
|
||||
frontmatter: { label: { ne: null } }
|
||||
fields: { slug: { regex: "/widgets/" } }
|
||||
}
|
||||
) {
|
||||
edges {
|
||||
node {
|
||||
frontmatter {
|
||||
label
|
||||
target
|
||||
}
|
||||
html
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default DocPage;
|
51
website/src/theme.js
Normal file
@ -0,0 +1,51 @@
|
||||
// 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'
|
||||
}
|