@yuuvis/client-shell 2.0.0-beta.0 → 2.0.0-beta.3

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.
Files changed (41) hide show
  1. package/fesm2022/yuuvis-client-shell-dashboard.component-DWdP5HSx.mjs +14 -0
  2. package/fesm2022/yuuvis-client-shell-dashboard.component-DWdP5HSx.mjs.map +1 -0
  3. package/fesm2022/yuuvis-client-shell-settings.component-R-GCMuxK.mjs +84 -0
  4. package/fesm2022/yuuvis-client-shell-settings.component-R-GCMuxK.mjs.map +1 -0
  5. package/fesm2022/yuuvis-client-shell-web-share-target.component-BQiQkEd_.mjs +21 -0
  6. package/fesm2022/yuuvis-client-shell-web-share-target.component-BQiQkEd_.mjs.map +1 -0
  7. package/fesm2022/yuuvis-client-shell.mjs +144 -143
  8. package/fesm2022/yuuvis-client-shell.mjs.map +1 -1
  9. package/lib/actions/manage-flavors/manage-flavors.component.d.ts +1 -0
  10. package/lib/assets/i18n/de.json +3 -3
  11. package/lib/assets/i18n/en.json +3 -3
  12. package/lib/client-shell.component.d.ts +4 -2
  13. package/lib/components/sidebar-nav/sidebar-nav.component.d.ts +8 -0
  14. package/lib/pages/dashboard/dashboard.component.d.ts +1 -1
  15. package/lib/pages/notifications/notifications.component.d.ts +0 -2
  16. package/lib/pages/settings/settings.component.d.ts +1 -0
  17. package/package.json +7 -18
  18. package/esm2022/index.mjs +0 -6
  19. package/esm2022/lib/actions/manage-flavors/manage-flavors.action.mjs +0 -39
  20. package/esm2022/lib/actions/manage-flavors/manage-flavors.component.mjs +0 -69
  21. package/esm2022/lib/client-shell.component.mjs +0 -191
  22. package/esm2022/lib/components/app-logo/app-logo.component.mjs +0 -18
  23. package/esm2022/lib/directives/inert.directive.mjs +0 -26
  24. package/esm2022/lib/lib.routes.mjs +0 -15
  25. package/esm2022/lib/pages/dashboard/dashboard.component.mjs +0 -11
  26. package/esm2022/lib/pages/notifications/notifications.component.mjs +0 -82
  27. package/esm2022/lib/pages/settings/settings.component.mjs +0 -71
  28. package/esm2022/lib/pages/web-share-target/web-share-target.component.mjs +0 -18
  29. package/esm2022/widget-dashboard/index.mjs +0 -3
  30. package/esm2022/widget-dashboard/lib/widget-dashboard.component.mjs +0 -46
  31. package/esm2022/widget-dashboard/lib/widget-dashboard.config.mjs +0 -3
  32. package/esm2022/widget-dashboard/lib/widget-dashboard.module.mjs +0 -49
  33. package/esm2022/widget-dashboard/yuuvis-client-shell-widget-dashboard.mjs +0 -5
  34. package/esm2022/yuuvis-client-shell.mjs +0 -5
  35. package/fesm2022/yuuvis-client-shell-widget-dashboard.mjs +0 -98
  36. package/fesm2022/yuuvis-client-shell-widget-dashboard.mjs.map +0 -1
  37. package/widget-dashboard/README.md +0 -19
  38. package/widget-dashboard/index.d.ts +0 -2
  39. package/widget-dashboard/lib/widget-dashboard.component.d.ts +0 -16
  40. package/widget-dashboard/lib/widget-dashboard.config.d.ts +0 -7
  41. package/widget-dashboard/lib/widget-dashboard.module.d.ts +0 -13
@@ -1,27 +1,39 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, ElementRef, input, effect, Directive, Component, signal, HostListener } from '@angular/core';
2
+ import { inject, ElementRef, input, effect, Directive, HostListener, Component, ChangeDetectionStrategy, signal, computed } from '@angular/core';
3
3
  import * as i1 from '@angular/common';
4
- import { DOCUMENT, CommonModule, NgIf, AsyncPipe } from '@angular/common';
4
+ import { CommonModule, AsyncPipe } from '@angular/common';
5
5
  import { toSignal } from '@angular/core/rxjs-interop';
6
+ import * as i3 from '@angular/material/button';
7
+ import { MatButtonModule, MatIconButton } from '@angular/material/button';
8
+ import * as i2 from '@angular/material/icon';
9
+ import { MatIconModule, MatIconRegistry, MatIcon } from '@angular/material/icon';
6
10
  import * as i2$2 from '@angular/router';
7
11
  import { Router, NavigationEnd, RouterModule } from '@angular/router';
8
12
  import { SwPush } from '@angular/service-worker';
9
- import * as i2 from '@yuuvis/client-core';
10
- import { UserService, ConfigService, TranslateService, TranslateModule, Utils, LocaleDatePipe, AuthService, DeviceService, UserRoles, DmsService, SystemType } from '@yuuvis/client-core';
11
- import { MetadataDefaultTemplatesComponent } from '@yuuvis/client-framework/metadata-form';
12
- import { ShellService, ShellNotificationsService, CommandPaletteService } from '@yuuvis/client-shell-core';
13
- import * as i2$1 from '@yuuvis/components/icon';
14
- import { ICONS, YvcIconModule } from '@yuuvis/components/icon';
15
- import { map, of, tap as tap$1 } from 'rxjs';
16
- import { tap, map as map$1, filter, catchError, switchMap } from 'rxjs/operators';
17
- import { FormBuilder, ReactiveFormsModule } from '@angular/forms';
13
+ import * as i2$1 from '@yuuvis/client-core';
14
+ import { Utils, LocaleDatePipe, TranslateModule, AuthService, UserService, TranslateService, DeviceService, SafeHtmlPipe, UserRoles, DmsService, SystemType } from '@yuuvis/client-core';
15
+ import { ShellNotificationsService, ShellService, CommandPaletteService } from '@yuuvis/client-shell-core';
16
+ import { of, switchMap as switchMap$1, tap as tap$1 } from 'rxjs';
17
+ import { map, shareReplay, tap, filter, catchError, switchMap } from 'rxjs/operators';
18
18
  import { CdkTrapFocus } from '@angular/cdk/a11y';
19
- import { LightDismissDirective, BusyOverlayDirective } from '@yuuvis/client-framework/common';
20
- import { YUV_ICONS } from '@yuuvis/client-framework/icons';
21
- import { ListComponent, ListItemDirective } from '@yuuvis/client-framework/list';
19
+ import { LightDismissDirective, ConfirmService, BusyOverlayDirective, DialogComponent } from '@yuuvis/client-framework/common';
20
+ import { YUV_ICONS, YuvIconComponent } from '@yuuvis/client-framework/icons';
21
+ import * as i4 from '@yuuvis/client-framework/list';
22
+ import { YuvListModule, ListItemDirective } from '@yuuvis/client-framework/list';
23
+ import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
24
+ import { MatListModule } from '@angular/material/list';
25
+ import * as i1$1 from '@angular/material/sidenav';
26
+ import { MatSidenavModule } from '@angular/material/sidenav';
27
+ import { MatToolbarModule } from '@angular/material/toolbar';
28
+ import * as i3$1 from '@yuuvis/client-framework/metadata-form-defaults';
29
+ import { YuvMetadataFormDefaultsModule } from '@yuuvis/client-framework/metadata-form-defaults';
30
+ import { MatProgressBar } from '@angular/material/progress-bar';
31
+ import * as i4$1 from '@angular/material/tooltip';
32
+ import { MatTooltipModule } from '@angular/material/tooltip';
33
+ import { MAT_DIALOG_DATA, MatDialogRef, MatDialog } from '@angular/material/dialog';
22
34
  import { AbstractContextAction, ACTION_ICON, SelectionRange } from '@yuuvis/client-framework/actions';
23
- import { YvcOverlayRef, YvcOverlayService } from '@yuuvis/components/overlay';
24
35
  import { FlavorChipComponent } from '@yuuvis/client-framework/object-flavor';
36
+ import { YuvButtonDirective } from '@yuuvis/material';
25
37
 
26
38
  class InertDirective {
27
39
  constructor() {
@@ -35,10 +47,10 @@ class InertDirective {
35
47
  el.removeAttribute('inert');
36
48
  });
37
49
  }
38
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: InertDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
39
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "18.2.13", type: InertDirective, isStandalone: true, selector: "[inert]", inputs: { inert: { classPropertyName: "inert", publicName: "inert", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 }); }
50
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: InertDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
51
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.1", type: InertDirective, isStandalone: true, selector: "[inert]", inputs: { inert: { classPropertyName: "inert", publicName: "inert", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 }); }
40
52
  }
41
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: InertDirective, decorators: [{
53
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: InertDirective, decorators: [{
42
54
  type: Directive,
43
55
  args: [{
44
56
  // eslint-disable-next-line @angular-eslint/directive-selector
@@ -47,76 +59,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImpo
47
59
  }]
48
60
  }], ctorParameters: () => [] });
49
61
 
