@rxap/layout 18.0.3-dev.1 → 18.1.0-dev.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.
Files changed (212) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +267 -1
  3. package/compodoc/changelog.html +16 -0
  4. package/compodoc/components/AppsButtonComponent.html +197 -153
  5. package/compodoc/components/BaseLayoutComponent.html +351 -0
  6. package/compodoc/components/DefaultHeaderComponent.html +545 -0
  7. package/compodoc/components/FooterComponent.html +58 -79
  8. package/compodoc/components/HeaderComponent.html +49 -294
  9. package/compodoc/components/LanguageSelectorComponent.html +6 -54
  10. package/compodoc/components/LayoutComponent.html +69 -464
  11. package/compodoc/components/MinimalLayoutComponent.html +349 -0
  12. package/compodoc/components/NavigationComponent.html +116 -312
  13. package/compodoc/components/NavigationItemComponent.html +130 -361
  14. package/compodoc/components/NavigationProgressBarComponent.html +41 -107
  15. package/compodoc/components/ReleaseInfoComponent.html +536 -0
  16. package/compodoc/components/SettingsButtonComponent.html +186 -225
  17. package/compodoc/components/SidenavComponent.html +566 -142
  18. package/compodoc/components/SidenavToggleButtonComponent.html +71 -91
  19. package/compodoc/components/SignOutComponent.html +7 -60
  20. package/compodoc/components/UserProfileIconComponent.html +97 -161
  21. package/compodoc/dependencies.html +9 -25
  22. package/compodoc/directives/FooterDirective-1.html +293 -0
  23. package/compodoc/directives/FooterDirective.html +8 -86
  24. package/compodoc/directives/HeaderDirective.html +293 -0
  25. package/compodoc/index.html +177 -2
  26. package/compodoc/injectables/ExternalAppsService.html +1311 -0
  27. package/compodoc/injectables/FooterService.html +573 -0
  28. package/compodoc/injectables/HeaderService.html +576 -0
  29. package/compodoc/injectables/LayoutService.html +899 -0
  30. package/compodoc/injectables/LogoService.html +411 -0
  31. package/compodoc/injectables/NavigationService.html +46 -57
  32. package/compodoc/interfaces/ReleaseInfoModule.html +385 -0
  33. package/compodoc/interfaces/SettingsMenuItem.html +385 -0
  34. package/compodoc/js/menu-wc.js +24 -40
  35. package/compodoc/js/menu-wc_es5.js +1 -1
  36. package/compodoc/js/search/search_index.js +2 -2
  37. package/compodoc/miscellaneous/functions.html +532 -0
  38. package/compodoc/miscellaneous/typealiases.html +40 -2
  39. package/compodoc/miscellaneous/variables.html +123 -9
  40. package/compodoc/overview.html +2 -10
  41. package/compodoc/properties.html +1 -1
  42. package/docs/assets/highlight.css +42 -0
  43. package/docs/assets/navigation.js +1 -1
  44. package/docs/assets/search.js +1 -1
  45. package/docs/classes/AppsButtonComponent.html +8 -8
  46. package/docs/classes/BaseLayoutComponent.html +2 -0
  47. package/docs/classes/DefaultHeaderComponent.html +7 -0
  48. package/docs/classes/ExternalAppsService.html +19 -0
  49. package/docs/classes/FooterComponent.html +5 -3
  50. package/docs/classes/FooterDirective.html +2 -2
  51. package/docs/classes/FooterService.html +14 -0
  52. package/docs/classes/HeaderComponent.html +6 -8
  53. package/docs/classes/HeaderDirective.html +8 -0
  54. package/docs/classes/HeaderService.html +14 -0
  55. package/docs/classes/LayoutComponent.html +4 -12
  56. package/docs/classes/LayoutService.html +20 -0
  57. package/docs/classes/LogoService.html +7 -0
  58. package/docs/classes/MinimalLayoutComponent.html +2 -0
  59. package/docs/classes/NavigationComponent.html +7 -8
  60. package/docs/classes/NavigationItemComponent.html +6 -9
  61. package/docs/classes/NavigationProgressBarComponent.html +3 -3
  62. package/docs/classes/NavigationService.html +3 -3
  63. package/docs/classes/ReleaseInfoComponent.html +6 -0
  64. package/docs/classes/SettingsButtonComponent.html +6 -11
  65. package/docs/classes/SidenavComponent.html +17 -5
  66. package/docs/classes/SidenavFooterDirective.html +2 -2
  67. package/docs/classes/SidenavHeaderDirective.html +2 -2
  68. package/docs/classes/SidenavToggleButtonComponent.html +4 -3
  69. package/docs/classes/UserProfileIconComponent.html +5 -4
  70. package/docs/documentation.json +9635 -9292
  71. package/docs/functions/IsNavigationDividerItem.html +1 -1
  72. package/docs/functions/IsNavigationInsertItem.html +1 -1
  73. package/docs/functions/IsNavigationItem.html +1 -1
  74. package/docs/functions/provideLayout.html +1 -0
  75. package/docs/functions/widthDefaultHeaderComponent.html +1 -0
  76. package/docs/functions/withExternalApps.html +1 -0
  77. package/docs/functions/withFooterComponents.html +1 -0
  78. package/docs/functions/withHeaderComponents.html +1 -0
  79. package/docs/functions/withNavigationConfig.html +1 -0
  80. package/docs/functions/withNavigationInserts.html +1 -0
  81. package/docs/functions/withReleaseInfoModules.html +1 -0
  82. package/docs/functions/withSettingsMenuItems.html +1 -0
  83. package/docs/index.html +65 -2
  84. package/docs/interfaces/NavigationDividerItem.html +2 -2
  85. package/docs/interfaces/NavigationInsertItem.html +2 -2
  86. package/docs/interfaces/NavigationItem.html +2 -2
  87. package/docs/interfaces/NavigationStatus.html +2 -2
  88. package/docs/interfaces/ReleaseInfoModule.html +4 -0
  89. package/docs/interfaces/SettingsMenuItem.html +4 -0
  90. package/docs/modules.html +31 -17
  91. package/docs/types/ExternalApp.html +1 -0
  92. package/docs/types/ExtractUsernameFromProfileFn.html +1 -1
  93. package/docs/types/Navigation.html +1 -1
  94. package/docs/types/NavigationWithInserts.html +1 -1
  95. package/docs/types/SettingsMenuItemComponent.html +1 -0
  96. package/docs/variables/EXTRACT_USERNAME_FROM_PROFILE.html +1 -1
  97. package/docs/variables/RXAP_EXTERNAL_APP.html +1 -0
  98. package/docs/variables/RXAP_EXTERNAL_APP_FILTER.html +1 -0
  99. package/docs/variables/RXAP_FOOTER_COMPONENT.html +1 -1
  100. package/docs/variables/RXAP_HEADER_COMPONENT.html +1 -1
  101. package/docs/variables/RXAP_LAYOUT_APPS_GRID.html +1 -1
  102. package/docs/variables/RXAP_LOGO_CONFIG.html +1 -1
  103. package/docs/variables/RXAP_NAVIGATION_CONFIG.html +1 -1
  104. package/docs/variables/RXAP_NAVIGATION_CONFIG_INSERTS.html +1 -1
  105. package/docs/variables/RXAP_RELEASE_INFO_MODULE.html +1 -0
  106. package/docs/variables/RXAP_SETTINGS_MENU_ITEM.html +1 -0
  107. package/docs/variables/RXAP_SETTINGS_MENU_ITEM_COMPONENT.html +1 -0
  108. package/esm2022/index.mjs +35 -40
  109. package/esm2022/lib/base-layout/base-layout.component.mjs +16 -0
  110. package/esm2022/lib/default-header/apps-button/apps-button.component.mjs +40 -0
  111. package/esm2022/lib/default-header/default-header.component.mjs +32 -0
  112. package/esm2022/lib/default-header/settings-button/settings-button.component.mjs +73 -0
  113. package/esm2022/lib/default-header/sidenav-toggle-button/sidenav-toggle-button.component.mjs +24 -0
  114. package/esm2022/lib/default-header/user-profile-icon/user-profile-icon.component.mjs +35 -0
  115. package/esm2022/lib/external-apps.service.mjs +99 -0
  116. package/esm2022/lib/footer/footer.component.mjs +13 -13
  117. package/esm2022/lib/footer/footer.directive.mjs +30 -0
  118. package/esm2022/lib/footer.service.mjs +58 -0
  119. package/esm2022/lib/header/header.component.mjs +17 -65
  120. package/esm2022/lib/header/header.directive.mjs +30 -0
  121. package/esm2022/lib/header.service.mjs +60 -0
  122. package/esm2022/lib/layout/layout.component.mjs +33 -47
  123. package/esm2022/lib/layout.service.mjs +93 -0
  124. package/esm2022/lib/logo.service.mjs +23 -0
  125. package/esm2022/lib/minimal-layout/minimal-layout.component.mjs +14 -0
  126. package/esm2022/lib/navigation/navigation-item/navigation-item.component.mjs +30 -64
  127. package/esm2022/lib/navigation/navigation.component.mjs +22 -48
  128. package/esm2022/lib/navigation-progress-bar/navigation-progress-bar.component.mjs +23 -0
  129. package/esm2022/lib/navigation.service.mjs +141 -0
  130. package/esm2022/lib/provide.mjs +80 -0
  131. package/esm2022/lib/release-info/release-info.component.mjs +28 -0
  132. package/esm2022/lib/sidenav/sidenav.component.mjs +50 -33
  133. package/esm2022/lib/tokens.mjs +10 -1
  134. package/esm2022/lib/types.mjs +1 -1
  135. package/fesm2022/rxap-layout.mjs +856 -833
  136. package/fesm2022/rxap-layout.mjs.map +1 -1
  137. package/index.d.ts +18 -19
  138. package/lib/base-layout/base-layout.component.d.ts +5 -0
  139. package/lib/default-header/apps-button/apps-button.component.d.ts +15 -0
  140. package/lib/default-header/default-header.component.d.ts +11 -0
  141. package/lib/{header → default-header}/settings-button/settings-button.component.d.ts +6 -14
  142. package/lib/{header → default-header}/sidenav-toggle-button/sidenav-toggle-button.component.d.ts +3 -5
  143. package/lib/default-header/user-profile-icon/user-profile-icon.component.d.ts +10 -0
  144. package/lib/external-apps.service.d.ts +26 -0
  145. package/lib/footer/footer.component.d.ts +3 -3
  146. package/lib/{footer.directive.d.ts → footer/footer.directive.d.ts} +2 -4
  147. package/lib/footer.service.d.ts +32 -0
  148. package/lib/header/header.component.d.ts +6 -12
  149. package/lib/header/header.directive.d.ts +12 -0
  150. package/lib/header.service.d.ts +34 -0
  151. package/lib/layout/layout.component.d.ts +4 -17
  152. package/lib/layout.service.d.ts +26 -0
  153. package/lib/logo.service.d.ts +10 -0
  154. package/lib/minimal-layout/minimal-layout.component.d.ts +5 -0
  155. package/lib/navigation/navigation-item/navigation-item.component.d.ts +10 -18
  156. package/lib/navigation/navigation.component.d.ts +10 -15
  157. package/lib/{header/navigation-progress-bar → navigation-progress-bar}/navigation-progress-bar.component.d.ts +1 -3
  158. package/lib/{navigation/navigation.service.d.ts → navigation.service.d.ts} +4 -5
  159. package/lib/provide.d.ts +13 -0
  160. package/lib/release-info/release-info.component.d.ts +9 -0
  161. package/lib/sidenav/sidenav.component.d.ts +18 -6
  162. package/lib/tokens.d.ts +12 -3
  163. package/lib/types.d.ts +15 -4
  164. package/package.json +30 -66
  165. package/theme.css +1 -1
  166. package/docs/classes/AppUrlService.html +0 -13
  167. package/docs/classes/AuthenticationServiceMock.html +0 -3
  168. package/docs/classes/LanguageSelectorComponent.html +0 -3
  169. package/docs/classes/LayoutComponentService.html +0 -15
  170. package/docs/classes/ReplaceRouterPathsPipe.html +0 -4
  171. package/docs/classes/ReplaceRouterPathsService.html +0 -3
  172. package/docs/classes/ResetButtonComponent.html +0 -3
  173. package/docs/classes/SidenavComponentService.html +0 -5
  174. package/docs/classes/SignOutComponent.html +0 -4
  175. package/docs/classes/ToggleWindowSidenavButtonComponent.html +0 -5
  176. package/docs/classes/VersionComponent.html +0 -7
  177. package/docs/classes/WindowContainerSidenavComponent.html +0 -10
  178. package/docs/interfaces/ExternalApps.html +0 -8
  179. package/docs/interfaces/LogoConfig.html +0 -4
  180. package/esm2022/lib/app-url.service.mjs +0 -78
  181. package/esm2022/lib/authentication.service.mock.mjs +0 -13
  182. package/esm2022/lib/footer.directive.mjs +0 -40
  183. package/esm2022/lib/header/apps-button/apps-button.component.mjs +0 -46
  184. package/esm2022/lib/header/language-selector/language-selector.component.mjs +0 -35
  185. package/esm2022/lib/header/navigation-progress-bar/navigation-progress-bar.component.mjs +0 -30
  186. package/esm2022/lib/header/reset-button/reset-button.component.mjs +0 -23
  187. package/esm2022/lib/header/settings-button/settings-button.component.mjs +0 -87
  188. package/esm2022/lib/header/sidenav-toggle-button/sidenav-toggle-button.component.mjs +0 -26
  189. package/esm2022/lib/header/sign-out/sign-out.component.mjs +0 -23
  190. package/esm2022/lib/header/user-profile-icon/user-profile-icon.component.mjs +0 -45
  191. package/esm2022/lib/layout/layout.component.service.mjs +0 -77
  192. package/esm2022/lib/navigation/navigation.service.mjs +0 -145
  193. package/esm2022/lib/navigation/replace-router-paths.pipe.mjs +0 -22
  194. package/esm2022/lib/navigation/replace-router-paths.service.mjs +0 -15
  195. package/esm2022/lib/sidenav/sidenav.component.service.mjs +0 -22
  196. package/esm2022/lib/sidenav/version/version.component.mjs +0 -28
  197. package/esm2022/lib/toggle-window-sidenav-button/toggle-window-sidenav-button.component.mjs +0 -30
  198. package/esm2022/lib/window-container-sidenav/window-container-sidenav.component.mjs +0 -54
  199. package/lib/app-url.service.d.ts +0 -29
  200. package/lib/authentication.service.mock.d.ts +0 -6
  201. package/lib/header/apps-button/apps-button.component.d.ts +0 -16
  202. package/lib/header/language-selector/language-selector.component.d.ts +0 -8
  203. package/lib/header/reset-button/reset-button.component.d.ts +0 -8
  204. package/lib/header/sign-out/sign-out.component.d.ts +0 -9
  205. package/lib/header/user-profile-icon/user-profile-icon.component.d.ts +0 -15
  206. package/lib/layout/layout.component.service.d.ts +0 -25
  207. package/lib/navigation/replace-router-paths.pipe.d.ts +0 -11
  208. package/lib/navigation/replace-router-paths.service.d.ts +0 -7
  209. package/lib/sidenav/sidenav.component.service.d.ts +0 -11
  210. package/lib/sidenav/version/version.component.d.ts +0 -14
  211. package/lib/toggle-window-sidenav-button/toggle-window-sidenav-button.component.d.ts +0 -9
  212. package/lib/window-container-sidenav/window-container-sidenav.component.d.ts +0 -17
@@ -1,151 +1,36 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Component, ChangeDetectionStrategy, Inject, EventEmitter, Input, Output, TemplateRef, Directive, Injectable, signal, ElementRef, Renderer2, ViewContainerRef, ViewEncapsulation, forwardRef, ViewChild, HostBinding, InjectionToken, INJECTOR, Optional, ChangeDetectorRef, ContentChild, Pipe, computed, effect, LOCALE_ID, isDevMode, inject } from '@angular/core';
3
- import * as i1$1 from '@rxap/services';
4
- import { WindowContainerSidenavService, VersionService, HeaderService, ResetService, FooterService } from '@rxap/services';
5
- import * as i1 from '@angular/cdk/portal';
6
- import { ComponentPortal, PortalModule, TemplatePortal } from '@angular/cdk/portal';
7
- import { tap, filter, startWith, switchMap, catchError, map } from 'rxjs/operators';
8
- import { Subscription, BehaviorSubject, debounceTime, ReplaySubject, of, from, combineLatest, firstValueFrom, switchMap as switchMap$1, filter as filter$1, skip, distinctUntilChanged } from 'rxjs';
9
- import * as i4$1 from '@angular/common';
10
- import { NgFor, NgIf, KeyValuePipe, NgClass, AsyncPipe, NgTemplateOutlet, NgOptimizedImage, CommonModule, NgStyle } from '@angular/common';
11
- import * as i4 from '@angular/material/icon';
12
- import { MatIconModule } from '@angular/material/icon';
13
- import * as i3 from '@angular/material/button';
14
- import { MatButtonModule } from '@angular/material/button';
15
- import * as i1$2 from '@rxap/config';
2
+ import { TemplateRef, Directive, Inject, InjectionToken, inject, signal, computed, isDevMode, Injectable, effect, INJECTOR, Optional, input, ElementRef, Renderer2, Component, ChangeDetectionStrategy, ViewEncapsulation, forwardRef, runInInjectionContext, viewChild, contentChild, ViewContainerRef, Injector, LOCALE_ID } from '@angular/core';
3
+ import { NgIf, NgClass, NgFor, AsyncPipe, NgStyle, NgTemplateOutlet, NgOptimizedImage } from '@angular/common';
4
+ import { MatIconButton, MatButton, MatButtonModule, MatAnchor } from '@angular/material/button';
5
+ import * as i3 from '@angular/material/divider';
6
+ import { MatDividerModule, MatDivider } from '@angular/material/divider';
7
+ import * as i2 from '@angular/material/icon';
8
+ import { MatIconModule, MatIcon } from '@angular/material/icon';
9
+ import { MatSidenav, MatSidenavContainer, MatSidenavContent, MatSidenavModule } from '@angular/material/sidenav';
10
+ import { Router, NavigationEnd, RouterLinkActive, RouterLink, RouterOutlet, NavigationStart, NavigationCancel } from '@angular/router';
11
+ import { MediaMatcher } from '@angular/cdk/layout';
12
+ import { toSignal } from '@angular/core/rxjs-interop';
16
13
  import { ConfigService } from '@rxap/config';
17
- import * as i3$1 from '@angular/material/divider';
18
- import { MatDividerModule } from '@angular/material/divider';
19
- import { coerceBoolean, JoinPath } from '@rxap/utilities';
14
+ import { ObserveCurrentThemeDensity, ThemeService } from '@rxap/ngx-theme';
15
+ import { Observable, ReplaySubject, of, from, combineLatest, Subscription, debounceTime } from 'rxjs';
16
+ import * as i2$1 from '@angular/cdk/portal';
17
+ import { ComponentPortal, PortalModule, CdkPortalOutlet, TemplatePortal } from '@angular/cdk/portal';
18
+ import { coerceArray, JoinPath } from '@rxap/utilities';
19
+ import { switchMap, catchError, map, filter, startWith, tap } from 'rxjs/operators';
20
20
  import { trigger, transition, style, animate } from '@angular/animations';
21
- import * as i2 from '@angular/router';
22
- import { NavigationEnd, Router, RouterLinkActive, RouterLink, NavigationStart, NavigationCancel, RouterOutlet } from '@angular/router';
23
- import * as i6 from '@angular/cdk/overlay';
24
- import { Overlay } from '@angular/cdk/overlay';
21
+ import * as i1 from '@angular/material/core';
22
+ import { MatRippleModule } from '@angular/material/core';
25
23
  import { IconDirective } from '@rxap/material-directives/icon';
26
- import * as i1$3 from '@angular/material/core';
27
- import { MatRippleModule, MatOptionModule } from '@angular/material/core';
28
- import * as i2$1 from '@angular/cdk/layout';
29
- import { toSignal } from '@angular/core/rxjs-interop';
30
- import * as i1$6 from '@rxap/ngx-theme';
31
- import { ObserveCurrentThemeDensity, ThemeService } from '@rxap/ngx-theme';
32
- import * as i7 from '@angular/material/menu';
33
- import { MatMenuModule } from '@angular/material/menu';
34
- import * as i3$4 from '@angular/material/sidenav';
35
- import { MatSidenav, MatSidenavModule } from '@angular/material/sidenav';
36
- import { RXAP_ENVIRONMENT, DetermineReleaseName } from '@rxap/environment';
37
- import * as i2$6 from '@rxap/icon';
38
- import { StatusIndicatorComponent } from '@rxap/ngx-status-check';
39
- import * as i1$7 from '@rxap/ngx-user';
40
- import { UserSettingsThemeService, IsThemeDensity, ThemeDensity } from '@rxap/ngx-user';
41
- import * as i2$2 from '@angular/material/toolbar';
42
- import { MatToolbarModule } from '@angular/material/toolbar';
43
- import * as i5 from '@angular/forms';
44
- import { FormsModule } from '@angular/forms';
45
- import * as i2$5 from '@angular/material/form-field';
46
- import { MatFormFieldModule } from '@angular/material/form-field';
47
- import * as i3$2 from '@angular/material/select';
48
- import { MatSelectModule } from '@angular/material/select';
49
- import { MatSlideToggleModule } from '@angular/material/slide-toggle';
50
- import { DataSourceCollectionDirective } from '@rxap/data-source/directive';
51
- import { StopPropagationDirective } from '@rxap/directives';
52
- import * as i2$3 from '@rxap/authorization';
24
+ import { MatDialog } from '@angular/material/dialog';
25
+ import { DetermineReleaseName, RXAP_ENVIRONMENT, EnvironmentComponent } from '@rxap/environment';
26
+ import { MatProgressBar } from '@angular/material/progress-bar';
27
+ import * as i1$1 from '@angular/material/toolbar';
28
+ import { MatToolbarModule, MatToolbar, MatToolbarRow } from '@angular/material/toolbar';
29
+ import * as i1$2 from '@angular/material/menu';
30
+ import { MatMenuModule, MatMenu, MatMenuTrigger, MatMenuItem } from '@angular/material/menu';
31
+ import { UserSettingsThemeService, IsThemeDensity, ThemeDensity, UserProfileDataSource } from '@rxap/ngx-user';
32
+ import { PubSubService } from '@rxap/ngx-pub-sub';
53
33
  import { ClickOnLink } from '@rxap/browser-utilities';
