@yuuvis/client-shell 2.0.15 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,65 +1,262 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, ElementRef, input, effect, Directive, HostListener, Component, ChangeDetectionStrategy, signal, computed, Injectable } from '@angular/core';
3
- import * as i1 from '@angular/common';
2
+ import { inject, signal, Component, Injectable, ChangeDetectionStrategy, ElementRef, effect, HostListener, input, computed, TemplateRef, Directive, NgModule } from '@angular/core';
3
+ import { MAT_DIALOG_DATA, MatDialogRef, MatDialog } from '@angular/material/dialog';
4
+ import * as i1$1 from '@yuuvis/client-core';
5
+ import { DmsService, TranslateService, TranslateModule, SystemType, Utils, LocaleDatePipe, AuthService, UserService, DeviceService, SafeHtmlPipe, UserRoles } from '@yuuvis/client-core';
6
+ import { AbstractContextAction, ACTION_ICON, SelectionRange } from '@yuuvis/client-framework/actions';
7
+ import { ShellService, ShellNotificationsService, CommandPaletteService } from '@yuuvis/client-shell-core';
8
+ import { switchMap, of, tap, filter, debounceTime } from 'rxjs';
9
+ import * as i1$2 from '@angular/common';
4
10
  import { CommonModule, AsyncPipe } from '@angular/common';
5
- import { toSignal } from '@angular/core/rxjs-interop';
6
- import * as i3 from '@angular/material/button';
11
+ import * as i4 from '@angular/material/button';
7
12
  import { MatButtonModule, MatIconButton } from '@angular/material/button';
8
- import * as i2 from '@angular/material/icon';
13
+ import * as i1 from '@angular/material/icon';
9
14
  import { MatIconModule, MatIconRegistry, MatIcon } from '@angular/material/icon';
15
+ import * as i2 from '@angular/material/tooltip';
16
+ import { MatTooltipModule } from '@angular/material/tooltip';
17
+ import { ConfirmService, BusyOverlayDirective, DialogComponent, LightDismissDirective } from '@yuuvis/client-framework/common';
18
+ import * as i4$1 from '@yuuvis/client-framework/list';
19
+ import { ListItemDirective, YuvListModule } from '@yuuvis/client-framework/list';
20
+ import { FlavorChipComponent } from '@yuuvis/client-framework/object-flavor';
21
+ import { YmtButtonDirective } from '@yuuvis/material';
22
+ import { takeUntilDestroyed, toObservable, toSignal } from '@angular/core/rxjs-interop';
23
+ import { MatProgressBar } from '@angular/material/progress-bar';
10
24
  import * as i2$1 from '@angular/router';
11
25
  import { Router, NavigationEnd, RouterModule } from '@angular/router';
12
26
  import { SwPush } from '@angular/service-worker';
13
- import * as i1$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
- import { CdkTrapFocus } from '@angular/cdk/a11y';
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';
27
+ import * as i3 from '@yuuvis/client-framework/metadata-form-defaults';
28
+ import { YuvMetadataFormDefaultsModule } from '@yuuvis/client-framework/metadata-form-defaults';
29
+ import { map, shareReplay, tap as tap$1, filter as filter$1, catchError, switchMap as switchMap$1 } from 'rxjs/operators';
23
30
  import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
24
31
  import { MatListModule } from '@angular/material/list';
25
- import * as i1$2 from '@angular/material/sidenav';
32
+ import * as i1$3 from '@angular/material/sidenav';
26
33
  import { MatSidenavModule } from '@angular/material/sidenav';
27
34
  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';
35
+ import { CdkTrapFocus } from '@angular/cdk/a11y';
36
+ import { YUV_ICONS, YuvIconComponent } from '@yuuvis/client-framework/icons';
33
37
  import { WidgetGridRegistry } from '@yuuvis/client-framework/widget-grid';
34
- import { MAT_DIALOG_DATA, MatDialogRef, MatDialog } from '@angular/material/dialog';
35
- import { AbstractContextAction, ACTION_ICON, SelectionRange } from '@yuuvis/client-framework/actions';
36
- import { FlavorChipComponent } from '@yuuvis/client-framework/object-flavor';
37
- import { YmtButtonDirective } from '@yuuvis/material';
38
38
 
