diff --git a/src/app/features/project-editor/facade/project-editor.facade.ts b/src/app/features/project-editor/facade/project-editor.facade.ts index c07db96..b920ed8 100644 --- a/src/app/features/project-editor/facade/project-editor.facade.ts +++ b/src/app/features/project-editor/facade/project-editor.facade.ts @@ -12,6 +12,8 @@ import { ProjectValidator, ProjectValidationIssue } from '../services/project-va import { ProjectEditorSectionId } from '../models/project-editor.model'; import { EditorSchemaService } from '../schema/editor-schema.service'; import { History, commit as commitHistory, emptyHistory, redo as redoHistory, undo as undoHistory } from '../schema/history.util'; +import { ProjectEditorDraftStorageService } from '../services/project-editor-draft-storage.service'; +import { EDITOR_SECTION_BOOTSTRAP_KEYS } from '../models/project-editor.model'; const HISTORY_DEBOUNCE_MS = 300; @@ -23,8 +25,6 @@ export interface ChangeSummaryRow { readonly before: string; readonly after: string; } -import { ProjectEditorDraftStorageService } from '../services/project-editor-draft-storage.service'; -import { EDITOR_SECTION_BOOTSTRAP_KEYS } from '../models/project-editor.model'; @Injectable({ providedIn: 'root' }) export class ProjectEditorFacade { @@ -195,8 +195,14 @@ export class ProjectEditorFacade { // Capture the pre-burst snapshot so a run of rapid edits collapses into one // undo step. The baseline is cleared when the debounce fires (or on undo). + // A fresh burst also invalidates any redo stack immediately (not just once + // the debounced commit lands) - otherwise Redo would stay enabled for up to + // HISTORY_DEBOUNCE_MS after a post-undo edit and silently discard it. if (this.pendingBaseline === null) { this.pendingBaseline = current; + if (this.history().future.length > 0) { + this.history.update(history => ({ ...history, future: [] })); + } } const next = this.normalize(updater(JSON.parse(JSON.stringify(current)) as BootstrapConfig)); this.state.update(state => ({ ...state, bootstrap: next, draftRestored: false })); diff --git a/src/app/features/project-editor/sections/footer-section.component.ts b/src/app/features/project-editor/sections/footer-section.component.ts index 9fe9a1c..753b7af 100644 --- a/src/app/features/project-editor/sections/footer-section.component.ts +++ b/src/app/features/project-editor/sections/footer-section.component.ts @@ -10,9 +10,7 @@ import { KeyValueEditorComponent } from '../../../shared/ui/key-value-editor/key import { MediaPickerComponent } from '../../../shared/media/media-picker/media-picker.component'; import { MediaAsset } from '../../../core/media/models/media-asset.model'; import { FooterPaymentIconConfig, FooterSocialLinkConfig } from '../../../shared/models/config'; - -/** Mirrors the HTTP_URL check in project-validator.service.ts (kept as a local duplicate: shared/ui must not import from features). */ -const HTTP_URL = /^https?:\/\/\S+$/; +import { isValidHttpUrl } from '../schema/validators/primitives'; type FooterMediaTarget = 'logo' | { type: 'paymentIcon'; index: number }; @@ -118,6 +116,6 @@ export class ProjectEditorFooterSectionComponent { } isValidUrl(url: string): boolean { - return !url || HTTP_URL.test(url); + return !url || isValidHttpUrl(url); } }