commit
bf2bcaed1f
6 changed files with 116 additions and 143 deletions
|
|
@ -33,7 +33,7 @@ Venison shoulder *ham hock ham leberkas*. Flank beef ribs fatback, jerky meatbal
|
||||||
With the Graphics Kit, you'll likely get your text value from an ArchieML doc...
|
With the Graphics Kit, you'll likely get your text value from an ArchieML doc...
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
# Archie ML doc
|
# ArchieML doc
|
||||||
[blocks]
|
[blocks]
|
||||||
|
|
||||||
type: text
|
type: text
|
||||||
|
|
|
||||||
80
src/components/SEO/SEO.mdx
Normal file
80
src/components/SEO/SEO.mdx
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
import { Meta, Canvas } from '@storybook/blocks';
|
||||||
|
|
||||||
|
import * as SEOStories from './SEO.stories.svelte';
|
||||||
|
|
||||||
|
<Meta of={SEOStories} />
|
||||||
|
|
||||||
|
# SEO
|
||||||
|
|
||||||
|
The `SEO` component adds essential metadata to pages.
|
||||||
|
|
||||||
|
```svelte
|
||||||
|
<script>
|
||||||
|
import { SEO } from '@reuters-graphics/graphics-components';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<SEO
|
||||||
|
baseUrl="https://www.reuters.com/graphics/world-coronavirus-tracker-and-maps"
|
||||||
|
pageUrl={new URL(
|
||||||
|
'https://www.reuters.com/graphics/world-coronavirus-tracker-and-maps/countries/united-kingdom/'
|
||||||
|
)}
|
||||||
|
seoTitle="A title for Google"
|
||||||
|
seoDescription="A description for Google"
|
||||||
|
shareTitle="A title for Twitter/Facebook"
|
||||||
|
shareDescription="A description for Twitter/Facebook"
|
||||||
|
shareImgPath="https://www.reuters.com/graphics/world-coronavirus-tracker-and-maps/assets/images/share.jpg"
|
||||||
|
shareImgAlt="An image showing global COVID infection rates"
|
||||||
|
publishTime="2020-09-15T00:00:00.000Z"
|
||||||
|
updateTime="2021-01-10T12:30:00.000Z"
|
||||||
|
authors={[
|
||||||
|
{ name: 'Jane Doe', link: 'https://www.reuters.com/authors/jane-doe/' },
|
||||||
|
{ name: 'John Doe', link: 'https://www.reuters.com/authors/john-doe/' },
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Using with ArchieML docs
|
||||||
|
|
||||||
|
With the Graphics Kit, you'll likely get many of your text values from an ArchieML doc...
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# ArchieML doc
|
||||||
|
slug: ROOT-SLUG/WILD
|
||||||
|
seoTitle: Page title for search
|
||||||
|
seoDescription: Page description for search
|
||||||
|
shareTitle: Page title for social media
|
||||||
|
shareDescription: Page description for social media
|
||||||
|
shareImgPath: images/reuters-graphics.jpg
|
||||||
|
shareImgAlt: Alt text for share image.
|
||||||
|
```
|
||||||
|
|
||||||
|
... which you'll pass to the `SEO` component.
|
||||||
|
|
||||||
|
```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
|
||||||
|
baseUrl={VITE_BASE_URL}
|
||||||
|
pageUrl={$page.url}
|
||||||
|
seoTitle={content.seoTitle}
|
||||||
|
seoDescription={content.seoDescription}
|
||||||
|
shareTitle={content.shareTitle}
|
||||||
|
shareDescription={content.shareDescription}
|
||||||
|
shareImgPath={`${assets}/${content.shareImgPath}`}
|
||||||
|
shareImgAlt={content.shareImgAlt}
|
||||||
|
publishTime={pkg?.reuters?.graphic?.published}
|
||||||
|
updateTime={pkg?.reuters?.graphic?.updated}
|
||||||
|
authors={pkg?.reuters?.graphic?.authors}
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Note:** For _reasons_, we can't document the value of `VITE_BASE_URL` below. It's `import` + `.meta.env.BASE_URL` (concatenate all that) in the Graphics Kit and other Vite-based rigs.
|
||||||
|
|
||||||
|
<Canvas of={SEOStories.Demo} />
|
||||||
|
```
|
||||||
|
|
@ -1,49 +1,23 @@
|
||||||
<script module lang="ts">
|
<script module lang="ts">
|
||||||
// @ts-ignore raw
|
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||||
import componentDocs from './stories/docs/component.md?raw';
|
|
||||||
// @ts-ignore raw
|
|
||||||
import archieMLDocs from './stories/docs/archieML.md?raw';
|
|
||||||
|
|
||||||
import SEO from './SEO.svelte';
|
import SEO from './SEO.svelte';
|
||||||
|
|
||||||
import {
|
const { Story } = defineMeta({
|
||||||
withComponentDocs,
|
|
||||||
withStoryDocs,
|
|
||||||
} from '$lib/docs/utils/withParams.js';
|
|
||||||
|
|
||||||
export const meta = {
|
|
||||||
title: 'Components/Ads & analytics/SEO',
|
title: 'Components/Ads & analytics/SEO',
|
||||||
component: SEO,
|
component: SEO,
|
||||||
...withComponentDocs(componentDocs),
|
});
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<div>View page source to see the SEO metadata.</div>
|
||||||
import { Template, Story } from '@storybook/addon-svelte-csf';
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<Template >
|
|
||||||
{#snippet children({ args })}
|
|
||||||
<SEO {...args} />
|
|
||||||
<div>Nothing to see here. 😎</div>
|
|
||||||
{/snippet}
|
|
||||||
</Template>
|
|
||||||
|
|
||||||
<Story
|
<Story
|
||||||
name="Default"
|
name="Demo"
|
||||||
args="{{
|
args={{
|
||||||
baseUrl: 'https://graphics.reuters.com',
|
baseUrl: 'https://www.reuters.com',
|
||||||
pageUrl: new URL('https://graphics.reuters.com/hello-world/'),
|
seoTitle: 'A title for Google',
|
||||||
publishTime: new Date('2020-09-15').toISOString(),
|
seoDescription: 'A description for Google',
|
||||||
}}"
|
shareTitle: 'A title for Twitter/Facebook',
|
||||||
/>
|
shareDescription: 'A description for Twitter/Facebook',
|
||||||
|
shareImgPath:
|
||||||
<Story
|
'https://www.reuters.com/graphics/world-coronavirus-tracker-and-maps/assets/images/share.jpg',
|
||||||
name="ArchieML"
|
}}
|
||||||
args="{{
|
|
||||||
baseUrl: 'https://graphics.reuters.com',
|
|
||||||
pageUrl: new URL('https://graphics.reuters.com/hello-world/'),
|
|
||||||
publishTime: new Date('2020-09-15').toISOString(),
|
|
||||||
}}"
|
|
||||||
{...withStoryDocs(archieMLDocs)}
|
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -2,77 +2,59 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
interface GraphicAuthor {
|
interface GraphicAuthor {
|
||||||
name: string;
|
name: string;
|
||||||
url: string;
|
link: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
/**
|
/**
|
||||||
* Base url for the page, which in [Vite-based projects](https://vitejs.dev/guide/build.html#public-base-path)
|
* Base url for the page, which in [Vite-based projects](https://vitejs.dev/guide/build.html#public-base-path) is globally available as `import.meta.env.BASE_URL`.
|
||||||
* is globally available as `import.meta.env.BASE_URL`.
|
|
||||||
* @requiredx
|
|
||||||
* @type {string}
|
|
||||||
*/
|
*/
|
||||||
baseUrl?: string;
|
baseUrl: string;
|
||||||
/**
|
/**
|
||||||
* [URL](https://developer.mozilla.org/en-US/docs/Web/API/URL) object for the page.
|
* [URL](https://developer.mozilla.org/en-US/docs/Web/API/URL) object for the page.
|
||||||
* @required
|
|
||||||
* @type {URL}
|
|
||||||
*/
|
*/
|
||||||
pageUrl?: URL | null;
|
pageUrl: URL;
|
||||||
/**
|
/**
|
||||||
* SEO title
|
* SEO title
|
||||||
* @required
|
|
||||||
* @type {string}
|
|
||||||
*/
|
*/
|
||||||
seoTitle: string;
|
seoTitle: string;
|
||||||
/**
|
/**
|
||||||
* SEO description
|
* SEO description
|
||||||
* @required
|
|
||||||
* @type {string}
|
|
||||||
*/
|
*/
|
||||||
seoDescription: string;
|
seoDescription: string;
|
||||||
/**
|
/**
|
||||||
* Share title
|
* Share title
|
||||||
* @required
|
|
||||||
* @type {string}
|
|
||||||
*/
|
*/
|
||||||
shareTitle: string;
|
shareTitle: string;
|
||||||
/**
|
/**
|
||||||
* Share description
|
* Share description
|
||||||
* @required
|
|
||||||
* @type {string}
|
|
||||||
*/
|
*/
|
||||||
shareDescription: string;
|
shareDescription: string;
|
||||||
/**
|
/**
|
||||||
* Share image path. **Must be an absolute path.**
|
* Share image path. **Must be an absolute path.**
|
||||||
* @required
|
|
||||||
* @type {string}
|
|
||||||
*/
|
*/
|
||||||
shareImgPath: string;
|
shareImgPath: string;
|
||||||
/**
|
/**
|
||||||
* Share image alt text, up to 420 characters.
|
* Share image alt text, up to 420 characters.
|
||||||
* @type {string}
|
|
||||||
*/
|
*/
|
||||||
shareImgAlt?: string;
|
shareImgAlt?: string;
|
||||||
/**
|
/**
|
||||||
* Publish time as an [ISO string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
|
* Publish time as an [ISO string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
|
||||||
* @type {string}
|
|
||||||
*/
|
*/
|
||||||
publishTime?: string;
|
publishTime?: string;
|
||||||
/**
|
/**
|
||||||
* Updated time as an [ISO string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
|
* Updated time as an [ISO string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
|
||||||
* @type {string}
|
|
||||||
*/
|
*/
|
||||||
updateTime?: string;
|
updateTime?: string;
|
||||||
/**
|
/**
|
||||||
* Array of authors for the piece. Each author object must have `name` and `url` attributes.
|
* Array of authors for the piece. Each author object must have `name` and `link` attributes.
|
||||||
*/
|
*/
|
||||||
authors?: GraphicAuthor[];
|
authors?: GraphicAuthor[];
|
||||||
}
|
}
|
||||||
|
|
||||||
let {
|
let {
|
||||||
baseUrl = '',
|
baseUrl,
|
||||||
pageUrl = null,
|
pageUrl,
|
||||||
seoTitle,
|
seoTitle,
|
||||||
seoDescription,
|
seoDescription,
|
||||||
shareTitle,
|
shareTitle,
|
||||||
|
|
@ -83,7 +65,6 @@
|
||||||
updateTime = '',
|
updateTime = '',
|
||||||
authors = [],
|
authors = [],
|
||||||
}: Props = $props();
|
}: Props = $props();
|
||||||
|
|
||||||
const getOrigin = (baseUrl: string) => {
|
const getOrigin = (baseUrl: string) => {
|
||||||
try {
|
try {
|
||||||
return new URL(baseUrl).origin;
|
return new URL(baseUrl).origin;
|
||||||
|
|
@ -97,7 +78,7 @@
|
||||||
|
|
||||||
let origin = $derived(getOrigin(baseUrl));
|
let origin = $derived(getOrigin(baseUrl));
|
||||||
let canonicalUrl = $derived(
|
let canonicalUrl = $derived(
|
||||||
(origin + pageUrl?.pathname).replace(/index\.html\/$/, '')
|
(origin + (pageUrl?.pathname || '')).replace(/index\.html\/$/, '')
|
||||||
);
|
);
|
||||||
|
|
||||||
const orgLdJson = {
|
const orgLdJson = {
|
||||||
|
|
@ -138,10 +119,10 @@
|
||||||
dateCreated: publishTime,
|
dateCreated: publishTime,
|
||||||
datePublished: publishTime,
|
datePublished: publishTime,
|
||||||
dateModified: updateTime,
|
dateModified: updateTime,
|
||||||
author: authors.map(({ name, url }) => ({
|
author: authors.map(({ name, link }) => ({
|
||||||
'@type': 'Person',
|
'@type': 'Person',
|
||||||
name,
|
name,
|
||||||
url,
|
url: link,
|
||||||
})),
|
})),
|
||||||
creator: authors.map(({ name }) => name),
|
creator: authors.map(({ name }) => name),
|
||||||
articleSection: 'Graphics',
|
articleSection: 'Graphics',
|
||||||
|
|
@ -153,8 +134,8 @@
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
{#key canonicalUrl}
|
{#key canonicalUrl}
|
||||||
<title>{seoTitle}</title>
|
<title>{seoTitle}</title>
|
||||||
<meta name="description" content="{seoDescription}" />
|
<meta name="description" content={seoDescription} />
|
||||||
<link rel="canonical" href="{canonicalUrl}" />
|
<link rel="canonical" href={canonicalUrl} />
|
||||||
<link
|
<link
|
||||||
rel="shortcut icon"
|
rel="shortcut icon"
|
||||||
type="image/x-icon"
|
type="image/x-icon"
|
||||||
|
|
@ -179,26 +160,26 @@
|
||||||
sizes="96x96"
|
sizes="96x96"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<meta property="og:url" content="{canonicalUrl}" />
|
<meta property="og:url" content={canonicalUrl} />
|
||||||
<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
|
||||||
property="og:description"
|
property="og:description"
|
||||||
content="{shareDescription}"
|
content={shareDescription}
|
||||||
itemprop="description"
|
itemprop="description"
|
||||||
/>
|
/>
|
||||||
<meta property="og:image" content="{shareImgPath}" itemprop="image" />
|
<meta property="og:image" content={shareImgPath} itemprop="image" />
|
||||||
<meta property="og:site_name" content="Reuters" />
|
<meta property="og:site_name" content="Reuters" />
|
||||||
|
|
||||||
<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="{origin}" />
|
<meta name="twitter:domain" content={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" content="{shareImgPath}" />
|
<meta name="twitter:image" content={shareImgPath} />
|
||||||
{#if shareImgAlt}
|
{#if shareImgAlt}
|
||||||
<meta name="twitter:image:alt" content="{shareImgAlt}" />
|
<meta name="twitter:image:alt" content={shareImgAlt} />
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<meta property="fb:app_id" content="319194411438328" />
|
<meta property="fb:app_id" content="319194411438328" />
|
||||||
|
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
```yaml
|
|
||||||
slug: ROOT-SLUG/WILD
|
|
||||||
seoTitle: Page title for search
|
|
||||||
seoDescription: Page description for search
|
|
||||||
shareTitle: Page title for social media
|
|
||||||
shareDescription: Page description for social media
|
|
||||||
shareImgPath: images/reuters-graphics.jpg
|
|
||||||
shareImgAlt: Alt text for share image.
|
|
||||||
```
|
|
||||||
|
|
||||||
```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
|
|
||||||
baseUrl="{VITE_BASE_URL}"
|
|
||||||
pageUrl="{$page.url}"
|
|
||||||
seoTitle="{content.seoTitle}"
|
|
||||||
seoDescription="{content.seoDescription}"
|
|
||||||
shareTitle="{content.shareTitle}"
|
|
||||||
shareDescription="{content.shareDescription}"
|
|
||||||
shareImgPath="{`${assets}/${content.shareImgPath}`}"
|
|
||||||
shareImgAlt="{content.shareImgAlt}"
|
|
||||||
publishTime="{pkg?.reuters?.graphic?.published}"
|
|
||||||
updateTime="{pkg?.reuters?.graphic?.updated}"
|
|
||||||
authors="{pkg?.reuters?.graphic?.authors}"
|
|
||||||
/>
|
|
||||||
```
|
|
||||||
|
|
||||||
> **Note:** For _reasons_, we can't document the value of `VITE_BASE_URL` below. It's `import` + `.meta.env.BASE_URL` (concatenate all that) in the Graphics Kit and other Vite-based rigs.
|
|
||||||
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
||||||
The `SEO` component adds essential metadata to published pages.
|
|
||||||
|
|
||||||
```svelte
|
|
||||||
<script>
|
|
||||||
import { SEO } from '@reuters-graphics/graphics-components';
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<SEO
|
|
||||||
baseUrl="https://graphics.reuters.com"
|
|
||||||
pageUrl="{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"
|
|
||||||
shareImgAlt="An image showing global COVID infection rates"
|
|
||||||
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' },
|
|
||||||
]}"
|
|
||||||
/>
|
|
||||||
```
|
|
||||||
Loading…
Reference in a new issue