Skip to content
Open

Seo #81

Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/components/layout/layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import Seo from "../seo/seo"
import Callout from "../callout/callout"
import Tableau from "../tableau/tableau"

const shortcodes = { Callout, Tableau };
const shortcodes = { Callout, Tableau }

export default function Layout({ children }) {
return (
Expand Down
210 changes: 118 additions & 92 deletions src/components/seo/seo.js
Original file line number Diff line number Diff line change
@@ -1,103 +1,129 @@
import React from "react"
import PropTypes from "prop-types"
import { Helmet } from "react-helmet"
import { useLocation } from "@reach/router"
import Helmet from "react-helmet"
import { useStaticQuery, graphql } from "gatsby"
import faviconSvg from "../../assets/svg/greenlightFavicon.svg"
import faviconIco from "../../assets/ico/greenlight.ico"
import maskIcon from "../../assets/svg/greenlightMaskIcon.svg"

// Implementation reference available at: https://www.gatsbyjs.com/docs/add-seo-component/

const SEO = ({ title, description, image, article, siteLanguage }) => {
const { pathname } = useLocation();
const { site } = useStaticQuery(query);

// destructure the data from the query
const {
defaultTitle,
defaultDescription,
siteUrl,
defaultImage,
defaultLanguage,
} = site.siteMetadata;

// Aliasing the properties comes in handy here to avoid name collisions.
const seo = {
title: title || defaultTitle,
description: description || defaultDescription,
image: `${siteUrl}${image || defaultImage}`,
url: `${siteUrl}${pathname}`,
lang: siteLanguage || defaultLanguage,
};
import PropTypes from "prop-types"

// Adds meta tags for SEO and to generate previews for social media sharing.
// Checks if the props were used. If not, the default values are applied.
function SEO({ description, lang, meta, image: metaImage, title, pathname }) {
const { site } = useStaticQuery(
graphql`
query {
site {
siteMetadata {
title
description
author {
name
}
siteUrl
}
}
}
`
)
const metaDescription = description || site.siteMetadata.description
const image =
metaImage && metaImage.src
? `${site.siteMetadata.siteUrl}${metaImage.src}`
: null
const canonical = pathname ? `${site.siteMetadata.siteUrl}${pathname}` : null
return (
<Helmet title={seo.title}>
<html lang={seo.lang} />
{/* the favicon file has a static color, replace this value in the file itself */}
<link rel="icon" type="image/svg+xml" href={faviconSvg} />
{/* svg files need an alternative ico file in case client browser lacks support */}
<link rel="alternate icon" href={faviconIco} />
{/* change the color of the mask-icon for hover effect on Safari pinned tabs */}
<link rel="mask-icon" href={maskIcon} color="#0DF2C1" />

<meta name="description" content={seo.description} />
<meta name="image" content={seo.image} />

{/* Insert schema.org (facebook) and twitter data conditionally */}
{seo.url && <meta property="og:url" content={seo.url} />}
{(article ? true : null) && <meta property="og:type" content="article" />}
{seo.title && <meta property="og:title" content={seo.title} />}
{seo.description && (<meta property="og:description" content={seo.description} />)}
{seo.image && <meta property="og:image" content={seo.image} />}
<meta name="twitter:card" content="summary_large_image" />
{/* {twitterUsername && (<meta name="twitter:creator" content={twitterUsername} />)} */}
{seo.title && <meta name="twitter:title" content={seo.title} />}
{seo.description && (<meta name="twitter:description" content={seo.description} />)}
{seo.image && <meta name="twitter:image" content={seo.image} />}
<title>{seo.title}</title>
</Helmet>
<Helmet
htmlAttributes={{
lang,
}}
title={title}
titleTemplate={`%s | ${site.siteMetadata.title}`}
link={
canonical
? [
{
rel: "canonical",
href: canonical,
},
]
: []
}
meta={[
{
name: `description`,
content: metaDescription,
},
// {
// name: "keywords",
// content: site.siteMetadata.keywords.join(","),
// },
{
property: `og:title`,
content: title,
},
{
property: `og:description`,
content: metaDescription,
},
{
property: `og:type`,
content: `website`,
},
{
name: `twitter:creator`,
content: `${site.siteMetadata.author[0].name} ${site.siteMetadata.author[1].name}`,
},
{
name: `twitter:title`,
content: title,
},
{
name: `twitter:description`,
content: metaDescription,
},
].concat(
metaImage
? [
{
property: "og:image",
content: image,
},
{
property: "og:image:width",
content: metaImage.width,
},
{
property: "og:image:height",
content: metaImage.height,
},
{
name: "twitter:card",
content: "summary_large_image",
},
]
: [
{
name: "twitter:card",
content: "summary",
},
]
)}
/>
)
}

export default SEO
SEO.defaultProps = {
lang: `en`,
meta: [],
description: ``,
}

// propTypes ensure we get all the data needed in the component
// helps as a guide while destructuring or using the props.
SEO.propTypes = {
title: PropTypes.string,
description: PropTypes.string,
image: PropTypes.string,
article: PropTypes.bool,
siteLanguage: PropTypes.string,
url: PropTypes.string,
};

// SEO component is also in other files, e.g. post-template file,
// the component also accepts sensible defaults in the SEO.defaultProps section.
// This way the information in siteMetadata (gatsby-config.js) gets used every time unless you define the property explicitly.
SEO.defaultProps = {
title: null,
description: null,
image: null,
article: false,
siteLanguage: 'en',
url: null,
};
lang: PropTypes.string,
meta: PropTypes.arrayOf(PropTypes.object),
title: PropTypes.string.isRequired,
image: PropTypes.shape({
src: PropTypes.string.isRequired,
height: PropTypes.number.isRequired,
width: PropTypes.number.isRequired,
}),
pathname: PropTypes.string,
}

// Query data found in gatsby-config.js (change the siteUrl value once starter is deployed in production)
const query = graphql`
query SEO {
site {
siteMetadata {
defaultTitle: title
defaultDescription: description
siteUrl: siteUrl
defaultImage: image
defaultLanguage: siteLanguage
}
}
}
`;
export default SEO