fix(builder): un-hide and relabel static-page content editor, warn on publish/remove-language
- KNOWN-ISSUES item 11: the WYSIWYG page content editor was buried inside a collapsed Advanced <details>, labeled 'Raw HTML (advanced)'. Moved it to the top of the Content tab, unwrapped, relabeled 'Page Content' / 'Содержимое страницы' / 'Эջի բովանդակություն' with a plain-language description. Advanced tab keeps genuinely technical fields (id, slug, route, custom template). - Publish (save-bar) and Remove language (languages-section) had no confirmation despite being destructive/high-impact — added window.confirm guards using the existing builder.confirm* i18n pattern (matches resetDraft/resetSection/dirty-guard precedent), all 3 locales. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -49,6 +49,25 @@
|
|||||||
</app-form-field>
|
</app-form-field>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<div class="page-editor__content-block">
|
||||||
|
<h3 class="page-editor__content-heading">{{ 'contentManagement.pageContentLabel' | translate }}</h3>
|
||||||
|
<p class="page-editor__explain">{{ 'contentManagement.pageContentDesc' | translate }}</p>
|
||||||
|
@for (locale of locales(); track locale) {
|
||||||
|
<label class="full page-editor__html-block">
|
||||||
|
@if (locales().length > 1) {
|
||||||
|
<span>{{ ('contentManagement.pageContentLabel' | translate) + ' — ' + locale }}</span>
|
||||||
|
}
|
||||||
|
<app-marketplace-html-editor
|
||||||
|
[html]="page().translations[locale]?.html || ''"
|
||||||
|
(htmlChange)="updateTranslation.emit({ locale, field: 'html', value: $event })"
|
||||||
|
/>
|
||||||
|
@if (hasInvalidHtml()) {
|
||||||
|
<p class="page-editor__error">{{ 'staticPages.invalidHtml' | translate }}</p>
|
||||||
|
}
|
||||||
|
</label>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="page-editor__media-grid">
|
<div class="page-editor__media-grid">
|
||||||
<div class="media-block">
|
<div class="media-block">
|
||||||
<span class="media-block__label">{{ 'staticPages.heroImageLabel' | translate }}</span>
|
<span class="media-block__label">{{ 'staticPages.heroImageLabel' | translate }}</span>
|
||||||
@@ -193,22 +212,6 @@
|
|||||||
<app-form-field [label]="'builder.seoKeywords' | translate">
|
<app-form-field [label]="'builder.seoKeywords' | translate">
|
||||||
<app-input [ngModel]="page().seo?.keywords || ''" (ngModelChange)="updateSeo.emit({ keywords: $event })" />
|
<app-input [ngModel]="page().seo?.keywords || ''" (ngModelChange)="updateSeo.emit({ keywords: $event })" />
|
||||||
</app-form-field>
|
</app-form-field>
|
||||||
|
|
||||||
<details class="page-editor__html-disclosure">
|
|
||||||
<summary>{{ 'contentManagement.groupAdvancedHtml' | translate }}</summary>
|
|
||||||
@for (locale of locales(); track locale) {
|
|
||||||
<label class="full page-editor__html-block">
|
|
||||||
<span>{{ 'builder.htmlPreview' | translate }} {{ locale }}</span>
|
|
||||||
<app-marketplace-html-editor
|
|
||||||
[html]="page().translations[locale]?.html || ''"
|
|
||||||
(htmlChange)="updateTranslation.emit({ locale, field: 'html', value: $event })"
|
|
||||||
/>
|
|
||||||
@if (hasInvalidHtml()) {
|
|
||||||
<p class="page-editor__error">{{ 'staticPages.invalidHtml' | translate }}</p>
|
|
||||||
}
|
|
||||||
</label>
|
|
||||||
}
|
|
||||||
</details>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -109,17 +109,17 @@
|
|||||||
gap: 8px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.page-editor__html-disclosure {
|
.page-editor__content-block {
|
||||||
border: 1px solid var(--border-subtle, #e7ece9);
|
display: grid;
|
||||||
border-radius: 10px;
|
gap: 8px;
|
||||||
padding: 10px 14px;
|
}
|
||||||
|
|
||||||
summary {
|
.page-editor__content-heading {
|
||||||
cursor: pointer;
|
margin: 0;
|
||||||
|
font-size: var(--font-size-base, 0.875rem);
|
||||||
font-weight: var(--font-weight-bold, 700);
|
font-weight: var(--font-weight-bold, 700);
|
||||||
color: var(--text-primary, #1e3c38);
|
color: var(--text-primary, #1e3c38);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
.page-editor__html-block {
|
.page-editor__html-block {
|
||||||
display: grid;
|
display: grid;
|
||||||
|
|||||||
@@ -37,8 +37,10 @@ export class ProjectEditorSaveBarComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
publish(): void {
|
publish(): void {
|
||||||
|
if (confirm(this.translate.t('builder.confirmPublish'))) {
|
||||||
this.facade.publish();
|
this.facade.publish();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
resetDraft(): void {
|
resetDraft(): void {
|
||||||
if (confirm(this.translate.t('builder.confirmResetDraft'))) {
|
if (confirm(this.translate.t('builder.confirmResetDraft'))) {
|
||||||
|
|||||||
@@ -59,8 +59,10 @@ export class ProjectEditorLanguagesSectionComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
removeLocale(code: string): void {
|
removeLocale(code: string): void {
|
||||||
|
if (confirm(this.translate.t('builder.confirmRemoveLanguage'))) {
|
||||||
this.facade.removeLocale(code);
|
this.facade.removeLocale(code);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setDefault(code: string): void {
|
setDefault(code: string): void {
|
||||||
this.facade.setDefaultLocale(code);
|
this.facade.setDefaultLocale(code);
|
||||||
|
|||||||
@@ -574,6 +574,8 @@ export const en: Translations = {
|
|||||||
save: 'Save',
|
save: 'Save',
|
||||||
publish: 'Publish',
|
publish: 'Publish',
|
||||||
confirmLeaveUnsaved: 'You have unsaved changes. Leave anyway?',
|
confirmLeaveUnsaved: 'You have unsaved changes. Leave anyway?',
|
||||||
|
confirmPublish: 'This makes your current changes live on the storefront immediately, replacing what shoppers see now. Continue?',
|
||||||
|
confirmRemoveLanguage: 'This removes the language and any content translated into it. Shoppers using this language will see the default language instead. Continue?',
|
||||||
promptLinkUrl: 'URL',
|
promptLinkUrl: 'URL',
|
||||||
promptImageUrl: 'Image URL',
|
promptImageUrl: 'Image URL',
|
||||||
promptEmbedUrl: 'Embed URL',
|
promptEmbedUrl: 'Embed URL',
|
||||||
@@ -1040,6 +1042,8 @@ export const en: Translations = {
|
|||||||
groupSharing: 'Sharing',
|
groupSharing: 'Sharing',
|
||||||
groupAdvanced: 'Advanced',
|
groupAdvanced: 'Advanced',
|
||||||
groupAdvancedHtml: 'Raw HTML (advanced)',
|
groupAdvancedHtml: 'Raw HTML (advanced)',
|
||||||
|
pageContentLabel: 'Page Content',
|
||||||
|
pageContentDesc: 'Write and format the text, images, and links shoppers will see on this page.',
|
||||||
seoExplainDesc: 'This is what shows up in search results — a clear title and description help customers find this page.',
|
seoExplainDesc: 'This is what shows up in search results — a clear title and description help customers find this page.',
|
||||||
seoTitleHelp: 'The headline shown in search results. Keep it short and descriptive.',
|
seoTitleHelp: 'The headline shown in search results. Keep it short and descriptive.',
|
||||||
seoDescriptionHelp: 'A short summary shown under the title in search results.',
|
seoDescriptionHelp: 'A short summary shown under the title in search results.',
|
||||||
|
|||||||
@@ -574,6 +574,8 @@ export const hy: Translations = {
|
|||||||
save: 'Պահպանել',
|
save: 'Պահպանել',
|
||||||
publish: 'Հրապարակել',
|
publish: 'Հրապարակել',
|
||||||
confirmLeaveUnsaved: 'Կան չպահված փոփոխություններ։ Այնուամենայնիվ դուրս գա՞լ։',
|
confirmLeaveUnsaved: 'Կան չպահված փոփոխություններ։ Այնուամենայնիվ դուրս գա՞լ։',
|
||||||
|
confirmPublish: 'Սա անմիջապես կկիրառի ընթացիկ փոփոխությունները կայքում՝ փոխարինելով այն, ինչ գնորդներն այժմ տեսնում են։ Շարունակե՞լ։',
|
||||||
|
confirmRemoveLanguage: 'Սա կհեռացնի լեզուն և դրանով թարգմանված ողջ բովանդակությունը։ Այս լեզվով օգտվող գնորդները կտեսնեն հիմնական լեզուն։ Շարունակե՞լ։',
|
||||||
promptLinkUrl: 'URL',
|
promptLinkUrl: 'URL',
|
||||||
promptImageUrl: 'Նկարի URL',
|
promptImageUrl: 'Նկարի URL',
|
||||||
promptEmbedUrl: 'Ներդրման URL',
|
promptEmbedUrl: 'Ներդրման URL',
|
||||||
@@ -1040,6 +1042,8 @@ export const hy: Translations = {
|
|||||||
groupSharing: 'Տարածում',
|
groupSharing: 'Տարածում',
|
||||||
groupAdvanced: 'Լրացուցիչ',
|
groupAdvanced: 'Լրացուցիչ',
|
||||||
groupAdvancedHtml: 'Հում HTML (լրացուցիչ)',
|
groupAdvancedHtml: 'Հում HTML (լրացուցիչ)',
|
||||||
|
pageContentLabel: 'Էջի բովանդակություն',
|
||||||
|
pageContentDesc: 'Գրեք և ձևավորեք տեքստը, նկարներն ու հղումները, որոնք գնորդները կտեսնեն այս էջում։',
|
||||||
seoExplainDesc: 'Սա այն է, ինչ երևում է որոնման արդյունքներում․ հստակ վերնագիրն ու նկարագրությունը օգնում են հաճախորդներին գտնել այս էջը։',
|
seoExplainDesc: 'Սա այն է, ինչ երևում է որոնման արդյունքներում․ հստակ վերնագիրն ու նկարագրությունը օգնում են հաճախորդներին գտնել այս էջը։',
|
||||||
seoTitleHelp: 'Վերնագիրը, որ երևում է որոնման արդյունքներում։ Պահեք կարճ և հստակ։',
|
seoTitleHelp: 'Վերնագիրը, որ երևում է որոնման արդյունքներում։ Պահեք կարճ և հստակ։',
|
||||||
seoDescriptionHelp: 'Կարճ նկարագրություն՝ վերնագրի տակ, որոնման արդյունքներում։',
|
seoDescriptionHelp: 'Կարճ նկարագրություն՝ վերնագրի տակ, որոնման արդյունքներում։',
|
||||||
|
|||||||
@@ -574,6 +574,8 @@ export const ru: Translations = {
|
|||||||
save: 'Сохранить',
|
save: 'Сохранить',
|
||||||
publish: 'Опубликовать',
|
publish: 'Опубликовать',
|
||||||
confirmLeaveUnsaved: 'Есть несохранённые изменения. Всё равно уйти?',
|
confirmLeaveUnsaved: 'Есть несохранённые изменения. Всё равно уйти?',
|
||||||
|
confirmPublish: 'Это сразу применит текущие изменения на витрине магазина вместо того, что покупатели видят сейчас. Продолжить?',
|
||||||
|
confirmRemoveLanguage: 'Это удалит язык и весь переведённый на него контент. Покупатели, использующие этот язык, увидят язык по умолчанию. Продолжить?',
|
||||||
promptLinkUrl: 'URL',
|
promptLinkUrl: 'URL',
|
||||||
promptImageUrl: 'URL изображения',
|
promptImageUrl: 'URL изображения',
|
||||||
promptEmbedUrl: 'URL для встраивания',
|
promptEmbedUrl: 'URL для встраивания',
|
||||||
@@ -1040,6 +1042,8 @@ export const ru: Translations = {
|
|||||||
groupSharing: 'Публикация в соцсетях',
|
groupSharing: 'Публикация в соцсетях',
|
||||||
groupAdvanced: 'Дополнительно',
|
groupAdvanced: 'Дополнительно',
|
||||||
groupAdvancedHtml: 'Исходный HTML (дополнительно)',
|
groupAdvancedHtml: 'Исходный HTML (дополнительно)',
|
||||||
|
pageContentLabel: 'Содержимое страницы',
|
||||||
|
pageContentDesc: 'Напишите и оформите текст, изображения и ссылки, которые увидят покупатели на этой странице.',
|
||||||
seoExplainDesc: 'Это то, что видно в результатах поиска — понятный заголовок и описание помогают клиентам найти страницу.',
|
seoExplainDesc: 'Это то, что видно в результатах поиска — понятный заголовок и описание помогают клиентам найти страницу.',
|
||||||
seoTitleHelp: 'Заголовок, отображаемый в результатах поиска. Делайте его коротким и понятным.',
|
seoTitleHelp: 'Заголовок, отображаемый в результатах поиска. Делайте его коротким и понятным.',
|
||||||
seoDescriptionHelp: 'Краткое описание под заголовком в результатах поиска.',
|
seoDescriptionHelp: 'Краткое описание под заголовком в результатах поиска.',
|
||||||
|
|||||||
@@ -572,6 +572,8 @@ export interface Translations {
|
|||||||
save: string;
|
save: string;
|
||||||
publish: string;
|
publish: string;
|
||||||
confirmLeaveUnsaved: string;
|
confirmLeaveUnsaved: string;
|
||||||
|
confirmPublish: string;
|
||||||
|
confirmRemoveLanguage: string;
|
||||||
promptLinkUrl: string;
|
promptLinkUrl: string;
|
||||||
promptImageUrl: string;
|
promptImageUrl: string;
|
||||||
promptEmbedUrl: string;
|
promptEmbedUrl: string;
|
||||||
@@ -1039,6 +1041,8 @@ export interface Translations {
|
|||||||
groupSharing: string;
|
groupSharing: string;
|
||||||
groupAdvanced: string;
|
groupAdvanced: string;
|
||||||
groupAdvancedHtml: string;
|
groupAdvancedHtml: string;
|
||||||
|
pageContentLabel: string;
|
||||||
|
pageContentDesc: string;
|
||||||
seoExplainDesc: string;
|
seoExplainDesc: string;
|
||||||
seoTitleHelp: string;
|
seoTitleHelp: string;
|
||||||
seoDescriptionHelp: string;
|
seoDescriptionHelp: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user