adds headpile

This commit is contained in:
hobbes7878 2025-05-20 17:55:06 +01:00
parent c1da24da0c
commit f64ec229bf
Failed to extract signature
8 changed files with 316 additions and 0 deletions

View file

@ -0,0 +1,37 @@
import { Meta, Canvas } from '@storybook/blocks';
import * as HeadpileStories from './Headpile.stories.svelte';
<Meta of={HeadpileStories} />
# Headpile
The `Headpile` component is a headshot-bulleted list of people, identifying them with their names, roles and a short description of their significance to a story.
It's designed to be used with headshots that have had their background removed, which can be done in the [Preview app](https://support.apple.com/en-gb/guide/preview/prvw15636/mac?#apd320b3b1b750a4) on macOS.
```svelte
<script>
import { Headpile } from '@reuters-graphics/graphics-components';
import { assets } from '$app/paths'; // 👈 If using in the graphics kit...
</script>
<Headpile
figures={[
{
img: `${assets}/images/person-A.jpg`,
name: 'General Abdel Fattah al-Burhan',
role: "Sudan's Sovereign Council Chief and military commander",
text: 'Burhan was little known in public life until taking part in the coup ...',
},
{
img: `${assets}/images/person-B.jpg`,
name: 'General Mohamed Hamdan Dagalo',
role: 'Leader of the Sudanese paramilitary Rapid Support Forces (RSF)',
text: 'Popularly known as Hemedti, Dagalo rose from lowly beginnings ...',
},
]}
/>
```
<Canvas of={HeadpileStories.Demo} />

View file

@ -0,0 +1,37 @@
<script module lang="ts">
import { defineMeta } from '@storybook/addon-svelte-csf';
import Headpile from './Headpile.svelte';
import hed1 from './images/abdel.png';
import hed2 from './images/hemedti.png';
const { Story } = defineMeta({
title: 'Components/Text elements/Headpile',
component: Headpile,
argTypes: {},
});
const defaultArgs = [
{
name: 'General Abdel Fattah al-Burhan',
role: "Sudan's Sovereign Council Chief and military commander",
img: hed1,
text: 'Burhan was little known in public life until taking part in the coup against Bashir in 2019 after a popular uprising against his rule. In August 2019, his role as de facto head of state was affirmed when he became head of the Sovereign Council, a body comprising civilian and military leaders formed to oversee the transition towards elections.',
// colour: '#957caa',
},
{
name: 'General Mohamed Hamdan Dagalo',
role: 'Leader of the Sudanese paramilitary Rapid Support Forces (RSF)',
img: hed2,
text: "Popularly known as Hemedti, Dagalo rose from lowly beginnings as a camel trader to head a widely feared Arab militia that crushed a revolt in Darfur, winning him influence and eventually a role as Sudan's former deputy head of state.\r\n\r\nOver the past decade, he has been a key figure in Sudanese politics, aiding in the ousting of Bashir in 2019 and suppressing pro-democracy protests. As the country limped from one economic crisis to another, Hemedti became one of Sudans richest men, exporting gold from mines in Darfur seized by his fighters.",
colour: '#afb776',
},
];
</script>
<Story
name="Demo"
args={{
figures: defaultArgs,
}}
/>

View file