54
- import * as i2$4 from '@rxap/authentication';
55
- import * as i1$4 from '@angular/material/progress-bar';
56
- import { MatProgressBarModule } from '@angular/material/progress-bar';
57
- import * as i3$3 from '@rxap/ngx-changelog';
58
- import * as i1$5 from '@rxap/ngx-localize';
59
-
60
- class WindowContainerSidenavComponent {
61
- constructor(service) {
62
- this.service = service;
63
- this.portals = new Map();
64
- this.subscription = new Subscription();
65
- }
66
- ngOnInit() {
67
- const components = this.service.getAll();
68
- for (const component of components) {
69
- this.add(component);
70
- }
71
- this.subscription.add(this.service.add$.pipe(tap(component => this.add(component))).subscribe());
72
- this.subscription.add(this.service.remove$.pipe(tap(component => this.remove(component))).subscribe());
73
- }
74
- ngOnDestroy() {
75
- this.subscription.unsubscribe();
76
- }
77
- trackBy(index, id) {
78
- return id;
79
- }
80
- add(component) {
81
- if (this.portals.has(component.id)) {
82
- throw new Error(`Component portal with id ${component.id} already exists`);
83
- }
84
- const portal = new ComponentPortal(component.component, component.viewContainerRef, component.injector, component.componentFactoryResolver);
85
- this.portals.set(component.id, portal);
86
- }
87
- remove(component) {
88
- if (this.portals.has(component.id)) {
89
- const portal = this.portals.get(component.id);
90
- this.portals.delete(component.id);
91
- portal.detach();
92
- }
93
- }
94
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: WindowContainerSidenavComponent, deps: [{ token: WindowContainerSidenavService }], target: i0.ɵɵFactoryTarget.Component }); }
95
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.1", type: WindowContainerSidenavComponent, isStandalone: true, selector: "rxap-window-container-sidenav", ngImport: i0, template: "<div class=\"flex flex-col gap-4 p-2\">\n\n <div *ngFor=\"let portalId of portals.keys(); trackBy: trackBy\" class=\"grow-0\">\n <ng-template [cdkPortalOutlet]=\"portals.get(portalId)\"></ng-template>\n </div>\n\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: PortalModule }, { kind: "directive", type: i1.CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
96
- }
97
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: WindowContainerSidenavComponent, decorators: [{
98
- type: Component,
99
- args: [{ selector: 'rxap-window-container-sidenav', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [NgFor, PortalModule], template: "<div class=\"flex flex-col gap-4 p-2\">\n\n <div *ngFor=\"let portalId of portals.keys(); trackBy: trackBy\" class=\"grow-0\">\n <ng-template [cdkPortalOutlet]=\"portals.get(portalId)\"></ng-template>\n </div>\n\n</div>\n" }]
100
- }], ctorParameters: () => [{ type: i1$1.WindowContainerSidenavService, decorators: [{
101
- type: Inject,
102
- args: [WindowContainerSidenavService]
103
- }] }] });
104
-
105
- class ToggleWindowSidenavButtonComponent {
106
- constructor() {
107
- this.openWindowSidenav = false;
108
- this.openWindowSidenavChange = new EventEmitter();
109
- }
110
- toggle() {
111
- this.openWindowSidenav = !this.openWindowSidenav;
112
- this.openWindowSidenavChange.emit(this.openWindowSidenav);
113
- }
114
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: ToggleWindowSidenavButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
115
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.1", type: ToggleWindowSidenavButtonComponent, isStandalone: true, selector: "rxap-toggle-window-sidenav-button", inputs: { openWindowSidenav: "openWindowSidenav" }, outputs: { openWindowSidenavChange: "openWindowSidenavChange" }, host: { classAttribute: "rxap-toggle-window-sidenav-button" }, ngImport: i0, template: "<div class=\"toggle-button\">\n <button (click)=\"toggle()\" mat-icon-button>\n <ng-template [ngIfElse]=\"hide\" [ngIf]=\"!openWindowSidenav\">\n <mat-icon svgIcon=\"arrow-left-bold\"></mat-icon>\n </ng-template>\n <ng-template #hide>\n <mat-icon svgIcon=\"arrow-right-bold\"></mat-icon>\n </ng-template>\n </button>\n</div>\n", styles: [".toggle-button{position:absolute;top:70px;right:0;z-index:10000;border-radius:15px 0 0 15px;border:1px solid black;background:#000}\n"], dependencies: [{ kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
116
- }
117
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: ToggleWindowSidenavButtonComponent, decorators: [{
118
- type: Component,
119
- args: [{ selector: 'rxap-toggle-window-sidenav-button', changeDetection: ChangeDetectionStrategy.OnPush, host: {
120
- class: 'rxap-toggle-window-sidenav-button',
121
- }, standalone: true, imports: [MatButtonModule, NgIf, MatIconModule], template: "<div class=\"toggle-button\">\n <button (click)=\"toggle()\" mat-icon-button>\n <ng-template [ngIfElse]=\"hide\" [ngIf]=\"!openWindowSidenav\">\n <mat-icon svgIcon=\"arrow-left-bold\"></mat-icon>\n </ng-template>\n <ng-template #hide>\n <mat-icon svgIcon=\"arrow-right-bold\"></mat-icon>\n </ng-template>\n </button>\n</div>\n", styles: [".toggle-button{position:absolute;top:70px;right:0;z-index:10000;border-radius:15px 0 0 15px;border:1px solid black;background:#000}\n"] }]
122
- }], propDecorators: { openWindowSidenav: [{
123
- type: Input
124
- }], openWindowSidenavChange: [{
125
- type: Output
126
- }] } });
127
-
128
- class VersionComponent {
129
- constructor(version) {
130
- this.version = version;
131
- }
132
- ngOnInit() {
133
- this.modules = this.version.get();
134
- this.subscription = this.version.update$.pipe(tap(() => this.modules = this.version.get())).subscribe();
135
- }
136
- ngOnDestroy() {
137
- this.subscription?.unsubscribe();
138
- }
139
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: VersionComponent, deps: [{ token: VersionService }], target: i0.ɵɵFactoryTarget.Component }); }
140
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.1", type: VersionComponent, isStandalone: true, selector: "rxap-version", ngImport: i0, template: "<div class=\"version flex flex-col gap-2\">\n <div *ngFor=\"let module of modules | keyvalue\" class=\"flex flex-col\">\n <span class=\"name grow-0\">{{module.value.name}}</span>\n <span class=\"semantic grow-0\">{{module.value.semantic}}</span>\n <span class=\"hash grow-0\">{{module.value.hash}}</span>\n </div>\n</div>\n", styles: [".version{width:100%;font-size:9px;padding:8px}.version .name{padding-bottom:12px;font-size:10px}\n"], dependencies: [{ kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "pipe", type: KeyValuePipe, name: "keyvalue" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
141
- }
142
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: VersionComponent, decorators: [{
143
- type: Component,
144
- args: [{ selector: 'rxap-version', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [NgFor, KeyValuePipe], template: "<div class=\"version flex flex-col gap-2\">\n <div *ngFor=\"let module of modules | keyvalue\" class=\"flex flex-col\">\n <span class=\"name grow-0\">{{module.value.name}}</span>\n <span class=\"semantic grow-0\">{{module.value.semantic}}</span>\n <span class=\"hash grow-0\">{{module.value.hash}}</span>\n </div>\n</div>\n", styles: [".version{width:100%;font-size:9px;padding:8px}.version .name{padding-bottom:12px;font-size:10px}\n"] }]
145
- }], ctorParameters: () => [{ type: i1$1.VersionService, decorators: [{
146
- type: Inject,
147
- args: [VersionService]
148
- }] }] });
149
34
 
150
35
  class SidenavFooterDirective {
151
36
  constructor(template) {
@@ -183,170 +68,213 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImpor
183
68
  args: [TemplateRef]
184
69
  }] }] });
185
70
 
186
- class SidenavComponentService {
187
- constructor(config) {
188
- this.config = config;
189
- this.collapsed$ = new BehaviorSubject(true);
190
- this.collapsed$.next(this.config.get('navigation.collapsed', this.collapsed$.value));
71
+ const RXAP_NAVIGATION_CONFIG = new InjectionToken('rxap/layout/navigation-config');
72
+ const RXAP_NAVIGATION_CONFIG_INSERTS = new InjectionToken('rxap/layout/navigation-config-inserts');
73
+ const RXAP_FOOTER_COMPONENT = new InjectionToken('rxap/layout/footer-component');
74
+ const RXAP_HEADER_COMPONENT = new InjectionToken('rxap/layout/header-component');
75
+ const RXAP_LOGO_CONFIG = new InjectionToken('rxap/layout/logo-config');
76
+ const RXAP_LAYOUT_APPS_GRID = new InjectionToken('rxap/layout/apps-grid');
77
+ const RXAP_EXTERNAL_APP_FILTER = new InjectionToken('rxap/layout/app-config-filter');
78
+ const EXTRACT_USERNAME_FROM_PROFILE = new InjectionToken('extract-username-from-profile', {
79
+ providedIn: 'root',
80
+ factory: () => (profile) => (profile ? profile.username ?? profile.email ?? profile.name : null) ?? null,
81
+ });
82
+ const RXAP_EXTERNAL_APP = new InjectionToken('rxap/layout/external-app');
83
+ const RXAP_RELEASE_INFO_MODULE = new InjectionToken('rxap/layout/release-info-module');
84
+ const RXAP_SETTINGS_MENU_ITEM_COMPONENT = new InjectionToken('rxap/layout/settings-menu-item-component');
85
+ const RXAP_SETTINGS_MENU_ITEM = new InjectionToken('rxap/layout/settings-menu-item');
86
+
87
+ class FooterService {
88
+ constructor() {
89
+ this.components = coerceArray(inject(RXAP_FOOTER_COMPONENT, { optional: true }));
90
+ /**
91
+ * Represents an array of `Portal` objects with unknown type.
92
+ */
93
+ this.portals = signal(this.components.map(component => new ComponentPortal(component)));
94
+ /**
95
+ * Computes the count of portals.
96
+ *
97
+ * @returns {number} The count of portals.
98
+ */
99
+ this.portalCount = computed(() => this.portals().length);
191
100
  }
192
- toggleNavigationCollapse() {
193
- this.collapsed$.next(!this.collapsed$.value);
101
+ /**
102
+ * Adds a portal to the list of portals.
103
+ *
104
+ * @param {Portal<unknown>} portal - The portal to be added.
105
+ *
106
+ * @return {void}
107
+ */
108
+ pushPortal(portal) {
109
+ if (!this.portals().includes(portal)) {
110
+ this.portals.update(portals => [...portals, portal]);
111
+ }
112
+ else {
113
+ if (isDevMode()) {
114
+ console.warn('Can not add the same portal multiple times');
115
+ }
116
+ }
117
+ }
118
+ /**
119
+ * Removes a portal from the list of portals.
120
+ *
121
+ * @param {Portal<unknown>} portal - The portal to be removed.
122
+ * @return {void}
123
+ */
124
+ removePortal(portal) {
125
+ const index = this.portals().indexOf(portal);
126
+ if (index !== -1) {
127
+ this.portals.update(portals => {
128
+ portals.splice(index, 1);
129
+ return portals.slice();
130
+ });
131
+ }
194
132
  }
195
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: SidenavComponentService, deps: [{ token: i1$2.ConfigService }], target: i0.ɵɵFactoryTarget.Injectable }); }
196
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: SidenavComponentService, providedIn: 'root' }); }
133
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: FooterService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
134
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: FooterService }); }
197
135
  }
198
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: SidenavComponentService, decorators: [{
199
- type: Injectable,
200
- args: [{ providedIn: 'root' }]
201
- }], ctorParameters: () => [{ type: i1$2.ConfigService }] });
136
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: FooterService, decorators: [{
137
+ type: Injectable
138
+ }] });
202
139
 
203
- class NavigationItemComponent {
204
- get isActive() {
205
- return this._isActive;
206
- }
207
- set isActive(value) {
208
- this._isActive = value;
209
- this.active.set(value);
210
- }
211
- constructor(router, sidenav, elementRef, renderer, overlay, viewContainerRef) {
212
- this.router = router;
213
- this.sidenav = sidenav;
214
- this.elementRef = elementRef;
215
- this.renderer = renderer;
216
- this.overlay = overlay;
217
- this.viewContainerRef = viewContainerRef;
218
- this.level = 0;
219
- this._isActive = false;
220
- this.children = null;
221
- this.active = signal(false);
222
- this._subscription = new Subscription();
140
+ class HeaderService {
141
+ constructor() {
142
+ this.components = coerceArray(inject(RXAP_HEADER_COMPONENT, { optional: true }));
143
+ /**
144
+ * Represents an array of `Portal` objects with unknown type.
145
+ *
146
+ * @typedef {Array<Portal<unknown>>} SignalPortals
147
+ */
148
+ this.portals = signal(this.components.map(component => new ComponentPortal(component)));
149
+ /**
150
+ * Computes the count of portals.
151
+ *
152
+ * @returns {number} The count of portals.
153
+ */
154
+ this.portalCount = computed(() => this.portals().length);
223
155
  }
224
- ngOnChanges(changes) {
225
- if (changes['item']) {
226
- const item = changes['item'].currentValue;
227
- this.children =
228
- item.children && item.children.length ? item.children : null;
156
+ /**
157
+ * Adds a portal to the list of portals.
158
+ *
159
+ * @param {Portal<unknown>} portal - The portal to be added.
160
+ *
161
+ * @return {void}
162
+ */
163
+ pushPortal(portal) {
164
+ if (!this.portals().includes(portal)) {
165
+ this.portals.update(portals => [...portals, portal]);
229
166
  }
230
- }
231
- ngAfterViewInit() {
232
- this._subscription.add(this.router.events
233
- .pipe(filter((event) => event instanceof NavigationEnd), debounceTime(100), startWith(true), tap(() => {
234
- let isActive = true;
235
- const urlParts = this.router.url.split('/');
236
- if (urlParts[0] === '') {
237
- urlParts[0] = '/';
167
+ else {
168
+ if (isDevMode()) {
169
+ console.warn('Can not add the same portal multiple times');
238
170
  }
239
- for (let i = 0; i < this.item.routerLink.length; i++) {
240
- if (urlParts[i] !== this.item.routerLink[i]) {
241
- isActive = false;
242
- break;
171
+ }
172
+ }
173
+ /**
174
+ * Removes a portal from the list of portals.
175
+ *
176
+ * @param {Portal<unknown>} portal - The portal to be removed.
177
+ * @return {void}
178
+ */
179
+ removePortal(portal) {
180
+ const index = this.portals().indexOf(portal);
181
+ if (index !== -1) {
182
+ this.portals.update(portals => {
183
+ portals.splice(index, 1);
184
+ return portals.slice();
185
+ });
186
+ }
187
+ }
188
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: HeaderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
189
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: HeaderService }); }
190
+ }
191
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: HeaderService, decorators: [{
192
+ type: Injectable
193
+ }] });
194
+
195
+ class LayoutService {
196
+ constructor() {
197
+ this.currentThemeDensity = toSignal(ObserveCurrentThemeDensity());
198
+ this.footerService = inject(FooterService);
199
+ this.headerService = inject(HeaderService);
200
+ this.config = inject(ConfigService);
201
+ this.mediaMatcher = inject(MediaMatcher);
202
+ const mobileQuery = this.mediaMatcher.matchMedia('(max-width: 959px)');
203
+ this.isMobile = toSignal(new Observable(subscriber => {
204
+ mobileQuery.addEventListener('change', (event) => {
205
+ subscriber.next(event.matches);
206
+ });
207
+ }), { initialValue: mobileQuery.matches });
208
+ const initialCollapsable = this.config.get('navigation.collapsable', true);
209
+ const collapsable = initialCollapsable && !this.isMobile();
210
+ const pinned = this.config.get('navigation.pinned', false);
211
+ const mode = this.config.get('navigation.mode', pinned || !collapsable ? 'side' : 'over');
212
+ const opened = this.config.get('navigation.opened', (!collapsable || pinned) && !this.isMobile());
213
+ const fixedInViewport = this.config.get('navigation.fixedInViewport', true);
214
+ if (isDevMode()) {
215
+ console.log({
216
+ initialCollapsable,
217
+ collapsable,
218
+ pinned,
219
+ mode,
220
+ opened,
221
+ fixedInViewport,
222
+ });
223
+ }
224
+ this.opened = signal(opened);
225
+ this.mode = signal(mode);
226
+ this.pinned = signal(pinned);
227
+ this.collapsable = signal(collapsable);
228
+ this.fixedInViewport = signal(fixedInViewport);
229
+ this.collapsed = computed(() => this.collapsable() && !this.opened() && !this.pinned());
230
+ this.fixedBottomGap = computed(() => {
231
+ const footerPortalCount = this.footerService.portalCount();
232
+ const currentThemeDensity = this.currentThemeDensity() ?? 0;
233
+ return footerPortalCount * (currentThemeDensity * 4 + 64);
234
+ });
235
+ this.fixedTopGap = computed(() => {
236
+ const headerPortalCount = this.headerService.portalCount();
237
+ const currentThemeDensity = this.currentThemeDensity() ?? 0;
238
+ return headerPortalCount * (currentThemeDensity * 4 + 64);
239
+ });
240
+ if (initialCollapsable) {
241
+ effect(() => {
242
+ const isMobile = this.isMobile();
243
+ this.collapsable.set(!isMobile);
244
+ if (!isMobile && !this.pinned()) {
245
+ this.opened.set(false);
243
246
  }
244
- }
245
- this.isActive = isActive;
246
- if (isActive) {
247
- this.renderer.addClass(this.elementRef.nativeElement, 'active');
247
+ }, { allowSignalWrites: true });
248
+ }
249
+ effect(() => {
250
+ if (this.pinned()) {
251
+ this.mode.set('side');
252
+ this.opened.set(true);
248
253
  }
249
254
  else {
250
- this.renderer.removeClass(this.elementRef.nativeElement, 'active');
255
+ this.mode.set('over');
256
+ this.opened.set(false);
251
257
  }
252
- }))
253
- .subscribe());
258
+ }, { allowSignalWrites: true });
254
259
  }
255
- ngOnDestroy() {
256
- this._subscription?.unsubscribe();
260
+ toggleOpened() {
261
+ this.opened.update(opened => !opened);
257
262
  }
258
- // region type save item property
259
- // required to check the type of the item property in the ngFor loop
260
- isNavigationDividerItem(item) {
261
- return item['divider'];
263
+ togglePinned() {
264
+ this.pinned.update(pinned => !pinned);
262
265
  }
263
- isNavigationItem(item) {
264
- return !this.isNavigationDividerItem(item);
266
+ openSidenav() {
267
+ this.opened.set(true);
265
268
  }
266
- asNavigationItem(item) {
267
- if (!this.isNavigationItem(item)) {
268
- throw new Error('The item is not a NavigationItem');
269
- }
270
- return item;
269
+ closeSidenav() {
270
+ this.opened.set(false);
271
271
  }
272
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: NavigationItemComponent, deps: [{ token: Router }, { token: SidenavComponentService }, { token: ElementRef }, { token: Renderer2 }, { token: Overlay }, { token: ViewContainerRef }], target: i0.ɵɵFactoryTarget.Component }); }
273
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.1", type: NavigationItemComponent, isStandalone: true, selector: "li[rxap-navigation-item]", inputs: { level: "level", item: "item" }, host: { properties: { "class.active": "this.isActive" } }, viewQueries: [{ propertyName: "routerLinkActive", first: true, predicate: RouterLinkActive, descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<div [ngClass]=\"{\n 'border-l-4 text-accent-400 border-accent-600': active(),\n }\">\n <a [routerLink]=\"item.routerLink\"\n class=\"h-12 pl-4 pr-5 flex flex-row justify-between items-center gap-x-4\"\n matRipple\n routerLinkActive\n\n >\n <span\n [ngClass]=\"{\n 'pl-0': level === 0,\n 'pl-4': level === 1,\n 'pl-8': level === 2,\n 'pl-12': level === 3\n }\"\n class=\"grow whitespace-nowrap\"\n >\n {{ item.label }}\n </span>\n <mat-icon *ngIf=\"item.icon\" [rxapIcon]=\"item.icon\"></mat-icon>\n </a>\n\n <ng-container *ngIf=\"item.children?.length && active()\">\n\n <mat-divider></mat-divider>\n\n <ul [@sub-nav]\n [items]=\"children ?? []\"\n [level]=\"level + 1\"\n rxap-navigation\n >\n </ul>\n\n <mat-divider></mat-divider>\n\n </ng-container>\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: i0.forwardRef(() => RouterLinkActive), selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "directive", type: i0.forwardRef(() => RouterLink), selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i0.forwardRef(() => NgIf), selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: i0.forwardRef(() => MatRippleModule) }, { kind: "directive", type: i0.forwardRef(() => i1$3.MatRipple), selector: "[mat-ripple], [matRipple]", inputs: ["matRippleColor", "matRippleUnbounded", "matRippleCentered", "matRippleRadius", "matRippleAnimation", "matRippleDisabled", "matRippleTrigger"], exportAs: ["matRipple"] }, { kind: "ngmodule", type: i0.forwardRef(() => MatIconModule) }, { kind: "component", type: i0.forwardRef(() => i4.MatIcon), selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i0.forwardRef(() => IconDirective), selector: "mat-icon[rxapIcon]", inputs: ["rxapIcon"] }, { kind: "ngmodule", type: i0.forwardRef(() => MatDividerModule) }, { kind: "component", type: i0.forwardRef(() => i3$1.MatDivider), selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "component", type: i0.forwardRef(() => NavigationComponent), selector: "ul[rxap-navigation]", inputs: ["items", "level", "root"] }, { kind: "directive", type: i0.forwardRef(() => NgClass), selector: "[ngClass]", inputs: ["class", "ngClass"] }], animations: [
274
- trigger('sub-nav', [
275
- transition(':enter', [
276
- style({
277
- display: 'block',
278
- height: '0',
279
- overflow: 'hidden',
280
- }),
281
- animate(150, style({ height: '*' })),
282
- ]),
283
- transition(':leave', [
284
- style({ overflow: 'hidden' }),
285
- animate(300, style({ height: '0' })),
286
- style({ display: 'none' }),
287
- ]),
288
- ]),
289
- ], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
272
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: LayoutService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
273
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: LayoutService }); }
290
274
  }
