1
0
mirror of https://github.com/oceanprotocol/docs.git synced 2024-11-26 19:49:26 +01:00

Merge pull request #63 from oceanprotocol/feature/seo

SEO component
This commit is contained in:
Matthias Kretschmann 2018-11-23 13:00:46 +01:00 committed by GitHub
commit 90654b3016
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 225 additions and 82 deletions

View File

@ -4,7 +4,7 @@ module.exports = {
siteDescription:
'Learn about the components of the Ocean Protocol software stack, and how to run or use the components relevant to you.',
siteUrl: process.env.SITE_URL || 'https://docs.oceanprotocol.com',
siteIcon: 'src/images/profile.png',
siteIcon: 'node_modules/@oceanprotocol/art/logo/favicon-black.png',
siteCompany: 'Ocean Protocol Foundation Ltd.',
analyticsId: 'UA-60614729-11',
social: {

View File

@ -75,7 +75,7 @@ module.exports = {
maxWidth: 666,
quality: 80,
withWebp: true,
linkImagesToOriginal: false,
linkImagesToOriginal: true,
showCaptions: true,
sizeByPixelDensity: true
}

View File

@ -22,7 +22,7 @@
"deploy": "./scripts/deploy.sh"
},
"dependencies": {
"@oceanprotocol/art": "^2.0.0",
"@oceanprotocol/art": "^2.1.0",
"axios": "^0.18.0",
"classnames": "^2.2.6",
"gatsby": "^2.0.52",

View File

@ -14,7 +14,9 @@ const DocHeader = ({ title, description }) => {
return (
<header className={styles.header}>
<h1 className={styles.title}>{title}</h1>
{description && <p className={styles.lead}>{descriptionHtml}</p>}
{description && (
<div className={styles.lead}>{descriptionHtml}</div>
)}
</header>
)
}

View File

@ -1,45 +1,17 @@
import React from 'react'
import PropTypes from 'prop-types'
import Helmet from 'react-helmet'
import { graphql, StaticQuery } from 'gatsby'
import Header from './Header'
import Footer from './Footer'
const query = graphql`
query {
site {
siteMetadata {
siteTitle
siteDescription
}
}
}
`
const Layout = ({ children, header }) => {
const headerElement = header || <Header />
return (
<StaticQuery
query={query}
render={data => {
const siteMeta = data.site.siteMetadata
return (
<>
<Helmet
defaultTitle={siteMeta.siteTitle}
titleTemplate={`%s - ${siteMeta.siteTitle}`}
>
<meta name="robots" content="noindex, nofollow" />
</Helmet>
{headerElement}
{children}
<Footer />
</>
)
}}
/>
<>
{headerElement}
{children}
<Footer />
</>
)
}

167
src/components/Seo.jsx Normal file
View File

@ -0,0 +1,167 @@
import React from 'react'
import PropTypes from 'prop-types'
import { StaticQuery, graphql } from 'gatsby'
import Helmet from 'react-helmet'
const query = graphql`
query {
site {
siteMetadata {
siteTitle
siteDescription
siteUrl
}
}
shareImage: allFile(filter: { name: { eq: "share" } }) {
edges {
node {
childImageSharp {
original {
src
}
}
}
}
}
}
`
const createSchemaOrg = (title, description, image, url, siteMeta, article) => {
const schemaOrgJSONLD = [
{
'@context': 'http://schema.org',
'@type': 'WebSite',
url: siteMeta.siteUrl,
name: title
}
]
if (article) {
schemaOrgJSONLD.push(
{
'@context': 'http://schema.org',
'@type': 'BreadcrumbList',
itemListElement: [
{
'@type': 'ListItem',
position: 1,
item: { '@id': url, name: title, image }
}
]
},
{
// https://schema.org/TechArticle
'@context': 'http://schema.org',
'@type': 'TechArticle',
name: title,
headline: title,
description,
url,
image: { '@type': 'URL', url: image }
}
)
}
return schemaOrgJSONLD
}
const MetaTags = ({
title,
description,
url,
image,
schema,
siteMeta,
article
}) => (
<Helmet
defaultTitle={siteMeta.siteTitle}
titleTemplate={`%s - ${siteMeta.siteTitle}`}
>
<html lang="en" />
{title && <title>{title}</title>}
<meta name="robots" content="noindex, nofollow" />
{/* General tags */}
<meta name="description" content={description} />
<meta name="image" content={image} />
<link rel="canonical" href={url} />
{/* Schema.org tags */}
<script type="application/ld+json">{schema}</script>
{/* OpenGraph tags */}
<meta property="og:url" content={url} />
{article && <meta property="og:type" content="article" />}
<meta property="og:title" content={title} />
<meta property="og:description" content={description} />
<meta property="og:image" content={image} />
{/* Twitter Card tags */}
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:creator" content="@oceanprotocol" />
<meta name="twitter:title" content={title} />
<meta name="twitter:description" content={description} />
<meta name="twitter:image" content={image} />
</Helmet>
)
MetaTags.propTypes = {
title: PropTypes.string,
description: PropTypes.string,
url: PropTypes.string,
image: PropTypes.string,
schema: PropTypes.string,
siteMeta: PropTypes.object,
article: PropTypes.bool
}
const SEO = ({ title, description, slug, article }) => (
<StaticQuery
query={query}
render={data => {
const siteMeta = data.site.siteMetadata
const shareImage =
data.shareImage.edges[0].node.childImageSharp.original.src
title = title || siteMeta.siteTitle
description = description || siteMeta.siteDescription
let url = siteMeta.siteUrl || siteMeta.siteUrl + slug
let image = siteMeta.siteUrl + shareImage
let schema = createSchemaOrg(
title,
description,
image,
url,
siteMeta,
article
)
schema = JSON.stringify(schema)
return (
<MetaTags
title={title}
description={description}
url={url}
image={image}
schema={schema}
siteMeta={siteMeta}
article={article}
/>
)
}}
/>
)
SEO.propTypes = {
title: PropTypes.string,
description: PropTypes.string,
slug: PropTypes.string,
article: PropTypes.bool
}
export default SEO

BIN
src/images/share.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

View File

@ -6,7 +6,7 @@ import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { Link } from 'gatsby'
import giphyAPI from 'giphy-js-sdk-core'
import Helmet from 'react-helmet'
import SEO from '../components/Seo'
import Layout from '../components/Layout'
import Content from '../components/Content'
import styles from './404.module.scss'
@ -45,7 +45,7 @@ export default class NotFoundPage extends Component {
render() {
return (
<>
<Helmet title="404 - Not Found" />
<SEO title="404 - Not Found" />
<Layout location={this.props.location}>
<Content>
<article className={styles.content}>

View File

@ -1,8 +1,8 @@
import React from 'react'
import PropTypes from 'prop-types'
import { Link, graphql } from 'gatsby'
import Helmet from 'react-helmet'
import classnames from 'classnames'
import SEO from '../components/Seo'
import Layout from '../components/Layout'
import Content from '../components/Content'
import HeaderHome from '../components/HeaderHome'
@ -38,12 +38,8 @@ SectionLink.propTypes = {
const IndexPage = ({ data, location }) => (
<>
<Helmet>
<meta
name="description"
content={data.site.siteMetadata.siteDescription}
/>
</Helmet>
<SEO />
<Layout location={location} header={<HeaderHome />}>
<Content>
<ul className={styles.sections}>

View File

@ -10,8 +10,28 @@ import DocToc from '../components/DocToc'
import DocContent from '../components/DocContent'
import DocHeader from '../components/DocHeader'
import DocFooter from '../components/DocFooter'
import SEO from '../components/Seo'
import styles from './Doc.module.scss'
const DocMain = ({ title, description, tableOfContents, post, single }) => (
<article className={single ? styles.mainSingle : styles.main}>
<DocHeader title={title} description={description} />
{tableOfContents && <DocToc tableOfContents={tableOfContents} />}
<DocContent html={post.html} htmlAst={post.htmlAst} />
<DocFooter post={post} />
</article>
)
DocMain.propTypes = {
title: PropTypes.string.isRequired,
description: PropTypes.string.isRequired,
tableOfContents: PropTypes.string.isRequired,
post: PropTypes.object.isRequired,
single: PropTypes.bool
}
export default class DocTemplate extends Component {
static propTypes = {
data: PropTypes.object.isRequired,
@ -22,7 +42,7 @@ export default class DocTemplate extends Component {
const { location } = this.props
const post = this.props.data.markdownRemark
const sections = this.props.data.allSectionsYaml.edges
const { section } = post.fields
const { section, slug } = post.fields
const { title, description } = post.frontmatter
const { tableOfContents } = post
@ -37,10 +57,16 @@ export default class DocTemplate extends Component {
return (
<>
<Helmet>
<title>{title}</title>
<meta name="description" content={description} />
<body className={section} />
</Helmet>
<SEO
title={title}
description={description}
slug={slug}
article
/>
<Layout location={location}>
<HeaderSection title={section ? sectionTitle : title} />
@ -53,42 +79,21 @@ export default class DocTemplate extends Component {
sidebar={section}
/>
</aside>
<article className={styles.main}>
<DocHeader
title={title}
description={description}
/>
{tableOfContents && (
<DocToc
tableOfContents={tableOfContents}
/>
)}
<DocContent
html={post.html}
htmlAst={post.htmlAst}
/>
<DocFooter post={post} />
</article>
</main>
) : (
<article className={styles.mainSingle}>
<DocHeader
<DocMain
title={title}
description={description}
tableOfContents={tableOfContents}
post={post}
/>
{tableOfContents && (
<DocToc tableOfContents={tableOfContents} />
)}
<DocContent
html={post.html}
htmlAst={post.htmlAst}
/>
<DocFooter post={post} />
</article>
</main>
) : (
<DocMain
title={title}
description={description}
tableOfContents={tableOfContents}
post={post}
single
/>
)}
</Content>
</Layout>
@ -110,6 +115,7 @@ export const pageQuery = graphql`
}
fields {
section
slug
}
...PageFooter
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 31 KiB