feat(gioser): deck swipeable + minimize, brand+copyleft en taskbar (vista-web)

Nuevo módulo agnóstico:
- `crates/modules/vista/vista-web` — Deck::mount(strip) instala swipe
  horizontal con snap a la página más cercana, estilo Flutter PageView.
  goto(idx, smooth) navega programáticamente. on_change(cb) fires tras
  snap. Drag decision: horizontal si dx > 8px y > 1.3*dy; sino cede al
  pan-y nativo (scroll vertical del contenido). resize listener ajusta
  --vista-offset sin animar usando .vista-instant un frame.

App rediseñada:
- Brand "GioSer" sacado del centro de la chacana → ahora en la taskbar
  junto al botón home (data-home). brand-dot dorado entre Gio·Ser. El
  centro de la chacana queda con sol limpio.
- Copyleft + sergio@gioser.net a la derecha de la taskbar, abre
  https://sergio.gioser.net en nueva pestaña (target=_blank rel=noopener).
- 4 drawers separados → reemplazados por un único `.deck` con `.deck-strip`
  vista-web manejado. Las páginas se crean dinámicamente al abrir un
  elemento por primera vez (`ensure_page_dom`).
- Cada página tiene controles minimizar (─) y cerrar (×) arriba a la
  derecha, con ambience animada por elemento.
- Click minimize → active=None, deck scale(0) hacia la cajita del
  taskbar (origin = bounding rect del taskbar-item). Página queda en
  memoria, tab sigue en la barra.
- Click cajita del taskbar:
  - Si está activa → minimize (toggle).
  - Si está minimizada → restore con scale-up desde la cajita.
- Click home / brand → minimize all (estilo Show Desktop, no destruye).
- Swipe horizontal o click cajita → deck.goto(idx, smooth=true) con snap
  animado por vista-web. on_swipe sync de taskbar active state.
- Cerrar página → remueve del strip + del Vec pages; si era activa,
  reemplaza por neighbor o hide deck si era la última.

CSS:
- Eliminado `.brand` fixed center y `.drawer` × 4 individuales.
- `.deck` único + `.deck-strip` con `transform: translate3d(--vista-offset)`
  y transition transform 360ms cubic-bezier(0.22, 0.61, 0.36, 1).
- `.deck-strip.vista-dragging` / `.vista-instant` → transition: none.
- `.deck-page[data-element]` cada una con su page-ambience animada
  (aire-drift, fuego-flicker, agua-tide, tierra static).
- `.taskbar-brand` Cinzel 1.3rem dorado + .brand-dot.
- `.taskbar-credit` con `.copyleft-mark` (© con scaleX(-1) = copyleft
  visual).
- `.taskbar-spacer { flex:1 }` empuja credit a la derecha.
- `.taskbar-item.active` glow del color del elemento + border-bottom.
- `body.deck-visible` baja opacity del canvas + esconde tips y brand.