291
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: NavigationItemComponent, decorators: [{
292
- type: Component,
293
- args: [{ selector: 'li[rxap-navigation-item]', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, animations: [
294
- trigger('sub-nav', [
295
- transition(':enter', [
296
- style({
297
- display: 'block',
298
- height: '0',
299
- overflow: 'hidden',
300
- }),
301
- animate(150, style({ height: '*' })),
302
- ]),
303
- transition(':leave', [
304
- style({ overflow: 'hidden' }),
305
- animate(300, style({ height: '0' })),
306
- style({ display: 'none' }),
307
- ]),
308
- ]),
309
- ], standalone: true, imports: [
310
- RouterLinkActive,
311
- RouterLink,
312
- NgIf,
313
- MatRippleModule,
314
- MatIconModule,
315
- IconDirective,
316
- MatDividerModule,
317
- forwardRef(() => NavigationComponent),
318
- NgClass,
319
- ], template: "<div [ngClass]=\"{\n 'border-l-4 text-accent-400 border-accent-600': active(),\n }\">\n <a [routerLink]=\"item.routerLink\"\n class=\"h-12 pl-4 pr-5 flex flex-row justify-between items-center gap-x-4\"\n matRipple\n routerLinkActive\n\n >\n <span\n [ngClass]=\"{\n 'pl-0': level === 0,\n 'pl-4': level === 1,\n 'pl-8': level === 2,\n 'pl-12': level === 3\n }\"\n class=\"grow whitespace-nowrap\"\n >\n {{ item.label }}\n </span>\n <mat-icon *ngIf=\"item.icon\" [rxapIcon]=\"item.icon\"></mat-icon>\n </a>\n\n <ng-container *ngIf=\"item.children?.length && active()\">\n\n <mat-divider></mat-divider>\n\n <ul [@sub-nav]\n [items]=\"children ?? []\"\n [level]=\"level + 1\"\n rxap-navigation\n >\n </ul>\n\n <mat-divider></mat-divider>\n\n </ng-container>\n</div>\n" }]
320
- }], ctorParameters: () => [{ type: i2.Router, decorators: [{
321
- type: Inject,
322
- args: [Router]
323
- }] }, { type: SidenavComponentService, decorators: [{
324
- type: Inject,
325
- args: [SidenavComponentService]
326
- }] }, { type: i0.ElementRef, decorators: [{
327
- type: Inject,
328
- args: [ElementRef]
329
- }] }, { type: i0.Renderer2, decorators: [{
330
- type: Inject,
331
- args: [Renderer2]
332
- }] }, { type: i6.Overlay, decorators: [{
333
- type: Inject,
334
- args: [Overlay]
335
- }] }, { type: i0.ViewContainerRef, decorators: [{
336
- type: Inject,
337
- args: [ViewContainerRef]
338
- }] }], propDecorators: { level: [{
339
- type: Input
340
- }], routerLinkActive: [{
341
- type: ViewChild,
342
- args: [RouterLinkActive, { static: true }]
343
- }], item: [{
344
- type: Input,
345
- args: [{ required: true }]
346
- }], isActive: [{
347
- type: HostBinding,
348
- args: ['class.active']
349
- }] } });
275
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: LayoutService, decorators: [{
276
+ type: Injectable
277
+ }], ctorParameters: () => [] });
350
278
 
351
279
  function IsNavigationDividerItem(item) {
352
280
  return !!item && !!item['divider'];
@@ -358,18 +286,11 @@ function IsNavigationItem(item) {
358
286
  return (!!item && !!item['routerLink'] && !!item['label']);
359
287
  }
360
288
 
361
- const RXAP_NAVIGATION_CONFIG = new InjectionToken('rxap/layout/navigation-config');
362
- const RXAP_NAVIGATION_CONFIG_INSERTS = new InjectionToken('rxap/layout/navigation-config-inserts');
363
- const RXAP_FOOTER_COMPONENT = new InjectionToken('rxap/layout/footer-component');
364
- const RXAP_HEADER_COMPONENT = new InjectionToken('rxap/layout/header-component');
365
- const RXAP_LOGO_CONFIG = new InjectionToken('rxap/layout/logo-config');
366
- const RXAP_LAYOUT_APPS_GRID = new InjectionToken('rxap/layout/apps-grid');
367
-
368
289
  class NavigationService {
369
- constructor(navigation, injector, inserts = null) {
370
- this.injector = injector;
290
+ constructor(navigation, inserts = null) {
371
291
  this.inserts = new Map();
372
292
  this.navigation$ = new ReplaySubject(1);
293
+ this.injector = inject(INJECTOR);
373
294
  if (typeof navigation === 'function') {
374
295
  this.navigation = navigation();
375
296
  }
@@ -420,7 +341,8 @@ class NavigationService {
420
341
  if (IsNavigationDividerItem(navigationItem) || !navigationItem.status) {
421
342
  return of(navigationItem);
422
343
  }
423
- const isVisibleArray$ = navigationItem.status
344
+ const isVisibleArray$ = navigationItem
345
+ .status
424
346
  .map((statusToken) => this.injector.get(statusToken))
425
347
  .map((status) => {
426
348
  const isVisible = status.isVisible(navigationItem);
@@ -432,8 +354,7 @@ class NavigationService {
432
354
  }
433
355
  })
434
356
  .map(isVisible$ => isVisible$.pipe(catchError(e => {
435
- console.error('isVisible method failed: ' +
436
- e.message);
357
+ console.error(`isVisible method failed: ${e.message}`);
437
358
  return of(false);
438
359
  })));
439
360
  // TODO : dont wait for all status services to complete, but cancel waiting if one returns false
@@ -485,18 +406,14 @@ class NavigationService {
485
406
  }
486
407
  return navigation;
487
408
  }
488
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: NavigationService, deps: [{ token: RXAP_NAVIGATION_CONFIG }, { token: INJECTOR }, { token: RXAP_NAVIGATION_CONFIG_INSERTS, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
489
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: NavigationService, providedIn: 'root' }); }
409
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: NavigationService, deps: [{ token: RXAP_NAVIGATION_CONFIG }, { token: RXAP_NAVIGATION_CONFIG_INSERTS, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); }
410
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: NavigationService }); }
490
411
  }
491
412
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: NavigationService, decorators: [{
492
- type: Injectable,
493
- args: [{ providedIn: 'root' }]
413
+ type: Injectable
494
414
  }], ctorParameters: () => [{ type: undefined, decorators: [{
495
415
  type: Inject,
496
416
  args: [RXAP_NAVIGATION_CONFIG]
497
- }] }, { type: undefined, decorators: [{
498
- type: Inject,
499
- args: [INJECTOR]
500
417
  }] }, { type: undefined, decorators: [{
501
418
  type: Optional
502
419
  }, {
@@ -504,28 +421,59 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImpor
504
421
  args: [RXAP_NAVIGATION_CONFIG_INSERTS]
505
422
  }] }] });
506
423
 
507
- class NavigationComponent {
508
- constructor(navigationService, cdr, sidenav) {
509
- this.navigationService = navigationService;
510
- this.cdr = cdr;
511
- this.sidenav = sidenav;
512
- this.level = 0;
513
- this._root = false;
514
- }
515
- set root(value) {
516
- this._root = coerceBoolean(value);
424
+ class NavigationItemComponent {
425
+ constructor() {
426
+ this.level = input(0);
427
+ this.children = null;
428
+ this.item = input.required();
429
+ this.active = signal(false);
430
+ this.itemClasses = computed(() => {
431
+ let classes = `level-${this.level() * 4}`;
432
+ if (this.collapsed()) {
433
+ classes += ' invisible';
434
+ }
435
+ return classes;
436
+ });
437
+ this.layoutService = inject(LayoutService);
438
+ this.collapsed = computed(() => this.layoutService.collapsed());
439
+ this._subscription = new Subscription();
440
+ this.router = inject(Router);
441
+ this.elementRef = inject(ElementRef);
442
+ this.renderer = inject(Renderer2);
517
443
  }
518
- ngOnInit() {
519
- if (this._root) {
520
- this.items = [];
521
- this.subscription = this.navigationService.config$
522
- .pipe(tap((navigation) => (this.items = navigation)), tap(() => this.cdr.detectChanges()))
523
- .subscribe();
444
+ ngOnChanges(changes) {
445
+ if (changes['item']) {
446
+ const item = changes['item'].currentValue;
447
+ this.children =
448
+ item.children && item.children.length ? item.children : null;
524
449
  }
525
- this.items ??= [];
450
+ }
451
+ ngAfterViewInit() {
452
+ this._subscription.add(this.router.events
453
+ .pipe(filter((event) => event instanceof NavigationEnd), debounceTime(100), startWith(true), tap(() => {
454
+ let isActive = true;
455
+ const urlParts = this.router.url.split('/');
456
+ if (urlParts[0] === '') {
457
+ urlParts[0] = '/';
458
+ }
459
+ for (let i = 0; i < this.item().routerLink.length; i++) {
460
+ if (urlParts[i] !== this.item().routerLink[i]) {
461
+ isActive = false;
462
+ break;
463
+ }
464
+ }
465
+ this.active.set(isActive);
466
+ if (isActive) {
467
+ this.renderer.addClass(this.elementRef.nativeElement, 'active');
468
+ }
469
+ else {
470
+ this.renderer.removeClass(this.elementRef.nativeElement, 'active');
471
+ }
472
+ }))
473
+ .subscribe());
526
474
  }
527
475
  ngOnDestroy() {
528
- this.subscription?.unsubscribe();
476
+ this._subscription?.unsubscribe();
529
477
  }
530
478
  // region type save item property
531
479
  // required to check the type of the item property in the ngFor loop
@@ -541,350 +489,431 @@ class NavigationComponent {
541
489
  }
542
490
  return item;
543
491
  }
544
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: NavigationComponent, deps: [{ token: NavigationService }, { token: ChangeDetectorRef }, { token: SidenavComponentService }], target: i0.ɵɵFactoryTarget.Component }); }
545
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.1", type: NavigationComponent, isStandalone: true, selector: "ul[rxap-navigation]", inputs: { items: "items", level: "level", root: "root" }, host: { properties: { "class.rxap-root-navigation": "this._root" }, classAttribute: "list-none dark:text-neutral-400 text-neutral-700" }, ngImport: i0, template: "<ng-template [ngForOf]=\"items\" let-item ngFor>\n <ng-template [ngIf]=\"isNavigationDividerItem(item)\">\n <mat-divider></mat-divider>\n <div *ngIf=\"(sidenav.collapsed$ | async) === false\" class=\"pl-5 h-6\">\n <span *ngIf=\"item.title\">{{item.title}}</span>\n </div>\n </ng-template>\n <ng-template [ngIf]=\"isNavigationItem(item)\">\n <li [item]=\"asNavigationItem(item)\" [level]=\"level\" class=\"dark:hover:text-white hover:text-black\"\n rxap-navigation-item></li>\n </ng-template>\n</ng-template>\n", styles: [""], dependencies: [{ kind: "directive", type: i0.forwardRef(() => NgFor), selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i0.forwardRef(() => NgIf), selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: i0.forwardRef(() => MatDividerModule) }, { kind: "component", type: i0.forwardRef(() => i3$1.MatDivider), selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "component", type: i0.forwardRef(() => NavigationItemComponent), selector: "li[rxap-navigation-item]", inputs: ["level", "item"] }, { kind: "pipe", type: i0.forwardRef(() => AsyncPipe), name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
492
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: NavigationItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
493
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "18.0.1", type: NavigationItemComponent, isStandalone: true, selector: "li[rxap-navigation-item]", inputs: { level: { classPropertyName: "level", publicName: "level", isSignal: true, isRequired: false, transformFunction: null }, item: { classPropertyName: "item", publicName: "item", isSignal: true, isRequired: true, transformFunction: null } }, usesOnChanges: true, ngImport: i0, template: "<div [ngClass]=\"{\n 'border-l-4 text-accent-400 border-accent-600': active(),\n }\">\n <a [routerLink]=\"item().routerLink\"\n class=\"h-12 pl-4 pr-5 flex flex-row justify-between items-center gap-x-4\"\n matRipple\n routerLinkActive\n\n >\n <span\n [ngClass]=\"itemClasses()\"\n class=\"grow whitespace-nowrap\"\n >\n {{ item().label }}\n </span>\n <mat-icon *ngIf=\"item().icon\" [rxapIcon]=\"item().icon\"></mat-icon>\n </a>\n\n <ng-container *ngIf=\"item().children?.length && active()\">\n\n <mat-divider></mat-divider>\n\n <ul [@sub-nav]\n [items]=\"children ?? []\"\n [level]=\"level() + 1\"\n rxap-navigation\n >\n </ul>\n\n <mat-divider></mat-divider>\n\n </ng-container>\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: i0.forwardRef(() => RouterLinkActive), selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "directive", type: i0.forwardRef(() => RouterLink), selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i0.forwardRef(() => NgIf), selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: i0.forwardRef(() => MatRippleModule) }, { kind: "directive", type: i0.forwardRef(() => i1.MatRipple), selector: "[mat-ripple], [matRipple]", inputs: ["matRippleColor", "matRippleUnbounded", "matRippleCentered", "matRippleRadius", "matRippleAnimation", "matRippleDisabled", "matRippleTrigger"], exportAs: ["matRipple"] }, { kind: "ngmodule", type: i0.forwardRef(() => MatIconModule) }, { kind: "component", type: i0.forwardRef(() => i2.MatIcon), selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i0.forwardRef(() => IconDirective), selector: "mat-icon[rxapIcon]", inputs: ["rxapIcon"] }, { kind: "ngmodule", type: i0.forwardRef(() => MatDividerModule) }, { kind: "component", type: i0.forwardRef(() => i3.MatDivider), selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "component", type: i0.forwardRef(() => NavigationComponent), selector: "ul[rxap-navigation]", inputs: ["items", "level", "root"] }, { kind: "directive", type: i0.forwardRef(() => NgClass), selector: "[ngClass]", inputs: ["class", "ngClass"] }], animations: [
494
+ trigger('sub-nav', [
495
+ transition(':enter', [
496
+ style({
497
+ display: 'block',
498
+ height: '0',
499
+ overflow: 'hidden',
500
+ }),
501
+ animate(150, style({ height: '*' })),
502
+ ]),
503
+ transition(':leave', [
504
+ style({ overflow: 'hidden' }),
505
+ animate(300, style({ height: '0' })),
506
+ style({ display: 'none' }),
507
+ ]),
508
+ ]),
509
+ ], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
546
510
  }
547
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: NavigationComponent, decorators: [{
511
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: NavigationItemComponent, decorators: [{
548
512
  type: Component,
549
- args: [{ selector: 'ul[rxap-navigation]', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, standalone: true, host: {
550
- class: 'list-none dark:text-neutral-400 text-neutral-700',
551
- }, imports: [
552
- NgFor,
553
- NgIf,
554
- MatDividerModule,
555
- forwardRef(() => NavigationItemComponent),
556
- AsyncPipe,
557
- ], template: "<ng-template [ngForOf]=\"items\" let-item ngFor>\n <ng-template [ngIf]=\"isNavigationDividerItem(item)\">\n <mat-divider></mat-divider>\n <div *ngIf=\"(sidenav.collapsed$ | async) === false\" class=\"pl-5 h-6\">\n <span *ngIf=\"item.title\">{{item.title}}</span>\n </div>\n </ng-template>\n <ng-template [ngIf]=\"isNavigationItem(item)\">\n <li [item]=\"asNavigationItem(item)\" [level]=\"level\" class=\"dark:hover:text-white hover:text-black\"\n rxap-navigation-item></li>\n </ng-template>\n</ng-template>\n" }]
558
- }], ctorParameters: () => [{ type: NavigationService, decorators: [{
559
- type: Inject,
560
- args: [NavigationService]
561
- }] }, { type: i0.ChangeDetectorRef, decorators: [{
562
- type: Inject,
563
- args: [ChangeDetectorRef]
564
- }] }, { type: SidenavComponentService, decorators: [{
565
- type: Inject,
566
- args: [SidenavComponentService]
567
- }] }], propDecorators: { items: [{
568
- type: Input
569
- }], level: [{
570
- type: Input
571
- }], _root: [{
572
- type: HostBinding,
573
- args: ['class.rxap-root-navigation']
574
- }], root: [{
575
- type: Input
576
- }] } });
513
+ args: [{ selector: 'li[rxap-navigation-item]', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, animations: [
514
+ trigger('sub-nav', [
515
+ transition(':enter', [
516
+ style({
517
+ display: 'block',
518
+ height: '0',
519
+ overflow: 'hidden',
520
+ }),
521
+ animate(150, style({ height: '*' })),
522
+ ]),
523
+ transition(':leave', [
524
+ style({ overflow: 'hidden' }),
525
+ animate(300, style({ height: '0' })),
526
+ style({ display: 'none' }),
527
+ ]),
528
+ ]),
529
+ ], standalone: true, imports: [
530
+ RouterLinkActive,
531
+ RouterLink,
532
+ NgIf,
533
+ MatRippleModule,
534
+ MatIconModule,
535
+ IconDirective,
536
+ MatDividerModule,
537
+ forwardRef(() => NavigationComponent),
538
+ NgClass,
539
+ ], template: "<div [ngClass]=\"{\n 'border-l-4 text-accent-400 border-accent-600': active(),\n }\">\n <a [routerLink]=\"item().routerLink\"\n class=\"h-12 pl-4 pr-5 flex flex-row justify-between items-center gap-x-4\"\n matRipple\n routerLinkActive\n\n >\n <span\n [ngClass]=\"itemClasses()\"\n class=\"grow whitespace-nowrap\"\n >\n {{ item().label }}\n </span>\n <mat-icon *ngIf=\"item().icon\" [rxapIcon]=\"item().icon\"></mat-icon>\n </a>\n\n <ng-container *ngIf=\"item().children?.length && active()\">\n\n <mat-divider></mat-divider>\n\n <ul [@sub-nav]\n [items]=\"children ?? []\"\n [level]=\"level() + 1\"\n rxap-navigation\n >\n </ul>\n\n <mat-divider></mat-divider>\n\n </ng-container>\n</div>\n" }]
540
+ }] });
577
541
 
578
- class SidenavComponent {
579
- constructor(sidenav) {
580
- this.sidenav = sidenav;
542
+ class NavigationComponent {
543
+ constructor() {
544
+ this.items = input();
545
+ this.level = input(0);
546
+ this.navigationService = inject(NavigationService);
547
+ this.layoutService = inject(LayoutService);
548
+ this.collapsed = computed(() => this.layoutService.collapsed());
549
+ this.navigationItems = computed(() => this.items() ?? []);
550
+ this.root = input(false);
551
+ this.injector = inject(INJECTOR);
552
+ }
553
+ ngOnInit() {
554
+ if (this.root()) {
555
+ runInInjectionContext(this.injector, () => {
556
+ this.navigationItems = toSignal(this.navigationService.config$, { initialValue: [] });
557
+ });
558
+ }
559
+ }
560
+ // region type save item property
561
+ // required to check the type of the item property in the ngFor loop
562
+ isNavigationDividerItem(item) {
563
+ return item['divider'];
564
+ }
565
+ isNavigationItem(item) {
566
+ return !this.isNavigationDividerItem(item);
567
+ }
568
+ asNavigationItem(item) {
569
+ if (!this.isNavigationItem(item)) {
570
+ throw new Error('The item is not a NavigationItem');
571
+ }
572
+ return item;
581
573
  }
582
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: SidenavComponent, deps: [{ token: SidenavComponentService }], target: i0.ɵɵFactoryTarget.Component }); }
583
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.1", type: SidenavComponent, isStandalone: true, selector: "rxap-sidenav", host: { classAttribute: "rxap-layout-sidenav" }, queries: [{ propertyName: "sidenavFooterDirective", first: true, predicate: SidenavFooterDirective, descendants: true }, { propertyName: "sidenavHeaderDirective", first: true, predicate: SidenavHeaderDirective, descendants: true }], ngImport: i0, template: "<div [ngClass]=\"{ 'collapsed': sidenav.collapsed$ | async }\" class=\"rxap-container\">\n <div class=\"inner flex flex-col justify-between items-stretch\">\n <ng-template [ngIf]=\"sidenavHeaderDirective?.template\">\n <div [ngClass]=\"{ hidden: sidenav.collapsed$ | async }\" class=\"header grow-0\">\n <ng-container *ngTemplateOutlet=\"sidenavHeaderDirective?.template ?? null\"></ng-container>\n </div>\n <mat-divider [ngClass]=\"{ hidden: sidenav.collapsed$ | async }\" class=\"grow-0\"></mat-divider>\n </ng-template>\n <div class=\"nav-container grow\">\n <ul class=\"flex flex-col\" root rxap-navigation></ul>\n </div>\n <mat-divider class=\"grow-0\"></mat-divider>\n <button (click)=\"sidenav.toggleNavigationCollapse()\" [ngClass]=\"{ 'collapsed': sidenav.collapsed$ | async }\"\n class=\"sidebar-toggle grow-0\"\n mat-button>\n <span class=\"sidebar-toggle-inner flex flex-row items-center gap-4\">\n <mat-icon class=\"arrow grow-0\">double_arrow</mat-icon>\n <span [ngClass]=\"{ hidden: sidenav.collapsed$ | async }\" class=\"label grow-0\" i18n>Collapse sidebar</span>\n </span>\n </button>\n <ng-template [ngIf]=\"sidenavFooterDirective?.template ?? null\">\n <mat-divider [ngClass]=\"{ hidden: sidenav.collapsed$ | async }\" class=\"grow-0\"></mat-divider>\n <div [ngClass]=\"{ hidden: sidenav.collapsed$ | async }\" class=\"footer grow-0\">\n <ng-container *ngTemplateOutlet=\"sidenavFooterDirective?.template ?? null\"></ng-container>\n </div>\n </ng-template>\n </div>\n</div>\n", styles: [".rxap-container,.rxap-container .inner{height:100%}.rxap-container .inner .header{padding-bottom:12px}.rxap-container .inner .footer{padding-top:12px}.rxap-container .inner .nav-container{overflow-y:scroll;padding-top:12px}.rxap-container .inner .nav-container::-webkit-scrollbar{width:6px}.rxap-container .inner .nav-container::-webkit-scrollbar-track{border-radius:2px}.rxap-container .inner .nav-container::-webkit-scrollbar-thumb{border-radius:10px}.rxap-container .sidebar-toggle{min-height:48px}.rxap-container .sidebar-toggle .sidebar-toggle-inner{padding:0}.rxap-container .sidebar-toggle .arrow{transform:rotate(180deg)}.rxap-container .sidebar-toggle.collapsed .arrow{transform:initial}.rxap-container .sidebar-toggle.collapsed .sidebar-toggle-inner{justify-content:space-around!important}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: MatDividerModule }, { kind: "component", type: i3$1.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "component", type: NavigationComponent, selector: "ul[rxap-navigation]", inputs: ["items", "level", "root"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
574
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: NavigationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
575
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "18.0.1", type: NavigationComponent, isStandalone: true, selector: "ul[rxap-navigation]", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, level: { classPropertyName: "level", publicName: "level", isSignal: true, isRequired: false, transformFunction: null }, root: { classPropertyName: "root", publicName: "root", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "list-none dark:text-neutral-400 text-neutral-700" }, ngImport: i0, template: "<ng-template [ngForOf]=\"navigationItems()\" let-item ngFor>\n <ng-template [ngIf]=\"isNavigationDividerItem(item)\">\n <mat-divider></mat-divider>\n <div *ngIf=\"!collapsed() && item.title\" class=\"pl-5 h-6\">\n {{item.title}}\n </div>\n </ng-template>\n <ng-template [ngIf]=\"isNavigationItem(item)\">\n <li [item]=\"asNavigationItem(item)\"\n [level]=\"level()\"\n class=\"dark:hover:text-white hover:text-black\"\n rxap-navigation-item>\n </li>\n </ng-template>\n</ng-template>\n", styles: [""], dependencies: [{ kind: "directive", type: i0.forwardRef(() => NgFor), selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i0.forwardRef(() => NgIf), selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: i0.forwardRef(() => MatDividerModule) }, { kind: "component", type: i0.forwardRef(() => i3.MatDivider), selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "component", type: i0.forwardRef(() => NavigationItemComponent), selector: "li[rxap-navigation-item]", inputs: ["level", "item"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
584
576
  }
585
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: SidenavComponent, decorators: [{
577
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: NavigationComponent, decorators: [{
586
578
  type: Component,
587
- args: [{ selector: 'rxap-sidenav', changeDetection: ChangeDetectionStrategy.OnPush, host: {
588
- class: 'rxap-layout-sidenav',
589
- }, standalone: true, imports: [
590
- NgClass,
579
+ args: [{ selector: 'ul[rxap-navigation]', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, standalone: true, host: {
580
+ class: 'list-none dark:text-neutral-400 text-neutral-700',
581
+ }, imports: [
582
+ NgFor,
591
583
  NgIf,
592
- NgTemplateOutlet,
593
584
  MatDividerModule,
594
- NavigationComponent,
595
- MatButtonModule,
596
- MatIconModule,
585
+ forwardRef(() => NavigationItemComponent),
597
586
  AsyncPipe,
598
- ], template: "<div [ngClass]=\"{ 'collapsed': sidenav.collapsed$ | async }\" class=\"rxap-container\">\n <div class=\"inner flex flex-col justify-between items-stretch\">\n <ng-template [ngIf]=\"sidenavHeaderDirective?.template\">\n <div [ngClass]=\"{ hidden: sidenav.collapsed$ | async }\" class=\"header grow-0\">\n <ng-container *ngTemplateOutlet=\"sidenavHeaderDirective?.template ?? null\"></ng-container>\n </div>\n <mat-divider [ngClass]=\"{ hidden: sidenav.collapsed$ | async }\" class=\"grow-0\"></mat-divider>\n </ng-template>\n <div class=\"nav-container grow\">\n <ul class=\"flex flex-col\" root rxap-navigation></ul>\n </div>\n <mat-divider class=\"grow-0\"></mat-divider>\n <button (click)=\"sidenav.toggleNavigationCollapse()\" [ngClass]=\"{ 'collapsed': sidenav.collapsed$ | async }\"\n class=\"sidebar-toggle grow-0\"\n mat-button>\n <span class=\"sidebar-toggle-inner flex flex-row items-center gap-4\">\n <mat-icon class=\"arrow grow-0\">double_arrow</mat-icon>\n <span [ngClass]=\"{ hidden: sidenav.collapsed$ | async }\" class=\"label grow-0\" i18n>Collapse sidebar</span>\n </span>\n </button>\n <ng-template [ngIf]=\"sidenavFooterDirective?.template ?? null\">\n <mat-divider [ngClass]=\"{ hidden: sidenav.collapsed$ | async }\" class=\"grow-0\"></mat-divider>\n <div [ngClass]=\"{ hidden: sidenav.collapsed$ | async }\" class=\"footer grow-0\">\n <ng-container *ngTemplateOutlet=\"sidenavFooterDirective?.template ?? null\"></ng-container>\n </div>\n </ng-template>\n </div>\n</div>\n", styles: [".rxap-container,.rxap-container .inner{height:100%}.rxap-container .inner .header{padding-bottom:12px}.rxap-container .inner .footer{padding-top:12px}.rxap-container .inner .nav-container{overflow-y:scroll;padding-top:12px}.rxap-container .inner .nav-container::-webkit-scrollbar{width:6px}.rxap-container .inner .nav-container::-webkit-scrollbar-track{border-radius:2px}.rxap-container .inner .nav-container::-webkit-scrollbar-thumb{border-radius:10px}.rxap-container .sidebar-toggle{min-height:48px}.rxap-container .sidebar-toggle .sidebar-toggle-inner{padding:0}.rxap-container .sidebar-toggle .arrow{transform:rotate(180deg)}.rxap-container .sidebar-toggle.collapsed .arrow{transform:initial}.rxap-container .sidebar-toggle.collapsed .sidebar-toggle-inner{justify-content:space-around!important}\n"] }]
599
- }], ctorParameters: () => [{ type: SidenavComponentService }], propDecorators: { sidenavFooterDirective: [{
600
- type: ContentChild,
601
- args: [SidenavFooterDirective]
602
- }], sidenavHeaderDirective: [{
603
- type: ContentChild,
604
- args: [SidenavHeaderDirective]
605
- }] } });
587
+ ], template: "<ng-template [ngForOf]=\"navigationItems()\" let-item ngFor>\n <ng-template [ngIf]=\"isNavigationDividerItem(item)\">\n <mat-divider></mat-divider>\n <div *ngIf=\"!collapsed() && item.title\" class=\"pl-5 h-6\">\n {{item.title}}\n </div>\n </ng-template>\n <ng-template [ngIf]=\"isNavigationItem(item)\">\n <li [item]=\"asNavigationItem(item)\"\n [level]=\"level()\"\n class=\"dark:hover:text-white hover:text-black\"\n rxap-navigation-item>\n </li>\n </ng-template>\n</ng-template>\n" }]
588
+ }] });
606
589
 
