Width and formatting.

This commit is contained in:
wires 2026-05-09 20:40:36 -04:00
parent ac1c2ea8d1
commit 024857de84
10 changed files with 188 additions and 21 deletions

View file

@ -1 +1,4 @@
doodly fuck # Scratch
## (And the starting over thereof)
We'll build this by hand, one part at a time.

View file

@ -13,6 +13,7 @@
}, },
"dependencies": { "dependencies": {
"@astrojs/svelte": "^8.1.0", "@astrojs/svelte": "^8.1.0",
"@reuters-graphics/svelte-markdown": "^0.0.3",
"@rferl/veronica": "github:rferl/veronica", "@rferl/veronica": "github:rferl/veronica",
"astro": "^6.3.1", "astro": "^6.3.1",
"svelte": "^5.55.5", "svelte": "^5.55.5",

View file

@ -11,6 +11,9 @@ importers:
'@astrojs/svelte': '@astrojs/svelte':
specifier: ^8.1.0 specifier: ^8.1.0
version: 8.1.0(astro@6.3.1(rollup@4.60.3)(sass-embedded@1.99.0)(sass@1.99.0))(sass-embedded@1.99.0)(sass@1.99.0)(svelte@5.55.5)(typescript@5.9.3) version: 8.1.0(astro@6.3.1(rollup@4.60.3)(sass-embedded@1.99.0)(sass@1.99.0))(sass-embedded@1.99.0)(sass@1.99.0)(svelte@5.55.5)(typescript@5.9.3)
'@reuters-graphics/svelte-markdown':
specifier: ^0.0.3
version: 0.0.3(svelte@5.55.5)
'@rferl/veronica': '@rferl/veronica':
specifier: github:rferl/veronica specifier: github:rferl/veronica
version: https://codeload.github.com/rferl/veronica/tar.gz/6935ec341ba7dce2a839f045deaba4783f4e8afc version: https://codeload.github.com/rferl/veronica/tar.gz/6935ec341ba7dce2a839f045deaba4783f4e8afc
@ -506,6 +509,11 @@ packages:
resolution: {integrity: sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==} resolution: {integrity: sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==}
engines: {node: '>= 10.0.0'} engines: {node: '>= 10.0.0'}
'@reuters-graphics/svelte-markdown@0.0.3':
resolution: {integrity: sha512-K3DWKjm1XZxnwua+Vz9c7BRFrkFVWpVU+DnMKBPu3eadhCpT09Z0y+1MhJgs/573h4BpraZFuUVCl1h4XUxd1Q==}
peerDependencies:
svelte: ^5.0.0
'@rferl/veronica@https://codeload.github.com/rferl/veronica/tar.gz/6935ec341ba7dce2a839f045deaba4783f4e8afc': '@rferl/veronica@https://codeload.github.com/rferl/veronica/tar.gz/6935ec341ba7dce2a839f045deaba4783f4e8afc':
resolution: {gitHosted: true, integrity: sha512-xkeBP1Te2lwj1/9Nstbz6GmaTuAudZ35SGBm5ZUUaobBTeuTxcstHw491d+bTbbewgRY3P652tQJsx8hP+Q3KA==, tarball: https://codeload.github.com/rferl/veronica/tar.gz/6935ec341ba7dce2a839f045deaba4783f4e8afc} resolution: {gitHosted: true, integrity: sha512-xkeBP1Te2lwj1/9Nstbz6GmaTuAudZ35SGBm5ZUUaobBTeuTxcstHw491d+bTbbewgRY3P652tQJsx8hP+Q3KA==, tarball: https://codeload.github.com/rferl/veronica/tar.gz/6935ec341ba7dce2a839f045deaba4783f4e8afc}
version: 1.0.0 version: 1.0.0
@ -918,6 +926,9 @@ packages:
es-module-lexer@2.1.0: es-module-lexer@2.1.0:
resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==} resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==}
es-toolkit@1.46.1:
resolution: {integrity: sha512-5eNtXOs3tbfxXOj04tjjseeWkRWaoCjdEI+96DgwzZoe6c9juL49pXlzAFTI72aWC9Y8p7168g6XIKjh7k6pyQ==}
esbuild@0.27.7: esbuild@0.27.7:
resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==}
engines: {node: '>=18'} engines: {node: '>=18'}
@ -1100,6 +1111,16 @@ packages:
markdown-table@3.0.4: markdown-table@3.0.4:
resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==}
marked-smartypants@1.1.12:
resolution: {integrity: sha512-Z0QL2GpihbSeG5aaCrQxMEoqvngMftF/gq1SrdlCnbecUSrX3HYgPtCZzCW+OyNe2ideQqaFdxfGryqQX1MBDA==}
peerDependencies:
marked: '>=4 <19'
marked@15.0.12:
resolution: {integrity: sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA==}
engines: {node: '>= 18'}
hasBin: true
mdast-util-definitions@6.0.0: mdast-util-definitions@6.0.0:
resolution: {integrity: sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==} resolution: {integrity: sha512-scTllyX6pnYNZH/AIp/0ePz6s4cZtARxImwoPJ7kS42n+MnVsI4XbnG6d4ibehRIldYMWM2LD7ImQblVhUejVQ==}
@ -1541,6 +1562,10 @@ packages:
sisteransi@1.0.5: sisteransi@1.0.5:
resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
smartypants@0.2.2:
resolution: {integrity: sha512-TzobUYoEft/xBtb2voRPryAUIvYguG0V7Tt3de79I1WfXgCwelqVsGuZSnu3GFGRZhXR90AeEYIM+icuB/S06Q==}
hasBin: true
smol-toml@1.6.1: smol-toml@1.6.1:
resolution: {integrity: sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg==} resolution: {integrity: sha512-dWUG8F5sIIARXih1DTaQAX4SsiTXhInKf1buxdY9DIg4ZYPZK5nGM1VRIYmEbDbsHt7USo99xSLFu5Q1IqTmsg==}
engines: {node: '>= 18'} engines: {node: '>= 18'}
@ -1552,6 +1577,9 @@ packages:
space-separated-tokens@2.0.2: space-separated-tokens@2.0.2:
resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==}
spark-md5@3.0.2:
resolution: {integrity: sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw==}
stringify-entities@4.0.4: stringify-entities@4.0.4:
resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==}
@ -2163,6 +2191,15 @@ snapshots:
'@parcel/watcher-win32-x64': 2.5.6 '@parcel/watcher-win32-x64': 2.5.6
optional: true optional: true
'@reuters-graphics/svelte-markdown@0.0.3(svelte@5.55.5)':
dependencies:
es-toolkit: 1.46.1
marked: 15.0.12
marked-smartypants: 1.1.12(marked@15.0.12)
parse5: 7.3.0
spark-md5: 3.0.2
svelte: 5.55.5
'@rferl/veronica@https://codeload.github.com/rferl/veronica/tar.gz/6935ec341ba7dce2a839f045deaba4783f4e8afc': {} '@rferl/veronica@https://codeload.github.com/rferl/veronica/tar.gz/6935ec341ba7dce2a839f045deaba4783f4e8afc': {}
'@rollup/pluginutils@5.3.0(rollup@4.60.3)': '@rollup/pluginutils@5.3.0(rollup@4.60.3)':
@ -2567,6 +2604,8 @@ snapshots:
es-module-lexer@2.1.0: {} es-module-lexer@2.1.0: {}
es-toolkit@1.46.1: {}
esbuild@0.27.7: esbuild@0.27.7:
optionalDependencies: optionalDependencies:
'@esbuild/aix-ppc64': 0.27.7 '@esbuild/aix-ppc64': 0.27.7
@ -2804,6 +2843,13 @@ snapshots:
markdown-table@3.0.4: {} markdown-table@3.0.4: {}
marked-smartypants@1.1.12(marked@15.0.12):
dependencies:
marked: 15.0.12
smartypants: 0.2.2
marked@15.0.12: {}
mdast-util-definitions@6.0.0: mdast-util-definitions@6.0.0:
dependencies: dependencies:
'@types/mdast': 4.0.4 '@types/mdast': 4.0.4
@ -3498,12 +3544,16 @@ snapshots:
sisteransi@1.0.5: {} sisteransi@1.0.5: {}
smartypants@0.2.2: {}
smol-toml@1.6.1: {} smol-toml@1.6.1: {}
source-map-js@1.2.1: {} source-map-js@1.2.1: {}
space-separated-tokens@2.0.2: {} space-separated-tokens@2.0.2: {}
spark-md5@3.0.2: {}
stringify-entities@4.0.4: stringify-entities@4.0.4:
dependencies: dependencies:
character-entities-html4: 2.1.0 character-entities-html4: 2.1.0

