This commit is contained in:
Jon McClure 2022-08-15 18:32:51 +01:00
parent bfdd36ff9c
commit 9873372623
7 changed files with 172 additions and 73 deletions

View file

@ -0,0 +1,45 @@
<script>
import { Meta, Template, Story } from '@storybook/addon-svelte-csf';
// @ts-ignore
import componentDocs from './stories/docs/component.md?raw';
// @ts-ignore
import quickitDocs from './stories/docs/quickit.md?raw';
import SEO from './SEO.svelte';
import {
withComponentDocs,
withStoryDocs,
} from '$lib/docs/utils/withParams.js';
const meta = {
title: 'Utilities/SEO',
component: SEO,
...withComponentDocs(componentDocs),
};
</script>
<Meta {...meta} />
<Template let:args>
<SEO {...args} />
<div>Nothing to see here. 😎</div>
</Template>
<Story
name="Default"
args={{
url: new URL('https://graphics.reuters.com/hello-world/'),
publishTime: new Date('2020-09-15').toISOString(),
}}
/>
<Story
name="🚀 QUICKIT"
args={{
url: new URL('https://graphics.reuters.com/hello-world/'),
publishTime: new Date('2020-09-15').toISOString(),
}}
{...withStoryDocs(quickitDocs)}
/>

View file