39
- class InertDirective {
39
+ class ManageFlavorsComponent {
40
40
  constructor() {
41
- this.elRef = inject(ElementRef);
42
- this.inert = input(false);
43
- effect(() => {
44
- const el = this.elRef.nativeElement;
45
- if (this.inert())
46
- el.setAttribute('inert', 'true');
47
- else
48
- el.removeAttribute('inert');
41
+ this.#shell = inject(ShellService);
42
+ this.#dmsService = inject(DmsService);
43
+ this.#dialogData = inject(MAT_DIALOG_DATA);
44
+ this.#dialogRef = inject((MatDialogRef));
45
+ this.item = this.#dialogData;
46
+ this.#confirm = inject(ConfirmService);
47
+ this.translate = inject(TranslateService);
48
+ this.busy = signal(false);
49
+ this.appliedFlavors = [];
50
+ this.applicableFlavors = [];
51
+ }
52
+ #shell;
53
+ #dmsService;
54
+ #dialogData;
55
+ #dialogRef;
56
+ #confirm;
57
+ applyFlavor(flavor) {
58
+ this.busy.set(true);
59
+ this.#shell.triggerApplyObjectFlavor(this.item, flavor).subscribe(() => {
60
+ this.#dialogRef.close();
61
+ this.busy.set(false);
49
62
  });
50
63
  }
51
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: InertDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
52
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.12", type: InertDirective, isStandalone: true, selector: "[inert]", inputs: { inert: { classPropertyName: "inert", publicName: "inert", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 }); }
64
+ removeFlavor(flavor) {
65
+ this.busy.set(true);
66
+ this.#confirm
67
+ .confirm({
68
+ message: this.translate.instant('yuv.object-flavor.flavor.remove.confirm.message', {
69
+ flavor: this.#shell.getFlavorLabel(flavor.id)
70
+ })
71
+ })
72
+ .pipe(switchMap((confirmed) => (confirmed ? this.#shell.removeObjectFlavor(this.item, flavor) : of(undefined))))
73
+ .subscribe((res) => {
74
+ if (res !== undefined)
75
+ this.#dialogRef.close();
76
+ this.busy.set(false);
77
+ });
78
+ }
79
+ #refreshDmsObject() {
80
+ this.busy.set(true);
81
+ this.#dmsService
82
+ .getDmsObject(this.item.id)
83
+ .pipe(tap((dmsObject) => {
84
+ this.item = dmsObject;
85
+ this.#getAppliedFlavors(this.item);
86
+ }))
87
+ .subscribe()
88
+ .add(() => this.busy.set(false));
89
+ }
90
+ #getAppliedFlavors(dmsObject) {
91
+ const res = this.#shell.getAppliedObjectFlavors(dmsObject);
92
+ this.appliedFlavors = res.applied;
93
+ this.applicableFlavors = res.applicable;
94
+ }
95
+ cancel() {
96
+ this.#dialogRef.close();
97
+ }
98
+ ngOnInit() {
99
+ this.#refreshDmsObject();
100
+ }
101
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: ManageFlavorsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
102
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.12", 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: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i2.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$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: i4.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "directive", type: YmtButtonDirective, selector: "button[ymtButton], a[ymtButton]", inputs: ["ymtButton", "disabled", "aria-disabled", "disableRipple", "disabledInteractive", "button-size"] }] }); }
53
103
  }
54
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: InertDirective, decorators: [{
55
- type: Directive,
104
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: ManageFlavorsComponent, decorators: [{
105
+ type: Component,
106
+ args: [{ selector: 'yuv-manage-flavors', standalone: true, imports: [
107
+ CommonModule,
108
+ BusyOverlayDirective,
109
+ MatIconModule,
110
+ MatTooltipModule,
111
+ TranslateModule,
112
+ ListItemDirective,
113
+ FlavorChipComponent,
114
+ DialogComponent,
115
+ MatButtonModule,
116
+ YmtButtonDirective
117
+ ], 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"] }]
118
+ }] });
119
+
120
+ class ManageFlavorsAction extends AbstractContextAction {
121
+ constructor() {
122
+ super(...arguments);
123
+ this.#shell = inject(ShellService);
124
+ this.#dialog = inject(MatDialog);
125
+ this.translate = inject(TranslateService);
126
+ this.id = 'yuv.base.manage-flavor';
127
+ this.label = this.translate.instant('yuv.shell.action.manage-flavor.label');
128
+ this.description = this.translate.instant('yuv.shell.action.manage-flavor.description');
129
+ this.priority = 8;
130
+ this.icon = ACTION_ICON.manageFlavor;
131
+ this.group = 'common';
132
+ this.range = SelectionRange.SINGLE_SELECT;
133
+ this.supports = {
134
+ types: [SystemType.DOCUMENT]
135
+ };
136
+ }
137
+ #shell;
138
+ #dialog;
139
+ isExecutable(items) {
140
+ const item = items[0];
141
+ if (!item)
142
+ return of(false);
143
+ const applicableFlavors = item.isFolder
144
+ ? this.#shell.getApplicableFolderFlavors()
145
+ : item.content
146
+ ? this.#shell.getApplicableDocumentFlavors(item.content.mimeType)
147
+ : [];
148
+ return of(item && !!item.permissions?.writeIndexData && applicableFlavors.length > 0);
149
+ }
150
+ run(items) {
151
+ this.#dialog.open(ManageFlavorsComponent, {
152
+ width: '400px',
153
+ maxWidth: '90vw',
154
+ data: items[0]
155
+ });
156
+ return of(true);
157
+ }
158
+ }
159
+
160
+ class ClientShellService {
161
+ #router;
162
+ #shell;
163
+ constructor() {
164
+ this.#router = inject(Router);
165
+ this.#shell = inject(ShellService);
166
+ this.appHeaderSlots = signal({});
167
+ this.apps = this.#shell.apps;
168
+ this.currentApp = signal(undefined);
169
+ this.appHeader = signal(false);
170
+ this.#router.events
171
+ .pipe(takeUntilDestroyed(), filter((e) => e instanceof NavigationEnd))
172
+ .subscribe((e) => {
173
+ this.#getAppFromUrl(this.#router.routerState.snapshot.url);
174
+ });
175
+ }
176
+ #getAppFromUrl(url) {
177
+ // remove request params
178
+ if (url.indexOf('?') !== -1)
179
+ url = url.substring(0, url.indexOf('?'));
180
+ // remove fragments
181
+ if (url.indexOf('#') !== -1)
182
+ url = url.substring(0, url.indexOf('#'));
183
+ const urlTokens = url.split('/').filter((t) => !!t);
184
+ // TODO: what about context path
185
+ const appPath = urlTokens[0];
186
+ if (this.currentApp()?.path !== appPath) {
187
+ const app = this.apps().find((a) => a.path === appPath);
188
+ this.currentApp.set(app);
189
+ const appData = app?.options;
190
+ this.appHeader.set(!!appData?.appHeader);
191
+ this.appHeaderSlots.set({});
192
+ }
193
+ }
194
+ addAppHeaderSlot(slot, tpl) {
195
+ this.appHeaderSlots.update((curr) => ({ ...curr, [slot]: tpl }));
196
+ }
197
+ getCssVars(vars) {
198
+ // const vars = ['--ymt-spacing-m'];
199
+ const style = window.getComputedStyle(document.getElementsByTagName('body')[0]);
200
+ return vars.reduce((prev, curr) => ({ ...prev, [curr]: style.getPropertyValue(curr) }), {});
201
+ }
202
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: ClientShellService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
203
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: ClientShellService, providedIn: 'root' }); }
204
+ }
205
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: ClientShellService, decorators: [{
206
+ type: Injectable,
56
207
  args: [{
57
- // eslint-disable-next-line @angular-eslint/directive-selector
58
- selector: '[inert]',
59
- standalone: true
208
+ providedIn: 'root'
60
209
  }]
61
210
  }], ctorParameters: () => [] });