View file

@ -0,0 +1,39 @@
import { Meta } from '@storybook/blocks';
import { parameters } from '../../docs/utils/docsPage.js';
<Meta title="Actions/cssVariables" parameters={{ ...parameters }} />
# `cssVariables`
An action you can use to easily set [CSS variables](https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties) on HTML elements. Useful for passing JavaScript values to your component SCSS like this:
```svelte
<script>
import { cssVariables } from '@reuters-graphics/graphics-components';
let { height = 300, textColour = 'red' } = $props();
// Create an object of variable names and CSS values...
let variables = $derived({
height: height + 'px',
textColour: textColour,
});
</script>
<!-- Attach it to a parent element with the action -->
<div use:cssVariables={variables}>
<p>My text...</p>
</div>
<style lang="scss">
/**
* Now use your variables in your SCSS!
*/
div {
height: var(--height);
p {
color: var(--textColour);
}
}
</style>
```

View file

@ -0,0 +1,20 @@
// Shamelessly stolen from: https://github.com/kaisermann/svelte-css-vars
export default (node: HTMLElement, props: Record<string, string>) => {
Object.entries(props).forEach(([key, value]) => {
node.style.setProperty(`--${key}`, value);
});
return {
update(newProps: Record<string, string>) {
Object.entries(newProps).forEach(([key, value]) => {
node.style.setProperty(`--${key}`, value);
delete props[key];
});
Object.keys(props).forEach((name) => {
node.style.removeProperty(`--${name}`);
});
props = newProps;
},
};
};

