codexly-ui 0.11.0 → 0.11.1
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.
- package/fesm2022/codexly-ui.mjs +262 -174
- package/fesm2022/codexly-ui.mjs.map +1 -1
- package/package.json +1 -1
- package/types/codexly-ui.d.ts +31 -20
package/fesm2022/codexly-ui.mjs
CHANGED
|
@@ -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>
|
|
@@ -11272,29 +11285,60 @@ const NOTIFICATION_SEVERITY_ICON = {
|
|
|
11272
11285
|
error: 'error',
|
|
11273
11286
|
};
|
|
11274
11287
|
|
|
11275
|
-
/**
|
|
11276
|
-
*
|
|
11277
|
-
*
|
|
11278
|
-
*
|
|
11279
|
-
*
|
|
11288
|
+
/** Self-contained bell trigger + floating panel — same overlay pattern as clx-profile (CDK
|
|
11289
|
+
* Overlay anchored to the trigger, no page-level backdrop), not a full-height clx-drawer. It's
|
|
11290
|
+
* "dumb" beyond that: renders whatever `items()` it's given and emits intent (itemClick/
|
|
11291
|
+
* markRead/delete/...) outward. Callers (e.g. a NotificationService backed by SSE) own fetching
|
|
11292
|
+
* and persistence — this component never calls an API itself. */
|
|
11280
11293
|
class ClxNotificationComponent {
|
|
11281
11294
|
_themeSvc = inject(ClxThemeService);
|
|
11282
11295
|
items = input.required(...(ngDevMode ? [{ debugName: "items" }] : /* istanbul ignore next */ []));
|
|
11283
11296
|
color = input(undefined, ...(ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []));
|
|
11284
|
-
|
|
11297
|
+
/** Optional third tab that filters items by ClxNotificationItem.category — e.g.
|
|
11298
|
+
* `{ id: 'orders', label: 'Órdenes' }`. Omit for just Todas/Sin leer. */
|
|
11299
|
+
categoryTab = input(undefined, ...(ngDevMode ? [{ debugName: "categoryTab" }] : /* istanbul ignore next */ []));
|
|
11285
11300
|
itemClick = output();
|
|
11286
11301
|
markRead = output();
|
|
11287
11302
|
markAllRead = output();
|
|
11288
11303
|
delete = output();
|
|
11289
11304
|
deleteAllRead = output();
|
|
11290
|
-
_filter = signal('all', ...(ngDevMode ? [{ debugName: "_filter" }] : /* istanbul ignore next */ []));
|
|
11291
11305
|
_style = this._themeSvc.notificationStyle;
|
|
11292
11306
|
_color = computed(() => this.color() ?? this._themeSvc.config().primaryColor, ...(ngDevMode ? [{ debugName: "_color" }] : /* istanbul ignore next */ []));
|
|
11293
|
-
|
|
11294
|
-
|
|
11307
|
+
// ── CDK Overlay ─────────────────────────────────────────────────────────────
|
|
11308
|
+
_sso = inject(ScrollStrategyOptions);
|
|
11309
|
+
_scrollStrategy = this._sso.reposition();
|
|
11310
|
+
_positions = [
|
|
11311
|
+
{ originX: 'end', originY: 'bottom', overlayX: 'end', overlayY: 'top', offsetY: 8 },
|
|
11312
|
+
{ originX: 'end', originY: 'top', overlayX: 'end', overlayY: 'bottom', offsetY: -8 },
|
|
11313
|
+
];
|
|
11314
|
+
_isOpen = signal(false, ...(ngDevMode ? [{ debugName: "_isOpen" }] : /* istanbul ignore next */ []));
|
|
11315
|
+
_filter = signal('all', ...(ngDevMode ? [{ debugName: "_filter" }] : /* istanbul ignore next */ []));
|
|
11316
|
+
_ringClass = computed(() => {
|
|
11317
|
+
const t = resolveColor(this._color());
|
|
11318
|
+
return `focus-visible:${t.ringBase}`;
|
|
11319
|
+
}, ...(ngDevMode ? [{ debugName: "_ringClass" }] : /* istanbul ignore next */ []));
|
|
11320
|
+
_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
11321
|
_unreadCount = computed(() => this.items().filter(i => !i.read).length, ...(ngDevMode ? [{ debugName: "_unreadCount" }] : /* istanbul ignore next */ []));
|
|
11296
11322
|
_readCount = computed(() => this.items().filter(i => i.read).length, ...(ngDevMode ? [{ debugName: "_readCount" }] : /* istanbul ignore next */ []));
|
|
11297
|
-
|
|
11323
|
+
_tabs = computed(() => {
|
|
11324
|
+
const tabs = [
|
|
11325
|
+
{ id: 'all', label: 'Todas', badge: this.items().length || undefined },
|
|
11326
|
+
{ id: 'unread', label: 'Sin leer', badge: this._unreadCount() || undefined },
|
|
11327
|
+
];
|
|
11328
|
+
const category = this.categoryTab();
|
|
11329
|
+
if (category)
|
|
11330
|
+
tabs.push({ id: category.id, label: category.label });
|
|
11331
|
+
return tabs;
|
|
11332
|
+
}, ...(ngDevMode ? [{ debugName: "_tabs" }] : /* istanbul ignore next */ []));
|
|
11333
|
+
_visibleItems = computed(() => {
|
|
11334
|
+
const f = this._filter();
|
|
11335
|
+
if (f === 'unread')
|
|
11336
|
+
return this.items().filter(i => !i.read);
|
|
11337
|
+
const category = this.categoryTab();
|
|
11338
|
+
if (category && f === category.id)
|
|
11339
|
+
return this.items().filter(i => i.category === category.id);
|
|
11340
|
+
return this.items();
|
|
11341
|
+
}, ...(ngDevMode ? [{ debugName: "_visibleItems" }] : /* istanbul ignore next */ []));
|
|
11298
11342
|
_groups = computed(() => {
|
|
11299
11343
|
const byLabel = new Map();
|
|
11300
11344
|
for (const item of this._visibleItems()) {
|
|
@@ -11307,10 +11351,9 @@ class ClxNotificationComponent {
|
|
|
11307
11351
|
}
|
|
11308
11352
|
return Array.from(byLabel, ([label, items]) => ({ label, items }));
|
|
11309
11353
|
}, ...(ngDevMode ? [{ debugName: "_groups" }] : /* istanbul ignore next */ []));
|
|
11310
|
-
_wrapClass = computed(() => `flex flex-col ${resolveContainerRadius(this._style().radius)}`, ...(ngDevMode ? [{ debugName: "_wrapClass" }] : /* istanbul ignore next */ []));
|
|
11311
11354
|
_groupLabelClass = computed(() => {
|
|
11312
11355
|
const w = this._style().groupLabelWeight;
|
|
11313
|
-
return `px-
|
|
11356
|
+
return `px-2 pt-3 pb-1.5 text-[11px] uppercase tracking-wide text-clx-text-subtle font-[${w}]`;
|
|
11314
11357
|
}, ...(ngDevMode ? [{ debugName: "_groupLabelClass" }] : /* istanbul ignore next */ []));
|
|
11315
11358
|
_linkClass = computed(() => resolveColor(this._color()).textSubtle, ...(ngDevMode ? [{ debugName: "_linkClass" }] : /* istanbul ignore next */ []));
|
|
11316
11359
|
_unreadRailClass = computed(() => resolveColor(this._style().unreadColor).bg, ...(ngDevMode ? [{ debugName: "_unreadRailClass" }] : /* istanbul ignore next */ []));
|
|
@@ -11322,7 +11365,7 @@ class ClxNotificationComponent {
|
|
|
11322
11365
|
}
|
|
11323
11366
|
_iconWrapClass(item) {
|
|
11324
11367
|
const c = resolveColor(this._severityColor(item.severity));
|
|
11325
|
-
return `flex items-center justify-center rounded-lg shrink-0 ${c.bgSubtle} ${c.textSubtle}
|
|
11368
|
+
return `flex items-center justify-center rounded-lg shrink-0 w-8.5 h-8.5 mt-0.5 ${c.bgSubtle} ${c.textSubtle}`;
|
|
11326
11369
|
}
|
|
11327
11370
|
_defaultIcon(severity) {
|
|
11328
11371
|
return NOTIFICATION_SEVERITY_ICON[severity];
|
|
@@ -11332,11 +11375,11 @@ class ClxNotificationComponent {
|
|
|
11332
11375
|
if (!item.read)
|
|
11333
11376
|
this.markRead.emit(item.id);
|
|
11334
11377
|
}
|
|
11335
|
-
|
|
11336
|
-
|
|
11337
|
-
|
|
11338
|
-
|
|
11339
|
-
|
|
11378
|
+
_toggle() { this._isOpen.update(v => !v); }
|
|
11379
|
+
_close() { this._isOpen.set(false); }
|
|
11380
|
+
_onKeydown(event) {
|
|
11381
|
+
if (event.key === 'Escape')
|
|
11382
|
+
this._close();
|
|
11340
11383
|
}
|
|
11341
11384
|
_severityColor(severity) {
|
|
11342
11385
|
return this._style().severityColors[severity];
|
|
@@ -11358,199 +11401,244 @@ class ClxNotificationComponent {
|
|
|
11358
11401
|
return new Date(iso).toLocaleTimeString('es-CO', { hour: '2-digit', minute: '2-digit' });
|
|
11359
11402
|
}
|
|
11360
11403
|
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 },
|
|
11362
|
-
|
|
11363
|
-
|
|
11364
|
-
|
|
11365
|
-
|
|
11366
|
-
|
|
11367
|
-
|
|
11368
|
-
|
|
11369
|
-
|
|
11370
|
-
|
|
11371
|
-
|
|
11372
|
-
|
|
11373
|
-
|
|
11374
|
-
|
|
11375
|
-
|
|
11376
|
-
|
|
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>
|
|
11404
|
+
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: `
|
|
11405
|
+
<!-- Trigger -->
|
|
11406
|
+
<button
|
|
11407
|
+
#origin="cdkOverlayOrigin"
|
|
11408
|
+
cdkOverlayOrigin
|
|
11409
|
+
type="button"
|
|
11410
|
+
aria-label="Notificaciones"
|
|
11411
|
+
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"
|
|
11412
|
+
[class]="_ringClass()"
|
|
11413
|
+
(click)="_toggle()">
|
|
11414
|
+
<span clx-icon name="notifications" size="sm"></span>
|
|
11415
|
+
@if (_unreadCount() > 0) {
|
|
11416
|
+
<span clx-badge [color]="_style().unreadColor" variant="solid" size="xs" shape="circle"
|
|
11417
|
+
class="absolute -top-0.5 -right-0.5">{{ _unreadCount() > 9 ? '9+' : _unreadCount() }}</span>
|
|
11418
|
+
}
|
|
11419
|
+
</button>
|
|
11397
11420
|
|
|
11398
|
-
|
|
11399
|
-
|
|
11400
|
-
|
|
11401
|
-
|
|
11402
|
-
|
|
11403
|
-
|
|
11404
|
-
|
|
11405
|
-
|
|
11406
|
-
|
|
11407
|
-
|
|
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>
|
|
11421
|
+
<!-- Overlay panel -->
|
|
11422
|
+
<ng-template
|
|
11423
|
+
cdkConnectedOverlay
|
|
11424
|
+
[cdkConnectedOverlayOrigin]="origin"
|
|
11425
|
+
[cdkConnectedOverlayOpen]="_isOpen()"
|
|
11426
|
+
[cdkConnectedOverlayPositions]="_positions"
|
|
11427
|
+
[cdkConnectedOverlayScrollStrategy]="_scrollStrategy"
|
|
11428
|
+
[cdkConnectedOverlayPush]="true"
|
|
11429
|
+
(overlayOutsideClick)="_close()"
|
|
11430
|
+
(overlayKeydown)="_onKeydown($event)">
|
|
11416
11431
|
|
|
11417
|
-
|
|
11418
|
-
|
|
11419
|
-
|
|
11420
|
-
|
|
11432
|
+
<div [class]="_panelClass()">
|
|
11433
|
+
<!-- Header -->
|
|
11434
|
+
<div class="flex items-center justify-between gap-3 px-4 pt-4 pb-1">
|
|
11435
|
+
<p class="text-base font-semibold text-clx-text-label">Notificaciones</p>
|
|
11436
|
+
<div class="flex items-center gap-3">
|
|
11437
|
+
@if (_unreadCount() > 0) {
|
|
11438
|
+
<button type="button" class="text-xs font-semibold shrink-0" [class]="_linkClass()"
|
|
11439
|
+
(click)="markAllRead.emit()">
|
|
11440
|
+
Marcar todo leído
|
|
11441
|
+
</button>
|
|
11442
|
+
}
|
|
11443
|
+
<button type="button" class="w-6 h-6 flex items-center justify-center rounded-md text-clx-text-muted hover:bg-clx-surface-2"
|
|
11444
|
+
aria-label="Cerrar" (click)="_close()">
|
|
11445
|
+
<span clx-icon name="close" size="xs"></span>
|
|
11446
|
+
</button>
|
|
11447
|
+
</div>
|
|
11448
|
+
</div>
|
|
11449
|
+
|
|
11450
|
+
<!-- Tabs -->
|
|
11451
|
+
<div class="px-4">
|
|
11452
|
+
<clx-tabs [tabs]="_tabs()" [(activeTab)]="_filter" [clxColor]="_color()" />
|
|
11453
|
+
</div>
|
|
11454
|
+
|
|
11455
|
+
<!-- List -->
|
|
11456
|
+
<div class="max-h-105 overflow-y-auto px-2 pb-2">
|
|
11457
|
+
@if (_groups().length) {
|
|
11458
|
+
@for (group of _groups(); track group.label) {
|
|
11459
|
+
<p [class]="_groupLabelClass()">{{ group.label }}</p>
|
|
11460
|
+
@for (item of group.items; track item.id) {
|
|
11461
|
+
<div
|
|
11462
|
+
class="group relative flex items-start gap-3 pl-3 pr-2 rounded-lg cursor-pointer hover:bg-clx-surface-2 py-2.5"
|
|
11463
|
+
role="button"
|
|
11464
|
+
tabindex="0"
|
|
11465
|
+
(click)="_open(item)"
|
|
11466
|
+
(keydown.enter)="_open(item)">
|
|
11467
|
+
|
|
11468
|
+
<span class="absolute left-0.5 top-1 bottom-1 w-0.75 rounded-full {{ item.read ? '' : _unreadRailClass() }}"></span>
|
|
11469
|
+
|
|
11470
|
+
<span [class]="_iconWrapClass(item)">
|
|
11471
|
+
<span clx-icon [name]="item.icon || _defaultIcon(item.severity)" size="sm"></span>
|
|
11472
|
+
</span>
|
|
11473
|
+
|
|
11474
|
+
<div class="flex-1 min-w-0">
|
|
11475
|
+
<p class="flex items-baseline gap-1.5 text-sm" [class]="_titleClass(item)">
|
|
11476
|
+
@if (!item.read) {
|
|
11477
|
+
<span [class]="_unreadDotClass()"></span>
|
|
11478
|
+
}
|
|
11479
|
+
<span class="truncate">{{ item.title }}</span>
|
|
11480
|
+
</p>
|
|
11481
|
+
@if (item.detail) {
|
|
11482
|
+
<p class="mt-0.5 text-sm line-clamp-2" [class]="_detailClass()">{{ item.detail }}</p>
|
|
11421
11483
|
}
|
|
11422
|
-
<
|
|
11423
|
-
</
|
|
11424
|
-
@if (item.detail) {
|
|
11425
|
-
<p class="mt-0.5 line-clamp-2 {{ _sizeTokens().detail }}" [class]="_detailClass()">{{ item.detail }}</p>
|
|
11426
|
-
}
|
|
11427
|
-
</div>
|
|
11484
|
+
<p class="mt-1 text-xs text-clx-text-subtle tabular-nums">{{ _timeOf(item.createdAt) }}</p>
|
|
11485
|
+
</div>
|
|
11428
11486
|
|
|
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
11487
|
<button type="button"
|
|
11432
|
-
class="opacity-0 group-hover:opacity-100 focus-visible:opacity-100 transition-opacity rounded-md p-
|
|
11488
|
+
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
11489
|
aria-label="Eliminar notificación"
|
|
11434
11490
|
(click)="$event.stopPropagation(); delete.emit(item.id)">
|
|
11435
11491
|
<span clx-icon name="close" size="xs"></span>
|
|
11436
11492
|
</button>
|
|
11437
11493
|
</div>
|
|
11438
|
-
|
|
11494
|
+
}
|
|
11439
11495
|
}
|
|
11496
|
+
} @else {
|
|
11497
|
+
<div class="flex flex-col items-center justify-center gap-2 py-14 text-center">
|
|
11498
|
+
<span clx-icon name="notifications_off" size="xl" class="text-clx-text-subtle"></span>
|
|
11499
|
+
<p class="text-sm font-medium text-clx-text-label">
|
|
11500
|
+
{{ _filter() === 'unread' ? 'No tienes notificaciones sin leer' : 'No hay notificaciones' }}
|
|
11501
|
+
</p>
|
|
11502
|
+
</div>
|
|
11440
11503
|
}
|
|
11441
11504
|
</div>
|
|
11442
|
-
|
|
11443
|
-
|
|
11444
|
-
<
|
|
11445
|
-
|
|
11446
|
-
|
|
11447
|
-
|
|
11448
|
-
|
|
11449
|
-
|
|
11450
|
-
|
|
11451
|
-
|
|
11505
|
+
|
|
11506
|
+
@if (_readCount() > 0) {
|
|
11507
|
+
<div class="flex justify-end px-4 py-2.5 border-t border-clx-border-soft">
|
|
11508
|
+
<button type="button" class="text-xs font-semibold text-clx-text-subtle hover:text-red-500"
|
|
11509
|
+
(click)="deleteAllRead.emit()">
|
|
11510
|
+
Eliminar leídas
|
|
11511
|
+
</button>
|
|
11512
|
+
</div>
|
|
11513
|
+
}
|
|
11514
|
+
</div>
|
|
11515
|
+
</ng-template>
|
|
11516
|
+
`, 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: ClxTabsComponent, selector: "clx-tabs", inputs: ["tabs", "clxColor", "activeTab"], outputs: ["activeTabChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
11452
11517
|
}
|
|
11453
11518
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.15", ngImport: i0, type: ClxNotificationComponent, decorators: [{
|
|
11454
11519
|
type: Component,
|
|
11455
11520
|
args: [{
|
|
11456
11521
|
selector: 'clx-notification',
|
|
11457
11522
|
standalone: true,
|
|
11458
|
-
imports: [
|
|
11523
|
+
imports: [OverlayModule, ClxIconComponent, ClxBadgeComponent, ClxTabsComponent],
|
|
11459
11524
|
template: `
|
|
11460
|
-
|
|
11461
|
-
|
|
11462
|
-
|
|
11463
|
-
|
|
11464
|
-
|
|
11465
|
-
|
|
11466
|
-
|
|
11467
|
-
|
|
11468
|
-
|
|
11469
|
-
|
|
11470
|
-
|
|
11471
|
-
|
|
11472
|
-
|
|
11473
|
-
|
|
11474
|
-
|
|
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>
|
|
11525
|
+
<!-- Trigger -->
|
|
11526
|
+
<button
|
|
11527
|
+
#origin="cdkOverlayOrigin"
|
|
11528
|
+
cdkOverlayOrigin
|
|
11529
|
+
type="button"
|
|
11530
|
+
aria-label="Notificaciones"
|
|
11531
|
+
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"
|
|
11532
|
+
[class]="_ringClass()"
|
|
11533
|
+
(click)="_toggle()">
|
|
11534
|
+
<span clx-icon name="notifications" size="sm"></span>
|
|
11535
|
+
@if (_unreadCount() > 0) {
|
|
11536
|
+
<span clx-badge [color]="_style().unreadColor" variant="solid" size="xs" shape="circle"
|
|
11537
|
+
class="absolute -top-0.5 -right-0.5">{{ _unreadCount() > 9 ? '9+' : _unreadCount() }}</span>
|
|
11538
|
+
}
|
|
11539
|
+
</button>
|
|
11495
11540
|
|
|
11496
|
-
|
|
11497
|
-
|
|
11498
|
-
|
|
11499
|
-
|
|
11500
|
-
|
|
11501
|
-
|
|
11502
|
-
|
|
11503
|
-
|
|
11504
|
-
|
|
11505
|
-
|
|
11506
|
-
|
|
11507
|
-
|
|
11508
|
-
|
|
11509
|
-
|
|
11510
|
-
|
|
11511
|
-
|
|
11512
|
-
|
|
11513
|
-
|
|
11541
|
+
<!-- Overlay panel -->
|
|
11542
|
+
<ng-template
|
|
11543
|
+
cdkConnectedOverlay
|
|
11544
|
+
[cdkConnectedOverlayOrigin]="origin"
|
|
11545
|
+
[cdkConnectedOverlayOpen]="_isOpen()"
|
|
11546
|
+
[cdkConnectedOverlayPositions]="_positions"
|
|
11547
|
+
[cdkConnectedOverlayScrollStrategy]="_scrollStrategy"
|
|
11548
|
+
[cdkConnectedOverlayPush]="true"
|
|
11549
|
+
(overlayOutsideClick)="_close()"
|
|
11550
|
+
(overlayKeydown)="_onKeydown($event)">
|
|
11551
|
+
|
|
11552
|
+
<div [class]="_panelClass()">
|
|
11553
|
+
<!-- Header -->
|
|
11554
|
+
<div class="flex items-center justify-between gap-3 px-4 pt-4 pb-1">
|
|
11555
|
+
<p class="text-base font-semibold text-clx-text-label">Notificaciones</p>
|
|
11556
|
+
<div class="flex items-center gap-3">
|
|
11557
|
+
@if (_unreadCount() > 0) {
|
|
11558
|
+
<button type="button" class="text-xs font-semibold shrink-0" [class]="_linkClass()"
|
|
11559
|
+
(click)="markAllRead.emit()">
|
|
11560
|
+
Marcar todo leído
|
|
11561
|
+
</button>
|
|
11562
|
+
}
|
|
11563
|
+
<button type="button" class="w-6 h-6 flex items-center justify-center rounded-md text-clx-text-muted hover:bg-clx-surface-2"
|
|
11564
|
+
aria-label="Cerrar" (click)="_close()">
|
|
11565
|
+
<span clx-icon name="close" size="xs"></span>
|
|
11566
|
+
</button>
|
|
11567
|
+
</div>
|
|
11568
|
+
</div>
|
|
11569
|
+
|
|
11570
|
+
<!-- Tabs -->
|
|
11571
|
+
<div class="px-4">
|
|
11572
|
+
<clx-tabs [tabs]="_tabs()" [(activeTab)]="_filter" [clxColor]="_color()" />
|
|
11573
|
+
</div>
|
|
11514
11574
|
|
|
11515
|
-
|
|
11516
|
-
|
|
11517
|
-
|
|
11518
|
-
|
|
11575
|
+
<!-- List -->
|
|
11576
|
+
<div class="max-h-105 overflow-y-auto px-2 pb-2">
|
|
11577
|
+
@if (_groups().length) {
|
|
11578
|
+
@for (group of _groups(); track group.label) {
|
|
11579
|
+
<p [class]="_groupLabelClass()">{{ group.label }}</p>
|
|
11580
|
+
@for (item of group.items; track item.id) {
|
|
11581
|
+
<div
|
|
11582
|
+
class="group relative flex items-start gap-3 pl-3 pr-2 rounded-lg cursor-pointer hover:bg-clx-surface-2 py-2.5"
|
|
11583
|
+
role="button"
|
|
11584
|
+
tabindex="0"
|
|
11585
|
+
(click)="_open(item)"
|
|
11586
|
+
(keydown.enter)="_open(item)">
|
|
11587
|
+
|
|
11588
|
+
<span class="absolute left-0.5 top-1 bottom-1 w-0.75 rounded-full {{ item.read ? '' : _unreadRailClass() }}"></span>
|
|
11589
|
+
|
|
11590
|
+
<span [class]="_iconWrapClass(item)">
|
|
11591
|
+
<span clx-icon [name]="item.icon || _defaultIcon(item.severity)" size="sm"></span>
|
|
11592
|
+
</span>
|
|
11593
|
+
|
|
11594
|
+
<div class="flex-1 min-w-0">
|
|
11595
|
+
<p class="flex items-baseline gap-1.5 text-sm" [class]="_titleClass(item)">
|
|
11596
|
+
@if (!item.read) {
|
|
11597
|
+
<span [class]="_unreadDotClass()"></span>
|
|
11598
|
+
}
|
|
11599
|
+
<span class="truncate">{{ item.title }}</span>
|
|
11600
|
+
</p>
|
|
11601
|
+
@if (item.detail) {
|
|
11602
|
+
<p class="mt-0.5 text-sm line-clamp-2" [class]="_detailClass()">{{ item.detail }}</p>
|
|
11519
11603
|
}
|
|
11520
|
-
<
|
|
11521
|
-
</
|
|
11522
|
-
@if (item.detail) {
|
|
11523
|
-
<p class="mt-0.5 line-clamp-2 {{ _sizeTokens().detail }}" [class]="_detailClass()">{{ item.detail }}</p>
|
|
11524
|
-
}
|
|
11525
|
-
</div>
|
|
11604
|
+
<p class="mt-1 text-xs text-clx-text-subtle tabular-nums">{{ _timeOf(item.createdAt) }}</p>
|
|
11605
|
+
</div>
|
|
11526
11606
|
|
|
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
11607
|
<button type="button"
|
|
11530
|
-
class="opacity-0 group-hover:opacity-100 focus-visible:opacity-100 transition-opacity rounded-md p-
|
|
11608
|
+
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
11609
|
aria-label="Eliminar notificación"
|
|
11532
11610
|
(click)="$event.stopPropagation(); delete.emit(item.id)">
|
|
11533
11611
|
<span clx-icon name="close" size="xs"></span>
|
|
11534
11612
|
</button>
|
|
11535
11613
|
</div>
|
|
11536
|
-
|
|
11614
|
+
}
|
|
11537
11615
|
}
|
|
11616
|
+
} @else {
|
|
11617
|
+
<div class="flex flex-col items-center justify-center gap-2 py-14 text-center">
|
|
11618
|
+
<span clx-icon name="notifications_off" size="xl" class="text-clx-text-subtle"></span>
|
|
11619
|
+
<p class="text-sm font-medium text-clx-text-label">
|
|
11620
|
+
{{ _filter() === 'unread' ? 'No tienes notificaciones sin leer' : 'No hay notificaciones' }}
|
|
11621
|
+
</p>
|
|
11622
|
+
</div>
|
|
11538
11623
|
}
|
|
11539
11624
|
</div>
|
|
11540
|
-
|
|
11541
|
-
|
|
11542
|
-
<
|
|
11543
|
-
|
|
11544
|
-
|
|
11545
|
-
|
|
11546
|
-
|
|
11547
|
-
|
|
11548
|
-
|
|
11625
|
+
|
|
11626
|
+
@if (_readCount() > 0) {
|
|
11627
|
+
<div class="flex justify-end px-4 py-2.5 border-t border-clx-border-soft">
|
|
11628
|
+
<button type="button" class="text-xs font-semibold text-clx-text-subtle hover:text-red-500"
|
|
11629
|
+
(click)="deleteAllRead.emit()">
|
|
11630
|
+
Eliminar leídas
|
|
11631
|
+
</button>
|
|
11632
|
+
</div>
|
|
11633
|
+
}
|
|
11634
|
+
</div>
|
|
11635
|
+
</ng-template>
|
|
11549
11636
|
`,
|
|
11550
11637
|
encapsulation: ViewEncapsulation.None,
|
|
11551
11638
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
11639
|
+
host: { class: 'relative inline-flex items-center' },
|
|
11552
11640
|
}]
|
|
11553
|
-
}], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: true }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }],
|
|
11641
|
+
}], 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
11642
|
|
|
11555
11643
|
// ─── CDK overlay token (carries the resolved ref into the component) ──────────
|
|
11556
11644
|
const CLX_ALERT_OPTIONS = new InjectionToken('CLX_ALERT_OPTIONS');
|