diff --git a/src/app/features/project-editor/components/save-bar/project-editor-save-bar.component.html b/src/app/features/project-editor/components/save-bar/project-editor-save-bar.component.html
new file mode 100644
index 0000000..175bf9d
--- /dev/null
+++ b/src/app/features/project-editor/components/save-bar/project-editor-save-bar.component.html
@@ -0,0 +1,19 @@
+
+
+
{{ (status() === 'published' ? 'builder.statusPublished' : 'builder.statusDraft') | translate }}
+ @if (dirty()) {
+
{{ 'builder.unsavedChanges' | translate }}
+ }
+ @if (issues().length > 0) {
+
+ @for (issue of issues(); track issue.code) {
+ - {{ issue.message | translate }}
+ }
+
+ }
+
+
+
+
+
+
diff --git a/src/app/features/project-editor/components/save-bar/project-editor-save-bar.component.scss b/src/app/features/project-editor/components/save-bar/project-editor-save-bar.component.scss
new file mode 100644
index 0000000..4a213a4
--- /dev/null
+++ b/src/app/features/project-editor/components/save-bar/project-editor-save-bar.component.scss
@@ -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;
+}
diff --git a/src/app/features/project-editor/components/save-bar/project-editor-save-bar.component.ts b/src/app/features/project-editor/components/save-bar/project-editor-save-bar.component.ts
new file mode 100644
index 0000000..3b858ed
--- /dev/null
+++ b/src/app/features/project-editor/components/save-bar/project-editor-save-bar.component.ts
@@ -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();
+ }
+}
diff --git a/src/app/features/project-editor/pages/project-editor-page.component.html b/src/app/features/project-editor/pages/project-editor-page.component.html
index 821be84..fa0d546 100644
--- a/src/app/features/project-editor/pages/project-editor-page.component.html
+++ b/src/app/features/project-editor/pages/project-editor-page.component.html
@@ -28,5 +28,6 @@
@case ('preview') { }
}
+
}
diff --git a/src/app/features/project-editor/pages/project-editor-page.component.ts b/src/app/features/project-editor/pages/project-editor-page.component.ts
index bde7495..3dbb9a7 100644
--- a/src/app/features/project-editor/pages/project-editor-page.component.ts
+++ b/src/app/features/project-editor/pages/project-editor-page.component.ts
@@ -17,6 +17,7 @@ import { ProjectEditorNavigationSectionComponent } from '../sections/navigation-
import { ProjectEditorPreviewSectionComponent } from '../sections/preview-section.component';
import { TranslatePipe } from '../../../i18n/translate.pipe';
import { StaticPagesEditorComponent } from '../../content-management/components/static-pages-editor.component';
+import { ProjectEditorSaveBarComponent } from '../components/save-bar/project-editor-save-bar.component';
import { ProjectEditorSectionId } from '../models/project-editor.model';
const KNOWN_SECTIONS: ProjectEditorSectionId[] = [
@@ -41,6 +42,7 @@ const KNOWN_SECTIONS: ProjectEditorSectionId[] = [
ProjectEditorLanguagesSectionComponent,
ProjectEditorNavigationSectionComponent,
ProjectEditorPreviewSectionComponent,
+ ProjectEditorSaveBarComponent,
],
templateUrl: './project-editor-page.component.html',
styleUrls: ['./project-editor-page.component.scss'],
diff --git a/src/app/i18n/en.ts b/src/app/i18n/en.ts
index 008c031..5d09372 100644
--- a/src/app/i18n/en.ts
+++ b/src/app/i18n/en.ts
@@ -512,6 +512,11 @@ export const en: Translations = {
validationMissingWidget: 'A homepage section has a widget with no type.',
validationDuplicateNavLinks: 'Two or more header navigation links are duplicates.',
validationInvalidColors: 'One or more theme colors are not valid hex colors.',
+ statusDraft: 'Draft',
+ statusPublished: 'Published',
+ unsavedChanges: 'Unsaved changes',
+ save: 'Save',
+ publish: 'Publish',
},
staticPages: {
notFound: 'Page not found',
diff --git a/src/app/i18n/hy.ts b/src/app/i18n/hy.ts
index 483e80e..532131f 100644
--- a/src/app/i18n/hy.ts
+++ b/src/app/i18n/hy.ts
@@ -512,6 +512,11 @@ export const hy: Translations = {
validationMissingWidget: 'Գլխավոր էջի սեկցիաներից մեկն ունի վիջեթ առանց տիպի։',
validationDuplicateNavLinks: 'Վերնագրի նավիգացիայում կան կրկնվող հղումներ։',
validationInvalidColors: 'Թեմայի գույներից մեկը կամ մի քանիսը վավեր hex գույն չեն։',
+ statusDraft: 'Սևագիր',
+ statusPublished: 'Հրապարակված',
+ unsavedChanges: 'Չպահված փոփոխություններ',
+ save: 'Պահպանել',
+ publish: 'Հրապարակել',
},
staticPages: {
notFound: 'Էջը չի գտնվել',
diff --git a/src/app/i18n/ru.ts b/src/app/i18n/ru.ts
index 7d46a2b..4658433 100644
--- a/src/app/i18n/ru.ts
+++ b/src/app/i18n/ru.ts
@@ -512,6 +512,11 @@ export const ru: Translations = {
validationMissingWidget: 'В секции главной страницы есть виджет без типа.',
validationDuplicateNavLinks: 'Две или более ссылки в навигации шапки дублируются.',
validationInvalidColors: 'Один или несколько цветов темы указаны некорректно.',
+ statusDraft: 'Черновик',
+ statusPublished: 'Опубликовано',
+ unsavedChanges: 'Есть несохранённые изменения',
+ save: 'Сохранить',
+ publish: 'Опубликовать',
},
staticPages: {
notFound: 'Страница не найдена',
diff --git a/src/app/i18n/translations.ts b/src/app/i18n/translations.ts
index d1b15f8..f42d861 100644
--- a/src/app/i18n/translations.ts
+++ b/src/app/i18n/translations.ts
@@ -510,6 +510,11 @@ export interface Translations {
validationMissingWidget: string;
validationDuplicateNavLinks: string;
validationInvalidColors: string;
+ statusDraft: string;
+ statusPublished: string;
+ unsavedChanges: string;
+ save: string;
+ publish: string;
};
staticPages: {
notFound: string;