Merge pull request #243 from reuters-graphics/mf-photo
Updates FeaturePhoto
This commit is contained in:
commit
6c854957e4
7 changed files with 159 additions and 158 deletions
72
src/components/FeaturePhoto/FeaturePhoto.mdx
Normal file
72
src/components/FeaturePhoto/FeaturePhoto.mdx
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
import { Meta, Canvas } from '@storybook/blocks';
|
||||
|
||||
import * as FeaturePhotoStories from './FeaturePhoto.stories.svelte';
|
||||
|
||||
<Meta of={FeaturePhotoStories} />
|
||||
|
||||
# FeaturePhoto
|
||||
|
||||
The `FeaturePhoto` component adds a full-width photo.
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
import { FeaturePhoto } from '@reuters-graphics/graphics-components';
|
||||
import { assets } from '$app/paths'; // 👈 If using in the Graphics Kit...
|
||||
</script>
|
||||
|
||||
<FeaturePhoto
|
||||
src={`${assets}/images/myImage.jpg`}
|
||||
altText="Some alt text"
|
||||
caption="A caption"
|
||||
/>
|
||||
```
|
||||
|
||||
<Canvas of={FeaturePhotoStories.Demo} />
|
||||
|
||||
## Using with ArchieML docs
|
||||
|
||||
With the Graphics Kit, you'll likely get your text value from an ArchieML doc...
|
||||
|
||||
```yaml
|
||||
# ArchieML doc
|
||||
[blocks]
|
||||
|
||||
type: photo
|
||||
width: normal
|
||||
src: images/shark.jpg
|
||||
altText: The king of the sea
|
||||
caption: Carcharodon carcharias - REUTERS
|
||||
|
||||
[]
|
||||
```
|
||||
|
||||
... which you'll parse out of a ArchieML block object before passing to the `FeaturePhoto` component.
|
||||
|
||||
```svelte
|
||||
<!-- App.svelte -->
|
||||
<script>
|
||||
import { FeaturePhoto } from '@reuters-graphics/graphics-components';
|
||||
|
||||
import content from '$locales/en/content.json';
|
||||
import { assets } from '$app/paths';
|
||||
</script>
|
||||
|
||||
{#each content.blocks as block}
|
||||
{#if block.Type === 'text'}
|
||||
<!-- ... -->
|
||||
{:else if block.type === 'photo'}
|
||||
<FeaturePhoto
|
||||
width={block.width}
|
||||
src={`${assets}/${block.src}`}
|
||||
altText={block.altText}
|
||||
caption={block.caption}
|
||||
/>
|
||||
{/if}
|
||||
{/each}
|
||||
```
|
||||
|
||||
## Missing alt text
|
||||
|
||||
`altText` is required in this component. If your photo is missing it, a small red text box will overlay the image.
|
||||
|
||||
<Canvas of={FeaturePhotoStories.MissingAltText} />
|
||||
|
|
@ -1,26 +1,10 @@
|
|||
<script module lang="ts">
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
|
||||
// @ts-ignore raw
|
||||
import componentDocs from './stories/docs/component.md?raw';
|
||||
// @ts-ignore raw
|
||||
import archieMLDocs from './stories/docs/archieML.md?raw';
|
||||
// @ts-ignore raw
|
||||
import missingAltTextDocs from './stories/docs/missingAltText.md?raw';
|
||||
|
||||
import { defineMeta } from '@storybook/addon-svelte-csf';
|
||||
import FeaturePhoto from './FeaturePhoto.svelte';
|
||||
|
||||
// import {
|
||||
// withComponentDocs,
|
||||
// withStoryDocs,
|
||||
// } from '$lib/docs/utils/withParams.js';
|
||||
|
||||
|
||||
const { Story } = defineMeta({
|
||||
title: 'Components/Multimedia/FeaturePhoto',
|
||||
component: FeaturePhoto,
|
||||
// ...withComponentDocs(componentDocs),
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
width: {
|
||||
control: 'select',
|
||||
|
|
@ -35,38 +19,23 @@
|
|||
</script>
|
||||
|
||||
<script>
|
||||
// @ts-ignore jpg
|
||||
import sharkSrc from './stories/shark.jpg';
|
||||
import sharkSrc from './images/shark.jpg';
|
||||
</script>
|
||||
|
||||
|
||||
<Story
|
||||
name="Default"
|
||||
args="{{
|
||||
name="Demo"
|
||||
args={{
|
||||
src: sharkSrc,
|
||||
altText: 'A shark!',
|
||||
width: 'normal',
|
||||
caption: 'Carcharodon carcharias - REUTERS',
|
||||
}}"
|
||||
}}
|
||||
/>
|
||||
|
||||
<Story
|
||||
name="ArchieML"
|
||||
args="{{
|
||||
src: sharkSrc,
|
||||
altText: 'A shark!',
|
||||
width: 'normal',
|
||||
caption: 'Carcharodon carcharias - REUTERS',
|
||||
}}"
|
||||
/>
|
||||
<!-- {...withStoryDocs(archieMLDocs)} -->
|
||||
|
||||
<Story
|
||||
name="Missing altText"
|
||||
args="{{
|
||||
exportName="MissingAltText"
|
||||
args={{
|
||||
src: sharkSrc,
|
||||
width: 'normal',
|
||||
caption: 'Carcharodon carcharias - REUTERS',
|
||||
}}"
|
||||
}}
|
||||
/>
|
||||
<!-- {...withStoryDocs(missingAltTextDocs)} -->
|
||||
|
|
|
|||
|
|
@ -1,75 +1,89 @@
|
|||
<!-- @migration-task Error while migrating Svelte code: Cannot set properties of undefined (setting 'next') -->
|
||||
<!-- @component `FeaturePhoto` [Read the docs.](https://reuters-graphics.github.io/graphics-components/?path=/docs/components-multimedia-featurephoto--docs) -->
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import Block from '../Block/Block.svelte';
|
||||
import type { ContainerWidth } from '../@types/global';
|
||||
|
||||
import Block from '../Block/Block.svelte';
|
||||
import PaddingReset from '../PaddingReset/PaddingReset.svelte';
|
||||
|
||||
/**
|
||||
* Photo src
|
||||
* @type {string}
|
||||
* @required
|
||||
*/
|
||||
export let src: string;
|
||||
/**
|
||||
* Photo altText
|
||||
* @type {string}
|
||||
* @required
|
||||
*/
|
||||
export let altText: string;
|
||||
/**
|
||||
* Add an id 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 };
|
||||
/**
|
||||
* Caption below the photo
|
||||
* @type {string}
|
||||
*/
|
||||
export let caption: string;
|
||||
/**
|
||||
* Height of the photo placeholder when lazy-loading
|
||||
*/
|
||||
export let height: number = 100;
|
||||
/**
|
||||
* Width of the container, one of: normal, wide, wider, widest or fluid
|
||||
*/
|
||||
export let width: ContainerWidth = 'normal';
|
||||
interface Props {
|
||||
/**
|
||||
* Photo source
|
||||
*/
|
||||
src: string;
|
||||
/**
|
||||
* Photo altText
|
||||
*/
|
||||
altText: string;
|
||||
/**
|
||||
* Add an id to target with custom CSS.
|
||||
*/
|
||||
id?: string;
|
||||
/**
|
||||
* Add classes to target with custom CSS.
|
||||
*/
|
||||
class?: string;
|
||||
/**
|
||||
* Photo caption
|
||||
*/
|
||||
caption?: string;
|
||||
/**
|
||||
* Height of the photo placeholder when lazy-loading
|
||||
*/
|
||||
height?: number;
|
||||
/**
|
||||
* Width of the container: normal, wide, wider, widest or fluid
|
||||
*/
|
||||
width?: ContainerWidth;
|
||||
/**
|
||||
* Set a different width for the text vs the photo. For example, "normal" to keep the title, description and notes inline with the rest of the text well. Can't ever be wider than `width`.
|
||||
*/
|
||||
textWidth?: ContainerWidth;
|
||||
/**
|
||||
* Whether to lazy load the photo using the [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API)
|
||||
*/
|
||||
lazy?: boolean;
|
||||
/**
|
||||
* Set Intersection Observer [rootMargin](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#rootmargin) `top` when lazy loading.
|
||||
*/
|
||||
top?: number;
|
||||
/**
|
||||
* Set Intersection Observer [rootMargin](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#rootmargin) `bottom` when lazy loading.
|
||||
*/
|
||||
bottom?: number;
|
||||
/**
|
||||
* Set Intersection Observer [rootMargin](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#rootmargin) `left` when lazy loading.
|
||||
*/
|
||||
left?: number;
|
||||
/**
|
||||
* Set Intersection Observer [rootMargin](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#rootmargin) `right` when lazy loading.
|
||||
*/
|
||||
right?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a different width for the text within the text well, for example,
|
||||
* "normal" to keep the title, description and notes inline with the rest
|
||||
* of the text well. Can't ever be wider than `width`.
|
||||
* @type {string}
|
||||
*/
|
||||
export let textWidth: ContainerWidth | null = 'normal';
|
||||
let {
|
||||
src,
|
||||
altText,
|
||||
id = '',
|
||||
class: cls = '',
|
||||
caption,
|
||||
height = 100,
|
||||
width = 'normal',
|
||||
textWidth = 'normal',
|
||||
lazy = true,
|
||||
top = 0,
|
||||
bottom = 0,
|
||||
left = 0,
|
||||
right = 0,
|
||||
}: Props = $props();
|
||||
|
||||
/**
|
||||
* Whether to lazy load the photo using the [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API)
|
||||
*/
|
||||
export let lazy: boolean = false;
|
||||
/** Set Intersection Observer [rootMargin](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#rootmargin) `top` when lazy loading. */
|
||||
export let top = 0;
|
||||
/** Set Intersection Observer [rootMargin](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#rootmargin) `bottom` when lazy loading. */
|
||||
export let bottom = 0;
|
||||
/** Set Intersection Observer [rootMargin](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#rootmargin) `left` when lazy loading. */
|
||||
export let left = 0;
|
||||
/** Set Intersection Observer [rootMargin](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#rootmargin) `right` when lazy loading. */
|
||||
export let right = 0;
|
||||
|
||||
let intersecting = false;
|
||||
let container;
|
||||
let intersecting = $state(false);
|
||||
let container: HTMLElement;
|
||||
const intersectable = typeof IntersectionObserver !== 'undefined';
|
||||
|
||||
onMount(() => {
|
||||
if (!lazy) return;
|
||||
|
||||
if (intersectable) {
|
||||
const rootMargin = `${bottom}px ${left}px ${top}px ${right}px`;
|
||||
|
||||
|
|
@ -93,18 +107,18 @@
|
|||
|
||||
<Block {width} class="photo fmy-6 {cls}" {id}>
|
||||
<figure
|
||||
bind:this="{container}"
|
||||
bind:this={container}
|
||||
aria-label="media"
|
||||
class="w-full flex flex-col relative"
|
||||
>
|
||||
{#if !lazy || (intersectable && intersecting)}
|
||||
<img class="w-full my-0" {src} alt="{altText}" />
|
||||
<img class="w-full my-0" {src} alt={altText} />
|
||||
{:else}
|
||||
<div class="placeholder w-full" style="{`height: ${height}px;`}"></div>
|
||||
<div class="placeholder w-full" style={`height: ${height}px;`}></div>
|
||||
{/if}
|
||||
{#if caption}
|
||||
<PaddingReset containerIsFluid="{width === 'fluid'}">
|
||||
<Block width="{textWidth}" class="notes w-full fmy-0">
|
||||
<PaddingReset containerIsFluid={width === 'fluid'}>
|
||||
<Block width={textWidth} class="notes w-full fmy-0">
|
||||
<figcaption>
|
||||
{caption}
|
||||
</figcaption>
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 103 KiB After Width: | Height: | Size: 103 KiB |
|
|
@ -1,37 +0,0 @@
|
|||
```yaml
|
||||
[blocks]
|
||||
|
||||
type: photo
|
||||
width: normal
|
||||
src: images/shark.jpg
|
||||
altText: The king of the sea
|
||||
caption: Carcharodon carcharias - REUTERS
|
||||
|
||||
[]
|
||||
```
|
||||
|
||||
```svelte
|
||||
<!-- App.svelte -->
|
||||
<script>
|
||||
import { FeaturePhoto } from '@reuters-graphics/graphics-components';
|
||||
|
||||
import content from '$locales/en/content.json';
|
||||
import { assets } from '$app/paths';
|
||||
</script>
|
||||
|
||||
{#each content.blocks as block}
|
||||
{#if block.Type === 'text'}
|
||||
<!-- ... -->
|
||||
|
||||
{:else if block.type === 'photo'}
|
||||
<FeaturePhoto
|
||||
width="{block.width}"
|
||||
src="{`${assets}/${block.src}`}"
|
||||
altText="{block.altText}"
|
||||
caption="{block.caption}"
|
||||
/>
|
||||
|
||||
<!-- ... -->
|
||||
{/if}
|
||||
{/each}
|
||||
```
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
A full-width photo inside the text well.
|
||||
|
||||
```svelte
|
||||
<script>
|
||||
import { FeaturePhoto } from '@reuters-graphics/graphics-components';
|
||||
import { assets } from '$app/paths'; // 👈 If using in the Graphics Kit...
|
||||
</script>
|
||||
|
||||
<FeaturePhoto
|
||||
src="{`${assets}/images/myImage.jpg`}"
|
||||
altText="Some alt text"
|
||||
caption="A caption"
|
||||
lazy="{false}"
|
||||
width="normal"
|
||||
/>
|
||||
```
|
||||
|
|
@ -1 +0,0 @@
|
|||
If your photo is missing `altText` a small warning will overlay the image.
|
||||
Loading…
Reference in a new issue