50
- class DashboardPageComponent {
51
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DashboardPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
52
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: DashboardPageComponent, selector: "yuv-dashboard", ngImport: i0, template: "yuuvis Momentum\n", styles: [":host{display:grid;align-items:center;justify-content:center;height:100%;overflow:hidden;color:var(--text-color-hint);font-size:var(--font-display)}\n"] }); }
53
- }
54
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DashboardPageComponent, decorators: [{
55
- type: Component,
56
- args: [{ selector: 'yuv-dashboard', template: "yuuvis Momentum\n", styles: [":host{display:grid;align-items:center;justify-content:center;height:100%;overflow:hidden;color:var(--text-color-hint);font-size:var(--font-display)}\n"] }]
57
- }] });
58
-
59
- class SettingsPageComponent {
60
- constructor() {
61
- this.userService = inject(UserService);
62
- this.config = inject(ConfigService);
63
- this.translate = inject(TranslateService);
64
- this.shell = inject(ShellService);
65
- this.document = inject(DOCUMENT);
66
- this.#fb = inject(FormBuilder);
67
- this.clientLocales = signal([]);
68
- this.clientVersion = signal(undefined);
69
- this.user = toSignal(this.userService.user$);
70
- this.appSettingForms$ = this.shell.appSettings$.pipe(map((settings) => settings.map((e) => {
71
- const x = {};
72
- const fcn = e.properties.map((p) => ({
73
- label: this.translate.instant(p.label) || p.label,
74
- name: p.name,
75
- type: p.type
76
- }));
77
- e.properties.forEach((p) => {
78
- x[p.name] = [p.value];
79
- });
80
- return {
81
- appID: e.appID,
82
- label: e.label,
83
- formControls: fcn,
84
- form: this.#fb.group(x)
85
- };
86
- })));
87
- }
88
- #fb;
89
- saveAppSettings(appID, form) {
90
- this.userService
91
- .saveUserSettings({
92
- clientAppSettings: {
93
- [appID]: form.value
94
- }
95
- })
96
- .subscribe({
97
- next: () => {
98
- form.markAsPristine();
99
- },
100
- error: (err) => {
101
- console.error('Error saving app settings', err);
102
- }
103
- });
104
- }
105
- changeClientLocale(iso) {
106
- this.userService.changeClientLocale(iso);
107
- }
108
- ngOnInit() {
109
- this.clientVersion.set(this.document.body.getAttribute('data-version') ?? 'dev');
110
- this.clientLocales.set(this.config.getClientLocales());
111
- }
112
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SettingsPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
113
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: SettingsPageComponent, isStandalone: true, selector: "yuv-settings", ngImport: i0, template: "<header>\n <h1>{{ 'yuv.shell.settings.title' | translate }}</h1>\n <h4>{{ 'yuc.shell.settings.client.version' | translate }}: {{ clientVersion() }}</h4>\n</header>\n\n\n<main>@if (user()) {\n <section class=\"user\">\n <!-- <yuv-user-avatar class=\"background\" [user]=\"user()\"></yuv-user-avatar> -->\n <div class=\"user\">\n <div class=\"meta uname\">{{ user()!.username }}</div>\n <h2>{{ user()!.title }}</h2>\n <div class=\"meta uemail\">{{ user()!.email }}</div>\n <div class=\"meta utenant\">{{ 'yuv.shell.settings.tenant' | translate }}: {{ user()!.tenant }}</div>\n </div>\n </section>\n}\n <!-- language -->\n <section yuvOfflineDisabled>\n <div class=\"label\" translate>yuv.shell.settings.language</div>\n <div class=\"value buttons\">\n @for (locale of clientLocales(); track locale.iso) {\n <button class=\"toggle secondary\" (click)=\"changeClientLocale(locale.iso)\" [ngClass]=\"{ active: translate.currentLang === locale.iso }\">\n {{ locale.label }}\n </button>\n }\n </div>\n </section>\n\n <!-- app settings -->\n <!-- TODO: activate one feature is refined -->\n <!-- @for (c of appSettingForms$ | async; track $index) {\n <section>\n {{ c.label }}\n <form [formGroup]=\"c.form\" (ngSubmit)=\"saveAppSettings(c.appID, c.form)\">\n @for (n of c.formControls; track $index) {\n <label\n >{{ n.label }}\n\n @switch (n.type) {\n @case ('string') {\n <input type=\"text\" [formControlName]=\"n.name\" />\n }\n @case ('number') {\n <input type=\"number\" [formControlName]=\"n.name\" />\n }\n }\n </label>\n }\n <button [ngClass]=\"{ hideen: c.form.untouched }\" [disabled]=\"c.form.invalid\">Save</button>\n </form>\n </section>\n } -->\n</main>\n", styles: [":host{display:grid;grid-template-columns:1fr auto;grid-template-rows:auto 1fr;grid-template-areas:\"header\" \"settings\";height:100%;overflow:hidden;overflow-y:auto}:host header{grid-area:header;padding:calc(var(--app-pane-padding) * 2)}:host header h1,:host header h4{margin:0}:host header h1{font-size:var(--font-display);font-weight:400}:host header h4{font-size:var(--font-cation);font-weight:400;font-style:italic;color:var(--text-color-caption)}:host main{grid-area:settings;padding:var(--app-pane-padding);overflow-y:auto}:host main section{display:flex;flex-flow:column;padding:var(--app-pane-padding)}:host main section .label{margin-block-end:1em}:host main section .value{display:flex;flex-flow:row wrap;gap:calc(var(--app-pane-padding) / 4)}:host main section.user h2{margin:0 0 1rem;font-weight:400}:host button.active{background-color:var(--color-accent);color:var(--color-accent-tone);pointer-events:none}:host button.color.clear{padding:2px 8px}:host button.color.accent.active{outline:2px solid #fff;outline-offset:-2px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }, { kind: "directive", type: i2.TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "ngmodule", type: ReactiveFormsModule }] }); }
114
- }
115
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SettingsPageComponent, decorators: [{
116
- type: Component,
117
- args: [{ selector: 'yuv-settings', standalone: true, imports: [CommonModule, TranslateModule, ReactiveFormsModule], template: "<header>\n <h1>{{ 'yuv.shell.settings.title' | translate }}</h1>\n <h4>{{ 'yuc.shell.settings.client.version' | translate }}: {{ clientVersion() }}</h4>\n</header>\n\n\n<main>@if (user()) {\n <section class=\"user\">\n <!-- <yuv-user-avatar class=\"background\" [user]=\"user()\"></yuv-user-avatar> -->\n <div class=\"user\">\n <div class=\"meta uname\">{{ user()!.username }}</div>\n <h2>{{ user()!.title }}</h2>\n <div class=\"meta uemail\">{{ user()!.email }}</div>\n <div class=\"meta utenant\">{{ 'yuv.shell.settings.tenant' | translate }}: {{ user()!.tenant }}</div>\n </div>\n </section>\n}\n <!-- language -->\n <section yuvOfflineDisabled>\n <div class=\"label\" translate>yuv.shell.settings.language</div>\n <div class=\"value buttons\">\n @for (locale of clientLocales(); track locale.iso) {\n <button class=\"toggle secondary\" (click)=\"changeClientLocale(locale.iso)\" [ngClass]=\"{ active: translate.currentLang === locale.iso }\">\n {{ locale.label }}\n </button>\n }\n </div>\n </section>\n\n <!-- app settings -->\n <!-- TODO: activate one feature is refined -->\n <!-- @for (c of appSettingForms$ | async; track $index) {\n <section>\n {{ c.label }}\n <form [formGroup]=\"c.form\" (ngSubmit)=\"saveAppSettings(c.appID, c.form)\">\n @for (n of c.formControls; track $index) {\n <label\n >{{ n.label }}\n\n @switch (n.type) {\n @case ('string') {\n <input type=\"text\" [formControlName]=\"n.name\" />\n }\n @case ('number') {\n <input type=\"number\" [formControlName]=\"n.name\" />\n }\n }\n </label>\n }\n <button [ngClass]=\"{ hideen: c.form.untouched }\" [disabled]=\"c.form.invalid\">Save</button>\n </form>\n </section>\n } -->\n</main>\n", styles: [":host{display:grid;grid-template-columns:1fr auto;grid-template-rows:auto 1fr;grid-template-areas:\"header\" \"settings\";height:100%;overflow:hidden;overflow-y:auto}:host header{grid-area:header;padding:calc(var(--app-pane-padding) * 2)}:host header h1,:host header h4{margin:0}:host header h1{font-size:var(--font-display);font-weight:400}:host header h4{font-size:var(--font-cation);font-weight:400;font-style:italic;color:var(--text-color-caption)}:host main{grid-area:settings;padding:var(--app-pane-padding);overflow-y:auto}:host main section{display:flex;flex-flow:column;padding:var(--app-pane-padding)}:host main section .label{margin-block-end:1em}:host main section .value{display:flex;flex-flow:row wrap;gap:calc(var(--app-pane-padding) / 4)}:host main section.user h2{margin:0 0 1rem;font-weight:400}:host button.active{background-color:var(--color-accent);color:var(--color-accent-tone);pointer-events:none}:host button.color.clear{padding:2px 8px}:host button.color.accent.active{outline:2px solid #fff;outline-offset:-2px}\n"] }]
118
- }] });
119
-
120
62
  class NotificationsPageComponent {
121
63
  constructor() {
122
64
  this.router = inject(Router);
@@ -127,8 +69,6 @@ class NotificationsPageComponent {
127
69
  this.notifications = toSignal(this.shellNotifications.shellNotifications$);
128
70
  this.notificationsIdEffect = effect(() => (this._notificationIDs = (this.notifications() || []).map((n) => n.id)));
129
71
  this.icons = {
130
- close: ICONS.clear,
131
- trash: YUV_ICONS.trash,
132
72
  note: YUV_ICONS.notification
133
73
  };
134
74
  }
@@ -173,47 +113,59 @@ class NotificationsPageComponent {
173
113
  fc[0].focus();
174
114
  });
175
115
  }
