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.
213 lines
5.8 KiB
213 lines
5.8 KiB
<script lang="ts">
|
|
/**
|
|
* Shell del tema Grafito.
|
|
*
|
|
* Arranca su propio `ActiveUix` + `Soma` + `ActiveEidos` (igual que la
|
|
* docs-site de UIX) pero con el patch de tema `untitled-ui`. Es la
|
|
* raíz de composición de esta ruta: posee modo (claro/oscuro) y
|
|
* densidad, que se inyectan a Eidos como fuentes visuales.
|
|
*
|
|
* `+layout@.svelte` resetea la herencia al layout raíz (passthrough),
|
|
* así esta ruta no hereda el chrome de `/uix`.
|
|
*/
|
|
import { onDestroy } from 'svelte'
|
|
import type { Density } from '$libs/density'
|
|
import type { ThemeEffective } from '$libs/theme'
|
|
import { createActiveUix, setActiveUix } from '$active-uix'
|
|
import { Soma } from '$soma/core/soma.svelte'
|
|
import { siumLangs } from '$sium/langs/langs'
|
|
import { secsLangs } from '$libs/secs'
|
|
import { ActiveEidos, SCALING_KEYS, type ScalingKey } from '$uix/eidos'
|
|
import {
|
|
accordionSema,
|
|
checkboxSema,
|
|
contextMenuSema,
|
|
dialogSema,
|
|
dropdownMenuSema,
|
|
menubarSema,
|
|
popoverSema,
|
|
radioGroupSema,
|
|
selectSema,
|
|
sliderSema,
|
|
switchSema,
|
|
tabsSema,
|
|
toggleSema,
|
|
toggleGroupSema,
|
|
toolbarSema,
|
|
tooltipSema
|
|
} from '$uix/sema/components'
|
|
import { grafitoConfig } from '../_lib/grafito'
|
|
import '@/uix/eidos/index.css'
|
|
import './theme.css'
|
|
import './grafito.css'
|
|
|
|
let { children } = $props()
|
|
|
|
// ── Runtime ───────────────────────────────────────────────────────
|
|
// `events` enciende la capa semántica (sema): sonido + haptic + las
|
|
// reacciones visuales `data-event-*`. Los packs afinan la cascada por
|
|
// componente. Cablearlo además resuelve la hidratación de los
|
|
// componentes con portal (menubar / dropdown / tooltip / popover /
|
|
// dialog), que acceden a `uix.events` al montar.
|
|
const uix = createActiveUix({
|
|
langs: { schema: { sium: siumLangs, secs: secsLangs }, defaultLocale: 'es' as const },
|
|
events: {
|
|
sound: true,
|
|
haptic: true,
|
|
components: [
|
|
accordionSema,
|
|
checkboxSema,
|
|
contextMenuSema,
|
|
dialogSema,
|
|
dropdownMenuSema,
|
|
menubarSema,
|
|
popoverSema,
|
|
radioGroupSema,
|
|
selectSema,
|
|
sliderSema,
|
|
switchSema,
|
|
tabsSema,
|
|
toggleSema,
|
|
toggleGroupSema,
|
|
toolbarSema,
|
|
tooltipSema
|
|
]
|
|
}
|
|
})
|
|
setActiveUix(uix)
|
|
Soma.create()
|
|
|
|
// ── Modo + densidad (fuentes visuales para Eidos) ─────────────────
|
|
let mode = $state<ThemeEffective>('light')
|
|
let density = $state<Density>('comfortable')
|
|
let scaling = $state<ScalingKey>('100')
|
|
|
|
const modeListeners = new Set<(v: ThemeEffective) => void>()
|
|
const densityListeners = new Set<(v: Density) => void>()
|
|
const scalingListeners = new Set<(v: ScalingKey) => void>()
|
|
|
|
const activeEidos = ActiveEidos.create({
|
|
applyDom: true,
|
|
config: grafitoConfig,
|
|
theme: 'grafito',
|
|
modeSource: {
|
|
get: () => mode,
|
|
onChange(handler) {
|
|
modeListeners.add(handler)
|
|
return () => modeListeners.delete(handler)
|
|
}
|
|
},
|
|
densitySource: {
|
|
get: () => density,
|
|
onChange(handler) {
|
|
densityListeners.add(handler)
|
|
return () => densityListeners.delete(handler)
|
|
}
|
|
},
|
|
scalingSource: {
|
|
get: () => scaling,
|
|
onChange(handler) {
|
|
scalingListeners.add(handler)
|
|
return () => scalingListeners.delete(handler)
|
|
}
|
|
}
|
|
})
|
|
|
|
$effect(() => {
|
|
const m = mode
|
|
for (const l of modeListeners) l(m)
|
|
})
|
|
$effect(() => {
|
|
const d = density
|
|
for (const l of densityListeners) l(d)
|
|
})
|
|
$effect(() => {
|
|
const s = scaling
|
|
for (const l of scalingListeners) l(s)
|
|
})
|
|
|
|
const DENSITIES: { id: Density; label: string }[] = [
|
|
{ id: 'compact', label: 'Compact' },
|
|
{ id: 'comfortable', label: 'Comfortable' },
|
|
{ id: 'spacious', label: 'Spacious' }
|
|
]
|
|
|
|
onDestroy(() => {
|
|
activeEidos.dispose()
|
|
uix.dispose()
|
|
})
|
|
|
|
</script>
|
|
|
|
<svelte:head>
|
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="anonymous" />
|
|
<link
|
|
rel="stylesheet"
|
|
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Roboto+Mono:wght@400;500&display=swap"
|
|
/>
|
|
</svelte:head>
|
|
|
|
<div data-temas-shell>
|
|
<header data-temas-topbar>
|
|
<div data-temas-brand>
|
|
<span data-temas-brand-mark>G</span>
|
|
<div data-temas-brand-text>
|
|
<strong>Grafito</strong>
|
|
<small>Tema · activeUIX / Eidos</small>
|
|
</div>
|
|
</div>
|
|
|
|
<div data-temas-tools>
|
|
<div data-temas-segmented role="group" aria-label="Densidad">
|
|
{#each DENSITIES as d}
|
|
<button
|
|
type="button"
|
|
data-active={density === d.id ? 'true' : 'false'}
|
|
onclick={() => (density = d.id)}
|
|
>
|
|
{d.label}
|
|
</button>
|
|
{/each}
|
|
</div>
|
|
|
|
<div data-temas-segmented role="group" aria-label="Scaling">
|
|
{#each SCALING_KEYS as s}
|
|
<button
|
|
type="button"
|
|
data-active={scaling === s ? 'true' : 'false'}
|
|
onclick={() => (scaling = s)}
|
|
>
|
|
{s}%
|
|
</button>
|
|
{/each}
|
|
</div>
|
|
|
|
<button
|
|
type="button"
|
|
data-temas-mode-btn
|
|
aria-label="Cambiar modo"
|
|
aria-pressed={mode === 'dark'}
|
|
onclick={() => (mode = mode === 'light' ? 'dark' : 'light')}
|
|
>
|
|
{#if mode === 'light'}
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" />
|
|
</svg>
|
|
<span>Light</span>
|
|
{:else}
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
<circle cx="12" cy="12" r="4" />
|
|
<path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M17.66 17.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M17.66 6.34l1.41-1.41" />
|
|
</svg>
|
|
<span>Dark</span>
|
|
{/if}
|
|
</button>
|
|
</div>
|
|
</header>
|
|
|
|
<main data-temas-canvas>
|
|
{@render children?.()}
|
|
</main>
|
|
</div>
|