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/+layout.svelte

178 lines
6.7 KiB

<script lang="ts">
import { createActiveUix, setActiveUix } from '$active-uix';
eidos: pilot wrapper pattern + doctrinal API conventions Toggle as the eidos pilot: subdirectory layout (recipe + Svelte wrapper + types + index + README) replacing the flat CSS-only form. Pattern is documented in eidos/components/README.md and the toggle README. Shared types live in eidos/lib/types.ts. First export is `Size` (8 values xxs..xxl + full); components narrow with `Extract<Size, ...>` per the per-component-subset doctrine. No `Eidos` prefix on types — module path already conveys the layer. API doctrine: - soma stays compound (Toggle.Provider) for symmetry with multi-part - eidos exports both default + Provider so single-part components accept both `<Toggle>` (ergonomic) and `<Toggle.Provider>` (compound-style consumers) SoundChannel eager-init fixes the autoplay race: AudioContext is created + resumed synchronously on the first user gesture (capture-phase listener registered in the constructor), avoiding the previous race where the first emit() scheduled the resume in a microtask outside the gesture window. Demo page (web/routes/toggle/+page.svelte) restructured so the live preview renders ALWAYS above the tablist — Sema-tab Play buttons can fire on the real toggle. Motion preview amplifies scale ×8 visually only; doctrinal values stay in the <dl>. Conventions 7-13 added to src/docs/sema-implementation-guide.md covering: directory structure, wrapper composition, no Eidos prefix, soma compound vs eidos flat, iconOnly sr-only body, sound eager-init, docs-preview amplification. CLAUDE.md gets a session hand-off block listing where things stand and next concrete steps (migrate switch/collapsible/dialog/drawer/popover/ toast/avatar; wire topbar sound mute to masterGain; rename theme tokens to drop the success/warning/danger fallback aliases). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
import { page } from '$app/state';
import { Soma } from '$soma/core/soma.svelte';
import { accordionSema } from '$uix/sema/components/accordion';
import { checkboxSema } from '$uix/sema/components/checkbox';
sema/morfo/eidos: typed selector builder + dialog wrapper + emerge color sema architecture - sema-map: 5-channel registry (motion / sound / color / presence / haptic) via SemaChannelSignatures declaration merging; engine stamps data-event-* tokens; flat CSS-style cascade replaces the eventLabel-overrides middle layer. - sema-map: emerge family gains base.color so intent deltas can shift hue / saturation / intensity. Without a base, the resolver was skipping the channel and Dialog open with intent='threat' rendered as neutral blue in the Sema tab visualisation. - types: SEMA_FAMILY_POLICY const drives compile-time + runtime intent requirements per family. Object shape so future per-family policy fields fit alongside. Emerge events MAY now declare intent (canon update — a Dialog confirming threat carries it in its very appearance). - chans: rename vibra→haptic, add HapticChannel V1 (Vibration API); SoundChannel eager-init on first user gesture (autoplay race fix). morfo selector discipline - morfo/selectors.ts (new): semaSelector(morfo, partKebab, matchers?) — type-checked against morfo.parts and morfo.events. Sema cascade rules MUST use it; hand-written strings are an architecture violation that breaks silently when morfo renames a part. - dialog morfo: open carries intent via fromProp; close-cancel / close-dismiss / close-dismiss-outside drop intent (cancellation has no evaluative load); close-save stays hardcoded fulfill (commit fulfils the user's decision regardless of dialog context). eidos dialog migration (4th pilot) - eidos/components/dialog/: full subdirectory wrapper — flat <Dialog> + compound Provider/Trigger/Overlay/Content/Title/Description/Close/Header/ Footer; size + position responsive props; sheet auto-form on narrow viewports; closePosition for the auto-X. - sema/components/dialog.ts: cascade rules use semaSelector(dialogMorfo, 'content', matchers?). Intent block adds character (haptic kind / pattern) but never overrides pitch / gain / contour — those are intent.deltas signature ownership and overriding flattens per-intent perceptual difference. demo controls + dialog page - src/lib/_demo (DemoSwitch / DemoEnum / DemoText / DemoRange) — unified controls reused across all component demos. - web/routes/dialog: live preview always rendered above tabs; per-event Sema tab with independent intent probe; signature visualisation + Play buttons with fallback target chain. documentation - CLAUDE.md: intent.deltas signature ownership rule; eidos drift defense doctrine (types over lint); 2026-05-09 hand-off entry. - morfo/README: Typed selector builder section. - eidos/README: linter section reframed as opt-in safety net for plain CSS recipes; the architectural mechanism is compile-time typing. - sema/README: open channel registry + flat cascade docs + override semantics + intent policy const + selector builder discipline. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
import { dialogSema } from '$uix/sema/components/dialog';
import { drawerSema } from '$uix/sema/components/drawer';
import { popoverSema } from '$uix/sema/components/popover';
import { radioGroupSema } from '$uix/sema/components/radio-group';
import { tabsSema } from '$uix/sema/components/tabs';
import { toastSema } from '$uix/sema/components/toast';
demos: web/routes/* for the 8 migrated soma components First demos under the new web/routes location (configured by phase C of the cleanup as `kit.files.routes`). One demo per component: toggle, switch, collapsible, avatar, dialog, drawer, popover, toast. Layout (web/routes/+layout.svelte): - Bootstraps the UIX via createActiveUix({ lang: { schema: {}, defaultLocale: 'es' } }) — minimal config, full UIX surface. - Wraps in <Uix> which sets the active-uix context and creates the Soma scope so providers can require it. - Imports the eidos index.css so the visual layer is applied. - Tiny demo-only stylesheet (web/routes/layout.css) for the page chrome (topbar, demo grid, sections) — explicitly NOT part of eidos. Each demo page exercises the public API: - toggle: bound, initially-pressed, disabled - switch: bound, disabled - collapsible: bound show/hide, disabled trigger - avatar: loaded, error fallback, delayed - dialog: basic with overlay + focus trap + escape dismissal - drawer: right / left / bottom (with handle) - popover: click + hover trigger - toast: 4 intents (fulfill, risk, threat, neutral) via createToaster Verified end-to-end with scripts/demo-probe.ts (Playwright): - All 9 routes (landing + 8 demos) serve 200. - Zero console errors except avatar's pravatar.cc network failure (sandbox limitation, not a real bug). - Interactive checks: dialog open shows modal + overlay backdrop + focused Cancel button; popover open positions floating content next to trigger; toast Fulfill shows the green-tinted shadow driven by data-event-intent='fulfill' from sema's visual channel reacting to the morfo's announce event semantics — confirms the full morfo → sema → eidos pipeline works end-to-end on a migrated soma component. scripts/demo-probe.ts: small Playwright runner that loads each route, captures console errors, takes a screenshot of the static state, then clicks the trigger on dialog/collapsible/popover/toast for a second "open" screenshot. Output goes to g:/tmp/demos/. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
import '@/uix/eidos/index.css';
import './layout.css';
let { children } = $props();
demos: web/routes/* for the 8 migrated soma components First demos under the new web/routes location (configured by phase C of the cleanup as `kit.files.routes`). One demo per component: toggle, switch, collapsible, avatar, dialog, drawer, popover, toast. Layout (web/routes/+layout.svelte): - Bootstraps the UIX via createActiveUix({ lang: { schema: {}, defaultLocale: 'es' } }) — minimal config, full UIX surface. - Wraps in <Uix> which sets the active-uix context and creates the Soma scope so providers can require it. - Imports the eidos index.css so the visual layer is applied. - Tiny demo-only stylesheet (web/routes/layout.css) for the page chrome (topbar, demo grid, sections) — explicitly NOT part of eidos. Each demo page exercises the public API: - toggle: bound, initially-pressed, disabled - switch: bound, disabled - collapsible: bound show/hide, disabled trigger - avatar: loaded, error fallback, delayed - dialog: basic with overlay + focus trap + escape dismissal - drawer: right / left / bottom (with handle) - popover: click + hover trigger - toast: 4 intents (fulfill, risk, threat, neutral) via createToaster Verified end-to-end with scripts/demo-probe.ts (Playwright): - All 9 routes (landing + 8 demos) serve 200. - Zero console errors except avatar's pravatar.cc network failure (sandbox limitation, not a real bug). - Interactive checks: dialog open shows modal + overlay backdrop + focused Cancel button; popover open positions floating content next to trigger; toast Fulfill shows the green-tinted shadow driven by data-event-intent='fulfill' from sema's visual channel reacting to the morfo's announce event semantics — confirms the full morfo → sema → eidos pipeline works end-to-end on a migrated soma component. scripts/demo-probe.ts: small Playwright runner that loads each route, captures console errors, takes a screenshot of the static state, then clicks the trigger on dialog/collapsible/popover/toast for a second "open" screenshot. Output goes to g:/tmp/demos/. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
const uix = createActiveUix({
eidos: pilot wrapper pattern + doctrinal API conventions Toggle as the eidos pilot: subdirectory layout (recipe + Svelte wrapper + types + index + README) replacing the flat CSS-only form. Pattern is documented in eidos/components/README.md and the toggle README. Shared types live in eidos/lib/types.ts. First export is `Size` (8 values xxs..xxl + full); components narrow with `Extract<Size, ...>` per the per-component-subset doctrine. No `Eidos` prefix on types — module path already conveys the layer. API doctrine: - soma stays compound (Toggle.Provider) for symmetry with multi-part - eidos exports both default + Provider so single-part components accept both `<Toggle>` (ergonomic) and `<Toggle.Provider>` (compound-style consumers) SoundChannel eager-init fixes the autoplay race: AudioContext is created + resumed synchronously on the first user gesture (capture-phase listener registered in the constructor), avoiding the previous race where the first emit() scheduled the resume in a microtask outside the gesture window. Demo page (web/routes/toggle/+page.svelte) restructured so the live preview renders ALWAYS above the tablist — Sema-tab Play buttons can fire on the real toggle. Motion preview amplifies scale ×8 visually only; doctrinal values stay in the <dl>. Conventions 7-13 added to src/docs/sema-implementation-guide.md covering: directory structure, wrapper composition, no Eidos prefix, soma compound vs eidos flat, iconOnly sr-only body, sound eager-init, docs-preview amplification. CLAUDE.md gets a session hand-off block listing where things stand and next concrete steps (migrate switch/collapsible/dialog/drawer/popover/ toast/avatar; wire topbar sound mute to masterGain; rename theme tokens to drop the success/warning/danger fallback aliases). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
lang: { schema: {}, defaultLocale: 'es' as const },
sema/morfo/eidos: typed selector builder + dialog wrapper + emerge color sema architecture - sema-map: 5-channel registry (motion / sound / color / presence / haptic) via SemaChannelSignatures declaration merging; engine stamps data-event-* tokens; flat CSS-style cascade replaces the eventLabel-overrides middle layer. - sema-map: emerge family gains base.color so intent deltas can shift hue / saturation / intensity. Without a base, the resolver was skipping the channel and Dialog open with intent='threat' rendered as neutral blue in the Sema tab visualisation. - types: SEMA_FAMILY_POLICY const drives compile-time + runtime intent requirements per family. Object shape so future per-family policy fields fit alongside. Emerge events MAY now declare intent (canon update — a Dialog confirming threat carries it in its very appearance). - chans: rename vibra→haptic, add HapticChannel V1 (Vibration API); SoundChannel eager-init on first user gesture (autoplay race fix). morfo selector discipline - morfo/selectors.ts (new): semaSelector(morfo, partKebab, matchers?) — type-checked against morfo.parts and morfo.events. Sema cascade rules MUST use it; hand-written strings are an architecture violation that breaks silently when morfo renames a part. - dialog morfo: open carries intent via fromProp; close-cancel / close-dismiss / close-dismiss-outside drop intent (cancellation has no evaluative load); close-save stays hardcoded fulfill (commit fulfils the user's decision regardless of dialog context). eidos dialog migration (4th pilot) - eidos/components/dialog/: full subdirectory wrapper — flat <Dialog> + compound Provider/Trigger/Overlay/Content/Title/Description/Close/Header/ Footer; size + position responsive props; sheet auto-form on narrow viewports; closePosition for the auto-X. - sema/components/dialog.ts: cascade rules use semaSelector(dialogMorfo, 'content', matchers?). Intent block adds character (haptic kind / pattern) but never overrides pitch / gain / contour — those are intent.deltas signature ownership and overriding flattens per-intent perceptual difference. demo controls + dialog page - src/lib/_demo (DemoSwitch / DemoEnum / DemoText / DemoRange) — unified controls reused across all component demos. - web/routes/dialog: live preview always rendered above tabs; per-event Sema tab with independent intent probe; signature visualisation + Play buttons with fallback target chain. documentation - CLAUDE.md: intent.deltas signature ownership rule; eidos drift defense doctrine (types over lint); 2026-05-09 hand-off entry. - morfo/README: Typed selector builder section. - eidos/README: linter section reframed as opt-in safety net for plain CSS recipes; the architectural mechanism is compile-time typing. - sema/README: open channel registry + flat cascade docs + override semantics + intent policy const + selector builder discipline. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
// Enable the SoundChannel + HapticChannel. Per-component packs
// register the cascade rules that discriminate event sounds
// (open vs close, fulfill vs threat, etc.) — without `components`
// the engine has only the family/intent base, which is too generic
// to distinguish open from close-cancel.
semantic: {
sound: true,
haptic: true,
components: [accordionSema, checkboxSema, dialogSema, drawerSema, popoverSema, radioGroupSema, tabsSema, toastSema]
sema/morfo/eidos: typed selector builder + dialog wrapper + emerge color sema architecture - sema-map: 5-channel registry (motion / sound / color / presence / haptic) via SemaChannelSignatures declaration merging; engine stamps data-event-* tokens; flat CSS-style cascade replaces the eventLabel-overrides middle layer. - sema-map: emerge family gains base.color so intent deltas can shift hue / saturation / intensity. Without a base, the resolver was skipping the channel and Dialog open with intent='threat' rendered as neutral blue in the Sema tab visualisation. - types: SEMA_FAMILY_POLICY const drives compile-time + runtime intent requirements per family. Object shape so future per-family policy fields fit alongside. Emerge events MAY now declare intent (canon update — a Dialog confirming threat carries it in its very appearance). - chans: rename vibra→haptic, add HapticChannel V1 (Vibration API); SoundChannel eager-init on first user gesture (autoplay race fix). morfo selector discipline - morfo/selectors.ts (new): semaSelector(morfo, partKebab, matchers?) — type-checked against morfo.parts and morfo.events. Sema cascade rules MUST use it; hand-written strings are an architecture violation that breaks silently when morfo renames a part. - dialog morfo: open carries intent via fromProp; close-cancel / close-dismiss / close-dismiss-outside drop intent (cancellation has no evaluative load); close-save stays hardcoded fulfill (commit fulfils the user's decision regardless of dialog context). eidos dialog migration (4th pilot) - eidos/components/dialog/: full subdirectory wrapper — flat <Dialog> + compound Provider/Trigger/Overlay/Content/Title/Description/Close/Header/ Footer; size + position responsive props; sheet auto-form on narrow viewports; closePosition for the auto-X. - sema/components/dialog.ts: cascade rules use semaSelector(dialogMorfo, 'content', matchers?). Intent block adds character (haptic kind / pattern) but never overrides pitch / gain / contour — those are intent.deltas signature ownership and overriding flattens per-intent perceptual difference. demo controls + dialog page - src/lib/_demo (DemoSwitch / DemoEnum / DemoText / DemoRange) — unified controls reused across all component demos. - web/routes/dialog: live preview always rendered above tabs; per-event Sema tab with independent intent probe; signature visualisation + Play buttons with fallback target chain. documentation - CLAUDE.md: intent.deltas signature ownership rule; eidos drift defense doctrine (types over lint); 2026-05-09 hand-off entry. - morfo/README: Typed selector builder section. - eidos/README: linter section reframed as opt-in safety net for plain CSS recipes; the architectural mechanism is compile-time typing. - sema/README: open channel registry + flat cascade docs + override semantics + intent policy const + selector builder discipline. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
}
eidos: pilot wrapper pattern + doctrinal API conventions Toggle as the eidos pilot: subdirectory layout (recipe + Svelte wrapper + types + index + README) replacing the flat CSS-only form. Pattern is documented in eidos/components/README.md and the toggle README. Shared types live in eidos/lib/types.ts. First export is `Size` (8 values xxs..xxl + full); components narrow with `Extract<Size, ...>` per the per-component-subset doctrine. No `Eidos` prefix on types — module path already conveys the layer. API doctrine: - soma stays compound (Toggle.Provider) for symmetry with multi-part - eidos exports both default + Provider so single-part components accept both `<Toggle>` (ergonomic) and `<Toggle.Provider>` (compound-style consumers) SoundChannel eager-init fixes the autoplay race: AudioContext is created + resumed synchronously on the first user gesture (capture-phase listener registered in the constructor), avoiding the previous race where the first emit() scheduled the resume in a microtask outside the gesture window. Demo page (web/routes/toggle/+page.svelte) restructured so the live preview renders ALWAYS above the tablist — Sema-tab Play buttons can fire on the real toggle. Motion preview amplifies scale ×8 visually only; doctrinal values stay in the <dl>. Conventions 7-13 added to src/docs/sema-implementation-guide.md covering: directory structure, wrapper composition, no Eidos prefix, soma compound vs eidos flat, iconOnly sr-only body, sound eager-init, docs-preview amplification. CLAUDE.md gets a session hand-off block listing where things stand and next concrete steps (migrate switch/collapsible/dialog/drawer/popover/ toast/avatar; wire topbar sound mute to masterGain; rename theme tokens to drop the success/warning/danger fallback aliases). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
});
setActiveUix(uix);
Soma.create({ portalTo: uix.somaPortalTo });
eidos: pilot wrapper pattern + doctrinal API conventions Toggle as the eidos pilot: subdirectory layout (recipe + Svelte wrapper + types + index + README) replacing the flat CSS-only form. Pattern is documented in eidos/components/README.md and the toggle README. Shared types live in eidos/lib/types.ts. First export is `Size` (8 values xxs..xxl + full); components narrow with `Extract<Size, ...>` per the per-component-subset doctrine. No `Eidos` prefix on types — module path already conveys the layer. API doctrine: - soma stays compound (Toggle.Provider) for symmetry with multi-part - eidos exports both default + Provider so single-part components accept both `<Toggle>` (ergonomic) and `<Toggle.Provider>` (compound-style consumers) SoundChannel eager-init fixes the autoplay race: AudioContext is created + resumed synchronously on the first user gesture (capture-phase listener registered in the constructor), avoiding the previous race where the first emit() scheduled the resume in a microtask outside the gesture window. Demo page (web/routes/toggle/+page.svelte) restructured so the live preview renders ALWAYS above the tablist — Sema-tab Play buttons can fire on the real toggle. Motion preview amplifies scale ×8 visually only; doctrinal values stay in the <dl>. Conventions 7-13 added to src/docs/sema-implementation-guide.md covering: directory structure, wrapper composition, no Eidos prefix, soma compound vs eidos flat, iconOnly sr-only body, sound eager-init, docs-preview amplification. CLAUDE.md gets a session hand-off block listing where things stand and next concrete steps (migrate switch/collapsible/dialog/drawer/popover/ toast/avatar; wire topbar sound mute to masterGain; rename theme tokens to drop the success/warning/danger fallback aliases). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
type NavItem = {
slug: string;
label: string;
group: 'controls' | 'overlays' | 'media';
};
const components: NavItem[] = [
{ slug: 'toggle', label: 'Toggle', group: 'controls' },
{ slug: 'switch', label: 'Switch', group: 'controls' },
{ slug: 'collapsible', label: 'Collapsible', group: 'controls' },
{ slug: 'accordion', label: 'Accordion', group: 'controls' },
eidos: pilot wrapper pattern + doctrinal API conventions Toggle as the eidos pilot: subdirectory layout (recipe + Svelte wrapper + types + index + README) replacing the flat CSS-only form. Pattern is documented in eidos/components/README.md and the toggle README. Shared types live in eidos/lib/types.ts. First export is `Size` (8 values xxs..xxl + full); components narrow with `Extract<Size, ...>` per the per-component-subset doctrine. No `Eidos` prefix on types — module path already conveys the layer. API doctrine: - soma stays compound (Toggle.Provider) for symmetry with multi-part - eidos exports both default + Provider so single-part components accept both `<Toggle>` (ergonomic) and `<Toggle.Provider>` (compound-style consumers) SoundChannel eager-init fixes the autoplay race: AudioContext is created + resumed synchronously on the first user gesture (capture-phase listener registered in the constructor), avoiding the previous race where the first emit() scheduled the resume in a microtask outside the gesture window. Demo page (web/routes/toggle/+page.svelte) restructured so the live preview renders ALWAYS above the tablist — Sema-tab Play buttons can fire on the real toggle. Motion preview amplifies scale ×8 visually only; doctrinal values stay in the <dl>. Conventions 7-13 added to src/docs/sema-implementation-guide.md covering: directory structure, wrapper composition, no Eidos prefix, soma compound vs eidos flat, iconOnly sr-only body, sound eager-init, docs-preview amplification. CLAUDE.md gets a session hand-off block listing where things stand and next concrete steps (migrate switch/collapsible/dialog/drawer/popover/ toast/avatar; wire topbar sound mute to masterGain; rename theme tokens to drop the success/warning/danger fallback aliases). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
{ slug: 'avatar', label: 'Avatar', group: 'media' },
{ slug: 'icon', label: 'Icon', group: 'media' },
eidos: pilot wrapper pattern + doctrinal API conventions Toggle as the eidos pilot: subdirectory layout (recipe + Svelte wrapper + types + index + README) replacing the flat CSS-only form. Pattern is documented in eidos/components/README.md and the toggle README. Shared types live in eidos/lib/types.ts. First export is `Size` (8 values xxs..xxl + full); components narrow with `Extract<Size, ...>` per the per-component-subset doctrine. No `Eidos` prefix on types — module path already conveys the layer. API doctrine: - soma stays compound (Toggle.Provider) for symmetry with multi-part - eidos exports both default + Provider so single-part components accept both `<Toggle>` (ergonomic) and `<Toggle.Provider>` (compound-style consumers) SoundChannel eager-init fixes the autoplay race: AudioContext is created + resumed synchronously on the first user gesture (capture-phase listener registered in the constructor), avoiding the previous race where the first emit() scheduled the resume in a microtask outside the gesture window. Demo page (web/routes/toggle/+page.svelte) restructured so the live preview renders ALWAYS above the tablist — Sema-tab Play buttons can fire on the real toggle. Motion preview amplifies scale ×8 visually only; doctrinal values stay in the <dl>. Conventions 7-13 added to src/docs/sema-implementation-guide.md covering: directory structure, wrapper composition, no Eidos prefix, soma compound vs eidos flat, iconOnly sr-only body, sound eager-init, docs-preview amplification. CLAUDE.md gets a session hand-off block listing where things stand and next concrete steps (migrate switch/collapsible/dialog/drawer/popover/ toast/avatar; wire topbar sound mute to masterGain; rename theme tokens to drop the success/warning/danger fallback aliases). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
{ slug: 'dialog', label: 'Dialog', group: 'overlays' },
{ slug: 'drawer', label: 'Drawer', group: 'overlays' },
{ slug: 'popover', label: 'Popover', group: 'overlays' },
{ slug: 'toast', label: 'Toast', group: 'overlays' }
];
const groups: { id: NavItem['group']; heading: string }[] = [
{ id: 'controls', heading: 'Controls' },
{ id: 'overlays', heading: 'Overlays' },
{ id: 'media', heading: 'Media' }
];
const current = $derived(page.url.pathname);
// ── Theme ─────────────────────────────────────────────────────────────
let theme = $state<'light' | 'dark'>('light');
let soundOn = $state(true);
$effect(() => {
if (typeof document === 'undefined') return;
document.documentElement.dataset.theme = theme;
});
// Persist across reloads
$effect(() => {
if (typeof localStorage === 'undefined') return;
const stored = localStorage.getItem('uix-theme');
if (stored === 'dark' || stored === 'light') theme = stored;
});
$effect(() => {
if (typeof localStorage === 'undefined') return;
localStorage.setItem('uix-theme', theme);
demos: web/routes/* for the 8 migrated soma components First demos under the new web/routes location (configured by phase C of the cleanup as `kit.files.routes`). One demo per component: toggle, switch, collapsible, avatar, dialog, drawer, popover, toast. Layout (web/routes/+layout.svelte): - Bootstraps the UIX via createActiveUix({ lang: { schema: {}, defaultLocale: 'es' } }) — minimal config, full UIX surface. - Wraps in <Uix> which sets the active-uix context and creates the Soma scope so providers can require it. - Imports the eidos index.css so the visual layer is applied. - Tiny demo-only stylesheet (web/routes/layout.css) for the page chrome (topbar, demo grid, sections) — explicitly NOT part of eidos. Each demo page exercises the public API: - toggle: bound, initially-pressed, disabled - switch: bound, disabled - collapsible: bound show/hide, disabled trigger - avatar: loaded, error fallback, delayed - dialog: basic with overlay + focus trap + escape dismissal - drawer: right / left / bottom (with handle) - popover: click + hover trigger - toast: 4 intents (fulfill, risk, threat, neutral) via createToaster Verified end-to-end with scripts/demo-probe.ts (Playwright): - All 9 routes (landing + 8 demos) serve 200. - Zero console errors except avatar's pravatar.cc network failure (sandbox limitation, not a real bug). - Interactive checks: dialog open shows modal + overlay backdrop + focused Cancel button; popover open positions floating content next to trigger; toast Fulfill shows the green-tinted shadow driven by data-event-intent='fulfill' from sema's visual channel reacting to the morfo's announce event semantics — confirms the full morfo → sema → eidos pipeline works end-to-end on a migrated soma component. scripts/demo-probe.ts: small Playwright runner that loads each route, captures console errors, takes a screenshot of the static state, then clicks the trigger on dialog/collapsible/popover/toast for a second "open" screenshot. Output goes to g:/tmp/demos/. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
});
</script>
eidos: pilot wrapper pattern + doctrinal API conventions Toggle as the eidos pilot: subdirectory layout (recipe + Svelte wrapper + types + index + README) replacing the flat CSS-only form. Pattern is documented in eidos/components/README.md and the toggle README. Shared types live in eidos/lib/types.ts. First export is `Size` (8 values xxs..xxl + full); components narrow with `Extract<Size, ...>` per the per-component-subset doctrine. No `Eidos` prefix on types — module path already conveys the layer. API doctrine: - soma stays compound (Toggle.Provider) for symmetry with multi-part - eidos exports both default + Provider so single-part components accept both `<Toggle>` (ergonomic) and `<Toggle.Provider>` (compound-style consumers) SoundChannel eager-init fixes the autoplay race: AudioContext is created + resumed synchronously on the first user gesture (capture-phase listener registered in the constructor), avoiding the previous race where the first emit() scheduled the resume in a microtask outside the gesture window. Demo page (web/routes/toggle/+page.svelte) restructured so the live preview renders ALWAYS above the tablist — Sema-tab Play buttons can fire on the real toggle. Motion preview amplifies scale ×8 visually only; doctrinal values stay in the <dl>. Conventions 7-13 added to src/docs/sema-implementation-guide.md covering: directory structure, wrapper composition, no Eidos prefix, soma compound vs eidos flat, iconOnly sr-only body, sound eager-init, docs-preview amplification. CLAUDE.md gets a session hand-off block listing where things stand and next concrete steps (migrate switch/collapsible/dialog/drawer/popover/ toast/avatar; wire topbar sound mute to masterGain; rename theme tokens to drop the success/warning/danger fallback aliases). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
<svelte:head>
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="anonymous" />
<link
href="https://fonts.googleapis.com/css2?family=Geist:wght@300..700&family=Geist+Mono:wght@400..600&display=swap"
rel="stylesheet"
/>
</svelte:head>
<header class="topbar">
eidos: pilot wrapper pattern + doctrinal API conventions Toggle as the eidos pilot: subdirectory layout (recipe + Svelte wrapper + types + index + README) replacing the flat CSS-only form. Pattern is documented in eidos/components/README.md and the toggle README. Shared types live in eidos/lib/types.ts. First export is `Size` (8 values xxs..xxl + full); components narrow with `Extract<Size, ...>` per the per-component-subset doctrine. No `Eidos` prefix on types — module path already conveys the layer. API doctrine: - soma stays compound (Toggle.Provider) for symmetry with multi-part - eidos exports both default + Provider so single-part components accept both `<Toggle>` (ergonomic) and `<Toggle.Provider>` (compound-style consumers) SoundChannel eager-init fixes the autoplay race: AudioContext is created + resumed synchronously on the first user gesture (capture-phase listener registered in the constructor), avoiding the previous race where the first emit() scheduled the resume in a microtask outside the gesture window. Demo page (web/routes/toggle/+page.svelte) restructured so the live preview renders ALWAYS above the tablist — Sema-tab Play buttons can fire on the real toggle. Motion preview amplifies scale ×8 visually only; doctrinal values stay in the <dl>. Conventions 7-13 added to src/docs/sema-implementation-guide.md covering: directory structure, wrapper composition, no Eidos prefix, soma compound vs eidos flat, iconOnly sr-only body, sound eager-init, docs-preview amplification. CLAUDE.md gets a session hand-off block listing where things stand and next concrete steps (migrate switch/collapsible/dialog/drawer/popover/ toast/avatar; wire topbar sound mute to masterGain; rename theme tokens to drop the success/warning/danger fallback aliases). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
<div class="topbar-left">
<a href="/" class="brand">
<span class="brand-mark">U</span>
<span class="brand-name">UIX</span>
<span class="brand-version">v0.1</span>
</a>
<nav class="topbar-nav" aria-label="Primary">
<a href="/" class:active={current === '/'}>Components</a>
<a href="/docs" class:active={current.startsWith('/docs')}>Docs</a>
<a href="/playground" class:active={current.startsWith('/playground')}>Playground</a>
</nav>
</div>
<div class="topbar-right">
<button
type="button"
class="iconbtn"
title={soundOn ? 'Mute sema sounds' : 'Unmute sema sounds'}
aria-label={soundOn ? 'Mute sema sounds' : 'Unmute sema sounds'}
onclick={() => (soundOn = !soundOn)}
aria-pressed={soundOn}
>
{#if soundOn}
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2"><path d="M11 5L6 9H2v6h4l5 4V5z"/><path d="M15.5 8.5a5 5 0 010 7"/><path d="M19 5a9 9 0 010 14"/></svg>
{:else}
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2"><path d="M11 5L6 9H2v6h4l5 4V5z"/><line x1="22" y1="9" x2="16" y2="15"/><line x1="16" y1="9" x2="22" y2="15"/></svg>
{/if}
</button>
<button
type="button"
class="iconbtn"
title="Toggle theme"
aria-label="Toggle theme"
onclick={() => (theme = theme === 'light' ? 'dark' : 'light')}
>
{#if theme === 'light'}
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 12.79A9 9 0 1111.21 3 7 7 0 0021 12.79z"/></svg>
{:else}
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2"><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>
{/if}
</button>
<a
class="iconbtn"
href="https://github.com/"
target="_blank"
rel="noreferrer"
title="GitHub"
aria-label="GitHub"
>
<svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor"><path d="M12 .5C5.65.5.5 5.65.5 12c0 5.08 3.29 9.39 7.86 10.91.57.1.78-.25.78-.55v-2.06c-3.2.7-3.87-1.36-3.87-1.36-.52-1.32-1.27-1.67-1.27-1.67-1.04-.71.08-.7.08-.7 1.15.08 1.76 1.18 1.76 1.18 1.02 1.75 2.69 1.24 3.34.95.1-.74.4-1.24.72-1.53-2.55-.29-5.24-1.28-5.24-5.69 0-1.26.45-2.29 1.18-3.1-.12-.29-.51-1.46.11-3.04 0 0 .97-.31 3.18 1.18a11.04 11.04 0 015.79 0c2.21-1.49 3.18-1.18 3.18-1.18.62 1.58.23 2.75.11 3.04.74.81 1.18 1.84 1.18 3.1 0 4.42-2.69 5.4-5.25 5.68.41.36.78 1.06.78 2.14v3.18c0 .31.21.66.79.55C20.21 21.39 23.5 17.07 23.5 12 23.5 5.65 18.35.5 12 .5z"/></svg>
</a>
</div>
demos: web/routes/* for the 8 migrated soma components First demos under the new web/routes location (configured by phase C of the cleanup as `kit.files.routes`). One demo per component: toggle, switch, collapsible, avatar, dialog, drawer, popover, toast. Layout (web/routes/+layout.svelte): - Bootstraps the UIX via createActiveUix({ lang: { schema: {}, defaultLocale: 'es' } }) — minimal config, full UIX surface. - Wraps in <Uix> which sets the active-uix context and creates the Soma scope so providers can require it. - Imports the eidos index.css so the visual layer is applied. - Tiny demo-only stylesheet (web/routes/layout.css) for the page chrome (topbar, demo grid, sections) — explicitly NOT part of eidos. Each demo page exercises the public API: - toggle: bound, initially-pressed, disabled - switch: bound, disabled - collapsible: bound show/hide, disabled trigger - avatar: loaded, error fallback, delayed - dialog: basic with overlay + focus trap + escape dismissal - drawer: right / left / bottom (with handle) - popover: click + hover trigger - toast: 4 intents (fulfill, risk, threat, neutral) via createToaster Verified end-to-end with scripts/demo-probe.ts (Playwright): - All 9 routes (landing + 8 demos) serve 200. - Zero console errors except avatar's pravatar.cc network failure (sandbox limitation, not a real bug). - Interactive checks: dialog open shows modal + overlay backdrop + focused Cancel button; popover open positions floating content next to trigger; toast Fulfill shows the green-tinted shadow driven by data-event-intent='fulfill' from sema's visual channel reacting to the morfo's announce event semantics — confirms the full morfo → sema → eidos pipeline works end-to-end on a migrated soma component. scripts/demo-probe.ts: small Playwright runner that loads each route, captures console errors, takes a screenshot of the static state, then clicks the trigger on dialog/collapsible/popover/toast for a second "open" screenshot. Output goes to g:/tmp/demos/. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
</header>
eidos: pilot wrapper pattern + doctrinal API conventions Toggle as the eidos pilot: subdirectory layout (recipe + Svelte wrapper + types + index + README) replacing the flat CSS-only form. Pattern is documented in eidos/components/README.md and the toggle README. Shared types live in eidos/lib/types.ts. First export is `Size` (8 values xxs..xxl + full); components narrow with `Extract<Size, ...>` per the per-component-subset doctrine. No `Eidos` prefix on types — module path already conveys the layer. API doctrine: - soma stays compound (Toggle.Provider) for symmetry with multi-part - eidos exports both default + Provider so single-part components accept both `<Toggle>` (ergonomic) and `<Toggle.Provider>` (compound-style consumers) SoundChannel eager-init fixes the autoplay race: AudioContext is created + resumed synchronously on the first user gesture (capture-phase listener registered in the constructor), avoiding the previous race where the first emit() scheduled the resume in a microtask outside the gesture window. Demo page (web/routes/toggle/+page.svelte) restructured so the live preview renders ALWAYS above the tablist — Sema-tab Play buttons can fire on the real toggle. Motion preview amplifies scale ×8 visually only; doctrinal values stay in the <dl>. Conventions 7-13 added to src/docs/sema-implementation-guide.md covering: directory structure, wrapper composition, no Eidos prefix, soma compound vs eidos flat, iconOnly sr-only body, sound eager-init, docs-preview amplification. CLAUDE.md gets a session hand-off block listing where things stand and next concrete steps (migrate switch/collapsible/dialog/drawer/popover/ toast/avatar; wire topbar sound mute to masterGain; rename theme tokens to drop the success/warning/danger fallback aliases). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 months ago
<div class="shell">
<aside class="rail">
<nav class="nav">
{#each groups as group}
{@const items = components.filter((c) => c.group === group.id)}
<div>
<div class="nav-group-head">{group.heading}</div>
<ul>
{#each items as comp}
<li>
<a
href="/{comp.slug}"
class:active={current === `/${comp.slug}`}
>
{comp.label}
</a>
</li>
{/each}
</ul>
</div>
{/each}
</nav>
<footer class="rail-foot">
soma · morfo · sema · eidos
</footer>
</aside>
<div class="canvas-wrap">
{@render children?.()}
</div>
</div>

Powered by TurnKey Linux.