metis-desk/docs/navegacion-responsive-v01-2.md
David 74b63cb385 feat: Implement responsive navigation architecture V01.2 for tablet and laptop
- Introduced `CompanyDetailBody` to maintain content identity and landmark separation from menu presentation.
- Added `CompanyFixedNavigation` to ensure visibility of identity while allowing navigation without content displacement.
- Created sidebar preference helper functions for reading and saving sidebar collapsed state.
- Defined workspace navigation capacity budgets and modes to manage responsive behavior based on shell width.
- Implemented focus management for workspace navigation to ensure proper accessibility and user experience.
- Developed a custom hook `useWorkspaceCapacity` to observe shell size changes and update navigation capacity accordingly.
- Updated documentation to reflect changes in responsive navigation architecture and testing procedures.
2026-10-21 23:35:56 +02:00

16 KiB
Raw Blame History

V01.2 — Navegación responsive en portátil y tablet

21 de octubre de 2026. Segunda entrega de la arquitectura B híbrida. Completa la adaptación de las navegaciones; V01 sigue parcialmente resuelto y quedan pendientes V01.3/V01.4.

Arquitectura y alcance

La navegación global presenta tres modos: expandida de 228 px, raíl de 72 px y Sheet sin reserva lateral. La navegación de compañía presenta una columna de 240 px o el Sheet existente. Los destinos se comparten entre presentaciones: no se copian los 21 enlaces, contadores, permisos ni consultas. Rutas, filtros y paginación mantienen sus contratos.

WorkspaceMobileNavigationProvider amplía el coordinador de V01.1: conserva una sola raíz Sheet y añade la preferencia manual global, intención contextual temporal y modos efectivos. useWorkspaceCapacity observa únicamente el contenedor del shell con un ResizeObserver, publica bandas discretas y se desconecta al desmontar. No almacena anchuras en React ni observa tablas o paneles. Las clases/CSS responden al modo publicado; no hay otra colección de umbrales por componente.

Los nombres Mobile de los componentes de V01.1 se mantienen para evitar una migración de rutas/imports ajena a la entrega; sus presentaciones superpuestas ahora se reutilizan también en tablet y portátil.

La columna contextual agrupa identidad, edición, ocultación y destinos en CompanyFixedNavigation. CompanyDetailBody mantiene el landmark y la identidad de contenido separados de la presentación de menús, con key estable por sección. Su navegación tiene scroll independiente; el contenido conserva una zona principal de scroll. La cabecera es sticky también en escritorio. La franja contextual solo aparece cuando la columna está superpuesta: mantiene compañía, sección y activador sin duplicar una segunda cabecera cuando ya existe columna fija.

El raíl conserva nombres accesibles y tooltips al foco/hover, incluidos compañías y catálogos. Ofrece Menú global y expansión temporal con etiquetas en Sheet. En los tamaños sin raíl el activador está en la cabecera. Búsqueda y cuenta conservan su comportamiento y traducciones es/en.

No se modifica vendor, backend, autenticación, permisos, dependencias, inventario ni selección/detalle de activos y recursos. Los breakpoints inventory=1100, dashboard=1200 y useCompactDetail siguen iguales.

Presupuestos y modos

La fuente única de la política es workspace-navigation-capacity.ts. Se contrasta con el ancho del shell, sin asumir que coincide siempre con el viewport:

Capacidad del shell Global efectiva Compañía efectiva por defecto
<920 px Sheet Sheet
≥920 y <1160 px Raíl 72 Sheet
≥1160 y <1660 px Raíl 72 Columna 240
≥1660 px 228 o 72 según preferencia Columna 240

Se conserva además la composición de cabecera de 768 px de V01.1: nominal 56 px por debajo y 88 px desde esa anchura. No es otro presupuesto horizontal de navegación.

