Skip to content

Commit

Permalink
Merge pull request #102 from arcticicestudio/feature/gh-101-metadata-…
Browse files Browse the repository at this point in the history
…component

Metadata Component
  • Loading branch information
arcticicestudio authored Dec 22, 2018
2 parents ca4ed67 + f0afd74 commit a8fb8ed
Show file tree
Hide file tree
Showing 18 changed files with 12,977 additions and 19 deletions.
12,394 changes: 12,394 additions & 0 deletions assets/metadata-banner.ai

Large diffs are not rendered by default.

Binary file added src/assets/images/metadata-banner.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions src/assets/images/metadata-banner.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
78 changes: 78 additions & 0 deletions src/components/atoms/core/SiteMetadata/JsonLd.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* Copyright (C) 2018-present Arctic Ice Studio <development@arcticicestudio.com>
* Copyright (C) 2018-present Sven Greb <development@svengreb.de>
*
* Project: Nord Docs
* Repository: https://github.com/arcticicestudio/nord-docs
* License: MIT
*/

import React from "react";
import PropTypes from "prop-types";
import Helmet from "react-helmet";

/**
* Provides the linked data schema using the JSON-LD specification.
*
* @author Arctic Ice Studio <development@arcticicestudio.com>
* @author Sven Greb <development@svengreb.de>
* @since 0.4.0
* @see https://json-ld.org
* @see https://schema.org
*/
const JsonLd = ({ author, canonicalUrl, defaultTitle, description, imageUrl, keywords, title, url }) => {
const baseSchema = [
{
"@context": "http://schema.org",
"@type": "Website",
url,
canonicalUrl,
name: title,
alternateName: defaultTitle,
description,
author: {
"@type": "Person",
name: author.name,
url: author.url
},
publisher: {
"@type": "Organization",
name: author.name,
url: author.url,
logo: imageUrl
},
creator: {
"@type": "Person",
name: author.name,
url: author.url
},
image: {
"@type": "ImageObject",
url: imageUrl
},
keywords
}
];

return (
<Helmet>
<script type="application/ld+json">{JSON.stringify(baseSchema)}</script>
</Helmet>
);
};

JsonLd.propTypes = {
author: PropTypes.shape({
name: PropTypes.string,
url: PropTypes.string
}).isRequired,
canonicalUrl: PropTypes.string.isRequired,
defaultTitle: PropTypes.string.isRequired,
description: PropTypes.string.isRequired,
imageUrl: PropTypes.string.isRequired,
keywords: PropTypes.arrayOf(PropTypes.string).isRequired,
title: PropTypes.string.isRequired,
url: PropTypes.string.isRequired
};

export default React.memo(JsonLd);
162 changes: 162 additions & 0 deletions src/components/atoms/core/SiteMetadata/SiteMetadata.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
/*
* Copyright (C) 2018-present Arctic Ice Studio <development@arcticicestudio.com>
* Copyright (C) 2018-present Sven Greb <development@svengreb.de>
*
* Project: Nord Docs
* Repository: https://github.com/arcticicestudio/nord-docs
* License: MIT
*/

import React, { Fragment } from "react";
import PropTypes from "prop-types";
import { Helmet } from "react-helmet";
import { graphql, StaticQuery } from "gatsby";

import metadataBanner from "assets/images/metadata-banner.png";

import JsonLd from "./JsonLd";

const PureSiteMetadata = ({
data: {
site: {
siteMetadata: {
keywords: keywordsNordDocs,
nord: {
author,
description,
keywords: keywordsNord,
links: {
social: { twitter }
},
title
},
siteUrl
}
}
},
pathName
}) => (
<Fragment>
<Helmet defaultTitle={title} titleTemplate={`${title} | %s`}>
<html lang="en" prefix="og: http://ogp.me/ns#" />
<meta content={description} name="description" />
<meta content={author.name} name="author" />
<meta content={Array.from(new Set([...keywordsNord, ...keywordsNordDocs]))} name="keywords" />
<meta content={author.name} name="creator" />
<meta content={author.name} name="publisher" />

<meta content={`${siteUrl}${pathName}`} property="og:url" />
<meta content="website" property="og:type" />
<meta content="en" property="og:locale" />
<meta content={title} property="og:title" />
<meta content={title} property="og:site_name" />
<meta content={`${siteUrl}${metadataBanner}`} property="og:image" />
<meta content="image/png" property="og:image:type" />
<meta content="1200" property="og:image:width" />
<meta content="630" property="og:image:height" />
<meta content={description} property="og:description" />

<meta content="summary_large_image" name="twitter:card" />
<meta content={`@${twitter.id}`} name="twitter:site" />
<meta content={title} name="twitter:title" />
<meta content={description} name="twitter:description" />
<meta content={`${siteUrl}${metadataBanner}`} name="twitter:image" />
<meta content="A banner consisting of Nord's logo and a caption" name="twitter:image:alt" />
<meta content={`@${twitter.id}`} name="twitter:creator" />
</Helmet>
<JsonLd
author={author}
canonicalUrl={siteUrl}
defaultTitle={title}
description={description}
imageUrl={`${siteUrl}${metadataBanner}`}
keywords={Array.from(new Set([...keywordsNord, ...keywordsNordDocs]))}
title={title}
url={`${siteUrl}${pathName}`}
/>
</Fragment>
);

