Targ Apps Docs

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).

SlotRol
skip link«Saltar al contenido» — enfoca #taf-main sin cambiar el hash
headerHeader mobile: marca + «Menú» (Show <768px)
topbar-navHeader desktop: marca + NavBar topbar (Show ≥768px)
mainContenedor sin padding lateral (id="taf-main")
main-cardCard de contenido (.taf-main-card): margen 10px, borde, scroll vertical
mobile-drawerPanel lateral con NavBar variante drawer (texto)

data-variant en el root del layout: "desktop" | "mobile" (derivado de useBreakpoint()).

Breakpoints

NombreMedia queryComportamiento
Mobile (default)< 768pxMarca + Menú, drawer de texto, sin tab bar
Desktop≥ 768pxMarca y enlaces en una sola fila (proximidad, sin caja extra)
Desktop compacto768px–1024pxMisma 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ás env(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: NavBar topbar, solo texto, sentence case, peso 400.
  • Tema: no vive en el header; ThemeToggle queda 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.

Variantepadding-top en .taf-main
Mobile y desktopheader-height + safe-area

.taf-main-card: margin: 10px en los cuatro lados.

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; inert en main mientras está abierto.
  • prefers-reduced-motion desactiva 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.

PropTipoDescripción
titlestringTítulo de página (requerido)
descriptionstring?Subtítulo opcional
eyebrowstring?Etiqueta superior en mayúsculas
actionsVNode | VNode[]?Slot de acción primaria (botón, enlace)
classstring?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ónCuá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.

TokenValorCapa
--taf-z-main20Contenido principal
--taf-z-bottom-nav25Legado (tab bar ya no se monta)
--taf-z-header70Header fijo
--taf-z-drawer80Drawer mobile
--taf-z-toast90Toasts
--taf-z-select-open1300Select abierto (por encima de modales ~1050–1100)

Archivos clave

  • src/components/SiteFrame.js (deprecado; no se monta en el shell)
  • src/components/Layout.js
  • src/components/NavBar.js
  • src/components/PageHeader.js
  • src/components/TargMark.js
  • src/styles/layout.css
  • logic/useBreakpoint.js
  • src/animations.js

On this page