Las sumas de referencia son 72+48+800=920, 72+240+48+800=1160 y 228+240+48+800+24+320=1660. Los 800 px son una referencia operativa, no un mínimo absoluto para dispositivos físicos ni una nueva política de panel. Bordes y distribución real se registran en la matriz; no se presenta la suma teórica como medición.

La misma política se aplica en dashboard/directorio y compañía, evitando que cambiar de sección expanda/contraiga el raíl automáticamente. Ocultar la secundaria libera 240 px; no fuerza expansión de la global. Abrir el detalle de inventario tampoco altera los modos del shell.

Preferencias e intención

  • Solo se conserva la clave existente metis-desk:sidebar-collapsed. true solicita raíl; false, ausencia o valor inválido conserva la expansión predeterminada cuando cabe.
  • La adaptación automática no escribe localStorage. Al recuperar capacidad vuelve a aplicarse la preferencia manual. La acción de contraer/expandir en ancho amplio sigue siendo la única que guarda esa elección.
  • Cuando no cabe la global expandida, Expandir menú abre un Sheet temporal: no sustituye la preferencia guardada ni resta ancho al contenido.
  • Ocultar secciones conserva una intención temporal en el workspace. Sobrevive a cambios de anchura y de compañía dentro de ese montaje; no se persiste y se reinicia al recargar. Fijar secciones vuelve a la columna cuando cabe.
  • Si no cabe la columna, Fijar secciones permanece deshabilitado con explicación. Ganar espacio no sobrescribe una ocultación manual.
  • Apertura de Sheet, compañía activa y mediciones no se incorporan a las preferencias. Los errores de acceso/escritura de localStorage mantienen navegación en memoria.

Foco, modalidad y estabilidad

Base UI mantiene trap, inert y bloqueo del fondo. Los destinos siguen siendo BrowserLink reales: Enter, clic modificado, clic central, URL directa e historial conservan su semántica. Escape/cerrar restaura el origen; navegar de manera ordinaria enfoca el contenido.

Al ensanchar, un menú cuya presentación pasa a fija se cierra y busca el enlace equivalente, o su destino activo. Si continúa necesitando Sheet, permanece abierto. Al estrechar nunca se abre por sí solo: los enlaces o activadores que desaparecen trasladan foco a un control visible equivalente. Si el foco continúa en el contenido o un formulario, se conserva.

La resolución de foco se realiza después del commit, sobre la presentación realmente visible. Los elementos de navegaciones ocultas no forman parte del recorrido de teclado. El cambio contextual → global usa la misma raíz modal, sin dos menús simultáneos ni retorno intermedio al fondo.

Cabecera/franja y foco emplean el offset del shell, scroll-padding y scroll-margin. Los cambios de modo no cambian el key del contenido ni sus filtros, búsqueda, selección o formularios.

Mediciones antes/después

Línea base: V01.1 cargada por URL directa, una compañía y un activo sintéticos, sin preferencias. Cinco pantallas —dashboard, directorio, resumen, listado y ficha de activo— en once resoluciones: 55 mediciones y capturas por fase. Se esperan fuentes, frames y transiciones antes de medir.

Resolución Global / compañía Ancho main antes → después Tabla útil después Y de main después
1920×1080 228 / 240 1452 → 1452 1401 88
1660×900 228 / 240 1192 → 1192 1141 88
1440×900 72 / 240 972 → 1128 1077 88
1366×768 72 / 240 898 → 1054 1003 88
1160×800 72 / 240 692 → 848 797 88
1100×800 72 / Sheet 632 → 1028 978 137
1024×768 72 / Sheet 556 → 952 902 137
920×768 72 / Sheet 452 → 848 798 137
768×1024 Sheet / Sheet 300 → 768 718 137
390×844 Sheet / Sheet 390 → 390 356 106
320×640 Sheet / Sheet 320 → 320 286 106