607
- class ReplaceRouterPathsService {
608
- transform(routerLink) {
609
- return of(routerLink);
590
+ class SidenavComponent {
591
+ constructor() {
592
+ this.layoutService = inject(LayoutService);
593
+ this.sidenav = viewChild(MatSidenav);
594
+ this.sidenavMode = computed(() => this.layoutService.mode());
595
+ this.fixedBottomGap = computed(() => this.layoutService.fixedBottomGap());
596
+ this.fixedTopGap = computed(() => this.layoutService.fixedTopGap());
597
+ this.fixedInViewport = computed(() => this.layoutService.fixedInViewport());
598
+ this.pinned = computed(() => this.layoutService.pinned());
599
+ this.collapsed = computed(() => this.layoutService.collapsed());
600
+ this.collapsable = computed(() => this.layoutService.collapsable());
601
+ this.opened = computed(() => this.layoutService.opened());
602
+ this.sidenavFooterDirective = contentChild(SidenavFooterDirective);
603
+ this.sidenavHeaderDirective = contentChild(SidenavHeaderDirective);
604
+ }
605
+ togglePinned() {
606
+ this.layoutService.togglePinned();
607
+ }
608
+ async openSidenav() {
609
+ await this.sidenav()?.open();
610
+ this.layoutService.openSidenav();
610
611
  }
611
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: ReplaceRouterPathsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
612
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: ReplaceRouterPathsService, providedIn: 'root' }); }
612
+ async closeSidenav() {
613
+ await this.sidenav()?.close();
614
+ this.layoutService.closeSidenav();
615
+ }
616
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: SidenavComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
617
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.1", type: SidenavComponent, isStandalone: true, selector: "rxap-sidenav", queries: [{ propertyName: "sidenavFooterDirective", first: true, predicate: SidenavFooterDirective, descendants: true, isSignal: true }, { propertyName: "sidenavHeaderDirective", first: true, predicate: SidenavHeaderDirective, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "sidenav", first: true, predicate: MatSidenav, descendants: true, isSignal: true }], ngImport: i0, template: "<mat-sidenav-container [ngStyle]=\"{\n 'padding-top.px': fixedTopGap(),\n 'padding-bottom.px': fixedBottomGap(),\n }\" class=\"h-full\">\n <mat-sidenav\n [fixedBottomGap]=\"fixedBottomGap()\"\n [fixedInViewport]=\"fixedInViewport()\"\n [fixedTopGap]=\"fixedTopGap()\"\n [mode]=\"sidenavMode()\"\n [ngClass]=\"{ collapsable: collapsable() }\"\n [opened]=\"opened()\"\n >\n <div (mouseleave)=\"collapsable() && !pinned() && closeSidenav()\"\n class=\"h-full py-2 flex flex-col items-center gap-y-5 justify-items-stretch\">\n\n <div (click)=\"togglePinned()\" *ngIf=\"collapsable()\"\n class=\"pl-2 self-stretch grow-0 flex flex-row justify-between items-center\">\n <span class=\"text-lg\" i18n>Navigation</span>\n <div class=\"flex flex-row items-center justify-center\" style=\"width: 64px\">\n <button mat-icon-button>\n <mat-icon *ngIf=\"!pinned()\">radio_button_unchecked</mat-icon>\n <mat-icon *ngIf=\"pinned()\">radio_button_checked</mat-icon>\n </button>\n </div>\n </div>\n\n @if (sidenavHeaderDirective()?.template; as template) {\n <div [ngClass]=\"{ hidden: collapsed() }\" class=\"header grow-0\">\n <ng-container *ngTemplateOutlet=\"template\"></ng-container>\n </div>\n <mat-divider [ngClass]=\"{ hidden: collapsed() }\" class=\"grow-0\"></mat-divider>\n }\n\n <ul\n (mouseenter)=\"collapsable() && !pinned() && openSidenav()\"\n class=\"grow self-stretch\"\n [root]=\"true\"\n rxap-navigation\n >\n </ul>\n\n @if (sidenavFooterDirective()?.template; as template) {\n <mat-divider [ngClass]=\"{ hidden: collapsed() }\" class=\"grow-0\"></mat-divider>\n <div [ngClass]=\"{ hidden: collapsed() }\" class=\"footer grow-0\">\n <ng-container *ngTemplateOutlet=\"template\"></ng-container>\n </div>\n }\n </div>\n </mat-sidenav>\n <mat-sidenav-content [ngClass]=\"{ 'ml-16': collapsable() }\" class=\"p-4\">\n <ng-content></ng-content>\n </mat-sidenav-content>\n</mat-sidenav-container>\n", styles: [":host .collapsable:not(.mat-drawer-opened){transform:translate(calc(-100% + 64px))!important;visibility:visible!important;box-shadow:inherit!important;transition-property:transform;transition-delay:.25s;display:flex;border-right:solid 1px rgba(0,0,0,.12)}:host .collapsable ::ng-deep .mat-drawer-inner-container::-webkit-scrollbar{display:none}.rxap-container,.rxap-container .inner{height:100%}.rxap-container .inner .header{padding-bottom:12px}.rxap-container .inner .footer{padding-top:12px}.rxap-container .inner .nav-container{overflow-y:scroll;padding-top:12px}.rxap-container .inner .nav-container::-webkit-scrollbar{width:6px}.rxap-container .inner .nav-container::-webkit-scrollbar-track{border-radius:2px}.rxap-container .inner .nav-container::-webkit-scrollbar-thumb{border-radius:10px}.rxap-container .sidebar-toggle{min-height:48px}.rxap-container .sidebar-toggle .sidebar-toggle-inner{padding:0}.rxap-container .sidebar-toggle .arrow{transform:rotate(180deg)}.rxap-container .sidebar-toggle.collapsed .arrow{transform:initial}.rxap-container .sidebar-toggle.collapsed .sidebar-toggle-inner{justify-content:space-around!important}\n"], dependencies: [{ kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "component", type: MatSidenav, selector: "mat-sidenav", inputs: ["fixedInViewport", "fixedTopGap", "fixedBottomGap"], exportAs: ["matSidenav"] }, { kind: "component", type: MatSidenavContainer, selector: "mat-sidenav-container", exportAs: ["matSidenavContainer"] }, { kind: "component", type: MatSidenavContent, selector: "mat-sidenav-content" }, { kind: "component", type: NavigationComponent, selector: "ul[rxap-navigation]", inputs: ["items", "level", "root"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
613
618
  }
614
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: ReplaceRouterPathsService, decorators: [{
615
- type: Injectable,
616
- args: [{ providedIn: 'root' }]
619
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: SidenavComponent, decorators: [{
620
+ type: Component,
621
+ args: [{ selector: 'rxap-sidenav', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
622
+ MatIcon,
623
+ MatIconButton,
624
+ MatSidenav,
625
+ MatSidenavContainer,
626
+ MatSidenavContent,
627
+ NavigationComponent,
628
+ NgIf,
629
+ RouterOutlet,
630
+ NgClass,
631
+ NgStyle,
632
+ MatDivider,
633
+ NgTemplateOutlet,
634
+ MatButton,
635
+ ], template: "<mat-sidenav-container [ngStyle]=\"{\n 'padding-top.px': fixedTopGap(),\n 'padding-bottom.px': fixedBottomGap(),\n }\" class=\"h-full\">\n <mat-sidenav\n [fixedBottomGap]=\"fixedBottomGap()\"\n [fixedInViewport]=\"fixedInViewport()\"\n [fixedTopGap]=\"fixedTopGap()\"\n [mode]=\"sidenavMode()\"\n [ngClass]=\"{ collapsable: collapsable() }\"\n [opened]=\"opened()\"\n >\n <div (mouseleave)=\"collapsable() && !pinned() && closeSidenav()\"\n class=\"h-full py-2 flex flex-col items-center gap-y-5 justify-items-stretch\">\n\n <div (click)=\"togglePinned()\" *ngIf=\"collapsable()\"\n class=\"pl-2 self-stretch grow-0 flex flex-row justify-between items-center\">\n <span class=\"text-lg\" i18n>Navigation</span>\n <div class=\"flex flex-row items-center justify-center\" style=\"width: 64px\">\n <button mat-icon-button>\n <mat-icon *ngIf=\"!pinned()\">radio_button_unchecked</mat-icon>\n <mat-icon *ngIf=\"pinned()\">radio_button_checked</mat-icon>\n </button>\n </div>\n </div>\n\n @if (sidenavHeaderDirective()?.template; as template) {\n <div [ngClass]=\"{ hidden: collapsed() }\" class=\"header grow-0\">\n <ng-container *ngTemplateOutlet=\"template\"></ng-container>\n </div>\n <mat-divider [ngClass]=\"{ hidden: collapsed() }\" class=\"grow-0\"></mat-divider>\n }\n\n <ul\n (mouseenter)=\"collapsable() && !pinned() && openSidenav()\"\n class=\"grow self-stretch\"\n [root]=\"true\"\n rxap-navigation\n >\n </ul>\n\n @if (sidenavFooterDirective()?.template; as template) {\n <mat-divider [ngClass]=\"{ hidden: collapsed() }\" class=\"grow-0\"></mat-divider>\n <div [ngClass]=\"{ hidden: collapsed() }\" class=\"footer grow-0\">\n <ng-container *ngTemplateOutlet=\"template\"></ng-container>\n </div>\n }\n </div>\n </mat-sidenav>\n <mat-sidenav-content [ngClass]=\"{ 'ml-16': collapsable() }\" class=\"p-4\">\n <ng-content></ng-content>\n </mat-sidenav-content>\n</mat-sidenav-container>\n", styles: [":host .collapsable:not(.mat-drawer-opened){transform:translate(calc(-100% + 64px))!important;visibility:visible!important;box-shadow:inherit!important;transition-property:transform;transition-delay:.25s;display:flex;border-right:solid 1px rgba(0,0,0,.12)}:host .collapsable ::ng-deep .mat-drawer-inner-container::-webkit-scrollbar{display:none}.rxap-container,.rxap-container .inner{height:100%}.rxap-container .inner .header{padding-bottom:12px}.rxap-container .inner .footer{padding-top:12px}.rxap-container .inner .nav-container{overflow-y:scroll;padding-top:12px}.rxap-container .inner .nav-container::-webkit-scrollbar{width:6px}.rxap-container .inner .nav-container::-webkit-scrollbar-track{border-radius:2px}.rxap-container .inner .nav-container::-webkit-scrollbar-thumb{border-radius:10px}.rxap-container .sidebar-toggle{min-height:48px}.rxap-container .sidebar-toggle .sidebar-toggle-inner{padding:0}.rxap-container .sidebar-toggle .arrow{transform:rotate(180deg)}.rxap-container .sidebar-toggle.collapsed .arrow{transform:initial}.rxap-container .sidebar-toggle.collapsed .sidebar-toggle-inner{justify-content:space-around!important}\n"] }]
617
636
  }] });
618
637
 
619
- class ReplaceRouterPathsPipe {
620
- constructor(rrp) {
621
- this.rrp = rrp;
638
+ class ReleaseInfoComponent {
639
+ constructor() {
640
+ this.modules = coerceArray(inject(RXAP_RELEASE_INFO_MODULE, { optional: true }));
641
+ this.release = DetermineReleaseName(inject(RXAP_ENVIRONMENT));
642
+ this.dialog = inject(MatDialog);
622
643
  }
623
- transform(routerLink) {
624
- return this.rrp.transform(routerLink);
644
+ openEnvironmentInfo() {
645
+ this.dialog.open(EnvironmentComponent, {
646
+ closeOnNavigation: true,
647
+ });
625
648
  }
626
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: ReplaceRouterPathsPipe, deps: [{ token: ReplaceRouterPathsService }], target: i0.ɵɵFactoryTarget.Pipe }); }
627
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.0.1", ngImport: i0, type: ReplaceRouterPathsPipe, isStandalone: true, name: "replaceRouterPaths" }); }
649
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: ReleaseInfoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
650
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.1", type: ReleaseInfoComponent, isStandalone: true, selector: "rxap-release-info", ngImport: i0, template: "<div class=\"flex flex-col gap-2 w-full justify-center\">\n <button (click)=\"openEnvironmentInfo()\" mat-button>{{ release }}</button>\n @if (modules.length) {\n <table class=\"table-auto border-separate border-spacing-2 bg-white dark:bg-slate-800 text-sm shadow-sm\">\n <thead class=\"bg-slate-50 dark:bg-slate-700\">\n <th class=\"text-sm border-slate-300 dark:border-slate-600 text-slate-900 dark:text-slate-200 border p-2\">Module</th>\n <th class=\"text-sm border-slate-300 dark:border-slate-600 text-slate-900 dark:text-slate-200 border p-2\">Version</th>\n <th class=\"text-sm border-slate-300 dark:border-slate-600 text-slate-900 dark:text-slate-200 border p-2\">Hash</th>\n </thead>\n <tbody>\n @for (module of modules; track module.name) {\n <tr>\n <th class=\"text-sm border border-slate-300 dark:border-slate-700 text-slate-500 dark:text-slate-400 py-2 px-4\">{{ module.name }}</th>\n <td class=\"text-sm border border-slate-300 dark:border-slate-700 text-slate-500 dark:text-slate-400 p-2\">{{ module.version }}</td>\n <td class=\"text-sm border border-slate-300 dark:border-slate-700 text-slate-500 dark:text-slate-400 p-2\">{{ module.hash }}</td>\n </tr>\n }\n </tbody>\n </table>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "component", type: MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
628
651
  }
629
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: ReplaceRouterPathsPipe, decorators: [{
630
- type: Pipe,
631
- args: [{
632
- name: 'replaceRouterPaths',
633
- standalone: true,
634
- }]
635
- }], ctorParameters: () => [{ type: ReplaceRouterPathsService }] });
652
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: ReleaseInfoComponent, decorators: [{
653
+ type: Component,
654
+ args: [{ selector: 'rxap-release-info', standalone: true, imports: [
655
+ MatButton,
656
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"flex flex-col gap-2 w-full justify-center\">\n <button (click)=\"openEnvironmentInfo()\" mat-button>{{ release }}</button>\n @if (modules.length) {\n <table class=\"table-auto border-separate border-spacing-2 bg-white dark:bg-slate-800 text-sm shadow-sm\">\n <thead class=\"bg-slate-50 dark:bg-slate-700\">\n <th class=\"text-sm border-slate-300 dark:border-slate-600 text-slate-900 dark:text-slate-200 border p-2\">Module</th>\n <th class=\"text-sm border-slate-300 dark:border-slate-600 text-slate-900 dark:text-slate-200 border p-2\">Version</th>\n <th class=\"text-sm border-slate-300 dark:border-slate-600 text-slate-900 dark:text-slate-200 border p-2\">Hash</th>\n </thead>\n <tbody>\n @for (module of modules; track module.name) {\n <tr>\n <th class=\"text-sm border border-slate-300 dark:border-slate-700 text-slate-500 dark:text-slate-400 py-2 px-4\">{{ module.name }}</th>\n <td class=\"text-sm border border-slate-300 dark:border-slate-700 text-slate-500 dark:text-slate-400 p-2\">{{ module.version }}</td>\n <td class=\"text-sm border border-slate-300 dark:border-slate-700 text-slate-500 dark:text-slate-400 p-2\">{{ module.hash }}</td>\n </tr>\n }\n </tbody>\n </table>\n }\n</div>\n" }]
657
+ }] });
636
658
 
637
- class LayoutComponentService {
638
- constructor(footerComponentService, headerComponentService, logoConfig = null, config, mediaMatcher) {
639
- this.footerComponentService = footerComponentService;
640
- this.headerComponentService = headerComponentService;
641
- this.config = config;
642
- this.currentThemeDensity = toSignal(ObserveCurrentThemeDensity());
643
- const mobileQuery = mediaMatcher.matchMedia('(max-width: 959px)');
644
- const mobile = mobileQuery.matches;
645
- const initialCollapsable = this.config.get('navigation.collapsable', true);
646
- const collapsable = initialCollapsable && !mobile;
647
- const pinned = this.config.get('navigation.pinned', false);
648
- const mode = this.config.get('navigation.mode', pinned || !collapsable ? 'side' : 'over');
649
- const opened = this.config.get('navigation.opened', (!collapsable || pinned) && !mobile);
650
- this.opened = signal(opened);
651
- this.mode = signal(mode);
652
- this.pinned = signal(pinned);
653
- this.collapsable = signal(collapsable);
654
- this.fixedBottomGap = computed(() => this.footerComponentService.portalCount() * (64 + (this.currentThemeDensity() ?? 0) * 4));
655
- this.fixedTopGap = computed(() => this.headerComponentService.componentCount() * (64 + (this.currentThemeDensity() ?? 0) * 4));
656
- this.logo = logoConfig ?? {
657
- src: 'assets/logo.png',
658
- width: 192,
659
- };
660
- mobileQuery.addEventListener('change', (event) => {
661
- if (initialCollapsable) {
662
- this.collapsable.set(!event.matches);
663
- if (this.collapsable()) {
664
- if (!this.pinned()) {
665
- this.opened.set(false);
666
- }
667
- }
668
- }
669
- });
670
- effect(() => {
671
- if (this.pinned()) {
672
- this.mode.set('side');
673
- this.opened.set(true);
674
- }
675
- else {
676
- this.mode.set('over');
677
- this.opened.set(false);
678
- }
679
- }, { allowSignalWrites: true });
680
- }
681
- toggleOpened() {
682
- this.opened.set(!this.opened());
683
- }
684
- togglePinned() {
685
- this.pinned.set(!this.pinned());
659
+ class NavigationProgressBarComponent {
660
+ constructor() {
661
+ this.router = inject(Router);
662
+ this.navigating = toSignal(this.router.events.pipe(filter(event => event instanceof NavigationStart ||
663
+ event instanceof NavigationEnd ||
664
+ event instanceof NavigationCancel), map(event => event instanceof NavigationStart)), { initialValue: true });
686
665
  }
687
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: LayoutComponentService, deps: [{ token: i1$1.FooterService }, { token: i1$1.HeaderService }, { token: RXAP_LOGO_CONFIG, optional: true }, { token: ConfigService }, { token: i2$1.MediaMatcher }], target: i0.ɵɵFactoryTarget.Injectable }); }
688
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: LayoutComponentService, providedIn: 'root' }); }
666
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: NavigationProgressBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
667
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.1", type: NavigationProgressBarComponent, isStandalone: true, selector: "rxap-navigation-progress-bar", ngImport: i0, template: "@if (navigating()) {\n<mat-progress-bar color=\"accent\" mode=\"indeterminate\"></mat-progress-bar>\n}\n", styles: [""], dependencies: [{ kind: "component", type: MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
689
668
  }
690
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: LayoutComponentService, decorators: [{
691
- type: Injectable,
692
- args: [{ providedIn: 'root' }]
693
- }], ctorParameters: () => [{ type: i1$1.FooterService }, { type: i1$1.HeaderService }, { type: undefined, decorators: [{
694
- type: Optional
695
- }, {
696
- type: Inject,
697
- args: [RXAP_LOGO_CONFIG]
698
- }] }, { type: i1$2.ConfigService, decorators: [{
699
- type: Inject,
700
- args: [ConfigService]
701
- }] }, { type: i2$1.MediaMatcher }] });
669
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: NavigationProgressBarComponent, decorators: [{
670
+ type: Component,
671
+ args: [{ selector: 'rxap-navigation-progress-bar', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
672
+ MatProgressBar,
673
+ ], template: "@if (navigating()) {\n<mat-progress-bar color=\"accent\" mode=\"indeterminate\"></mat-progress-bar>\n}\n" }]
674
+ }] });
702
675
 