@ -0,0 +1,86 @@
<script lang="ts">
import type { ContainerWidth } from '../@types/global';
import Block from '../Block/Block.svelte';
import KeyFigure from './KeyFigure.svelte';
interface Props {
/**
* Add classes to target with custom CSS.
*/
class: string;
/**
* Add an id to target with custom CSS.
*/
id: string;
/**
* Width of the container.
*/
width: Extract<ContainerWidth, 'normal' | 'wide'>;
/**
* Default background colour to be used as a mount behind the headshot.
*/
colour: string;
/**
* Individual figures -- i.e., people -- for the headpile.
*/
figures: {
/**
* Headshot image src. Be sure to prefix the image
*
* ```typescript
* import { assets } from '$app/paths';
*
* const imgSrc = `${assets}/images/my-image.jpg`;
* ```
*/
img: string;
/**
* Figure name.
*/
name: string;
/**
* Figure role or title.
*/
role?: string;
/**
* Text describing the person.
*/
text: string;
/**
* Background colour to be used as a mount behind the headshot.
*/
colour?: string;
}[];
}
let {
figures,
class: cls,
id,
width = 'normal',
colour = '#cccccc',
}: Props = $props();
</script>
<Block class={cls} {id} {width}>
<div class="figures">
{#each figures as figure}
<KeyFigure {...{ ...figure, colour: figure.colour ?? colour }} />
{/each}
</div>
</Block>
<style lang="scss">
@use '../../scss/mixins' as mixins;
div.figures {
display: flex;
flex-direction: column;
gap: 40px;
@include mixins.fpt-4;
@media (max-width: 600px) {
gap: 0px;
padding-block-start: 0;
}
}
</style>

View file

@ -0,0 +1,41 @@
<script lang="ts">
let { img = '', colour = 'var(--theme-colour-accent)' } = $props();
</script>
<div class="headshot-wrapper">
<div class="background" style="background-color: {colour};"></div>
<div class="headshot" style="background-image: url({img}); "></div>
</div>
<style lang="scss">
.headshot-wrapper {
width: 100px;
height: 120px;
position: relative;
margin-top: -46px;
margin-bottom: -46px;
border-radius: 4px;
overflow: hidden;
}
.background {
position: absolute;
bottom: 0;
left: 0;
width: 100px;
height: 70px;
display: inline-block;
border-radius: 4px;
}
.headshot {
display: inline-block;
width: 100%;
height: 100%;
background-size: 106%;
background-position: center bottom;
background-repeat: no-repeat;
position: absolute;
bottom: 0;
left: 0;
overflow: hidden;
}
</style>

View file

@ -0,0 +1,114 @@
<script lang="ts">
import { Markdown } from '@reuters-graphics/svelte-markdown';
import Headshot from './Headshot.svelte';
import { MediaQuery } from 'svelte/reactivity';
interface Props {
img: string;
name: string;
role?: string;
text: string;
colour?: string;
}
let { name, role, img, text, colour }: Props = $props();
const mobile = new MediaQuery('max-width: 600px');
</script>
<div>
<div class="wrapper-profile">
<div>
<Headshot {img} {colour} />
</div>
<div class="text">
<div class="title">{name}</div>
<div class="role">{role || ''}</div>
{#if !mobile.current}
<div class="description desktop">
<Markdown source={text} />
</div>
{/if}
</div>
</div>
{#if mobile.current}
<div class="description mobile">
<Markdown source={text} />
</div>
{/if}
</div>
<style lang="scss">
@use '../../scss/mixins' as mixins;
.wrapper-profile {
display: flex;
align-items: flex-start;
justify-content: start;
gap: 20px;
width: 100%;
min-height: 100px;
@media (max-width: 600px) {
align-items: center;
margin-bottom: 10px;
.text {
flex-grow: 1;
margin-top: 20px;
}
}
}
.title {
@include mixins.font-bold;
@include mixins.text-base;
line-height: 1.125;
}
.role {
border-top: 1px solid #dedede;
margin-top: 5px;
padding-top: 5px;
margin-left: -10px;
padding-left: 10px;
@include mixins.fmb-2;
@include mixins.font-note;
@include mixins.text-sm;
@include mixins.text-secondary;
font-weight: 300;
line-height: 1.25;
@media (max-width: 600px) {
margin-left: 0px;
padding-left: 0;
@include mixins.fmb-4;
}
}
.description {
@include mixins.fmb-3;
:global(p) {
@include mixins.font-note;
font-size: calc(0.925 * var(--theme-font-size-base, 1rem));
font-weight: 300;
}
&.desktop {
display: block;
}
&.mobile {
display: none;
@include mixins.fmt-2;
}
@media (max-width: 600px) {
&.desktop {
display: none;
}
&.mobile {
display: block;
}
}
}
.text {
margin-bottom: -20px;
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 407 KiB

View file

@ -20,6 +20,7 @@ export { default as FeaturePhoto } from './components/FeaturePhoto/FeaturePhoto.
export { default as Framer } from './components/Framer/Framer.svelte';
export { default as GraphicBlock } from './components/GraphicBlock/GraphicBlock.svelte';
export { default as Headline } from './components/Headline/Headline.svelte';
export { default as Headpile } from './components/Headpile/Headpile.svelte';
export { default as HeroHeadline } from './components/HeroHeadline/HeroHeadline.svelte';
export { default as EndNotes } from './components/EndNotes/EndNotes.svelte';
export { default as InfoBox } from './components/InfoBox/InfoBox.svelte';