FactuGES_ERP/docs/frontend/UI/page-layouts.md
David 3d2ce8b981 feat: add page layouts documentation and visual system design for Rdx UI components
- Introduced `page-layouts.md` to outline approved page patterns for progressive adoption.
- Created `visual-system-design.md` to consolidate visual, architectural, and adoption decisions for a uniform UI/UX system in the ERP frontend.
- Added `RdxEditorActionBar` component for managing action bars in editor screens.
- Implemented `RdxPanel` component for grouping related content with optional headers and actions.
2026-09-04 11:07:59 +02:00

8.2 KiB

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:

Listado

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:

<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

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

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

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:

<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:

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

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:

<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:

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

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.