703
676
  class FooterComponent {
704
- constructor(footerService) {
705
- this.footerService = footerService;
677
+ constructor() {
678
+ this.footerService = inject(FooterService);
679
+ this.portals = computed(() => this.footerService.portals());
680
+ this.hasPortals = computed(() => this.portals().length > 0);
706
681
  }
707
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: FooterComponent, deps: [{ token: i1$1.FooterService }], target: i0.ɵɵFactoryTarget.Component }); }
708
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.1", type: FooterComponent, isStandalone: true, selector: "rxap-footer", ngImport: i0, template: "<ng-template [ngIf]=\"footerService.portals()\" let-portals>\n <mat-toolbar *ngIf=\"portals.length\" class=\"footer mat-elevation-z1\">\n <mat-toolbar-row *ngFor=\"let portal of portals\">\n <ng-template [cdkPortalOutlet]=\"portal\"></ng-template>\n </mat-toolbar-row>\n </mat-toolbar>\n</ng-template>\n", styles: [""], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatToolbarModule }, { kind: "component", type: i2$2.MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { kind: "directive", type: i2$2.MatToolbarRow, selector: "mat-toolbar-row", exportAs: ["matToolbarRow"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: PortalModule }, { kind: "directive", type: i1.CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
682
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: FooterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
683
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.1", type: FooterComponent, isStandalone: true, selector: "rxap-footer", ngImport: i0, template: "@if (hasPortals()) {\n <mat-toolbar class=\"mat-elevation-z1\">\n @for (portal of portals(); track portal) {\n <mat-toolbar-row>\n <ng-template [cdkPortalOutlet]=\"portal\"></ng-template>\n </mat-toolbar-row>\n }\n </mat-toolbar>\n}\n", styles: [""], dependencies: [{ kind: "ngmodule", type: MatToolbarModule }, { kind: "component", type: i1$1.MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { kind: "directive", type: i1$1.MatToolbarRow, selector: "mat-toolbar-row", exportAs: ["matToolbarRow"] }, { kind: "ngmodule", type: PortalModule }, { kind: "directive", type: i2$1.CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
709
684
  }
710
685
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: FooterComponent, decorators: [{
711
686
  type: Component,
712
- args: [{ selector: 'rxap-footer', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [NgIf, MatToolbarModule, NgFor, PortalModule, AsyncPipe], template: "<ng-template [ngIf]=\"footerService.portals()\" let-portals>\n <mat-toolbar *ngIf=\"portals.length\" class=\"footer mat-elevation-z1\">\n <mat-toolbar-row *ngFor=\"let portal of portals\">\n <ng-template [cdkPortalOutlet]=\"portal\"></ng-template>\n </mat-toolbar-row>\n </mat-toolbar>\n</ng-template>\n" }]
713
- }], ctorParameters: () => [{ type: i1$1.FooterService }] });
687
+ args: [{ selector: 'rxap-footer', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [MatToolbarModule, PortalModule], template: "@if (hasPortals()) {\n <mat-toolbar class=\"mat-elevation-z1\">\n @for (portal of portals(); track portal) {\n <mat-toolbar-row>\n <ng-template [cdkPortalOutlet]=\"portal\"></ng-template>\n </mat-toolbar-row>\n }\n </mat-toolbar>\n}\n" }]
688
+ }] });
714
689
 
715
- class AppUrlService {
716
- constructor(config, localeId, authorizationService, environment) {
717
- this.config = config;
718
- this.localeId = localeId;
719
- this.authorizationService = authorizationService;
720
- this.environment = environment;
721
- this._apps = this.config.get('navigation.apps', []);
690
+ class HeaderComponent {
691
+ constructor() {
692
+ this.color = input();
693
+ this.headerService = inject(HeaderService);
694
+ this.portals = computed(() => this.headerService.portals());
695
+ this.hasPortals = computed(() => this.portals().length > 0);
722
696
  }
723
- getApp(appId) {
724
- return this._apps.find(app => app.id === appId) ?? null;
697
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: HeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
698
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.1", type: HeaderComponent, isStandalone: true, selector: "rxap-header", inputs: { color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "@if (hasPortals()) {\n <mat-toolbar [color]=\"color()\" class=\"mat-elevation-z1\">\n @for (portal of portals(); track portal) {\n <mat-toolbar-row>\n <ng-template [cdkPortalOutlet]=\"portal\"></ng-template>\n </mat-toolbar-row>\n }\n </mat-toolbar>\n}\n", styles: [""], dependencies: [{ kind: "component", type: MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { kind: "directive", type: MatToolbarRow, selector: "mat-toolbar-row", exportAs: ["matToolbarRow"] }, { kind: "directive", type: CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
699
+ }
700
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: HeaderComponent, decorators: [{
701
+ type: Component,
702
+ args: [{ selector: 'rxap-header', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
703
+ MatToolbar,
704
+ MatToolbarRow,
705
+ CdkPortalOutlet,
706
+ ], template: "@if (hasPortals()) {\n <mat-toolbar [color]=\"color()\" class=\"mat-elevation-z1\">\n @for (portal of portals(); track portal) {\n <mat-toolbar-row>\n <ng-template [cdkPortalOutlet]=\"portal\"></ng-template>\n </mat-toolbar-row>\n }\n </mat-toolbar>\n}\n" }]
707
+ }] });
708
+
709
+ class BaseLayoutComponent {
710
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: BaseLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
711
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.1", type: BaseLayoutComponent, isStandalone: true, selector: "rxap-base-layout", ngImport: i0, template: "<div class=\"flex flex-col h-screen justify-between\">\n <rxap-header class=\"z-10 w-full fixed top-0\"></rxap-header>\n <ng-content></ng-content>\n <rxap-footer class=\"z-10 w-full fixed bottom-0\"></rxap-footer>\n</div>\n", styles: [""], dependencies: [{ kind: "component", type: HeaderComponent, selector: "rxap-header", inputs: ["color"] }, { kind: "component", type: FooterComponent, selector: "rxap-footer" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
712
+ }
713
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: BaseLayoutComponent, decorators: [{
714
+ type: Component,
715
+ args: [{ selector: 'rxap-base-layout', standalone: true, imports: [
716
+ HeaderComponent,
717
+ FooterComponent,
718
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"flex flex-col h-screen justify-between\">\n <rxap-header class=\"z-10 w-full fixed top-0\"></rxap-header>\n <ng-content></ng-content>\n <rxap-footer class=\"z-10 w-full fixed bottom-0\"></rxap-footer>\n</div>\n" }]
719
+ }] });
720
+
721
+ class MinimalLayoutComponent {
722
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: MinimalLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
723
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.1", type: MinimalLayoutComponent, isStandalone: true, selector: "rxap-minimal-layout", ngImport: i0, template: "<rxap-base-layout>\n <rxap-navigation-progress-bar></rxap-navigation-progress-bar>\n <router-outlet></router-outlet>\n</rxap-base-layout>\n", styles: [""], dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "component", type: BaseLayoutComponent, selector: "rxap-base-layout" }, { kind: "component", type: NavigationProgressBarComponent, selector: "rxap-navigation-progress-bar" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
724
+ }
725
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: MinimalLayoutComponent, decorators: [{
726
+ type: Component,
727
+ args: [{ selector: 'rxap-minimal-layout', standalone: true, imports: [RouterOutlet, BaseLayoutComponent, NavigationProgressBarComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<rxap-base-layout>\n <rxap-navigation-progress-bar></rxap-navigation-progress-bar>\n <router-outlet></router-outlet>\n</rxap-base-layout>\n" }]
728
+ }] });
729
+
730
+ class LogoService {
731
+ constructor() {
732
+ this.config = inject(ConfigService);
733
+ this.logo = signal(inject(RXAP_LOGO_CONFIG, { optional: true }) ??
734
+ this.config.get('logo', {
735
+ src: 'logo.png',
736
+ width: 192,
737
+ }));
738
+ this.src = computed(() => this.logo().src);
739
+ this.width = computed(() => this.logo().width);
740
+ this.height = computed(() => this.logo().height);
741
+ }
742
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: LogoService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
743
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: LogoService }); }
744
+ }
745
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: LogoService, decorators: [{
746
+ type: Injectable
747
+ }] });
748
+
749
+ class LayoutComponent {
750
+ constructor() {
751
+ this.userSettingsThemeService = inject(UserSettingsThemeService);
752
+ this.themeService = inject(ThemeService);
753
+ this.logoService = inject(LogoService);
754
+ this.logoSrc = computed(() => this.logoService.src());
755
+ this.logoWidth = computed(() => this.logoService.width());
756
+ this.logoHeight = computed(() => this.logoService.height());
725
757
  }
726
- getAppUrl(appId, path, infix = this.getPathPrefix()) {
727
- const app = this.getApp(appId);
728
- if (app) {
729
- return JoinPath(app.href, infix, path);
730
- }
731
- return null;
758
+ ngOnDestroy() {
759
+ this.userSettingsThemeService.stopSync();
732
760
  }
733
- getAppUrlOrThrow(appId, path) {
734
- const url = this.getAppUrl(appId, path);
735
- if (url) {
736
- return url;
737
- }
738
- throw new Error(`Could not find app with id "${appId}"`);
761
+ ngOnInit() {
762
+ this.userSettingsThemeService.startSync().then(() => {
763
+ this.userSettingsThemeService.get().then(theme => {
764
+ if (theme.preset && theme.preset !== 'default') {
765
+ this.themeService.setTheme(theme.preset, true);
766
+ }
767
+ if (theme.density && IsThemeDensity(theme.density) && theme.density !== ThemeDensity.Normal) {
768
+ this.themeService.setDensity(theme.density, true);
769
+ }
770
+ if (theme.typography && theme.typography !== 'default') {
771
+ this.themeService.setTypography(theme.typography, true);
772
+ }
773
+ });
774
+ });
739
775
  }
740
- navigate(appId, path) {
741
- const url = this.getAppUrl(appId, path);
742
- if (url) {
743
- ClickOnLink(url);
744
- }
776
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: LayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
777
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.1", type: LayoutComponent, isStandalone: true, selector: "rxap-layout", ngImport: i0, template: "<rxap-header class=\"z-10 w-full fixed top-0\"></rxap-header>\n<rxap-navigation-progress-bar></rxap-navigation-progress-bar>\n<rxap-sidenav>\n <router-outlet></router-outlet>\n <ng-template rxapSidenavFooter>\n <img\n [src]=\"logoSrc()\"\n [routerLink]=\"['/']\"\n [width]=\"logoWidth()\"\n [height]=\"logoHeight()\"\n alt=\"logo\"\n class=\"grow-0 mx-16 cursor-pointer\"\n />\n <div class=\"grow-0 px-16 mt-4\">\n <rxap-release-info></rxap-release-info>\n </div>\n </ng-template>\n</rxap-sidenav>\n<rxap-footer class=\"z-10 w-full fixed bottom-0\"></rxap-footer>\n", styles: [":host .collapsable:not(.mat-drawer-opened){transform:translate(calc(-100% + 64px))!important;visibility:visible!important;box-shadow:inherit!important;transition-property:transform;transition-delay:.25s;display:flex;border-right:solid 1px rgba(0,0,0,.12)}:host .collapsable ::ng-deep .mat-drawer-inner-container::-webkit-scrollbar{display:none}\n"], dependencies: [{ kind: "component", type: HeaderComponent, selector: "rxap-header", inputs: ["color"] }, { kind: "ngmodule", type: MatSidenavModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: MatButtonModule }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: FooterComponent, selector: "rxap-footer" }, { kind: "ngmodule", type: MatMenuModule }, { kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "component", type: SidenavComponent, selector: "rxap-sidenav" }, { kind: "component", type: ReleaseInfoComponent, selector: "rxap-release-info" }, { kind: "directive", type: SidenavFooterDirective, selector: "[rxapSidenavFooter]" }, { kind: "component", type: NavigationProgressBarComponent, selector: "rxap-navigation-progress-bar" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
778
+ }
779
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: LayoutComponent, decorators: [{
780
+ type: Component,
781
+ args: [{ selector: 'rxap-layout', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
782
+ HeaderComponent,
783
+ MatSidenavModule,
784
+ AsyncPipe,
785
+ MatIconModule,
786
+ MatButtonModule,
787
+ RouterLink,
788
+ NgIf,
789
+ FooterComponent,
790
+ MatMenuModule,
791
+ NgOptimizedImage,
792
+ NavigationComponent,
793
+ RouterOutlet,
794
+ NgStyle,
795
+ NgClass,
796
+ SidenavComponent,
797
+ ReleaseInfoComponent,
798
+ SidenavFooterDirective,
799
+ NavigationProgressBarComponent,
800
+ ], template: "<rxap-header class=\"z-10 w-full fixed top-0\"></rxap-header>\n<rxap-navigation-progress-bar></rxap-navigation-progress-bar>\n<rxap-sidenav>\n <router-outlet></router-outlet>\n <ng-template rxapSidenavFooter>\n <img\n [src]=\"logoSrc()\"\n [routerLink]=\"['/']\"\n [width]=\"logoWidth()\"\n [height]=\"logoHeight()\"\n alt=\"logo\"\n class=\"grow-0 mx-16 cursor-pointer\"\n />\n <div class=\"grow-0 px-16 mt-4\">\n <rxap-release-info></rxap-release-info>\n </div>\n </ng-template>\n</rxap-sidenav>\n<rxap-footer class=\"z-10 w-full fixed bottom-0\"></rxap-footer>\n", styles: [":host .collapsable:not(.mat-drawer-opened){transform:translate(calc(-100% + 64px))!important;visibility:visible!important;box-shadow:inherit!important;transition-property:transform;transition-delay:.25s;display:flex;border-right:solid 1px rgba(0,0,0,.12)}:host .collapsable ::ng-deep .mat-drawer-inner-container::-webkit-scrollbar{display:none}\n"] }]
801
+ }] });
802
+
803
+ class HeaderDirective {
804
+ constructor() {
805
+ this.headerService = inject(HeaderService);
806
+ this.template = inject(TemplateRef);
807
+ this.viewContainerRef = inject(ViewContainerRef);
745
808
  }
746
- async getAppList() {
747
- const appList = this
748
- ._apps
749
- .filter(app => !app.hidden)
750
- .map(app => ({
751
- ...app,
752
- href: JoinPath(app.href, this.getPathPrefix()),
753
- }));
754
- const filteredAppList = [];
755
- for (const app of appList) {
756
- if (await firstValueFrom(this.authorizationService.hasPermission$(app.permissions))) {
757
- filteredAppList.push(app);
758
- }
759
- }
760
- return filteredAppList;
809
+ ngOnInit() {
810
+ this._portal = new TemplatePortal(this.template, this.viewContainerRef);
811
+ this.headerService.pushPortal(this._portal);
761
812
  }
762
- getPathPrefix() {
763
- if (this.environment.production && this.localeId) {
764
- return this.localeId.replace(/-.+$/, '');
813
+ ngOnDestroy() {
814
+ if (this._portal) {
815
+ this.headerService.removePortal(this._portal);
765
816
  }
766
- return '';
767
817
  }
768
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: AppUrlService, deps: [{ token: i1$2.ConfigService }, { token: LOCALE_ID }, { token: i2$3.AuthorizationService }, { token: RXAP_ENVIRONMENT }], target: i0.ɵɵFactoryTarget.Injectable }); }
769
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: AppUrlService, providedIn: 'root' }); }
818
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: HeaderDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
819
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.0.1", type: HeaderDirective, isStandalone: true, selector: "[rxapHeader]", ngImport: i0 }); }
770
820
  }
771
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: AppUrlService, decorators: [{
772
- type: Injectable,
773
- args: [{ providedIn: 'root' }]
774
- }], ctorParameters: () => [{ type: i1$2.ConfigService }, { type: undefined, decorators: [{
775
- type: Inject,
776
- args: [LOCALE_ID]
777
- }] }, { type: i2$3.AuthorizationService }, { type: undefined, decorators: [{
778
- type: Inject,
779
- args: [RXAP_ENVIRONMENT]
780
- }] }] });
821
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: HeaderDirective, decorators: [{
822
+ type: Directive,
823
+ args: [{
824
+ selector: '[rxapHeader]',
825
+ standalone: true,
826
+ }]
827
+ }] });
781
828
 
782
- class AppsButtonComponent {
783
- constructor(grid, appUrlService, authenticationService) {
784
- this.appUrlService = appUrlService;
785
- this.authenticationService = authenticationService;
786
- this.isOpen = false;
787
- this.appList = signal([]);
829
+ class FooterDirective {
830
+ constructor() {
831
+ this.footerService = inject(FooterService);
832
+ this.template = inject(TemplateRef);
833
+ this.viewContainerRef = inject(ViewContainerRef);
788
834
  }
789
835
  ngOnInit() {
790
- this._subscription = this.authenticationService.isAuthenticated$.pipe(filter(Boolean), switchMap$1(() => this.appUrlService.getAppList()), tap((apps) => this.appList.set(apps))).subscribe();
836
+ this._portal = new TemplatePortal(this.template, this.viewContainerRef);
837
+ this.footerService.pushPortal(this._portal);
791
838
  }
792
839
  ngOnDestroy() {
793
- this._subscription?.unsubscribe();
840
+ if (this._portal) {
841
+ this.footerService.removePortal(this._portal);
842
+ }
794
843
  }
795
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: AppsButtonComponent, deps: [{ token: RXAP_LAYOUT_APPS_GRID, optional: true }, { token: AppUrlService }, { token: i2$4.RxapAuthenticationService }], target: i0.ɵɵFactoryTarget.Component }); }
796
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.1", type: AppsButtonComponent, isStandalone: true, selector: "rxap-apps-button", ngImport: i0, template: "<div *ngIf=\"appList()?.length\" class=\"flex flex-row items-center gap-8\">\n\n <div *ngIf=\"isOpen\" class=\"flex flex-row items-center gap-6\">\n\n <div *ngFor=\"let app of appList()\" class=\"h-10\">\n <a [href]=\"app.href\" mat-stroked-button>\n <span class=\"flex flex-row items-center gap-4\">\n <img *ngIf=\"app.image\" [alt]=\"app.label\" [ngSrc]=\"app.image\" height=\"40\" width=\"40\">\n <span class=\"label grow-0\">{{app.label}}</span>\n </span>\n </a>\n </div>\n\n </div>\n\n <button (click)=\"isOpen = !isOpen\" mat-icon-button>\n <mat-icon svgIcon=\"apps\"></mat-icon>\n </button>\n\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatAnchor, selector: "a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button]", exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: NgOptimizedImage, selector: "img[ngSrc]", inputs: ["ngSrc", "ngSrcset", "sizes", "width", "height", "loading", "priority", "loaderParams", "disableOptimizedSrcset", "fill", "placeholder", "placeholderConfig", "src", "srcset"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
844
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: FooterDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
845
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.0.1", type: FooterDirective, isStandalone: true, selector: "[rxapFooter]", ngImport: i0 }); }
797
846
  }
798
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: AppsButtonComponent, decorators: [{
799
- type: Component,
800
- args: [{ selector: 'rxap-apps-button', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
801
- NgIf,
802
- NgFor,
803
- MatButtonModule,
804
- MatIconModule,
805
- NgOptimizedImage,
806
- ], template: "<div *ngIf=\"appList()?.length\" class=\"flex flex-row items-center gap-8\">\n\n <div *ngIf=\"isOpen\" class=\"flex flex-row items-center gap-6\">\n\n <div *ngFor=\"let app of appList()\" class=\"h-10\">\n <a [href]=\"app.href\" mat-stroked-button>\n <span class=\"flex flex-row items-center gap-4\">\n <img *ngIf=\"app.image\" [alt]=\"app.label\" [ngSrc]=\"app.image\" height=\"40\" width=\"40\">\n <span class=\"label grow-0\">{{app.label}}</span>\n </span>\n </a>\n </div>\n\n </div>\n\n <button (click)=\"isOpen = !isOpen\" mat-icon-button>\n <mat-icon svgIcon=\"apps\"></mat-icon>\n </button>\n\n</div>\n" }]
807
- }], ctorParameters: () => [{ type: undefined, decorators: [{
808
- type: Optional
809
- }, {
810
- type: Inject,
811
- args: [RXAP_LAYOUT_APPS_GRID]
812
- }] }, { type: AppUrlService }, { type: i2$4.RxapAuthenticationService }] });
847
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: FooterDirective, decorators: [{
848
+ type: Directive,
849
+ args: [{
850
+ selector: '[rxapFooter]',
851
+ standalone: true,
852
+ }]
853
+ }] });
813
854
 
