refactor: finalize bootstrap-driven layout and widget runtime
This commit is contained in:
@@ -2,13 +2,17 @@ import { Injectable } from '@angular/core';
|
||||
import { PageConfig } from '../../shared/models/config';
|
||||
import { PageRenderModel } from '../page-renderer/page-renderer.model';
|
||||
import { SectionRendererService } from '../section-renderer/section-renderer.service';
|
||||
import { PlatformLayoutConfig, PlatformLayoutType } from '../../shared/models/config';
|
||||
import { SectionConfig } from '../../shared/models/config';
|
||||
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class SectionEngineService {
|
||||
constructor(private readonly sectionRenderer: SectionRendererService) {}
|
||||
|
||||
toPageRenderModel(page: PageConfig): PageRenderModel {
|
||||
const sections = (page.sections ?? [])
|
||||
const layoutType = this.resolveLayoutType(page.layout);
|
||||
|
||||
const sections = this.normalizeSectionsByLayout(page.sections ?? [], layoutType)
|
||||
.filter((section) => section.visible !== false)
|
||||
.sort((a, b) => a.order - b.order)
|
||||
.map((section) => this.sectionRenderer.toRenderNode(section));
|
||||
@@ -17,9 +21,111 @@ export class SectionEngineService {
|
||||
id: page.id,
|
||||
key: page.key,
|
||||
title: page.title,
|
||||
layout: page.layout,
|
||||
layout: layoutType,
|
||||
sections,
|
||||
source: page
|
||||
};
|
||||
}
|
||||
|
||||
private resolveLayoutType(layout: PageConfig['layout']): string {
|
||||
if (typeof layout === 'string') {
|
||||
return layout;
|
||||
}
|
||||
|
||||
return (layout as PlatformLayoutConfig)?.type ?? 'default';
|
||||
}
|
||||
|
||||
private normalizeSectionsByLayout(sections: PageConfig['sections'], layoutType: string): PageConfig['sections'] {
|
||||
const normalized = [...sections];
|
||||
const lowerLayout = (layoutType as PlatformLayoutType).toLowerCase();
|
||||
|
||||
if (lowerLayout === 'minimal') {
|
||||
return normalized.filter(section => {
|
||||
const type = section.type.toLowerCase();
|
||||
return type === 'product-collection' || type === 'products' || type === 'catalog';
|
||||
});
|
||||
}
|
||||
|
||||
if (lowerLayout === 'sidebar-left') {
|
||||
return this.composeSidebarLayout(normalized);
|
||||
}
|
||||
|
||||
if (lowerLayout === 'carousel-home') {
|
||||
return normalized.sort((left, right) => this.getCarouselPriority(left.type) - this.getCarouselPriority(right.type));
|
||||
}
|
||||
|
||||
if (lowerLayout === 'default') {
|
||||
return normalized.sort((left, right) => this.getDefaultPriority(left.type) - this.getDefaultPriority(right.type));
|
||||
}
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
private getDefaultPriority(type: string): number {
|
||||
const normalizedType = type.toLowerCase();
|
||||
if (normalizedType === 'categories') return 10;
|
||||
if (normalizedType === 'product-collection' || normalizedType === 'products') return 20;
|
||||
if (normalizedType === 'hero') return 30;
|
||||
return 100;
|
||||
}
|
||||
|
||||
private getSidebarPriority(type: string): number {
|
||||
const normalizedType = type.toLowerCase();
|
||||
if (normalizedType === 'categories') return 10;
|
||||
if (normalizedType === 'product-collection' || normalizedType === 'products') return 20;
|
||||
if (normalizedType === 'hero') return 30;
|
||||
return 100;
|
||||
}
|
||||
|
||||
private getCarouselPriority(type: string): number {
|
||||
const normalizedType = type.toLowerCase();
|
||||
if (normalizedType === 'hero' || normalizedType === 'banner') return 10;
|
||||
if (normalizedType === 'product-collection' || normalizedType === 'product-carousel') return 20;
|
||||
if (normalizedType === 'categories') return 30;
|
||||
return 100;
|
||||
}
|
||||
|
||||
private composeSidebarLayout(sections: PageConfig['sections']): PageConfig['sections'] {
|
||||
const categoriesSection = sections.find(section => section.type.toLowerCase() === 'categories');
|
||||
const productsSection = sections.find(section => {
|
||||
const type = section.type.toLowerCase();
|
||||
return type === 'product-collection' || type === 'products' || type === 'catalog';
|
||||
});
|
||||
|
||||
if (!categoriesSection || !productsSection) {
|
||||
return [...sections].sort((left, right) => this.getSidebarPriority(left.type) - this.getSidebarPriority(right.type));
|
||||
}
|
||||
|
||||
const combined: SectionConfig = {
|
||||
...categoriesSection,
|
||||
id: `${categoriesSection.id}-sidebar-layout`,
|
||||
type: 'sidebar-left',
|
||||
order: Math.min(categoriesSection.order, productsSection.order),
|
||||
layout: {
|
||||
strategy: 'grid',
|
||||
columns: 2,
|
||||
gap: '1.5rem',
|
||||
align: 'start'
|
||||
},
|
||||
widgets: [
|
||||
...categoriesSection.widgets.map((widget, index) => ({
|
||||
...widget,
|
||||
order: index,
|
||||
padding: widget.padding ?? '0',
|
||||
visibility: widget.visibility ?? { desktop: true, tablet: true, mobile: true }
|
||||
})),
|
||||
...productsSection.widgets.map((widget, index) => ({
|
||||
...widget,
|
||||
order: 100 + index,
|
||||
padding: widget.padding ?? '0',
|
||||
visibility: widget.visibility ?? { desktop: true, tablet: true, mobile: true }
|
||||
}))
|
||||
]
|
||||
};
|
||||
|
||||
return [
|
||||
combined,
|
||||
...sections.filter(section => section.id !== categoriesSection.id && section.id !== productsSection.id)
|
||||
].sort((left, right) => left.order - right.order);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user