View file

@ -0,0 +1,25 @@
// Shamelessly stolen from https://github.com/sveltejs/svelte/issues/7583#issue-1260717165
let observer: ResizeObserver;
let callbacks: WeakMap<Element, (el: Element) => unknown>;
export default (element: HTMLElement, onResize: (el: Element) => unknown) => {
if (!observer) {
callbacks = new WeakMap();
observer = new ResizeObserver((entries) => {
for (const entry of entries) {
const onResize = callbacks.get(entry.target);
if (onResize) onResize(entry.target);
}
});
}
callbacks.set(element, onResize);
observer.observe(element);
return {
destroy: () => {
callbacks.delete(element);
observer.unobserve(element);
},
};
};

View file

@ -0,0 +1,20 @@
import { Meta } from '@storybook/blocks';
import { parameters } from '../../docs/utils/docsPage.js';
<Meta title="Actions/resizeObserver" parameters={{ ...parameters }} />
# `resizeObserver`
An action you can use to easily to check when a DOM element's dimensions change using the [Resize Observer API](https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver). Use it like this:
```svelte
<script>
import { resizeObserver } from '@reuters-graphics/graphics-components';
let elementWidth = 0;
</script>
<div use:resizeObserver={(element) => (elementWidth = element.clientWidth)}>
My width is: {elementWidth}
</div>
```

View file

@ -1,3 +1,6 @@
---
import '../scss/main.scss';
---
<!doctype html> <!doctype html>
<html lang="en"> <html lang="en">
<head> <head>
@ -16,10 +19,8 @@
<style> <style>
html, html,
body { body {
margin: 0;
width: 100%;
height: 100%;
background-color: #3a3a3a; background-color: #3a3a3a;
color: #eeeeee; color: #eeeeee;
} }
</style> </style>

View file

