feat(cms): add static pages module

This commit is contained in:
sdarbinyan
2026-07-10 13:52:01 +04:00
parent e2c8747fcc
commit 7d6c09a346
25 changed files with 890 additions and 159 deletions

View File

@@ -14,7 +14,11 @@
<ul>
@for (item of group.items; track item.id) {
<li>
<a [routerLink]="item.route | langRoute">{{ item.label | translate }}</a>
@if (item.external) {
<a [href]="item.route" target="_blank" rel="noopener">{{ item.label | translate }}</a>
} @else {
<a [routerLink]="item.route | langRoute">{{ item.label | translate }}</a>
}
</li>
}
</ul>

View File

@@ -20,7 +20,11 @@
{{ 'header.catalog' | translate }}
</button>
}
<!-- TODO(CMS): Render backend-configured header content links here. -->
@for (page of headerPages(); track page.id) {
<button type="button" (click)="navigateToStatic(page.route)" class="platform-nav-btn platform-nav-btn-left">
{{ page.title }}
</button>
}
</div>
</nav>
@@ -140,7 +144,14 @@
</a>
}
<!-- TODO(CMS): Render backend-configured mobile content links here. -->
@for (page of headerPages(); track page.id) {
<a (click)="navigateToStatic(page.route)" class="platform-mobile-item" style="cursor: pointer;">
<span>{{ page.title }}</span>
<svg class="platform-mobile-chevron" width="8" height="14" viewBox="0 0 8 14" fill="none">
<path d="M1 1L7 7L1 13" stroke="#697777" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</a>
}
<div class="platform-mobile-controls">
@if (headerConfig().showRegion) {

View File

@@ -11,6 +11,7 @@ import { UiRuntimeFacade } from '../../facades/runtime/ui-runtime.facade';
import { UserExperienceFacade } from '../../facades/platform/user-experience.facade';
import { ConfigService } from '../../core/config/config.service';
import { DEFAULT_HEADER_CONFIG, DEFAULT_USER_EXPERIENCE_CONFIG } from '../../shared/models/config';
import { StaticPageResolverService } from '../../core/config/static-page-resolver.service';
@Component({
selector: 'app-header',
@@ -30,11 +31,13 @@ export class HeaderComponent {
private uiRuntime = inject(UiRuntimeFacade);
private uxFacade = inject(UserExperienceFacade);
private configService = inject(ConfigService);
private staticPageResolver = inject(StaticPageResolverService);
readonly wishlistCount = this.uxFacade.wishlistCount;
readonly compareCount = this.uxFacade.compareCount;
readonly userExperienceConfig = computed(() => this.resolveUserExperienceConfig());
readonly headerConfig = computed(() => this.resolveHeaderConfig());
readonly headerPages = computed(() => this.resolveHeaderPages());
constructor(private cartService: CartService, private router: Router) {
this.cartItemCount = this.cartService.itemCount;
@@ -111,6 +114,12 @@ export class HeaderComponent {
this.router.navigate([`/${lang}/compare`]);
}
navigateToStatic(route: string): void {
this.closeMenu();
const lang = this.langService.currentLanguage();
this.router.navigate([`/${lang}${route.startsWith('/') ? route : `/${route}`}`]);
}
formatCartTotal(total: number): string {
const locale = this.langService.currentLanguage() === 'en'
? 'en-US'
@@ -154,6 +163,31 @@ export class HeaderComponent {
...raw,
};
}
private resolveHeaderPages() {
this.configService.bootstrapRevision();
const bootstrap = this.configService.getBootstrapSnapshot();
if (!bootstrap?.staticPages) {
return [] as Array<{ id: string; title: string; route: string; icon?: string; order: number }>;
}
const lang = this.langService.currentLanguage();
const pages = Object.values(bootstrap.staticPages as Record<string, any>)
.filter(page => page.showInHeader === true)
.map(page => {
const resolved = this.staticPageResolver.resolveByKeyFromBootstrap(bootstrap, page.id, lang);
return resolved ? {
id: resolved.id,
title: resolved.title,
route: resolved.route,
icon: resolved.icon,
order: page.order ?? 0,
} : null;
})
.filter((page): page is { id: string; title: string; route: string; icon: string | undefined; order: number } => page !== null);
return pages.sort((left, right) => left.order - right.order);
}
}