Layout & Navigation
Shell responsive, navegación hash-based y animaciones de transición (TAF-005, TAF-023).
Layout & Navigation
Shell de la app en src/components/Layout.js y src/components/NavBar.js. Estilos estructurales en src/styles/layout.css; tokens y utilidades vienen del plugin chroma-style (plugins/chroma-style/).
Estructura
┌──────────────────────────────────────────── desktop (≥768px)
│ header flush, chrome terciario, hairline oklch(92% 0.005 250)
│ TargMark + Targ Apps — Finance Dashboard Transacciones …
│ main
│ └─ .taf-main-card (margen 10px, card gigante scrollable)
└────────────────────────────────────────────
┌──────────────────── mobile (<768px)
│ header flush
│ [ marca ] [ Menú ]
│ main → .taf-main-card (10px margen, scroll)
│ drawer (texto, sin iconos ni cabecera extra)
└────────────────────Auth y onboarding (#/auth, #/onboarding) no montan Layout — pantalla limpia vía AppShell (isFullScreenRoute).
| Slot | Rol |
|---|---|
| skip link | «Saltar al contenido» — enfoca #taf-main sin cambiar el hash |
header | Header mobile: marca + «Menú» (Show <768px) |
topbar-nav | Header desktop: marca + NavBar topbar (Show ≥768px) |
main | Contenedor sin padding lateral (id="taf-main") |
main-card | Card de contenido (.taf-main-card): margen 10px, borde, scroll vertical |
mobile-drawer | Panel lateral con NavBar variante drawer (texto) |
data-variant en el root del layout: "desktop" | "mobile" (derivado de useBreakpoint()).
Breakpoints
| Nombre | Media query | Comportamiento |
|---|---|---|
| Mobile (default) | < 768px | Marca + Menú, drawer de texto, sin tab bar |
| Desktop | ≥ 768px | Marca y enlaces en una sola fila (proximidad, sin caja extra) |
| Desktop compacto | 768px–1024px | Misma estructura; tipo y gap un poco más justos |
Hook: logic/useBreakpoint.js — hookState + listener matchMedia("(min-width: 768px)").
Header (.taf-header-label)
Chrome terciario: el contenido gana. Barra fija a ancho completo, sin caja extra alrededor de la nav.
- Posición:
position: fixed; z-index: var(--taf-z-header);top: 0. - Altura:
--taf-header-label-height(2.75rem / 44px) másenv(safe-area-inset-top). - Desktop: un grupo — marca + enlaces (gap 8–16px entre hermanos).
- Mobile: dos grupos — marca a la izquierda, «Menú» a la derecha (32px+ entre clusters).
- Fondo:
--background(sin tinte, sin sombra, sin glass). - Regla: hairline
1px solid oklch(92% 0.005 250)(oscuro:oklch(24% 0.008 250)). - Marca:
TargMark+ «Targ Apps — Finance» en peso 500 y tracking-0.03em. - Nav desktop:
NavBartopbar, solo texto, sentence case, peso 400. - Tema: no vive en el header;
ThemeTogglequeda en Ajustes. - Skip link: «Saltar al contenido», visible en
:focus-visible.
--taf-header-label-offset queda en 0.
Padding del main
El main no aplica padding lateral; el card interno define márgenes.
| Variante | padding-top en .taf-main |
|---|---|
| Mobile y desktop | header-height + safe-area |
.taf-main-card: margin: 10px en los cuatro lados.
NavBar
Siete rutas hash: Dashboard, Transacciones, Recurrentes, Presupuestos, Cuentas, Reportes, Ajustes.
Enlaces de texto únicamente (NAV_ITEMS en src/components/NavBar.js). Sin iconos, pills, badges ni tab bar inferior.
- Inactivos: peso 400, opacidad ~60%.
- Hover: opacidad 1 en 150ms (sin scale, lift ni sombra).
- Activo: peso 500 + una subrayado de 1px en
--taf-shell-ledger(cobre de marca). - Drawer: la misma lista de texto; sin cabecera, iconos ni barra inset.
- Accesibilidad:
<nav>+aria-label,aria-current="page",.focus-ring(:focus-visible). - Mobile: targets 44px; Escape cierra; focus trap en el panel;
inertenmainmientras está abierto. prefers-reduced-motiondesactiva las transiciones de opacidad del shell.
PageHeader (chrome compartido)
src/components/PageHeader.js — cabecera reutilizable para páginas de ruta. Los agentes de redesign de páginas deben usarla en lugar de <h1> sueltos.
| Prop | Tipo | Descripción |
|---|---|---|
title | string | Título de página (requerido) |
description | string? | Subtítulo opcional |
eyebrow | string? | Etiqueta superior en mayúsculas |
actions | VNode | VNode[]? | Slot de acción primaria (botón, enlace) |
class | string? | Clases extra en el root |
Ejemplo:
import { PageHeader } from "../src/components/PageHeader.js";
e(PageHeader, {
title: "Transacciones",
description: "Movimientos registrados en tus cuentas.",
actions: e("button", { class: "cs-btn cs-btn-primary", type: "button" }, "Nueva"),
})Estilos: [data-component="page-header"], .taf-page-header__title, .taf-page-header__actions en finance.css.
Integración con el router
AppShell (src/App.js) monta cada entrada de routes con Show dentro de Layout. La ruta activa (route() de useRouter()) se pasa como activeRoute a Layout → NavBar.
Los clics usan href hash nativos; no hay recarga de página.
Animaciones (Anime.js)
La nav no usa motion de entrada, stagger ni scale. El drawer abre/cierra con opacidad CSS (180ms).
src/animations.js — el shell solo llama:
| Función | Cuándo |
|---|---|
animateRouteChange(main) | Cambio de hash / página visible (contenido, no la nav) |
Anime.js se importa en src/main.js (globalThis.anime) y respeta prefers-reduced-motion.
Header corner SVG
src/components/SiteFrame.js exporta SiteCornerSvg y SITE_FRAME_CORNER_PATH (cuarto de círculo 50×50). El marco viewport y las bridas del header ya no se montan en el shell; el archivo queda como referencia.
CSS
- Chroma-Style: clases utilitarias (
bg-background,flex,focus-ring, …) en componentes. - layout.css: grid del shell, header flush,
.taf-main-card, drawer, nav lists, safe-area en iOS. - finance.css: estilos de dominio (dashboard, cards,
.cs-btn, …) — no duplica el shell.
Z-index del shell
Orden: main < header < drawer < toast < modals < select.
| Token | Valor | Capa |
|---|---|---|
--taf-z-main | 20 | Contenido principal |
--taf-z-bottom-nav | 25 | Legado (tab bar ya no se monta) |
--taf-z-header | 70 | Header fijo |
--taf-z-drawer | 80 | Drawer mobile |
--taf-z-toast | 90 | Toasts |
--taf-z-select-open | 1300 | Select abierto (por encima de modales ~1050–1100) |
Archivos clave
src/components/SiteFrame.js(deprecado; no se monta en el shell)src/components/Layout.jssrc/components/NavBar.jssrc/components/PageHeader.jssrc/components/TargMark.jssrc/styles/layout.csslogic/useBreakpoint.jssrc/animations.js