* Improve reusability of Meta component

* Rename page prop to fields on pages / posts

* Update config.yml with meta object for each item
This commit is contained in:
Eric Jinks 2018-06-06 14:36:47 +10:00 committed by GitHub
parent 7bd0b54b6d
commit 7b4780c581
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 186 additions and 158 deletions

View file

@ -1,3 +1,9 @@
## 0.4.0 - 2018-06-06
* Improve reusability of <Meta /> component
* Rename `page` prop to `fields` on pages / posts
* Update config.yml with meta object for each item
## 0.3.1 - 2018-06-01
* Encode CMS image urls

View file

@ -25,19 +25,19 @@ const posts = getDocuments('posts')
// Preview Templates
CMS.registerPreviewTemplate('home-page', ({ entry }) => (
<Home page={entry.toJS().data} />
<Home fields={entry.toJS().data} />
))
CMS.registerPreviewTemplate('about-page', ({ entry }) => (
<About page={entry.toJS().data} />
<About fields={entry.toJS().data} />
))
CMS.registerPreviewTemplate('contact-page', ({ entry }) => (
<Contact page={entry.toJS().data} siteTitle={globalSettings.siteTitle} />
<Contact fields={entry.toJS().data} siteTitle={globalSettings.siteTitle} />
))
CMS.registerPreviewTemplate('blog-page', ({ entry }) => (
<Blog page={entry.toJS().data} posts={posts} />
<Blog fields={entry.toJS().data} posts={posts} />
))
CMS.registerPreviewTemplate('posts', ({ entry }) => (
<SinglePost singlePost={entry.toJS().data} />
<SinglePost fields={entry.toJS().data} />
))
// Return to home when user logging out

View file

@ -1,3 +1,7 @@
---
title: Updates
meta:
description: Desc
title: Test Updates Title
---

View file

@ -1,8 +1,6 @@
---
title: Hello World!
status: Featured / Published
categories:
- category: News
date: '2018-03-27'
postFeaturedImage: /images/uploads/tim-marshall-155597.jpg
excerpt: >-
@ -10,6 +8,13 @@ excerpt: >-
interdum arcu vitae augue pulvinar sodales. Sed non dui diam. Quisque lectus
est, lobortis ac efficitur vitae, posuere a mauris. Phasellus ac dui
pellentesque, lacinia risus ut, imperdiet eros.
categories:
- category: News
meta:
canonicalLink: ''
description: ''
noindex: false
title: ''
---
Paragraphs are separated by a blank line.

View file

