feat(project-editor): route-driven tabs under /edit/:section

This commit is contained in:
sdarbinyan
2026-07-13 07:55:43 +04:00
parent e4a3ee25db
commit 74e5099b04
6 changed files with 53 additions and 12 deletions

View File

@@ -40,12 +40,22 @@ const coreRoutes: Routes = [
loadComponent: () => import('./features/website/catalog/containers/catalog-container.component').then(m => m.CatalogContainerComponent) loadComponent: () => import('./features/website/catalog/containers/catalog-container.component').then(m => m.CatalogContainerComponent)
}, },
{ {
path: 'builder', path: 'edit/:section',
loadComponent: () => import('./features/project-editor/pages/project-editor-page.component').then(m => m.ProjectEditorPageComponent) loadComponent: () => import('./features/project-editor/pages/project-editor-page.component').then(m => m.ProjectEditorPageComponent)
}, },
{
path: 'edit',
redirectTo: 'edit/general',
pathMatch: 'full'
},
{
path: 'builder',
redirectTo: 'edit/general',
pathMatch: 'full'
},
{ {
path: 'project-editor', path: 'project-editor',
redirectTo: 'builder', redirectTo: 'edit/general',
pathMatch: 'full' pathMatch: 'full'
}, },
{ {

View File

@@ -1,5 +1,9 @@
<nav class="editor-nav" [attr.aria-label]="'builder.title' | translate"> <nav class="editor-nav" [attr.aria-label]="'builder.title' | translate">
@for (section of sections; track section.id) { @for (section of sections; track section.id) {
<button type="button" [class.active]="active === section.id" (click)="activeChange.emit(section.id)">{{ section.label | translate }}</button> <a
[routerLink]="['/edit', section.id] | langRoute"
routerLinkActive="active"
class="editor-nav-link"
>{{ section.label | translate }}</a>
} }
</nav> </nav>

View File

@@ -4,7 +4,8 @@
gap: 10px; gap: 10px;
} }
button { button,
.editor-nav-link {
min-height: 40px; min-height: 40px;
border-radius: 999px; border-radius: 999px;
border: 1px solid var(--border-color, #d3dad9); border: 1px solid var(--border-color, #d3dad9);
@@ -15,8 +16,15 @@ button {
cursor: pointer; cursor: pointer;
} }
button.active { button.active,
.editor-nav-link.active {
border-color: #497671; border-color: #497671;
background: #497671; background: #497671;
color: #fff; color: #fff;
} }
.editor-nav-link {
text-decoration: none;
display: inline-block;
line-height: 40px;
}

View File

@@ -1,19 +1,18 @@
import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core'; import { ChangeDetectionStrategy, Component } from '@angular/core';
import { RouterLink, RouterLinkActive } from '@angular/router';
import { TranslatePipe } from '../../../i18n/translate.pipe'; import { TranslatePipe } from '../../../i18n/translate.pipe';
import { LangRoutePipe } from '../../../pipes/lang-route.pipe';
import { ProjectEditorSectionId } from '../models/project-editor.model'; import { ProjectEditorSectionId } from '../models/project-editor.model';
@Component({ @Component({
selector: 'app-project-editor-nav', selector: 'app-project-editor-nav',
standalone: true, standalone: true,
imports: [TranslatePipe], imports: [TranslatePipe, RouterLink, RouterLinkActive, LangRoutePipe],
templateUrl: './project-editor-nav.component.html', templateUrl: './project-editor-nav.component.html',
styleUrls: ['./project-editor-nav.component.scss'], styleUrls: ['./project-editor-nav.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush
}) })
export class ProjectEditorNavComponent { export class ProjectEditorNavComponent {
@Input() active: ProjectEditorSectionId = 'general';
@Output() activeChange = new EventEmitter<ProjectEditorSectionId>();
readonly sections: Array<{ id: ProjectEditorSectionId; label: string }> = [ readonly sections: Array<{ id: ProjectEditorSectionId; label: string }> = [
{ id: 'general', label: 'builder.general' }, { id: 'general', label: 'builder.general' },
{ id: 'branding', label: 'builder.branding' }, { id: 'branding', label: 'builder.branding' },

View File

@@ -4,7 +4,7 @@
<h1>{{ 'builder.title' | translate }}</h1> <h1>{{ 'builder.title' | translate }}</h1>
<p>{{ 'builder.subtitle' | translate }}</p> <p>{{ 'builder.subtitle' | translate }}</p>
</div> </div>
<app-project-editor-nav [active]="activeSection()" (activeChange)="facade.setActiveSection($event)" /> <app-project-editor-nav />
</header> </header>
@if (!bootstrap()) { @if (!bootstrap()) {

View File

@@ -1,4 +1,7 @@
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'; import { ChangeDetectionStrategy, Component, effect, inject } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { toSignal } from '@angular/core/rxjs-interop';
import { map } from 'rxjs/operators';
import { ProjectEditorFacade } from '../facade/project-editor.facade'; import { ProjectEditorFacade } from '../facade/project-editor.facade';
import { ProjectEditorNavComponent } from '../components/project-editor-nav.component'; import { ProjectEditorNavComponent } from '../components/project-editor-nav.component';
import { ProjectEditorGeneralSectionComponent } from '../sections/general-section.component'; import { ProjectEditorGeneralSectionComponent } from '../sections/general-section.component';
@@ -12,6 +15,11 @@ import { ProjectEditorFeaturesSectionComponent } from '../sections/features-sect
import { ProjectEditorPreviewSectionComponent } from '../sections/preview-section.component'; import { ProjectEditorPreviewSectionComponent } from '../sections/preview-section.component';
import { TranslatePipe } from '../../../i18n/translate.pipe'; import { TranslatePipe } from '../../../i18n/translate.pipe';
import { StaticPagesEditorComponent } from '../../content-management/components/static-pages-editor.component'; import { StaticPagesEditorComponent } from '../../content-management/components/static-pages-editor.component';
import { ProjectEditorSectionId } from '../models/project-editor.model';
const KNOWN_SECTIONS: ProjectEditorSectionId[] = [
'general', 'branding', 'theme', 'header', 'footer', 'homepage', 'widgets', 'static-pages', 'features', 'preview'
];
@Component({ @Component({
selector: 'app-project-editor-page', selector: 'app-project-editor-page',
@@ -36,10 +44,22 @@ import { StaticPagesEditorComponent } from '../../content-management/components/
}) })
export class ProjectEditorPageComponent { export class ProjectEditorPageComponent {
readonly facade = inject(ProjectEditorFacade); readonly facade = inject(ProjectEditorFacade);
private readonly route = inject(ActivatedRoute);
readonly bootstrap = this.facade.bootstrap; readonly bootstrap = this.facade.bootstrap;
readonly activeSection = this.facade.activeSection; readonly activeSection = this.facade.activeSection;
private readonly routeSection = toSignal(
this.route.paramMap.pipe(map(params => params.get('section') as ProjectEditorSectionId | null)),
{ initialValue: null }
);
constructor() { constructor() {
this.facade.loadBootstrap(); this.facade.loadBootstrap();
effect(() => {
const section = this.routeSection();
if (section && KNOWN_SECTIONS.includes(section)) {
this.facade.setActiveSection(section);
}
});
} }
} }