codexly-ui 0.10.58 → 0.10.59

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13034,43 +13034,18 @@ class ClxPageEmptyComponent {
13034
13034
  ctaLabel = input('', ...(ngDevMode ? [{ debugName: "ctaLabel" }] : /* istanbul ignore next */ []));
13035
13035
  ctaIcon = input('add', ...(ngDevMode ? [{ debugName: "ctaIcon" }] : /* istanbul ignore next */ []));
13036
13036
  ctaColor = input(undefined, ...(ngDevMode ? [{ debugName: "ctaColor" }] : /* istanbul ignore next */ []));
13037
- size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
13038
13037
  _ctaColor = computed(() => this.ctaColor() ?? this._themeSvc.config().primaryColor, ...(ngDevMode ? [{ debugName: "_ctaColor" }] : /* istanbul ignore next */ []));
13039
13038
  cta = output();
13040
- _iconWrap() {
13041
- const s = this.size();
13042
- const sz = s === 'sm' ? 'w-12 h-12' : s === 'lg' ? 'w-20 h-20' : 'w-16 h-16';
13043
- return `${sz} rounded-2xl bg-clx-surface-2 flex items-center justify-center mb-4`;
13044
- }
13045
- _iconSize() {
13046
- const s = this.size();
13047
- return s === 'sm' ? 'md' : s === 'lg' ? 'xl' : 'lg';
13048
- }
13049
- _titleCls() {
13050
- const s = this.size();
13051
- return s === 'sm'
13052
- ? 'text-sm font-semibold text-clx-text-label mb-1'
13053
- : s === 'lg'
13054
- ? 'text-xl font-semibold text-clx-text-label mb-2'
13055
- : 'text-base font-semibold text-clx-text-label mb-1';
13056
- }
13057
- _descCls() {
13058
- const s = this.size();
13059
- return `${s === 'lg' ? 'text-sm' : 'text-xs'} text-clx-text-subtle max-w-xs mb-5`;
13060
- }
13061
- _ctaCls() {
13062
- return this.size() === 'sm' ? 'mt-3' : 'mt-5';
13063
- }
13064
13039
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxPageEmptyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
13065
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxPageEmptyComponent, isStandalone: true, selector: "clx-page-empty", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, ctaLabel: { classPropertyName: "ctaLabel", publicName: "ctaLabel", isSignal: true, isRequired: false, transformFunction: null }, ctaIcon: { classPropertyName: "ctaIcon", publicName: "ctaIcon", isSignal: true, isRequired: false, transformFunction: null }, ctaColor: { classPropertyName: "ctaColor", publicName: "ctaColor", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { cta: "cta" }, host: { classAttribute: "flex flex-col items-center justify-center w-full px-6 text-center" }, ngImport: i0, template: `
13066
- <div [class]="_iconWrap()">
13067
- <span clx-icon [name]="icon()" [size]="_iconSize()" class="text-clx-text-faint"></span>
13040
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxPageEmptyComponent, isStandalone: true, selector: "clx-page-empty", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, ctaLabel: { classPropertyName: "ctaLabel", publicName: "ctaLabel", isSignal: true, isRequired: false, transformFunction: null }, ctaIcon: { classPropertyName: "ctaIcon", publicName: "ctaIcon", isSignal: true, isRequired: false, transformFunction: null }, ctaColor: { classPropertyName: "ctaColor", publicName: "ctaColor", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { cta: "cta" }, host: { classAttribute: "flex flex-col items-center justify-center w-full px-6 text-center text-sm" }, ngImport: i0, template: `
13041
+ <div class="w-20 h-20 rounded-2xl bg-clx-surface-2 flex items-center justify-center mb-6">
13042
+ <span clx-icon [name]="icon()" size="xl" class="text-clx-text-faint"></span>
13068
13043
  </div>
13069
13044
 
13070
- <p [class]="_titleCls()">{{ title() }}</p>
13045
+ <h1 class="text-base font-semibold text-clx-text-label mb-2">{{ title() }}</h1>
13071
13046
 
13072
13047
  @if (description()) {
13073
- <p [class]="_descCls()">{{ description() }}</p>
13048
+ <p class="text-clx-text-subtle max-w-sm mb-8">{{ description() }}</p>
13074
13049
  }
13075
13050
 
13076
13051
  @if (ctaLabel()) {
@@ -13080,7 +13055,6 @@ class ClxPageEmptyComponent {
13080
13055
  [color]="_ctaColor()"
13081
13056
  variant="solid"
13082
13057
  [icon]="ctaIcon()"
13083
- [class]="_ctaCls()"
13084
13058
  (click)="cta.emit()">
13085
13059
  {{ ctaLabel() }}
13086
13060
  </button>
@@ -13095,16 +13069,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
13095
13069
  imports: [ClxButtonComponent, ClxIconComponent],
13096
13070
  encapsulation: ViewEncapsulation.None,
13097
13071
  changeDetection: ChangeDetectionStrategy.OnPush,
13098
- host: { class: 'flex flex-col items-center justify-center w-full px-6 text-center' },
13072
+ host: { class: 'flex flex-col items-center justify-center w-full px-6 text-center text-sm' },
13099
13073
  template: `
13100
- <div [class]="_iconWrap()">
13101
- <span clx-icon [name]="icon()" [size]="_iconSize()" class="text-clx-text-faint"></span>
13074
+ <div class="w-20 h-20 rounded-2xl bg-clx-surface-2 flex items-center justify-center mb-6">
13075
+ <span clx-icon [name]="icon()" size="xl" class="text-clx-text-faint"></span>
13102
13076
  </div>
13103
13077
 
13104
- <p [class]="_titleCls()">{{ title() }}</p>
13078
+ <h1 class="text-base font-semibold text-clx-text-label mb-2">{{ title() }}</h1>
13105
13079
 
13106
13080
  @if (description()) {
13107
- <p [class]="_descCls()">{{ description() }}</p>
13081
+ <p class="text-clx-text-subtle max-w-sm mb-8">{{ description() }}</p>
13108
13082
  }
13109
13083
 
13110
13084
  @if (ctaLabel()) {
@@ -13114,14 +13088,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
13114
13088
  [color]="_ctaColor()"
13115
13089
  variant="solid"
13116
13090
  [icon]="ctaIcon()"
13117
- [class]="_ctaCls()"
13118
13091
  (click)="cta.emit()">
13119
13092
  {{ ctaLabel() }}
13120
13093
  </button>
13121
13094
  }
13122
13095
  `,
13123
13096
  }]
13124
- }], propDecorators: { icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], ctaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ctaLabel", required: false }] }], ctaIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "ctaIcon", required: false }] }], ctaColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "ctaColor", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], cta: [{ type: i0.Output, args: ["cta"] }] } });
13097
+ }], propDecorators: { icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], ctaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ctaLabel", required: false }] }], ctaIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "ctaIcon", required: false }] }], ctaColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "ctaColor", required: false }] }], cta: [{ type: i0.Output, args: ["cta"] }] } });
13125
13098
 
13126
13099
  class ClxTableComponent {
13127
13100
  _themeSvc = inject(ClxThemeService);
@@ -13416,7 +13389,7 @@ class ClxTableComponent {
13416
13389
  </div>
13417
13390
  }
13418
13391
  }