No se registra overflow horizontal del documento en ninguna de las 55 mediciones posteriores. En los límites nominales la tabla útil mide 797–798 px, 2–3 px menos que la referencia de 800 por bordes/distribución; se mantienen los presupuestos redondos como prioridades, no mínimos absolutos. No se introducen umbrales adicionales para compensar esa diferencia.

El móvil conserva la geometría de V01.1. Los controles intermedios dejan de reservar ambas columnas; no se confunde esta recuperación con la resolución del panel de inventario.

Pruebas y resultados

Se reutiliza el procedimiento scripts/visual-audit.py y el cliente Playwright MCP mediante Docker/Chromium. Se prepara una única instancia sintética de auditoría; la BD de tests globales se aísla en otro contenedor. No se usa la BD local real ni se crean usuarios adicionales para ampliar la cobertura.

sidebar-preference.test.ts conserva las pruebas de valores inválidos/almacenamiento inaccesible y añade límites, preferencia frente a modo efectivo e intención contextual. scripts/visual-audit-ui.test.py amplía las pruebas ya existentes, sin framework paralelo.

La validación cubre límites a ambos lados, los 21 destinos, teclado, foco, tooltip, preferencias y recarga, ocultación/fijación, resize, conservación de tabla/formulario, scroll independiente, traducciones y nombres largos. Se repiten las regresiones V02/V03/V06/V09 con datos sintéticos. Los intentos fallidos de desarrollo no se cuentan como pasadas aprobadas.

Suite final completa: 16 pruebas Playwright MCP aprobadas en 453,516 s. Incluye las regresiones V01.1, V02, V03, V06 y V09. La consola final registra cero errores y cero avisos. La comprobación semántica de orientación confirma compañía y sección visibles en once resoluciones; sus anchos/Y finales coinciden con la matriz posterior tras los últimos ajustes de composición.

Pasan las cinco pruebas ejecutadas directamente de preferencia/capacidad y las doce pruebas de app.test.tsx, además del caso dirigido de navegación de compañía es/en. La suite global de Node mantiene dos expectativas antiguas fallidas de companies-page.test.tsx; no se confunde el éxito de los casos dirigidos con el éxito de toda la suite.

Comando / comprobación Resultado real
pnpm --filter @metis/companies typecheck Pasa
pnpm --filter @metis/web typecheck Pasa
Biome dirigido, 20 archivos propios TS/TSX/JSON Pasa sin errores ni avisos
ESLint de espaciado, 18 archivos TS/TSX Pasa
pnpm build Pasa; conserva aviso de chunk grande
pnpm typecheck Falla en vendor calendar.tsx:165, incompatibilidad locale/exactOptionalPropertyTypes ya documentada; vendor intacto
pnpm lint Falla: 15 errores, un aviso y cuatro informaciones en archivos ajenos, como fotos/procesos/migraciones/skills
pnpm check Falla: 168 errores, un aviso y cuatro informaciones de formato/reglas globales ajenas; propios comprobados separadamente
pnpm test con MariaDB aislada Falla en las expectativas previas «Personas (1)» y «Esta persona no tiene acceso a Metis Desk». Turbo termina con 7 tareas correctas de 8 y no acredita las suites que el fallo interrumpe

Estos fallos globales ya figuran en el seguimiento del sprint 1 y V01.1; se contrastan los diagnósticos, no se atribuye automáticamente cualquier fallo a deuda previa. Los contenedores de tests se retiraron al finalizar. El preparador visual cerró sus servicios, retiró su BD y borró sesión/credenciales al terminar la auditoría; se conservaron los contenedores previos ajenos. No se corrigen archivos ajenos para conseguir checks globales verdes.

Se reprodujo con una prueba adicional el foco en BODY al desaparecer el activador entre 390→768; después de corregir el reconocimiento de los activadores, pasan los cuatro escenarios de cambio de cabecera/contexto. Se mantienen la prueba fallida previa y la posterior como evidencia de la corrección. También se corrigieron errores del propio guion MCP —ejecución DOM fuera de page.evaluate, nombres de botones y esperas de frames—; no se contabilizan como defectos de Metis ni como pruebas aprobadas.

Para verificar cambio de compañía se creó una segunda compañía exclusivamente en la BD sintética, mediante el formulario real. La excepción HTTP del guion permite solo ese POST de fixture; los demás formularios se cancelan y no se realizan borrados. La matriz antes/después se tomó antes de añadir esa segunda compañía. No se crean usuarios adicionales.

Para repetir, mantener abierto el preparador y usar la ruta privada que imprima:

METIS_PLAYWRIGHT_STORAGE_STATE=.artifacts/playwright/authenticated-ID/session.json \
METIS_UI_AUDIT_DIRECTORY=.artifacts/playwright/v01-2/after \
python3 scripts/visual-audit-ui.test.py -v

Sustituir ID por la sesión real. No versionar ni compartir esa sesión.

Evidencias y límites

Evidencias locales excluidas de Git, bajo .artifacts/playwright/v01-2/. Las capturas se abren y examinan: geometría, snapshot y comportamiento no son pruebas intercambiables. Los logs identifican fallos previos y regresiones corregidas de esta entrega.

A 1100 px se conserva el panel de 320 y la tabla queda en 634; a 1024 se conserva el diálogo, de aproximadamente 922 px. Captura del límite pendiente. No se presenta esta tabla todavía estrecha como un problema resuelto por V01.2.

Para compartir evidencia, entregar únicamente el directorio v01-2/; excluir authenticated-*, sesiones y credenciales. Se revisan las cabeceras PNG y dimensiones al generar el índice. La configuración MCP permanece sin cambios.

No se declara cumplimiento WCAG ni verificación con lector de pantalla. El zoom real de Chromium headless no se considera probado por ampliar la fuente raíz; se conserva esa distinción de V01.1. Tampoco se prueba Cmd+clic en macOS, Docker Desktop/arm64 o todas las combinaciones de roles/compañías/tema oscuro.

V01.3 sigue pendiente: la política actual de panel/diálogo depende del viewport, no de la capacidad del inventario tras las navegaciones. V01.4 —migración de recursos y regresión final global de V01— tampoco se implementa. No se abordan V04–V12.

Archivos principales y documentación

  • Shell: companies-workspace, workspace-sidebar, workspace-header, workspace-navigation-content, workspace-search, workspace-navigation-button y el provider/context de V01.1.
  • Política/DOM: workspace-navigation-capacity.ts, use-workspace-capacity.ts y workspace-navigation-focus.ts. El helper de preferencia se mueve, sin cambiar su contrato, de view a shared para que el coordinador no dependa de una operación superior.
  • Compañía: company-detail, company-detail-body, company-fixed-navigation, company-context-bar y company-navigation-sheet.
  • Estilos locales de composición en apps/web/src/global.css, textos en common/locales/es.json y en.json, pruebas de preferencias y el guion MCP existente.
  • Documentación actualizada: DESIGN, componentes, propuesta V01, seguimiento de auditoría y descripción responsive de rutas. No cambia ningún destino.

Skills y APIs consultadas

ux-navigation dirige orientación, ámbitos, etiquetas y descubribilidad; frontend-design conserva jerarquía e identidad existentes; shadcn guía Sheet y Tooltip sobre sus APIs instaladas. Las reglas de composición y React sustentan el coordinador compartido, estado mínimo y una suscripción discreta con cleanup. No se consulta Pro Max sin una duda específica ni se genera otra paleta/sistema visual.

La CLI informativa pnpm dlx shadcn@latest docs sheet tooltip falla por DNS. Se consultan las docs de Sheet, Tooltip y Dialog/Base UI, contrastadas con vendor instalado, sin modificarlo. Los auditores especializados no instalados no se presentan como ejecutados; la comprobación interactiva se realiza con MCP.