176
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NotificationsPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
177
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: NotificationsPageComponent, isStandalone: true, selector: "yuv-notifications", host: { listeners: { "keydown": "onKeydown($event)" } }, ngImport: i0, template: "<div class=\"notifications\" (yuvLightDismiss)=\"close()\" cdkTrapFocus>\n <h2>{{ 'yuv.shell.notifications.title' | translate }}</h2>\n\n @if (notifications()?.length) {\n <yuv-list (itemSelect)=\"itemSelected($event)\" (itemFocus)=\"itemFocused($event)\">\n @for (n of notifications(); track n.id) {\n <div class=\"note {{ n.level }}\" [ngClass]=\"{ withRoute: n.targetRoute }\" yuvListItem>\n <div class=\"icon\"><yvc-icon [svg]=\"n.icon || icons.note\"></yvc-icon></div>\n <div class=\"received\">{{ n.timestamp | localeDate }}</div>\n <div class=\"title\">{{ n.title }}</div>\n <div class=\"description\">{{ n.description }}</div>\n <div class=\"meta\"></div>\n\n <div class=\"actions\">\n <button (click)=\"remove(n.id)\">\n <yvc-icon [svg]=\"icons.trash\"></yvc-icon>\n </button>\n </div>\n </div>\n }\n </yuv-list>\n\n <div class=\"actions\">\n <button [hidden]=\"!notifications()?.length\" class=\"icon secondary\" (click)=\"removeAll()\">\n {{ 'yuv.shell.notifications.button.remove.all' | translate }}<yvc-icon [svg]=\"icons.trash\"></yvc-icon>\n </button>\n </div>\n } @else {\n <div class=\"empty\">\n <p>{{ 'yuv.shell.notifications.empty' | translate }}</p>\n </div>\n }\n\n <button class=\"icon close\" (click)=\"close()\">\n <yvc-icon [svg]=\"icons.close\"></yvc-icon>\n </button>\n</div>\n", styles: [":host{height:100%;display:flex}:host .notifications{background-color:var(--panel-background-lightgrey);border-inline-end:1px solid var(--panel-divider-color);height:100%;overflow:hidden;box-sizing:border-box;padding:var(--app-pane-padding);display:grid;grid-template-rows:auto auto 1fr;grid-template-columns:1fr auto;grid-template-areas:\"title close\" \"actions actions\" \"list list\";gap:var(--app-pane-padding);max-width:30vw;min-width:300px;box-shadow:8px 0 8px #0000001a;animation:dialogAppear .2s ease-in-out}:host .notifications h2{color:var(--text-color-caption);grid-area:title;margin:0;padding:0;align-self:center;font-size:var(--font-title);font-weight:400;text-overflow:ellipsis;overflow:hidden}:host .notifications .actions{grid-area:actions;display:flex;justify-content:end;--icon-size: 18px}:host .notifications .actions button{border-radius:.4em}:host .notifications .close{grid-area:close;--icon-size: 18px}:host .notifications yuv-list,:host .notifications .empty{grid-area:list}:host .notifications .empty{display:grid;align-items:center;justify-content:center;color:var(--text-color-caption)}:host .notifications .note{--level-color: transparent;display:grid;grid-template-rows:auto auto auto auto;grid-template-columns:auto 1fr auto;grid-template-areas:\"icon received actions\" \"icon title title\" \"icon description description\" \"icon meta meta\";row-gap:calc(var(--app-pane-padding) / 4);column-gap:calc(var(--app-pane-padding) / 2);align-items:center;padding:calc(var(--app-pane-padding) / 2);padding-inline-start:var(--app-pane-padding);margin-block-end:calc(var(--app-pane-padding) / 2);background-color:var(--panel-background);outline:1px solid var(--panel-divider-color);outline-offset:-1px;position:relative;cursor:default}:host .notifications .note.withRoute{cursor:pointer}:host .notifications .note:before{content:\"\";width:4px;position:absolute;left:2px;top:2px;bottom:2px;border-radius:2px;background-color:var(--level-color)}:host .notifications .note.alert{--level-color: var(--color-error)}:host .notifications .note.warning{--level-color: var(--color-warning)}:host .notifications .note.success{--level-color: var(--color-success)}:host .notifications .note:hover,:host .notifications .note[aria-current=true]{background-color:var(--item-focus-background-color)}:host .notifications .note:hover button,:host .notifications .note[aria-current=true] button{opacity:1}:host .notifications .note .icon{grid-area:icon;color:var(--text-color-caption)}:host .notifications .note .title{overflow:hidden;text-overflow:ellipsis;font-weight:700;grid-area:title;color:var(--text-color-body)}:host .notifications .note .description{grid-area:description;overflow:hidden;text-overflow:ellipsis}:host .notifications .note .meta{grid-area:meta}:host .notifications .note .received{grid-area:received;color:var(--text-color-caption)}:host .notifications .note button{grid-area:actions;padding:0;opacity:0}:host .notifications .note button yvc-icon{width:18px;height:18px}@keyframes dialogAppear{0%{opacity:0;transform:translate(calc(var(--app-pane-padding) * -1))}to{opacity:1;transform:translate(0)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: LightDismissDirective, selector: "[yuvLightDismiss]", outputs: ["yuvLightDismiss"] }, { kind: "pipe", type: LocaleDatePipe, name: "localeDate" }, { kind: "ngmodule", type: YvcIconModule }, { kind: "component", type: i2$1.Icon, selector: "yvc-icon", inputs: ["label", "svg", "svgSrc"] }, { kind: "directive", type: CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "component", type: ListComponent, selector: "yuv-list", inputs: ["multiselect", "selfHandleSelection", "disableSelection"], outputs: ["itemSelect", "itemFocus"] }, { kind: "directive", type: ListItemDirective, selector: "[yuvListItem]", inputs: ["disabled", "active", "selected"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }] }); }
116
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: NotificationsPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
117
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.1", type: NotificationsPageComponent, isStandalone: true, selector: "yuv-notifications", host: { listeners: { "keydown": "onKeydown($event)" } }, ngImport: i0, template: "<div class=\"notifications\" (yuvLightDismiss)=\"close()\" cdkTrapFocus>\n <h2>{{ 'yuv.shell.notifications.title' | translate }}</h2>\n\n @if (notifications()?.length) {\n <yuv-list (itemSelect)=\"itemSelected($event)\" (itemFocus)=\"itemFocused($event)\">\n @for (n of notifications(); track n.id) {\n <div class=\"note {{ n.level }}\" [ngClass]=\"{ withRoute: n.targetRoute }\" yuvListItem>\n <div class=\"icon\"><yuv-icon [svg]=\"n.icon || icons.note\"></yuv-icon></div>\n <div class=\"received\">{{ n.timestamp | localeDate }}</div>\n <div class=\"title\">{{ n.title }}</div>\n <div class=\"description\">{{ n.description }}</div>\n <div class=\"meta\"></div>\n\n <div class=\"actions\">\n <button mat-icon-button (click)=\"remove(n.id)\">\n <mat-icon>delete</mat-icon>\n </button>\n </div>\n </div>\n }\n </yuv-list>\n\n <div class=\"actions\">\n <button mat-icon-button [hidden]=\"!notifications()?.length\" class=\"icon secondary\" (click)=\"removeAll()\">\n {{ 'yuv.shell.notifications.button.remove.all' | translate }}<mat-icon>delete</mat-icon>\n </button>\n </div>\n } @else {\n <div class=\"empty\">\n <p>{{ 'yuv.shell.notifications.empty' | translate }}</p>\n </div>\n }\n\n <button mat-icon-button class=\"icon close\" (click)=\"close()\">\n <mat-icon>close</mat-icon>\n </button>\n</div>\n", styles: [":host{height:100%;display:flex}:host .notifications{background-color:var(--ymt-surface-panel);border-inline-end:1px solid var(--ymt-outline-variant);height:100%;overflow:hidden;box-sizing:border-box;padding:var(--ymt-spacing-m);display:grid;grid-template-rows:auto auto 1fr;grid-template-columns:1fr auto;grid-template-areas:\"title close\" \"actions actions\" \"list list\";gap:var(--ymt-spacing-m);max-width:30vw;min-width:300px;box-shadow:8px 0 8px #0000001a;animation:dialogAppear .2s ease-in-out}:host .notifications h2{color:var(--ymt-text-color-subtle);grid-area:title;margin:0;padding:0;align-self:center;text-overflow:ellipsis;overflow:hidden}:host .notifications .actions{grid-area:actions;display:flex;justify-content:end;--icon-size: 18px}:host .notifications .actions button{border-radius:.4em}:host .notifications .close{grid-area:close;--icon-size: 18px}:host .notifications yuv-list,:host .notifications .empty{grid-area:list}:host .notifications .empty{display:grid;align-items:center;justify-content:center;color:var(--ymt-text-color-subtle)}:host .notifications .note{--level-color: transparent;display:grid;grid-template-rows:auto auto auto auto;grid-template-columns:auto 1fr auto;grid-template-areas:\"icon received actions\" \"icon title title\" \"icon description description\" \"icon meta meta\";row-gap:var(--ymt-spacing-2xs);column-gap:var(--ymt-spacing-xs);align-items:center;padding:var(--ymt-spacing-xs);padding-inline-start:var(--ymt-spacing-m);margin-block-end:var(--ymt-spacing-xs);background-color:var(--ymt-surface-panel);outline:1px solid var(--ymt-outline-variant);outline-offset:-1px;position:relative;cursor:default}:host .notifications .note.withRoute{cursor:pointer}:host .notifications .note:before{content:\"\";width:4px;position:absolute;left:2px;top:2px;bottom:2px;border-radius:2px;background-color:var(--level-color)}:host .notifications .note.alert{--level-color: var(--ymt-danger)}:host .notifications .note.warning{--level-color: var(--ymt-warning)}:host .notifications .note.success{--level-color: var(--ymt-success)}:host .notifications .note:hover,:host .notifications .note[aria-current=true]{background-color:var(--ymt-focus-background)}:host .notifications .note:hover button,:host .notifications .note[aria-current=true] button{opacity:1}:host .notifications .note .icon{grid-area:icon;color:var(--ymt-text-color-subtle)}:host .notifications .note .title{overflow:hidden;text-overflow:ellipsis;font-weight:700;grid-area:title;color:var(--ymt-text-color)}:host .notifications .note .description{grid-area:description;overflow:hidden;text-overflow:ellipsis}:host .notifications .note .meta{grid-area:meta}:host .notifications .note .received{grid-area:received;color:var(--ymt-text-color-subtle)}:host .notifications .note button{grid-area:actions;padding:0;opacity:0}@keyframes dialogAppear{0%{opacity:0;transform:translate(calc(var(--ymt-spacing-m) * -1))}to{opacity:1;transform:translate(0)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: LightDismissDirective, selector: "[yuvLightDismiss]", outputs: ["yuvLightDismiss"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "pipe", type: LocaleDatePipe, name: "localeDate" }, { kind: "component", type: YuvIconComponent, selector: "yuv-icon", inputs: ["label", "svg", "svgSrc"] }, { kind: "directive", type: CdkTrapFocus, selector: "[cdkTrapFocus]", inputs: ["cdkTrapFocus", "cdkTrapFocusAutoCapture"], exportAs: ["cdkTrapFocus"] }, { kind: "ngmodule", type: YuvListModule }, { kind: "component", type: i4.ListComponent, selector: "yuv-list", inputs: ["multiselect", "selfHandleSelection", "disableSelection"], outputs: ["itemSelect", "itemFocus"] }, { kind: "directive", type: i4.ListItemDirective, selector: "[yuvListItem]", inputs: ["disabled", "active", "selected"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2$1.TranslatePipe, name: "translate" }] }); }
178
118
  }
179
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: NotificationsPageComponent, decorators: [{
119
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: NotificationsPageComponent, decorators: [{
180
120
  type: Component,
181
- args: [{ selector: 'yuv-notifications', standalone: true, imports: [CommonModule, LightDismissDirective, LocaleDatePipe, YvcIconModule, CdkTrapFocus, ListComponent, ListItemDirective, TranslateModule], template: "<div class=\"notifications\" (yuvLightDismiss)=\"close()\" cdkTrapFocus>\n <h2>{{ 'yuv.shell.notifications.title' | translate }}</h2>\n\n @if (notifications()?.length) {\n <yuv-list (itemSelect)=\"itemSelected($event)\" (itemFocus)=\"itemFocused($event)\">\n @for (n of notifications(); track n.id) {\n <div class=\"note {{ n.level }}\" [ngClass]=\"{ withRoute: n.targetRoute }\" yuvListItem>\n <div class=\"icon\"><yvc-icon [svg]=\"n.icon || icons.note\"></yvc-icon></div>\n <div class=\"received\">{{ n.timestamp | localeDate }}</div>\n <div class=\"title\">{{ n.title }}</div>\n <div class=\"description\">{{ n.description }}</div>\n <div class=\"meta\"></div>\n\n <div class=\"actions\">\n <button (click)=\"remove(n.id)\">\n <yvc-icon [svg]=\"icons.trash\"></yvc-icon>\n </button>\n </div>\n </div>\n }\n </yuv-list>\n\n <div class=\"actions\">\n <button [hidden]=\"!notifications()?.length\" class=\"icon secondary\" (click)=\"removeAll()\">\n {{ 'yuv.shell.notifications.button.remove.all' | translate }}<yvc-icon [svg]=\"icons.trash\"></yvc-icon>\n </button>\n </div>\n } @else {\n <div class=\"empty\">\n <p>{{ 'yuv.shell.notifications.empty' | translate }}</p>\n </div>\n }\n\n <button class=\"icon close\" (click)=\"close()\">\n <yvc-icon [svg]=\"icons.close\"></yvc-icon>\n </button>\n</div>\n", styles: [":host{height:100%;display:flex}:host .notifications{background-color:var(--panel-background-lightgrey);border-inline-end:1px solid var(--panel-divider-color);height:100%;overflow:hidden;box-sizing:border-box;padding:var(--app-pane-padding);display:grid;grid-template-rows:auto auto 1fr;grid-template-columns:1fr auto;grid-template-areas:\"title close\" \"actions actions\" \"list list\";gap:var(--app-pane-padding);max-width:30vw;min-width:300px;box-shadow:8px 0 8px #0000001a;animation:dialogAppear .2s ease-in-out}:host .notifications h2{color:var(--text-color-caption);grid-area:title;margin:0;padding:0;align-self:center;font-size:var(--font-title);font-weight:400;text-overflow:ellipsis;overflow:hidden}:host .notifications .actions{grid-area:actions;display:flex;justify-content:end;--icon-size: 18px}:host .notifications .actions button{border-radius:.4em}:host .notifications .close{grid-area:close;--icon-size: 18px}:host .notifications yuv-list,:host .notifications .empty{grid-area:list}:host .notifications .empty{display:grid;align-items:center;justify-content:center;color:var(--text-color-caption)}:host .notifications .note{--level-color: transparent;display:grid;grid-template-rows:auto auto auto auto;grid-template-columns:auto 1fr auto;grid-template-areas:\"icon received actions\" \"icon title title\" \"icon description description\" \"icon meta meta\";row-gap:calc(var(--app-pane-padding) / 4);column-gap:calc(var(--app-pane-padding) / 2);align-items:center;padding:calc(var(--app-pane-padding) / 2);padding-inline-start:var(--app-pane-padding);margin-block-end:calc(var(--app-pane-padding) / 2);background-color:var(--panel-background);outline:1px solid var(--panel-divider-color);outline-offset:-1px;position:relative;cursor:default}:host .notifications .note.withRoute{cursor:pointer}:host .notifications .note:before{content:\"\";width:4px;position:absolute;left:2px;top:2px;bottom:2px;border-radius:2px;background-color:var(--level-color)}:host .notifications .note.alert{--level-color: var(--color-error)}:host .notifications .note.warning{--level-color: var(--color-warning)}:host .notifications .note.success{--level-color: var(--color-success)}:host .notifications .note:hover,:host .notifications .note[aria-current=true]{background-color:var(--item-focus-background-color)}:host .notifications .note:hover button,:host .notifications .note[aria-current=true] button{opacity:1}:host .notifications .note .icon{grid-area:icon;color:var(--text-color-caption)}:host .notifications .note .title{overflow:hidden;text-overflow:ellipsis;font-weight:700;grid-area:title;color:var(--text-color-body)}:host .notifications .note .description{grid-area:description;overflow:hidden;text-overflow:ellipsis}:host .notifications .note .meta{grid-area:meta}:host .notifications .note .received{grid-area:received;color:var(--text-color-caption)}:host .notifications .note button{grid-area:actions;padding:0;opacity:0}:host .notifications .note button yvc-icon{width:18px;height:18px}@keyframes dialogAppear{0%{opacity:0;transform:translate(calc(var(--app-pane-padding) * -1))}to{opacity:1;transform:translate(0)}}\n"] }]
121
+ args: [{ selector: 'yuv-notifications', standalone: true, imports: [
122
+ CommonModule,
123
+ LightDismissDirective,
124
+ MatIconModule,
125
+ MatButtonModule,
126
+ LocaleDatePipe,
127
+ YuvIconComponent,
128
+ CdkTrapFocus,
129
+ YuvListModule,
130
+ TranslateModule
131
+ ], template: "<div class=\"notifications\" (yuvLightDismiss)=\"close()\" cdkTrapFocus>\n <h2>{{ 'yuv.shell.notifications.title' | translate }}</h2>\n\n @if (notifications()?.length) {\n <yuv-list (itemSelect)=\"itemSelected($event)\" (itemFocus)=\"itemFocused($event)\">\n @for (n of notifications(); track n.id) {\n <div class=\"note {{ n.level }}\" [ngClass]=\"{ withRoute: n.targetRoute }\" yuvListItem>\n <div class=\"icon\"><yuv-icon [svg]=\"n.icon || icons.note\"></yuv-icon></div>\n <div class=\"received\">{{ n.timestamp | localeDate }}</div>\n <div class=\"title\">{{ n.title }}</div>\n <div class=\"description\">{{ n.description }}</div>\n <div class=\"meta\"></div>\n\n <div class=\"actions\">\n <button mat-icon-button (click)=\"remove(n.id)\">\n <mat-icon>delete</mat-icon>\n </button>\n </div>\n </div>\n }\n </yuv-list>\n\n <div class=\"actions\">\n <button mat-icon-button [hidden]=\"!notifications()?.length\" class=\"icon secondary\" (click)=\"removeAll()\">\n {{ 'yuv.shell.notifications.button.remove.all' | translate }}<mat-icon>delete</mat-icon>\n </button>\n </div>\n } @else {\n <div class=\"empty\">\n <p>{{ 'yuv.shell.notifications.empty' | translate }}</p>\n </div>\n }\n\n <button mat-icon-button class=\"icon close\" (click)=\"close()\">\n <mat-icon>close</mat-icon>\n </button>\n</div>\n", styles: [":host{height:100%;display:flex}:host .notifications{background-color:var(--ymt-surface-panel);border-inline-end:1px solid var(--ymt-outline-variant);height:100%;overflow:hidden;box-sizing:border-box;padding:var(--ymt-spacing-m);display:grid;grid-template-rows:auto auto 1fr;grid-template-columns:1fr auto;grid-template-areas:\"title close\" \"actions actions\" \"list list\";gap:var(--ymt-spacing-m);max-width:30vw;min-width:300px;box-shadow:8px 0 8px #0000001a;animation:dialogAppear .2s ease-in-out}:host .notifications h2{color:var(--ymt-text-color-subtle);grid-area:title;margin:0;padding:0;align-self:center;text-overflow:ellipsis;overflow:hidden}:host .notifications .actions{grid-area:actions;display:flex;justify-content:end;--icon-size: 18px}:host .notifications .actions button{border-radius:.4em}:host .notifications .close{grid-area:close;--icon-size: 18px}:host .notifications yuv-list,:host .notifications .empty{grid-area:list}:host .notifications .empty{display:grid;align-items:center;justify-content:center;color:var(--ymt-text-color-subtle)}:host .notifications .note{--level-color: transparent;display:grid;grid-template-rows:auto auto auto auto;grid-template-columns:auto 1fr auto;grid-template-areas:\"icon received actions\" \"icon title title\" \"icon description description\" \"icon meta meta\";row-gap:var(--ymt-spacing-2xs);column-gap:var(--ymt-spacing-xs);align-items:center;padding:var(--ymt-spacing-xs);padding-inline-start:var(--ymt-spacing-m);margin-block-end:var(--ymt-spacing-xs);background-color:var(--ymt-surface-panel);outline:1px solid var(--ymt-outline-variant);outline-offset:-1px;position:relative;cursor:default}:host .notifications .note.withRoute{cursor:pointer}:host .notifications .note:before{content:\"\";width:4px;position:absolute;left:2px;top:2px;bottom:2px;border-radius:2px;background-color:var(--level-color)}:host .notifications .note.alert{--level-color: var(--ymt-danger)}:host .notifications .note.warning{--level-color: var(--ymt-warning)}:host .notifications .note.success{--level-color: var(--ymt-success)}:host .notifications .note:hover,:host .notifications .note[aria-current=true]{background-color:var(--ymt-focus-background)}:host .notifications .note:hover button,:host .notifications .note[aria-current=true] button{opacity:1}:host .notifications .note .icon{grid-area:icon;color:var(--ymt-text-color-subtle)}:host .notifications .note .title{overflow:hidden;text-overflow:ellipsis;font-weight:700;grid-area:title;color:var(--ymt-text-color)}:host .notifications .note .description{grid-area:description;overflow:hidden;text-overflow:ellipsis}:host .notifications .note .meta{grid-area:meta}:host .notifications .note .received{grid-area:received;color:var(--ymt-text-color-subtle)}:host .notifications .note button{grid-area:actions;padding:0;opacity:0}@keyframes dialogAppear{0%{opacity:0;transform:translate(calc(var(--ymt-spacing-m) * -1))}to{opacity:1;transform:translate(0)}}\n"] }]
182
132
  }], propDecorators: { onKeydown: [{
183
133
  type: HostListener,
184
134
  args: ['keydown', ['$event']]
185
135
  }] } });
186
136
 
187
- class WebShareTargetPageComponent {
188
- constructor() {
189
- navigator.serviceWorker.onmessage = (e) => {
190
- const file = e.data.file;
191
- console.log(file);
192
- };
193
- }
194
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: WebShareTargetPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
195
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: WebShareTargetPageComponent, isStandalone: true, selector: "yuv-web-share-target", ngImport: i0, template: "<p>web-share-target works!</p>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }] }); }
196
- }
197
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: WebShareTargetPageComponent, decorators: [{
198
- type: Component,
199
- args: [{ selector: 'yuv-web-share-target', standalone: true, imports: [CommonModule], template: "<p>web-share-target works!</p>\n" }]
200
- }], ctorParameters: () => [] });
201
-
202
137
  const clientShellRoutes = [
203
- { path: 'dashboard', component: DashboardPageComponent },
138
+ { path: 'dashboard', loadComponent: () => import('./yuuvis-client-shell-dashboard.component-DWdP5HSx.mjs').then((comp) => comp.DashboardPageComponent) },
204
139
  { path: 'notifications', component: NotificationsPageComponent, outlet: 'aside' },
205
- { path: 'settings', component: SettingsPageComponent },
206
- { path: 'web-share-target', component: WebShareTargetPageComponent },
140
+ { path: 'settings', loadComponent: () => import('./yuuvis-client-shell-settings.component-R-GCMuxK.mjs').then((comp) => comp.SettingsPageComponent) },
141
+ {
142
+ path: 'web-share-target',
143
+ loadComponent: () => import('./yuuvis-client-shell-web-share-target.component-BQiQkEd_.mjs').then((comp) => comp.WebShareTargetPageComponent)
144
+ },
207
145
  // default route
208
146
  { path: '', redirectTo: '/dashboard', pathMatch: 'full' },
209
147
  // redirecting route
210
148
  { path: '**', redirectTo: '/' }
211
149
  ];