13419
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ClxCheckboxComponent, selector: "clx-checkbox", inputs: ["color", "variant", "size", "label", "value", "disabled"] }, { kind: "component", type: ClxInputComponent, selector: "clx-input", inputs: ["label", "placeholder", "type", "color", "hint", "prefixIcon", "suffixIcon", "prefixText", "suffixText", "status", "statusMessage", "size", "value", "disabled", "autocomplete"] }, { kind: "component", type: ClxSkeletonComponent, selector: "clx-skeleton", inputs: ["variant", "size", "width", "height"] }, { kind: "component", type: ClxIconComponent, selector: "span[clx-icon]", inputs: ["name", "size", "color", "fill"] }, { kind: "component", type: ClxPaginationComponent, selector: "clx-pagination", inputs: ["totalItems", "color", "size", "showPageSize", "pageSizeOptions", "currentPage", "pageSize"], outputs: ["currentPageChange", "pageSizeChange", "pageChange", "sizeChange"] }, { kind: "component", type: ClxPageEmptyComponent, selector: "clx-page-empty", inputs: ["icon", "title", "description", "ctaLabel", "ctaIcon", "ctaColor", "size"], outputs: ["cta"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
13392
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ClxCheckboxComponent, selector: "clx-checkbox", inputs: ["color", "variant", "size", "label", "value", "disabled"] }, { kind: "component", type: ClxInputComponent, selector: "clx-input", inputs: ["label", "placeholder", "type", "color", "hint", "prefixIcon", "suffixIcon", "prefixText", "suffixText", "status", "statusMessage", "size", "value", "disabled", "autocomplete"] }, { kind: "component", type: ClxSkeletonComponent, selector: "clx-skeleton", inputs: ["variant", "size", "width", "height"] }, { kind: "component", type: ClxIconComponent, selector: "span[clx-icon]", inputs: ["name", "size", "color", "fill"] }, { kind: "component", type: ClxPaginationComponent, selector: "clx-pagination", inputs: ["totalItems", "color", "size", "showPageSize", "pageSizeOptions", "currentPage", "pageSize"], outputs: ["currentPageChange", "pageSizeChange", "pageChange", "sizeChange"] }, { kind: "component", type: ClxPageEmptyComponent, selector: "clx-page-empty", inputs: ["icon", "title", "description", "ctaLabel", "ctaIcon", "ctaColor"], outputs: ["cta"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
13420
13393
  }
13421
13394
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxTableComponent, decorators: [{
13422
13395
  type: Component,
@@ -13576,13 +13549,13 @@ class ClxPageNotFoundComponent {
13576
13549
  backLabel = input('Volver al inicio', ...(ngDevMode ? [{ debugName: "backLabel" }] : /* istanbul ignore next */ []));
13577
13550
  back = output();
13578
13551
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxPageNotFoundComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
13579
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxPageNotFoundComponent, isStandalone: true, selector: "clx-page-not-found", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, backLabel: { classPropertyName: "backLabel", publicName: "backLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { back: "back" }, host: { classAttribute: "flex flex-col items-center justify-center min-h-[60vh] px-6 text-center" }, ngImport: i0, template: `
13552
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxPageNotFoundComponent, isStandalone: true, selector: "clx-page-not-found", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, backLabel: { classPropertyName: "backLabel", publicName: "backLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { back: "back" }, host: { classAttribute: "flex flex-col items-center justify-center min-h-[60vh] px-6 text-center text-sm" }, ngImport: i0, template: `
13580
13553
  <div class="w-20 h-20 rounded-2xl bg-indigo-50 flex items-center justify-center mb-6">
13581
13554
  <span clx-icon name="search_off" size="xl" class="text-indigo-400"></span>
13582
13555
  </div>
13583
13556
 
13584
- <p class="text-7xl font-black text-clx-text-faint leading-none select-none mb-2">404</p>
13585
- <h1 class="text-xl font-semibold text-clx-text-label mb-2">{{ title() }}</h1>
13557
+ <p class="text-[50px] font-black text-clx-text-faint leading-none select-none mb-2">404</p>
13558
+ <h1 class="text-base font-semibold text-clx-text-label mb-2">{{ title() }}</h1>
13586
13559
  <p class="text-clx-text-subtle max-w-sm mb-8">{{ description() }}</p>
13587
13560
 
13588
13561
  @if (backLabel()) {
@@ -13606,14 +13579,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
13606
13579
  imports: [ClxButtonComponent, ClxIconComponent],
13607
13580
  encapsulation: ViewEncapsulation.None,
13608
13581
  changeDetection: ChangeDetectionStrategy.OnPush,
13609
- host: { class: 'flex flex-col items-center justify-center min-h-[60vh] px-6 text-center' },
13582
+ host: { class: 'flex flex-col items-center justify-center min-h-[60vh] px-6 text-center text-sm' },
13610
13583
  template: `
13611
13584
  <div class="w-20 h-20 rounded-2xl bg-indigo-50 flex items-center justify-center mb-6">
13612
13585
  <span clx-icon name="search_off" size="xl" class="text-indigo-400"></span>
13613
13586
  </div>
13614
13587
 
13615
- <p class="text-7xl font-black text-clx-text-faint leading-none select-none mb-2">404</p>
13616
- <h1 class="text-xl font-semibold text-clx-text-label mb-2">{{ title() }}</h1>
13588
+ <p class="text-[50px] font-black text-clx-text-faint leading-none select-none mb-2">404</p>
13589
+ <h1 class="text-base font-semibold text-clx-text-label mb-2">{{ title() }}</h1>
13617
13590
  <p class="text-clx-text-subtle max-w-sm mb-8">{{ description() }}</p>
13618
13591
 
13619
13592
  @if (backLabel()) {
@@ -13640,13 +13613,13 @@ class ClxPageUnauthorizedComponent {
13640
13613
  login = output();
13641
13614
  back = output();
13642
13615
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxPageUnauthorizedComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
13643
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxPageUnauthorizedComponent, isStandalone: true, selector: "clx-page-unauthorized", inputs: { code: { classPropertyName: "code", publicName: "code", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, loginLabel: { classPropertyName: "loginLabel", publicName: "loginLabel", isSignal: true, isRequired: false, transformFunction: null }, backLabel: { classPropertyName: "backLabel", publicName: "backLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { login: "login", back: "back" }, host: { classAttribute: "flex flex-col items-center justify-center min-h-[60vh] px-6 text-center" }, ngImport: i0, template: `
13616
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxPageUnauthorizedComponent, isStandalone: true, selector: "clx-page-unauthorized", inputs: { code: { classPropertyName: "code", publicName: "code", isSignal: true, isRequired: false, transformFunction: null }, title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, loginLabel: { classPropertyName: "loginLabel", publicName: "loginLabel", isSignal: true, isRequired: false, transformFunction: null }, backLabel: { classPropertyName: "backLabel", publicName: "backLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { login: "login", back: "back" }, host: { classAttribute: "flex flex-col items-center justify-center min-h-[60vh] px-6 text-center text-sm" }, ngImport: i0, template: `
13644
13617
  <div class="w-20 h-20 rounded-2xl bg-amber-50 flex items-center justify-center mb-6">
13645
13618
  <span clx-icon name="lock" size="xl" class="text-amber-400"></span>
13646
13619
  </div>
13647
13620
 
13648
- <p class="text-7xl font-black text-clx-text-faint leading-none select-none mb-2">{{ code() }}</p>
13649
- <h1 class="text-xl font-semibold text-clx-text-label mb-2">{{ title() }}</h1>
13621
+ <p class="text-[50px] font-black text-clx-text-faint leading-none select-none mb-2">{{ code() }}</p>
13622
+ <h1 class="text-base font-semibold text-clx-text-label mb-2">{{ title() }}</h1>
13650
13623
  <p class="text-clx-text-subtle max-w-sm mb-8">{{ description() }}</p>
13651
13624
 
13652
13625
  <div class="flex items-center gap-3">
@@ -13683,14 +13656,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
13683
13656
  imports: [ClxButtonComponent, ClxIconComponent],
13684
13657
  encapsulation: ViewEncapsulation.None,
13685
13658
  changeDetection: ChangeDetectionStrategy.OnPush,
13686
- host: { class: 'flex flex-col items-center justify-center min-h-[60vh] px-6 text-center' },
13659
+ host: { class: 'flex flex-col items-center justify-center min-h-[60vh] px-6 text-center text-sm' },
13687
13660
  template: `
13688
13661
  <div class="w-20 h-20 rounded-2xl bg-amber-50 flex items-center justify-center mb-6">
13689
13662
  <span clx-icon name="lock" size="xl" class="text-amber-400"></span>
13690
13663
  </div>
13691
13664
 
13692
- <p class="text-7xl font-black text-clx-text-faint leading-none select-none mb-2">{{ code() }}</p>
13693
- <h1 class="text-xl font-semibold text-clx-text-label mb-2">{{ title() }}</h1>
13665
+ <p class="text-[50px] font-black text-clx-text-faint leading-none select-none mb-2">{{ code() }}</p>
13666
+ <h1 class="text-base font-semibold text-clx-text-label mb-2">{{ title() }}</h1>
13694
13667
  <p class="text-clx-text-subtle max-w-sm mb-8">{{ description() }}</p>
13695
13668
 
13696
13669
  <div class="flex items-center gap-3">
@@ -13730,13 +13703,13 @@ class ClxPageServerErrorComponent {
13730
13703
  retry = output();
13731
13704
  back = output();
13732
13705
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxPageServerErrorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
13733
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxPageServerErrorComponent, isStandalone: true, selector: "clx-page-server-error", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, retryLabel: { classPropertyName: "retryLabel", publicName: "retryLabel", isSignal: true, isRequired: false, transformFunction: null }, backLabel: { classPropertyName: "backLabel", publicName: "backLabel", isSignal: true, isRequired: false, transformFunction: null }, errorId: { classPropertyName: "errorId", publicName: "errorId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { retry: "retry", back: "back" }, host: { classAttribute: "flex flex-col items-center justify-center min-h-[60vh] px-6 text-center" }, ngImport: i0, template: `
13706
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxPageServerErrorComponent, isStandalone: true, selector: "clx-page-server-error", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, retryLabel: { classPropertyName: "retryLabel", publicName: "retryLabel", isSignal: true, isRequired: false, transformFunction: null }, backLabel: { classPropertyName: "backLabel", publicName: "backLabel", isSignal: true, isRequired: false, transformFunction: null }, errorId: { classPropertyName: "errorId", publicName: "errorId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { retry: "retry", back: "back" }, host: { classAttribute: "flex flex-col items-center justify-center min-h-[60vh] px-6 text-center text-sm" }, ngImport: i0, template: `
13734
13707
  <div class="w-20 h-20 rounded-2xl bg-red-50 flex items-center justify-center mb-6">
13735
13708
  <span clx-icon name="error_outline" size="xl" class="text-red-400"></span>
13736
13709
  </div>
13737
13710
 
13738
- <p class="text-7xl font-black text-clx-text-faint leading-none select-none mb-2">500</p>
13739
- <h1 class="text-xl font-semibold text-clx-text-label mb-2">{{ title() }}</h1>
13711
+ <p class="text-[50px] font-black text-clx-text-faint leading-none select-none mb-2">500</p>
13712
+ <h1 class="text-base font-semibold text-clx-text-label mb-2">{{ title() }}</h1>
13740
13713
  <p class="text-clx-text-subtle max-w-sm mb-8">{{ description() }}</p>
13741
13714
 
13742
13715
  @if (errorId()) {
@@ -13777,14 +13750,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
13777
13750
  imports: [ClxButtonComponent, ClxIconComponent],
13778
13751
  encapsulation: ViewEncapsulation.None,
13779
13752
  changeDetection: ChangeDetectionStrategy.OnPush,
13780
- host: { class: 'flex flex-col items-center justify-center min-h-[60vh] px-6 text-center' },
13753
+ host: { class: 'flex flex-col items-center justify-center min-h-[60vh] px-6 text-center text-sm' },
13781
13754
  template: `
13782
13755
  <div class="w-20 h-20 rounded-2xl bg-red-50 flex items-center justify-center mb-6">
13783
13756
  <span clx-icon name="error_outline" size="xl" class="text-red-400"></span>
13784
13757
  </div>
13785
13758
 
13786
- <p class="text-7xl font-black text-clx-text-faint leading-none select-none mb-2">500</p>
13787
- <h1 class="text-xl font-semibold text-clx-text-label mb-2">{{ title() }}</h1>
13759
+ <p class="text-[50px] font-black text-clx-text-faint leading-none select-none mb-2">500</p>
13760
+ <h1 class="text-base font-semibold text-clx-text-label mb-2">{{ title() }}</h1>
13788
13761
  <p class="text-clx-text-subtle max-w-sm mb-8">{{ description() }}</p>
13789
13762
 
13790
13763
  @if (errorId()) {
@@ -14292,10 +14265,10 @@ class ClxProductComponent {
14292
14265
 
14293
14266
  <!-- Price -->
14294
14267
  <div class="flex items-baseline gap-2 mt-2">
14295
- <span [class]="_priceClass()">{{ _price() | currency:'COP':'symbol':'1.0-0' }}</span>
14268
+ <span [class]="_priceClass()">{{ _price() | currency:'COP':'$':'1.0-0' }}</span>
14296
14269
  @if (product()?.has_discount && product()?.discount_price) {
14297
14270
  <span class="text-sm text-clx-text-subtle line-through">
14298
- {{ product()?.discount_price | currency:'COP':'symbol':'1.0-0' }}
14271
+ {{ product()?.discount_price | currency:'COP':'$':'1.0-0' }}
14299
14272
  </span>
14300
14273
  }
14301
14274
  </div>
@@ -14427,10 +14400,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
14427
14400
 
14428
14401
  <!-- Price -->
14429
14402
  <div class="flex items-baseline gap-2 mt-2">
14430
- <span [class]="_priceClass()">{{ _price() | currency:'COP':'symbol':'1.0-0' }}</span>
14403
+ <span [class]="_priceClass()">{{ _price() | currency:'COP':'$':'1.0-0' }}</span>
14431
14404
  @if (product()?.has_discount && product()?.discount_price) {
14432
14405
  <span class="text-sm text-clx-text-subtle line-through">
14433
- {{ product()?.discount_price | currency:'COP':'symbol':'1.0-0' }}
14406
+ {{ product()?.discount_price | currency:'COP':'$':'1.0-0' }}
14434
14407
  </span>
14435
14408
  }
14436
14409
  </div>
@@ -14559,7 +14532,7 @@ class ClxProductDetailComponent {
14559
14532
  specsLeft(specs) { return specs.slice(0, Math.ceil(specs.length / 2)); }
14560
14533
  specsRight(specs) { return specs.slice(Math.ceil(specs.length / 2)); }
14561
14534
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxProductDetailComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
14562
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxProductDetailComponent, isStandalone: true, selector: "clx-product-detail", inputs: { product: { classPropertyName: "product", publicName: "product", isSignal: true, isRequired: false, transformFunction: null }, initialVariationId: { classPropertyName: "initialVariationId", publicName: "initialVariationId", isSignal: true, isRequired: false, transformFunction: null }, clxColor: { classPropertyName: "clxColor", publicName: "clxColor", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, currency: { classPropertyName: "currency", publicName: "currency", isSignal: true, isRequired: false, transformFunction: null }, compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { addToCart: "addToCart", buyNow: "buyNow", wishlist: "wishlist", variationChange: "variationChange" }, viewQueries: [{ propertyName: "_carousel", first: true, predicate: ClxCarouselComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<!-- \u2550\u2550 SKELETON \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n@if (loading()) {\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-8 p-6\">\n <div class=\"space-y-3\">\n <clx-skeleton variant=\"rectangular\" width=\"100%\" height=\"420px\" class=\"rounded-2xl\"></clx-skeleton>\n <div class=\"flex gap-2\">\n @for (t of [1,2,3,4]; track t) {\n <clx-skeleton variant=\"rectangular\" width=\"80px\" height=\"80px\" class=\"rounded-xl\"></clx-skeleton>\n }\n </div>\n </div>\n <div class=\"space-y-4 pt-2\">\n <clx-skeleton variant=\"text\" size=\"lg\" width=\"70%\"></clx-skeleton>\n <clx-skeleton variant=\"text\" size=\"sm\" width=\"40%\"></clx-skeleton>\n <clx-skeleton variant=\"text\" size=\"xl\" width=\"50%\"></clx-skeleton>\n <clx-skeleton variant=\"rectangular\" width=\"100%\" height=\"100px\" class=\"rounded-xl\"></clx-skeleton>\n <clx-skeleton variant=\"rectangular\" width=\"100%\" height=\"52px\" class=\"rounded-xl\"></clx-skeleton>\n <clx-skeleton variant=\"rectangular\" width=\"100%\" height=\"52px\" class=\"rounded-xl\"></clx-skeleton>\n </div>\n </div>\n}\n\n<!-- \u2550\u2550 CONTENT \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n@if (!loading() && product(); as p) {\n @let v = activeVariation();\n <div class=\"space-y-8\">\n\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-8 md:items-start\">\n\n <!-- \u2500\u2500 Column 1: Image Gallery \u2014 each column sizes to its own content (no forced equal\n height, no position:sticky). A `sticky` gallery reads great in isolation, but a host app\n that already has its own `position: sticky` header (a full-width top bar, as opposed to\n this library's own `clx-app-layout` sidebar, which is `fixed` and never competes) forces\n the browser to keep recomputing both stickies' viewport-relative offsets together on every\n resize \u2014 confirmed as the source of a persistent resize-lag bug in codexly-store's product\n page. Not worth reintroducing until sticky positioning is made robust to an arbitrary host\n header. \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"flex flex-col gap-3\">\n <div class=\"relative aspect-4/3\">\n <clx-carousel [clxColor]=\"clxColor()\" aspectRatio=\"4/3\" [loop]=\"true\">\n @for (img of v?.images ?? []; track i; let i = $index) {\n <ng-template clxSlide>\n <div class=\"w-full h-full p-5 sm:p-12.5 md:p-5 lg:p-12.5\">\n <img [src]=\"img\" [alt]=\"p.product_name\" class=\"w-full h-full object-contain\"\n [loading]=\"i === 0 ? 'eager' : 'lazy'\"\n [attr.fetchpriority]=\"i === 0 ? 'high' : null\" />\n </div>\n </ng-template>\n }\n </clx-carousel>\n <div class=\"absolute top-3 right-3 z-10\">\n <button clx-button type=\"button\" variant=\"solid\" [color]=\"clxColor()\" shape=\"circle\" size=\"md\"\n [iconOnly]=\"true\" clxTooltip=\"Agregar a favoritos\" [clxTooltipColor]=\"clxColor()\" clxTooltipPosition=\"left\"\n (click)=\"wishlist.emit()\">\n <span clx-icon name=\"favorite_border\" size=\"sm\"></span>\n </button>\n </div>\n </div>\n <div class=\"flex flex-wrap gap-2\">\n @for (img of v?.images ?? []; track i; let i = $index) {\n <img [src]=\"img\" [alt]=\"p.product_name\"\n class=\"w-20 h-20 rounded-xl object-cover border-[3px] cursor-pointer shrink-0 transition-[border-color,opacity]\"\n [class]=\"_carousel()?.currentPageIndex() === i\n ? 'border-' + clxColor() + '-500 opacity-100'\n : 'border-transparent opacity-60 hover:opacity-90'\"\n loading=\"lazy\"\n (click)=\"_carousel()?.goTo(i)\" />\n }\n </div>\n </div>\n\n <!-- \u2500\u2500 Column 2: Purchase Info \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"space-y-2.5\">\n\n <!-- Stock status -->\n @if (v) {\n <span clx-badge [variant]=\"v.in_stock ? 'light' : 'solid'\" [color]=\"v.in_stock ? clxColor() : 'green'\" size=\"sm\" shape=\"pill\">\n @if (v.in_stock) {\n @if (v.stock_quantity != null) {\n {{ v.stock_quantity }} en stock\n } @else {\n En stock\n }\n } @else {\n Sin stock\n }\n </span>\n }\n\n <!-- Tags (st_products.tags) -->\n <div class=\"flex flex-wrap gap-1\">\n @for (tag of p.tags; track tag) {\n <span clx-badge variant=\"light\" [color]=\"clxColor()\" size=\"sm\" shape=\"pill\">{{ tag }}</span>\n }\n </div>\n\n <!-- Title -->\n <div>\n <p class=\"text-sm text-clx-text-subtle uppercase tracking-wide font-medium\">{{ p.trademark }}</p>\n <h1 class=\"text-2xl font-bold text-clx-text-label leading-tight mt-0.5\">{{ v?.name || p.product_name }}</h1>\n @if (p.product_detail) {\n <p class=\"text-clx-text-muted text-sm mt-1\">{{ p.product_detail }}</p>\n }\n </div>\n\n <!-- Rating -->\n <div class=\"flex items-center gap-2\">\n <clx-rating [value]=\"p.rating\" [color]=\"clxColor()\"></clx-rating>\n <span class=\"text-sm font-semibold text-clx-text-label\">{{ p.rating | number:'1.1-1' }}</span>\n <span class=\"text-sm text-clx-text-subtle\">({{ p.review_count }} reviews)</span>\n </div>\n\n <!-- Price block -->\n <div>\n <div class=\"flex items-baseline gap-3\">\n <span class=\"text-2xl font-black text-clx-text-label\">\n {{ finalPrice() | currency:currency():'symbol':'1.0-0' }}\n </span>\n @if (p.has_discount && p.discount_price) {\n <span class=\"text-base text-clx-text-subtle line-through\">\n {{ p.discount_price | currency:currency():'symbol':'1.0-0' }}\n </span>\n <span clx-badge variant=\"solid\" [color]=\"clxColor()\" size=\"sm\" shape=\"pill\">\n -{{ discount() }}%\n </span>\n }\n </div>\n </div>\n\n <!-- Selectores de variaci\u00F3n (st_spec_types + st_spec_options) \u2014 opciones no disponibles\n para la combinaci\u00F3n actual (ej. Talla S con Color Rojo) se ocultan por completo en vez\n de mostrarse deshabilitadas; reaparecen si el usuario cambia a una combinaci\u00F3n donde s\u00ED\n aplican, ya que isOptionAvailable() se reeval\u00FAa contra selectedSpecs() en cada cambio. -->\n @for (specType of p.spec_types; track specType.id) {\n @if (specType.input_type === 'color') {\n <clx-button-group [label]=\"specType.name\" shape=\"circular\" [attached]=\"false\">\n @for (opt of specType.options; track opt.id) {\n @if (isOptionAvailable(specType.id, opt.id)) {\n <button\n type=\"button\"\n class=\"w-7 h-7 rounded-full border-2 transition-[transform,box-shadow] shrink-0 cursor-pointer\"\n [class]=\"isSpecSelected(specType.id, opt.id) ? 'scale-110 shadow-md' : 'opacity-90 hover:opacity-100'\"\n [style.background-color]=\"opt.value\"\n [style.border-color]=\"isSpecSelected(specType.id, opt.id) ? 'var(--clx-text-label, #111)' : 'transparent'\"\n [clxTooltip]=\"opt.label ?? opt.value\"\n clxTooltipPosition=\"top\"\n (click)=\"selectSpec(specType.id, opt.id)\">\n </button>\n }\n }\n </clx-button-group>\n } @else {\n <clx-button-group [label]=\"specType.name\" shape=\"flat\" [attached]=\"false\">\n @for (opt of specType.options; track opt.id) {\n @if (isOptionAvailable(specType.id, opt.id)) {\n <button clx-button\n type=\"button\"\n [variant]=\"isSpecSelected(specType.id, opt.id) ? 'solid' : 'outline'\"\n [color]=\"clxColor()\" size=\"sm\"\n (click)=\"selectSpec(specType.id, opt.id)\">\n {{ opt.label ?? opt.value }}\n </button>\n }\n }\n </clx-button-group>\n }\n }\n\n <!-- Quantity -->\n <clx-number label=\"Quantity:\" variant=\"stepper\" [color]=\"clxColor()\"\n [min]=\"1\" [max]=\"99\" [ngModel]=\"quantity()\" (ngModelChange)=\"quantity.set($event)\">\n </clx-number>\n\n <!-- CTA -->\n <div class=\"flex gap-3\">\n <button clx-button type=\"button\" variant=\"solid\" [color]=\"clxColor()\" size=\"md\" [block]=\"true\" icon=\"bolt\"\n [disabled]=\"!v?.in_stock\" (click)=\"_emitBuyNow()\">Comprar ahora</button>\n <button clx-button type=\"button\" variant=\"light\" [color]=\"clxColor()\" size=\"md\" [block]=\"true\" icon=\"shopping_cart\"\n [disabled]=\"!v?.in_stock\" (click)=\"_emitAddToCart()\">Agrega al carrito</button>\n </div>\n\n </div>\n </div>\n\n @if (!compact()) {\n <!-- \u2500\u2500 Tabs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <clx-tabs [tabs]=\"tabItems\" [clxColor]=\"clxColor()\" [(activeTab)]=\"activeTab\">\n\n <!-- Tab: Caracter\u00EDsticas generales (st_product_specs \u2014 ficha t\u00E9cnica global) -->\n <ng-template [clxTabPanel]=\"'general'\">\n <div class=\"grid grid-cols-1 sm:grid-cols-2 gap-x-8\">\n <clx-list [color]=\"clxColor()\" variant=\"flush\" size=\"sm\">\n @for (spec of specsLeft(p.product_specs); track spec.id) {\n <clx-list-item [icon]=\"spec.icon ?? ''\">\n <div clxContent>\n <p class=\"text-sm font-medium text-clx-text-label\">{{ spec.name }}:</p>\n <p class=\"text-sm text-clx-text-muted mt-0.5\">{{ spec.value }}</p>\n </div>\n </clx-list-item>\n }\n </clx-list>\n <clx-list [color]=\"clxColor()\" variant=\"flush\" size=\"sm\">\n @for (spec of specsRight(p.product_specs); track spec.id) {\n <clx-list-item [icon]=\"spec.icon ?? ''\">\n <div clxContent>\n <p class=\"text-sm font-medium text-clx-text-label\">{{ spec.name }}:</p>\n <p class=\"text-sm text-clx-text-muted mt-0.5\">{{ spec.value }}</p>\n </div>\n </clx-list-item>\n }\n </clx-list>\n </div>\n </ng-template>\n\n <!-- Tab: Especificaciones (st_spec_types \u2014 specs de la variaci\u00F3n activa) -->\n <ng-template [clxTabPanel]=\"'specs'\">\n <div class=\"grid grid-cols-1 sm:grid-cols-2 gap-x-8\">\n <clx-list [color]=\"clxColor()\" variant=\"flush\" size=\"sm\">\n @for (st of specsLeft(p.spec_types); track st.id) {\n <clx-list-item [label]=\"st.name + ':'\" [sublabel]=\"selectedOptionLabel(st)\" [icon]=\"st.icon ?? ''\" />\n }\n </clx-list>\n <clx-list [color]=\"clxColor()\" variant=\"flush\" size=\"sm\">\n @for (st of specsRight(p.spec_types); track st.id) {\n <clx-list-item [label]=\"st.name + ':'\" [sublabel]=\"selectedOptionLabel(st)\" [icon]=\"st.icon ?? ''\" />\n }\n </clx-list>\n </div>\n </ng-template>\n\n <!-- Tab: Descripci\u00F3n (st_product_descriptions) -->\n <ng-template [clxTabPanel]=\"'description'\">\n <div class=\"space-y-5\">\n @for (block of p.descriptions; track block.id) {\n <div>\n @if (block.title) {\n <h3 class=\"text-base font-semibold text-clx-text-label mb-1\">{{ block.title }}</h3>\n }\n <p class=\"text-sm text-clx-text-muted leading-relaxed\">{{ block.body }}</p>\n </div>\n }\n </div>\n </ng-template>\n\n </clx-tabs>\n\n <!-- \u2500\u2500 Reviews \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"grid grid-cols-1 xl:grid-cols-3 gap-8 border-t border-clx-border pt-8\">\n\n <div class=\"space-y-3\">\n <h2 class=\"text-base font-bold text-clx-text-label\">Customer Reviews</h2>\n <div class=\"flex items-end gap-3\">\n <span class=\"text-5xl font-black text-clx-text-label\">{{ p.rating | number:'1.1-1' }}</span>\n <div class=\"pb-1 space-y-1\">\n <clx-rating [value]=\"p.rating\" [color]=\"clxColor()\"></clx-rating>\n <p class=\"text-xs text-clx-text-muted\">{{ p.review_count }} verified ratings</p>\n </div>\n </div>\n <p class=\"text-sm font-semibold\" [class]=\"'text-' + clxColor() + '-600'\">Very Good</p>\n <div class=\"pt-2 space-y-2\">\n <button clx-button type=\"button\" variant=\"solid\" [color]=\"clxColor()\" size=\"md\" [block]=\"true\" icon=\"rate_review\">\n Leave Us a Review\n </button>\n <button clx-button type=\"button\" variant=\"light\" [color]=\"clxColor()\" size=\"md\" [block]=\"true\" icon=\"flag\">\n Report abuse\n </button>\n </div>\n </div>\n\n <div class=\"lg:col-span-2 space-y-4\">\n @for (review of p.reviews ?? []; track review.id) {\n <div class=\"rounded-2xl overflow-hidden shadow-sm\">\n <div class=\"flex items-center gap-3 px-4 py-3\">\n <div class=\"w-10 h-10 rounded-full bg-clx-surface-2 flex items-center justify-center shrink-0\">\n <span class=\"text-sm font-bold text-clx-text-muted\">\n {{ review.author_name.substring(0,1) }}{{ review.author_name.split(' ')[1]?.substring(0,1) ?? '' }}\n </span>\n </div>\n <div class=\"flex-1 min-w-0\">\n <p class=\"font-semibold text-sm text-clx-text-label truncate\">{{ review.author_name }}</p>\n <p class=\"text-xs text-clx-text-subtle\">{{ review.created_at }}</p>\n </div>\n @if (review.is_verified) {\n <span clx-badge variant=\"light\" color=\"emerald\" size=\"sm\" shape=\"pill\">Verified</span>\n }\n </div>\n <div class=\"px-4 pb-4 space-y-2\">\n <div class=\"flex items-center gap-2\">\n <clx-rating [value]=\"review.rating\" [color]=\"clxColor()\"></clx-rating>\n @if (review.title) {\n <span class=\"text-sm font-semibold text-clx-text-label\">{{ review.title }}</span>\n }\n </div>\n @if (review.body) {\n <p class=\"text-sm text-clx-text-muted\">{{ review.body }}</p>\n }\n <div class=\"flex items-center gap-3 pt-1\">\n <span class=\"text-xs text-clx-text-subtle\">Helpful?</span>\n <button clx-button type=\"button\" variant=\"ghost\" color=\"slate\" size=\"xs\" icon=\"thumb_up\">{{ review.helpful }}</button>\n <button clx-button type=\"button\" variant=\"ghost\" color=\"slate\" size=\"xs\" icon=\"thumb_down\">{{ review.not_helpful }}</button>\n </div>\n </div>\n </div>\n }\n </div>\n\n </div>\n }\n\n </div>\n}\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ClxButtonComponent, selector: "button[clx-button], a[clx-button]", inputs: ["variant", "color", "textColor", "size", "shape", "loading", "disabled", "block", "icon", "iconPosition", "iconOnly", "badge", "badgeColor"] }, { kind: "component", type: ClxButtonGroupComponent, selector: "clx-button-group", inputs: ["label", "shape", "attached", "orientation"] }, { kind: "component", type: ClxBadgeComponent, selector: "span[clx-badge]", inputs: ["variant", "color", "size", "shape", "positioned"] }, { kind: "component", type: ClxIconComponent, selector: "span[clx-icon]", inputs: ["name", "size", "color", "fill"] }, { kind: "component", type: ClxSkeletonComponent, selector: "clx-skeleton", inputs: ["variant", "size", "width", "height"] }, { kind: "component", type: ClxRatingComponent, selector: "clx-rating", inputs: ["value", "max", "color"] }, { kind: "component", type: ClxCarouselComponent, selector: "clx-carousel", inputs: ["clxColor", "autoPlay", "interval", "loop", "aspectRatio", "transparent"] }, { kind: "directive", type: ClxCarouselDirective, selector: "[clxSlide]" }, { kind: "component", type: ClxTabsComponent, selector: "clx-tabs", inputs: ["tabs", "clxColor", "activeTab"], outputs: ["activeTabChange"] }, { kind: "directive", type: ClxTabDirective, selector: "[clxTabPanel]", inputs: ["clxTabPanel"] }, { kind: "component", type: ClxNumberComponent, selector: "clx-number", inputs: ["variant", "size", "color", "label", "placeholder", "hint", "prefixIcon", "min", "max", "step", "value", "disabled"] }, { kind: "directive", type: ClxTooltipDirective, selector: "[clxTooltip]", inputs: ["clxTooltip", "clxTooltipPosition", "clxTooltipColor", "clxTooltipSize", "clxTooltipDelay"] }, { kind: "component", type: ClxListComponent, selector: "clx-list", inputs: ["color", "variant", "size", "numbered"] }, { kind: "component", type: ClxListItemComponent, selector: "clx-list-item", inputs: ["label", "sublabel", "icon", "meta", "metaColor", "disabled"] }, { kind: "pipe", type: CurrencyPipe, name: "currency" }, { kind: "pipe", type: DecimalPipe, name: "number" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
14535
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxProductDetailComponent, isStandalone: true, selector: "clx-product-detail", inputs: { product: { classPropertyName: "product", publicName: "product", isSignal: true, isRequired: false, transformFunction: null }, initialVariationId: { classPropertyName: "initialVariationId", publicName: "initialVariationId", isSignal: true, isRequired: false, transformFunction: null }, clxColor: { classPropertyName: "clxColor", publicName: "clxColor", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, currency: { classPropertyName: "currency", publicName: "currency", isSignal: true, isRequired: false, transformFunction: null }, compact: { classPropertyName: "compact", publicName: "compact", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { addToCart: "addToCart", buyNow: "buyNow", wishlist: "wishlist", variationChange: "variationChange" }, viewQueries: [{ propertyName: "_carousel", first: true, predicate: ClxCarouselComponent, descendants: true, isSignal: true }], ngImport: i0, template: "<!-- \u2550\u2550 SKELETON \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n@if (loading()) {\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-8 p-6\">\n <div class=\"space-y-3\">\n <clx-skeleton variant=\"rectangular\" width=\"100%\" height=\"420px\" class=\"rounded-2xl\"></clx-skeleton>\n <div class=\"flex gap-2\">\n @for (t of [1,2,3,4]; track t) {\n <clx-skeleton variant=\"rectangular\" width=\"80px\" height=\"80px\" class=\"rounded-xl\"></clx-skeleton>\n }\n </div>\n </div>\n <div class=\"space-y-4 pt-2\">\n <clx-skeleton variant=\"text\" size=\"lg\" width=\"70%\"></clx-skeleton>\n <clx-skeleton variant=\"text\" size=\"sm\" width=\"40%\"></clx-skeleton>\n <clx-skeleton variant=\"text\" size=\"xl\" width=\"50%\"></clx-skeleton>\n <clx-skeleton variant=\"rectangular\" width=\"100%\" height=\"100px\" class=\"rounded-xl\"></clx-skeleton>\n <clx-skeleton variant=\"rectangular\" width=\"100%\" height=\"52px\" class=\"rounded-xl\"></clx-skeleton>\n <clx-skeleton variant=\"rectangular\" width=\"100%\" height=\"52px\" class=\"rounded-xl\"></clx-skeleton>\n </div>\n </div>\n}\n\n<!-- \u2550\u2550 CONTENT \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n@if (!loading() && product(); as p) {\n @let v = activeVariation();\n <div class=\"space-y-8\">\n\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-8 md:items-start\">\n\n <!-- \u2500\u2500 Column 1: Image Gallery \u2014 each column sizes to its own content (no forced equal\n height, no position:sticky). A `sticky` gallery reads great in isolation, but a host app\n that already has its own `position: sticky` header (a full-width top bar, as opposed to\n this library's own `clx-app-layout` sidebar, which is `fixed` and never competes) forces\n the browser to keep recomputing both stickies' viewport-relative offsets together on every\n resize \u2014 confirmed as the source of a persistent resize-lag bug in codexly-store's product\n page. Not worth reintroducing until sticky positioning is made robust to an arbitrary host\n header. \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"flex flex-col gap-3\">\n <div class=\"relative aspect-4/3\">\n <clx-carousel [clxColor]=\"clxColor()\" aspectRatio=\"4/3\" [loop]=\"true\">\n @for (img of v?.images ?? []; track i; let i = $index) {\n <ng-template clxSlide>\n <div class=\"w-full h-full p-5 sm:p-12.5 md:p-5 lg:p-12.5\">\n <img [src]=\"img\" [alt]=\"p.product_name\" class=\"w-full h-full object-contain\"\n [loading]=\"i === 0 ? 'eager' : 'lazy'\"\n [attr.fetchpriority]=\"i === 0 ? 'high' : null\" />\n </div>\n </ng-template>\n }\n </clx-carousel>\n <div class=\"absolute top-3 right-3 z-10\">\n <button clx-button type=\"button\" variant=\"solid\" [color]=\"clxColor()\" shape=\"circle\" size=\"md\"\n [iconOnly]=\"true\" clxTooltip=\"Agregar a favoritos\" [clxTooltipColor]=\"clxColor()\" clxTooltipPosition=\"left\"\n (click)=\"wishlist.emit()\">\n <span clx-icon name=\"favorite_border\" size=\"sm\"></span>\n </button>\n </div>\n </div>\n <div class=\"flex flex-wrap gap-2\">\n @for (img of v?.images ?? []; track i; let i = $index) {\n <img [src]=\"img\" [alt]=\"p.product_name\"\n class=\"w-20 h-20 rounded-xl object-cover border-[3px] cursor-pointer shrink-0 transition-[border-color,opacity]\"\n [class]=\"_carousel()?.currentPageIndex() === i\n ? 'border-' + clxColor() + '-500 opacity-100'\n : 'border-transparent opacity-60 hover:opacity-90'\"\n loading=\"lazy\"\n (click)=\"_carousel()?.goTo(i)\" />\n }\n </div>\n </div>\n\n <!-- \u2500\u2500 Column 2: Purchase Info \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"space-y-2.5\">\n\n <!-- Stock status -->\n @if (v) {\n <span clx-badge [variant]=\"v.in_stock ? 'light' : 'solid'\" [color]=\"v.in_stock ? clxColor() : 'green'\" size=\"sm\" shape=\"pill\">\n @if (v.in_stock) {\n @if (v.stock_quantity != null) {\n {{ v.stock_quantity }} en stock\n } @else {\n En stock\n }\n } @else {\n Sin stock\n }\n </span>\n }\n\n <!-- Tags (st_products.tags) -->\n <div class=\"flex flex-wrap gap-1\">\n @for (tag of p.tags; track tag) {\n <span clx-badge variant=\"light\" [color]=\"clxColor()\" size=\"sm\" shape=\"pill\">{{ tag }}</span>\n }\n </div>\n\n <!-- Title -->\n <div>\n <p class=\"text-sm text-clx-text-subtle uppercase tracking-wide font-medium\">{{ p.trademark }}</p>\n <h1 class=\"text-2xl font-bold text-clx-text-label leading-tight mt-0.5\">{{ v?.name || p.product_name }}</h1>\n @if (p.product_detail) {\n <p class=\"text-clx-text-muted text-sm mt-1\">{{ p.product_detail }}</p>\n }\n </div>\n\n <!-- Rating -->\n <div class=\"flex items-center gap-2\">\n <clx-rating [value]=\"p.rating\" [color]=\"clxColor()\"></clx-rating>\n <span class=\"text-sm font-semibold text-clx-text-label\">{{ p.rating | number:'1.1-1' }}</span>\n <span class=\"text-sm text-clx-text-subtle\">({{ p.review_count }} reviews)</span>\n </div>\n\n <!-- Price block -->\n <div>\n <div class=\"flex items-baseline gap-3\">\n <span class=\"text-2xl font-black text-clx-text-label\">\n {{ finalPrice() | currency:currency():'$':'1.0-0' }}\n </span>\n @if (p.has_discount && p.discount_price) {\n <span class=\"text-base text-clx-text-subtle line-through\">\n {{ p.discount_price | currency:currency():'$':'1.0-0' }}\n </span>\n <span clx-badge variant=\"solid\" [color]=\"clxColor()\" size=\"sm\" shape=\"pill\">\n -{{ discount() }}%\n </span>\n }\n </div>\n </div>\n\n <!-- Selectores de variaci\u00F3n (st_spec_types + st_spec_options) \u2014 opciones no disponibles\n para la combinaci\u00F3n actual (ej. Talla S con Color Rojo) se ocultan por completo en vez\n de mostrarse deshabilitadas; reaparecen si el usuario cambia a una combinaci\u00F3n donde s\u00ED\n aplican, ya que isOptionAvailable() se reeval\u00FAa contra selectedSpecs() en cada cambio. -->\n @for (specType of p.spec_types; track specType.id) {\n @if (specType.input_type === 'color') {\n <clx-button-group [label]=\"specType.name\" shape=\"circular\" [attached]=\"false\">\n @for (opt of specType.options; track opt.id) {\n @if (isOptionAvailable(specType.id, opt.id)) {\n <button\n type=\"button\"\n class=\"w-7 h-7 rounded-full border-2 transition-[transform,box-shadow] shrink-0 cursor-pointer\"\n [class]=\"isSpecSelected(specType.id, opt.id) ? 'scale-110 shadow-md' : 'opacity-90 hover:opacity-100'\"\n [style.background-color]=\"opt.value\"\n [style.border-color]=\"isSpecSelected(specType.id, opt.id) ? 'var(--clx-text-label, #111)' : 'transparent'\"\n [clxTooltip]=\"opt.label ?? opt.value\"\n clxTooltipPosition=\"top\"\n (click)=\"selectSpec(specType.id, opt.id)\">\n </button>\n }\n }\n </clx-button-group>\n } @else {\n <clx-button-group [label]=\"specType.name\" shape=\"flat\" [attached]=\"false\">\n @for (opt of specType.options; track opt.id) {\n @if (isOptionAvailable(specType.id, opt.id)) {\n <button clx-button\n type=\"button\"\n [variant]=\"isSpecSelected(specType.id, opt.id) ? 'solid' : 'outline'\"\n [color]=\"clxColor()\" size=\"sm\"\n (click)=\"selectSpec(specType.id, opt.id)\">\n {{ opt.label ?? opt.value }}\n </button>\n }\n }\n </clx-button-group>\n }\n }\n\n <!-- Quantity -->\n <clx-number label=\"Quantity:\" variant=\"stepper\" [color]=\"clxColor()\"\n [min]=\"1\" [max]=\"99\" [ngModel]=\"quantity()\" (ngModelChange)=\"quantity.set($event)\">\n </clx-number>\n\n <!-- CTA -->\n <div class=\"flex gap-3\">\n <button clx-button type=\"button\" variant=\"solid\" [color]=\"clxColor()\" size=\"md\" [block]=\"true\" icon=\"bolt\"\n [disabled]=\"!v?.in_stock\" (click)=\"_emitBuyNow()\">Comprar ahora</button>\n <button clx-button type=\"button\" variant=\"light\" [color]=\"clxColor()\" size=\"md\" [block]=\"true\" icon=\"shopping_cart\"\n [disabled]=\"!v?.in_stock\" (click)=\"_emitAddToCart()\">Agrega al carrito</button>\n </div>\n\n </div>\n </div>\n\n @if (!compact()) {\n <!-- \u2500\u2500 Tabs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <clx-tabs [tabs]=\"tabItems\" [clxColor]=\"clxColor()\" [(activeTab)]=\"activeTab\">\n\n <!-- Tab: Caracter\u00EDsticas generales (st_product_specs \u2014 ficha t\u00E9cnica global) -->\n <ng-template [clxTabPanel]=\"'general'\">\n <div class=\"grid grid-cols-1 sm:grid-cols-2 gap-x-8\">\n <clx-list [color]=\"clxColor()\" variant=\"flush\" size=\"sm\">\n @for (spec of specsLeft(p.product_specs); track spec.id) {\n <clx-list-item [icon]=\"spec.icon ?? ''\">\n <div clxContent>\n <p class=\"text-sm font-medium text-clx-text-label\">{{ spec.name }}:</p>\n <p class=\"text-sm text-clx-text-muted mt-0.5\">{{ spec.value }}</p>\n </div>\n </clx-list-item>\n }\n </clx-list>\n <clx-list [color]=\"clxColor()\" variant=\"flush\" size=\"sm\">\n @for (spec of specsRight(p.product_specs); track spec.id) {\n <clx-list-item [icon]=\"spec.icon ?? ''\">\n <div clxContent>\n <p class=\"text-sm font-medium text-clx-text-label\">{{ spec.name }}:</p>\n <p class=\"text-sm text-clx-text-muted mt-0.5\">{{ spec.value }}</p>\n </div>\n </clx-list-item>\n }\n </clx-list>\n </div>\n </ng-template>\n\n <!-- Tab: Especificaciones (st_spec_types \u2014 specs de la variaci\u00F3n activa) -->\n <ng-template [clxTabPanel]=\"'specs'\">\n <div class=\"grid grid-cols-1 sm:grid-cols-2 gap-x-8\">\n <clx-list [color]=\"clxColor()\" variant=\"flush\" size=\"sm\">\n @for (st of specsLeft(p.spec_types); track st.id) {\n <clx-list-item [label]=\"st.name + ':'\" [sublabel]=\"selectedOptionLabel(st)\" [icon]=\"st.icon ?? ''\" />\n }\n </clx-list>\n <clx-list [color]=\"clxColor()\" variant=\"flush\" size=\"sm\">\n @for (st of specsRight(p.spec_types); track st.id) {\n <clx-list-item [label]=\"st.name + ':'\" [sublabel]=\"selectedOptionLabel(st)\" [icon]=\"st.icon ?? ''\" />\n }\n </clx-list>\n </div>\n </ng-template>\n\n <!-- Tab: Descripci\u00F3n (st_product_descriptions) -->\n <ng-template [clxTabPanel]=\"'description'\">\n <div class=\"space-y-5\">\n @for (block of p.descriptions; track block.id) {\n <div>\n @if (block.title) {\n <h3 class=\"text-base font-semibold text-clx-text-label mb-1\">{{ block.title }}</h3>\n }\n <p class=\"text-sm text-clx-text-muted leading-relaxed\">{{ block.body }}</p>\n </div>\n }\n </div>\n </ng-template>\n\n </clx-tabs>\n\n <!-- \u2500\u2500 Reviews \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"grid grid-cols-1 xl:grid-cols-3 gap-8 border-t border-clx-border pt-8\">\n\n <div class=\"space-y-3\">\n <h2 class=\"text-base font-bold text-clx-text-label\">Customer Reviews</h2>\n <div class=\"flex items-end gap-3\">\n <span class=\"text-5xl font-black text-clx-text-label\">{{ p.rating | number:'1.1-1' }}</span>\n <div class=\"pb-1 space-y-1\">\n <clx-rating [value]=\"p.rating\" [color]=\"clxColor()\"></clx-rating>\n <p class=\"text-xs text-clx-text-muted\">{{ p.review_count }} verified ratings</p>\n </div>\n </div>\n <p class=\"text-sm font-semibold\" [class]=\"'text-' + clxColor() + '-600'\">Very Good</p>\n <div class=\"pt-2 space-y-2\">\n <button clx-button type=\"button\" variant=\"solid\" [color]=\"clxColor()\" size=\"md\" [block]=\"true\" icon=\"rate_review\">\n Leave Us a Review\n </button>\n <button clx-button type=\"button\" variant=\"light\" [color]=\"clxColor()\" size=\"md\" [block]=\"true\" icon=\"flag\">\n Report abuse\n </button>\n </div>\n </div>\n\n <div class=\"lg:col-span-2 space-y-4\">\n @for (review of p.reviews ?? []; track review.id) {\n <div class=\"rounded-2xl overflow-hidden shadow-sm\">\n <div class=\"flex items-center gap-3 px-4 py-3\">\n <div class=\"w-10 h-10 rounded-full bg-clx-surface-2 flex items-center justify-center shrink-0\">\n <span class=\"text-sm font-bold text-clx-text-muted\">\n {{ review.author_name.substring(0,1) }}{{ review.author_name.split(' ')[1]?.substring(0,1) ?? '' }}\n </span>\n </div>\n <div class=\"flex-1 min-w-0\">\n <p class=\"font-semibold text-sm text-clx-text-label truncate\">{{ review.author_name }}</p>\n <p class=\"text-xs text-clx-text-subtle\">{{ review.created_at }}</p>\n </div>\n @if (review.is_verified) {\n <span clx-badge variant=\"light\" color=\"emerald\" size=\"sm\" shape=\"pill\">Verified</span>\n }\n </div>\n <div class=\"px-4 pb-4 space-y-2\">\n <div class=\"flex items-center gap-2\">\n <clx-rating [value]=\"review.rating\" [color]=\"clxColor()\"></clx-rating>\n @if (review.title) {\n <span class=\"text-sm font-semibold text-clx-text-label\">{{ review.title }}</span>\n }\n </div>\n @if (review.body) {\n <p class=\"text-sm text-clx-text-muted\">{{ review.body }}</p>\n }\n <div class=\"flex items-center gap-3 pt-1\">\n <span class=\"text-xs text-clx-text-subtle\">Helpful?</span>\n <button clx-button type=\"button\" variant=\"ghost\" color=\"slate\" size=\"xs\" icon=\"thumb_up\">{{ review.helpful }}</button>\n <button clx-button type=\"button\" variant=\"ghost\" color=\"slate\" size=\"xs\" icon=\"thumb_down\">{{ review.not_helpful }}</button>\n </div>\n </div>\n </div>\n }\n </div>\n\n </div>\n }\n\n </div>\n}\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ClxButtonComponent, selector: "button[clx-button], a[clx-button]", inputs: ["variant", "color", "textColor", "size", "shape", "loading", "disabled", "block", "icon", "iconPosition", "iconOnly", "badge", "badgeColor"] }, { kind: "component", type: ClxButtonGroupComponent, selector: "clx-button-group", inputs: ["label", "shape", "attached", "orientation"] }, { kind: "component", type: ClxBadgeComponent, selector: "span[clx-badge]", inputs: ["variant", "color", "size", "shape", "positioned"] }, { kind: "component", type: ClxIconComponent, selector: "span[clx-icon]", inputs: ["name", "size", "color", "fill"] }, { kind: "component", type: ClxSkeletonComponent, selector: "clx-skeleton", inputs: ["variant", "size", "width", "height"] }, { kind: "component", type: ClxRatingComponent, selector: "clx-rating", inputs: ["value", "max", "color"] }, { kind: "component", type: ClxCarouselComponent, selector: "clx-carousel", inputs: ["clxColor", "autoPlay", "interval", "loop", "aspectRatio", "transparent"] }, { kind: "directive", type: ClxCarouselDirective, selector: "[clxSlide]" }, { kind: "component", type: ClxTabsComponent, selector: "clx-tabs", inputs: ["tabs", "clxColor", "activeTab"], outputs: ["activeTabChange"] }, { kind: "directive", type: ClxTabDirective, selector: "[clxTabPanel]", inputs: ["clxTabPanel"] }, { kind: "component", type: ClxNumberComponent, selector: "clx-number", inputs: ["variant", "size", "color", "label", "placeholder", "hint", "prefixIcon", "min", "max", "step", "value", "disabled"] }, { kind: "directive", type: ClxTooltipDirective, selector: "[clxTooltip]", inputs: ["clxTooltip", "clxTooltipPosition", "clxTooltipColor", "clxTooltipSize", "clxTooltipDelay"] }, { kind: "component", type: ClxListComponent, selector: "clx-list", inputs: ["color", "variant", "size", "numbered"] }, { kind: "component", type: ClxListItemComponent, selector: "clx-list-item", inputs: ["label", "sublabel", "icon", "meta", "metaColor", "disabled"] }, { kind: "pipe", type: CurrencyPipe, name: "currency" }, { kind: "pipe", type: DecimalPipe, name: "number" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
14563
14536
  }
14564
14537
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxProductDetailComponent, decorators: [{
14565
14538
  type: Component,
@@ -14581,7 +14554,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
14581
14554
  ClxTooltipDirective,
14582
14555
  ClxListComponent,
14583
14556
  ClxListItemComponent,
14584
- ], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- \u2550\u2550 SKELETON \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n@if (loading()) {\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-8 p-6\">\n <div class=\"space-y-3\">\n <clx-skeleton variant=\"rectangular\" width=\"100%\" height=\"420px\" class=\"rounded-2xl\"></clx-skeleton>\n <div class=\"flex gap-2\">\n @for (t of [1,2,3,4]; track t) {\n <clx-skeleton variant=\"rectangular\" width=\"80px\" height=\"80px\" class=\"rounded-xl\"></clx-skeleton>\n }\n </div>\n </div>\n <div class=\"space-y-4 pt-2\">\n <clx-skeleton variant=\"text\" size=\"lg\" width=\"70%\"></clx-skeleton>\n <clx-skeleton variant=\"text\" size=\"sm\" width=\"40%\"></clx-skeleton>\n <clx-skeleton variant=\"text\" size=\"xl\" width=\"50%\"></clx-skeleton>\n <clx-skeleton variant=\"rectangular\" width=\"100%\" height=\"100px\" class=\"rounded-xl\"></clx-skeleton>\n <clx-skeleton variant=\"rectangular\" width=\"100%\" height=\"52px\" class=\"rounded-xl\"></clx-skeleton>\n <clx-skeleton variant=\"rectangular\" width=\"100%\" height=\"52px\" class=\"rounded-xl\"></clx-skeleton>\n </div>\n </div>\n}\n\n<!-- \u2550\u2550 CONTENT \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n@if (!loading() && product(); as p) {\n @let v = activeVariation();\n <div class=\"space-y-8\">\n\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-8 md:items-start\">\n\n <!-- \u2500\u2500 Column 1: Image Gallery \u2014 each column sizes to its own content (no forced equal\n height, no position:sticky). A `sticky` gallery reads great in isolation, but a host app\n that already has its own `position: sticky` header (a full-width top bar, as opposed to\n this library's own `clx-app-layout` sidebar, which is `fixed` and never competes) forces\n the browser to keep recomputing both stickies' viewport-relative offsets together on every\n resize \u2014 confirmed as the source of a persistent resize-lag bug in codexly-store's product\n page. Not worth reintroducing until sticky positioning is made robust to an arbitrary host\n header. \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"flex flex-col gap-3\">\n <div class=\"relative aspect-4/3\">\n <clx-carousel [clxColor]=\"clxColor()\" aspectRatio=\"4/3\" [loop]=\"true\">\n @for (img of v?.images ?? []; track i; let i = $index) {\n <ng-template clxSlide>\n <div class=\"w-full h-full p-5 sm:p-12.5 md:p-5 lg:p-12.5\">\n <img [src]=\"img\" [alt]=\"p.product_name\" class=\"w-full h-full object-contain\"\n [loading]=\"i === 0 ? 'eager' : 'lazy'\"\n [attr.fetchpriority]=\"i === 0 ? 'high' : null\" />\n </div>\n </ng-template>\n }\n </clx-carousel>\n <div class=\"absolute top-3 right-3 z-10\">\n <button clx-button type=\"button\" variant=\"solid\" [color]=\"clxColor()\" shape=\"circle\" size=\"md\"\n [iconOnly]=\"true\" clxTooltip=\"Agregar a favoritos\" [clxTooltipColor]=\"clxColor()\" clxTooltipPosition=\"left\"\n (click)=\"wishlist.emit()\">\n <span clx-icon name=\"favorite_border\" size=\"sm\"></span>\n </button>\n </div>\n </div>\n <div class=\"flex flex-wrap gap-2\">\n @for (img of v?.images ?? []; track i; let i = $index) {\n <img [src]=\"img\" [alt]=\"p.product_name\"\n class=\"w-20 h-20 rounded-xl object-cover border-[3px] cursor-pointer shrink-0 transition-[border-color,opacity]\"\n [class]=\"_carousel()?.currentPageIndex() === i\n ? 'border-' + clxColor() + '-500 opacity-100'\n : 'border-transparent opacity-60 hover:opacity-90'\"\n loading=\"lazy\"\n (click)=\"_carousel()?.goTo(i)\" />\n }\n </div>\n </div>\n\n <!-- \u2500\u2500 Column 2: Purchase Info \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"space-y-2.5\">\n\n <!-- Stock status -->\n @if (v) {\n <span clx-badge [variant]=\"v.in_stock ? 'light' : 'solid'\" [color]=\"v.in_stock ? clxColor() : 'green'\" size=\"sm\" shape=\"pill\">\n @if (v.in_stock) {\n @if (v.stock_quantity != null) {\n {{ v.stock_quantity }} en stock\n } @else {\n En stock\n }\n } @else {\n Sin stock\n }\n </span>\n }\n\n <!-- Tags (st_products.tags) -->\n <div class=\"flex flex-wrap gap-1\">\n @for (tag of p.tags; track tag) {\n <span clx-badge variant=\"light\" [color]=\"clxColor()\" size=\"sm\" shape=\"pill\">{{ tag }}</span>\n }\n </div>\n\n <!-- Title -->\n <div>\n <p class=\"text-sm text-clx-text-subtle uppercase tracking-wide font-medium\">{{ p.trademark }}</p>\n <h1 class=\"text-2xl font-bold text-clx-text-label leading-tight mt-0.5\">{{ v?.name || p.product_name }}</h1>\n @if (p.product_detail) {\n <p class=\"text-clx-text-muted text-sm mt-1\">{{ p.product_detail }}</p>\n }\n </div>\n\n <!-- Rating -->\n <div class=\"flex items-center gap-2\">\n <clx-rating [value]=\"p.rating\" [color]=\"clxColor()\"></clx-rating>\n <span class=\"text-sm font-semibold text-clx-text-label\">{{ p.rating | number:'1.1-1' }}</span>\n <span class=\"text-sm text-clx-text-subtle\">({{ p.review_count }} reviews)</span>\n </div>\n\n <!-- Price block -->\n <div>\n <div class=\"flex items-baseline gap-3\">\n <span class=\"text-2xl font-black text-clx-text-label\">\n {{ finalPrice() | currency:currency():'symbol':'1.0-0' }}\n </span>\n @if (p.has_discount && p.discount_price) {\n <span class=\"text-base text-clx-text-subtle line-through\">\n {{ p.discount_price | currency:currency():'symbol':'1.0-0' }}\n </span>\n <span clx-badge variant=\"solid\" [color]=\"clxColor()\" size=\"sm\" shape=\"pill\">\n -{{ discount() }}%\n </span>\n }\n </div>\n </div>\n\n <!-- Selectores de variaci\u00F3n (st_spec_types + st_spec_options) \u2014 opciones no disponibles\n para la combinaci\u00F3n actual (ej. Talla S con Color Rojo) se ocultan por completo en vez\n de mostrarse deshabilitadas; reaparecen si el usuario cambia a una combinaci\u00F3n donde s\u00ED\n aplican, ya que isOptionAvailable() se reeval\u00FAa contra selectedSpecs() en cada cambio. -->\n @for (specType of p.spec_types; track specType.id) {\n @if (specType.input_type === 'color') {\n <clx-button-group [label]=\"specType.name\" shape=\"circular\" [attached]=\"false\">\n @for (opt of specType.options; track opt.id) {\n @if (isOptionAvailable(specType.id, opt.id)) {\n <button\n type=\"button\"\n class=\"w-7 h-7 rounded-full border-2 transition-[transform,box-shadow] shrink-0 cursor-pointer\"\n [class]=\"isSpecSelected(specType.id, opt.id) ? 'scale-110 shadow-md' : 'opacity-90 hover:opacity-100'\"\n [style.background-color]=\"opt.value\"\n [style.border-color]=\"isSpecSelected(specType.id, opt.id) ? 'var(--clx-text-label, #111)' : 'transparent'\"\n [clxTooltip]=\"opt.label ?? opt.value\"\n clxTooltipPosition=\"top\"\n (click)=\"selectSpec(specType.id, opt.id)\">\n </button>\n }\n }\n </clx-button-group>\n } @else {\n <clx-button-group [label]=\"specType.name\" shape=\"flat\" [attached]=\"false\">\n @for (opt of specType.options; track opt.id) {\n @if (isOptionAvailable(specType.id, opt.id)) {\n <button clx-button\n type=\"button\"\n [variant]=\"isSpecSelected(specType.id, opt.id) ? 'solid' : 'outline'\"\n [color]=\"clxColor()\" size=\"sm\"\n (click)=\"selectSpec(specType.id, opt.id)\">\n {{ opt.label ?? opt.value }}\n </button>\n }\n }\n </clx-button-group>\n }\n }\n\n <!-- Quantity -->\n <clx-number label=\"Quantity:\" variant=\"stepper\" [color]=\"clxColor()\"\n [min]=\"1\" [max]=\"99\" [ngModel]=\"quantity()\" (ngModelChange)=\"quantity.set($event)\">\n </clx-number>\n\n <!-- CTA -->\n <div class=\"flex gap-3\">\n <button clx-button type=\"button\" variant=\"solid\" [color]=\"clxColor()\" size=\"md\" [block]=\"true\" icon=\"bolt\"\n [disabled]=\"!v?.in_stock\" (click)=\"_emitBuyNow()\">Comprar ahora</button>\n <button clx-button type=\"button\" variant=\"light\" [color]=\"clxColor()\" size=\"md\" [block]=\"true\" icon=\"shopping_cart\"\n [disabled]=\"!v?.in_stock\" (click)=\"_emitAddToCart()\">Agrega al carrito</button>\n </div>\n\n </div>\n </div>\n\n @if (!compact()) {\n <!-- \u2500\u2500 Tabs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <clx-tabs [tabs]=\"tabItems\" [clxColor]=\"clxColor()\" [(activeTab)]=\"activeTab\">\n\n <!-- Tab: Caracter\u00EDsticas generales (st_product_specs \u2014 ficha t\u00E9cnica global) -->\n <ng-template [clxTabPanel]=\"'general'\">\n <div class=\"grid grid-cols-1 sm:grid-cols-2 gap-x-8\">\n <clx-list [color]=\"clxColor()\" variant=\"flush\" size=\"sm\">\n @for (spec of specsLeft(p.product_specs); track spec.id) {\n <clx-list-item [icon]=\"spec.icon ?? ''\">\n <div clxContent>\n <p class=\"text-sm font-medium text-clx-text-label\">{{ spec.name }}:</p>\n <p class=\"text-sm text-clx-text-muted mt-0.5\">{{ spec.value }}</p>\n </div>\n </clx-list-item>\n }\n </clx-list>\n <clx-list [color]=\"clxColor()\" variant=\"flush\" size=\"sm\">\n @for (spec of specsRight(p.product_specs); track spec.id) {\n <clx-list-item [icon]=\"spec.icon ?? ''\">\n <div clxContent>\n <p class=\"text-sm font-medium text-clx-text-label\">{{ spec.name }}:</p>\n <p class=\"text-sm text-clx-text-muted mt-0.5\">{{ spec.value }}</p>\n </div>\n </clx-list-item>\n }\n </clx-list>\n </div>\n </ng-template>\n\n <!-- Tab: Especificaciones (st_spec_types \u2014 specs de la variaci\u00F3n activa) -->\n <ng-template [clxTabPanel]=\"'specs'\">\n <div class=\"grid grid-cols-1 sm:grid-cols-2 gap-x-8\">\n <clx-list [color]=\"clxColor()\" variant=\"flush\" size=\"sm\">\n @for (st of specsLeft(p.spec_types); track st.id) {\n <clx-list-item [label]=\"st.name + ':'\" [sublabel]=\"selectedOptionLabel(st)\" [icon]=\"st.icon ?? ''\" />\n }\n </clx-list>\n <clx-list [color]=\"clxColor()\" variant=\"flush\" size=\"sm\">\n @for (st of specsRight(p.spec_types); track st.id) {\n <clx-list-item [label]=\"st.name + ':'\" [sublabel]=\"selectedOptionLabel(st)\" [icon]=\"st.icon ?? ''\" />\n }\n </clx-list>\n </div>\n </ng-template>\n\n <!-- Tab: Descripci\u00F3n (st_product_descriptions) -->\n <ng-template [clxTabPanel]=\"'description'\">\n <div class=\"space-y-5\">\n @for (block of p.descriptions; track block.id) {\n <div>\n @if (block.title) {\n <h3 class=\"text-base font-semibold text-clx-text-label mb-1\">{{ block.title }}</h3>\n }\n <p class=\"text-sm text-clx-text-muted leading-relaxed\">{{ block.body }}</p>\n </div>\n }\n </div>\n </ng-template>\n\n </clx-tabs>\n\n <!-- \u2500\u2500 Reviews \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"grid grid-cols-1 xl:grid-cols-3 gap-8 border-t border-clx-border pt-8\">\n\n <div class=\"space-y-3\">\n <h2 class=\"text-base font-bold text-clx-text-label\">Customer Reviews</h2>\n <div class=\"flex items-end gap-3\">\n <span class=\"text-5xl font-black text-clx-text-label\">{{ p.rating | number:'1.1-1' }}</span>\n <div class=\"pb-1 space-y-1\">\n <clx-rating [value]=\"p.rating\" [color]=\"clxColor()\"></clx-rating>\n <p class=\"text-xs text-clx-text-muted\">{{ p.review_count }} verified ratings</p>\n </div>\n </div>\n <p class=\"text-sm font-semibold\" [class]=\"'text-' + clxColor() + '-600'\">Very Good</p>\n <div class=\"pt-2 space-y-2\">\n <button clx-button type=\"button\" variant=\"solid\" [color]=\"clxColor()\" size=\"md\" [block]=\"true\" icon=\"rate_review\">\n Leave Us a Review\n </button>\n <button clx-button type=\"button\" variant=\"light\" [color]=\"clxColor()\" size=\"md\" [block]=\"true\" icon=\"flag\">\n Report abuse\n </button>\n </div>\n </div>\n\n <div class=\"lg:col-span-2 space-y-4\">\n @for (review of p.reviews ?? []; track review.id) {\n <div class=\"rounded-2xl overflow-hidden shadow-sm\">\n <div class=\"flex items-center gap-3 px-4 py-3\">\n <div class=\"w-10 h-10 rounded-full bg-clx-surface-2 flex items-center justify-center shrink-0\">\n <span class=\"text-sm font-bold text-clx-text-muted\">\n {{ review.author_name.substring(0,1) }}{{ review.author_name.split(' ')[1]?.substring(0,1) ?? '' }}\n </span>\n </div>\n <div class=\"flex-1 min-w-0\">\n <p class=\"font-semibold text-sm text-clx-text-label truncate\">{{ review.author_name }}</p>\n <p class=\"text-xs text-clx-text-subtle\">{{ review.created_at }}</p>\n </div>\n @if (review.is_verified) {\n <span clx-badge variant=\"light\" color=\"emerald\" size=\"sm\" shape=\"pill\">Verified</span>\n }\n </div>\n <div class=\"px-4 pb-4 space-y-2\">\n <div class=\"flex items-center gap-2\">\n <clx-rating [value]=\"review.rating\" [color]=\"clxColor()\"></clx-rating>\n @if (review.title) {\n <span class=\"text-sm font-semibold text-clx-text-label\">{{ review.title }}</span>\n }\n </div>\n @if (review.body) {\n <p class=\"text-sm text-clx-text-muted\">{{ review.body }}</p>\n }\n <div class=\"flex items-center gap-3 pt-1\">\n <span class=\"text-xs text-clx-text-subtle\">Helpful?</span>\n <button clx-button type=\"button\" variant=\"ghost\" color=\"slate\" size=\"xs\" icon=\"thumb_up\">{{ review.helpful }}</button>\n <button clx-button type=\"button\" variant=\"ghost\" color=\"slate\" size=\"xs\" icon=\"thumb_down\">{{ review.not_helpful }}</button>\n </div>\n </div>\n </div>\n }\n </div>\n\n </div>\n }\n\n </div>\n}\n" }]
14557
+ ], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- \u2550\u2550 SKELETON \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n@if (loading()) {\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-8 p-6\">\n <div class=\"space-y-3\">\n <clx-skeleton variant=\"rectangular\" width=\"100%\" height=\"420px\" class=\"rounded-2xl\"></clx-skeleton>\n <div class=\"flex gap-2\">\n @for (t of [1,2,3,4]; track t) {\n <clx-skeleton variant=\"rectangular\" width=\"80px\" height=\"80px\" class=\"rounded-xl\"></clx-skeleton>\n }\n </div>\n </div>\n <div class=\"space-y-4 pt-2\">\n <clx-skeleton variant=\"text\" size=\"lg\" width=\"70%\"></clx-skeleton>\n <clx-skeleton variant=\"text\" size=\"sm\" width=\"40%\"></clx-skeleton>\n <clx-skeleton variant=\"text\" size=\"xl\" width=\"50%\"></clx-skeleton>\n <clx-skeleton variant=\"rectangular\" width=\"100%\" height=\"100px\" class=\"rounded-xl\"></clx-skeleton>\n <clx-skeleton variant=\"rectangular\" width=\"100%\" height=\"52px\" class=\"rounded-xl\"></clx-skeleton>\n <clx-skeleton variant=\"rectangular\" width=\"100%\" height=\"52px\" class=\"rounded-xl\"></clx-skeleton>\n </div>\n </div>\n}\n\n<!-- \u2550\u2550 CONTENT \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 -->\n@if (!loading() && product(); as p) {\n @let v = activeVariation();\n <div class=\"space-y-8\">\n\n <div class=\"grid grid-cols-1 md:grid-cols-2 gap-8 md:items-start\">\n\n <!-- \u2500\u2500 Column 1: Image Gallery \u2014 each column sizes to its own content (no forced equal\n height, no position:sticky). A `sticky` gallery reads great in isolation, but a host app\n that already has its own `position: sticky` header (a full-width top bar, as opposed to\n this library's own `clx-app-layout` sidebar, which is `fixed` and never competes) forces\n the browser to keep recomputing both stickies' viewport-relative offsets together on every\n resize \u2014 confirmed as the source of a persistent resize-lag bug in codexly-store's product\n page. Not worth reintroducing until sticky positioning is made robust to an arbitrary host\n header. \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"flex flex-col gap-3\">\n <div class=\"relative aspect-4/3\">\n <clx-carousel [clxColor]=\"clxColor()\" aspectRatio=\"4/3\" [loop]=\"true\">\n @for (img of v?.images ?? []; track i; let i = $index) {\n <ng-template clxSlide>\n <div class=\"w-full h-full p-5 sm:p-12.5 md:p-5 lg:p-12.5\">\n <img [src]=\"img\" [alt]=\"p.product_name\" class=\"w-full h-full object-contain\"\n [loading]=\"i === 0 ? 'eager' : 'lazy'\"\n [attr.fetchpriority]=\"i === 0 ? 'high' : null\" />\n </div>\n </ng-template>\n }\n </clx-carousel>\n <div class=\"absolute top-3 right-3 z-10\">\n <button clx-button type=\"button\" variant=\"solid\" [color]=\"clxColor()\" shape=\"circle\" size=\"md\"\n [iconOnly]=\"true\" clxTooltip=\"Agregar a favoritos\" [clxTooltipColor]=\"clxColor()\" clxTooltipPosition=\"left\"\n (click)=\"wishlist.emit()\">\n <span clx-icon name=\"favorite_border\" size=\"sm\"></span>\n </button>\n </div>\n </div>\n <div class=\"flex flex-wrap gap-2\">\n @for (img of v?.images ?? []; track i; let i = $index) {\n <img [src]=\"img\" [alt]=\"p.product_name\"\n class=\"w-20 h-20 rounded-xl object-cover border-[3px] cursor-pointer shrink-0 transition-[border-color,opacity]\"\n [class]=\"_carousel()?.currentPageIndex() === i\n ? 'border-' + clxColor() + '-500 opacity-100'\n : 'border-transparent opacity-60 hover:opacity-90'\"\n loading=\"lazy\"\n (click)=\"_carousel()?.goTo(i)\" />\n }\n </div>\n </div>\n\n <!-- \u2500\u2500 Column 2: Purchase Info \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"space-y-2.5\">\n\n <!-- Stock status -->\n @if (v) {\n <span clx-badge [variant]=\"v.in_stock ? 'light' : 'solid'\" [color]=\"v.in_stock ? clxColor() : 'green'\" size=\"sm\" shape=\"pill\">\n @if (v.in_stock) {\n @if (v.stock_quantity != null) {\n {{ v.stock_quantity }} en stock\n } @else {\n En stock\n }\n } @else {\n Sin stock\n }\n </span>\n }\n\n <!-- Tags (st_products.tags) -->\n <div class=\"flex flex-wrap gap-1\">\n @for (tag of p.tags; track tag) {\n <span clx-badge variant=\"light\" [color]=\"clxColor()\" size=\"sm\" shape=\"pill\">{{ tag }}</span>\n }\n </div>\n\n <!-- Title -->\n <div>\n <p class=\"text-sm text-clx-text-subtle uppercase tracking-wide font-medium\">{{ p.trademark }}</p>\n <h1 class=\"text-2xl font-bold text-clx-text-label leading-tight mt-0.5\">{{ v?.name || p.product_name }}</h1>\n @if (p.product_detail) {\n <p class=\"text-clx-text-muted text-sm mt-1\">{{ p.product_detail }}</p>\n }\n </div>\n\n <!-- Rating -->\n <div class=\"flex items-center gap-2\">\n <clx-rating [value]=\"p.rating\" [color]=\"clxColor()\"></clx-rating>\n <span class=\"text-sm font-semibold text-clx-text-label\">{{ p.rating | number:'1.1-1' }}</span>\n <span class=\"text-sm text-clx-text-subtle\">({{ p.review_count }} reviews)</span>\n </div>\n\n <!-- Price block -->\n <div>\n <div class=\"flex items-baseline gap-3\">\n <span class=\"text-2xl font-black text-clx-text-label\">\n {{ finalPrice() | currency:currency():'$':'1.0-0' }}\n </span>\n @if (p.has_discount && p.discount_price) {\n <span class=\"text-base text-clx-text-subtle line-through\">\n {{ p.discount_price | currency:currency():'$':'1.0-0' }}\n </span>\n <span clx-badge variant=\"solid\" [color]=\"clxColor()\" size=\"sm\" shape=\"pill\">\n -{{ discount() }}%\n </span>\n }\n </div>\n </div>\n\n <!-- Selectores de variaci\u00F3n (st_spec_types + st_spec_options) \u2014 opciones no disponibles\n para la combinaci\u00F3n actual (ej. Talla S con Color Rojo) se ocultan por completo en vez\n de mostrarse deshabilitadas; reaparecen si el usuario cambia a una combinaci\u00F3n donde s\u00ED\n aplican, ya que isOptionAvailable() se reeval\u00FAa contra selectedSpecs() en cada cambio. -->\n @for (specType of p.spec_types; track specType.id) {\n @if (specType.input_type === 'color') {\n <clx-button-group [label]=\"specType.name\" shape=\"circular\" [attached]=\"false\">\n @for (opt of specType.options; track opt.id) {\n @if (isOptionAvailable(specType.id, opt.id)) {\n <button\n type=\"button\"\n class=\"w-7 h-7 rounded-full border-2 transition-[transform,box-shadow] shrink-0 cursor-pointer\"\n [class]=\"isSpecSelected(specType.id, opt.id) ? 'scale-110 shadow-md' : 'opacity-90 hover:opacity-100'\"\n [style.background-color]=\"opt.value\"\n [style.border-color]=\"isSpecSelected(specType.id, opt.id) ? 'var(--clx-text-label, #111)' : 'transparent'\"\n [clxTooltip]=\"opt.label ?? opt.value\"\n clxTooltipPosition=\"top\"\n (click)=\"selectSpec(specType.id, opt.id)\">\n </button>\n }\n }\n </clx-button-group>\n } @else {\n <clx-button-group [label]=\"specType.name\" shape=\"flat\" [attached]=\"false\">\n @for (opt of specType.options; track opt.id) {\n @if (isOptionAvailable(specType.id, opt.id)) {\n <button clx-button\n type=\"button\"\n [variant]=\"isSpecSelected(specType.id, opt.id) ? 'solid' : 'outline'\"\n [color]=\"clxColor()\" size=\"sm\"\n (click)=\"selectSpec(specType.id, opt.id)\">\n {{ opt.label ?? opt.value }}\n </button>\n }\n }\n </clx-button-group>\n }\n }\n\n <!-- Quantity -->\n <clx-number label=\"Quantity:\" variant=\"stepper\" [color]=\"clxColor()\"\n [min]=\"1\" [max]=\"99\" [ngModel]=\"quantity()\" (ngModelChange)=\"quantity.set($event)\">\n </clx-number>\n\n <!-- CTA -->\n <div class=\"flex gap-3\">\n <button clx-button type=\"button\" variant=\"solid\" [color]=\"clxColor()\" size=\"md\" [block]=\"true\" icon=\"bolt\"\n [disabled]=\"!v?.in_stock\" (click)=\"_emitBuyNow()\">Comprar ahora</button>\n <button clx-button type=\"button\" variant=\"light\" [color]=\"clxColor()\" size=\"md\" [block]=\"true\" icon=\"shopping_cart\"\n [disabled]=\"!v?.in_stock\" (click)=\"_emitAddToCart()\">Agrega al carrito</button>\n </div>\n\n </div>\n </div>\n\n @if (!compact()) {\n <!-- \u2500\u2500 Tabs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <clx-tabs [tabs]=\"tabItems\" [clxColor]=\"clxColor()\" [(activeTab)]=\"activeTab\">\n\n <!-- Tab: Caracter\u00EDsticas generales (st_product_specs \u2014 ficha t\u00E9cnica global) -->\n <ng-template [clxTabPanel]=\"'general'\">\n <div class=\"grid grid-cols-1 sm:grid-cols-2 gap-x-8\">\n <clx-list [color]=\"clxColor()\" variant=\"flush\" size=\"sm\">\n @for (spec of specsLeft(p.product_specs); track spec.id) {\n <clx-list-item [icon]=\"spec.icon ?? ''\">\n <div clxContent>\n <p class=\"text-sm font-medium text-clx-text-label\">{{ spec.name }}:</p>\n <p class=\"text-sm text-clx-text-muted mt-0.5\">{{ spec.value }}</p>\n </div>\n </clx-list-item>\n }\n </clx-list>\n <clx-list [color]=\"clxColor()\" variant=\"flush\" size=\"sm\">\n @for (spec of specsRight(p.product_specs); track spec.id) {\n <clx-list-item [icon]=\"spec.icon ?? ''\">\n <div clxContent>\n <p class=\"text-sm font-medium text-clx-text-label\">{{ spec.name }}:</p>\n <p class=\"text-sm text-clx-text-muted mt-0.5\">{{ spec.value }}</p>\n </div>\n </clx-list-item>\n }\n </clx-list>\n </div>\n </ng-template>\n\n <!-- Tab: Especificaciones (st_spec_types \u2014 specs de la variaci\u00F3n activa) -->\n <ng-template [clxTabPanel]=\"'specs'\">\n <div class=\"grid grid-cols-1 sm:grid-cols-2 gap-x-8\">\n <clx-list [color]=\"clxColor()\" variant=\"flush\" size=\"sm\">\n @for (st of specsLeft(p.spec_types); track st.id) {\n <clx-list-item [label]=\"st.name + ':'\" [sublabel]=\"selectedOptionLabel(st)\" [icon]=\"st.icon ?? ''\" />\n }\n </clx-list>\n <clx-list [color]=\"clxColor()\" variant=\"flush\" size=\"sm\">\n @for (st of specsRight(p.spec_types); track st.id) {\n <clx-list-item [label]=\"st.name + ':'\" [sublabel]=\"selectedOptionLabel(st)\" [icon]=\"st.icon ?? ''\" />\n }\n </clx-list>\n </div>\n </ng-template>\n\n <!-- Tab: Descripci\u00F3n (st_product_descriptions) -->\n <ng-template [clxTabPanel]=\"'description'\">\n <div class=\"space-y-5\">\n @for (block of p.descriptions; track block.id) {\n <div>\n @if (block.title) {\n <h3 class=\"text-base font-semibold text-clx-text-label mb-1\">{{ block.title }}</h3>\n }\n <p class=\"text-sm text-clx-text-muted leading-relaxed\">{{ block.body }}</p>\n </div>\n }\n </div>\n </ng-template>\n\n </clx-tabs>\n\n <!-- \u2500\u2500 Reviews \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 -->\n <div class=\"grid grid-cols-1 xl:grid-cols-3 gap-8 border-t border-clx-border pt-8\">\n\n <div class=\"space-y-3\">\n <h2 class=\"text-base font-bold text-clx-text-label\">Customer Reviews</h2>\n <div class=\"flex items-end gap-3\">\n <span class=\"text-5xl font-black text-clx-text-label\">{{ p.rating | number:'1.1-1' }}</span>\n <div class=\"pb-1 space-y-1\">\n <clx-rating [value]=\"p.rating\" [color]=\"clxColor()\"></clx-rating>\n <p class=\"text-xs text-clx-text-muted\">{{ p.review_count }} verified ratings</p>\n </div>\n </div>\n <p class=\"text-sm font-semibold\" [class]=\"'text-' + clxColor() + '-600'\">Very Good</p>\n <div class=\"pt-2 space-y-2\">\n <button clx-button type=\"button\" variant=\"solid\" [color]=\"clxColor()\" size=\"md\" [block]=\"true\" icon=\"rate_review\">\n Leave Us a Review\n </button>\n <button clx-button type=\"button\" variant=\"light\" [color]=\"clxColor()\" size=\"md\" [block]=\"true\" icon=\"flag\">\n Report abuse\n </button>\n </div>\n </div>\n\n <div class=\"lg:col-span-2 space-y-4\">\n @for (review of p.reviews ?? []; track review.id) {\n <div class=\"rounded-2xl overflow-hidden shadow-sm\">\n <div class=\"flex items-center gap-3 px-4 py-3\">\n <div class=\"w-10 h-10 rounded-full bg-clx-surface-2 flex items-center justify-center shrink-0\">\n <span class=\"text-sm font-bold text-clx-text-muted\">\n {{ review.author_name.substring(0,1) }}{{ review.author_name.split(' ')[1]?.substring(0,1) ?? '' }}\n </span>\n </div>\n <div class=\"flex-1 min-w-0\">\n <p class=\"font-semibold text-sm text-clx-text-label truncate\">{{ review.author_name }}</p>\n <p class=\"text-xs text-clx-text-subtle\">{{ review.created_at }}</p>\n </div>\n @if (review.is_verified) {\n <span clx-badge variant=\"light\" color=\"emerald\" size=\"sm\" shape=\"pill\">Verified</span>\n }\n </div>\n <div class=\"px-4 pb-4 space-y-2\">\n <div class=\"flex items-center gap-2\">\n <clx-rating [value]=\"review.rating\" [color]=\"clxColor()\"></clx-rating>\n @if (review.title) {\n <span class=\"text-sm font-semibold text-clx-text-label\">{{ review.title }}</span>\n }\n </div>\n @if (review.body) {\n <p class=\"text-sm text-clx-text-muted\">{{ review.body }}</p>\n }\n <div class=\"flex items-center gap-3 pt-1\">\n <span class=\"text-xs text-clx-text-subtle\">Helpful?</span>\n <button clx-button type=\"button\" variant=\"ghost\" color=\"slate\" size=\"xs\" icon=\"thumb_up\">{{ review.helpful }}</button>\n <button clx-button type=\"button\" variant=\"ghost\" color=\"slate\" size=\"xs\" icon=\"thumb_down\">{{ review.not_helpful }}</button>\n </div>\n </div>\n </div>\n }\n </div>\n\n </div>\n }\n\n </div>\n}\n" }]
14585
14558
  }], ctorParameters: () => [], propDecorators: { product: [{ type: i0.Input, args: [{ isSignal: true, alias: "product", required: false }] }], initialVariationId: [{ type: i0.Input, args: [{ isSignal: true, alias: "initialVariationId", required: false }] }], clxColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "clxColor", required: false }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], currency: [{ type: i0.Input, args: [{ isSignal: true, alias: "currency", required: false }] }], compact: [{ type: i0.Input, args: [{ isSignal: true, alias: "compact", required: false }] }], addToCart: [{ type: i0.Output, args: ["addToCart"] }], buyNow: [{ type: i0.Output, args: ["buyNow"] }], wishlist: [{ type: i0.Output, args: ["wishlist"] }], variationChange: [{ type: i0.Output, args: ["variationChange"] }], _carousel: [{ type: i0.ViewChild, args: [i0.forwardRef(() => ClxCarouselComponent), { isSignal: true }] }] } });
14586
14559
 
14587
14560
  class ClxProductQuickViewComponent {
@@ -14758,22 +14731,19 @@ class ClxWishlistComponent {
14758
14731
  <!-- ── Info Bar ─────────────────────────────────────────────────────── -->
14759
14732
  <div class="flex flex-col sm:flex-row sm:items-center justify-between gap-3">
14760
14733
  <div class="flex items-center gap-2">
14761
- <span class="text-clx-text-muted text-sm">Adding</span>
14762
- <span class="font-bold text-clx-text-label text-sm">{{ _totalItems() }}</span>
14763
- <span clx-badge variant="light" [color]="color()" size="sm">items</span>
14764
- <span class="text-clx-text-muted text-sm">to your wishlist</span>
14734
+ <h2 class="text-base font-semibold text-clx-text-label">Productos</h2>
14735
+ <span clx-badge variant="light" [color]="color()" size="sm">{{ _totalItems() }}</span>
14765
14736
  </div>
14766
14737
  <button
14767
14738
  clx-button
14768
14739
  type="button"
14769
14740
  variant="light"
14770
14741
  [color]="color()"
14771
- size="sm"
14772
14742
  icon="arrow_forward"
14773
14743
  iconPosition="right"
14774
14744
  [disabled]="_totalItems() === 0"
14775
14745
  (click)="handleCheckoutAll()"
14776
- >Checkout All</button>
14746
+ >Agregar todo al carrito</button>
14777
14747
  </div>
14778
14748
 
14779
14749
  <!-- ── List ─────────────────────────────────────────────────────────── -->
@@ -14797,11 +14767,14 @@ class ClxWishlistComponent {
14797
14767
 
14798
14768
  } @else if (_pagedItems().length === 0) {
14799
14769
 
14800
- <div class="flex flex-col items-center justify-center py-20 gap-4 text-clx-text-subtle">
14801
- <span clx-icon name="heart_broken" size="xl"></span>
14802
- <p class="text-base font-medium">Your wishlist is empty</p>
14803
- <p class="text-sm">Start adding items you love!</p>
14804
- </div>
14770
+ <clx-page-empty
14771
+ icon="favorite"
14772
+ title="Sin favoritos"
14773
+ description="No tienes productos guardados."
14774
+ [ctaColor]="color()"
14775
+ ctaIcon="storefront"
14776
+ ctaLabel="Ir a la tienda">
14777
+ </clx-page-empty>
14805
14778
 
14806
14779
  } @else {
14807
14780
 
@@ -14845,10 +14818,10 @@ class ClxWishlistComponent {
14845
14818
 
14846
14819
  <!-- Price -->
14847
14820
  <div class="flex items-baseline gap-2 mt-2">
14848
- <span [class]="_priceClass">{{ (item.sale_price ?? item.product_sale_price) | currency:'COP':'symbol':'1.0-0' }}</span>
14821
+ <span [class]="_priceClass">{{ (item.sale_price ?? item.product_sale_price) | currency:'COP':'$':'1.0-0' }}</span>
14849
14822
  @if (item.has_discount && item.discount_price) {
14850
14823
  <span class="text-sm text-clx-text-subtle line-through">
14851
- {{ item.discount_price | currency:'COP':'symbol':'1.0-0' }}
14824
+ {{ item.discount_price | currency:'COP':'$':'1.0-0' }}
14852
14825
  </span>
14853
14826
  }
14854
14827
  </div>
@@ -14910,7 +14883,7 @@ class ClxWishlistComponent {
14910
14883
  }
14911
14884
 
14912
14885
  </div>
14913
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ClxButtonComponent, selector: "button[clx-button], a[clx-button]", inputs: ["variant", "color", "textColor", "size", "shape", "loading", "disabled", "block", "icon", "iconPosition", "iconOnly", "badge", "badgeColor"] }, { kind: "component", type: ClxBadgeComponent, selector: "span[clx-badge]", inputs: ["variant", "color", "size", "shape", "positioned"] }, { kind: "component", type: ClxIconComponent, selector: "span[clx-icon]", inputs: ["name", "size", "color", "fill"] }, { kind: "component", type: ClxSkeletonComponent, selector: "clx-skeleton", inputs: ["variant", "size", "width", "height"] }, { kind: "component", type: ClxPaginationComponent, selector: "clx-pagination", inputs: ["totalItems", "color", "size", "showPageSize", "pageSizeOptions", "currentPage", "pageSize"], outputs: ["currentPageChange", "pageSizeChange", "pageChange", "sizeChange"] }, { kind: "component", type: ClxInputComponent, selector: "clx-input", inputs: ["label", "placeholder", "type", "color", "hint", "prefixIcon", "suffixIcon", "prefixText", "suffixText", "status", "statusMessage", "size", "value", "disabled", "autocomplete"] }, { kind: "component", type: ClxSelectComponent, selector: "clx-select", inputs: ["label", "placeholder", "options", "multiple", "searchable", "searchPlaceholder", "activeColor", "size", "hint", "errorMessage", "disabled", "async", "loadOptions", "debounceMs", "minChars"] }, { kind: "directive", type: ClxTooltipDirective, selector: "[clxTooltip]", inputs: ["clxTooltip", "clxTooltipPosition", "clxTooltipColor", "clxTooltipSize", "clxTooltipDelay"] }, { kind: "pipe", type: CurrencyPipe, name: "currency" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
14886
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ClxButtonComponent, selector: "button[clx-button], a[clx-button]", inputs: ["variant", "color", "textColor", "size", "shape", "loading", "disabled", "block", "icon", "iconPosition", "iconOnly", "badge", "badgeColor"] }, { kind: "component", type: ClxBadgeComponent, selector: "span[clx-badge]", inputs: ["variant", "color", "size", "shape", "positioned"] }, { kind: "component", type: ClxSkeletonComponent, selector: "clx-skeleton", inputs: ["variant", "size", "width", "height"] }, { kind: "component", type: ClxPaginationComponent, selector: "clx-pagination", inputs: ["totalItems", "color", "size", "showPageSize", "pageSizeOptions", "currentPage", "pageSize"], outputs: ["currentPageChange", "pageSizeChange", "pageChange", "sizeChange"] }, { kind: "component", type: ClxInputComponent, selector: "clx-input", inputs: ["label", "placeholder", "type", "color", "hint", "prefixIcon", "suffixIcon", "prefixText", "suffixText", "status", "statusMessage", "size", "value", "disabled", "autocomplete"] }, { kind: "component", type: ClxSelectComponent, selector: "clx-select", inputs: ["label", "placeholder", "options", "multiple", "searchable", "searchPlaceholder", "activeColor", "size", "hint", "errorMessage", "disabled", "async", "loadOptions", "debounceMs", "minChars"] }, { kind: "directive", type: ClxTooltipDirective, selector: "[clxTooltip]", inputs: ["clxTooltip", "clxTooltipPosition", "clxTooltipColor", "clxTooltipSize", "clxTooltipDelay"] }, { kind: "component", type: ClxPageEmptyComponent, selector: "clx-page-empty", inputs: ["icon", "title", "description", "ctaLabel", "ctaIcon", "ctaColor"], outputs: ["cta"] }, { kind: "pipe", type: CurrencyPipe, name: "currency" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
14914
14887
  }
14915
14888
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxWishlistComponent, decorators: [{
14916
14889
  type: Component,
@@ -14922,12 +14895,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
14922
14895
  FormsModule,
14923
14896
  ClxButtonComponent,
14924
14897
  ClxBadgeComponent,
14925
- ClxIconComponent,
14926
14898
  ClxSkeletonComponent,
14927
14899
  ClxPaginationComponent,
14928
14900
  ClxInputComponent,
14929
14901
  ClxSelectComponent,
14930
- ClxTooltipDirective
14902
+ ClxTooltipDirective,
14903
+ ClxPageEmptyComponent
14931
14904
  ],
14932
14905
  template: `
14933
14906
  <div class="flex flex-col gap-6">
@@ -14960,22 +14933,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
14960
14933
  <!-- ── Info Bar ─────────────────────────────────────────────────────── -->
14961
14934
  <div class="flex flex-col sm:flex-row sm:items-center justify-between gap-3">
14962
14935
  <div class="flex items-center gap-2">
14963
- <span class="text-clx-text-muted text-sm">Adding</span>
14964
- <span class="font-bold text-clx-text-label text-sm">{{ _totalItems() }}</span>
14965
- <span clx-badge variant="light" [color]="color()" size="sm">items</span>
14966
- <span class="text-clx-text-muted text-sm">to your wishlist</span>
14936
+ <h2 class="text-base font-semibold text-clx-text-label">Productos</h2>
14937
+ <span clx-badge variant="light" [color]="color()" size="sm">{{ _totalItems() }}</span>
14967
14938
  </div>
14968
14939
  <button
14969
14940
  clx-button
14970
14941
  type="button"
14971
14942
  variant="light"
14972
14943
  [color]="color()"
14973
- size="sm"
14974
14944
  icon="arrow_forward"
14975
14945
  iconPosition="right"
14976
14946
  [disabled]="_totalItems() === 0"
14977
14947
  (click)="handleCheckoutAll()"
14978
- >Checkout All</button>
14948
+ >Agregar todo al carrito</button>
14979
14949
  </div>
14980
14950
 
14981
14951
  <!-- ── List ─────────────────────────────────────────────────────────── -->
@@ -14999,11 +14969,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
14999
14969
 
15000
14970
  } @else if (_pagedItems().length === 0) {
15001
14971
 
15002
- <div class="flex flex-col items-center justify-center py-20 gap-4 text-clx-text-subtle">
15003
- <span clx-icon name="heart_broken" size="xl"></span>
15004
- <p class="text-base font-medium">Your wishlist is empty</p>
15005
- <p class="text-sm">Start adding items you love!</p>
15006
- </div>
14972
+ <clx-page-empty
14973
+ icon="favorite"
14974
+ title="Sin favoritos"
14975
+ description="No tienes productos guardados."
14976
+ [ctaColor]="color()"
14977
+ ctaIcon="storefront"
14978
+ ctaLabel="Ir a la tienda">
14979
+ </clx-page-empty>
15007
14980
 
15008
14981
  } @else {
15009
14982
 
@@ -15047,10 +15020,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
15047
15020
 
15048
15021
  <!-- Price -->
15049
15022
  <div class="flex items-baseline gap-2 mt-2">
15050
- <span [class]="_priceClass">{{ (item.sale_price ?? item.product_sale_price) | currency:'COP':'symbol':'1.0-0' }}</span>
15023
+ <span [class]="_priceClass">{{ (item.sale_price ?? item.product_sale_price) | currency:'COP':'$':'1.0-0' }}</span>
15051
15024
  @if (item.has_discount && item.discount_price) {
15052
15025
  <span class="text-sm text-clx-text-subtle line-through">
15053
- {{ item.discount_price | currency:'COP':'symbol':'1.0-0' }}
15026
+ {{ item.discount_price | currency:'COP':'$':'1.0-0' }}
15054
15027
  </span>
15055
15028
  }
15056
15029
  </div>
@@ -15190,11 +15163,14 @@ class ClxCartComponent {
15190
15163
  <!-- ── Empty ───────────────────────────────────────────────────────────────── -->
15191
15164
  } @else if (items().length === 0) {
15192
15165
 
15193
- <div class="flex flex-col items-center justify-center py-24 gap-4 text-clx-text-subtle">
15194
- <span clx-icon name="shopping_cart" size="xl"></span>
15195
- <p class="text-base font-semibold text-clx-text-muted">Tu carrito está vacío</p>
15196
- <p class="text-sm">Agrega productos para continuar.</p>
15197
- </div>
15166
+ <clx-page-empty
15167
+ icon="remove_shopping_cart"
15168
+ title="Carrito vacio"
15169
+ description="Tu carrito esta vacio. Agrega productos para continuar."
15170
+ [ctaColor]="color()"
15171
+ ctaIcon="storefront"
15172
+ ctaLabel="Ir a la tienda">
15173
+ </clx-page-empty>
15198
15174
 
15199
15175
  <!-- ── Main layout ─────────────────────────────────────────────────────────── -->
15200
15176
  } @else {
@@ -15207,19 +15183,19 @@ class ClxCartComponent {
15207
15183
  <!-- Top bar -->
15208
15184
  <div class="flex items-center justify-between">
15209
15185
  <div class="flex items-center gap-2">
15210
- <h2 class="text-base font-semibold text-clx-text-label">Cart Items</h2>
15186
+ <h2 class="text-base font-semibold text-clx-text-label">Productos</h2>
15211
15187
  <span clx-badge variant="light" [color]="color()" size="sm">{{ _totalUnits() }}</span>
15212
15188
  </div>
15213
15189
  <button
15214
- clx-button type="button" variant="ghost" color="red" size="sm" icon="delete_sweep"
15190
+ clx-button type="button" variant="light" color="red" icon="delete"
15215
15191
  (click)="onClearCart.emit()">
15216
- Vaciar
15192
+ Vaciar carrito
15217
15193
  </button>
15218
15194
  </div>
15219
15195
 
15220
15196
  <!-- Item cards -->
15221
15197
  @for (item of items(); track item.id) {
15222
- <article class="bg-clx-surface rounded-2xl shadow-sm flex gap-0 overflow-hidden group transition-[box-shadow,transform] duration-300 hover:shadow-xl hover:-translate-y-0.5">
15198
+ <article class="bg-clx-surface rounded-2xl shadow-sm flex gap-0 overflow-hidden group transition-[box-shadow,transform] duration-300 hover:shadow-md hover:-translate-y-0.5">
15223
15199
 
15224
15200
  <!-- Image — fixed square -->
15225
15201
  <div class="relative shrink-0 w-28 h-28 lg:w-36 lg:h-36 overflow-hidden bg-clx-surface-2">
@@ -15264,54 +15240,29 @@ class ClxCartComponent {
15264
15240
  <p class="text-xs font-mono text-clx-text-subtle mt-0.5">{{ item.sku }}</p>
15265
15241
  </div>
15266
15242
 
15267
- @if (item.rating) {
15268
- <div class="flex items-center gap-1.5">
15269
- <clx-rating [value]="item.rating" [max]="5" color="amber" />
15270
- @if (item.review_count) {
15271
- <span class="text-xs text-clx-text-subtle">({{ item.review_count }})</span>
15272
- }
15273
- </div>
15274
- }
15275
-
15276
15243
  <!-- Price + Quantity row -->
15277
15244
  <div class="flex items-center justify-between gap-2 mt-auto flex-wrap">
15278
15245
 
15279
15246
  <!-- Price -->
15280
15247
  <div class="flex items-baseline gap-1.5">
15281
15248
  <span class="text-base font-bold text-clx-text-label">
15282
- {{ item.unit_price | currency:'COP':'symbol':'1.0-0' }}
15249
+ {{ item.unit_price | currency:'COP':'$':'1.0-0' }}
15283
15250
  </span>
15284
15251
  @if (item.has_discount && item.original_price) {
15285
15252
  <span class="text-xs text-clx-text-subtle line-through">
15286
- {{ item.original_price | currency:'COP':'symbol':'1.0-0' }}
15253
+ {{ item.original_price | currency:'COP':'$':'1.0-0' }}
15287
15254
  </span>
15288
15255
  }
15289
15256
  </div>
15290
15257
 
15291
15258
  <!-- Quantity control -->
15292
- <div class="flex items-center border border-clx-border rounded-xl overflow-hidden">
15293
- <button
15294
- clx-button type="button" variant="ghost" color="slate" size="sm"
15295
- icon="remove" [iconOnly]="true"
15296
- [disabled]="item.quantity <= 1"
15297
- (click)="onQuantityChange.emit({ item, quantity: item.quantity - 1 })">
15298
- </button>
15299
- <span class="w-8 text-center text-sm font-semibold text-clx-text-label select-none">
15300
- {{ item.quantity }}
15301
- </span>
15302
- <button
15303
- clx-button type="button" variant="ghost" [color]="color()" size="sm"
15304
- icon="add" [iconOnly]="true"
15305
- [disabled]="!item.in_stock || (!!item.max_quantity && item.quantity >= item.max_quantity)"
15306
- (click)="onQuantityChange.emit({ item, quantity: item.quantity + 1 })">
15307
- </button>
15308
- </div>
15309
-
15310
- <!-- Line total -->
15311
- <p class="text-sm font-bold text-clx-text-label">
15312
- {{ (item.unit_price * item.quantity) | currency:'COP':'symbol':'1.0-0' }}
15313
- </p>
15314
-
15259
+ <clx-number
15260
+ variant="stepper" size="sm" [color]="color()"
15261
+ [min]="1" [max]="item.max_quantity ?? null"
15262
+ [disabled]="!item.in_stock"
15263
+ [ngModel]="item.quantity"
15264
+ (ngModelChange)="onQuantityChange.emit({ item, quantity: $event })">
15265
+ </clx-number>
15315
15266
  </div>
15316
15267
  </div>
15317
15268
 
@@ -15376,12 +15327,12 @@ class ClxCartComponent {
15376
15327
  <dl class="flex flex-col gap-2.5 text-sm">
15377
15328
  <div class="flex justify-between text-clx-text-muted">
15378
15329
  <dt>Subtotal <span class="text-clx-text-subtle text-xs">({{ _totalUnits() }} items)</span></dt>
15379
- <dd class="font-medium">{{ _subtotal() | currency:'COP':'symbol':'1.0-0' }}</dd>
15330
+ <dd class="font-medium">{{ _subtotal() | currency:'COP':'$':'1.0-0' }}</dd>
15380
15331
  </div>
15381
15332
  @if (_savingsAmount() > 0) {
15382
15333
  <div class="flex justify-between text-emerald-600">
15383
15334
  <dt>Descuento productos</dt>
15384
- <dd class="font-medium">-{{ _savingsAmount() | currency:'COP':'symbol':'1.0-0' }}</dd>
15335
+ <dd class="font-medium">-{{ _savingsAmount() | currency:'COP':'$':'1.0-0' }}</dd>
15385
15336
  </div>
15386
15337
  }
15387
15338
  @if (coupon()?.valid) {
@@ -15390,18 +15341,18 @@ class ClxCartComponent {
15390
15341
  Cupón
15391
15342
  <code class="bg-emerald-50 px-1 rounded text-xs ml-1">{{ coupon()!.code }}</code>
15392
15343
  </dt>
15393
- <dd class="font-medium">-{{ _couponDiscount() | currency:'COP':'symbol':'1.0-0' }}</dd>
15344
+ <dd class="font-medium">-{{ _couponDiscount() | currency:'COP':'$':'1.0-0' }}</dd>
15394
15345
  </div>
15395
15346
  }
15396
15347
  <div class="flex justify-between border-t border-clx-border-soft pt-2.5">
15397
15348
  <dt class="font-bold text-clx-text-label">Total</dt>
15398
- <dd class="text-xl font-black text-clx-text-label">{{ _total() | currency:'COP':'symbol':'1.0-0' }}</dd>
15349
+ <dd class="text-lg font-black text-clx-text-label">{{ _total() | currency:'COP':'$':'1.0-0' }}</dd>
15399
15350
  </div>
15400
15351
  </dl>
15401
15352
 
15402
15353
  <!-- Checkout -->
15403
15354
  <button
15404
- clx-button type="button" [color]="color()" variant="solid" size="lg"
15355
+ clx-button type="button" [color]="color()" variant="solid" size="md"
15405
15356
  icon="arrow_forward" iconPosition="right" [block]="true"
15406
15357
  (click)="onCheckout.emit()">
15407
15358
  Proceder al pago
@@ -15420,7 +15371,7 @@ class ClxCartComponent {
15420
15371
  </div>
15421
15372
 
15422
15373
  }
15423
- `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ClxButtonComponent, selector: "button[clx-button], a[clx-button]", inputs: ["variant", "color", "textColor", "size", "shape", "loading", "disabled", "block", "icon", "iconPosition", "iconOnly", "badge", "badgeColor"] }, { kind: "component", type: ClxBadgeComponent, selector: "span[clx-badge]", inputs: ["variant", "color", "size", "shape", "positioned"] }, { kind: "component", type: ClxIconComponent, selector: "span[clx-icon]", inputs: ["name", "size", "color", "fill"] }, { kind: "component", type: ClxSkeletonComponent, selector: "clx-skeleton", inputs: ["variant", "size", "width", "height"] }, { kind: "component", type: ClxInputComponent, selector: "clx-input", inputs: ["label", "placeholder", "type", "color", "hint", "prefixIcon", "suffixIcon", "prefixText", "suffixText", "status", "statusMessage", "size", "value", "disabled", "autocomplete"] }, { kind: "component", type: ClxRatingComponent, selector: "clx-rating", inputs: ["value", "max", "color"] }, { kind: "pipe", type: CurrencyPipe, name: "currency" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
15374
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ClxButtonComponent, selector: "button[clx-button], a[clx-button]", inputs: ["variant", "color", "textColor", "size", "shape", "loading", "disabled", "block", "icon", "iconPosition", "iconOnly", "badge", "badgeColor"] }, { kind: "component", type: ClxBadgeComponent, selector: "span[clx-badge]", inputs: ["variant", "color", "size", "shape", "positioned"] }, { kind: "component", type: ClxIconComponent, selector: "span[clx-icon]", inputs: ["name", "size", "color", "fill"] }, { kind: "component", type: ClxSkeletonComponent, selector: "clx-skeleton", inputs: ["variant", "size", "width", "height"] }, { kind: "component", type: ClxInputComponent, selector: "clx-input", inputs: ["label", "placeholder", "type", "color", "hint", "prefixIcon", "suffixIcon", "prefixText", "suffixText", "status", "statusMessage", "size", "value", "disabled", "autocomplete"] }, { kind: "component", type: ClxNumberComponent, selector: "clx-number", inputs: ["variant", "size", "color", "label", "placeholder", "hint", "prefixIcon", "min", "max", "step", "value", "disabled"] }, { kind: "component", type: ClxPageEmptyComponent, selector: "clx-page-empty", inputs: ["icon", "title", "description", "ctaLabel", "ctaIcon", "ctaColor"], outputs: ["cta"] }, { kind: "pipe", type: CurrencyPipe, name: "currency" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
15424
15375
  }
15425
15376
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxCartComponent, decorators: [{
15426
15377
  type: Component,
@@ -15435,7 +15386,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
15435
15386
  ClxIconComponent,
15436
15387
  ClxSkeletonComponent,
15437
15388
  ClxInputComponent,
15438
- ClxRatingComponent,
15389
+ ClxNumberComponent,
15390
+ ClxPageEmptyComponent
15439
15391
  ],
15440
15392
  encapsulation: ViewEncapsulation.None,
15441
15393
  changeDetection: ChangeDetectionStrategy.OnPush,
@@ -15470,11 +15422,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
15470
15422
  <!-- ── Empty ───────────────────────────────────────────────────────────────── -->
15471
15423
  } @else if (items().length === 0) {
15472
15424
 
15473
- <div class="flex flex-col items-center justify-center py-24 gap-4 text-clx-text-subtle">
15474
- <span clx-icon name="shopping_cart" size="xl"></span>
15475
- <p class="text-base font-semibold text-clx-text-muted">Tu carrito está vacío</p>
15476
- <p class="text-sm">Agrega productos para continuar.</p>
15477
- </div>
15425
+ <clx-page-empty
15426
+ icon="remove_shopping_cart"
15427
+ title="Carrito vacio"
15428
+ description="Tu carrito esta vacio. Agrega productos para continuar."
15429
+ [ctaColor]="color()"
15430
+ ctaIcon="storefront"
15431
+ ctaLabel="Ir a la tienda">
15432
+ </clx-page-empty>
15478
15433
 
15479
15434
  <!-- ── Main layout ─────────────────────────────────────────────────────────── -->
15480
15435
  } @else {
@@ -15487,19 +15442,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
15487
15442
  <!-- Top bar -->
15488
15443
  <div class="flex items-center justify-between">
15489
15444
  <div class="flex items-center gap-2">
15490
- <h2 class="text-base font-semibold text-clx-text-label">Cart Items</h2>
15445
+ <h2 class="text-base font-semibold text-clx-text-label">Productos</h2>
15491
15446
  <span clx-badge variant="light" [color]="color()" size="sm">{{ _totalUnits() }}</span>
15492
15447
  </div>
15493
15448
  <button
15494
- clx-button type="button" variant="ghost" color="red" size="sm" icon="delete_sweep"
15449
+ clx-button type="button" variant="light" color="red" icon="delete"
15495
15450
  (click)="onClearCart.emit()">
15496
- Vaciar
15451
+ Vaciar carrito
15497
15452
  </button>
15498
15453
  </div>
15499
15454
 
15500
15455
  <!-- Item cards -->
15501
15456
  @for (item of items(); track item.id) {
15502
- <article class="bg-clx-surface rounded-2xl shadow-sm flex gap-0 overflow-hidden group transition-[box-shadow,transform] duration-300 hover:shadow-xl hover:-translate-y-0.5">
15457
+ <article class="bg-clx-surface rounded-2xl shadow-sm flex gap-0 overflow-hidden group transition-[box-shadow,transform] duration-300 hover:shadow-md hover:-translate-y-0.5">
15503
15458
 
15504
15459
  <!-- Image — fixed square -->
15505
15460
  <div class="relative shrink-0 w-28 h-28 lg:w-36 lg:h-36 overflow-hidden bg-clx-surface-2">
@@ -15544,54 +15499,29 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
15544
15499
  <p class="text-xs font-mono text-clx-text-subtle mt-0.5">{{ item.sku }}</p>
15545
15500
  </div>
15546
15501
 
15547
- @if (item.rating) {
15548
- <div class="flex items-center gap-1.5">
15549
- <clx-rating [value]="item.rating" [max]="5" color="amber" />
15550
- @if (item.review_count) {
15551
- <span class="text-xs text-clx-text-subtle">({{ item.review_count }})</span>
15552
- }
15553
- </div>
15554
- }
15555
-
15556
15502
  <!-- Price + Quantity row -->
15557
15503
  <div class="flex items-center justify-between gap-2 mt-auto flex-wrap">
15558
15504
 
15559
15505
  <!-- Price -->
15560
15506
  <div class="flex items-baseline gap-1.5">
15561
15507
  <span class="text-base font-bold text-clx-text-label">
15562
- {{ item.unit_price | currency:'COP':'symbol':'1.0-0' }}
15508
+ {{ item.unit_price | currency:'COP':'$':'1.0-0' }}
15563
15509
  </span>
15564
15510
  @if (item.has_discount && item.original_price) {
15565
15511
  <span class="text-xs text-clx-text-subtle line-through">
15566
- {{ item.original_price | currency:'COP':'symbol':'1.0-0' }}
15512
+ {{ item.original_price | currency:'COP':'$':'1.0-0' }}
15567
15513
  </span>
15568
15514
  }
15569
15515
  </div>
15570
15516
 
15571
15517
  <!-- Quantity control -->
15572
- <div class="flex items-center border border-clx-border rounded-xl overflow-hidden">
15573
- <button
15574
- clx-button type="button" variant="ghost" color="slate" size="sm"
15575
- icon="remove" [iconOnly]="true"
15576
- [disabled]="item.quantity <= 1"
15577
- (click)="onQuantityChange.emit({ item, quantity: item.quantity - 1 })">
15578
- </button>
15579
- <span class="w-8 text-center text-sm font-semibold text-clx-text-label select-none">
15580
- {{ item.quantity }}
15581
- </span>
15582
- <button
15583
- clx-button type="button" variant="ghost" [color]="color()" size="sm"
15584
- icon="add" [iconOnly]="true"
15585
- [disabled]="!item.in_stock || (!!item.max_quantity && item.quantity >= item.max_quantity)"
15586
- (click)="onQuantityChange.emit({ item, quantity: item.quantity + 1 })">
15587
- </button>
15588
- </div>
15589
-
15590
- <!-- Line total -->
15591
- <p class="text-sm font-bold text-clx-text-label">
15592
- {{ (item.unit_price * item.quantity) | currency:'COP':'symbol':'1.0-0' }}
15593
- </p>
15594
-
15518
+ <clx-number
15519
+ variant="stepper" size="sm" [color]="color()"
15520
+ [min]="1" [max]="item.max_quantity ?? null"
15521
+ [disabled]="!item.in_stock"
15522
+ [ngModel]="item.quantity"
15523
+ (ngModelChange)="onQuantityChange.emit({ item, quantity: $event })">
15524
+ </clx-number>
15595
15525
  </div>
15596
15526
  </div>
15597
15527
 
@@ -15656,12 +15586,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
15656
15586
  <dl class="flex flex-col gap-2.5 text-sm">
15657
15587
  <div class="flex justify-between text-clx-text-muted">
15658
15588
  <dt>Subtotal <span class="text-clx-text-subtle text-xs">({{ _totalUnits() }} items)</span></dt>
15659
- <dd class="font-medium">{{ _subtotal() | currency:'COP':'symbol':'1.0-0' }}</dd>
15589
+ <dd class="font-medium">{{ _subtotal() | currency:'COP':'$':'1.0-0' }}</dd>
15660
15590
  </div>
15661
15591
  @if (_savingsAmount() > 0) {
15662
15592
  <div class="flex justify-between text-emerald-600">
15663
15593
  <dt>Descuento productos</dt>
15664
- <dd class="font-medium">-{{ _savingsAmount() | currency:'COP':'symbol':'1.0-0' }}</dd>
15594
+ <dd class="font-medium">-{{ _savingsAmount() | currency:'COP':'$':'1.0-0' }}</dd>
15665
15595
  </div>
15666
15596
  }
15667
15597
  @if (coupon()?.valid) {
@@ -15670,18 +15600,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
15670
15600
  Cupón
15671
15601
  <code class="bg-emerald-50 px-1 rounded text-xs ml-1">{{ coupon()!.code }}</code>
15672
15602
  </dt>
15673
- <dd class="font-medium">-{{ _couponDiscount() | currency:'COP':'symbol':'1.0-0' }}</dd>
15603
+ <dd class="font-medium">-{{ _couponDiscount() | currency:'COP':'$':'1.0-0' }}</dd>
15674
15604
  </div>
15675
15605
  }
15676
15606
  <div class="flex justify-between border-t border-clx-border-soft pt-2.5">
15677
15607
  <dt class="font-bold text-clx-text-label">Total</dt>
15678
- <dd class="text-xl font-black text-clx-text-label">{{ _total() | currency:'COP':'symbol':'1.0-0' }}</dd>
15608
+ <dd class="text-lg font-black text-clx-text-label">{{ _total() | currency:'COP':'$':'1.0-0' }}</dd>
15679
15609
  </div>
15680
15610
  </dl>
15681
15611
 
15682
15612
  <!-- Checkout -->
15683
15613
  <button
15684
- clx-button type="button" [color]="color()" variant="solid" size="lg"
15614
+ clx-button type="button" [color]="color()" variant="solid" size="md"
15685
15615
  icon="arrow_forward" iconPosition="right" [block]="true"
15686
15616
  (click)="onCheckout.emit()">
15687
15617
  Proceder al pago
@@ -15744,7 +15674,7 @@ class ClxCartSummaryDrawer {
15744
15674
  <p class="text-xs text-clx-text-subtle">x{{ item.quantity }}</p>
15745
15675
  </div>
15746
15676
  <span class="text-sm font-semibold text-clx-text-label shrink-0">
15747
- {{ (item.unit_price * item.quantity) | currency:'COP':'symbol':'1.0-0' }}
15677
+ {{ (item.unit_price * item.quantity) | currency:'COP':'$':'1.0-0' }}
15748
15678
  </span>
15749
15679
  </li>
15750
15680
  }
@@ -15757,12 +15687,12 @@ class ClxCartSummaryDrawer {
15757
15687
  <dl class="space-y-2">
15758
15688
  <div class="flex justify-between text-sm text-clx-text-muted">
15759
15689
  <dt>Subtotal</dt>
15760
- <dd class="font-medium">{{ data.subtotal | currency:'COP':'symbol':'1.0-0' }}</dd>
15690
+ <dd class="font-medium">{{ data.subtotal | currency:'COP':'$':'1.0-0' }}</dd>
15761
15691
  </div>
15762
15692
  @if (data.savingsAmount > 0) {
15763
15693
  <div class="flex justify-between text-sm text-emerald-600">
15764
15694
  <dt>Descuento</dt>
15765
- <dd class="font-medium">-{{ data.savingsAmount | currency:'COP':'symbol':'1.0-0' }}</dd>
15695
+ <dd class="font-medium">-{{ data.savingsAmount | currency:'COP':'$':'1.0-0' }}</dd>
15766
15696
  </div>
15767
15697
  }
15768
15698
  @if (data.coupon?.valid) {
@@ -15771,12 +15701,12 @@ class ClxCartSummaryDrawer {
15771
15701
  Cupón
15772
15702
  <code class="bg-emerald-50 px-1 rounded text-xs ml-1">{{ data.coupon!.code }}</code>
15773
15703
  </dt>
15774
- <dd class="font-medium">-{{ data.couponDiscount | currency:'COP':'symbol':'1.0-0' }}</dd>
15704
+ <dd class="font-medium">-{{ data.couponDiscount | currency:'COP':'$':'1.0-0' }}</dd>
15775
15705
  </div>
15776
15706
  }
15777
15707
  <div class="border-t border-clx-border-soft pt-2 flex justify-between">
15778
15708
  <dt class="font-bold text-clx-text-label">Total</dt>
15779
- <dd class="text-xl font-black text-clx-text-label">{{ data.total | currency:'COP':'symbol':'1.0-0' }}</dd>
15709
+ <dd class="text-xl font-black text-clx-text-label">{{ data.total | currency:'COP':'$':'1.0-0' }}</dd>
15780
15710
  </div>
15781
15711
  </dl>
15782
15712
 
@@ -15833,7 +15763,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
15833
15763
  <p class="text-xs text-clx-text-subtle">x{{ item.quantity }}</p>
15834
15764
  </div>
15835
15765
  <span class="text-sm font-semibold text-clx-text-label shrink-0">
15836
- {{ (item.unit_price * item.quantity) | currency:'COP':'symbol':'1.0-0' }}
15766
+ {{ (item.unit_price * item.quantity) | currency:'COP':'$':'1.0-0' }}
15837
15767
  </span>
15838
15768
  </li>
15839
15769
  }
@@ -15846,12 +15776,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
15846
15776
  <dl class="space-y-2">
15847
15777
  <div class="flex justify-between text-sm text-clx-text-muted">
15848
15778
  <dt>Subtotal</dt>
15849
- <dd class="font-medium">{{ data.subtotal | currency:'COP':'symbol':'1.0-0' }}</dd>
15779
+ <dd class="font-medium">{{ data.subtotal | currency:'COP':'$':'1.0-0' }}</dd>
15850
15780
  </div>
15851
15781
  @if (data.savingsAmount > 0) {
15852
15782
  <div class="flex justify-between text-sm text-emerald-600">
15853
15783
  <dt>Descuento</dt>
15854
- <dd class="font-medium">-{{ data.savingsAmount | currency:'COP':'symbol':'1.0-0' }}</dd>
15784
+ <dd class="font-medium">-{{ data.savingsAmount | currency:'COP':'$':'1.0-0' }}</dd>
15855
15785
  </div>
15856
15786
  }
15857
15787
  @if (data.coupon?.valid) {
@@ -15860,12 +15790,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
15860
15790
  Cupón
15861
15791
  <code class="bg-emerald-50 px-1 rounded text-xs ml-1">{{ data.coupon!.code }}</code>
15862
15792
  </dt>
15863
- <dd class="font-medium">-{{ data.couponDiscount | currency:'COP':'symbol':'1.0-0' }}</dd>
15793
+ <dd class="font-medium">-{{ data.couponDiscount | currency:'COP':'$':'1.0-0' }}</dd>
15864
15794
  </div>
15865
15795
  }
15866
15796
  <div class="border-t border-clx-border-soft pt-2 flex justify-between">
15867
15797
  <dt class="font-bold text-clx-text-label">Total</dt>
15868
- <dd class="text-xl font-black text-clx-text-label">{{ data.total | currency:'COP':'symbol':'1.0-0' }}</dd>
15798
+ <dd class="text-xl font-black text-clx-text-label">{{ data.total | currency:'COP':'$':'1.0-0' }}</dd>
15869
15799
  </div>
15870
15800
  </dl>
15871
15801