2026-07-10 13:43:53 +04:00
import { CdkDragDrop , DragDropModule , moveItemInArray } from '@angular/cdk/drag-drop' ;
2026-07-26 00:08:00 +04:00
import { ChangeDetectionStrategy , Component , computed , inject , signal } from '@angular/core' ;
2026-07-10 13:43:53 +04:00
import { FormsModule } from '@angular/forms' ;
import { ProjectEditorFacade } from '../facade/project-editor.facade' ;
import { TranslatePipe } from '../../../i18n/translate.pipe' ;
2026-07-17 16:18:22 +04:00
import { TranslateService } from '../../../i18n/translate.service' ;
feat(project-editor): adopt Design System primitives across editor sections
Applied app-input/app-form-field/app-button to 9 of 11 Project Editor
sections: general, branding, theme, footer, homepage, widgets, languages,
navigation, preview. header and features sections were left unchanged -
they contain only checkboxes and selects, and no Checkbox/Select primitive
exists yet.
Theme section's 8 color pickers stay native <input type=color> (app-input's
type union doesn't include 'color') but are now wrapped in app-form-field
for consistent label/hint treatment. Added app-form-field.full grid-column
rule to section.shared.scss (shared by all 11 sections) alongside the
existing label.full rule, since the custom element doesn't match that
selector.
Production build green, arch:check passes.
2026-07-15 07:55:38 +04:00
import { InputComponent } from '../../../shared/ui/input/input.component' ;
2026-07-16 02:07:41 +04:00
import { SectionCardComponent } from '../../../shared/ui/section-card/section-card.component' ;
import { ToggleComponent } from '../../../shared/ui/toggle/toggle.component' ;
fix(builder): composition audit fixes for project editor sections
- Reset-section button: raw <button> with hardcoded colors -> app-button variant="danger"
- section.shared.scss: raw button/input/select colors switched to CSS theme vars (--primary-color, --bg-primary, --bg-secondary, --error-color) instead of bare hex
- save-bar scss referenced nonexistent CSS vars (--surface, --border, --warning, --danger, --muted-foreground, --info-bg, --info) that always fell back to hardcoded hex; renamed to the real theme vars (--bg-primary, --border-color, --warning-color, --error-color, --text-secondary, --info-color) so the save bar is actually theme-aware
- footer/homepage/widgets section scss: nonexistent --danger-color var renamed to --error-color
- static-pages-editor: replaced dead `.editor-section-card` wrapper class (removed from shared stylesheet in the Sprint 30 redesign, never migrated here) with app-section-card, restoring the card chrome every sibling editor section has
- widgets-section: empty state (no widgets) rendered nothing; added app-empty-state
- homepage-section: empty state (no homepage page) rendered nothing; added app-empty-state
- navigation-section: header/footer nav move-up/move-down buttons had no accessible name (bare uarr/darr glyphs); added aria-label
- Added builder.widgetsEmptyTitle/Desc and builder.homepageEmptyTitle/Desc i18n keys (en/ru/hy)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-23 10:47:37 +04:00
import { EmptyStateComponent } from '../../../shared/ui/empty-state/empty-state.component' ;
feat(builder): implement visual homepage builder
New HomepageOverviewComponent (Tasks 1+8), mounted at the top of the
existing Homepage section page: completion ring, active/hidden section
counts, recommended next step, last-modified timestamp, and a 6-item
Homepage Health checklist (hero/categories/products/promotion/
newsletter/any-sections) - all derived from the real page.sections/
widgets data already in the facade, nothing fabricated.
Existing page-level drag-and-drop reordering (homepage-section's
CdkDragDrop over page.sections) was already implemented pre-Sprint 5 -
left as-is per "build on top of, do not replace."
Widgets section (Task 2) rewritten from a bare list into visual cards:
per-widget icon + humanized type label (hero/categories/product-
collection), a visible/hidden toggle and badge, up/down move buttons
(keyboard-accessible reorder within a section - see Known limitations
for why this replaces pointer drag for widgets specifically), duplicate,
and remove (with confirm). The existing per-type field editors (hero/
categories/product-collection) are unchanged; the raw-JSON fallback for
unknown widget types now sits behind a collapsed "Advanced settings"
disclosure instead of being the default view.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-18 10:24:13 +04:00
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' ;
fix(icons): migrate Marketplace Builder to Lucide
Replace every PrimeIcons pi-* usage across the builder: overview page
(back link, next-step arrow, section cards, readiness checklist,
quick links), sidebar nav (group/section status dots), main layout
(back/home/menu/help icons), brand + homepage overview panels
(checklist ok/pending dots, contrast warning), footer/homepage/widgets
section editors (drag handles, move up/down, duplicate, remove), and
the HTML editor toolbar (list/link/image/table/divider/code/embed).
Notable correctness fix: PrimeIcons reused pi-bars for both the
hamburger menu toggle AND every drag handle - two different meanings
sharing one icon (exactly the kind of icon collision the audit calls
out). Added a dedicated 'grip' icon (GripVertical) for drag handles so
menu and drag-to-reorder are visually distinct.
Added a global .spin utility (icon-registry has no built-in spinner
animation) for the one loading-spinner icon in the builder overview
checklist.
All icon-bearing fields (BuilderGroup.icon, BlockCatalogEntry.icon,
WIDGET_ICONS, STATUS_ICON, HtmlEditorToolbarCommand.icon, etc.) are
now typed AppIconName instead of string.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-20 02:31:06 +04:00
import { IconComponent } from '../../../shared/ui/icon/icon.component' ;
import { AppIconName } from '../../../shared/ui/icon/icon-registry' ;
2026-07-26 00:08:00 +04:00
import { ConfirmDialogComponent } from '../../../shared/ui/confirm-dialog/confirm-dialog.component' ;
2026-07-27 10:00:42 +04:00
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' ;
2026-07-10 13:43:53 +04:00
feat(project-editor): finish field descriptions + enum dropdowns across all sections
Wires up the remaining editor sections (theme, header, footer, homepage,
widgets, features, languages, navigation) with the description text and
dropdown UX started for General/Branding:
- Every enum-backed field is now a <select> with a description per option,
not free text: theme.mode, the new site-wide layout.type (previously had
no editor at all - added to the Theme section, and added to that
section's reset-scope), homepage section layout.strategy, and
catalog.navigationMode (also previously unedited, added to Features).
- Every other field (colors, header toggles, footer contact/company fields,
widget props, feature flags, language add, nav link label/url/visible)
gets a one-line plain-language description under its label via the new
*Desc i18n keys (en/ru/hy) prepared earlier.
- Genuinely open text (widget layout variant strings, JSON props) stays
free text, description-only, per the existing widgetLayoutDesc/widgetJsonDesc
wording - not force-fit into a dropdown.
Verified: tsc --noEmit and ng build both clean.
2026-07-15 00:45:41 +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 ;
fix(icons): migrate Marketplace Builder to Lucide
Replace every PrimeIcons pi-* usage across the builder: overview page
(back link, next-step arrow, section cards, readiness checklist,
quick links), sidebar nav (group/section status dots), main layout
(back/home/menu/help icons), brand + homepage overview panels
(checklist ok/pending dots, contrast warning), footer/homepage/widgets
section editors (drag handles, move up/down, duplicate, remove), and
the HTML editor toolbar (list/link/image/table/divider/code/embed).
Notable correctness fix: PrimeIcons reused pi-bars for both the
hamburger menu toggle AND every drag handle - two different meanings
sharing one icon (exactly the kind of icon collision the audit calls
out). Added a dedicated 'grip' icon (GripVertical) for drag handles so
menu and drag-to-reorder are visually distinct.
Added a global .spin utility (icon-registry has no built-in spinner
animation) for the one loading-spinner icon in the builder overview
checklist.
All icon-bearing fields (BuilderGroup.icon, BlockCatalogEntry.icon,
WIDGET_ICONS, STATUS_ICON, HtmlEditorToolbarCommand.icon, etc.) are
now typed AppIconName instead of string.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-20 02:31:06 +04:00
icon : AppIconName ;
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
labelKey : string ;
descKey : string ;
defaultLayout : LayoutStrategyOption [ 'value' ] ;
}
const BLOCK_CATALOG : BlockCatalogEntry [ ] = [
fix(icons): migrate Marketplace Builder to Lucide
Replace every PrimeIcons pi-* usage across the builder: overview page
(back link, next-step arrow, section cards, readiness checklist,
quick links), sidebar nav (group/section status dots), main layout
(back/home/menu/help icons), brand + homepage overview panels
(checklist ok/pending dots, contrast warning), footer/homepage/widgets
section editors (drag handles, move up/down, duplicate, remove), and
the HTML editor toolbar (list/link/image/table/divider/code/embed).
Notable correctness fix: PrimeIcons reused pi-bars for both the
hamburger menu toggle AND every drag handle - two different meanings
sharing one icon (exactly the kind of icon collision the audit calls
out). Added a dedicated 'grip' icon (GripVertical) for drag handles so
menu and drag-to-reorder are visually distinct.
Added a global .spin utility (icon-registry has no built-in spinner
animation) for the one loading-spinner icon in the builder overview
checklist.
All icon-bearing fields (BuilderGroup.icon, BlockCatalogEntry.icon,
WIDGET_ICONS, STATUS_ICON, HtmlEditorToolbarCommand.icon, etc.) are
now typed AppIconName instead of string.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-20 02:31:06 +04:00
{ type : 'hero' , icon : 'image' , labelKey : 'builder.blockHero' , descKey : 'builder.blockHeroDesc' , defaultLayout : 'hero' } ,
{ type : 'categories' , icon : 'layoutGrid' , labelKey : 'builder.blockCategories' , descKey : 'builder.blockCategoriesDesc' , defaultLayout : 'grid' } ,
{ type : 'product-collection' , icon : 'package' , labelKey : 'builder.blockFeaturedProducts' , descKey : 'builder.blockFeaturedProductsDesc' , defaultLayout : 'grid' } ,
{ type : 'product-carousel' , icon : 'images' , labelKey : 'builder.blockProductCarousel' , descKey : 'builder.blockProductCarouselDesc' , defaultLayout : 'carousel' } ,
{ type : 'recently-viewed' , icon : 'history' , labelKey : 'builder.blockRecentlyViewed' , descKey : 'builder.blockRecentlyViewedDesc' , defaultLayout : 'grid' } ,
{ type : 'banner' , icon : 'megaphone' , labelKey : 'builder.blockBanner' , descKey : 'builder.blockBannerDesc' , defaultLayout : 'split' } ,
{ type : 'partners' , icon : 'verified' , labelKey : 'builder.blockPartners' , descKey : 'builder.blockPartnersDesc' , defaultLayout : 'stack' } ,
{ type : 'html' , icon : 'code' , labelKey : 'builder.blockCustomHtml' , descKey : 'builder.blockCustomHtmlDesc' , defaultLayout : 'stack' } ,
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
] ;
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 ,
2026-07-27 10:00:42 +04:00
imports : [ DragDropModule , FormsModule , TranslatePipe , InputComponent , SectionCardComponent , ToggleComponent , EmptyStateComponent , HomepageOverviewComponent , IconComponent , ConfirmDialogComponent , FormFieldComponent , VisualLayoutPickerComponent , HighlightSourceDirective ] ,
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 ) ;
2026-07-17 16:18:22 +04:00
private readonly translate = inject ( TranslateService ) ;
2026-07-10 13:43:53 +04:00
readonly homePage = this . facade . homepagePage ;
2026-07-17 16:18:22 +04:00
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 ;
feat(project-editor): finish field descriptions + enum dropdowns across all sections
Wires up the remaining editor sections (theme, header, footer, homepage,
widgets, features, languages, navigation) with the description text and
dropdown UX started for General/Branding:
- Every enum-backed field is now a <select> with a description per option,
not free text: theme.mode, the new site-wide layout.type (previously had
no editor at all - added to the Theme section, and added to that
section's reset-scope), homepage section layout.strategy, and
catalog.navigationMode (also previously unedited, added to Features).
- Every other field (colors, header toggles, footer contact/company fields,
widget props, feature flags, language add, nav link label/url/visible)
gets a one-line plain-language description under its label via the new
*Desc i18n keys (en/ru/hy) prepared earlier.
- Genuinely open text (widget layout variant strings, JSON props) stays
free text, description-only, per the existing widgetLayoutDesc/widgetJsonDesc
wording - not force-fit into a dropdown.
Verified: tsc --noEmit and ng build both clean.
2026-07-15 00:45:41 +04:00
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' } ,
] ;
2026-07-27 10:00:42 +04:00
/** 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 ] ,
} ) ) ;
feat(project-editor): finish field descriptions + enum dropdowns across all sections
Wires up the remaining editor sections (theme, header, footer, homepage,
widgets, features, languages, navigation) with the description text and
dropdown UX started for General/Branding:
- Every enum-backed field is now a <select> with a description per option,
not free text: theme.mode, the new site-wide layout.type (previously had
no editor at all - added to the Theme section, and added to that
section's reset-scope), homepage section layout.strategy, and
catalog.navigationMode (also previously unedited, added to Features).
- Every other field (colors, header toggles, footer contact/company fields,
widget props, feature flags, language add, nav link label/url/visible)
gets a one-line plain-language description under its label via the new
*Desc i18n keys (en/ru/hy) prepared earlier.
- Genuinely open text (widget layout variant strings, JSON props) stays
free text, description-only, per the existing widgetLayoutDesc/widgetJsonDesc
wording - not force-fit into a dropdown.
Verified: tsc --noEmit and ng build both clean.
2026-07-15 00:45:41 +04:00
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 ) : '' ;
}
fix(icons): migrate Marketplace Builder to Lucide
Replace every PrimeIcons pi-* usage across the builder: overview page
(back link, next-step arrow, section cards, readiness checklist,
quick links), sidebar nav (group/section status dots), main layout
(back/home/menu/help icons), brand + homepage overview panels
(checklist ok/pending dots, contrast warning), footer/homepage/widgets
section editors (drag handles, move up/down, duplicate, remove), and
the HTML editor toolbar (list/link/image/table/divider/code/embed).
Notable correctness fix: PrimeIcons reused pi-bars for both the
hamburger menu toggle AND every drag handle - two different meanings
sharing one icon (exactly the kind of icon collision the audit calls
out). Added a dedicated 'grip' icon (GripVertical) for drag handles so
menu and drag-to-reorder are visually distinct.
Added a global .spin utility (icon-registry has no built-in spinner
animation) for the one loading-spinner icon in the builder overview
checklist.
All icon-bearing fields (BuilderGroup.icon, BlockCatalogEntry.icon,
WIDGET_ICONS, STATUS_ICON, HtmlEditorToolbarCommand.icon, etc.) are
now typed AppIconName instead of string.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-20 02:31:06 +04:00
blockIcon ( type : string ) : AppIconName {
return BLOCK_BY_TYPE . get ( type ) ? . icon ? ? 'stop' ;
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
}
2026-07-17 18:14:58 +04:00
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
}
fix(builder): WCAG 2.1 AA accessibility fixes
RC A11Y-01 audit pass, Builder (project-editor) + content-management static
pages editor. Builds on 4ebc15f's composition pass without redoing it.
- Skip link: Builder's /edit and /edit/:section routes render outside the
storefront app-shell (isAdminRoute() branch has no skip link/landmark, only
a bare router-outlet, unlike the storefront's app.html) - added a
"skip to content" link targeting a new #builder-main-content landmark on
project-editor-page.component, reusing the existing adminShell.skipToContent
key and global .skip-link style. Nav landmark already had aria-label
(builder.appName) from the prior pass, verified correct.
- Save bar: added role="status"/aria-live="polite" to the save/publish status
block and role="status" to the draft-restored notice so save/publish state
changes and draft recovery are announced to screen readers (previously
silent DOM updates).
- Media picker (shared, used by both Builder and static-pages editor): upload
error message had no aria-live wiring - added role="alert".
- HTML editor (marketplace-html-editor): the contenteditable rich-text surface
had no accessible role/name - added role="textbox", aria-multiline="true",
aria-label.
- Drag-and-drop keyboard fallback (WCAG 2.1.1): homepage-section's block list
and footer-section's column list + per-column link list use Angular CDK
drag-drop (cdkDrag/cdkDropList), which has no built-in keyboard reordering.
Added move-up/move-down icon buttons (disabled at the first/last boundary),
matching the existing pattern already used by widgets-section and
navigation-section.
- Color picker: the swatch <input type="color"> had no accessible name (only
the paired text input was labelled via app-form-field) - added explicit
ariaLabel bindings to all 8 color-picker instances in theme-section.
- Languages: the new-locale code input relied on a placeholder ("de") as its
only accessible name - added ariaLabel + new builder.newLanguageLabel i18n
key (en/ru/hy).
- Undefined CSS var --color-primary (never defined anywhere, silently used its
hardcoded hex fallback and never responded to tenant theming - same
recurring bug class as 4ebc15f) - remapped to the real --primary-color token
in marketplace-html-editor, homepage-section, and section.shared (7 usages).
- role="alert" added to all 11 validation-error <p class="editor-error">
occurrences across footer/homepage/languages/navigation/preview/widgets
sections and the static-pages editor, so field/section validation messages
are announced.
- scope="col" added to preview-section's change-summary table headers.
Flagged, not fixed (design-system decisions, matching the storefront pass's
precedent):
- Save bar's --warning-color/--error-color/--info-color text fail WCAG AA
4.5:1 in some themes - same genuine brand semantic colors flagged (not
fixed) in fb1afb7's storefront pass; needs a deliberate token decision,
not a Builder-specific issue.
- locale-tabs (app-locale-tabs, shared) has role="tablist"/"tab" and
aria-selected but no roving-tabindex/arrow-key navigation - matches the
same partial-tablist pattern already accepted for product-tabs in the
storefront pass; all tabs remain natively Tab-focusable, so this meets
4.1.2/2.1.1 without the full ARIA authoring-practice pattern.
Verified: npx tsc --noEmit clean; npm run build green (only the pre-existing
bundle-budget warning, unrelated to this pass).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-24 09:01:38 +04:00
/** Keyboard-operable fallback for the drag-and-drop block reorder above (WCAG 2.1.1). */
moveBlock ( sectionId : string , direction : - 1 | 1 ) : void {
const sections = [ . . . this . sections ( ) ] ;
const index = sections . findIndex ( section = > section . id === sectionId ) ;
const targetIndex = index + direction ;
if ( index === - 1 || targetIndex < 0 || targetIndex >= sections . length ) {
return ;
}
moveItemInArray ( sections , index , targetIndex ) ;
this . replaceSections ( sections . map ( ( section , i ) = > ( { . . . section , order : i + 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 ] ) ;
}
2026-07-26 00:08:00 +04:00
readonly pendingRemoveBlockId = signal < string | null > ( null ) ;
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
removeBlock ( sectionId : string ) : void {
2026-07-26 00:08:00 +04:00
this . pendingRemoveBlockId . set ( sectionId ) ;
}
confirmRemoveBlock ( ) : void {
const sectionId = this . pendingRemoveBlockId ( ) ;
this . pendingRemoveBlockId . set ( null ) ;
if ( ! sectionId ) return ;
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 ( ) . 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
} ) ) ;
}
}