814
- class NavigationProgressBarComponent {
815
- constructor(router) {
816
- this.router = router;
817
- this.navigating$ = this.router.events.pipe(filter(event => event instanceof NavigationStart ||
818
- event instanceof NavigationEnd ||
819
- event instanceof NavigationCancel), map(event => event instanceof NavigationStart));
855
+ class UserProfileIconComponent {
856
+ constructor() {
857
+ this.extractUsernameFromProfile = inject(EXTRACT_USERNAME_FROM_PROFILE);
858
+ this.pubSubService = inject(PubSubService);
859
+ this.profile = input.required();
860
+ this.username = computed(() => {
861
+ const profile = this.profile();
862
+ if (profile) {
863
+ return this.extractUsernameFromProfile(profile);
864
+ }
865
+ return null;
866
+ });
820
867
  }
821
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: NavigationProgressBarComponent, deps: [{ token: Router }], target: i0.ɵɵFactoryTarget.Component }); }
822
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.1", type: NavigationProgressBarComponent, isStandalone: true, selector: "rxap-navigation-progress-bar", ngImport: i0, template: "<mat-progress-bar\n *ngIf=\"navigating$ | async\"\n color=\"accent\"\n mode=\"indeterminate\"\n></mat-progress-bar>\n", styles: [""], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatProgressBarModule }, { kind: "component", type: i1$4.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
868
+ logout() {
869
+ this.pubSubService.publish('authentication.logout');
870
+ }
871
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: UserProfileIconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
872
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.1", type: UserProfileIconComponent, isStandalone: true, selector: "rxap-user-profile-icon", inputs: { profile: { classPropertyName: "profile", publicName: "profile", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<button [matMenuTriggerFor]=\"menu\"\n class=\"rounded-full cursor-pointer outline-none overflow-hidden h-8 w-8 bg-center bg-no-repeat bg-cover flex flex-row justify-center items-center\">\n <mat-icon class=\"h-8 w-8 text-[32px]\" svgIcon=\"account-circle\"></mat-icon>\n</button>\n\n<mat-menu #menu=\"matMenu\" [yPosition]=\"'below'\" class=\"!max-w-none\">\n @if (this.username(); as username) {\n <button mat-menu-item>\n <span class=\"flex flex-row gap-2\">\n <mat-icon svgIcon=\"account\"></mat-icon>\n <span>{{username}}</span>\n </span>\n </button>\n }\n <button (click)=\"logout()\" mat-menu-item>\n <span class=\"flex flex-row gap-2\">\n <mat-icon svgIcon=\"logout\"></mat-icon>\n <span i18n>Logout</span>\n </span>\n </button>\n</mat-menu>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i1$2.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i1$2.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i1$2.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i2.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
823
873
  }
824
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: NavigationProgressBarComponent, decorators: [{
874
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: UserProfileIconComponent, decorators: [{
825
875
  type: Component,
826
- args: [{ selector: 'rxap-navigation-progress-bar', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
827
- NgIf,
828
- MatProgressBarModule,
829
- AsyncPipe,
830
- ], template: "<mat-progress-bar\n *ngIf=\"navigating$ | async\"\n color=\"accent\"\n mode=\"indeterminate\"\n></mat-progress-bar>\n" }]
831
- }], ctorParameters: () => [{ type: i2.Router, decorators: [{
832
- type: Inject,
833
- args: [Router]
834
- }] }] });
876
+ args: [{ selector: 'rxap-user-profile-icon', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
877
+ MatMenuModule,
878
+ MatIconModule,
879
+ ], template: "<button [matMenuTriggerFor]=\"menu\"\n class=\"rounded-full cursor-pointer outline-none overflow-hidden h-8 w-8 bg-center bg-no-repeat bg-cover flex flex-row justify-center items-center\">\n <mat-icon class=\"h-8 w-8 text-[32px]\" svgIcon=\"account-circle\"></mat-icon>\n</button>\n\n<mat-menu #menu=\"matMenu\" [yPosition]=\"'below'\" class=\"!max-w-none\">\n @if (this.username(); as username) {\n <button mat-menu-item>\n <span class=\"flex flex-row gap-2\">\n <mat-icon svgIcon=\"account\"></mat-icon>\n <span>{{username}}</span>\n </span>\n </button>\n }\n <button (click)=\"logout()\" mat-menu-item>\n <span class=\"flex flex-row gap-2\">\n <mat-icon svgIcon=\"logout\"></mat-icon>\n <span i18n>Logout</span>\n </span>\n </button>\n</mat-menu>\n" }]
880
+ }] });
835
881
 
836
- class LanguageSelectorComponent {
837
- constructor(language) {
838
- this.language = language;
882
+ class SidenavToggleButtonComponent {
883
+ constructor() {
884
+ this.layoutComponentService = inject(LayoutService);
885
+ this.opened = computed(() => this.layoutComponentService.opened());
839
886
  }
840
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: LanguageSelectorComponent, deps: [{ token: i1$5.LanguageSelectorService }], target: i0.ɵɵFactoryTarget.Component }); }
841
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.1", type: LanguageSelectorComponent, isStandalone: true, selector: "rxap-language-selector", ngImport: i0, template: "<ng-template [ngIf]=\"(language.languages | keyvalue).length\">\n <div>\n <mat-form-field appearance=\"outline\" class=\"language-selector\" rxapStopPropagation>\n <mat-label i18n>Select Language</mat-label>\n <mat-select (ngModelChange)=\"language.setLanguage($event)\" [ngModel]=\"language.selectedLanguage\">\n <mat-option *ngFor=\"let item of language.languages | keyvalue\" [value]=\"item.key\">{{item.value}}</mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n</ng-template>\n", styles: [".language-selector{width:calc(100% - 32px);margin:0 16px}.language-selector ::ng-deep .mat-form-field-wrapper{padding-bottom:0}.language-selector ::ng-deep .mat-form-field-wrapper .mat-form-field-infix{padding:12px 0;border-width:6px}.language-selector ::ng-deep .mat-form-field-wrapper .mat-form-field-infix .mat-select-arrow-wrapper{transform:translateY(0)}\n"], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i2$5.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i2$5.MatLabel, selector: "mat-label" }, { kind: "directive", type: StopPropagationDirective, selector: "[rxapStopPropagation]" }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i3$2.MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: i1$3.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i5.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: MatOptionModule }, { kind: "pipe", type: KeyValuePipe, name: "keyvalue" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
887
+ toggle() {
888
+ this.layoutComponentService.toggleOpened();
889
+ }
890
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: SidenavToggleButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
891
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.1", type: SidenavToggleButtonComponent, isStandalone: true, selector: "rxap-sidenav-toggle-button", ngImport: i0, template: "<button (click)=\"toggle()\" mat-icon-button>\n @if (opened()) {\n <mat-icon>menu_open</mat-icon>\n } @else {\n <mat-icon>menu</mat-icon>\n }\n</button>\n", styles: [""], dependencies: [{ kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
842
892
  }
843
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: LanguageSelectorComponent, decorators: [{
893
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: SidenavToggleButtonComponent, decorators: [{
844
894
  type: Component,
845
- args: [{ selector: 'rxap-language-selector', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
846
- NgIf,
847
- MatFormFieldModule,
848
- StopPropagationDirective,
849
- MatSelectModule,
850
- FormsModule,
851
- NgFor,
852
- MatOptionModule,
853
- KeyValuePipe,
854
- ], template: "<ng-template [ngIf]=\"(language.languages | keyvalue).length\">\n <div>\n <mat-form-field appearance=\"outline\" class=\"language-selector\" rxapStopPropagation>\n <mat-label i18n>Select Language</mat-label>\n <mat-select (ngModelChange)=\"language.setLanguage($event)\" [ngModel]=\"language.selectedLanguage\">\n <mat-option *ngFor=\"let item of language.languages | keyvalue\" [value]=\"item.key\">{{item.value}}</mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n</ng-template>\n", styles: [".language-selector{width:calc(100% - 32px);margin:0 16px}.language-selector ::ng-deep .mat-form-field-wrapper{padding-bottom:0}.language-selector ::ng-deep .mat-form-field-wrapper .mat-form-field-infix{padding:12px 0;border-width:6px}.language-selector ::ng-deep .mat-form-field-wrapper .mat-form-field-infix .mat-select-arrow-wrapper{transform:translateY(0)}\n"] }]
855
- }], ctorParameters: () => [{ type: i1$5.LanguageSelectorService }] });
895
+ args: [{ selector: 'rxap-sidenav-toggle-button', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
896
+ MatIcon,
897
+ MatIconButton,
898
+ ], template: "<button (click)=\"toggle()\" mat-icon-button>\n @if (opened()) {\n <mat-icon>menu_open</mat-icon>\n } @else {\n <mat-icon>menu</mat-icon>\n }\n</button>\n" }]
899
+ }] });
856
900
 
857
901
  class SettingsButtonComponent {
858
- constructor(theme, route, injector, changelogService) {
859
- this.theme = theme;
860
- this.route = route;
861
- this.injector = injector;
862
- this.changelogService = changelogService;
902
+ constructor() {
863
903
  this.isDevMode = isDevMode();
864
- this.items = signal([]);
904
+ this.theme = inject(ThemeService);
905
+ this.injector = inject(Injector);
906
+ this.customItemComponents = signal(coerceArray(inject(RXAP_SETTINGS_MENU_ITEM_COMPONENT, { optional: true }))
907
+ .map(item => new ComponentPortal(item, null, this.injector)));
908
+ this.customItems = signal(coerceArray(inject(RXAP_SETTINGS_MENU_ITEM, { optional: true })));
865
909
  this.savePreviewDensityValue = false;
866
910
  this.currentDensityValue = null;
867
911
  this.savePreviewTypographyValue = false;
868
912
  this.currentTypographyValue = null;
913
+ this.availableTypographies = this.theme.getAvailableTypographies();
869
914
  this.savePreviewThemeValue = false;
870
- this.currentThemeValue = null;
871
915
  this.availableThemes = this.theme.getAvailableThemes();
872
- this.availableTypographies = this.theme.getAvailableTypographies();
873
- }
874
- ngOnDestroy() {
875
- this._subscription?.unsubscribe();
876
- }
877
- ngOnInit() {
878
- this._subscription = this.route.data.pipe(map(data => this.getCustomMenuItems(data)), map(items => items.map(item => new ComponentPortal(item, undefined, this.injector))), tap(items => this.items.set(items))).subscribe();
879
- }
880
- getCustomMenuItems(data) {
881
- if (data?.layout?.header?.menu?.items?.length) {
882
- return data.layout.header.menu.items;
883
- }
884
- return [];
885
- }
886
- openChangelogDialog() {
887
- this.changelogService.showChangelogDialog();
916
+ this.currentThemeValue = null;
888
917
  }
889
918
  previewDensity(density) {
890
919
  this.theme.applyDensity(density);
@@ -913,255 +942,249 @@ class SettingsButtonComponent {
913
942
  setTheme(theme) {
914
943
  this.theme.setTheme(theme);
915
944
  }
916
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: SettingsButtonComponent, deps: [{ token: i1$6.ThemeService }, { token: i2.ActivatedRoute }, { token: i0.Injector }, { token: i3$3.ChangelogService }], target: i0.ɵɵFactoryTarget.Component }); }
917
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.1", type: SettingsButtonComponent, isStandalone: true, selector: "rxap-settings-button", ngImport: i0, template: "<button [matMenuTriggerFor]=\"menu\" mat-icon-button>\n <mat-icon svgIcon=\"cog\"></mat-icon>\n</button>\n\n<mat-menu #menu=\"matMenu\">\n <button (click)=\"theme.toggleDarkTheme()\" mat-menu-item>\n <mat-icon *ngIf=\"theme.darkMode()\" svgIcon=\"brightness-2\"></mat-icon>\n <mat-icon *ngIf=\"!theme.darkMode()\" svgIcon=\"brightness-5\"></mat-icon>\n <span i18n>Mode</span>\n </button>\n <button [matMenuTriggerFor]=\"themeMenu\" mat-menu-item>\n <mat-icon svgIcon=\"compare\"></mat-icon>\n <span i18n>Theme</span>\n </button>\n <rxap-language-selector></rxap-language-selector>\n <button (click)=\"openChangelogDialog()\" mat-menu-item>\n <mat-icon svgIcon=\"format-list-numbered\"></mat-icon>\n <span i18n>What's new</span>\n </button>\n <ng-container *ngFor=\"let item of items()\">\n <ng-template [cdkPortalOutlet]=\"item\"></ng-template>\n </ng-container>\n</mat-menu>\n\n<mat-menu #themeMenu=\"matMenu\" xPosition=\"before\">\n <button [matMenuTriggerFor]=\"themeDensityMenu\" mat-menu-item>\n <mat-icon svgIcon=\"move-resize\"></mat-icon>\n <span i18n>Density</span>\n </button>\n <button *ngIf=\"availableTypographies?.length\" [matMenuTriggerFor]=\"themeFontMenu\" mat-menu-item>\n <mat-icon svgIcon=\"format-font\"></mat-icon>\n <span i18n>Font</span>\n </button>\n <button *ngIf=\"availableThemes?.length\" [matMenuTriggerFor]=\"themePresetMenu\" mat-menu-item>\n <mat-icon svgIcon=\"shape-outline\"></mat-icon>\n <span i18n>Preset</span>\n </button>\n</mat-menu>\n\n<mat-menu #themeDensityMenu=\"matMenu\" xPosition=\"before\">\n <button (click)=\"setDensity(0)\" (mouseenter)=\"previewDensity(0)\" (mouseleave)=\"restoreDensity()\" mat-menu-item>\n <mat-icon svgIcon=\"size-l\"></mat-icon>\n <span i18n>Normal</span>\n </button>\n <button (click)=\"setDensity(-1)\" (mouseenter)=\"previewDensity(-1)\" (mouseleave)=\"restoreDensity()\" mat-menu-item>\n <mat-icon svgIcon=\"size-m\"></mat-icon>\n <span i18n>Dense</span>\n </button>\n <button (click)=\"setDensity(-2)\" (mouseenter)=\"previewDensity(-2)\" (mouseleave)=\"restoreDensity()\" mat-menu-item>\n <mat-icon svgIcon=\"size-s\"></mat-icon>\n <span i18n>Very Dense</span>\n </button>\n <button (click)=\"setDensity(-3)\" (mouseenter)=\"previewDensity(-3)\" (mouseleave)=\"restoreDensity()\" mat-menu-item>\n <mat-icon svgIcon=\"size-xs\"></mat-icon>\n <span i18n>Extreme Dense</span>\n </button>\n</mat-menu>\n<mat-menu #themeFontMenu=\"matMenu\" xPosition=\"before\">\n <ng-template [ngIf]=\"availableTypographies?.length\">\n <button (click)=\"setTypography(typographyName)\"\n (mouseenter)=\"previewTypography(typographyName)\"\n (mouseleave)=\"restoreTypography()\"\n *ngFor=\"let typographyName of availableTypographies\"\n mat-menu-item>\n {{ typographyName }}\n </button>\n </ng-template>\n</mat-menu>\n\n<mat-menu #themePresetMenu=\"matMenu\" xPosition=\"before\">\n <ng-template [ngIf]=\"availableThemes?.length\">\n <button (click)=\"setTheme(themeName)\"\n (mouseenter)=\"previewTheme(themeName)\"\n (mouseleave)=\"restoreTheme()\"\n *ngFor=\"let themeName of availableThemes\"\n mat-menu-item>\n {{ themeName }}\n </button>\n </ng-template>\n</mat-menu>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i4$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i4$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: LanguageSelectorComponent, selector: "rxap-language-selector" }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i7.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i7.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i7.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: PortalModule }, { kind: "directive", type: i1.CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }] }); }
945
+ clickItem(item) {
946
+ runInInjectionContext(this.injector, () => item.action());
947
+ }
948
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: SettingsButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
949
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.1", type: SettingsButtonComponent, isStandalone: true, selector: "rxap-settings-button", ngImport: i0, template: "<button [matMenuTriggerFor]=\"menu\" mat-icon-button>\n <mat-icon svgIcon=\"cog\"></mat-icon>\n</button>\n\n<mat-menu #menu=\"matMenu\">\n <button (click)=\"theme.toggleDarkTheme()\" mat-menu-item>\n @if (theme.darkMode()) {\n <mat-icon svgIcon=\"brightness-2\"></mat-icon>\n } @else {\n <mat-icon svgIcon=\"brightness-5\"></mat-icon>\n }\n <span i18n>Mode</span>\n </button>\n <button [matMenuTriggerFor]=\"themeMenu\" mat-menu-item>\n <mat-icon svgIcon=\"compare\"></mat-icon>\n <span i18n>Theme</span>\n </button>\n @for (item of customItems(); track item.label) {\n <button (click)=\"clickItem(item)\" mat-menu-item>\n <mat-icon [rxapIcon]=\"item.icon\"></mat-icon>\n <span>{{ item.label }}</span>\n </button>\n }\n @for (item of customItemComponents(); track item) {\n <ng-template [cdkPortalOutlet]=\"item\"></ng-template>\n }\n</mat-menu>\n\n<mat-menu #themeMenu=\"matMenu\" xPosition=\"before\">\n <button [matMenuTriggerFor]=\"themeDensityMenu\" mat-menu-item>\n <mat-icon svgIcon=\"move-resize\"></mat-icon>\n <span i18n>Density</span>\n </button>\n @if (availableTypographies?.length) {\n <button [matMenuTriggerFor]=\"themeFontMenu\" mat-menu-item>\n <mat-icon svgIcon=\"format-font\"></mat-icon>\n <span i18n>Font</span>\n </button>\n }\n @if (availableThemes?.length) {\n <button [matMenuTriggerFor]=\"themePresetMenu\" mat-menu-item>\n <mat-icon svgIcon=\"shape-outline\"></mat-icon>\n <span i18n>Preset</span>\n </button>\n }\n</mat-menu>\n\n<mat-menu #themeDensityMenu=\"matMenu\" xPosition=\"before\">\n <button (click)=\"setDensity(0)\" (mouseenter)=\"previewDensity(0)\" (mouseleave)=\"restoreDensity()\" mat-menu-item>\n <mat-icon svgIcon=\"size-l\"></mat-icon>\n <span i18n>Normal</span>\n </button>\n <button (click)=\"setDensity(-1)\" (mouseenter)=\"previewDensity(-1)\" (mouseleave)=\"restoreDensity()\" mat-menu-item>\n <mat-icon svgIcon=\"size-m\"></mat-icon>\n <span i18n>Dense</span>\n </button>\n <button (click)=\"setDensity(-2)\" (mouseenter)=\"previewDensity(-2)\" (mouseleave)=\"restoreDensity()\" mat-menu-item>\n <mat-icon svgIcon=\"size-s\"></mat-icon>\n <span i18n>Very Dense</span>\n </button>\n <button (click)=\"setDensity(-3)\" (mouseenter)=\"previewDensity(-3)\" (mouseleave)=\"restoreDensity()\" mat-menu-item>\n <mat-icon svgIcon=\"size-xs\"></mat-icon>\n <span i18n>Extreme Dense</span>\n </button>\n</mat-menu>\n<mat-menu #themeFontMenu=\"matMenu\" xPosition=\"before\">\n @for (typographyName of availableTypographies ?? []; track typographyName) {\n <button (click)=\"setTypography(typographyName)\"\n (mouseenter)=\"previewTypography(typographyName)\"\n (mouseleave)=\"restoreTypography()\"\n mat-menu-item>\n {{ typographyName }}\n </button>\n }\n</mat-menu>\n\n<mat-menu #themePresetMenu=\"matMenu\" xPosition=\"before\">\n @for (themeName of availableThemes ?? []; track themeName) {\n <button (click)=\"setTheme(themeName)\"\n (mouseenter)=\"previewTheme(themeName)\"\n (mouseleave)=\"restoreTheme()\"\n mat-menu-item>\n {{ themeName }}\n </button>\n }\n</mat-menu>\n", styles: [""], dependencies: [{ 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: MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "directive", type: MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "component", type: MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }, { kind: "directive", type: IconDirective, selector: "mat-icon[rxapIcon]", inputs: ["rxapIcon"] }] }); }
918
950
  }
