You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/web/routes/blocks/content-section/+page.svelte

257 lines
11 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<script lang="ts">
/**
* Content section demo. Full-bleed on the page; device widths from `./preview`.
*/
import { Stack } from '$uix/eidos/components/stack';
import { Group } from '$uix/eidos/components/group';
import { Wrap } from '$uix/eidos/components/wrap';
import { Text } from '$uix/eidos/components/text';
import { Code } from '$uix/eidos/components/code';
import { ToggleGroup } from '$uix/eidos/components/toggle-group';
import BlockDemo from '../_lib/BlockDemo.svelte';
import ContentSectionSite from './ContentSectionSite.svelte';
import DocRow from '../_lib/DocRow.svelte';
import type { ContentWidth } from '$blocks/content-section';
import type { ContainerSize } from '$uix/eidos/components/container';
import type { TextMeasure } from '$uix/eidos/lib/types';
let measure = $state<TextMeasure>('normal');
// `responsive` is an axis of the demo, not a value of the prop: it shows what
// only a per-breakpoint value can say — edge to edge on a phone, contained
// from `md` up.
// Starts at the block's DEFAULT: a demo that silently overrides it would be
// showing something the block does not do on its own.
let figure = $state<ContentWidth | 'responsive'>('measure');
const figureProp = $derived(
figure === 'responsive' ? ({ base: 'full', md: 'wide' } as const) : figure
);
let wide = $state<ContainerSize>('lg');
const previewSrc = $derived(
`/blocks/content-section/preview?measure=${measure}&figure=${figure}&wide=${wide}`
);
</script>
<BlockDemo
name="Content section"
slug="$blocks/content-section"
{previewSrc}
previewHeight="1100px"
meta={[
{ key: 'compone', value: 'Section · Grid · Box · Prose · Heading · Text · Motion' },
{ key: 'forma', value: 'compound — Body y Media se repiten' },
{ key: 'anchuras', value: 'measure · wide · full' },
{ key: 'estado', value: 'ninguno — es layout' }
]}
>
{#snippet preview()}
<ContentSectionSite {measure} figure={figureProp} {wide} />
{/snippet}
{#snippet lede()}
Texto largo: una cabecera, la prosa del artículo y figuras que <strong
>se salen de la columna de lectura sin salirse del flujo</strong
>. Es la superficie de lectura de un post, un changelog o una página legal.
{/snippet}
{#snippet controls()}
<Wrap gap={5}>
<Group gap={2} align="center" justify="start">
<Text size="sm" color="muted">medida</Text>
<ToggleGroup
selectionMode="single"
size="sm"
attached
value={[measure]}
onValueChange={(v) => (measure = (v[0] ?? measure) as TextMeasure)}
aria-label="columna de lectura"
>
<ToggleGroup.Item value="narrow">narrow</ToggleGroup.Item>
<ToggleGroup.Item value="normal">normal</ToggleGroup.Item>
<ToggleGroup.Item value="wide">wide</ToggleGroup.Item>
</ToggleGroup>
</Group>
<Group gap={2} align="center" justify="start">
<Text size="sm" color="muted">la figura</Text>
<ToggleGroup
selectionMode="single"
size="sm"
attached
value={[figure]}
onValueChange={(v) => (figure = (v[0] ?? figure) as ContentWidth | 'responsive')}
aria-label="alcance de la figura"
>
<ToggleGroup.Item value="measure">measure</ToggleGroup.Item>
<ToggleGroup.Item value="wide">wide</ToggleGroup.Item>
<ToggleGroup.Item value="full">full</ToggleGroup.Item>
<ToggleGroup.Item value="responsive">responsive</ToggleGroup.Item>
</ToggleGroup>
</Group>
<Group gap={2} align="center" justify="start">
<Text size="sm" color="muted">pista ancha</Text>
<ToggleGroup
selectionMode="single"
size="sm"
attached
value={[wide]}
onValueChange={(v) => (wide = (v[0] ?? wide) as ContainerSize)}
aria-label="ancho de la pista wide"
>
<ToggleGroup.Item value="md">md</ToggleGroup.Item>
<ToggleGroup.Item value="lg">lg</ToggleGroup.Item>
<ToggleGroup.Item value="xl">xl</ToggleGroup.Item>
</ToggleGroup>
</Group>
</Wrap>
{/snippet}
{#snippet composition()}
<Stack gap={4}>
<Text color="muted">
El block pone la rejilla, la medida y la semántica del artículo. El HTML renderizado, la
media y las palabras son del app.
</Text>
<Stack gap={3}>
<DocRow term="por qué es una rejilla y no un Container">
Dentro de un <Code>Container</Code> nada puede ser MÁS ancho que él, así que una figura a sangre
habría que sacarla del artículo y ponerla de hermana — rompiendo el orden de lectura. La sección
es un
<Code>Grid</Code> cuya pista central es la medida, y cada parte dice hasta dónde llega: <Code
>3</Code
> · <Code>2 / 5</Code> · <Code>1 / -1</Code>. Ese escape es lo que separa a este block de
un <Code>Prose</Code> dentro de una caja.
</DocRow>
<DocRow term="la medida de Prose va APAGADA">
<Code>Body</Code> pasa <Code>measure={false}</Code> al <Code>Prose</Code>: la rejilla ya
posee el ancho y dos dueños de la misma medida se pelean — ganaría el más estrecho en
silencio, así que un <Code>Body</Code> ancho no lo sería.
</DocRow>
<DocRow term="todas las longitudes son tokens">
Las medidas son <Code>--measure-*</Code> (54 · 66 · 78ch) y la pista ancha es un <Code
>--container-width-*</Code
>
<strong>menos el padding de ese contenedor</strong>: un token de container es el ancho
EXTERIOR y lo que se ve alineado es la caja de CONTENIDO. En <Code>lg</Code> la pista ancha
son 992, no 1024, y así una figura que se sale cae justo sobre el texto de las secciones de
arriba y de abajo — sin eso sobresalía 16px por cada lado. Los canalones son
<Code>1fr</Code> con suelo en <Code>--container-padding-inline</Code>.
</DocRow>
<DocRow term="el pie de foto se queda estrecho">
Un <Code>figcaption</Code> al ancho de una imagen a sangre no se lee. Se limita a la medida
de lectura y se centra, así que cae justo bajo la prosa aunque su figura no lo esté — varias
referencias no lo hacen. Verificado en 3 viewports × 3 medidas × 3 anchuras: el pie tiene el
mismo ancho y la misma x que la prosa en las 18.
</DocRow>
<DocRow term="los huecos de columna no existen aquí">
<Code>gap</Code> separa también las COLUMNAS, y una parte que las cruza se lleva esos huecos
encima: medido, <Code>wide</Code> salía 1088 en vez de los 1024 del contenedor, y a 420px <Code
>full</Code
> llegaba a 532 dentro de una rejilla de 404 y hacía scrollear la página. Las columnas son un
instrumento de medida, no cosas puestas al lado — van con
<Code>rowGap</Code> y <Code>columnGap={0}</Code>.
</DocRow>
</Stack>
</Stack>
{/snippet}
{#snippet api()}
<Stack gap={3}>
<DocRow term="ContentSection">
<Code>measure</Code> (<Code>narrow · normal · wide</Code>, def.
<Code>normal</Code>) · <Code>wide</Code> (ancho de la pista ancha, def. un
<Code>--container-width-lg</Code>) · <Code>size</Code> · <Code>level</Code>, y los snippets
de cabecera <Code>eyebrow</Code> · <Code>title</Code> ·
<Code>lede</Code> · <Code>meta</Code>.
</DocRow>
<DocRow term="por qué aquí «wide» y «full» se parecen">
<Code>full</Code> llega al borde de <strong>su contenedor</strong>, y en esta galería el
contenedor es la columna de contenido — el raíl se lleva 240px, así que a 1280 quedan 1024 y <Code
>wide</Code
> ya mide eso. Medido en la ruta
<Code>preview</Code>, que es un documento propio: a 1600,
<Code>wide</Code> da 1024 contra <Code>full</Code> 1584. Baja la
<strong>pista ancha</strong> a <Code>md</Code> y la relación se ve aquí mismo; o abre la vista
previa.
</DocRow>
<DocRow term="los tres ejes son responsive">
<Code>measure</Code>, <Code>wide</Code> y el <Code>width</Code> de cada parte aceptan <Code
>ResponsiveProp</Code
>, como los props del propio ecosistema — se resuelven con <Code>eidos.resolve()</Code>,
igual que los de <Code>Box</Code>. Es lo que un valor único no puede decir:
<Code>{'{ base: "full", md: "wide" }'}</Code> = foto a sangre en móvil y contenida de <Code
>md</Code
> en adelante. Verificado contra el breakpoint canónico: a 767 va a sangre, a 768 se contiene.
</DocRow>
<DocRow term="ContentSection.Body">
Una tirada de prosa. Acepta lo de <Code>Prose</Code> (<Code>size</Code>) menos
<Code>measure</Code>, que lo gobierna la rejilla, más <Code>width</Code> por si esa tirada tiene
que salirse.
</DocRow>
<DocRow term="ContentSection.Media">
<Code>width</Code> (def. <Code>measure</Code> — la figura sigue al texto y salirse se pide) y
el snippet <Code>caption</Code>. Renderiza un <Code>figure</Code> de verdad y el pie como
<Code>figcaption</Code>: es la semántica de la cosa, no un párrafo que va debajo.
</DocRow>
</Stack>
{/snippet}
{#snippet a11y()}
<Stack gap={3}>
<DocRow term="La sección tiene nombre">
<Code>&lt;section aria-labelledby&gt;</Code> apuntando al título, así que el artículo es una región
navegable con nombre. El nivel del encabezado es un prop (<Code>level</Code>): la estructura
del documento la decide la página, no el block.
</DocRow>
<DocRow term="Figura y pie van atados">
<Code>figure</Code> + <Code>figcaption</Code> son elementos reales, no un
<Code>div</Code> con un texto debajo: un lector de pantalla anuncia el pie como lo que es. Es
la única superficie de a11y propia de un block — estructura de documento.
</DocRow>
<DocRow term="El orden de lectura no se rompe">
La figura a sangre sigue estando ENTRE las dos tiradas de prosa en el DOM. Con un contenedor
habría que sacarla fuera, y el orden de tabulación y de lectura dejarían de coincidir con lo
que se ve.
</DocRow>
</Stack>
{/snippet}
{#snippet gaps()}
<Stack gap={3}>
<DocRow term="Un Figure del canon">
<strong>Señalado</strong> — el canon tiene <Code>Image</Code> y
<Code>AspectRatio</Code>, pero no una primitiva de figura, así que el block pone el <Code
>figure</Code
>/<Code>figcaption</Code> él mismo. Con un segundo consumidor, eso es el disparador de promoción.
</DocRow>
<DocRow term="El margen del figure">
<strong><Code>&lt;style&gt;</Code> justificado</strong> (D-BLK.2) — el navegador da <Code
>margin: 1em 40px</Code
> y la fundación no trae reset de elementos, así que esos 40px se comerían la pista que la rejilla
acaba de asignar. Misma raíz que F18.
</DocRow>
<DocRow term="Notas al margen y citas destacadas">
<strong>Sin construir</strong> — una nota en la pista lateral es un patrón editorial real,
pero no lo ha pedido ningún consumidor;
<Code>Media width="wide"</Code> cubre el caso común.
</DocRow>
</Stack>
{/snippet}
{#snippet notes()}
<Stack gap={3}>
<DocRow term="No posee estado, y está bien">
Aquí no hay nada que coordinar: es layout. Inventarle una máquina a un block que solo coloca
es el error contrario al que arregló <Code>contact</Code>.
</DocRow>
<DocRow term="Un componente del canon dentro de la prosa">
El <Code>Callout</Code> de la segunda tirada conserva su propio estilo sin anotar nada: todas
las reglas de <Code>Prose</Code> se emiten a especificidad CERO, así que el <Code
>[data-callout]</Code
> les gana. Ninguna librería de referencia puede hacer esto — no poseen el markup de sus consumidores.
</DocRow>
</Stack>
{/snippet}
</BlockDemo>

Powered by TurnKey Linux.