import { ChangeDetectionStrategy, Component, signal } from '@angular/core'; import { LayoutHeight, LayoutTypeClass } from '@pi/ui'; import { ShowcaseSection } from '../showcase-section'; interface LayoutDemo { /** Nombre corto para el título del apartado. */ name: string; /** Constante de `LayoutTypeClass`, tal cual se aplica en el HostBinding. */ classes: string; /** Qué hace realmente el CSS de este layout. */ description: string; /** Bloques de relleno que se pintan dentro de la vista previa. */ blocks: string[]; } @Component({ selector: 'app-layouts', changeDetection: ChangeDetectionStrategy.OnPush, templateUrl: './layouts.page.html', styleUrl: './layouts.page.scss', imports: [ShowcaseSection], }) export class LayoutsPage { /** * Layouts que se sostienen solos: su CSS actúa sobre el propio contenedor, * así que la vista previa con bloques sueltos ya enseña lo que hacen. */ protected readonly standalone: LayoutDemo[] = [ { name: 'Vertically centered', classes: LayoutTypeClass.VerticallyCentered, description: 'Columna flex centrada verticalmente (justify-content: center). Típico de login, errores o estados vacíos.', blocks: ['Bloque centrado'], }, { name: 'Space between', classes: LayoutTypeClass.SpaceBetween, description: 'Columna flex con justify-content: space-between: empuja el primer bloque arriba y el último abajo.', blocks: ['Cabecera', 'Pie'], }, { name: 'Full width auto', classes: LayoutTypeClass.FullWidthAuto, description: 'Añade margin: auto sobre el full width, para centrar el bloque cuando no ocupa todo el ancho.', blocks: ['Contenido centrado'], }, { name: 'Pricing', classes: LayoutTypeClass.Pricing, description: 'Rejilla de 3 columnas (repeat(3, 1fr)) para tarifas; tiene variante 1fr 3fr con tarjeta destacada.', blocks: ['Básico', 'Pro', 'Empresas'], }, ]; /** * Estos no se pueden enseñar con bloques sueltos: su CSS apunta a los * componentes de wrapper o a estados del shell de la aplicación, así que * fuera de esa composición no cambian nada visible. */ protected readonly compositional = [ { name: 'Full width', classes: LayoutTypeClass.FullWidth, needs: 'Un ancestro con `aside-is-open`: los anchos máximos se calculan a partir del aside y el navbar.', }, { name: 'Splitted', classes: LayoutTypeClass.Splitted, needs: 'No parte en dos por sí solo: es una columna a 100vh y las mitades las aportan los slots izquierdo/derecho de `pi-main-wrapper`.', }, { name: 'Edge to edge', classes: LayoutTypeClass.EdgeToEdge, needs: 'Un `pi-wrapper__header` como hijo dentro de `.pi-container-layout`: lo que ajusta es su espaciado superior.', }, { name: 'List', classes: LayoutTypeClass.List, needs: 'Wrappers (`pi-wrapper`, `pi-wrapper__list`) y un `pi-data-grid`: limita sus anchos y centra la rejilla.', }, { name: 'List auto', classes: LayoutTypeClass.ListAuto, needs: 'Igual que List, para listados con scroll infinito.', }, { name: 'Form', classes: LayoutTypeClass.Form, needs: 'Ir anidado dentro de un `pi-layout__05-splitted`: solo ahí recibe padding y scrollbar propios.', }, ]; /** Alturas mínimas, aplicables sobre cualquier layout. */ protected readonly heights = [ { label: 'small', cls: LayoutHeight.Small, hint: '33.33vh' }, { label: 'medium', cls: LayoutHeight.Medium, hint: '40vh' }, { label: 'large', cls: LayoutHeight.Large, hint: '75vh' }, { label: 'full', cls: LayoutHeight.Full, hint: '100vh' }, ]; /** * Las vistas previas van recortadas: varios layouts piden `vh` y ocuparían * pantallas enteras. Se puede soltar el recorte para verlos a tamaño real. */ protected readonly clipped = signal(true); }