@ -25,6 +25,14 @@ collections: # A list of collections the CMS should be able to edit
- {label: Address, name: address, widget: text}
- {label: Phone, name: phone, widget: string}
- {label: Email Address, name: email, widget: string}
- label: "Meta"
name: "meta"
widget: "object"
fields:
- {label: Title, name: title, widget: string, required: false}
- {label: Description, name: description, widget: text, required: false, pattern: [".{,300}", "Must not exceed 300 characters"]}
- {label: Canonical Link, name: canonicalLink, widget: string, required: false}
- {label: Noindex, name: noindex, widget: boolean, required: false}
- file: "content/pages/blog.md"
label: "Blog Page"
@ -33,6 +41,14 @@ collections: # A list of collections the CMS should be able to edit
- {label: Title, name: title, widget: string}
- {label: Featured Image, name: featuredImage, widget: image}
- {label: Subtitle, name: subtitle, widget: markdown}
- label: "Meta"
name: "meta"
widget: "object"
fields:
- {label: Title, name: title, widget: string, required: false}
- {label: Description, name: description, widget: text, required: false, pattern: [".{,300}", "Must not exceed 300 characters"]}
- {label: Canonical Link, name: canonicalLink, widget: string, required: false}
- {label: Noindex, name: noindex, widget: boolean, required: false}
- file: "content/pages/about.md"
label: "About Page"
@ -43,6 +59,14 @@ collections: # A list of collections the CMS should be able to edit
- {label: Subtitle, name: subtitle, widget: markdown}
- {label: Section 1, name: section1, widget: markdown}
- {label: Section 2, name: section2, widget: markdown}
- label: "Meta"
name: "meta"
widget: "object"
fields:
- {label: Title, name: title, widget: string, required: false}
- {label: Description, name: description, widget: text, required: false, pattern: [".{,300}", "Must not exceed 300 characters"]}
- {label: Canonical Link, name: canonicalLink, widget: string, required: false}
- {label: Noindex, name: noindex, widget: boolean, required: false}
- file: "content/pages/home.md"
label: "Home Page"
@ -52,6 +76,14 @@ collections: # A list of collections the CMS should be able to edit
- {label: Featured Image, name: featuredImage, widget: image}
- {label: Subtitle, name: subtitle, widget: markdown}
- {label: Body, name: body, widget: markdown}
- label: "Meta"
name: "meta"
widget: "object"
fields:
- {label: Title, name: title, widget: string, required: false}
- {label: Description, name: description, widget: text, required: false, pattern: [".{,300}", "Must not exceed 300 characters"]}
- {label: Canonical Link, name: canonicalLink, widget: string, required: false}
- {label: Noindex, name: noindex, widget: boolean, required: false}
- name: posts
@ -83,6 +115,14 @@ collections: # A list of collections the CMS should be able to edit
collection: "postCategories"
searchFields: ["title"]
valueField: "title"
- label: "Meta"
name: "meta"
widget: "object"
fields:
- {label: Title, name: title, widget: string, required: false}
- {label: Description, name: description, widget: text, required: false, pattern: [".{,300}", "Must not exceed 300 characters"]}
- {label: Canonical Link, name: canonicalLink, widget: string, required: false}
- {label: Noindex, name: noindex, widget: boolean, required: false}
- name: postCategories
@ -94,6 +134,14 @@ collections: # A list of collections the CMS should be able to edit
create: true # Allow users to create new documents in this collection
fields: # The fields each document in this collection have
- {label: Title, name: title, widget: string}
- label: "Meta"
name: "meta"
widget: "object"
fields:
- {label: Title, name: title, widget: string, required: false}
- {label: Description, name: description, widget: text, required: false, pattern: [".{,300}", "Must not exceed 300 characters"]}
- {label: Canonical Link, name: canonicalLink, widget: string, required: false}
- {label: Noindex, name: noindex, widget: boolean, required: false}
- name: "settings"

View file

