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/stats-band/+page.svelte

194 lines
6.8 KiB

<script lang="ts">
/**
* StatsBand 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 StatsBandSite from './StatsBandSite.svelte';
import DocRow from '../_lib/DocRow.svelte';
let columns = $state(0); // 0 = fluido
let withCount = $state(true);
let dir = $state<'ltr' | 'rtl'>('ltr');
const previewSrc = $derived(
`/blocks/stats-band/preview?columns=${columns}&count=${withCount}&dir=${dir}`
);
</script>
<BlockDemo
name="Stats band"
slug="$blocks/stats-band"
{previewSrc}
previewHeight="620px"
meta={[
{ key: 'compone', value: 'Section · Container · AutoGrid · Metrics · CountUp · Motion' },
{ key: 'tipo', value: 'compound (.Stat repite)' },
{ key: 'superación', value: 'count-up (ninguna ref puede)' },
{ key: 'strings propias', value: '0' }
]}
>
{#snippet preview()}
<StatsBandSite {columns} {withCount} />
{/snippet}
{#snippet lede()}
La fila de cifras que respalda lo que la página acaba de afirmar. Compone el <Code>Metrics</Code
>
del canon para la semántica de KPI y <Code>CountUp</Code> para la cifra que se cuenta sola al entrar
en pantalla — <strong>lo único de este tier que ninguna referencia puede shipear</strong>,
porque todas entregan markup estático.
{/snippet}
{#snippet controls()}
<Wrap gap={5}>
<Group gap={2} align="center" justify="start">
<Text size="sm" color="muted">columnas</Text>
<ToggleGroup
selectionMode="single"
size="sm"
attached
value={[String(columns)]}
onValueChange={(v) => (columns = Number(v[0] ?? columns))}
aria-label="columnas"
>
<ToggleGroup.Item value="0">fluido</ToggleGroup.Item>
{#each [2, 3, 4] as value (value)}
<ToggleGroup.Item value={String(value)}>{value}</ToggleGroup.Item>
{/each}
</ToggleGroup>
</Group>
<Group gap={2} align="center" justify="start">
<Text size="sm" color="muted">count-up</Text>
<ToggleGroup
selectionMode="single"
size="sm"
attached
value={[withCount ? 'sí' : 'no']}
onValueChange={(v) => (withCount = (v[0] ?? 'sí') === 'sí')}
aria-label="contar las cifras"
>
<ToggleGroup.Item value="sí">sí</ToggleGroup.Item>
<ToggleGroup.Item value="no">no</ToggleGroup.Item>
</ToggleGroup>
</Group>
<Group gap={2} align="center" justify="start">
<Text size="sm" color="muted">dir</Text>
<ToggleGroup
selectionMode="single"
size="sm"
attached
value={[dir]}
onValueChange={(v) => (dir = (v[0] ?? dir) as typeof dir)}
aria-label="dirección (solo la vista previa)"
>
<ToggleGroup.Item value="ltr">ltr</ToggleGroup.Item>
<ToggleGroup.Item value="rtl">rtl</ToggleGroup.Item>
</ToggleGroup>
</Group>
</Wrap>
{/snippet}
{#snippet composition()}
<Stack gap={4}>
<Text color="muted">
El block coloca y escalona; la semántica de KPI es del <Code>Metrics</Code> del canon y el conteo,
del <Code>CountUp</Code>. Cifras y palabras son de la app.
</Text>
<Stack gap={3}>
<DocRow term="raíz">
<Code>&lt;section&gt;</Code> + <Code>Section</Code> + <Code>Container</Code> +
<Code>AutoGrid</Code> con <Code>data-stagger</Code>: fluido por
<Code>minChildWidth</Code> o con <Code>columns</Code> fijas.
</DocRow>
<DocRow term=".Stat">
<Code>Motion trigger="viewport"</Code> envolviendo un <Code>Metrics</Code>. ES el reveal,
así que debe seguir siendo hijo directo de la banda para recibir su índice estructural.
</DocRow>
<DocRow term=".Value">
<Code>Metrics.Value</Code>; con <Code>count</Code> compone <Code>CountUp</Code>. El
formato es locale-aware y reduced-motion salta al valor final — ambas cosas del
<Code>CountUp</Code>, no del block.
</DocRow>
<DocRow term=".Label"><Code>Metrics.Label</Code>. Las palabras, de la app.</DocRow>
</Stack>
</Stack>
{/snippet}
{#snippet api()}
<Stack gap={3}>
<DocRow term="StatsBand">
<Code>containerSize</Code> (def. <Code>lg</Code>) · <Code>sectionSize</Code> (def. <Code
>lg</Code
>) ·
<Code>columns</Code> o <Code>minChildWidth</Code> (def. <Code>12rem</Code>) ·
<Code>gap</Code> (def. <Code>8</Code>).
</DocRow>
<DocRow term=".Stat">
Todo lo de <Code>Metrics</Code>: <Code>align</Code> (def. <Code>center</Code> — una banda son
cifras centradas, no tarjetas de panel), <Code>sectionSize</Code> (def. <Code>lg</Code>),
<Code>live</Code>…
</DocRow>
<DocRow term=".Value">
<Code>count</Code> (number, opt-in) + <Code>countOptions</Code> (todo lo de
<Code>CountUp</Code> menos <Code>to</Code>). Sin <Code>count</Code>, la cifra la pone la app
por children.
</DocRow>
</Stack>
{/snippet}
{#snippet a11y()}
<Stack gap={3}>
<DocRow term="Movimiento">
El conteo respeta <Code>prefers-reduced-motion</Code>: salta directo al valor final, sin
animar. Lo resuelve el <Code>CountUp</Code>, no el block.
</DocRow>
<DocRow term="Cifras">
El formato numérico sale de <Code>uix.format</Code> (separadores por idioma), así que la cifra
se lee correcta en cada locale sin que la app la reescriba.
</DocRow>
<DocRow term="Estructura">
Sin encabezados: una banda son datos, no una sección con título. Si la página necesita uno,
lo pone alrededor.
</DocRow>
</Stack>
{/snippet}
{#snippet gaps()}
<Stack gap={3}>
<DocRow term="Split con imagen">
<strong>Diferido</strong> — la banda junto a una foto: otra disposición (2 columnas), que
recurre en las refs. Entra como <Code>layout</Code> o hermano cuando una demo lo pida.
</DocRow>
<DocRow term="Timeline / stepped">
<strong>Diferido</strong> — el <Code>Timeline</Code> del canon existe; es otra sección, no una
banda.
</DocRow>
<DocRow term="Delta / tendencia por cifra">
<strong>App-land</strong> — <Code>Metrics.Delta</Code> se compone dentro del
<Code>.Stat</Code> hoy; re-exponerlo solo añadiría superficie.
</DocRow>
</Stack>
{/snippet}
{#snippet notes()}
<Stack gap={3}>
<DocRow term="El count-up es opt-in, nunca por defecto">
Una cifra que se anima sin que el lector lo pida es ruido, y algunas no son contables
(«99,98 %»). Por eso <Code>count</Code> se pide explícitamente.
</DocRow>
<DocRow term="El block no formatea ni escribe">
Ni una palabra ni un separador decimal salen de aquí: las palabras por children, el formato
por <Code>uix.format</Code> dentro del <Code>CountUp</Code>.
</DocRow>
</Stack>
{/snippet}
</BlockDemo>

Powered by TurnKey Linux.