import { CommonModule } from '@angular/common'; import { ChangeDetectionStrategy, Component, Input } from '@angular/core'; import { NgComponentOutlet } from '@angular/common'; import { Observable } from 'rxjs'; import { PageRenderModel } from '../../dynamic-renderer/page-renderer/page-renderer.model'; import { WidgetRenderNode } from '../../dynamic-renderer/widget-host/widget-host.model'; import { ResolvedWidget } from '../../widgets/contracts/widget-component.contract'; import { WidgetHostService } from '../../dynamic-renderer/widget-host/widget-host.service'; @Component({ selector: 'app-dynamic-page-layout', standalone: true, imports: [CommonModule, NgComponentOutlet], template: ` @if (model) { @for (section of model.sections; track section.id) { @for (widget of section.widgets; track widget.id) { @if (resolveWidget(widget, section, model.id) | async; as resolved) { } } } } `, styles: [ ` .dynamic-page-layout { display: block; } .dynamic-section__content { display: grid; gap: var(--section-gap, 1rem); align-items: var(--section-align, stretch); } .dynamic-section[data-section-layout='grid'] .dynamic-section__content { grid-template-columns: repeat(var(--section-columns, 1), minmax(0, 1fr)); } .dynamic-section[data-section-layout='hero'] .dynamic-section__content { grid-template-columns: minmax(0, 1fr); } .dynamic-section--desktop-hidden { display: none; } @media (max-width: 1023px) { .dynamic-section--tablet-hidden { display: none; } } @media (max-width: 767px) { .dynamic-section--mobile-hidden { display: none; } } ` ], changeDetection: ChangeDetectionStrategy.OnPush }) export class DynamicPageLayoutComponent { @Input() model: PageRenderModel | null = null; constructor(private readonly widgetHost: WidgetHostService) {} resolveWidget(widget: WidgetRenderNode, section: PageRenderModel['sections'][number], pageId: string): Observable { return this.widgetHost.resolveWidget(widget.source, section.source, pageId); } }