feat(static-pages): media picker + per-page modified indicator

Milestone 4 of the Static Pages Module sprint.

- heroImage/thumbnail now wire through the existing MediaPickerComponent
  (same media-field-row + "choose image" pattern as branding-section), not
  plain URL text alone. gallery stays a lightweight CSV field ("future
  ready" per the brief - no dedicated multi-upload UI this sprint).
- ProjectEditorFacade: add originalStaticPages, a narrow computed exposing
  the originally loaded/published staticPages snapshot (mirrors the facade's
  existing pattern of small single-purpose computeds).
- StaticPagesEditorComponent: isModified(page) diffs a page against its
  normalized original snapshot, reusing ContentManagementFacade.pages() for
  normalization rather than reimplementing it. Renders as an amber
  "unsaved changes" badge per page.

Draft/published status UI, publish/unpublish actions, and the plain-text
media fields landed already in M2; this milestone completes M4's remaining
scope (visual media picker + modified indicator) without duplicating that
work.

Gate: tsc --noEmit, npm test (57/57), arch:check, build all green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
sdarbinyan
2026-07-17 10:05:50 +04:00
parent bfee935798
commit 910690c4d1
3 changed files with 56 additions and 2 deletions

View File

@@ -63,6 +63,8 @@ export class ProjectEditorFacade {
readonly lastSavedAt = computed(() => this.state().lastSavedAt);
readonly lastPublishedAt = computed(() => this.state().lastPublishedAt);
readonly draftRestored = computed(() => this.state().draftRestored);
/** The originally loaded/published `staticPages` snapshot, for per-page modified-state comparison in the Static Pages editor. */
readonly originalStaticPages = computed(() => this.state().originalBootstrap?.staticPages ?? null);
readonly validationIssues = computed(() => {
const current = this.bootstrap();
return current ? this.validator.validate(current) : [];