feat: Page Editor UX Phase 1 - live preview, hover mapping, visual layout picker
- PreviewHighlightService + appHighlightSource directive: shared hover/focus bridge between editor fields and the schematic live preview. - BuilderLivePreviewComponent: in-page schematic homepage render (header/hero/blocks/footer) reading the same bootstrap the sections mutate, highlighting the area matching the active field. - VisualLayoutPickerComponent: card-based layout picker (ControlValueAccessor, same shape as app-select) replacing the raw layout <select> in homepage-section. - app-form-field gains optional usedBy/usedByLabel inputs for the "Where is this used?" helper text, wired into aria-describedby. - Wired homepage/branding/theme sections with highlight sources + usedBy hints; live preview panel shown in project-editor-page for those three sections. - All new copy added as translation keys (en/ru/hy).
This commit is contained in:
@@ -13,6 +13,9 @@ import { SectionConfig } from '../../../shared/models/config';
|
||||
import { IconComponent } from '../../../shared/ui/icon/icon.component';
|
||||
import { AppIconName } from '../../../shared/ui/icon/icon-registry';
|
||||
import { ConfirmDialogComponent } from '../../../shared/ui/confirm-dialog/confirm-dialog.component';
|
||||
import { FormFieldComponent } from '../../../shared/ui/form-field/form-field.component';
|
||||
import { VisualLayoutPickerComponent, VisualLayoutOption } from '../../../shared/ui/visual-layout-picker/visual-layout-picker.component';
|
||||
import { HighlightSourceDirective } from '../../../shared/ui/highlight-source/highlight-source.directive';
|
||||
|
||||
export interface LayoutStrategyOption {
|
||||
value: 'stack' | 'grid' | 'hero' | 'carousel' | 'split';
|
||||
@@ -45,7 +48,7 @@ const BLOCK_BY_TYPE = new Map(BLOCK_CATALOG.map(entry => [entry.type, entry]));
|
||||
@Component({
|
||||
selector: 'app-project-editor-homepage-section',
|
||||
standalone: true,
|
||||
imports: [DragDropModule, FormsModule, TranslatePipe, InputComponent, SectionCardComponent, ToggleComponent, EmptyStateComponent, HomepageOverviewComponent, IconComponent, ConfirmDialogComponent],
|
||||
imports: [DragDropModule, FormsModule, TranslatePipe, InputComponent, SectionCardComponent, ToggleComponent, EmptyStateComponent, HomepageOverviewComponent, IconComponent, ConfirmDialogComponent, FormFieldComponent, VisualLayoutPickerComponent, HighlightSourceDirective],
|
||||
templateUrl: './homepage-section.component.html',
|
||||
styleUrls: ['./section.shared.scss', './homepage-section.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush
|
||||
@@ -70,9 +73,21 @@ export class ProjectEditorHomepageSectionComponent {
|
||||
{ value: 'split', labelKey: 'builder.layoutStrategySplit', descKey: 'builder.layoutStrategySplitDesc' },
|
||||
];
|
||||
|
||||
layoutStrategyDescKey(strategy: string | undefined): string {
|
||||
return this.layoutStrategyOptions.find(option => option.value === strategy)?.descKey ?? '';
|
||||
}
|
||||
/** Card icons for the visual layout picker - purely decorative shorthand for each strategy's shape. */
|
||||
private readonly layoutStrategyIcons: Record<LayoutStrategyOption['value'], AppIconName> = {
|
||||
stack: 'list',
|
||||
grid: 'layoutGrid',
|
||||
hero: 'image',
|
||||
carousel: 'images',
|
||||
split: 'table',
|
||||
};
|
||||
|
||||
readonly layoutStrategyPickerOptions: VisualLayoutOption[] = this.layoutStrategyOptions.map(option => ({
|
||||
value: option.value,
|
||||
labelKey: option.labelKey,
|
||||
descKey: option.descKey,
|
||||
icon: this.layoutStrategyIcons[option.value],
|
||||
}));
|
||||
|
||||
blockLabel(type: string): string {
|
||||
const entry = BLOCK_BY_TYPE.get(type);
|
||||
|
||||
Reference in New Issue
Block a user