@ -1,7 +1,6 @@
import React, { Component } from 'react'
import React, { Component, Fragment } from 'react'
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'
import Helmet from 'react-helmet'
import _findIndex from 'lodash/findIndex'
import ScrollToTop from './components/ScrollToTop'
import Meta from './components/Meta'
@ -19,6 +18,18 @@ import data from './data.json'
import { slugify } from './util/url'
import { documentHasTerm, getCollectionTerms } from './util/collection'
const RouteWithMeta = ({ component: Component, ...props }) => (
<Route
{...props}
render={routeProps => (
<Fragment>
<Meta {...props} />
<Component {...routeProps} {...props} />
</Fragment>
)}
/>
)
class App extends Component {
state = {
data
@ -28,7 +39,7 @@ class App extends Component {
this.state.data[collection] &&
this.state.data[collection].filter(page => page.name === name)[0]
getDocuments = collection => this.state.data[collection]
getDocuments = collection => this.state.data[collection] || []
render () {
const globalSettings = this.getDocument('settings', 'global')
@ -59,9 +70,7 @@ class App extends Component {
titleTemplate={`${siteTitle} | %s`}
/>
<Meta
title={siteTitle}
url={siteUrl}
description={siteDescription}
headerScripts={headerScripts}
absoluteImageUrl={
socialMediaCard &&
socialMediaCard.image &&
@ -73,95 +82,75 @@ class App extends Component {
twitterSiteAccount={
socialMediaCard && socialMediaCard.twitterSiteAccount
}
headerScripts={headerScripts}
/>
<Nav />
<Switch>
<Route
<RouteWithMeta
path='/'
exact
render={props => (
<Home page={this.getDocument('pages', 'home')} {...props} />
)}
component={Home}
description={siteDescription}
fields={this.getDocument('pages', 'home')}
/>
<Route
<RouteWithMeta
path='/about/'
exact
render={props => (
<About page={this.getDocument('pages', 'about')} {...props} />
)}
component={About}
fields={this.getDocument('pages', 'about')}
/>
<Route
<RouteWithMeta
path='/contact/'
exact
render={props => (
<Contact
page={this.getDocument('pages', 'contact')}
siteTitle={siteTitle}
{...props}
/>
)}
component={Contact}
fields={this.getDocument('pages', 'contact')}
siteTitle={siteTitle}
/>
{/* Blog Routes */}
<Route
<RouteWithMeta
path='/blog/'
exact
render={props => (
<Blog
page={this.getDocument('pages', 'blog')}
posts={posts}
postCategories={postCategories}
{...props}
component={Blog}
fields={this.getDocument('pages', 'blog')}
posts={posts}
postCategories={postCategories}
/>
{posts.map((post, index) => {
const path = slugify(`/blog/${post.title}`)
const nextPost = posts[index - 1]
const prevPost = posts[index + 1]
return (
<RouteWithMeta
key={path}
path={path}
exact
component={SinglePost}
fields={post}
nextPostURL={nextPost && slugify(`/blog/${nextPost.title}/`)}
prevPostURL={prevPost && slugify(`/blog/${prevPost.title}/`)}
/>
)}
/>
<Route
path='/blog/category/:slug/'
render={props => {
// help needed
const slug = props.match.params.slug
const categoryPosts = posts.filter(post =>
documentHasTerm(post, 'categories', slug)
)
if (!categoryPosts.length) return <NoMatch siteUrl={siteUrl} />
return (
<Blog
page={this.getDocument('pages', 'blog')}
posts={categoryPosts}
postCategories={postCategories}
showFeatured={false}
{...props}
/>
)
}}
/>
<Route
path='/blog/:slug/'
render={props => {
const slug = props.match.params.slug
const singlePostID = _findIndex(
posts,
item => slugify(item.title) === slug
)
const singlePost = posts[singlePostID]
const nextPost = posts[singlePostID - 1]
const prevPost = posts[singlePostID + 1]
if (!singlePost) return <NoMatch siteUrl={siteUrl} />
return (
<SinglePost
singlePost={singlePost}
nextPostURL={
nextPost && `/blog/${slugify(nextPost.title)}/`
}
prevPostURL={
prevPost && `/blog/${slugify(prevPost.title)}/`
}
{...props}
/>
)
}}
/>
)
})}
{postCategories.map(postCategory => {
const slug = slugify(postCategory.title)
const path = slugify(`/blog/category/${slug}`)
const categoryPosts = posts.filter(post =>
documentHasTerm(post, 'categories', slug)
)
return (
<RouteWithMeta
key={path}
path={path}
exact
component={Blog}
fields={this.getDocument('pages', 'blog')}
posts={categoryPosts}
postCategories={postCategories}
/>
)
})}
<Route render={() => <NoMatch siteUrl={siteUrl} />} />
</Switch>

View file

@ -1,58 +1,56 @@
import React from 'react'
import Helmet from 'react-helmet'
import _get from 'lodash/get'
import _pickBy from 'lodash/pickBy'
const Meta = ({
title,
url,
description,
absoluteImageUrl,
twitterSiteAccount,
twitterCreatorAccount,
headerScripts
}) => {
const onlyTruthyValues = obj => _pickBy(obj, item => item)
const Meta = props => {
const {
title,
url,
description,
absoluteImageUrl,
twitterSiteAccount,
twitterCreatorAccount,
headerScripts,
noindex,
canonicalLink
// overwrite { title, description } if in fields or fields.meta
} = {
...props,
...onlyTruthyValues(_get(props, 'fields')),
...onlyTruthyValues(_get(props, 'fields.meta'))
}
// write headerScripts
const headerScriptsElement = document.head.querySelector('#headerScripts')
if (headerScripts && headerScriptsElement) {
headerScriptsElement.outerHTML = headerScripts
}
const runChecks = () => {
if (process.env.NODE_ENV !== 'development') return
// Site Url Check
if (url === 'https://netlify-cms-react-starter.netlify.com') {
console.warn(`Site url may need updating (${url})`)
}
// Title
if (!title) {
console.error(`Missing Site Title`)
}
// Description
if (!description) {
console.error(`Missing Site Description`)
}
}
runChecks()
return (
<Helmet>
<meta name='description' content={description} />
<meta property='og:title' content={title} />
<meta property='og:type' content='website' />
<meta property='og:url' content={url} />
<meta property='og:description' content={description} />
{title && <title>{title}</title>}
{title && <meta property='og:title' content={title} />}
{description && <meta name='description' content={description} />}
{description && <meta property='og:description' content={description} />}
{url && <meta property='og:type' content='website' />}
{url && <meta property='og:url' content={url} />}
{absoluteImageUrl && (
<meta name='twitter:card' content='summary_large_image' />
)}
{absoluteImageUrl && (
<meta property='og:image' content={absoluteImageUrl} />
)}
<meta name='twitter:card' content='summary_large_image' />
{twitterSiteAccount && (
<meta name='twitter:site' content={twitterSiteAccount} />
)}
{twitterCreatorAccount && (
<meta name='twitter:creator' content={twitterCreatorAccount} />
)}
{noindex && <meta name='robots' content='noindex' />}
{canonicalLink && <link rel='canonical' href={canonicalLink} />}
</Helmet>
)
}

View file

@ -1,18 +1,14 @@
import React from 'react'
import Helmet from 'react-helmet'
import PageHeader from '../components/PageHeader'
import LazyImage from '../components/LazyImage'
import Content from '../components/Content.js'
import './About.css'
export default ({ page }) => {
const { title, subtitle, featuredImage, section1, section2 } = page
export default ({ fields }) => {
const { title, subtitle, featuredImage, section1, section2 } = fields
return (
<div className='About'>
<Helmet>
<title>{title}</title>
</Helmet>
<PageHeader
title={title}
subtitle={subtitle}

View file

@ -1,5 +1,4 @@
import React from 'react'
import Helmet from 'react-helmet'
import _sortBy from 'lodash/sortBy'
import PageHeader from '../components/PageHeader'
@ -9,20 +8,16 @@ import PostSection from '../components/PostSection'
import './Blog.css'
export default ({
page,
fields,
posts = [],
postCategories = [],
showFeatured = true
}) => {
const { title, subtitle, featuredImage } = page
const { title, subtitle, featuredImage } = fields
posts = _sortBy(posts, ['date']).reverse()
return (
<main className='Blog'>
<Helmet>
<title>{title}</title>
</Helmet>
<PageHeader
title={title}
subtitle={subtitle}
@ -32,6 +27,7 @@ export default ({
{!!postCategories.length && (
<PostCategoriesNav categories={postCategories} />
)}
{!!posts.length && <PostSection posts={posts} />}
</main>
)

View file

@ -1,5 +1,4 @@
import React from 'react'
import Helmet from 'react-helmet'
import { MapPin, Smartphone, Mail } from 'react-feather'
import PageHeader from '../components/PageHeader'
@ -7,14 +6,10 @@ import EnquiryFormSimpleAjax from '../components/EnquiryFormSimpleAjax'
import Content from '../components/Content'
import './Contact.css'
export default ({ page }) => {
const { title, subtitle, featuredImage, address, phone, email } = page
export default ({ fields }) => {
const { body, title, subtitle, featuredImage, address, phone, email } = fields
return (
<div className='Contact'>
<Helmet>
<title>{page.title}</title>
</Helmet>
<PageHeader
title={title}
subtitle={subtitle}
@ -24,7 +19,7 @@ export default ({ page }) => {
<div className='section Contact--Section1'>
<div className='container Contact--Section1--Container'>
<div>
<Content source={page.body} />
<Content source={body} />
<div className='Contact--Details'>
{address && (

View file

@ -1,23 +1,20 @@
import React from 'react'
import Helmet from 'react-helmet'
import Content from '../components/Content'
import PageHeader from '../components/PageHeader'
import './Home.css'
export default ({ page }) => {
const { title, subtitle, featuredImage, body } = page
export default ({ fields }) => {
const { title, subtitle, featuredImage, body } = fields
return (
<main className='Home'>
<Helmet>
<title>{title}</title>
</Helmet>
<PageHeader
large
title={title}
subtitle={subtitle}
backgroundImage={featuredImage}
/>
<div className='section'>
<div className='container'>
<Content source={body} />

View file

@ -1,22 +1,16 @@
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'
import { dateFormatted } from '../util/date'
import './SinglePost.css'
export default ({ singlePost, nextPostURL, prevPostURL }) => {
const { title, date, postFeaturedImage, body, categories = [] } = singlePost
export default ({ fields, nextPostURL, prevPostURL }) => {
const { title, date, postFeaturedImage, body, categories = [] } = fields
return (
<article className='SinglePost section light'>
<Helmet>
<title>{title}</title>
</Helmet>
{postFeaturedImage && (
<BackgroundImage
className='SinglePost--BackgroundImage'