makes SvelteScroller, updates docs
This commit is contained in:
parent
ee205b81c1
commit
27a89998a0
4 changed files with 80 additions and 385 deletions
|
|
@ -117,7 +117,7 @@
|
|||
top = 0,
|
||||
bottom = 1,
|
||||
threshold = 0.5,
|
||||
query = 'section',
|
||||
query = 'div.step-foreground-container',
|
||||
parallax = false,
|
||||
backgroundSnippet,
|
||||
foregroundSnippet,
|
||||
|
|
|
|||
|
|
@ -6,274 +6,70 @@ import * as SvelteScrollerStories from './SvelteScroller.stories.svelte';
|
|||
|
||||
# SvelteScroller
|
||||
|
||||
The `SvelteScroller` component creates a basic scrollytelling graphic with layout options.
|
||||
The `SvelteScroller` component is the base Scroller component that powers the [`Scroller` component](?path=/story/components-graphics-scroller--docs). It is a Svelte 5 version of the [svelte-scroller](https://github.com/sveltejs/svelte-scroller).
|
||||
|
||||
> This component is designed to handle most common layouts for scrollytelling. To make something more complex, customise [ScrollerBase](https://github.com/reuters-graphics/graphics-components/blob/main/src/components/Scroller/ScrollerBase/index.svelte), which is a Svelte 5 version of the [svelte-scroller](https://github.com/sveltejs/svelte-scroller).
|
||||
This component allows for customisation that the [`Scroller` component](?path=/story/components-graphics-scroller--docs) can't handle.
|
||||
|
||||
[Demo](?path=/story/components-graphics-scroller--demo)
|
||||
> **Important❗:** Make sure each foreground step's container is a div with the class `step-foreground-container`. If you're modifying the class, pass the appropriate selector to the `query` prop.
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
import { Scroller } from '@reuters-graphics/graphics-components';
|
||||
|
||||
import MyBackground from './MyBackground.svelte'; // Your own background component
|
||||
|
||||
// Array of step objects that define the steps in your scroller.
|
||||
const steps = [
|
||||
{
|
||||
background: MyBackground,
|
||||
backgroundProps: { colour: 'red' }, // Optional props for your background component
|
||||
foreground: '#### Step 1\n\nLorem ipsum red',
|
||||
altText: 'Red background',
|
||||
},
|
||||
{
|
||||
background: MyBackground,
|
||||
backgroundProps: { colour: 'blue' },
|
||||
foreground: '#### Step 2\n\nLorem ipsum blue',
|
||||
altText: 'Blue background',
|
||||
},
|
||||
{
|
||||
background: MyBackground,
|
||||
backgroundProps: { colour: 'green' },
|
||||
foreground: '#### Step 3\n\nLorem ipsum green',
|
||||
altText: 'Green background',
|
||||
},
|
||||
];
|
||||
</script>
|
||||
|
||||
<Scroller {steps} foregroundPosition="middle" backgroundWidth="fluid" />
|
||||
```
|
||||
|
||||
## Using with ArchieML and ai2svelte
|
||||
|
||||
[Demo](?path=/story/components-graphics-scroller--archie-ml)
|
||||
|
||||
In your graphics kit project, import your ai2svelte graphics in `App.svelte` and add them to the `aiCharts` object:
|
||||
[Demo](?path=/story/components-graphics-sveltescroller--demo)
|
||||
|
||||
```svelte
|
||||
<!-- App.svelte -->
|
||||
<script>
|
||||
import AiMap1 from './ai2svelte/my-map-1.svelte';
|
||||
import AiMap2 from './ai2svelte/my-map-2.svelte';
|
||||
import AiMap3 from './ai2svelte/my-map-3.svelte';
|
||||
import { SvelteScroller } from '@reuters-graphics/graphics-components';
|
||||
|
||||
import content from '$locales/en/content.json';
|
||||
|
||||
// Graphics kit only
|
||||
import { assets } from '$app/paths'; // 👈 If using in the graphics kit...
|
||||
import { truthy } from '$utils/propValidators'; // 👈 If using in the graphics kit...
|
||||
|
||||
const aiCharts = {
|
||||
AiMap1,
|
||||
AiMap2,
|
||||
AiMap3,
|
||||
// Other charts...
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
Then add the following structure to your ArchieML Doc, making sure that the names of your charts in the `aiCharts` object match the names of each step's `background` in the ArchieML doc:
|
||||
|
||||
```yaml
|
||||
# ArchieML doc
|
||||
[blocks]
|
||||
type: ai-scroller
|
||||
id: my-map-scroller
|
||||
width: fluid
|
||||
foregroundPosition: right
|
||||
stackBackground: true
|
||||
|
||||
# Array of step objects
|
||||
[.steps]
|
||||
background: AiMap1
|
||||
foreground: #### Step 1
|
||||
|
||||
Here's where something happend.
|
||||
:end
|
||||
altText: A map showing the Upper West side in New York City.
|
||||
|
||||
Can add paragraphs of alt text if you want to break up sentences.
|
||||
:end
|
||||
|
||||
background: AiMap2
|
||||
foreground: #### Step 2
|
||||
|
||||
Something happened on some street...
|
||||
:end
|
||||
altText: The same map now highlights 98th Street.
|
||||
:end
|
||||
|
||||
background: AiMap3
|
||||
foreground: #### Step 3
|
||||
|
||||
... and now there are multiple protests.
|
||||
:end
|
||||
altText: The same map now highlights three locations near 98th Street where something particulary important happened.
|
||||
:end
|
||||
[]
|
||||
[]
|
||||
```
|
||||
|
||||
Then parse the relevant ArchieML block object before passing to the `Scroller` component.
|
||||
|
||||
```svelte
|
||||
<!-- App.svelte -->
|
||||
{#each content.blocks as block}
|
||||
{#if block.type === 'ai-scroller'}
|
||||
<Scroller
|
||||
id={block.id}
|
||||
backgroundWidth={block.width}
|
||||
foregroundPosition={block.foregroundPosition}
|
||||
stackBackground={truthy(block.stackBackground)}
|
||||
steps={block.steps.map((step) => ({
|
||||
background: aiCharts[step.background],
|
||||
backgroundProps: { assetsPath: assets || '/' },
|
||||
foreground: step.foreground,
|
||||
altText: step.altText,
|
||||
}))}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
```
|
||||
|
||||
> **Note:** Some props, like `stackBackground`, expect boolean values. If you're using the graphics kit, use the `truthy()` util function to convert a string value to a boolean.
|
||||
|
||||
> **Note:** In the graphics kit, the image source paths in ai2svelte components have to be fixed by passing `assets` to each step object, like in the example above.
|
||||
|
||||
## Custom foreground
|
||||
|
||||
[Demo](?path=/story/components-graphics-scroller--custom-foreground)
|
||||
|
||||
Instead of just text, you can use components as foregrounds, and optionally pass props to it.
|
||||
|
||||
If you're customising your own foreground component, remember to add alt text that describes the background graphic.
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
import MyBackground from './MyBackground.svelte'; // Your own background component
|
||||
import MyInteractiveForeground from './MyInteractiveForeground.svelte'; // Your custom foreground component
|
||||
|
||||
const steps = [
|
||||
{
|
||||
background: MyBackground,
|
||||
backgroundProps: { colour: 'red' }, // Props for your background component, if needed
|
||||
foreground: MyInteractiveForeground, // Custom foreground component
|
||||
},
|
||||
{
|
||||
background: MyBackground,
|
||||
backgroundProps: { colour: 'blue' },
|
||||
foreground: '#### Step 2\n\nLorem ipsum blue', // You can still add a markdown string as foreground; you can mix and match
|
||||
},
|
||||
{
|
||||
background: MyBackground,
|
||||
backgroundProps: { colour: 'green' },
|
||||
foreground: MyInteractiveForeground,
|
||||
foregroundProps: { count: 100 }, // Props for your custom foreground component, if needed
|
||||
},
|
||||
];
|
||||
// Optional: Bind your own `index`, `progress`, and other bindable variables to use them in your code.
|
||||
let myIndex = $state(0);
|
||||
let myProgress = $state(0);
|
||||
</script>
|
||||
|
||||
<Scroller {steps} />
|
||||
<SvelteScroller
|
||||
bind:index={myIndex}
|
||||
bind:progress={myProgress}
|
||||
query="div.step-foreground-container"
|
||||
>
|
||||
{#snippet backgroundSnippet()}
|
||||
<!-- Add custom backgroud as a snippet -->
|
||||
<div class="custom-background">
|
||||
<p>
|
||||
This is the background content. It will stay fixed in place while the
|
||||
foreground scrolls over the top.
|
||||
</p>
|
||||
</div>
|
||||
{/snippet}
|
||||
{#snippet foregroundSnippet()}
|
||||
<!-- Add custom foreground as a snippet -->
|
||||
<div class="step-foreground-container flex items-center justify-center">
|
||||
<p>Index {myIndex}: This is the first section.</p>
|
||||
</div>
|
||||
<div class="step-foreground-container flex items-center justify-center">
|
||||
<p>Index {myIndex}: This is the second section.</p>
|
||||
</div>
|
||||
<div class="step-foreground-container flex items-center justify-center">
|
||||
<p>Index {myIndex}: This is the third section.</p>
|
||||
</div>
|
||||
{/snippet}
|
||||
</SvelteScroller>
|
||||
```
|
||||
|
||||
## Custom foreground with ArchieML
|
||||
To add your own styling, you can write styles in a global SCSS stylesheet:
|
||||
|
||||
[Demo](?path=/story/components-graphics-scroller--customforeground-archie-ml)
|
||||
```scss
|
||||
// global.scss
|
||||
.custom-background {
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
You can use custom foreground components with ArchieML with a few additional steps.
|
||||
.step-foreground-container {
|
||||
height: 100vh;
|
||||
p {
|
||||
padding: 1em;
|
||||
background-color: rgba(162, 220, 231, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
In your graphics kit project's `App.svelte`, import your custom foregroud components and add them to a `foregroundComponents` object, just as you import ai2svelte background graphics and add them to the `aiCharts` object:
|
||||
|
||||
```svelte
|
||||
<!-- App.svelte -->
|
||||
<script>
|
||||
import content from '$locales/en/content.json';
|
||||
|
||||
// Background ai2svelte graphics
|
||||
import AiMap1 from './ai2svelte/my-map-1.svelte';
|
||||
import AiMap2 from './ai2svelte/my-map-2.svelte';
|
||||
import AiMap3 from './ai2svelte/my-map-3.svelte';
|
||||
|
||||
// Foreground components, which can be ai2svelte or not.
|
||||
import Foreground1 from './ai2svelte/my-foreground-1.svelte';
|
||||
|
||||
// Graphics kit only
|
||||
import { assets } from '$app/paths'; // 👈 If using in the graphics kit...
|
||||
import { truthy } from '$utils/propValidators'; // 👈 If using in the graphics kit...
|
||||
|
||||
// Background ai2svelte graphics components
|
||||
const aiCharts = {
|
||||
AiMap1,
|
||||
AiMap2,
|
||||
AiMap3,
|
||||
// Other charts...
|
||||
};
|
||||
|
||||
// Foreground components
|
||||
const foregroundComponents = {
|
||||
Foreground1,
|
||||
// Other components...
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
Then add the following structure to your ArchieML Doc, making sure that the names of your charts in the `aiCharts` and `foregroundComponents` objects match the names of each step's `background` and `foreground` in the ArchieML doc:
|
||||
|
||||
```yaml
|
||||
# ArchieML doc
|
||||
[blocks]
|
||||
type: ai-scroller
|
||||
id: my-map-scroller
|
||||
foregroundPosition: left
|
||||
stackBackground: true
|
||||
|
||||
# Array of step objects
|
||||
[.steps]
|
||||
background: AiMap1
|
||||
# You can still use a markdown string even if other step/s use a custom foreground component
|
||||
foreground: #### Step 1
|
||||
|
||||
Here's where something happend.
|
||||
:end
|
||||
altText: A map showing the Upper West side in New York City.
|
||||
:end
|
||||
|
||||
background: AiMap2
|
||||
foreground: Foreground1 # The name of your custom foreground component
|
||||
altText: The same map now highlights 98th Street.
|
||||
:end
|
||||
background: AiMap3
|
||||
foreground: #### Step 3
|
||||
|
||||
... and now there are multiple protests.
|
||||
:end
|
||||
altText: The same map now highlights three locations near 98th Street where something particulary important happened.
|
||||
:end
|
||||
[]
|
||||
[]
|
||||
```
|
||||
|
||||
Then parse the relevant ArchieML block object before passing to the `Scroller` component.
|
||||
|
||||
```svelte
|
||||
<!-- App.svelte -->
|
||||
{#each content.blocks as block}
|
||||
{#if block.type === 'ai-scroller'}
|
||||
<Scroller
|
||||
id={block.id}
|
||||
backgroundWidth={block.width}
|
||||
foregroundPosition={block.foregroundPosition}
|
||||
stackBackground={truthy(block.stackBackground)}
|
||||
steps={block.steps.map((step) => ({
|
||||
background: aiCharts[step.background],
|
||||
backgroundProps: { assetsPath: assets || '/' },
|
||||
foreground: foregroundComponents[step.foreground] || step.foreground,
|
||||
foregroundProps: { assetsPath: assets || '/' },
|
||||
altText: step.altText,
|
||||
}))}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
```
|
||||
|
||||
> **Note:** You only need to pass `foregroundProps: { assetsPath: assets || '/' }` in the graphics kit if your foreground components are ai2svelte graphicss.
|
||||
|
|
|
|||
|
|
@ -5,155 +5,54 @@
|
|||
const { Story } = defineMeta({
|
||||
title: 'Components/Graphics/SvelteScroller',
|
||||
component: SvelteScroller,
|
||||
argTypes: {
|
||||
steps: { control: false },
|
||||
backgroundWidth: {
|
||||
control: 'select',
|
||||
options: ['normal', 'wide', 'wider', 'widest', 'fluid'],
|
||||
},
|
||||
foregroundPosition: {
|
||||
control: 'select',
|
||||
options: ['middle', 'left', 'right', 'left opposite', 'right opposite'],
|
||||
},
|
||||
embeddedLayout: {
|
||||
control: 'select',
|
||||
options: ['fb', 'bf'],
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import MyBackground from './demo/components/basic/Step.svelte';
|
||||
import MyInteractiveForeground from './demo/components/basic/InteractiveForeground.svelte';
|
||||
|
||||
// ai2svelte backgrounds
|
||||
import AiMap1 from './demo/components/ai2svelte/ai-scroller-1.svelte';
|
||||
import AiMap2 from './demo/components/ai2svelte/ai-scroller-2.svelte';
|
||||
import AiMap3 from './demo/components/ai2svelte/ai-scroller-3.svelte';
|
||||
|
||||
// ai2svelte foreground
|
||||
import AiForeground from './demo/components/ai2svelte/ai-foreground.svelte';
|
||||
|
||||
const aiCharts = {
|
||||
AiMap1,
|
||||
AiMap2,
|
||||
AiMap3,
|
||||
};
|
||||
|
||||
const foregroundComponents = {
|
||||
AiForeground,
|
||||
};
|
||||
|
||||
const docBlock = {
|
||||
foregroundPosition: 'right',
|
||||
id: 'my-scroller',
|
||||
stackBackground: 'true',
|
||||
steps: [
|
||||
{
|
||||
background: aiCharts.AiMap1,
|
||||
foreground: "#### Step 1\n\nHere's where something happend.",
|
||||
altText: 'A map showing the Upper West side in New York City.',
|
||||
},
|
||||
{
|
||||
background: aiCharts.AiMap2,
|
||||
foreground: '#### Step 2\n\nSomething happened on some street...',
|
||||
altText: 'The same map now highlights 98th Street.',
|
||||
},
|
||||
{
|
||||
background: aiCharts.AiMap3,
|
||||
foreground: '#### Step 3\n\n... and now there are multiple protests.',
|
||||
altText:
|
||||
'The same map now highlights three locations near 98th Street where something particulary important happened.',
|
||||
},
|
||||
],
|
||||
} as const;
|
||||
|
||||
const docBlockCustomForeground = {
|
||||
foregroundPosition: 'left',
|
||||
id: 'my-scroller',
|
||||
stackBackground: 'true',
|
||||
steps: [
|
||||
{
|
||||
background: aiCharts.AiMap1,
|
||||
foreground: "#### Step 1\n\nHere's where something happend.",
|
||||
altText: 'A map showing the Upper West side in New York City.',
|
||||
},
|
||||
{
|
||||
background: aiCharts.AiMap2,
|
||||
foreground: foregroundComponents.AiForeground,
|
||||
altText: 'The same map now highlights 98th Street.',
|
||||
},
|
||||
{
|
||||
background: aiCharts.AiMap3,
|
||||
foreground: '#### Step 3\n\n... and now there are multiple protests.',
|
||||
altText:
|
||||
'The same map now highlights three locations near 98th Street where something particulary important happened.',
|
||||
},
|
||||
],
|
||||
} as const;
|
||||
let myIndex = $state(0);
|
||||
let myProgress = $state(0);
|
||||
</script>
|
||||
|
||||
<Story name="Demo">
|
||||
<SvelteScroller>
|
||||
{#snippet backgroundSnippet(index)}
|
||||
<SvelteScroller
|
||||
bind:index={myIndex}
|
||||
bind:progress={myProgress}
|
||||
query="div.step-foreground-container"
|
||||
>
|
||||
{#snippet backgroundSnippet()}
|
||||
<div class="custom-background">
|
||||
<p>
|
||||
This is the background content. It will stay fixed in place while the
|
||||
foreground scrolls over the top.
|
||||
</p>
|
||||
|
||||
<p>Section {index + 1} is currently active.</p>
|
||||
</div>
|
||||
{/snippet}
|
||||
{#snippet foregroundSnippet(index)}
|
||||
<div class="foreground">Index {index}: This is the first section.</div>
|
||||
<div class="foreground">Index {index}: This is the second section.</div>
|
||||
<div class="foreground">Index {index}: This is the third section.</div>
|
||||
{#snippet foregroundSnippet()}
|
||||
<div class="step-foreground-container flex items-center justify-center">
|
||||
<p>Index {myIndex}: This is the first section.</p>
|
||||
</div>
|
||||
<div class="step-foreground-container flex items-center justify-center">
|
||||
<p>Index {myIndex}: This is the second section.</p>
|
||||
</div>
|
||||
<div class="step-foreground-container flex items-center justify-center">
|
||||
<p>Index {myIndex}: This is the third section.</p>
|
||||
</div>
|
||||
{/snippet}
|
||||
</SvelteScroller>
|
||||
</Story>
|
||||
|
||||
<!--
|
||||
<Story name="ArchieML and ai2svelte" exportName="ArchieML">
|
||||
<SvelteScroller
|
||||
id={docBlock.id}
|
||||
foregroundPosition={docBlock.foregroundPosition}
|
||||
stackBackground={docBlock.stackBackground === 'true'}
|
||||
steps={docBlock.steps.map((step) => ({
|
||||
background: step.background,
|
||||
foreground: step.foreground,
|
||||
altText: step.altText,
|
||||
}))}
|
||||
/>
|
||||
</Story> -->
|
||||
|
||||
<!-- <Story
|
||||
name="Custom foreground with ArchiemL"
|
||||
exportName="CustomforegroundArchieML"
|
||||
>
|
||||
<SvelteScroller
|
||||
id={docBlockCustomForeground.id}
|
||||
foregroundPosition={docBlockCustomForeground.foregroundPosition}
|
||||
stackBackground={docBlockCustomForeground.stackBackground === 'true'}
|
||||
steps={docBlockCustomForeground.steps.map((step) => ({
|
||||
background: step.background,
|
||||
foreground: step.foreground,
|
||||
altText: step.altText,
|
||||
}))}
|
||||
/>
|
||||
</Story> -->
|
||||
<style lang="scss">
|
||||
.custom-background {
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
height: 100vh;
|
||||
}
|
||||
.foreground {
|
||||
height: 80vh;
|
||||
background-color: rgba(0, 0, 0, 0.5);
|
||||
color: white;
|
||||
padding: 1em;
|
||||
margin: 0 0 2em 0;
|
||||
|
||||
.step-foreground-container {
|
||||
height: 100vh;
|
||||
p {
|
||||
padding: 1em;
|
||||
background-color: rgba(162, 220, 231, 0.5);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@
|
|||
top = 0,
|
||||
bottom = 1,
|
||||
threshold = 0.5,
|
||||
query = 'section',
|
||||
query = 'div.step-foreground-container',
|
||||
parallax = false,
|
||||
backgroundSnippet,
|
||||
foregroundSnippet,
|
||||
|
|
@ -211,7 +211,7 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<svelte:window bind:setinnerHeight={wh} />
|
||||
<svelte:window bind:innerHeight={wh} />
|
||||
|
||||
<svelte-scroller-outer bind:this={outer}>
|
||||
<svelte-scroller-background-container
|
||||
|
|
@ -219,12 +219,12 @@
|
|||
style="{style}{widthStyle}"
|
||||
>
|
||||
<svelte-scroller-background bind:this={background}>
|
||||
{@render backgroundSnippet(index)}
|
||||
{@render backgroundSnippet()}
|
||||
</svelte-scroller-background>
|
||||
</svelte-scroller-background-container>
|
||||
|
||||
<svelte-scroller-foreground bind:this={foreground}>
|
||||
{@render foregroundSnippet(index)}
|
||||
{@render foregroundSnippet()}
|
||||
</svelte-scroller-foreground>
|
||||
</svelte-scroller-outer>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue