feat(project-editor): add sticky save/publish bar with validation summary

Mounts a new ProjectEditorSaveBarComponent in the editor page that shows
draft/published status, unsaved-changes indicator, and validation issues,
wiring the Task 8 facade save()/publish()/dirty/status/validationIssues
signals to an actual UI for the first time.
This commit is contained in:
sdarbinyan
2026-07-13 15:00:03 +04:00
parent 85038df24a
commit 1e7add2fc8
9 changed files with 95 additions and 0 deletions

View File

@@ -0,0 +1,19 @@
<div class="project-editor-save-bar">
<div class="project-editor-save-bar-status">
<span>{{ (status() === 'published' ? 'builder.statusPublished' : 'builder.statusDraft') | translate }}</span>
@if (dirty()) {
<span class="project-editor-save-bar-dirty">{{ 'builder.unsavedChanges' | translate }}</span>
}
@if (issues().length > 0) {
<ul class="project-editor-save-bar-issues">
@for (issue of issues(); track issue.code) {
<li>{{ issue.message | translate }}</li>
}
</ul>
}
</div>
<div class="project-editor-save-bar-actions">
<button type="button" (click)="save()">{{ 'builder.save' | translate }}</button>
<button type="button" [disabled]="issues().length > 0" (click)="publish()">{{ 'builder.publish' | translate }}</button>
</div>
</div>

View File

@@ -0,0 +1,27 @@
.project-editor-save-bar {
position: sticky;
bottom: 0;
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: 1rem;
padding: 0.75rem 1rem;
background: var(--surface, #fff);
border-top: 1px solid var(--border, #ddd);
z-index: 5;
}
.project-editor-save-bar-dirty {
color: var(--warning, #b45309);
margin-left: 0.5rem;
}
.project-editor-save-bar-issues {
margin: 0.25rem 0 0;
padding-left: 1.25rem;
color: var(--danger, #b91c1c);
}
.project-editor-save-bar-actions button + button {
margin-left: 0.5rem;
}

View File

@@ -0,0 +1,26 @@
import { ChangeDetectionStrategy, Component, inject } from '@angular/core';
import { TranslatePipe } from '../../../../i18n/translate.pipe';
import { ProjectEditorFacade } from '../../facade/project-editor.facade';
@Component({
selector: 'app-project-editor-save-bar',
standalone: true,
imports: [TranslatePipe],
templateUrl: './project-editor-save-bar.component.html',
styleUrls: ['./project-editor-save-bar.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ProjectEditorSaveBarComponent {
private readonly facade = inject(ProjectEditorFacade);
readonly dirty = this.facade.dirty;
readonly status = this.facade.status;
readonly issues = this.facade.validationIssues;
save(): void {
this.facade.save();
}
publish(): void {
this.facade.publish();
}
}