mesauth-angular 1.15.1 → 1.16.0
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/README.md +337 -337
- package/fesm2022/mesauth-angular.mjs +233 -99
- package/fesm2022/mesauth-angular.mjs.map +1 -1
- package/mesauth-angular-1.16.0.tgz +0 -0
- package/package.json +1 -1
- package/types/mesauth-angular.d.ts +39 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { signal, Injectable, InjectionToken, makeEnvironmentProviders, provideAppInitializer, inject, NgModule, input, booleanAttribute, computed, HostBinding, Component, output, effect, HostListener, ViewChild, DestroyRef, Directive } from '@angular/core';
|
|
2
|
+
import { signal, Injectable, InjectionToken, makeEnvironmentProviders, provideAppInitializer, inject, NgModule, input, booleanAttribute, computed, HostBinding, Component, output, effect, HostListener, ViewChild, ElementRef, DestroyRef, Directive } from '@angular/core';
|
|
3
3
|
import { toObservable, toSignal, takeUntilDestroyed, rxResource } from '@angular/core/rxjs-interop';
|
|
4
|
-
import { catchError, of, Subject, EMPTY, timer, throwError, firstValueFrom, forkJoin } from 'rxjs';
|
|
4
|
+
import { catchError, of, Subject, EMPTY, timer, throwError, firstValueFrom, distinctUntilChanged, switchMap as switchMap$1, forkJoin } from 'rxjs';
|
|
5
5
|
import { HttpClient } from '@angular/common/http';
|
|
6
6
|
import { HubConnectionBuilder, LogLevel } from '@microsoft/signalr';
|
|
7
7
|
import { map, tap, catchError as catchError$1, switchMap } from 'rxjs/operators';
|
|
@@ -10,7 +10,7 @@ import { DomSanitizer } from '@angular/platform-browser';
|
|
|
10
10
|
import { DatePipe } from '@angular/common';
|
|
11
11
|
|
|
12
12
|
/** Current installed package version — keep in sync with package.json. */
|
|
13
|
-
const PACKAGE_VERSION = '1.
|
|
13
|
+
const PACKAGE_VERSION = '1.16.0';
|
|
14
14
|
/**
|
|
15
15
|
* Provides server-driven UI configuration loaded from the hosted manifest.
|
|
16
16
|
* Components read `labels()` and `features()` signals instead of hardcoded strings.
|
|
@@ -72,10 +72,10 @@ class MaUiConfigService {
|
|
|
72
72
|
}
|
|
73
73
|
});
|
|
74
74
|
}
|
|
75
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
76
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
75
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: MaUiConfigService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
76
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: MaUiConfigService, providedIn: 'root' });
|
|
77
77
|
}
|
|
78
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
78
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: MaUiConfigService, decorators: [{
|
|
79
79
|
type: Injectable,
|
|
80
80
|
args: [{ providedIn: 'root' }]
|
|
81
81
|
}] });
|
|
@@ -360,10 +360,14 @@ class MesAuthService {
|
|
|
360
360
|
}
|
|
361
361
|
}));
|
|
362
362
|
}
|
|
363
|
-
|
|
364
|
-
|
|
363
|
+
getUserX(userId) {
|
|
364
|
+
const url = `${this.apiBase}/urs/users/${userId}`;
|
|
365
|
+
return this.http.get(url, { withCredentials: this.config?.withCredentials ?? true });
|
|
366
|
+
}
|
|
367
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: MesAuthService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
368
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: MesAuthService });
|
|
365
369
|
}
|
|
366
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
370
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: MesAuthService, decorators: [{
|
|
367
371
|
type: Injectable
|
|
368
372
|
}], ctorParameters: () => [] });
|
|
369
373
|
|
|
@@ -435,13 +439,13 @@ function appendPermissions(body, allowedActions) {
|
|
|
435
439
|
}
|
|
436
440
|
|
|
437
441
|
class MesAuthModule {
|
|
438
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
439
|
-
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.
|
|
440
|
-
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.
|
|
442
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: MesAuthModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
443
|
+
static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.7", ngImport: i0, type: MesAuthModule });
|
|
444
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: MesAuthModule, providers: [
|
|
441
445
|
MesAuthService
|
|
442
446
|
] });
|
|
443
447
|
}
|
|
444
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
448
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: MesAuthModule, decorators: [{
|
|
445
449
|
type: NgModule,
|
|
446
450
|
args: [{
|
|
447
451
|
providers: [
|
|
@@ -471,10 +475,15 @@ class ThemeService {
|
|
|
471
475
|
return;
|
|
472
476
|
}
|
|
473
477
|
const html = document.documentElement;
|
|
478
|
+
const body = document.body;
|
|
474
479
|
const isDark = html.classList.contains('dark') ||
|
|
475
480
|
html.getAttribute('data-theme') === 'dark' ||
|
|
476
481
|
html.getAttribute('theme') === 'dark' ||
|
|
477
|
-
html.getAttribute('data-coreui-theme') === 'dark'
|
|
482
|
+
html.getAttribute('data-coreui-theme') === 'dark' ||
|
|
483
|
+
body.classList.contains('dark') ||
|
|
484
|
+
body.getAttribute('data-theme') === 'dark' ||
|
|
485
|
+
body.getAttribute('theme') === 'dark' ||
|
|
486
|
+
body.getAttribute('data-coreui-theme') === 'dark';
|
|
478
487
|
this._currentTheme.set(isDark ? 'dark' : 'light');
|
|
479
488
|
}
|
|
480
489
|
startWatching() {
|
|
@@ -482,11 +491,13 @@ class ThemeService {
|
|
|
482
491
|
setInterval(() => this.detectTheme(), 1000);
|
|
483
492
|
return;
|
|
484
493
|
}
|
|
485
|
-
|
|
486
|
-
this.observer.observe(document.documentElement, {
|
|
494
|
+
const config = {
|
|
487
495
|
attributes: true,
|
|
488
496
|
attributeFilter: ['class', 'data-theme', 'theme', 'data-coreui-theme']
|
|
489
|
-
}
|
|
497
|
+
};
|
|
498
|
+
this.observer = new MutationObserver(() => this.detectTheme());
|
|
499
|
+
this.observer.observe(document.documentElement, config);
|
|
500
|
+
this.observer.observe(document.body, config);
|
|
490
501
|
}
|
|
491
502
|
stopWatching() {
|
|
492
503
|
if (this.observer) {
|
|
@@ -507,10 +518,10 @@ class ThemeService {
|
|
|
507
518
|
refreshTheme() {
|
|
508
519
|
this.detectTheme();
|
|
509
520
|
}
|
|
510
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
511
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
521
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: ThemeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
522
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: ThemeService, providedIn: 'root' });
|
|
512
523
|
}
|
|
513
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
524
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: ThemeService, decorators: [{
|
|
514
525
|
type: Injectable,
|
|
515
526
|
args: [{
|
|
516
527
|
providedIn: 'root'
|
|
@@ -556,12 +567,12 @@ class MaAvatarComponent {
|
|
|
556
567
|
'--avatar-scale': this.scale()
|
|
557
568
|
}), ...(ngDevMode ? [{ debugName: "wrapperStyle" }] : /* istanbul ignore next */ []));
|
|
558
569
|
showImage = computed(() => !!this.src(), ...(ngDevMode ? [{ debugName: "showImage" }] : /* istanbul ignore next */ []));
|
|
559
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
560
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
570
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: MaAvatarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
571
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: MaAvatarComponent, isStandalone: true, selector: "ma-avatar", inputs: { src: { classPropertyName: "src", publicName: "src", isSignal: true, isRequired: false, transformFunction: null }, alt: { classPropertyName: "alt", publicName: "alt", isSignal: true, isRequired: false, transformFunction: null }, initials: { classPropertyName: "initials", publicName: "initials", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, shape: { classPropertyName: "shape", publicName: "shape", isSignal: true, isRequired: false, transformFunction: null }, frame: { classPropertyName: "frame", publicName: "frame", isSignal: true, isRequired: false, transformFunction: null }, ratio: { classPropertyName: "ratio", publicName: "ratio", isSignal: true, isRequired: false, transformFunction: null }, scale: { classPropertyName: "scale", publicName: "scale", isSignal: true, isRequired: false, transformFunction: null }, ring: { classPropertyName: "ring", publicName: "ring", isSignal: true, isRequired: false, transformFunction: null }, ringActive: { classPropertyName: "ringActive", publicName: "ringActive", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "this.themeClass" } }, ngImport: i0, template: "<div [class]=\"wrapperClass()\" [style]=\"wrapperStyle()\">\r\n @if (showImage()) {\r\n <img [src]=\"src()\" [alt]=\"alt()\" class=\"ma-avatar__img\" />\r\n } @else {\r\n <span class=\"ma-avatar__initial\">{{ initials() }}</span>\r\n }\r\n</div>\r\n", styles: [".ma-avatar{position:relative;flex-shrink:0;overflow:visible}.ma-avatar--circle{border-radius:50%}.ma-avatar--rounded{border-radius:20%}.ma-avatar--rectangle{border-radius:0}.ma-avatar--portrait{border-radius:4px}.ma-avatar--circle .ma-avatar__img,.ma-avatar--circle .ma-avatar__initial{border-radius:50%}.ma-avatar--rounded .ma-avatar__img,.ma-avatar--rounded .ma-avatar__initial{border-radius:20%}.ma-avatar--rectangle .ma-avatar__img,.ma-avatar--rectangle .ma-avatar__initial{border-radius:0}.ma-avatar--portrait .ma-avatar__img,.ma-avatar--portrait .ma-avatar__initial{border-radius:4px}.ma-avatar--ring{cursor:pointer;transition:box-shadow .3s ease,filter .3s ease}.ma-avatar--ring:hover{box-shadow:0 0 0 2px var(--primary-color, #1976d2),0 0 8px 2px var(--primary-glow, rgba(25, 118, 210, .4));filter:drop-shadow(0 0 6px var(--primary-glow, rgba(25, 118, 210, .45)))}.ma-avatar--ring-active{box-shadow:0 0 0 2px var(--primary-color, #1976d2),0 0 10px 4px var(--primary-glow, rgba(25, 118, 210, .5));animation:ring-breathe 2.5s ease-in-out infinite}@keyframes ring-breathe{0%,to{filter:drop-shadow(0 0 5px var(--primary-color, #1976d2)) drop-shadow(0 0 12px var(--primary-glow, rgba(25, 118, 210, .3)))}50%{filter:drop-shadow(0 0 10px var(--primary-color, #1976d2)) drop-shadow(0 0 24px var(--primary-glow, rgba(25, 118, 210, .5)))}}.ma-avatar__img,.ma-avatar__initial{width:100%;height:100%;object-fit:cover;display:block;position:relative;z-index:0}.ma-avatar__initial{background:linear-gradient(135deg,var(--primary-color, #1976d2),var(--primary-glow, rgba(79,70,229,.4)));color:#fff;display:flex;align-items:center;justify-content:center;font-weight:700}.ma-avatar--sm .ma-avatar__initial{font-size:14px}.ma-avatar--md .ma-avatar__initial{font-size:17px}.ma-avatar--lg .ma-avatar__initial{font-size:22px}.ma-avatar--xl .ma-avatar__initial{font-size:38px}.ma-avatar--sm{--h: calc(36px * var(--avatar-scale, 1));--h-m: 30px}.ma-avatar--md{--h: calc(44px * var(--avatar-scale, 1));--h-m: 38px}.ma-avatar--lg{--h: calc(56px * var(--avatar-scale, 1));--h-m: 48px}.ma-avatar--xl{--h: calc(96px * var(--avatar-scale, 1))}[class*=ma-avatar--ratio-]{height:var(--h);width:var(--h)}.ma-avatar--ratio-ar-43{width:calc(var(--h) * 4 / 3)}.ma-avatar--ratio-ar-169{width:calc(var(--h) * 16 / 9)}@media(max-width:768px){[class*=ma-avatar--ratio-]{height:var(--h-m);width:var(--h-m)}.ma-avatar--ratio-ar-43{width:calc(var(--h-m) * 4 / 3)}.ma-avatar--ratio-ar-169{width:calc(var(--h-m) * 16 / 9)}}\n"] });
|
|
561
572
|
}
|
|
562
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
573
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: MaAvatarComponent, decorators: [{
|
|
563
574
|
type: Component,
|
|
564
|
-
args: [{ selector: 'ma-avatar', imports: [], template: "<div [class]=\"wrapperClass()\" [style]=\"wrapperStyle()\">\n @if (showImage()) {\n <img [src]=\"src()\" [alt]=\"alt()\" class=\"ma-avatar__img\" />\n } @else {\n <span class=\"ma-avatar__initial\">{{ initials() }}</span>\n }\n</div>\n", styles: [".ma-avatar{position:relative;flex-shrink:0;overflow:visible}.ma-avatar--circle{border-radius:50%}.ma-avatar--rounded{border-radius:20%}.ma-avatar--rectangle{border-radius:0}.ma-avatar--portrait{border-radius:4px}.ma-avatar--circle .ma-avatar__img,.ma-avatar--circle .ma-avatar__initial{border-radius:50%}.ma-avatar--rounded .ma-avatar__img,.ma-avatar--rounded .ma-avatar__initial{border-radius:20%}.ma-avatar--rectangle .ma-avatar__img,.ma-avatar--rectangle .ma-avatar__initial{border-radius:0}.ma-avatar--portrait .ma-avatar__img,.ma-avatar--portrait .ma-avatar__initial{border-radius:4px}.ma-avatar--ring{cursor:pointer;transition:box-shadow .3s ease,filter .3s ease}.ma-avatar--ring:hover{box-shadow:0 0 0 2px var(--primary-color, #1976d2),0 0 8px 2px var(--primary-glow, rgba(25, 118, 210, .4));filter:drop-shadow(0 0 6px var(--primary-glow, rgba(25, 118, 210, .45)))}.ma-avatar--ring-active{box-shadow:0 0 0 2px var(--primary-color, #1976d2),0 0 10px 4px var(--primary-glow, rgba(25, 118, 210, .5));animation:ring-breathe 2.5s ease-in-out infinite}@keyframes ring-breathe{0%,to{filter:drop-shadow(0 0 5px var(--primary-color, #1976d2)) drop-shadow(0 0 12px var(--primary-glow, rgba(25, 118, 210, .3)))}50%{filter:drop-shadow(0 0 10px var(--primary-color, #1976d2)) drop-shadow(0 0 24px var(--primary-glow, rgba(25, 118, 210, .5)))}}.ma-avatar__img,.ma-avatar__initial{width:100%;height:100%;object-fit:cover;display:block;position:relative;z-index:0}.ma-avatar__initial{background:linear-gradient(135deg,var(--primary-color, #1976d2),var(--primary-glow, rgba(79,70,229,.4)));color:#fff;display:flex;align-items:center;justify-content:center;font-weight:700}.ma-avatar--sm .ma-avatar__initial{font-size:14px}.ma-avatar--md .ma-avatar__initial{font-size:17px}.ma-avatar--lg .ma-avatar__initial{font-size:22px}.ma-avatar--xl .ma-avatar__initial{font-size:38px}.ma-avatar--sm{--h: calc(36px * var(--avatar-scale, 1));--h-m: 30px}.ma-avatar--md{--h: calc(44px * var(--avatar-scale, 1));--h-m: 38px}.ma-avatar--lg{--h: calc(56px * var(--avatar-scale, 1));--h-m: 48px}.ma-avatar--xl{--h: calc(96px * var(--avatar-scale, 1))}[class*=ma-avatar--ratio-]{height:var(--h);width:var(--h)}.ma-avatar--ratio-ar-43{width:calc(var(--h) * 4 / 3)}.ma-avatar--ratio-ar-169{width:calc(var(--h) * 16 / 9)}@media(max-width:768px){[class*=ma-avatar--ratio-]{height:var(--h-m);width:var(--h-m)}.ma-avatar--ratio-ar-43{width:calc(var(--h-m) * 4 / 3)}.ma-avatar--ratio-ar-169{width:calc(var(--h-m) * 16 / 9)}}\n"] }]
|
|
575
|
+
args: [{ selector: 'ma-avatar', imports: [], template: "<div [class]=\"wrapperClass()\" [style]=\"wrapperStyle()\">\r\n @if (showImage()) {\r\n <img [src]=\"src()\" [alt]=\"alt()\" class=\"ma-avatar__img\" />\r\n } @else {\r\n <span class=\"ma-avatar__initial\">{{ initials() }}</span>\r\n }\r\n</div>\r\n", styles: [".ma-avatar{position:relative;flex-shrink:0;overflow:visible}.ma-avatar--circle{border-radius:50%}.ma-avatar--rounded{border-radius:20%}.ma-avatar--rectangle{border-radius:0}.ma-avatar--portrait{border-radius:4px}.ma-avatar--circle .ma-avatar__img,.ma-avatar--circle .ma-avatar__initial{border-radius:50%}.ma-avatar--rounded .ma-avatar__img,.ma-avatar--rounded .ma-avatar__initial{border-radius:20%}.ma-avatar--rectangle .ma-avatar__img,.ma-avatar--rectangle .ma-avatar__initial{border-radius:0}.ma-avatar--portrait .ma-avatar__img,.ma-avatar--portrait .ma-avatar__initial{border-radius:4px}.ma-avatar--ring{cursor:pointer;transition:box-shadow .3s ease,filter .3s ease}.ma-avatar--ring:hover{box-shadow:0 0 0 2px var(--primary-color, #1976d2),0 0 8px 2px var(--primary-glow, rgba(25, 118, 210, .4));filter:drop-shadow(0 0 6px var(--primary-glow, rgba(25, 118, 210, .45)))}.ma-avatar--ring-active{box-shadow:0 0 0 2px var(--primary-color, #1976d2),0 0 10px 4px var(--primary-glow, rgba(25, 118, 210, .5));animation:ring-breathe 2.5s ease-in-out infinite}@keyframes ring-breathe{0%,to{filter:drop-shadow(0 0 5px var(--primary-color, #1976d2)) drop-shadow(0 0 12px var(--primary-glow, rgba(25, 118, 210, .3)))}50%{filter:drop-shadow(0 0 10px var(--primary-color, #1976d2)) drop-shadow(0 0 24px var(--primary-glow, rgba(25, 118, 210, .5)))}}.ma-avatar__img,.ma-avatar__initial{width:100%;height:100%;object-fit:cover;display:block;position:relative;z-index:0}.ma-avatar__initial{background:linear-gradient(135deg,var(--primary-color, #1976d2),var(--primary-glow, rgba(79,70,229,.4)));color:#fff;display:flex;align-items:center;justify-content:center;font-weight:700}.ma-avatar--sm .ma-avatar__initial{font-size:14px}.ma-avatar--md .ma-avatar__initial{font-size:17px}.ma-avatar--lg .ma-avatar__initial{font-size:22px}.ma-avatar--xl .ma-avatar__initial{font-size:38px}.ma-avatar--sm{--h: calc(36px * var(--avatar-scale, 1));--h-m: 30px}.ma-avatar--md{--h: calc(44px * var(--avatar-scale, 1));--h-m: 38px}.ma-avatar--lg{--h: calc(56px * var(--avatar-scale, 1));--h-m: 48px}.ma-avatar--xl{--h: calc(96px * var(--avatar-scale, 1))}[class*=ma-avatar--ratio-]{height:var(--h);width:var(--h)}.ma-avatar--ratio-ar-43{width:calc(var(--h) * 4 / 3)}.ma-avatar--ratio-ar-169{width:calc(var(--h) * 16 / 9)}@media(max-width:768px){[class*=ma-avatar--ratio-]{height:var(--h-m);width:var(--h-m)}.ma-avatar--ratio-ar-43{width:calc(var(--h-m) * 4 / 3)}.ma-avatar--ratio-ar-169{width:calc(var(--h-m) * 16 / 9)}}\n"] }]
|
|
565
576
|
}], propDecorators: { src: [{ type: i0.Input, args: [{ isSignal: true, alias: "src", required: false }] }], alt: [{ type: i0.Input, args: [{ isSignal: true, alias: "alt", required: false }] }], initials: [{ type: i0.Input, args: [{ isSignal: true, alias: "initials", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], shape: [{ type: i0.Input, args: [{ isSignal: true, alias: "shape", required: false }] }], frame: [{ type: i0.Input, args: [{ isSignal: true, alias: "frame", required: false }] }], ratio: [{ type: i0.Input, args: [{ isSignal: true, alias: "ratio", required: false }] }], scale: [{ type: i0.Input, args: [{ isSignal: true, alias: "scale", required: false }] }], ring: [{ type: i0.Input, args: [{ isSignal: true, alias: "ring", required: false }] }], ringActive: [{ type: i0.Input, args: [{ isSignal: true, alias: "ringActive", required: false }] }], themeClass: [{
|
|
566
577
|
type: HostBinding,
|
|
567
578
|
args: ['class']
|
|
@@ -725,12 +736,12 @@ class UserProfileComponent {
|
|
|
725
736
|
onNotificationClick() {
|
|
726
737
|
this.notificationClick.emit();
|
|
727
738
|
}
|
|
728
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
729
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: UserProfileComponent, isStandalone: true, selector: "ma-user-profile", inputs: { inputAvatarShape: { classPropertyName: "inputAvatarShape", publicName: "inputAvatarShape", isSignal: true, isRequired: false, transformFunction: null }, showBell: { classPropertyName: "showBell", publicName: "showBell", isSignal: true, isRequired: false, transformFunction: null }, showApproval: { classPropertyName: "showApproval", publicName: "showApproval", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { notificationClick: "notificationClick", approvalClick: "approvalClick" }, host: { listeners: { "document:click": "onDocumentClick($event)" }, properties: { "class": "this.themeClass" } }, ngImport: i0, template: "<div class=\"user-profile-container\">\n @if (!currentUser()) {\n <!-- Not logged in -->\n <button class=\"login-btn\" (click)=\"onLogin()\">Login</button>\n } @else {\n <!-- Logged in -->\n <div class=\"user-header\">\n <!-- Notification Bell -->\n @if (showBell()) {\n <button class=\"notification-btn\" [class.has-unread]=\"unreadCount() > 0\" (click)=\"onNotificationClick()\" title=\"Notifications\" aria-label=\"Notifications\">\n <svg class=\"bell-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9\"/>\n <path d=\"M13.73 21a2 2 0 0 1-3.46 0\"/>\n </svg>\n @if (unreadCount() > 0) {\n <span class=\"badge\">{{ unreadCount() > 99 ? '99+' : unreadCount() }}</span>\n }\n </button>\n }\n \n\n <!-- Approval Button -->\n @if (showApproval()) {\n <button class=\"notification-btn\" [class.has-unread]=\"pendingApprovalCount() > 0\" (click)=\"onApprovalClick()\" title=\"Approvals\" aria-label=\"Approvals\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M9 11l3 3L22 4\"/>\n <path d=\"M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11\"/>\n </svg>\n @if (pendingApprovalCount() > 0) {\n <span class=\"badge\">{{ pendingApprovalCount() > 99 ? '99+' : pendingApprovalCount() }}</span>\n }\n </button>\n } \n\n <!-- User Avatar + Dropdown -->\n <div class=\"user-menu-wrapper\">\n <button class=\"user-menu-btn\" (click)=\"toggleDropdown()\" [attr.aria-label]=\"'User menu for ' + (currentUser().fullName || currentUser().userName)\" aria-haspopup=\"true\" [attr.aria-expanded]=\"dropdownOpen()\">\n <ma-avatar\n [src]=\"getAvatarUrl(currentUser())\"\n [alt]=\"currentUser().fullName || currentUser().userName || ''\"\n [initials]=\"getLastNameInitial(currentUser())\"\n [size]=\"navAvatarSize()\"\n [shape]=\"avatarShape()\"\n [ratio]=\"avatarRatio()\"\n [frame]=\"avatarFrame()\" \n [ring]=\"true\"\n [ringActive]=\"dropdownOpen()\" /> \n </button>\n\n @if (dropdownOpen()) {\n <div class=\"mes-dropdown-menu\">\n <!-- User info header -->\n <div class=\"mes-dropdown-header\">\n <div class=\"dropdown-avatar-wrap\">\n <ma-avatar\n [src]=\"getAvatarUrl(currentUser())\"\n [alt]=\"currentUser().fullName || currentUser().userName || ''\"\n [initials]=\"getLastNameInitial(currentUser())\"\n [size]=\"dropAvatarSize()\"\n [shape]=\"avatarShape()\"\n [ratio]=\"avatarRatio()\"\n [frame]=\"avatarFrame()\"\n [scale]=\"1.5\" /> \n </div>\n <div class=\"dropdown-info-col\">\n <div class=\"dropdown-user-info\">\n <span class=\"dropdown-user-name\">{{ currentUser().fullName || currentUser().userName }}</span> \n <span class=\"dropdown-user-sub\">\n @if (currentUser().position || currentUser().department) {\n {{ currentUser().position || currentUser().department }} \n }\n @if (currentUser().givenTitle) {\n <span class=\"given-title-badge given-title\"\n [class]=\"'given-color-' + givenStyle()\">{{ currentUser().givenTitle }}</span>\n }\n </span>\n </div>\n <div class=\"dropdown-user-actions\">\n <button class=\"icon-action profile-link\" (click)=\"onViewProfile()\" title=\"View Profile\" aria-label=\"View Profile\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2\"/><circle cx=\"12\" cy=\"7\" r=\"4\"/>\n </svg>\n </button>\n <button class=\"icon-action logout-item\" (click)=\"onLogout()\" title=\"Logout\" aria-label=\"Logout\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\"/><polyline points=\"16 17 21 12 16 7\"/><line x1=\"21\" y1=\"12\" x2=\"9\" y2=\"12\"/>\n </svg>\n </button>\n </div>\n </div>\n </div>\n\n <div class=\"mes-dropdown-items\">\n <ng-content></ng-content>\n </div>\n </div>\n }\n </div>\n </div>\n }\n</div>\n", styles: [".user-profile-container{display:flex;align-items:center;gap:4px}.login-btn{padding:7px 18px;background-color:var(--primary-color);color:#fff;border:none;border-radius:8px;cursor:pointer;font-weight:500;font-size:13px;letter-spacing:.2px;transition:background-color .2s,transform .15s}.login-btn:hover{background-color:var(--primary-hover);transform:translateY(-1px)}.user-header{display:flex;align-items:center;gap:4px}.notification-btn{position:relative;background:none;border:none;cursor:pointer;padding:8px;border-radius:10px;color:var(--text-secondary);display:flex;align-items:center;justify-content:center;transition:color .2s,background-color .2s}.notification-btn:hover{background-color:var(--primary-light);color:var(--primary-color)}.notification-btn.has-unread{color:var(--primary-color)}.bell-icon{display:block;transition:transform .35s cubic-bezier(.34,1.56,.64,1)}.notification-btn:hover .bell-icon{transform:rotate(-20deg) scale(1.15)}.badge{position:absolute;top:2px;right:2px;background-color:var(--error-color);color:#fff;border-radius:10px;min-width:17px;height:17px;padding:0 4px;display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:700;line-height:1;box-shadow:0 0 0 2px var(--bg-primary);animation:badge-pop .25s cubic-bezier(.34,1.56,.64,1)}@keyframes badge-pop{0%{transform:scale(0)}to{transform:scale(1)}}.user-menu-wrapper{position:relative}.user-menu-btn{background:none;border:none;cursor:pointer;padding:4px;display:flex;align-items:center;justify-content:center;transition:transform .2s}.user-menu-btn:hover{transform:scale(1.06)}.mes-dropdown-menu{position:absolute;top:calc(100% + 10px);right:0;background:var(--bg-primary);border:1px solid var(--border-color);border-radius:14px;box-shadow:0 8px 32px var(--shadow-lg),0 2px 8px var(--shadow);min-width:220px;z-index:1000;overflow:hidden;animation:dropdown-in .16s cubic-bezier(.16,1,.3,1)}@keyframes dropdown-in{0%{opacity:0;transform:translateY(-8px) scale(.96)}to{opacity:1;transform:translateY(0) scale(1)}}.mes-dropdown-header{display:flex;align-items:center;gap:12px;padding:16px;background:var(--bg-secondary)}.dropdown-avatar-wrap{flex-shrink:0}.mes-dropdown-header .dropdown-avatar-wrap{margin-right:5px}.dropdown-user-info{display:flex;flex-direction:column;gap:3px;min-width:0}.dropdown-user-name{font-weight:600;font-size:14px;color:var(--text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-bottom:5px}.dropdown-user-sub{font-size:11px;color:var(--primary-color);font-weight:500;white-space:nowrap;text-overflow:ellipsis;margin-bottom:12px}.given-title{float:inline-end}.mes-dropdown-divider{height:1px;background:var(--border-color)}.dropdown-info-col{display:flex;flex-direction:column;gap:6px;min-width:0;flex:1}.dropdown-user-actions{display:flex;align-items:center;justify-content:flex-end;gap:4px}.icon-action{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;border:none;background:none;border-radius:8px;cursor:pointer;color:var(--text-secondary);transition:background-color .15s,color .15s,transform .15s}.icon-action:hover{transform:translateY(-1px)}.icon-action.profile-link{color:var(--primary-color)}.icon-action.profile-link:hover{background-color:var(--primary-light)}.icon-action.logout-item{color:var(--error-color)}.icon-action.logout-item:hover{background-color:var(--error-light)}.mes-dropdown-items:not(:empty){border-top:1px solid var(--border-color)}\n"], dependencies: [{ kind: "component", type: MaAvatarComponent, selector: "ma-avatar", inputs: ["src", "alt", "initials", "size", "shape", "frame", "ratio", "scale", "ring", "ringActive"] }] });
|
|
739
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: UserProfileComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
740
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: UserProfileComponent, isStandalone: true, selector: "ma-user-profile", inputs: { inputAvatarShape: { classPropertyName: "inputAvatarShape", publicName: "inputAvatarShape", isSignal: true, isRequired: false, transformFunction: null }, showBell: { classPropertyName: "showBell", publicName: "showBell", isSignal: true, isRequired: false, transformFunction: null }, showApproval: { classPropertyName: "showApproval", publicName: "showApproval", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { notificationClick: "notificationClick", approvalClick: "approvalClick" }, host: { listeners: { "document:click": "onDocumentClick($event)" }, properties: { "class": "this.themeClass" } }, ngImport: i0, template: "<div class=\"user-profile-container\">\r\n @if (!currentUser()) {\r\n <!-- Not logged in -->\r\n <button class=\"login-btn\" (click)=\"onLogin()\">Login</button>\r\n } @else {\r\n <!-- Logged in -->\r\n <div class=\"user-header\">\r\n <!-- Notification Bell -->\r\n @if (showBell()) {\r\n <button class=\"notification-btn\" [class.has-unread]=\"unreadCount() > 0\" (click)=\"onNotificationClick()\" title=\"Notifications\" aria-label=\"Notifications\">\r\n <svg class=\"bell-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9\"/>\r\n <path d=\"M13.73 21a2 2 0 0 1-3.46 0\"/>\r\n </svg>\r\n @if (unreadCount() > 0) {\r\n <span class=\"badge\">{{ unreadCount() > 99 ? '99+' : unreadCount() }}</span>\r\n }\r\n </button>\r\n }\r\n \r\n\r\n <!-- Approval Button -->\r\n @if (showApproval()) {\r\n <button class=\"notification-btn\" [class.has-unread]=\"pendingApprovalCount() > 0\" (click)=\"onApprovalClick()\" title=\"Approvals\" aria-label=\"Approvals\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M9 11l3 3L22 4\"/>\r\n <path d=\"M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11\"/>\r\n </svg>\r\n @if (pendingApprovalCount() > 0) {\r\n <span class=\"badge\">{{ pendingApprovalCount() > 99 ? '99+' : pendingApprovalCount() }}</span>\r\n }\r\n </button>\r\n } \r\n\r\n <!-- User Avatar + Dropdown -->\r\n <div class=\"user-menu-wrapper\">\r\n <button class=\"user-menu-btn\" (click)=\"toggleDropdown()\" [attr.aria-label]=\"'User menu for ' + (currentUser().fullName || currentUser().userName)\" aria-haspopup=\"true\" [attr.aria-expanded]=\"dropdownOpen()\">\r\n <ma-avatar\r\n [src]=\"getAvatarUrl(currentUser())\"\r\n [alt]=\"currentUser().fullName || currentUser().userName || ''\"\r\n [initials]=\"getLastNameInitial(currentUser())\"\r\n [size]=\"navAvatarSize()\"\r\n [shape]=\"avatarShape()\"\r\n [ratio]=\"avatarRatio()\"\r\n [frame]=\"avatarFrame()\" \r\n [ring]=\"true\"\r\n [ringActive]=\"dropdownOpen()\" /> \r\n </button>\r\n\r\n @if (dropdownOpen()) {\r\n <div class=\"mes-dropdown-menu\">\r\n <!-- User info header -->\r\n <div class=\"mes-dropdown-header\">\r\n <div class=\"dropdown-avatar-wrap\">\r\n <ma-avatar\r\n [src]=\"getAvatarUrl(currentUser())\"\r\n [alt]=\"currentUser().fullName || currentUser().userName || ''\"\r\n [initials]=\"getLastNameInitial(currentUser())\"\r\n [size]=\"dropAvatarSize()\"\r\n [shape]=\"avatarShape()\"\r\n [ratio]=\"avatarRatio()\"\r\n [frame]=\"avatarFrame()\"\r\n [scale]=\"1.5\" /> \r\n </div>\r\n <div class=\"dropdown-info-col\">\r\n <div class=\"dropdown-user-info\">\r\n <span class=\"dropdown-user-name\">{{ currentUser().fullName || currentUser().userName }}</span> \r\n <span class=\"dropdown-user-sub\">\r\n @if (currentUser().position || currentUser().department) {\r\n {{ currentUser().position || currentUser().department }} \r\n }\r\n @if (currentUser().givenTitle) {\r\n <span class=\"given-title-badge given-title\"\r\n [class]=\"'given-color-' + givenStyle()\">{{ currentUser().givenTitle }}</span>\r\n }\r\n </span>\r\n </div>\r\n <div class=\"dropdown-user-actions\">\r\n <button class=\"icon-action profile-link\" (click)=\"onViewProfile()\" title=\"View Profile\" aria-label=\"View Profile\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2\"/><circle cx=\"12\" cy=\"7\" r=\"4\"/>\r\n </svg>\r\n </button>\r\n <button class=\"icon-action logout-item\" (click)=\"onLogout()\" title=\"Logout\" aria-label=\"Logout\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\"/><polyline points=\"16 17 21 12 16 7\"/><line x1=\"21\" y1=\"12\" x2=\"9\" y2=\"12\"/>\r\n </svg>\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"mes-dropdown-items\">\r\n <ng-content></ng-content>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n }\r\n</div>\r\n", styles: [".user-profile-container{display:flex;align-items:center;gap:4px}.login-btn{padding:7px 18px;background-color:var(--primary-color);color:#fff;border:none;border-radius:8px;cursor:pointer;font-weight:500;font-size:13px;letter-spacing:.2px;transition:background-color .2s,transform .15s}.login-btn:hover{background-color:var(--primary-hover);transform:translateY(-1px)}.user-header{display:flex;align-items:center;gap:4px}.notification-btn{position:relative;background:none;border:none;cursor:pointer;padding:8px;border-radius:10px;color:var(--text-secondary);display:flex;align-items:center;justify-content:center;transition:color .2s,background-color .2s}.notification-btn:hover{background-color:var(--primary-light);color:var(--primary-color)}.notification-btn.has-unread{color:var(--primary-color)}.bell-icon{display:block;transition:transform .35s cubic-bezier(.34,1.56,.64,1)}.notification-btn:hover .bell-icon{transform:rotate(-20deg) scale(1.15)}.badge{position:absolute;top:2px;right:2px;background-color:var(--error-color);color:#fff;border-radius:10px;min-width:17px;height:17px;padding:0 4px;display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:700;line-height:1;box-shadow:0 0 0 2px var(--bg-primary);animation:badge-pop .25s cubic-bezier(.34,1.56,.64,1)}@keyframes badge-pop{0%{transform:scale(0)}to{transform:scale(1)}}.user-menu-wrapper{position:relative}.user-menu-btn{background:none;border:none;cursor:pointer;padding:4px;display:flex;align-items:center;justify-content:center;transition:transform .2s}.user-menu-btn:hover{transform:scale(1.06)}.mes-dropdown-menu{position:absolute;top:calc(100% + 10px);right:0;background:var(--bg-primary);border:1px solid var(--border-color);border-radius:14px;box-shadow:0 8px 32px var(--shadow-lg),0 2px 8px var(--shadow);min-width:220px;z-index:1000;overflow:hidden;animation:dropdown-in .16s cubic-bezier(.16,1,.3,1)}@keyframes dropdown-in{0%{opacity:0;transform:translateY(-8px) scale(.96)}to{opacity:1;transform:translateY(0) scale(1)}}.mes-dropdown-header{display:flex;align-items:center;gap:12px;padding:16px;background:var(--bg-secondary)}.dropdown-avatar-wrap{flex-shrink:0}.mes-dropdown-header .dropdown-avatar-wrap{margin-right:5px}.dropdown-user-info{display:flex;flex-direction:column;gap:3px;min-width:0}.dropdown-user-name{font-weight:600;font-size:14px;color:var(--text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-bottom:5px;min-width:120px}.dropdown-user-sub{font-size:11px;color:var(--primary-color);font-weight:500;white-space:nowrap;text-overflow:ellipsis;margin-bottom:12px}.given-title{float:inline-end}.mes-dropdown-divider{height:1px;background:var(--border-color)}.dropdown-info-col{display:flex;flex-direction:column;gap:6px;min-width:0;flex:1}.dropdown-user-actions{display:flex;align-items:center;justify-content:flex-end;gap:4px}.icon-action{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;border:none;background:none;border-radius:8px;cursor:pointer;color:var(--text-secondary);transition:background-color .15s,color .15s,transform .15s}.icon-action:hover{transform:translateY(-1px)}.icon-action.profile-link{color:var(--primary-color)}.icon-action.profile-link:hover{background-color:var(--primary-light)}.icon-action.logout-item{color:var(--error-color)}.icon-action.logout-item:hover{background-color:var(--error-light)}.mes-dropdown-items:not(:empty){border-top:1px solid var(--border-color)}\n"], dependencies: [{ kind: "component", type: MaAvatarComponent, selector: "ma-avatar", inputs: ["src", "alt", "initials", "size", "shape", "frame", "ratio", "scale", "ring", "ringActive"] }] });
|
|
730
741
|
}
|
|
731
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
742
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: UserProfileComponent, decorators: [{
|
|
732
743
|
type: Component,
|
|
733
|
-
args: [{ selector: 'ma-user-profile', imports: [MaAvatarComponent], template: "<div class=\"user-profile-container\">\n @if (!currentUser()) {\n <!-- Not logged in -->\n <button class=\"login-btn\" (click)=\"onLogin()\">Login</button>\n } @else {\n <!-- Logged in -->\n <div class=\"user-header\">\n <!-- Notification Bell -->\n @if (showBell()) {\n <button class=\"notification-btn\" [class.has-unread]=\"unreadCount() > 0\" (click)=\"onNotificationClick()\" title=\"Notifications\" aria-label=\"Notifications\">\n <svg class=\"bell-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9\"/>\n <path d=\"M13.73 21a2 2 0 0 1-3.46 0\"/>\n </svg>\n @if (unreadCount() > 0) {\n <span class=\"badge\">{{ unreadCount() > 99 ? '99+' : unreadCount() }}</span>\n }\n </button>\n }\n \n\n <!-- Approval Button -->\n @if (showApproval()) {\n <button class=\"notification-btn\" [class.has-unread]=\"pendingApprovalCount() > 0\" (click)=\"onApprovalClick()\" title=\"Approvals\" aria-label=\"Approvals\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M9 11l3 3L22 4\"/>\n <path d=\"M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11\"/>\n </svg>\n @if (pendingApprovalCount() > 0) {\n <span class=\"badge\">{{ pendingApprovalCount() > 99 ? '99+' : pendingApprovalCount() }}</span>\n }\n </button>\n } \n\n <!-- User Avatar + Dropdown -->\n <div class=\"user-menu-wrapper\">\n <button class=\"user-menu-btn\" (click)=\"toggleDropdown()\" [attr.aria-label]=\"'User menu for ' + (currentUser().fullName || currentUser().userName)\" aria-haspopup=\"true\" [attr.aria-expanded]=\"dropdownOpen()\">\n <ma-avatar\n [src]=\"getAvatarUrl(currentUser())\"\n [alt]=\"currentUser().fullName || currentUser().userName || ''\"\n [initials]=\"getLastNameInitial(currentUser())\"\n [size]=\"navAvatarSize()\"\n [shape]=\"avatarShape()\"\n [ratio]=\"avatarRatio()\"\n [frame]=\"avatarFrame()\" \n [ring]=\"true\"\n [ringActive]=\"dropdownOpen()\" /> \n </button>\n\n @if (dropdownOpen()) {\n <div class=\"mes-dropdown-menu\">\n <!-- User info header -->\n <div class=\"mes-dropdown-header\">\n <div class=\"dropdown-avatar-wrap\">\n <ma-avatar\n [src]=\"getAvatarUrl(currentUser())\"\n [alt]=\"currentUser().fullName || currentUser().userName || ''\"\n [initials]=\"getLastNameInitial(currentUser())\"\n [size]=\"dropAvatarSize()\"\n [shape]=\"avatarShape()\"\n [ratio]=\"avatarRatio()\"\n [frame]=\"avatarFrame()\"\n [scale]=\"1.5\" /> \n </div>\n <div class=\"dropdown-info-col\">\n <div class=\"dropdown-user-info\">\n <span class=\"dropdown-user-name\">{{ currentUser().fullName || currentUser().userName }}</span> \n <span class=\"dropdown-user-sub\">\n @if (currentUser().position || currentUser().department) {\n {{ currentUser().position || currentUser().department }} \n }\n @if (currentUser().givenTitle) {\n <span class=\"given-title-badge given-title\"\n [class]=\"'given-color-' + givenStyle()\">{{ currentUser().givenTitle }}</span>\n }\n </span>\n </div>\n <div class=\"dropdown-user-actions\">\n <button class=\"icon-action profile-link\" (click)=\"onViewProfile()\" title=\"View Profile\" aria-label=\"View Profile\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2\"/><circle cx=\"12\" cy=\"7\" r=\"4\"/>\n </svg>\n </button>\n <button class=\"icon-action logout-item\" (click)=\"onLogout()\" title=\"Logout\" aria-label=\"Logout\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\"/><polyline points=\"16 17 21 12 16 7\"/><line x1=\"21\" y1=\"12\" x2=\"9\" y2=\"12\"/>\n </svg>\n </button>\n </div>\n </div>\n </div>\n\n <div class=\"mes-dropdown-items\">\n <ng-content></ng-content>\n </div>\n </div>\n }\n </div>\n </div>\n }\n</div>\n", styles: [".user-profile-container{display:flex;align-items:center;gap:4px}.login-btn{padding:7px 18px;background-color:var(--primary-color);color:#fff;border:none;border-radius:8px;cursor:pointer;font-weight:500;font-size:13px;letter-spacing:.2px;transition:background-color .2s,transform .15s}.login-btn:hover{background-color:var(--primary-hover);transform:translateY(-1px)}.user-header{display:flex;align-items:center;gap:4px}.notification-btn{position:relative;background:none;border:none;cursor:pointer;padding:8px;border-radius:10px;color:var(--text-secondary);display:flex;align-items:center;justify-content:center;transition:color .2s,background-color .2s}.notification-btn:hover{background-color:var(--primary-light);color:var(--primary-color)}.notification-btn.has-unread{color:var(--primary-color)}.bell-icon{display:block;transition:transform .35s cubic-bezier(.34,1.56,.64,1)}.notification-btn:hover .bell-icon{transform:rotate(-20deg) scale(1.15)}.badge{position:absolute;top:2px;right:2px;background-color:var(--error-color);color:#fff;border-radius:10px;min-width:17px;height:17px;padding:0 4px;display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:700;line-height:1;box-shadow:0 0 0 2px var(--bg-primary);animation:badge-pop .25s cubic-bezier(.34,1.56,.64,1)}@keyframes badge-pop{0%{transform:scale(0)}to{transform:scale(1)}}.user-menu-wrapper{position:relative}.user-menu-btn{background:none;border:none;cursor:pointer;padding:4px;display:flex;align-items:center;justify-content:center;transition:transform .2s}.user-menu-btn:hover{transform:scale(1.06)}.mes-dropdown-menu{position:absolute;top:calc(100% + 10px);right:0;background:var(--bg-primary);border:1px solid var(--border-color);border-radius:14px;box-shadow:0 8px 32px var(--shadow-lg),0 2px 8px var(--shadow);min-width:220px;z-index:1000;overflow:hidden;animation:dropdown-in .16s cubic-bezier(.16,1,.3,1)}@keyframes dropdown-in{0%{opacity:0;transform:translateY(-8px) scale(.96)}to{opacity:1;transform:translateY(0) scale(1)}}.mes-dropdown-header{display:flex;align-items:center;gap:12px;padding:16px;background:var(--bg-secondary)}.dropdown-avatar-wrap{flex-shrink:0}.mes-dropdown-header .dropdown-avatar-wrap{margin-right:5px}.dropdown-user-info{display:flex;flex-direction:column;gap:3px;min-width:0}.dropdown-user-name{font-weight:600;font-size:14px;color:var(--text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-bottom:5px}.dropdown-user-sub{font-size:11px;color:var(--primary-color);font-weight:500;white-space:nowrap;text-overflow:ellipsis;margin-bottom:12px}.given-title{float:inline-end}.mes-dropdown-divider{height:1px;background:var(--border-color)}.dropdown-info-col{display:flex;flex-direction:column;gap:6px;min-width:0;flex:1}.dropdown-user-actions{display:flex;align-items:center;justify-content:flex-end;gap:4px}.icon-action{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;border:none;background:none;border-radius:8px;cursor:pointer;color:var(--text-secondary);transition:background-color .15s,color .15s,transform .15s}.icon-action:hover{transform:translateY(-1px)}.icon-action.profile-link{color:var(--primary-color)}.icon-action.profile-link:hover{background-color:var(--primary-light)}.icon-action.logout-item{color:var(--error-color)}.icon-action.logout-item:hover{background-color:var(--error-light)}.mes-dropdown-items:not(:empty){border-top:1px solid var(--border-color)}\n"] }]
|
|
744
|
+
args: [{ selector: 'ma-user-profile', imports: [MaAvatarComponent], template: "<div class=\"user-profile-container\">\r\n @if (!currentUser()) {\r\n <!-- Not logged in -->\r\n <button class=\"login-btn\" (click)=\"onLogin()\">Login</button>\r\n } @else {\r\n <!-- Logged in -->\r\n <div class=\"user-header\">\r\n <!-- Notification Bell -->\r\n @if (showBell()) {\r\n <button class=\"notification-btn\" [class.has-unread]=\"unreadCount() > 0\" (click)=\"onNotificationClick()\" title=\"Notifications\" aria-label=\"Notifications\">\r\n <svg class=\"bell-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9\"/>\r\n <path d=\"M13.73 21a2 2 0 0 1-3.46 0\"/>\r\n </svg>\r\n @if (unreadCount() > 0) {\r\n <span class=\"badge\">{{ unreadCount() > 99 ? '99+' : unreadCount() }}</span>\r\n }\r\n </button>\r\n }\r\n \r\n\r\n <!-- Approval Button -->\r\n @if (showApproval()) {\r\n <button class=\"notification-btn\" [class.has-unread]=\"pendingApprovalCount() > 0\" (click)=\"onApprovalClick()\" title=\"Approvals\" aria-label=\"Approvals\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M9 11l3 3L22 4\"/>\r\n <path d=\"M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11\"/>\r\n </svg>\r\n @if (pendingApprovalCount() > 0) {\r\n <span class=\"badge\">{{ pendingApprovalCount() > 99 ? '99+' : pendingApprovalCount() }}</span>\r\n }\r\n </button>\r\n } \r\n\r\n <!-- User Avatar + Dropdown -->\r\n <div class=\"user-menu-wrapper\">\r\n <button class=\"user-menu-btn\" (click)=\"toggleDropdown()\" [attr.aria-label]=\"'User menu for ' + (currentUser().fullName || currentUser().userName)\" aria-haspopup=\"true\" [attr.aria-expanded]=\"dropdownOpen()\">\r\n <ma-avatar\r\n [src]=\"getAvatarUrl(currentUser())\"\r\n [alt]=\"currentUser().fullName || currentUser().userName || ''\"\r\n [initials]=\"getLastNameInitial(currentUser())\"\r\n [size]=\"navAvatarSize()\"\r\n [shape]=\"avatarShape()\"\r\n [ratio]=\"avatarRatio()\"\r\n [frame]=\"avatarFrame()\" \r\n [ring]=\"true\"\r\n [ringActive]=\"dropdownOpen()\" /> \r\n </button>\r\n\r\n @if (dropdownOpen()) {\r\n <div class=\"mes-dropdown-menu\">\r\n <!-- User info header -->\r\n <div class=\"mes-dropdown-header\">\r\n <div class=\"dropdown-avatar-wrap\">\r\n <ma-avatar\r\n [src]=\"getAvatarUrl(currentUser())\"\r\n [alt]=\"currentUser().fullName || currentUser().userName || ''\"\r\n [initials]=\"getLastNameInitial(currentUser())\"\r\n [size]=\"dropAvatarSize()\"\r\n [shape]=\"avatarShape()\"\r\n [ratio]=\"avatarRatio()\"\r\n [frame]=\"avatarFrame()\"\r\n [scale]=\"1.5\" /> \r\n </div>\r\n <div class=\"dropdown-info-col\">\r\n <div class=\"dropdown-user-info\">\r\n <span class=\"dropdown-user-name\">{{ currentUser().fullName || currentUser().userName }}</span> \r\n <span class=\"dropdown-user-sub\">\r\n @if (currentUser().position || currentUser().department) {\r\n {{ currentUser().position || currentUser().department }} \r\n }\r\n @if (currentUser().givenTitle) {\r\n <span class=\"given-title-badge given-title\"\r\n [class]=\"'given-color-' + givenStyle()\">{{ currentUser().givenTitle }}</span>\r\n }\r\n </span>\r\n </div>\r\n <div class=\"dropdown-user-actions\">\r\n <button class=\"icon-action profile-link\" (click)=\"onViewProfile()\" title=\"View Profile\" aria-label=\"View Profile\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2\"/><circle cx=\"12\" cy=\"7\" r=\"4\"/>\r\n </svg>\r\n </button>\r\n <button class=\"icon-action logout-item\" (click)=\"onLogout()\" title=\"Logout\" aria-label=\"Logout\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\"/><polyline points=\"16 17 21 12 16 7\"/><line x1=\"21\" y1=\"12\" x2=\"9\" y2=\"12\"/>\r\n </svg>\r\n </button>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"mes-dropdown-items\">\r\n <ng-content></ng-content>\r\n </div>\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n }\r\n</div>\r\n", styles: [".user-profile-container{display:flex;align-items:center;gap:4px}.login-btn{padding:7px 18px;background-color:var(--primary-color);color:#fff;border:none;border-radius:8px;cursor:pointer;font-weight:500;font-size:13px;letter-spacing:.2px;transition:background-color .2s,transform .15s}.login-btn:hover{background-color:var(--primary-hover);transform:translateY(-1px)}.user-header{display:flex;align-items:center;gap:4px}.notification-btn{position:relative;background:none;border:none;cursor:pointer;padding:8px;border-radius:10px;color:var(--text-secondary);display:flex;align-items:center;justify-content:center;transition:color .2s,background-color .2s}.notification-btn:hover{background-color:var(--primary-light);color:var(--primary-color)}.notification-btn.has-unread{color:var(--primary-color)}.bell-icon{display:block;transition:transform .35s cubic-bezier(.34,1.56,.64,1)}.notification-btn:hover .bell-icon{transform:rotate(-20deg) scale(1.15)}.badge{position:absolute;top:2px;right:2px;background-color:var(--error-color);color:#fff;border-radius:10px;min-width:17px;height:17px;padding:0 4px;display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:700;line-height:1;box-shadow:0 0 0 2px var(--bg-primary);animation:badge-pop .25s cubic-bezier(.34,1.56,.64,1)}@keyframes badge-pop{0%{transform:scale(0)}to{transform:scale(1)}}.user-menu-wrapper{position:relative}.user-menu-btn{background:none;border:none;cursor:pointer;padding:4px;display:flex;align-items:center;justify-content:center;transition:transform .2s}.user-menu-btn:hover{transform:scale(1.06)}.mes-dropdown-menu{position:absolute;top:calc(100% + 10px);right:0;background:var(--bg-primary);border:1px solid var(--border-color);border-radius:14px;box-shadow:0 8px 32px var(--shadow-lg),0 2px 8px var(--shadow);min-width:220px;z-index:1000;overflow:hidden;animation:dropdown-in .16s cubic-bezier(.16,1,.3,1)}@keyframes dropdown-in{0%{opacity:0;transform:translateY(-8px) scale(.96)}to{opacity:1;transform:translateY(0) scale(1)}}.mes-dropdown-header{display:flex;align-items:center;gap:12px;padding:16px;background:var(--bg-secondary)}.dropdown-avatar-wrap{flex-shrink:0}.mes-dropdown-header .dropdown-avatar-wrap{margin-right:5px}.dropdown-user-info{display:flex;flex-direction:column;gap:3px;min-width:0}.dropdown-user-name{font-weight:600;font-size:14px;color:var(--text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin-bottom:5px;min-width:120px}.dropdown-user-sub{font-size:11px;color:var(--primary-color);font-weight:500;white-space:nowrap;text-overflow:ellipsis;margin-bottom:12px}.given-title{float:inline-end}.mes-dropdown-divider{height:1px;background:var(--border-color)}.dropdown-info-col{display:flex;flex-direction:column;gap:6px;min-width:0;flex:1}.dropdown-user-actions{display:flex;align-items:center;justify-content:flex-end;gap:4px}.icon-action{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;border:none;background:none;border-radius:8px;cursor:pointer;color:var(--text-secondary);transition:background-color .15s,color .15s,transform .15s}.icon-action:hover{transform:translateY(-1px)}.icon-action.profile-link{color:var(--primary-color)}.icon-action.profile-link:hover{background-color:var(--primary-light)}.icon-action.logout-item{color:var(--error-color)}.icon-action.logout-item:hover{background-color:var(--error-light)}.mes-dropdown-items:not(:empty){border-top:1px solid var(--border-color)}\n"] }]
|
|
734
745
|
}], ctorParameters: () => [], propDecorators: { inputAvatarShape: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputAvatarShape", required: false }] }], showBell: [{ type: i0.Input, args: [{ isSignal: true, alias: "showBell", required: false }] }], showApproval: [{ type: i0.Input, args: [{ isSignal: true, alias: "showApproval", required: false }] }], notificationClick: [{ type: i0.Output, args: ["notificationClick"] }], approvalClick: [{ type: i0.Output, args: ["approvalClick"] }], themeClass: [{
|
|
735
746
|
type: HostBinding,
|
|
736
747
|
args: ['class']
|
|
@@ -757,10 +768,10 @@ class ToastService {
|
|
|
757
768
|
clear() {
|
|
758
769
|
this._toasts.set([]);
|
|
759
770
|
}
|
|
760
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
761
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
771
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: ToastService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
772
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: ToastService, providedIn: 'root' });
|
|
762
773
|
}
|
|
763
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
774
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: ToastService, decorators: [{
|
|
764
775
|
type: Injectable,
|
|
765
776
|
args: [{ providedIn: 'root' }]
|
|
766
777
|
}] });
|
|
@@ -775,12 +786,12 @@ class ToastContainerComponent {
|
|
|
775
786
|
close(id) {
|
|
776
787
|
this.toastService.remove(id);
|
|
777
788
|
}
|
|
778
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
779
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
789
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: ToastContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
790
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: ToastContainerComponent, isStandalone: true, selector: "ma-toast-container", host: { properties: { "class": "this.themeClass" } }, ngImport: i0, template: "<div class=\"toast-container\">\r\n @for (toast of toasts(); track toast.id) {\r\n <div class=\"toast toast-{{ toast.type }}\">\r\n\r\n <!-- Type icon -->\r\n <div class=\"toast-icon\">\r\n @if (toast.type === 'info') {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9\"/><path d=\"M13.73 21a2 2 0 0 1-3.46 0\"/>\r\n </svg>\r\n }\r\n @if (toast.type === 'success') {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M22 11.08V12a10 10 0 1 1-5.93-9.14\"/><polyline points=\"22 4 12 14.01 9 11.01\"/>\r\n </svg>\r\n }\r\n @if (toast.type === 'warning') {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"/><line x1=\"12\" y1=\"9\" x2=\"12\" y2=\"13\"/><line x1=\"12\" y1=\"17\" x2=\"12.01\" y2=\"17\"/>\r\n </svg>\r\n }\r\n @if (toast.type === 'error') {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <circle cx=\"12\" cy=\"12\" r=\"10\"/><line x1=\"15\" y1=\"9\" x2=\"9\" y2=\"15\"/><line x1=\"9\" y1=\"9\" x2=\"15\" y2=\"15\"/>\r\n </svg>\r\n }\r\n </div>\r\n\r\n <!-- Content -->\r\n <div class=\"toast-content\">\r\n @if (toast.title) {\r\n <div class=\"toast-title\">{{ toast.title }}</div>\r\n }\r\n <div class=\"toast-message\" [innerHTML]=\"toast.message\"></div>\r\n </div>\r\n\r\n <!-- Close -->\r\n <button class=\"toast-close\" (click)=\"close(toast.id)\" aria-label=\"Close\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/>\r\n </svg>\r\n </button>\r\n\r\n <!-- Auto-dismiss progress bar \u2014 hidden when duration <= 0 (persistent toast) -->\r\n @if (toast.duration == null || toast.duration > 0) {\r\n <div class=\"toast-progress\" [style.animation-duration]=\"(toast.duration ?? 5000) + 'ms'\"></div>\r\n }\r\n </div>\r\n }\r\n</div>\r\n", styles: [".toast-container{position:fixed;top:20px;right:20px;z-index:9999;pointer-events:none;display:flex;flex-direction:column;gap:10px}.toast{position:relative;display:flex;align-items:flex-start;gap:11px;padding:13px 13px 16px 16px;border-radius:12px;background:var(--bg-primary);border:1px solid var(--border-color);box-shadow:0 8px 28px var(--shadow-lg),0 2px 8px var(--shadow);pointer-events:auto;min-width:300px;max-width:420px;overflow:hidden;animation:toast-in .35s cubic-bezier(.16,1,.3,1)}@keyframes toast-in{0%{opacity:0;transform:translate(36px) scale(.96)}to{opacity:1;transform:translate(0) scale(1)}}.toast:before{content:\"\";position:absolute;left:0;top:0;bottom:0;width:4px;border-radius:12px 0 0 12px}.toast-info:before{background:var(--info-color)}.toast-success:before{background:var(--success-color)}.toast-warning:before{background:var(--warning-color)}.toast-error:before{background:var(--error-color)}.toast-icon{flex-shrink:0;width:34px;height:34px;border-radius:9px;display:flex;align-items:center;justify-content:center;margin-left:2px}.toast-info .toast-icon{color:var(--info-color);background:var(--info-bg)}.toast-success .toast-icon{color:var(--success-color);background:var(--success-bg)}.toast-warning .toast-icon{color:var(--warning-color);background:var(--warning-bg)}.toast-error .toast-icon{color:var(--error-color);background:var(--error-bg)}.toast-content{flex:1;min-width:0;padding-top:1px}.toast-title{font-weight:700;font-size:13.5px;margin-bottom:3px;line-height:1.3}.toast-info .toast-title{color:var(--info-color)}.toast-success .toast-title{color:var(--success-color)}.toast-warning .toast-title{color:var(--warning-color)}.toast-error .toast-title{color:var(--error-color)}.toast-message{font-size:12.5px;line-height:1.45;color:var(--text-secondary)}.toast-message h3{margin:0 0 4px;font-size:13.5px;color:inherit}.toast-close{background:none;border:none;cursor:pointer;color:var(--text-secondary);width:26px;height:26px;border-radius:6px;display:flex;align-items:center;justify-content:center;flex-shrink:0;padding:0;transition:color .15s,background-color .15s}.toast-close:hover{color:var(--text-primary);background:var(--border-color)}.toast-progress{position:absolute;bottom:0;left:4px;right:0;height:3px;border-radius:0 0 12px;animation:toast-progress linear forwards;opacity:.7}.toast-info .toast-progress{background:var(--info-color)}.toast-success .toast-progress{background:var(--success-color)}.toast-warning .toast-progress{background:var(--warning-color)}.toast-error .toast-progress{background:var(--error-color)}@keyframes toast-progress{0%{width:calc(100% - 4px)}to{width:0}}@media(max-width:600px){.toast-container{top:10px;right:10px;left:10px}.toast{min-width:auto;max-width:100%}}\n"] });
|
|
780
791
|
}
|
|
781
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
792
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: ToastContainerComponent, decorators: [{
|
|
782
793
|
type: Component,
|
|
783
|
-
args: [{ selector: 'ma-toast-container', imports: [], template: "<div class=\"toast-container\">\n @for (toast of toasts(); track toast.id) {\n <div class=\"toast toast-{{ toast.type }}\">\n\n <!-- Type icon -->\n <div class=\"toast-icon\">\n @if (toast.type === 'info') {\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9\"/><path d=\"M13.73 21a2 2 0 0 1-3.46 0\"/>\n </svg>\n }\n @if (toast.type === 'success') {\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M22 11.08V12a10 10 0 1 1-5.93-9.14\"/><polyline points=\"22 4 12 14.01 9 11.01\"/>\n </svg>\n }\n @if (toast.type === 'warning') {\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"/><line x1=\"12\" y1=\"9\" x2=\"12\" y2=\"13\"/><line x1=\"12\" y1=\"17\" x2=\"12.01\" y2=\"17\"/>\n </svg>\n }\n @if (toast.type === 'error') {\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\"/><line x1=\"15\" y1=\"9\" x2=\"9\" y2=\"15\"/><line x1=\"9\" y1=\"9\" x2=\"15\" y2=\"15\"/>\n </svg>\n }\n </div>\n\n <!-- Content -->\n <div class=\"toast-content\">\n @if (toast.title) {\n <div class=\"toast-title\">{{ toast.title }}</div>\n }\n <div class=\"toast-message\" [innerHTML]=\"toast.message\"></div>\n </div>\n\n <!-- Close -->\n <button class=\"toast-close\" (click)=\"close(toast.id)\" aria-label=\"Close\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/>\n </svg>\n </button>\n\n <!-- Auto-dismiss progress bar \u2014 hidden when duration <= 0 (persistent toast) -->\n @if (toast.duration == null || toast.duration > 0) {\n <div class=\"toast-progress\" [style.animation-duration]=\"(toast.duration ?? 5000) + 'ms'\"></div>\n }\n </div>\n }\n</div>\n", styles: [".toast-container{position:fixed;top:20px;right:20px;z-index:9999;pointer-events:none;display:flex;flex-direction:column;gap:10px}.toast{position:relative;display:flex;align-items:flex-start;gap:11px;padding:13px 13px 16px 16px;border-radius:12px;background:var(--bg-primary);border:1px solid var(--border-color);box-shadow:0 8px 28px var(--shadow-lg),0 2px 8px var(--shadow);pointer-events:auto;min-width:300px;max-width:420px;overflow:hidden;animation:toast-in .35s cubic-bezier(.16,1,.3,1)}@keyframes toast-in{0%{opacity:0;transform:translate(36px) scale(.96)}to{opacity:1;transform:translate(0) scale(1)}}.toast:before{content:\"\";position:absolute;left:0;top:0;bottom:0;width:4px;border-radius:12px 0 0 12px}.toast-info:before{background:var(--info-color)}.toast-success:before{background:var(--success-color)}.toast-warning:before{background:var(--warning-color)}.toast-error:before{background:var(--error-color)}.toast-icon{flex-shrink:0;width:34px;height:34px;border-radius:9px;display:flex;align-items:center;justify-content:center;margin-left:2px}.toast-info .toast-icon{color:var(--info-color);background:var(--info-bg)}.toast-success .toast-icon{color:var(--success-color);background:var(--success-bg)}.toast-warning .toast-icon{color:var(--warning-color);background:var(--warning-bg)}.toast-error .toast-icon{color:var(--error-color);background:var(--error-bg)}.toast-content{flex:1;min-width:0;padding-top:1px}.toast-title{font-weight:700;font-size:13.5px;margin-bottom:3px;line-height:1.3}.toast-info .toast-title{color:var(--info-color)}.toast-success .toast-title{color:var(--success-color)}.toast-warning .toast-title{color:var(--warning-color)}.toast-error .toast-title{color:var(--error-color)}.toast-message{font-size:12.5px;line-height:1.45;color:var(--text-secondary)}.toast-message h3{margin:0 0 4px;font-size:13.5px;color:inherit}.toast-close{background:none;border:none;cursor:pointer;color:var(--text-secondary);width:26px;height:26px;border-radius:6px;display:flex;align-items:center;justify-content:center;flex-shrink:0;padding:0;transition:color .15s,background-color .15s}.toast-close:hover{color:var(--text-primary);background:var(--border-color)}.toast-progress{position:absolute;bottom:0;left:4px;right:0;height:3px;border-radius:0 0 12px;animation:toast-progress linear forwards;opacity:.7}.toast-info .toast-progress{background:var(--info-color)}.toast-success .toast-progress{background:var(--success-color)}.toast-warning .toast-progress{background:var(--warning-color)}.toast-error .toast-progress{background:var(--error-color)}@keyframes toast-progress{0%{width:calc(100% - 4px)}to{width:0}}@media(max-width:600px){.toast-container{top:10px;right:10px;left:10px}.toast{min-width:auto;max-width:100%}}\n"] }]
|
|
794
|
+
args: [{ selector: 'ma-toast-container', imports: [], template: "<div class=\"toast-container\">\r\n @for (toast of toasts(); track toast.id) {\r\n <div class=\"toast toast-{{ toast.type }}\">\r\n\r\n <!-- Type icon -->\r\n <div class=\"toast-icon\">\r\n @if (toast.type === 'info') {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9\"/><path d=\"M13.73 21a2 2 0 0 1-3.46 0\"/>\r\n </svg>\r\n }\r\n @if (toast.type === 'success') {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M22 11.08V12a10 10 0 1 1-5.93-9.14\"/><polyline points=\"22 4 12 14.01 9 11.01\"/>\r\n </svg>\r\n }\r\n @if (toast.type === 'warning') {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"/><line x1=\"12\" y1=\"9\" x2=\"12\" y2=\"13\"/><line x1=\"12\" y1=\"17\" x2=\"12.01\" y2=\"17\"/>\r\n </svg>\r\n }\r\n @if (toast.type === 'error') {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <circle cx=\"12\" cy=\"12\" r=\"10\"/><line x1=\"15\" y1=\"9\" x2=\"9\" y2=\"15\"/><line x1=\"9\" y1=\"9\" x2=\"15\" y2=\"15\"/>\r\n </svg>\r\n }\r\n </div>\r\n\r\n <!-- Content -->\r\n <div class=\"toast-content\">\r\n @if (toast.title) {\r\n <div class=\"toast-title\">{{ toast.title }}</div>\r\n }\r\n <div class=\"toast-message\" [innerHTML]=\"toast.message\"></div>\r\n </div>\r\n\r\n <!-- Close -->\r\n <button class=\"toast-close\" (click)=\"close(toast.id)\" aria-label=\"Close\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/>\r\n </svg>\r\n </button>\r\n\r\n <!-- Auto-dismiss progress bar \u2014 hidden when duration <= 0 (persistent toast) -->\r\n @if (toast.duration == null || toast.duration > 0) {\r\n <div class=\"toast-progress\" [style.animation-duration]=\"(toast.duration ?? 5000) + 'ms'\"></div>\r\n }\r\n </div>\r\n }\r\n</div>\r\n", styles: [".toast-container{position:fixed;top:20px;right:20px;z-index:9999;pointer-events:none;display:flex;flex-direction:column;gap:10px}.toast{position:relative;display:flex;align-items:flex-start;gap:11px;padding:13px 13px 16px 16px;border-radius:12px;background:var(--bg-primary);border:1px solid var(--border-color);box-shadow:0 8px 28px var(--shadow-lg),0 2px 8px var(--shadow);pointer-events:auto;min-width:300px;max-width:420px;overflow:hidden;animation:toast-in .35s cubic-bezier(.16,1,.3,1)}@keyframes toast-in{0%{opacity:0;transform:translate(36px) scale(.96)}to{opacity:1;transform:translate(0) scale(1)}}.toast:before{content:\"\";position:absolute;left:0;top:0;bottom:0;width:4px;border-radius:12px 0 0 12px}.toast-info:before{background:var(--info-color)}.toast-success:before{background:var(--success-color)}.toast-warning:before{background:var(--warning-color)}.toast-error:before{background:var(--error-color)}.toast-icon{flex-shrink:0;width:34px;height:34px;border-radius:9px;display:flex;align-items:center;justify-content:center;margin-left:2px}.toast-info .toast-icon{color:var(--info-color);background:var(--info-bg)}.toast-success .toast-icon{color:var(--success-color);background:var(--success-bg)}.toast-warning .toast-icon{color:var(--warning-color);background:var(--warning-bg)}.toast-error .toast-icon{color:var(--error-color);background:var(--error-bg)}.toast-content{flex:1;min-width:0;padding-top:1px}.toast-title{font-weight:700;font-size:13.5px;margin-bottom:3px;line-height:1.3}.toast-info .toast-title{color:var(--info-color)}.toast-success .toast-title{color:var(--success-color)}.toast-warning .toast-title{color:var(--warning-color)}.toast-error .toast-title{color:var(--error-color)}.toast-message{font-size:12.5px;line-height:1.45;color:var(--text-secondary)}.toast-message h3{margin:0 0 4px;font-size:13.5px;color:inherit}.toast-close{background:none;border:none;cursor:pointer;color:var(--text-secondary);width:26px;height:26px;border-radius:6px;display:flex;align-items:center;justify-content:center;flex-shrink:0;padding:0;transition:color .15s,background-color .15s}.toast-close:hover{color:var(--text-primary);background:var(--border-color)}.toast-progress{position:absolute;bottom:0;left:4px;right:0;height:3px;border-radius:0 0 12px;animation:toast-progress linear forwards;opacity:.7}.toast-info .toast-progress{background:var(--info-color)}.toast-success .toast-progress{background:var(--success-color)}.toast-warning .toast-progress{background:var(--warning-color)}.toast-error .toast-progress{background:var(--error-color)}@keyframes toast-progress{0%{width:calc(100% - 4px)}to{width:0}}@media(max-width:600px){.toast-container{top:10px;right:10px;left:10px}.toast{min-width:auto;max-width:100%}}\n"] }]
|
|
784
795
|
}], propDecorators: { themeClass: [{
|
|
785
796
|
type: HostBinding,
|
|
786
797
|
args: ['class']
|
|
@@ -980,12 +991,12 @@ class NotificationPanelComponent {
|
|
|
980
991
|
}
|
|
981
992
|
return normalized;
|
|
982
993
|
}
|
|
983
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
984
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: NotificationPanelComponent, isStandalone: true, selector: "ma-notification-panel", outputs: { notificationRead: "notificationRead" }, host: { properties: { "class": "this.themeClass" } }, ngImport: i0, template: "<div class=\"notification-panel\" [class.open]=\"isOpen()\">\n <!-- Header -->\n <div class=\"panel-header\">\n <div class=\"panel-header-left\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9\"/>\n <path d=\"M13.73 21a2 2 0 0 1-3.46 0\"/>\n </svg>\n <h3>Notifications</h3>\n </div>\n <button class=\"close-btn\" (click)=\"close()\" title=\"Close\" aria-label=\"Close notifications\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/>\n </svg>\n </button>\n </div>\n\n <!-- Tabs -->\n <div class=\"tabs\">\n <button class=\"tab-btn\" [class.active]=\"activeTab() === 'unread'\" (click)=\"switchTab('unread')\">\n Unread\n @if (unreadNotifications().length > 0) {\n <span class=\"tab-badge\">{{ unreadNotifications().length }}</span>\n }\n </button>\n <button class=\"tab-btn\" [class.active]=\"activeTab() === 'read'\" (click)=\"switchTab('read')\">\n Read\n @if (readNotifications().length > 0) {\n <span class=\"tab-badge read-badge\">{{ readNotifications().length }}</span>\n }\n </button>\n </div>\n\n <!-- Notifications List -->\n <div class=\"notifications-list\">\n @if (currentNotifications().length > 0) {\n @for (notification of currentNotifications(); track notification.id) {\n <div\n class=\"notification-item\"\n [class.unread]=\"!notification.isRead\"\n (click)=\"openDetails(notification)\"\n >\n @let t = typeOf(notification);\n <div class=\"notif-accent\"\n [class.type-info]=\"t === 'Info'\"\n [class.type-success]=\"t === 'Success'\"\n [class.type-warning]=\"t === 'Warning'\"\n [class.type-error]=\"t === 'Error'\"></div>\n <div class=\"notif-type-icon\"\n [class.type-info]=\"t === 'Info'\"\n [class.type-success]=\"t === 'Success'\"\n [class.type-warning]=\"t === 'Warning'\"\n [class.type-error]=\"t === 'Error'\">\n @if (t === 'Info') {\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9\"/><path d=\"M13.73 21a2 2 0 0 1-3.46 0\"/>\n </svg>\n }\n @if (t === 'Success') {\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <polyline points=\"20 6 9 17 4 12\"/>\n </svg>\n }\n @if (t === 'Warning') {\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"/><line x1=\"12\" y1=\"9\" x2=\"12\" y2=\"13\"/><line x1=\"12\" y1=\"17\" x2=\"12.01\" y2=\"17\"/>\n </svg>\n }\n @if (t === 'Error') {\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\"/><line x1=\"15\" y1=\"9\" x2=\"9\" y2=\"15\"/><line x1=\"9\" y1=\"9\" x2=\"15\" y2=\"15\"/>\n </svg>\n }\n </div>\n <div class=\"notification-content\">\n <div class=\"notification-title\">{{ notification.title }}</div>\n <div class=\"notification-message\">{{ notification.message }}</div>\n <div class=\"notification-meta\">\n <span class=\"app-name\">{{ notification.sourceAppName }}</span>\n <span class=\"time\">{{ dateLabels().get(notification.id) }}</span>\n </div>\n </div>\n @if (!notification.isRead) {\n <button class=\"icon-btn read-btn\" (click)=\"markAsRead(notification.id, $event)\" title=\"Mark as read\" aria-label=\"Mark as read\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <polyline points=\"20 6 9 17 4 12\"/>\n </svg>\n </button>\n }\n @if (notification.isRead) {\n <button class=\"icon-btn delete-btn\" (click)=\"delete(notification.id, $event)\" title=\"Delete\" aria-label=\"Delete notification\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <polyline points=\"3 6 5 6 21 6\"/><path d=\"M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6\"/><path d=\"M10 11v6\"/><path d=\"M14 11v6\"/><path d=\"M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2\"/>\n </svg>\n </button>\n }\n </div>\n }\n } @else {\n <div class=\"empty-state\">\n <svg class=\"empty-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"44\" height=\"44\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9\"/>\n <path d=\"M13.73 21a2 2 0 0 1-3.46 0\"/>\n </svg>\n <p>No {{ activeTab() }} notifications</p>\n </div>\n }\n </div>\n\n <!-- Footer Actions -->\n @if (currentNotifications().length > 0) {\n <div class=\"panel-footer\">\n @if (activeTab() === 'unread') {\n <div class=\"footer-actions\">\n @if (unreadNotifications().length > 0) {\n <button class=\"action-btn\" (click)=\"markAllAsRead()\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"/></svg>\n Mark all read\n </button>\n <button class=\"action-btn delete-all-btn\" (click)=\"deleteAllUnread()\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"3 6 5 6 21 6\"/><path d=\"M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6\"/></svg>\n Delete all\n </button>\n }\n </div>\n }\n @if (activeTab() === 'read' && readNotifications().length > 0) {\n <button class=\"action-btn delete-all-btn\" (click)=\"deleteAllRead()\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"3 6 5 6 21 6\"/><path d=\"M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6\"/></svg>\n Delete all\n </button>\n }\n </div>\n }\n</div>\n\n<!-- Details Modal -->\n@if (selectedNotification()) {\n <div class=\"modal-overlay\" (click)=\"closeDetails()\">\n <div class=\"modal-container\" (click)=\"$event.stopPropagation()\">\n <div class=\"modal-header\"\n [class.modal-type-info]=\"typeOf(selectedNotification()!) === 'Info'\"\n [class.modal-type-success]=\"typeOf(selectedNotification()!) === 'Success'\"\n [class.modal-type-warning]=\"typeOf(selectedNotification()!) === 'Warning'\"\n [class.modal-type-error]=\"typeOf(selectedNotification()!) === 'Error'\">\n <div class=\"modal-header-left\">\n <div class=\"modal-type-icon\">\n @if (typeOf(selectedNotification()!) === 'Info') {\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9\"/><path d=\"M13.73 21a2 2 0 0 1-3.46 0\"/>\n </svg>\n }\n @if (typeOf(selectedNotification()!) === 'Success') {\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M22 11.08V12a10 10 0 1 1-5.93-9.14\"/><polyline points=\"22 4 12 14.01 9 11.01\"/>\n </svg>\n }\n @if (typeOf(selectedNotification()!) === 'Warning') {\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"/><line x1=\"12\" y1=\"9\" x2=\"12\" y2=\"13\"/>\n </svg>\n }\n @if (typeOf(selectedNotification()!) === 'Error') {\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\"/><line x1=\"15\" y1=\"9\" x2=\"9\" y2=\"15\"/><line x1=\"9\" y1=\"9\" x2=\"15\" y2=\"15\"/>\n </svg>\n }\n </div>\n <h3>{{ selectedNotification()!.title }}</h3>\n </div>\n <button class=\"close-btn\" (click)=\"closeDetails()\" title=\"Close\" aria-label=\"Close notification detail\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/>\n </svg>\n </button>\n </div>\n <div class=\"modal-meta\">\n <span class=\"app-name\">{{ selectedNotification()!.sourceAppName }}</span>\n <span class=\"time\">{{ selectedNotificationDate() }}</span>\n </div>\n <div class=\"modal-body\" [innerHTML]=\"selectedNotificationHtml()\"></div>\n <div class=\"modal-footer\">\n @if (selectedNotification()?.url?.trim()) {\n <button class=\"action-btn see-details-btn\" (click)=\"openUrl()\">See Details</button>\n }\n <button class=\"action-btn\" (click)=\"closeDetails()\">Close</button>\n </div>\n </div>\n </div>\n}\n", styles: [".panel-header{display:flex;justify-content:space-between;align-items:center;padding:16px 18px;border-bottom:1px solid var(--border-color);background:var(--bg-secondary);flex-shrink:0}.panel-header-left{display:flex;align-items:center;gap:9px;color:var(--primary)}.panel-header h3{margin:0;font-size:16px;font-weight:700;color:var(--text-primary)}.close-btn{background:none;border:none;cursor:pointer;color:var(--text-muted);width:32px;height:32px;border-radius:8px;display:flex;align-items:center;justify-content:center;transition:background .15s,color .15s}.close-btn:hover{background:var(--bg-hover);color:var(--text-primary)}.tabs{display:flex;border-bottom:1px solid var(--border-color);background:var(--bg-secondary);flex-shrink:0}.tab-btn{flex:1;display:flex;align-items:center;justify-content:center;gap:6px;padding:11px 8px;background:none;border:none;border-bottom:2px solid transparent;color:var(--text-muted);cursor:pointer;font-size:13px;font-weight:500;transition:color .15s,border-color .15s}.tab-btn.active{color:var(--primary);border-bottom-color:var(--primary)}.tab-btn:hover:not(.active){color:var(--text-secondary)}.tab-badge{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:18px;padding:0 5px;background:var(--primary);color:#fff;font-size:11px;font-weight:700;border-radius:9px}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px 20px;gap:12px;color:var(--text-muted)}.empty-state p{margin:0;font-size:13px}.loading-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px;gap:12px;color:var(--text-muted);font-size:13px}.spinner{width:24px;height:24px;border:2px solid var(--border-color);border-top-color:var(--primary);border-radius:50%;animation:spin .7s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}\n", ":host{display:block;position:relative;--primary: #1976d2;--primary-hover: #1565c0;--success: #43a047;--error: #f44336;--error-hover: #d32f2f;--info-color: #2196f3;--info-bg: rgba(33, 150, 243, .1);--success-bg: rgba(67, 160, 71, .1);--warning-color: #f57c00;--warning-bg: rgba(245, 124, 0, .1);--error-bg: rgba(244, 67, 54, .1);--text-primary: #212121;--text-secondary: #616161;--text-muted: #9e9e9e;--bg-primary: #ffffff;--bg-secondary: #f8f9fa;--bg-hover: #f0f4ff;--bg-unread: rgba(25, 118, 210, .06);--border-color: #e0e0e0;--border-light: #eeeeee;--shadow: rgba(0, 0, 0, .15)}.tab-btn:not(.active) .tab-badge{background:var(--error)}.read-badge{background:var(--text-muted)}.notification-panel{position:fixed;top:0;right:-360px;width:360px;height:100vh;background:var(--bg-primary);box-shadow:-4px 0 24px var(--shadow);display:flex;flex-direction:column;z-index:1030;transition:right .3s cubic-bezier(.16,1,.3,1)}.notification-panel.open{right:0}.notifications-list{flex:1;overflow-y:auto}.notification-item{display:flex;align-items:flex-start;gap:0;border-bottom:1px solid var(--border-light);cursor:pointer;background:var(--bg-primary);transition:background-color .15s;position:relative}.notification-item:hover{background:var(--bg-hover)}.notification-item.unread{background:var(--bg-unread)}.notif-accent{width:3px;align-self:stretch;flex-shrink:0;background:transparent;border-radius:0 2px 2px 0;opacity:.3}.notification-item.unread .notif-accent{opacity:1}.notif-accent.type-info{background:var(--info-color)}.notif-accent.type-success{background:var(--success)}.notif-accent.type-warning{background:var(--warning-color)}.notif-accent.type-error{background:var(--error)}.notif-type-icon{flex-shrink:0;width:26px;height:26px;border-radius:7px;display:flex;align-items:center;justify-content:center;align-self:center;margin-left:10px}.notif-type-icon.type-info{color:var(--info-color);background:var(--info-bg)}.notif-type-icon.type-success{color:var(--success);background:var(--success-bg)}.notif-type-icon.type-warning{color:var(--warning-color);background:var(--warning-bg)}.notif-type-icon.type-error{color:var(--error);background:var(--error-bg)}.notification-content{flex:1;min-width:0;padding:12px 8px 12px 12px}.notification-title{font-weight:600;color:var(--text-primary);font-size:13.5px;margin-bottom:3px;line-height:1.35}.notification-message{color:var(--text-secondary);font-size:12px;line-height:1.45;margin-bottom:7px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.notification-meta{display:flex;justify-content:space-between;font-size:11px;color:var(--text-muted)}.app-name{font-weight:600;color:var(--primary)}.icon-btn{background:none;border:none;cursor:pointer;width:32px;height:32px;border-radius:8px;display:flex;align-items:center;justify-content:center;flex-shrink:0;align-self:center;margin-right:8px;transition:color .15s,background-color .15s;color:var(--text-muted)}.read-btn:hover{color:var(--success);background:#43a0471a}.delete-btn:hover{color:var(--error);background:#f443361a}.panel-footer{padding:10px 14px;border-top:1px solid var(--border-color);background:var(--bg-secondary);flex-shrink:0}.footer-actions{display:flex;gap:8px}.footer-actions .action-btn{flex:1}.action-btn{display:flex;align-items:center;justify-content:center;gap:6px;width:100%;padding:8px 12px;background:var(--primary);color:#fff;border:none;border-radius:8px;cursor:pointer;font-size:12.5px;font-weight:600;transition:background-color .18s,transform .12s}.action-btn:hover{background:var(--primary-hover);transform:translateY(-1px)}.delete-all-btn{background:var(--error)}.delete-all-btn:hover{background:var(--error-hover)}.modal-overlay{position:fixed;inset:0;background:#00000080;display:flex;align-items:center;justify-content:center;z-index:1060;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.modal-container{background:var(--bg-primary);border-radius:14px;width:92%;max-width:860px;max-height:88vh;display:flex;flex-direction:column;box-shadow:0 16px 48px #00000040;animation:modal-in .2s cubic-bezier(.16,1,.3,1)}@keyframes modal-in{0%{opacity:0;transform:scale(.94) translateY(8px)}to{opacity:1;transform:scale(1) translateY(0)}}.modal-header{display:flex;justify-content:space-between;align-items:center;padding:16px 20px;border-bottom:1px solid var(--border-color);background:var(--bg-secondary);border-radius:14px 14px 0 0;border-top:3px solid transparent}.modal-header.modal-type-info{border-top-color:var(--info-color)}.modal-header.modal-type-success{border-top-color:var(--success)}.modal-header.modal-type-warning{border-top-color:var(--warning-color)}.modal-header.modal-type-error{border-top-color:var(--error)}.modal-header-left{display:flex;align-items:center;gap:10px;min-width:0}.modal-type-icon{flex-shrink:0;width:32px;height:32px;border-radius:8px;display:flex;align-items:center;justify-content:center}.modal-type-info .modal-type-icon{color:var(--info-color);background:var(--info-bg)}.modal-type-success .modal-type-icon{color:var(--success);background:var(--success-bg)}.modal-type-warning .modal-type-icon{color:var(--warning-color);background:var(--warning-bg)}.modal-type-error .modal-type-icon{color:var(--error);background:var(--error-bg)}.modal-header h3{margin:0;font-size:15px;font-weight:700;color:var(--text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.modal-meta{display:flex;justify-content:space-between;padding:8px 20px;font-size:11.5px;color:var(--text-muted);border-bottom:1px solid var(--border-light)}.modal-body{padding:20px;overflow-y:auto;flex:1;color:var(--text-primary);font-size:14px;line-height:1.65}.modal-footer{padding:12px 20px;border-top:1px solid var(--border-color);background:var(--bg-secondary);border-radius:0 0 14px 14px;display:flex;justify-content:flex-end;gap:8px}.modal-footer .action-btn{width:auto;padding:8px 24px}.modal-footer .see-details-btn{background:var(--info-bg);color:var(--info-color);border:1px solid var(--info-color)}.modal-footer .see-details-btn:hover{opacity:.85}@media(max-width:600px){.notification-panel{width:100%;right:-100%}.modal-container{width:95%;max-height:90vh}}\n"] });
|
|
994
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: NotificationPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
995
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: NotificationPanelComponent, isStandalone: true, selector: "ma-notification-panel", outputs: { notificationRead: "notificationRead" }, host: { properties: { "class": "this.themeClass" } }, ngImport: i0, template: "<div class=\"notification-panel\" [class.open]=\"isOpen()\">\r\n <!-- Header -->\r\n <div class=\"panel-header\">\r\n <div class=\"panel-header-left\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9\"/>\r\n <path d=\"M13.73 21a2 2 0 0 1-3.46 0\"/>\r\n </svg>\r\n <h3>Notifications</h3>\r\n </div>\r\n <button class=\"close-btn\" (click)=\"close()\" title=\"Close\" aria-label=\"Close notifications\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/>\r\n </svg>\r\n </button>\r\n </div>\r\n\r\n <!-- Tabs -->\r\n <div class=\"tabs\">\r\n <button class=\"tab-btn\" [class.active]=\"activeTab() === 'unread'\" (click)=\"switchTab('unread')\">\r\n Unread\r\n @if (unreadNotifications().length > 0) {\r\n <span class=\"tab-badge\">{{ unreadNotifications().length }}</span>\r\n }\r\n </button>\r\n <button class=\"tab-btn\" [class.active]=\"activeTab() === 'read'\" (click)=\"switchTab('read')\">\r\n Read\r\n @if (readNotifications().length > 0) {\r\n <span class=\"tab-badge read-badge\">{{ readNotifications().length }}</span>\r\n }\r\n </button>\r\n </div>\r\n\r\n <!-- Notifications List -->\r\n <div class=\"notifications-list\">\r\n @if (currentNotifications().length > 0) {\r\n @for (notification of currentNotifications(); track notification.id) {\r\n <div\r\n class=\"notification-item\"\r\n [class.unread]=\"!notification.isRead\"\r\n (click)=\"openDetails(notification)\"\r\n >\r\n @let t = typeOf(notification);\r\n <div class=\"notif-accent\"\r\n [class.type-info]=\"t === 'Info'\"\r\n [class.type-success]=\"t === 'Success'\"\r\n [class.type-warning]=\"t === 'Warning'\"\r\n [class.type-error]=\"t === 'Error'\"></div>\r\n <div class=\"notif-type-icon\"\r\n [class.type-info]=\"t === 'Info'\"\r\n [class.type-success]=\"t === 'Success'\"\r\n [class.type-warning]=\"t === 'Warning'\"\r\n [class.type-error]=\"t === 'Error'\">\r\n @if (t === 'Info') {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9\"/><path d=\"M13.73 21a2 2 0 0 1-3.46 0\"/>\r\n </svg>\r\n }\r\n @if (t === 'Success') {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <polyline points=\"20 6 9 17 4 12\"/>\r\n </svg>\r\n }\r\n @if (t === 'Warning') {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"/><line x1=\"12\" y1=\"9\" x2=\"12\" y2=\"13\"/><line x1=\"12\" y1=\"17\" x2=\"12.01\" y2=\"17\"/>\r\n </svg>\r\n }\r\n @if (t === 'Error') {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <circle cx=\"12\" cy=\"12\" r=\"10\"/><line x1=\"15\" y1=\"9\" x2=\"9\" y2=\"15\"/><line x1=\"9\" y1=\"9\" x2=\"15\" y2=\"15\"/>\r\n </svg>\r\n }\r\n </div>\r\n <div class=\"notification-content\">\r\n <div class=\"notification-title\">{{ notification.title }}</div>\r\n <div class=\"notification-message\">{{ notification.message }}</div>\r\n <div class=\"notification-meta\">\r\n <span class=\"app-name\">{{ notification.sourceAppName }}</span>\r\n <span class=\"time\">{{ dateLabels().get(notification.id) }}</span>\r\n </div>\r\n </div>\r\n @if (!notification.isRead) {\r\n <button class=\"icon-btn read-btn\" (click)=\"markAsRead(notification.id, $event)\" title=\"Mark as read\" aria-label=\"Mark as read\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <polyline points=\"20 6 9 17 4 12\"/>\r\n </svg>\r\n </button>\r\n }\r\n @if (notification.isRead) {\r\n <button class=\"icon-btn delete-btn\" (click)=\"delete(notification.id, $event)\" title=\"Delete\" aria-label=\"Delete notification\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <polyline points=\"3 6 5 6 21 6\"/><path d=\"M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6\"/><path d=\"M10 11v6\"/><path d=\"M14 11v6\"/><path d=\"M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2\"/>\r\n </svg>\r\n </button>\r\n }\r\n </div>\r\n }\r\n } @else {\r\n <div class=\"empty-state\">\r\n <svg class=\"empty-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"44\" height=\"44\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9\"/>\r\n <path d=\"M13.73 21a2 2 0 0 1-3.46 0\"/>\r\n </svg>\r\n <p>No {{ activeTab() }} notifications</p>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Footer Actions -->\r\n @if (currentNotifications().length > 0) {\r\n <div class=\"panel-footer\">\r\n @if (activeTab() === 'unread') {\r\n <div class=\"footer-actions\">\r\n @if (unreadNotifications().length > 0) {\r\n <button class=\"action-btn\" (click)=\"markAllAsRead()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"/></svg>\r\n Mark all read\r\n </button>\r\n <button class=\"action-btn delete-all-btn\" (click)=\"deleteAllUnread()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"3 6 5 6 21 6\"/><path d=\"M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6\"/></svg>\r\n Delete all\r\n </button>\r\n }\r\n </div>\r\n }\r\n @if (activeTab() === 'read' && readNotifications().length > 0) {\r\n <button class=\"action-btn delete-all-btn\" (click)=\"deleteAllRead()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"3 6 5 6 21 6\"/><path d=\"M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6\"/></svg>\r\n Delete all\r\n </button>\r\n }\r\n </div>\r\n }\r\n</div>\r\n\r\n<!-- Details Modal -->\r\n@if (selectedNotification()) {\r\n <div class=\"modal-overlay\" (click)=\"closeDetails()\">\r\n <div class=\"modal-container\" (click)=\"$event.stopPropagation()\">\r\n <div class=\"modal-header\"\r\n [class.modal-type-info]=\"typeOf(selectedNotification()!) === 'Info'\"\r\n [class.modal-type-success]=\"typeOf(selectedNotification()!) === 'Success'\"\r\n [class.modal-type-warning]=\"typeOf(selectedNotification()!) === 'Warning'\"\r\n [class.modal-type-error]=\"typeOf(selectedNotification()!) === 'Error'\">\r\n <div class=\"modal-header-left\">\r\n <div class=\"modal-type-icon\">\r\n @if (typeOf(selectedNotification()!) === 'Info') {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9\"/><path d=\"M13.73 21a2 2 0 0 1-3.46 0\"/>\r\n </svg>\r\n }\r\n @if (typeOf(selectedNotification()!) === 'Success') {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M22 11.08V12a10 10 0 1 1-5.93-9.14\"/><polyline points=\"22 4 12 14.01 9 11.01\"/>\r\n </svg>\r\n }\r\n @if (typeOf(selectedNotification()!) === 'Warning') {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"/><line x1=\"12\" y1=\"9\" x2=\"12\" y2=\"13\"/>\r\n </svg>\r\n }\r\n @if (typeOf(selectedNotification()!) === 'Error') {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <circle cx=\"12\" cy=\"12\" r=\"10\"/><line x1=\"15\" y1=\"9\" x2=\"9\" y2=\"15\"/><line x1=\"9\" y1=\"9\" x2=\"15\" y2=\"15\"/>\r\n </svg>\r\n }\r\n </div>\r\n <h3>{{ selectedNotification()!.title }}</h3>\r\n </div>\r\n <button class=\"close-btn\" (click)=\"closeDetails()\" title=\"Close\" aria-label=\"Close notification detail\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/>\r\n </svg>\r\n </button>\r\n </div>\r\n <div class=\"modal-meta\">\r\n <span class=\"app-name\">{{ selectedNotification()!.sourceAppName }}</span>\r\n <span class=\"time\">{{ selectedNotificationDate() }}</span>\r\n </div>\r\n <div class=\"modal-body\" [innerHTML]=\"selectedNotificationHtml()\"></div>\r\n <div class=\"modal-footer\">\r\n @if (selectedNotification()?.url?.trim()) {\r\n <button class=\"action-btn see-details-btn\" (click)=\"openUrl()\">See Details</button>\r\n }\r\n <button class=\"action-btn\" (click)=\"closeDetails()\">Close</button>\r\n </div>\r\n </div>\r\n </div>\r\n}\r\n", styles: [".panel-header{display:flex;justify-content:space-between;align-items:center;padding:16px 18px;border-bottom:1px solid var(--border-color);background:var(--bg-secondary);flex-shrink:0}.panel-header-left{display:flex;align-items:center;gap:9px;color:var(--primary)}.panel-header h3{margin:0;font-size:16px;font-weight:700;color:var(--text-primary)}.close-btn{background:none;border:none;cursor:pointer;color:var(--text-muted);width:32px;height:32px;border-radius:8px;display:flex;align-items:center;justify-content:center;transition:background .15s,color .15s}.close-btn:hover{background:var(--bg-hover);color:var(--text-primary)}.tabs{display:flex;border-bottom:1px solid var(--border-color);background:var(--bg-secondary);flex-shrink:0}.tab-btn{flex:1;display:flex;align-items:center;justify-content:center;gap:6px;padding:11px 8px;background:none;border:none;border-bottom:2px solid transparent;color:var(--text-muted);cursor:pointer;font-size:13px;font-weight:500;transition:color .15s,border-color .15s}.tab-btn.active{color:var(--primary);border-bottom-color:var(--primary)}.tab-btn:hover:not(.active){color:var(--text-secondary)}.tab-badge{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:18px;padding:0 5px;background:var(--primary);color:#fff;font-size:11px;font-weight:700;border-radius:9px}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px 20px;gap:12px;color:var(--text-muted)}.empty-state p{margin:0;font-size:13px}.loading-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px;gap:12px;color:var(--text-muted);font-size:13px}.spinner{width:24px;height:24px;border:2px solid var(--border-color);border-top-color:var(--primary);border-radius:50%;animation:spin .7s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}\n", ":host{display:block;position:relative;--primary: #1976d2;--primary-hover: #1565c0;--success: #43a047;--error: #f44336;--error-hover: #d32f2f;--info-color: #2196f3;--info-bg: rgba(33, 150, 243, .1);--success-bg: rgba(67, 160, 71, .1);--warning-color: #f57c00;--warning-bg: rgba(245, 124, 0, .1);--error-bg: rgba(244, 67, 54, .1);--text-primary: #212121;--text-secondary: #616161;--text-muted: #9e9e9e;--bg-primary: #ffffff;--bg-secondary: #f8f9fa;--bg-hover: #f0f4ff;--bg-unread: rgba(25, 118, 210, .06);--border-color: #e0e0e0;--border-light: #eeeeee;--shadow: rgba(0, 0, 0, .15)}.tab-btn:not(.active) .tab-badge{background:var(--error)}.read-badge{background:var(--text-muted)}.notification-panel{position:fixed;top:0;right:-360px;width:360px;height:100vh;background:var(--bg-primary);box-shadow:-4px 0 24px var(--shadow);display:flex;flex-direction:column;z-index:1030;transition:right .3s cubic-bezier(.16,1,.3,1)}.notification-panel.open{right:0}.notifications-list{flex:1;overflow-y:auto}.notification-item{display:flex;align-items:flex-start;gap:0;border-bottom:1px solid var(--border-light);cursor:pointer;background:var(--bg-primary);transition:background-color .15s;position:relative}.notification-item:hover{background:var(--bg-hover)}.notification-item.unread{background:var(--bg-unread)}.notif-accent{width:3px;align-self:stretch;flex-shrink:0;background:transparent;border-radius:0 2px 2px 0;opacity:.3}.notification-item.unread .notif-accent{opacity:1}.notif-accent.type-info{background:var(--info-color)}.notif-accent.type-success{background:var(--success)}.notif-accent.type-warning{background:var(--warning-color)}.notif-accent.type-error{background:var(--error)}.notif-type-icon{flex-shrink:0;width:26px;height:26px;border-radius:7px;display:flex;align-items:center;justify-content:center;align-self:center;margin-left:10px}.notif-type-icon.type-info{color:var(--info-color);background:var(--info-bg)}.notif-type-icon.type-success{color:var(--success);background:var(--success-bg)}.notif-type-icon.type-warning{color:var(--warning-color);background:var(--warning-bg)}.notif-type-icon.type-error{color:var(--error);background:var(--error-bg)}.notification-content{flex:1;min-width:0;padding:12px 8px 12px 12px}.notification-title{font-weight:600;color:var(--text-primary);font-size:13.5px;margin-bottom:3px;line-height:1.35}.notification-message{color:var(--text-secondary);font-size:12px;line-height:1.45;margin-bottom:7px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.notification-meta{display:flex;justify-content:space-between;font-size:11px;color:var(--text-muted)}.app-name{font-weight:600;color:var(--primary)}.icon-btn{background:none;border:none;cursor:pointer;width:32px;height:32px;border-radius:8px;display:flex;align-items:center;justify-content:center;flex-shrink:0;align-self:center;margin-right:8px;transition:color .15s,background-color .15s;color:var(--text-muted)}.read-btn:hover{color:var(--success);background:#43a0471a}.delete-btn:hover{color:var(--error);background:#f443361a}.panel-footer{padding:10px 14px;border-top:1px solid var(--border-color);background:var(--bg-secondary);flex-shrink:0}.footer-actions{display:flex;gap:8px}.footer-actions .action-btn{flex:1}.action-btn{display:flex;align-items:center;justify-content:center;gap:6px;width:100%;padding:8px 12px;background:var(--primary);color:#fff;border:none;border-radius:8px;cursor:pointer;font-size:12.5px;font-weight:600;transition:background-color .18s,transform .12s}.action-btn:hover{background:var(--primary-hover);transform:translateY(-1px)}.delete-all-btn{background:var(--error)}.delete-all-btn:hover{background:var(--error-hover)}.modal-overlay{position:fixed;inset:0;background:#00000080;display:flex;align-items:center;justify-content:center;z-index:1060;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.modal-container{background:var(--bg-primary);border-radius:14px;width:92%;max-width:860px;max-height:88vh;display:flex;flex-direction:column;box-shadow:0 16px 48px #00000040;animation:modal-in .2s cubic-bezier(.16,1,.3,1)}@keyframes modal-in{0%{opacity:0;transform:scale(.94) translateY(8px)}to{opacity:1;transform:scale(1) translateY(0)}}.modal-header{display:flex;justify-content:space-between;align-items:center;padding:16px 20px;border-bottom:1px solid var(--border-color);background:var(--bg-secondary);border-radius:14px 14px 0 0;border-top:3px solid transparent}.modal-header.modal-type-info{border-top-color:var(--info-color)}.modal-header.modal-type-success{border-top-color:var(--success)}.modal-header.modal-type-warning{border-top-color:var(--warning-color)}.modal-header.modal-type-error{border-top-color:var(--error)}.modal-header-left{display:flex;align-items:center;gap:10px;min-width:0}.modal-type-icon{flex-shrink:0;width:32px;height:32px;border-radius:8px;display:flex;align-items:center;justify-content:center}.modal-type-info .modal-type-icon{color:var(--info-color);background:var(--info-bg)}.modal-type-success .modal-type-icon{color:var(--success);background:var(--success-bg)}.modal-type-warning .modal-type-icon{color:var(--warning-color);background:var(--warning-bg)}.modal-type-error .modal-type-icon{color:var(--error);background:var(--error-bg)}.modal-header h3{margin:0;font-size:15px;font-weight:700;color:var(--text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.modal-meta{display:flex;justify-content:space-between;padding:8px 20px;font-size:11.5px;color:var(--text-muted);border-bottom:1px solid var(--border-light)}.modal-body{padding:20px;overflow-y:auto;flex:1;color:var(--text-primary);font-size:14px;line-height:1.65}.modal-footer{padding:12px 20px;border-top:1px solid var(--border-color);background:var(--bg-secondary);border-radius:0 0 14px 14px;display:flex;justify-content:flex-end;gap:8px}.modal-footer .action-btn{width:auto;padding:8px 24px}.modal-footer .see-details-btn{background:var(--info-bg);color:var(--info-color);border:1px solid var(--info-color)}.modal-footer .see-details-btn:hover{opacity:.85}@media(max-width:600px){.notification-panel{width:100%;right:-100%}.modal-container{width:95%;max-height:90vh}}\n"] });
|
|
985
996
|
}
|
|
986
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
997
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: NotificationPanelComponent, decorators: [{
|
|
987
998
|
type: Component,
|
|
988
|
-
args: [{ selector: 'ma-notification-panel', imports: [], template: "<div class=\"notification-panel\" [class.open]=\"isOpen()\">\n <!-- Header -->\n <div class=\"panel-header\">\n <div class=\"panel-header-left\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9\"/>\n <path d=\"M13.73 21a2 2 0 0 1-3.46 0\"/>\n </svg>\n <h3>Notifications</h3>\n </div>\n <button class=\"close-btn\" (click)=\"close()\" title=\"Close\" aria-label=\"Close notifications\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/>\n </svg>\n </button>\n </div>\n\n <!-- Tabs -->\n <div class=\"tabs\">\n <button class=\"tab-btn\" [class.active]=\"activeTab() === 'unread'\" (click)=\"switchTab('unread')\">\n Unread\n @if (unreadNotifications().length > 0) {\n <span class=\"tab-badge\">{{ unreadNotifications().length }}</span>\n }\n </button>\n <button class=\"tab-btn\" [class.active]=\"activeTab() === 'read'\" (click)=\"switchTab('read')\">\n Read\n @if (readNotifications().length > 0) {\n <span class=\"tab-badge read-badge\">{{ readNotifications().length }}</span>\n }\n </button>\n </div>\n\n <!-- Notifications List -->\n <div class=\"notifications-list\">\n @if (currentNotifications().length > 0) {\n @for (notification of currentNotifications(); track notification.id) {\n <div\n class=\"notification-item\"\n [class.unread]=\"!notification.isRead\"\n (click)=\"openDetails(notification)\"\n >\n @let t = typeOf(notification);\n <div class=\"notif-accent\"\n [class.type-info]=\"t === 'Info'\"\n [class.type-success]=\"t === 'Success'\"\n [class.type-warning]=\"t === 'Warning'\"\n [class.type-error]=\"t === 'Error'\"></div>\n <div class=\"notif-type-icon\"\n [class.type-info]=\"t === 'Info'\"\n [class.type-success]=\"t === 'Success'\"\n [class.type-warning]=\"t === 'Warning'\"\n [class.type-error]=\"t === 'Error'\">\n @if (t === 'Info') {\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9\"/><path d=\"M13.73 21a2 2 0 0 1-3.46 0\"/>\n </svg>\n }\n @if (t === 'Success') {\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <polyline points=\"20 6 9 17 4 12\"/>\n </svg>\n }\n @if (t === 'Warning') {\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"/><line x1=\"12\" y1=\"9\" x2=\"12\" y2=\"13\"/><line x1=\"12\" y1=\"17\" x2=\"12.01\" y2=\"17\"/>\n </svg>\n }\n @if (t === 'Error') {\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\"/><line x1=\"15\" y1=\"9\" x2=\"9\" y2=\"15\"/><line x1=\"9\" y1=\"9\" x2=\"15\" y2=\"15\"/>\n </svg>\n }\n </div>\n <div class=\"notification-content\">\n <div class=\"notification-title\">{{ notification.title }}</div>\n <div class=\"notification-message\">{{ notification.message }}</div>\n <div class=\"notification-meta\">\n <span class=\"app-name\">{{ notification.sourceAppName }}</span>\n <span class=\"time\">{{ dateLabels().get(notification.id) }}</span>\n </div>\n </div>\n @if (!notification.isRead) {\n <button class=\"icon-btn read-btn\" (click)=\"markAsRead(notification.id, $event)\" title=\"Mark as read\" aria-label=\"Mark as read\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <polyline points=\"20 6 9 17 4 12\"/>\n </svg>\n </button>\n }\n @if (notification.isRead) {\n <button class=\"icon-btn delete-btn\" (click)=\"delete(notification.id, $event)\" title=\"Delete\" aria-label=\"Delete notification\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <polyline points=\"3 6 5 6 21 6\"/><path d=\"M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6\"/><path d=\"M10 11v6\"/><path d=\"M14 11v6\"/><path d=\"M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2\"/>\n </svg>\n </button>\n }\n </div>\n }\n } @else {\n <div class=\"empty-state\">\n <svg class=\"empty-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"44\" height=\"44\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9\"/>\n <path d=\"M13.73 21a2 2 0 0 1-3.46 0\"/>\n </svg>\n <p>No {{ activeTab() }} notifications</p>\n </div>\n }\n </div>\n\n <!-- Footer Actions -->\n @if (currentNotifications().length > 0) {\n <div class=\"panel-footer\">\n @if (activeTab() === 'unread') {\n <div class=\"footer-actions\">\n @if (unreadNotifications().length > 0) {\n <button class=\"action-btn\" (click)=\"markAllAsRead()\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"/></svg>\n Mark all read\n </button>\n <button class=\"action-btn delete-all-btn\" (click)=\"deleteAllUnread()\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"3 6 5 6 21 6\"/><path d=\"M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6\"/></svg>\n Delete all\n </button>\n }\n </div>\n }\n @if (activeTab() === 'read' && readNotifications().length > 0) {\n <button class=\"action-btn delete-all-btn\" (click)=\"deleteAllRead()\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"3 6 5 6 21 6\"/><path d=\"M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6\"/></svg>\n Delete all\n </button>\n }\n </div>\n }\n</div>\n\n<!-- Details Modal -->\n@if (selectedNotification()) {\n <div class=\"modal-overlay\" (click)=\"closeDetails()\">\n <div class=\"modal-container\" (click)=\"$event.stopPropagation()\">\n <div class=\"modal-header\"\n [class.modal-type-info]=\"typeOf(selectedNotification()!) === 'Info'\"\n [class.modal-type-success]=\"typeOf(selectedNotification()!) === 'Success'\"\n [class.modal-type-warning]=\"typeOf(selectedNotification()!) === 'Warning'\"\n [class.modal-type-error]=\"typeOf(selectedNotification()!) === 'Error'\">\n <div class=\"modal-header-left\">\n <div class=\"modal-type-icon\">\n @if (typeOf(selectedNotification()!) === 'Info') {\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9\"/><path d=\"M13.73 21a2 2 0 0 1-3.46 0\"/>\n </svg>\n }\n @if (typeOf(selectedNotification()!) === 'Success') {\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M22 11.08V12a10 10 0 1 1-5.93-9.14\"/><polyline points=\"22 4 12 14.01 9 11.01\"/>\n </svg>\n }\n @if (typeOf(selectedNotification()!) === 'Warning') {\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"/><line x1=\"12\" y1=\"9\" x2=\"12\" y2=\"13\"/>\n </svg>\n }\n @if (typeOf(selectedNotification()!) === 'Error') {\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"10\"/><line x1=\"15\" y1=\"9\" x2=\"9\" y2=\"15\"/><line x1=\"9\" y1=\"9\" x2=\"15\" y2=\"15\"/>\n </svg>\n }\n </div>\n <h3>{{ selectedNotification()!.title }}</h3>\n </div>\n <button class=\"close-btn\" (click)=\"closeDetails()\" title=\"Close\" aria-label=\"Close notification detail\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/>\n </svg>\n </button>\n </div>\n <div class=\"modal-meta\">\n <span class=\"app-name\">{{ selectedNotification()!.sourceAppName }}</span>\n <span class=\"time\">{{ selectedNotificationDate() }}</span>\n </div>\n <div class=\"modal-body\" [innerHTML]=\"selectedNotificationHtml()\"></div>\n <div class=\"modal-footer\">\n @if (selectedNotification()?.url?.trim()) {\n <button class=\"action-btn see-details-btn\" (click)=\"openUrl()\">See Details</button>\n }\n <button class=\"action-btn\" (click)=\"closeDetails()\">Close</button>\n </div>\n </div>\n </div>\n}\n", styles: [".panel-header{display:flex;justify-content:space-between;align-items:center;padding:16px 18px;border-bottom:1px solid var(--border-color);background:var(--bg-secondary);flex-shrink:0}.panel-header-left{display:flex;align-items:center;gap:9px;color:var(--primary)}.panel-header h3{margin:0;font-size:16px;font-weight:700;color:var(--text-primary)}.close-btn{background:none;border:none;cursor:pointer;color:var(--text-muted);width:32px;height:32px;border-radius:8px;display:flex;align-items:center;justify-content:center;transition:background .15s,color .15s}.close-btn:hover{background:var(--bg-hover);color:var(--text-primary)}.tabs{display:flex;border-bottom:1px solid var(--border-color);background:var(--bg-secondary);flex-shrink:0}.tab-btn{flex:1;display:flex;align-items:center;justify-content:center;gap:6px;padding:11px 8px;background:none;border:none;border-bottom:2px solid transparent;color:var(--text-muted);cursor:pointer;font-size:13px;font-weight:500;transition:color .15s,border-color .15s}.tab-btn.active{color:var(--primary);border-bottom-color:var(--primary)}.tab-btn:hover:not(.active){color:var(--text-secondary)}.tab-badge{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:18px;padding:0 5px;background:var(--primary);color:#fff;font-size:11px;font-weight:700;border-radius:9px}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px 20px;gap:12px;color:var(--text-muted)}.empty-state p{margin:0;font-size:13px}.loading-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px;gap:12px;color:var(--text-muted);font-size:13px}.spinner{width:24px;height:24px;border:2px solid var(--border-color);border-top-color:var(--primary);border-radius:50%;animation:spin .7s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}\n", ":host{display:block;position:relative;--primary: #1976d2;--primary-hover: #1565c0;--success: #43a047;--error: #f44336;--error-hover: #d32f2f;--info-color: #2196f3;--info-bg: rgba(33, 150, 243, .1);--success-bg: rgba(67, 160, 71, .1);--warning-color: #f57c00;--warning-bg: rgba(245, 124, 0, .1);--error-bg: rgba(244, 67, 54, .1);--text-primary: #212121;--text-secondary: #616161;--text-muted: #9e9e9e;--bg-primary: #ffffff;--bg-secondary: #f8f9fa;--bg-hover: #f0f4ff;--bg-unread: rgba(25, 118, 210, .06);--border-color: #e0e0e0;--border-light: #eeeeee;--shadow: rgba(0, 0, 0, .15)}.tab-btn:not(.active) .tab-badge{background:var(--error)}.read-badge{background:var(--text-muted)}.notification-panel{position:fixed;top:0;right:-360px;width:360px;height:100vh;background:var(--bg-primary);box-shadow:-4px 0 24px var(--shadow);display:flex;flex-direction:column;z-index:1030;transition:right .3s cubic-bezier(.16,1,.3,1)}.notification-panel.open{right:0}.notifications-list{flex:1;overflow-y:auto}.notification-item{display:flex;align-items:flex-start;gap:0;border-bottom:1px solid var(--border-light);cursor:pointer;background:var(--bg-primary);transition:background-color .15s;position:relative}.notification-item:hover{background:var(--bg-hover)}.notification-item.unread{background:var(--bg-unread)}.notif-accent{width:3px;align-self:stretch;flex-shrink:0;background:transparent;border-radius:0 2px 2px 0;opacity:.3}.notification-item.unread .notif-accent{opacity:1}.notif-accent.type-info{background:var(--info-color)}.notif-accent.type-success{background:var(--success)}.notif-accent.type-warning{background:var(--warning-color)}.notif-accent.type-error{background:var(--error)}.notif-type-icon{flex-shrink:0;width:26px;height:26px;border-radius:7px;display:flex;align-items:center;justify-content:center;align-self:center;margin-left:10px}.notif-type-icon.type-info{color:var(--info-color);background:var(--info-bg)}.notif-type-icon.type-success{color:var(--success);background:var(--success-bg)}.notif-type-icon.type-warning{color:var(--warning-color);background:var(--warning-bg)}.notif-type-icon.type-error{color:var(--error);background:var(--error-bg)}.notification-content{flex:1;min-width:0;padding:12px 8px 12px 12px}.notification-title{font-weight:600;color:var(--text-primary);font-size:13.5px;margin-bottom:3px;line-height:1.35}.notification-message{color:var(--text-secondary);font-size:12px;line-height:1.45;margin-bottom:7px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.notification-meta{display:flex;justify-content:space-between;font-size:11px;color:var(--text-muted)}.app-name{font-weight:600;color:var(--primary)}.icon-btn{background:none;border:none;cursor:pointer;width:32px;height:32px;border-radius:8px;display:flex;align-items:center;justify-content:center;flex-shrink:0;align-self:center;margin-right:8px;transition:color .15s,background-color .15s;color:var(--text-muted)}.read-btn:hover{color:var(--success);background:#43a0471a}.delete-btn:hover{color:var(--error);background:#f443361a}.panel-footer{padding:10px 14px;border-top:1px solid var(--border-color);background:var(--bg-secondary);flex-shrink:0}.footer-actions{display:flex;gap:8px}.footer-actions .action-btn{flex:1}.action-btn{display:flex;align-items:center;justify-content:center;gap:6px;width:100%;padding:8px 12px;background:var(--primary);color:#fff;border:none;border-radius:8px;cursor:pointer;font-size:12.5px;font-weight:600;transition:background-color .18s,transform .12s}.action-btn:hover{background:var(--primary-hover);transform:translateY(-1px)}.delete-all-btn{background:var(--error)}.delete-all-btn:hover{background:var(--error-hover)}.modal-overlay{position:fixed;inset:0;background:#00000080;display:flex;align-items:center;justify-content:center;z-index:1060;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.modal-container{background:var(--bg-primary);border-radius:14px;width:92%;max-width:860px;max-height:88vh;display:flex;flex-direction:column;box-shadow:0 16px 48px #00000040;animation:modal-in .2s cubic-bezier(.16,1,.3,1)}@keyframes modal-in{0%{opacity:0;transform:scale(.94) translateY(8px)}to{opacity:1;transform:scale(1) translateY(0)}}.modal-header{display:flex;justify-content:space-between;align-items:center;padding:16px 20px;border-bottom:1px solid var(--border-color);background:var(--bg-secondary);border-radius:14px 14px 0 0;border-top:3px solid transparent}.modal-header.modal-type-info{border-top-color:var(--info-color)}.modal-header.modal-type-success{border-top-color:var(--success)}.modal-header.modal-type-warning{border-top-color:var(--warning-color)}.modal-header.modal-type-error{border-top-color:var(--error)}.modal-header-left{display:flex;align-items:center;gap:10px;min-width:0}.modal-type-icon{flex-shrink:0;width:32px;height:32px;border-radius:8px;display:flex;align-items:center;justify-content:center}.modal-type-info .modal-type-icon{color:var(--info-color);background:var(--info-bg)}.modal-type-success .modal-type-icon{color:var(--success);background:var(--success-bg)}.modal-type-warning .modal-type-icon{color:var(--warning-color);background:var(--warning-bg)}.modal-type-error .modal-type-icon{color:var(--error);background:var(--error-bg)}.modal-header h3{margin:0;font-size:15px;font-weight:700;color:var(--text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.modal-meta{display:flex;justify-content:space-between;padding:8px 20px;font-size:11.5px;color:var(--text-muted);border-bottom:1px solid var(--border-light)}.modal-body{padding:20px;overflow-y:auto;flex:1;color:var(--text-primary);font-size:14px;line-height:1.65}.modal-footer{padding:12px 20px;border-top:1px solid var(--border-color);background:var(--bg-secondary);border-radius:0 0 14px 14px;display:flex;justify-content:flex-end;gap:8px}.modal-footer .action-btn{width:auto;padding:8px 24px}.modal-footer .see-details-btn{background:var(--info-bg);color:var(--info-color);border:1px solid var(--info-color)}.modal-footer .see-details-btn:hover{opacity:.85}@media(max-width:600px){.notification-panel{width:100%;right:-100%}.modal-container{width:95%;max-height:90vh}}\n"] }]
|
|
999
|
+
args: [{ selector: 'ma-notification-panel', imports: [], template: "<div class=\"notification-panel\" [class.open]=\"isOpen()\">\r\n <!-- Header -->\r\n <div class=\"panel-header\">\r\n <div class=\"panel-header-left\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9\"/>\r\n <path d=\"M13.73 21a2 2 0 0 1-3.46 0\"/>\r\n </svg>\r\n <h3>Notifications</h3>\r\n </div>\r\n <button class=\"close-btn\" (click)=\"close()\" title=\"Close\" aria-label=\"Close notifications\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/>\r\n </svg>\r\n </button>\r\n </div>\r\n\r\n <!-- Tabs -->\r\n <div class=\"tabs\">\r\n <button class=\"tab-btn\" [class.active]=\"activeTab() === 'unread'\" (click)=\"switchTab('unread')\">\r\n Unread\r\n @if (unreadNotifications().length > 0) {\r\n <span class=\"tab-badge\">{{ unreadNotifications().length }}</span>\r\n }\r\n </button>\r\n <button class=\"tab-btn\" [class.active]=\"activeTab() === 'read'\" (click)=\"switchTab('read')\">\r\n Read\r\n @if (readNotifications().length > 0) {\r\n <span class=\"tab-badge read-badge\">{{ readNotifications().length }}</span>\r\n }\r\n </button>\r\n </div>\r\n\r\n <!-- Notifications List -->\r\n <div class=\"notifications-list\">\r\n @if (currentNotifications().length > 0) {\r\n @for (notification of currentNotifications(); track notification.id) {\r\n <div\r\n class=\"notification-item\"\r\n [class.unread]=\"!notification.isRead\"\r\n (click)=\"openDetails(notification)\"\r\n >\r\n @let t = typeOf(notification);\r\n <div class=\"notif-accent\"\r\n [class.type-info]=\"t === 'Info'\"\r\n [class.type-success]=\"t === 'Success'\"\r\n [class.type-warning]=\"t === 'Warning'\"\r\n [class.type-error]=\"t === 'Error'\"></div>\r\n <div class=\"notif-type-icon\"\r\n [class.type-info]=\"t === 'Info'\"\r\n [class.type-success]=\"t === 'Success'\"\r\n [class.type-warning]=\"t === 'Warning'\"\r\n [class.type-error]=\"t === 'Error'\">\r\n @if (t === 'Info') {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9\"/><path d=\"M13.73 21a2 2 0 0 1-3.46 0\"/>\r\n </svg>\r\n }\r\n @if (t === 'Success') {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <polyline points=\"20 6 9 17 4 12\"/>\r\n </svg>\r\n }\r\n @if (t === 'Warning') {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"/><line x1=\"12\" y1=\"9\" x2=\"12\" y2=\"13\"/><line x1=\"12\" y1=\"17\" x2=\"12.01\" y2=\"17\"/>\r\n </svg>\r\n }\r\n @if (t === 'Error') {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <circle cx=\"12\" cy=\"12\" r=\"10\"/><line x1=\"15\" y1=\"9\" x2=\"9\" y2=\"15\"/><line x1=\"9\" y1=\"9\" x2=\"15\" y2=\"15\"/>\r\n </svg>\r\n }\r\n </div>\r\n <div class=\"notification-content\">\r\n <div class=\"notification-title\">{{ notification.title }}</div>\r\n <div class=\"notification-message\">{{ notification.message }}</div>\r\n <div class=\"notification-meta\">\r\n <span class=\"app-name\">{{ notification.sourceAppName }}</span>\r\n <span class=\"time\">{{ dateLabels().get(notification.id) }}</span>\r\n </div>\r\n </div>\r\n @if (!notification.isRead) {\r\n <button class=\"icon-btn read-btn\" (click)=\"markAsRead(notification.id, $event)\" title=\"Mark as read\" aria-label=\"Mark as read\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <polyline points=\"20 6 9 17 4 12\"/>\r\n </svg>\r\n </button>\r\n }\r\n @if (notification.isRead) {\r\n <button class=\"icon-btn delete-btn\" (click)=\"delete(notification.id, $event)\" title=\"Delete\" aria-label=\"Delete notification\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <polyline points=\"3 6 5 6 21 6\"/><path d=\"M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6\"/><path d=\"M10 11v6\"/><path d=\"M14 11v6\"/><path d=\"M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2\"/>\r\n </svg>\r\n </button>\r\n }\r\n </div>\r\n }\r\n } @else {\r\n <div class=\"empty-state\">\r\n <svg class=\"empty-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"44\" height=\"44\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9\"/>\r\n <path d=\"M13.73 21a2 2 0 0 1-3.46 0\"/>\r\n </svg>\r\n <p>No {{ activeTab() }} notifications</p>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Footer Actions -->\r\n @if (currentNotifications().length > 0) {\r\n <div class=\"panel-footer\">\r\n @if (activeTab() === 'unread') {\r\n <div class=\"footer-actions\">\r\n @if (unreadNotifications().length > 0) {\r\n <button class=\"action-btn\" (click)=\"markAllAsRead()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"/></svg>\r\n Mark all read\r\n </button>\r\n <button class=\"action-btn delete-all-btn\" (click)=\"deleteAllUnread()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"3 6 5 6 21 6\"/><path d=\"M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6\"/></svg>\r\n Delete all\r\n </button>\r\n }\r\n </div>\r\n }\r\n @if (activeTab() === 'read' && readNotifications().length > 0) {\r\n <button class=\"action-btn delete-all-btn\" (click)=\"deleteAllRead()\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"3 6 5 6 21 6\"/><path d=\"M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6\"/></svg>\r\n Delete all\r\n </button>\r\n }\r\n </div>\r\n }\r\n</div>\r\n\r\n<!-- Details Modal -->\r\n@if (selectedNotification()) {\r\n <div class=\"modal-overlay\" (click)=\"closeDetails()\">\r\n <div class=\"modal-container\" (click)=\"$event.stopPropagation()\">\r\n <div class=\"modal-header\"\r\n [class.modal-type-info]=\"typeOf(selectedNotification()!) === 'Info'\"\r\n [class.modal-type-success]=\"typeOf(selectedNotification()!) === 'Success'\"\r\n [class.modal-type-warning]=\"typeOf(selectedNotification()!) === 'Warning'\"\r\n [class.modal-type-error]=\"typeOf(selectedNotification()!) === 'Error'\">\r\n <div class=\"modal-header-left\">\r\n <div class=\"modal-type-icon\">\r\n @if (typeOf(selectedNotification()!) === 'Info') {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9\"/><path d=\"M13.73 21a2 2 0 0 1-3.46 0\"/>\r\n </svg>\r\n }\r\n @if (typeOf(selectedNotification()!) === 'Success') {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M22 11.08V12a10 10 0 1 1-5.93-9.14\"/><polyline points=\"22 4 12 14.01 9 11.01\"/>\r\n </svg>\r\n }\r\n @if (typeOf(selectedNotification()!) === 'Warning') {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z\"/><line x1=\"12\" y1=\"9\" x2=\"12\" y2=\"13\"/>\r\n </svg>\r\n }\r\n @if (typeOf(selectedNotification()!) === 'Error') {\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <circle cx=\"12\" cy=\"12\" r=\"10\"/><line x1=\"15\" y1=\"9\" x2=\"9\" y2=\"15\"/><line x1=\"9\" y1=\"9\" x2=\"15\" y2=\"15\"/>\r\n </svg>\r\n }\r\n </div>\r\n <h3>{{ selectedNotification()!.title }}</h3>\r\n </div>\r\n <button class=\"close-btn\" (click)=\"closeDetails()\" title=\"Close\" aria-label=\"Close notification detail\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/>\r\n </svg>\r\n </button>\r\n </div>\r\n <div class=\"modal-meta\">\r\n <span class=\"app-name\">{{ selectedNotification()!.sourceAppName }}</span>\r\n <span class=\"time\">{{ selectedNotificationDate() }}</span>\r\n </div>\r\n <div class=\"modal-body\" [innerHTML]=\"selectedNotificationHtml()\"></div>\r\n <div class=\"modal-footer\">\r\n @if (selectedNotification()?.url?.trim()) {\r\n <button class=\"action-btn see-details-btn\" (click)=\"openUrl()\">See Details</button>\r\n }\r\n <button class=\"action-btn\" (click)=\"closeDetails()\">Close</button>\r\n </div>\r\n </div>\r\n </div>\r\n}\r\n", styles: [".panel-header{display:flex;justify-content:space-between;align-items:center;padding:16px 18px;border-bottom:1px solid var(--border-color);background:var(--bg-secondary);flex-shrink:0}.panel-header-left{display:flex;align-items:center;gap:9px;color:var(--primary)}.panel-header h3{margin:0;font-size:16px;font-weight:700;color:var(--text-primary)}.close-btn{background:none;border:none;cursor:pointer;color:var(--text-muted);width:32px;height:32px;border-radius:8px;display:flex;align-items:center;justify-content:center;transition:background .15s,color .15s}.close-btn:hover{background:var(--bg-hover);color:var(--text-primary)}.tabs{display:flex;border-bottom:1px solid var(--border-color);background:var(--bg-secondary);flex-shrink:0}.tab-btn{flex:1;display:flex;align-items:center;justify-content:center;gap:6px;padding:11px 8px;background:none;border:none;border-bottom:2px solid transparent;color:var(--text-muted);cursor:pointer;font-size:13px;font-weight:500;transition:color .15s,border-color .15s}.tab-btn.active{color:var(--primary);border-bottom-color:var(--primary)}.tab-btn:hover:not(.active){color:var(--text-secondary)}.tab-badge{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:18px;padding:0 5px;background:var(--primary);color:#fff;font-size:11px;font-weight:700;border-radius:9px}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px 20px;gap:12px;color:var(--text-muted)}.empty-state p{margin:0;font-size:13px}.loading-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px;gap:12px;color:var(--text-muted);font-size:13px}.spinner{width:24px;height:24px;border:2px solid var(--border-color);border-top-color:var(--primary);border-radius:50%;animation:spin .7s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}\n", ":host{display:block;position:relative;--primary: #1976d2;--primary-hover: #1565c0;--success: #43a047;--error: #f44336;--error-hover: #d32f2f;--info-color: #2196f3;--info-bg: rgba(33, 150, 243, .1);--success-bg: rgba(67, 160, 71, .1);--warning-color: #f57c00;--warning-bg: rgba(245, 124, 0, .1);--error-bg: rgba(244, 67, 54, .1);--text-primary: #212121;--text-secondary: #616161;--text-muted: #9e9e9e;--bg-primary: #ffffff;--bg-secondary: #f8f9fa;--bg-hover: #f0f4ff;--bg-unread: rgba(25, 118, 210, .06);--border-color: #e0e0e0;--border-light: #eeeeee;--shadow: rgba(0, 0, 0, .15)}.tab-btn:not(.active) .tab-badge{background:var(--error)}.read-badge{background:var(--text-muted)}.notification-panel{position:fixed;top:0;right:-360px;width:360px;height:100vh;background:var(--bg-primary);box-shadow:-4px 0 24px var(--shadow);display:flex;flex-direction:column;z-index:1030;transition:right .3s cubic-bezier(.16,1,.3,1)}.notification-panel.open{right:0}.notifications-list{flex:1;overflow-y:auto}.notification-item{display:flex;align-items:flex-start;gap:0;border-bottom:1px solid var(--border-light);cursor:pointer;background:var(--bg-primary);transition:background-color .15s;position:relative}.notification-item:hover{background:var(--bg-hover)}.notification-item.unread{background:var(--bg-unread)}.notif-accent{width:3px;align-self:stretch;flex-shrink:0;background:transparent;border-radius:0 2px 2px 0;opacity:.3}.notification-item.unread .notif-accent{opacity:1}.notif-accent.type-info{background:var(--info-color)}.notif-accent.type-success{background:var(--success)}.notif-accent.type-warning{background:var(--warning-color)}.notif-accent.type-error{background:var(--error)}.notif-type-icon{flex-shrink:0;width:26px;height:26px;border-radius:7px;display:flex;align-items:center;justify-content:center;align-self:center;margin-left:10px}.notif-type-icon.type-info{color:var(--info-color);background:var(--info-bg)}.notif-type-icon.type-success{color:var(--success);background:var(--success-bg)}.notif-type-icon.type-warning{color:var(--warning-color);background:var(--warning-bg)}.notif-type-icon.type-error{color:var(--error);background:var(--error-bg)}.notification-content{flex:1;min-width:0;padding:12px 8px 12px 12px}.notification-title{font-weight:600;color:var(--text-primary);font-size:13.5px;margin-bottom:3px;line-height:1.35}.notification-message{color:var(--text-secondary);font-size:12px;line-height:1.45;margin-bottom:7px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}.notification-meta{display:flex;justify-content:space-between;font-size:11px;color:var(--text-muted)}.app-name{font-weight:600;color:var(--primary)}.icon-btn{background:none;border:none;cursor:pointer;width:32px;height:32px;border-radius:8px;display:flex;align-items:center;justify-content:center;flex-shrink:0;align-self:center;margin-right:8px;transition:color .15s,background-color .15s;color:var(--text-muted)}.read-btn:hover{color:var(--success);background:#43a0471a}.delete-btn:hover{color:var(--error);background:#f443361a}.panel-footer{padding:10px 14px;border-top:1px solid var(--border-color);background:var(--bg-secondary);flex-shrink:0}.footer-actions{display:flex;gap:8px}.footer-actions .action-btn{flex:1}.action-btn{display:flex;align-items:center;justify-content:center;gap:6px;width:100%;padding:8px 12px;background:var(--primary);color:#fff;border:none;border-radius:8px;cursor:pointer;font-size:12.5px;font-weight:600;transition:background-color .18s,transform .12s}.action-btn:hover{background:var(--primary-hover);transform:translateY(-1px)}.delete-all-btn{background:var(--error)}.delete-all-btn:hover{background:var(--error-hover)}.modal-overlay{position:fixed;inset:0;background:#00000080;display:flex;align-items:center;justify-content:center;z-index:1060;-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.modal-container{background:var(--bg-primary);border-radius:14px;width:92%;max-width:860px;max-height:88vh;display:flex;flex-direction:column;box-shadow:0 16px 48px #00000040;animation:modal-in .2s cubic-bezier(.16,1,.3,1)}@keyframes modal-in{0%{opacity:0;transform:scale(.94) translateY(8px)}to{opacity:1;transform:scale(1) translateY(0)}}.modal-header{display:flex;justify-content:space-between;align-items:center;padding:16px 20px;border-bottom:1px solid var(--border-color);background:var(--bg-secondary);border-radius:14px 14px 0 0;border-top:3px solid transparent}.modal-header.modal-type-info{border-top-color:var(--info-color)}.modal-header.modal-type-success{border-top-color:var(--success)}.modal-header.modal-type-warning{border-top-color:var(--warning-color)}.modal-header.modal-type-error{border-top-color:var(--error)}.modal-header-left{display:flex;align-items:center;gap:10px;min-width:0}.modal-type-icon{flex-shrink:0;width:32px;height:32px;border-radius:8px;display:flex;align-items:center;justify-content:center}.modal-type-info .modal-type-icon{color:var(--info-color);background:var(--info-bg)}.modal-type-success .modal-type-icon{color:var(--success);background:var(--success-bg)}.modal-type-warning .modal-type-icon{color:var(--warning-color);background:var(--warning-bg)}.modal-type-error .modal-type-icon{color:var(--error);background:var(--error-bg)}.modal-header h3{margin:0;font-size:15px;font-weight:700;color:var(--text-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.modal-meta{display:flex;justify-content:space-between;padding:8px 20px;font-size:11.5px;color:var(--text-muted);border-bottom:1px solid var(--border-light)}.modal-body{padding:20px;overflow-y:auto;flex:1;color:var(--text-primary);font-size:14px;line-height:1.65}.modal-footer{padding:12px 20px;border-top:1px solid var(--border-color);background:var(--bg-secondary);border-radius:0 0 14px 14px;display:flex;justify-content:flex-end;gap:8px}.modal-footer .action-btn{width:auto;padding:8px 24px}.modal-footer .see-details-btn{background:var(--info-bg);color:var(--info-color);border:1px solid var(--info-color)}.modal-footer .see-details-btn:hover{opacity:.85}@media(max-width:600px){.notification-panel{width:100%;right:-100%}.modal-container{width:95%;max-height:90vh}}\n"] }]
|
|
989
1000
|
}], ctorParameters: () => [], propDecorators: { notificationRead: [{ type: i0.Output, args: ["notificationRead"] }], themeClass: [{
|
|
990
1001
|
type: HostBinding,
|
|
991
1002
|
args: ['class']
|
|
@@ -1076,10 +1087,10 @@ class MaApprovalService {
|
|
|
1076
1087
|
createApproval(request) {
|
|
1077
1088
|
return this.http.post(`${this.apiBase}/approval/documents`, request, this.opts);
|
|
1078
1089
|
}
|
|
1079
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1080
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.
|
|
1090
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: MaApprovalService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
1091
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: MaApprovalService });
|
|
1081
1092
|
}
|
|
1082
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1093
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: MaApprovalService, decorators: [{
|
|
1083
1094
|
type: Injectable
|
|
1084
1095
|
}], ctorParameters: () => [] });
|
|
1085
1096
|
|
|
@@ -1216,12 +1227,12 @@ class MaApprovalPanelComponent {
|
|
|
1216
1227
|
this.close();
|
|
1217
1228
|
this.router.navigate(['/auth/approval/my-requests'], { queryParams: { status } });
|
|
1218
1229
|
}
|
|
1219
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1220
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
1230
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: MaApprovalPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1231
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: MaApprovalPanelComponent, isStandalone: true, selector: "ma-approval-panel", outputs: { approvalActioned: "approvalActioned" }, ngImport: i0, template: "<div class=\"approval-backdrop\" [class.open]=\"isOpen()\" (click)=\"close()\"></div>\r\n<div class=\"approval-panel\" [class.open]=\"isOpen()\">\r\n\r\n <!-- Header -->\r\n <div class=\"panel-header\">\r\n <div class=\"panel-header-left\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M9 11l3 3L22 4\"/>\r\n <path d=\"M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11\"/>\r\n </svg>\r\n <h3>Approvals</h3>\r\n </div>\r\n <button class=\"close-btn\" (click)=\"close()\" aria-label=\"Close\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/>\r\n </svg>\r\n </button>\r\n </div>\r\n\r\n <!-- Tabs -->\r\n <div class=\"tabs\">\r\n <button class=\"tab-btn\" [class.active]=\"activeTab() === 'processing'\" (click)=\"switchTab('processing')\">\r\n Processing\r\n @if (processingItems().length > 0) {\r\n <span class=\"tab-badge\">{{ processingItems().length }}</span>\r\n }\r\n </button>\r\n <button class=\"tab-btn\" [class.active]=\"activeTab() === 'approved'\" (click)=\"switchTab('approved')\">\r\n Approved\r\n </button>\r\n <button class=\"tab-btn\" [class.active]=\"activeTab() === 'rejected'\" (click)=\"switchTab('rejected')\">\r\n Rejected\r\n </button>\r\n </div>\r\n\r\n <!-- Content -->\r\n <div class=\"panel-content\">\r\n <!-- Loading -->\r\n @if (loading()) {\r\n <div class=\"loading-state\">\r\n <div class=\"spinner\"></div>\r\n <span>Loading...</span>\r\n </div>\r\n }\r\n\r\n <!-- Processing tab -->\r\n @if (!loading() && activeTab() === 'processing') {\r\n @if (processingItems().length === 0) {\r\n <div class=\"empty-state\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" opacity=\"0.4\"><path d=\"M9 11l3 3L22 4\"/><path d=\"M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11\"/></svg>\r\n <p>No pending approvals</p>\r\n </div>\r\n }\r\n @for (item of processingItems(); track item.id) {\r\n <div class=\"approval-item\" (click)=\"navigateToDetail(item.id)\">\r\n <div class=\"item-title\">{{ item.title }}</div>\r\n <div class=\"item-meta\">\r\n <span class=\"item-requester\">By {{ item.requestedByUserName }}</span>\r\n @if (item.currentStepName) {\r\n <span class=\"item-step\">\u00B7 {{ item.currentStepName }}</span>\r\n }\r\n </div>\r\n <div class=\"item-footer\">\r\n <span class=\"item-time\">{{ item.createdAt | date:'shortDate' }}</span>\r\n <span class=\"item-link\">View →</span>\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n <!-- Approved tab -->\r\n @if (!loading() && activeTab() === 'approved') {\r\n @if (approvedItems().length === 0) {\r\n <div class=\"empty-state\">\r\n <p>No approved documents</p>\r\n </div>\r\n }\r\n @for (item of approvedItems(); track item.id) {\r\n <div class=\"approval-item approved\" (click)=\"navigateToDetail(item.id)\">\r\n <div class=\"item-title\">{{ item.title }}</div>\r\n <div class=\"item-meta\">\r\n <span class=\"item-requester\">By {{ item.requestedByUserName }}</span>\r\n </div>\r\n <div class=\"item-footer\">\r\n <span class=\"status-badge approved-badge\">Approved</span>\r\n <span class=\"item-time\">{{ item.completedAt | date:'shortDate' }}</span>\r\n <span class=\"item-link\">View →</span>\r\n </div>\r\n </div>\r\n }\r\n @if (approvedItems().length >= 10) {\r\n <div class=\"show-more\" (click)=\"showMore('approved')\">Show more →</div>\r\n }\r\n }\r\n\r\n <!-- Rejected tab -->\r\n @if (!loading() && activeTab() === 'rejected') {\r\n @if (rejectedItems().length === 0) {\r\n <div class=\"empty-state\">\r\n <p>No rejected documents</p>\r\n </div>\r\n }\r\n @for (item of rejectedItems(); track item.id) {\r\n <div class=\"approval-item rejected\" (click)=\"navigateToDetail(item.id)\">\r\n <div class=\"item-title\">{{ item.title }}</div>\r\n <div class=\"item-meta\">\r\n <span class=\"item-requester\">By {{ item.requestedByUserName }}</span>\r\n </div>\r\n <div class=\"item-footer\">\r\n <span class=\"status-badge rejected-badge\">Rejected</span>\r\n <span class=\"item-time\">{{ item.completedAt | date:'shortDate' }}</span>\r\n <span class=\"item-link\">View →</span>\r\n </div>\r\n </div>\r\n }\r\n @if (rejectedItems().length >= 10) {\r\n <div class=\"show-more\" (click)=\"showMore('rejected')\">Show more →</div>\r\n }\r\n }\r\n </div>\r\n</div>\r\n", styles: [".panel-header{display:flex;justify-content:space-between;align-items:center;padding:16px 18px;border-bottom:1px solid var(--border-color);background:var(--bg-secondary);flex-shrink:0}.panel-header-left{display:flex;align-items:center;gap:9px;color:var(--primary)}.panel-header h3{margin:0;font-size:16px;font-weight:700;color:var(--text-primary)}.close-btn{background:none;border:none;cursor:pointer;color:var(--text-muted);width:32px;height:32px;border-radius:8px;display:flex;align-items:center;justify-content:center;transition:background .15s,color .15s}.close-btn:hover{background:var(--bg-hover);color:var(--text-primary)}.tabs{display:flex;border-bottom:1px solid var(--border-color);background:var(--bg-secondary);flex-shrink:0}.tab-btn{flex:1;display:flex;align-items:center;justify-content:center;gap:6px;padding:11px 8px;background:none;border:none;border-bottom:2px solid transparent;color:var(--text-muted);cursor:pointer;font-size:13px;font-weight:500;transition:color .15s,border-color .15s}.tab-btn.active{color:var(--primary);border-bottom-color:var(--primary)}.tab-btn:hover:not(.active){color:var(--text-secondary)}.tab-badge{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:18px;padding:0 5px;background:var(--primary);color:#fff;font-size:11px;font-weight:700;border-radius:9px}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px 20px;gap:12px;color:var(--text-muted)}.empty-state p{margin:0;font-size:13px}.loading-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px;gap:12px;color:var(--text-muted);font-size:13px}.spinner{width:24px;height:24px;border:2px solid var(--border-color);border-top-color:var(--primary);border-radius:50%;animation:spin .7s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}\n", ":host{--primary: #90caf9;--success: #66bb6a;--error: #ef5350;--text-primary: #e0e0e0;--text-secondary: #b0b0b0;--text-muted: #757575;--bg-primary: #1e1e2e;--bg-secondary: #27273a;--bg-hover: #2a2d4a;--border-color: #383850;--shadow: rgba(0,0,0,.4)}:host(.theme-light){--primary: #1565c0;--success: #2e7d32;--error: #c62828;--text-primary: #212121;--text-secondary: #616161;--text-muted: #9e9e9e;--bg-primary: #ffffff;--bg-secondary: #f5f5f5;--bg-hover: #e8eaf6;--border-color: #e0e0e0;--shadow: rgba(0,0,0,.15)}.approval-backdrop{display:none;position:fixed;inset:0;background:#0006;z-index:1029}.approval-backdrop.open{display:block}.approval-panel{position:fixed;top:0;right:-380px;width:380px;height:100vh;background:var(--bg-primary);box-shadow:-4px 0 24px var(--shadow);display:flex;flex-direction:column;z-index:1030;transition:right .3s cubic-bezier(.16,1,.3,1)}.approval-panel.open{right:0}.panel-content{flex:1;overflow-y:auto;padding:8px 0}.approval-item{padding:14px 18px;border-bottom:1px solid var(--border-color);cursor:pointer;transition:background .15s}.approval-item:hover{background:var(--bg-hover)}.approval-item:last-child{border-bottom:none}.item-title{font-size:14px;font-weight:600;color:var(--text-primary);margin-bottom:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.item-meta{font-size:12px;color:var(--text-muted);margin-bottom:8px;display:flex;gap:4px;flex-wrap:wrap}.item-footer{display:flex;align-items:center;gap:8px}.item-time{font-size:11px;color:var(--text-muted);margin-right:auto}.item-link{font-size:12px;color:var(--primary);font-weight:500}.status-badge{display:inline-block;padding:2px 8px;border-radius:10px;font-size:11px;font-weight:600;letter-spacing:.3px}.approved-badge{background:#66bb6a26;color:var(--success)}.rejected-badge{background:#ef53501f;color:var(--error)}.show-more{text-align:center;padding:14px;font-size:13px;color:var(--primary);cursor:pointer;font-weight:500}.show-more:hover{text-decoration:underline}\n"], dependencies: [{ kind: "pipe", type: DatePipe, name: "date" }] });
|
|
1221
1232
|
}
|
|
1222
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1233
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: MaApprovalPanelComponent, decorators: [{
|
|
1223
1234
|
type: Component,
|
|
1224
|
-
args: [{ selector: 'ma-approval-panel', imports: [DatePipe], template: "<div class=\"approval-backdrop\" [class.open]=\"isOpen()\" (click)=\"close()\"></div>\n<div class=\"approval-panel\" [class.open]=\"isOpen()\">\n\n <!-- Header -->\n <div class=\"panel-header\">\n <div class=\"panel-header-left\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M9 11l3 3L22 4\"/>\n <path d=\"M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11\"/>\n </svg>\n <h3>Approvals</h3>\n </div>\n <button class=\"close-btn\" (click)=\"close()\" aria-label=\"Close\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/>\n </svg>\n </button>\n </div>\n\n <!-- Tabs -->\n <div class=\"tabs\">\n <button class=\"tab-btn\" [class.active]=\"activeTab() === 'processing'\" (click)=\"switchTab('processing')\">\n Processing\n @if (processingItems().length > 0) {\n <span class=\"tab-badge\">{{ processingItems().length }}</span>\n }\n </button>\n <button class=\"tab-btn\" [class.active]=\"activeTab() === 'approved'\" (click)=\"switchTab('approved')\">\n Approved\n </button>\n <button class=\"tab-btn\" [class.active]=\"activeTab() === 'rejected'\" (click)=\"switchTab('rejected')\">\n Rejected\n </button>\n </div>\n\n <!-- Content -->\n <div class=\"panel-content\">\n <!-- Loading -->\n @if (loading()) {\n <div class=\"loading-state\">\n <div class=\"spinner\"></div>\n <span>Loading...</span>\n </div>\n }\n\n <!-- Processing tab -->\n @if (!loading() && activeTab() === 'processing') {\n @if (processingItems().length === 0) {\n <div class=\"empty-state\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" opacity=\"0.4\"><path d=\"M9 11l3 3L22 4\"/><path d=\"M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11\"/></svg>\n <p>No pending approvals</p>\n </div>\n }\n @for (item of processingItems(); track item.id) {\n <div class=\"approval-item\" (click)=\"navigateToDetail(item.id)\">\n <div class=\"item-title\">{{ item.title }}</div>\n <div class=\"item-meta\">\n <span class=\"item-requester\">By {{ item.requestedByUserName }}</span>\n @if (item.currentStepName) {\n <span class=\"item-step\">\u00B7 {{ item.currentStepName }}</span>\n }\n </div>\n <div class=\"item-footer\">\n <span class=\"item-time\">{{ item.createdAt | date:'shortDate' }}</span>\n <span class=\"item-link\">View →</span>\n </div>\n </div>\n }\n }\n\n <!-- Approved tab -->\n @if (!loading() && activeTab() === 'approved') {\n @if (approvedItems().length === 0) {\n <div class=\"empty-state\">\n <p>No approved documents</p>\n </div>\n }\n @for (item of approvedItems(); track item.id) {\n <div class=\"approval-item approved\" (click)=\"navigateToDetail(item.id)\">\n <div class=\"item-title\">{{ item.title }}</div>\n <div class=\"item-meta\">\n <span class=\"item-requester\">By {{ item.requestedByUserName }}</span>\n </div>\n <div class=\"item-footer\">\n <span class=\"status-badge approved-badge\">Approved</span>\n <span class=\"item-time\">{{ item.completedAt | date:'shortDate' }}</span>\n <span class=\"item-link\">View →</span>\n </div>\n </div>\n }\n @if (approvedItems().length >= 10) {\n <div class=\"show-more\" (click)=\"showMore('approved')\">Show more →</div>\n }\n }\n\n <!-- Rejected tab -->\n @if (!loading() && activeTab() === 'rejected') {\n @if (rejectedItems().length === 0) {\n <div class=\"empty-state\">\n <p>No rejected documents</p>\n </div>\n }\n @for (item of rejectedItems(); track item.id) {\n <div class=\"approval-item rejected\" (click)=\"navigateToDetail(item.id)\">\n <div class=\"item-title\">{{ item.title }}</div>\n <div class=\"item-meta\">\n <span class=\"item-requester\">By {{ item.requestedByUserName }}</span>\n </div>\n <div class=\"item-footer\">\n <span class=\"status-badge rejected-badge\">Rejected</span>\n <span class=\"item-time\">{{ item.completedAt | date:'shortDate' }}</span>\n <span class=\"item-link\">View →</span>\n </div>\n </div>\n }\n @if (rejectedItems().length >= 10) {\n <div class=\"show-more\" (click)=\"showMore('rejected')\">Show more →</div>\n }\n }\n </div>\n</div>\n", styles: [".panel-header{display:flex;justify-content:space-between;align-items:center;padding:16px 18px;border-bottom:1px solid var(--border-color);background:var(--bg-secondary);flex-shrink:0}.panel-header-left{display:flex;align-items:center;gap:9px;color:var(--primary)}.panel-header h3{margin:0;font-size:16px;font-weight:700;color:var(--text-primary)}.close-btn{background:none;border:none;cursor:pointer;color:var(--text-muted);width:32px;height:32px;border-radius:8px;display:flex;align-items:center;justify-content:center;transition:background .15s,color .15s}.close-btn:hover{background:var(--bg-hover);color:var(--text-primary)}.tabs{display:flex;border-bottom:1px solid var(--border-color);background:var(--bg-secondary);flex-shrink:0}.tab-btn{flex:1;display:flex;align-items:center;justify-content:center;gap:6px;padding:11px 8px;background:none;border:none;border-bottom:2px solid transparent;color:var(--text-muted);cursor:pointer;font-size:13px;font-weight:500;transition:color .15s,border-color .15s}.tab-btn.active{color:var(--primary);border-bottom-color:var(--primary)}.tab-btn:hover:not(.active){color:var(--text-secondary)}.tab-badge{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:18px;padding:0 5px;background:var(--primary);color:#fff;font-size:11px;font-weight:700;border-radius:9px}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px 20px;gap:12px;color:var(--text-muted)}.empty-state p{margin:0;font-size:13px}.loading-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px;gap:12px;color:var(--text-muted);font-size:13px}.spinner{width:24px;height:24px;border:2px solid var(--border-color);border-top-color:var(--primary);border-radius:50%;animation:spin .7s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}\n", ":host{--primary: #90caf9;--success: #66bb6a;--error: #ef5350;--text-primary: #e0e0e0;--text-secondary: #b0b0b0;--text-muted: #757575;--bg-primary: #1e1e2e;--bg-secondary: #27273a;--bg-hover: #2a2d4a;--border-color: #383850;--shadow: rgba(0,0,0,.4)}:host(.theme-light){--primary: #1565c0;--success: #2e7d32;--error: #c62828;--text-primary: #212121;--text-secondary: #616161;--text-muted: #9e9e9e;--bg-primary: #ffffff;--bg-secondary: #f5f5f5;--bg-hover: #e8eaf6;--border-color: #e0e0e0;--shadow: rgba(0,0,0,.15)}.approval-backdrop{display:none;position:fixed;inset:0;background:#0006;z-index:1029}.approval-backdrop.open{display:block}.approval-panel{position:fixed;top:0;right:-380px;width:380px;height:100vh;background:var(--bg-primary);box-shadow:-4px 0 24px var(--shadow);display:flex;flex-direction:column;z-index:1030;transition:right .3s cubic-bezier(.16,1,.3,1)}.approval-panel.open{right:0}.panel-content{flex:1;overflow-y:auto;padding:8px 0}.approval-item{padding:14px 18px;border-bottom:1px solid var(--border-color);cursor:pointer;transition:background .15s}.approval-item:hover{background:var(--bg-hover)}.approval-item:last-child{border-bottom:none}.item-title{font-size:14px;font-weight:600;color:var(--text-primary);margin-bottom:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.item-meta{font-size:12px;color:var(--text-muted);margin-bottom:8px;display:flex;gap:4px;flex-wrap:wrap}.item-footer{display:flex;align-items:center;gap:8px}.item-time{font-size:11px;color:var(--text-muted);margin-right:auto}.item-link{font-size:12px;color:var(--primary);font-weight:500}.status-badge{display:inline-block;padding:2px 8px;border-radius:10px;font-size:11px;font-weight:600;letter-spacing:.3px}.approved-badge{background:#66bb6a26;color:var(--success)}.rejected-badge{background:#ef53501f;color:var(--error)}.show-more{text-align:center;padding:14px;font-size:13px;color:var(--primary);cursor:pointer;font-weight:500}.show-more:hover{text-decoration:underline}\n"] }]
|
|
1235
|
+
args: [{ selector: 'ma-approval-panel', imports: [DatePipe], template: "<div class=\"approval-backdrop\" [class.open]=\"isOpen()\" (click)=\"close()\"></div>\r\n<div class=\"approval-panel\" [class.open]=\"isOpen()\">\r\n\r\n <!-- Header -->\r\n <div class=\"panel-header\">\r\n <div class=\"panel-header-left\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M9 11l3 3L22 4\"/>\r\n <path d=\"M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11\"/>\r\n </svg>\r\n <h3>Approvals</h3>\r\n </div>\r\n <button class=\"close-btn\" (click)=\"close()\" aria-label=\"Close\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/>\r\n </svg>\r\n </button>\r\n </div>\r\n\r\n <!-- Tabs -->\r\n <div class=\"tabs\">\r\n <button class=\"tab-btn\" [class.active]=\"activeTab() === 'processing'\" (click)=\"switchTab('processing')\">\r\n Processing\r\n @if (processingItems().length > 0) {\r\n <span class=\"tab-badge\">{{ processingItems().length }}</span>\r\n }\r\n </button>\r\n <button class=\"tab-btn\" [class.active]=\"activeTab() === 'approved'\" (click)=\"switchTab('approved')\">\r\n Approved\r\n </button>\r\n <button class=\"tab-btn\" [class.active]=\"activeTab() === 'rejected'\" (click)=\"switchTab('rejected')\">\r\n Rejected\r\n </button>\r\n </div>\r\n\r\n <!-- Content -->\r\n <div class=\"panel-content\">\r\n <!-- Loading -->\r\n @if (loading()) {\r\n <div class=\"loading-state\">\r\n <div class=\"spinner\"></div>\r\n <span>Loading...</span>\r\n </div>\r\n }\r\n\r\n <!-- Processing tab -->\r\n @if (!loading() && activeTab() === 'processing') {\r\n @if (processingItems().length === 0) {\r\n <div class=\"empty-state\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" opacity=\"0.4\"><path d=\"M9 11l3 3L22 4\"/><path d=\"M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11\"/></svg>\r\n <p>No pending approvals</p>\r\n </div>\r\n }\r\n @for (item of processingItems(); track item.id) {\r\n <div class=\"approval-item\" (click)=\"navigateToDetail(item.id)\">\r\n <div class=\"item-title\">{{ item.title }}</div>\r\n <div class=\"item-meta\">\r\n <span class=\"item-requester\">By {{ item.requestedByUserName }}</span>\r\n @if (item.currentStepName) {\r\n <span class=\"item-step\">\u00B7 {{ item.currentStepName }}</span>\r\n }\r\n </div>\r\n <div class=\"item-footer\">\r\n <span class=\"item-time\">{{ item.createdAt | date:'shortDate' }}</span>\r\n <span class=\"item-link\">View →</span>\r\n </div>\r\n </div>\r\n }\r\n }\r\n\r\n <!-- Approved tab -->\r\n @if (!loading() && activeTab() === 'approved') {\r\n @if (approvedItems().length === 0) {\r\n <div class=\"empty-state\">\r\n <p>No approved documents</p>\r\n </div>\r\n }\r\n @for (item of approvedItems(); track item.id) {\r\n <div class=\"approval-item approved\" (click)=\"navigateToDetail(item.id)\">\r\n <div class=\"item-title\">{{ item.title }}</div>\r\n <div class=\"item-meta\">\r\n <span class=\"item-requester\">By {{ item.requestedByUserName }}</span>\r\n </div>\r\n <div class=\"item-footer\">\r\n <span class=\"status-badge approved-badge\">Approved</span>\r\n <span class=\"item-time\">{{ item.completedAt | date:'shortDate' }}</span>\r\n <span class=\"item-link\">View →</span>\r\n </div>\r\n </div>\r\n }\r\n @if (approvedItems().length >= 10) {\r\n <div class=\"show-more\" (click)=\"showMore('approved')\">Show more →</div>\r\n }\r\n }\r\n\r\n <!-- Rejected tab -->\r\n @if (!loading() && activeTab() === 'rejected') {\r\n @if (rejectedItems().length === 0) {\r\n <div class=\"empty-state\">\r\n <p>No rejected documents</p>\r\n </div>\r\n }\r\n @for (item of rejectedItems(); track item.id) {\r\n <div class=\"approval-item rejected\" (click)=\"navigateToDetail(item.id)\">\r\n <div class=\"item-title\">{{ item.title }}</div>\r\n <div class=\"item-meta\">\r\n <span class=\"item-requester\">By {{ item.requestedByUserName }}</span>\r\n </div>\r\n <div class=\"item-footer\">\r\n <span class=\"status-badge rejected-badge\">Rejected</span>\r\n <span class=\"item-time\">{{ item.completedAt | date:'shortDate' }}</span>\r\n <span class=\"item-link\">View →</span>\r\n </div>\r\n </div>\r\n }\r\n @if (rejectedItems().length >= 10) {\r\n <div class=\"show-more\" (click)=\"showMore('rejected')\">Show more →</div>\r\n }\r\n }\r\n </div>\r\n</div>\r\n", styles: [".panel-header{display:flex;justify-content:space-between;align-items:center;padding:16px 18px;border-bottom:1px solid var(--border-color);background:var(--bg-secondary);flex-shrink:0}.panel-header-left{display:flex;align-items:center;gap:9px;color:var(--primary)}.panel-header h3{margin:0;font-size:16px;font-weight:700;color:var(--text-primary)}.close-btn{background:none;border:none;cursor:pointer;color:var(--text-muted);width:32px;height:32px;border-radius:8px;display:flex;align-items:center;justify-content:center;transition:background .15s,color .15s}.close-btn:hover{background:var(--bg-hover);color:var(--text-primary)}.tabs{display:flex;border-bottom:1px solid var(--border-color);background:var(--bg-secondary);flex-shrink:0}.tab-btn{flex:1;display:flex;align-items:center;justify-content:center;gap:6px;padding:11px 8px;background:none;border:none;border-bottom:2px solid transparent;color:var(--text-muted);cursor:pointer;font-size:13px;font-weight:500;transition:color .15s,border-color .15s}.tab-btn.active{color:var(--primary);border-bottom-color:var(--primary)}.tab-btn:hover:not(.active){color:var(--text-secondary)}.tab-badge{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:18px;padding:0 5px;background:var(--primary);color:#fff;font-size:11px;font-weight:700;border-radius:9px}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px 20px;gap:12px;color:var(--text-muted)}.empty-state p{margin:0;font-size:13px}.loading-state{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:40px;gap:12px;color:var(--text-muted);font-size:13px}.spinner{width:24px;height:24px;border:2px solid var(--border-color);border-top-color:var(--primary);border-radius:50%;animation:spin .7s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}\n", ":host{--primary: #90caf9;--success: #66bb6a;--error: #ef5350;--text-primary: #e0e0e0;--text-secondary: #b0b0b0;--text-muted: #757575;--bg-primary: #1e1e2e;--bg-secondary: #27273a;--bg-hover: #2a2d4a;--border-color: #383850;--shadow: rgba(0,0,0,.4)}:host(.theme-light){--primary: #1565c0;--success: #2e7d32;--error: #c62828;--text-primary: #212121;--text-secondary: #616161;--text-muted: #9e9e9e;--bg-primary: #ffffff;--bg-secondary: #f5f5f5;--bg-hover: #e8eaf6;--border-color: #e0e0e0;--shadow: rgba(0,0,0,.15)}.approval-backdrop{display:none;position:fixed;inset:0;background:#0006;z-index:1029}.approval-backdrop.open{display:block}.approval-panel{position:fixed;top:0;right:-380px;width:380px;height:100vh;background:var(--bg-primary);box-shadow:-4px 0 24px var(--shadow);display:flex;flex-direction:column;z-index:1030;transition:right .3s cubic-bezier(.16,1,.3,1)}.approval-panel.open{right:0}.panel-content{flex:1;overflow-y:auto;padding:8px 0}.approval-item{padding:14px 18px;border-bottom:1px solid var(--border-color);cursor:pointer;transition:background .15s}.approval-item:hover{background:var(--bg-hover)}.approval-item:last-child{border-bottom:none}.item-title{font-size:14px;font-weight:600;color:var(--text-primary);margin-bottom:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.item-meta{font-size:12px;color:var(--text-muted);margin-bottom:8px;display:flex;gap:4px;flex-wrap:wrap}.item-footer{display:flex;align-items:center;gap:8px}.item-time{font-size:11px;color:var(--text-muted);margin-right:auto}.item-link{font-size:12px;color:var(--primary);font-weight:500}.status-badge{display:inline-block;padding:2px 8px;border-radius:10px;font-size:11px;font-weight:600;letter-spacing:.3px}.approved-badge{background:#66bb6a26;color:var(--success)}.rejected-badge{background:#ef53501f;color:var(--error)}.show-more{text-align:center;padding:14px;font-size:13px;color:var(--primary);cursor:pointer;font-weight:500}.show-more:hover{text-decoration:underline}\n"] }]
|
|
1225
1236
|
}], ctorParameters: () => [], propDecorators: { approvalActioned: [{ type: i0.Output, args: ["approvalActioned"] }] } });
|
|
1226
1237
|
|
|
1227
1238
|
class MaUserComponent {
|
|
@@ -1256,12 +1267,12 @@ class MaUserComponent {
|
|
|
1256
1267
|
this.userProfile.loadPendingApprovalCount();
|
|
1257
1268
|
}
|
|
1258
1269
|
}
|
|
1259
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1260
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.
|
|
1270
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: MaUserComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1271
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.7", type: MaUserComponent, isStandalone: true, selector: "ma-user", inputs: { avatarShape: { classPropertyName: "avatarShape", publicName: "avatarShape", isSignal: true, isRequired: false, transformFunction: null }, showBell: { classPropertyName: "showBell", publicName: "showBell", isSignal: true, isRequired: false, transformFunction: null }, showApproval: { classPropertyName: "showApproval", publicName: "showApproval", isSignal: true, isRequired: false, transformFunction: null }, theme: { classPropertyName: "theme", publicName: "theme", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "userProfile", first: true, predicate: UserProfileComponent, descendants: true }, { propertyName: "approvalPanel", first: true, predicate: MaApprovalPanelComponent, descendants: true }], ngImport: i0, template: "<ma-toast-container></ma-toast-container>\r\n<div class=\"user-header\">\r\n <ma-user-profile\r\n (notificationClick)=\"notificationPanel.open()\"\r\n (approvalClick)=\"approvalPanel.open()\"\r\n [inputAvatarShape]=\"avatarShape()\"\r\n [showBell]=\"showBell()\"\r\n [showApproval]=\"showApproval()\">\r\n <ng-content></ng-content>\r\n </ma-user-profile>\r\n</div>\r\n<ma-notification-panel #notificationPanel (notificationRead)=\"onNotificationRead()\"></ma-notification-panel>\r\n<ma-approval-panel #approvalPanel (approvalActioned)=\"onApprovalActioned()\"></ma-approval-panel>\r\n", styles: [".user-header{display:flex;justify-content:flex-end}\n"], dependencies: [{ kind: "component", type: ToastContainerComponent, selector: "ma-toast-container" }, { kind: "component", type: UserProfileComponent, selector: "ma-user-profile", inputs: ["inputAvatarShape", "showBell", "showApproval"], outputs: ["notificationClick", "approvalClick"] }, { kind: "component", type: NotificationPanelComponent, selector: "ma-notification-panel", outputs: ["notificationRead"] }, { kind: "component", type: MaApprovalPanelComponent, selector: "ma-approval-panel", outputs: ["approvalActioned"] }] });
|
|
1261
1272
|
}
|
|
1262
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1273
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: MaUserComponent, decorators: [{
|
|
1263
1274
|
type: Component,
|
|
1264
|
-
args: [{ selector: 'ma-user', imports: [ToastContainerComponent, UserProfileComponent, NotificationPanelComponent, MaApprovalPanelComponent], template: "<ma-toast-container></ma-toast-container>\n<div class=\"user-header\">\n <ma-user-profile\n (notificationClick)=\"notificationPanel.open()\"\n (approvalClick)=\"approvalPanel.open()\"\n [inputAvatarShape]=\"avatarShape()\"\n [showBell]=\"showBell()\"\n [showApproval]=\"showApproval()\">\n <ng-content></ng-content>\n </ma-user-profile>\n</div>\n<ma-notification-panel #notificationPanel (notificationRead)=\"onNotificationRead()\"></ma-notification-panel>\n<ma-approval-panel #approvalPanel (approvalActioned)=\"onApprovalActioned()\"></ma-approval-panel>\n", styles: [".user-header{display:flex;justify-content:flex-end}\n"] }]
|
|
1275
|
+
args: [{ selector: 'ma-user', imports: [ToastContainerComponent, UserProfileComponent, NotificationPanelComponent, MaApprovalPanelComponent], template: "<ma-toast-container></ma-toast-container>\r\n<div class=\"user-header\">\r\n <ma-user-profile\r\n (notificationClick)=\"notificationPanel.open()\"\r\n (approvalClick)=\"approvalPanel.open()\"\r\n [inputAvatarShape]=\"avatarShape()\"\r\n [showBell]=\"showBell()\"\r\n [showApproval]=\"showApproval()\">\r\n <ng-content></ng-content>\r\n </ma-user-profile>\r\n</div>\r\n<ma-notification-panel #notificationPanel (notificationRead)=\"onNotificationRead()\"></ma-notification-panel>\r\n<ma-approval-panel #approvalPanel (approvalActioned)=\"onApprovalActioned()\"></ma-approval-panel>\r\n", styles: [".user-header{display:flex;justify-content:flex-end}\n"] }]
|
|
1265
1276
|
}], ctorParameters: () => [], propDecorators: { userProfile: [{
|
|
1266
1277
|
type: ViewChild,
|
|
1267
1278
|
args: [UserProfileComponent]
|
|
@@ -1270,6 +1281,129 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
1270
1281
|
args: [MaApprovalPanelComponent]
|
|
1271
1282
|
}], avatarShape: [{ type: i0.Input, args: [{ isSignal: true, alias: "avatarShape", required: false }] }], showBell: [{ type: i0.Input, args: [{ isSignal: true, alias: "showBell", required: false }] }], showApproval: [{ type: i0.Input, args: [{ isSignal: true, alias: "showApproval", required: false }] }], theme: [{ type: i0.Input, args: [{ isSignal: true, alias: "theme", required: false }] }] } });
|
|
1272
1283
|
|
|
1284
|
+
class MaUserXComponent {
|
|
1285
|
+
userId = input(null, ...(ngDevMode ? [{ debugName: "userId" }] : /* istanbul ignore next */ []));
|
|
1286
|
+
showName = input('full', ...(ngDevMode ? [{ debugName: "showName" }] : /* istanbul ignore next */ []));
|
|
1287
|
+
showTitle = input(true, ...(ngDevMode ? [{ debugName: "showTitle" }] : /* istanbul ignore next */ []));
|
|
1288
|
+
scale = input(0.5, ...(ngDevMode ? [{ debugName: "scale" }] : /* istanbul ignore next */ []));
|
|
1289
|
+
shape = input(null, ...(ngDevMode ? [{ debugName: "shape" }] : /* istanbul ignore next */ []));
|
|
1290
|
+
ratio = input('ar-11', ...(ngDevMode ? [{ debugName: "ratio" }] : /* istanbul ignore next */ []));
|
|
1291
|
+
user = input(null, ...(ngDevMode ? [{ debugName: "user" }] : /* istanbul ignore next */ []));
|
|
1292
|
+
useDefault = input(false, ...(ngDevMode ? [{ debugName: "useDefault" }] : /* istanbul ignore next */ []));
|
|
1293
|
+
showTooltip = input(true, ...(ngDevMode ? [{ debugName: "showTooltip" }] : /* istanbul ignore next */ []));
|
|
1294
|
+
theme = input(null, ...(ngDevMode ? [{ debugName: "theme" }] : /* istanbul ignore next */ []));
|
|
1295
|
+
themeService = inject(ThemeService);
|
|
1296
|
+
authService = inject(MesAuthService);
|
|
1297
|
+
hostEl = inject((ElementRef));
|
|
1298
|
+
xUser = signal(null, ...(ngDevMode ? [{ debugName: "xUser" }] : /* istanbul ignore next */ []));
|
|
1299
|
+
avatarRefresh = signal(Date.now(), ...(ngDevMode ? [{ debugName: "avatarRefresh" }] : /* istanbul ignore next */ []));
|
|
1300
|
+
tooltipOpen = signal(false, ...(ngDevMode ? [{ debugName: "tooltipOpen" }] : /* istanbul ignore next */ []));
|
|
1301
|
+
tooltipTop = signal(0, ...(ngDevMode ? [{ debugName: "tooltipTop" }] : /* istanbul ignore next */ []));
|
|
1302
|
+
tooltipLeft = signal(0, ...(ngDevMode ? [{ debugName: "tooltipLeft" }] : /* istanbul ignore next */ []));
|
|
1303
|
+
avatarShape = computed(() => this.shape() ?? this.xUser()?.avatarShape ?? 'circle', ...(ngDevMode ? [{ debugName: "avatarShape" }] : /* istanbul ignore next */ []));
|
|
1304
|
+
avatarFrame = computed(() => this.xUser()?.avatarFrame ?? null, ...(ngDevMode ? [{ debugName: "avatarFrame" }] : /* istanbul ignore next */ []));
|
|
1305
|
+
avatarRatio = computed(() => this.ratio() ?? this.xUser()?.avatarRatio, ...(ngDevMode ? [{ debugName: "avatarRatio" }] : /* istanbul ignore next */ []));
|
|
1306
|
+
avatarSize = computed(() => this.xUser()?.avatarSize ?? 'md', ...(ngDevMode ? [{ debugName: "avatarSize" }] : /* istanbul ignore next */ []));
|
|
1307
|
+
get themeClass() { return `theme-${this.themeService.currentTheme()}`; }
|
|
1308
|
+
constructor() {
|
|
1309
|
+
effect(() => {
|
|
1310
|
+
const t = this.theme();
|
|
1311
|
+
if (t) {
|
|
1312
|
+
this.themeService.setFixTheme(t);
|
|
1313
|
+
}
|
|
1314
|
+
});
|
|
1315
|
+
effect(() => {
|
|
1316
|
+
const user = this.user();
|
|
1317
|
+
if (user)
|
|
1318
|
+
this.xUser.set(user);
|
|
1319
|
+
});
|
|
1320
|
+
toObservable(this.userId).pipe(distinctUntilChanged(), switchMap$1(id => {
|
|
1321
|
+
if (this.user())
|
|
1322
|
+
return of(null);
|
|
1323
|
+
if (!id) {
|
|
1324
|
+
this.xUser.set(null);
|
|
1325
|
+
return of(null);
|
|
1326
|
+
}
|
|
1327
|
+
return this.authService.getUserX(id);
|
|
1328
|
+
}), takeUntilDestroyed()).subscribe({
|
|
1329
|
+
next: (u) => { if (u)
|
|
1330
|
+
this.xUser.set(u); },
|
|
1331
|
+
error: () => this.xUser.set(null)
|
|
1332
|
+
});
|
|
1333
|
+
}
|
|
1334
|
+
name = computed(() => {
|
|
1335
|
+
const fullname = this.xUser()?.fullName ?? '';
|
|
1336
|
+
if (this.showName() == 'none')
|
|
1337
|
+
return '';
|
|
1338
|
+
else if (this.showName() == 'short') {
|
|
1339
|
+
const parts = fullname?.split(' ');
|
|
1340
|
+
return parts[parts.length - 1];
|
|
1341
|
+
}
|
|
1342
|
+
return fullname;
|
|
1343
|
+
}, ...(ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []));
|
|
1344
|
+
getAvatarUrl(user) {
|
|
1345
|
+
// Use the refresh signal to force update
|
|
1346
|
+
//const refresh = this.avatarRefresh();
|
|
1347
|
+
const config = this.authService.getConfig();
|
|
1348
|
+
const baseUrl = config?.apiBaseUrl || '';
|
|
1349
|
+
// if (user.avatarPath) {
|
|
1350
|
+
// if (user.avatarPath.startsWith('http://') || user.avatarPath.startsWith('https://')) {
|
|
1351
|
+
// return user.avatarPath;
|
|
1352
|
+
// }
|
|
1353
|
+
// return `${baseUrl.replace(/\/$/, '')}${user.avatarPath}?t=${refresh}`;
|
|
1354
|
+
// }
|
|
1355
|
+
const userId = user?.userId ?? user?.id;
|
|
1356
|
+
if (userId && baseUrl) {
|
|
1357
|
+
return this.useDefault() ? `${baseUrl.replace(/\/$/, '')}/auth/${userId}/avatar/__default__` //?t=${refresh}
|
|
1358
|
+
: `${baseUrl.replace(/\/$/, '')}/auth/${userId}/avatar`; //?t=${refresh}
|
|
1359
|
+
}
|
|
1360
|
+
const displayName = user?.userName || user?.userId || 'User';
|
|
1361
|
+
return `https://ui-avatars.com/api/?name=${encodeURIComponent(displayName)}&background=1976d2&color=fff`;
|
|
1362
|
+
}
|
|
1363
|
+
getLastNameInitial(user) {
|
|
1364
|
+
const fullName = user.fullName || user.userName || 'U';
|
|
1365
|
+
const parts = fullName.split(' ');
|
|
1366
|
+
const lastPart = parts[parts.length - 1];
|
|
1367
|
+
return lastPart.charAt(0).toUpperCase();
|
|
1368
|
+
}
|
|
1369
|
+
onHostMouseEnter() {
|
|
1370
|
+
if (!this.showTooltip() || !this.xUser())
|
|
1371
|
+
return;
|
|
1372
|
+
const rect = this.hostEl.nativeElement.getBoundingClientRect();
|
|
1373
|
+
this.tooltipTop.set(rect.top - 8);
|
|
1374
|
+
this.tooltipLeft.set(rect.left);
|
|
1375
|
+
this.tooltipOpen.set(true);
|
|
1376
|
+
}
|
|
1377
|
+
onHostMouseLeave() {
|
|
1378
|
+
this.tooltipOpen.set(false);
|
|
1379
|
+
}
|
|
1380
|
+
onViewportChange() {
|
|
1381
|
+
if (this.tooltipOpen())
|
|
1382
|
+
this.tooltipOpen.set(false);
|
|
1383
|
+
}
|
|
1384
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: MaUserXComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1385
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: MaUserXComponent, isStandalone: true, selector: "ma-ux", inputs: { userId: { classPropertyName: "userId", publicName: "userId", isSignal: true, isRequired: false, transformFunction: null }, showName: { classPropertyName: "showName", publicName: "showName", isSignal: true, isRequired: false, transformFunction: null }, showTitle: { classPropertyName: "showTitle", publicName: "showTitle", isSignal: true, isRequired: false, transformFunction: null }, scale: { classPropertyName: "scale", publicName: "scale", isSignal: true, isRequired: false, transformFunction: null }, shape: { classPropertyName: "shape", publicName: "shape", isSignal: true, isRequired: false, transformFunction: null }, ratio: { classPropertyName: "ratio", publicName: "ratio", isSignal: true, isRequired: false, transformFunction: null }, user: { classPropertyName: "user", publicName: "user", isSignal: true, isRequired: false, transformFunction: null }, useDefault: { classPropertyName: "useDefault", publicName: "useDefault", isSignal: true, isRequired: false, transformFunction: null }, showTooltip: { classPropertyName: "showTooltip", publicName: "showTooltip", isSignal: true, isRequired: false, transformFunction: null }, theme: { classPropertyName: "theme", publicName: "theme", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mouseenter": "onHostMouseEnter()", "mouseleave": "onHostMouseLeave()", "window:scroll": "onViewportChange()", "window:resize": "onViewportChange()" }, properties: { "class": "this.themeClass" } }, ngImport: i0, template: "<ng-container>\r\n @if (xUser()){\r\n <ma-avatar\r\n [src]=\"getAvatarUrl(xUser())\"\r\n [alt]=\"xUser()?.fullName || xUser()?.userName || ''\"\r\n [initials]=\"getLastNameInitial(xUser())\"\r\n [size]=\"avatarSize()\"\r\n [shape]=\"avatarShape()\"\r\n [ratio]=\"avatarRatio()\"\r\n [frame]=\"avatarFrame()\"\r\n [scale]=\"scale()\" />\r\n <span class=\"user-name\">{{ name() }}</span>\r\n @if (showTitle() && xUser()?.givenTitle){\r\n <span class=\"given-title-cell given-title-badge\" [class]=\"'given-color-' + xUser()?.givenColor\">{{xUser()?.givenTitle }}</span>\r\n }\r\n @if (showTooltip() && xUser(); as u) {\r\n <div class=\"ma-ux-tooltip\"\r\n [class.open]=\"tooltipOpen()\"\r\n [style.top.px]=\"tooltipTop()\"\r\n [style.left.px]=\"tooltipLeft()\"\r\n role=\"tooltip\">\r\n <ma-avatar\r\n [src]=\"getAvatarUrl(u)\"\r\n [alt]=\"u.fullName || u.userName || ''\"\r\n [initials]=\"getLastNameInitial(u)\"\r\n [size]=\"avatarSize()\"\r\n [frame]=\"avatarFrame()\"\r\n [shape]=\"avatarShape()\"\r\n [scale]=\"1\" />\r\n <div class=\"ma-ux-tooltip-info\">\r\n <div class=\"ma-ux-tooltip-name\">{{ u.fullName || u.userName }}</div>\r\n <div class=\"ma-ux-tooltip-meta\"> \r\n <span>{{ u.department || '-' }}</span>\r\n <span class=\"sep\">\u00B7</span>\r\n <span>{{ u.position || '-' }}</span>\r\n @if (showTitle() && xUser()?.givenTitle){ \r\n <span class=\"given-title-cell given-title-badge\" [class]=\"'given-color-' + xUser()?.givenColor\">{{xUser()?.givenTitle }}</span> \r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n }\r\n @else {\r\n <span>User | UserId is not config!</span>\r\n }\r\n \r\n</ng-container>\r\n", styles: [":host{display:flex;justify-content:flex-start;align-items:center;gap:5px;position:relative}.given-title-cell{display:inline-block;padding:1px 8px;border-radius:10px;font-size:11px;font-weight:600;height:19px}.ma-ux-tooltip{position:fixed;top:0;left:0;z-index:2147483000;display:none;align-items:center;gap:10px;padding:8px 12px;min-width:220px;max-width:320px;background:var(--ma-tooltip-bg, #ffffff);color:var(--ma-tooltip-fg, #212529);border:1px solid var(--ma-tooltip-border, rgba(0, 0, 0, .12));border-radius:8px;box-shadow:0 6px 18px #0000002e;pointer-events:none;opacity:0;transform:translateY(calc(-100% + 4px));transition:opacity .12s ease,transform .12s ease;white-space:nowrap}:host(.theme-dark) .ma-ux-tooltip,:host-context(.theme-dark) .ma-ux-tooltip{--ma-tooltip-bg: #2a2d31;--ma-tooltip-fg: #f1f3f5;--ma-tooltip-border: rgba(255, 255, 255, .12)}.ma-ux-tooltip.open{display:flex;opacity:1;transform:translateY(-100%)}.ma-ux-tooltip-info{display:flex;flex-direction:column;gap:2px;min-width:180px}.ma-ux-tooltip-name{font-size:13px;font-weight:600;line-height:1.2;overflow:hidden;text-overflow:ellipsis;margin-bottom:3px}.ma-ux-tooltip-meta{font-size:12px;opacity:.85;line-height:1.4;display:flex;align-items:center;gap:6px;text-overflow:ellipsis}.ma-ux-tooltip-meta .sep{opacity:.5}\n"], dependencies: [{ kind: "component", type: MaAvatarComponent, selector: "ma-avatar", inputs: ["src", "alt", "initials", "size", "shape", "frame", "ratio", "scale", "ring", "ringActive"] }] });
|
|
1386
|
+
}
|
|
1387
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: MaUserXComponent, decorators: [{
|
|
1388
|
+
type: Component,
|
|
1389
|
+
args: [{ selector: 'ma-ux', imports: [MaAvatarComponent], template: "<ng-container>\r\n @if (xUser()){\r\n <ma-avatar\r\n [src]=\"getAvatarUrl(xUser())\"\r\n [alt]=\"xUser()?.fullName || xUser()?.userName || ''\"\r\n [initials]=\"getLastNameInitial(xUser())\"\r\n [size]=\"avatarSize()\"\r\n [shape]=\"avatarShape()\"\r\n [ratio]=\"avatarRatio()\"\r\n [frame]=\"avatarFrame()\"\r\n [scale]=\"scale()\" />\r\n <span class=\"user-name\">{{ name() }}</span>\r\n @if (showTitle() && xUser()?.givenTitle){\r\n <span class=\"given-title-cell given-title-badge\" [class]=\"'given-color-' + xUser()?.givenColor\">{{xUser()?.givenTitle }}</span>\r\n }\r\n @if (showTooltip() && xUser(); as u) {\r\n <div class=\"ma-ux-tooltip\"\r\n [class.open]=\"tooltipOpen()\"\r\n [style.top.px]=\"tooltipTop()\"\r\n [style.left.px]=\"tooltipLeft()\"\r\n role=\"tooltip\">\r\n <ma-avatar\r\n [src]=\"getAvatarUrl(u)\"\r\n [alt]=\"u.fullName || u.userName || ''\"\r\n [initials]=\"getLastNameInitial(u)\"\r\n [size]=\"avatarSize()\"\r\n [frame]=\"avatarFrame()\"\r\n [shape]=\"avatarShape()\"\r\n [scale]=\"1\" />\r\n <div class=\"ma-ux-tooltip-info\">\r\n <div class=\"ma-ux-tooltip-name\">{{ u.fullName || u.userName }}</div>\r\n <div class=\"ma-ux-tooltip-meta\"> \r\n <span>{{ u.department || '-' }}</span>\r\n <span class=\"sep\">\u00B7</span>\r\n <span>{{ u.position || '-' }}</span>\r\n @if (showTitle() && xUser()?.givenTitle){ \r\n <span class=\"given-title-cell given-title-badge\" [class]=\"'given-color-' + xUser()?.givenColor\">{{xUser()?.givenTitle }}</span> \r\n }\r\n </div>\r\n </div>\r\n </div>\r\n }\r\n }\r\n @else {\r\n <span>User | UserId is not config!</span>\r\n }\r\n \r\n</ng-container>\r\n", styles: [":host{display:flex;justify-content:flex-start;align-items:center;gap:5px;position:relative}.given-title-cell{display:inline-block;padding:1px 8px;border-radius:10px;font-size:11px;font-weight:600;height:19px}.ma-ux-tooltip{position:fixed;top:0;left:0;z-index:2147483000;display:none;align-items:center;gap:10px;padding:8px 12px;min-width:220px;max-width:320px;background:var(--ma-tooltip-bg, #ffffff);color:var(--ma-tooltip-fg, #212529);border:1px solid var(--ma-tooltip-border, rgba(0, 0, 0, .12));border-radius:8px;box-shadow:0 6px 18px #0000002e;pointer-events:none;opacity:0;transform:translateY(calc(-100% + 4px));transition:opacity .12s ease,transform .12s ease;white-space:nowrap}:host(.theme-dark) .ma-ux-tooltip,:host-context(.theme-dark) .ma-ux-tooltip{--ma-tooltip-bg: #2a2d31;--ma-tooltip-fg: #f1f3f5;--ma-tooltip-border: rgba(255, 255, 255, .12)}.ma-ux-tooltip.open{display:flex;opacity:1;transform:translateY(-100%)}.ma-ux-tooltip-info{display:flex;flex-direction:column;gap:2px;min-width:180px}.ma-ux-tooltip-name{font-size:13px;font-weight:600;line-height:1.2;overflow:hidden;text-overflow:ellipsis;margin-bottom:3px}.ma-ux-tooltip-meta{font-size:12px;opacity:.85;line-height:1.4;display:flex;align-items:center;gap:6px;text-overflow:ellipsis}.ma-ux-tooltip-meta .sep{opacity:.5}\n"] }]
|
|
1390
|
+
}], ctorParameters: () => [], propDecorators: { userId: [{ type: i0.Input, args: [{ isSignal: true, alias: "userId", required: false }] }], showName: [{ type: i0.Input, args: [{ isSignal: true, alias: "showName", required: false }] }], showTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTitle", required: false }] }], scale: [{ type: i0.Input, args: [{ isSignal: true, alias: "scale", required: false }] }], shape: [{ type: i0.Input, args: [{ isSignal: true, alias: "shape", required: false }] }], ratio: [{ type: i0.Input, args: [{ isSignal: true, alias: "ratio", required: false }] }], user: [{ type: i0.Input, args: [{ isSignal: true, alias: "user", required: false }] }], useDefault: [{ type: i0.Input, args: [{ isSignal: true, alias: "useDefault", required: false }] }], showTooltip: [{ type: i0.Input, args: [{ isSignal: true, alias: "showTooltip", required: false }] }], theme: [{ type: i0.Input, args: [{ isSignal: true, alias: "theme", required: false }] }], themeClass: [{
|
|
1391
|
+
type: HostBinding,
|
|
1392
|
+
args: ['class']
|
|
1393
|
+
}], onHostMouseEnter: [{
|
|
1394
|
+
type: HostListener,
|
|
1395
|
+
args: ['mouseenter']
|
|
1396
|
+
}], onHostMouseLeave: [{
|
|
1397
|
+
type: HostListener,
|
|
1398
|
+
args: ['mouseleave']
|
|
1399
|
+
}], onViewportChange: [{
|
|
1400
|
+
type: HostListener,
|
|
1401
|
+
args: ['window:scroll']
|
|
1402
|
+
}, {
|
|
1403
|
+
type: HostListener,
|
|
1404
|
+
args: ['window:resize']
|
|
1405
|
+
}] } });
|
|
1406
|
+
|
|
1273
1407
|
class NotificationBadgeComponent {
|
|
1274
1408
|
notificationClick = output();
|
|
1275
1409
|
get themeClass() {
|
|
@@ -1303,12 +1437,12 @@ class NotificationBadgeComponent {
|
|
|
1303
1437
|
onNotificationClick() {
|
|
1304
1438
|
this.notificationClick.emit();
|
|
1305
1439
|
}
|
|
1306
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1307
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.
|
|
1440
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: NotificationBadgeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1441
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: NotificationBadgeComponent, isStandalone: true, selector: "ma-notification-badge", outputs: { notificationClick: "notificationClick" }, host: { properties: { "class": "this.themeClass" } }, ngImport: i0, template: "<button class=\"notification-btn\" (click)=\"onNotificationClick()\" title=\"Notifications\">\r\n <span class=\"icon\">\uD83D\uDD14</span>\r\n @if (unreadCount() > 0) {\r\n <span class=\"badge\">{{ unreadCount() }}</span>\r\n }\r\n</button>\r\n", styles: [".notification-btn{position:relative;background:none;border:none;font-size:24px;cursor:pointer;padding:8px;transition:opacity .2s}.notification-btn:hover{opacity:.7}.icon{display:inline-block}.badge{position:absolute;top:0;right:0;background-color:var(--error-color);color:#fff;border-radius:50%;width:20px;height:20px;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700}\n"] });
|
|
1308
1442
|
}
|
|
1309
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
1443
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: NotificationBadgeComponent, decorators: [{
|
|
1310
1444
|
type: Component,
|
|
1311
|
-
args: [{ selector: 'ma-notification-badge', imports: [], template: "<button class=\"notification-btn\" (click)=\"onNotificationClick()\" title=\"Notifications\">\n <span class=\"icon\">\uD83D\uDD14</span>\n @if (unreadCount() > 0) {\n <span class=\"badge\">{{ unreadCount() }}</span>\n }\n</button>\n", styles: [".notification-btn{position:relative;background:none;border:none;font-size:24px;cursor:pointer;padding:8px;transition:opacity .2s}.notification-btn:hover{opacity:.7}.icon{display:inline-block}.badge{position:absolute;top:0;right:0;background-color:var(--error-color);color:#fff;border-radius:50%;width:20px;height:20px;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700}\n"] }]
|
|
1445
|
+
args: [{ selector: 'ma-notification-badge', imports: [], template: "<button class=\"notification-btn\" (click)=\"onNotificationClick()\" title=\"Notifications\">\r\n <span class=\"icon\">\uD83D\uDD14</span>\r\n @if (unreadCount() > 0) {\r\n <span class=\"badge\">{{ unreadCount() }}</span>\r\n }\r\n</button>\r\n", styles: [".notification-btn{position:relative;background:none;border:none;font-size:24px;cursor:pointer;padding:8px;transition:opacity .2s}.notification-btn:hover{opacity:.7}.icon{display:inline-block}.badge{position:absolute;top:0;right:0;background-color:var(--error-color);color:#fff;border-radius:50%;width:20px;height:20px;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700}\n"] }]
|
|
1312
1446
|
}], ctorParameters: () => [], propDecorators: { notificationClick: [{ type: i0.Output, args: ["notificationClick"] }], themeClass: [{
|
|
1313
1447
|
type: HostBinding,
|
|
1314
1448
|
args: ['class']
|
|
@@ -1884,36 +2018,36 @@ class MaArvContainerComponent {
|
|
|
1884
2018
|
el.removeAttribute('class');
|
|
1885
2019
|
});
|
|
1886
2020
|
// Step 7: Wrap in a clean, print-friendly HTML document
|
|
1887
|
-
return `<!DOCTYPE html>
|
|
1888
|
-
<html>
|
|
1889
|
-
<head>
|
|
1890
|
-
<meta charset="utf-8">
|
|
1891
|
-
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
1892
|
-
<style>
|
|
1893
|
-
*, *::before, *::after { box-sizing: border-box; }
|
|
1894
|
-
body {
|
|
1895
|
-
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
1896
|
-
margin: 0; padding: 24px;
|
|
1897
|
-
color: #212121; background: #fff;
|
|
1898
|
-
font-size: 14px; line-height: 1.6;
|
|
1899
|
-
max-width: 210mm;
|
|
1900
|
-
}
|
|
1901
|
-
h1, h2, h3, h4, h5, h6 { color: #1565c0; margin: 0 0 12px; }
|
|
1902
|
-
p { margin: 0 0 8px; }
|
|
1903
|
-
img { max-width: 100%; }
|
|
1904
|
-
table { border-collapse: collapse; width: 100%; }
|
|
1905
|
-
td, th { padding: 8px 12px; border: 1px solid #ddd; text-align: left; vertical-align: top; }
|
|
1906
|
-
input, textarea, select {
|
|
1907
|
-
border: 1px solid #ccc; border-radius: 4px; padding: 6px 10px;
|
|
1908
|
-
font-size: 14px; width: 100%; background: #fafafa; color: #333;
|
|
1909
|
-
}
|
|
1910
|
-
label { font-weight: 500; display: block; margin-bottom: 4px; color: #333; }
|
|
1911
|
-
div { max-width: 100%; }
|
|
1912
|
-
</style>
|
|
1913
|
-
</head>
|
|
1914
|
-
<body>
|
|
1915
|
-
${clone.outerHTML}
|
|
1916
|
-
</body>
|
|
2021
|
+
return `<!DOCTYPE html>
|
|
2022
|
+
<html>
|
|
2023
|
+
<head>
|
|
2024
|
+
<meta charset="utf-8">
|
|
2025
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
2026
|
+
<style>
|
|
2027
|
+
*, *::before, *::after { box-sizing: border-box; }
|
|
2028
|
+
body {
|
|
2029
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
2030
|
+
margin: 0; padding: 24px;
|
|
2031
|
+
color: #212121; background: #fff;
|
|
2032
|
+
font-size: 14px; line-height: 1.6;
|
|
2033
|
+
max-width: 210mm;
|
|
2034
|
+
}
|
|
2035
|
+
h1, h2, h3, h4, h5, h6 { color: #1565c0; margin: 0 0 12px; }
|
|
2036
|
+
p { margin: 0 0 8px; }
|
|
2037
|
+
img { max-width: 100%; }
|
|
2038
|
+
table { border-collapse: collapse; width: 100%; }
|
|
2039
|
+
td, th { padding: 8px 12px; border: 1px solid #ddd; text-align: left; vertical-align: top; }
|
|
2040
|
+
input, textarea, select {
|
|
2041
|
+
border: 1px solid #ccc; border-radius: 4px; padding: 6px 10px;
|
|
2042
|
+
font-size: 14px; width: 100%; background: #fafafa; color: #333;
|
|
2043
|
+
}
|
|
2044
|
+
label { font-weight: 500; display: block; margin-bottom: 4px; color: #333; }
|
|
2045
|
+
div { max-width: 100%; }
|
|
2046
|
+
</style>
|
|
2047
|
+
</head>
|
|
2048
|
+
<body>
|
|
2049
|
+
${clone.outerHTML}
|
|
2050
|
+
</body>
|
|
1917
2051
|
</html>`;
|
|
1918
2052
|
}
|
|
1919
2053
|
async captureThumbnail() {
|
|
@@ -1937,12 +2071,12 @@ ${clone.outerHTML}
|
|
|
1937
2071
|
'text-transform', 'letter-spacing', 'white-space', 'word-break'
|
|
1938
2072
|
];
|
|
1939
2073
|
}
|
|
1940
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
1941
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: MaArvContainerComponent, isStandalone: true, selector: "ma-arv-container", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, referenceId: { classPropertyName: "referenceId", publicName: "referenceId", isSignal: true, isRequired: false, transformFunction: null }, templateIds: { classPropertyName: "templateIds", publicName: "templateIds", isSignal: true, isRequired: false, transformFunction: null }, callbackUrl: { classPropertyName: "callbackUrl", publicName: "callbackUrl", isSignal: true, isRequired: false, transformFunction: null }, deadlineHours: { classPropertyName: "deadlineHours", publicName: "deadlineHours", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { approvalSubmitted: "approvalSubmitted", approvalSubmitting: "approvalSubmitting", cancelled: "cancelled" }, host: { properties: { "class": "this.themeClass" } }, viewQueries: [{ propertyName: "contentBody", first: true, predicate: ["contentBody"], descendants: true, static: true }], ngImport: i0, template: "<div class=\"arv-container\">\n <!-- Content Area -->\n <div class=\"arv-content-body\" #contentBody>\n <ng-content></ng-content>\n </div>\n\n <!-- Approval Footer -->\n <div class=\"arv-footer\">\n @if (!isSubmitted()) {\n <div class=\"arv-footer-inner\">\n\n <!-- Routing mode -->\n <div class=\"arv-routing\">\n <div class=\"arv-routing-header\">\n <h4 class=\"arv-section-title\">Approval Routing</h4>\n <!-- Show routing toggle only when templateId is NOT locked to a single template -->\n @if (!templateIds() || templateIds()!.length <= 0) {\n <div class=\"arv-routing-mode\">\n <label class=\"arv-radio\">\n <input type=\"radio\" name=\"routingMode\" value=\"template\" [checked]=\"routingMode() === 'template'\" (change)=\"routingMode.set('template')\"> Use Template\n </label>\n <label class=\"arv-radio\">\n <input type=\"radio\" name=\"routingMode\" value=\"adhoc\" [checked]=\"routingMode() === 'adhoc'\" (change)=\"routingMode.set('adhoc')\"> Custom Steps\n </label>\n </div>\n }\n </div>\n\n <!-- Locked template: only when templateId set and no multi-choice -->\n @if (templateIds() && templateIds()!.length === 1 && routingMode() === 'template') {\n <div class=\"arv-template-select\">\n @if (loadingTemplate()) {\n <div class=\"arv-template-loading\">Loading template...</div>\n }\n @if (selectedTemplate() && !loadingTemplate()) {\n <div class=\"arv-locked-template\">\n <span class=\"arv-locked-label\">Template</span>\n <span class=\"arv-locked-name\">{{ selectedTemplate()!.name }}</span>\n </div>\n }\n </div>\n }\n <!-- Template selector: shown when no templateId, OR when templateIds has multiple choices -->\n @else if (routingMode() === 'template') {\n <div class=\"arv-template-select\">\n <label class=\"arv-label\">Select Template</label>\n <select class=\"arv-select\" (change)=\"onTemplateChange($event)\">\n <option value=\"\">-- Select a template --</option>\n @for (t of templates(); track t.id) {\n <option [value]=\"t.id\" [selected]=\"t.id === selectedTemplateId()\">{{ t.name }}</option>\n }\n </select>\n </div>\n }\n\n <!-- Step pickers (shared for both locked and free template) -->\n @if (routingMode() === 'template') {\n <div class=\"arv-template-select\">\n @if (!loadingTemplate() && selectedTemplate()) {\n <!-- arv-template-steps -->\n <div class=\"arv-steps\">\n @for (s of selectedTemplate()!.steps; track s.stepOrder; let i = $index) {\n <div class=\"arv-step\">\n <div class=\"arv-step-card-header\">\n <span class=\"arv-step-preview-num\">Step {{ s.stepOrder }}</span>\n <span class=\"arv-step-preview-name\">{{ s.stepName }}</span>\n @if(isStepsError()[i]) {\n <span class=\"arv-step-error\">Required (*)</span>\n }\n @if (s.roles && s.roles.length > 0) {\n <span class=\"arv-step-role-badge\">\n @for (r of s.roles; track r.id) {\n {{ r.positionLevel }}{{ r.orgName ? ' \u00B7 ' + r.orgName : '' }}{{ r !== s.roles[s.roles.length - 1] ? ', ' : '' }}\n } \n </span>\n }\n </div>\n <!-- Selectable step: show approver picker -->\n @if (stepCandidates()[i]?.length > 1 || stepLoadingCandidates()[i]) {\n @if (stepLoadingCandidates()[i]) {\n <div class=\"arv-template-loading\">Loading candidates...</div>\n }\n @if (!stepLoadingCandidates()[i]) {\n <div class=\"arv-approvers\">\n <div class=\"arv-approver-tags\">\n @if (stepSelectedUsers()[i]) {\n <span class=\"arv-tag\">\n {{ userLabelMap()[stepSelectedUsers()[i]] || stepSelectedUsers()[i] }}\n <button class=\"arv-tag-remove\" (click)=\"onStepUserChangeInput(i, '')\">x</button>\n </span>\n }\n </div>\n @if (!stepSelectedUsers()[i]) {\n <div class=\"arv-user-search arv-step-picker\">\n <input class=\"arv-input arv-input-sm\" [value]=\"candidateSearchQuery()[i] || ''\"\n (input)=\"onCandidateSearchInput(i, $any($event.target).value)\"\n (focus)=\"onCandidateSearchInput(i, candidateSearchQuery()[i] || '')\"\n (blur)=\"clearCandidateResults(i)\"\n placeholder=\"Search approver...\" />\n @if (candidateSearchResults()[i]?.length) {\n <div class=\"arv-search-results\">\n @for (u of candidateSearchResults()[i]; track u.userId) {\n <div class=\"arv-search-item\" (mousedown)=\"onStepUserChangeInput(i, u.userId)\">\n {{ u.fullName || u.userName }} {{ u.department ? ' \u00B7 ' + u.department : '' }} {{ u.position ? ' (' + u.position + ')' : '' }} {{ u.employeeCode ? ' (' + u.employeeCode + ')' : '' }}\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n\n }\n <!-- Single fixed-user step: show who is assigned -->\n @if (!stepLoadingCandidates()[i] && stepCandidates()[i]?.length === 1) {\n <div class=\"arv-step-fixed\">\n {{ stepCandidates()[i][0].fullName || stepCandidates()[i][0].userId }}{{ stepCandidates()[i][0].department ? ' \u00B7 ' + stepCandidates()[i][0].department : '' }}{{ stepCandidates()[i][0].position ? ' (' + stepCandidates()[i][0].position + ')' : '' }}{{ stepCandidates()[i][0].employeeCode ? ' (' + stepCandidates()[i][0].employeeCode + ')' : '' }}\n </div>\n }\n </div>\n }\n @if (selectedTemplate() && selectedTemplate()!.referenceUserIds.length > 0) {\n <div class=\"arv-step-preview arv-step-preview-cc\">\n <span class=\"arv-step-preview-num\">CC</span>\n <span class=\"arv-step-preview-name\">{{ selectedTemplate()!.referenceUserIds.length }} reference user(s) from template</span>\n </div>\n }\n </div>\n }\n </div>\n }\n\n <!-- Ad-hoc steps -->\n @if (routingMode() === 'adhoc') {\n <div class=\"arv-steps\">\n @for (step of adHocSteps(); track step.stepOrder; let i = $index) {\n <div class=\"arv-step\">\n <div class=\"arv-step-header\">\n <span class=\"arv-step-num\">Step {{ i + 1 }}</span>\n @if (isStepsError()[i]) {\n <span class=\"arv-step-error\">Required (*)</span>\n }\n <input class=\"arv-input\" [value]=\"step.stepName\" (input)=\"updateStepName(i, $any($event.target).value)\" placeholder=\"Step name\" />\n <button class=\"arv-btn-icon arv-btn-danger\" (click)=\"removeStep(i)\" title=\"Remove step\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/></svg>\n </button>\n </div>\n <div class=\"arv-approvers\">\n <div class=\"arv-approver-tags\">\n @for (uid of step.approverUserIds; track uid; let j = $index) {\n <span class=\"arv-tag\">\n {{ userLabelMap()[uid] || uid }}\n <button class=\"arv-tag-remove\" (click)=\"removeApprover(i, j)\">x</button>\n </span>\n }\n </div>\n @if (step.approverUserIds.length === 0) {\n <div class=\"arv-user-search\">\n <input class=\"arv-input arv-input-sm\" [value]=\"userSearchQuery()[i] || ''\"\n (input)=\"onUserSearchInput(i, $any($event.target).value)\"\n placeholder=\"Search approver...\" />\n @if (userSearchResults()[i]?.length) {\n <div class=\"arv-search-results\">\n @for (u of userSearchResults()[i]; track u.id) {\n <div class=\"arv-search-item\" (click)=\"addApprover(i, u.id)\">\n {{ u.fullName || u.userName }} {{ u.department ? ' \u00B7 ' + u.department : '' }} {{ u.position ? ' (' + u.position + ')' : '' }} {{ u.employeeCode ? ' (' + u.employeeCode + ')' : '' }}\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n </div>\n }\n <button class=\"arv-btn arv-btn-outline\" (click)=\"addStep()\">+ Add Step</button>\n </div>\n }\n </div>\n\n <!-- Reference / CC users -->\n <div class=\"arv-references\">\n <h4 class=\"arv-section-title\">CC / Reference</h4>\n <p class=\"arv-hint\">These users will be notified when the approval completes, but won't be asked to approve.</p>\n <div class=\"arv-approver-tags\">\n @for (uid of referenceUserIds(); track uid; let j = $index) {\n <span class=\"arv-tag\">\n {{ userLabelMap()[uid] || uid }}\n <button class=\"arv-tag-remove\" (click)=\"removeReference(j)\">x</button>\n </span>\n }\n </div>\n <div class=\"arv-user-search\">\n <input class=\"arv-input arv-input-sm\" [value]=\"refSearchQuery()\"\n (input)=\"onRefSearchInput($any($event.target).value)\"\n placeholder=\"Search CC user...\" />\n @if (refSearchResults().length) {\n <div class=\"arv-search-results\">\n @for (u of refSearchResults(); track u.id) {\n <div class=\"arv-search-item\" (click)=\"addReference(u.id)\">\n {{ u.fullName || u.userName }} {{ u.department ? ' \u00B7 ' + u.department : '' }} {{ u.position ? ' (' + u.position + ')' : '' }} {{ u.employeeCode ? ' (' + u.employeeCode + ')' : '' }}\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n <!-- Actions -->\n <div class=\"arv-actions\">\n <button class=\"arv-btn arv-btn-secondary\" (click)=\"onCancel()\">Cancel</button>\n <button class=\"arv-btn arv-btn-primary\" [disabled]=\"submitting() || isError()\" (click)=\"submit()\">\n @if (submitting()) {\n <span class=\"arv-spinner\"></span>\n }\n {{isError() ? 'Complete Form to Submit' : submitting() ? 'Submitting...' : 'Submit for Approval' }}\n </button>\n </div>\n\n @if (errorMessage() || submitResultError()) {\n <div class=\"arv-error\">{{ errorMessage() || submitResultError() }}</div>\n }\n </div>\n }\n </div>\n\n <!-- Success state -->\n @if (isSubmitted()) {\n <div class=\"arv-success\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"40\" height=\"40\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#66bb6a\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M22 11.08V12a10 10 0 1 1-5.93-9.14\"/>\n <polyline points=\"22 4 12 14.01 9 11.01\"/>\n </svg>\n <p>Submitted for approval successfully.</p>\n </div>\n }\n</div>\n", styles: [".arv-container{display:flex;flex-direction:column;height:100%}.arv-content-body{flex:1;overflow:auto}.arv-footer{border-top:1px solid var(--arv-border);background:var(--arv-bg2)}.arv-footer-inner{padding:16px;display:flex;flex-direction:column;gap:14px}.arv-section-title{margin:0 0 8px;font-size:13px;font-weight:700;color:var(--arv-primary);text-transform:uppercase;letter-spacing:.5px}.arv-routing-header{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px}.arv-routing-mode{display:flex;gap:12px}.arv-radio{display:flex;align-items:center;gap:6px;font-size:13px;color:var(--arv-text);cursor:pointer}.arv-label{font-size:12px;color:var(--arv-text-muted);display:block;margin-bottom:4px}.arv-template-select{margin-bottom:10px}.arv-select{width:100%;padding:8px 32px 8px 10px;border:1px solid var(--arv-border);border-radius:var(--arv-radius);background:var(--arv-bg) url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E\") no-repeat right 10px center;color:var(--arv-text);font-size:13px;appearance:none;-webkit-appearance:none;cursor:pointer}.arv-input{padding:7px 10px;border:1px solid var(--arv-border);border-radius:var(--arv-radius);background:var(--arv-bg);color:var(--arv-text);font-size:13px}.arv-input-sm{width:100%;margin-top:0;padding:3px 10px}.arv-steps{display:flex;flex-direction:column;gap:10px}.arv-step{background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:var(--arv-radius);padding:10px}.arv-step-header{display:flex;align-items:center;gap:8px;margin-bottom:8px}.arv-step-num{font-size:12px;font-weight:700;color:var(--arv-primary);min-width:44px}.arv-approver-tags{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:6px}.arv-template-select .arv-approver-tags{margin-top:6px}.arv-tag{display:inline-flex;align-items:center;gap:4px;padding:3px 8px;background:#90caf91f;border:1px solid rgba(144,202,249,.3);border-radius:12px;font-size:12px;color:var(--arv-primary)}.arv-tag-remove{background:none;border:none;cursor:pointer;color:var(--arv-text-muted);font-size:11px;padding:0 2px;line-height:1}.arv-tag-remove:hover{color:var(--arv-danger)}.arv-user-search{position:relative}.arv-search-results{position:absolute;left:0;right:0;z-index:100;background:var(--arv-bg2);border:1px solid var(--arv-border);border-radius:var(--arv-radius);max-height:150px;overflow-y:auto}.arv-search-item{padding:8px 12px;cursor:pointer;font-size:13px;color:var(--arv-text)}.arv-search-item:hover{background:var(--arv-bg)}.arv-hint{font-size:12px;color:var(--arv-text-muted);margin:0 0 8px}.arv-btn-icon{background:none;border:none;cursor:pointer;padding:2px;border-radius:4px;display:inline-flex;align-items:center;justify-content:center}.arv-btn-danger{color:var(--arv-danger)}.arv-btn-danger:hover{background:#ef53501a}.arv-actions{display:flex;justify-content:flex-end;gap:10px}.arv-btn{padding:9px 18px;border-radius:var(--arv-radius);font-size:13px;font-weight:600;cursor:pointer;border:none;transition:background .15s}.arv-btn-primary{background:var(--arv-primary);color:#fff}.arv-btn-primary:hover:not(:disabled){background:var(--arv-primary-hover)}.arv-btn-primary:disabled{opacity:.6;cursor:not-allowed}.arv-btn-secondary{background:transparent;border:1px solid var(--arv-border);color:var(--arv-text-muted)}.arv-btn-secondary:hover{color:var(--arv-text);border-color:var(--arv-text-muted)}.arv-btn-outline{background:transparent;border:1px dashed var(--arv-border);color:var(--arv-text-muted);font-size:12px;padding:6px 12px}.arv-btn-outline:hover{border-color:var(--arv-primary);color:var(--arv-primary)}.arv-spinner{display:inline-block;width:14px;height:14px;border:2px solid rgba(255,255,255,.3);border-top-color:#fff;border-radius:50%;animation:arv-spin .6s linear infinite;margin-right:6px}@keyframes arv-spin{to{transform:rotate(360deg)}}.arv-error{padding:8px 12px;background:#ef53501a;border:1px solid rgba(239,83,80,.3);border-radius:var(--arv-radius);font-size:13px;color:var(--arv-danger)}.arv-success{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:32px;gap:12px;text-align:center}.arv-success p{color:var(--arv-success);font-size:15px;font-weight:600;margin:0}.arv-references{border-top:1px solid var(--arv-border);padding-top:12px}.arv-template-loading{font-size:12px;color:var(--arv-text-muted);margin-top:8px;padding:4px 0}.arv-template-steps{margin-top:8px;display:flex;flex-direction:column;gap:6px}.arv-step-card{background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:var(--arv-radius);overflow:hidden}.arv-step-card-header{display:flex;align-items:center;gap:8px;padding:7px 10px;background:#00000008;border-bottom:1px solid var(--arv-border);flex-wrap:wrap}.arv-step-preview{display:flex;align-items:center;gap:8px;padding:5px 8px;background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:4px;font-size:12px}.arv-step-preview-num{font-weight:700;color:var(--arv-primary);min-width:44px;flex-shrink:0;font-size:12px}.arv-step-preview-name{flex:1;color:var(--arv-text);font-size:12px;font-weight:600}.arv-step-error{font-size:11px;color:var(--arv-danger);font-weight:600}.arv-step-role-badge{font-size:11px;color:var(--arv-text-muted);background:#90caf91a;border:1px solid rgba(144,202,249,.25);border-radius:10px;padding:1px 7px}.arv-step-preview-cc .arv-step-preview-num{color:var(--arv-text-muted)}.arv-locked-template{display:flex;align-items:center;gap:8px;padding:7px 10px;background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:var(--arv-radius);margin-top:6px}.arv-locked-label{font-size:11px;color:var(--arv-text-muted);text-transform:uppercase;letter-spacing:.5px;flex-shrink:0}.arv-locked-name{font-size:13px;font-weight:600;color:var(--arv-text)}.arv-step-picker{padding:0}.arv-select-sm{font-size:12px;padding:6px 8px}.arv-step-fixed{padding:6px 10px;font-size:12px;color:var(--arv-text-muted)}\n"] });
|
|
2074
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: MaArvContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2075
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: MaArvContainerComponent, isStandalone: true, selector: "ma-arv-container", inputs: { title: { classPropertyName: "title", publicName: "title", isSignal: true, isRequired: false, transformFunction: null }, description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null }, referenceId: { classPropertyName: "referenceId", publicName: "referenceId", isSignal: true, isRequired: false, transformFunction: null }, templateIds: { classPropertyName: "templateIds", publicName: "templateIds", isSignal: true, isRequired: false, transformFunction: null }, callbackUrl: { classPropertyName: "callbackUrl", publicName: "callbackUrl", isSignal: true, isRequired: false, transformFunction: null }, deadlineHours: { classPropertyName: "deadlineHours", publicName: "deadlineHours", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { approvalSubmitted: "approvalSubmitted", approvalSubmitting: "approvalSubmitting", cancelled: "cancelled" }, host: { properties: { "class": "this.themeClass" } }, viewQueries: [{ propertyName: "contentBody", first: true, predicate: ["contentBody"], descendants: true, static: true }], ngImport: i0, template: "<div class=\"arv-container\">\r\n <!-- Content Area -->\r\n <div class=\"arv-content-body\" #contentBody>\r\n <ng-content></ng-content>\r\n </div>\r\n\r\n <!-- Approval Footer -->\r\n <div class=\"arv-footer\">\r\n @if (!isSubmitted()) {\r\n <div class=\"arv-footer-inner\">\r\n\r\n <!-- Routing mode -->\r\n <div class=\"arv-routing\">\r\n <div class=\"arv-routing-header\">\r\n <h4 class=\"arv-section-title\">Approval Routing</h4>\r\n <!-- Show routing toggle only when templateId is NOT locked to a single template -->\r\n @if (!templateIds() || templateIds()!.length <= 0) {\r\n <div class=\"arv-routing-mode\">\r\n <label class=\"arv-radio\">\r\n <input type=\"radio\" name=\"routingMode\" value=\"template\" [checked]=\"routingMode() === 'template'\" (change)=\"routingMode.set('template')\"> Use Template\r\n </label>\r\n <label class=\"arv-radio\">\r\n <input type=\"radio\" name=\"routingMode\" value=\"adhoc\" [checked]=\"routingMode() === 'adhoc'\" (change)=\"routingMode.set('adhoc')\"> Custom Steps\r\n </label>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Locked template: only when templateId set and no multi-choice -->\r\n @if (templateIds() && templateIds()!.length === 1 && routingMode() === 'template') {\r\n <div class=\"arv-template-select\">\r\n @if (loadingTemplate()) {\r\n <div class=\"arv-template-loading\">Loading template...</div>\r\n }\r\n @if (selectedTemplate() && !loadingTemplate()) {\r\n <div class=\"arv-locked-template\">\r\n <span class=\"arv-locked-label\">Template</span>\r\n <span class=\"arv-locked-name\">{{ selectedTemplate()!.name }}</span>\r\n </div>\r\n }\r\n </div>\r\n }\r\n <!-- Template selector: shown when no templateId, OR when templateIds has multiple choices -->\r\n @else if (routingMode() === 'template') {\r\n <div class=\"arv-template-select\">\r\n <label class=\"arv-label\">Select Template</label>\r\n <select class=\"arv-select\" (change)=\"onTemplateChange($event)\">\r\n <option value=\"\">-- Select a template --</option>\r\n @for (t of templates(); track t.id) {\r\n <option [value]=\"t.id\" [selected]=\"t.id === selectedTemplateId()\">{{ t.name }}</option>\r\n }\r\n </select>\r\n </div>\r\n }\r\n\r\n <!-- Step pickers (shared for both locked and free template) -->\r\n @if (routingMode() === 'template') {\r\n <div class=\"arv-template-select\">\r\n @if (!loadingTemplate() && selectedTemplate()) {\r\n <!-- arv-template-steps -->\r\n <div class=\"arv-steps\">\r\n @for (s of selectedTemplate()!.steps; track s.stepOrder; let i = $index) {\r\n <div class=\"arv-step\">\r\n <div class=\"arv-step-card-header\">\r\n <span class=\"arv-step-preview-num\">Step {{ s.stepOrder }}</span>\r\n <span class=\"arv-step-preview-name\">{{ s.stepName }}</span>\r\n @if(isStepsError()[i]) {\r\n <span class=\"arv-step-error\">Required (*)</span>\r\n }\r\n @if (s.roles && s.roles.length > 0) {\r\n <span class=\"arv-step-role-badge\">\r\n @for (r of s.roles; track r.id) {\r\n {{ r.positionLevel }}{{ r.orgName ? ' \u00B7 ' + r.orgName : '' }}{{ r !== s.roles[s.roles.length - 1] ? ', ' : '' }}\r\n } \r\n </span>\r\n }\r\n </div>\r\n <!-- Selectable step: show approver picker -->\r\n @if (stepCandidates()[i]?.length > 1 || stepLoadingCandidates()[i]) {\r\n @if (stepLoadingCandidates()[i]) {\r\n <div class=\"arv-template-loading\">Loading candidates...</div>\r\n }\r\n @if (!stepLoadingCandidates()[i]) {\r\n <div class=\"arv-approvers\">\r\n <div class=\"arv-approver-tags\">\r\n @if (stepSelectedUsers()[i]) {\r\n <span class=\"arv-tag\">\r\n {{ userLabelMap()[stepSelectedUsers()[i]] || stepSelectedUsers()[i] }}\r\n <button class=\"arv-tag-remove\" (click)=\"onStepUserChangeInput(i, '')\">x</button>\r\n </span>\r\n }\r\n </div>\r\n @if (!stepSelectedUsers()[i]) {\r\n <div class=\"arv-user-search arv-step-picker\">\r\n <input class=\"arv-input arv-input-sm\" [value]=\"candidateSearchQuery()[i] || ''\"\r\n (input)=\"onCandidateSearchInput(i, $any($event.target).value)\"\r\n (focus)=\"onCandidateSearchInput(i, candidateSearchQuery()[i] || '')\"\r\n (blur)=\"clearCandidateResults(i)\"\r\n placeholder=\"Search approver...\" />\r\n @if (candidateSearchResults()[i]?.length) {\r\n <div class=\"arv-search-results\">\r\n @for (u of candidateSearchResults()[i]; track u.userId) {\r\n <div class=\"arv-search-item\" (mousedown)=\"onStepUserChangeInput(i, u.userId)\">\r\n {{ u.fullName || u.userName }} {{ u.department ? ' \u00B7 ' + u.department : '' }} {{ u.position ? ' (' + u.position + ')' : '' }} {{ u.employeeCode ? ' (' + u.employeeCode + ')' : '' }}\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n }\r\n <!-- Single fixed-user step: show who is assigned -->\r\n @if (!stepLoadingCandidates()[i] && stepCandidates()[i]?.length === 1) {\r\n <div class=\"arv-step-fixed\">\r\n {{ stepCandidates()[i][0].fullName || stepCandidates()[i][0].userId }}{{ stepCandidates()[i][0].department ? ' \u00B7 ' + stepCandidates()[i][0].department : '' }}{{ stepCandidates()[i][0].position ? ' (' + stepCandidates()[i][0].position + ')' : '' }}{{ stepCandidates()[i][0].employeeCode ? ' (' + stepCandidates()[i][0].employeeCode + ')' : '' }}\r\n </div>\r\n }\r\n </div>\r\n }\r\n @if (selectedTemplate() && selectedTemplate()!.referenceUserIds.length > 0) {\r\n <div class=\"arv-step-preview arv-step-preview-cc\">\r\n <span class=\"arv-step-preview-num\">CC</span>\r\n <span class=\"arv-step-preview-name\">{{ selectedTemplate()!.referenceUserIds.length }} reference user(s) from template</span>\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Ad-hoc steps -->\r\n @if (routingMode() === 'adhoc') {\r\n <div class=\"arv-steps\">\r\n @for (step of adHocSteps(); track step.stepOrder; let i = $index) {\r\n <div class=\"arv-step\">\r\n <div class=\"arv-step-header\">\r\n <span class=\"arv-step-num\">Step {{ i + 1 }}</span>\r\n @if (isStepsError()[i]) {\r\n <span class=\"arv-step-error\">Required (*)</span>\r\n }\r\n <input class=\"arv-input\" [value]=\"step.stepName\" (input)=\"updateStepName(i, $any($event.target).value)\" placeholder=\"Step name\" />\r\n <button class=\"arv-btn-icon arv-btn-danger\" (click)=\"removeStep(i)\" title=\"Remove step\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/></svg>\r\n </button>\r\n </div>\r\n <div class=\"arv-approvers\">\r\n <div class=\"arv-approver-tags\">\r\n @for (uid of step.approverUserIds; track uid; let j = $index) {\r\n <span class=\"arv-tag\">\r\n {{ userLabelMap()[uid] || uid }}\r\n <button class=\"arv-tag-remove\" (click)=\"removeApprover(i, j)\">x</button>\r\n </span>\r\n }\r\n </div>\r\n @if (step.approverUserIds.length === 0) {\r\n <div class=\"arv-user-search\">\r\n <input class=\"arv-input arv-input-sm\" [value]=\"userSearchQuery()[i] || ''\"\r\n (input)=\"onUserSearchInput(i, $any($event.target).value)\"\r\n placeholder=\"Search approver...\" />\r\n @if (userSearchResults()[i]?.length) {\r\n <div class=\"arv-search-results\">\r\n @for (u of userSearchResults()[i]; track u.id) {\r\n <div class=\"arv-search-item\" (click)=\"addApprover(i, u.id)\">\r\n {{ u.fullName || u.userName }} {{ u.department ? ' \u00B7 ' + u.department : '' }} {{ u.position ? ' (' + u.position + ')' : '' }} {{ u.employeeCode ? ' (' + u.employeeCode + ')' : '' }}\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n }\r\n <button class=\"arv-btn arv-btn-outline\" (click)=\"addStep()\">+ Add Step</button>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Reference / CC users -->\r\n <div class=\"arv-references\">\r\n <h4 class=\"arv-section-title\">CC / Reference</h4>\r\n <p class=\"arv-hint\">These users will be notified when the approval completes, but won't be asked to approve.</p>\r\n <div class=\"arv-approver-tags\">\r\n @for (uid of referenceUserIds(); track uid; let j = $index) {\r\n <span class=\"arv-tag\">\r\n {{ userLabelMap()[uid] || uid }}\r\n <button class=\"arv-tag-remove\" (click)=\"removeReference(j)\">x</button>\r\n </span>\r\n }\r\n </div>\r\n <div class=\"arv-user-search\">\r\n <input class=\"arv-input arv-input-sm\" [value]=\"refSearchQuery()\"\r\n (input)=\"onRefSearchInput($any($event.target).value)\"\r\n placeholder=\"Search CC user...\" />\r\n @if (refSearchResults().length) {\r\n <div class=\"arv-search-results\">\r\n @for (u of refSearchResults(); track u.id) {\r\n <div class=\"arv-search-item\" (click)=\"addReference(u.id)\">\r\n {{ u.fullName || u.userName }} {{ u.department ? ' \u00B7 ' + u.department : '' }} {{ u.position ? ' (' + u.position + ')' : '' }} {{ u.employeeCode ? ' (' + u.employeeCode + ')' : '' }}\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n\r\n <!-- Actions -->\r\n <div class=\"arv-actions\">\r\n <button class=\"arv-btn arv-btn-secondary\" (click)=\"onCancel()\">Cancel</button>\r\n <button class=\"arv-btn arv-btn-primary\" [disabled]=\"submitting() || isError()\" (click)=\"submit()\">\r\n @if (submitting()) {\r\n <span class=\"arv-spinner\"></span>\r\n }\r\n {{isError() ? 'Complete Form to Submit' : submitting() ? 'Submitting...' : 'Submit for Approval' }}\r\n </button>\r\n </div>\r\n\r\n @if (errorMessage() || submitResultError()) {\r\n <div class=\"arv-error\">{{ errorMessage() || submitResultError() }}</div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Success state -->\r\n @if (isSubmitted()) {\r\n <div class=\"arv-success\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"40\" height=\"40\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#66bb6a\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M22 11.08V12a10 10 0 1 1-5.93-9.14\"/>\r\n <polyline points=\"22 4 12 14.01 9 11.01\"/>\r\n </svg>\r\n <p>Submitted for approval successfully.</p>\r\n </div>\r\n }\r\n</div>\r\n", styles: [".arv-container{display:flex;flex-direction:column;height:100%}.arv-content-body{flex:1;overflow:auto}.arv-footer{border-top:1px solid var(--arv-border);background:var(--arv-bg2)}.arv-footer-inner{padding:16px;display:flex;flex-direction:column;gap:14px}.arv-section-title{margin:0 0 8px;font-size:13px;font-weight:700;color:var(--arv-primary);text-transform:uppercase;letter-spacing:.5px}.arv-routing-header{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px}.arv-routing-mode{display:flex;gap:12px}.arv-radio{display:flex;align-items:center;gap:6px;font-size:13px;color:var(--arv-text);cursor:pointer}.arv-label{font-size:12px;color:var(--arv-text-muted);display:block;margin-bottom:4px}.arv-template-select{margin-bottom:10px}.arv-select{width:100%;padding:8px 32px 8px 10px;border:1px solid var(--arv-border);border-radius:var(--arv-radius);background:var(--arv-bg) url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E\") no-repeat right 10px center;color:var(--arv-text);font-size:13px;appearance:none;-webkit-appearance:none;cursor:pointer}.arv-input{padding:7px 10px;border:1px solid var(--arv-border);border-radius:var(--arv-radius);background:var(--arv-bg);color:var(--arv-text);font-size:13px}.arv-input-sm{width:100%;margin-top:0;padding:3px 10px}.arv-steps{display:flex;flex-direction:column;gap:10px}.arv-step{background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:var(--arv-radius);padding:10px}.arv-step-header{display:flex;align-items:center;gap:8px;margin-bottom:8px}.arv-step-num{font-size:12px;font-weight:700;color:var(--arv-primary);min-width:44px}.arv-approver-tags{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:6px}.arv-template-select .arv-approver-tags{margin-top:6px}.arv-tag{display:inline-flex;align-items:center;gap:4px;padding:3px 8px;background:#90caf91f;border:1px solid rgba(144,202,249,.3);border-radius:12px;font-size:12px;color:var(--arv-primary)}.arv-tag-remove{background:none;border:none;cursor:pointer;color:var(--arv-text-muted);font-size:11px;padding:0 2px;line-height:1}.arv-tag-remove:hover{color:var(--arv-danger)}.arv-user-search{position:relative}.arv-search-results{position:absolute;left:0;right:0;z-index:100;background:var(--arv-bg2);border:1px solid var(--arv-border);border-radius:var(--arv-radius);max-height:150px;overflow-y:auto}.arv-search-item{padding:8px 12px;cursor:pointer;font-size:13px;color:var(--arv-text)}.arv-search-item:hover{background:var(--arv-bg)}.arv-hint{font-size:12px;color:var(--arv-text-muted);margin:0 0 8px}.arv-btn-icon{background:none;border:none;cursor:pointer;padding:2px;border-radius:4px;display:inline-flex;align-items:center;justify-content:center}.arv-btn-danger{color:var(--arv-danger)}.arv-btn-danger:hover{background:#ef53501a}.arv-actions{display:flex;justify-content:flex-end;gap:10px}.arv-btn{padding:9px 18px;border-radius:var(--arv-radius);font-size:13px;font-weight:600;cursor:pointer;border:none;transition:background .15s}.arv-btn-primary{background:var(--arv-primary);color:#fff}.arv-btn-primary:hover:not(:disabled){background:var(--arv-primary-hover)}.arv-btn-primary:disabled{opacity:.6;cursor:not-allowed}.arv-btn-secondary{background:transparent;border:1px solid var(--arv-border);color:var(--arv-text-muted)}.arv-btn-secondary:hover{color:var(--arv-text);border-color:var(--arv-text-muted)}.arv-btn-outline{background:transparent;border:1px dashed var(--arv-border);color:var(--arv-text-muted);font-size:12px;padding:6px 12px}.arv-btn-outline:hover{border-color:var(--arv-primary);color:var(--arv-primary)}.arv-spinner{display:inline-block;width:14px;height:14px;border:2px solid rgba(255,255,255,.3);border-top-color:#fff;border-radius:50%;animation:arv-spin .6s linear infinite;margin-right:6px}@keyframes arv-spin{to{transform:rotate(360deg)}}.arv-error{padding:8px 12px;background:#ef53501a;border:1px solid rgba(239,83,80,.3);border-radius:var(--arv-radius);font-size:13px;color:var(--arv-danger)}.arv-success{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:32px;gap:12px;text-align:center}.arv-success p{color:var(--arv-success);font-size:15px;font-weight:600;margin:0}.arv-references{border-top:1px solid var(--arv-border);padding-top:12px}.arv-template-loading{font-size:12px;color:var(--arv-text-muted);margin-top:8px;padding:4px 0}.arv-template-steps{margin-top:8px;display:flex;flex-direction:column;gap:6px}.arv-step-card{background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:var(--arv-radius);overflow:hidden}.arv-step-card-header{display:flex;align-items:center;gap:8px;padding:7px 10px;background:#00000008;border-bottom:1px solid var(--arv-border);flex-wrap:wrap}.arv-step-preview{display:flex;align-items:center;gap:8px;padding:5px 8px;background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:4px;font-size:12px}.arv-step-preview-num{font-weight:700;color:var(--arv-primary);min-width:44px;flex-shrink:0;font-size:12px}.arv-step-preview-name{flex:1;color:var(--arv-text);font-size:12px;font-weight:600}.arv-step-error{font-size:11px;color:var(--arv-danger);font-weight:600}.arv-step-role-badge{font-size:11px;color:var(--arv-text-muted);background:#90caf91a;border:1px solid rgba(144,202,249,.25);border-radius:10px;padding:1px 7px}.arv-step-preview-cc .arv-step-preview-num{color:var(--arv-text-muted)}.arv-locked-template{display:flex;align-items:center;gap:8px;padding:7px 10px;background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:var(--arv-radius);margin-top:6px}.arv-locked-label{font-size:11px;color:var(--arv-text-muted);text-transform:uppercase;letter-spacing:.5px;flex-shrink:0}.arv-locked-name{font-size:13px;font-weight:600;color:var(--arv-text)}.arv-step-picker{padding:0}.arv-select-sm{font-size:12px;padding:6px 8px}.arv-step-fixed{padding:6px 10px;font-size:12px;color:var(--arv-text-muted)}\n"] });
|
|
1942
2076
|
}
|
|
1943
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
2077
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: MaArvContainerComponent, decorators: [{
|
|
1944
2078
|
type: Component,
|
|
1945
|
-
args: [{ selector: 'ma-arv-container', imports: [], template: "<div class=\"arv-container\">\n <!-- Content Area -->\n <div class=\"arv-content-body\" #contentBody>\n <ng-content></ng-content>\n </div>\n\n <!-- Approval Footer -->\n <div class=\"arv-footer\">\n @if (!isSubmitted()) {\n <div class=\"arv-footer-inner\">\n\n <!-- Routing mode -->\n <div class=\"arv-routing\">\n <div class=\"arv-routing-header\">\n <h4 class=\"arv-section-title\">Approval Routing</h4>\n <!-- Show routing toggle only when templateId is NOT locked to a single template -->\n @if (!templateIds() || templateIds()!.length <= 0) {\n <div class=\"arv-routing-mode\">\n <label class=\"arv-radio\">\n <input type=\"radio\" name=\"routingMode\" value=\"template\" [checked]=\"routingMode() === 'template'\" (change)=\"routingMode.set('template')\"> Use Template\n </label>\n <label class=\"arv-radio\">\n <input type=\"radio\" name=\"routingMode\" value=\"adhoc\" [checked]=\"routingMode() === 'adhoc'\" (change)=\"routingMode.set('adhoc')\"> Custom Steps\n </label>\n </div>\n }\n </div>\n\n <!-- Locked template: only when templateId set and no multi-choice -->\n @if (templateIds() && templateIds()!.length === 1 && routingMode() === 'template') {\n <div class=\"arv-template-select\">\n @if (loadingTemplate()) {\n <div class=\"arv-template-loading\">Loading template...</div>\n }\n @if (selectedTemplate() && !loadingTemplate()) {\n <div class=\"arv-locked-template\">\n <span class=\"arv-locked-label\">Template</span>\n <span class=\"arv-locked-name\">{{ selectedTemplate()!.name }}</span>\n </div>\n }\n </div>\n }\n <!-- Template selector: shown when no templateId, OR when templateIds has multiple choices -->\n @else if (routingMode() === 'template') {\n <div class=\"arv-template-select\">\n <label class=\"arv-label\">Select Template</label>\n <select class=\"arv-select\" (change)=\"onTemplateChange($event)\">\n <option value=\"\">-- Select a template --</option>\n @for (t of templates(); track t.id) {\n <option [value]=\"t.id\" [selected]=\"t.id === selectedTemplateId()\">{{ t.name }}</option>\n }\n </select>\n </div>\n }\n\n <!-- Step pickers (shared for both locked and free template) -->\n @if (routingMode() === 'template') {\n <div class=\"arv-template-select\">\n @if (!loadingTemplate() && selectedTemplate()) {\n <!-- arv-template-steps -->\n <div class=\"arv-steps\">\n @for (s of selectedTemplate()!.steps; track s.stepOrder; let i = $index) {\n <div class=\"arv-step\">\n <div class=\"arv-step-card-header\">\n <span class=\"arv-step-preview-num\">Step {{ s.stepOrder }}</span>\n <span class=\"arv-step-preview-name\">{{ s.stepName }}</span>\n @if(isStepsError()[i]) {\n <span class=\"arv-step-error\">Required (*)</span>\n }\n @if (s.roles && s.roles.length > 0) {\n <span class=\"arv-step-role-badge\">\n @for (r of s.roles; track r.id) {\n {{ r.positionLevel }}{{ r.orgName ? ' \u00B7 ' + r.orgName : '' }}{{ r !== s.roles[s.roles.length - 1] ? ', ' : '' }}\n } \n </span>\n }\n </div>\n <!-- Selectable step: show approver picker -->\n @if (stepCandidates()[i]?.length > 1 || stepLoadingCandidates()[i]) {\n @if (stepLoadingCandidates()[i]) {\n <div class=\"arv-template-loading\">Loading candidates...</div>\n }\n @if (!stepLoadingCandidates()[i]) {\n <div class=\"arv-approvers\">\n <div class=\"arv-approver-tags\">\n @if (stepSelectedUsers()[i]) {\n <span class=\"arv-tag\">\n {{ userLabelMap()[stepSelectedUsers()[i]] || stepSelectedUsers()[i] }}\n <button class=\"arv-tag-remove\" (click)=\"onStepUserChangeInput(i, '')\">x</button>\n </span>\n }\n </div>\n @if (!stepSelectedUsers()[i]) {\n <div class=\"arv-user-search arv-step-picker\">\n <input class=\"arv-input arv-input-sm\" [value]=\"candidateSearchQuery()[i] || ''\"\n (input)=\"onCandidateSearchInput(i, $any($event.target).value)\"\n (focus)=\"onCandidateSearchInput(i, candidateSearchQuery()[i] || '')\"\n (blur)=\"clearCandidateResults(i)\"\n placeholder=\"Search approver...\" />\n @if (candidateSearchResults()[i]?.length) {\n <div class=\"arv-search-results\">\n @for (u of candidateSearchResults()[i]; track u.userId) {\n <div class=\"arv-search-item\" (mousedown)=\"onStepUserChangeInput(i, u.userId)\">\n {{ u.fullName || u.userName }} {{ u.department ? ' \u00B7 ' + u.department : '' }} {{ u.position ? ' (' + u.position + ')' : '' }} {{ u.employeeCode ? ' (' + u.employeeCode + ')' : '' }}\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n }\n\n }\n <!-- Single fixed-user step: show who is assigned -->\n @if (!stepLoadingCandidates()[i] && stepCandidates()[i]?.length === 1) {\n <div class=\"arv-step-fixed\">\n {{ stepCandidates()[i][0].fullName || stepCandidates()[i][0].userId }}{{ stepCandidates()[i][0].department ? ' \u00B7 ' + stepCandidates()[i][0].department : '' }}{{ stepCandidates()[i][0].position ? ' (' + stepCandidates()[i][0].position + ')' : '' }}{{ stepCandidates()[i][0].employeeCode ? ' (' + stepCandidates()[i][0].employeeCode + ')' : '' }}\n </div>\n }\n </div>\n }\n @if (selectedTemplate() && selectedTemplate()!.referenceUserIds.length > 0) {\n <div class=\"arv-step-preview arv-step-preview-cc\">\n <span class=\"arv-step-preview-num\">CC</span>\n <span class=\"arv-step-preview-name\">{{ selectedTemplate()!.referenceUserIds.length }} reference user(s) from template</span>\n </div>\n }\n </div>\n }\n </div>\n }\n\n <!-- Ad-hoc steps -->\n @if (routingMode() === 'adhoc') {\n <div class=\"arv-steps\">\n @for (step of adHocSteps(); track step.stepOrder; let i = $index) {\n <div class=\"arv-step\">\n <div class=\"arv-step-header\">\n <span class=\"arv-step-num\">Step {{ i + 1 }}</span>\n @if (isStepsError()[i]) {\n <span class=\"arv-step-error\">Required (*)</span>\n }\n <input class=\"arv-input\" [value]=\"step.stepName\" (input)=\"updateStepName(i, $any($event.target).value)\" placeholder=\"Step name\" />\n <button class=\"arv-btn-icon arv-btn-danger\" (click)=\"removeStep(i)\" title=\"Remove step\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/></svg>\n </button>\n </div>\n <div class=\"arv-approvers\">\n <div class=\"arv-approver-tags\">\n @for (uid of step.approverUserIds; track uid; let j = $index) {\n <span class=\"arv-tag\">\n {{ userLabelMap()[uid] || uid }}\n <button class=\"arv-tag-remove\" (click)=\"removeApprover(i, j)\">x</button>\n </span>\n }\n </div>\n @if (step.approverUserIds.length === 0) {\n <div class=\"arv-user-search\">\n <input class=\"arv-input arv-input-sm\" [value]=\"userSearchQuery()[i] || ''\"\n (input)=\"onUserSearchInput(i, $any($event.target).value)\"\n placeholder=\"Search approver...\" />\n @if (userSearchResults()[i]?.length) {\n <div class=\"arv-search-results\">\n @for (u of userSearchResults()[i]; track u.id) {\n <div class=\"arv-search-item\" (click)=\"addApprover(i, u.id)\">\n {{ u.fullName || u.userName }} {{ u.department ? ' \u00B7 ' + u.department : '' }} {{ u.position ? ' (' + u.position + ')' : '' }} {{ u.employeeCode ? ' (' + u.employeeCode + ')' : '' }}\n </div>\n }\n </div>\n }\n </div>\n }\n </div>\n </div>\n }\n <button class=\"arv-btn arv-btn-outline\" (click)=\"addStep()\">+ Add Step</button>\n </div>\n }\n </div>\n\n <!-- Reference / CC users -->\n <div class=\"arv-references\">\n <h4 class=\"arv-section-title\">CC / Reference</h4>\n <p class=\"arv-hint\">These users will be notified when the approval completes, but won't be asked to approve.</p>\n <div class=\"arv-approver-tags\">\n @for (uid of referenceUserIds(); track uid; let j = $index) {\n <span class=\"arv-tag\">\n {{ userLabelMap()[uid] || uid }}\n <button class=\"arv-tag-remove\" (click)=\"removeReference(j)\">x</button>\n </span>\n }\n </div>\n <div class=\"arv-user-search\">\n <input class=\"arv-input arv-input-sm\" [value]=\"refSearchQuery()\"\n (input)=\"onRefSearchInput($any($event.target).value)\"\n placeholder=\"Search CC user...\" />\n @if (refSearchResults().length) {\n <div class=\"arv-search-results\">\n @for (u of refSearchResults(); track u.id) {\n <div class=\"arv-search-item\" (click)=\"addReference(u.id)\">\n {{ u.fullName || u.userName }} {{ u.department ? ' \u00B7 ' + u.department : '' }} {{ u.position ? ' (' + u.position + ')' : '' }} {{ u.employeeCode ? ' (' + u.employeeCode + ')' : '' }}\n </div>\n }\n </div>\n }\n </div>\n </div>\n\n <!-- Actions -->\n <div class=\"arv-actions\">\n <button class=\"arv-btn arv-btn-secondary\" (click)=\"onCancel()\">Cancel</button>\n <button class=\"arv-btn arv-btn-primary\" [disabled]=\"submitting() || isError()\" (click)=\"submit()\">\n @if (submitting()) {\n <span class=\"arv-spinner\"></span>\n }\n {{isError() ? 'Complete Form to Submit' : submitting() ? 'Submitting...' : 'Submit for Approval' }}\n </button>\n </div>\n\n @if (errorMessage() || submitResultError()) {\n <div class=\"arv-error\">{{ errorMessage() || submitResultError() }}</div>\n }\n </div>\n }\n </div>\n\n <!-- Success state -->\n @if (isSubmitted()) {\n <div class=\"arv-success\">\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"40\" height=\"40\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#66bb6a\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M22 11.08V12a10 10 0 1 1-5.93-9.14\"/>\n <polyline points=\"22 4 12 14.01 9 11.01\"/>\n </svg>\n <p>Submitted for approval successfully.</p>\n </div>\n }\n</div>\n", styles: [".arv-container{display:flex;flex-direction:column;height:100%}.arv-content-body{flex:1;overflow:auto}.arv-footer{border-top:1px solid var(--arv-border);background:var(--arv-bg2)}.arv-footer-inner{padding:16px;display:flex;flex-direction:column;gap:14px}.arv-section-title{margin:0 0 8px;font-size:13px;font-weight:700;color:var(--arv-primary);text-transform:uppercase;letter-spacing:.5px}.arv-routing-header{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px}.arv-routing-mode{display:flex;gap:12px}.arv-radio{display:flex;align-items:center;gap:6px;font-size:13px;color:var(--arv-text);cursor:pointer}.arv-label{font-size:12px;color:var(--arv-text-muted);display:block;margin-bottom:4px}.arv-template-select{margin-bottom:10px}.arv-select{width:100%;padding:8px 32px 8px 10px;border:1px solid var(--arv-border);border-radius:var(--arv-radius);background:var(--arv-bg) url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E\") no-repeat right 10px center;color:var(--arv-text);font-size:13px;appearance:none;-webkit-appearance:none;cursor:pointer}.arv-input{padding:7px 10px;border:1px solid var(--arv-border);border-radius:var(--arv-radius);background:var(--arv-bg);color:var(--arv-text);font-size:13px}.arv-input-sm{width:100%;margin-top:0;padding:3px 10px}.arv-steps{display:flex;flex-direction:column;gap:10px}.arv-step{background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:var(--arv-radius);padding:10px}.arv-step-header{display:flex;align-items:center;gap:8px;margin-bottom:8px}.arv-step-num{font-size:12px;font-weight:700;color:var(--arv-primary);min-width:44px}.arv-approver-tags{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:6px}.arv-template-select .arv-approver-tags{margin-top:6px}.arv-tag{display:inline-flex;align-items:center;gap:4px;padding:3px 8px;background:#90caf91f;border:1px solid rgba(144,202,249,.3);border-radius:12px;font-size:12px;color:var(--arv-primary)}.arv-tag-remove{background:none;border:none;cursor:pointer;color:var(--arv-text-muted);font-size:11px;padding:0 2px;line-height:1}.arv-tag-remove:hover{color:var(--arv-danger)}.arv-user-search{position:relative}.arv-search-results{position:absolute;left:0;right:0;z-index:100;background:var(--arv-bg2);border:1px solid var(--arv-border);border-radius:var(--arv-radius);max-height:150px;overflow-y:auto}.arv-search-item{padding:8px 12px;cursor:pointer;font-size:13px;color:var(--arv-text)}.arv-search-item:hover{background:var(--arv-bg)}.arv-hint{font-size:12px;color:var(--arv-text-muted);margin:0 0 8px}.arv-btn-icon{background:none;border:none;cursor:pointer;padding:2px;border-radius:4px;display:inline-flex;align-items:center;justify-content:center}.arv-btn-danger{color:var(--arv-danger)}.arv-btn-danger:hover{background:#ef53501a}.arv-actions{display:flex;justify-content:flex-end;gap:10px}.arv-btn{padding:9px 18px;border-radius:var(--arv-radius);font-size:13px;font-weight:600;cursor:pointer;border:none;transition:background .15s}.arv-btn-primary{background:var(--arv-primary);color:#fff}.arv-btn-primary:hover:not(:disabled){background:var(--arv-primary-hover)}.arv-btn-primary:disabled{opacity:.6;cursor:not-allowed}.arv-btn-secondary{background:transparent;border:1px solid var(--arv-border);color:var(--arv-text-muted)}.arv-btn-secondary:hover{color:var(--arv-text);border-color:var(--arv-text-muted)}.arv-btn-outline{background:transparent;border:1px dashed var(--arv-border);color:var(--arv-text-muted);font-size:12px;padding:6px 12px}.arv-btn-outline:hover{border-color:var(--arv-primary);color:var(--arv-primary)}.arv-spinner{display:inline-block;width:14px;height:14px;border:2px solid rgba(255,255,255,.3);border-top-color:#fff;border-radius:50%;animation:arv-spin .6s linear infinite;margin-right:6px}@keyframes arv-spin{to{transform:rotate(360deg)}}.arv-error{padding:8px 12px;background:#ef53501a;border:1px solid rgba(239,83,80,.3);border-radius:var(--arv-radius);font-size:13px;color:var(--arv-danger)}.arv-success{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:32px;gap:12px;text-align:center}.arv-success p{color:var(--arv-success);font-size:15px;font-weight:600;margin:0}.arv-references{border-top:1px solid var(--arv-border);padding-top:12px}.arv-template-loading{font-size:12px;color:var(--arv-text-muted);margin-top:8px;padding:4px 0}.arv-template-steps{margin-top:8px;display:flex;flex-direction:column;gap:6px}.arv-step-card{background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:var(--arv-radius);overflow:hidden}.arv-step-card-header{display:flex;align-items:center;gap:8px;padding:7px 10px;background:#00000008;border-bottom:1px solid var(--arv-border);flex-wrap:wrap}.arv-step-preview{display:flex;align-items:center;gap:8px;padding:5px 8px;background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:4px;font-size:12px}.arv-step-preview-num{font-weight:700;color:var(--arv-primary);min-width:44px;flex-shrink:0;font-size:12px}.arv-step-preview-name{flex:1;color:var(--arv-text);font-size:12px;font-weight:600}.arv-step-error{font-size:11px;color:var(--arv-danger);font-weight:600}.arv-step-role-badge{font-size:11px;color:var(--arv-text-muted);background:#90caf91a;border:1px solid rgba(144,202,249,.25);border-radius:10px;padding:1px 7px}.arv-step-preview-cc .arv-step-preview-num{color:var(--arv-text-muted)}.arv-locked-template{display:flex;align-items:center;gap:8px;padding:7px 10px;background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:var(--arv-radius);margin-top:6px}.arv-locked-label{font-size:11px;color:var(--arv-text-muted);text-transform:uppercase;letter-spacing:.5px;flex-shrink:0}.arv-locked-name{font-size:13px;font-weight:600;color:var(--arv-text)}.arv-step-picker{padding:0}.arv-select-sm{font-size:12px;padding:6px 8px}.arv-step-fixed{padding:6px 10px;font-size:12px;color:var(--arv-text-muted)}\n"] }]
|
|
2079
|
+
args: [{ selector: 'ma-arv-container', imports: [], template: "<div class=\"arv-container\">\r\n <!-- Content Area -->\r\n <div class=\"arv-content-body\" #contentBody>\r\n <ng-content></ng-content>\r\n </div>\r\n\r\n <!-- Approval Footer -->\r\n <div class=\"arv-footer\">\r\n @if (!isSubmitted()) {\r\n <div class=\"arv-footer-inner\">\r\n\r\n <!-- Routing mode -->\r\n <div class=\"arv-routing\">\r\n <div class=\"arv-routing-header\">\r\n <h4 class=\"arv-section-title\">Approval Routing</h4>\r\n <!-- Show routing toggle only when templateId is NOT locked to a single template -->\r\n @if (!templateIds() || templateIds()!.length <= 0) {\r\n <div class=\"arv-routing-mode\">\r\n <label class=\"arv-radio\">\r\n <input type=\"radio\" name=\"routingMode\" value=\"template\" [checked]=\"routingMode() === 'template'\" (change)=\"routingMode.set('template')\"> Use Template\r\n </label>\r\n <label class=\"arv-radio\">\r\n <input type=\"radio\" name=\"routingMode\" value=\"adhoc\" [checked]=\"routingMode() === 'adhoc'\" (change)=\"routingMode.set('adhoc')\"> Custom Steps\r\n </label>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Locked template: only when templateId set and no multi-choice -->\r\n @if (templateIds() && templateIds()!.length === 1 && routingMode() === 'template') {\r\n <div class=\"arv-template-select\">\r\n @if (loadingTemplate()) {\r\n <div class=\"arv-template-loading\">Loading template...</div>\r\n }\r\n @if (selectedTemplate() && !loadingTemplate()) {\r\n <div class=\"arv-locked-template\">\r\n <span class=\"arv-locked-label\">Template</span>\r\n <span class=\"arv-locked-name\">{{ selectedTemplate()!.name }}</span>\r\n </div>\r\n }\r\n </div>\r\n }\r\n <!-- Template selector: shown when no templateId, OR when templateIds has multiple choices -->\r\n @else if (routingMode() === 'template') {\r\n <div class=\"arv-template-select\">\r\n <label class=\"arv-label\">Select Template</label>\r\n <select class=\"arv-select\" (change)=\"onTemplateChange($event)\">\r\n <option value=\"\">-- Select a template --</option>\r\n @for (t of templates(); track t.id) {\r\n <option [value]=\"t.id\" [selected]=\"t.id === selectedTemplateId()\">{{ t.name }}</option>\r\n }\r\n </select>\r\n </div>\r\n }\r\n\r\n <!-- Step pickers (shared for both locked and free template) -->\r\n @if (routingMode() === 'template') {\r\n <div class=\"arv-template-select\">\r\n @if (!loadingTemplate() && selectedTemplate()) {\r\n <!-- arv-template-steps -->\r\n <div class=\"arv-steps\">\r\n @for (s of selectedTemplate()!.steps; track s.stepOrder; let i = $index) {\r\n <div class=\"arv-step\">\r\n <div class=\"arv-step-card-header\">\r\n <span class=\"arv-step-preview-num\">Step {{ s.stepOrder }}</span>\r\n <span class=\"arv-step-preview-name\">{{ s.stepName }}</span>\r\n @if(isStepsError()[i]) {\r\n <span class=\"arv-step-error\">Required (*)</span>\r\n }\r\n @if (s.roles && s.roles.length > 0) {\r\n <span class=\"arv-step-role-badge\">\r\n @for (r of s.roles; track r.id) {\r\n {{ r.positionLevel }}{{ r.orgName ? ' \u00B7 ' + r.orgName : '' }}{{ r !== s.roles[s.roles.length - 1] ? ', ' : '' }}\r\n } \r\n </span>\r\n }\r\n </div>\r\n <!-- Selectable step: show approver picker -->\r\n @if (stepCandidates()[i]?.length > 1 || stepLoadingCandidates()[i]) {\r\n @if (stepLoadingCandidates()[i]) {\r\n <div class=\"arv-template-loading\">Loading candidates...</div>\r\n }\r\n @if (!stepLoadingCandidates()[i]) {\r\n <div class=\"arv-approvers\">\r\n <div class=\"arv-approver-tags\">\r\n @if (stepSelectedUsers()[i]) {\r\n <span class=\"arv-tag\">\r\n {{ userLabelMap()[stepSelectedUsers()[i]] || stepSelectedUsers()[i] }}\r\n <button class=\"arv-tag-remove\" (click)=\"onStepUserChangeInput(i, '')\">x</button>\r\n </span>\r\n }\r\n </div>\r\n @if (!stepSelectedUsers()[i]) {\r\n <div class=\"arv-user-search arv-step-picker\">\r\n <input class=\"arv-input arv-input-sm\" [value]=\"candidateSearchQuery()[i] || ''\"\r\n (input)=\"onCandidateSearchInput(i, $any($event.target).value)\"\r\n (focus)=\"onCandidateSearchInput(i, candidateSearchQuery()[i] || '')\"\r\n (blur)=\"clearCandidateResults(i)\"\r\n placeholder=\"Search approver...\" />\r\n @if (candidateSearchResults()[i]?.length) {\r\n <div class=\"arv-search-results\">\r\n @for (u of candidateSearchResults()[i]; track u.userId) {\r\n <div class=\"arv-search-item\" (mousedown)=\"onStepUserChangeInput(i, u.userId)\">\r\n {{ u.fullName || u.userName }} {{ u.department ? ' \u00B7 ' + u.department : '' }} {{ u.position ? ' (' + u.position + ')' : '' }} {{ u.employeeCode ? ' (' + u.employeeCode + ')' : '' }}\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n }\r\n <!-- Single fixed-user step: show who is assigned -->\r\n @if (!stepLoadingCandidates()[i] && stepCandidates()[i]?.length === 1) {\r\n <div class=\"arv-step-fixed\">\r\n {{ stepCandidates()[i][0].fullName || stepCandidates()[i][0].userId }}{{ stepCandidates()[i][0].department ? ' \u00B7 ' + stepCandidates()[i][0].department : '' }}{{ stepCandidates()[i][0].position ? ' (' + stepCandidates()[i][0].position + ')' : '' }}{{ stepCandidates()[i][0].employeeCode ? ' (' + stepCandidates()[i][0].employeeCode + ')' : '' }}\r\n </div>\r\n }\r\n </div>\r\n }\r\n @if (selectedTemplate() && selectedTemplate()!.referenceUserIds.length > 0) {\r\n <div class=\"arv-step-preview arv-step-preview-cc\">\r\n <span class=\"arv-step-preview-num\">CC</span>\r\n <span class=\"arv-step-preview-name\">{{ selectedTemplate()!.referenceUserIds.length }} reference user(s) from template</span>\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n\r\n <!-- Ad-hoc steps -->\r\n @if (routingMode() === 'adhoc') {\r\n <div class=\"arv-steps\">\r\n @for (step of adHocSteps(); track step.stepOrder; let i = $index) {\r\n <div class=\"arv-step\">\r\n <div class=\"arv-step-header\">\r\n <span class=\"arv-step-num\">Step {{ i + 1 }}</span>\r\n @if (isStepsError()[i]) {\r\n <span class=\"arv-step-error\">Required (*)</span>\r\n }\r\n <input class=\"arv-input\" [value]=\"step.stepName\" (input)=\"updateStepName(i, $any($event.target).value)\" placeholder=\"Step name\" />\r\n <button class=\"arv-btn-icon arv-btn-danger\" (click)=\"removeStep(i)\" title=\"Remove step\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\"/><line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\"/></svg>\r\n </button>\r\n </div>\r\n <div class=\"arv-approvers\">\r\n <div class=\"arv-approver-tags\">\r\n @for (uid of step.approverUserIds; track uid; let j = $index) {\r\n <span class=\"arv-tag\">\r\n {{ userLabelMap()[uid] || uid }}\r\n <button class=\"arv-tag-remove\" (click)=\"removeApprover(i, j)\">x</button>\r\n </span>\r\n }\r\n </div>\r\n @if (step.approverUserIds.length === 0) {\r\n <div class=\"arv-user-search\">\r\n <input class=\"arv-input arv-input-sm\" [value]=\"userSearchQuery()[i] || ''\"\r\n (input)=\"onUserSearchInput(i, $any($event.target).value)\"\r\n placeholder=\"Search approver...\" />\r\n @if (userSearchResults()[i]?.length) {\r\n <div class=\"arv-search-results\">\r\n @for (u of userSearchResults()[i]; track u.id) {\r\n <div class=\"arv-search-item\" (click)=\"addApprover(i, u.id)\">\r\n {{ u.fullName || u.userName }} {{ u.department ? ' \u00B7 ' + u.department : '' }} {{ u.position ? ' (' + u.position + ')' : '' }} {{ u.employeeCode ? ' (' + u.employeeCode + ')' : '' }}\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n }\r\n <button class=\"arv-btn arv-btn-outline\" (click)=\"addStep()\">+ Add Step</button>\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Reference / CC users -->\r\n <div class=\"arv-references\">\r\n <h4 class=\"arv-section-title\">CC / Reference</h4>\r\n <p class=\"arv-hint\">These users will be notified when the approval completes, but won't be asked to approve.</p>\r\n <div class=\"arv-approver-tags\">\r\n @for (uid of referenceUserIds(); track uid; let j = $index) {\r\n <span class=\"arv-tag\">\r\n {{ userLabelMap()[uid] || uid }}\r\n <button class=\"arv-tag-remove\" (click)=\"removeReference(j)\">x</button>\r\n </span>\r\n }\r\n </div>\r\n <div class=\"arv-user-search\">\r\n <input class=\"arv-input arv-input-sm\" [value]=\"refSearchQuery()\"\r\n (input)=\"onRefSearchInput($any($event.target).value)\"\r\n placeholder=\"Search CC user...\" />\r\n @if (refSearchResults().length) {\r\n <div class=\"arv-search-results\">\r\n @for (u of refSearchResults(); track u.id) {\r\n <div class=\"arv-search-item\" (click)=\"addReference(u.id)\">\r\n {{ u.fullName || u.userName }} {{ u.department ? ' \u00B7 ' + u.department : '' }} {{ u.position ? ' (' + u.position + ')' : '' }} {{ u.employeeCode ? ' (' + u.employeeCode + ')' : '' }}\r\n </div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n\r\n <!-- Actions -->\r\n <div class=\"arv-actions\">\r\n <button class=\"arv-btn arv-btn-secondary\" (click)=\"onCancel()\">Cancel</button>\r\n <button class=\"arv-btn arv-btn-primary\" [disabled]=\"submitting() || isError()\" (click)=\"submit()\">\r\n @if (submitting()) {\r\n <span class=\"arv-spinner\"></span>\r\n }\r\n {{isError() ? 'Complete Form to Submit' : submitting() ? 'Submitting...' : 'Submit for Approval' }}\r\n </button>\r\n </div>\r\n\r\n @if (errorMessage() || submitResultError()) {\r\n <div class=\"arv-error\">{{ errorMessage() || submitResultError() }}</div>\r\n }\r\n </div>\r\n }\r\n </div>\r\n\r\n <!-- Success state -->\r\n @if (isSubmitted()) {\r\n <div class=\"arv-success\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"40\" height=\"40\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#66bb6a\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\r\n <path d=\"M22 11.08V12a10 10 0 1 1-5.93-9.14\"/>\r\n <polyline points=\"22 4 12 14.01 9 11.01\"/>\r\n </svg>\r\n <p>Submitted for approval successfully.</p>\r\n </div>\r\n }\r\n</div>\r\n", styles: [".arv-container{display:flex;flex-direction:column;height:100%}.arv-content-body{flex:1;overflow:auto}.arv-footer{border-top:1px solid var(--arv-border);background:var(--arv-bg2)}.arv-footer-inner{padding:16px;display:flex;flex-direction:column;gap:14px}.arv-section-title{margin:0 0 8px;font-size:13px;font-weight:700;color:var(--arv-primary);text-transform:uppercase;letter-spacing:.5px}.arv-routing-header{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px}.arv-routing-mode{display:flex;gap:12px}.arv-radio{display:flex;align-items:center;gap:6px;font-size:13px;color:var(--arv-text);cursor:pointer}.arv-label{font-size:12px;color:var(--arv-text-muted);display:block;margin-bottom:4px}.arv-template-select{margin-bottom:10px}.arv-select{width:100%;padding:8px 32px 8px 10px;border:1px solid var(--arv-border);border-radius:var(--arv-radius);background:var(--arv-bg) url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23888' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E\") no-repeat right 10px center;color:var(--arv-text);font-size:13px;appearance:none;-webkit-appearance:none;cursor:pointer}.arv-input{padding:7px 10px;border:1px solid var(--arv-border);border-radius:var(--arv-radius);background:var(--arv-bg);color:var(--arv-text);font-size:13px}.arv-input-sm{width:100%;margin-top:0;padding:3px 10px}.arv-steps{display:flex;flex-direction:column;gap:10px}.arv-step{background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:var(--arv-radius);padding:10px}.arv-step-header{display:flex;align-items:center;gap:8px;margin-bottom:8px}.arv-step-num{font-size:12px;font-weight:700;color:var(--arv-primary);min-width:44px}.arv-approver-tags{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:6px}.arv-template-select .arv-approver-tags{margin-top:6px}.arv-tag{display:inline-flex;align-items:center;gap:4px;padding:3px 8px;background:#90caf91f;border:1px solid rgba(144,202,249,.3);border-radius:12px;font-size:12px;color:var(--arv-primary)}.arv-tag-remove{background:none;border:none;cursor:pointer;color:var(--arv-text-muted);font-size:11px;padding:0 2px;line-height:1}.arv-tag-remove:hover{color:var(--arv-danger)}.arv-user-search{position:relative}.arv-search-results{position:absolute;left:0;right:0;z-index:100;background:var(--arv-bg2);border:1px solid var(--arv-border);border-radius:var(--arv-radius);max-height:150px;overflow-y:auto}.arv-search-item{padding:8px 12px;cursor:pointer;font-size:13px;color:var(--arv-text)}.arv-search-item:hover{background:var(--arv-bg)}.arv-hint{font-size:12px;color:var(--arv-text-muted);margin:0 0 8px}.arv-btn-icon{background:none;border:none;cursor:pointer;padding:2px;border-radius:4px;display:inline-flex;align-items:center;justify-content:center}.arv-btn-danger{color:var(--arv-danger)}.arv-btn-danger:hover{background:#ef53501a}.arv-actions{display:flex;justify-content:flex-end;gap:10px}.arv-btn{padding:9px 18px;border-radius:var(--arv-radius);font-size:13px;font-weight:600;cursor:pointer;border:none;transition:background .15s}.arv-btn-primary{background:var(--arv-primary);color:#fff}.arv-btn-primary:hover:not(:disabled){background:var(--arv-primary-hover)}.arv-btn-primary:disabled{opacity:.6;cursor:not-allowed}.arv-btn-secondary{background:transparent;border:1px solid var(--arv-border);color:var(--arv-text-muted)}.arv-btn-secondary:hover{color:var(--arv-text);border-color:var(--arv-text-muted)}.arv-btn-outline{background:transparent;border:1px dashed var(--arv-border);color:var(--arv-text-muted);font-size:12px;padding:6px 12px}.arv-btn-outline:hover{border-color:var(--arv-primary);color:var(--arv-primary)}.arv-spinner{display:inline-block;width:14px;height:14px;border:2px solid rgba(255,255,255,.3);border-top-color:#fff;border-radius:50%;animation:arv-spin .6s linear infinite;margin-right:6px}@keyframes arv-spin{to{transform:rotate(360deg)}}.arv-error{padding:8px 12px;background:#ef53501a;border:1px solid rgba(239,83,80,.3);border-radius:var(--arv-radius);font-size:13px;color:var(--arv-danger)}.arv-success{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:32px;gap:12px;text-align:center}.arv-success p{color:var(--arv-success);font-size:15px;font-weight:600;margin:0}.arv-references{border-top:1px solid var(--arv-border);padding-top:12px}.arv-template-loading{font-size:12px;color:var(--arv-text-muted);margin-top:8px;padding:4px 0}.arv-template-steps{margin-top:8px;display:flex;flex-direction:column;gap:6px}.arv-step-card{background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:var(--arv-radius);overflow:hidden}.arv-step-card-header{display:flex;align-items:center;gap:8px;padding:7px 10px;background:#00000008;border-bottom:1px solid var(--arv-border);flex-wrap:wrap}.arv-step-preview{display:flex;align-items:center;gap:8px;padding:5px 8px;background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:4px;font-size:12px}.arv-step-preview-num{font-weight:700;color:var(--arv-primary);min-width:44px;flex-shrink:0;font-size:12px}.arv-step-preview-name{flex:1;color:var(--arv-text);font-size:12px;font-weight:600}.arv-step-error{font-size:11px;color:var(--arv-danger);font-weight:600}.arv-step-role-badge{font-size:11px;color:var(--arv-text-muted);background:#90caf91a;border:1px solid rgba(144,202,249,.25);border-radius:10px;padding:1px 7px}.arv-step-preview-cc .arv-step-preview-num{color:var(--arv-text-muted)}.arv-locked-template{display:flex;align-items:center;gap:8px;padding:7px 10px;background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:var(--arv-radius);margin-top:6px}.arv-locked-label{font-size:11px;color:var(--arv-text-muted);text-transform:uppercase;letter-spacing:.5px;flex-shrink:0}.arv-locked-name{font-size:13px;font-weight:600;color:var(--arv-text)}.arv-step-picker{padding:0}.arv-select-sm{font-size:12px;padding:6px 8px}.arv-step-fixed{padding:6px 10px;font-size:12px;color:var(--arv-text-muted)}\n"] }]
|
|
1946
2080
|
}], ctorParameters: () => [], propDecorators: { title: [{ type: i0.Input, args: [{ isSignal: true, alias: "title", required: false }] }], description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], referenceId: [{ type: i0.Input, args: [{ isSignal: true, alias: "referenceId", required: false }] }], templateIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "templateIds", required: false }] }], callbackUrl: [{ type: i0.Input, args: [{ isSignal: true, alias: "callbackUrl", required: false }] }], deadlineHours: [{ type: i0.Input, args: [{ isSignal: true, alias: "deadlineHours", required: false }] }], approvalSubmitted: [{ type: i0.Output, args: ["approvalSubmitted"] }], approvalSubmitting: [{ type: i0.Output, args: ["approvalSubmitting"] }], cancelled: [{ type: i0.Output, args: ["cancelled"] }], contentBody: [{
|
|
1947
2081
|
type: ViewChild,
|
|
1948
2082
|
args: ['contentBody', { static: true }]
|
|
@@ -2014,10 +2148,10 @@ class MaIconComponent {
|
|
|
2014
2148
|
return `<svg ${base}><circle cx="12" cy="12" r="10"/></svg>`;
|
|
2015
2149
|
}
|
|
2016
2150
|
}
|
|
2017
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
2018
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.
|
|
2151
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: MaIconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2152
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.7", type: MaIconComponent, isStandalone: true, selector: "ma-icon", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, stroke: { classPropertyName: "stroke", publicName: "stroke", isSignal: true, isRequired: false, transformFunction: null }, strokeWidth: { classPropertyName: "strokeWidth", publicName: "strokeWidth", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `<span class="ma-icon" [style.width.px]="size()" [style.height.px]="size()" [innerHTML]="svgContent()"></span>`, isInline: true, styles: [":host{display:inline-flex;align-items:center;justify-content:center}.ma-icon{display:flex;align-items:center;justify-content:center}.ma-icon svg{display:block}\n"] });
|
|
2019
2153
|
}
|
|
2020
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
2154
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: MaIconComponent, decorators: [{
|
|
2021
2155
|
type: Component,
|
|
2022
2156
|
args: [{ selector: 'ma-icon', template: `<span class="ma-icon" [style.width.px]="size()" [style.height.px]="size()" [innerHTML]="svgContent()"></span>`, styles: [":host{display:inline-flex;align-items:center;justify-content:center}.ma-icon{display:flex;align-items:center;justify-content:center}.ma-icon svg{display:block}\n"] }]
|
|
2023
2157
|
}], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], stroke: [{ type: i0.Input, args: [{ isSignal: true, alias: "stroke", required: false }] }], strokeWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "strokeWidth", required: false }] }] } });
|
|
@@ -2040,10 +2174,10 @@ class MaThemeDirective {
|
|
|
2040
2174
|
get themeClass() {
|
|
2041
2175
|
return `theme-${this.themeService.currentTheme()}`;
|
|
2042
2176
|
}
|
|
2043
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
2044
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.
|
|
2177
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: MaThemeDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
2178
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.7", type: MaThemeDirective, isStandalone: true, selector: "[maTheme]", host: { properties: { "class": "this.themeClass" } }, ngImport: i0 });
|
|
2045
2179
|
}
|
|
2046
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
2180
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: MaThemeDirective, decorators: [{
|
|
2047
2181
|
type: Directive,
|
|
2048
2182
|
args: [{
|
|
2049
2183
|
selector: '[maTheme]'
|
|
@@ -2073,12 +2207,12 @@ class MaUserMenuComponent {
|
|
|
2073
2207
|
return;
|
|
2074
2208
|
this.itemClick.emit();
|
|
2075
2209
|
}
|
|
2076
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.
|
|
2077
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.
|
|
2210
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: MaUserMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2211
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.7", type: MaUserMenuComponent, isStandalone: true, selector: "ma-user-menu", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { itemClick: "itemClick" }, ngImport: i0, template: "<button\r\n type=\"button\"\r\n class=\"ma-user-menu-btn\"\r\n [class]=\"'ma-user-menu--' + color()\"\r\n [disabled]=\"disabled()\"\r\n (click)=\"onClick()\">\r\n <span class=\"ma-user-menu-icon\">\r\n <ng-content select=\"[maUserMenuIcon]\"></ng-content>\r\n </span>\r\n <span class=\"ma-user-menu-name\">{{ name() }}</span>\r\n</button>\r\n", styles: [":host{display:block}.ma-user-menu-btn{display:flex;align-items:center;gap:10px;width:100%;padding:11px 16px;border:none;background:none;text-align:left;cursor:pointer;font-size:13.5px;font-weight:500;color:var(--text-primary);transition:background-color .15s,color .15s}.ma-user-menu-btn:disabled{opacity:.5;cursor:not-allowed}.ma-user-menu-icon{flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;opacity:.8}.ma-user-menu-icon:empty{display:none}.ma-user-menu-name{flex:1 1 auto;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ma-user-menu--default{color:var(--text-primary)}.ma-user-menu--default:hover:not(:disabled){background-color:var(--bg-secondary)}.ma-user-menu--primary{color:var(--primary-color, #1976d2)}.ma-user-menu--primary:hover:not(:disabled){background-color:var(--primary-light, rgba(25, 118, 210, .08))}.ma-user-menu--success{color:var(--success-color, #2e7d32)}.ma-user-menu--success:hover:not(:disabled){background-color:var(--success-light, rgba(46, 125, 50, .08))}.ma-user-menu--warning{color:var(--warning-color, #ed6c02)}.ma-user-menu--warning:hover:not(:disabled){background-color:var(--warning-light, rgba(237, 108, 2, .08))}.ma-user-menu--danger{color:var(--error-color, #d32f2f)}.ma-user-menu--danger:hover:not(:disabled){background-color:var(--error-light, rgba(211, 47, 47, .08))}.ma-user-menu--info{color:var(--info-color, #0288d1)}.ma-user-menu--info:hover:not(:disabled){background-color:var(--info-light, rgba(2, 136, 209, .08))}\n"] });
|
|
2078
2212
|
}
|
|
2079
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.
|
|
2213
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: MaUserMenuComponent, decorators: [{
|
|
2080
2214
|
type: Component,
|
|
2081
|
-
args: [{ selector: 'ma-user-menu', template: "<button\n type=\"button\"\n class=\"ma-user-menu-btn\"\n [class]=\"'ma-user-menu--' + color()\"\n [disabled]=\"disabled()\"\n (click)=\"onClick()\">\n <span class=\"ma-user-menu-icon\">\n <ng-content select=\"[maUserMenuIcon]\"></ng-content>\n </span>\n <span class=\"ma-user-menu-name\">{{ name() }}</span>\n</button>\n", styles: [":host{display:block}.ma-user-menu-btn{display:flex;align-items:center;gap:10px;width:100%;padding:11px 16px;border:none;background:none;text-align:left;cursor:pointer;font-size:13.5px;font-weight:500;color:var(--text-primary);transition:background-color .15s,color .15s}.ma-user-menu-btn:disabled{opacity:.5;cursor:not-allowed}.ma-user-menu-icon{flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;opacity:.8}.ma-user-menu-icon:empty{display:none}.ma-user-menu-name{flex:1 1 auto;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ma-user-menu--default{color:var(--text-primary)}.ma-user-menu--default:hover:not(:disabled){background-color:var(--bg-secondary)}.ma-user-menu--primary{color:var(--primary-color, #1976d2)}.ma-user-menu--primary:hover:not(:disabled){background-color:var(--primary-light, rgba(25, 118, 210, .08))}.ma-user-menu--success{color:var(--success-color, #2e7d32)}.ma-user-menu--success:hover:not(:disabled){background-color:var(--success-light, rgba(46, 125, 50, .08))}.ma-user-menu--warning{color:var(--warning-color, #ed6c02)}.ma-user-menu--warning:hover:not(:disabled){background-color:var(--warning-light, rgba(237, 108, 2, .08))}.ma-user-menu--danger{color:var(--error-color, #d32f2f)}.ma-user-menu--danger:hover:not(:disabled){background-color:var(--error-light, rgba(211, 47, 47, .08))}.ma-user-menu--info{color:var(--info-color, #0288d1)}.ma-user-menu--info:hover:not(:disabled){background-color:var(--info-light, rgba(2, 136, 209, .08))}\n"] }]
|
|
2215
|
+
args: [{ selector: 'ma-user-menu', template: "<button\r\n type=\"button\"\r\n class=\"ma-user-menu-btn\"\r\n [class]=\"'ma-user-menu--' + color()\"\r\n [disabled]=\"disabled()\"\r\n (click)=\"onClick()\">\r\n <span class=\"ma-user-menu-icon\">\r\n <ng-content select=\"[maUserMenuIcon]\"></ng-content>\r\n </span>\r\n <span class=\"ma-user-menu-name\">{{ name() }}</span>\r\n</button>\r\n", styles: [":host{display:block}.ma-user-menu-btn{display:flex;align-items:center;gap:10px;width:100%;padding:11px 16px;border:none;background:none;text-align:left;cursor:pointer;font-size:13.5px;font-weight:500;color:var(--text-primary);transition:background-color .15s,color .15s}.ma-user-menu-btn:disabled{opacity:.5;cursor:not-allowed}.ma-user-menu-icon{flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;opacity:.8}.ma-user-menu-icon:empty{display:none}.ma-user-menu-name{flex:1 1 auto;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ma-user-menu--default{color:var(--text-primary)}.ma-user-menu--default:hover:not(:disabled){background-color:var(--bg-secondary)}.ma-user-menu--primary{color:var(--primary-color, #1976d2)}.ma-user-menu--primary:hover:not(:disabled){background-color:var(--primary-light, rgba(25, 118, 210, .08))}.ma-user-menu--success{color:var(--success-color, #2e7d32)}.ma-user-menu--success:hover:not(:disabled){background-color:var(--success-light, rgba(46, 125, 50, .08))}.ma-user-menu--warning{color:var(--warning-color, #ed6c02)}.ma-user-menu--warning:hover:not(:disabled){background-color:var(--warning-light, rgba(237, 108, 2, .08))}.ma-user-menu--danger{color:var(--error-color, #d32f2f)}.ma-user-menu--danger:hover:not(:disabled){background-color:var(--error-light, rgba(211, 47, 47, .08))}.ma-user-menu--info{color:var(--info-color, #0288d1)}.ma-user-menu--info:hover:not(:disabled){background-color:var(--info-light, rgba(2, 136, 209, .08))}\n"] }]
|
|
2082
2216
|
}], propDecorators: { name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: true }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], itemClick: [{ type: i0.Output, args: ["itemClick"] }] } });
|
|
2083
2217
|
|
|
2084
2218
|
// mesauth-angular — primary entry point (backward compatible)
|
|
@@ -2090,5 +2224,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
2090
2224
|
* Generated bundle index. Do not edit.
|
|
2091
2225
|
*/
|
|
2092
2226
|
|
|
2093
|
-
export { ALL_ACTIONS, AVATAR_FRAMES, ApprovalActionType, ApprovalDocumentStatus, ApprovalStepMode, ApprovalStepStatus, MES_AUTH_CONFIG, MaApprovalPanelComponent, MaApprovalService, MaArvContainerComponent, MaAvatarComponent, MaIconComponent, MaThemeDirective, MaUiConfigService, MaUserComponent, MaUserMenuColor, MaUserMenuComponent, MesAuthModule, MesAuthService, NotificationBadgeComponent, NotificationPanelComponent, NotificationType, PACKAGE_VERSION, ThemeService, ToastContainerComponent, ToastService, UserProfileComponent, extractXMaPerm, mesAuthInterceptor, provideMesAuth, withXMaPerm, xMaResource };
|
|
2227
|
+
export { ALL_ACTIONS, AVATAR_FRAMES, ApprovalActionType, ApprovalDocumentStatus, ApprovalStepMode, ApprovalStepStatus, MES_AUTH_CONFIG, MaApprovalPanelComponent, MaApprovalService, MaArvContainerComponent, MaAvatarComponent, MaIconComponent, MaThemeDirective, MaUiConfigService, MaUserComponent, MaUserMenuColor, MaUserMenuComponent, MaUserXComponent, MesAuthModule, MesAuthService, NotificationBadgeComponent, NotificationPanelComponent, NotificationType, PACKAGE_VERSION, ThemeService, ToastContainerComponent, ToastService, UserProfileComponent, extractXMaPerm, mesAuthInterceptor, provideMesAuth, withXMaPerm, xMaResource };
|
|
2094
2228
|
//# sourceMappingURL=mesauth-angular.mjs.map
|