Merge branch 'migrate-to-svelte5' into mf-end-notes
This commit is contained in:
commit
a4f612ec57
35 changed files with 355 additions and 308 deletions
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
|
|
@ -12,7 +12,7 @@
|
|||
"editor.wordWrap": "on"
|
||||
},
|
||||
"[svelte]": {
|
||||
"editor.defaultFormatter": "svelte.svelte-vscode"
|
||||
},
|
||||
"editor.defaultFormatter": "svelte.svelte-vscode"
|
||||
},
|
||||
"typescript.tsdk": "node_modules/typescript/lib"
|
||||
}
|
||||
|
|
|
|||
20
src/app.html
20
src/app.html
|
|
@ -1,11 +1,11 @@
|
|||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body>
|
||||
%sveltekit.body%
|
||||
</body>
|
||||
</html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
%sveltekit.head%
|
||||
</head>
|
||||
<body>
|
||||
%sveltekit.body%
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@
|
|||
});
|
||||
</script>
|
||||
|
||||
<div data-freestar-ad={dataFreestarAd || null} id={adId}></div>
|
||||
<div data-freestar-ad="{dataFreestarAd || null}" id="{adId}"></div>
|
||||
|
||||
<style>
|
||||
:global(div.freestar-adslot:has(.unfulfilled-ad)) {
|
||||
|
|
|
|||
|
|
@ -46,11 +46,11 @@ You may add **up to three** inline ads per page, but must set the `n` prop on mu
|
|||
|
||||
```svelte
|
||||
<!-- First inline ad on the page -->
|
||||
<InlineAd n={1} />
|
||||
<InlineAd n="{1}" />
|
||||
<!-- ... second ... -->
|
||||
<InlineAd n={2} />
|
||||
<InlineAd n="{2}" />
|
||||
<!-- ... third and final. -->
|
||||
<InlineAd n={3} />
|
||||
<InlineAd n="{3}" />
|
||||
```
|
||||
|
||||
<Canvas of={InlineAdStories.Demo} />
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@
|
|||
});
|
||||
</script>
|
||||
|
||||
<svelte:window bind:innerWidth={windowWidth} />
|
||||
<svelte:window bind:innerWidth="{windowWidth}" />
|
||||
|
||||
<div
|
||||
class="freestar-adslot leaderboard__sticky {cls}"
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@
|
|||
let adType = $derived(getAdType(placementName));
|
||||
</script>
|
||||
|
||||
<svelte:window bind:innerWidth={windowWidth} />
|
||||
<svelte:window bind:innerWidth="{windowWidth}" />
|
||||
|
||||
{#if windowWidth}
|
||||
{#key placementName}
|
||||
|
|
|
|||
|
|
@ -40,13 +40,13 @@ When combined with the `Block` component, you can set custom column widths by pa
|
|||
|
||||
```svelte
|
||||
<Article
|
||||
columnWidths={{
|
||||
columnWidths="{{
|
||||
narrower: 310,
|
||||
narrow: 450,
|
||||
normal: 550,
|
||||
wide: 675,
|
||||
wider: 1400,
|
||||
}}
|
||||
}}"
|
||||
>
|
||||
<Block width="narrower" />
|
||||
<Block width="narrow" />
|
||||
|
|
|
|||
53
src/components/Byline/Byline.mdx
Normal file
53
src/components/Byline/Byline.mdx
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
import { Meta, Canvas } from '@storybook/blocks';
|
||||
|
||||
import * as BylineStories from './Byline.stories.svelte';
|
||||
|
||||
<Meta of={BylineStories} />
|
||||
|
||||
# Byline
|
||||
|
||||
The `Byline` component adds a byline, published and updated datelines to your page.
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
import { Byline } from '@reuters-graphics/graphics-components';
|
||||
</script>
|
||||
|
||||
<Byline
|
||||
authors={[
|
||||
'Dea Bankova',
|
||||
'Prasanta Kumar Dutta',
|
||||
'Anurag Rao',
|
||||
'Mariano Zafra',
|
||||
]}
|
||||
publishTime="2021-09-12T00:00:00.000Z"
|
||||
updateTime="2021-09-12T12:57:00.000Z"
|
||||
/>
|
||||
```
|
||||
|
||||
<Canvas of={BylineStories.Demo} />
|
||||
|
||||
## Cutomisation
|
||||
|
||||
Use [snippets](https://svelte.dev/docs/svelte/snippet) to customise the byline, published and updated datelines.
|
||||
|
||||
```svelte
|
||||
<Byline publishTime="2021-09-12T00:00:00Z" updateTime="2021-09-12T13:57:00Z">
|
||||
<!-- Optional custom byline -->
|
||||
{#snippet byline()}
|
||||
<strong>BY REUTERS GRAPHICS</strong>
|
||||
{/snippet}
|
||||
|
||||
<!-- Optional custom published dateline -->
|
||||
{#snippet published()}
|
||||
PUBLISHED on some custom date and time
|
||||
{/snippet}
|
||||
|
||||
<!-- Optional custom updated dateline -->
|
||||
{#snippet updated()}
|
||||
<em>Updated every 5 minutes</em>
|
||||
{/snippet}
|
||||
</Byline>
|
||||
```
|
||||
|
||||
<Canvas of={BylineStories.Customised} />
|
||||
|
|
@ -1,17 +1,11 @@
|
|||
<script module lang="ts">
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import Byline from './Byline.svelte';
|
||||
// @ts-ignore raw
|
||||
import componentDocs from './stories/docs/component.md?raw';
|
||||
|
||||
import { withComponentDocs } from '$docs/utils/withParams.js';
|
||||
|
||||
import type { ComponentProps } from 'svelte';
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Components/Text elements/Byline',
|
||||
component: Byline,
|
||||
...withComponentDocs(componentDocs),
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
align: {
|
||||
control: 'select',
|
||||
|
|
@ -21,17 +15,12 @@
|
|||
});
|
||||
</script>
|
||||
|
||||
{#snippet template(args: ComponentProps<Byline>)}
|
||||
<Byline {...args} />
|
||||
{/snippet}
|
||||
|
||||
<Story
|
||||
name="Default"
|
||||
name="Demo"
|
||||
args={{
|
||||
align: 'left',
|
||||
authors: [
|
||||
'Dea Bankova',
|
||||
'Aditi Bhandari',
|
||||
'Prasanta Kumar Dutta',
|
||||
'Anurag Rao',
|
||||
'Mariano Zafra',
|
||||
|
|
@ -39,5 +28,18 @@
|
|||
publishTime: new Date('2021-09-12').toISOString(),
|
||||
updateTime: new Date('2021-09-12T13:57:00').toISOString(),
|
||||
}}
|
||||
children={template}
|
||||
/>
|
||||
|
||||
<Story name="Customised" tags={['!autodocs', '!dev']}>
|
||||
<Byline publishTime="2021-09-12T00:00:00Z" updateTime="2021-09-12T13:57:00Z">
|
||||
{#snippet byline()}
|
||||
<strong>BY REUTERS GRAPHICS</strong>
|
||||
{/snippet}
|
||||
{#snippet published()}
|
||||
PUBLISHED on some custom date and time
|
||||
{/snippet}
|
||||
{#snippet updated()}
|
||||
<em>Updated every 5 minutes</em>
|
||||
{/snippet}
|
||||
</Byline>
|
||||
</Story>
|
||||
|
|
|
|||
|
|
@ -4,63 +4,91 @@
|
|||
import Block from '../Block/Block.svelte';
|
||||
import slugify from 'slugify';
|
||||
import { apdate } from 'journalize';
|
||||
import type { Snippet } from 'svelte';
|
||||
|
||||
interface Props {
|
||||
/**
|
||||
* Array of author names, which will be slugified to create links to Reuters author pages
|
||||
*/
|
||||
authors?: string[];
|
||||
/**
|
||||
* Publish time as a datetime string.
|
||||
*/
|
||||
publishTime: string;
|
||||
/**
|
||||
* Update time as a datetime string.
|
||||
* @type {string}
|
||||
*/
|
||||
updateTime: string;
|
||||
/**
|
||||
* Alignment of the byline.
|
||||
* @type {string}
|
||||
*/
|
||||
align?: 'left' | 'center';
|
||||
/**
|
||||
* Add an id to to target with custom CSS.
|
||||
* @type {string}
|
||||
*/
|
||||
id?: string;
|
||||
/**
|
||||
* Add extra classes to target with custom CSS.
|
||||
* @type {string}
|
||||
*/
|
||||
cls?: string;
|
||||
/**
|
||||
* Custom function that returns an author page URL.
|
||||
*/
|
||||
getAuthorPage?: (author: string) => string;
|
||||
/**
|
||||
* Optional snippet for a custom byline.
|
||||
*/
|
||||
byline?: Snippet | null;
|
||||
/**
|
||||
* Optional snippet for a custom published dateline.
|
||||
*/
|
||||
// Specify that this prop should have the type of a Svelte snippet, i.e. basic html
|
||||
published?: Snippet | null;
|
||||
/**
|
||||
* Optional snippet for a custom updated dateline.
|
||||
*/
|
||||
updated?: Snippet | null;
|
||||
}
|
||||
|
||||
let {
|
||||
authors = [],
|
||||
publishTime,
|
||||
updateTime,
|
||||
align = 'left',
|
||||
id = '',
|
||||
cls = '',
|
||||
getAuthorPage = (author: string): string => {
|
||||
const authorSlug = slugify(author.trim(), { lower: true });
|
||||
return `https://www.reuters.com/authors/${authorSlug}/`;
|
||||
},
|
||||
byline = null,
|
||||
published = null,
|
||||
updated = null,
|
||||
}: Props = $props();
|
||||
|
||||
let alignmentClass = $derived(align === 'left' ? 'text-left' : 'text-center');
|
||||
|
||||
/**
|
||||
* Array of author names, which will be slugified to create links to Reuters author pages
|
||||
/* Date validation and formatter functions
|
||||
*/
|
||||
export let authors: string[] = [];
|
||||
/**
|
||||
* Publish time as a datetime string.
|
||||
* @type {string}
|
||||
*/
|
||||
export let publishTime: string = '';
|
||||
/**
|
||||
* Update time as a datetime string.
|
||||
* @type {string}
|
||||
*/
|
||||
export let updateTime: string = '';
|
||||
/**
|
||||
* Alignment of the byline.
|
||||
* @type {string}
|
||||
*/
|
||||
export let align: 'left' | 'center' = 'left';
|
||||
/**
|
||||
* Add an id to to target with custom CSS.
|
||||
* @type {string}
|
||||
*/
|
||||
export let id: string = '';
|
||||
/**
|
||||
* Add extra classes to target with custom CSS.
|
||||
* @type {string}
|
||||
*/
|
||||
let cls: string = '';
|
||||
export { cls as class };
|
||||
|
||||
/**
|
||||
* Custom function that returns an author page URL.
|
||||
* @param author
|
||||
*/
|
||||
export let getAuthorPage = (author: string): string => {
|
||||
const authorSlug = slugify(author.trim(), { lower: true });
|
||||
return `https://www.reuters.com/authors/${authorSlug}/`;
|
||||
};
|
||||
|
||||
$: alignmentClass = align === 'left' ? 'text-left' : 'text-center';
|
||||
|
||||
const isValidDate = (datetime) => {
|
||||
const isValidDate = (datetime: string) => {
|
||||
if (!datetime) return false;
|
||||
if (!Date.parse(datetime)) return false;
|
||||
return true;
|
||||
};
|
||||
|
||||
const formatTime = (datetime) =>
|
||||
const formatTime = (datetime: string) =>
|
||||
new Date(datetime).toLocaleTimeString([], {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
timeZoneName: 'short',
|
||||
});
|
||||
|
||||
const areSameDay = (first, second) =>
|
||||
const areSameDay = (first: Date, second: Date) =>
|
||||
first.getFullYear() === second.getFullYear() &&
|
||||
first.getMonth() === second.getMonth() &&
|
||||
first.getDate() === second.getDate();
|
||||
|
|
@ -69,16 +97,16 @@
|
|||
<Block {id} class="byline-container {alignmentClass} {cls}" width="normal">
|
||||
<aside class="article-metadata font-subhed">
|
||||
<div class="byline body-caption fmb-1">
|
||||
{#if $$slots.byline}
|
||||
{#if byline}
|
||||
<!-- Custom byline -->
|
||||
<slot name="byline" />
|
||||
{@render byline()}
|
||||
{:else}
|
||||
By
|
||||
{#if authors.length > 0}
|
||||
{#each authors as author, i}
|
||||
<a
|
||||
class="no-underline whitespace-nowrap text-primary font-bold"
|
||||
href="{getAuthorPage(author)}"
|
||||
href={getAuthorPage(author)}
|
||||
rel="author"
|
||||
>
|
||||
{author.trim()}</a
|
||||
|
|
@ -95,15 +123,17 @@
|
|||
{/if}
|
||||
</div>
|
||||
<div class="dateline body-caption fmt-0">
|
||||
{#if $$slots.published}
|
||||
{#if published}
|
||||
<div class="whitespace-nowrap inline-block">
|
||||
<!-- Custom published dateline -->
|
||||
<slot name="published" />
|
||||
<!-- Custom published dateline snippet -->
|
||||
<time datetime={publishTime}>
|
||||
{@render published()}
|
||||
</time>
|
||||
</div>
|
||||
{:else if isValidDate(publishTime)}
|
||||
<div class="whitespace-nowrap inline-block">
|
||||
Published
|
||||
<time datetime="{publishTime}">
|
||||
<time datetime={publishTime}>
|
||||
{#if isValidDate(updateTime)}
|
||||
{apdate(new Date(publishTime))}
|
||||
{:else}
|
||||
|
|
@ -114,15 +144,17 @@
|
|||
</time>
|
||||
</div>
|
||||
{/if}
|
||||
{#if $$slots.updated}
|
||||
{#if updated}
|
||||
<div class="whitespace-nowrap inline-block">
|
||||
<!-- Custom updated dateline -->
|
||||
<slot name="updated" />
|
||||
<!-- Custom updated dateline snippet -->
|
||||
<time datetime={updateTime}>
|
||||
{@render updated()}
|
||||
</time>
|
||||
</div>
|
||||
{:else if isValidDate(publishTime) && isValidDate(updateTime)}
|
||||
<div class="whitespace-nowrap inline-block">
|
||||
Last updated
|
||||
<time datetime="{updateTime}">
|
||||
<time datetime={updateTime}>
|
||||
{#if areSameDay(new Date(publishTime), new Date(updateTime))}
|
||||
{formatTime(updateTime)}
|
||||
{:else}
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
Byline and dateline.
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
import { Byline } from '@reuters-graphics/graphics-components';
|
||||
</script>
|
||||
|
||||
<Byline
|
||||
authors="{[
|
||||
'Dea Bankova',
|
||||
'Aditi Bhandari',
|
||||
'Prasanta Kumar Dutta',
|
||||
'Anurag Rao',
|
||||
'Mariano Zafra',
|
||||
]}"
|
||||
publishTime="2021-09-12T00:00:00.000Z"
|
||||
updateTime="2021-09-12T12:57:00.000Z"
|
||||
/>
|
||||
```
|
||||
|
|
@ -17,18 +17,18 @@
|
|||
|
||||
<Story
|
||||
name="Demo"
|
||||
args={{
|
||||
args="{{
|
||||
src: 'https://reuters.com/graphics/USA-ABORTION/lgpdwggnwvo/media-embed.html',
|
||||
id: 'abortion-rights-map',
|
||||
ariaLabel: 'map',
|
||||
frameTitle: 'Global abortion access',
|
||||
}}
|
||||
}}"
|
||||
/>
|
||||
|
||||
<Story
|
||||
name="With chatter"
|
||||
tags={['!autodocs']}
|
||||
args={{
|
||||
tags="{['!autodocs']}"
|
||||
args="{{
|
||||
frameTitle: 'Global abortion access',
|
||||
ariaLabel: 'map',
|
||||
id: 'abortion-rights-map',
|
||||
|
|
@ -37,5 +37,5 @@
|
|||
description: 'A map of worldwide access to abortion.',
|
||||
notes:
|
||||
'Note: Different indicators and additional restrictions, including different gestational limits, apply in some countries. Refer to source for full classification. Current as of May 4, 2022.\n\nSource: Center for Reproductive Rights',
|
||||
}}
|
||||
}}"
|
||||
/>
|
||||
|
|
|
|||
19
src/components/EmbedPreviewerLink/EmbedPreviewerLink.mdx
Normal file
19
src/components/EmbedPreviewerLink/EmbedPreviewerLink.mdx
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
import { Meta } from '@storybook/blocks';
|
||||
|
||||
import * as EmbedPreviewerLinkStories from './EmbedPreviewerLink.stories.svelte';
|
||||
|
||||
<Meta of={EmbedPreviewerLinkStories} />
|
||||
|
||||
# EmbedPreviewerLink
|
||||
|
||||
The `EmbedPreviewerLink` component is a tool for previewing the embeds in development. It adds an icon at the bottom of the page that, when clicked, opens a previewer with the embeds.
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
import { EmbedPreviewerLink } from '@reuters-graphics/graphics-components';
|
||||
|
||||
import { dev } from '$app/env';
|
||||
</script>
|
||||
|
||||
<EmbedPreviewerLink {dev} />
|
||||
```
|
||||
|
|
@ -1,30 +1,17 @@
|
|||
<script module lang="ts">
|
||||
import EmbedPreviewerLink from './EmbedPreviewerLink.svelte';
|
||||
// @ts-ignore raw
|
||||
import componentDocs from './stories/docs/component.md?raw';
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
|
||||
import { withComponentDocs } from '$lib/docs/utils/withParams.js';
|
||||
|
||||
export const meta = {
|
||||
const { Story } = defineMeta({
|
||||
title: 'Components/Utilities/EmbedPreviewerLink',
|
||||
component: EmbedPreviewerLink,
|
||||
...withComponentDocs(componentDocs),
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
import { Template, Story } from '@storybook/addon-svelte-csf';
|
||||
</script>
|
||||
|
||||
<Template >
|
||||
{#snippet children({ args })}
|
||||
<EmbedPreviewerLink {...args} />
|
||||
{/snippet}
|
||||
</Template>
|
||||
|
||||
<Story
|
||||
name="Default"
|
||||
args="{{
|
||||
name="Demo"
|
||||
tags={['!autodocs', '!dev']}
|
||||
args={{
|
||||
dev: true,
|
||||
}}"
|
||||
}}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
<script lang="ts">
|
||||
|
||||
import Fa from 'svelte-fa/src/fa.svelte';
|
||||
import { faWindowRestore } from '@fortawesome/free-regular-svg-icons';
|
||||
interface Props {
|
||||
|
|
@ -12,7 +11,7 @@
|
|||
{#if dev}
|
||||
<div>
|
||||
<a rel="external" href="/embed-previewer">
|
||||
<Fa icon="{faWindowRestore}" />
|
||||
<Fa icon={faWindowRestore} />
|
||||
</a>
|
||||
</div>
|
||||
{/if}
|
||||
|
|
|
|||
|
|
@ -1,11 +0,0 @@
|
|||
An embed tool for development in graphics kit.
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
import { EmbedPreviewerLink } from '@reuters-graphics/graphics-components';
|
||||
|
||||
import { dev } from '$app/env';
|
||||
</script>
|
||||
|
||||
<EmbedPreviewerLink dev="{dev}" />
|
||||
```
|
||||
|
|
@ -11,7 +11,11 @@
|
|||
minFrameWidth?: number;
|
||||
}
|
||||
|
||||
let { breakpoints = [330, 510, 660, 930, 1200], maxFrameWidth = 1200, minFrameWidth = 320 }: Props = $props();
|
||||
let {
|
||||
breakpoints = [330, 510, 660, 930, 1200],
|
||||
maxFrameWidth = 1200,
|
||||
minFrameWidth = 320,
|
||||
}: Props = $props();
|
||||
|
||||
let container = $state();
|
||||
|
||||
|
|
@ -91,9 +95,9 @@
|
|||
</script>
|
||||
|
||||
<svelte:window
|
||||
onmousemove={move}
|
||||
onmouseup={end}
|
||||
onkeydown={handleKeyDown}
|
||||
onmousemove="{move}"
|
||||
onmouseup="{end}"
|
||||
onkeydown="{handleKeyDown}"
|
||||
bind:innerWidth="{windowInnerWidth}"
|
||||
/>
|
||||
|
||||
|
|
@ -105,10 +109,10 @@
|
|||
<button
|
||||
class="icon left"
|
||||
disabled="{$width === minWidth}"
|
||||
onclick={decrement}
|
||||
onfocus={onFocus}
|
||||
onmouseover={onFocus}
|
||||
onmouseleave={onBlur}
|
||||
onclick="{decrement}"
|
||||
onfocus="{onFocus}"
|
||||
onmouseover="{onFocus}"
|
||||
onmouseleave="{onBlur}"
|
||||
>
|
||||
<Fa icon="{faMobileAlt}" fw />
|
||||
</button>
|
||||
|
|
@ -119,18 +123,18 @@
|
|||
tabindex="0"
|
||||
role="button"
|
||||
style="left: calc({offset * 100}% - 5px);"
|
||||
onmousedown={start}
|
||||
onfocus={onFocus}
|
||||
onblur={onBlur}
|
||||
onmousedown="{start}"
|
||||
onfocus="{onFocus}"
|
||||
onblur="{onBlur}"
|
||||
></div>
|
||||
</div>
|
||||
<button
|
||||
class="icon right"
|
||||
disabled="{$width === maxWidth}"
|
||||
onclick={increment}
|
||||
onfocus={onFocus}
|
||||
onmouseover={onFocus}
|
||||
onmouseleave={onBlur}
|
||||
onclick="{increment}"
|
||||
onfocus="{onFocus}"
|
||||
onmouseover="{onFocus}"
|
||||
onmouseleave="{onBlur}"
|
||||
>
|
||||
<Fa icon="{faDesktop}" fw />
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
<script lang="ts">
|
||||
|
||||
// For demo purposes only, hard-wiring img paths from Vite
|
||||
// @ts-ignore img
|
||||
import chartXs from '../imgs/ai-chart-xs.png';
|
||||
|
|
|
|||
|
|
@ -4,9 +4,6 @@
|
|||
import { marked } from 'marked';
|
||||
import { staticMarkdown } from './stores';
|
||||
|
||||
|
||||
|
||||
|
||||
interface Props {
|
||||
/** A Markdown formatted string */
|
||||
source?: string;
|
||||
|
|
@ -16,7 +13,9 @@
|
|||
|
||||
let { source = '', parseInline = false }: Props = $props();
|
||||
|
||||
let markdown = $derived(parseInline ? marked.parseInline(source) : marked.parse(source));
|
||||
let markdown = $derived(
|
||||
parseInline ? marked.parseInline(source) : marked.parse(source)
|
||||
);
|
||||
|
||||
const setInnerHTML: Action<HTMLElement, string> = (node, html) => {
|
||||
node.innerHTML = html;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
<!-- @component `PymChild` [Read the docs.](https://reuters-graphics.github.io/graphics-components/?path=/docs/components-utilities-pymchild--docs) -->
|
||||
<script lang="ts">
|
||||
|
||||
|
||||
import { onMount } from 'svelte';
|
||||
import pym from 'pym.js';
|
||||
import { pymChildStore } from './stores.js';
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
<!-- @component `ReutersGraphicsLogo` [Read the docs.](https://reuters-graphics.github.io/graphics-components/?path=/docs/components-logos-reutersgraphicslogo--docs) -->
|
||||
<script lang="ts">
|
||||
|
||||
|
||||
|
||||
interface Props {
|
||||
/** "Kinesis" colour */
|
||||
logoColour?: string;
|
||||
|
|
@ -12,7 +9,11 @@
|
|||
width?: string;
|
||||
}
|
||||
|
||||
let { logoColour = '#D64000', textColour = '#212223', width = '100%' }: Props = $props();
|
||||
let {
|
||||
logoColour = '#D64000',
|
||||
textColour = '#212223',
|
||||
width = '100%',
|
||||
}: Props = $props();
|
||||
</script>
|
||||
|
||||
<svg
|
||||
|
|
|
|||
|
|
@ -1,8 +1,5 @@
|
|||
<!-- @component `ReutersLogo` [Read the docs.](https://reuters-graphics.github.io/graphics-components/?path=/docs/components-logos-reuterslogo--docs) -->
|
||||
<script lang="ts">
|
||||
|
||||
|
||||
|
||||
interface Props {
|
||||
/** "Kinesis" colour */
|
||||
logoColour?: string;
|
||||
|
|
@ -12,7 +9,11 @@
|
|||
width?: string;
|
||||
}
|
||||
|
||||
let { logoColour = '#D64000', textColour = '#212223', width = '100%' }: Props = $props();
|
||||
let {
|
||||
logoColour = '#D64000',
|
||||
textColour = '#212223',
|
||||
width = '100%',
|
||||
}: Props = $props();
|
||||
</script>
|
||||
|
||||
<svg
|
||||
|
|
|
|||
|
|
@ -1,85 +1,72 @@
|
|||
<!-- @component `SEO` [Read the docs.](https://reuters-graphics.github.io/graphics-components/?path=/docs/components-ads-analytic-seo--docs) -->
|
||||
<script lang="ts">
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
interface GraphicAuthor {
|
||||
name: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
|
||||
interface Props {
|
||||
/**
|
||||
* 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`.
|
||||
* @requiredx
|
||||
* @type {string}
|
||||
*/
|
||||
* 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`.
|
||||
* @requiredx
|
||||
* @type {string}
|
||||
*/
|
||||
baseUrl?: string;
|
||||
/**
|
||||
* [URL](https://developer.mozilla.org/en-US/docs/Web/API/URL) object for the page.
|
||||
* @required
|
||||
* @type {URL}
|
||||
*/
|
||||
* [URL](https://developer.mozilla.org/en-US/docs/Web/API/URL) object for the page.
|
||||
* @required
|
||||
* @type {URL}
|
||||
*/
|
||||
pageUrl?: URL | null;
|
||||
/**
|
||||
* SEO title
|
||||
* @required
|
||||
* @type {string}
|
||||
*/
|
||||
* SEO title
|
||||
* @required
|
||||
* @type {string}
|
||||
*/
|
||||
seoTitle: string;
|
||||
/**
|
||||
* SEO description
|
||||
* @required
|
||||
* @type {string}
|
||||
*/
|
||||
* SEO description
|
||||
* @required
|
||||
* @type {string}
|
||||
*/
|
||||
seoDescription: string;
|
||||
/**
|
||||
* Share title
|
||||
* @required
|
||||
* @type {string}
|
||||
*/
|
||||
* Share title
|
||||
* @required
|
||||
* @type {string}
|
||||
*/
|
||||
shareTitle: string;
|
||||
/**
|
||||
* Share description
|
||||
* @required
|
||||
* @type {string}
|
||||
*/
|
||||
* Share description
|
||||
* @required
|
||||
* @type {string}
|
||||
*/
|
||||
shareDescription: string;
|
||||
/**
|
||||
* Share image path. **Must be an absolute path.**
|
||||
* @required
|
||||
* @type {string}
|
||||
*/
|
||||
* Share image path. **Must be an absolute path.**
|
||||
* @required
|
||||
* @type {string}
|
||||
*/
|
||||
shareImgPath: string;
|
||||
/**
|
||||
* Share image alt text, up to 420 characters.
|
||||
* @type {string}
|
||||
*/
|
||||
* Share image alt text, up to 420 characters.
|
||||
* @type {string}
|
||||
*/
|
||||
shareImgAlt?: string;
|
||||
/**
|
||||
* Publish time as an [ISO string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
|
||||
* @type {string}
|
||||
*/
|
||||
* Publish time as an [ISO string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
|
||||
* @type {string}
|
||||
*/
|
||||
publishTime?: string;
|
||||
/**
|
||||
* Updated time as an [ISO string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
|
||||
* @type {string}
|
||||
*/
|
||||
* Updated time as an [ISO string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
|
||||
* @type {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 `url` attributes.
|
||||
*/
|
||||
authors?: GraphicAuthor[];
|
||||
}
|
||||
|
||||
|
|
@ -94,7 +81,7 @@
|
|||
shareImgAlt = '',
|
||||
publishTime = '',
|
||||
updateTime = '',
|
||||
authors = []
|
||||
authors = [],
|
||||
}: Props = $props();
|
||||
|
||||
const getOrigin = (baseUrl: string) => {
|
||||
|
|
@ -109,7 +96,9 @@
|
|||
};
|
||||
|
||||
let origin = $derived(getOrigin(baseUrl));
|
||||
let canonicalUrl = $derived((origin + pageUrl?.pathname).replace(/index\.html\/$/, ''));
|
||||
let canonicalUrl = $derived(
|
||||
(origin + pageUrl?.pathname).replace(/index\.html\/$/, '')
|
||||
);
|
||||
|
||||
const orgLdJson = {
|
||||
'@context': 'http://schema.org',
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
<script lang="ts">
|
||||
import type { ContainerWidth, ScrollerStep } from '../../@types/global';
|
||||
|
||||
|
||||
type EmbeddedLayout = 'fb' | 'bf';
|
||||
|
||||
|
||||
import Background from './Background.svelte';
|
||||
import Foreground from './Foreground.svelte';
|
||||
interface Props {
|
||||
|
|
@ -13,7 +11,11 @@
|
|||
backgroundWidth?: ContainerWidth;
|
||||
}
|
||||
|
||||
let { steps = [], embeddedLayout = 'fb', backgroundWidth = 'fluid' }: Props = $props();
|
||||
let {
|
||||
steps = [],
|
||||
embeddedLayout = 'fb',
|
||||
backgroundWidth = 'fluid',
|
||||
}: Props = $props();
|
||||
</script>
|
||||
|
||||
{#each steps as step, index}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
<p>The count is {count}</p>
|
||||
|
||||
<button
|
||||
onclick={() => {
|
||||
onclick="{() => {
|
||||
count += 1;
|
||||
}}>Click Me</button
|
||||
}}">Click Me</button
|
||||
>
|
||||
|
|
|
|||
|
|
@ -4,12 +4,11 @@
|
|||
import MagnifyingGlass from './MagnifyingGlass.svelte';
|
||||
import X from './X.svelte';
|
||||
|
||||
|
||||
interface Props {
|
||||
/**
|
||||
* The placeholder text that appears in the search box.
|
||||
* @type {string}
|
||||
*/
|
||||
* The placeholder text that appears in the search box.
|
||||
* @type {string}
|
||||
*/
|
||||
searchPlaceholder?: string;
|
||||
}
|
||||
|
||||
|
|
@ -40,7 +39,7 @@
|
|||
class="search--input body-caption pl-8"
|
||||
type="text"
|
||||
placeholder="{searchPlaceholder}"
|
||||
oninput={input}
|
||||
oninput="{input}"
|
||||
bind:value
|
||||
/>
|
||||
<div
|
||||
|
|
@ -48,8 +47,8 @@
|
|||
role="button"
|
||||
tabindex="0"
|
||||
class:invisible="{!active}"
|
||||
onclick={clear}
|
||||
onkeyup={clear}
|
||||
onclick="{clear}"
|
||||
onkeyup="{clear}"
|
||||
>
|
||||
<X />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -9,11 +9,10 @@
|
|||
import starterData from './data.json';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
|
||||
interface Props {
|
||||
/**
|
||||
* Set to `false` to remove graphics referrals
|
||||
*/
|
||||
* Set to `false` to remove graphics referrals
|
||||
*/
|
||||
includeReferrals?: boolean;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,7 +9,11 @@
|
|||
releaseMobileMenu?: any;
|
||||
}
|
||||
|
||||
let { data = [], isMobileMenuOpen = false, releaseMobileMenu = () => {} }: Props = $props();
|
||||
let {
|
||||
data = [],
|
||||
isMobileMenuOpen = false,
|
||||
releaseMobileMenu = () => {},
|
||||
}: Props = $props();
|
||||
</script>
|
||||
|
||||
{#if isMobileMenuOpen}
|
||||
|
|
@ -31,7 +35,7 @@
|
|||
textColour="var(--nav-primary)"
|
||||
/>
|
||||
</div>
|
||||
<button class="button close-button" onclick={releaseMobileMenu}>
|
||||
<button class="button close-button" onclick="{releaseMobileMenu}">
|
||||
<div class="button-container">
|
||||
<CloseIcon />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -5,10 +5,11 @@
|
|||
|
||||
let { section = {}, headingText } = $props();
|
||||
|
||||
let splitCount =
|
||||
$derived(section.children && section.children.length > 7 ?
|
||||
let splitCount = $derived(
|
||||
section.children && section.children.length > 7 ?
|
||||
Math.ceil(section.children.length / 2)
|
||||
: 0);
|
||||
: 0
|
||||
);
|
||||
</script>
|
||||
|
||||
<NavDropdown {headingText}>
|
||||
|
|
|
|||
|
|
@ -35,27 +35,27 @@
|
|||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||
<li
|
||||
class="nav-item category link"
|
||||
onmouseenter={() => {
|
||||
onmouseenter="{() => {
|
||||
navTimeout = setTimeout(
|
||||
() => activeSection.set(section.id),
|
||||
timeout
|
||||
);
|
||||
}}
|
||||
onfocus={() => activeSection.set(section.id)}
|
||||
onmouseleave={() => {
|
||||
}}"
|
||||
onfocus="{() => activeSection.set(section.id)}"
|
||||
onmouseleave="{() => {
|
||||
clearTimeout(navTimeout);
|
||||
activeSection.set(null);
|
||||
}}
|
||||
onblur={() => {
|
||||
}}"
|
||||
onblur="{() => {
|
||||
clearTimeout(navTimeout);
|
||||
activeSection.set(null);
|
||||
}}
|
||||
onclick={() => {
|
||||
}}"
|
||||
onclick="{() => {
|
||||
if ($activeSection === section.id) {
|
||||
clearTimeout(navTimeout);
|
||||
activeSection.set(null);
|
||||
}
|
||||
}}
|
||||
}}"
|
||||
>
|
||||
<div
|
||||
class="nav-button link"
|
||||
|
|
@ -88,24 +88,24 @@
|
|||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||
<li
|
||||
class="nav-item"
|
||||
onmouseenter={() => {
|
||||
onmouseenter="{() => {
|
||||
navTimeout = setTimeout(() => activeSection.set('more'), timeout);
|
||||
}}
|
||||
onfocus={() => activeSection.set('more')}
|
||||
onmouseleave={() => {
|
||||
}}"
|
||||
onfocus="{() => activeSection.set('more')}"
|
||||
onmouseleave="{() => {
|
||||
clearTimeout(navTimeout);
|
||||
activeSection.set(null);
|
||||
}}
|
||||
onblur={() => {
|
||||
}}"
|
||||
onblur="{() => {
|
||||
clearTimeout(navTimeout);
|
||||
activeSection.set(null);
|
||||
}}
|
||||
onclick={() => {
|
||||
}}"
|
||||
onclick="{() => {
|
||||
if ($activeSection === 'more') {
|
||||
clearTimeout(navTimeout);
|
||||
activeSection.set(null);
|
||||
}
|
||||
}}
|
||||
}}"
|
||||
>
|
||||
<div
|
||||
class="nav-button more link"
|
||||
|
|
|
|||
|
|
@ -77,9 +77,9 @@
|
|||
aria-label="Menu"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="{isMobileMenuOpen}"
|
||||
onclick={() => {
|
||||
onclick="{() => {
|
||||
isMobileMenuOpen = !isMobileMenuOpen;
|
||||
}}
|
||||
}}"
|
||||
>
|
||||
<div class="button-container">
|
||||
<MenuIcon />
|
||||
|
|
|
|||
|
|
@ -3,33 +3,26 @@
|
|||
import LeftArrow from './LeftArrow.svelte';
|
||||
import RightArrow from './RightArrow.svelte';
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
interface Props {
|
||||
/**
|
||||
* The current page number.
|
||||
* @type {number}
|
||||
*/
|
||||
* The current page number.
|
||||
* @type {number}
|
||||
*/
|
||||
pageNumber?: number;
|
||||
/**
|
||||
* The default page size.
|
||||
* @type {number}
|
||||
*/
|
||||
* The default page size.
|
||||
* @type {number}
|
||||
*/
|
||||
pageSize?: number;
|
||||
/**
|
||||
* The number of records in the current page.
|
||||
* @type {number}
|
||||
*/
|
||||
* The number of records in the current page.
|
||||
* @type {number}
|
||||
*/
|
||||
pageLength?: number;
|
||||
/**
|
||||
* The total number of records in the data set.
|
||||
* @type {number}
|
||||
*/
|
||||
* The total number of records in the data set.
|
||||
* @type {number}
|
||||
*/
|
||||
n?: number;
|
||||
}
|
||||
|
||||
|
|
@ -37,7 +30,7 @@
|
|||
pageNumber = $bindable(1),
|
||||
pageSize = 25,
|
||||
pageLength = null,
|
||||
n = null
|
||||
n = null,
|
||||
}: Props = $props();
|
||||
|
||||
let minRow = $derived(pageNumber * pageSize - pageSize + 1);
|
||||
|
|
@ -58,7 +51,7 @@
|
|||
</script>
|
||||
|
||||
<nav aria-label="pagination" class="pagination fmt-4">
|
||||
<button onclick={goToPreviousPage} disabled="{pageNumber === 1}"
|
||||
<button onclick="{goToPreviousPage}" disabled="{pageNumber === 1}"
|
||||
><div class="icon-wrapper">
|
||||
<LeftArrow />
|
||||
<span class="visually-hidden">Previous page</span>
|
||||
|
|
@ -70,7 +63,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<button
|
||||
onclick={goToNextPage}
|
||||
onclick="{goToNextPage}"
|
||||
disabled="{pageNumber === Math.ceil(n / pageSize)}"
|
||||
><div class="icon-wrapper">
|
||||
<RightArrow />
|
||||
|
|
|
|||
|
|
@ -2,19 +2,16 @@
|
|||
import { createEventDispatcher } from 'svelte';
|
||||
import type { Option } from '../@types/global';
|
||||
|
||||
|
||||
|
||||
|
||||
interface Props {
|
||||
/**
|
||||
* The label that appears above the select input.
|
||||
* @type {string}
|
||||
*/
|
||||
* The label that appears above the select input.
|
||||
* @type {string}
|
||||
*/
|
||||
label?: string;
|
||||
/**
|
||||
* The label that appears above the select input.
|
||||
* @type {Array}
|
||||
*/
|
||||
* The label that appears above the select input.
|
||||
* @type {Array}
|
||||
*/
|
||||
options?: Option[];
|
||||
}
|
||||
|
||||
|
|
@ -36,7 +33,7 @@
|
|||
class="select--input body-caption fpx-2"
|
||||
name="select--input"
|
||||
id="select--input"
|
||||
oninput={input}
|
||||
oninput="{input}"
|
||||
>
|
||||
{#each options as obj}
|
||||
<option value="{obj.value}">{obj.text}</option>
|
||||
|
|
|
|||
|
|
@ -5,13 +5,12 @@
|
|||
*/
|
||||
type SortDirection = 'ascending' | 'descending';
|
||||
|
||||
|
||||
interface Props {
|
||||
sortDirection?: SortDirection;
|
||||
/**
|
||||
* Whether or not this arrow is currently sorting. It is false by default.
|
||||
* @type {boolean}
|
||||
*/
|
||||
* Whether or not this arrow is currently sorting. It is false by default.
|
||||
* @type {boolean}
|
||||
*/
|
||||
active?: boolean;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
controlsBorderOffset,
|
||||
resetCondition,
|
||||
separateReplayIcon,
|
||||
controlsColour
|
||||
controlsColour,
|
||||
} = $props();
|
||||
|
||||
function forwardBtnClick() {
|
||||
|
|
@ -29,7 +29,7 @@
|
|||
</script>
|
||||
|
||||
<button
|
||||
onclick={forwardBtnClick}
|
||||
onclick="{forwardBtnClick}"
|
||||
style="
|
||||
opacity: {controlsOpacity};
|
||||
top: {controlsPosition === 'top left' || controlsPosition === 'top right' ?
|
||||
|
|
|
|||
Loading…
Reference in a new issue