@ -1,5 +1,6 @@
<script lang="ts"> <script lang="ts">
import ScrollerBase from '../components/ScrollerBase/ScrollerBase.svelte'; import ScrollerBase from '../components/ScrollerBase/ScrollerBase.svelte';
import type { ContainerWidth } from '../components/@types/global';
type Graphic = { type Graphic = {
src: string; src: string;
@ -8,6 +9,8 @@
title?: string; title?: string;
description?: string; description?: string;
notes?: string; notes?: string;
width?: ContainerWidth;
}; };
interface Props { interface Props {
@ -56,7 +59,7 @@
style="--animation-time: {animationDuration}ms" style="--animation-time: {animationDuration}ms"
src={graphics[displayedIndex].src} src={graphics[displayedIndex].src}
srcset={graphics[displayedIndex].srcset} srcset={graphics[displayedIndex].srcset}
sizes="100vw" sizes="(min-width: 690px) 660px, calc(100vw - 30px)"
alt={graphics[displayedIndex].alt} alt={graphics[displayedIndex].alt}
/> />
{/snippet} {/snippet}
@ -77,9 +80,7 @@
.graphic { .graphic {
display: block; display: block;
width: 100%; object-fit: contain;
height: 100%;
object-fit: cover;
transform-origin: bottom center; transform-origin: bottom center;
animation: squash var(--animation-time) linear(0, 0.417 25.5%, 0.867 49.4%, 1 57.7%, 0.925 65.1%, 0.908 68.6%, 0.902 72.2%, 0.916 78.2%, 0.988 92.1%, 1) forwards; animation: squash var(--animation-time) linear(0, 0.417 25.5%, 0.867 49.4%, 1 57.7%, 0.925 65.1%, 0.908 68.6%, 0.902 72.2%, 0.916 78.2%, 0.988 92.1%, 1) forwards;
} }
@ -107,15 +108,16 @@
} }
.step-foreground-container { .step-foreground-container {
height: 100vh; height: 50vh;
width: 50%; /* background-color: rgba(0, 0, 0, 0.2); */
background-color: rgba(0, 0, 0, 0.2);
padding: 1em; padding: 1em;
margin: 0 0 2em 0; margin: 0 0 2em 0;
max-width: var(--normal-column-width, 660px);
position: relative; position: relative;
left: 50%;
} }
.step-background-container { .step-background-container {
width: 80ch; max-width: var(--normal-column-width, 660px);
} }
</style> </style>

View file