212
150
 
151
+ class SidebarNavComponent {
152
+ constructor() {
153
+ this.breakpointObserver = inject(BreakpointObserver);
154
+ this.isHandset$ = this.breakpointObserver.observe(Breakpoints.Handset).pipe(map((result) => result.matches), shareReplay());
155
+ }
156
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: SidebarNavComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
157
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.1", type: SidebarNavComponent, isStandalone: true, selector: "yuv-sidebar-nav", ngImport: i0, template: "<mat-sidenav-container class=\"sidenav-container\">\n <mat-sidenav class=\"sidenav\"\n attr.role=\"navigation\"\n mode=\"side\"\n opened>\n <div class=\"sidenav-content\">\n <div class=\"app-logo\">\n <ng-content select=\".shell-nav__shell-logo-button\"></ng-content>\n </div>\n <div class=\"nav-list\">\n <ng-content select=\".shell-nav__nav-list\"></ng-content>\n </div>\n <div class=\"actions\">\n <ng-content select=\".shell-nav__actions\"></ng-content>\n </div>\n </div>\n </mat-sidenav>\n <mat-sidenav-content></mat-sidenav-content>\n</mat-sidenav-container>\n", styles: [":host{--mat-sidenav-container-shape: none}:host{--mat-sidenav-container-width: calc(24px + var(--ymt-spacing-s) + 1px + 16px)}:host{--mat-sidenav-container-divider-color: var(--ymt-outline-variant)}:host{--mat-sidenav-container-background-color: transparent}:host{--mat-sidenav-content-background-color: transparent}:host{--mat-sidenav-container-text-color: var(--ymt-on-surface)}.sidenav-container{height:100%;width:calc(24px + var(--ymt-spacing-s) + 1px + 16px)}.sidenav-container .sidenav .sidenav-content{height:100%;display:flex;flex-flow:column nowrap;justify-content:flex-start;gap:var(--ymt-spacing-2xs)}.sidenav-container .sidenav .sidenav-content .app-logo{height:30px;width:100%;flex:0 0 auto;background-color:var(--ymt-brand);margin-bottom:8px}.sidenav-container .sidenav .sidenav-content .nav-list{flex:1 0 auto;display:flex;flex-flow:column nowrap;align-items:center;gap:var(--ymt-spacing-2xs)}.sidenav-container .sidenav .sidenav-content .actions{flex:0 0 auto;display:flex;flex-flow:column nowrap;align-items:center;margin-bottom:8px;gap:var(--ymt-spacing-2xs)}:host-context([data-screen-size=s][data-screen-orientation=portrait]) .sidenav-container{width:100%;height:calc(24px + var(--ymt-spacing-s) + 1px + 16px)}:host-context([data-screen-size=s][data-screen-orientation=portrait]) .sidenav-container .sidenav{width:100%;border:none;border-top:1px solid var(--ymt-outline-variant)}:host-context([data-screen-size=s][data-screen-orientation=portrait]) .sidenav-container .sidenav .sidenav-content{flex-flow:row nowrap;height:calc(calc(24px + var(--ymt-spacing-s) + 1px + 16px) - 1px);margin-block-start:0;overflow-y:hidden}:host-context([data-screen-size=s][data-screen-orientation=portrait]) .sidenav-container .sidenav .sidenav-content .app-logo{height:100%;width:auto;aspect-ratio:1/1;margin-bottom:0;margin-right:8px}:host-context([data-screen-size=s][data-screen-orientation=portrait]) .sidenav-container .sidenav .sidenav-content .nav-list{flex-flow:row nowrap;height:auto}:host-context([data-screen-size=s][data-screen-orientation=portrait]) .sidenav-container .sidenav .sidenav-content .actions{flex-flow:row nowrap;margin-bottom:0;margin-right:8px}\n"], dependencies: [{ kind: "ngmodule", type: TranslateModule }, { kind: "ngmodule", type: MatToolbarModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "ngmodule", type: MatSidenavModule }, { kind: "component", type: i1$1.MatSidenav, selector: "mat-sidenav", inputs: ["fixedInViewport", "fixedTopGap", "fixedBottomGap"], exportAs: ["matSidenav"] }, { kind: "component", type: i1$1.MatSidenavContainer, selector: "mat-sidenav-container", exportAs: ["matSidenavContainer"] }, { kind: "component", type: i1$1.MatSidenavContent, selector: "mat-sidenav-content" }, { kind: "ngmodule", type: MatListModule }, { kind: "ngmodule", type: MatIconModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
158
+ }
159
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: SidebarNavComponent, decorators: [{
160
+ type: Component,
161
+ args: [{ selector: 'yuv-sidebar-nav', changeDetection: ChangeDetectionStrategy.OnPush, imports: [TranslateModule, MatToolbarModule, MatButtonModule, MatSidenavModule, MatListModule, MatIconModule], template: "<mat-sidenav-container class=\"sidenav-container\">\n <mat-sidenav class=\"sidenav\"\n attr.role=\"navigation\"\n mode=\"side\"\n opened>\n <div class=\"sidenav-content\">\n <div class=\"app-logo\">\n <ng-content select=\".shell-nav__shell-logo-button\"></ng-content>\n </div>\n <div class=\"nav-list\">\n <ng-content select=\".shell-nav__nav-list\"></ng-content>\n </div>\n <div class=\"actions\">\n <ng-content select=\".shell-nav__actions\"></ng-content>\n </div>\n </div>\n </mat-sidenav>\n <mat-sidenav-content></mat-sidenav-content>\n</mat-sidenav-container>\n", styles: [":host{--mat-sidenav-container-shape: none}:host{--mat-sidenav-container-width: calc(24px + var(--ymt-spacing-s) + 1px + 16px)}:host{--mat-sidenav-container-divider-color: var(--ymt-outline-variant)}:host{--mat-sidenav-container-background-color: transparent}:host{--mat-sidenav-content-background-color: transparent}:host{--mat-sidenav-container-text-color: var(--ymt-on-surface)}.sidenav-container{height:100%;width:calc(24px + var(--ymt-spacing-s) + 1px + 16px)}.sidenav-container .sidenav .sidenav-content{height:100%;display:flex;flex-flow:column nowrap;justify-content:flex-start;gap:var(--ymt-spacing-2xs)}.sidenav-container .sidenav .sidenav-content .app-logo{height:30px;width:100%;flex:0 0 auto;background-color:var(--ymt-brand);margin-bottom:8px}.sidenav-container .sidenav .sidenav-content .nav-list{flex:1 0 auto;display:flex;flex-flow:column nowrap;align-items:center;gap:var(--ymt-spacing-2xs)}.sidenav-container .sidenav .sidenav-content .actions{flex:0 0 auto;display:flex;flex-flow:column nowrap;align-items:center;margin-bottom:8px;gap:var(--ymt-spacing-2xs)}:host-context([data-screen-size=s][data-screen-orientation=portrait]) .sidenav-container{width:100%;height:calc(24px + var(--ymt-spacing-s) + 1px + 16px)}:host-context([data-screen-size=s][data-screen-orientation=portrait]) .sidenav-container .sidenav{width:100%;border:none;border-top:1px solid var(--ymt-outline-variant)}:host-context([data-screen-size=s][data-screen-orientation=portrait]) .sidenav-container .sidenav .sidenav-content{flex-flow:row nowrap;height:calc(calc(24px + var(--ymt-spacing-s) + 1px + 16px) - 1px);margin-block-start:0;overflow-y:hidden}:host-context([data-screen-size=s][data-screen-orientation=portrait]) .sidenav-container .sidenav .sidenav-content .app-logo{height:100%;width:auto;aspect-ratio:1/1;margin-bottom:0;margin-right:8px}:host-context([data-screen-size=s][data-screen-orientation=portrait]) .sidenav-container .sidenav .sidenav-content .nav-list{flex-flow:row nowrap;height:auto}:host-context([data-screen-size=s][data-screen-orientation=portrait]) .sidenav-container .sidenav .sidenav-content .actions{flex-flow:row nowrap;margin-bottom:0;margin-right:8px}\n"] }]
162
+ }] });
163
+
213
164
  class ClientShellComponent {
214
165
  #shell;
215
166
  #device;
216
167
  #swPush;
168
+ #matIconRegistryService;
217
169
  onFocusChange(event) {
218
170
  // console.log('focused: ', document.activeElement);
219
171
  }
@@ -234,6 +186,7 @@ class ClientShellComponent {
234
186
  this.commandPalette = inject(CommandPaletteService);
235
187
  this.#device = inject(DeviceService);
236
188
  this.#swPush = inject(SwPush);
189
+ this.#matIconRegistryService = inject(MatIconRegistry);
237
190
  this.APP_LOGOUT_EVENT_KEY = 'yuv.app.event.logout';
238
191
  this._levels = {
239
192
  info: 0,
@@ -241,10 +194,11 @@ class ClientShellComponent {
241
194
  warning: 2,
242
195
  alert: 3
243
196
  };
197
+ this.safeHtmlPipe = inject(SafeHtmlPipe);
244
198
  this.showUploadOverlay = false;
245
199
  this.busy$ = this.#shell.isBusy$;
246
200
  this.showNotifications = signal(false);
247
- this.newNotifications = toSignal(this.shellNotifications.shellNotifications$.pipe(tap((n) => this.showNotifications.set(n.length > 0)), map$1((notifications) => {
201
+ this.newNotifications = toSignal(this.shellNotifications.shellNotifications$.pipe(tap((n) => this.showNotifications.set(n.length > 0)), map((notifications) => {
248
202
  let maxLevel = 'info';
249
203
  const count = notifications.filter((n) => !n.seen).length;
250
204
  notifications.forEach((n) => (maxLevel = n.level && this._levels[n.level] > this._levels[maxLevel] ? n.level : maxLevel));
@@ -260,10 +214,24 @@ class ClientShellComponent {
260
214
  if (cfg) {
261
215
  this.#shell.setShellConfig(cfg);
262
216
  }
263
- }, {
264
- allowSignalWrites: true
265
217
  });
266
- this.shellConfig = this.#shell.shellConfig;
218
+ this.registerIcons = computed(() => {
219
+ const apps = this.apps();
220
+ const config = this.#shell.shellConfig();
221
+ const namespace = config.shellIconNamespace;
222
+ // find svg-icons to register and put them in an array
223
+ const customSvgIconsToRegister = apps
224
+ .filter(({ svgIcon }) => !!svgIcon)
225
+ .map(({ svgIcon, iconName }) => ({ svgIcon, iconName }));
226
+ customSvgIconsToRegister.push(config.appIcon);
227
+ // register svg-icons
228
+ const allRegistered = customSvgIconsToRegister.every((icon) => {
229
+ return namespace && icon && icon.svgIcon && icon.iconName
230
+ ? !!this.#matIconRegistryService.addSvgIconLiteralInNamespace(namespace, icon.iconName, this.safeHtmlPipe.transform(icon.svgIcon))
231
+ : false;
232
+ });
233
+ return allRegistered;
234
+ });
267
235
  this.translate.onLangChange.subscribe(() => this._setCommands(true));
268
236
  // this.router.events.pipe(
269
237
  // // filter(e => e instanceof NavigationStart)
@@ -271,7 +239,7 @@ class ClientShellComponent {
271
239
  // console.log(e);
272
240
  // });
273
241
  this.router.events
274
- .pipe(filter((e) => e instanceof NavigationEnd), map$1((e) => e))
242
+ .pipe(filter((e) => e instanceof NavigationEnd), map((e) => e))
275
243
  .subscribe((e) => this._processRouterNavigationEnd(e));
276
244
  this.#device.init();
277
245
  this.userService.user$.subscribe((user) => {
@@ -287,6 +255,9 @@ class ClientShellComponent {
287
255
  }
288
256
  });
289
257
  }
258
+ getAppTitle(a) {
259
+ return a.title || '';
260
+ }
290
261
  openNotifications() {
291
262
  this.router.navigate([{}]);
292
263
  }
@@ -322,7 +293,6 @@ class ClientShellComponent {
322
293
  }
323
294
  requestSubscription() {
324
295
  if (!this.#swPush.isEnabled) {
325
- console.log('Notification is not enabled.');
326
296
  return;
327
297
  }
328
298
  this.#swPush.messages
@@ -350,7 +320,7 @@ class ClientShellComponent {
350
320
  // get persisted routes to decide where to redirect the logged in user to
351
321
  this.auth
352
322
  .getInitialRequestUri()
353
- .pipe(switchMap((res) => this.auth.resetInitialRequestUri().pipe(map$1((_) => res))))
323
+ .pipe(switchMap((res) => this.auth.resetInitialRequestUri().pipe(map((_) => res))))
354
324
  .subscribe((res) => {
355
325
  const loginRes = res && !ignoreRoutes.includes(res.uri) ? res : null;
356
326
  if (loginRes)
@@ -371,12 +341,12 @@ class ClientShellComponent {
371
341
  this._setCommands();
372
342
  this.requestSubscription();
373
343
  }
374
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ClientShellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
375
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: ClientShellComponent, isStandalone: true, selector: "yuv-client-shell", inputs: { apps: { classPropertyName: "apps", publicName: "apps", isSignal: true, isRequired: true, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "document:focusin": "onFocusChange($event)", "dragover": "onDragOver($event)" } }, ngImport: i0, template: "<yuv-metadata-default-templates></yuv-metadata-default-templates>\n<!-- <yuv-focus-indicator /> -->\n\n<!-- gloabl busy indicator -->\n@if (busy$ | async) {\n <div class=\"yuv-loader-linear\"></div>\n}\n<nav class=\"apps\" [inert]=\"asideOutlet.isActivated\" [attr.aria-label]=\"'yuv.shell.naviagtion.aria.label' | translate\">\n <div class=\"app-icon\">\n <button routerLink=\"/\" routerLinkActive=\"active\" [attr.aria-label]=\"'yuv.shell.logo.aria.label' | translate\">\n <yvc-icon [svg]=\"shellConfig().icons!.appIcon!\"></yvc-icon>\n </button>\n </div>\n <ul class=\"apps\">\n @for (a of apps(); track a.path) {\n <li>\n <button routerLinkActive=\"active\" [routerLink]=\"a.path\" title=\"{{ a.title }}\">\n <yvc-icon [svg]=\"a.icon\" title=\"{{ a.title }}\" *ngIf=\"a.icon\"></yvc-icon>\n <!-- @if (getNotifications(a.id)) {\n <div [ngClass]=\"'badge ' + getNotifications(a.id).maxLevel\">{{ getNotifications(a.id).count }}</div>\n } -->\n </button>\n </li>\n }\n </ul>\n\n <section class=\"actions\">\n @if (showNotifications()) {\n <button [routerLink]=\"[{ outlets: { aside: 'notifications' } }]\" routerLinkActive=\"active\" title=\"{{ 'yuv.shell.notifications.title' | translate }}\">\n <yvc-icon [svg]=\"shellConfig().icons!.notifications!\"></yvc-icon>\n @if (newNotifications(); as note) {\n <div class=\"badge {{ note.maxLevel }}\">{{ note.count }}</div>\n }\n </button>\n }\n <button [routerLink]=\"['/settings']\" routerLinkActive=\"active\" title=\"{{ 'yuv.shell.settings.title' | translate }}\">\n <yvc-icon [svg]=\"shellConfig().icons!.settings!\"></yvc-icon>\n </button>\n <button (click)=\"appLogout()\" title=\"{{ 'yuv.shell.cmd.logout' | translate }}\"><yvc-icon [svg]=\"shellConfig().icons!.logout!\"></yvc-icon></button>\n </section>\n</nav>\n<main id=\"main-shell_content\" aria-label=\"main shell content\" [inert]=\"asideOutlet.isActivated\">\n <router-outlet></router-outlet>\n</main>\n\n<!-- outlet for aside modals like notifications -->\n<div class=\"asideOutlet\" [hidden]=\"!asideOutlet.isActivated\">\n <router-outlet name=\"aside\" #asideOutlet=\"outlet\"></router-outlet>\n</div>\n\n<div id=\"fi\" inert></div>\n", styles: [":host{--client-shell-background-color: var(--main-background);--client-shell-bar-background-color: var(--panel-background);--client-shell-bar-icon-size: 24px;--client-shell-bar-button-padding: calc(var(--app-pane-padding) * .75);--client-shell-bar-width: calc(var(--client-shell-bar-icon-size) + var(--client-shell-bar-button-padding) * 2 + 1px);position:absolute;inset:0;overflow:hidden;display:flex;background-color:var(--client-shell-background-color)}:host .yuv-loader-linear{position:absolute}:host nav{background-color:var(--client-shell-bar-background-color);height:100%;overflow-y:auto;border-inline-end:1px solid var(--panel-divider-color);flex:0 0 auto;display:var(--nav-display, grid);grid-template-rows:auto 1fr auto;grid-template-columns:1fr;grid-template-areas:\"appIcon\" \"apps\" \"actions\"}:host nav button{padding:var(--client-shell-bar-button-padding);border-radius:0;border:0}:host nav button yvc-icon{--icon-size: var(--client-shell-bar-icon-size)}:host nav button.active{color:var(--color-accent)}:host nav .app-icon{grid-area:appIcon}:host nav ul.apps{grid-area:apps;list-style:none;margin:0;padding:0;overflow-y:auto}:host nav ul.apps button{position:relative}:host nav ul.apps button .badge{--badge-color: var(--color-accent);--badge-color-tone: var(--color-accent-tone);position:absolute;background-color:var(--badge-color);color:var(--badge-color-tone);font-size:10px;display:block;padding:1px 2px;border-radius:.25em;line-height:1em;top:calc(var(--app-pane-padding) / 4);right:calc(var(--app-pane-padding) / 4)}:host nav ul.apps button .badge.success{--badge-color: var(--color-success);--badge-color-tone: #fff}:host nav ul.apps button .badge.warning{--badge-color: var(--color-warning);--badge-color-tone: #fff}:host nav ul.apps button .badge.alert{--badge-color: var(--color-error);--badge-color-tone: #fff}:host nav ul.apps li a{display:block;padding:var(--app-pane-padding)}:host nav section.actions{grid-area:actions}:host nav section.actions button{position:relative}:host nav section.actions button .badge{--badge-color: var(--color-accent);--badge-color-tone: var(--color-accent-tone);position:absolute;background-color:var(--badge-color);color:var(--badge-color-tone);font-size:10px;display:block;padding:1px 2px;border-radius:.25em;line-height:1em;top:calc(var(--app-pane-padding) / 4);right:calc(var(--app-pane-padding) / 4)}:host nav section.actions button .badge.success{--badge-color: var(--color-success);--badge-color-tone: #fff}:host nav section.actions button .badge.warning{--badge-color: var(--color-warning);--badge-color-tone: #fff}:host nav section.actions button .badge.alert{--badge-color: var(--color-error);--badge-color-tone: #fff}:host main{flex:1;color:var(--text-color-body)}:host .asideOutlet{position:absolute;inset:0;padding-inline-start:var(--client-shell-bar-width)}:host-context([data-screen-size=s][data-screen-orientation=portrait]){flex-flow:column-reverse}:host-context([data-screen-size=s][data-screen-orientation=portrait]) nav{height:auto;grid-template-rows:1fr;grid-template-columns:auto 1fr auto;grid-template-areas:\"appIcon apps actions\";border:0;border-block-start:1px solid var(--panel-divider-color)}:host-context([data-screen-size=s][data-screen-orientation=portrait]) nav .app-icon{display:none}:host-context([data-screen-size=s][data-screen-orientation=portrait]) nav ul.apps,:host-context([data-screen-size=s][data-screen-orientation=portrait]) nav section.actions{display:flex}:host-context([data-screen-size=s][data-screen-orientation=portrait]) main{overflow:hidden}:host-context([data-screen-size=s][data-screen-orientation=portrait]) .asideOutlet{padding-inline-start:0}\n"], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i2$2.RouterOutlet, selector: "router-outlet", inputs: ["name"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "directive", type: i2$2.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i2$2.RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "ngmodule", type: YvcIconModule }, { kind: "component", type: i2$1.Icon, selector: "yvc-icon", inputs: ["label", "svg", "svgSrc"] }, { kind: "component", type: MetadataDefaultTemplatesComponent, selector: "yuv-metadata-default-templates" }] }); }
344
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: ClientShellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
345
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.1", type: ClientShellComponent, isStandalone: true, selector: "yuv-client-shell", inputs: { apps: { classPropertyName: "apps", publicName: "apps", isSignal: true, isRequired: true, transformFunction: null }, config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "document:focusin": "onFocusChange($event)", "dragover": "onDragOver($event)" } }, providers: [SafeHtmlPipe], ngImport: i0, template: "<yuv-metadata-default-templates></yuv-metadata-default-templates>\n\n<!-- gloabl busy indicator -->\n@if (busy$ | async) {\n <mat-progress-bar\n mode=\"indeterminate\"\n class=\"progress-bar\"\n ></mat-progress-bar>\n}\n\n@let iconsRegistered = registerIcons();\n\n<yuv-sidebar-nav class=\"shell-nav\">\n <button class=\"shell-nav__shell-logo-button\" routerLink=\"/\" routerLinkActive=\"active\" [attr.aria-label]=\"'yuv.shell.logo.aria.label' | translate\">\n @if (iconsRegistered) {\n <mat-icon svgIcon=\"shellIcons:app_logo\"></mat-icon>\n }\n </button>\n <ul class=\"shell-nav__nav-list\">\n @for (a of apps(); track a.path) {\n <li class=\"shell-nav__nav-list-item\">\n <button class=\"shell-nav__nav-list-item-button\" mat-icon-button routerLinkActive=\"active\" [routerLink]=\"a.path\" \n matTooltipPosition=\"after\"\n [matTooltip]=\"getAppTitle(a)\">\n @if (a.svgIcon) {\n @if (iconsRegistered) {\n <mat-icon [svgIcon]=\"'shellIcons:' + a.iconName\"></mat-icon>\n }\n } @else {\n <mat-icon>{{ a.iconName }}</mat-icon>\n }\n <!--@if (getNotifications(a.id)) {\n <div [ngClass]=\"'badge ' + getNotifications(a.id).maxLevel\">{{ getNotifications(a.id).count }}</div>\n }-->\n </button>\n </li>\n }\n </ul>\n <section class=\"shell-nav__actions\">\n @if (showNotifications()) {\n <button\n class=\"shell-nav__actions-button\"\n mat-icon-button\n [routerLink]=\"[{ outlets: { aside: 'notifications' } }]\"\n routerLinkActive=\"active\"\n matTooltipPosition=\"after\"\n [matTooltip]=\"'yuv.shell.notifications.title' | translate\"\n >\n <mat-icon>notifications</mat-icon>\n @if (newNotifications(); as note) {\n <div class=\"badge {{ note.maxLevel }}\">{{ note.count }}</div>\n }\n </button>\n }\n <button\n class=\"shell-nav__actions-button\"\n mat-icon-button\n [routerLink]=\"['/settings']\"\n routerLinkActive=\"active\"\n [matTooltip]=\"'yuv.shell.settings.title' | translate\"\n >\n <mat-icon>settings</mat-icon>\n </button>\n <button class=\"shell-nav__actions-button\" mat-icon-button (click)=\"appLogout()\" [matTooltip]=\"'yuv.shell.cmd.logout' | translate\">\n <mat-icon>power_settings_new</mat-icon>\n </button>\n </section>\n</yuv-sidebar-nav>\n\n<main id=\"main-shell_content\" aria-label=\"main shell content\" [inert]=\"asideOutlet.isActivated\">\n <router-outlet></router-outlet>\n</main>\n\n<!-- outlet for aside modals like notifications -->\n<div class=\"asideOutlet\" [hidden]=\"!asideOutlet.isActivated\">\n <router-outlet name=\"aside\" #asideOutlet=\"outlet\"></router-outlet>\n</div>\n\n<div id=\"fi\" inert></div>\n", styles: [":host{--mat-sidenav-container-shape: none}:host{--mat-sidenav-container-width: calc(24px + var(--ymt-spacing-s) + 1px + 16px)}:host{--mat-sidenav-container-divider-color: var(--ymt-outline-variant)}:host{--mat-sidenav-container-background-color: transparent}:host{--mat-sidenav-content-background-color: transparent}:host{--mat-sidenav-container-text-color: var(--ymt-on-surface)}.sidenav-container{height:100%;width:calc(24px + var(--ymt-spacing-s) + 1px + 16px)}.sidenav-container .sidenav .sidenav-content{height:100%;display:flex;flex-flow:column nowrap;justify-content:flex-start;gap:var(--ymt-spacing-2xs)}.sidenav-container .sidenav .sidenav-content .app-logo{height:30px;width:100%;flex:0 0 auto;background-color:var(--ymt-brand);margin-bottom:8px}.sidenav-container .sidenav .sidenav-content .nav-list{flex:1 0 auto;display:flex;flex-flow:column nowrap;align-items:center;gap:var(--ymt-spacing-2xs)}.sidenav-container .sidenav .sidenav-content .actions{flex:0 0 auto;display:flex;flex-flow:column nowrap;align-items:center;margin-bottom:8px;gap:var(--ymt-spacing-2xs)}:host-context([data-screen-size=s][data-screen-orientation=portrait]) .sidenav-container{width:100%;height:calc(24px + var(--ymt-spacing-s) + 1px + 16px)}:host-context([data-screen-size=s][data-screen-orientation=portrait]) .sidenav-container .sidenav{width:100%;border:none;border-top:1px solid var(--ymt-outline-variant)}:host-context([data-screen-size=s][data-screen-orientation=portrait]) .sidenav-container .sidenav .sidenav-content{flex-flow:row nowrap;height:calc(calc(24px + var(--ymt-spacing-s) + 1px + 16px) - 1px);margin-block-start:0;overflow-y:hidden}:host-context([data-screen-size=s][data-screen-orientation=portrait]) .sidenav-container .sidenav .sidenav-content .app-logo{height:100%;width:auto;aspect-ratio:1/1;margin-bottom:0;margin-right:8px}:host-context([data-screen-size=s][data-screen-orientation=portrait]) .sidenav-container .sidenav .sidenav-content .nav-list{flex-flow:row nowrap;height:auto}:host-context([data-screen-size=s][data-screen-orientation=portrait]) .sidenav-container .sidenav .sidenav-content .actions{flex-flow:row nowrap;margin-bottom:0;margin-right:8px}:host{position:absolute;inset:0;overflow:hidden;display:flex;background-color:var(--ymt-surface-frame)}:host .progress-bar{position:absolute}:host .shell-nav{flex:0 0 auto}:host .shell-nav__nav-list{display:contents;list-style:none}:host .shell-nav__nav-list-item{display:inline-block}:host .shell-nav__shell-logo-button{-webkit-user-select:none;user-select:none;display:block;position:relative;box-sizing:border-box;border:none;outline:none;cursor:pointer;height:100%;width:100%;-webkit-tap-highlight-color:rgba(0,0,0,0);padding:0;padding-block:0;background:none}:host .shell-nav__shell-logo-button mat-icon{width:100%;height:100%}:host .shell-nav__actions{display:contents}:host main{flex:1;color:var(--ymt-text-color)}:host .asideOutlet{position:absolute;inset:0;padding-inline-start:calc(24px + var(--ymt-spacing-s) + 1px + 16px)}:host-context([data-screen-size=s][data-screen-orientation=portrait]){flex-flow:column-reverse}:host-context([data-screen-size=s][data-screen-orientation=portrait]) main{overflow:hidden}:host-context([data-screen-size=s][data-screen-orientation=portrait]) .asideOutlet{padding-inline-start:0}\n"], dependencies: [{ kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2$1.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i2$2.RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "directive", type: i2$2.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i2$2.RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "ngmodule", type: YuvMetadataFormDefaultsModule }, { kind: "component", type: i3$1.MetadataDefaultTemplatesComponent, selector: "yuv-metadata-default-templates" }, { kind: "component", type: SidebarNavComponent, selector: "yuv-sidebar-nav" }, { kind: "component", type: MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] }); }
376
346
  }
377
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ClientShellComponent, decorators: [{
347
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: ClientShellComponent, decorators: [{
378
348
  type: Component,
379
- args: [{ selector: 'yuv-client-shell', standalone: true, imports: [NgIf, AsyncPipe, TranslateModule, RouterModule, YvcIconModule, MetadataDefaultTemplatesComponent], template: "<yuv-metadata-default-templates></yuv-metadata-default-templates>\n<!-- <yuv-focus-indicator /> -->\n\n<!-- gloabl busy indicator -->\n@if (busy$ | async) {\n <div class=\"yuv-loader-linear\"></div>\n}\n<nav class=\"apps\" [inert]=\"asideOutlet.isActivated\" [attr.aria-label]=\"'yuv.shell.naviagtion.aria.label' | translate\">\n <div class=\"app-icon\">\n <button routerLink=\"/\" routerLinkActive=\"active\" [attr.aria-label]=\"'yuv.shell.logo.aria.label' | translate\">\n <yvc-icon [svg]=\"shellConfig().icons!.appIcon!\"></yvc-icon>\n </button>\n </div>\n <ul class=\"apps\">\n @for (a of apps(); track a.path) {\n <li>\n <button routerLinkActive=\"active\" [routerLink]=\"a.path\" title=\"{{ a.title }}\">\n <yvc-icon [svg]=\"a.icon\" title=\"{{ a.title }}\" *ngIf=\"a.icon\"></yvc-icon>\n <!-- @if (getNotifications(a.id)) {\n <div [ngClass]=\"'badge ' + getNotifications(a.id).maxLevel\">{{ getNotifications(a.id).count }}</div>\n } -->\n </button>\n </li>\n }\n </ul>\n\n <section class=\"actions\">\n @if (showNotifications()) {\n <button [routerLink]=\"[{ outlets: { aside: 'notifications' } }]\" routerLinkActive=\"active\" title=\"{{ 'yuv.shell.notifications.title' | translate }}\">\n <yvc-icon [svg]=\"shellConfig().icons!.notifications!\"></yvc-icon>\n @if (newNotifications(); as note) {\n <div class=\"badge {{ note.maxLevel }}\">{{ note.count }}</div>\n }\n </button>\n }\n <button [routerLink]=\"['/settings']\" routerLinkActive=\"active\" title=\"{{ 'yuv.shell.settings.title' | translate }}\">\n <yvc-icon [svg]=\"shellConfig().icons!.settings!\"></yvc-icon>\n </button>\n <button (click)=\"appLogout()\" title=\"{{ 'yuv.shell.cmd.logout' | translate }}\"><yvc-icon [svg]=\"shellConfig().icons!.logout!\"></yvc-icon></button>\n </section>\n</nav>\n<main id=\"main-shell_content\" aria-label=\"main shell content\" [inert]=\"asideOutlet.isActivated\">\n <router-outlet></router-outlet>\n</main>\n\n<!-- outlet for aside modals like notifications -->\n<div class=\"asideOutlet\" [hidden]=\"!asideOutlet.isActivated\">\n <router-outlet name=\"aside\" #asideOutlet=\"outlet\"></router-outlet>\n</div>\n\n<div id=\"fi\" inert></div>\n", styles: [":host{--client-shell-background-color: var(--main-background);--client-shell-bar-background-color: var(--panel-background);--client-shell-bar-icon-size: 24px;--client-shell-bar-button-padding: calc(var(--app-pane-padding) * .75);--client-shell-bar-width: calc(var(--client-shell-bar-icon-size) + var(--client-shell-bar-button-padding) * 2 + 1px);position:absolute;inset:0;overflow:hidden;display:flex;background-color:var(--client-shell-background-color)}:host .yuv-loader-linear{position:absolute}:host nav{background-color:var(--client-shell-bar-background-color);height:100%;overflow-y:auto;border-inline-end:1px solid var(--panel-divider-color);flex:0 0 auto;display:var(--nav-display, grid);grid-template-rows:auto 1fr auto;grid-template-columns:1fr;grid-template-areas:\"appIcon\" \"apps\" \"actions\"}:host nav button{padding:var(--client-shell-bar-button-padding);border-radius:0;border:0}:host nav button yvc-icon{--icon-size: var(--client-shell-bar-icon-size)}:host nav button.active{color:var(--color-accent)}:host nav .app-icon{grid-area:appIcon}:host nav ul.apps{grid-area:apps;list-style:none;margin:0;padding:0;overflow-y:auto}:host nav ul.apps button{position:relative}:host nav ul.apps button .badge{--badge-color: var(--color-accent);--badge-color-tone: var(--color-accent-tone);position:absolute;background-color:var(--badge-color);color:var(--badge-color-tone);font-size:10px;display:block;padding:1px 2px;border-radius:.25em;line-height:1em;top:calc(var(--app-pane-padding) / 4);right:calc(var(--app-pane-padding) / 4)}:host nav ul.apps button .badge.success{--badge-color: var(--color-success);--badge-color-tone: #fff}:host nav ul.apps button .badge.warning{--badge-color: var(--color-warning);--badge-color-tone: #fff}:host nav ul.apps button .badge.alert{--badge-color: var(--color-error);--badge-color-tone: #fff}:host nav ul.apps li a{display:block;padding:var(--app-pane-padding)}:host nav section.actions{grid-area:actions}:host nav section.actions button{position:relative}:host nav section.actions button .badge{--badge-color: var(--color-accent);--badge-color-tone: var(--color-accent-tone);position:absolute;background-color:var(--badge-color);color:var(--badge-color-tone);font-size:10px;display:block;padding:1px 2px;border-radius:.25em;line-height:1em;top:calc(var(--app-pane-padding) / 4);right:calc(var(--app-pane-padding) / 4)}:host nav section.actions button .badge.success{--badge-color: var(--color-success);--badge-color-tone: #fff}:host nav section.actions button .badge.warning{--badge-color: var(--color-warning);--badge-color-tone: #fff}:host nav section.actions button .badge.alert{--badge-color: var(--color-error);--badge-color-tone: #fff}:host main{flex:1;color:var(--text-color-body)}:host .asideOutlet{position:absolute;inset:0;padding-inline-start:var(--client-shell-bar-width)}:host-context([data-screen-size=s][data-screen-orientation=portrait]){flex-flow:column-reverse}:host-context([data-screen-size=s][data-screen-orientation=portrait]) nav{height:auto;grid-template-rows:1fr;grid-template-columns:auto 1fr auto;grid-template-areas:\"appIcon apps actions\";border:0;border-block-start:1px solid var(--panel-divider-color)}:host-context([data-screen-size=s][data-screen-orientation=portrait]) nav .app-icon{display:none}:host-context([data-screen-size=s][data-screen-orientation=portrait]) nav ul.apps,:host-context([data-screen-size=s][data-screen-orientation=portrait]) nav section.actions{display:flex}:host-context([data-screen-size=s][data-screen-orientation=portrait]) main{overflow:hidden}:host-context([data-screen-size=s][data-screen-orientation=portrait]) .asideOutlet{padding-inline-start:0}\n"] }]
349
+ args: [{ selector: 'yuv-client-shell', standalone: true, imports: [AsyncPipe, TranslateModule, RouterModule, YuvMetadataFormDefaultsModule, SidebarNavComponent, MatIconButton, MatIcon, MatProgressBar, MatTooltipModule], providers: [SafeHtmlPipe], template: "<yuv-metadata-default-templates></yuv-metadata-default-templates>\n\n<!-- gloabl busy indicator -->\n@if (busy$ | async) {\n <mat-progress-bar\n mode=\"indeterminate\"\n class=\"progress-bar\"\n ></mat-progress-bar>\n}\n\n@let iconsRegistered = registerIcons();\n\n<yuv-sidebar-nav class=\"shell-nav\">\n <button class=\"shell-nav__shell-logo-button\" routerLink=\"/\" routerLinkActive=\"active\" [attr.aria-label]=\"'yuv.shell.logo.aria.label' | translate\">\n @if (iconsRegistered) {\n <mat-icon svgIcon=\"shellIcons:app_logo\"></mat-icon>\n }\n </button>\n <ul class=\"shell-nav__nav-list\">\n @for (a of apps(); track a.path) {\n <li class=\"shell-nav__nav-list-item\">\n <button class=\"shell-nav__nav-list-item-button\" mat-icon-button routerLinkActive=\"active\" [routerLink]=\"a.path\" \n matTooltipPosition=\"after\"\n [matTooltip]=\"getAppTitle(a)\">\n @if (a.svgIcon) {\n @if (iconsRegistered) {\n <mat-icon [svgIcon]=\"'shellIcons:' + a.iconName\"></mat-icon>\n }\n } @else {\n <mat-icon>{{ a.iconName }}</mat-icon>\n }\n <!--@if (getNotifications(a.id)) {\n <div [ngClass]=\"'badge ' + getNotifications(a.id).maxLevel\">{{ getNotifications(a.id).count }}</div>\n }-->\n </button>\n </li>\n }\n </ul>\n <section class=\"shell-nav__actions\">\n @if (showNotifications()) {\n <button\n class=\"shell-nav__actions-button\"\n mat-icon-button\n [routerLink]=\"[{ outlets: { aside: 'notifications' } }]\"\n routerLinkActive=\"active\"\n matTooltipPosition=\"after\"\n [matTooltip]=\"'yuv.shell.notifications.title' | translate\"\n >\n <mat-icon>notifications</mat-icon>\n @if (newNotifications(); as note) {\n <div class=\"badge {{ note.maxLevel }}\">{{ note.count }}</div>\n }\n </button>\n }\n <button\n class=\"shell-nav__actions-button\"\n mat-icon-button\n [routerLink]=\"['/settings']\"\n routerLinkActive=\"active\"\n [matTooltip]=\"'yuv.shell.settings.title' | translate\"\n >\n <mat-icon>settings</mat-icon>\n </button>\n <button class=\"shell-nav__actions-button\" mat-icon-button (click)=\"appLogout()\" [matTooltip]=\"'yuv.shell.cmd.logout' | translate\">\n <mat-icon>power_settings_new</mat-icon>\n </button>\n </section>\n</yuv-sidebar-nav>\n\n<main id=\"main-shell_content\" aria-label=\"main shell content\" [inert]=\"asideOutlet.isActivated\">\n <router-outlet></router-outlet>\n</main>\n\n<!-- outlet for aside modals like notifications -->\n<div class=\"asideOutlet\" [hidden]=\"!asideOutlet.isActivated\">\n <router-outlet name=\"aside\" #asideOutlet=\"outlet\"></router-outlet>\n</div>\n\n<div id=\"fi\" inert></div>\n", styles: [":host{--mat-sidenav-container-shape: none}:host{--mat-sidenav-container-width: calc(24px + var(--ymt-spacing-s) + 1px + 16px)}:host{--mat-sidenav-container-divider-color: var(--ymt-outline-variant)}:host{--mat-sidenav-container-background-color: transparent}:host{--mat-sidenav-content-background-color: transparent}:host{--mat-sidenav-container-text-color: var(--ymt-on-surface)}.sidenav-container{height:100%;width:calc(24px + var(--ymt-spacing-s) + 1px + 16px)}.sidenav-container .sidenav .sidenav-content{height:100%;display:flex;flex-flow:column nowrap;justify-content:flex-start;gap:var(--ymt-spacing-2xs)}.sidenav-container .sidenav .sidenav-content .app-logo{height:30px;width:100%;flex:0 0 auto;background-color:var(--ymt-brand);margin-bottom:8px}.sidenav-container .sidenav .sidenav-content .nav-list{flex:1 0 auto;display:flex;flex-flow:column nowrap;align-items:center;gap:var(--ymt-spacing-2xs)}.sidenav-container .sidenav .sidenav-content .actions{flex:0 0 auto;display:flex;flex-flow:column nowrap;align-items:center;margin-bottom:8px;gap:var(--ymt-spacing-2xs)}:host-context([data-screen-size=s][data-screen-orientation=portrait]) .sidenav-container{width:100%;height:calc(24px + var(--ymt-spacing-s) + 1px + 16px)}:host-context([data-screen-size=s][data-screen-orientation=portrait]) .sidenav-container .sidenav{width:100%;border:none;border-top:1px solid var(--ymt-outline-variant)}:host-context([data-screen-size=s][data-screen-orientation=portrait]) .sidenav-container .sidenav .sidenav-content{flex-flow:row nowrap;height:calc(calc(24px + var(--ymt-spacing-s) + 1px + 16px) - 1px);margin-block-start:0;overflow-y:hidden}:host-context([data-screen-size=s][data-screen-orientation=portrait]) .sidenav-container .sidenav .sidenav-content .app-logo{height:100%;width:auto;aspect-ratio:1/1;margin-bottom:0;margin-right:8px}:host-context([data-screen-size=s][data-screen-orientation=portrait]) .sidenav-container .sidenav .sidenav-content .nav-list{flex-flow:row nowrap;height:auto}:host-context([data-screen-size=s][data-screen-orientation=portrait]) .sidenav-container .sidenav .sidenav-content .actions{flex-flow:row nowrap;margin-bottom:0;margin-right:8px}:host{position:absolute;inset:0;overflow:hidden;display:flex;background-color:var(--ymt-surface-frame)}:host .progress-bar{position:absolute}:host .shell-nav{flex:0 0 auto}:host .shell-nav__nav-list{display:contents;list-style:none}:host .shell-nav__nav-list-item{display:inline-block}:host .shell-nav__shell-logo-button{-webkit-user-select:none;user-select:none;display:block;position:relative;box-sizing:border-box;border:none;outline:none;cursor:pointer;height:100%;width:100%;-webkit-tap-highlight-color:rgba(0,0,0,0);padding:0;padding-block:0;background:none}:host .shell-nav__shell-logo-button mat-icon{width:100%;height:100%}:host .shell-nav__actions{display:contents}:host main{flex:1;color:var(--ymt-text-color)}:host .asideOutlet{position:absolute;inset:0;padding-inline-start:calc(24px + var(--ymt-spacing-s) + 1px + 16px)}:host-context([data-screen-size=s][data-screen-orientation=portrait]){flex-flow:column-reverse}:host-context([data-screen-size=s][data-screen-orientation=portrait]) main{overflow:hidden}:host-context([data-screen-size=s][data-screen-orientation=portrait]) .asideOutlet{padding-inline-start:0}\n"] }]
380
350
  }], ctorParameters: () => [], propDecorators: { onFocusChange: [{
381
351
  type: HostListener,
382
352
  args: ['document:focusin', ['$event']]
@@ -390,38 +360,51 @@ class AppLogoComponent {
390
360
  this.icon = input();
391
361
  this.label = input.required();
392
362
  }
393
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AppLogoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
394
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: AppLogoComponent, isStandalone: true, selector: "yuv-app-logo", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "@let ico = icon();\n@if(ico){\n<yvc-icon [svg]=\"ico\"></yvc-icon>\n}<span class=\"label\">{{label()}}</span>", styles: [":host{--band-color: var(--text-color-body);--band-height: var(--client-shell-bar-icon-size);--band-icon-size: 32px;--text-color: var(--main-background);--icon-color: var(--text-color);--icon-background-color: transparent;display:flex;align-items:center;padding:0 calc(var(--app-pane-padding) / 1) 0 calc(var(--app-pane-padding) / 2);height:calc(var(--client-shell-bar-icon-size));font-size:var(--font-caption);line-height:1em;cursor:pointer;background-color:var(--band-color);color:var(--text-color)}:host yvc-icon{--icon-size: var(--band-icon-size);grid-column:2;grid-row:1;border-radius:4px;margin-inline-end:calc(var(--app-pane-padding) / 2);opacity:.5;color:var(--icon-color);background-color:var(--icon-background-color)}:host .label{line-height:1em}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: YvcIconModule }, { kind: "component", type: i2$1.Icon, selector: "yvc-icon", inputs: ["label", "svg", "svgSrc"] }] }); }
363
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: AppLogoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
364
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.1", type: AppLogoComponent, isStandalone: true, selector: "yuv-app-logo", inputs: { icon: { classPropertyName: "icon", publicName: "icon", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<span class=\"label\">{{label()}}</span>\n", styles: [":host{--text-color: var(--ymt-on-brand);--icon-color: var(--text-color);--surface-color: var(--ymt-brand);--band-icon-size: 32px;--icon-background-color: transparent;padding:var(--ymt-spacing-xs) calc(var(--ymt-spacing-m)) var(--ymt-spacing-xs) calc(var(--ymt-spacing-m));font:var(--ymt-font-title-small);line-height:1;background-color:var(--surface-color);color:var(--text-color)}:host .label{line-height:1em}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }] }); }
395
365
  }
396
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AppLogoComponent, decorators: [{
366
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: AppLogoComponent, decorators: [{
397
367
  type: Component,
398
- args: [{ selector: 'yuv-app-logo', standalone: true, imports: [CommonModule, YvcIconModule], template: "@let ico = icon();\n@if(ico){\n<yvc-icon [svg]=\"ico\"></yvc-icon>\n}<span class=\"label\">{{label()}}</span>", styles: [":host{--band-color: var(--text-color-body);--band-height: var(--client-shell-bar-icon-size);--band-icon-size: 32px;--text-color: var(--main-background);--icon-color: var(--text-color);--icon-background-color: transparent;display:flex;align-items:center;padding:0 calc(var(--app-pane-padding) / 1) 0 calc(var(--app-pane-padding) / 2);height:calc(var(--client-shell-bar-icon-size));font-size:var(--font-caption);line-height:1em;cursor:pointer;background-color:var(--band-color);color:var(--text-color)}:host yvc-icon{--icon-size: var(--band-icon-size);grid-column:2;grid-row:1;border-radius:4px;margin-inline-end:calc(var(--app-pane-padding) / 2);opacity:.5;color:var(--icon-color);background-color:var(--icon-background-color)}:host .label{line-height:1em}\n"] }]
368
+ args: [{ selector: 'yuv-app-logo', standalone: true, imports: [CommonModule], template: "<span class=\"label\">{{label()}}</span>\n", styles: [":host{--text-color: var(--ymt-on-brand);--icon-color: var(--text-color);--surface-color: var(--ymt-brand);--band-icon-size: 32px;--icon-background-color: transparent;padding:var(--ymt-spacing-xs) calc(var(--ymt-spacing-m)) var(--ymt-spacing-xs) calc(var(--ymt-spacing-m));font:var(--ymt-font-title-small);line-height:1;background-color:var(--surface-color);color:var(--text-color)}:host .label{line-height:1em}\n"] }]
399
369
  }] });
400
370
 
401
371
  class ManageFlavorsComponent {
402
372
  constructor() {
403
- this.#overlayRef = inject(YvcOverlayRef);
404
373
  this.#shell = inject(ShellService);
405
374
  this.#dmsService = inject(DmsService);
406
- this.item = this.#overlayRef.data;
375
+ this.#dialogData = inject(MAT_DIALOG_DATA);
376
+ this.#dialogRef = inject((MatDialogRef));
377
+ this.item = this.#dialogData;
378
+ this.#confirm = inject(ConfirmService);
379
+ this.translate = inject(TranslateService);
407
380
  this.busy = signal(false);
408
381
  this.appliedFlavors = [];
409
382
  this.applicableFlavors = [];
410
383
  }
411
- #overlayRef;
412
384
  #shell;
413
385
  #dmsService;
386
+ #dialogData;
387
+ #dialogRef;
388
+ #confirm;
414
389
  applyFlavor(flavor) {
415
390
  this.busy.set(true);
416
391
  this.#shell.triggerApplyObjectFlavor(this.item, flavor).subscribe(() => {
417
- this.#overlayRef.close();
392
+ this.#dialogRef.close();
418
393
  this.busy.set(false);
419
394
  });
420
395
  }
421
396
  removeFlavor(flavor) {
422
397
  this.busy.set(true);
423
- this.#shell.removeObjectFlavor(this.item, flavor).subscribe(() => {
424
- this.#overlayRef.close();
398
+ this.#confirm
399
+ .confirm({
400
+ message: this.translate.instant('yuv.object-flavor.flavor.remove.confirm.message', {
401
+ flavor: this.#shell.getFlavorLabel(flavor.id)
402
+ })
403
+ })
404
+ .pipe(switchMap$1((confirmed) => (confirmed ? this.#shell.removeObjectFlavor(this.item, flavor) : of(undefined))))
405
+ .subscribe((res) => {
406
+ if (res !== undefined)
407
+ this.#dialogRef.close();
425
408
  this.busy.set(false);
426
409
  });
427
410
  }
@@ -442,25 +425,35 @@ class ManageFlavorsComponent {
442
425
  this.applicableFlavors = res.applicable;
443
426
  }
444
427
  cancel() {
445
- if (this.#overlayRef)
446
- this.#overlayRef.close();
428
+ this.#dialogRef.close();
447
429
  }
448
430
  ngOnInit() {
449
431
  this.#refreshDmsObject();
450
432
  }
451
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ManageFlavorsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
452
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: ManageFlavorsComponent, isStandalone: true, selector: "yuv-manage-flavors", ngImport: i0, template: "<header>\n <h2>{{ 'yuv.shell.action.manage-flavors.title' | translate }}</h2>\n <p>{{ 'yuv.shell.action.manage-flavors.text' | translate }}</p>\n</header>\n<main [yuvBusyOverlay]=\"busy()\">\n @if (appliedFlavors.length) {\n <h3>{{ 'yuv.shell.action.manage-flavors.applied.headline' | translate }}</h3>\n <ul>\n @for (f of appliedFlavors; track $index) {\n <li>\n <yuv-flavor-chip [flavor]=\"f\" yuvListItem></yuv-flavor-chip>\n <button class=\"secondary\" (click)=\"removeFlavor(f)\">{{ 'yuv.shell.action.manage-flavors.applicable.button.remove' | translate }}</button>\n </li>\n }\n </ul>\n }\n @if (applicableFlavors.length) {\n <h3>{{ 'yuv.shell.action.manage-flavors.applicable.headline' | translate }}</h3>\n <ul>\n @for (f of applicableFlavors; track $index) {\n <li>\n <yuv-flavor-chip [flavor]=\"f\" yuvListItem></yuv-flavor-chip>\n <button class=\"secondary\" (click)=\"applyFlavor(f)\">{{ 'yuv.shell.action.manage-flavors.applied.button.apply' | translate }}</button>\n </li>\n }\n </ul>\n }\n</main>\n<footer>\n <button class=\"secondary\" (click)=\"cancel()\">{{ 'yuv.shell.action.manage-flavors.button.cancel' | translate }}</button>\n</footer>\n", styles: [":host{display:flex;flex-flow:column;padding:var(--app-pane-padding)}:host header{flex:0 0 auto}:host header h2{padding:0;font-weight:400;font-size:var(--font-headline);margin:0 0 var(--app-pane-padding) 0}:host header p{max-width:42ch;line-height:1.3em}:host main{flex:1;overflow-y:auto}:host main yuv-flavor-chip{border-color:transparent;flex:1}:host main ul{padding:0;margin:0;list-style-type:none}:host main li{display:flex;gap:calc(var(--app-pane-padding) / 2);align-items:center;border:1px solid var(--panel-divider-color);margin-block-end:2px;padding:calc(var(--app-pane-padding) / 4)}:host main li button{padding:calc(var(--app-pane-padding) / 4) calc(var(--app-pane-padding) / 2)}:host footer{flex:0 0 auto;margin-block-start:var(--app-pane-padding)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: BusyOverlayDirective, selector: "[yuvBusyOverlay]", inputs: ["yuvBusyOverlay"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }, { kind: "directive", type: ListItemDirective, selector: "[yuvListItem]", inputs: ["disabled", "active", "selected"] }, { kind: "component", type: FlavorChipComponent, selector: "yuv-flavor-chip", inputs: ["flavor", "enableRemove", "enableDescription"], outputs: ["flavorRemove"] }] }); }
433
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: ManageFlavorsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
434
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.1", type: ManageFlavorsComponent, isStandalone: true, selector: "yuv-manage-flavors", ngImport: i0, template: "<yuv-dialog [headertitel]=\"'yuv.shell.action.manage-flavors.title' | translate\">\n <main [yuvBusyOverlay]=\"busy()\">\n <p>{{ 'yuv.shell.action.manage-flavors.text' | translate }}</p>\n @if (appliedFlavors.length) {\n <h3>{{ 'yuv.shell.action.manage-flavors.applied.headline' | translate }}</h3>\n <ul>\n @for (f of appliedFlavors; track $index) {\n <li>\n <yuv-flavor-chip [flavor]=\"f\" yuvListItem></yuv-flavor-chip>\n <button mat-icon-button [matTooltip]=\"'yuv.shell.action.manage-flavors.applicable.button.remove.tooltip' | translate\" (click)=\"removeFlavor(f)\">\n <mat-icon>delete_forever</mat-icon>\n </button>\n </li>\n }\n </ul>\n }\n @if (applicableFlavors.length) {\n <h3>{{ 'yuv.shell.action.manage-flavors.applicable.headline' | translate }}</h3>\n <ul>\n @for (f of applicableFlavors; track $index) {\n <li>\n <yuv-flavor-chip [flavor]=\"f\" yuvListItem></yuv-flavor-chip>\n <button mat-icon-button [matTooltip]=\"'yuv.shell.action.manage-flavors.applied.button.apply.tooltip' | translate\" (click)=\"applyFlavor(f)\">\n <mat-icon>add</mat-icon>\n </button>\n </li>\n }\n </ul>\n }\n </main>\n <footer>\n <button ymtButton=\"secondary\" (click)=\"cancel()\">{{ 'yuv.shell.action.manage-flavors.button.cancel' | translate }}</button>\n </footer>\n</yuv-dialog>\n", styles: [":host main{display:flex;flex-flow:column;padding:var(--ymt-spacing-m);flex:1;overflow-y:auto}:host main yuv-flavor-chip{border-color:transparent;flex:1}:host main ul{padding:0;margin:0;list-style-type:none}:host main li{display:flex;gap:var(--ymt-spacing-xs);align-items:center;border:1px solid var(--ymt-outline-variant);margin-block-end:2px;padding:var(--ymt-spacing-2xs)}:host footer{flex:0 0 auto;margin-block-start:var(--ymt-spacing-m)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: BusyOverlayDirective, selector: "[yuvBusyOverlay]", inputs: ["yuvBusyOverlay"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i4$1.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i2$1.TranslatePipe, name: "translate" }, { kind: "directive", type: ListItemDirective, selector: "[yuvListItem]", inputs: ["disabled", "active", "selected"] }, { kind: "component", type: FlavorChipComponent, selector: "yuv-flavor-chip", inputs: ["flavor", "enableRemove", "enableDescription"], outputs: ["flavorRemove"] }, { kind: "component", type: DialogComponent, selector: "yuv-dialog", inputs: ["headertitel"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "directive", type: YuvButtonDirective, selector: "button[ymtButton], a[ymtButton]", inputs: ["ymtButton", "disabled", "aria-disabled", "disableRipple", "disabledInteractive"] }] }); }
453
435
  }
454
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: ManageFlavorsComponent, decorators: [{
436
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.1", ngImport: i0, type: ManageFlavorsComponent, decorators: [{
455
437
  type: Component,
456
- args: [{ selector: 'yuv-manage-flavors', standalone: true, imports: [CommonModule, ListComponent, BusyOverlayDirective, TranslateModule, ListItemDirective, FlavorChipComponent], template: "<header>\n <h2>{{ 'yuv.shell.action.manage-flavors.title' | translate }}</h2>\n <p>{{ 'yuv.shell.action.manage-flavors.text' | translate }}</p>\n</header>\n<main [yuvBusyOverlay]=\"busy()\">\n @if (appliedFlavors.length) {\n <h3>{{ 'yuv.shell.action.manage-flavors.applied.headline' | translate }}</h3>\n <ul>\n @for (f of appliedFlavors; track $index) {\n <li>\n <yuv-flavor-chip [flavor]=\"f\" yuvListItem></yuv-flavor-chip>\n <button class=\"secondary\" (click)=\"removeFlavor(f)\">{{ 'yuv.shell.action.manage-flavors.applicable.button.remove' | translate }}</button>\n </li>\n }\n </ul>\n }\n @if (applicableFlavors.length) {\n <h3>{{ 'yuv.shell.action.manage-flavors.applicable.headline' | translate }}</h3>\n <ul>\n @for (f of applicableFlavors; track $index) {\n <li>\n <yuv-flavor-chip [flavor]=\"f\" yuvListItem></yuv-flavor-chip>\n <button class=\"secondary\" (click)=\"applyFlavor(f)\">{{ 'yuv.shell.action.manage-flavors.applied.button.apply' | translate }}</button>\n </li>\n }\n </ul>\n }\n</main>\n<footer>\n <button class=\"secondary\" (click)=\"cancel()\">{{ 'yuv.shell.action.manage-flavors.button.cancel' | translate }}</button>\n</footer>\n", styles: [":host{display:flex;flex-flow:column;padding:var(--app-pane-padding)}:host header{flex:0 0 auto}:host header h2{padding:0;font-weight:400;font-size:var(--font-headline);margin:0 0 var(--app-pane-padding) 0}:host header p{max-width:42ch;line-height:1.3em}:host main{flex:1;overflow-y:auto}:host main yuv-flavor-chip{border-color:transparent;flex:1}:host main ul{padding:0;margin:0;list-style-type:none}:host main li{display:flex;gap:calc(var(--app-pane-padding) / 2);align-items:center;border:1px solid var(--panel-divider-color);margin-block-end:2px;padding:calc(var(--app-pane-padding) / 4)}:host main li button{padding:calc(var(--app-pane-padding) / 4) calc(var(--app-pane-padding) / 2)}:host footer{flex:0 0 auto;margin-block-start:var(--app-pane-padding)}\n"] }]
438
+ args: [{ selector: 'yuv-manage-flavors', standalone: true, imports: [
439
+ CommonModule,
440
+ BusyOverlayDirective,
441
+ MatIconModule,
442
+ MatTooltipModule,
443
+ TranslateModule,
444
+ ListItemDirective,
445
+ FlavorChipComponent,
446
+ DialogComponent,
447
+ MatButtonModule,
448
+ YuvButtonDirective
449
+ ], template: "<yuv-dialog [headertitel]=\"'yuv.shell.action.manage-flavors.title' | translate\">\n <main [yuvBusyOverlay]=\"busy()\">\n <p>{{ 'yuv.shell.action.manage-flavors.text' | translate }}</p>\n @if (appliedFlavors.length) {\n <h3>{{ 'yuv.shell.action.manage-flavors.applied.headline' | translate }}</h3>\n <ul>\n @for (f of appliedFlavors; track $index) {\n <li>\n <yuv-flavor-chip [flavor]=\"f\" yuvListItem></yuv-flavor-chip>\n <button mat-icon-button [matTooltip]=\"'yuv.shell.action.manage-flavors.applicable.button.remove.tooltip' | translate\" (click)=\"removeFlavor(f)\">\n <mat-icon>delete_forever</mat-icon>\n </button>\n </li>\n }\n </ul>\n }\n @if (applicableFlavors.length) {\n <h3>{{ 'yuv.shell.action.manage-flavors.applicable.headline' | translate }}</h3>\n <ul>\n @for (f of applicableFlavors; track $index) {\n <li>\n <yuv-flavor-chip [flavor]=\"f\" yuvListItem></yuv-flavor-chip>\n <button mat-icon-button [matTooltip]=\"'yuv.shell.action.manage-flavors.applied.button.apply.tooltip' | translate\" (click)=\"applyFlavor(f)\">\n <mat-icon>add</mat-icon>\n </button>\n </li>\n }\n </ul>\n }\n </main>\n <footer>\n <button ymtButton=\"secondary\" (click)=\"cancel()\">{{ 'yuv.shell.action.manage-flavors.button.cancel' | translate }}</button>\n </footer>\n</yuv-dialog>\n", styles: [":host main{display:flex;flex-flow:column;padding:var(--ymt-spacing-m);flex:1;overflow-y:auto}:host main yuv-flavor-chip{border-color:transparent;flex:1}:host main ul{padding:0;margin:0;list-style-type:none}:host main li{display:flex;gap:var(--ymt-spacing-xs);align-items:center;border:1px solid var(--ymt-outline-variant);margin-block-end:2px;padding:var(--ymt-spacing-2xs)}:host footer{flex:0 0 auto;margin-block-start:var(--ymt-spacing-m)}\n"] }]
457
450
  }] });
458
451
 
459
452
  class ManageFlavorsAction extends AbstractContextAction {
460
453
  constructor() {
461
454
  super(...arguments);
462
455
  this.#shell = inject(ShellService);
463
- this.#overlay = inject(YvcOverlayService);
456
+ this.#dialog = inject(MatDialog);
464
457
  this.translate = inject(TranslateService);
465
458
  this.id = 'yuv.base.manage-flavor';
466
459
  this.label = this.translate.instant('yuv.shell.action.manage-flavor.label');
@@ -474,15 +467,23 @@ class ManageFlavorsAction extends AbstractContextAction {
474
467
  };
475
468
  }
476
469
  #shell;
477
- #overlay;
470
+ #dialog;
478
471
  isExecutable(items) {
479
472
  const item = items[0];
480
- return of(item && !!item.permissions?.writeIndexData && !!item.content && this.#shell.getApplicableObjectFlavors(item.content.mimeType).length > 0);
473
+ if (!item)
474
+ return of(false);
475
+ const applicableFlavors = item.isFolder
476
+ ? this.#shell.getApplicableFolderFlavors()
477
+ : item.content
478
+ ? this.#shell.getApplicableDocumentFlavors(item.content.mimeType)
479
+ : [];
480
+ return of(item && !!item.permissions?.writeIndexData && applicableFlavors.length > 0);
481
481
  }
482
482
  run(items) {
483
- this.#overlay.open(ManageFlavorsComponent, items[0], {
483
+ this.#dialog.open(ManageFlavorsComponent, {
484
484
  width: '400px',
485
485
  maxWidth: '90vw',
486
+ data: items[0]
486
487
  });
487
488
  return of(true);
488
489
  }