11
CHANGELOG.md
|
|
@ -1,3 +1,14 @@
|
|||
## 0.3.0 - 2018-06-01
|
||||
|
||||
* General design updates
|
||||
* Improved default logo / favicon
|
||||
* Improved default card-og.png
|
||||
* Improved contact page layout
|
||||
* Update <BackgroundImage />
|
||||
* Change normalize.css to modern-normalize
|
||||
* Add react-feather icons
|
||||
* Remove AOS
|
||||
|
||||
## 0.2.9 - 2018-05-30
|
||||
|
||||
* IE11 support updates
|
||||
|
|
|
|||
18
README.md
|
|
@ -1,4 +1,4 @@
|
|||
# 🌶 Netlify CMS + React Starter
|
||||
# Netlify CMS + React Starter
|
||||
|
||||
[](http://standardjs.com/)
|
||||
[](https://github.com/prettier/prettier)
|
||||
|
|
@ -18,18 +18,18 @@ I aim to include commonly used components and best-practices e.g. forms, setting
|
|||
|
||||
[](https://app.netlify.com/start/deploy?repository=https://github.com/Jinksi/netlify-cms-react-starter)
|
||||
|
||||
1. Hit the **Deploy to Netlify** button. This will:
|
||||
1. Hit the **Deploy to Netlify** button. This will:
|
||||
|
||||
* Clone the repo into your Github account
|
||||
* Create you a new project on Netlify, build & deploy
|
||||
|
||||
1. Once your Netlify project has been created, change a couple of settings:
|
||||
1. Once your Netlify project has been created, change a couple of settings:
|
||||
|
||||
* Enable **Identity**
|
||||
* Change **Registration Preferences** to **Invite Only**
|
||||
* Enable **Git Gateway**
|
||||
|
||||
1. Invite users (probably yourself) to enable admin access
|
||||
1. Invite users (probably yourself) to enable admin access
|
||||
|
||||
* Open the **Identity** tab and hit **Invite Users**
|
||||
|
||||
|
|
@ -39,21 +39,21 @@ The CMS lives at [\_\_YOUR_SITE_NAME\_\_.netlify.com/admin](https://__YOUR_SITE_
|
|||
|
||||
## Developing
|
||||
|
||||
1. Clone your repo to your local machine
|
||||
1. Clone your repo to your local machine
|
||||
|
||||
1. Install dependencies
|
||||
1. Install dependencies
|
||||
|
||||
`yarn` or `npm install`
|
||||
|
||||
1. Run the development server
|
||||
1. Run the development server
|
||||
|
||||
`yarn start` or `npm run start`
|
||||
|
||||
If you are adding or editing content locally in the CMS, a couple of things to note:
|
||||
|
||||
1. Changes will be pushed to the remote repo.
|
||||
1. Changes will be pushed to the remote repo.
|
||||
|
||||
1. You will be prompted to enter your site's url, this is necessary for Netlify Identity to manage user login. This is stored in `localStorage`, so you might have to empty your browser cache if you are switching projects but remaining on `localhost:3000`.
|
||||
1. You will be prompted to enter your site's url, this is necessary for Netlify Identity to manage user login. This is stored in `localStorage`, so you might have to empty your browser cache if you are switching projects but remaining on `localhost:3000`.
|
||||
|
||||
## Editing CMS fields
|
||||
|
||||
|
|
|
|||
|
|
@ -4,8 +4,9 @@ import '../src/globalStyles.css'
|
|||
import data from '../src/data.json'
|
||||
import Home from '../src/views/Home'
|
||||
import About from '../src/views/About'
|
||||
import SinglePost from '../src/views/SinglePost'
|
||||
import Contact from '../src/views/Contact'
|
||||
import Blog from '../src/views/Blog'
|
||||
import SinglePost from '../src/views/SinglePost'
|
||||
|
||||
console.log('React version', React.version)
|
||||
|
||||
|
|
@ -17,7 +18,10 @@ CMS.registerPreviewStyle('/admin/cms.bundle.css')
|
|||
|
||||
const getDocument = (collection, name) =>
|
||||
data[collection] && data[collection].filter(page => page.name === name)[0]
|
||||
const getDocuments = (collection, name) => data[collection]
|
||||
|
||||
const globalSettings = getDocument('settings', 'global')
|
||||
const posts = getDocuments('posts')
|
||||
|
||||
// Preview Templates
|
||||
CMS.registerPreviewTemplate('home-page', ({ entry }) => (
|
||||
|
|
@ -29,6 +33,9 @@ CMS.registerPreviewTemplate('about-page', ({ entry }) => (
|
|||
CMS.registerPreviewTemplate('contact-page', ({ entry }) => (
|
||||
<Contact page={entry.toJS().data} siteTitle={globalSettings.siteTitle} />
|
||||
))
|
||||
CMS.registerPreviewTemplate('blog-page', ({ entry }) => (
|
||||
<Blog page={entry.toJS().data} posts={posts} />
|
||||
))
|
||||
CMS.registerPreviewTemplate('posts', ({ entry }) => (
|
||||
<SinglePost singlePost={entry.toJS().data} />
|
||||
))
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
---
|
||||
title: About page title
|
||||
subtitle: <About />
|
||||
featuredImage: /images/uploads/tim-marshall-155597.jpg
|
||||
section1: |-
|
||||
## Hello World!
|
||||
## Lorem Ipsum
|
||||
|
||||
Netlify CMS works with both `.md` and `.json`.
|
||||
|
||||
|
|
@ -15,10 +14,9 @@ section1: |-
|
|||
|
||||
<iframe width="560" height="315" src="https://www.youtube.com/embed/Js00yn142ic" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen></iframe>
|
||||
|
||||
section2: >-
|
||||
section2: |-
|
||||
## This is a Container component
|
||||
|
||||
|
||||
A sem vel nec sodales mi vivamus senectus sed potenti a parturient nascetur
|
||||
tincidunt nisi pulvinar rhoncus a. Risus imperdiet taciti suspendisse facilisi
|
||||
a per metus cubilia varius a nostra adipiscing amet ultrices quisque ac mi a.
|
||||
|
|
@ -28,9 +26,7 @@ section2: >-
|
|||
bibendum duis netus a consectetur dui magnis ac aliquet sem posuere tincidunt
|
||||
vestibulum.
|
||||
|
||||
|
||||
The image below will have a `srcset` attribute generated:
|
||||
|
||||
|
||||

|
||||
---
|
||||
|
|
|
|||
4
content/pages/blog.md
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
title: Blog
|
||||
featuredImage: /images/uploads/ng-32703.jpg
|
||||
---
|
||||
|
|
@ -1,13 +1,18 @@
|
|||
---
|
||||
title: Contact
|
||||
subtitle: <Contact />
|
||||
title: Contact us
|
||||
subtitle: ''
|
||||
featuredImage: '/images/uploads/mark-chang-74-3.jpg'
|
||||
address: 404 James St, Burleigh Heads QLD 4220
|
||||
phone: 0987 123 456
|
||||
email: example@example.com
|
||||
---
|
||||
|
||||
# Example contact form
|
||||
|
||||
This form is setup to use Netlify's form handling:
|
||||
|
||||
- the form action is set to the current absolute url: `action: '/contact/'`
|
||||
- a name attribute is sent with the form's data `'form-name': 'Contact'`
|
||||
- netlify data attributes are added to the form `data-netlify data-netlify-honeypot`
|
||||
* the form action is set to the current absolute url: `action: '/contact/'`
|
||||
* a name attribute is sent with the form's data `'form-name': 'Contact'`
|
||||
* netlify data attributes are added to the form `data-netlify data-netlify-honeypot`
|
||||
|
||||
Find out more in the [Netlify Docs](https://www.netlify.com/docs/form-handling/).
|
||||
|
|
|
|||
|
|
@ -1,13 +1,10 @@
|
|||
---
|
||||
title: Hello World!
|
||||
subtitle: <Home />
|
||||
subtitle: This is the home page subtitle
|
||||
featuredImage: '/images/uploads/isabella juskova.jpg'
|
||||
---
|
||||
|
||||
# 🌶 Netlify CMS + React Starter
|
||||
|
||||
[](http://standardjs.com/)
|
||||
[](https://github.com/prettier/prettier)
|
||||
[](https://david-dm.org/jinksi/netlify-cms-react-starter)
|
||||
# Netlify CMS + React Starter
|
||||
|
||||
A starter project for creating lightning-fast, offline-first websites with [Netlify CMS](https://netlifycms.org) and React.
|
||||
|
||||
|
|
@ -17,50 +14,6 @@ A starter project for creating lightning-fast, offline-first websites with [Netl
|
|||
* **[React Snapshot](https://github.com/geelen/react-snapshot)** for pre-rendering to static html so it works without Javascript ⭐️
|
||||
* **[Netlify CMS](https://github.com/netlify/netlify-cms)** for content management
|
||||
|
||||
I aim to include commonly used components and best-practices e.g. forms, settings, <head> tags, lazy-loading images, etc.
|
||||
|
||||
## Get going
|
||||
|
||||
[](https://app.netlify.com/start/deploy?repository=https://github.com/Jinksi/netlify-cms-react-starter)
|
||||
|
||||
1. Hit the **Deploy to Netlify** button. This will:
|
||||
|
||||
* Clone the repo into your Github account
|
||||
* Create you a new project on Netlify, build & deploy
|
||||
|
||||
1. Once your Netlify project has been created, change a couple of settings:
|
||||
|
||||
* Enable **Identity**
|
||||
* Change **Registration Preferences** to **Invite Only**
|
||||
* Enable **Git Gateway**
|
||||
|
||||
1. Invite users (probably yourself) to enable admin access
|
||||
* Open the **Identity** tab and hit **Invite Users**
|
||||
|
||||
## Developing
|
||||
|
||||
1. Clone your repo to your local machine
|
||||
|
||||
1. Install dependencies
|
||||
|
||||
`yarn` or `npm install`
|
||||
|
||||
1. Run the development server
|
||||
|
||||
`yarn start` or `npm run start`
|
||||
|
||||
If you are adding or editing content locally in the CMS, a couple of things to note:
|
||||
|
||||
* Changes will be pushed to the remote repo.
|
||||
|
||||
* You will be prompted to enter your site's url, this is necessary for Netlify Identity to manage user login. This is stored in `localStorage`, so you might have to empty your browser cache if you are switching projects but remaining on `localhost:3000`.
|
||||
|
||||
## Editing CMS fields
|
||||
|
||||
The Netlify CMS configuration is located in `public/admin/config.yml`. This is where you will configure the pages, fields, posts and settings that are editable by the CMS.
|
||||
|
||||
Find out more in the [Netlify CMS Docs](https://www.netlifycms.org/docs/#configuration).
|
||||
|
||||
## See also
|
||||
|
||||
[Netlify CMS Docs](https://www.netlifycms.org/docs/)
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
---
|
||||
title: Fluff
|
||||
---
|
||||
|
||||
3
content/postCategories/updates.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
title: Updates
|
||||
---
|
||||
|
|
@ -1,8 +1,11 @@
|
|||
---
|
||||
title: Testing 1.8.2
|
||||
title: Post Three
|
||||
status: Published
|
||||
date: '2018-05-25'
|
||||
postFeaturedImage: /images/uploads/isabella juskova.jpg
|
||||
excerpt: Test
|
||||
excerpt: This is placeholder text that our web designers put here to make sure words appear properly on your website. This text is going to be replaced once the website is completed. You are currently reading text that is written in English, not any other language.
|
||||
---
|
||||
Test
|
||||
|
||||
This is placeholder text that our web designers put here to make sure words appear properly on your website. This text is going to be replaced once the website is completed. You are currently reading text that is written in English, not any other language.
|
||||
|
||||
Be careful not to waste too much time reading placeholder text! This text isn’t going to remain here because it doesn't pertain to the website. This paragraph has been copied from a program that automatically generates paragraphs like this. It is useful for web designers to use placeholder text so they can easily see what different fonts look like on a realistic paragraph.
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
title: Post Two
|
||||
status: Published
|
||||
categories:
|
||||
- category: Fluff
|
||||
- category: Updates
|
||||
date: '2018-03-28'
|
||||
postFeaturedImage: /images/uploads/vyouw5byhlc.jpeg
|
||||
excerpt: This is an excerpt of Post Two
|
||||
|
|
|
|||
|
|
@ -31,17 +31,17 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@researchgate/react-intersection-observer": "^0.7.0",
|
||||
"aos": "^2.2.0",
|
||||
"core-js": "^2.5.3",
|
||||
"date-fns": "^1.29.0",
|
||||
"dom-form-serializer": "^1.0.7",
|
||||
"intersection-observer": "^0.5.0",
|
||||
"lodash": "^4.17.10",
|
||||
"modern-normalize": "^0.4.0",
|
||||
"moveto": "^1.7.1",
|
||||
"netlify-identity-widget": "^1.2.0",
|
||||
"normalize.css": "^8.0.0",
|
||||
"react": "^16.0.0",
|
||||
"react-dom": "^16.0.0",
|
||||
"react-feather": "^1.1.0",
|
||||
"react-helmet": "^5.1.3",
|
||||
"react-markdown": "3",
|
||||
"react-router-dom": "^4.1.1",
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@
|
|||
|
||||
/* Custom logo */
|
||||
|
||||
/* .nc-githubAuthenticationPage-logo {
|
||||
.nc-githubAuthenticationPage-logo {
|
||||
background-image: url(/images/logo.svg);
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
|
|
@ -79,4 +79,4 @@
|
|||
transform: translate(-50%, -50%);
|
||||
width: auto;
|
||||
text-indent: 0;
|
||||
} */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,30 +14,42 @@ collections: # A list of collections the CMS should be able to edit
|
|||
editor:
|
||||
preview: true
|
||||
files:
|
||||
- file: "content/pages/home.md"
|
||||
label: "Home Page"
|
||||
name: "home-page"
|
||||
- file: "content/pages/contact.md"
|
||||
label: "Contact Page"
|
||||
name: "contact-page"
|
||||
fields:
|
||||
- {label: Title, name: title, widget: string}
|
||||
- {label: Subtitle, name: subtitle, widget: string}
|
||||
- {label: Subtitle, name: subtitle, widget: markdown}
|
||||
- {label: Featured Image, name: featuredImage, widget: image}
|
||||
- {label: Body, name: body, widget: markdown}
|
||||
- {label: Address, name: address, widget: text}
|
||||
- {label: Phone, name: phone, widget: string}
|
||||
- {label: Email Address, name: email, widget: string}
|
||||
|
||||
- file: "content/pages/blog.md"
|
||||
label: "Blog Page"
|
||||
name: "blog-page"
|
||||
fields:
|
||||
- {label: Title, name: title, widget: string}
|
||||
- {label: Subtitle, name: subtitle, widget: markdown}
|
||||
- {label: Featured Image, name: featuredImage, widget: image}
|
||||
|
||||
- file: "content/pages/about.md"
|
||||
label: "About Page"
|
||||
name: "about-page"
|
||||
fields:
|
||||
- {label: Title, name: title, widget: string}
|
||||
- {label: Subtitle, name: subtitle, widget: string}
|
||||
- {label: Subtitle, name: subtitle, widget: markdown}
|
||||
- {label: Featured Image, name: featuredImage, widget: image}
|
||||
- {label: Section 1, name: section1, widget: markdown}
|
||||
- {label: Section 2, name: section2, widget: markdown}
|
||||
|
||||
- file: "content/pages/contact.md"
|
||||
label: "Contact Page"
|
||||
name: "contact-page"
|
||||
- file: "content/pages/home.md"
|
||||
label: "Home Page"
|
||||
name: "home-page"
|
||||
fields:
|
||||
- {label: Title, name: title, widget: string}
|
||||
- {label: Subtitle, name: subtitle, widget: string}
|
||||
- {label: Subtitle, name: subtitle, widget: markdown}
|
||||
- {label: Body, name: body, widget: markdown}
|
||||
|
||||
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 7.8 KiB |
|
|
@ -1 +1,6 @@
|
|||
<svg fill="#FF3D3D" width="100pt" height="100pt" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path d="M79 34.699c-.3.398-.898.602-1.7.602-1 0-2.3-.301-3.698-.801-1.5-.602-3.899-1.899-4.301-3.102L69 31.5c-2.3.8-4.3 2.5-5.898 4.398C60.703 38.698 59 42 58.3 45.797c-3.2 17.3-17.301 33.602-38.602 37.8-2.102.399-3.7 1.7-3.7 3.301 0 1.602 1.7 2.899 4.102 3C44.203 91 68.101 77.2 79.402 53.2c2.602-5.3 2.602-11.3.899-15.602-.2-.996-.7-1.996-1.301-2.898zM61.699 53.398c-5.8 14.699-18 25.898-32.898 30.5-.2.102-.398 0-.5-.102 0-.101.102-.3.3-.398 14.5-5.2 25.603-16.699 30.5-30.898.302-1 1.2-1.7 1.9-1.5.8.3 1.1 1.398.698 2.398z"/><path d="M83.801 10.801c-.102-.602-.602-.898-1.2-.7-2.1.602-2.898 2.5-3.3 4.4-.5 2.6-.7 5.198-1.398 7.8-.399 1.5-.899 2.898-1.602 4.3-.3.7-.7 1.4-1.2 2-.898 1.4-2.198 1.7-3.698 2.102-.301.102-1.399.399-1.399.399-.199.699 1.399 2 3.801 2.8 2.3.9 4.398 1 4.7.301 0 0-1.2-1.5-1.9-2.5a1.358 1.358 0 0 1 0-1.699c3.102-4.101 3.5-9.5 4.4-14.398.3-1.5.398-3.398 2.198-3.898.399-.008.696-.508.598-.906z"/></svg>
|
||||
<svg width="100pt" height="100pt" version="1.1" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
|
||||
<g fill-rule="evenodd">
|
||||
<path d="m55.441 1.5547 33.68 19.172c3.625 2.0742 5.6992 5.6992 5.6992 9.8438v38.859c0 4.1445-2.0742 7.7734-5.6992 9.8438l-33.68 19.172c-3.625 2.0742-7.7734 2.0742-11.398 0l-33.16-19.172c-3.625-2.0742-5.6992-5.6992-5.6992-9.8438v-38.859c0-4.1445 2.0742-7.7734 5.6992-9.8438l33.16-19.172c3.625-2.0742 7.7734-2.0742 11.398 0zm-2.0742 8.8086 29.016 16.582c2.5898 1.5547 3.625 3.625 3.625 6.2188v33.68c0 2.5898-1.0352 4.6641-3.625 6.2188l-29.016 16.582c-2.0742 1.0352-4.6641 1.0352-6.7344 0l-29.016-16.582c-2.5898-1.5547-3.625-3.625-3.625-6.2188v-33.68c0-2.5898 1.0352-4.6641 3.625-6.2188l29.016-16.582c2.0742-1.5547 4.6641-1.5547 6.7344 0z"/>
|
||||
<path d="m49.742 16.582 29.016 16.578v33.68l-29.016 16.578-29.016-16.578v-33.68z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 1 KiB After Width: | Height: | Size: 872 B |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 31 KiB |
BIN
public/images/uploads/ng-32703.jpg
Normal file
|
After Width: | Height: | Size: 372 KiB |
|
|
@ -31,16 +31,16 @@
|
|||
-->
|
||||
<script src="https://identity-js.netlify.com/v1/netlify-identity-widget.js"></script>
|
||||
<script>
|
||||
// check for netlifyIdentity, redirect to admin if user is logging in
|
||||
if (window.localStorage && window.netlifyIdentity) {
|
||||
netlifyIdentity.on('init', function (user) {
|
||||
if (!user) {
|
||||
netlifyIdentity.on('login', function () {
|
||||
document.location.href = '/admin/'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
// check for netlifyIdentity, redirect to admin if user is logging in
|
||||
if (window.localStorage && window.netlifyIdentity) {
|
||||
netlifyIdentity.on('init', function(user) {
|
||||
if (!user) {
|
||||
netlifyIdentity.on('login', function() {
|
||||
document.location.href = '/admin/'
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ import Nav from './components/Nav'
|
|||
import Footer from './components/Footer'
|
||||
import GithubCorner from './components/GithubCorner'
|
||||
import ServiceWorkerNotifications from './components/ServiceWorkerNotifications'
|
||||
import AOS from './components/AOS'
|
||||
import data from './data.json'
|
||||
import { slugify } from './util/url'
|
||||
import { documentHasTerm, getCollectionTerms } from './util/collection'
|
||||
|
|
@ -52,7 +51,6 @@ class App extends Component {
|
|||
return (
|
||||
<Router>
|
||||
<div className='React-Wrap'>
|
||||
<AOS options={{ duration: 250 }} />
|
||||
<ScrollToTop />
|
||||
<ServiceWorkerNotifications reloadOnUpdate />
|
||||
<GithubCorner url='https://github.com/Jinksi/netlify-cms-react-starter' />
|
||||
|
|
@ -111,6 +109,7 @@ class App extends Component {
|
|||
exact
|
||||
render={props => (
|
||||
<Blog
|
||||
page={this.getDocument('pages', 'blog')}
|
||||
posts={posts}
|
||||
postCategories={postCategories}
|
||||
{...props}
|
||||
|
|
@ -128,6 +127,7 @@ class App extends Component {
|
|||
if (!categoryPosts.length) return <NoMatch siteUrl={siteUrl} />
|
||||
return (
|
||||
<Blog
|
||||
page={this.getDocument('pages', 'blog')}
|
||||
posts={categoryPosts}
|
||||
postCategories={postCategories}
|
||||
showFeatured={false}
|
||||
|
|
@ -145,8 +145,8 @@ class App extends Component {
|
|||
item => slugify(item.title) === slug
|
||||
)
|
||||
const singlePost = posts[singlePostID]
|
||||
const nextPost = posts[singlePostID + 1]
|
||||
const prevPost = posts[singlePostID - 1]
|
||||
const nextPost = posts[singlePostID - 1]
|
||||
const prevPost = posts[singlePostID + 1]
|
||||
if (!singlePost) return <NoMatch siteUrl={siteUrl} />
|
||||
return (
|
||||
<SinglePost
|
||||
|
|
|
|||
|
|
@ -1,31 +0,0 @@
|
|||
import React from 'react'
|
||||
import AOS from 'aos'
|
||||
import Helmet from 'react-helmet'
|
||||
import 'aos/dist/aos.css'
|
||||
|
||||
export default ({ options }) => {
|
||||
// See more: https://github.com/michalsnik/aos
|
||||
const defaultOptions = {
|
||||
offset: 300,
|
||||
duration: 300,
|
||||
easing: 'ease-out-sine',
|
||||
delay: 0,
|
||||
once: true
|
||||
}
|
||||
|
||||
AOS.init({ ...defaultOptions, ...options })
|
||||
|
||||
return (
|
||||
<Helmet>
|
||||
<noscript>{`
|
||||
<style>
|
||||
/* override AOS css if no JS */
|
||||
[data-aos] {
|
||||
opacity: 1 !important;
|
||||
transform: translate(0) scale(1) !important;
|
||||
}
|
||||
</style>
|
||||
`}</noscript>
|
||||
</Helmet>
|
||||
)
|
||||
}
|
||||
|
|
@ -5,7 +5,8 @@
|
|||
bottom: 0;
|
||||
right: 0;
|
||||
background-position: center;
|
||||
transition: opacity 0.5s ease;
|
||||
transform: translate3d(0, 0, 0);
|
||||
transition: filter 0.3s ease-in-out;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,8 +54,22 @@ export default class BackgroundImage extends React.Component {
|
|||
}
|
||||
|
||||
render () {
|
||||
let { className, contain, opacity, lazy } = this.props
|
||||
let { className, contain, opacity, lazy, imageSize } = this.props
|
||||
let { loaded, src } = this.state
|
||||
|
||||
if (!lazy) {
|
||||
return (
|
||||
<div
|
||||
className={`BackgroundImage absolute ${className}`}
|
||||
style={{
|
||||
backgroundImage: `url(${getImageSrc(this.props.src, imageSize)})`,
|
||||
backgroundSize: contain ? 'contain' : 'cover',
|
||||
opacity: opacity
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
if (loaded) className += ' BackgroundImage-lazy-loaded'
|
||||
if (lazy) className += ' BackgroundImage-lazy'
|
||||
const options = {
|
||||
|
|
@ -68,7 +82,6 @@ export default class BackgroundImage extends React.Component {
|
|||
<Observer {...options}>
|
||||
<div
|
||||
className={`BackgroundImage absolute ${className}`}
|
||||
src={src}
|
||||
style={{
|
||||
backgroundImage: `url(${src})`,
|
||||
backgroundSize: contain ? 'contain' : 'cover',
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
}
|
||||
|
||||
.EnquiryForm > * + * {
|
||||
margin-top: 1.5rem;
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.EnquiryForm--Label {
|
||||
|
|
@ -21,21 +21,19 @@
|
|||
|
||||
.EnquiryForm--Input {
|
||||
font-family: inherit;
|
||||
font-weight: 400;
|
||||
flex-grow: 1;
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
margin: 0;
|
||||
border: none;
|
||||
border-bottom: 1px solid #bababa;
|
||||
padding: 0.75rem 0.5rem;
|
||||
line-height: 1;
|
||||
border: 1px solid #bababa;
|
||||
padding: 1.5rem 2rem;
|
||||
border-radius: var(--borderRadius);
|
||||
line-height: 1.25em;
|
||||
transition: border-color 0.2s;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.EnquiryForm--Select {
|
||||
border-radius: 0;
|
||||
background: none;
|
||||
appearance: none;
|
||||
}
|
||||
|
|
@ -43,7 +41,7 @@
|
|||
.EnquiryForm--Label.has-arrow:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: 3px;
|
||||
right: 2.5rem;
|
||||
top: 50%;
|
||||
border-right: 1px solid;
|
||||
border-bottom: 1px solid;
|
||||
|
|
|
|||
|
|
@ -1,14 +1,4 @@
|
|||
.Footer {
|
||||
background: var(--primary);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.Footer--Lower {
|
||||
background: var(--primary);
|
||||
padding: 1rem 0;
|
||||
font-weight: 100;
|
||||
}
|
||||
|
||||
.Footer--Lower a {
|
||||
color: inherit;
|
||||
padding: 3rem 0;
|
||||
background: var(--lightGrey);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,10 +4,8 @@ import './Footer.css'
|
|||
|
||||
export default ({ globalSettings, socialSettings, navLinks }) => (
|
||||
<footer className='Footer'>
|
||||
<div className='Footer--Lower'>
|
||||
<div className='container taCenter'>
|
||||
<span>© 2017 All rights reserved.</span>
|
||||
</div>
|
||||
<div className='container taCenter'>
|
||||
<span>© 2017 All rights reserved.</span>
|
||||
</div>
|
||||
</footer>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -7,8 +7,10 @@
|
|||
.GithubCorner svg {
|
||||
color: #fff;
|
||||
border: 0;
|
||||
max-width: 12.5vmin;
|
||||
max-height: 12.5vmin;
|
||||
width: 12vmin;
|
||||
height: 12vmin;
|
||||
max-width: 6rem;
|
||||
max-height: 6rem;
|
||||
}
|
||||
|
||||
.GithubCorner .octo-arm {
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
.Logo {
|
||||
display: block;
|
||||
display: flex;
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
height: 2.5rem;
|
||||
width: 2.5rem;
|
||||
margin-right: 1rem;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,4 +7,10 @@
|
|||
|
||||
.Nav--Container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 6rem;
|
||||
}
|
||||
|
||||
.Nav .Logo {
|
||||
margin-right: 3rem;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,18 @@
|
|||
.NavLink {
|
||||
padding: 0.5rem 1rem;
|
||||
display: block;
|
||||
font-weight: 400;
|
||||
font-weight: 500;
|
||||
transition: color 0.2s, border-bottom-color 0.2s;
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
border-bottom: 1px solid;
|
||||
border-bottom: 2px solid;
|
||||
border-bottom-color: transparent;
|
||||
}
|
||||
|
||||
.NavLink + .NavLink {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
.NavLink:hover,
|
||||
.NavLink.active,
|
||||
.NavLink:focus {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,19 @@
|
|||
.PageHeader {
|
||||
line-height: 1em;
|
||||
color: var(--primary);
|
||||
background: var(--primary);
|
||||
background-color: var(--darkGrey);
|
||||
color: white;
|
||||
padding: 15rem 0;
|
||||
}
|
||||
|
||||
.PageHeader-large {
|
||||
padding: 20rem 0;
|
||||
}
|
||||
|
||||
.PageHeader--Title {
|
||||
font-size: 6rem;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.PageHeader--Subtitle {
|
||||
font-weight: 200;
|
||||
font-weight: 400;
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,31 +1,32 @@
|
|||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
import Content from './Content'
|
||||
import BackgroundImage from './BackgroundImage'
|
||||
import './PageHeader.css'
|
||||
|
||||
const PageHeader = ({ title, subtitle, backgroundImage }) => (
|
||||
<div className='section PageHeader relative'>
|
||||
{backgroundImage && <BackgroundImage src={backgroundImage} opacity={0.5} />}
|
||||
<div className='container relative'>
|
||||
<h1 className='PageHeader--Title' data-aos='fade-left'>
|
||||
{title}
|
||||
</h1>
|
||||
{subtitle ? (
|
||||
<h2
|
||||
className='PageHeader--Subtitle'
|
||||
data-aos='fade-left'
|
||||
data-aos-duration='400'
|
||||
>
|
||||
{subtitle}
|
||||
</h2>
|
||||
) : (
|
||||
''
|
||||
const PageHeader = ({
|
||||
title,
|
||||
subtitle,
|
||||
backgroundImage,
|
||||
large,
|
||||
className = ''
|
||||
}) => {
|
||||
if (large) className += ' PageHeader-large'
|
||||
return (
|
||||
<div className={`PageHeader relative ${className}`}>
|
||||
{backgroundImage && (
|
||||
<BackgroundImage src={backgroundImage} opacity={0.4} />
|
||||
)}
|
||||
<div className='container relative'>
|
||||
<h1 className='PageHeader--Title'>{title}</h1>
|
||||
{subtitle && (
|
||||
<Content className='PageHeader--Subtitle' src={subtitle} />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
)
|
||||
}
|
||||
PageHeader.propTypes = {
|
||||
title: PropTypes.string,
|
||||
subtitle: PropTypes.string
|
||||
|
|
|
|||
|
|
@ -1,7 +1,19 @@
|
|||
.PostCard {
|
||||
text-decoration: none;
|
||||
margin: 4rem 2rem;
|
||||
margin: 2rem;
|
||||
background: white;
|
||||
color: inherit;
|
||||
border: 1px solid var(--lightGrey);
|
||||
border-radius: var(--borderRadius);
|
||||
box-shadow: 0 2px 15px rgba(0, 0, 0, 0.1);
|
||||
transition: all 0.15s ease-in-out;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.PostCard:hover,
|
||||
.PostCard:focus {
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 2px 30px rgba(0, 0, 0, 0.15);
|
||||
}
|
||||
|
||||
.PostCard--Image {
|
||||
|
|
@ -10,16 +22,15 @@
|
|||
height: 15rem;
|
||||
}
|
||||
|
||||
.PostCard--Title {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.PostCard--Content {
|
||||
padding: 0 2.5rem 2.5rem;
|
||||
}
|
||||
|
||||
.PostCard--Category {
|
||||
font-size: 1rem;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.PostCard--Content {
|
||||
margin: 0 auto;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.PostCard--Title {
|
||||
margin: 2rem 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
.PostCategoriesNav {
|
||||
margin: 4rem 0;
|
||||
margin: 2rem 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,6 @@
|
|||
.PostSection {
|
||||
padding: 2rem 0;
|
||||
}
|
||||
.PostSection .PostCard {
|
||||
width: calc(33.33% - 4rem);
|
||||
}
|
||||
|
|
@ -7,6 +10,7 @@
|
|||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
@supports (display: grid) {
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ class PostSection extends React.Component {
|
|||
.slice(0, limit || posts.length)
|
||||
|
||||
return (
|
||||
<div className='section thin PostSection'>
|
||||
<div className='PostSection'>
|
||||
<div className='container'>
|
||||
{title && <h2 className='PostSection--Title'>{title}</h2>}
|
||||
{!!visiblePosts.length && (
|
||||
|
|
@ -46,12 +46,12 @@ class PostSection extends React.Component {
|
|||
)}
|
||||
{showLoadMore &&
|
||||
visiblePosts.length < posts.length && (
|
||||
<div className='taCenter'>
|
||||
<button className='button' onClick={this.increaseLimit}>
|
||||
{loadMoreTitle}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
<div className='taCenter'>
|
||||
<button className='button' onClick={this.increaseLimit}>
|
||||
{loadMoreTitle}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
:root {
|
||||
--primary: #ff3d3d;
|
||||
--primary-light: #ff6f6f;
|
||||
--primary: #0984d2;
|
||||
--primary-light: #6fadff;
|
||||
--secondary: #212121;
|
||||
--lightGrey: whitesmoke;
|
||||
--midGrey: #cacaca;
|
||||
--darkGrey: #272727;
|
||||
--danger: #ff3d3d;
|
||||
--font-primary: 'Open Sans', sans-serif;
|
||||
--font-system: '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto',
|
||||
|
|
@ -26,18 +27,12 @@ body {
|
|||
background: white;
|
||||
color: var(--secondary);
|
||||
font-size: 1.6em;
|
||||
font-weight: 300;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0.01em;
|
||||
line-height: 1.6;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
*,
|
||||
*:before,
|
||||
*:after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--primary);
|
||||
}
|
||||
|
|
@ -140,13 +135,13 @@ blockquote {
|
|||
|
||||
.section {
|
||||
width: 100%;
|
||||
padding: 5rem 0;
|
||||
padding: 7.5rem 0;
|
||||
}
|
||||
.section.thick {
|
||||
padding: 10rem 0;
|
||||
}
|
||||
.section.thin {
|
||||
padding: 2.5rem 0;
|
||||
padding: 3.5rem 0;
|
||||
}
|
||||
.section.noPadding {
|
||||
padding: 0;
|
||||
|
|
@ -171,11 +166,11 @@ blockquote {
|
|||
color: white;
|
||||
text-transform: uppercase;
|
||||
text-decoration: none;
|
||||
font-weight: 400;
|
||||
letter-spacing: 0.15em;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.05em;
|
||||
font-size: 1.4rem;
|
||||
display: inline-block;
|
||||
padding: 1rem 2rem;
|
||||
padding: 1.25rem 3rem;
|
||||
border: none;
|
||||
transition: all 0.2s ease;
|
||||
cursor: pointer;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import 'core-js/es6'
|
||||
import React from 'react'
|
||||
import { render } from 'react-snapshot'
|
||||
import 'normalize.css'
|
||||
import 'modern-normalize/modern-normalize.css'
|
||||
import './globalStyles.css'
|
||||
import App from './App'
|
||||
import registerServiceWorker, { unregister } from './registerServiceWorker'
|
||||
|
|
|
|||
|
|
@ -6,27 +6,30 @@ import LazyImage from '../components/LazyImage'
|
|||
import Content from '../components/Content.js'
|
||||
import './About.css'
|
||||
|
||||
export default ({ page }) => (
|
||||
<div className='About'>
|
||||
<Helmet>
|
||||
<title>{page.title}</title>
|
||||
</Helmet>
|
||||
<PageHeader
|
||||
title={page.title}
|
||||
subtitle={page.subtitle}
|
||||
backgroundImage={page.featuredImage}
|
||||
/>
|
||||
<div className='section thin'>
|
||||
<div className='container'>
|
||||
<Content source={page.section1} />
|
||||
export default ({ page }) => {
|
||||
const { title, subtitle, featuredImage, section1, section2 } = page
|
||||
return (
|
||||
<div className='About'>
|
||||
<Helmet>
|
||||
<title>{title}</title>
|
||||
</Helmet>
|
||||
<PageHeader
|
||||
title={title}
|
||||
subtitle={subtitle}
|
||||
backgroundImage={featuredImage}
|
||||
/>
|
||||
<div className='section'>
|
||||
<div className='container'>
|
||||
<Content source={section1} />
|
||||
</div>
|
||||
</div>
|
||||
<div className='section'>
|
||||
<div className='container'>
|
||||
<Content source={section2} />
|
||||
<p>The image below is a {'<LazyImage />'}</p>
|
||||
<LazyImage src={featuredImage} alt='LazyImage' />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='section thin'>
|
||||
<div className='container'>
|
||||
<Content source={page.section2} />
|
||||
<p>The image below is a {'<LazyImage />'}</p>
|
||||
<LazyImage src={page.featuredImage} alt='LazyImage' />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,17 +8,30 @@ import PostSection from '../components/PostSection'
|
|||
|
||||
import './Blog.css'
|
||||
|
||||
export default ({ page, posts, postCategories, showFeatured = true }) => {
|
||||
export default ({
|
||||
page,
|
||||
posts = [],
|
||||
postCategories = [],
|
||||
showFeatured = true
|
||||
}) => {
|
||||
const { title, subtitle, featuredImage } = page
|
||||
posts = _sortBy(posts, ['date']).reverse()
|
||||
|
||||
return (
|
||||
<main className='Blog'>
|
||||
<Helmet>
|
||||
<title>Blog</title>
|
||||
<title>{title}</title>
|
||||
</Helmet>
|
||||
<PageHeader title='Blog' />
|
||||
|
||||
<PostCategoriesNav categories={postCategories} />
|
||||
<PageHeader
|
||||
title={title}
|
||||
subtitle={subtitle}
|
||||
backgroundImage={featuredImage}
|
||||
/>
|
||||
|
||||
{!!postCategories.length && (
|
||||
<PostCategoriesNav categories={postCategories} />
|
||||
)}
|
||||
{!!posts.length && <PostSection posts={posts} />}
|
||||
</main>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,2 +1,38 @@
|
|||
.Contact {
|
||||
}
|
||||
|
||||
.Contact--Details {
|
||||
margin-top: 3rem;
|
||||
}
|
||||
|
||||
.Contact--Details--Item {
|
||||
display: flex;
|
||||
padding: 2rem 0;
|
||||
border-top: 1px solid var(--lightGrey);
|
||||
font-weight: 500;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
transition: color 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.Contact--Details--Item:hover,
|
||||
.Contact--Details--Item:focus {
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
.Contact--Details--Item svg {
|
||||
margin-right: 1.5rem;
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
@media (min-width: 750px) {
|
||||
.Contact--Section1--Container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.Contact--Section1--Container > * {
|
||||
width: calc(50% - 2rem);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,35 +1,61 @@
|
|||
import React from 'react'
|
||||
import Helmet from 'react-helmet'
|
||||
import { MapPin, Smartphone, Mail } from 'react-feather'
|
||||
|
||||
import PageHeader from '../components/PageHeader'
|
||||
import EnquiryFormControlled from '../components/EnquiryFormControlled'
|
||||
import EnquiryFormSimple from '../components/EnquiryFormSimple'
|
||||
import EnquiryFormSimpleAjax from '../components/EnquiryFormSimpleAjax'
|
||||
import Content from '../components/Content'
|
||||
import './Contact.css'
|
||||
|
||||
export default ({ page, siteTitle }) => (
|
||||
<div className='Contact'>
|
||||
<PageHeader title={page.title} subtitle='<Contact />' />
|
||||
<div className='section thin'>
|
||||
<div className='container'>
|
||||
<Content source={page.body} />
|
||||
<h3>{'<EnquiryFormSimple />'}</h3>
|
||||
<EnquiryFormSimple name='Simple Form' />
|
||||
<br />
|
||||
<h3>{'<EnquiryFormSimpleAjax />'}</h3>
|
||||
<EnquiryFormSimpleAjax name='Simple Form Ajax' />
|
||||
<br />
|
||||
<h3>{'<EnquiryFormControlled />'}</h3>
|
||||
<EnquiryFormControlled siteTitle={siteTitle} name={'Controlled Form'} />
|
||||
<br />
|
||||
<em>Note: these will only work when deployed on Netlify</em>
|
||||
<br />
|
||||
<em>Also, they are active and I will receive submissions</em> 😉
|
||||
export default ({ page }) => {
|
||||
const { title, subtitle, featuredImage, address, phone, email } = page
|
||||
return (
|
||||
<div className='Contact'>
|
||||
<Helmet>
|
||||
<title>{page.title}</title>
|
||||
</Helmet>
|
||||
|
||||
<PageHeader
|
||||
title={title}
|
||||
subtitle={subtitle}
|
||||
backgroundImage={featuredImage}
|
||||
/>
|
||||
|
||||
<div className='section Contact--Section1'>
|
||||
<div className='container Contact--Section1--Container'>
|
||||
<div>
|
||||
<Content source={page.body} />
|
||||
|
||||
<div className='Contact--Details'>
|
||||
{address && (
|
||||
<a
|
||||
className='Contact--Details--Item'
|
||||
href={`https://www.google.com.au/maps/search/${encodeURI(
|
||||
address
|
||||
)}`}
|
||||
target='_blank'
|
||||
>
|
||||
<MapPin /> {address}
|
||||
</a>
|
||||
)}
|
||||
{phone && (
|
||||
<a className='Contact--Details--Item' href={`tel:${phone}`}>
|
||||
<Smartphone /> {phone}
|
||||
</a>
|
||||
)}
|
||||
{email && (
|
||||
<a className='Contact--Details--Item' href={`mailto:${email}`}>
|
||||
<Mail /> {email}
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<EnquiryFormSimpleAjax name='Simple Form Ajax' />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Helmet>
|
||||
<title>{page.title}</title>
|
||||
</Helmet>
|
||||
</div>
|
||||
)
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,18 +6,23 @@ import PageHeader from '../components/PageHeader'
|
|||
import './Home.css'
|
||||
|
||||
export default ({ page }) => {
|
||||
const { title, subtitle, body } = page
|
||||
const { title, subtitle, featuredImage, body } = page
|
||||
return (
|
||||
<main className='Home'>
|
||||
<PageHeader title={title} subtitle={subtitle} />
|
||||
<div className='section thin'>
|
||||
<Helmet>
|
||||
<title>{title}</title>
|
||||
</Helmet>
|
||||
<PageHeader
|
||||
large
|
||||
title={title}
|
||||
subtitle={subtitle}
|
||||
backgroundImage={featuredImage}
|
||||
/>
|
||||
<div className='section'>
|
||||
<div className='container'>
|
||||
<Content source={body} />
|
||||
</div>
|
||||
</div>
|
||||
<Helmet>
|
||||
<title>{title}</title>
|
||||
</Helmet>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,27 @@
|
|||
height: 50rem;
|
||||
}
|
||||
|
||||
.SinglePost--BackButton {
|
||||
color: white;
|
||||
position: relative;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
letter-spacing: 0.1em;
|
||||
}
|
||||
|
||||
.SinglePost--BackButton svg {
|
||||
transition: transform 0.2s ease-out;
|
||||
transform: translateX(0);
|
||||
height: 1.2em;
|
||||
}
|
||||
|
||||
.SinglePost--BackButton:hover svg,
|
||||
.SinglePost--BackButton:focus svg {
|
||||
transform: translateX(-0.25em);
|
||||
}
|
||||
|
||||
.SinglePost--Content {
|
||||
background: white;
|
||||
margin-top: 30rem;
|
||||
|
|
@ -43,10 +64,19 @@
|
|||
}
|
||||
|
||||
.SinglePost--Pagination {
|
||||
margin: 6rem 0 0 0;
|
||||
margin: 4rem 0 0 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.SinglePost--Pagination--Link {
|
||||
text-transform: uppercase;
|
||||
font-size: 1.2rem;
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.SinglePost--Pagination--Link.next {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import React from 'react'
|
||||
import Helmet from 'react-helmet'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { ChevronLeft } from 'react-feather'
|
||||
|
||||
import Content from '../components/Content'
|
||||
import BackgroundImage from '../components/BackgroundImage'
|
||||
|
|
@ -9,12 +10,13 @@ import { dateFormatted } from '../util/date'
|
|||
import './SinglePost.css'
|
||||
|
||||
export default ({ singlePost, nextPostURL, prevPostURL }) => {
|
||||
const { body, categories, postFeaturedImage, title, date } = singlePost
|
||||
const { title, date, postFeaturedImage, body, categories = [] } = singlePost
|
||||
return (
|
||||
<article className='SinglePost section light'>
|
||||
<Helmet>
|
||||
<title>{title}</title>
|
||||
</Helmet>
|
||||
|
||||
{postFeaturedImage && (
|
||||
<BackgroundImage
|
||||
className='SinglePost--BackgroundImage'
|
||||
|
|
@ -24,9 +26,12 @@ export default ({ singlePost, nextPostURL, prevPostURL }) => {
|
|||
)}
|
||||
|
||||
<div className='container skinny'>
|
||||
<Link className='SinglePost--BackButton' to='/blog/'>
|
||||
<ChevronLeft /> BACK
|
||||
</Link>
|
||||
<div className='SinglePost--Content relative'>
|
||||
<div className='SinglePost--Meta'>
|
||||
{!!categories &&
|
||||
{!!categories.length &&
|
||||
categories.map(obj => (
|
||||
<span key={obj.category} className='SinglePost--Meta--Category'>
|
||||
{obj.category}
|
||||
|
|
@ -45,15 +50,21 @@ export default ({ singlePost, nextPostURL, prevPostURL }) => {
|
|||
<Content source={body} />
|
||||
</div>
|
||||
|
||||
<div className='SinglePost--Pagination Flex alignStretch justifyBetween flexWrap'>
|
||||
{nextPostURL && (
|
||||
<Link className='SinglePost--Pagination--Link' to={nextPostURL}>
|
||||
Next Post
|
||||
<div className='SinglePost--Pagination'>
|
||||
{prevPostURL && (
|
||||
<Link
|
||||
className='SinglePost--Pagination--Link prev'
|
||||
to={prevPostURL}
|
||||
>
|
||||
Previous Post
|
||||
</Link>
|
||||
)}
|
||||
{prevPostURL && (
|
||||
<Link className='SinglePost--Pagination--Link' to={prevPostURL}>
|
||||
Previous Post
|
||||
{nextPostURL && (
|
||||
<Link
|
||||
className='SinglePost--Pagination--Link next'
|
||||
to={nextPostURL}
|
||||
>
|
||||
Next Post
|
||||
</Link>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||