@ -2,6 +2,8 @@
import { getImage } from 'astro:assets'; import { getImage } from 'astro:assets';
import Layout from '../layouts/Layout.astro'; import Layout from '../layouts/Layout.astro';
import Squash from './Squash.svelte'; import Squash from './Squash.svelte';
import Article from '../components/Article/Article.svelte';
import BodyText from '../components/BodyText/BodyText.svelte';
import graphicOne from '../assets/Photo-3468.jpg'; import graphicOne from '../assets/Photo-3468.jpg';
import graphicTwo from '../assets/Photo-3471.jpg'; import graphicTwo from '../assets/Photo-3471.jpg';
import graphicThree from '../assets/Photo-3515.jpg'; import graphicThree from '../assets/Photo-3515.jpg';
@ -9,6 +11,8 @@ import graphicFour from '../assets/Photo-3585.jpg';
const widths = [330, 510, 660, 930, 1200]; const widths = [330, 510, 660, 930, 1200];
import type { ContainerWidth } from '../components/@types/global';
async function buildSrcset(srcImg: ImageMetadata) { async function buildSrcset(srcImg: ImageMetadata) {
const images = await Promise.all( const images = await Promise.all(
widths.map((w) => getImage({ src: srcImg, width: w, format: 'jpeg' })) widths.map((w) => getImage({ src: srcImg, width: w, format: 'jpeg' }))
@ -20,15 +24,17 @@ async function buildSrcset(srcImg: ImageMetadata) {
} }
const graphics = [ const graphics = [
{ ...(await buildSrcset(graphicOne)), alt: 'Photo one', title: 'Graphic One', description: 'a caption', notes: '' }, { ...(await buildSrcset(graphicOne)), alt: 'Photo one', title: 'Graphic One', description: 'a caption', notes: '', width: 'normal' as const },
{ ...(await buildSrcset(graphicTwo)), alt: 'Photo two', title: 'Graphic Two', description: 'a description', notes: 'noted' }, { ...(await buildSrcset(graphicTwo)), alt: 'Photo two', title: 'Graphic Two', description: 'a description', notes: 'noted', width: 'normal' as const },
{ ...(await buildSrcset(graphicThree)), alt: 'Photo three', title: 'Graphic Three', description: 'an observation', notes: '' }, { ...(await buildSrcset(graphicThree)), alt: 'Photo three', title: 'Graphic Three', description: 'an observation', notes: '', width: 'normal' as const },
{ ...(await buildSrcset(graphicFour)), alt: 'Photo four', title: 'Graphic Four', description: 'blah', notes: 'note here' }, { ...(await buildSrcset(graphicFour)), alt: 'Photo four', title: 'Graphic Four', description: 'blah', notes: 'note here', width: 'normal' as const },
]; ];
--- ---
<Layout> <Layout>
<p>Cras eu consectetur justo, eu luctus felis. Suspendisse lectus enim, bibendum vitae euismod et, condimentum quis tortor. Donec sit amet orci nibh. Vivamus facilisis nunc quis nunc feugiat placerat. Nunc ut augue vitae metus fermentum venenatis vel at dui. Nulla aliquet nibh porttitor odio imperdiet, in ullamcorper augue bibendum. Cras ornare nunc ut sollicitudin egestas. Suspendisse neque ipsum, faucibus eu hendrerit porttitor, tincidunt a tortor. Aliquam at facilisis diam, a ullamcorper lacus. Suspendisse pharetra faucibus venenatis. Donec efficitur condimentum neque ut vehicula. p> <Article>
<BodyText text="Cras eu consectetur justo, eu luctus felis. Suspendisse lectus enim, bibendum vitae euismod et, condimentum quis tortor. Donec sit amet orci nibh. Vivamus facilisis nunc quis nunc feugiat placerat. Nunc ut augue vitae metus fermentum venenatis vel at dui. Nulla aliquet nibh porttitor odio imperdiet, in ullamcorper augue bibendum. Cras ornare nunc ut sollicitudin egestas. Suspendisse neque ipsum, faucibus eu hendrerit porttitor, tincidunt a tortor. Aliquam at facilisis diam, a ullamcorper lacus. Suspendisse pharetra faucibus venenatis. Donec efficitur condimentum neque ut vehicula." />
<Squash client:only="svelte" {graphics} /> <Squash client:only="svelte" {graphics} />
<p>Sed feugiat, lacus id elementum tristique, urna elit consectetur mauris, in commodo ipsum neque sed turpis. Ut elit ex, pharetra laoreet leo vitae, rhoncus condimentum ligula. Morbi et sagittis tellus. Proin sed felis euismod ipsum lacinia feugiat. Donec finibus pretium dignissim. Integer ornare egestas scelerisque. Donec purus elit, viverra vitae felis at, volutpat sollicitudin tellus. Vivamus fermentum dictum dapibus. Phasellus non ligula ac augue efficitur ultrices sit amet at quam. Fusce dapibus luctus ex, non semper massa commodo eget.</p> <BodyText text="Sed feugiat, lacus id elementum tristique, urna elit consectetur mauris, in commodo ipsum neque sed turpis. Ut elit ex, pharetra laoreet leo vitae, rhoncus condimentum ligula. Morbi et sagittis tellus. Proin sed felis euismod ipsum lacinia feugiat. Donec finibus pretium dignissim. Integer ornare egestas scelerisque. Donec purus elit, viverra vitae felis at, volutpat sollicitudin tellus. Vivamus fermentum dictum dapibus. Phasellus non ligula ac augue efficitur ultrices sit amet at quam. Fusce dapibus luctus ex, non semper massa commodo eget." />
</Article>
</Layout> </Layout>