/**
* Provides metadata tags that'll be injected into the `<head>` for SEO & social media purposes including
* "Twitter Card", "Open Graph Protocol" and "JSON-LD" specification elements.
*
* @author Arctic Ice Studio <development@arcticicestudio.com>
* @author Sven Greb <development@svengreb.de>
* @since 0.4.0
* @see https://developer.twitter.com/en/docs/tweets/optimize-with-cards/overview/summary-card-with-large-image
* @see https://developer.twitter.com/en/docs/tweets/optimize-with-cards/overview/markup
* @see https://developers.facebook.com/docs/sharing/opengraph/object-properties
* @see http://ogp.me
* @see https://developers.facebook.com/docs/sharing/best-practices
* @see https://json-ld.org
* @see https://schema.org
* @see https://rdfa.info
* @see https://en.wikipedia.org/wiki/RDFa
* @see https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta
*/
const SiteMetadata = ({ pathName, ...passProp }) => (
<StaticQuery
query={graphql`
{
site {
siteMetadata {
keywords
nord {
author {
name
url
}
description
keywords
links {
social {
twitter {
id
}
}
}
title
}
siteUrl
}
}
}
`}
/* eslint-disable-next-line react/jsx-no-bind */
render={data => <PureSiteMetadata data={data} pathName={pathName} {...passProp} />}
/>
);

PureSiteMetadata.propTypes = {
data: PropTypes.shape({
site: PropTypes.shape({
siteMetadata: PropTypes.shape({
keywords: PropTypes.arrayOf(PropTypes.string),
nord: PropTypes.shape({
author: PropTypes.shape({
name: PropTypes.string,
url: PropTypes.string
}),
description: PropTypes.string,
keywords: PropTypes.arrayOf(PropTypes.string),
links: PropTypes.shape({
social: PropTypes.shape({
twitter: PropTypes.shape({
id: PropTypes.string
})
})
}),
title: PropTypes.string
}),
siteUrl: PropTypes.string
})
})
}).isRequired,
pathName: PropTypes.string.isRequired
};

SiteMetadata.propTypes = { pathName: PropTypes.string.isRequired };

export { PureSiteMetadata };
export default SiteMetadata;
14 changes: 14 additions & 0 deletions src/components/atoms/core/SiteMetadata/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Copyright (C) 2018-present Arctic Ice Studio <development@arcticicestudio.com>
* Copyright (C) 2018-present Sven Greb <development@svengreb.de>
*
* Project: Nord Docs
* Repository: https://github.com/arcticicestudio/nord-docs
* License: MIT
*/

import JsonLd from "./JsonLd";
import SiteMetadata, { PureSiteMetadata } from "./SiteMetadata";

export { JsonLd, PureSiteMetadata };
export default SiteMetadata;
7 changes: 5 additions & 2 deletions src/components/layouts/core/BaseLayout/BaseLayout.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import PropTypes from "prop-types";
import Header from "organisms/core/Header";
import Page from "containers/core/Page";
import Root from "containers/core/Root";
import SiteMetadata from "atoms/core/SiteMetadata";

/**
* The base page layout providing the main container that wraps the content.
Expand All @@ -21,17 +22,19 @@ import Root from "containers/core/Root";
* @author Sven Greb <development@svengreb.de>
* @since 0.3.0
*/
const BaseLayout = ({ children }) => (
const BaseLayout = ({ children, pathName }) => (
<Root>
<Fragment>
<SiteMetadata pathName={pathName} />
<Header />
<Page>{children}</Page>
</Fragment>
</Root>
);

BaseLayout.propTypes = {
children: PropTypes.node.isRequired
children: PropTypes.node.isRequired,
pathName: PropTypes.string.isRequired
};

export default BaseLayout;
35 changes: 35 additions & 0 deletions src/data/pages/shared/propTypes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright (C) 2018-present Arctic Ice Studio <development@arcticicestudio.com>
* Copyright (C) 2018-present Sven Greb <development@svengreb.de>
*
* Project: Nord Docs
* Repository: https://github.com/arcticicestudio/nord-docs
* License: MIT
*/

/**
* @file Provides shared prop types for pages.
* @author Arctic Ice Studio <development@arcticicestudio.com>
* @author Sven Greb <development@svengreb.de>
* @see https://reactjs.org/docs/typechecking-with-proptypes.html
* @since 0.4.0
*/

import PropTypes from "prop-types";

const locationPropTypes = {
/**
* The `location` object provided by React/Reach Router.
*
* @see https://reach.tech/router/api/Router
*/
location: PropTypes.shape({
/**
* The name of the current route/path.
*/
pathname: PropTypes.string
}).isRequired
};

/* eslint-disable-next-line import/prefer-default-export */
export { locationPropTypes };
Loading

0 comments on commit a8fb8ed

Please sign in to comment.