|
|
|
|
|
<script lang="ts">
|
demo(blocks): la sección tiene cromo de verdad — tema, idioma, dirección, densidad y catálogo
La crítica era exacta: no se podía cambiar a oscuro, ni de idioma, ni había
forma de moverse entre blocks. La sección arrancaba UIX y renderizaba la
página desnuda, con un comentario que decía que el modo seguía al sistema
operativo «para verificar oscuro emulando prefers-color-scheme» — cómodo para
mí, inútil para quien mira la página.
Ahora hay shell: topbar pegajosa con los ejes que de verdad mueven el
framework (idioma ES/EN/FR/DE y dirección como INTENTS de prefs, así que
llegan a langs, formatos y al AGENTS.md debug.log routes tsconfig.json
CLAUDE.md docs scripts tsconfig.tsbuildinfo
README.md node_modules src vite.config.ts
STUMBLES.md package-lock.json static web
audit package.json svelte.config.js worker.js
build plans tmp workers del documento por el camino del sistema;
densidad proyectada en :root para que la hereden también los overlays
porteados; y el conmutador de tema, que alimenta el del
ActiveEidos) y un raíl con el catálogo entero de los 27 blocks planificados,
marcando el actual y atenuando los que aún no existen. Todo persiste en
localStorage, así que una recarga te deja donde estabas.
El catálogo pasa a : raíl y galería leen la MISMA fuente, y
un block que aterriza no hay que recordarlo en dos sitios.
Las tres regiones las coloca — cromo de app-land, el papel que
hace en las docs de componentes; la regla de «sin CSS» del contrato
B es para el tier (), no para el sitio que lo enseña. Dentro
de esas regiones todo son componentes del canon.
Verificado en navegador: el botón conmuta a oscuro de verdad (fondo
oklch(0.1776 0 0)), el idioma llega a , el raíl lista los 27 y
desaparece por debajo de 64rem sin desbordes, cero errores de consola.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
|
|
|
|
/**
|
|
|
|
|
|
* Blocks section shell. Boots UIX (createActiveUix → Soma → prefs projection
|
|
|
|
|
|
* → ActiveEidos) and puts REAL chrome around it: a rail with the catalog and
|
|
|
|
|
|
* a topbar whose axes actually drive the framework — colour mode, language,
|
|
|
|
|
|
* direction and density. Without them a demo can only be looked at, never
|
|
|
|
|
|
* exercised, which is the whole point of a demo.
|
|
|
|
|
|
*
|
|
|
|
|
|
* The three regions are placed by `blocks.css` (app-land chrome, the role
|
|
|
|
|
|
* `uix.css` plays for the component docs); everything inside them is a canon
|
|
|
|
|
|
* component, so the section dogfoods the framework like the rest of the site.
|
|
|
|
|
|
*/
|
|
|
|
|
|
import { onDestroy } from 'svelte';
|
demo(blocks): la sección tiene cromo de verdad — tema, idioma, dirección, densidad y catálogo
La crítica era exacta: no se podía cambiar a oscuro, ni de idioma, ni había
forma de moverse entre blocks. La sección arrancaba UIX y renderizaba la
página desnuda, con un comentario que decía que el modo seguía al sistema
operativo «para verificar oscuro emulando prefers-color-scheme» — cómodo para
mí, inútil para quien mira la página.
Ahora hay shell: topbar pegajosa con los ejes que de verdad mueven el
framework (idioma ES/EN/FR/DE y dirección como INTENTS de prefs, así que
llegan a langs, formatos y al AGENTS.md debug.log routes tsconfig.json
CLAUDE.md docs scripts tsconfig.tsbuildinfo
README.md node_modules src vite.config.ts
STUMBLES.md package-lock.json static web
audit package.json svelte.config.js worker.js
build plans tmp workers del documento por el camino del sistema;
densidad proyectada en :root para que la hereden también los overlays
porteados; y el conmutador de tema, que alimenta el del
ActiveEidos) y un raíl con el catálogo entero de los 27 blocks planificados,
marcando el actual y atenuando los que aún no existen. Todo persiste en
localStorage, así que una recarga te deja donde estabas.
El catálogo pasa a : raíl y galería leen la MISMA fuente, y
un block que aterriza no hay que recordarlo en dos sitios.
Las tres regiones las coloca — cromo de app-land, el papel que
hace en las docs de componentes; la regla de «sin CSS» del contrato
B es para el tier (), no para el sitio que lo enseña. Dentro
de esas regiones todo son componentes del canon.
Verificado en navegador: el botón conmuta a oscuro de verdad (fondo
oklch(0.1776 0 0)), el idioma llega a , el raíl lista los 27 y
desaparece por debajo de 64rem sin desbordes, cero errores de consola.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
|
|
|
|
import { page } from '$app/state';
|
|
|
|
|
|
import { createActiveUix, setActiveUix } from '$active-uix';
|
feat(direction): la proyeccion prefs->DOM es del boot, y el DOM la siembra
La proyeccion cross-modal (dir · lang · data-motion/sound/haptic sobre <html>)
era cableado manual de cada app: solo 4 de ~13 boots de la demo la tenian, y el
estampado per-componente del valor de prefs actuaba de SUSTITUTO de la
proyeccion que faltaba. Para que el flip de P3 pueda soltar prefs del atributo,
el ambiente tiene que llegar al DOM una vez y siempre:
- createActiveUix la crea por defecto (opt-out `projectPrefs: false` cuando la
app posee <html>: i18n por routing, proyeccion propia). En attach es opt-IN —
el inverso — porque el host puede gobernar el documento.
- Se dispone la PRIMERA en dispose(), antes de que prefs/dom mueran debajo.
- Los 3 cableados manuales commiteables se borran EN ESTE MISMO commit (uix,
blocks, BootUix); el de web/routes/alpha se edita en arbol pero no se
commitea nunca (regla de la rama). Borrarlos junto a la automatica evita el
agujero medido del doble montaje: dispose() BORRA los attrs gestionados sin
restaurar.
Y LA SEMILLA, que es lo que hace la automatica segura: sin ella, el boot
REESCRIBIRIA un <html dir="rtl"> puesto a mano (el escenario 013ceac57) con el
valor derivado del idioma. `readPrefsEnvironmentFromDom` lee <html dir> UNA vez
al boot (SSR-safe: {} sin document; auto/vacio = "la pagina no declaro") y la
dimension direction la honra con la precedencia:
intent del usuario > semilla del entorno > derivacion(idioma) > default
Una declaracion a nivel de pagina es una AFIRMACION explicita; el enlace por
idioma es una heuristica — la afirmacion gana. Lo que pase la app en
options.prefs.environment pisa la semilla.
Un guard viejo fijaba el comportamiento anterior ("does not auto-project…") —
es exactamente lo que la decision D2 (firmada 2026-08-05) revierte. Pasa a
fijar el nuevo contrato: se proyectan SOLO los attrs cross-modales; data-theme/
mode/density siguen prohibidos (son de eidos).
Tests: semilla y precedencia 6/6 (dom-environment.test.ts) · proyeccion
automatica, opt-out, adopcion del dir a mano y limpieza en dispose (4 nuevos en
active-uix.svelte.test.ts) · suites active-uix + prefs 79/79.
Verificado en Chrome por el camino real: el toggle del topbar mueve <html dir>
via prefs->proyeccion AUTOMATICA (ltr -> rtl -> auto) con el cableado manual ya
borrado, en /uix y en /blocks; <html lang> viaja con el.
check 77 = linea base · rtl:check 1 (palabras) · docs:check 0/566.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
import { standardPrefsDimensions } from '$prefs';
|
|
|
|
|
|
import { Soma } from '$soma/core/soma.svelte';
|
|
|
|
|
|
import { siumLangs } from '$sium/langs/langs';
|
|
|
|
|
|
import { secsLangs } from '$libs/secs';
|
feat(blocks): contact CERRADO — la coordinacion entra en el contrato B
El estado se le pregunta al ESQUEMA, no al Form. `form.isValid` con
`validationBehaviour: 'progressive'` significa «aun no se ha encontrado nada
mal»: un formulario vacio e intacto no tiene errores, asi que se declaraba
valido y `incomplete` era INALCANZABLE al cargar — la seccion pedia resolver la
verificacion con los tres campos vacios, justo el hueco que la doctrina existe
para cerrar. Ahora la raiz valida los valores con `validateSync` de SIUM:
sincrono y sin escribir errores (`form.validate()` habria encendido los tres
campos en rojo en el primer frame).
`state.test.ts` fija la maquina con 9 casos — primer test unitario del tier,
porque `state.ts` es su primera logica pura: el orden de prioridad, que solo
`ready` deja enviar, y que todo estado bloqueado tiene frase.
Contrato B (architecture/blocks.md): seccion «Coordination» con las tres cosas
que posee un block que coordina (estado, forma de sus datos, palabras), B-5
admite el esquema por defecto, B-7 enmendado (posee las palabras de SUS estados
como idlangref con fallback ingles) y la convencion de servicios acotada: el
traductor es el UNICO servicio sancionado. Dice tambien a quien NO aplica — los
blocks de layout no coordinan nada.
i18n por la via real: el arnes registra el namespace `blocks` en las DOS cadenas
de arranque (galeria y previews, que duplican el boot) y la demo se lee en
castellano en vez de caer al fallback ingles.
Ademas: README y pestanas de doc rehechos al reparto nuevo, ficha F2.13 y
bitacora en PLAN-blocks.md, y el control vivo que faltaba para un prop publico
— `verification` con reto / sin reto, porque omitir el prop no es lo mismo que
pasar un estado que nunca verifica.
Verificado en navegador, arco completo y las dos ramas: sin reto vacio → un
campo → tres campos (se desbloquea) → «Enviando…» → «Enviado»; con reto, con
los tres campos llenos el boton sigue bloqueado y la razon pasa a «Resuelve la
verificacion de arriba». `verifying` y `rejected` quedan cubiertos por test
unitario, no por el reto en vivo: el provider de ProofOfHuman escribe `status`
el mismo y el veredicto del app no se sostiene (hilo de canon abierto).
Gates: blocks:check verde (14 blocks) · vitest 9/9 · docs:check 0 ·
svelte-check sin errores propios · prettier limpio en los ficheros propios.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
import { blocksLangs } from './_lib/blocks-langs';
|
|
|
|
|
|
import { ActiveEidos } from '$uix/eidos';
|
fix(blocks): la galeria emite — packs de sema y canales perceptivos en el arnes
El motor SI emitia: pulsar un boton de un block estampa
`data-event=contact-activate` con `family=contact` y `phase=active`, porque el
morfo del `Button` declara ese evento (verbo `activate`, secuencia `pre`, sin
intent a proposito — una pulsacion no carga intencion evaluativa). Lo que
faltaba era el otro lado: la seccion arrancaba UIX **sin `events` y con cero
packs de sema**, frente a los 69 de `/uix`. El evento salia a una sala sin
altavoces. Viene de F0, cuando el arranque se monto como «espejo minimo» de
`/uix` y sema se quedo fuera.
Un framework semantico cuya propia galeria no suena no esta demostrando lo que
existe para demostrar, asi que los canales van ENCENDIDOS aqui: `sound` y
`haptic` a true en las dos cadenas de arranque (galeria y previews).
La lista de packs es DERIVADA del barrel (`Object.values(packs)`), no escrita a
mano, y eso es deliberado: la lista a mano del otro arnes se quedo atras dos
veces — `69c108d2a` tuvo que anadir «los 25 packs que faltaban en la composicion
de demos». Una lista derivada no puede quedarse atras. El barrel recomienda
importar solo los que usas por tree-shaking; aqui no aplica, porque esto no es
un producto sino la galeria del framework y un block compone lo que quiera del
canon.
Verificado espiando la Web Audio API en un clic real dentro del block: al cargar
1 AudioContext y 0 fuentes; tras pulsar, 2 fuentes y 3 nodos de ganancia mas. Y
las 15 demos cargan limpias con los 69 packs, cero errores de pagina.
Gates: blocks:check verde (15) · svelte-check sin errores en lo tocado ·
prettier limpio.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
import { semaPacks } from './_lib/sema-packs';
|
demo(blocks): la sección tiene cromo de verdad — tema, idioma, dirección, densidad y catálogo
La crítica era exacta: no se podía cambiar a oscuro, ni de idioma, ni había
forma de moverse entre blocks. La sección arrancaba UIX y renderizaba la
página desnuda, con un comentario que decía que el modo seguía al sistema
operativo «para verificar oscuro emulando prefers-color-scheme» — cómodo para
mí, inútil para quien mira la página.
Ahora hay shell: topbar pegajosa con los ejes que de verdad mueven el
framework (idioma ES/EN/FR/DE y dirección como INTENTS de prefs, así que
llegan a langs, formatos y al AGENTS.md debug.log routes tsconfig.json
CLAUDE.md docs scripts tsconfig.tsbuildinfo
README.md node_modules src vite.config.ts
STUMBLES.md package-lock.json static web
audit package.json svelte.config.js worker.js
build plans tmp workers del documento por el camino del sistema;
densidad proyectada en :root para que la hereden también los overlays
porteados; y el conmutador de tema, que alimenta el del
ActiveEidos) y un raíl con el catálogo entero de los 27 blocks planificados,
marcando el actual y atenuando los que aún no existen. Todo persiste en
localStorage, así que una recarga te deja donde estabas.
El catálogo pasa a : raíl y galería leen la MISMA fuente, y
un block que aterriza no hay que recordarlo en dos sitios.
Las tres regiones las coloca — cromo de app-land, el papel que
hace en las docs de componentes; la regla de «sin CSS» del contrato
B es para el tier (), no para el sitio que lo enseña. Dentro
de esas regiones todo son componentes del canon.
Verificado en navegador: el botón conmuta a oscuro de verdad (fondo
oklch(0.1776 0 0)), el idioma llega a , el raíl lista los 27 y
desaparece por debajo de 64rem sin desbordes, cero errores de consola.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
|
|
|
|
import { Stack } from '$uix/eidos/components/stack';
|
|
|
|
|
|
import { Group } from '$uix/eidos/components/group';
|
|
|
|
|
|
import { Text } from '$uix/eidos/components/text';
|
|
|
|
|
|
import { Link } from '$uix/eidos/components/link';
|
|
|
|
|
|
import { Badge } from '$uix/eidos/components/badge';
|
|
|
|
|
|
import { Separator } from '$uix/eidos/components/separator';
|
|
|
|
|
|
import { ToggleGroup } from '$uix/eidos/components/toggle-group';
|
|
|
|
|
|
import { Button } from '$uix/eidos/components/button';
|
|
|
|
|
|
import * as Icon from '$uix/eidos/components/icon';
|
|
|
|
|
|
import { BLOCK_CATALOG } from './_lib/catalog';
|
|
|
|
|
|
import '@/uix/eidos/index.css';
|
feat(blocks): `newsletter` — el alta al boletín, y el reset que el framework daba por hecho
F2.9. Slots de snippet (eyebrow · title · description · field · submit · note ·
children), `center` y `justified`, y `panel` como interruptor real: el panel de
marca es la cara de las referencias, pero el control, la ayuda y el error están
calibrados para la superficie de página, así que apagarlo es un estado de primera
y no un fallback.
La fila es `Grid templateColumns={{ base: '1fr', sm: '1fr auto' }}`: el campo se
queda la pista libre y la acción abraza su contenido —eso es lo que hace que un
alta se lea como UN gesto— y bajo `sm` pasa a una columna, porque un botón al lado
de un campo de correo deja inservibles a los dos.
El block NO valida y NO emite sema. `Form` posee el runtime, el esquema, dirty/
touched, la agregación de errores y el foco al primer error; `Field` posee el
cableado ARIA; el morfo del `Form` ya declara `commit-submit` y `signal-invalid`.
El app posee esquema, valores y handler. No hay ni un `if` sobre un correo aquí.
## Superación del dossier: la etiqueta
El único hueco que el dossier nombraba era la nota de privacidad, y está. Pero la
diferencia de verdad es la etiqueta: las referencias shipean la fila escondiéndola
con `sr-only` o dejando solo un placeholder. El canon tiene `Field floatingLabel`
—arranca dentro del control y sube al borde al enfocar o rellenar—, así que la fila
queda alineada CON etiqueta real y asociada. Verificado con pulsaciones de teclado
de verdad: 10px dentro en reposo → −11px sobre el borde al enfocar y al rellenar.
## Tres hallazgos de canon más, medidos
- **La fundación de eidos no trae reset de modelo de caja y lo asume del app.**
`[data-field-control]` declara `inline-size: 100%` + padding, así que bajo
`content-box` el control mide 30px más que su contenedor: el campo se metía por
debajo del botón de envío. Campo 480 / control 510 en la galería frente a
502 / 502 en los docs de componentes, que sí resetean (igual que
`web/routes/active/styles.css`). Arreglado en app-land con
`web/routes/blocks/_lib/reset.css`, con A/B sobre los 10 previews y 5 páginas de
shell: cambia el newsletter y NADA más. Hay que importarlo dos veces porque la
galería arranca UIX en línea en vez de pasar por `BootUix` — deuda del arnés,
anotada en el handoff.
- **`onValidSubmit` es un no-op silencioso** cuando se pasa un `form` ya
construido: el componente solo lo reenvía al `createForm` que hace él mismo. El
envío validaba, limpiaba el error y no anunciaba nada. Por eso el block no
expone el prop: el handler va en el `createForm` del app.
- **Los mensajes de SIUM son idlangref.** La vía correcta es
`uix.langs.t(issue.message, issue.params)` —verificado, sale «Debe ser una
dirección de correo válida»—, pero la demo de docs del propio `Form` parte la
cadena a mano tras el `|`, así que el único ejemplo del repo enseña el patrón
equivocado y siempre muestra inglés.
Los tres quedan en los gaps del README y en `PLAN-blocks-quality.md` §6
(F18/F19/F20), sin tocar nada fuera del tier.
Verificado en navegador el arco completo: correo inválido → error traducido con
`role="alert"`, `aria-invalid`, `aria-describedby` y foco al primer error; correo
válido → confirmación del app (`Callout` afirmativo con la dirección) y error
limpio. Claro/oscuro/RTL, tres colores, `panel` sí/no, 420px. Cero errores de
página. Gates: `blocks:check` verde (10 blocks) · `svelte-check` sin errores
propios · prettier limpio.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
// The box-model reset the section needs. Imported HERE as well as in `BootUix`
|
|
|
|
|
|
// because this shell boots UIX inline instead of going through it — the
|
|
|
|
|
|
// previews get it from `BootUix`, the gallery from this line.
|
|
|
|
|
|
import './_lib/reset.css';
|
demo(blocks): la sección tiene cromo de verdad — tema, idioma, dirección, densidad y catálogo
La crítica era exacta: no se podía cambiar a oscuro, ni de idioma, ni había
forma de moverse entre blocks. La sección arrancaba UIX y renderizaba la
página desnuda, con un comentario que decía que el modo seguía al sistema
operativo «para verificar oscuro emulando prefers-color-scheme» — cómodo para
mí, inútil para quien mira la página.
Ahora hay shell: topbar pegajosa con los ejes que de verdad mueven el
framework (idioma ES/EN/FR/DE y dirección como INTENTS de prefs, así que
llegan a langs, formatos y al AGENTS.md debug.log routes tsconfig.json
CLAUDE.md docs scripts tsconfig.tsbuildinfo
README.md node_modules src vite.config.ts
STUMBLES.md package-lock.json static web
audit package.json svelte.config.js worker.js
build plans tmp workers del documento por el camino del sistema;
densidad proyectada en :root para que la hereden también los overlays
porteados; y el conmutador de tema, que alimenta el del
ActiveEidos) y un raíl con el catálogo entero de los 27 blocks planificados,
marcando el actual y atenuando los que aún no existen. Todo persiste en
localStorage, así que una recarga te deja donde estabas.
El catálogo pasa a : raíl y galería leen la MISMA fuente, y
un block que aterriza no hay que recordarlo en dos sitios.
Las tres regiones las coloca — cromo de app-land, el papel que
hace en las docs de componentes; la regla de «sin CSS» del contrato
B es para el tier (), no para el sitio que lo enseña. Dentro
de esas regiones todo son componentes del canon.
Verificado en navegador: el botón conmuta a oscuro de verdad (fondo
oklch(0.1776 0 0)), el idioma llega a , el raíl lista los 27 y
desaparece por debajo de 64rem sin desbordes, cero errores de consola.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
|
|
|
|
import './blocks.css';
|
|
|
|
|
|
|
|
|
|
|
|
let { children } = $props();
|
|
|
|
|
|
|
demo(blocks): la sección tiene cromo de verdad — tema, idioma, dirección, densidad y catálogo
La crítica era exacta: no se podía cambiar a oscuro, ni de idioma, ni había
forma de moverse entre blocks. La sección arrancaba UIX y renderizaba la
página desnuda, con un comentario que decía que el modo seguía al sistema
operativo «para verificar oscuro emulando prefers-color-scheme» — cómodo para
mí, inútil para quien mira la página.
Ahora hay shell: topbar pegajosa con los ejes que de verdad mueven el
framework (idioma ES/EN/FR/DE y dirección como INTENTS de prefs, así que
llegan a langs, formatos y al AGENTS.md debug.log routes tsconfig.json
CLAUDE.md docs scripts tsconfig.tsbuildinfo
README.md node_modules src vite.config.ts
STUMBLES.md package-lock.json static web
audit package.json svelte.config.js worker.js
build plans tmp workers del documento por el camino del sistema;
densidad proyectada en :root para que la hereden también los overlays
porteados; y el conmutador de tema, que alimenta el del
ActiveEidos) y un raíl con el catálogo entero de los 27 blocks planificados,
marcando el actual y atenuando los que aún no existen. Todo persiste en
localStorage, así que una recarga te deja donde estabas.
El catálogo pasa a : raíl y galería leen la MISMA fuente, y
un block que aterriza no hay que recordarlo en dos sitios.
Las tres regiones las coloca — cromo de app-land, el papel que
hace en las docs de componentes; la regla de «sin CSS» del contrato
B es para el tier (), no para el sitio que lo enseña. Dentro
de esas regiones todo son componentes del canon.
Verificado en navegador: el botón conmuta a oscuro de verdad (fondo
oklch(0.1776 0 0)), el idioma llega a , el raíl lista los 27 y
desaparece por debajo de 64rem sin desbordes, cero errores de consola.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
|
|
|
|
type Language = 'es' | 'en' | 'fr' | 'de';
|
|
|
|
|
|
type Density = 'compact' | 'comfortable' | 'spacious';
|
|
|
|
|
|
|
|
|
|
|
|
const blocksPrefsSchema = standardPrefsDimensions({
|
|
|
|
|
|
languages: ['es', 'en', 'fr', 'de'] satisfies readonly Language[],
|
|
|
|
|
|
locales: ['es-ES', 'en-US', 'en-GB', 'de-DE'] as const,
|
|
|
|
|
|
currencies: ['EUR', 'USD', 'GBP', 'JPY'] as const,
|
|
|
|
|
|
defaults: { language: 'es', locale: 'es-ES', currency: 'EUR' }
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const uix = createActiveUix({
|
feat(blocks): contact CERRADO — la coordinacion entra en el contrato B
El estado se le pregunta al ESQUEMA, no al Form. `form.isValid` con
`validationBehaviour: 'progressive'` significa «aun no se ha encontrado nada
mal»: un formulario vacio e intacto no tiene errores, asi que se declaraba
valido y `incomplete` era INALCANZABLE al cargar — la seccion pedia resolver la
verificacion con los tres campos vacios, justo el hueco que la doctrina existe
para cerrar. Ahora la raiz valida los valores con `validateSync` de SIUM:
sincrono y sin escribir errores (`form.validate()` habria encendido los tres
campos en rojo en el primer frame).
`state.test.ts` fija la maquina con 9 casos — primer test unitario del tier,
porque `state.ts` es su primera logica pura: el orden de prioridad, que solo
`ready` deja enviar, y que todo estado bloqueado tiene frase.
Contrato B (architecture/blocks.md): seccion «Coordination» con las tres cosas
que posee un block que coordina (estado, forma de sus datos, palabras), B-5
admite el esquema por defecto, B-7 enmendado (posee las palabras de SUS estados
como idlangref con fallback ingles) y la convencion de servicios acotada: el
traductor es el UNICO servicio sancionado. Dice tambien a quien NO aplica — los
blocks de layout no coordinan nada.
i18n por la via real: el arnes registra el namespace `blocks` en las DOS cadenas
de arranque (galeria y previews, que duplican el boot) y la demo se lee en
castellano en vez de caer al fallback ingles.
Ademas: README y pestanas de doc rehechos al reparto nuevo, ficha F2.13 y
bitacora en PLAN-blocks.md, y el control vivo que faltaba para un prop publico
— `verification` con reto / sin reto, porque omitir el prop no es lo mismo que
pasar un estado que nunca verifica.
Verificado en navegador, arco completo y las dos ramas: sin reto vacio → un
campo → tres campos (se desbloquea) → «Enviando…» → «Enviado»; con reto, con
los tres campos llenos el boton sigue bloqueado y la razon pasa a «Resuelve la
verificacion de arriba». `verifying` y `rejected` quedan cubiertos por test
unitario, no por el reto en vivo: el provider de ProofOfHuman escribe `status`
el mismo y el veredicto del app no se sostiene (hilo de canon abierto).
Gates: blocks:check verde (14 blocks) · vitest 9/9 · docs:check 0 ·
svelte-check sin errores propios · prettier limpio en los ficheros propios.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
langs: {
|
|
|
|
|
|
schema: { sium: siumLangs, secs: secsLangs, blocks: blocksLangs },
|
|
|
|
|
|
defaultLocale: 'es' as const
|
|
|
|
|
|
},
|
fix(blocks): la galeria emite — packs de sema y canales perceptivos en el arnes
El motor SI emitia: pulsar un boton de un block estampa
`data-event=contact-activate` con `family=contact` y `phase=active`, porque el
morfo del `Button` declara ese evento (verbo `activate`, secuencia `pre`, sin
intent a proposito — una pulsacion no carga intencion evaluativa). Lo que
faltaba era el otro lado: la seccion arrancaba UIX **sin `events` y con cero
packs de sema**, frente a los 69 de `/uix`. El evento salia a una sala sin
altavoces. Viene de F0, cuando el arranque se monto como «espejo minimo» de
`/uix` y sema se quedo fuera.
Un framework semantico cuya propia galeria no suena no esta demostrando lo que
existe para demostrar, asi que los canales van ENCENDIDOS aqui: `sound` y
`haptic` a true en las dos cadenas de arranque (galeria y previews).
La lista de packs es DERIVADA del barrel (`Object.values(packs)`), no escrita a
mano, y eso es deliberado: la lista a mano del otro arnes se quedo atras dos
veces — `69c108d2a` tuvo que anadir «los 25 packs que faltaban en la composicion
de demos». Una lista derivada no puede quedarse atras. El barrel recomienda
importar solo los que usas por tree-shaking; aqui no aplica, porque esto no es
un producto sino la galeria del framework y un block compone lo que quiera del
canon.
Verificado espiando la Web Audio API en un clic real dentro del block: al cargar
1 AudioContext y 0 fuentes; tras pulsar, 2 fuentes y 3 nodos de ganancia mas. Y
las 15 demos cargan limpias con los 69 packs, cero errores de pagina.
Gates: blocks:check verde (15) · svelte-check sin errores en lo tocado ·
prettier limpio.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2 months ago
|
|
|
|
// The blocks tier is shown, not shipped: this is the gallery of a SEMANTIC
|
|
|
|
|
|
// framework, so the perceptual channels are on. Without this the engine
|
|
|
|
|
|
// still stamps `data-event-*` correctly and nothing is ever audible —
|
|
|
|
|
|
// which is how the section shipped from F0.
|
|
|
|
|
|
events: { sound: true, haptic: true, components: semaPacks },
|
demo(blocks): la sección tiene cromo de verdad — tema, idioma, dirección, densidad y catálogo
La crítica era exacta: no se podía cambiar a oscuro, ni de idioma, ni había
forma de moverse entre blocks. La sección arrancaba UIX y renderizaba la
página desnuda, con un comentario que decía que el modo seguía al sistema
operativo «para verificar oscuro emulando prefers-color-scheme» — cómodo para
mí, inútil para quien mira la página.
Ahora hay shell: topbar pegajosa con los ejes que de verdad mueven el
framework (idioma ES/EN/FR/DE y dirección como INTENTS de prefs, así que
llegan a langs, formatos y al AGENTS.md debug.log routes tsconfig.json
CLAUDE.md docs scripts tsconfig.tsbuildinfo
README.md node_modules src vite.config.ts
STUMBLES.md package-lock.json static web
audit package.json svelte.config.js worker.js
build plans tmp workers del documento por el camino del sistema;
densidad proyectada en :root para que la hereden también los overlays
porteados; y el conmutador de tema, que alimenta el del
ActiveEidos) y un raíl con el catálogo entero de los 27 blocks planificados,
marcando el actual y atenuando los que aún no existen. Todo persiste en
localStorage, así que una recarga te deja donde estabas.
El catálogo pasa a : raíl y galería leen la MISMA fuente, y
un block que aterriza no hay que recordarlo en dos sitios.
Las tres regiones las coloca — cromo de app-land, el papel que
hace en las docs de componentes; la regla de «sin CSS» del contrato
B es para el tier (), no para el sitio que lo enseña. Dentro
de esas regiones todo son componentes del canon.
Verificado en navegador: el botón conmuta a oscuro de verdad (fondo
oklch(0.1776 0 0)), el idioma llega a , el raíl lista los 27 y
desaparece por debajo de 64rem sin desbordes, cero errores de consola.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
|
|
|
|
prefs: { schema: blocksPrefsSchema }
|
|
|
|
|
|
});
|
|
|
|
|
|
setActiveUix(uix);
|
|
|
|
|
|
Soma.create();
|
|
|
|
|
|
|
demo(blocks): la sección tiene cromo de verdad — tema, idioma, dirección, densidad y catálogo
La crítica era exacta: no se podía cambiar a oscuro, ni de idioma, ni había
forma de moverse entre blocks. La sección arrancaba UIX y renderizaba la
página desnuda, con un comentario que decía que el modo seguía al sistema
operativo «para verificar oscuro emulando prefers-color-scheme» — cómodo para
mí, inútil para quien mira la página.
Ahora hay shell: topbar pegajosa con los ejes que de verdad mueven el
framework (idioma ES/EN/FR/DE y dirección como INTENTS de prefs, así que
llegan a langs, formatos y al AGENTS.md debug.log routes tsconfig.json
CLAUDE.md docs scripts tsconfig.tsbuildinfo
README.md node_modules src vite.config.ts
STUMBLES.md package-lock.json static web
audit package.json svelte.config.js worker.js
build plans tmp workers del documento por el camino del sistema;
densidad proyectada en :root para que la hereden también los overlays
porteados; y el conmutador de tema, que alimenta el del
ActiveEidos) y un raíl con el catálogo entero de los 27 blocks planificados,
marcando el actual y atenuando los que aún no existen. Todo persiste en
localStorage, así que una recarga te deja donde estabas.
El catálogo pasa a : raíl y galería leen la MISMA fuente, y
un block que aterriza no hay que recordarlo en dos sitios.
Las tres regiones las coloca — cromo de app-land, el papel que
hace en las docs de componentes; la regla de «sin CSS» del contrato
B es para el tier (), no para el sitio que lo enseña. Dentro
de esas regiones todo son componentes del canon.
Verificado en navegador: el botón conmuta a oscuro de verdad (fondo
oklch(0.1776 0 0)), el idioma llega a , el raíl lista los 27 y
desaparece por debajo de 64rem sin desbordes, cero errores de consola.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
|
|
|
|
// ── Axes ──────────────────────────────────────────────────────────────
|
|
|
|
|
|
let mode = $state<'light' | 'dark'>('light');
|
demo(blocks): la sección tiene cromo de verdad — tema, idioma, dirección, densidad y catálogo
La crítica era exacta: no se podía cambiar a oscuro, ni de idioma, ni había
forma de moverse entre blocks. La sección arrancaba UIX y renderizaba la
página desnuda, con un comentario que decía que el modo seguía al sistema
operativo «para verificar oscuro emulando prefers-color-scheme» — cómodo para
mí, inútil para quien mira la página.
Ahora hay shell: topbar pegajosa con los ejes que de verdad mueven el
framework (idioma ES/EN/FR/DE y dirección como INTENTS de prefs, así que
llegan a langs, formatos y al AGENTS.md debug.log routes tsconfig.json
CLAUDE.md docs scripts tsconfig.tsbuildinfo
README.md node_modules src vite.config.ts
STUMBLES.md package-lock.json static web
audit package.json svelte.config.js worker.js
build plans tmp workers del documento por el camino del sistema;
densidad proyectada en :root para que la hereden también los overlays
porteados; y el conmutador de tema, que alimenta el del
ActiveEidos) y un raíl con el catálogo entero de los 27 blocks planificados,
marcando el actual y atenuando los que aún no existen. Todo persiste en
localStorage, así que una recarga te deja donde estabas.
El catálogo pasa a : raíl y galería leen la MISMA fuente, y
un block que aterriza no hay que recordarlo en dos sitios.
Las tres regiones las coloca — cromo de app-land, el papel que
hace en las docs de componentes; la regla de «sin CSS» del contrato
B es para el tier (), no para el sitio que lo enseña. Dentro
de esas regiones todo son componentes del canon.
Verificado en navegador: el botón conmuta a oscuro de verdad (fondo
oklch(0.1776 0 0)), el idioma llega a , el raíl lista los 27 y
desaparece por debajo de 64rem sin desbordes, cero errores de consola.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
|
|
|
|
let language = $state<Language>('es');
|
|
|
|
|
|
let dir = $state<'ltr' | 'rtl'>('ltr');
|
|
|
|
|
|
let density = $state<Density>('comfortable');
|
|
|
|
|
|
|
|
|
|
|
|
const DENSITY_SCALES: Record<Density, { space: number; control: number }> = {
|
|
|
|
|
|
compact: { space: 0.85, control: 0.9 },
|
|
|
|
|
|
comfortable: { space: 1, control: 1 },
|
|
|
|
|
|
spacious: { space: 1.15, control: 1.1 }
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
const modeListeners = new Set<(value: 'light' | 'dark') => void>();
|
|
|
|
|
|
const activeEidos = ActiveEidos.create({
|
|
|
|
|
|
applyDom: true,
|
|
|
|
|
|
theme: 'base',
|
|
|
|
|
|
modeSource: {
|
|
|
|
|
|
get: () => mode,
|
|
|
|
|
|
onChange(handler) {
|
|
|
|
|
|
modeListeners.add(handler);
|
|
|
|
|
|
return () => modeListeners.delete(handler);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
|
|
|
|
|
|
demo(blocks): la sección tiene cromo de verdad — tema, idioma, dirección, densidad y catálogo
La crítica era exacta: no se podía cambiar a oscuro, ni de idioma, ni había
forma de moverse entre blocks. La sección arrancaba UIX y renderizaba la
página desnuda, con un comentario que decía que el modo seguía al sistema
operativo «para verificar oscuro emulando prefers-color-scheme» — cómodo para
mí, inútil para quien mira la página.
Ahora hay shell: topbar pegajosa con los ejes que de verdad mueven el
framework (idioma ES/EN/FR/DE y dirección como INTENTS de prefs, así que
llegan a langs, formatos y al AGENTS.md debug.log routes tsconfig.json
CLAUDE.md docs scripts tsconfig.tsbuildinfo
README.md node_modules src vite.config.ts
STUMBLES.md package-lock.json static web
audit package.json svelte.config.js worker.js
build plans tmp workers del documento por el camino del sistema;
densidad proyectada en :root para que la hereden también los overlays
porteados; y el conmutador de tema, que alimenta el del
ActiveEidos) y un raíl con el catálogo entero de los 27 blocks planificados,
marcando el actual y atenuando los que aún no existen. Todo persiste en
localStorage, así que una recarga te deja donde estabas.
El catálogo pasa a : raíl y galería leen la MISMA fuente, y
un block que aterriza no hay que recordarlo en dos sitios.
Las tres regiones las coloca — cromo de app-land, el papel que
hace en las docs de componentes; la regla de «sin CSS» del contrato
B es para el tier (), no para el sitio que lo enseña. Dentro
de esas regiones todo son componentes del canon.
Verificado en navegador: el botón conmuta a oscuro de verdad (fondo
oklch(0.1776 0 0)), el idioma llega a , el raíl lista los 27 y
desaparece por debajo de 64rem sin desbordes, cero errores de consola.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
|
|
|
|
// Restore once: a stored choice wins, otherwise the OS scheme decides.
|
|
|
|
|
|
$effect(() => {
|
|
|
|
|
|
if (typeof localStorage === 'undefined') return;
|
|
|
|
|
|
const stored = localStorage.getItem('uix-blocks-prefs');
|
|
|
|
|
|
if (stored) {
|
|
|
|
|
|
try {
|
|
|
|
|
|
const blob = JSON.parse(stored);
|
|
|
|
|
|
if (blob.mode === 'dark' || blob.mode === 'light') mode = blob.mode;
|
|
|
|
|
|
if (blob.language) language = blob.language;
|
|
|
|
|
|
if (blob.dir) dir = blob.dir;
|
|
|
|
|
|
if (blob.density) density = blob.density;
|
|
|
|
|
|
return;
|
|
|
|
|
|
} catch {
|
|
|
|
|
|
/* ignore a corrupt blob */
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
mode = window.matchMedia?.('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
$effect(() => {
|
|
|
|
|
|
if (typeof localStorage === 'undefined') return;
|
|
|
|
|
|
localStorage.setItem('uix-blocks-prefs', JSON.stringify({ mode, language, dir, density }));
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
$effect(() => {
|
demo(blocks): la sección tiene cromo de verdad — tema, idioma, dirección, densidad y catálogo
La crítica era exacta: no se podía cambiar a oscuro, ni de idioma, ni había
forma de moverse entre blocks. La sección arrancaba UIX y renderizaba la
página desnuda, con un comentario que decía que el modo seguía al sistema
operativo «para verificar oscuro emulando prefers-color-scheme» — cómodo para
mí, inútil para quien mira la página.
Ahora hay shell: topbar pegajosa con los ejes que de verdad mueven el
framework (idioma ES/EN/FR/DE y dirección como INTENTS de prefs, así que
llegan a langs, formatos y al AGENTS.md debug.log routes tsconfig.json
CLAUDE.md docs scripts tsconfig.tsbuildinfo
README.md node_modules src vite.config.ts
STUMBLES.md package-lock.json static web
audit package.json svelte.config.js worker.js
build plans tmp workers del documento por el camino del sistema;
densidad proyectada en :root para que la hereden también los overlays
porteados; y el conmutador de tema, que alimenta el del
ActiveEidos) y un raíl con el catálogo entero de los 27 blocks planificados,
marcando el actual y atenuando los que aún no existen. Todo persiste en
localStorage, así que una recarga te deja donde estabas.
El catálogo pasa a : raíl y galería leen la MISMA fuente, y
un block que aterriza no hay que recordarlo en dos sitios.
Las tres regiones las coloca — cromo de app-land, el papel que
hace en las docs de componentes; la regla de «sin CSS» del contrato
B es para el tier (), no para el sitio que lo enseña. Dentro
de esas regiones todo son componentes del canon.
Verificado en navegador: el botón conmuta a oscuro de verdad (fondo
oklch(0.1776 0 0)), el idioma llega a , el raíl lista los 27 y
desaparece por debajo de 64rem sin desbordes, cero errores de consola.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
|
|
|
|
const current = mode;
|
|
|
|
|
|
for (const listener of modeListeners) listener(current);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
demo(blocks): la sección tiene cromo de verdad — tema, idioma, dirección, densidad y catálogo
La crítica era exacta: no se podía cambiar a oscuro, ni de idioma, ni había
forma de moverse entre blocks. La sección arrancaba UIX y renderizaba la
página desnuda, con un comentario que decía que el modo seguía al sistema
operativo «para verificar oscuro emulando prefers-color-scheme» — cómodo para
mí, inútil para quien mira la página.
Ahora hay shell: topbar pegajosa con los ejes que de verdad mueven el
framework (idioma ES/EN/FR/DE y dirección como INTENTS de prefs, así que
llegan a langs, formatos y al AGENTS.md debug.log routes tsconfig.json
CLAUDE.md docs scripts tsconfig.tsbuildinfo
README.md node_modules src vite.config.ts
STUMBLES.md package-lock.json static web
audit package.json svelte.config.js worker.js
build plans tmp workers del documento por el camino del sistema;
densidad proyectada en :root para que la hereden también los overlays
porteados; y el conmutador de tema, que alimenta el del
ActiveEidos) y un raíl con el catálogo entero de los 27 blocks planificados,
marcando el actual y atenuando los que aún no existen. Todo persiste en
localStorage, así que una recarga te deja donde estabas.
El catálogo pasa a : raíl y galería leen la MISMA fuente, y
un block que aterriza no hay que recordarlo en dos sitios.
Las tres regiones las coloca — cromo de app-land, el papel que
hace en las docs de componentes; la regla de «sin CSS» del contrato
B es para el tier (), no para el sitio que lo enseña. Dentro
de esas regiones todo son componentes del canon.
Verificado en navegador: el botón conmuta a oscuro de verdad (fondo
oklch(0.1776 0 0)), el idioma llega a , el raíl lista los 27 y
desaparece por debajo de 64rem sin desbordes, cero errores de consola.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
|
|
|
|
// Language and direction are PREFS intents: they reach langs, formats and the
|
|
|
|
|
|
// document direction through the framework, not through local wiring.
|
|
|
|
|
|
$effect(() => {
|
|
|
|
|
|
uix.prefs.setIntent('language', language);
|
|
|
|
|
|
uix.prefs.setIntent('direction', dir);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
// Density on :root, so portaled overlays get it too.
|
|
|
|
|
|
$effect(() => {
|
|
|
|
|
|
const d = DENSITY_SCALES[density];
|
|
|
|
|
|
uix.dom.writeStyle(
|
|
|
|
|
|
'uix-blocks-display',
|
|
|
|
|
|
`:root{--density-space-scale:${d.space};--density-control-scale:${d.control};}`
|
|
|
|
|
|
);
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
const currentSlug = $derived(page.url.pathname.replace(/^\/blocks\/?/, ''));
|
|
|
|
|
|
|
|
|
|
|
|
onDestroy(() => {
|
|
|
|
|
|
activeEidos.dispose();
|
|
|
|
|
|
uix.dispose();
|
|
|
|
|
|
});
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<svelte:head>
|
|
|
|
|
|
<title>Blocks — UIX</title>
|
|
|
|
|
|
<meta name="color-scheme" content="light dark" />
|
|
|
|
|
|
</svelte:head>
|
|
|
|
|
|
|
demo(blocks): la sección tiene cromo de verdad — tema, idioma, dirección, densidad y catálogo
La crítica era exacta: no se podía cambiar a oscuro, ni de idioma, ni había
forma de moverse entre blocks. La sección arrancaba UIX y renderizaba la
página desnuda, con un comentario que decía que el modo seguía al sistema
operativo «para verificar oscuro emulando prefers-color-scheme» — cómodo para
mí, inútil para quien mira la página.
Ahora hay shell: topbar pegajosa con los ejes que de verdad mueven el
framework (idioma ES/EN/FR/DE y dirección como INTENTS de prefs, así que
llegan a langs, formatos y al AGENTS.md debug.log routes tsconfig.json
CLAUDE.md docs scripts tsconfig.tsbuildinfo
README.md node_modules src vite.config.ts
STUMBLES.md package-lock.json static web
audit package.json svelte.config.js worker.js
build plans tmp workers del documento por el camino del sistema;
densidad proyectada en :root para que la hereden también los overlays
porteados; y el conmutador de tema, que alimenta el del
ActiveEidos) y un raíl con el catálogo entero de los 27 blocks planificados,
marcando el actual y atenuando los que aún no existen. Todo persiste en
localStorage, así que una recarga te deja donde estabas.
El catálogo pasa a : raíl y galería leen la MISMA fuente, y
un block que aterriza no hay que recordarlo en dos sitios.
Las tres regiones las coloca — cromo de app-land, el papel que
hace en las docs de componentes; la regla de «sin CSS» del contrato
B es para el tier (), no para el sitio que lo enseña. Dentro
de esas regiones todo son componentes del canon.
Verificado en navegador: el botón conmuta a oscuro de verdad (fondo
oklch(0.1776 0 0)), el idioma llega a , el raíl lista los 27 y
desaparece por debajo de 64rem sin desbordes, cero errores de consola.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
3 months ago
|
|
|
|
<div data-blocks-shell data-theme={mode} data-mode={mode}>
|
|
|
|
|
|
<header data-blocks-topbar>
|
|
|
|
|
|
<Group align="center" gap={3} justify="start">
|
|
|
|
|
|
<Link href="/blocks" variant="plain" underline="none">
|
|
|
|
|
|
<Group align="center" gap={2} justify="start">
|
|
|
|
|
|
<Icon.Boxes size="sm" />
|
|
|
|
|
|
<Text weight="semibold">Blocks</Text>
|
|
|
|
|
|
</Group>
|
|
|
|
|
|
</Link>
|
|
|
|
|
|
<Badge size="xs" variant="soft">tier</Badge>
|
|
|
|
|
|
</Group>
|
|
|
|
|
|
|
|
|
|
|
|
<Group align="center" gap={4} justify="end">
|
|
|
|
|
|
<Group align="center" gap={2} justify="end">
|
|
|
|
|
|
<Text size="xs" color="muted">idioma</Text>
|
|
|
|
|
|
<ToggleGroup
|
|
|
|
|
|
selectionMode="single"
|
|
|
|
|
|
size="sm"
|
|
|
|
|
|
attached
|
|
|
|
|
|
value={[language]}
|
|
|
|
|
|
onValueChange={(v) => (language = (v[0] ?? language) as Language)}
|
|
|
|
|
|
aria-label="Idioma"
|
|
|
|
|
|
>
|
|
|
|
|
|
{#each ['es', 'en', 'fr', 'de'] as value (value)}
|
|
|
|
|
|
<ToggleGroup.Item {value}>{value.toUpperCase()}</ToggleGroup.Item>
|
|
|
|
|
|
{/each}
|
|
|
|
|
|
</ToggleGroup>
|
|
|
|
|
|
</Group>
|
|
|
|
|
|
|
|
|
|
|
|
<Group align="center" gap={2} justify="end">
|
|
|
|
|
|
<Text size="xs" color="muted">densidad</Text>
|
|
|
|
|
|
<ToggleGroup
|
|
|
|
|
|
selectionMode="single"
|
|
|
|
|
|
size="sm"
|
|
|
|
|
|
attached
|
|
|
|
|
|
value={[density]}
|
|
|
|
|
|
onValueChange={(v) => (density = (v[0] ?? density) as Density)}
|
|
|
|
|
|
aria-label="Densidad"
|
|
|
|
|
|
>
|
|
|
|
|
|
<ToggleGroup.Item value="compact">−</ToggleGroup.Item>
|
|
|
|
|
|
<ToggleGroup.Item value="comfortable">·</ToggleGroup.Item>
|
|
|
|
|
|
<ToggleGroup.Item value="spacious">+</ToggleGroup.Item>
|
|
|
|
|
|
</ToggleGroup>
|
|
|
|
|
|
</Group>
|
|
|
|
|
|
|
|
|
|
|
|
<Group align="center" gap={2} justify="end">
|
|
|
|
|
|
<Text size="xs" color="muted">dir</Text>
|
|
|
|
|
|
<ToggleGroup
|
|
|
|
|
|
selectionMode="single"
|
|
|
|
|
|
size="sm"
|
|
|
|
|
|
attached
|
|
|
|
|
|
value={[dir]}
|
|
|
|
|
|
onValueChange={(v) => (dir = (v[0] ?? dir) as 'ltr' | 'rtl')}
|
|
|
|
|
|
aria-label="Dirección"
|
|
|
|
|
|
>
|
|
|
|
|
|
<ToggleGroup.Item value="ltr">LTR</ToggleGroup.Item>
|
|
|
|
|
|
<ToggleGroup.Item value="rtl">RTL</ToggleGroup.Item>
|
|
|
|
|
|
</ToggleGroup>
|
|
|
|
|
|
</Group>
|
|
|
|
|
|
|
|
|
|
|
|
<Button
|
|
|
|
|
|
size="sm"
|
|
|
|
|
|
variant="ghost"
|
|
|
|
|
|
aria-label={mode === 'light' ? 'Cambiar a modo oscuro' : 'Cambiar a modo claro'}
|
|
|
|
|
|
onclick={() => (mode = mode === 'light' ? 'dark' : 'light')}
|
|
|
|
|
|
>
|
|
|
|
|
|
{#if mode === 'light'}
|
|
|
|
|
|
<Icon.Moon size="sm" />
|
|
|
|
|
|
{:else}
|
|
|
|
|
|
<Icon.Sun size="sm" />
|
|
|
|
|
|
{/if}
|
|
|
|
|
|
</Button>
|
|
|
|
|
|
</Group>
|
|
|
|
|
|
</header>
|
|
|
|
|
|
|
|
|
|
|
|
<div data-blocks-body>
|
|
|
|
|
|
<nav data-blocks-rail aria-label="Catálogo de blocks">
|
|
|
|
|
|
<Stack gap={4}>
|
|
|
|
|
|
{#each BLOCK_CATALOG as group, i (group.title)}
|
|
|
|
|
|
<Stack gap={2}>
|
|
|
|
|
|
<Text size="xs" weight="medium" color="muted">{group.title}</Text>
|
|
|
|
|
|
<Stack gap={1}>
|
|
|
|
|
|
{#each group.items as item (item.slug)}
|
|
|
|
|
|
{#if item.shipped}
|
|
|
|
|
|
<Link href={`/blocks/${item.slug}`} variant="plain" underline="none">
|
|
|
|
|
|
<Text
|
|
|
|
|
|
size="sm"
|
|
|
|
|
|
weight={currentSlug === item.slug ? 'semibold' : 'regular'}
|
|
|
|
|
|
color={currentSlug === item.slug ? 'primary' : 'secondary'}
|
|
|
|
|
|
>
|
|
|
|
|
|
{item.label}
|
|
|
|
|
|
</Text>
|
|
|
|
|
|
</Link>
|
|
|
|
|
|
{:else}
|
|
|
|
|
|
<Text size="sm" color="disabled">{item.label}</Text>
|
|
|
|
|
|
{/if}
|
|
|
|
|
|
{/each}
|
|
|
|
|
|
</Stack>
|
|
|
|
|
|
</Stack>
|
|
|
|
|
|
{#if i < BLOCK_CATALOG.length - 1}
|
|
|
|
|
|
<Separator />
|
|
|
|
|
|
{/if}
|
|
|
|
|
|
{/each}
|
|
|
|
|
|
</Stack>
|
|
|
|
|
|
</nav>
|
|
|
|
|
|
|
|
|
|
|
|
<div data-blocks-content {dir}>
|
|
|
|
|
|
{@render children?.()}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|