Merge branch 'migrate-to-svelte5' into mf-markdown
This commit is contained in:
commit
cea01f416d
40 changed files with 610 additions and 406 deletions
4
.vscode/settings.json
vendored
4
.vscode/settings.json
vendored
|
|
@ -12,7 +12,7 @@
|
||||||
"editor.wordWrap": "on"
|
"editor.wordWrap": "on"
|
||||||
},
|
},
|
||||||
"[svelte]": {
|
"[svelte]": {
|
||||||
"editor.defaultFormatter": "svelte.svelte-vscode"
|
"editor.defaultFormatter": "svelte.svelte-vscode"
|
||||||
},
|
},
|
||||||
"typescript.tsdk": "node_modules/typescript/lib"
|
"typescript.tsdk": "node_modules/typescript/lib"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
18
src/app.html
18
src/app.html
|
|
@ -1,11 +1,11 @@
|
||||||
<!DOCTYPE html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
%sveltekit.head%
|
%sveltekit.head%
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
%sveltekit.body%
|
%sveltekit.body%
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
@ -55,7 +55,7 @@
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div data-freestar-ad={dataFreestarAd || null} id={adId}></div>
|
<div data-freestar-ad="{dataFreestarAd || null}" id="{adId}"></div>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
:global(div.freestar-adslot:has(.unfulfilled-ad)) {
|
: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
|
```svelte
|
||||||
<!-- First inline ad on the page -->
|
<!-- First inline ad on the page -->
|
||||||
<InlineAd n={1} />
|
<InlineAd n="{1}" />
|
||||||
<!-- ... second ... -->
|
<!-- ... second ... -->
|
||||||
<InlineAd n={2} />
|
<InlineAd n="{2}" />
|
||||||
<!-- ... third and final. -->
|
<!-- ... third and final. -->
|
||||||
<InlineAd n={3} />
|
<InlineAd n="{3}" />
|
||||||
```
|
```
|
||||||
|
|
||||||
<Canvas of={InlineAdStories.Demo} />
|
<Canvas of={InlineAdStories.Demo} />
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:window bind:innerWidth={windowWidth} />
|
<svelte:window bind:innerWidth="{windowWidth}" />
|
||||||
|
|
||||||
<div
|
<div
|
||||||
class="freestar-adslot leaderboard__sticky {cls}"
|
class="freestar-adslot leaderboard__sticky {cls}"
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@
|
||||||
let adType = $derived(getAdType(placementName));
|
let adType = $derived(getAdType(placementName));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:window bind:innerWidth={windowWidth} />
|
<svelte:window bind:innerWidth="{windowWidth}" />
|
||||||
|
|
||||||
{#if windowWidth}
|
{#if windowWidth}
|
||||||
{#key placementName}
|
{#key placementName}
|
||||||
|
|
|
||||||
|
|
@ -40,13 +40,13 @@ When combined with the `Block` component, you can set custom column widths by pa
|
||||||
|
|
||||||
```svelte
|
```svelte
|
||||||
<Article
|
<Article
|
||||||
columnWidths={{
|
columnWidths="{{
|
||||||
narrower: 310,
|
narrower: 310,
|
||||||
narrow: 450,
|
narrow: 450,
|
||||||
normal: 550,
|
normal: 550,
|
||||||
wide: 675,
|
wide: 675,
|
||||||
wider: 1400,
|
wider: 1400,
|
||||||
}}
|
}}"
|
||||||
>
|
>
|
||||||
<Block width="narrower" />
|
<Block width="narrower" />
|
||||||
<Block width="narrow" />
|
<Block width="narrow" />
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ Venison shoulder *ham hock ham leberkas*. Flank beef ribs fatback, jerky meatbal
|
||||||
|
|
||||||
## Using with ArchieML docs
|
## Using with ArchieML docs
|
||||||
|
|
||||||
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
|
# Archie ML doc
|
||||||
|
|
|
||||||
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">
|
<script module lang="ts">
|
||||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||||
import Byline from './Byline.svelte';
|
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({
|
const { Story } = defineMeta({
|
||||||
title: 'Components/Text elements/Byline',
|
title: 'Components/Text elements/Byline',
|
||||||
component: Byline,
|
component: Byline,
|
||||||
...withComponentDocs(componentDocs),
|
tags: ['autodocs'],
|
||||||
argTypes: {
|
argTypes: {
|
||||||
align: {
|
align: {
|
||||||
control: 'select',
|
control: 'select',
|
||||||
|
|
@ -21,17 +15,12 @@
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#snippet template(args: ComponentProps<Byline>)}
|
|
||||||
<Byline {...args} />
|
|
||||||
{/snippet}
|
|
||||||
|
|
||||||
<Story
|
<Story
|
||||||
name="Default"
|
name="Demo"
|
||||||
args={{
|
args={{
|
||||||
align: 'left',
|
align: 'left',
|
||||||
authors: [
|
authors: [
|
||||||
'Dea Bankova',
|
'Dea Bankova',
|
||||||
'Aditi Bhandari',
|
|
||||||
'Prasanta Kumar Dutta',
|
'Prasanta Kumar Dutta',
|
||||||
'Anurag Rao',
|
'Anurag Rao',
|
||||||
'Mariano Zafra',
|
'Mariano Zafra',
|
||||||
|
|
@ -39,5 +28,18 @@
|
||||||
publishTime: new Date('2021-09-12').toISOString(),
|
publishTime: new Date('2021-09-12').toISOString(),
|
||||||
updateTime: new Date('2021-09-12T13:57:00').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 Block from '../Block/Block.svelte';
|
||||||
import slugify from 'slugify';
|
import slugify from 'slugify';
|
||||||
import { apdate } from 'journalize';
|
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[] = [];
|
const isValidDate = (datetime: 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) => {
|
|
||||||
if (!datetime) return false;
|
if (!datetime) return false;
|
||||||
if (!Date.parse(datetime)) return false;
|
if (!Date.parse(datetime)) return false;
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
const formatTime = (datetime) =>
|
const formatTime = (datetime: string) =>
|
||||||
new Date(datetime).toLocaleTimeString([], {
|
new Date(datetime).toLocaleTimeString([], {
|
||||||
hour: '2-digit',
|
hour: '2-digit',
|
||||||
minute: '2-digit',
|
minute: '2-digit',
|
||||||
timeZoneName: 'short',
|
timeZoneName: 'short',
|
||||||
});
|
});
|
||||||
|
|
||||||
const areSameDay = (first, second) =>
|
const areSameDay = (first: Date, second: Date) =>
|
||||||
first.getFullYear() === second.getFullYear() &&
|
first.getFullYear() === second.getFullYear() &&
|
||||||
first.getMonth() === second.getMonth() &&
|
first.getMonth() === second.getMonth() &&
|
||||||
first.getDate() === second.getDate();
|
first.getDate() === second.getDate();
|
||||||
|
|
@ -69,16 +97,16 @@
|
||||||
<Block {id} class="byline-container {alignmentClass} {cls}" width="normal">
|
<Block {id} class="byline-container {alignmentClass} {cls}" width="normal">
|
||||||
<aside class="article-metadata font-subhed">
|
<aside class="article-metadata font-subhed">
|
||||||
<div class="byline body-caption fmb-1">
|
<div class="byline body-caption fmb-1">
|
||||||
{#if $$slots.byline}
|
{#if byline}
|
||||||
<!-- Custom byline -->
|
<!-- Custom byline -->
|
||||||
<slot name="byline" />
|
{@render byline()}
|
||||||
{:else}
|
{:else}
|
||||||
By
|
By
|
||||||
{#if authors.length > 0}
|
{#if authors.length > 0}
|
||||||
{#each authors as author, i}
|
{#each authors as author, i}
|
||||||
<a
|
<a
|
||||||
class="no-underline whitespace-nowrap text-primary font-bold"
|
class="no-underline whitespace-nowrap text-primary font-bold"
|
||||||
href="{getAuthorPage(author)}"
|
href={getAuthorPage(author)}
|
||||||
rel="author"
|
rel="author"
|
||||||
>
|
>
|
||||||
{author.trim()}</a
|
{author.trim()}</a
|
||||||
|
|
@ -95,15 +123,17 @@
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<div class="dateline body-caption fmt-0">
|
<div class="dateline body-caption fmt-0">
|
||||||
{#if $$slots.published}
|
{#if published}
|
||||||
<div class="whitespace-nowrap inline-block">
|
<div class="whitespace-nowrap inline-block">
|
||||||
<!-- Custom published dateline -->
|
<!-- Custom published dateline snippet -->
|
||||||
<slot name="published" />
|
<time datetime={publishTime}>
|
||||||
|
{@render published()}
|
||||||
|
</time>
|
||||||
</div>
|
</div>
|
||||||
{:else if isValidDate(publishTime)}
|
{:else if isValidDate(publishTime)}
|
||||||
<div class="whitespace-nowrap inline-block">
|
<div class="whitespace-nowrap inline-block">
|
||||||
Published
|
Published
|
||||||
<time datetime="{publishTime}">
|
<time datetime={publishTime}>
|
||||||
{#if isValidDate(updateTime)}
|
{#if isValidDate(updateTime)}
|
||||||
{apdate(new Date(publishTime))}
|
{apdate(new Date(publishTime))}
|
||||||
{:else}
|
{:else}
|
||||||
|
|
@ -114,15 +144,17 @@
|
||||||
</time>
|
</time>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#if $$slots.updated}
|
{#if updated}
|
||||||
<div class="whitespace-nowrap inline-block">
|
<div class="whitespace-nowrap inline-block">
|
||||||
<!-- Custom updated dateline -->
|
<!-- Custom updated dateline snippet -->
|
||||||
<slot name="updated" />
|
<time datetime={updateTime}>
|
||||||
|
{@render updated()}
|
||||||
|
</time>
|
||||||
</div>
|
</div>
|
||||||
{:else if isValidDate(publishTime) && isValidDate(updateTime)}
|
{:else if isValidDate(publishTime) && isValidDate(updateTime)}
|
||||||
<div class="whitespace-nowrap inline-block">
|
<div class="whitespace-nowrap inline-block">
|
||||||
Last updated
|
Last updated
|
||||||
<time datetime="{updateTime}">
|
<time datetime={updateTime}>
|
||||||
{#if areSameDay(new Date(publishTime), new Date(updateTime))}
|
{#if areSameDay(new Date(publishTime), new Date(updateTime))}
|
||||||
{formatTime(updateTime)}
|
{formatTime(updateTime)}
|
||||||
{:else}
|
{: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
|
<Story
|
||||||
name="Demo"
|
name="Demo"
|
||||||
args={{
|
args="{{
|
||||||
src: 'https://reuters.com/graphics/USA-ABORTION/lgpdwggnwvo/media-embed.html',
|
src: 'https://reuters.com/graphics/USA-ABORTION/lgpdwggnwvo/media-embed.html',
|
||||||
id: 'abortion-rights-map',
|
id: 'abortion-rights-map',
|
||||||
ariaLabel: 'map',
|
ariaLabel: 'map',
|
||||||
frameTitle: 'Global abortion access',
|
frameTitle: 'Global abortion access',
|
||||||
}}
|
}}"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Story
|
<Story
|
||||||
name="With chatter"
|
name="With chatter"
|
||||||
tags={['!autodocs']}
|
tags="{['!autodocs']}"
|
||||||
args={{
|
args="{{
|
||||||
frameTitle: 'Global abortion access',
|
frameTitle: 'Global abortion access',
|
||||||
ariaLabel: 'map',
|
ariaLabel: 'map',
|
||||||
id: 'abortion-rights-map',
|
id: 'abortion-rights-map',
|
||||||
|
|
@ -37,5 +37,5 @@
|
||||||
description: 'A map of worldwide access to abortion.',
|
description: 'A map of worldwide access to abortion.',
|
||||||
notes:
|
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',
|
'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">
|
<script module lang="ts">
|
||||||
import EmbedPreviewerLink from './EmbedPreviewerLink.svelte';
|
import EmbedPreviewerLink from './EmbedPreviewerLink.svelte';
|
||||||
// @ts-ignore raw
|
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||||
import componentDocs from './stories/docs/component.md?raw';
|
|
||||||
|
|
||||||
import { withComponentDocs } from '$lib/docs/utils/withParams.js';
|
const { Story } = defineMeta({
|
||||||
|
|
||||||
export const meta = {
|
|
||||||
title: 'Components/Utilities/EmbedPreviewerLink',
|
title: 'Components/Utilities/EmbedPreviewerLink',
|
||||||
component: EmbedPreviewerLink,
|
component: EmbedPreviewerLink,
|
||||||
...withComponentDocs(componentDocs),
|
});
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
|
||||||
import { Template, Story } from '@storybook/addon-svelte-csf';
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<Template >
|
|
||||||
{#snippet children({ args })}
|
|
||||||
<EmbedPreviewerLink {...args} />
|
|
||||||
{/snippet}
|
|
||||||
</Template>
|
|
||||||
|
|
||||||
<Story
|
<Story
|
||||||
name="Default"
|
name="Demo"
|
||||||
args="{{
|
tags={['!autodocs', '!dev']}
|
||||||
|
args={{
|
||||||
dev: true,
|
dev: true,
|
||||||
}}"
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
||||||
import Fa from 'svelte-fa/src/fa.svelte';
|
import Fa from 'svelte-fa/src/fa.svelte';
|
||||||
import { faWindowRestore } from '@fortawesome/free-regular-svg-icons';
|
import { faWindowRestore } from '@fortawesome/free-regular-svg-icons';
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|
@ -12,7 +11,7 @@
|
||||||
{#if dev}
|
{#if dev}
|
||||||
<div>
|
<div>
|
||||||
<a rel="external" href="/embed-previewer">
|
<a rel="external" href="/embed-previewer">
|
||||||
<Fa icon="{faWindowRestore}" />
|
<Fa icon={faWindowRestore} />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/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}" />
|
|
||||||
```
|
|
||||||
|
|
@ -12,15 +12,13 @@
|
||||||
text: string;
|
text: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
import Block from '../Block/Block.svelte';
|
import Block from '../Block/Block.svelte';
|
||||||
import Markdown from '../Markdown/Markdown.svelte';
|
import Markdown from '../Markdown/Markdown.svelte';
|
||||||
interface Props {
|
interface Props {
|
||||||
/**
|
/**
|
||||||
* An array of endnote items.
|
* An array of endnote items.
|
||||||
* @required
|
* @required
|
||||||
*/
|
*/
|
||||||
notes?: EndNote[];
|
notes?: EndNote[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,11 @@
|
||||||
minFrameWidth?: number;
|
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();
|
let container = $state();
|
||||||
|
|
||||||
|
|
@ -91,9 +95,9 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:window
|
<svelte:window
|
||||||
onmousemove={move}
|
onmousemove="{move}"
|
||||||
onmouseup={end}
|
onmouseup="{end}"
|
||||||
onkeydown={handleKeyDown}
|
onkeydown="{handleKeyDown}"
|
||||||
bind:innerWidth="{windowInnerWidth}"
|
bind:innerWidth="{windowInnerWidth}"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
@ -105,10 +109,10 @@
|
||||||
<button
|
<button
|
||||||
class="icon left"
|
class="icon left"
|
||||||
disabled="{$width === minWidth}"
|
disabled="{$width === minWidth}"
|
||||||
onclick={decrement}
|
onclick="{decrement}"
|
||||||
onfocus={onFocus}
|
onfocus="{onFocus}"
|
||||||
onmouseover={onFocus}
|
onmouseover="{onFocus}"
|
||||||
onmouseleave={onBlur}
|
onmouseleave="{onBlur}"
|
||||||
>
|
>
|
||||||
<Fa icon="{faMobileAlt}" fw />
|
<Fa icon="{faMobileAlt}" fw />
|
||||||
</button>
|
</button>
|
||||||
|
|
@ -119,18 +123,18 @@
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
role="button"
|
role="button"
|
||||||
style="left: calc({offset * 100}% - 5px);"
|
style="left: calc({offset * 100}% - 5px);"
|
||||||
onmousedown={start}
|
onmousedown="{start}"
|
||||||
onfocus={onFocus}
|
onfocus="{onFocus}"
|
||||||
onblur={onBlur}
|
onblur="{onBlur}"
|
||||||
></div>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
class="icon right"
|
class="icon right"
|
||||||
disabled="{$width === maxWidth}"
|
disabled="{$width === maxWidth}"
|
||||||
onclick={increment}
|
onclick="{increment}"
|
||||||
onfocus={onFocus}
|
onfocus="{onFocus}"
|
||||||
onmouseover={onFocus}
|
onmouseover="{onFocus}"
|
||||||
onmouseleave={onBlur}
|
onmouseleave="{onBlur}"
|
||||||
>
|
>
|
||||||
<Fa icon="{faDesktop}" fw />
|
<Fa icon="{faDesktop}" fw />
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
||||||
// For demo purposes only, hard-wiring img paths from Vite
|
// For demo purposes only, hard-wiring img paths from Vite
|
||||||
// @ts-ignore img
|
// @ts-ignore img
|
||||||
import chartXs from '../imgs/ai-chart-xs.png';
|
import chartXs from '../imgs/ai-chart-xs.png';
|
||||||
|
|
|
||||||
122
src/components/InfoBox/InfoBox.mdx
Normal file
122
src/components/InfoBox/InfoBox.mdx
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
import { Meta, Canvas } from '@storybook/blocks';
|
||||||
|
|
||||||
|
import * as InfoBoxStories from './InfoBox.stories.svelte';
|
||||||
|
|
||||||
|
<Meta of={InfoBoxStories} />
|
||||||
|
|
||||||
|
# InfoBox
|
||||||
|
|
||||||
|
The `InfoBox` component creates a stylised text box that provides additional information that needs to be visually separate from the main content flow, such as methodology, detailed notes about data and extra context.
|
||||||
|
|
||||||
|
```svelte
|
||||||
|
<script>
|
||||||
|
import { InfoBox } from '@reuters-graphics/graphics-components';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<InfoBox
|
||||||
|
title="About this data"
|
||||||
|
text={'Reuters is collecting daily COVID-19 infections and deaths data for 240 countries and territories around the world, updated regularly throughout each day. \n\n Every country reports those figures a little differently and, inevitably, misses undiagnosed infections and deaths. With this project we are focusing on the trends within countries as they try to contain the virus’ spread, whether they are approaching or past peak infection rates, or if they are seeing a resurgence of infections or deaths.'}
|
||||||
|
notes={'[Read more about our methodology](https://www.reuters.com/world-coronavirus-tracker-and-maps/en/methodology/)'}
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
<Canvas of={InfoBoxStories.Demo} />
|
||||||
|
|
||||||
|
## Using with ArchieML docs
|
||||||
|
|
||||||
|
With the graphics kit, you'll likely get your text value from an ArchieML doc...
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Archie ML doc
|
||||||
|
[blocks]
|
||||||
|
|
||||||
|
type: info-box
|
||||||
|
title: What you need to know about the war
|
||||||
|
text: Reuters is collecting daily COVID-19 infections and deaths data for 240 countries and territories around the world, updated regularly throughout each day.
|
||||||
|
|
||||||
|
Every country reports those figures a little differently and, inevitably, misses undiagnosed infections and deaths. With this project we are focusing on the trends within countries as they try to contain the virus’ spread, whether they are approaching or past peak infection rates, or if they are seeing a resurgence of infections or deaths.
|
||||||
|
:end
|
||||||
|
notes: [Read more about our methodology](https://www.reuters.com/world-coronavirus-tracker-and-maps/en/methodology/)
|
||||||
|
[]
|
||||||
|
```
|
||||||
|
|
||||||
|
... which you'll parse out of a ArchieML block object before passing to the `InfoBox` component.
|
||||||
|
|
||||||
|
```svelte
|
||||||
|
<!-- Graphics Kit -->
|
||||||
|
<script>
|
||||||
|
import { InfoBox } from '@reuters-graphics/graphics-components';
|
||||||
|
import content from '$locales/en/content.json';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
# Graphics Kit
|
||||||
|
{#each content.blocks as block}
|
||||||
|
{#if block.type === 'info-box'}
|
||||||
|
<InfoBox title={block.title} text={block.text} notes={block.notes} />
|
||||||
|
<!-- ... -->
|
||||||
|
{/if}
|
||||||
|
{/each}
|
||||||
|
```
|
||||||
|
|
||||||
|
<Canvas of={InfoBoxStories.Demo} />
|
||||||
|
|
||||||
|
## Lists
|
||||||
|
|
||||||
|
Use markdown to add lists to `InfoBox`.
|
||||||
|
|
||||||
|
```svelte
|
||||||
|
<script>
|
||||||
|
import { InfoBox } from '@reuters-graphics/graphics-components';
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<InfoBox
|
||||||
|
title="What you need to know about the war"
|
||||||
|
text={"- **Food crisis**: [Russia's invasion of Ukraine](#) in late February dramatically worsened the outlook for already inflated global food prices.\n- **Under fire**: Civillian homes destroyed in the conflict and Russia accused of war crimes.\n- **Nordstream sabotage**: A series of clandestine bombings and subsequent underwater gas leaks occurred on the Nord Stream 1 and Nord Stream 2 natural gas pipelines."}
|
||||||
|
notes={'[Read more about our methodology](https://www.reuters.com/world-coronavirus-tracker-and-maps/en/methodology/)'}
|
||||||
|
/>
|
||||||
|
```
|
||||||
|
|
||||||
|
<Canvas of={InfoBoxStories.Lists} />
|
||||||
|
## Customisation
|
||||||
|
|
||||||
|
Use [snippets](https://svelte.dev/docs/svelte/snippet) to customise the `InfoBox`, such as adding tables, icons and thumbnail images.
|
||||||
|
|
||||||
|
```svelte
|
||||||
|
<InfoBox title="About this data">
|
||||||
|
<!-- Optional custom header -->
|
||||||
|
{#snippet header()}
|
||||||
|
<h3>Global video game market</h3>
|
||||||
|
{/snippet}
|
||||||
|
<!-- Optional custom body -->
|
||||||
|
{#snippet body()}
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Year</th>
|
||||||
|
<th>Market size ($bln)</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>2024</td>
|
||||||
|
<td>274.63</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>2023</td>
|
||||||
|
<td>281.77</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>2022</td>
|
||||||
|
<td>249.55</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{/snippet}
|
||||||
|
<!-- Optional custom footer -->
|
||||||
|
{#snippet updated()}
|
||||||
|
<div class="text-xs font-note">Source: Precedence Research</div>
|
||||||
|
{/snippet}
|
||||||
|
</InfoBox>
|
||||||
|
```
|
||||||
|
|
||||||
|
<Canvas of={InfoBoxStories.Customised} />
|
||||||
|
|
@ -1,15 +1,12 @@
|
||||||
<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';
|
|
||||||
|
|
||||||
import InfoBox from './InfoBox.svelte';
|
import InfoBox from './InfoBox.svelte';
|
||||||
|
import BodyText from '../BodyText/BodyText.svelte';
|
||||||
|
|
||||||
import { withComponentDocs } from '$lib/docs/utils/withParams.js';
|
const { Story } = defineMeta({
|
||||||
|
|
||||||
export const meta = {
|
|
||||||
title: 'Components/Text elements/InfoBox',
|
title: 'Components/Text elements/InfoBox',
|
||||||
component: InfoBox,
|
component: InfoBox,
|
||||||
...withComponentDocs(componentDocs),
|
tags: ['autodocs'],
|
||||||
argTypes: {
|
argTypes: {
|
||||||
theme: {
|
theme: {
|
||||||
control: 'select',
|
control: 'select',
|
||||||
|
|
@ -20,38 +17,82 @@
|
||||||
options: ['normal', 'wide', 'wider', 'widest', 'fluid'],
|
options: ['normal', 'wide', 'wider', 'widest', 'fluid'],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<Story name="Demo">
|
||||||
import { Template, Story } from '@storybook/addon-svelte-csf';
|
|
||||||
|
|
||||||
import BodyText from '../BodyText/BodyText.svelte';
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<Template >
|
|
||||||
{#snippet children({ args })}
|
|
||||||
<InfoBox {...args} />
|
|
||||||
{/snippet}
|
|
||||||
</Template>
|
|
||||||
|
|
||||||
<Story name="Default">
|
|
||||||
<BodyText
|
<BodyText
|
||||||
text="If you haven't seen Game of Thrones, go watch it right now. If you have then you'll totally get why this Hodor themed lorem ipsum generator is just brilliant."
|
text="Bacon ipsum dolor amet turducken buffalo beef ribs bresaola pancetta ribeye pork belly doner hamburger biltong cupim porchetta chuck ham tenderloin. Turducken bresaola jerky chicken."
|
||||||
/>
|
/>
|
||||||
<InfoBox
|
<InfoBox
|
||||||
title="About this data"
|
title="About this data"
|
||||||
text="{'Reuters is collecting daily COVID-19 infections and deaths data for 240 countries and territories around the world, updated regularly throughout each day. \n\n Every country reports those figures a little differently and, inevitably, misses undiagnosed infections and deaths. With this project we are focusing on the trends within countries as they try to contain the virus’ spread, whether they are approaching or past peak infection rates, or if they are seeing a resurgence of infections or deaths.'}"
|
text={'Reuters is collecting daily COVID-19 infections and deaths data for 240 countries and territories around the world, updated regularly throughout each day. \n\n Every country reports those figures a little differently and, inevitably, misses undiagnosed infections and deaths. With this project we are focusing on the trends within countries as they try to contain the virus’ spread, whether they are approaching or past peak infection rates, or if they are seeing a resurgence of infections or deaths.'}
|
||||||
notes="{'[Read more about our methodology](https://www.reuters.com/world-coronavirus-tracker-and-maps/en/methodology/)'}"
|
notes={'[Read more about our methodology](https://www.reuters.com/world-coronavirus-tracker-and-maps/en/methodology/)'}
|
||||||
/>
|
/>
|
||||||
<BodyText
|
<BodyText
|
||||||
text="In case you don't read Twitter, the news, or just can't get enough of The Apprentice host's legendary oration, try this Trump lorem ipsum generator on for size."
|
text="Ham drumstick tail ribeye pancetta, leberkas hamburger chicken spare ribs buffalo jerky sausage ground round meatball. Leberkas kevin short loin, tri-tip shank spare ribs buffalo beef pork belly corned beef chislic tongue."
|
||||||
/>
|
/>
|
||||||
</Story>
|
</Story>
|
||||||
|
<Story
|
||||||
|
name="Lists"
|
||||||
|
tags={['!autodocs', '!dev']}
|
||||||
|
args={{
|
||||||
|
title: 'What you need to know about the war',
|
||||||
|
text: "- **Food crisis**: [Russia's invasion of Ukraine](#) in late February dramatically worsened the outlook for already inflated global food prices. \n- **Under fire**: Civillian homes destroyed in the conflict and Russia accused of war crimes. \n- **Nordstream sabotage**: A series of clandestine bombings and subsequent underwater gas leaks occurred on the Nord Stream 1 and Nord Stream 2 natural gas pipelines. ",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Story name="Customised" tags={['!autodocs', '!dev']}>
|
||||||
|
<InfoBox>
|
||||||
|
{#snippet header()}
|
||||||
|
<h3>Global video game market</h3>
|
||||||
|
{/snippet}
|
||||||
|
{#snippet body()}
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Year</th>
|
||||||
|
<th>Market size ($bln)</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>2024</td>
|
||||||
|
<td>274.63</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>2023</td>
|
||||||
|
<td>281.77</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>2022</td>
|
||||||
|
<td>249.55</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
{/snippet}
|
||||||
|
{#snippet footer()}
|
||||||
|
<div class="text-xs font-note">Source: Precedence Research</div>
|
||||||
|
{/snippet}
|
||||||
|
</InfoBox>
|
||||||
|
</Story>
|
||||||
|
|
||||||
<Story name="List">
|
<style lang="scss">
|
||||||
<InfoBox
|
h3 {
|
||||||
title="What you need to know about the war"
|
margin: 0;
|
||||||
text="{"- **Food crisis**: [Russia's invasion of Ukraine](#) in late February dramatically worsened the outlook for already inflated global food prices. \n- **Under fire**: Civillian homes destroyed in the conflict and Russia accused of war crimes. \n- **Nordstream sabotage**: A series of clandestine bombings and subsequent underwater gas leaks occurred on the Nord Stream 1 and Nord Stream 2 natural gas pipelines. "}"
|
}
|
||||||
/>
|
// Style the table nicely
|
||||||
</Story>
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
|
th,
|
||||||
|
td {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
padding: 8px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
th {
|
||||||
|
background-color: #f2f2f2;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -1,47 +1,59 @@
|
||||||
<!-- @migration-task Error while migrating Svelte code: Cannot set properties of undefined (setting 'next') -->
|
|
||||||
<!-- @component `InfoBox` [Read the docs.](https://reuters-graphics.github.io/graphics-components/?path=/docs/components-text-elements-infobox--docs) -->
|
<!-- @component `InfoBox` [Read the docs.](https://reuters-graphics.github.io/graphics-components/?path=/docs/components-text-elements-infobox--docs) -->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import type { Snippet } from 'svelte';
|
||||||
import type { ContainerWidth } from '../@types/global';
|
import type { ContainerWidth } from '../@types/global';
|
||||||
|
|
||||||
type Theme = 'light' | 'dark';
|
type Theme = 'light' | 'dark';
|
||||||
|
|
||||||
/**
|
interface Props {
|
||||||
* Title of the box
|
/**
|
||||||
*/
|
* Title of the box
|
||||||
export let title: string | null = null;
|
*/
|
||||||
|
title?: string | null;
|
||||||
|
/**
|
||||||
|
* Contents of the note as a markdown string
|
||||||
|
*/
|
||||||
|
text?: string;
|
||||||
|
/**
|
||||||
|
* Additional footnotes
|
||||||
|
*/
|
||||||
|
notes?: string | null;
|
||||||
|
/**
|
||||||
|
* Width of the component within the text well.
|
||||||
|
*/
|
||||||
|
width?: ContainerWidth;
|
||||||
|
/**
|
||||||
|
* Add extra classes to the block tag to target it with custom CSS.
|
||||||
|
*/
|
||||||
|
class?: string;
|
||||||
|
/**
|
||||||
|
* Add an id to the block tag to target it with custom CSS.
|
||||||
|
*/
|
||||||
|
id?: string;
|
||||||
|
/**
|
||||||
|
* Page theme
|
||||||
|
*/
|
||||||
|
theme?: Theme;
|
||||||
|
/** Optional custom header snippet */
|
||||||
|
header?: Snippet;
|
||||||
|
/** Optional custom body snippet */
|
||||||
|
body?: Snippet;
|
||||||
|
/** Optional custom footer snippet */
|
||||||
|
footer?: Snippet;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
let {
|
||||||
* Contents of the note as a markdown string
|
title = null,
|
||||||
*/
|
text,
|
||||||
export let text: string = '';
|
notes = null,
|
||||||
|
width = 'normal',
|
||||||
/**
|
class: cls = '',
|
||||||
* Additional footnotes
|
id = '',
|
||||||
*/ export let notes: string | null = null;
|
theme = 'light',
|
||||||
|
header,
|
||||||
/**
|
body,
|
||||||
* Width of the component within the text well.
|
footer,
|
||||||
* @type {string}
|
}: Props = $props();
|
||||||
*/
|
|
||||||
export let width: ContainerWidth = 'normal';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add extra classes to the block tag to target it with custom CSS.
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
let cls: string = '';
|
|
||||||
export { cls as class };
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add an id to the block tag to target it with custom CSS.
|
|
||||||
* @type {string}
|
|
||||||
*/
|
|
||||||
export let id: string = '';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Page theme
|
|
||||||
*/
|
|
||||||
export let theme: Theme = 'light';
|
|
||||||
|
|
||||||
import Block from '../Block/Block.svelte';
|
import Block from '../Block/Block.svelte';
|
||||||
import Markdown from '../Markdown/Markdown.svelte';
|
import Markdown from '../Markdown/Markdown.svelte';
|
||||||
|
|
@ -53,36 +65,36 @@
|
||||||
{id}
|
{id}
|
||||||
class="{cls} fmy-6 fpx-6 fpy-5 border border-solid rounded"
|
class="{cls} fmy-6 fpx-6 fpy-5 border border-solid rounded"
|
||||||
>
|
>
|
||||||
{#if $$slots.header}
|
{#if header}
|
||||||
<div class="header fmb-2">
|
<div class="header fmb-2">
|
||||||
<!-- Custom title content -->
|
<!-- Custom header content -->
|
||||||
<slot name="header" />
|
{@render header()}
|
||||||
</div>
|
</div>
|
||||||
{:else if title}
|
{:else if title}
|
||||||
<div class="header fmb-2">
|
<div class="header fmb-2">
|
||||||
<Markdown source="{title}" />
|
<Markdown source={title} />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if $$slots.body}
|
{#if body}
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<!-- Custom content -->
|
<!-- Custom body content -->
|
||||||
<slot name="body" />
|
{@render body()}
|
||||||
</div>
|
</div>
|
||||||
{:else}
|
{:else}
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<Markdown source="{text}" />
|
<Markdown source={text} />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if $$slots.footer}
|
{#if footer}
|
||||||
<div class="footer fmt-2">
|
<div class="footer fmt-2">
|
||||||
<!-- Custom footer content -->
|
<!-- Custom footer content -->
|
||||||
<slot name="footer" />
|
{@render footer()}
|
||||||
</div>
|
</div>
|
||||||
{:else if notes}
|
{:else if notes}
|
||||||
<div class="footer fmt-2">
|
<div class="footer fmt-2">
|
||||||
<Markdown source="{notes}" />
|
<Markdown source={notes} />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</Block>
|
</Block>
|
||||||
|
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
InfoBox is used to provide additional information that needs to be visually set aside from the main content flow. e.g. Methodology, Detailed notes about data, Extra context as text stories.
|
|
||||||
|
|
||||||
Switch the theme prop to `dark` for a dark page infobox.
|
|
||||||
|
|
||||||
Use the slots to customize the content as needed, e.g. adding icons and thumbnail images etc.
|
|
||||||
|
|
||||||
```svelte
|
|
||||||
<script>
|
|
||||||
import { InfoBox } from '@reuters-graphics/graphics-components';
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<InfoBox
|
|
||||||
title="About this data"
|
|
||||||
text="{'Reuters is collecting daily COVID-19 infections and deaths data for 240 countries and territories around the world, updated regularly throughout each day. \n\n Every country reports those figures a little differently and, inevitably, misses undiagnosed infections and deaths. With this project we are focusing on the trends within countries as they try to contain the virus’ spread, whether they are approaching or past peak infection rates, or if they are seeing a resurgence of infections or deaths.'}"
|
|
||||||
notes="{'[Read more about our methodology](https://www.reuters.com/world-coronavirus-tracker-and-maps/en/methodology/)'}"
|
|
||||||
/>
|
|
||||||
```
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
<!-- @component `PymChild` [Read the docs.](https://reuters-graphics.github.io/graphics-components/?path=/docs/components-utilities-pymchild--docs) -->
|
<!-- @component `PymChild` [Read the docs.](https://reuters-graphics.github.io/graphics-components/?path=/docs/components-utilities-pymchild--docs) -->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
||||||
|
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import pym from 'pym.js';
|
import pym from 'pym.js';
|
||||||
import { pymChildStore } from './stores.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) -->
|
<!-- @component `ReutersGraphicsLogo` [Read the docs.](https://reuters-graphics.github.io/graphics-components/?path=/docs/components-logos-reutersgraphicslogo--docs) -->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
/** "Kinesis" colour */
|
/** "Kinesis" colour */
|
||||||
logoColour?: string;
|
logoColour?: string;
|
||||||
|
|
@ -12,7 +9,11 @@
|
||||||
width?: string;
|
width?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { logoColour = '#D64000', textColour = '#212223', width = '100%' }: Props = $props();
|
let {
|
||||||
|
logoColour = '#D64000',
|
||||||
|
textColour = '#212223',
|
||||||
|
width = '100%',
|
||||||
|
}: Props = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svg
|
<svg
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,5 @@
|
||||||
<!-- @component `ReutersLogo` [Read the docs.](https://reuters-graphics.github.io/graphics-components/?path=/docs/components-logos-reuterslogo--docs) -->
|
<!-- @component `ReutersLogo` [Read the docs.](https://reuters-graphics.github.io/graphics-components/?path=/docs/components-logos-reuterslogo--docs) -->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
/** "Kinesis" colour */
|
/** "Kinesis" colour */
|
||||||
logoColour?: string;
|
logoColour?: string;
|
||||||
|
|
@ -12,7 +9,11 @@
|
||||||
width?: string;
|
width?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { logoColour = '#D64000', textColour = '#212223', width = '100%' }: Props = $props();
|
let {
|
||||||
|
logoColour = '#D64000',
|
||||||
|
textColour = '#212223',
|
||||||
|
width = '100%',
|
||||||
|
}: Props = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svg
|
<svg
|
||||||
|
|
|
||||||
|
|
@ -1,85 +1,72 @@
|
||||||
<!-- @component `SEO` [Read the docs.](https://reuters-graphics.github.io/graphics-components/?path=/docs/components-ads-analytic-seo--docs) -->
|
<!-- @component `SEO` [Read the docs.](https://reuters-graphics.github.io/graphics-components/?path=/docs/components-ads-analytic-seo--docs) -->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
interface GraphicAuthor {
|
interface GraphicAuthor {
|
||||||
name: string;
|
name: string;
|
||||||
url: string;
|
url: 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
|
* @requiredx
|
||||||
* @type {string}
|
* @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
|
* @required
|
||||||
* @type {URL}
|
* @type {URL}
|
||||||
*/
|
*/
|
||||||
pageUrl?: URL | null;
|
pageUrl?: URL | null;
|
||||||
/**
|
/**
|
||||||
* SEO title
|
* SEO title
|
||||||
* @required
|
* @required
|
||||||
* @type {string}
|
* @type {string}
|
||||||
*/
|
*/
|
||||||
seoTitle: string;
|
seoTitle: string;
|
||||||
/**
|
/**
|
||||||
* SEO description
|
* SEO description
|
||||||
* @required
|
* @required
|
||||||
* @type {string}
|
* @type {string}
|
||||||
*/
|
*/
|
||||||
seoDescription: string;
|
seoDescription: string;
|
||||||
/**
|
/**
|
||||||
* Share title
|
* Share title
|
||||||
* @required
|
* @required
|
||||||
* @type {string}
|
* @type {string}
|
||||||
*/
|
*/
|
||||||
shareTitle: string;
|
shareTitle: string;
|
||||||
/**
|
/**
|
||||||
* Share description
|
* Share description
|
||||||
* @required
|
* @required
|
||||||
* @type {string}
|
* @type {string}
|
||||||
*/
|
*/
|
||||||
shareDescription: string;
|
shareDescription: string;
|
||||||
/**
|
/**
|
||||||
* Share image path. **Must be an absolute path.**
|
* Share image path. **Must be an absolute path.**
|
||||||
* @required
|
* @required
|
||||||
* @type {string}
|
* @type {string}
|
||||||
*/
|
*/
|
||||||
shareImgPath: string;
|
shareImgPath: string;
|
||||||
/**
|
/**
|
||||||
* Share image alt text, up to 420 characters.
|
* Share image alt text, up to 420 characters.
|
||||||
* @type {string}
|
* @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}
|
* @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}
|
* @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 `url` attributes.
|
||||||
*/
|
*/
|
||||||
authors?: GraphicAuthor[];
|
authors?: GraphicAuthor[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -94,7 +81,7 @@
|
||||||
shareImgAlt = '',
|
shareImgAlt = '',
|
||||||
publishTime = '',
|
publishTime = '',
|
||||||
updateTime = '',
|
updateTime = '',
|
||||||
authors = []
|
authors = [],
|
||||||
}: Props = $props();
|
}: Props = $props();
|
||||||
|
|
||||||
const getOrigin = (baseUrl: string) => {
|
const getOrigin = (baseUrl: string) => {
|
||||||
|
|
@ -109,7 +96,9 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
let origin = $derived(getOrigin(baseUrl));
|
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 = {
|
const orgLdJson = {
|
||||||
'@context': 'http://schema.org',
|
'@context': 'http://schema.org',
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { ContainerWidth, ScrollerStep } from '../../@types/global';
|
import type { ContainerWidth, ScrollerStep } from '../../@types/global';
|
||||||
|
|
||||||
|
|
||||||
type EmbeddedLayout = 'fb' | 'bf';
|
type EmbeddedLayout = 'fb' | 'bf';
|
||||||
|
|
||||||
|
|
||||||
import Background from './Background.svelte';
|
import Background from './Background.svelte';
|
||||||
import Foreground from './Foreground.svelte';
|
import Foreground from './Foreground.svelte';
|
||||||
interface Props {
|
interface Props {
|
||||||
|
|
@ -13,7 +11,11 @@
|
||||||
backgroundWidth?: ContainerWidth;
|
backgroundWidth?: ContainerWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { steps = [], embeddedLayout = 'fb', backgroundWidth = 'fluid' }: Props = $props();
|
let {
|
||||||
|
steps = [],
|
||||||
|
embeddedLayout = 'fb',
|
||||||
|
backgroundWidth = 'fluid',
|
||||||
|
}: Props = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#each steps as step, index}
|
{#each steps as step, index}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
<p>The count is {count}</p>
|
<p>The count is {count}</p>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
onclick={() => {
|
onclick="{() => {
|
||||||
count += 1;
|
count += 1;
|
||||||
}}>Click Me</button
|
}}">Click Me</button
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,11 @@
|
||||||
import MagnifyingGlass from './MagnifyingGlass.svelte';
|
import MagnifyingGlass from './MagnifyingGlass.svelte';
|
||||||
import X from './X.svelte';
|
import X from './X.svelte';
|
||||||
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
/**
|
/**
|
||||||
* The placeholder text that appears in the search box.
|
* The placeholder text that appears in the search box.
|
||||||
* @type {string}
|
* @type {string}
|
||||||
*/
|
*/
|
||||||
searchPlaceholder?: string;
|
searchPlaceholder?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -40,7 +39,7 @@
|
||||||
class="search--input body-caption pl-8"
|
class="search--input body-caption pl-8"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="{searchPlaceholder}"
|
placeholder="{searchPlaceholder}"
|
||||||
oninput={input}
|
oninput="{input}"
|
||||||
bind:value
|
bind:value
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
|
|
@ -48,8 +47,8 @@
|
||||||
role="button"
|
role="button"
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
class:invisible="{!active}"
|
class:invisible="{!active}"
|
||||||
onclick={clear}
|
onclick="{clear}"
|
||||||
onkeyup={clear}
|
onkeyup="{clear}"
|
||||||
>
|
>
|
||||||
<X />
|
<X />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -9,11 +9,10 @@
|
||||||
import starterData from './data.json';
|
import starterData from './data.json';
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
/**
|
/**
|
||||||
* Set to `false` to remove graphics referrals
|
* Set to `false` to remove graphics referrals
|
||||||
*/
|
*/
|
||||||
includeReferrals?: boolean;
|
includeReferrals?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,11 @@
|
||||||
releaseMobileMenu?: any;
|
releaseMobileMenu?: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { data = [], isMobileMenuOpen = false, releaseMobileMenu = () => {} }: Props = $props();
|
let {
|
||||||
|
data = [],
|
||||||
|
isMobileMenuOpen = false,
|
||||||
|
releaseMobileMenu = () => {},
|
||||||
|
}: Props = $props();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if isMobileMenuOpen}
|
{#if isMobileMenuOpen}
|
||||||
|
|
@ -31,7 +35,7 @@
|
||||||
textColour="var(--nav-primary)"
|
textColour="var(--nav-primary)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<button class="button close-button" onclick={releaseMobileMenu}>
|
<button class="button close-button" onclick="{releaseMobileMenu}">
|
||||||
<div class="button-container">
|
<div class="button-container">
|
||||||
<CloseIcon />
|
<CloseIcon />
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,11 @@
|
||||||
|
|
||||||
let { section = {}, headingText } = $props();
|
let { section = {}, headingText } = $props();
|
||||||
|
|
||||||
let splitCount =
|
let splitCount = $derived(
|
||||||
$derived(section.children && section.children.length > 7 ?
|
section.children && section.children.length > 7 ?
|
||||||
Math.ceil(section.children.length / 2)
|
Math.ceil(section.children.length / 2)
|
||||||
: 0);
|
: 0
|
||||||
|
);
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<NavDropdown {headingText}>
|
<NavDropdown {headingText}>
|
||||||
|
|
|
||||||
|
|
@ -35,27 +35,27 @@
|
||||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||||
<li
|
<li
|
||||||
class="nav-item category link"
|
class="nav-item category link"
|
||||||
onmouseenter={() => {
|
onmouseenter="{() => {
|
||||||
navTimeout = setTimeout(
|
navTimeout = setTimeout(
|
||||||
() => activeSection.set(section.id),
|
() => activeSection.set(section.id),
|
||||||
timeout
|
timeout
|
||||||
);
|
);
|
||||||
}}
|
}}"
|
||||||
onfocus={() => activeSection.set(section.id)}
|
onfocus="{() => activeSection.set(section.id)}"
|
||||||
onmouseleave={() => {
|
onmouseleave="{() => {
|
||||||
clearTimeout(navTimeout);
|
clearTimeout(navTimeout);
|
||||||
activeSection.set(null);
|
activeSection.set(null);
|
||||||
}}
|
}}"
|
||||||
onblur={() => {
|
onblur="{() => {
|
||||||
clearTimeout(navTimeout);
|
clearTimeout(navTimeout);
|
||||||
activeSection.set(null);
|
activeSection.set(null);
|
||||||
}}
|
}}"
|
||||||
onclick={() => {
|
onclick="{() => {
|
||||||
if ($activeSection === section.id) {
|
if ($activeSection === section.id) {
|
||||||
clearTimeout(navTimeout);
|
clearTimeout(navTimeout);
|
||||||
activeSection.set(null);
|
activeSection.set(null);
|
||||||
}
|
}
|
||||||
}}
|
}}"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="nav-button link"
|
class="nav-button link"
|
||||||
|
|
@ -88,24 +88,24 @@
|
||||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||||
<li
|
<li
|
||||||
class="nav-item"
|
class="nav-item"
|
||||||
onmouseenter={() => {
|
onmouseenter="{() => {
|
||||||
navTimeout = setTimeout(() => activeSection.set('more'), timeout);
|
navTimeout = setTimeout(() => activeSection.set('more'), timeout);
|
||||||
}}
|
}}"
|
||||||
onfocus={() => activeSection.set('more')}
|
onfocus="{() => activeSection.set('more')}"
|
||||||
onmouseleave={() => {
|
onmouseleave="{() => {
|
||||||
clearTimeout(navTimeout);
|
clearTimeout(navTimeout);
|
||||||
activeSection.set(null);
|
activeSection.set(null);
|
||||||
}}
|
}}"
|
||||||
onblur={() => {
|
onblur="{() => {
|
||||||
clearTimeout(navTimeout);
|
clearTimeout(navTimeout);
|
||||||
activeSection.set(null);
|
activeSection.set(null);
|
||||||
}}
|
}}"
|
||||||
onclick={() => {
|
onclick="{() => {
|
||||||
if ($activeSection === 'more') {
|
if ($activeSection === 'more') {
|
||||||
clearTimeout(navTimeout);
|
clearTimeout(navTimeout);
|
||||||
activeSection.set(null);
|
activeSection.set(null);
|
||||||
}
|
}
|
||||||
}}
|
}}"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
class="nav-button more link"
|
class="nav-button more link"
|
||||||
|
|
|
||||||
|
|
@ -77,9 +77,9 @@
|
||||||
aria-label="Menu"
|
aria-label="Menu"
|
||||||
aria-haspopup="true"
|
aria-haspopup="true"
|
||||||
aria-expanded="{isMobileMenuOpen}"
|
aria-expanded="{isMobileMenuOpen}"
|
||||||
onclick={() => {
|
onclick="{() => {
|
||||||
isMobileMenuOpen = !isMobileMenuOpen;
|
isMobileMenuOpen = !isMobileMenuOpen;
|
||||||
}}
|
}}"
|
||||||
>
|
>
|
||||||
<div class="button-container">
|
<div class="button-container">
|
||||||
<MenuIcon />
|
<MenuIcon />
|
||||||
|
|
|
||||||
|
|
@ -3,33 +3,26 @@
|
||||||
import LeftArrow from './LeftArrow.svelte';
|
import LeftArrow from './LeftArrow.svelte';
|
||||||
import RightArrow from './RightArrow.svelte';
|
import RightArrow from './RightArrow.svelte';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
/**
|
/**
|
||||||
* The current page number.
|
* The current page number.
|
||||||
* @type {number}
|
* @type {number}
|
||||||
*/
|
*/
|
||||||
pageNumber?: number;
|
pageNumber?: number;
|
||||||
/**
|
/**
|
||||||
* The default page size.
|
* The default page size.
|
||||||
* @type {number}
|
* @type {number}
|
||||||
*/
|
*/
|
||||||
pageSize?: number;
|
pageSize?: number;
|
||||||
/**
|
/**
|
||||||
* The number of records in the current page.
|
* The number of records in the current page.
|
||||||
* @type {number}
|
* @type {number}
|
||||||
*/
|
*/
|
||||||
pageLength?: number;
|
pageLength?: number;
|
||||||
/**
|
/**
|
||||||
* The total number of records in the data set.
|
* The total number of records in the data set.
|
||||||
* @type {number}
|
* @type {number}
|
||||||
*/
|
*/
|
||||||
n?: number;
|
n?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -37,7 +30,7 @@
|
||||||
pageNumber = $bindable(1),
|
pageNumber = $bindable(1),
|
||||||
pageSize = 25,
|
pageSize = 25,
|
||||||
pageLength = null,
|
pageLength = null,
|
||||||
n = null
|
n = null,
|
||||||
}: Props = $props();
|
}: Props = $props();
|
||||||
|
|
||||||
let minRow = $derived(pageNumber * pageSize - pageSize + 1);
|
let minRow = $derived(pageNumber * pageSize - pageSize + 1);
|
||||||
|
|
@ -58,7 +51,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<nav aria-label="pagination" class="pagination fmt-4">
|
<nav aria-label="pagination" class="pagination fmt-4">
|
||||||
<button onclick={goToPreviousPage} disabled="{pageNumber === 1}"
|
<button onclick="{goToPreviousPage}" disabled="{pageNumber === 1}"
|
||||||
><div class="icon-wrapper">
|
><div class="icon-wrapper">
|
||||||
<LeftArrow />
|
<LeftArrow />
|
||||||
<span class="visually-hidden">Previous page</span>
|
<span class="visually-hidden">Previous page</span>
|
||||||
|
|
@ -70,7 +63,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onclick={goToNextPage}
|
onclick="{goToNextPage}"
|
||||||
disabled="{pageNumber === Math.ceil(n / pageSize)}"
|
disabled="{pageNumber === Math.ceil(n / pageSize)}"
|
||||||
><div class="icon-wrapper">
|
><div class="icon-wrapper">
|
||||||
<RightArrow />
|
<RightArrow />
|
||||||
|
|
|
||||||
|
|
@ -2,19 +2,16 @@
|
||||||
import { createEventDispatcher } from 'svelte';
|
import { createEventDispatcher } from 'svelte';
|
||||||
import type { Option } from '../@types/global';
|
import type { Option } from '../@types/global';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
/**
|
/**
|
||||||
* The label that appears above the select input.
|
* The label that appears above the select input.
|
||||||
* @type {string}
|
* @type {string}
|
||||||
*/
|
*/
|
||||||
label?: string;
|
label?: string;
|
||||||
/**
|
/**
|
||||||
* The label that appears above the select input.
|
* The label that appears above the select input.
|
||||||
* @type {Array}
|
* @type {Array}
|
||||||
*/
|
*/
|
||||||
options?: Option[];
|
options?: Option[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -36,7 +33,7 @@
|
||||||
class="select--input body-caption fpx-2"
|
class="select--input body-caption fpx-2"
|
||||||
name="select--input"
|
name="select--input"
|
||||||
id="select--input"
|
id="select--input"
|
||||||
oninput={input}
|
oninput="{input}"
|
||||||
>
|
>
|
||||||
{#each options as obj}
|
{#each options as obj}
|
||||||
<option value="{obj.value}">{obj.text}</option>
|
<option value="{obj.value}">{obj.text}</option>
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,12 @@
|
||||||
*/
|
*/
|
||||||
type SortDirection = 'ascending' | 'descending';
|
type SortDirection = 'ascending' | 'descending';
|
||||||
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
sortDirection?: SortDirection;
|
sortDirection?: SortDirection;
|
||||||
/**
|
/**
|
||||||
* Whether or not this arrow is currently sorting. It is false by default.
|
* Whether or not this arrow is currently sorting. It is false by default.
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
*/
|
*/
|
||||||
active?: boolean;
|
active?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
controlsBorderOffset,
|
controlsBorderOffset,
|
||||||
resetCondition,
|
resetCondition,
|
||||||
separateReplayIcon,
|
separateReplayIcon,
|
||||||
controlsColour
|
controlsColour,
|
||||||
} = $props();
|
} = $props();
|
||||||
|
|
||||||
function forwardBtnClick() {
|
function forwardBtnClick() {
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
onclick={forwardBtnClick}
|
onclick="{forwardBtnClick}"
|
||||||
style="
|
style="
|
||||||
opacity: {controlsOpacity};
|
opacity: {controlsOpacity};
|
||||||
top: {controlsPosition === 'top left' || controlsPosition === 'top right' ?
|
top: {controlsPosition === 'top left' || controlsPosition === 'top right' ?
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue