FactuGES_ERP/docs/frontend/UI/page-layouts.md

261 lines
8.2 KiB
Markdown
Raw Normal View History

# Page Layouts Rdx
## Estado
Este documento describe los patrones conceptuales de página aprobados para adopción progresiva.
El documento canónico de contexto global es:
- [visual-system-design.md](./visual-system-design.md)
## Listado
```txt
RdxPageContainer
└── RdxPageStack
├── RdxPageHeader
├── notices opcionales
└── contenido del listado
```
Reglas:
- anchura por defecto `full`;
- acciones principales en cabecera;
- acciones de fila frecuentes visibles y acciones destructivas en overflow mediante `RdxRowActions`;
- panel contextual solo cuando aporte contexto real;
- la composición del listado no debe acoplarse a React Query, routing ni dominio.
Ejemplo de integración real validado en `proformas/list` y `customers/list`:
```tsx
<RdxPageContainer width="full">
<RdxPageStack spacing="default">
<RdxPageHeader
title={title}
description={description}
actions={<RdxPageActions primary={primaryAction} />}
/>
{notice}
{content}
</RdxPageStack>
{dialogs}
</RdxPageContainer>
```
Aclaraciones:
- `RdxPageContainer` resuelve el padding exterior y la anchura de página;
- `RdxPageStack` resuelve el ritmo vertical principal entre cabecera, aviso y contenido;
- `RdxPageHeader` no conoce navegación ni callbacks de React Router;
- la tabla, los filtros, los panels, los dialogs y los controllers permanecen fuera de las foundations;
- `RdxRowActions` puede vivir dentro de las columnas de tabla, pero recibe acciones ya decididas por el consumidor;
- en ambos pilotos el panel contextual sigue viviendo en composición local mediante `ResizablePanelGroup`;
- no documentar todavía `RdxListPageLayout` ni `RdxResponsivePageGrid` mientras el resize y la apertura del aside dependan del caso de uso.
### Evidencia de pilotos de listado
```txt
DECISIÓN_CONFIRMADA
Container + Stack + Header + Actions cubren la capa exterior del listado.
DECISIÓN_PROVISIONAL
La Page puede extraer una vista pura si mejora el test y reduce wiring.
NO_ABSTRAER_TODAVÍA
main + aside redimensionable
shell específico del panel contextual
toolbars
```
## Listado con panel contextual
```txt
ResizablePanelGroup
├── main
└── RightPanel
└── RdxContextPanel
```
Reglas:
- `ResizablePanelGroup` gestiona la geometría, el resize y la persistencia local del split;
- `RightPanel` gestiona la superficie lateral, la altura y el overflow base;
- `RdxContextPanel` gestiona cabecera, cierre, body y footer visual del panel;
- el contenido interno del panel sigue siendo específico del dominio;
- no documentar todavía un layout genérico de listado a partir de este patrón.
## Editor simple
```txt
scroll container
└── RdxEditorPageLayout complexity="simple"
└── form stack
├── RdxPanel
├── RdxPanel
└── ...
```
Reglas:
- las rutas cuya tarea principal sea crear, editar o configurar mediante un formulario focalizado deben entrar por el shell `app-fullscreen`;
- listados, dashboards, detalle y navegación de settings mantienen `app-sidebar` salvo necesidad funcional explícita;
- `RdxEditorPageLayout` resuelve padding interior, ancho centrado y `min-w-0`;
- el editor simple puede apoyarse en una única superficie contenedora para diferenciar la página del área editable, sin volver a cards por sección;
- `RdxPanel` expresa jerarquía por defecto con spacing y divisor inferior;
- `RdxFormGrid` mantiene la retícula del formulario sin conocer RHF ni dominio;
- priorizar lectura y velocidad de escaneo;
- usar secciones planas con espacio o divisores;
- reservar sticky footer solo cuando el scroll lo justifique.
Ejemplo validado en `customers/update`, `customers/create` y `/account`:
```tsx
<AppFullscreenLayout>
<PageFormHeader backLabel={backLabel} onBack={onBack} title={title} />
<div className="flex-1 overflow-y-auto">
<RdxEditorPageLayout complexity="simple">
<div className="flex min-w-0 flex-col gap-6">
{notice}
<form className="flex min-w-0 flex-col gap-6">
<RdxPanel title={title} description={description}>
<RdxFormGrid>{fields}</RdxFormGrid>
</RdxPanel>
</form>
</div>
</RdxEditorPageLayout>
</div>
</AppFullscreenLayout>
```
Deuda registrada:
- `PageFormHeader` sigue siendo full-width mientras el contenido del editor queda centrado en `max-w-5xl`;
- no modificar todavía el header legacy sin validación visual manual real.
Evidencia adicional de create/update:
```txt
DECISIÓN_CONFIRMADA
ambos flujos reutilizan el mismo layout, superficie y secciones.
ESPECÍFICO
defaults iniciales
wiring de submit
feedback de error
navegación de retorno concreta
```
Candidatos explícitos para auditoría posterior:
- `customers/create`
- `customers/update`
- `/account`
- `proformas/update`
## Editor complejo
```txt
shell
├── PageFormHeader
├── scroll container
│ └── RdxEditorPageLayout complexity="complex"
│ ├── main
│ │ └── única superficie editable
│ │ ├── RdxPanel
│ │ ├── RdxPanel
│ │ ├── bloque de líneas con layout propio
│ │ └── ...
│ └── aside
│ └── controles secundarios o contexto de apoyo
└── RdxEditorStickyFooter
├── summary/context region
└── action region
```
Reglas:
- `RdxEditorPageLayout` resuelve padding exterior, `min-w-0` y la geometría `main + aside`;
- el `main` debe alojar los campos editables y sus bloques funcionales;
- el `aside` debe reservarse para metadata, configuración o contexto de apoyo ya existente en la pantalla;
- el `aside` del editor complejo usa una geometría aproximada `minmax(0, 1fr) 22rem` en desktop y se apila debajo del `main` cuando no hay ancho suficiente;
- no mover campos editables al `aside` solo por estética si eso empeora el flujo;
- no mover los totales al `aside`;
- los bloques con layout interno propio, como una tabla de líneas, no deben forzarse dentro de `RdxFormGrid`;
- `RdxEditorStickyFooter` resuelve una única superficie sticky con una región contextual flexible y una región de acciones;
- los totales siguen perteneciendo al dominio de Proformas aunque se rendericen dentro de la región contextual del footer;
- `PageFormHeader` puede seguir existiendo, pero no debe duplicar `Guardar` y `Cancelar` cuando el footer sticky ya los contiene.
Ejemplo validado en `proformas/update`:
```tsx
<div className="fixed inset-0 flex flex-col overflow-hidden">
<PageFormHeader />
<div className="flex min-h-0 flex-1 flex-col bg-muted/20">
<div className="min-h-0 flex-1 overflow-y-auto">
{notice}
<RdxEditorPageLayout
complexity="complex"
aside={aside}
>
<div className="rounded-2xl border border-border bg-background px-4 py-4 shadow-xs md:px-6 md:py-6">
<form className="flex min-w-0 flex-col gap-6">
<RdxPanel title={documentTitle}>
<RdxFormGrid>{documentFields}</RdxFormGrid>
</RdxPanel>
{lineEditor}
</form>
</div>
</RdxEditorPageLayout>
</div>
<RdxEditorStickyFooter
leading={<TotalsSummary />}
secondary={cancelButton}
primary={saveButton}
status={status}
/>
</div>
</div>
```
Evidencia del piloto:
```txt
DECISIÓN_CONFIRMADA
main contiene la única superficie editable
aside contiene bloques secundarios ya existentes del editor
la sticky zone inferior pasa a una única superficie visual
los totales permanecen como dominio de Proformas dentro de la región contextual
las acciones principales comparten el mismo footer sin una segunda franja
RdxFormGrid se mantiene solo para campos
DECISIÓN_PROVISIONAL
visual exacta del header legacy frente al ancho full del editor complejo
NO_ABSTRAER_TODAVÍA
layout específico del bloque de líneas
layout específico del footer de totales
```
## Detalle
```txt
width="wide" o "full"
main + aside opcional
aside para metadata, actividad, resumen o acciones
```
Reglas:
- mantener patrón consistente de label/value;
- usar aside solo cuando el contenido realmente gane claridad;
- no implementar todavía `RdxDetailPageLayout` en esta fase.