Workspace verde + 18 tests (geom 6 + palette 4 + physics 3 + pluma-md 5).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
sergio
2026-05-14 02:20:34 +00:00
parent 5e0fcae4b4
commit 62058ab193
8 changed files with 830 additions and 346 deletions
+18 -52
View File
@@ -12,10 +12,6 @@
<body>
<canvas id="gioser-canvas" aria-hidden="true"></canvas>
<header id="brand" class="brand">
<h1 class="brand-title">Gio<span class="brand-dot">·</span>Ser</h1>
</header>
<main id="tips" aria-label="Cuatro elementos">
<a id="tip-aire" class="tip tip-aire" href="#aire" data-md="./md/aire.md" aria-label="Aire — Software e IA">
<svg viewBox="0 0 48 48" class="tip-glyph" aria-hidden="true">
@@ -59,55 +55,14 @@
</a>
</main>
<!-- DRAWERS: uno por elemento. Cada uno crece desde la posición del tip
clickeado (origin set via CSS vars desde WASM) hasta fullscreen. -->
<aside id="drawer-aire" class="drawer drawer-aire" data-element="aire" aria-hidden="true">
<button class="drawer-close" data-close-drawer aria-label="Cerrar Aire">×</button>
<div class="drawer-ambience" aria-hidden="true"></div>
<header class="drawer-head">
<span class="drawer-mark">aire</span>
<h2 class="drawer-title">Aire</h2>
<span class="drawer-tag">Software · IA · Aspiración</span>
</header>
<section class="drawer-content" id="drawer-aire-content"></section>
</aside>
<!-- DECK: contenedor único con strip horizontal. Las páginas se inyectan
dinámicamente desde WASM. vista-web maneja swipe + snap. -->
<div id="deck" class="deck vista-deck" aria-hidden="true">
<div id="deck-strip" class="deck-strip vista-strip" role="region" aria-label="Vistas abiertas"></div>
</div>
<aside id="drawer-fuego" class="drawer drawer-fuego" data-element="fuego" aria-hidden="true">
<button class="drawer-close" data-close-drawer aria-label="Cerrar Fuego">×</button>
<div class="drawer-ambience" aria-hidden="true"></div>
<header class="drawer-head">
<span class="drawer-mark">fuego</span>
<h2 class="drawer-title">Fuego</h2>
<span class="drawer-tag">Inspiración</span>
</header>
<section class="drawer-content" id="drawer-fuego-content"></section>
</aside>
<aside id="drawer-tierra" class="drawer drawer-tierra" data-element="tierra" aria-hidden="true">
<button class="drawer-close" data-close-drawer aria-label="Cerrar Tierra">×</button>
<div class="drawer-ambience" aria-hidden="true"></div>
<header class="drawer-head">
<span class="drawer-mark">tierra</span>
<h2 class="drawer-title">Tierra</h2>
<span class="drawer-tag">Cuerpo</span>
</header>
<section class="drawer-content" id="drawer-tierra-content"></section>
</aside>
<aside id="drawer-agua" class="drawer drawer-agua" data-element="agua" aria-hidden="true">
<button class="drawer-close" data-close-drawer aria-label="Cerrar Agua">×</button>
<div class="drawer-ambience" aria-hidden="true"></div>
<header class="drawer-head">
<span class="drawer-mark">agua</span>
<h2 class="drawer-title">Agua</h2>
<span class="drawer-tag">Espiritualidad aplicada</span>
</header>
<section class="drawer-content" id="drawer-agua-content"></section>
</aside>
<!-- TASKBAR estilo Windows: home a la izquierda + cajitas dinámicas
de las vistas MD abiertas. Sincronizada por WASM. -->
<nav class="taskbar" aria-label="Vistas abiertas">
<!-- TASKBAR estilo Windows: home + GioSer + tabs + copyleft -->
<nav class="taskbar" aria-label="Barra de vistas">
<button class="taskbar-home" data-home aria-label="Volver al home" type="button">
<svg viewBox="0 0 24 24" class="taskbar-home-glyph" aria-hidden="true">
<path d="M3 12 L12 3 L21 12" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round" stroke-linecap="round"/>
@@ -115,8 +70,19 @@
<circle cx="12" cy="17" r="0.8" fill="currentColor"/>
</svg>
</button>
<a class="taskbar-brand" data-home href="#home" aria-label="GioSer · home">
<span>Gio</span><span class="brand-dot">·</span><span>Ser</span>
</a>
<span class="taskbar-divider" aria-hidden="true"></span>
<ul class="taskbar-list" id="taskbar-list" role="presentation"></ul>
<span class="taskbar-spacer" aria-hidden="true"></span>
<a class="taskbar-credit" href="https://sergio.gioser.net" target="_blank" rel="noopener noreferrer" aria-label="Copyleft sergio arroba gioser punto net">
<span class="copyleft-mark" aria-hidden="true">©</span>
<span class="taskbar-credit-text">sergio@gioser.net</span>
</a>
</nav>
<script type="module">