919
951
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: SettingsButtonComponent, decorators: [{
920
952
  type: Component,
921
- args: [{ selector: 'rxap-settings-button', standalone: true, imports: [CommonModule, MatButtonModule, MatIconModule, LanguageSelectorComponent, MatMenuModule, PortalModule], template: "<button [matMenuTriggerFor]=\"menu\" mat-icon-button>\n <mat-icon svgIcon=\"cog\"></mat-icon>\n</button>\n\n<mat-menu #menu=\"matMenu\">\n <button (click)=\"theme.toggleDarkTheme()\" mat-menu-item>\n <mat-icon *ngIf=\"theme.darkMode()\" svgIcon=\"brightness-2\"></mat-icon>\n <mat-icon *ngIf=\"!theme.darkMode()\" svgIcon=\"brightness-5\"></mat-icon>\n <span i18n>Mode</span>\n </button>\n <button [matMenuTriggerFor]=\"themeMenu\" mat-menu-item>\n <mat-icon svgIcon=\"compare\"></mat-icon>\n <span i18n>Theme</span>\n </button>\n <rxap-language-selector></rxap-language-selector>\n <button (click)=\"openChangelogDialog()\" mat-menu-item>\n <mat-icon svgIcon=\"format-list-numbered\"></mat-icon>\n <span i18n>What's new</span>\n </button>\n <ng-container *ngFor=\"let item of items()\">\n <ng-template [cdkPortalOutlet]=\"item\"></ng-template>\n </ng-container>\n</mat-menu>\n\n<mat-menu #themeMenu=\"matMenu\" xPosition=\"before\">\n <button [matMenuTriggerFor]=\"themeDensityMenu\" mat-menu-item>\n <mat-icon svgIcon=\"move-resize\"></mat-icon>\n <span i18n>Density</span>\n </button>\n <button *ngIf=\"availableTypographies?.length\" [matMenuTriggerFor]=\"themeFontMenu\" mat-menu-item>\n <mat-icon svgIcon=\"format-font\"></mat-icon>\n <span i18n>Font</span>\n </button>\n <button *ngIf=\"availableThemes?.length\" [matMenuTriggerFor]=\"themePresetMenu\" mat-menu-item>\n <mat-icon svgIcon=\"shape-outline\"></mat-icon>\n <span i18n>Preset</span>\n </button>\n</mat-menu>\n\n<mat-menu #themeDensityMenu=\"matMenu\" xPosition=\"before\">\n <button (click)=\"setDensity(0)\" (mouseenter)=\"previewDensity(0)\" (mouseleave)=\"restoreDensity()\" mat-menu-item>\n <mat-icon svgIcon=\"size-l\"></mat-icon>\n <span i18n>Normal</span>\n </button>\n <button (click)=\"setDensity(-1)\" (mouseenter)=\"previewDensity(-1)\" (mouseleave)=\"restoreDensity()\" mat-menu-item>\n <mat-icon svgIcon=\"size-m\"></mat-icon>\n <span i18n>Dense</span>\n </button>\n <button (click)=\"setDensity(-2)\" (mouseenter)=\"previewDensity(-2)\" (mouseleave)=\"restoreDensity()\" mat-menu-item>\n <mat-icon svgIcon=\"size-s\"></mat-icon>\n <span i18n>Very Dense</span>\n </button>\n <button (click)=\"setDensity(-3)\" (mouseenter)=\"previewDensity(-3)\" (mouseleave)=\"restoreDensity()\" mat-menu-item>\n <mat-icon svgIcon=\"size-xs\"></mat-icon>\n <span i18n>Extreme Dense</span>\n </button>\n</mat-menu>\n<mat-menu #themeFontMenu=\"matMenu\" xPosition=\"before\">\n <ng-template [ngIf]=\"availableTypographies?.length\">\n <button (click)=\"setTypography(typographyName)\"\n (mouseenter)=\"previewTypography(typographyName)\"\n (mouseleave)=\"restoreTypography()\"\n *ngFor=\"let typographyName of availableTypographies\"\n mat-menu-item>\n {{ typographyName }}\n </button>\n </ng-template>\n</mat-menu>\n\n<mat-menu #themePresetMenu=\"matMenu\" xPosition=\"before\">\n <ng-template [ngIf]=\"availableThemes?.length\">\n <button (click)=\"setTheme(themeName)\"\n (mouseenter)=\"previewTheme(themeName)\"\n (mouseleave)=\"restoreTheme()\"\n *ngFor=\"let themeName of availableThemes\"\n mat-menu-item>\n {{ themeName }}\n </button>\n </ng-template>\n</mat-menu>\n" }]
922
- }], ctorParameters: () => [{ type: i1$6.ThemeService }, { type: i2.ActivatedRoute }, { type: i0.Injector }, { type: i3$3.ChangelogService }] });
953
+ args: [{ selector: 'rxap-settings-button', standalone: true, imports: [
954
+ MatIconButton,
955
+ MatIcon,
956
+ MatMenu,
957
+ MatMenuTrigger,
958
+ MatMenuItem,
959
+ CdkPortalOutlet,
960
+ IconDirective,
961
+ ], template: "<button [matMenuTriggerFor]=\"menu\" mat-icon-button>\n <mat-icon svgIcon=\"cog\"></mat-icon>\n</button>\n\n<mat-menu #menu=\"matMenu\">\n <button (click)=\"theme.toggleDarkTheme()\" mat-menu-item>\n @if (theme.darkMode()) {\n <mat-icon svgIcon=\"brightness-2\"></mat-icon>\n } @else {\n <mat-icon svgIcon=\"brightness-5\"></mat-icon>\n }\n <span i18n>Mode</span>\n </button>\n <button [matMenuTriggerFor]=\"themeMenu\" mat-menu-item>\n <mat-icon svgIcon=\"compare\"></mat-icon>\n <span i18n>Theme</span>\n </button>\n @for (item of customItems(); track item.label) {\n <button (click)=\"clickItem(item)\" mat-menu-item>\n <mat-icon [rxapIcon]=\"item.icon\"></mat-icon>\n <span>{{ item.label }}</span>\n </button>\n }\n @for (item of customItemComponents(); track item) {\n <ng-template [cdkPortalOutlet]=\"item\"></ng-template>\n }\n</mat-menu>\n\n<mat-menu #themeMenu=\"matMenu\" xPosition=\"before\">\n <button [matMenuTriggerFor]=\"themeDensityMenu\" mat-menu-item>\n <mat-icon svgIcon=\"move-resize\"></mat-icon>\n <span i18n>Density</span>\n </button>\n @if (availableTypographies?.length) {\n <button [matMenuTriggerFor]=\"themeFontMenu\" mat-menu-item>\n <mat-icon svgIcon=\"format-font\"></mat-icon>\n <span i18n>Font</span>\n </button>\n }\n @if (availableThemes?.length) {\n <button [matMenuTriggerFor]=\"themePresetMenu\" mat-menu-item>\n <mat-icon svgIcon=\"shape-outline\"></mat-icon>\n <span i18n>Preset</span>\n </button>\n }\n</mat-menu>\n\n<mat-menu #themeDensityMenu=\"matMenu\" xPosition=\"before\">\n <button (click)=\"setDensity(0)\" (mouseenter)=\"previewDensity(0)\" (mouseleave)=\"restoreDensity()\" mat-menu-item>\n <mat-icon svgIcon=\"size-l\"></mat-icon>\n <span i18n>Normal</span>\n </button>\n <button (click)=\"setDensity(-1)\" (mouseenter)=\"previewDensity(-1)\" (mouseleave)=\"restoreDensity()\" mat-menu-item>\n <mat-icon svgIcon=\"size-m\"></mat-icon>\n <span i18n>Dense</span>\n </button>\n <button (click)=\"setDensity(-2)\" (mouseenter)=\"previewDensity(-2)\" (mouseleave)=\"restoreDensity()\" mat-menu-item>\n <mat-icon svgIcon=\"size-s\"></mat-icon>\n <span i18n>Very Dense</span>\n </button>\n <button (click)=\"setDensity(-3)\" (mouseenter)=\"previewDensity(-3)\" (mouseleave)=\"restoreDensity()\" mat-menu-item>\n <mat-icon svgIcon=\"size-xs\"></mat-icon>\n <span i18n>Extreme Dense</span>\n </button>\n</mat-menu>\n<mat-menu #themeFontMenu=\"matMenu\" xPosition=\"before\">\n @for (typographyName of availableTypographies ?? []; track typographyName) {\n <button (click)=\"setTypography(typographyName)\"\n (mouseenter)=\"previewTypography(typographyName)\"\n (mouseleave)=\"restoreTypography()\"\n mat-menu-item>\n {{ typographyName }}\n </button>\n }\n</mat-menu>\n\n<mat-menu #themePresetMenu=\"matMenu\" xPosition=\"before\">\n @for (themeName of availableThemes ?? []; track themeName) {\n <button (click)=\"setTheme(themeName)\"\n (mouseenter)=\"previewTheme(themeName)\"\n (mouseleave)=\"restoreTheme()\"\n mat-menu-item>\n {{ themeName }}\n </button>\n }\n</mat-menu>\n" }]
962
+ }] });
923
963
 
924
- class SidenavToggleButtonComponent {
925
- constructor(layoutComponentService) {
926
- this.layoutComponentService = layoutComponentService;
927
- this.opened = layoutComponentService.opened;
964
+ class ExternalAppsService {
965
+ constructor() {
966
+ this.appFilterList = coerceArray(inject(RXAP_EXTERNAL_APP_FILTER, { optional: true }));
967
+ this.config = inject(ConfigService);
968
+ this.localeId = inject(LOCALE_ID);
969
+ this.environment = inject(RXAP_ENVIRONMENT);
970
+ this.apps = this.config.get('navigation.apps', []);
971
+ this.externalApps = coerceArray(inject(RXAP_EXTERNAL_APP, { optional: true }));
972
+ /**
973
+ * The list of active apps that is processed by the getAppList method
974
+ */
975
+ this.activeAppList = signal([]);
976
+ }
977
+ hasApp(appId) {
978
+ return this.apps.some(app => app.id === appId);
928
979
  }
929
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: SidenavToggleButtonComponent, deps: [{ token: LayoutComponentService }], target: i0.ɵɵFactoryTarget.Component }); }
930
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.1", type: SidenavToggleButtonComponent, isStandalone: true, selector: "rxap-sidenav-toggle-button", ngImport: i0, template: "<button (click)=\"layoutComponentService.toggleOpened()\" mat-icon-button>\n <mat-icon *ngIf=\"!opened()\">menu</mat-icon>\n <mat-icon *ngIf=\"opened()\">menu_open</mat-icon>\n</button>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
931
- }
932
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: SidenavToggleButtonComponent, decorators: [{
933
- type: Component,
934
- args: [{ selector: 'rxap-sidenav-toggle-button', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
935
- MatButtonModule,
936
- NgIf,
937
- MatIconModule,
938
- ], template: "<button (click)=\"layoutComponentService.toggleOpened()\" mat-icon-button>\n <mat-icon *ngIf=\"!opened()\">menu</mat-icon>\n <mat-icon *ngIf=\"opened()\">menu_open</mat-icon>\n</button>\n" }]
939
- }], ctorParameters: () => [{ type: LayoutComponentService }] });
940
-
941
- const EXTRACT_USERNAME_FROM_PROFILE = new InjectionToken('extract-username-from-profile', {
942
- providedIn: 'root',
943
- factory: () => (profile) => (profile ? profile.username ?? profile.email ?? profile.name : null) ?? null,
944
- });
945
- class UserProfileIconComponent {
946
- constructor(userProfileService, authenticationService, extractUsernameFromProfile) {
947
- this.userProfileService = userProfileService;
948
- this.authenticationService = authenticationService;
949
- this.username = toSignal(this.authenticationService.isAuthenticated$.pipe(filter$1(Boolean), switchMap(() => this.userProfileService.connect({
950
- viewChange: this.authenticationService.isAuthenticated$.pipe(skip(1), filter$1(Boolean), distinctUntilChanged()),
951
- })), filter$1(Boolean), map(extractUsernameFromProfile)), { initialValue: null });
952
- }
953
- async logout() {
954
- await this.authenticationService.signOut();
955
- }
956
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: UserProfileIconComponent, deps: [{ token: i1$7.UserProfileDataSource }, { token: i2$4.RxapAuthenticationService }, { token: EXTRACT_USERNAME_FROM_PROFILE }], target: i0.ɵɵFactoryTarget.Component }); }
957
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.1", type: UserProfileIconComponent, isStandalone: true, selector: "rxap-user-profile-icon", ngImport: i0, template: "<button [matMenuTriggerFor]=\"menu\"\n [disabled]=\"!username()\"\n class=\"profile-icon flex flex-row justify-center items-center\">\n <mat-icon class=\"avatar-icon\" svgIcon=\"account-circle\"></mat-icon>\n</button>\n\n<mat-menu #menu=\"matMenu\" [yPosition]=\"'below'\" class=\"!max-w-none\">\n <button mat-menu-item>\n <span class=\"flex flex-row gap-2\">\n <mat-icon svgIcon=\"account\"></mat-icon>\n <span>{{username()}}</span>\n </span>\n </button>\n <button (click)=\"logout()\" mat-menu-item>\n <span class=\"flex flex-row gap-2\">\n <mat-icon svgIcon=\"logout\"></mat-icon>\n <span i18n>Logout</span>\n </span>\n </button>\n</mat-menu>\n", styles: [".profile-icon{border-radius:100%;border:none;height:32px;width:32px;overflow:hidden;background-position:center center;background-repeat:no-repeat;background-size:cover}.profile-icon .avatar-icon{width:32px;height:32px;font-size:32px}.profile-icon:hover{cursor:pointer}.profile-icon:focus{outline:none}\n"], dependencies: [{ kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: i7.MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: i7.MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i7.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
958
- }
959
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: UserProfileIconComponent, decorators: [{
960
- type: Component,
961
- args: [{ selector: 'rxap-user-profile-icon', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
962
- MatMenuModule,
963
- MatIconModule,
964
- NgIf,
965
- AsyncPipe,
966
- ], template: "<button [matMenuTriggerFor]=\"menu\"\n [disabled]=\"!username()\"\n class=\"profile-icon flex flex-row justify-center items-center\">\n <mat-icon class=\"avatar-icon\" svgIcon=\"account-circle\"></mat-icon>\n</button>\n\n<mat-menu #menu=\"matMenu\" [yPosition]=\"'below'\" class=\"!max-w-none\">\n <button mat-menu-item>\n <span class=\"flex flex-row gap-2\">\n <mat-icon svgIcon=\"account\"></mat-icon>\n <span>{{username()}}</span>\n </span>\n </button>\n <button (click)=\"logout()\" mat-menu-item>\n <span class=\"flex flex-row gap-2\">\n <mat-icon svgIcon=\"logout\"></mat-icon>\n <span i18n>Logout</span>\n </span>\n </button>\n</mat-menu>\n", styles: [".profile-icon{border-radius:100%;border:none;height:32px;width:32px;overflow:hidden;background-position:center center;background-repeat:no-repeat;background-size:cover}.profile-icon .avatar-icon{width:32px;height:32px;font-size:32px}.profile-icon:hover{cursor:pointer}.profile-icon:focus{outline:none}\n"] }]
967
- }], ctorParameters: () => [{ type: i1$7.UserProfileDataSource }, { type: i2$4.RxapAuthenticationService }, { type: undefined, decorators: [{
968
- type: Inject,
969
- args: [EXTRACT_USERNAME_FROM_PROFILE]
970
- }] }] });
971
-
972
- class HeaderComponent {
973
- constructor(headerComponentService, layoutComponentService, headerComponent) {
974
- this.headerComponentService = headerComponentService;
975
- this.layoutComponentService = layoutComponentService;
976
- this.headerComponent = headerComponent;
977
- this.color = undefined;
978
- this.collapsable = layoutComponentService.collapsable;
979
- this.opened = layoutComponentService.opened;
980
- }
981
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: HeaderComponent, deps: [{ token: HeaderService }, { token: LayoutComponentService }, { token: RXAP_HEADER_COMPONENT, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
982
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.1", type: HeaderComponent, isStandalone: true, selector: "rxap-header", inputs: { color: "color" }, ngImport: i0, template: "<mat-toolbar [color]=\"color\" [ngClass]=\"{ open: opened() }\" class=\"mat-elevation-z3 header\">\n <div class=\"w-full flex flex-row gap-x-4 justify-between items-center\">\n <rxap-sidenav-toggle-button *ngIf=\"!collapsable()\"></rxap-sidenav-toggle-button>\n <div class=\"grow\">\n <ng-content></ng-content>\n </div>\n <rxap-apps-button class=\"grow-0\"></rxap-apps-button>\n <rxap-settings-button class=\"grow-0\"></rxap-settings-button>\n <rxap-user-profile-icon class=\"grow-0\"></rxap-user-profile-icon>\n </div>\n</mat-toolbar>\n\n<rxap-navigation-progress-bar></rxap-navigation-progress-bar>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: MatToolbarModule }, { kind: "component", type: i2$2.MatToolbar, selector: "mat-toolbar", inputs: ["color"], exportAs: ["matToolbar"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "ngmodule", type: MatMenuModule }, { kind: "ngmodule", type: MatIconModule }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "ngmodule", type: MatSelectModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: MatOptionModule }, { kind: "ngmodule", type: MatSlideToggleModule }, { kind: "component", type: NavigationProgressBarComponent, selector: "rxap-navigation-progress-bar" }, { kind: "component", type: UserProfileIconComponent, selector: "rxap-user-profile-icon" }, { kind: "component", type: AppsButtonComponent, selector: "rxap-apps-button" }, { kind: "component", type: SettingsButtonComponent, selector: "rxap-settings-button" }, { kind: "component", type: SidenavToggleButtonComponent, selector: "rxap-sidenav-toggle-button" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
983
- }
984
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: HeaderComponent, decorators: [{
985
- type: Component,
986
- args: [{ selector: 'rxap-header', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
987
- MatToolbarModule,
988
- NgClass,
989
- NgIf,
990
- MatButtonModule,
991
- MatMenuModule,
992
- MatIconModule,
993
- MatFormFieldModule,
994
- StopPropagationDirective,
995
- MatSelectModule,
996
- FormsModule,
997
- MatOptionModule,
998
- DataSourceCollectionDirective,
999
- MatSlideToggleModule,
1000
- AsyncPipe,
1001
- NavigationProgressBarComponent,
1002
- UserProfileIconComponent,
1003
- AppsButtonComponent,
1004
- SettingsButtonComponent,
1005
- SidenavToggleButtonComponent,
1006
- ], template: "<mat-toolbar [color]=\"color\" [ngClass]=\"{ open: opened() }\" class=\"mat-elevation-z3 header\">\n <div class=\"w-full flex flex-row gap-x-4 justify-between items-center\">\n <rxap-sidenav-toggle-button *ngIf=\"!collapsable()\"></rxap-sidenav-toggle-button>\n <div class=\"grow\">\n <ng-content></ng-content>\n </div>\n <rxap-apps-button class=\"grow-0\"></rxap-apps-button>\n <rxap-settings-button class=\"grow-0\"></rxap-settings-button>\n <rxap-user-profile-icon class=\"grow-0\"></rxap-user-profile-icon>\n </div>\n</mat-toolbar>\n\n<rxap-navigation-progress-bar></rxap-navigation-progress-bar>\n" }]
1007
- }], ctorParameters: () => [{ type: i1$1.HeaderService, decorators: [{
1008
- type: Inject,
1009
- args: [HeaderService]
1010
- }] }, { type: LayoutComponentService }, { type: undefined, decorators: [{
1011
- type: Optional
1012
- }, {
1013
- type: Inject,
1014
- args: [RXAP_HEADER_COMPONENT]
1015
- }] }], propDecorators: { color: [{
1016
- type: Input
1017
- }] } });
1018
-
1019
- class LayoutComponent {
1020
- constructor(layoutComponentService, environment, iconLoaderService) {
1021
- this.layoutComponentService = layoutComponentService;
1022
- this.environment = environment;
1023
- this.userSettingsThemeService = inject(UserSettingsThemeService);
1024
- this.themeService = inject(ThemeService);
1025
- iconLoaderService.load();
1026
- this.fixedBottomGap = layoutComponentService.fixedBottomGap;
1027
- this.fixedTopGap = layoutComponentService.fixedTopGap;
1028
- this.pinned = layoutComponentService.pinned;
1029
- this.collapsable = layoutComponentService.collapsable;
1030
- this.opened = layoutComponentService.opened;
1031
- this.sidenavMode = layoutComponentService.mode;
1032
- this.logoSrc = this.layoutComponentService.logo.src ?? 'https://via.placeholder.com/256x128px';
1033
- this.logoWidth = this.layoutComponentService.logo.width ?? 256;
1034
- this.release = DetermineReleaseName(this.environment);
980
+ getApp(appId) {
981
+ if (!this.hasApp(appId)) {
982
+ return null;
983
+ }
984
+ const app = this.apps.find(app => app.id === appId);
985
+ if (!app) {
986
+ throw new Error(`FATAL: App with id "${appId}" not found!`);
987
+ }
988
+ return structuredClone(app);
1035
989
  }
1036
- ngOnDestroy() {
1037
- this.userSettingsThemeService.stopSync();
990
+ getAppUrl(appId, path, infix = this.getPathPrefix()) {
991
+ const app = this.getApp(appId);
992
+ if (!app || !app.href) {
993
+ return null;
994
+ }
995
+ return JoinPath(app.href, infix, path);
1038
996
  }
1039
- ngOnInit() {
1040
- this.userSettingsThemeService.startSync();
1041
- this.userSettingsThemeService.get().then(theme => {
1042
- if (theme.preset && theme.preset !== 'default') {
1043
- this.themeService.setTheme(theme.preset, true);
1044
- }
1045
- if (theme.density && IsThemeDensity(theme.density) && theme.density !== ThemeDensity.Normal) {
1046
- this.themeService.setDensity(theme.density, true);
1047
- }
1048
- if (theme.typography && theme.typography !== 'default') {
1049
- this.themeService.setTypography(theme.typography, true);
997
+ getAppRouterLink(appId, path) {
998
+ const app = this.getApp(appId);
999
+ if (!app || !app.routerLink) {
1000
+ return null;
1001
+ }
1002
+ return [...app.routerLink, path];
1003
+ }
1004
+ getAppUrlOrThrow(appId, path) {
1005
+ const url = this.getAppUrl(appId, path);
1006
+ if (url) {
1007
+ return url;
1008
+ }
1009
+ throw new Error(`Could not find url for app with id "${appId}"`);
1010
+ }
1011
+ getAppRouterLinkOrThrow(appId, path) {
1012
+ const routerLink = this.getAppRouterLink(appId, path);
1013
+ if (routerLink) {
1014
+ return routerLink;
1015
+ }
1016
+ throw new Error(`Could not find router link for app with id "${appId}"`);
1017
+ }
1018
+ navigate(appId, path) {
1019
+ const url = this.getAppUrl(appId, path);
1020
+ if (url) {
1021
+ ClickOnLink(url);
1022
+ }
1023
+ }
1024
+ async getAppList() {
1025
+ let appList = [
1026
+ ...this.externalApps,
1027
+ ...this.apps,
1028
+ ].filter(app => !app.hidden)
1029
+ .map(app => structuredClone(app));
1030
+ appList.forEach(app => {
1031
+ if (app.href) {
1032
+ app.href = JoinPath(app.href, this.getPathPrefix());
1050
1033
  }
1051
1034
  });
1035
+ for (const appFilter of this.appFilterList) {
1036
+ appList = await appFilter.call(structuredClone(appList));
1037
+ }
1038
+ appList = structuredClone(appList);
1039
+ this.activeAppList.set(appList);
1040
+ return appList;
1041
+ }
1042
+ getPathPrefix() {
1043
+ if (this.environment.production && this.localeId) {
1044
+ return this.localeId.replace(/-.+$/, '');
1045
+ }
1046
+ return '';
1052
1047
  }
1053
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: LayoutComponent, deps: [{ token: LayoutComponentService }, { token: RXAP_ENVIRONMENT }, { token: i2$6.IconLoaderService }], target: i0.ɵɵFactoryTarget.Component }); }
1054
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.1", type: LayoutComponent, isStandalone: true, selector: "rxap-layout", viewQueries: [{ propertyName: "sidenav", first: true, predicate: MatSidenav, descendants: true, static: true }], ngImport: i0, template: "<rxap-status-indicator class=\"fixed bottom-0 right-0 z-10\"></rxap-status-indicator>\n<div class=\"flex flex-col h-screen justify-between\">\n <rxap-header class=\"z-10 w-full fixed top-0\"></rxap-header>\n <mat-sidenav-container [ngStyle]=\"{\n 'margin-top.px': fixedTopGap(),\n 'margin-bottom.px': fixedBottomGap(),\n }\" class=\"grow\">\n <mat-sidenav\n #matSidenav=\"matSidenav\"\n [fixedBottomGap]=\"fixedBottomGap()\"\n [fixedInViewport]=\"true\"\n [fixedTopGap]=\"fixedTopGap()\"\n [mode]=\"sidenavMode()\"\n [ngClass]=\"{ collapsable: collapsable() }\"\n class=\"sidenav\"\n [opened]=\"opened()\"\n >\n <div (mouseleave)=\"collapsable() && !pinned() && matSidenav.close()\"\n class=\"h-full py-2 flex flex-col items-center gap-y-5 justify-items-stretch\">\n\n <div (click)=\"layoutComponentService.togglePinned()\" *ngIf=\"collapsable()\"\n class=\"pl-2 self-stretch grow-0 flex flex-row justify-between items-center\">\n <span class=\"text-lg\" i18n>Navigation</span>\n <div class=\"flex flex-row items-center justify-center\" style=\"width: 64px\">\n <button mat-icon-button>\n <mat-icon *ngIf=\"!pinned()\">radio_button_unchecked</mat-icon>\n <mat-icon *ngIf=\"pinned()\">radio_button_checked</mat-icon>\n </button>\n </div>\n </div>\n\n <ul\n (mouseenter)=\"collapsable() && !pinned() && matSidenav.open()\"\n class=\"grow self-stretch\"\n root\n rxap-navigation\n >\n </ul>\n\n <img\n [src]=\"logoSrc\"\n [routerLink]=\"['/']\"\n [width]=\"logoWidth\"\n alt=\"logo\"\n class=\"grow-0 mx-16\"\n />\n <div class=\"grow-0 px-16\">\n <span>{{release}}</span>\n </div>\n </div>\n </mat-sidenav>\n <mat-sidenav-content [ngClass]=\"{ 'ml-16': collapsable() }\" class=\"p-4\">\n <router-outlet></router-outlet>\n </mat-sidenav-content>\n </mat-sidenav-container>\n <rxap-footer class=\"z-10 w-full fixed bottom-0\"></rxap-footer>\n</div>\n<!--<rxap-window-task-bar-container></rxap-window-task-bar-container>-->\n", styles: [":host .sidenav.collapsable:not(.mat-drawer-opened){transform:translate(calc(-100% + 64px))!important;visibility:visible!important;box-shadow:inherit!important;transition-property:transform;transition-delay:.25s;display:flex;border-right:solid 1px rgba(0,0,0,.12)}:host .sidenav.collapsable ::ng-deep .mat-drawer-inner-container::-webkit-scrollbar{display:none}\n"], dependencies: [{ kind: "component", type: HeaderComponent, selector: "rxap-header", inputs: ["color"] }, { kind: "ngmodule", type: MatSidenavModule }, { kind: "component", type: i3$4.MatSidenav, selector: "mat-sidenav", inputs: ["fixedInViewport", "fixedTopGap", "fixedBottomGap"], exportAs: ["matSidenav"] }, { kind: "component", type: i3$4.MatSidenavContainer, selector: "mat-sidenav-container", exportAs: ["matSidenavContainer"] }, { kind: "component", type: i3$4.MatSidenavContent, selector: "mat-sidenav-content" }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.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: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: FooterComponent, selector: "rxap-footer" }, { kind: "ngmodule", type: MatMenuModule }, { kind: "component", type: NavigationComponent, selector: "ul[rxap-navigation]", inputs: ["items", "level", "root"] }, { kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "component", type: StatusIndicatorComponent, selector: "rxap-status-indicator" }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1048
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: ExternalAppsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1049
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: ExternalAppsService }); }
1055
1050
  }
