codexly-ui 0.11.0 → 0.11.2

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.
@@ -9603,6 +9603,13 @@ class ClxTabsComponent {
9603
9603
  _clxColor = computed(() => this.clxColor() ?? this._themeSvc.config().primaryColor, ...(ngDevMode ? [{ debugName: "_clxColor" }] : /* istanbul ignore next */ []));
9604
9604
  _panels = contentChildren(ClxTabDirective, ...(ngDevMode ? [{ debugName: "_panels" }] : /* istanbul ignore next */ []));
9605
9605
  _underlineClass = computed(() => resolveColor(this._clxColor()).bg, ...(ngDevMode ? [{ debugName: "_underlineClass" }] : /* istanbul ignore next */ []));
9606
+ _badgeClass(tabId) {
9607
+ const active = this.activeTab() === tabId;
9608
+ const t = resolveColor(this._clxColor());
9609
+ return active
9610
+ ? `ml-0.5 px-1.5 py-0.5 rounded-full text-[10px] font-bold leading-none tabular-nums ${t.bgSubtle} ${t.textSubtle}`
9611
+ : 'ml-0.5 px-1.5 py-0.5 rounded-full text-[10px] font-bold leading-none tabular-nums bg-clx-surface-2 text-clx-text-subtle';
9612
+ }
9606
9613
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxTabsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
9607
9614
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxTabsComponent, isStandalone: true, selector: "clx-tabs", inputs: { tabs: { classPropertyName: "tabs", publicName: "tabs", isSignal: true, isRequired: true, transformFunction: null }, clxColor: { classPropertyName: "clxColor", publicName: "clxColor", isSignal: true, isRequired: false, transformFunction: null }, activeTab: { classPropertyName: "activeTab", publicName: "activeTab", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeTab: "activeTabChange" }, queries: [{ propertyName: "_panels", predicate: ClxTabDirective, isSignal: true }], ngImport: i0, template: `
9608
9615
  <!-- Tab bar -->
@@ -9625,6 +9632,9 @@ class ClxTabsComponent {
9625
9632
  <span clx-icon [name]="tab.icon" size="xs" class="shrink-0"></span>
9626
9633
  }
9627
9634
  {{ tab.label }}
9635
+ @if (tab.badge !== undefined) {
9636
+ <span [class]="_badgeClass(tab.id)">{{ tab.badge }}</span>
9637
+ }
9628
9638
  </button>
9629
9639
  @if (activeTab() === tab.id) {
9630
9640
  <span class="absolute bottom-0 left-0 right-0 h-0.5 rounded-full {{ _underlineClass() }}"></span>
@@ -9666,6 +9676,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
9666
9676
  <span clx-icon [name]="tab.icon" size="xs" class="shrink-0"></span>
9667
9677
  }
9668
9678
  {{ tab.label }}
9679
+ @if (tab.badge !== undefined) {
9680
+ <span [class]="_badgeClass(tab.id)">{{ tab.badge }}</span>
9681
+ }
9669
9682
  </button>
9670
9683
  @if (activeTab() === tab.id) {
9671
9684
  <span class="absolute bottom-0 left-0 right-0 h-0.5 rounded-full {{ _underlineClass() }}"></span>
@@ -11258,6 +11271,78 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
11258
11271
  }]
11259
11272
  }], propDecorators: { size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], showClose: [{ type: i0.Input, args: [{ isSignal: true, alias: "showClose", required: false }] }], confirmButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "confirmButton", required: false }] }], cancelButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "cancelButton", required: false }] }], showCancelButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showCancelButton", required: false }] }], confirmClick: [{ type: i0.Output, args: ["confirmClick"] }], cancelClick: [{ type: i0.Output, args: ["cancelClick"] }] } });
11260
11273
 
11274
+ class ClxPageEmptyComponent {
11275
+ _themeSvc = inject(ClxThemeService);
11276
+ icon = input('inbox', ...(ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []));
11277
+ /** Named "heading", not "title" — the latter shadows the native HTML title attribute (tooltip
11278
+ * on hover) when bound without brackets, e.g. `title="..."` instead of `[title]="..."`. */
11279
+ heading = input('Sin resultados', ...(ngDevMode ? [{ debugName: "heading" }] : /* istanbul ignore next */ []));
11280
+ description = input('', ...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
11281
+ ctaLabel = input('', ...(ngDevMode ? [{ debugName: "ctaLabel" }] : /* istanbul ignore next */ []));
11282
+ ctaIcon = input('add', ...(ngDevMode ? [{ debugName: "ctaIcon" }] : /* istanbul ignore next */ []));
11283
+ ctaColor = input(undefined, ...(ngDevMode ? [{ debugName: "ctaColor" }] : /* istanbul ignore next */ []));
11284
+ _ctaColor = computed(() => this.ctaColor() ?? this._themeSvc.config().primaryColor, ...(ngDevMode ? [{ debugName: "_ctaColor" }] : /* istanbul ignore next */ []));
11285
+ cta = output();
11286
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxPageEmptyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
11287
+ 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 }, heading: { classPropertyName: "heading", publicName: "heading", 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: `
11288
+ <div class="w-20 h-20 rounded-2xl bg-clx-surface-2 flex items-center justify-center mb-6">
11289
+ <span clx-icon [name]="icon()" size="xl" class="text-clx-text-faint"></span>
11290
+ </div>
11291
+
11292
+ <h1 class="text-base font-semibold text-clx-text-label mb-2">{{ heading() }}</h1>
11293
+
11294
+ @if (description()) {
11295
+ <p class="text-clx-text-subtle max-w-sm mb-8">{{ description() }}</p>
11296
+ }
11297
+
11298
+ @if (ctaLabel()) {
11299
+ <button
11300
+ clx-button
11301
+ type="button"
11302
+ [color]="_ctaColor()"
11303
+ variant="solid"
11304
+ [icon]="ctaIcon()"
11305
+ (click)="cta.emit()">
11306
+ {{ ctaLabel() }}
11307
+ </button>
11308
+ }
11309
+ `, isInline: true, dependencies: [{ 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: ClxIconComponent, selector: "span[clx-icon]", inputs: ["name", "size", "color", "fill"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
11310
+ }
11311
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxPageEmptyComponent, decorators: [{
11312
+ type: Component,
11313
+ args: [{
11314
+ selector: 'clx-page-empty',
11315
+ standalone: true,
11316
+ imports: [ClxButtonComponent, ClxIconComponent],
11317
+ encapsulation: ViewEncapsulation.None,
11318
+ changeDetection: ChangeDetectionStrategy.OnPush,
11319
+ host: { class: 'flex flex-col items-center justify-center w-full px-6 text-center text-sm' },
11320
+ template: `
11321
+ <div class="w-20 h-20 rounded-2xl bg-clx-surface-2 flex items-center justify-center mb-6">
11322
+ <span clx-icon [name]="icon()" size="xl" class="text-clx-text-faint"></span>
11323
+ </div>
11324
+
11325
+ <h1 class="text-base font-semibold text-clx-text-label mb-2">{{ heading() }}</h1>
11326
+
11327
+ @if (description()) {
11328
+ <p class="text-clx-text-subtle max-w-sm mb-8">{{ description() }}</p>
11329
+ }
11330
+
11331
+ @if (ctaLabel()) {
11332
+ <button
11333
+ clx-button
11334
+ type="button"
11335
+ [color]="_ctaColor()"
11336
+ variant="solid"
11337
+ [icon]="ctaIcon()"
11338
+ (click)="cta.emit()">
11339
+ {{ ctaLabel() }}
11340
+ </button>
11341
+ }
11342
+ `,
11343
+ }]
11344
+ }], propDecorators: { icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], heading: [{ type: i0.Input, args: [{ isSignal: true, alias: "heading", 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"] }] } });
11345
+
11261
11346
  // ── Size map — same density-token shape as LIST_SIZE_MAP ──────────────────────
11262
11347
  const NOTIFICATION_SIZE_MAP = {
11263
11348
  sm: { row: 'py-2', iconWrap: 'w-7 h-7', iconSize: 'xs', title: 'text-xs', detail: 'text-[11px]', time: 'text-[10px]' },
@@ -11272,29 +11357,60 @@ const NOTIFICATION_SEVERITY_ICON = {
11272
11357
  error: 'error',
11273
11358
  };
11274
11359
 
11275
- /** "Dumb" panel: renders whatever list of items it's given via `items()` and emits intent
11276
- * (itemClick/markRead/markAllRead/delete/deleteAllRead) outward it never fetches, persists,
11277
- * or connects to a real-time source itself. Callers (e.g. codexly-app's NotificationService,
11278
- * backed by SSE) own that and just feed the current list in. Meant to be projected inside
11279
- * clx-drawer's body, same as any other content. */
11360
+ /** Self-contained bell trigger + floating panel same overlay pattern as clx-profile (CDK
11361
+ * Overlay anchored to the trigger, no page-level backdrop), not a full-height clx-drawer. It's
11362
+ * "dumb" beyond that: renders whatever `items()` it's given and emits intent (itemClick/
11363
+ * markRead/delete/...) outward. Callers (e.g. a NotificationService backed by SSE) own fetching
11364
+ * and persistence this component never calls an API itself. */
11280
11365
  class ClxNotificationComponent {
11281
11366
  _themeSvc = inject(ClxThemeService);
11282
11367
  items = input.required(...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
11283
11368
  color = input(undefined, ...(ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []));
11284
- size = input(undefined, ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
11369
+ /** Optional third tab that filters items by ClxNotificationItem.category e.g.
11370
+ * `{ id: 'orders', label: 'Órdenes' }`. Omit for just Todas/Sin leer. */
11371
+ categoryTab = input(undefined, ...(ngDevMode ? [{ debugName: "categoryTab" }] : /* istanbul ignore next */ []));
11285
11372
  itemClick = output();
11286
11373
  markRead = output();
11287
11374
  markAllRead = output();
11288
11375
  delete = output();
11289
11376
  deleteAllRead = output();
11290
- _filter = signal('all', ...(ngDevMode ? [{ debugName: "_filter" }] : /* istanbul ignore next */ []));
11291
11377
  _style = this._themeSvc.notificationStyle;
11292
11378
  _color = computed(() => this.color() ?? this._themeSvc.config().primaryColor, ...(ngDevMode ? [{ debugName: "_color" }] : /* istanbul ignore next */ []));
11293
- _resolvedSize = computed(() => this.size() ?? this._style().size, ...(ngDevMode ? [{ debugName: "_resolvedSize" }] : /* istanbul ignore next */ []));
11294
- _sizeTokens = computed(() => NOTIFICATION_SIZE_MAP[this._resolvedSize()], ...(ngDevMode ? [{ debugName: "_sizeTokens" }] : /* istanbul ignore next */ []));
11379
+ // ── CDK Overlay ─────────────────────────────────────────────────────────────
11380
+ _sso = inject(ScrollStrategyOptions);
11381
+ _scrollStrategy = this._sso.reposition();
11382
+ _positions = [
11383
+ { originX: 'end', originY: 'bottom', overlayX: 'end', overlayY: 'top', offsetY: 8 },
11384
+ { originX: 'end', originY: 'top', overlayX: 'end', overlayY: 'bottom', offsetY: -8 },
11385
+ ];
11386
+ _isOpen = signal(false, ...(ngDevMode ? [{ debugName: "_isOpen" }] : /* istanbul ignore next */ []));
11387
+ _filter = signal('all', ...(ngDevMode ? [{ debugName: "_filter" }] : /* istanbul ignore next */ []));
11388
+ _ringClass = computed(() => {
11389
+ const t = resolveColor(this._color());
11390
+ return `focus-visible:${t.ringBase}`;
11391
+ }, ...(ngDevMode ? [{ debugName: "_ringClass" }] : /* istanbul ignore next */ []));
11392
+ _panelClass = computed(() => `w-96 bg-clx-surface shadow-xl border border-clx-border-soft overflow-hidden mt-2 flex flex-col ${resolveContainerRadius(this._style().radius)}`, ...(ngDevMode ? [{ debugName: "_panelClass" }] : /* istanbul ignore next */ []));
11295
11393
  _unreadCount = computed(() => this.items().filter(i => !i.read).length, ...(ngDevMode ? [{ debugName: "_unreadCount" }] : /* istanbul ignore next */ []));
11296
11394
  _readCount = computed(() => this.items().filter(i => i.read).length, ...(ngDevMode ? [{ debugName: "_readCount" }] : /* istanbul ignore next */ []));
11297
- _visibleItems = computed(() => this._filter() === 'unread' ? this.items().filter(i => !i.read) : this.items(), ...(ngDevMode ? [{ debugName: "_visibleItems" }] : /* istanbul ignore next */ []));
11395
+ _tabs = computed(() => {
11396
+ const tabs = [
11397
+ { id: 'all', label: 'Todas', badge: this.items().length || undefined },
11398
+ { id: 'unread', label: 'Sin leer', badge: this._unreadCount() || undefined },
11399
+ ];
11400
+ const category = this.categoryTab();
11401
+ if (category)
11402
+ tabs.push({ id: category.id, label: category.label });
11403
+ return tabs;
11404
+ }, ...(ngDevMode ? [{ debugName: "_tabs" }] : /* istanbul ignore next */ []));
11405
+ _visibleItems = computed(() => {
11406
+ const f = this._filter();
11407
+ if (f === 'unread')
11408
+ return this.items().filter(i => !i.read);
11409
+ const category = this.categoryTab();
11410
+ if (category && f === category.id)
11411
+ return this.items().filter(i => i.category === category.id);
11412
+ return this.items();
11413
+ }, ...(ngDevMode ? [{ debugName: "_visibleItems" }] : /* istanbul ignore next */ []));
11298
11414
  _groups = computed(() => {
11299
11415
  const byLabel = new Map();
11300
11416
  for (const item of this._visibleItems()) {
@@ -11307,10 +11423,9 @@ class ClxNotificationComponent {
11307
11423
  }
11308
11424
  return Array.from(byLabel, ([label, items]) => ({ label, items }));
11309
11425
  }, ...(ngDevMode ? [{ debugName: "_groups" }] : /* istanbul ignore next */ []));
11310
- _wrapClass = computed(() => `flex flex-col ${resolveContainerRadius(this._style().radius)}`, ...(ngDevMode ? [{ debugName: "_wrapClass" }] : /* istanbul ignore next */ []));
11311
11426
  _groupLabelClass = computed(() => {
11312
11427
  const w = this._style().groupLabelWeight;
11313
- return `px-1 pt-3 pb-1.5 text-[11px] uppercase tracking-wide text-clx-text-subtle font-[${w}]`;
11428
+ return `px-2 pt-3 pb-1.5 text-[11px] uppercase tracking-wide text-clx-text-subtle font-[${w}]`;
11314
11429
  }, ...(ngDevMode ? [{ debugName: "_groupLabelClass" }] : /* istanbul ignore next */ []));
11315
11430
  _linkClass = computed(() => resolveColor(this._color()).textSubtle, ...(ngDevMode ? [{ debugName: "_linkClass" }] : /* istanbul ignore next */ []));
11316
11431
  _unreadRailClass = computed(() => resolveColor(this._style().unreadColor).bg, ...(ngDevMode ? [{ debugName: "_unreadRailClass" }] : /* istanbul ignore next */ []));
@@ -11322,7 +11437,7 @@ class ClxNotificationComponent {
11322
11437
  }
11323
11438
  _iconWrapClass(item) {
11324
11439
  const c = resolveColor(this._severityColor(item.severity));
11325
- return `flex items-center justify-center rounded-lg shrink-0 ${c.bgSubtle} ${c.textSubtle} ${this._sizeTokens().iconWrap}`;
11440
+ return `flex items-center justify-center rounded-lg shrink-0 w-8.5 h-8.5 mt-0.5 ${c.bgSubtle} ${c.textSubtle}`;
11326
11441
  }
11327
11442
  _defaultIcon(severity) {
11328
11443
  return NOTIFICATION_SEVERITY_ICON[severity];
@@ -11332,11 +11447,11 @@ class ClxNotificationComponent {
11332
11447
  if (!item.read)
11333
11448
  this.markRead.emit(item.id);
11334
11449
  }
11335
- _countBadgeClass(tab) {
11336
- const active = this._filter() === tab;
11337
- return active
11338
- ? 'ml-0.5 text-[10px] font-bold tabular-nums'
11339
- : 'ml-0.5 text-[10px] font-bold tabular-nums text-clx-text-subtle';
11450
+ _toggle() { this._isOpen.update(v => !v); }
11451
+ _close() { this._isOpen.set(false); }
11452
+ _onKeydown(event) {
11453
+ if (event.key === 'Escape')
11454
+ this._close();
11340
11455
  }
11341
11456
  _severityColor(severity) {
11342
11457
  return this._style().severityColors[severity];
@@ -11358,199 +11473,232 @@ class ClxNotificationComponent {
11358
11473
  return new Date(iso).toLocaleTimeString('es-CO', { hour: '2-digit', minute: '2-digit' });
11359
11474
  }
11360
11475
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxNotificationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
11361
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxNotificationComponent, isStandalone: true, selector: "clx-notification", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemClick: "itemClick", markRead: "markRead", markAllRead: "markAllRead", delete: "delete", deleteAllRead: "deleteAllRead" }, ngImport: i0, template: `
11362
- <div [class]="_wrapClass()">
11363
- <!-- Filter -->
11364
- <div class="flex items-center gap-2 px-1 pb-3">
11365
- <button clx-button type="button" size="xs" shape="pill"
11366
- [variant]="_filter() === 'all' ? 'solid' : 'ghost'"
11367
- [color]="_filter() === 'all' ? _color() : 'slate'"
11368
- (click)="_filter.set('all')">
11369
- Todas
11370
- @if (items().length) {
11371
- <span [class]="_countBadgeClass('all')">{{ items().length }}</span>
11372
- }
11373
- </button>
11374
- <button clx-button type="button" size="xs" shape="pill"
11375
- [variant]="_filter() === 'unread' ? 'solid' : 'ghost'"
11376
- [color]="_filter() === 'unread' ? _color() : 'slate'"
11377
- (click)="_filter.set('unread')">
11378
- Sin leer
11379
- @if (_unreadCount() > 0) {
11380
- <span [class]="_countBadgeClass('unread')">{{ _unreadCount() }}</span>
11381
- }
11382
- </button>
11383
- <div class="flex-1"></div>
11384
- @if (_unreadCount() > 0) {
11385
- <button type="button" class="text-xs font-semibold shrink-0" [class]="_linkClass()"
11386
- (click)="markAllRead.emit()">
11387
- Marcar todo leído
11388
- </button>
11389
- }
11390
- @if (_readCount() > 0) {
11391
- <button type="button" class="text-xs font-semibold shrink-0 text-clx-text-subtle hover:text-red-500"
11392
- (click)="deleteAllRead.emit()">
11393
- Eliminar leídas
11394
- </button>
11395
- }
11396
- </div>
11476
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.15", type: ClxNotificationComponent, isStandalone: true, selector: "clx-notification", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, categoryTab: { classPropertyName: "categoryTab", publicName: "categoryTab", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemClick: "itemClick", markRead: "markRead", markAllRead: "markAllRead", delete: "delete", deleteAllRead: "deleteAllRead" }, host: { classAttribute: "relative inline-flex items-center" }, ngImport: i0, template: `
11477
+ <!-- Trigger -->
11478
+ <button
11479
+ #origin="cdkOverlayOrigin"
11480
+ cdkOverlayOrigin
11481
+ type="button"
11482
+ aria-label="Notificaciones"
11483
+ class="relative flex items-center justify-center w-9 h-9 rounded-full text-clx-text-muted hover:bg-clx-surface-2 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 cursor-pointer"
11484
+ [class]="_ringClass()"
11485
+ (click)="_toggle()">
11486
+ <span clx-icon name="notifications" size="sm"></span>
11487
+ @if (_unreadCount() > 0) {
11488
+ <span clx-badge [color]="_style().unreadColor" variant="solid" size="xs" shape="circle"
11489
+ class="absolute -top-0.5 -right-0.5">{{ _unreadCount() > 9 ? '9+' : _unreadCount() }}</span>
11490
+ }
11491
+ </button>
11397
11492
 
11398
- <!-- List -->
11399
- @if (_groups().length) {
11400
- <div class="flex flex-col">
11401
- @for (group of _groups(); track group.label) {
11402
- <p [class]="_groupLabelClass()">{{ group.label }}</p>
11403
- @for (item of group.items; track item.id) {
11404
- <div
11405
- class="group relative flex items-start gap-3 px-1 rounded-lg cursor-pointer hover:bg-clx-surface-2 {{ _sizeTokens().row }}"
11406
- role="button"
11407
- tabindex="0"
11408
- (click)="_open(item)"
11409
- (keydown.enter)="_open(item)">
11410
-
11411
- <span class="absolute left-0 top-1.5 bottom-1.5 w-[3px] rounded-full {{ item.read ? '' : _unreadRailClass() }}"></span>
11412
-
11413
- <span [class]="_iconWrapClass(item)">
11414
- <span clx-icon [name]="item.icon || _defaultIcon(item.severity)" [size]="_sizeTokens().iconSize"></span>
11415
- </span>
11493
+ <!-- Overlay panel -->
11494
+ <ng-template
11495
+ cdkConnectedOverlay
11496
+ [cdkConnectedOverlayOrigin]="origin"
11497
+ [cdkConnectedOverlayOpen]="_isOpen()"
11498
+ [cdkConnectedOverlayPositions]="_positions"
11499
+ [cdkConnectedOverlayScrollStrategy]="_scrollStrategy"
11500
+ [cdkConnectedOverlayPush]="true"
11501
+ (overlayOutsideClick)="_close()"
11502
+ (overlayKeydown)="_onKeydown($event)">
11503
+
11504
+ <div [class]="_panelClass()">
11505
+ <!-- Header -->
11506
+ <div class="flex items-center justify-between gap-3 px-4 pt-4 pb-1">
11507
+ <p class="text-base font-semibold text-clx-text-label">Notificaciones</p>
11508
+ <div class="flex items-center gap-3">
11509
+ @if (_unreadCount() > 0) {
11510
+ <button type="button" class="text-xs font-semibold shrink-0" [class]="_linkClass()"
11511
+ (click)="markAllRead.emit()">
11512
+ Marcar todo leído
11513
+ </button>
11514
+ }
11515
+ <button clx-button type="button" variant="ghost" color="slate" shape="circle" size="xs"
11516
+ icon="close" [iconOnly]="true" aria-label="Cerrar" (click)="_close()"></button>
11517
+ </div>
11518
+ </div>
11519
+
11520
+ <!-- Tabs -->
11521
+ <div class="px-4">
11522
+ <clx-tabs [tabs]="_tabs()" [(activeTab)]="_filter" [clxColor]="_color()" />
11523
+ </div>
11416
11524
 
11417
- <div class="flex-1 min-w-0 pl-1.5">
11418
- <p class="flex items-baseline gap-1.5 {{ _sizeTokens().title }}" [class]="_titleClass(item)">
11419
- @if (!item.read) {
11420
- <span [class]="_unreadDotClass()"></span>
11525
+ <!-- List -->
11526
+ <div class="max-h-105 overflow-y-auto px-2 pb-2">
11527
+ @if (_groups().length) {
11528
+ @for (group of _groups(); track group.label) {
11529
+ <p [class]="_groupLabelClass()">{{ group.label }}</p>
11530
+ @for (item of group.items; track item.id) {
11531
+ <div
11532
+ class="group relative flex items-start gap-3 pl-3 pr-2 rounded-lg cursor-pointer hover:bg-clx-surface-2 py-2.5"
11533
+ role="button"
11534
+ tabindex="0"
11535
+ (click)="_open(item)"
11536
+ (keydown.enter)="_open(item)">
11537
+
11538
+ <span class="absolute left-0.5 top-1 bottom-1 w-0.75 rounded-full {{ item.read ? '' : _unreadRailClass() }}"></span>
11539
+
11540
+ <span [class]="_iconWrapClass(item)">
11541
+ <span clx-icon [name]="item.icon || _defaultIcon(item.severity)" size="sm"></span>
11542
+ </span>
11543
+
11544
+ <div class="flex-1 min-w-0">
11545
+ <p class="flex items-baseline gap-1.5 text-sm" [class]="_titleClass(item)">
11546
+ @if (!item.read) {
11547
+ <span [class]="_unreadDotClass()"></span>
11548
+ }
11549
+ <span class="truncate">{{ item.title }}</span>
11550
+ </p>
11551
+ @if (item.detail) {
11552
+ <p class="mt-0.5 text-sm line-clamp-2" [class]="_detailClass()">{{ item.detail }}</p>
11421
11553
  }
11422
- <span class="truncate">{{ item.title }}</span>
11423
- </p>
11424
- @if (item.detail) {
11425
- <p class="mt-0.5 line-clamp-2 {{ _sizeTokens().detail }}" [class]="_detailClass()">{{ item.detail }}</p>
11426
- }
11427
- </div>
11554
+ <p class="mt-1 text-xs text-clx-text-subtle tabular-nums">{{ _timeOf(item.createdAt) }}</p>
11555
+ </div>
11428
11556
 
11429
- <div class="flex flex-col items-end gap-1 shrink-0 pl-2">
11430
- <span class="text-clx-text-subtle tabular-nums {{ _sizeTokens().time }}">{{ _timeOf(item.createdAt) }}</span>
11431
11557
  <button type="button"
11432
- class="opacity-0 group-hover:opacity-100 focus-visible:opacity-100 transition-opacity rounded-md p-0.5 text-clx-text-subtle hover:text-red-500 hover:bg-red-50 dark:hover:bg-red-950"
11558
+ class="opacity-0 group-hover:opacity-100 focus-visible:opacity-100 transition-opacity shrink-0 rounded-md p-1 text-clx-text-subtle hover:text-red-500 hover:bg-red-50 dark:hover:bg-red-950"
11433
11559
  aria-label="Eliminar notificación"
11434
11560
  (click)="$event.stopPropagation(); delete.emit(item.id)">
11435
11561
  <span clx-icon name="close" size="xs"></span>
11436
11562
  </button>
11437
11563
  </div>
11438
- </div>
11564
+ }
11439
11565
  }
11566
+ } @else {
11567
+ <clx-page-empty icon="notifications_off" class="py-10"
11568
+ [heading]="_filter() === 'unread' ? 'No tienes notificaciones sin leer' : 'No hay notificaciones'" />
11440
11569
  }
11441
11570
  </div>
11442
- } @else {
11443
- <div class="flex flex-col items-center justify-center gap-2 py-14 text-center">
11444
- <span clx-icon name="notifications_off" size="xl" class="text-clx-text-subtle"></span>
11445
- <p class="text-sm font-medium text-clx-text-label">
11446
- {{ _filter() === 'unread' ? 'No tienes notificaciones sin leer' : 'No hay notificaciones' }}
11447
- </p>
11448
- </div>
11449
- }
11450
- </div>
11451
- `, isInline: true, dependencies: [{ 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: ClxIconComponent, selector: "span[clx-icon]", inputs: ["name", "size", "color", "fill"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
11571
+
11572
+ @if (_readCount() > 0) {
11573
+ <div class="flex justify-end px-4 py-2.5 border-t border-clx-border-soft">
11574
+ <button type="button" class="text-xs font-semibold text-clx-text-subtle hover:text-red-500"
11575
+ (click)="deleteAllRead.emit()">
11576
+ Eliminar leídas
11577
+ </button>
11578
+ </div>
11579
+ }
11580
+ </div>
11581
+ </ng-template>
11582
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i1.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "component", type: ClxIconComponent, selector: "span[clx-icon]", inputs: ["name", "size", "color", "fill"] }, { kind: "component", type: ClxBadgeComponent, selector: "span[clx-badge]", inputs: ["variant", "color", "size", "shape", "positioned"] }, { 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: ClxPageEmptyComponent, selector: "clx-page-empty", inputs: ["icon", "heading", "description", "ctaLabel", "ctaIcon", "ctaColor"], outputs: ["cta"] }, { kind: "component", type: ClxTabsComponent, selector: "clx-tabs", inputs: ["tabs", "clxColor", "activeTab"], outputs: ["activeTabChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
11452
11583
  }
11453
11584
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxNotificationComponent, decorators: [{
11454
11585
  type: Component,
11455
11586
  args: [{
11456
11587
  selector: 'clx-notification',
11457
11588
  standalone: true,
11458
- imports: [ClxButtonComponent, ClxIconComponent],
11589
+ imports: [OverlayModule, ClxIconComponent, ClxBadgeComponent, ClxButtonComponent, ClxPageEmptyComponent, ClxTabsComponent],
11459
11590
  template: `
11460
- <div [class]="_wrapClass()">
11461
- <!-- Filter -->
11462
- <div class="flex items-center gap-2 px-1 pb-3">
11463
- <button clx-button type="button" size="xs" shape="pill"
11464
- [variant]="_filter() === 'all' ? 'solid' : 'ghost'"
11465
- [color]="_filter() === 'all' ? _color() : 'slate'"
11466
- (click)="_filter.set('all')">
11467
- Todas
11468
- @if (items().length) {
11469
- <span [class]="_countBadgeClass('all')">{{ items().length }}</span>
11470
- }
11471
- </button>
11472
- <button clx-button type="button" size="xs" shape="pill"
11473
- [variant]="_filter() === 'unread' ? 'solid' : 'ghost'"
11474
- [color]="_filter() === 'unread' ? _color() : 'slate'"
11475
- (click)="_filter.set('unread')">
11476
- Sin leer
11477
- @if (_unreadCount() > 0) {
11478
- <span [class]="_countBadgeClass('unread')">{{ _unreadCount() }}</span>
11479
- }
11480
- </button>
11481
- <div class="flex-1"></div>
11482
- @if (_unreadCount() > 0) {
11483
- <button type="button" class="text-xs font-semibold shrink-0" [class]="_linkClass()"
11484
- (click)="markAllRead.emit()">
11485
- Marcar todo leído
11486
- </button>
11487
- }
11488
- @if (_readCount() > 0) {
11489
- <button type="button" class="text-xs font-semibold shrink-0 text-clx-text-subtle hover:text-red-500"
11490
- (click)="deleteAllRead.emit()">
11491
- Eliminar leídas
11492
- </button>
11493
- }
11494
- </div>
11591
+ <!-- Trigger -->
11592
+ <button
11593
+ #origin="cdkOverlayOrigin"
11594
+ cdkOverlayOrigin
11595
+ type="button"
11596
+ aria-label="Notificaciones"
11597
+ class="relative flex items-center justify-center w-9 h-9 rounded-full text-clx-text-muted hover:bg-clx-surface-2 focus:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 cursor-pointer"
11598
+ [class]="_ringClass()"
11599
+ (click)="_toggle()">
11600
+ <span clx-icon name="notifications" size="sm"></span>
11601
+ @if (_unreadCount() > 0) {
11602
+ <span clx-badge [color]="_style().unreadColor" variant="solid" size="xs" shape="circle"
11603
+ class="absolute -top-0.5 -right-0.5">{{ _unreadCount() > 9 ? '9+' : _unreadCount() }}</span>
11604
+ }
11605
+ </button>
11495
11606
 
11496
- <!-- List -->
11497
- @if (_groups().length) {
11498
- <div class="flex flex-col">
11499
- @for (group of _groups(); track group.label) {
11500
- <p [class]="_groupLabelClass()">{{ group.label }}</p>
11501
- @for (item of group.items; track item.id) {
11502
- <div
11503
- class="group relative flex items-start gap-3 px-1 rounded-lg cursor-pointer hover:bg-clx-surface-2 {{ _sizeTokens().row }}"
11504
- role="button"
11505
- tabindex="0"
11506
- (click)="_open(item)"
11507
- (keydown.enter)="_open(item)">
11508
-
11509
- <span class="absolute left-0 top-1.5 bottom-1.5 w-[3px] rounded-full {{ item.read ? '' : _unreadRailClass() }}"></span>
11510
-
11511
- <span [class]="_iconWrapClass(item)">
11512
- <span clx-icon [name]="item.icon || _defaultIcon(item.severity)" [size]="_sizeTokens().iconSize"></span>
11513
- </span>
11607
+ <!-- Overlay panel -->
11608
+ <ng-template
11609
+ cdkConnectedOverlay
11610
+ [cdkConnectedOverlayOrigin]="origin"
11611
+ [cdkConnectedOverlayOpen]="_isOpen()"
11612
+ [cdkConnectedOverlayPositions]="_positions"
11613
+ [cdkConnectedOverlayScrollStrategy]="_scrollStrategy"
11614
+ [cdkConnectedOverlayPush]="true"
11615
+ (overlayOutsideClick)="_close()"
11616
+ (overlayKeydown)="_onKeydown($event)">
11617
+
11618
+ <div [class]="_panelClass()">
11619
+ <!-- Header -->
11620
+ <div class="flex items-center justify-between gap-3 px-4 pt-4 pb-1">
11621
+ <p class="text-base font-semibold text-clx-text-label">Notificaciones</p>
11622
+ <div class="flex items-center gap-3">
11623
+ @if (_unreadCount() > 0) {
11624
+ <button type="button" class="text-xs font-semibold shrink-0" [class]="_linkClass()"
11625
+ (click)="markAllRead.emit()">
11626
+ Marcar todo leído
11627
+ </button>
11628
+ }
11629
+ <button clx-button type="button" variant="ghost" color="slate" shape="circle" size="xs"
11630
+ icon="close" [iconOnly]="true" aria-label="Cerrar" (click)="_close()"></button>
11631
+ </div>
11632
+ </div>
11514
11633
 
11515
- <div class="flex-1 min-w-0 pl-1.5">
11516
- <p class="flex items-baseline gap-1.5 {{ _sizeTokens().title }}" [class]="_titleClass(item)">
11517
- @if (!item.read) {
11518
- <span [class]="_unreadDotClass()"></span>
11634
+ <!-- Tabs -->
11635
+ <div class="px-4">
11636
+ <clx-tabs [tabs]="_tabs()" [(activeTab)]="_filter" [clxColor]="_color()" />
11637
+ </div>
11638
+
11639
+ <!-- List -->
11640
+ <div class="max-h-105 overflow-y-auto px-2 pb-2">
11641
+ @if (_groups().length) {
11642
+ @for (group of _groups(); track group.label) {
11643
+ <p [class]="_groupLabelClass()">{{ group.label }}</p>
11644
+ @for (item of group.items; track item.id) {
11645
+ <div
11646
+ class="group relative flex items-start gap-3 pl-3 pr-2 rounded-lg cursor-pointer hover:bg-clx-surface-2 py-2.5"
11647
+ role="button"
11648
+ tabindex="0"
11649
+ (click)="_open(item)"
11650
+ (keydown.enter)="_open(item)">
11651
+
11652
+ <span class="absolute left-0.5 top-1 bottom-1 w-0.75 rounded-full {{ item.read ? '' : _unreadRailClass() }}"></span>
11653
+
11654
+ <span [class]="_iconWrapClass(item)">
11655
+ <span clx-icon [name]="item.icon || _defaultIcon(item.severity)" size="sm"></span>
11656
+ </span>
11657
+
11658
+ <div class="flex-1 min-w-0">
11659
+ <p class="flex items-baseline gap-1.5 text-sm" [class]="_titleClass(item)">
11660
+ @if (!item.read) {
11661
+ <span [class]="_unreadDotClass()"></span>
11662
+ }
11663
+ <span class="truncate">{{ item.title }}</span>
11664
+ </p>
11665
+ @if (item.detail) {
11666
+ <p class="mt-0.5 text-sm line-clamp-2" [class]="_detailClass()">{{ item.detail }}</p>
11519
11667
  }
11520
- <span class="truncate">{{ item.title }}</span>
11521
- </p>
11522
- @if (item.detail) {
11523
- <p class="mt-0.5 line-clamp-2 {{ _sizeTokens().detail }}" [class]="_detailClass()">{{ item.detail }}</p>
11524
- }
11525
- </div>
11668
+ <p class="mt-1 text-xs text-clx-text-subtle tabular-nums">{{ _timeOf(item.createdAt) }}</p>
11669
+ </div>
11526
11670
 
11527
- <div class="flex flex-col items-end gap-1 shrink-0 pl-2">
11528
- <span class="text-clx-text-subtle tabular-nums {{ _sizeTokens().time }}">{{ _timeOf(item.createdAt) }}</span>
11529
11671
  <button type="button"
11530
- class="opacity-0 group-hover:opacity-100 focus-visible:opacity-100 transition-opacity rounded-md p-0.5 text-clx-text-subtle hover:text-red-500 hover:bg-red-50 dark:hover:bg-red-950"
11672
+ class="opacity-0 group-hover:opacity-100 focus-visible:opacity-100 transition-opacity shrink-0 rounded-md p-1 text-clx-text-subtle hover:text-red-500 hover:bg-red-50 dark:hover:bg-red-950"
11531
11673
  aria-label="Eliminar notificación"
11532
11674
  (click)="$event.stopPropagation(); delete.emit(item.id)">
11533
11675
  <span clx-icon name="close" size="xs"></span>
11534
11676
  </button>
11535
11677
  </div>
11536
- </div>
11678
+ }
11537
11679
  }
11680
+ } @else {
11681
+ <clx-page-empty icon="notifications_off" class="py-10"
11682
+ [heading]="_filter() === 'unread' ? 'No tienes notificaciones sin leer' : 'No hay notificaciones'" />
11538
11683
  }
11539
11684
  </div>
11540
- } @else {
11541
- <div class="flex flex-col items-center justify-center gap-2 py-14 text-center">
11542
- <span clx-icon name="notifications_off" size="xl" class="text-clx-text-subtle"></span>
11543
- <p class="text-sm font-medium text-clx-text-label">
11544
- {{ _filter() === 'unread' ? 'No tienes notificaciones sin leer' : 'No hay notificaciones' }}
11545
- </p>
11546
- </div>
11547
- }
11548
- </div>
11685
+
11686
+ @if (_readCount() > 0) {
11687
+ <div class="flex justify-end px-4 py-2.5 border-t border-clx-border-soft">
11688
+ <button type="button" class="text-xs font-semibold text-clx-text-subtle hover:text-red-500"
11689
+ (click)="deleteAllRead.emit()">
11690
+ Eliminar leídas
11691
+ </button>
11692
+ </div>
11693
+ }
11694
+ </div>
11695
+ </ng-template>
11549
11696
  `,
11550
11697
  encapsulation: ViewEncapsulation.None,
11551
11698
  changeDetection: ChangeDetectionStrategy.OnPush,
11699
+ host: { class: 'relative inline-flex items-center' },
11552
11700
  }]
11553
- }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], itemClick: [{ type: i0.Output, args: ["itemClick"] }], markRead: [{ type: i0.Output, args: ["markRead"] }], markAllRead: [{ type: i0.Output, args: ["markAllRead"] }], delete: [{ type: i0.Output, args: ["delete"] }], deleteAllRead: [{ type: i0.Output, args: ["deleteAllRead"] }] } });
11701
+ }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], categoryTab: [{ type: i0.Input, args: [{ isSignal: true, alias: "categoryTab", required: false }] }], itemClick: [{ type: i0.Output, args: ["itemClick"] }], markRead: [{ type: i0.Output, args: ["markRead"] }], markAllRead: [{ type: i0.Output, args: ["markAllRead"] }], delete: [{ type: i0.Output, args: ["delete"] }], deleteAllRead: [{ type: i0.Output, args: ["deleteAllRead"] }] } });
11554
11702
 
11555
11703
  // ─── CDK overlay token (carries the resolved ref into the component) ──────────
11556
11704
  const CLX_ALERT_OPTIONS = new InjectionToken('CLX_ALERT_OPTIONS');
@@ -13942,78 +14090,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImpo
13942
14090
  args: ['clxColumn']
13943
14091
  }], headerCell: [{ type: i0.ContentChild, args: [i0.forwardRef(() => ClxHeaderCellDirective), { isSignal: true }] }], cell: [{ type: i0.ContentChild, args: [i0.forwardRef(() => ClxCellDirective), { isSignal: true }] }] } });
13944
14092
 
13945
- class ClxPageEmptyComponent {
13946
- _themeSvc = inject(ClxThemeService);
13947
- icon = input('inbox', ...(ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []));
13948
- /** Named "heading", not "title" — the latter shadows the native HTML title attribute (tooltip
13949
- * on hover) when bound without brackets, e.g. `title="..."` instead of `[title]="..."`. */
13950
- heading = input('Sin resultados', ...(ngDevMode ? [{ debugName: "heading" }] : /* istanbul ignore next */ []));
13951
- description = input('', ...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
13952
- ctaLabel = input('', ...(ngDevMode ? [{ debugName: "ctaLabel" }] : /* istanbul ignore next */ []));
13953
- ctaIcon = input('add', ...(ngDevMode ? [{ debugName: "ctaIcon" }] : /* istanbul ignore next */ []));
13954
- ctaColor = input(undefined, ...(ngDevMode ? [{ debugName: "ctaColor" }] : /* istanbul ignore next */ []));
13955
- _ctaColor = computed(() => this.ctaColor() ?? this._themeSvc.config().primaryColor, ...(ngDevMode ? [{ debugName: "_ctaColor" }] : /* istanbul ignore next */ []));
13956
- cta = output();
13957
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxPageEmptyComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
13958
- 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 }, heading: { classPropertyName: "heading", publicName: "heading", 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: `
13959
- <div class="w-20 h-20 rounded-2xl bg-clx-surface-2 flex items-center justify-center mb-6">
13960
- <span clx-icon [name]="icon()" size="xl" class="text-clx-text-faint"></span>
13961
- </div>
13962
-
13963
- <h1 class="text-base font-semibold text-clx-text-label mb-2">{{ heading() }}</h1>
13964
-
13965
- @if (description()) {
13966
- <p class="text-clx-text-subtle max-w-sm mb-8">{{ description() }}</p>
13967
- }
13968
-
13969
- @if (ctaLabel()) {
13970
- <button
13971
- clx-button
13972
- type="button"
13973
- [color]="_ctaColor()"
13974
- variant="solid"
13975
- [icon]="ctaIcon()"
13976
- (click)="cta.emit()">
13977
- {{ ctaLabel() }}
13978
- </button>
13979
- }
13980
- `, isInline: true, dependencies: [{ 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: ClxIconComponent, selector: "span[clx-icon]", inputs: ["name", "size", "color", "fill"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
13981
- }
13982
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxPageEmptyComponent, decorators: [{
13983
- type: Component,
13984
- args: [{
13985
- selector: 'clx-page-empty',
13986
- standalone: true,
13987
- imports: [ClxButtonComponent, ClxIconComponent],
13988
- encapsulation: ViewEncapsulation.None,
13989
- changeDetection: ChangeDetectionStrategy.OnPush,
13990
- host: { class: 'flex flex-col items-center justify-center w-full px-6 text-center text-sm' },
13991
- template: `
13992
- <div class="w-20 h-20 rounded-2xl bg-clx-surface-2 flex items-center justify-center mb-6">
13993
- <span clx-icon [name]="icon()" size="xl" class="text-clx-text-faint"></span>
13994
- </div>
13995
-
13996
- <h1 class="text-base font-semibold text-clx-text-label mb-2">{{ heading() }}</h1>
13997
-
13998
- @if (description()) {
13999
- <p class="text-clx-text-subtle max-w-sm mb-8">{{ description() }}</p>
14000
- }
14001
-
14002
- @if (ctaLabel()) {
14003
- <button
14004
- clx-button
14005
- type="button"
14006
- [color]="_ctaColor()"
14007
- variant="solid"
14008
- [icon]="ctaIcon()"
14009
- (click)="cta.emit()">
14010
- {{ ctaLabel() }}
14011
- </button>
14012
- }
14013
- `,
14014
- }]
14015
- }], propDecorators: { icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], heading: [{ type: i0.Input, args: [{ isSignal: true, alias: "heading", 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"] }] } });
14016
-
14017
14093
  class ClxTableComponent {
14018
14094
  _themeSvc = inject(ClxThemeService);
14019
14095
  // ── Inputs ─────────────────────────────────────────────────────────────────