62
211
 
212
+ class ShellLogoComponent {
213
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: ShellLogoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
214
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.12", type: ShellLogoComponent, isStandalone: true, selector: "yuv-shell-logo", ngImport: i0, template: "<button routerLink=\"/\" [attr.aria-label]=\"'yuv.shell.logo.aria.label' | translate\">\n <mat-icon svgIcon=\"shellIcons:app_logo\"></mat-icon>\n</button>", styles: [":host button{width:var(--yuv-app-header-height);height:var(--yuv-app-header-height);border-radius:0;background-color:transparent;border:0;display:flex;justify-content:center;align-items:center}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] }); }
215
+ }
216
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: ShellLogoComponent, decorators: [{
217
+ type: Component,
218
+ args: [{ selector: 'yuv-shell-logo', standalone: true, imports: [CommonModule, MatIconModule, TranslateModule], template: "<button routerLink=\"/\" [attr.aria-label]=\"'yuv.shell.logo.aria.label' | translate\">\n <mat-icon svgIcon=\"shellIcons:app_logo\"></mat-icon>\n</button>", styles: [":host button{width:var(--yuv-app-header-height);height:var(--yuv-app-header-height);border-radius:0;background-color:transparent;border:0;display:flex;justify-content:center;align-items:center}\n"] }]
219
+ }] });
220
+
221
+ class YuvAppHeaderComponent {
222
+ #clientShellService;
223
+ #slots;
224
+ constructor() {
225
+ this.#clientShellService = inject(ClientShellService);
226
+ this.actionsSlot = null;
227
+ this.searchSlot = null;
228
+ this.notificationsSlot = null;
229
+ this.app = this.#clientShellService.currentApp;
230
+ this.#slots = this.#clientShellService.appHeaderSlots;
231
+ toObservable(this.#slots)
232
+ .pipe(debounceTime(1), takeUntilDestroyed())
233
+ .subscribe((slots) => {
234
+ this.actionsSlot = slots['actions'] || null;
235
+ this.searchSlot = slots['search'] || null;
236
+ this.notificationsSlot = slots['notifications'] || null;
237
+ });
238
+ }
239
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: YuvAppHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
240
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.12", type: YuvAppHeaderComponent, isStandalone: true, selector: "yuv-app-header", ngImport: i0, template: "@let a = app();\n\n@if (a) {\n <yuv-shell-logo />\n <div class=\"name\" routerLink=\".\">\n <div class=\"title\">{{ a.title }}</div>\n <div class=\"claim\">{{ a.options?.appClaim }}</div>\n </div>\n <div class=\"actions\">\n <ng-container *ngTemplateOutlet=\"actionsSlot\"></ng-container>\n </div>\n <div class=\"search\">\n <ng-container *ngTemplateOutlet=\"searchSlot\"></ng-container>\n </div>\n <div class=\"notifications\">\n <ng-container *ngTemplateOutlet=\"notificationsSlot\"></ng-container>\n </div>\n}\n", styles: [":host{display:grid;grid-template-columns:var(--yuv-app-header-height) auto 1fr auto auto;grid-template-rows:var(--yuv-app-header-height);grid-template-areas:\"logo name actions search notifications\";align-items:center;background-color:var(--ymt-surface);color:var(--ymt-on-surface);border-block-end:1px solid var(--ymt-outline-variant);box-sizing:border-box;padding-inline-end:var(--ymt-spacing-xl)}:host .logo{grid-area:logo;display:flex;flex-direction:column;align-items:center;justify-content:center}:host .name{grid-area:name;padding-inline-end:var(--ymt-spacing-3xl);padding-inline-start:var(--ymt-spacing-xs)}:host .name .title{font-weight:700}:host .name .claim{font:var(--ymt-font-body-font);color:var(--ymt-text-color-subtle);font-size:var(--ymt-font-body-subtle-size)}:host .actions{grid-area:actions}:host .search{grid-area:search}:host .notifications{grid-area:notifications}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: ShellLogoComponent, selector: "yuv-shell-logo" }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i2$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }] }); }
241
+ }
242
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: YuvAppHeaderComponent, decorators: [{
243
+ type: Component,
244
+ args: [{ selector: 'yuv-app-header', imports: [CommonModule, MatIconModule, ShellLogoComponent, RouterModule], template: "@let a = app();\n\n@if (a) {\n <yuv-shell-logo />\n <div class=\"name\" routerLink=\".\">\n <div class=\"title\">{{ a.title }}</div>\n <div class=\"claim\">{{ a.options?.appClaim }}</div>\n </div>\n <div class=\"actions\">\n <ng-container *ngTemplateOutlet=\"actionsSlot\"></ng-container>\n </div>\n <div class=\"search\">\n <ng-container *ngTemplateOutlet=\"searchSlot\"></ng-container>\n </div>\n <div class=\"notifications\">\n <ng-container *ngTemplateOutlet=\"notificationsSlot\"></ng-container>\n </div>\n}\n", styles: [":host{display:grid;grid-template-columns:var(--yuv-app-header-height) auto 1fr auto auto;grid-template-rows:var(--yuv-app-header-height);grid-template-areas:\"logo name actions search notifications\";align-items:center;background-color:var(--ymt-surface);color:var(--ymt-on-surface);border-block-end:1px solid var(--ymt-outline-variant);box-sizing:border-box;padding-inline-end:var(--ymt-spacing-xl)}:host .logo{grid-area:logo;display:flex;flex-direction:column;align-items:center;justify-content:center}:host .name{grid-area:name;padding-inline-end:var(--ymt-spacing-3xl);padding-inline-start:var(--ymt-spacing-xs)}:host .name .title{font-weight:700}:host .name .claim{font:var(--ymt-font-body-font);color:var(--ymt-text-color-subtle);font-size:var(--ymt-font-body-subtle-size)}:host .actions{grid-area:actions}:host .search{grid-area:search}:host .notifications{grid-area:notifications}\n"] }]
245
+ }], ctorParameters: () => [] });
246
+
247
+ class SidebarNavComponent {
248
+ constructor() {
249
+ this.breakpointObserver = inject(BreakpointObserver);
250
+ this.isHandset$ = this.breakpointObserver.observe(Breakpoints.Handset).pipe(map((result) => result.matches), shareReplay());
251
+ }
252
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: SidebarNavComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
253
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.12", 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=\"yuv-shell-logo\"></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: var(--yuv-navigation-rail-width)}: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:var(--yuv-navigation-rail-width)}.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 .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:var(--yuv-navigation-rail-width)}: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(var(--yuv-navigation-rail-width) - 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$3.MatSidenav, selector: "mat-sidenav", inputs: ["fixedInViewport", "fixedTopGap", "fixedBottomGap"], exportAs: ["matSidenav"] }, { kind: "component", type: i1$3.MatSidenavContainer, selector: "mat-sidenav-container", exportAs: ["matSidenavContainer"] }, { kind: "component", type: i1$3.MatSidenavContent, selector: "mat-sidenav-content" }, { kind: "ngmodule", type: MatListModule }, { kind: "ngmodule", type: MatIconModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
254
+ }
255
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: SidebarNavComponent, decorators: [{
256
+ type: Component,
257
+ 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=\"yuv-shell-logo\"></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: var(--yuv-navigation-rail-width)}: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:var(--yuv-navigation-rail-width)}.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 .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:var(--yuv-navigation-rail-width)}: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(var(--yuv-navigation-rail-width) - 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"] }]
258
+ }] });
259
+
63
260
  class NotificationsPageComponent {
64
261
  constructor() {
65
262
  this.router = inject(Router);
@@ -115,7 +312,7 @@ class NotificationsPageComponent {
115
312
  });
116
313
  }
