Grafito theme: rename from untitled-ui + 32-scale palette + Color 3-group
- Rename theme untitled-ui -> Grafito: route /temas/grafito, theme ids
grafito-light/dark, grafitoConfig, brand/hero/footer/index.
- Palette: Grafito now carries the full 32-scale library (spreads the
framework's 31 Radix scales + brand carbon, overriding the brand-tuned
gray/violet/blue + intents). Each directly usable as --scale-{name}-{step}.
- Roles: hierarchy explicit (primary->carbon, secondary->violet,
tertiary->blue); the 6 intents auto-derive from the palette by convention
(step 9). THEME_SCALES derived from palette keys, labelled by COLOR NAME.
- Demo Color section -> 3 groups (Paleta / Roles jerarquia / Intents
auto-derivados) + scaling control in the topbar.
Verified in browser: 32 distinct scales emitted, intents auto-derive
(affirm=teal, risk=amber, loss=plum), no validation error.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4 months ago
|
|
|
|
<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 & 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({ config })</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({ events: { sound, haptic, components } })</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({ config })</code> ·
|
|
|
|
|
|
primario carbón + paleta de 31 escalas; jerarquía aliasada, intents auto-derivados.
|
|
|
|
|
|
</footer>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|