1056
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: LayoutComponent, decorators: [{
1057
- type: Component,
1058
- args: [{ selector: 'rxap-layout', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
1059
- HeaderComponent,
1060
- MatSidenavModule,
1061
- AsyncPipe,
1062
- MatIconModule,
1063
- MatButtonModule,
1064
- RouterLink,
1065
- NgIf,
1066
- FooterComponent,
1067
- MatMenuModule,
1068
- NgOptimizedImage,
1069
- NavigationComponent,
1070
- RouterOutlet,
1071
- StatusIndicatorComponent,
1072
- NgStyle,
1073
- NgClass,
1074
- ], template: "<rxap-status-indicator class=\"fixed bottom-0 right-0 z-10\"></rxap-status-indicator>\n<div class=\"flex flex-col h-screen justify-between\">\n <rxap-header class=\"z-10 w-full fixed top-0\"></rxap-header>\n <mat-sidenav-container [ngStyle]=\"{\n 'margin-top.px': fixedTopGap(),\n 'margin-bottom.px': fixedBottomGap(),\n }\" class=\"grow\">\n <mat-sidenav\n #matSidenav=\"matSidenav\"\n [fixedBottomGap]=\"fixedBottomGap()\"\n [fixedInViewport]=\"true\"\n [fixedTopGap]=\"fixedTopGap()\"\n [mode]=\"sidenavMode()\"\n [ngClass]=\"{ collapsable: collapsable() }\"\n class=\"sidenav\"\n [opened]=\"opened()\"\n >\n <div (mouseleave)=\"collapsable() && !pinned() && matSidenav.close()\"\n class=\"h-full py-2 flex flex-col items-center gap-y-5 justify-items-stretch\">\n\n <div (click)=\"layoutComponentService.togglePinned()\" *ngIf=\"collapsable()\"\n class=\"pl-2 self-stretch grow-0 flex flex-row justify-between items-center\">\n <span class=\"text-lg\" i18n>Navigation</span>\n <div class=\"flex flex-row items-center justify-center\" style=\"width: 64px\">\n <button mat-icon-button>\n <mat-icon *ngIf=\"!pinned()\">radio_button_unchecked</mat-icon>\n <mat-icon *ngIf=\"pinned()\">radio_button_checked</mat-icon>\n </button>\n </div>\n </div>\n\n <ul\n (mouseenter)=\"collapsable() && !pinned() && matSidenav.open()\"\n class=\"grow self-stretch\"\n root\n rxap-navigation\n >\n </ul>\n\n <img\n [src]=\"logoSrc\"\n [routerLink]=\"['/']\"\n [width]=\"logoWidth\"\n alt=\"logo\"\n class=\"grow-0 mx-16\"\n />\n <div class=\"grow-0 px-16\">\n <span>{{release}}</span>\n </div>\n </div>\n </mat-sidenav>\n <mat-sidenav-content [ngClass]=\"{ 'ml-16': collapsable() }\" class=\"p-4\">\n <router-outlet></router-outlet>\n </mat-sidenav-content>\n </mat-sidenav-container>\n <rxap-footer class=\"z-10 w-full fixed bottom-0\"></rxap-footer>\n</div>\n<!--<rxap-window-task-bar-container></rxap-window-task-bar-container>-->\n", styles: [":host .sidenav.collapsable:not(.mat-drawer-opened){transform:translate(calc(-100% + 64px))!important;visibility:visible!important;box-shadow:inherit!important;transition-property:transform;transition-delay:.25s;display:flex;border-right:solid 1px rgba(0,0,0,.12)}:host .sidenav.collapsable ::ng-deep .mat-drawer-inner-container::-webkit-scrollbar{display:none}\n"] }]
1075
- }], ctorParameters: () => [{ type: LayoutComponentService }, { type: undefined, decorators: [{
1076
- type: Inject,
1077
- args: [RXAP_ENVIRONMENT]
1078
- }] }, { type: i2$6.IconLoaderService }], propDecorators: { sidenav: [{
1079
- type: ViewChild,
1080
- args: [MatSidenav, { static: true }]
1081
- }] } });
1051
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: ExternalAppsService, decorators: [{
1052
+ type: Injectable
1053
+ }] });
1082
1054
 
1083
- class SignOutComponent {
1084
- constructor(authenticationService) {
1085
- this.authenticationService = authenticationService;
1055
+ class AppsButtonComponent {
1056
+ constructor() {
1057
+ /**
1058
+ * The signal that indicates if the app list is open
1059
+ */
1060
+ this.isOpen = signal(false);
1061
+ this.externalAppsService = inject(ExternalAppsService);
1062
+ this.appList = computed(() => this.externalAppsService.activeAppList());
1063
+ this.hasApps = computed(() => this.appList().length > 0);
1086
1064
  }
1087
- async logout() {
1088
- await this.authenticationService.signOut();
1065
+ toggle() {
1066
+ this.isOpen.update(isOpen => !isOpen);
1089
1067
  }
1090
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: SignOutComponent, deps: [{ token: i2$4.RxapAuthenticationService }], target: i0.ɵɵFactoryTarget.Component }); }
1091
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.1", type: SignOutComponent, isStandalone: true, selector: "rxap-sign-out", ngImport: i0, template: "<button\n mat-icon-button\n (click)=\"logout()\"\n>\n <mat-icon svgIcon=\"logout\"></mat-icon>\n</button>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1092
- }
1093
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: SignOutComponent, decorators: [{
1094
- type: Component,
1095
- args: [{ selector: 'rxap-sign-out', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [MatButtonModule, MatIconModule], template: "<button\n mat-icon-button\n (click)=\"logout()\"\n>\n <mat-icon svgIcon=\"logout\"></mat-icon>\n</button>\n" }]
1096
- }], ctorParameters: () => [{ type: i2$4.RxapAuthenticationService }] });
1097
-
1098
- class ResetButtonComponent {
1099
- constructor(resetService) {
1100
- this.resetService = resetService;
1068
+ ngOnInit() {
1069
+ this.externalAppsService.getAppList();
1101
1070
  }
1102
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: ResetButtonComponent, deps: [{ token: ResetService }], target: i0.ɵɵFactoryTarget.Component }); }
1103
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.1", type: ResetButtonComponent, isStandalone: true, selector: "rxap-reset-button", ngImport: i0, template: "<button (click)=\"resetService.resetAll()\" mat-icon-button>\n <mat-icon svgIcon=\"refresh\"></mat-icon>\n</button>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i4.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1071
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: AppsButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1072
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.1", type: AppsButtonComponent, isStandalone: true, selector: "rxap-apps-button", ngImport: i0, template: "@if (hasApps()) {\n <div class=\"flex flex-row items-center gap-8\">\n\n @if (isOpen()) {\n <div class=\"flex flex-row items-center gap-6 h-10\">\n\n @for (app of appList(); track app.label) {\n @if (app.href) {\n <a [href]=\"app.href\" [target]=\"app.target ?? '_self'\" mat-stroked-button>\n <span class=\"flex flex-row items-center gap-4\">\n @if (app.icon) {\n <mat-icon [rxapIcon]=\"app.icon\"></mat-icon>\n }\n @if (app.image) {\n <img [alt]=\"app.label\" [ngSrc]=\"app.image\" height=\"40\" width=\"40\">\n }\n <span class=\"label grow-0\">{{ app.label }}</span>\n </span>\n </a>\n } @else if (app.routerLink) {\n <a mat-stroked-button [routerLink]=\"app.routerLink\">\n <span class=\"flex flex-row items-center gap-4\">\n @if (app.icon) {\n <mat-icon [rxapIcon]=\"app.icon\"></mat-icon>\n }\n @if (app.image) {\n <img [alt]=\"app.label\" [ngSrc]=\"app.image\" height=\"40\" width=\"40\">\n }\n <span class=\"label grow-0\">{{ app.label }}</span>\n </span>\n </a>\n } @else {\n <button mat-stroked-button [disabled]=\"true\">\n <span class=\"flex flex-row items-center gap-4\">\n @if (app.icon) {\n <mat-icon [rxapIcon]=\"app.icon\"></mat-icon>\n }\n @if (app.image) {\n <img [alt]=\"app.label\" [ngSrc]=\"app.image\" height=\"40\" width=\"40\">\n }\n <span class=\"label grow-0\">{{ app.label }}</span>\n </span>\n </button>\n }\n }\n\n </div>\n }\n\n <button (click)=\"toggle()\" mat-icon-button>\n <mat-icon svgIcon=\"apps\"></mat-icon>\n </button>\n\n </div>\n}\n", styles: [""], dependencies: [{ kind: "directive", type: NgOptimizedImage, selector: "img[ngSrc]", inputs: ["ngSrc", "ngSrcset", "sizes", "width", "height", "loading", "priority", "loaderParams", "disableOptimizedSrcset", "fill", "placeholder", "placeholderConfig", "src", "srcset"] }, { kind: "component", type: MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: MatAnchor, selector: "a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button]", exportAs: ["matButton", "matAnchor"] }, { 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: "directive", type: IconDirective, selector: "mat-icon[rxapIcon]", inputs: ["rxapIcon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1104
1073
  }
1105
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: ResetButtonComponent, decorators: [{
1074
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: AppsButtonComponent, decorators: [{
1106
1075
  type: Component,
1107
- args: [{ selector: 'rxap-reset-button', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [MatButtonModule, MatIconModule], template: "<button (click)=\"resetService.resetAll()\" mat-icon-button>\n <mat-icon svgIcon=\"refresh\"></mat-icon>\n</button>\n" }]
1108
- }], ctorParameters: () => [{ type: i1$1.ResetService, decorators: [{
1109
- type: Inject,
1110
- args: [ResetService]
1111
- }] }] });
1076
+ args: [{ selector: 'rxap-apps-button', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
1077
+ NgOptimizedImage,
1078
+ MatButton,
1079
+ RouterLink,
1080
+ MatAnchor,
1081
+ MatIconButton,
1082
+ MatIcon,
1083
+ IconDirective,
1084
+ ], template: "@if (hasApps()) {\n <div class=\"flex flex-row items-center gap-8\">\n\n @if (isOpen()) {\n <div class=\"flex flex-row items-center gap-6 h-10\">\n\n @for (app of appList(); track app.label) {\n @if (app.href) {\n <a [href]=\"app.href\" [target]=\"app.target ?? '_self'\" mat-stroked-button>\n <span class=\"flex flex-row items-center gap-4\">\n @if (app.icon) {\n <mat-icon [rxapIcon]=\"app.icon\"></mat-icon>\n }\n @if (app.image) {\n <img [alt]=\"app.label\" [ngSrc]=\"app.image\" height=\"40\" width=\"40\">\n }\n <span class=\"label grow-0\">{{ app.label }}</span>\n </span>\n </a>\n } @else if (app.routerLink) {\n <a mat-stroked-button [routerLink]=\"app.routerLink\">\n <span class=\"flex flex-row items-center gap-4\">\n @if (app.icon) {\n <mat-icon [rxapIcon]=\"app.icon\"></mat-icon>\n }\n @if (app.image) {\n <img [alt]=\"app.label\" [ngSrc]=\"app.image\" height=\"40\" width=\"40\">\n }\n <span class=\"label grow-0\">{{ app.label }}</span>\n </span>\n </a>\n } @else {\n <button mat-stroked-button [disabled]=\"true\">\n <span class=\"flex flex-row items-center gap-4\">\n @if (app.icon) {\n <mat-icon [rxapIcon]=\"app.icon\"></mat-icon>\n }\n @if (app.image) {\n <img [alt]=\"app.label\" [ngSrc]=\"app.image\" height=\"40\" width=\"40\">\n }\n <span class=\"label grow-0\">{{ app.label }}</span>\n </span>\n </button>\n }\n }\n\n </div>\n }\n\n <button (click)=\"toggle()\" mat-icon-button>\n <mat-icon svgIcon=\"apps\"></mat-icon>\n </button>\n\n </div>\n}\n" }]
1085
+ }] });
1112
1086
 
1113
- class AuthenticationServiceMock {
1114
- // eslint-disable-next-line @typescript-eslint/no-empty-function
1115
- signOut() {
1116
- }
1117
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: AuthenticationServiceMock, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1118
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: AuthenticationServiceMock }); }
1087
+ class DefaultHeaderComponent {
1088
+ constructor() {
1089
+ this.layoutComponentService = inject(LayoutService);
1090
+ this.collapsable = computed(() => this.layoutComponentService.collapsable());
1091
+ this.opened = computed(() => this.layoutComponentService.opened());
1092
+ this.userProfileService = inject(UserProfileDataSource);
1093
+ this.profile = toSignal(this.userProfileService.connect('user-profile'), { initialValue: null });
1094
+ }
1095
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: DefaultHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1096
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.1", type: DefaultHeaderComponent, isStandalone: true, selector: "rxap-default-header", host: { classAttribute: "grow" }, ngImport: i0, template: "<div class=\"w-full flex flex-row gap-x-4 justify-between items-center\">\n @if (!collapsable()) {\n <rxap-sidenav-toggle-button></rxap-sidenav-toggle-button>\n }\n <div class=\"grow\">\n <ng-content></ng-content>\n </div>\n <rxap-apps-button class=\"grow-0\"></rxap-apps-button>\n <rxap-settings-button class=\"grow-0\"></rxap-settings-button>\n @if (this.profile(); as profile) {\n <rxap-user-profile-icon [profile]=\"profile\" class=\"grow-0\"></rxap-user-profile-icon>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "component", type: AppsButtonComponent, selector: "rxap-apps-button" }, { kind: "component", type: SettingsButtonComponent, selector: "rxap-settings-button" }, { kind: "component", type: SidenavToggleButtonComponent, selector: "rxap-sidenav-toggle-button" }, { kind: "component", type: UserProfileIconComponent, selector: "rxap-user-profile-icon", inputs: ["profile"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1119
1097
  }
1120
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: AuthenticationServiceMock, decorators: [{
1121
- type: Injectable
1098
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: DefaultHeaderComponent, decorators: [{
1099
+ type: Component,
1100
+ args: [{ selector: 'rxap-default-header', standalone: true, imports: [
1101
+ AppsButtonComponent,
1102
+ SettingsButtonComponent,
1103
+ SidenavToggleButtonComponent,
1104
+ UserProfileIconComponent,
1105
+ ], host: {
1106
+ 'class': 'grow',
1107
+ }, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"w-full flex flex-row gap-x-4 justify-between items-center\">\n @if (!collapsable()) {\n <rxap-sidenav-toggle-button></rxap-sidenav-toggle-button>\n }\n <div class=\"grow\">\n <ng-content></ng-content>\n </div>\n <rxap-apps-button class=\"grow-0\"></rxap-apps-button>\n <rxap-settings-button class=\"grow-0\"></rxap-settings-button>\n @if (this.profile(); as profile) {\n <rxap-user-profile-icon [profile]=\"profile\" class=\"grow-0\"></rxap-user-profile-icon>\n }\n</div>\n" }]
1122
1108
  }] });
1123
1109
 
1124
- class FooterDirective {
1125
- constructor(footerService, template, viewContainerRef) {
1126
- this.footerService = footerService;
1127
- this.template = template;
1128
- this.viewContainerRef = viewContainerRef;
1129
- }
1130
- ngOnInit() {
1131
- this._portal = new TemplatePortal(this.template, this.viewContainerRef);
1132
- this.footerService.pushPortal(this._portal);
1133
- }
1134
- ngOnDestroy() {
1135
- if (this._portal) {
1136
- this.footerService.removePortal(this._portal);
1137
- }
1138
- }
1139
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: FooterDirective, deps: [{ token: FooterService }, { token: TemplateRef }, { token: ViewContainerRef }], target: i0.ɵɵFactoryTarget.Directive }); }
1140
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.0.1", type: FooterDirective, isStandalone: true, selector: "[rxapFooter]", ngImport: i0 }); }
1110
+ function provideLayout(...additionalProviders) {
1111
+ return [
1112
+ ExternalAppsService,
1113
+ LayoutService,
1114
+ LogoService,
1115
+ NavigationService,
1116
+ HeaderService,
1117
+ FooterService,
1118
+ ...additionalProviders,
1119
+ ];
1120
+ }
1121
+ function withNavigationConfig(config) {
1122
+ return [
1123
+ {
1124
+ provide: RXAP_NAVIGATION_CONFIG,
1125
+ useValue: config,
1126
+ },
1127
+ ];
1128
+ }
1129
+ function withExternalApps(...apps) {
1130
+ return apps.map(app => ({
1131
+ provide: RXAP_EXTERNAL_APP,
1132
+ useValue: app,
1133
+ multi: true,
1134
+ }));
1135
+ }
1136
+ function withNavigationInserts(inserts) {
1137
+ return [{
1138
+ provide: RXAP_NAVIGATION_CONFIG_INSERTS,
1139
+ useValue: inserts,
1140
+ }];
1141
+ }
1142
+ function withSettingsMenuItems(...items) {
1143
+ return [
1144
+ ...items.filter((item) => typeof item === 'function').map(component => ({
1145
+ provide: RXAP_SETTINGS_MENU_ITEM_COMPONENT,
1146
+ useValue: component,
1147
+ multi: true,
1148
+ })),
1149
+ ...items.filter((item) => typeof item !== 'function').map(item => ({
1150
+ provide: RXAP_SETTINGS_MENU_ITEM,
1151
+ useValue: item,
1152
+ multi: true,
1153
+ })),
1154
+ ];
1155
+ }
1156
+ function withReleaseInfoModules(...module) {
1157
+ return module.map(item => ({
1158
+ provide: RXAP_RELEASE_INFO_MODULE,
1159
+ useValue: item,
1160
+ multi: true,
1161
+ }));
1162
+ }
1163
+ function withHeaderComponents(components) {
1164
+ return components.map(component => ({
1165
+ provide: RXAP_HEADER_COMPONENT,
1166
+ useValue: component,
1167
+ }));
1168
+ }
1169
+ function withFooterComponents(components) {
1170
+ return components.map(component => ({
1171
+ provide: RXAP_FOOTER_COMPONENT,
1172
+ useValue: component,
1173
+ }));
1174
+ }
1175
+ function widthDefaultHeaderComponent() {
1176
+ return {
1177
+ provide: RXAP_HEADER_COMPONENT,
1178
+ useValue: DefaultHeaderComponent,
1179
+ };
1141
1180
  }
1142
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: FooterDirective, decorators: [{
1143
- type: Directive,
1144
- args: [{
1145
- selector: '[rxapFooter]',
1146
- standalone: true,
1147
- }]
1148
- }], ctorParameters: () => [{ type: i1$1.FooterService, decorators: [{
1149
- type: Inject,
1150
- args: [FooterService]
1151
- }] }, { type: i0.TemplateRef, decorators: [{
1152
- type: Inject,
1153
- args: [TemplateRef]
1154
- }] }, { type: i0.ViewContainerRef, decorators: [{
1155
- type: Inject,
1156
- args: [ViewContainerRef]
1157
- }] }] });
1158
1181
 
1159
- // region window-container-sidenav
1182
+ // region sidenav
1160
1183
  // endregion
1161
1184
 
1162
1185
  /**
1163
1186
  * Generated bundle index. Do not edit.
1164
1187
  */
1165
1188
 
1166
- export { AppUrlService, AppsButtonComponent, AuthenticationServiceMock, EXTRACT_USERNAME_FROM_PROFILE, FooterComponent, FooterDirective, HeaderComponent, IsNavigationDividerItem, IsNavigationInsertItem, IsNavigationItem, LanguageSelectorComponent, LayoutComponent, LayoutComponentService, NavigationComponent, NavigationItemComponent, NavigationProgressBarComponent, NavigationService, RXAP_FOOTER_COMPONENT, RXAP_HEADER_COMPONENT, RXAP_LAYOUT_APPS_GRID, RXAP_LOGO_CONFIG, RXAP_NAVIGATION_CONFIG, RXAP_NAVIGATION_CONFIG_INSERTS, ReplaceRouterPathsPipe, ReplaceRouterPathsService, ResetButtonComponent, SettingsButtonComponent, SidenavComponent, SidenavComponentService, SidenavFooterDirective, SidenavHeaderDirective, SidenavToggleButtonComponent, SignOutComponent, ToggleWindowSidenavButtonComponent, UserProfileIconComponent, VersionComponent, WindowContainerSidenavComponent };
1189
+ export { AppsButtonComponent, BaseLayoutComponent, DefaultHeaderComponent, EXTRACT_USERNAME_FROM_PROFILE, ExternalAppsService, FooterComponent, FooterDirective, FooterService, HeaderComponent, HeaderDirective, HeaderService, IsNavigationDividerItem, IsNavigationInsertItem, IsNavigationItem, LayoutComponent, LayoutService, LogoService, MinimalLayoutComponent, NavigationComponent, NavigationItemComponent, NavigationProgressBarComponent, NavigationService, RXAP_EXTERNAL_APP, RXAP_EXTERNAL_APP_FILTER, RXAP_FOOTER_COMPONENT, RXAP_HEADER_COMPONENT, RXAP_LAYOUT_APPS_GRID, RXAP_LOGO_CONFIG, RXAP_NAVIGATION_CONFIG, RXAP_NAVIGATION_CONFIG_INSERTS, RXAP_RELEASE_INFO_MODULE, RXAP_SETTINGS_MENU_ITEM, RXAP_SETTINGS_MENU_ITEM_COMPONENT, ReleaseInfoComponent, SettingsButtonComponent, SidenavComponent, SidenavFooterDirective, SidenavHeaderDirective, SidenavToggleButtonComponent, UserProfileIconComponent, provideLayout, widthDefaultHeaderComponent, withExternalApps, withFooterComponents, withHeaderComponents, withNavigationConfig, withNavigationInserts, withReleaseInfoModules, withSettingsMenuItems };
1167
1190
  //# sourceMappingURL=rxap-layout.mjs.map