117
314
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: NotificationsPageComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
118
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.12", 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: i1$1.TranslatePipe, name: "translate" }] }); }
315
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.12", 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$2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: LightDismissDirective, selector: "[yuvLightDismiss]", outputs: ["yuvLightDismiss"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i4.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$1.ListComponent, selector: "yuv-list", inputs: ["multiselect", "selfHandleSelection", "disableSelection"], outputs: ["itemSelect", "itemFocus"] }, { kind: "directive", type: i4$1.ListItemDirective, selector: "[yuvListItem]", inputs: ["disabled", "active", "selected"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "pipe", type: i1$1.TranslatePipe, name: "translate" }] }); }
119
316
  }
120
317
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: NotificationsPageComponent, decorators: [{
121
318
  type: Component,
@@ -138,26 +335,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.12", ngImpo
138
335
  const clientShellRoutes = [
139
336
  { path: 'dashboard', loadComponent: () => import('./yuuvis-client-shell-dashboard.component-akNayAfe.mjs').then((comp) => comp.DashboardPageComponent) },
140
337
  { path: 'notifications', component: NotificationsPageComponent, outlet: 'aside' },
141
- { path: 'settings', loadComponent: () => import('./yuuvis-client-shell-settings.component-Dyr0I9Gx.mjs').then((comp) => comp.SettingsPageComponent) },
338
+ { path: 'settings', loadComponent: () => import('./yuuvis-client-shell-settings.component-ANbgn9LN.mjs').then((comp) => comp.SettingsPageComponent) },
142
339
  // default route
143
340
  { path: '', redirectTo: '/dashboard', pathMatch: 'full' },
144
341
  // redirecting route
145
342
  { path: '**', redirectTo: '/' }
146
343
  ];
147
344
 
148
- class SidebarNavComponent {
149
- constructor() {
150
- this.breakpointObserver = inject(BreakpointObserver);
151
- this.isHandset$ = this.breakpointObserver.observe(Breakpoints.Handset).pipe(map((result) => result.matches), shareReplay());
152
- }
153
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: SidebarNavComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
154
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.12", 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$2.MatSidenav, selector: "mat-sidenav", inputs: ["fixedInViewport", "fixedTopGap", "fixedBottomGap"], exportAs: ["matSidenav"] }, { kind: "component", type: i1$2.MatSidenavContainer, selector: "mat-sidenav-container", exportAs: ["matSidenavContainer"] }, { kind: "component", type: i1$2.MatSidenavContent, selector: "mat-sidenav-content" }, { kind: "ngmodule", type: MatListModule }, { kind: "ngmodule", type: MatIconModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
155
- }
156
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: SidebarNavComponent, decorators: [{
157
- type: Component,
158
- 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"] }]
159
- }] });
160
-
161
345
  /**
162
346
  * Base component for the client shell application. In your apps
163
347
  * app.component.ts you can use this component as a base component
@@ -197,6 +381,7 @@ class ClientShellComponent {
197
381
  this.auth = inject(AuthService);
198
382
  this.userService = inject(UserService);
199
383
  this.#shell = inject(ShellService);
384
+ this.css = inject(ClientShellService);
200
385
  this.shellNotifications = inject(ShellNotificationsService);
201
386
  this.translate = inject(TranslateService);
202
387
  this.commandPalette = inject(CommandPaletteService);
@@ -214,14 +399,15 @@ class ClientShellComponent {
214
399
  this.showUploadOverlay = false;
215
400
  this.busy$ = this.#shell.isBusy$;
216
401
  this.showNotifications = signal(false);
217
- this.newNotifications = toSignal(this.shellNotifications.shellNotifications$.pipe(tap((n) => this.showNotifications.set(n.length > 0)), map((notifications) => {
402
+ this.newNotifications = toSignal(this.shellNotifications.shellNotifications$.pipe(tap$1((n) => this.showNotifications.set(n.length > 0)), map((notifications) => {
218
403
  let maxLevel = 'info';
219
404
  const count = notifications.filter((n) => !n.seen).length;
220
405
  notifications.forEach((n) => (maxLevel = n.level && this._levels[n.level] > this._levels[maxLevel] ? n.level : maxLevel));
221
406
  return count > 0 ? { maxLevel, count } : undefined;
222
407
  })));
223
408
  this.apps = input.required();
224
- this.#appsEffect = effect(() => this.#shell.setAppBaseRoutes(this.apps()));
409
+ this.navApps = computed(() => this.apps().filter(a => !a.options?.hideFromNav));
410
+ this.#appsEffect = effect(() => this.#shell.setApps(this.apps()));
225
411
  this.checkedForInitialRoute = false;
226
412
  this.enableTenantSwitch = false;
227
413
  this.config = input();
@@ -255,7 +441,7 @@ class ClientShellComponent {
255
441
  // console.log(e);
256
442
  // });
257
443
  this.router.events
258
- .pipe(filter((e) => e instanceof NavigationEnd), map((e) => e))
444
+ .pipe(filter$1((e) => e instanceof NavigationEnd), map((e) => e))
259
445
  .subscribe((e) => this._processRouterNavigationEnd(e));
260
446
  this.#device.init();
261
447
  this.userService.user$.subscribe((user) => {
@@ -312,7 +498,7 @@ class ClientShellComponent {
312
498
  return;
313
499
  }
314
500
  this.#swPush.messages
315
- .pipe(tap((msg) => console.log({ msg })), catchError((error) => {
501
+ .pipe(tap$1((msg) => console.log({ msg })), catchError((error) => {
316
502
  console.log({ error });
317
503
  return of(null);
318
504
  }))
@@ -336,7 +522,7 @@ class ClientShellComponent {
336
522
  // get persisted routes to decide where to redirect the logged in user to
337
523
  this.auth
338
524
  .getInitialRequestUri()
339
- .pipe(switchMap((res) => this.auth.resetInitialRequestUri().pipe(map((_) => res))))
525
+ .pipe(switchMap$1((res) => this.auth.resetInitialRequestUri().pipe(map((_) => res))))
340
526
  .subscribe((res) => {
341
527
  const loginRes = res && !ignoreRoutes.includes(res.uri) ? res : null;
342
528
  if (loginRes)
@@ -358,7 +544,7 @@ class ClientShellComponent {
358
544
  this.requestSubscription();
359
545
  }
360
546
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: ClientShellComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
361
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.12", 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: i1$1.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i2$1.RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "directive", type: i2$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i2$1.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"] }] }); }
547
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.12", 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 mode=\"indeterminate\" class=\"progress-bar\"></mat-progress-bar>\n}\n\n@let iconsRegistered = registerIcons();\n@let showAppHeader = css.appHeader();\n\n@if (showAppHeader) {\n <yuv-app-header> </yuv-app-header>\n}\n\n<yuv-sidebar-nav class=\"shell-nav\">\n @if (iconsRegistered && !showAppHeader) {\n <yuv-shell-logo />\n }\n <!-- </button> -->\n <ul class=\"shell-nav__nav-list\">\n @for (a of navApps(); track a.path) {\n <li class=\"shell-nav__nav-list-item\">\n <button\n class=\"shell-nav__nav-list-item-button\"\n mat-icon-button\n routerLinkActive=\"active\"\n [routerLink]=\"a.path\"\n matTooltipPosition=\"after\"\n [matTooltip]=\"getAppTitle(a)\"\n >\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: var(--yuv-navigation-rail-width)}: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:var(--yuv-navigation-rail-width)}.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 .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:var(--yuv-navigation-rail-width)}: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(var(--yuv-navigation-rail-width) - 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{--yuv-app-header-height: 60px;--yuv-navigation-rail-width: var(--yuv-app-header-height);position:absolute;inset:0;overflow:hidden;background-color:var(--ymt-surface-frame);display:grid;grid-template-rows:auto 1fr;grid-template-columns:auto 1fr;grid-template-areas:\"appheader appheader\" \"nav main\"}:host .progress-bar{position:absolute}:host yuv-app-header{grid-area:appheader}:host .shell-nav{grid-area:nav}:host .shell-nav__nav-list{display:contents;list-style:none}:host .shell-nav__nav-list-item{display:inline-block}:host .shell-nav__actions{display:contents}:host main{grid-area:main;overflow:hidden;color:var(--ymt-text-color)}:host .asideOutlet{position:absolute;inset:0;padding-inline-start:var(--yuv-navigation-rail-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]) 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: i1$1.TranslatePipe, name: "translate" }, { kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i2$1.RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "directive", type: i2$1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i2$1.RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "ngmodule", type: YuvMetadataFormDefaultsModule }, { kind: "component", type: i3.MetadataDefaultTemplatesComponent, selector: "yuv-metadata-default-templates" }, { kind: "component", type: YuvAppHeaderComponent, selector: "yuv-app-header" }, { 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: i2.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: ShellLogoComponent, selector: "yuv-shell-logo" }] }); }
362
548
  }
363
549
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: ClientShellComponent, decorators: [{
364
550
  type: Component,
@@ -367,12 +553,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.12", ngImpo
367
553
  TranslateModule,
368
554
  RouterModule,
369
555
  YuvMetadataFormDefaultsModule,
556
+ YuvAppHeaderComponent,
370
557
  SidebarNavComponent,
371
558
  MatIconButton,
372
559
  MatIcon,
373
560
  MatProgressBar,
374
- MatTooltipModule
375
- ], 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"] }]
561
+ MatTooltipModule,
562
+ ShellLogoComponent
563
+ ], providers: [SafeHtmlPipe], template: "<yuv-metadata-default-templates></yuv-metadata-default-templates>\n\n<!-- gloabl busy indicator -->\n@if (busy$ | async) {\n <mat-progress-bar mode=\"indeterminate\" class=\"progress-bar\"></mat-progress-bar>\n}\n\n@let iconsRegistered = registerIcons();\n@let showAppHeader = css.appHeader();\n\n@if (showAppHeader) {\n <yuv-app-header> </yuv-app-header>\n}\n\n<yuv-sidebar-nav class=\"shell-nav\">\n @if (iconsRegistered && !showAppHeader) {\n <yuv-shell-logo />\n }\n <!-- </button> -->\n <ul class=\"shell-nav__nav-list\">\n @for (a of navApps(); track a.path) {\n <li class=\"shell-nav__nav-list-item\">\n <button\n class=\"shell-nav__nav-list-item-button\"\n mat-icon-button\n routerLinkActive=\"active\"\n [routerLink]=\"a.path\"\n matTooltipPosition=\"after\"\n [matTooltip]=\"getAppTitle(a)\"\n >\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: var(--yuv-navigation-rail-width)}: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:var(--yuv-navigation-rail-width)}.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 .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:var(--yuv-navigation-rail-width)}: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(var(--yuv-navigation-rail-width) - 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{--yuv-app-header-height: 60px;--yuv-navigation-rail-width: var(--yuv-app-header-height);position:absolute;inset:0;overflow:hidden;background-color:var(--ymt-surface-frame);display:grid;grid-template-rows:auto 1fr;grid-template-columns:auto 1fr;grid-template-areas:\"appheader appheader\" \"nav main\"}:host .progress-bar{position:absolute}:host yuv-app-header{grid-area:appheader}:host .shell-nav{grid-area:nav}:host .shell-nav__nav-list{display:contents;list-style:none}:host .shell-nav__nav-list-item{display:inline-block}:host .shell-nav__actions{display:contents}:host main{grid-area:main;overflow:hidden;color:var(--ymt-text-color)}:host .asideOutlet{position:absolute;inset:0;padding-inline-start:var(--yuv-navigation-rail-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]) main{overflow:hidden}:host-context([data-screen-size=s][data-screen-orientation=portrait]) .asideOutlet{padding-inline-start:0}\n"] }]
376
564
  }], ctorParameters: () => [], propDecorators: { onFocusChange: [{
377
565
  type: HostListener,
378
566
  args: ['document:focusin', ['$event']]
@@ -381,19 +569,67 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.12", ngImpo
381
569
  args: ['dragover', ['$event']]
382
570
  }] } });
383
571
 
384
- class AppLogoComponent {
572
+ class YuvAppHeaderSlotDirective {
385
573
  constructor() {
386
- this.icon = input();
387
- this.label = input.required();
574
+ this.#tplRef = inject((TemplateRef));
575
+ this.#clientShellService = inject(ClientShellService);
576
+ this.yuvAppHeaderSlot = input.required();
577
+ }
578
+ #tplRef;
579
+ #clientShellService;
580
+ ngOnInit() {
581
+ this.#clientShellService.addAppHeaderSlot(this.yuvAppHeaderSlot(), this.#tplRef);
388
582
  }
389
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: AppLogoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
390
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.2.12", 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 }] }); }
583
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: YuvAppHeaderSlotDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
584
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.12", type: YuvAppHeaderSlotDirective, isStandalone: true, selector: "ng-template[yuvAppHeaderSlot]", inputs: { yuvAppHeaderSlot: { classPropertyName: "yuvAppHeaderSlot", publicName: "yuvAppHeaderSlot", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 }); }
391
585
  }
392
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: AppLogoComponent, decorators: [{
393
- type: Component,
394
- 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"] }]
586
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: YuvAppHeaderSlotDirective, decorators: [{
587
+ type: Directive,
588
+ args: [{
589
+ selector: 'ng-template[yuvAppHeaderSlot]'
590
+ }]
591
+ }] });
592
+
593
+ const cmp = [
594
+ YuvAppHeaderSlotDirective,
595
+ ];
596
+ class YuvClientShellModule {
597
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: YuvClientShellModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
598
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.12", ngImport: i0, type: YuvClientShellModule, imports: [YuvAppHeaderSlotDirective], exports: [YuvAppHeaderSlotDirective] }); }
599
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: YuvClientShellModule }); }
600
+ }
601
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: YuvClientShellModule, decorators: [{
602
+ type: NgModule,
603
+ args: [{
604
+ imports: [cmp],
605
+ exports: [cmp]
606
+ }]
395
607
  }] });
396
608
 
609
+ class InertDirective {
610
+ constructor() {
611
+ this.elRef = inject(ElementRef);
612
+ this.inert = input(false);
613
+ effect(() => {
614
+ const el = this.elRef.nativeElement;
615
+ if (this.inert())
616
+ el.setAttribute('inert', 'true');
617
+ else
618
+ el.removeAttribute('inert');
619
+ });
620
+ }
621
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: InertDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
622
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.12", type: InertDirective, isStandalone: true, selector: "[inert]", inputs: { inert: { classPropertyName: "inert", publicName: "inert", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 }); }
623
+ }
624
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: InertDirective, decorators: [{
625
+ type: Directive,
626
+ args: [{
627
+ // eslint-disable-next-line @angular-eslint/directive-selector
628
+ selector: '[inert]',
629
+ standalone: true
630
+ }]
631
+ }], ctorParameters: () => [] });
632
+
397
633
  class ShellWidgetsService {
398
634
  #widgetGridRegistry = inject(WidgetGridRegistry);
399
635
  #WIDGET_REGISTRY_BUCKET = 'io.yuuvis.shell.widgets';
@@ -413,130 +649,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.12", ngImpo
413
649
  }]
414
650
  }] });
415
651
 
416
- class ManageFlavorsComponent {
417
- constructor() {
418
- this.#shell = inject(ShellService);
419
- this.#dmsService = inject(DmsService);
420
- this.#dialogData = inject(MAT_DIALOG_DATA);
421
- this.#dialogRef = inject((MatDialogRef));
422
- this.item = this.#dialogData;
423
- this.#confirm = inject(ConfirmService);
424
- this.translate = inject(TranslateService);
425
- this.busy = signal(false);
426
- this.appliedFlavors = [];
427
- this.applicableFlavors = [];
428
- }
429
- #shell;
430
- #dmsService;
431
- #dialogData;
432
- #dialogRef;
433
- #confirm;
434
- applyFlavor(flavor) {
435
- this.busy.set(true);
436
- this.#shell.triggerApplyObjectFlavor(this.item, flavor).subscribe(() => {
437
- this.#dialogRef.close();
438
- this.busy.set(false);
439
- });
440
- }
441
- removeFlavor(flavor) {
442
- this.busy.set(true);
443
- this.#confirm
444
- .confirm({
445
- message: this.translate.instant('yuv.object-flavor.flavor.remove.confirm.message', {
446
- flavor: this.#shell.getFlavorLabel(flavor.id)
447
- })
448
- })
449
- .pipe(switchMap$1((confirmed) => (confirmed ? this.#shell.removeObjectFlavor(this.item, flavor) : of(undefined))))
450
- .subscribe((res) => {
451
- if (res !== undefined)
452
- this.#dialogRef.close();
453
- this.busy.set(false);
454
- });
455
- }
456
- #refreshDmsObject() {
457
- this.busy.set(true);
458
- this.#dmsService
459
- .getDmsObject(this.item.id)
460
- .pipe(tap$1((dmsObject) => {
461
- this.item = dmsObject;
462
- this.#getAppliedFlavors(this.item);
463
- }))
464
- .subscribe()
465
- .add(() => this.busy.set(false));
466
- }
467
- #getAppliedFlavors(dmsObject) {
468
- const res = this.#shell.getAppliedObjectFlavors(dmsObject);
469
- this.appliedFlavors = res.applied;
470
- this.applicableFlavors = res.applicable;
471
- }
472
- cancel() {
473
- this.#dialogRef.close();
474
- }
475
- ngOnInit() {
476
- this.#refreshDmsObject();
477
- }
478
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: ManageFlavorsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
479
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.12", 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: i1$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: YmtButtonDirective, selector: "button[ymtButton], a[ymtButton]", inputs: ["ymtButton", "disabled", "aria-disabled", "disableRipple", "disabledInteractive", "button-size"] }] }); }
480
- }
481
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.12", ngImport: i0, type: ManageFlavorsComponent, decorators: [{
482
- type: Component,
483
- args: [{ selector: 'yuv-manage-flavors', standalone: true, imports: [
484
- CommonModule,
485
- BusyOverlayDirective,
486
- MatIconModule,
487
- MatTooltipModule,
488
- TranslateModule,
489
- ListItemDirective,
490
- FlavorChipComponent,
491
- DialogComponent,
492
- MatButtonModule,
493
- YmtButtonDirective
494
- ], 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"] }]
495
- }] });
496
-
497
- class ManageFlavorsAction extends AbstractContextAction {
498
- constructor() {
499
- super(...arguments);
500
- this.#shell = inject(ShellService);
501
- this.#dialog = inject(MatDialog);
502
- this.translate = inject(TranslateService);
503
- this.id = 'yuv.base.manage-flavor';
504
- this.label = this.translate.instant('yuv.shell.action.manage-flavor.label');
505
- this.description = this.translate.instant('yuv.shell.action.manage-flavor.description');
506
- this.priority = 8;
507
- this.icon = ACTION_ICON.manageFlavor;
508
- this.group = 'common';
509
- this.range = SelectionRange.SINGLE_SELECT;
510
- this.supports = {
511
- types: [SystemType.DOCUMENT]
512
- };
513
- }
514
- #shell;
515
- #dialog;
516
- isExecutable(items) {
517
- const item = items[0];
518
- if (!item)
519
- return of(false);
520
- const applicableFlavors = item.isFolder
521
- ? this.#shell.getApplicableFolderFlavors()
522
- : item.content
523
- ? this.#shell.getApplicableDocumentFlavors(item.content.mimeType)
524
- : [];
525
- return of(item && !!item.permissions?.writeIndexData && applicableFlavors.length > 0);
526
- }
527
- run(items) {
528
- this.#dialog.open(ManageFlavorsComponent, {
529
- width: '400px',
530
- maxWidth: '90vw',
531
- data: items[0]
532
- });
533
- return of(true);
534
- }
535
- }
536
-
537
652
  /**
538
653
  * Generated bundle index. Do not edit.
539
654
  */
540
655
 
541
- export { AppLogoComponent, ClientShellComponent, InertDirective, ManageFlavorsAction, ShellWidgetsService, clientShellRoutes };
656
+ export { ClientShellComponent, InertDirective, ManageFlavorsAction, ShellLogoComponent, ShellWidgetsService, YuvAppHeaderSlotDirective, YuvClientShellModule, clientShellRoutes };
542
657
  //# sourceMappingURL=yuuvis-client-shell.mjs.map