diff --git a/src/components/BodyText/BodyText.svelte b/src/components/BodyText/BodyText.svelte index daee64b2..d46d40ab 100644 --- a/src/components/BodyText/BodyText.svelte +++ b/src/components/BodyText/BodyText.svelte @@ -1,5 +1,6 @@ - {#if text} - {@html marked.parse(text)} - {/if} + diff --git a/src/components/EndNotes/EndNotes.svelte b/src/components/EndNotes/EndNotes.svelte index 8a2dd765..71b2b162 100644 --- a/src/components/EndNotes/EndNotes.svelte +++ b/src/components/EndNotes/EndNotes.svelte @@ -4,12 +4,12 @@ /** * Title of the note item */ - title: String; + title: string; /** * Contents of the note as a markdown string * @required */ - text: String; + text: string; } /** @@ -18,15 +18,19 @@ */ export let notes: EndNote[] = []; - import { marked } from 'marked'; import Block from '../Block/Block.svelte'; + import Markdown from '../Markdown/Markdown.svelte'; {#if notes} {#each notes as note} -
{@html marked.parse(note.title)}
-
{@html marked.parse(note.text)}
+
+ +
+
+ +
{/each} {/if}
diff --git a/src/components/GraphicBlock/GraphicBlock.svelte b/src/components/GraphicBlock/GraphicBlock.svelte index 785b6be0..77b8ab4e 100644 --- a/src/components/GraphicBlock/GraphicBlock.svelte +++ b/src/components/GraphicBlock/GraphicBlock.svelte @@ -70,7 +70,7 @@ import TextBlock from './TextBlock.svelte'; import Block from '../Block/Block.svelte'; import PaddingReset from '../PaddingReset/PaddingReset.svelte'; - import { marked } from 'marked'; + import Markdown from '../Markdown/Markdown.svelte';

{title}

{#if description} - {@html marked(description)} + {/if} @@ -108,7 +108,7 @@ {:else} - {@html marked(ariaDescription)} + {/if} {/if} @@ -123,7 +123,7 @@ diff --git a/src/components/Headline/Headline.svelte b/src/components/Headline/Headline.svelte index 194ffa94..73c36705 100644 --- a/src/components/Headline/Headline.svelte +++ b/src/components/Headline/Headline.svelte @@ -50,7 +50,7 @@ import Block from '../Block/Block.svelte'; import Byline from '../Byline/Byline.svelte'; - import { marked } from 'marked'; + import Markdown from '../Markdown/Markdown.svelte'; let hedClass; $: { @@ -94,7 +94,9 @@ {:else} -

{@html marked.parseInline(hed)}

+

+ +

{/if} {#if $$slots.dek} @@ -103,7 +105,7 @@ {:else if dek}
- {@html marked(dek)} +
{/if} diff --git a/src/components/InfoBox/InfoBox.svelte b/src/components/InfoBox/InfoBox.svelte index d99ac074..c78ab3c1 100644 --- a/src/components/InfoBox/InfoBox.svelte +++ b/src/components/InfoBox/InfoBox.svelte @@ -43,7 +43,7 @@ export let theme: Theme = 'light'; import Block from '../Block/Block.svelte'; - import { marked } from 'marked'; + import Markdown from '../Markdown/Markdown.svelte'; diff --git a/src/components/Markdown/Markdown.stories.svelte b/src/components/Markdown/Markdown.stories.svelte new file mode 100644 index 00000000..c96e298f --- /dev/null +++ b/src/components/Markdown/Markdown.stories.svelte @@ -0,0 +1,31 @@ + + + + + + + diff --git a/src/components/Markdown/Markdown.svelte b/src/components/Markdown/Markdown.svelte new file mode 100644 index 00000000..1ea369be --- /dev/null +++ b/src/components/Markdown/Markdown.svelte @@ -0,0 +1,42 @@ + + + +{#if source} + {#if $staticMarkdown} +
+ {@html markdown} +
+ {:else} +
+ {/if} +{/if} + + diff --git a/src/components/Markdown/stores.ts b/src/components/Markdown/stores.ts new file mode 100644 index 00000000..5705ac9d --- /dev/null +++ b/src/components/Markdown/stores.ts @@ -0,0 +1,25 @@ +import { writable } from 'svelte/store'; + +/** + * Set to `false` in the browser to ensure Markdown content correctly updates + * when a SvelteKit app hyrates. + * + * @example + * ```javascript + * // +layout.js + * import { staticMarkdown } from '@reuters-graphics/graphics-components'; + * import { building } from '$app/environment'; + * + * export const load = async() => { + * // Set the store with the value of building. + * staticMarkdown.set(building); + * + * // Markdown using this content will correctly refresh when + * // a reader loads your page. + * const content = await fetchPageContent(); + * + * return { content }; + * } + * ``` + */ +export const staticMarkdown = writable(true); diff --git a/src/components/Markdown/stories/docs/component.md b/src/components/Markdown/stories/docs/component.md new file mode 100644 index 00000000..5ba4ae0a --- /dev/null +++ b/src/components/Markdown/stories/docs/component.md @@ -0,0 +1,39 @@ +The Markdown component renders markdown into HTML. That's it! + +--- + +```svelte + + + +``` + +... well, almost. + +Owing to a weird quirk of Svelte's [`@html`](https://svelte.dev/docs/special-tags#html) directive (see [this issue](https://github.com/reuters-graphics/graphics-components/issues/148)), if you want your resulting HTML to be dynamic — e.g., update after a SvelteKit app [hydrates](https://kit.svelte.dev/docs/glossary#hydration) — then you may need to set the included `$staticMarkdown` store to `false` in the browser. + +For example, if you're refreshing some data with markdown strings in a SvelteKit project using a [load function](https://kit.svelte.dev/docs/load), set the store to reflect the [`building`](https://kit.svelte.dev/docs/modules#$app-environment-building) variable, which will correctly [prerender](https://kit.svelte.dev/docs/glossary#prerendering) your markdown content AND update it after fresh data is fetched in the browser. + +```javascript +// +layout.js +import { staticMarkdown } from '@reuters-graphics/graphics-components'; +import { building } from '$app/environment'; + +/** @type {import('./$types').LayoutLoad} */ +export const load = async () => { + // Set the staticMarkdown store with the value of building. + staticMarkdown.set(building); + + // Now this content will correctly refresh when a reader loads your page. + const resp = await fetch( + 'https://graphics.thomsonreuters.com/data/my-page-content.json' + ); + const content = await resp.json(); + + return { content }; +}; +``` + +If you're not updating your markdown content as above, you can safely leave the `$staticMarkdown` store alone and your page will do the right thing. diff --git a/src/components/PhotoPack/PhotoPack.svelte b/src/components/PhotoPack/PhotoPack.svelte index 88eee261..2a425f66 100644 --- a/src/components/PhotoPack/PhotoPack.svelte +++ b/src/components/PhotoPack/PhotoPack.svelte @@ -57,7 +57,7 @@ import Block from '../Block/Block.svelte'; import PaddingReset from '../PaddingReset/PaddingReset.svelte'; - import { marked } from 'marked'; + import Markdown from '../Markdown/Markdown.svelte'; let containerWidth; @@ -123,7 +123,7 @@ {#each row as img, i} {#if img.caption}
- {@html marked(img.caption)} +
{/if} {/each} diff --git a/src/components/Scroller/Embedded/Foreground.svelte b/src/components/Scroller/Embedded/Foreground.svelte index a13bdaf8..c3247be1 100644 --- a/src/components/Scroller/Embedded/Foreground.svelte +++ b/src/components/Scroller/Embedded/Foreground.svelte @@ -4,8 +4,8 @@ export let step: ScrollerStep; export let index: number; - import { marked } from 'marked'; import Block from '../../Block/Block.svelte'; + import Markdown from '../../Markdown/Markdown.svelte'; {#if step.foreground === '' || !step.foreground} @@ -14,18 +14,18 @@ {#if typeof step.altText === 'string'}
- {@html marked.parse(step.altText)} +
{/if} {:else if typeof step.foreground === 'string'}
- {@html marked.parse(step.foreground)} +
{#if typeof step.altText === 'string'}
- {@html marked.parse(step.altText)} +
{/if}
diff --git a/src/components/Scroller/Foreground.svelte b/src/components/Scroller/Foreground.svelte index fbaf5f41..bdae6c74 100644 --- a/src/components/Scroller/Foreground.svelte +++ b/src/components/Scroller/Foreground.svelte @@ -3,7 +3,7 @@ export let steps: ScrollerStep[] = []; - import { marked } from 'marked'; + import Markdown from '../Markdown/Markdown.svelte'; {#each steps as step, i} @@ -16,13 +16,13 @@
{#if typeof step.altText === 'string'}
- {@html marked.parse(step.altText)} +
{/if} {:else}
{#if typeof step.foreground === 'string'} - {@html marked.parse(step.foreground)} + {:else} {#if typeof step.altText === 'string'}
- {@html marked.parse(step.altText)} +
{/if} {/if} diff --git a/src/components/SimpleTimeline/SimpleTimeline.svelte b/src/components/SimpleTimeline/SimpleTimeline.svelte index 4ecacefd..3c913044 100644 --- a/src/components/SimpleTimeline/SimpleTimeline.svelte +++ b/src/components/SimpleTimeline/SimpleTimeline.svelte @@ -39,7 +39,7 @@ import Block from '../Block/Block.svelte'; import Fa from 'svelte-fa/src/fa.svelte'; import { faLink } from '@fortawesome/free-solid-svg-icons'; - import { marked } from 'marked'; + import Markdown from '../Markdown/Markdown.svelte'; @@ -76,7 +76,7 @@
{/if} {#if event.context} - {@html marked(event.context)} + {/if} {/each} diff --git a/src/index.js b/src/index.js index 88c7d5e1..9a4d8135 100644 --- a/src/index.js +++ b/src/index.js @@ -24,11 +24,13 @@ export { default as HeroHeadline } from './components/HeroHeadline/Hero.svelte'; export { default as EndNotes } from './components/EndNotes/EndNotes.svelte'; export { default as InfoBox } from './components/InfoBox/InfoBox.svelte'; export { default as InlineAd } from './components/AdSlot/InlineAd.svelte'; +export { default as Markdown } from './components/Markdown/Markdown.svelte'; export { default as PaddingReset } from './components/PaddingReset/PaddingReset.svelte'; export { default as PhotoCarousel } from './components/PhotoCarousel/PhotoCarousel.svelte'; export { default as PhotoPack } from './components/PhotoPack/PhotoPack.svelte'; export { default as PymChild } from './components/PymChild/PymChild.svelte'; export { pymChildStore } from './components/PymChild/stores.js'; +export { staticMarkdown } from './components/Markdown/stores.js'; export { default as ReferralBlock } from './components/ReferralBlock/ReferralBlock.svelte'; export { default as ReutersGraphicsLogo } from './components/ReutersGraphicsLogo/ReutersGraphicsLogo.svelte'; export { default as ReutersLogo } from './components/ReutersLogo/ReutersLogo.svelte';