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/temas/grafito/+page.svelte

1005 lines
40 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">
/**
* Showcase del tema Untitled UI — estructurado por secciones (estilo
* Radix Themes): un TOC lateral sticky + Fundamentos (color, tipografía,
* espaciado, densidad & scaling) + Componentes + Sistema (semántica).
* Todo se renderiza con componentes Eidos reales sobre el tema.
*/
import { onMount } from 'svelte'
import Button from '$uix/eidos/components/button'
import Badge from '$uix/eidos/components/badge'
import Card from '$uix/eidos/components/card'
import Field from '$uix/eidos/components/field'
import Select from '$uix/eidos/components/select'
import Checkbox from '$uix/eidos/components/checkbox'
import RadioGroup from '$uix/eidos/components/radio-group'
import Switch from '$uix/eidos/components/switch'
import Slider from '$uix/eidos/components/slider'
import Progress from '$uix/eidos/components/progress'
import Banner from '$uix/eidos/components/banner'
import Avatar from '$uix/eidos/components/avatar'
import Separator from '$uix/eidos/components/separator'
import Tabs from '$uix/eidos/components/tabs'
import Accordion from '$uix/eidos/components/accordion'
import Toggle from '$uix/eidos/components/toggle'
import ToggleGroup from '$uix/eidos/components/toggle-group'
import Toolbar from '$uix/eidos/components/toolbar'
import Popover from '$uix/eidos/components/popover'
import Dialog from '$uix/eidos/components/dialog'
import DropdownMenu from '$uix/eidos/components/dropdown-menu'
import ContextMenu from '$uix/eidos/components/context-menu'
import Menubar from '$uix/eidos/components/menubar'
import Tooltip from '$uix/eidos/components/tooltip'
import { THEME_SCALES, THEME_INTENTS, COLOR_STEPS } from '../_lib/grafito'
// ── Hex resolución (lee los literales de las escalas en runtime) ──
let hex = $state<Record<string, string>>({})
function readHex() {
if (typeof document === 'undefined') return
const cs = getComputedStyle(document.documentElement)
const out: Record<string, string> = {}
for (const sc of THEME_SCALES) {
for (const step of COLOR_STEPS) {
const v = cs.getPropertyValue(`--scale-${sc.name}-${step}`).trim()
if (v) out[`${sc.name}-${step}`] = v
}
}
hex = out
}
function luminance(value: string): number {
const m = value.replace('#', '')
if (m.length < 6) return 0.5
const r = parseInt(m.slice(0, 2), 16) / 255
const g = parseInt(m.slice(2, 4), 16) / 255
const b = parseInt(m.slice(4, 6), 16) / 255
return 0.2126 * r + 0.7152 * g + 0.0722 * b
}
const stepInk = (key: string) =>
luminance(hex[key] ?? '#000000') > 0.55 ? '#101828' : '#ffffff'
// ── Métricas en vivo de los ejes densidad + scaling ──────────────
// Se leen de una sonda oculta (los custom props devuelven el `calc()`
// sin resolver; un elemento real sí da el px computado).
let axisProbe = $state<HTMLDivElement | null>(null)
let axis = $state({ density: 'comfortable', scaling: '100', space4: '', fontMd: '', ctrlMd: '' })
function readAxis() {
if (typeof document === 'undefined') return
const root = document.documentElement
const cs = axisProbe ? getComputedStyle(axisProbe) : null
axis = {
density: root.getAttribute('data-density') ?? 'comfortable',
scaling: root.getAttribute('data-scaling') ?? '100',
space4: cs ? cs.width : '',
fontMd: cs ? cs.fontSize : '',
ctrlMd: cs ? cs.height : ''
}
}
// ── Datos de las secciones de tokens ──────────────────────────────
const TYPE_STYLES = [
{ key: 'hero', label: 'Hero', sample: 'Diseña lo que ocurre' },
{ key: 'h1', label: 'Heading 1', sample: 'The quick brown fox' },
{ key: 'h2', label: 'Heading 2', sample: 'The quick brown fox' },
{ key: 'h3', label: 'Heading 3', sample: 'The quick brown fox jumps' },
{ key: 'h4', label: 'Heading 4', sample: 'The quick brown fox jumps over' },
{ key: 'body', label: 'Body', sample: 'The quick brown fox jumps over the lazy dog.' },
{ key: 'label', label: 'Label', sample: 'Email address' },
{ key: 'caption', label: 'Caption', sample: 'Last updated 3 minutes ago' },
{ key: 'code', label: 'Code', sample: 'const theme = "grafito"' }
]
const SPACE = ['0', '0-5', '1', '1-5', '2', '2-5', '3', '3-5', '4', '5', '6', '8', '10', '12', '16']
const RADII = ['none', 'sm', 'md', 'lg', 'xl', 'xxl']
const SHADOWS = ['1', '2', '3', '4', '5', '6']
const SIZES = ['xxs', 'xs', 'sm', 'md', 'lg', 'xl', 'xxl']
const BTN_VARIANTS = ['solid', 'soft', 'surface', 'outline', 'ghost', 'plain'] as const
const BTN_SIZES = ['xs', 'sm', 'md', 'lg', 'xl'] as const
const CHIP_VARIANTS = ['soft', 'solid', 'outline', 'ghost'] as const
const BADGE_COLORS = ['primary', 'neutral', 'affirm', 'fulfill', 'risk', 'threat', 'loss'] as const
// ── Estado de los controles interactivos ──────────────────────────
let email = $state('olivia@untitledui.com')
let fruit = $state<string[]>(['mango'])
let agree = $state(true)
let notify = $state(false)
let plan = $state('pro')
let wifi = $state(true)
let analytics = $state(false)
let volume = $state([64])
let tab = $state('overview')
let tabsPills = $state('account')
let faq = $state<string[]>(['what'])
let bold = $state(true)
let fmt = $state<string[]>(['bold'])
let align = $state<string[]>(['left'])
let toolbarFmt = $state<string[]>(['bold'])
// ── Estado de los overlays / menús ────────────────────────────────
let menuNotifications = $state(true)
let menuTheme = $state('system')
let menubarValue = $state('')
// ── TOC + scrollspy ───────────────────────────────────────────────
const TOC = [
{
group: 'Fundamentos',
items: [
{ id: 'color', label: 'Color' },
{ id: 'typography', label: 'Tipografía' },
{ id: 'spacing', label: 'Espaciado & tamaño' },
{ id: 'axes', label: 'Densidad & Scaling' }
]
},
{
group: 'Componentes',
items: [
{ id: 'buttons', label: 'Botones' },
{ id: 'badges', label: 'Badges' },
{ id: 'forms', label: 'Formulario' },
{ id: 'feedback', label: 'Feedback' },
{ id: 'tabs', label: 'Tabs' },
{ id: 'disclosure', label: 'Disclosure' },
{ id: 'toggles', label: 'Toggles' },
{ id: 'toolbar', label: 'Toolbar' },
{ id: 'overlays', label: 'Overlays' },
{ id: 'menus', label: 'Menús' }
]
},
{ group: 'Sistema', items: [{ id: 'sema', label: 'Semántica' }] }
]
let activeSection = $state('color')
onMount(() => {
readHex()
readAxis()
const mo = new MutationObserver(() => {
readHex()
readAxis()
})
mo.observe(document.documentElement, {
attributes: true,
attributeFilter: ['data-mode', 'data-theme', 'data-density', 'data-scaling']
})
const sections = [...document.querySelectorAll('section[data-temas-section][id]')]
const io = new IntersectionObserver(
(entries) => {
for (const e of entries) {
if (e.isIntersecting) activeSection = (e.target as HTMLElement).id
}
},
{ rootMargin: '-100px 0px -65% 0px' }
)
for (const s of sections) io.observe(s)
return () => {
mo.disconnect()
io.disconnect()
}
})
</script>
{#snippet plusIcon()}
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M12 5v14M5 12h14" />
</svg>
{/snippet}
{#snippet arrowIcon()}
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
<path d="M5 12h14M13 6l6 6-6 6" />
</svg>
{/snippet}
<!-- ═══ Hero ═══════════════════════════════════════════════════════ -->
<section data-temas-hero>
<h1>Grafito</h1>
<p>
Tema para activeUIX sobre el sistema de theming de Eidos. Primario <strong>carbón</strong>
monocromo, tipografía Inter, paleta derivada de Untitled UI (31 escalas), radios de 8px,
sombras en capas. Los 3 roles de jerarquía aliasan la paleta; los 6 intents auto-derivan por
la convención del libro — sin inventar variants ni roles nuevos.
</p>
<div data-temas-hero-meta>
<span data-temas-pill><i style="background: var(--color-primary-solid)"></i> Carbon · #1F2024</span>
<span data-temas-pill><i style="background: var(--color-content-primary)"></i> Inter</span>
<span data-temas-pill><i style="background: var(--color-fulfill-solid)"></i> 9 roles · 5 variants</span>
<span data-temas-pill><i style="background: var(--color-border-strong)"></i> Light · Dark · Density · Scaling</span>
</div>
</section>
<div data-temas-layout>
<aside data-temas-toc>
<nav aria-label="Secciones del tema">
{#each TOC as grp}
<p data-temas-toc-group>{grp.group}</p>
<ul>
{#each grp.items as it}
<li>
<a
href="#{it.id}"
data-active={activeSection === it.id ? 'true' : 'false'}
onclick={() => (activeSection = it.id)}
>
{it.label}
</a>
</li>
{/each}
</ul>
{/each}
</nav>
</aside>
<div data-temas-content>
<p data-temas-group-head>Fundamentos</p>
<!-- ═══ Color ══════════════════════════════════════════════════ -->
<section data-temas-section id="color">
<div data-temas-section-head>
<h2>Color</h2>
<p>
Tres capas: la <strong>Paleta</strong> (escalas, directamente usables) → los
<strong>Roles</strong> de jerarquía la aliasan → los <strong>Intents</strong> auto-derivan
de la paleta por la convención del libro (identidad = step 9). Los componentes pueden
override su color a cualquier escala. Los 9 roles son canon fijo; el tema solo trae la
paleta y mapea la jerarquía.
</p>
</div>
<div data-temas-stack>
<p data-temas-subhead>Paleta · escalas de 12 pasos</p>
<p data-temas-axis-note>Cada paso es directamente usable — p. ej. <code>var(--scale-teal-10)</code>.</p>
{#each THEME_SCALES as sc}
<div data-temas-ramp>
<div data-temas-ramp-head>
<strong>{sc.label}</strong>
<code>{hex[`${sc.name}-9`] ?? `--scale-${sc.name}-9`}</code>
</div>
<div data-temas-ramp-steps>
{#each COLOR_STEPS as step}
<div
data-temas-step
style="background: var(--scale-{sc.name}-{step}); color: {stepInk(`${sc.name}-${step}`)}"
title={hex[`${sc.name}-${step}`] ?? ''}
>
{step}
</div>
{/each}
</div>
</div>
{/each}
<div data-temas-step-legend>
<span>1–2 fondos</span>
<span>3–5 componente</span>
<span>6–8 bordes</span>
<span>9–10 sólido</span>
<span>11–12 texto</span>
</div>
</div>
<div data-temas-stack>
<p data-temas-subhead>Roles de jerarquía · alias explícito a una escala</p>
<div data-temas-roles>
{#each [{ role: 'primary', label: 'Primary', scale: 'carbon' }, { role: 'secondary', label: 'Secondary', scale: 'violet' }, { role: 'tertiary', label: 'Tertiary', scale: 'blue' }] as h}
<div data-temas-role>
<div data-temas-role-solid style="background: var(--color-{h.role}-solid)"></div>
<div data-temas-role-body>
<strong>{h.label}</strong>
<small>alias → <code>{h.scale}</code></small>
<div data-temas-role-tints>
<i style="background: var(--color-{h.role}-surface)" title="surface"></i>
<i style="background: var(--color-{h.role}-border)" title="border"></i>
<i style="background: var(--color-{h.role}-solid)" title="solid"></i>
<i style="background: var(--color-{h.role}-text)" title="text"></i>
</div>
</div>
</div>
{/each}
</div>
</div>
<div data-temas-stack>
<p data-temas-subhead>Intents · auto-derivados de la paleta (convención del libro)</p>
<div data-temas-roles>
{#each THEME_INTENTS as it}
<div data-temas-role>
<div data-temas-role-solid style="background: var(--color-{it.role}-solid)"></div>
<div data-temas-role-body>
<strong>{it.label}</strong>
<small>auto → <code>{it.scale}</code></small>
<div data-temas-role-tints>
<i style="background: var(--color-{it.role}-surface)" title="surface"></i>
<i style="background: var(--color-{it.role}-track)" title="track"></i>
<i style="background: var(--color-{it.role}-element)" title="element"></i>
<i style="background: var(--color-{it.role}-border)" title="border"></i>
<i style="background: var(--color-{it.role}-solid)" title="solid"></i>
<i style="background: var(--color-{it.role}-text)" title="text"></i>
</div>
</div>
</div>
{/each}
</div>
</div>
<div data-temas-stack>
<p data-temas-subhead>Superficies, contenido y bordes</p>
<div data-temas-surfaces>
<div data-temas-surface style="background: var(--color-surface-default)">
<span>surface</span><code>default</code>
</div>
<div data-temas-surface style="background: var(--color-surface-raised)">
<span>surface</span><code>raised</code>
</div>
<div data-temas-surface style="background: var(--color-surface-muted)">
<span>surface</span><code>muted</code>
</div>
<div data-temas-surface style="background: var(--color-content-primary); color: var(--color-surface-default)">
<span>content</span><code style="color: inherit; opacity: .7">primary</code>
</div>
<div data-temas-surface style="background: var(--color-content-secondary); color: var(--color-surface-default)">
<span>content</span><code style="color: inherit; opacity: .7">secondary</code>
</div>
<div data-temas-surface style="background: var(--color-surface-raised); border-color: var(--color-border-strong); border-width: 2px">
<span>border</span><code>strong</code>
</div>
</div>
</div>
</section>
<!-- ═══ Tipografía ═════════════════════════════════════════════ -->
<section data-temas-section id="typography">
<div data-temas-section-head>
<h2>Tipografía</h2>
<p>Inter para display y texto. Named styles del sistema (hero → caption + code).</p>
</div>
<div data-temas-panel>
{#each TYPE_STYLES as t}
<div data-temas-type-row>
<div data-temas-type-meta>
<strong>{t.label}</strong>
<code>--style-{t.key}</code>
</div>
<div
data-temas-type-sample
style="font-family: var(--style-{t.key}-font-family); font-size: var(--style-{t.key}-font-size); font-weight: var(--style-{t.key}-font-weight); line-height: var(--style-{t.key}-line-height); letter-spacing: var(--style-{t.key}-letter-spacing);"
>
{t.sample}
</div>
</div>
{/each}
</div>
</section>
<!-- ═══ Espaciado / Radio / Sombra / Tamaño ════════════════════ -->
<section data-temas-section id="spacing">
<div data-temas-section-head>
<h2>Espaciado, radio, sombra y tamaño</h2>
<p>Primitivas estables del tema. La escala base es de 4px; controles a 8px de radio.</p>
</div>
<div data-temas-fieldset>
<div data-temas-panel data-temas-stack>
<p data-temas-subhead>Spacing</p>
{#each SPACE as k}
<div data-temas-space-row>
<code>--space-{k}</code>
<div data-temas-space-bar style="inline-size: var(--space-{k})"></div>
</div>
{/each}
</div>
<div data-temas-stack>
<div data-temas-panel data-temas-stack>
<p data-temas-subhead>Radius</p>
<div data-temas-tiles>
{#each RADII as k}
<div data-temas-radius-tile style="border-radius: var(--radius-{k})">{k}</div>
{/each}
</div>
</div>
<div data-temas-panel data-temas-stack>
<p data-temas-subhead>Sizes · control-height</p>
{#each SIZES as k}
<div data-temas-size-row>
<div data-temas-size-bar style="block-size: var(--size-{k}-control-height)">{k}</div>
<code style="color: var(--color-content-muted); font-family: var(--font-mono); font-size: var(--font-size-xs)">var(--size-{k}-control-height)</code>
</div>
{/each}
</div>
</div>
</div>
<div data-temas-panel data-temas-stack>
<p data-temas-subhead>Shadows</p>
<div data-temas-tiles>
{#each SHADOWS as k}
<div data-temas-shadow-tile style="box-shadow: var(--shadow-{k})">shadow-{k}</div>
{/each}
</div>
</div>
</section>
<!-- ═══ Densidad & Scaling ═════════════════════════════════════ -->
<section data-temas-section id="axes">
<div data-temas-section-head>
<h2>Densidad &amp; Scaling</h2>
<p>Dos ejes ortogonales que se multiplican. Cámbialos en la barra superior y mira cómo reaccionan estas métricas y el specimen en vivo.</p>
</div>
<div data-temas-fieldset>
<div data-temas-panel data-temas-stack>
<p data-temas-subhead>Densidad · {axis.density}</p>
<p data-temas-axis-note>Ritmo de layout (espacio) + altura de control. La tipografía NO cambia con la densidad.</p>
<div data-temas-axis-metrics>
<div><code>--space-4</code><strong>{axis.space4 || '—'}</strong></div>
<div><code>--control-height-md</code><strong>{axis.ctrlMd || '—'}</strong></div>
</div>
</div>
<div data-temas-panel data-temas-stack>
<p data-temas-subhead>Scaling · {axis.scaling}%</p>
<p data-temas-axis-note>Zoom global (paridad Radix) — escala TODO proporcionalmente, incluida la tipografía. No toca radio, borde ni sombra.</p>
<div data-temas-axis-metrics>
<div><code>--font-size-md</code><strong>{axis.fontMd || '—'}</strong></div>
<div><code>--space-4 × scaling</code><strong>{axis.space4 || '—'}</strong></div>
</div>
</div>
<div data-temas-panel data-temas-stack>
<p data-temas-subhead>Specimen en vivo</p>
<div data-temas-cluster>
<Button size="md">Acción</Button>
<Badge color="primary" variant="soft">v2.4</Badge>
</div>
<p style="margin: 0; color: var(--color-content-secondary)">
Texto de cuerpo: escala con <strong>scaling</strong>, estable bajo <strong>densidad</strong>.
</p>
</div>
</div>
<!-- sonda oculta para leer las métricas resueltas en px -->
<div
bind:this={axisProbe}
aria-hidden="true"
style="position: absolute; visibility: hidden; pointer-events: none; inline-size: var(--space-4); block-size: var(--control-height-md); font-size: var(--font-size-md)"
></div>
</section>
<p data-temas-group-head>Componentes</p>
<!-- ═══ Botones ════════════════════════════════════════════════ -->
<section data-temas-section id="buttons">
<div data-temas-section-head>
<h2>Botones</h2>
<p>6 variants · 9 roles · 5 tamaños · estados. El primario es carbón; el texto sobre sólidos claros resuelve a oscuro por luminancia.</p>
</div>
<div data-temas-demo>
<div data-temas-demo-block>
<p data-temas-subhead>Variants</p>
<div data-temas-cluster>
{#each BTN_VARIANTS as v}
<Button variant={v}>{v}</Button>
{/each}
</div>
</div>
<div data-temas-demo-block>
<p data-temas-subhead>Roles e intents</p>
<div data-temas-cluster>
<Button color="primary">Primary</Button>
<Button color="secondary" variant="surface">Secondary</Button>
<Button color="neutral" variant="outline">Neutral</Button>
<Button intent="affirm">Affirm</Button>
<Button intent="fulfill">Fulfill</Button>
<Button intent="risk">Risk</Button>
<Button intent="threat">Threat</Button>
<Button intent="loss">Loss</Button>
</div>
</div>
<div data-temas-demo-block>
<p data-temas-subhead>Tamaños</p>
<div data-temas-cluster>
{#each BTN_SIZES as sz}
<Button size={sz}>Button {sz}</Button>
{/each}
</div>
</div>
<div data-temas-demo-block>
<p data-temas-subhead>Con icono y estados</p>
<div data-temas-cluster>
<Button icon={plusIcon}>Nuevo</Button>
<Button variant="outline" endIcon={arrowIcon}>Continuar</Button>
<Button iconOnly icon={plusIcon} aria-label="Añadir" />
<Button loading>Guardando</Button>
<Button disabled>Desactivado</Button>
<Button intent="threat" variant="soft">Eliminar</Button>
</div>
</div>
</div>
</section>
<!-- ═══ Badges ═════════════════════════════════════════════════ -->
<section data-temas-section id="badges">
<div data-temas-section-head>
<h2>Badges</h2>
<p>Pills de estado en los 4 chip-variants y la paleta completa de roles.</p>
</div>
<div data-temas-demo>
<div data-temas-demo-block>
<p data-temas-subhead>Colores (soft)</p>
<div data-temas-cluster>
{#each BADGE_COLORS as c}
<Badge color={c} dot>{c}</Badge>
{/each}
</div>
</div>
<div data-temas-demo-block>
<p data-temas-subhead>Variants</p>
<div data-temas-cluster>
{#each CHIP_VARIANTS as v}
<Badge color="primary" variant={v}>{v}</Badge>
{/each}
<Badge color="fulfill" variant="soft">Activo</Badge>
<Badge color="risk" variant="soft" removable onRemove={() => {}}>Filtro</Badge>
</div>
</div>
</div>
</section>
<!-- ═══ Formulario ═════════════════════════════════════════════ -->
<section data-temas-section id="forms">
<div data-temas-section-head>
<h2>Controles de formulario</h2>
<p>Field, Select, Checkbox, Radio, Switch y Slider con el aspecto del tema.</p>
</div>
<div data-temas-fieldset>
<div data-temas-panel data-temas-stack>
<Field name="email">
<Field.Label>Email <Field.RequiredIndicator /></Field.Label>
<Field.Control>
<Field.Input type="email" bind:value={email} placeholder="tú@empresa.com" />
</Field.Control>
<Field.HelperText>Usaremos esto para iniciar sesión.</Field.HelperText>
</Field>
<Field name="fruit">
<Field.Label>Fruta favorita</Field.Label>
<Select bind:value={fruit}>
<Select.Trigger>
<Select.Value placeholder="Elige una fruta" />
<Select.Indicator />
</Select.Trigger>
<Select.Portal>
<Select.Content sideOffset={6}>
<Select.Viewport>
<Select.Item value="mango" label="Mango">Mango<Select.ItemIndicator /></Select.Item>
<Select.Item value="lychee" label="Lichi">Lichi<Select.ItemIndicator /></Select.Item>
<Select.Item value="guava" label="Guayaba">Guayaba<Select.ItemIndicator /></Select.Item>
<Select.Item value="papaya" label="Papaya">Papaya<Select.ItemIndicator /></Select.Item>
</Select.Viewport>
</Select.Content>
</Select.Portal>
</Select>
</Field>
</div>
<div data-temas-panel data-temas-stack>
<p data-temas-subhead>Selección</p>
<label data-temas-cluster style="cursor: pointer">
<Checkbox bind:checked={agree}><Checkbox.Indicator /></Checkbox>
<span>Acepto los términos del servicio</span>
</label>
<label data-temas-cluster style="cursor: pointer">
<Checkbox bind:checked={notify} color="affirm"><Checkbox.Indicator /></Checkbox>
<span>Enviarme novedades del producto</span>
</label>
<Separator />
<RadioGroup bind:value={plan}>
<RadioGroup.Label data-temas-subhead>Plan</RadioGroup.Label>
<label data-temas-cluster style="cursor: pointer">
<RadioGroup.Item value="starter"><RadioGroup.Indicator /></RadioGroup.Item>
<span>Starter</span>
</label>
<label data-temas-cluster style="cursor: pointer">
<RadioGroup.Item value="pro"><RadioGroup.Indicator /></RadioGroup.Item>
<span>Pro</span>
</label>
<label data-temas-cluster style="cursor: pointer">
<RadioGroup.Item value="enterprise"><RadioGroup.Indicator /></RadioGroup.Item>
<span>Enterprise</span>
</label>
</RadioGroup>
</div>
<div data-temas-panel data-temas-stack>
<p data-temas-subhead>Switch & Slider</p>
<label data-temas-cluster style="justify-content: space-between; cursor: pointer">
<span>Wi-Fi</span>
<Switch bind:checked={wifi}><Switch.Thumb /></Switch>
</label>
<label data-temas-cluster style="justify-content: space-between; cursor: pointer">
<span>Analítica</span>
<Switch bind:checked={analytics} intent="affirm"><Switch.Thumb /></Switch>
</label>
<Separator />
<div data-temas-stack style="gap: var(--space-2)">
<span data-temas-subhead style="margin: 0">Volumen · {volume[0]}%</span>
<Slider bind:value={volume} min={0} max={100} aria-label="Volumen">
<Slider.Range />
<Slider.Thumb index={0} />
</Slider>
</div>
</div>
</div>
</section>
<!-- ═══ Feedback ═══════════════════════════════════════════════ -->
<section data-temas-section id="feedback">
<div data-temas-section-head>
<h2>Feedback y estado</h2>
<p>Banners por intent, progreso, avatares y tarjetas.</p>
</div>
<div data-temas-stack>
<Banner intent="primary" variant="soft">Tu prueba gratuita termina en 7 días. Mejora tu plan cuando quieras.</Banner>
<Banner intent="fulfill" variant="soft">Cambios guardados correctamente.</Banner>
<Banner intent="risk" variant="soft">Tu método de pago caduca pronto.</Banner>
<Banner intent="threat" variant="soft">No se pudo procesar el pago. Revisa tus datos.</Banner>
</div>
<div data-temas-fieldset>
<div data-temas-panel data-temas-stack>
<p data-temas-subhead>Progress</p>
<Progress value={64} max={100}>
<Progress.Label>Subiendo archivo</Progress.Label>
<Progress.ValueText />
<Progress.Indicator />
</Progress>
<div data-temas-cluster>
<Progress value={72} max={100} shape="circular"><Progress.Indicator /></Progress>
<Progress value={30} max={100} shape="circular"><Progress.Indicator /></Progress>
</div>
</div>
<div data-temas-panel data-temas-stack>
<p data-temas-subhead>Avatares</p>
<div data-temas-cluster>
<Avatar><Avatar.Fallback>OV</Avatar.Fallback></Avatar>
<Avatar color="primary"><Avatar.Fallback>AM</Avatar.Fallback></Avatar>
<Avatar color="affirm" variant="soft">
<Avatar.Fallback>JV</Avatar.Fallback>
<Avatar.Badge color="fulfill" position="bottom-end" dot />
</Avatar>
<Avatar color="risk" ring="soft"><Avatar.Fallback>SK</Avatar.Fallback></Avatar>
</div>
</div>
<Card variant="soft" color="primary">
<Card.Header>
<Card.Title>Plan Pro</Card.Title>
<Card.Description>Todo lo del Starter, más colaboración ilimitada.</Card.Description>
</Card.Header>
<Card.Body>
<strong style="font-size: var(--font-size-xl)">$29</strong>
<span style="color: var(--color-content-muted)"> / mes</span>
</Card.Body>
<Card.Footer>
<Button block icon={arrowIcon}>Elegir Pro</Button>
</Card.Footer>
</Card>
</div>
</section>
<!-- ═══ Tabs ═══════════════════════════════════════════════════ -->
<section data-temas-section id="tabs">
<div data-temas-section-head>
<h2>Tabs</h2>
<p>Variantes line y pills. Indicador animado, foco con anillo carbón, activo en color primario.</p>
</div>
<div data-temas-fieldset>
<div data-temas-panel data-temas-stack>
<p data-temas-subhead>Line</p>
<Tabs bind:value={tab} variant="line">
<Tabs.List aria-label="Secciones de ejemplo">
<Tabs.Trigger value="overview">Overview</Tabs.Trigger>
<Tabs.Trigger value="activity">Activity</Tabs.Trigger>
<Tabs.Trigger value="settings">Settings</Tabs.Trigger>
<Tabs.Indicator />
</Tabs.List>
<Tabs.Content value="overview">Resumen de la cuenta y métricas clave del mes.</Tabs.Content>
<Tabs.Content value="activity">Registro de actividad reciente del equipo.</Tabs.Content>
<Tabs.Content value="settings">Preferencias de notificación y seguridad.</Tabs.Content>
</Tabs>
</div>
<div data-temas-panel data-temas-stack>
<p data-temas-subhead>Pills</p>
<Tabs bind:value={tabsPills} variant="pills">
<Tabs.List aria-label="Secciones de ejemplo">
<Tabs.Trigger value="account">Account</Tabs.Trigger>
<Tabs.Trigger value="team">Team</Tabs.Trigger>
<Tabs.Trigger value="billing">Billing</Tabs.Trigger>
<Tabs.Indicator />
</Tabs.List>
<Tabs.Content value="account">Datos de perfil y sesión.</Tabs.Content>
<Tabs.Content value="team">Miembros e invitaciones.</Tabs.Content>
<Tabs.Content value="billing">Plan, método de pago y facturas.</Tabs.Content>
</Tabs>
</div>
</div>
</section>
<!-- ═══ Disclosure ═════════════════════════════════════════════ -->
<section data-temas-section id="disclosure">
<div data-temas-section-head>
<h2>Disclosure</h2>
<p>Accordion (outline) — apertura única, chevron y foco coherentes con el tema.</p>
</div>
<div data-temas-panel>
<Accordion bind:value={faq} type="single" variant="outline">
<Accordion.Item value="what">
<Accordion.Header><Accordion.Trigger>¿Qué es activeUIX?</Accordion.Trigger></Accordion.Header>
<Accordion.Content>
Un sistema de UI en cuatro capas — morfo, soma, sema y eidos — donde el theming vive en
eidos y retinta los roles canónicos.
</Accordion.Content>
</Accordion.Item>
<Accordion.Item value="theme">
<Accordion.Header><Accordion.Trigger>¿Cómo se crea un tema?</Accordion.Trigger></Accordion.Header>
<Accordion.Content>
Con <code>ActiveEidos.create(&#123; config &#125;)</code>: se remapean los 9 roles a paletas
y se ajustan primitivas estables (tipografía, radio, sombra).
</Accordion.Content>
</Accordion.Item>
<Accordion.Item value="dark">
<Accordion.Header><Accordion.Trigger>¿Y el modo oscuro?</Accordion.Trigger></Accordion.Header>
<Accordion.Content>
El tema declara escalas light y dark; el primario carbón se invierte solo gracias al slot
<code>contrast</code>.
</Accordion.Content>
</Accordion.Item>
</Accordion>
</div>
</section>
<!-- ═══ Toggles ════════════════════════════════════════════════ -->
<section data-temas-section id="toggles">
<div data-temas-section-head>
<h2>Toggles</h2>
<p>Toggle suelto y toggle-group (segmentado, single + multiple). Activo en color primario.</p>
</div>
<div data-temas-demo>
<div data-temas-demo-block>
<p data-temas-subhead>Toggle</p>
<div data-temas-cluster>
<Toggle bind:pressed={bold}>Bold</Toggle>
<Toggle variant="outline">Outline</Toggle>
<Toggle variant="ghost">Ghost</Toggle>
<Toggle disabled>Disabled</Toggle>
</div>
</div>
<div data-temas-demo-block>
<p data-temas-subhead>Toggle group · segmentado</p>
<div data-temas-cluster>
<ToggleGroup type="multiple" attached bind:value={fmt} aria-label="Formato de texto">
<ToggleGroup.Item value="bold">B</ToggleGroup.Item>
<ToggleGroup.Item value="italic">I</ToggleGroup.Item>
<ToggleGroup.Item value="underline">U</ToggleGroup.Item>
</ToggleGroup>
<ToggleGroup type="single" attached bind:value={align} aria-label="Alineación">
<ToggleGroup.Item value="left">Izq.</ToggleGroup.Item>
<ToggleGroup.Item value="center">Centro</ToggleGroup.Item>
<ToggleGroup.Item value="right">Der.</ToggleGroup.Item>
</ToggleGroup>
</div>
</div>
</div>
</section>
<!-- ═══ Toolbar ════════════════════════════════════════════════ -->
<section data-temas-section id="toolbar">
<div data-temas-section-head>
<h2>Toolbar</h2>
<p>Barra de herramientas con botones, separador y grupo segmentado.</p>
</div>
<div data-temas-panel>
<Toolbar aria-label="Editor">
<Toolbar.Button>Deshacer</Toolbar.Button>
<Toolbar.Button>Rehacer</Toolbar.Button>
<Toolbar.Separator />
<Toolbar.Group type="multiple" bind:value={toolbarFmt} aria-label="Formato">
<Toolbar.GroupItem value="bold">B</Toolbar.GroupItem>
<Toolbar.GroupItem value="italic">I</Toolbar.GroupItem>
<Toolbar.GroupItem value="underline">U</Toolbar.GroupItem>
</Toolbar.Group>
<Toolbar.Separator />
<Toolbar.Button>Compartir</Toolbar.Button>
</Toolbar>
</div>
</section>
<!-- ═══ Overlays ═══════════════════════════════════════════════ -->
<section data-temas-section id="overlays">
<div data-temas-section-head>
<h2>Overlays</h2>
<p>Popover y dialog — paneles portaleados con la superficie, borde y sombra del tema.</p>
</div>
<div data-temas-panel data-temas-cluster>
<Popover>
<Popover.Trigger>Abrir popover</Popover.Trigger>
<Popover.Portal>
<Popover.Content side="bottom" align="start" sideOffset={8}>
<Popover.Arrow />
<Popover.Title>Dimensiones</Popover.Title>
<Popover.Description>Ajusta el ancho del panel lateral.</Popover.Description>
<div data-temas-cluster style="margin-block-start: var(--space-3)">
<Button size="sm">Aplicar</Button>
<Popover.Close>Cerrar</Popover.Close>
</div>
</Popover.Content>
</Popover.Portal>
</Popover>
<Dialog>
<Dialog.Trigger>Abrir dialog</Dialog.Trigger>
<Dialog.Portal>
<Dialog.Overlay />
<Dialog.Content>
<Dialog.Header>
<Dialog.Title>¿Eliminar proyecto?</Dialog.Title>
<Dialog.Description>
Esta acción es permanente y no se puede deshacer.
</Dialog.Description>
</Dialog.Header>
<Dialog.Footer>
<Dialog.Close>Cancelar</Dialog.Close>
<Button intent="threat">Eliminar</Button>
</Dialog.Footer>
</Dialog.Content>
</Dialog.Portal>
</Dialog>
</div>
</section>
<!-- ═══ Menús ══════════════════════════════════════════════════ -->
<section data-temas-section id="menus">
<div data-temas-section-head>
<h2>Menús</h2>
<p>Dropdown, menubar, context menu y tooltip — todos portaleados, con la sombra del tema.</p>
</div>
<div data-temas-panel data-temas-stack>
<p data-temas-subhead>Menubar</p>
<Menubar bind:value={menubarValue}>
<Menubar.Menu value="file">
<Menubar.Trigger>Archivo</Menubar.Trigger>
<Menubar.Portal>
<Menubar.Content>
<Menubar.Item>Nuevo documento</Menubar.Item>
<Menubar.Item>Abrir…</Menubar.Item>
<Menubar.Separator />
<Menubar.Item>Guardar</Menubar.Item>
</Menubar.Content>
</Menubar.Portal>
</Menubar.Menu>
<Menubar.Menu value="edit">
<Menubar.Trigger>Editar</Menubar.Trigger>
<Menubar.Portal>
<Menubar.Content>
<Menubar.Item>Deshacer</Menubar.Item>
<Menubar.Item>Rehacer</Menubar.Item>
</Menubar.Content>
</Menubar.Portal>
</Menubar.Menu>
<Menubar.Menu value="view">
<Menubar.Trigger>Ver</Menubar.Trigger>
<Menubar.Portal>
<Menubar.Content>
<Menubar.CheckboxItem bind:checked={menuNotifications}>
Mostrar barra lateral
</Menubar.CheckboxItem>
</Menubar.Content>
</Menubar.Portal>
</Menubar.Menu>
</Menubar>
<div data-temas-cluster>
<DropdownMenu>
<DropdownMenu.Trigger variant="outline">Opciones</DropdownMenu.Trigger>
<DropdownMenu.Content side="bottom" align="start" sideOffset={6}>
<DropdownMenu.Group>
<DropdownMenu.GroupHeading>Cuenta</DropdownMenu.GroupHeading>
<DropdownMenu.Item>Perfil</DropdownMenu.Item>
<DropdownMenu.Item>Facturación</DropdownMenu.Item>
</DropdownMenu.Group>
<DropdownMenu.Separator />
<DropdownMenu.CheckboxItem bind:checked={menuNotifications}>
Notificaciones
</DropdownMenu.CheckboxItem>
<DropdownMenu.Separator />
<DropdownMenu.RadioGroup bind:value={menuTheme}>
<DropdownMenu.RadioItem value="light">Claro</DropdownMenu.RadioItem>
<DropdownMenu.RadioItem value="dark">Oscuro</DropdownMenu.RadioItem>
<DropdownMenu.RadioItem value="system">Sistema</DropdownMenu.RadioItem>
</DropdownMenu.RadioGroup>
</DropdownMenu.Content>
</DropdownMenu>
<Tooltip.Group delayDuration={250}>
<Tooltip>
<Tooltip.Trigger>Pasa el ratón</Tooltip.Trigger>
<Tooltip.Portal>
<Tooltip.Content>
<Tooltip.Arrow />
Tooltip con la superficie y la sombra del tema
</Tooltip.Content>
</Tooltip.Portal>
</Tooltip>
</Tooltip.Group>
</div>
<ContextMenu>
<ContextMenu.Trigger>
<div data-temas-ctx-target>Click derecho aquí</div>
</ContextMenu.Trigger>
<ContextMenu.Content>
<ContextMenu.Item>Copiar</ContextMenu.Item>
<ContextMenu.Item>Pegar</ContextMenu.Item>
<ContextMenu.Separator />
<ContextMenu.Item>Duplicar</ContextMenu.Item>
</ContextMenu.Content>
</ContextMenu>
</div>
</section>
<p data-temas-group-head>Sistema</p>
<!-- ═══ Semántica ══════════════════════════════════════════════ -->
<section data-temas-section id="sema">
<div data-temas-section-head>
<h2>Semántica (sema)</h2>
<p>
La capa perceptual está activa: cada interacción emite una señal con familia + intent que se
materializa en <strong>sonido</strong> (earcon), <strong>haptic</strong> (Vibration API) y una
<strong>reacción visual</strong> <code>data-event-*</code> teñida por el intent del tema.
Pulsa los botones — en un navegador con gesto de usuario sonarán.
</p>
</div>
<div data-temas-panel data-temas-stack>
<p data-temas-subhead>Intents perceptuales</p>
<div data-temas-cluster>
<Button intent="affirm">Affirm</Button>
<Button intent="fulfill">Fulfill</Button>
<Button intent="risk" variant="soft">Risk</Button>
<Button intent="threat" variant="soft">Threat</Button>
<Button intent="loss" variant="soft">Loss</Button>
</div>
<p style="color: var(--color-content-muted); font-size: var(--font-size-sm)">
El motor (<code>EngineSemantic</code>) se cablea en el layout vía
<code>createActiveUix(&#123; events: &#123; sound, haptic, components &#125; &#125;)</code> con
los packs sema por componente. Sonido y haptic son opt-in; aquí están encendidos.
</p>
</div>
</section>
<footer data-temas-foot>
Tema <code>grafito</code> · construido con <code>ActiveEidos.create(&#123; config &#125;)</code> ·
primario carbón + paleta de 31 escalas; jerarquía aliasada, intents auto-derivados.
</footer>
</div>
</div>

Powered by TurnKey Linux.