Files
marketplaces/src/app/features/project-editor/sections/homepage-section.component.ts

167 lines
7.3 KiB
TypeScript
Raw Normal View History

2026-07-10 13:43:53 +04:00
import { CdkDragDrop, DragDropModule, moveItemInArray } from '@angular/cdk/drag-drop';
import { ChangeDetectionStrategy, Component, computed, inject } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ProjectEditorFacade } from '../facade/project-editor.facade';
import { TranslatePipe } from '../../../i18n/translate.pipe';
import { TranslateService } from '../../../i18n/translate.service';
import { InputComponent } from '../../../shared/ui/input/input.component';
feat(builder): visual homepage blocks, merchant-language widget settings, real carousel arrows Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> P0 user feedback: homepage builder showed raw section.id like 'section-hero'/'section-categories'; hero widget exposed 'full-bleed'/'boxed' and raw px/vh as free text with no explanation; Overlay/Autoplay toggles made no sense without a slides concept; product carousel widgets rendered arrows nowhere near a working carousel. Homepage section (sections list -> visual blocks): - Replaced raw section.id display with a merchant-facing block catalog (icon + name + one-line explanation) for hero/categories/featured-products/product-carousel/recently-viewed/banner/partners/custom-html - Added block catalog picker to append new blocks (was fixed at whatever the seed data had - task asked 'what if we add manually? not fixed 3') - Added duplicate and remove per block, alongside the existing drag-to-reorder - Verified in browser: labels render correctly, add-block and duplicate both confirmed working end-to-end Widgets section (hero widget): - 'Layout' free-text replaced with a select (Full width / Boxed) instead of typing 'full-bleed'/'boxed' blind - 'Height' free-text replaced with a select (Compact/Medium/Tall/Full screen) mapped to real vh values - New Slides editor: title/subtitle pairs an admin can add/remove: this is the actual multi-slide data the Overlay/Autoplay toggles were referring to with nothing to point at before - HeroWidgetData contract gains slides[]/autoplay; HeroWidgetComponent now renders a real rotator (dots, click-to-jump, autoplay interval) when more than one slide exists - previously autoplay/overlay props existed but there was no slideshow behavior anywhere to control Carousel arrows root cause and fix: - widget-manifest.json offers 'carousel' as a layout option for product-collection/product-carousel widgets, and the admin UI let you select it, but ProductCarouselWidgetComponent always rendered a static CSS grid regardless - there was no carousel implementation to have arrows in the first place - Now renders a real horizontally-scrollable strip with working prev/next buttons (native scrollBy, disabled at each end) when section.layout.strategy === 'carousel'; falls back to the existing grid otherwise - Confirmed src/app/components/items-carousel (a PrimeNG p-carousel) is dead code, not wired into any route or widget - not the source of the reported bug New builder.* i18n keys (en/ru/hy), zero duplicate-key collisions verified via scan
2026-07-19 14:14:29 +04:00
import { ButtonComponent } from '../../../shared/ui/button/button.component';
import { SectionCardComponent } from '../../../shared/ui/section-card/section-card.component';
import { ToggleComponent } from '../../../shared/ui/toggle/toggle.component';
import { HomepageOverviewComponent } from './homepage/homepage-overview.component';
feat(builder): visual homepage blocks, merchant-language widget settings, real carousel arrows Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> P0 user feedback: homepage builder showed raw section.id like 'section-hero'/'section-categories'; hero widget exposed 'full-bleed'/'boxed' and raw px/vh as free text with no explanation; Overlay/Autoplay toggles made no sense without a slides concept; product carousel widgets rendered arrows nowhere near a working carousel. Homepage section (sections list -> visual blocks): - Replaced raw section.id display with a merchant-facing block catalog (icon + name + one-line explanation) for hero/categories/featured-products/product-carousel/recently-viewed/banner/partners/custom-html - Added block catalog picker to append new blocks (was fixed at whatever the seed data had - task asked 'what if we add manually? not fixed 3') - Added duplicate and remove per block, alongside the existing drag-to-reorder - Verified in browser: labels render correctly, add-block and duplicate both confirmed working end-to-end Widgets section (hero widget): - 'Layout' free-text replaced with a select (Full width / Boxed) instead of typing 'full-bleed'/'boxed' blind - 'Height' free-text replaced with a select (Compact/Medium/Tall/Full screen) mapped to real vh values - New Slides editor: title/subtitle pairs an admin can add/remove: this is the actual multi-slide data the Overlay/Autoplay toggles were referring to with nothing to point at before - HeroWidgetData contract gains slides[]/autoplay; HeroWidgetComponent now renders a real rotator (dots, click-to-jump, autoplay interval) when more than one slide exists - previously autoplay/overlay props existed but there was no slideshow behavior anywhere to control Carousel arrows root cause and fix: - widget-manifest.json offers 'carousel' as a layout option for product-collection/product-carousel widgets, and the admin UI let you select it, but ProductCarouselWidgetComponent always rendered a static CSS grid regardless - there was no carousel implementation to have arrows in the first place - Now renders a real horizontally-scrollable strip with working prev/next buttons (native scrollBy, disabled at each end) when section.layout.strategy === 'carousel'; falls back to the existing grid otherwise - Confirmed src/app/components/items-carousel (a PrimeNG p-carousel) is dead code, not wired into any route or widget - not the source of the reported bug New builder.* i18n keys (en/ru/hy), zero duplicate-key collisions verified via scan
2026-07-19 14:14:29 +04:00
import { SectionConfig } from '../../../shared/models/config';
2026-07-10 13:43:53 +04:00
export interface LayoutStrategyOption {
value: 'stack' | 'grid' | 'hero' | 'carousel' | 'split';
labelKey: string;
descKey: string;
}
feat(builder): visual homepage blocks, merchant-language widget settings, real carousel arrows Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> P0 user feedback: homepage builder showed raw section.id like 'section-hero'/'section-categories'; hero widget exposed 'full-bleed'/'boxed' and raw px/vh as free text with no explanation; Overlay/Autoplay toggles made no sense without a slides concept; product carousel widgets rendered arrows nowhere near a working carousel. Homepage section (sections list -> visual blocks): - Replaced raw section.id display with a merchant-facing block catalog (icon + name + one-line explanation) for hero/categories/featured-products/product-carousel/recently-viewed/banner/partners/custom-html - Added block catalog picker to append new blocks (was fixed at whatever the seed data had - task asked 'what if we add manually? not fixed 3') - Added duplicate and remove per block, alongside the existing drag-to-reorder - Verified in browser: labels render correctly, add-block and duplicate both confirmed working end-to-end Widgets section (hero widget): - 'Layout' free-text replaced with a select (Full width / Boxed) instead of typing 'full-bleed'/'boxed' blind - 'Height' free-text replaced with a select (Compact/Medium/Tall/Full screen) mapped to real vh values - New Slides editor: title/subtitle pairs an admin can add/remove: this is the actual multi-slide data the Overlay/Autoplay toggles were referring to with nothing to point at before - HeroWidgetData contract gains slides[]/autoplay; HeroWidgetComponent now renders a real rotator (dots, click-to-jump, autoplay interval) when more than one slide exists - previously autoplay/overlay props existed but there was no slideshow behavior anywhere to control Carousel arrows root cause and fix: - widget-manifest.json offers 'carousel' as a layout option for product-collection/product-carousel widgets, and the admin UI let you select it, but ProductCarouselWidgetComponent always rendered a static CSS grid regardless - there was no carousel implementation to have arrows in the first place - Now renders a real horizontally-scrollable strip with working prev/next buttons (native scrollBy, disabled at each end) when section.layout.strategy === 'carousel'; falls back to the existing grid otherwise - Confirmed src/app/components/items-carousel (a PrimeNG p-carousel) is dead code, not wired into any route or widget - not the source of the reported bug New builder.* i18n keys (en/ru/hy), zero duplicate-key collisions verified via scan
2026-07-19 14:14:29 +04:00
/** Merchant-facing catalog of the block types an admin can add to the homepage. Not the widget manifest (that carries technical settingsSchema) - this is presentation-only, matching the pattern already used in widgets-section.component.ts. */
interface BlockCatalogEntry {
type: string;
icon: string;
labelKey: string;
descKey: string;
defaultLayout: LayoutStrategyOption['value'];
}
const BLOCK_CATALOG: BlockCatalogEntry[] = [
{ type: 'hero', icon: 'pi-image', labelKey: 'builder.blockHero', descKey: 'builder.blockHeroDesc', defaultLayout: 'hero' },
{ type: 'categories', icon: 'pi-th-large', labelKey: 'builder.blockCategories', descKey: 'builder.blockCategoriesDesc', defaultLayout: 'grid' },
{ type: 'product-collection', icon: 'pi-box', labelKey: 'builder.blockFeaturedProducts', descKey: 'builder.blockFeaturedProductsDesc', defaultLayout: 'grid' },
{ type: 'product-carousel', icon: 'pi-images', labelKey: 'builder.blockProductCarousel', descKey: 'builder.blockProductCarouselDesc', defaultLayout: 'carousel' },
{ type: 'recently-viewed', icon: 'pi-history', labelKey: 'builder.blockRecentlyViewed', descKey: 'builder.blockRecentlyViewedDesc', defaultLayout: 'grid' },
{ type: 'banner', icon: 'pi-megaphone', labelKey: 'builder.blockBanner', descKey: 'builder.blockBannerDesc', defaultLayout: 'split' },
{ type: 'partners', icon: 'pi-verified', labelKey: 'builder.blockPartners', descKey: 'builder.blockPartnersDesc', defaultLayout: 'stack' },
{ type: 'html', icon: 'pi-code', labelKey: 'builder.blockCustomHtml', descKey: 'builder.blockCustomHtmlDesc', defaultLayout: 'stack' },
];
const BLOCK_BY_TYPE = new Map(BLOCK_CATALOG.map(entry => [entry.type, entry]));
2026-07-10 13:43:53 +04:00
@Component({
selector: 'app-project-editor-homepage-section',
standalone: true,
feat(builder): visual homepage blocks, merchant-language widget settings, real carousel arrows Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> P0 user feedback: homepage builder showed raw section.id like 'section-hero'/'section-categories'; hero widget exposed 'full-bleed'/'boxed' and raw px/vh as free text with no explanation; Overlay/Autoplay toggles made no sense without a slides concept; product carousel widgets rendered arrows nowhere near a working carousel. Homepage section (sections list -> visual blocks): - Replaced raw section.id display with a merchant-facing block catalog (icon + name + one-line explanation) for hero/categories/featured-products/product-carousel/recently-viewed/banner/partners/custom-html - Added block catalog picker to append new blocks (was fixed at whatever the seed data had - task asked 'what if we add manually? not fixed 3') - Added duplicate and remove per block, alongside the existing drag-to-reorder - Verified in browser: labels render correctly, add-block and duplicate both confirmed working end-to-end Widgets section (hero widget): - 'Layout' free-text replaced with a select (Full width / Boxed) instead of typing 'full-bleed'/'boxed' blind - 'Height' free-text replaced with a select (Compact/Medium/Tall/Full screen) mapped to real vh values - New Slides editor: title/subtitle pairs an admin can add/remove: this is the actual multi-slide data the Overlay/Autoplay toggles were referring to with nothing to point at before - HeroWidgetData contract gains slides[]/autoplay; HeroWidgetComponent now renders a real rotator (dots, click-to-jump, autoplay interval) when more than one slide exists - previously autoplay/overlay props existed but there was no slideshow behavior anywhere to control Carousel arrows root cause and fix: - widget-manifest.json offers 'carousel' as a layout option for product-collection/product-carousel widgets, and the admin UI let you select it, but ProductCarouselWidgetComponent always rendered a static CSS grid regardless - there was no carousel implementation to have arrows in the first place - Now renders a real horizontally-scrollable strip with working prev/next buttons (native scrollBy, disabled at each end) when section.layout.strategy === 'carousel'; falls back to the existing grid otherwise - Confirmed src/app/components/items-carousel (a PrimeNG p-carousel) is dead code, not wired into any route or widget - not the source of the reported bug New builder.* i18n keys (en/ru/hy), zero duplicate-key collisions verified via scan
2026-07-19 14:14:29 +04:00
imports: [DragDropModule, FormsModule, TranslatePipe, InputComponent, ButtonComponent, SectionCardComponent, ToggleComponent, HomepageOverviewComponent],
2026-07-10 13:43:53 +04:00
templateUrl: './homepage-section.component.html',
feat(builder): visual homepage blocks, merchant-language widget settings, real carousel arrows Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> P0 user feedback: homepage builder showed raw section.id like 'section-hero'/'section-categories'; hero widget exposed 'full-bleed'/'boxed' and raw px/vh as free text with no explanation; Overlay/Autoplay toggles made no sense without a slides concept; product carousel widgets rendered arrows nowhere near a working carousel. Homepage section (sections list -> visual blocks): - Replaced raw section.id display with a merchant-facing block catalog (icon + name + one-line explanation) for hero/categories/featured-products/product-carousel/recently-viewed/banner/partners/custom-html - Added block catalog picker to append new blocks (was fixed at whatever the seed data had - task asked 'what if we add manually? not fixed 3') - Added duplicate and remove per block, alongside the existing drag-to-reorder - Verified in browser: labels render correctly, add-block and duplicate both confirmed working end-to-end Widgets section (hero widget): - 'Layout' free-text replaced with a select (Full width / Boxed) instead of typing 'full-bleed'/'boxed' blind - 'Height' free-text replaced with a select (Compact/Medium/Tall/Full screen) mapped to real vh values - New Slides editor: title/subtitle pairs an admin can add/remove: this is the actual multi-slide data the Overlay/Autoplay toggles were referring to with nothing to point at before - HeroWidgetData contract gains slides[]/autoplay; HeroWidgetComponent now renders a real rotator (dots, click-to-jump, autoplay interval) when more than one slide exists - previously autoplay/overlay props existed but there was no slideshow behavior anywhere to control Carousel arrows root cause and fix: - widget-manifest.json offers 'carousel' as a layout option for product-collection/product-carousel widgets, and the admin UI let you select it, but ProductCarouselWidgetComponent always rendered a static CSS grid regardless - there was no carousel implementation to have arrows in the first place - Now renders a real horizontally-scrollable strip with working prev/next buttons (native scrollBy, disabled at each end) when section.layout.strategy === 'carousel'; falls back to the existing grid otherwise - Confirmed src/app/components/items-carousel (a PrimeNG p-carousel) is dead code, not wired into any route or widget - not the source of the reported bug New builder.* i18n keys (en/ru/hy), zero duplicate-key collisions verified via scan
2026-07-19 14:14:29 +04:00
styleUrls: ['./section.shared.scss', './homepage-section.component.scss'],
2026-07-10 13:43:53 +04:00
changeDetection: ChangeDetectionStrategy.OnPush
})
export class ProjectEditorHomepageSectionComponent {
private readonly facade = inject(ProjectEditorFacade);
private readonly translate = inject(TranslateService);
2026-07-10 13:43:53 +04:00
readonly homePage = this.facade.homepagePage;
readonly fieldError = (key: string): string | null => {
const messageKey = this.facade.fieldError(key);
return messageKey ? this.translate.t(messageKey) : null;
};
2026-07-10 13:43:53 +04:00
readonly sections = computed(() => [...(this.homePage()?.sections ?? [])].sort((a, b) => a.order - b.order));
feat(builder): visual homepage blocks, merchant-language widget settings, real carousel arrows Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> P0 user feedback: homepage builder showed raw section.id like 'section-hero'/'section-categories'; hero widget exposed 'full-bleed'/'boxed' and raw px/vh as free text with no explanation; Overlay/Autoplay toggles made no sense without a slides concept; product carousel widgets rendered arrows nowhere near a working carousel. Homepage section (sections list -> visual blocks): - Replaced raw section.id display with a merchant-facing block catalog (icon + name + one-line explanation) for hero/categories/featured-products/product-carousel/recently-viewed/banner/partners/custom-html - Added block catalog picker to append new blocks (was fixed at whatever the seed data had - task asked 'what if we add manually? not fixed 3') - Added duplicate and remove per block, alongside the existing drag-to-reorder - Verified in browser: labels render correctly, add-block and duplicate both confirmed working end-to-end Widgets section (hero widget): - 'Layout' free-text replaced with a select (Full width / Boxed) instead of typing 'full-bleed'/'boxed' blind - 'Height' free-text replaced with a select (Compact/Medium/Tall/Full screen) mapped to real vh values - New Slides editor: title/subtitle pairs an admin can add/remove: this is the actual multi-slide data the Overlay/Autoplay toggles were referring to with nothing to point at before - HeroWidgetData contract gains slides[]/autoplay; HeroWidgetComponent now renders a real rotator (dots, click-to-jump, autoplay interval) when more than one slide exists - previously autoplay/overlay props existed but there was no slideshow behavior anywhere to control Carousel arrows root cause and fix: - widget-manifest.json offers 'carousel' as a layout option for product-collection/product-carousel widgets, and the admin UI let you select it, but ProductCarouselWidgetComponent always rendered a static CSS grid regardless - there was no carousel implementation to have arrows in the first place - Now renders a real horizontally-scrollable strip with working prev/next buttons (native scrollBy, disabled at each end) when section.layout.strategy === 'carousel'; falls back to the existing grid otherwise - Confirmed src/app/components/items-carousel (a PrimeNG p-carousel) is dead code, not wired into any route or widget - not the source of the reported bug New builder.* i18n keys (en/ru/hy), zero duplicate-key collisions verified via scan
2026-07-19 14:14:29 +04:00
readonly blockCatalog = BLOCK_CATALOG;
readonly layoutStrategyOptions: LayoutStrategyOption[] = [
{ value: 'stack', labelKey: 'builder.layoutStrategyStack', descKey: 'builder.layoutStrategyStackDesc' },
{ value: 'grid', labelKey: 'builder.layoutStrategyGrid', descKey: 'builder.layoutStrategyGridDesc' },
{ value: 'hero', labelKey: 'builder.layoutStrategyHero', descKey: 'builder.layoutStrategyHeroDesc' },
{ value: 'carousel', labelKey: 'builder.layoutStrategyCarousel', descKey: 'builder.layoutStrategyCarouselDesc' },
{ value: 'split', labelKey: 'builder.layoutStrategySplit', descKey: 'builder.layoutStrategySplitDesc' },
];
layoutStrategyDescKey(strategy: string | undefined): string {
return this.layoutStrategyOptions.find(option => option.value === strategy)?.descKey ?? '';
}
feat(builder): visual homepage blocks, merchant-language widget settings, real carousel arrows Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> P0 user feedback: homepage builder showed raw section.id like 'section-hero'/'section-categories'; hero widget exposed 'full-bleed'/'boxed' and raw px/vh as free text with no explanation; Overlay/Autoplay toggles made no sense without a slides concept; product carousel widgets rendered arrows nowhere near a working carousel. Homepage section (sections list -> visual blocks): - Replaced raw section.id display with a merchant-facing block catalog (icon + name + one-line explanation) for hero/categories/featured-products/product-carousel/recently-viewed/banner/partners/custom-html - Added block catalog picker to append new blocks (was fixed at whatever the seed data had - task asked 'what if we add manually? not fixed 3') - Added duplicate and remove per block, alongside the existing drag-to-reorder - Verified in browser: labels render correctly, add-block and duplicate both confirmed working end-to-end Widgets section (hero widget): - 'Layout' free-text replaced with a select (Full width / Boxed) instead of typing 'full-bleed'/'boxed' blind - 'Height' free-text replaced with a select (Compact/Medium/Tall/Full screen) mapped to real vh values - New Slides editor: title/subtitle pairs an admin can add/remove: this is the actual multi-slide data the Overlay/Autoplay toggles were referring to with nothing to point at before - HeroWidgetData contract gains slides[]/autoplay; HeroWidgetComponent now renders a real rotator (dots, click-to-jump, autoplay interval) when more than one slide exists - previously autoplay/overlay props existed but there was no slideshow behavior anywhere to control Carousel arrows root cause and fix: - widget-manifest.json offers 'carousel' as a layout option for product-collection/product-carousel widgets, and the admin UI let you select it, but ProductCarouselWidgetComponent always rendered a static CSS grid regardless - there was no carousel implementation to have arrows in the first place - Now renders a real horizontally-scrollable strip with working prev/next buttons (native scrollBy, disabled at each end) when section.layout.strategy === 'carousel'; falls back to the existing grid otherwise - Confirmed src/app/components/items-carousel (a PrimeNG p-carousel) is dead code, not wired into any route or widget - not the source of the reported bug New builder.* i18n keys (en/ru/hy), zero duplicate-key collisions verified via scan
2026-07-19 14:14:29 +04:00
blockLabel(type: string): string {
const entry = BLOCK_BY_TYPE.get(type);
return entry ? this.translate.t(entry.labelKey) : type;
}
blockDescription(type: string): string {
const entry = BLOCK_BY_TYPE.get(type);
return entry ? this.translate.t(entry.descKey) : '';
}
blockIcon(type: string): string {
return BLOCK_BY_TYPE.get(type)?.icon ?? 'pi-stop';
}
drop(event: CdkDragDrop<unknown[]>): void {
2026-07-10 13:43:53 +04:00
const sections = [...this.sections()];
moveItemInArray(sections, event.previousIndex, event.currentIndex);
feat(builder): visual homepage blocks, merchant-language widget settings, real carousel arrows Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> P0 user feedback: homepage builder showed raw section.id like 'section-hero'/'section-categories'; hero widget exposed 'full-bleed'/'boxed' and raw px/vh as free text with no explanation; Overlay/Autoplay toggles made no sense without a slides concept; product carousel widgets rendered arrows nowhere near a working carousel. Homepage section (sections list -> visual blocks): - Replaced raw section.id display with a merchant-facing block catalog (icon + name + one-line explanation) for hero/categories/featured-products/product-carousel/recently-viewed/banner/partners/custom-html - Added block catalog picker to append new blocks (was fixed at whatever the seed data had - task asked 'what if we add manually? not fixed 3') - Added duplicate and remove per block, alongside the existing drag-to-reorder - Verified in browser: labels render correctly, add-block and duplicate both confirmed working end-to-end Widgets section (hero widget): - 'Layout' free-text replaced with a select (Full width / Boxed) instead of typing 'full-bleed'/'boxed' blind - 'Height' free-text replaced with a select (Compact/Medium/Tall/Full screen) mapped to real vh values - New Slides editor: title/subtitle pairs an admin can add/remove: this is the actual multi-slide data the Overlay/Autoplay toggles were referring to with nothing to point at before - HeroWidgetData contract gains slides[]/autoplay; HeroWidgetComponent now renders a real rotator (dots, click-to-jump, autoplay interval) when more than one slide exists - previously autoplay/overlay props existed but there was no slideshow behavior anywhere to control Carousel arrows root cause and fix: - widget-manifest.json offers 'carousel' as a layout option for product-collection/product-carousel widgets, and the admin UI let you select it, but ProductCarouselWidgetComponent always rendered a static CSS grid regardless - there was no carousel implementation to have arrows in the first place - Now renders a real horizontally-scrollable strip with working prev/next buttons (native scrollBy, disabled at each end) when section.layout.strategy === 'carousel'; falls back to the existing grid otherwise - Confirmed src/app/components/items-carousel (a PrimeNG p-carousel) is dead code, not wired into any route or widget - not the source of the reported bug New builder.* i18n keys (en/ru/hy), zero duplicate-key collisions verified via scan
2026-07-19 14:14:29 +04:00
this.replaceSections(sections.map((section, index) => ({ ...section, order: index + 1 })));
2026-07-10 13:43:53 +04:00
}
updateSection(sectionId: string, field: 'visible' | 'type', value: unknown): void {
feat(builder): visual homepage blocks, merchant-language widget settings, real carousel arrows Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> P0 user feedback: homepage builder showed raw section.id like 'section-hero'/'section-categories'; hero widget exposed 'full-bleed'/'boxed' and raw px/vh as free text with no explanation; Overlay/Autoplay toggles made no sense without a slides concept; product carousel widgets rendered arrows nowhere near a working carousel. Homepage section (sections list -> visual blocks): - Replaced raw section.id display with a merchant-facing block catalog (icon + name + one-line explanation) for hero/categories/featured-products/product-carousel/recently-viewed/banner/partners/custom-html - Added block catalog picker to append new blocks (was fixed at whatever the seed data had - task asked 'what if we add manually? not fixed 3') - Added duplicate and remove per block, alongside the existing drag-to-reorder - Verified in browser: labels render correctly, add-block and duplicate both confirmed working end-to-end Widgets section (hero widget): - 'Layout' free-text replaced with a select (Full width / Boxed) instead of typing 'full-bleed'/'boxed' blind - 'Height' free-text replaced with a select (Compact/Medium/Tall/Full screen) mapped to real vh values - New Slides editor: title/subtitle pairs an admin can add/remove: this is the actual multi-slide data the Overlay/Autoplay toggles were referring to with nothing to point at before - HeroWidgetData contract gains slides[]/autoplay; HeroWidgetComponent now renders a real rotator (dots, click-to-jump, autoplay interval) when more than one slide exists - previously autoplay/overlay props existed but there was no slideshow behavior anywhere to control Carousel arrows root cause and fix: - widget-manifest.json offers 'carousel' as a layout option for product-collection/product-carousel widgets, and the admin UI let you select it, but ProductCarouselWidgetComponent always rendered a static CSS grid regardless - there was no carousel implementation to have arrows in the first place - Now renders a real horizontally-scrollable strip with working prev/next buttons (native scrollBy, disabled at each end) when section.layout.strategy === 'carousel'; falls back to the existing grid otherwise - Confirmed src/app/components/items-carousel (a PrimeNG p-carousel) is dead code, not wired into any route or widget - not the source of the reported bug New builder.* i18n keys (en/ru/hy), zero duplicate-key collisions verified via scan
2026-07-19 14:14:29 +04:00
this.replaceSections(this.sections().map(section => section.id !== sectionId ? section : ({
...section,
...(field === 'type' ? { type: String(value) } : { visible: Boolean(value) })
})));
2026-07-10 13:43:53 +04:00
}
updateLayout(sectionId: string, key: 'strategy' | 'columns', value: string): void {
feat(builder): visual homepage blocks, merchant-language widget settings, real carousel arrows Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> P0 user feedback: homepage builder showed raw section.id like 'section-hero'/'section-categories'; hero widget exposed 'full-bleed'/'boxed' and raw px/vh as free text with no explanation; Overlay/Autoplay toggles made no sense without a slides concept; product carousel widgets rendered arrows nowhere near a working carousel. Homepage section (sections list -> visual blocks): - Replaced raw section.id display with a merchant-facing block catalog (icon + name + one-line explanation) for hero/categories/featured-products/product-carousel/recently-viewed/banner/partners/custom-html - Added block catalog picker to append new blocks (was fixed at whatever the seed data had - task asked 'what if we add manually? not fixed 3') - Added duplicate and remove per block, alongside the existing drag-to-reorder - Verified in browser: labels render correctly, add-block and duplicate both confirmed working end-to-end Widgets section (hero widget): - 'Layout' free-text replaced with a select (Full width / Boxed) instead of typing 'full-bleed'/'boxed' blind - 'Height' free-text replaced with a select (Compact/Medium/Tall/Full screen) mapped to real vh values - New Slides editor: title/subtitle pairs an admin can add/remove: this is the actual multi-slide data the Overlay/Autoplay toggles were referring to with nothing to point at before - HeroWidgetData contract gains slides[]/autoplay; HeroWidgetComponent now renders a real rotator (dots, click-to-jump, autoplay interval) when more than one slide exists - previously autoplay/overlay props existed but there was no slideshow behavior anywhere to control Carousel arrows root cause and fix: - widget-manifest.json offers 'carousel' as a layout option for product-collection/product-carousel widgets, and the admin UI let you select it, but ProductCarouselWidgetComponent always rendered a static CSS grid regardless - there was no carousel implementation to have arrows in the first place - Now renders a real horizontally-scrollable strip with working prev/next buttons (native scrollBy, disabled at each end) when section.layout.strategy === 'carousel'; falls back to the existing grid otherwise - Confirmed src/app/components/items-carousel (a PrimeNG p-carousel) is dead code, not wired into any route or widget - not the source of the reported bug New builder.* i18n keys (en/ru/hy), zero duplicate-key collisions verified via scan
2026-07-19 14:14:29 +04:00
this.replaceSections(this.sections().map(section => section.id !== sectionId ? section : ({
...section,
layout: {
...section.layout,
[key]: key === 'columns' ? Number(value) || 1 : value,
}
})));
}
addBlock(type: string): void {
const entry = BLOCK_BY_TYPE.get(type);
if (!entry) {
return;
}
const id = `section-${type}-${Date.now()}`;
const widgetId = `widget-${type}-${Date.now()}`;
const newSection: SectionConfig = {
id,
type,
order: this.sections().length + 1,
layout: { strategy: entry.defaultLayout, columns: 1, gap: '1.5rem', align: 'stretch' },
visibility: { desktop: true, tablet: true, mobile: true },
visible: true,
widgets: [{
id: widgetId,
type,
version: '1.0.0',
order: 1,
visibility: { desktop: true, tablet: true, mobile: true },
visible: true,
props: {},
}],
};
this.replaceSections([...this.sections(), newSection]);
}
duplicateBlock(sectionId: string): void {
const source = this.sections().find(section => section.id === sectionId);
if (!source) {
return;
}
const suffix = Date.now();
const copy: SectionConfig = {
...source,
id: `${source.id}-copy-${suffix}`,
order: this.sections().length + 1,
widgets: source.widgets.map(widget => ({ ...widget, id: `${widget.id}-copy-${suffix}` })),
};
this.replaceSections([...this.sections(), copy]);
}
removeBlock(sectionId: string): void {
if (!confirm(this.translate.t('builder.blockRemoveConfirm'))) {
return;
}
this.replaceSections(this.sections().filter(section => section.id !== sectionId));
}
private replaceSections(sections: SectionConfig[]): void {
2026-07-10 13:43:53 +04:00
this.facade.updateBootstrap(current => ({
...current,
feat(builder): visual homepage blocks, merchant-language widget settings, real carousel arrows Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> P0 user feedback: homepage builder showed raw section.id like 'section-hero'/'section-categories'; hero widget exposed 'full-bleed'/'boxed' and raw px/vh as free text with no explanation; Overlay/Autoplay toggles made no sense without a slides concept; product carousel widgets rendered arrows nowhere near a working carousel. Homepage section (sections list -> visual blocks): - Replaced raw section.id display with a merchant-facing block catalog (icon + name + one-line explanation) for hero/categories/featured-products/product-carousel/recently-viewed/banner/partners/custom-html - Added block catalog picker to append new blocks (was fixed at whatever the seed data had - task asked 'what if we add manually? not fixed 3') - Added duplicate and remove per block, alongside the existing drag-to-reorder - Verified in browser: labels render correctly, add-block and duplicate both confirmed working end-to-end Widgets section (hero widget): - 'Layout' free-text replaced with a select (Full width / Boxed) instead of typing 'full-bleed'/'boxed' blind - 'Height' free-text replaced with a select (Compact/Medium/Tall/Full screen) mapped to real vh values - New Slides editor: title/subtitle pairs an admin can add/remove: this is the actual multi-slide data the Overlay/Autoplay toggles were referring to with nothing to point at before - HeroWidgetData contract gains slides[]/autoplay; HeroWidgetComponent now renders a real rotator (dots, click-to-jump, autoplay interval) when more than one slide exists - previously autoplay/overlay props existed but there was no slideshow behavior anywhere to control Carousel arrows root cause and fix: - widget-manifest.json offers 'carousel' as a layout option for product-collection/product-carousel widgets, and the admin UI let you select it, but ProductCarouselWidgetComponent always rendered a static CSS grid regardless - there was no carousel implementation to have arrows in the first place - Now renders a real horizontally-scrollable strip with working prev/next buttons (native scrollBy, disabled at each end) when section.layout.strategy === 'carousel'; falls back to the existing grid otherwise - Confirmed src/app/components/items-carousel (a PrimeNG p-carousel) is dead code, not wired into any route or widget - not the source of the reported bug New builder.* i18n keys (en/ru/hy), zero duplicate-key collisions verified via scan
2026-07-19 14:14:29 +04:00
pages: current.pages.map(page => page.id !== this.homePage()?.id ? page : ({ ...page, sections }))
2026-07-10 13:43:53 +04:00
}));
}
}