@ -1,45 +1,76 @@
<script> <script lang="ts">
import pkg from '$pkg';
import { page } from '$app/stores';
import { get } from 'lodash-es';
import urljoin from 'proper-url-join';
import { browser } from '$app/env';
import analytics from './analytics'; import analytics from './analytics';
import publisherTags from './publisherTags'; import publisherTags from './publisherTags';
import { assets } from '$app/paths';
/**
* [URL](https://developer.mozilla.org/en-US/docs/Web/API/URL) object for the page.
* @required
* @type {URL}
*/
export let url: URL | null = null;
/**
* SEO title
* @required
* @type {string}
*/
export let seoTitle; export let seoTitle;
/**
* SEO description
* @required
* @type {string}
*/
export let seoDescription; export let seoDescription;
/**
* Share title
* @required
* @type {string}
*/
export let shareTitle; export let shareTitle;
/**
* Share description
* @required
* @type {string}
*/
export let shareDescription; export let shareDescription;
/**
* Share image path. **Must be an absolute path.**
* @required
* @type {string}
*/
export let shareImgPath; export let shareImgPath;
/**
* [HTML lang attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/lang). **Two-letter code only.**
* @type {string}
*/
export let lang = 'en'; export let lang = 'en';
export let hostname = 'graphics.reuters.com'; /**
* Publish time as an [ISO string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
* @type {string}
*/
export let publishTime: string = '';
/**
* Updated time as an [ISO string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
* @type {string}
*/
export let updateTime: string = '';
interface GraphicAuthor {
name: string;
url: string;
}
const parseUrl = (url) => { /**
try { * Array of authors for the piece. Each author object must have `name` and `url` attributes.
return new URL(url); */
} catch { export let authors: GraphicAuthor[] = [];
return {}; /**
} * Whether to inject Google Analytics code for this page.
}; */
export let includeAnalytics: boolean = false;
const url = get(pkg, 'homepage')
? urljoin(parseUrl(pkg.homepage).origin, $page.url.pathname, {
trailingSlash: true,
})
: get(pkg, 'reuters.preview')
? urljoin(parseUrl(pkg.reuters.preview).origin, $page.url.pathname, {
trailingSlash: true,
})
: $page.host
? urljoin('https://' + $page.host, $page.url.pathname, {
trailingSlash: true,
})
: `https://${hostname}`;
// Only fire analytics on prod sites // Only fire analytics on prod sites
if (browser && window.location.host === 'graphics.reuters.com') { if (typeof window !== 'undefined' && includeAnalytics) {
analytics(url, seoTitle); analytics(url, seoTitle);
publisherTags(); publisherTags();
} }
@ -62,27 +93,27 @@
'@context': 'http://schema.org', '@context': 'http://schema.org',
'@type': 'NewsArticle', '@type': 'NewsArticle',
headline: seoTitle, headline: seoTitle,
url, url: url.href,
mainEntityOfPage: { mainEntityOfPage: {
'@type': 'WebPage', '@type': 'WebPage',
'@id': url, '@id': url.href,
}, },
thumbnailUrl: urljoin(assets, shareImgPath), thumbnailUrl: shareImgPath,
image: [ image: [
{ {
'@context': 'http://schema.org', '@context': 'http://schema.org',
'@type': 'ImageObject', '@type': 'ImageObject',
url: urljoin(assets, shareImgPath), url: shareImgPath,
}, },
], ],
publisher: { '@id': 'https://www.reuters.com/#publisher' }, publisher: { '@id': 'https://www.reuters.com/#publisher' },
copyrightHolder: { '@id': 'https://www.reuters.com/#publisher' }, copyrightHolder: { '@id': 'https://www.reuters.com/#publisher' },
sourceOrganization: { '@id': 'https://www.reuters.com/#publisher' }, sourceOrganization: { '@id': 'https://www.reuters.com/#publisher' },
copyrightYear: new Date().getFullYear(), copyrightYear: new Date().getFullYear(),
dateCreated: get(pkg, 'reuters.graphic.published'), dateCreated: publishTime,
datePublished: get(pkg, 'reuters.graphic.published'), datePublished: publishTime,
dateModified: get(pkg, 'reuters.graphic.updated'), dateModified: updateTime,
author: get(pkg, 'reuters.graphic.authors', []).map(({ name, url }) => ({ author: authors.map(({ name, url }) => ({
'@type': 'Person', '@type': 'Person',
name, name,
url, url,
@ -98,7 +129,7 @@
<html lang="{lang}"></html> <html lang="{lang}"></html>
<title>{seoTitle}</title> <title>{seoTitle}</title>
<meta name="description" content="{seoDescription}" /> <meta name="description" content="{seoDescription}" />
<link rel="canonical" href="{url}" /> <link rel="canonical" href="{url.href}" />
<link <link
rel="shortcut icon" rel="shortcut icon"
type="image/x-icon" type="image/x-icon"
@ -123,7 +154,7 @@
sizes="96x96" sizes="96x96"
/> />
<meta property="og:url" content="{url}" /> <meta property="og:url" content="{url.href}" />
<meta property="og:type" content="article" /> <meta property="og:type" content="article" />
<meta property="og:title" content="{shareTitle}" itemprop="name" /> <meta property="og:title" content="{shareTitle}" itemprop="name" />
<meta <meta
@ -133,7 +164,7 @@
/> />
<meta <meta
property="og:image" property="og:image"
content="{urljoin(assets, shareImgPath)}" content="{shareImgPath}"
itemprop="image" itemprop="image"
/> />
<meta property="og:site_name" content="Reuters" /> <meta property="og:site_name" content="Reuters" />
@ -141,10 +172,10 @@
<meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@ReutersGraphics" /> <meta name="twitter:site" content="@ReutersGraphics" />
<meta name="twitter:creator" content="@ReutersGraphics" /> <meta name="twitter:creator" content="@ReutersGraphics" />
<meta name="twitter:domain" content="{`https://${hostname}`}" /> <meta name="twitter:domain" content="{url.origin}" />
<meta name="twitter:title" content="{shareTitle}" /> <meta name="twitter:title" content="{shareTitle}" />
<meta name="twitter:description" content="{shareDescription}" /> <meta name="twitter:description" content="{shareDescription}" />
<meta name="twitter:image:src" content="{urljoin(assets, shareImgPath)}" /> <meta name="twitter:image:src" content="{shareImgPath}" />
<meta property="fb:app_id" content="319194411438328" /> <meta property="fb:app_id" content="319194411438328" />
<meta property="fb:admins" content="616167736" /> <meta property="fb:admins" content="616167736" />

View file

@ -1,3 +1,4 @@
// @ts-nocheck
/* eslint-disable */ /* eslint-disable */
const attachScript = function (i, s, o, g, r, a, m) { const attachScript = function (i, s, o, g, r, a, m) {
i.GoogleAnalyticsObject = r; i.GoogleAnalyticsObject = r;

View file

@ -1,29 +0,0 @@
---
title: SEO
description: Add SEO to the page.
slug: seo
---
<section>
## {title}
{description}
</section>
```svelte
<script>
import { SEO } from '@reuters-graphics/graphics-svelte-components';
</script>
<SEO
seoTitle="{'A title for Google'}"
seoDescription="{'A description for Google'}"
shareTitle="{'A title for Twitter/Facebook'}"
shareDecription="{'A description for Twitter/Facebook'}"
shareImgPath="{'images/share.jpg'}"
lang="{'en'}"
hostname="{'graphics.reuters.com'}"
/>
```

View file

@ -0,0 +1,24 @@
The `SEO` component adds essential metadata to published pages.
```svelte
<script>
import { SEO } from '@reuters-graphics/graphics-components';
</script>
<SEO
url={new URL('https://graphics.reuters.com/world-coronavirus-tracker-and-maps/')}
seoTitle="A title for Google"
seoDescription="A description for Google"
shareTitle="A title for Twitter/Facebook"
shareDecription="A description for Twitter/Facebook"
shareImgPath="https://graphics.reuters.com/world-coronavirus-tracker-and-maps/assets/images/share.jpg"
lang="en"
publishTime="2020-09-15T00:00:00.000Z"
updateTime="2021-01-10T12:30:00.000Z"
authors={[
{ name: 'Jane Doe', url: 'https://twitter.com/JaneDoe' },
{ name: 'John Doe', url: 'https://twitter.com/JohnDoe' },
]}
includeAnalytics={true}
/>
```

View file

@ -0,0 +1,27 @@
Add the `SEO` component to any page specified in the `pages/` directory of the Graphics Kit.
Most of the fields are filled in by other sources, like your Google Doc and package.json. (Usually, the fastest way is to copy the `SEO` component from one of the pages already in your project.)
```svelte
<script>
import { SEO } from '@reuters-graphics/graphics-components';
import pkg from '$pkg';
import content from '$locales/en/content.json';
import { assets } from '$app/paths';
import { page } from '$app/stores';
</script>
<SEO
lang="en"
url={$page.url}
seoTitle="{content.SEOTitle}"
seoDescription="{content.SEODescription}"
shareTitle="{content.ShareTitle}"
shareDescription="{content.ShareDescription}"
shareImgPath="{`${assets}/${content.ShareImgPath}`}"
publishTime={pkg?.reuters?.graphic?.published}
updateTime={pkg?.reuters?.graphic?.updated}
authors={pkg?.reuters?.graphic?.authors}
includeAnalytics={true}
/>
```

View file

@ -13,7 +13,7 @@ export { default as NoteText } from './components/NoteText/NoteText.svelte';
export { default as PymChild } from './components/PymChild/PymChild.svelte'; export { default as PymChild } from './components/PymChild/PymChild.svelte';
export { default as ReutersLogo } from './components/ReutersLogo/ReutersLogo.svelte'; export { default as ReutersLogo } from './components/ReutersLogo/ReutersLogo.svelte';
// export { default as Scroller } from './Scroller/index.svelte'; // export { default as Scroller } from './Scroller/index.svelte';
// export { default as SEO } from './SEO/index.svelte'; export { default as SEO } from './components/SEO/SEO.svelte';
export { default as Sharer } from './components/Sharer/Sharer.svelte'; export { default as Sharer } from './components/Sharer/Sharer.svelte';
export { export {
default as SiteFooter, default as SiteFooter,