@rxap/layout 18.0.3-dev.0 → 18.1.0-dev.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +280 -1
  3. package/compodoc/changelog.html +13 -0
  4. package/compodoc/components/AppsButtonComponent.html +185 -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 +11 -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 +183 -1
  26. package/compodoc/injectables/ExternalAppsService.html +1274 -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 +544 -1
  38. package/compodoc/miscellaneous/typealiases.html +40 -2
  39. package/compodoc/miscellaneous/variables.html +100 -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 +18 -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 +8546 -8346
  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/withFooterComponents.html +1 -0
  77. package/docs/functions/withHeaderComponents.html +1 -0
  78. package/docs/functions/withNavigationConfig.html +1 -0
  79. package/docs/functions/withNavigationInserts.html +1 -0
  80. package/docs/functions/withReleaseInfoModules.html +1 -0
  81. package/docs/functions/withSettingsMenuItems.html +1 -0
  82. package/docs/index.html +74 -2
  83. package/docs/interfaces/NavigationDividerItem.html +2 -2
  84. package/docs/interfaces/NavigationInsertItem.html +2 -2
  85. package/docs/interfaces/NavigationItem.html +2 -2
  86. package/docs/interfaces/NavigationStatus.html +2 -2
  87. package/docs/interfaces/ReleaseInfoModule.html +4 -0
  88. package/docs/interfaces/SettingsMenuItem.html +4 -0
  89. package/docs/modules.html +29 -17
  90. package/docs/types/ExternalApps.html +1 -0
  91. package/docs/types/ExtractUsernameFromProfileFn.html +1 -1
  92. package/docs/types/Navigation.html +1 -1
  93. package/docs/types/NavigationWithInserts.html +1 -1
  94. package/docs/types/SettingsMenuItemComponent.html +1 -0
  95. package/docs/variables/EXTRACT_USERNAME_FROM_PROFILE.html +1 -1
  96. package/docs/variables/RXAP_EXTERNAL_APP_FILTER.html +1 -0
  97. package/docs/variables/RXAP_FOOTER_COMPONENT.html +1 -1
  98. package/docs/variables/RXAP_HEADER_COMPONENT.html +1 -1
  99. package/docs/variables/RXAP_LAYOUT_APPS_GRID.html +1 -1
  100. package/docs/variables/RXAP_LOGO_CONFIG.html +1 -1
  101. package/docs/variables/RXAP_NAVIGATION_CONFIG.html +1 -1
  102. package/docs/variables/RXAP_NAVIGATION_CONFIG_INSERTS.html +1 -1
  103. package/docs/variables/RXAP_RELEASE_INFO_MODULE.html +1 -0
  104. package/docs/variables/RXAP_SETTINGS_MENU_ITEM.html +1 -0
  105. package/docs/variables/RXAP_SETTINGS_MENU_ITEM_COMPONENT.html +1 -0
  106. package/esm2022/index.mjs +35 -40
  107. package/esm2022/lib/base-layout/base-layout.component.mjs +16 -0
  108. package/esm2022/lib/default-header/apps-button/apps-button.component.mjs +38 -0
  109. package/esm2022/lib/default-header/default-header.component.mjs +32 -0
  110. package/esm2022/lib/default-header/settings-button/settings-button.component.mjs +73 -0
  111. package/esm2022/lib/default-header/sidenav-toggle-button/sidenav-toggle-button.component.mjs +24 -0
  112. package/esm2022/lib/default-header/user-profile-icon/user-profile-icon.component.mjs +35 -0
  113. package/esm2022/lib/external-apps.service.mjs +97 -0
  114. package/esm2022/lib/footer/footer.component.mjs +13 -13
  115. package/esm2022/lib/footer/footer.directive.mjs +30 -0
  116. package/esm2022/lib/footer.service.mjs +58 -0
  117. package/esm2022/lib/header/header.component.mjs +17 -65
  118. package/esm2022/lib/header/header.directive.mjs +30 -0
  119. package/esm2022/lib/header.service.mjs +60 -0
  120. package/esm2022/lib/layout/layout.component.mjs +33 -47
  121. package/esm2022/lib/layout.service.mjs +93 -0
  122. package/esm2022/lib/logo.service.mjs +23 -0
  123. package/esm2022/lib/minimal-layout/minimal-layout.component.mjs +14 -0
  124. package/esm2022/lib/navigation/navigation-item/navigation-item.component.mjs +30 -64
  125. package/esm2022/lib/navigation/navigation.component.mjs +22 -48
  126. package/esm2022/lib/navigation-progress-bar/navigation-progress-bar.component.mjs +23 -0
  127. package/esm2022/lib/navigation.service.mjs +141 -0
  128. package/esm2022/lib/provide.mjs +73 -0
  129. package/esm2022/lib/release-info/release-info.component.mjs +28 -0
  130. package/esm2022/lib/sidenav/sidenav.component.mjs +50 -33
  131. package/esm2022/lib/tokens.mjs +9 -1
  132. package/esm2022/lib/types.mjs +1 -1
  133. package/fesm2022/rxap-layout.mjs +845 -833
  134. package/fesm2022/rxap-layout.mjs.map +1 -1
  135. package/index.d.ts +18 -19
  136. package/lib/base-layout/base-layout.component.d.ts +5 -0
  137. package/lib/default-header/apps-button/apps-button.component.d.ts +15 -0
  138. package/lib/default-header/default-header.component.d.ts +11 -0
  139. package/lib/{header → default-header}/settings-button/settings-button.component.d.ts +6 -14
  140. package/lib/{header → default-header}/sidenav-toggle-button/sidenav-toggle-button.component.d.ts +3 -5
  141. package/lib/default-header/user-profile-icon/user-profile-icon.component.d.ts +10 -0
  142. package/lib/external-apps.service.d.ts +25 -0
  143. package/lib/footer/footer.component.d.ts +3 -3
  144. package/lib/{footer.directive.d.ts → footer/footer.directive.d.ts} +2 -4
  145. package/lib/footer.service.d.ts +32 -0
  146. package/lib/header/header.component.d.ts +6 -12
  147. package/lib/header/header.directive.d.ts +12 -0
  148. package/lib/header.service.d.ts +34 -0
  149. package/lib/layout/layout.component.d.ts +4 -17
  150. package/lib/layout.service.d.ts +26 -0
  151. package/lib/logo.service.d.ts +10 -0
  152. package/lib/minimal-layout/minimal-layout.component.d.ts +5 -0
  153. package/lib/navigation/navigation-item/navigation-item.component.d.ts +10 -18
  154. package/lib/navigation/navigation.component.d.ts +10 -15
  155. package/lib/{header/navigation-progress-bar → navigation-progress-bar}/navigation-progress-bar.component.d.ts +1 -3
  156. package/lib/{navigation/navigation.service.d.ts → navigation.service.d.ts} +4 -5
  157. package/lib/provide.d.ts +12 -0
  158. package/lib/release-info/release-info.component.d.ts +9 -0
  159. package/lib/sidenav/sidenav.component.d.ts +18 -6
  160. package/lib/tokens.d.ts +11 -3
  161. package/lib/types.d.ts +15 -4
  162. package/package.json +32 -66
  163. package/theme.css +1 -1
  164. package/docs/classes/AppUrlService.html +0 -13
  165. package/docs/classes/AuthenticationServiceMock.html +0 -3
  166. package/docs/classes/LanguageSelectorComponent.html +0 -3
  167. package/docs/classes/LayoutComponentService.html +0 -15
  168. package/docs/classes/ReplaceRouterPathsPipe.html +0 -4
  169. package/docs/classes/ReplaceRouterPathsService.html +0 -3
  170. package/docs/classes/ResetButtonComponent.html +0 -3
  171. package/docs/classes/SidenavComponentService.html +0 -5
  172. package/docs/classes/SignOutComponent.html +0 -4
  173. package/docs/classes/ToggleWindowSidenavButtonComponent.html +0 -5
  174. package/docs/classes/VersionComponent.html +0 -7
  175. package/docs/classes/WindowContainerSidenavComponent.html +0 -10
  176. package/docs/interfaces/ExternalApps.html +0 -8
  177. package/docs/interfaces/LogoConfig.html +0 -4
  178. package/esm2022/lib/app-url.service.mjs +0 -78
  179. package/esm2022/lib/authentication.service.mock.mjs +0 -13
  180. package/esm2022/lib/footer.directive.mjs +0 -40
  181. package/esm2022/lib/header/apps-button/apps-button.component.mjs +0 -46
  182. package/esm2022/lib/header/language-selector/language-selector.component.mjs +0 -35
  183. package/esm2022/lib/header/navigation-progress-bar/navigation-progress-bar.component.mjs +0 -30
  184. package/esm2022/lib/header/reset-button/reset-button.component.mjs +0 -23
  185. package/esm2022/lib/header/settings-button/settings-button.component.mjs +0 -87
  186. package/esm2022/lib/header/sidenav-toggle-button/sidenav-toggle-button.component.mjs +0 -26
  187. package/esm2022/lib/header/sign-out/sign-out.component.mjs +0 -23
  188. package/esm2022/lib/header/user-profile-icon/user-profile-icon.component.mjs +0 -45
  189. package/esm2022/lib/layout/layout.component.service.mjs +0 -77
  190. package/esm2022/lib/navigation/navigation.service.mjs +0 -145
  191. package/esm2022/lib/navigation/replace-router-paths.pipe.mjs +0 -22
  192. package/esm2022/lib/navigation/replace-router-paths.service.mjs +0 -15
  193. package/esm2022/lib/sidenav/sidenav.component.service.mjs +0 -22
  194. package/esm2022/lib/sidenav/version/version.component.mjs +0 -28
  195. package/esm2022/lib/toggle-window-sidenav-button/toggle-window-sidenav-button.component.mjs +0 -30
  196. package/esm2022/lib/window-container-sidenav/window-container-sidenav.component.mjs +0 -54
  197. package/lib/app-url.service.d.ts +0 -29
  198. package/lib/authentication.service.mock.d.ts +0 -6
  199. package/lib/header/apps-button/apps-button.component.d.ts +0 -16
  200. package/lib/header/language-selector/language-selector.component.d.ts +0 -8
  201. package/lib/header/reset-button/reset-button.component.d.ts +0 -8
  202. package/lib/header/sign-out/sign-out.component.d.ts +0 -9
  203. package/lib/header/user-profile-icon/user-profile-icon.component.d.ts +0 -15
  204. package/lib/layout/layout.component.service.d.ts +0 -25
  205. package/lib/navigation/replace-router-paths.pipe.d.ts +0 -11
  206. package/lib/navigation/replace-router-paths.service.d.ts +0 -7
  207. package/lib/sidenav/sidenav.component.service.d.ts +0 -11
  208. package/lib/sidenav/version/version.component.d.ts +0 -14
  209. package/lib/toggle-window-sidenav-button/toggle-window-sidenav-button.component.d.ts +0 -9
  210. 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,212 @@ 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_RELEASE_INFO_MODULE = new InjectionToken('rxap/layout/release-info-module');
83
+ const RXAP_SETTINGS_MENU_ITEM_COMPONENT = new InjectionToken('rxap/layout/settings-menu-item-component');
84
+ const RXAP_SETTINGS_MENU_ITEM = new InjectionToken('rxap/layout/settings-menu-item');
85
+
86
+ class FooterService {
87
+ constructor() {
88
+ this.components = coerceArray(inject(RXAP_FOOTER_COMPONENT, { optional: true }));
89
+ /**
90
+ * Represents an array of `Portal` objects with unknown type.
91
+ */
92
+ this.portals = signal(this.components.map(component => new ComponentPortal(component)));
93
+ /**
94
+ * Computes the count of portals.
95
+ *
96
+ * @returns {number} The count of portals.
97
+ */
98
+ this.portalCount = computed(() => this.portals().length);
191
99
  }
192
- toggleNavigationCollapse() {
193
- this.collapsed$.next(!this.collapsed$.value);
100
+ /**
101
+ * Adds a portal to the list of portals.
102
+ *
103
+ * @param {Portal<unknown>} portal - The portal to be added.
104
+ *
105
+ * @return {void}
106
+ */
107
+ pushPortal(portal) {
108
+ if (!this.portals().includes(portal)) {
109
+ this.portals.update(portals => [...portals, portal]);
110
+ }
111
+ else {
112
+ if (isDevMode()) {
113
+ console.warn('Can not add the same portal multiple times');
114
+ }
115
+ }
116
+ }
117
+ /**
118
+ * Removes a portal from the list of portals.
119
+ *
120
+ * @param {Portal<unknown>} portal - The portal to be removed.
121
+ * @return {void}
122
+ */
123
+ removePortal(portal) {
124
+ const index = this.portals().indexOf(portal);
125
+ if (index !== -1) {
126
+ this.portals.update(portals => {
127
+ portals.splice(index, 1);
128
+ return portals.slice();
129
+ });
130
+ }
194
131
  }
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' }); }
132
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: FooterService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
133
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: FooterService }); }
197
134
  }
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 }] });
135
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: FooterService, decorators: [{
136
+ type: Injectable
137
+ }] });
202
138
 
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();
139
+ class HeaderService {
140
+ constructor() {
141
+ this.components = coerceArray(inject(RXAP_HEADER_COMPONENT, { optional: true }));
142
+ /**
143
+ * Represents an array of `Portal` objects with unknown type.
144
+ *
145
+ * @typedef {Array<Portal<unknown>>} SignalPortals
146
+ */
147
+ this.portals = signal(this.components.map(component => new ComponentPortal(component)));
148
+ /**
149
+ * Computes the count of portals.
150
+ *
151
+ * @returns {number} The count of portals.
152
+ */
153
+ this.portalCount = computed(() => this.portals().length);
223
154
  }
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;
155
+ /**
156
+ * Adds a portal to the list of portals.
157
+ *
158
+ * @param {Portal<unknown>} portal - The portal to be added.
159
+ *
160
+ * @return {void}
161
+ */
162
+ pushPortal(portal) {
163
+ if (!this.portals().includes(portal)) {
164
+ this.portals.update(portals => [...portals, portal]);
229
165
  }
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] = '/';
166
+ else {
167
+ if (isDevMode()) {
168
+ console.warn('Can not add the same portal multiple times');
238
169
  }
239
- for (let i = 0; i < this.item.routerLink.length; i++) {
240
- if (urlParts[i] !== this.item.routerLink[i]) {
241
- isActive = false;
242
- break;
170
+ }
171
+ }
172
+ /**
173
+ * Removes a portal from the list of portals.
174
+ *
175
+ * @param {Portal<unknown>} portal - The portal to be removed.
176
+ * @return {void}
177
+ */
178
+ removePortal(portal) {
179
+ const index = this.portals().indexOf(portal);
180
+ if (index !== -1) {
181
+ this.portals.update(portals => {
182
+ portals.splice(index, 1);
183
+ return portals.slice();
184
+ });
185
+ }
186
+ }
187
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: HeaderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
188
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: HeaderService }); }
189
+ }
190
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: HeaderService, decorators: [{
191
+ type: Injectable
192
+ }] });
193
+
194
+ class LayoutService {
195
+ constructor() {
196
+ this.currentThemeDensity = toSignal(ObserveCurrentThemeDensity());
197
+ this.footerService = inject(FooterService);
198
+ this.headerService = inject(HeaderService);
199
+ this.config = inject(ConfigService);
200
+ this.mediaMatcher = inject(MediaMatcher);
201
+ const mobileQuery = this.mediaMatcher.matchMedia('(max-width: 959px)');
202
+ this.isMobile = toSignal(new Observable(subscriber => {
203
+ mobileQuery.addEventListener('change', (event) => {
204
+ subscriber.next(event.matches);
205
+ });
206
+ }), { initialValue: mobileQuery.matches });
207
+ const initialCollapsable = this.config.get('navigation.collapsable', true);
208
+ const collapsable = initialCollapsable && !this.isMobile();
209
+ const pinned = this.config.get('navigation.pinned', false);
210
+ const mode = this.config.get('navigation.mode', pinned || !collapsable ? 'side' : 'over');
211
+ const opened = this.config.get('navigation.opened', (!collapsable || pinned) && !this.isMobile());
212
+ const fixedInViewport = this.config.get('navigation.fixedInViewport', true);
213
+ if (isDevMode()) {
214
+ console.log({
215
+ initialCollapsable,
216
+ collapsable,
217
+ pinned,
218
+ mode,
219
+ opened,
220
+ fixedInViewport,
221
+ });
222
+ }
223
+ this.opened = signal(opened);
224
+ this.mode = signal(mode);
225
+ this.pinned = signal(pinned);
226
+ this.collapsable = signal(collapsable);
227
+ this.fixedInViewport = signal(fixedInViewport);
228
+ this.collapsed = computed(() => this.collapsable() && !this.opened() && !this.pinned());
229
+ this.fixedBottomGap = computed(() => {
230
+ const footerPortalCount = this.footerService.portalCount();
231
+ const currentThemeDensity = this.currentThemeDensity() ?? 0;
232
+ return footerPortalCount * (currentThemeDensity * 4 + 64);
233
+ });
234
+ this.fixedTopGap = computed(() => {
235
+ const headerPortalCount = this.headerService.portalCount();
236
+ const currentThemeDensity = this.currentThemeDensity() ?? 0;
237
+ return headerPortalCount * (currentThemeDensity * 4 + 64);
238
+ });
239
+ if (initialCollapsable) {
240
+ effect(() => {
241
+ const isMobile = this.isMobile();
242
+ this.collapsable.set(!isMobile);
243
+ if (!isMobile && !this.pinned()) {
244
+ this.opened.set(false);
243
245
  }
244
- }
245
- this.isActive = isActive;
246
- if (isActive) {
247
- this.renderer.addClass(this.elementRef.nativeElement, 'active');
246
+ }, { allowSignalWrites: true });
247
+ }
248
+ effect(() => {
249
+ if (this.pinned()) {
250
+ this.mode.set('side');
251
+ this.opened.set(true);
248
252
  }
249
253
  else {
250
- this.renderer.removeClass(this.elementRef.nativeElement, 'active');
254
+ this.mode.set('over');
255
+ this.opened.set(false);
251
256
  }
252
- }))
253
- .subscribe());
257
+ }, { allowSignalWrites: true });
254
258
  }
255
- ngOnDestroy() {
256
- this._subscription?.unsubscribe();
259
+ toggleOpened() {
260
+ this.opened.update(opened => !opened);
257
261
  }
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'];
262
+ togglePinned() {
263
+ this.pinned.update(pinned => !pinned);
262
264
  }
263
- isNavigationItem(item) {
264
- return !this.isNavigationDividerItem(item);
265
+ openSidenav() {
266
+ this.opened.set(true);
265
267
  }
266
- asNavigationItem(item) {
267
- if (!this.isNavigationItem(item)) {
268
- throw new Error('The item is not a NavigationItem');
269
- }
270
- return item;
268
+ closeSidenav() {
269
+ this.opened.set(false);
271
270
  }
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 }); }
271
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: LayoutService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
272
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: LayoutService }); }
290
273
  }
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
- }] } });
274
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: LayoutService, decorators: [{
275
+ type: Injectable
276
+ }], ctorParameters: () => [] });
350
277
 
351
278
  function IsNavigationDividerItem(item) {
352
279
  return !!item && !!item['divider'];
@@ -358,18 +285,11 @@ function IsNavigationItem(item) {
358
285
  return (!!item && !!item['routerLink'] && !!item['label']);
359
286
  }
360
287
 
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
288
  class NavigationService {
369
- constructor(navigation, injector, inserts = null) {
370
- this.injector = injector;
289
+ constructor(navigation, inserts = null) {
371
290
  this.inserts = new Map();
372
291
  this.navigation$ = new ReplaySubject(1);
292
+ this.injector = inject(INJECTOR);
373
293
  if (typeof navigation === 'function') {
374
294
  this.navigation = navigation();
375
295
  }
@@ -420,7 +340,8 @@ class NavigationService {
420
340
  if (IsNavigationDividerItem(navigationItem) || !navigationItem.status) {
421
341
  return of(navigationItem);
422
342
  }
423
- const isVisibleArray$ = navigationItem.status
343
+ const isVisibleArray$ = navigationItem
344
+ .status
424
345
  .map((statusToken) => this.injector.get(statusToken))
425
346
  .map((status) => {
426
347
  const isVisible = status.isVisible(navigationItem);
@@ -432,8 +353,7 @@ class NavigationService {
432
353
  }
433
354
  })
434
355
  .map(isVisible$ => isVisible$.pipe(catchError(e => {
435
- console.error('isVisible method failed: ' +
436
- e.message);
356
+ console.error(`isVisible method failed: ${e.message}`);
437
357
  return of(false);
438
358
  })));
439
359
  // TODO : dont wait for all status services to complete, but cancel waiting if one returns false
@@ -485,18 +405,14 @@ class NavigationService {
485
405
  }
486
406
  return navigation;
487
407
  }
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' }); }
408
+ 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 }); }
409
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: NavigationService }); }
490
410
  }
491
411
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: NavigationService, decorators: [{
492
- type: Injectable,
493
- args: [{ providedIn: 'root' }]
412
+ type: Injectable
494
413
  }], ctorParameters: () => [{ type: undefined, decorators: [{
495
414
  type: Inject,
496
415
  args: [RXAP_NAVIGATION_CONFIG]
497
- }] }, { type: undefined, decorators: [{
498
- type: Inject,
499
- args: [INJECTOR]
500
416
  }] }, { type: undefined, decorators: [{
501
417
  type: Optional
502
418
  }, {
@@ -504,28 +420,59 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImpor
504
420
  args: [RXAP_NAVIGATION_CONFIG_INSERTS]
505
421
  }] }] });
506
422
 
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);
423
+ class NavigationItemComponent {
424
+ constructor() {
425
+ this.level = input(0);
426
+ this.children = null;
427
+ this.item = input.required();
428
+ this.active = signal(false);
429
+ this.itemClasses = computed(() => {
430
+ let classes = `level-${this.level() * 4}`;
431
+ if (this.collapsed()) {
432
+ classes += ' invisible';
433
+ }
434
+ return classes;
435
+ });
436
+ this.layoutService = inject(LayoutService);
437
+ this.collapsed = computed(() => this.layoutService.collapsed());
438
+ this._subscription = new Subscription();
439
+ this.router = inject(Router);
440
+ this.elementRef = inject(ElementRef);
441
+ this.renderer = inject(Renderer2);
517
442
  }
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();
443
+ ngOnChanges(changes) {
444
+ if (changes['item']) {
445
+ const item = changes['item'].currentValue;
446
+ this.children =
447
+ item.children && item.children.length ? item.children : null;
524
448
  }
525
- this.items ??= [];
449
+ }
450
+ ngAfterViewInit() {
451
+ this._subscription.add(this.router.events
452
+ .pipe(filter((event) => event instanceof NavigationEnd), debounceTime(100), startWith(true), tap(() => {
453
+ let isActive = true;
454
+ const urlParts = this.router.url.split('/');
455
+ if (urlParts[0] === '') {
456
+ urlParts[0] = '/';
457
+ }
458
+ for (let i = 0; i < this.item().routerLink.length; i++) {
459
+ if (urlParts[i] !== this.item().routerLink[i]) {
460
+ isActive = false;
461
+ break;
462
+ }
463
+ }
464
+ this.active.set(isActive);
465
+ if (isActive) {
466
+ this.renderer.addClass(this.elementRef.nativeElement, 'active');
467
+ }
468
+ else {
469
+ this.renderer.removeClass(this.elementRef.nativeElement, 'active');
470
+ }
471
+ }))
472
+ .subscribe());
526
473
  }
527
474
  ngOnDestroy() {
528
- this.subscription?.unsubscribe();
475
+ this._subscription?.unsubscribe();
529
476
  }
530
477
  // region type save item property
531
478
  // required to check the type of the item property in the ngFor loop
@@ -541,350 +488,431 @@ class NavigationComponent {
541
488
  }
542
489
  return item;
543
490
  }
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 }); }
491
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: NavigationItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
492
+ 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: [
493
+ trigger('sub-nav', [
494
+ transition(':enter', [
495
+ style({
496
+ display: 'block',
497
+ height: '0',
498
+ overflow: 'hidden',
499
+ }),
500
+ animate(150, style({ height: '*' })),
501
+ ]),
502
+ transition(':leave', [
503
+ style({ overflow: 'hidden' }),
504
+ animate(300, style({ height: '0' })),
505
+ style({ display: 'none' }),
506
+ ]),
507
+ ]),
508
+ ], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
546
509
  }
547
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: NavigationComponent, decorators: [{
510
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: NavigationItemComponent, decorators: [{
548
511
  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
- }] } });
512
+ args: [{ selector: 'li[rxap-navigation-item]', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, animations: [
513
+ trigger('sub-nav', [
514
+ transition(':enter', [
515
+ style({
516
+ display: 'block',
517
+ height: '0',
518
+ overflow: 'hidden',
519
+ }),
520
+ animate(150, style({ height: '*' })),
521
+ ]),
522
+ transition(':leave', [
523
+ style({ overflow: 'hidden' }),
524
+ animate(300, style({ height: '0' })),
525
+ style({ display: 'none' }),
526
+ ]),
527
+ ]),
528
+ ], standalone: true, imports: [
529
+ RouterLinkActive,
530
+ RouterLink,
531
+ NgIf,
532
+ MatRippleModule,
533
+ MatIconModule,
534
+ IconDirective,
535
+ MatDividerModule,
536
+ forwardRef(() => NavigationComponent),
537
+ NgClass,
538
+ ], 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" }]
539
+ }] });
577
540
 
578
- class SidenavComponent {
579
- constructor(sidenav) {
580
- this.sidenav = sidenav;
541
+ class NavigationComponent {
542
+ constructor() {
543
+ this.items = input();
544
+ this.level = input(0);
545
+ this.navigationService = inject(NavigationService);
546
+ this.layoutService = inject(LayoutService);
547
+ this.collapsed = computed(() => this.layoutService.collapsed());
548
+ this.navigationItems = computed(() => this.items() ?? []);
549
+ this.root = input(false);
550
+ this.injector = inject(INJECTOR);
551
+ }
552
+ ngOnInit() {
553
+ if (this.root()) {
554
+ runInInjectionContext(this.injector, () => {
555
+ this.navigationItems = toSignal(this.navigationService.config$, { initialValue: [] });
556
+ });
557
+ }
558
+ }
559
+ // region type save item property
560
+ // required to check the type of the item property in the ngFor loop
561
+ isNavigationDividerItem(item) {
562
+ return item['divider'];
563
+ }
564
+ isNavigationItem(item) {
565
+ return !this.isNavigationDividerItem(item);
566
+ }
567
+ asNavigationItem(item) {
568
+ if (!this.isNavigationItem(item)) {
569
+ throw new Error('The item is not a NavigationItem');
570
+ }
571
+ return item;
581
572
  }
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 }); }
573
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: NavigationComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
574
+ 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
575
  }
585
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: SidenavComponent, decorators: [{
576
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: NavigationComponent, decorators: [{
586
577
  type: Component,
587
- args: [{ selector: 'rxap-sidenav', changeDetection: ChangeDetectionStrategy.OnPush, host: {
588
- class: 'rxap-layout-sidenav',
589
- }, standalone: true, imports: [
590
- NgClass,
578
+ args: [{ selector: 'ul[rxap-navigation]', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, standalone: true, host: {
579
+ class: 'list-none dark:text-neutral-400 text-neutral-700',
580
+ }, imports: [
581
+ NgFor,
591
582
  NgIf,
592
- NgTemplateOutlet,
593
583
  MatDividerModule,
594
- NavigationComponent,
595
- MatButtonModule,
596
- MatIconModule,
584
+ forwardRef(() => NavigationItemComponent),
597
585
  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
- }] } });
586
+ ], 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" }]
587
+ }] });
606
588
 
607
- class ReplaceRouterPathsService {
608
- transform(routerLink) {
609
- return of(routerLink);
589
+ class SidenavComponent {
590
+ constructor() {
591
+ this.layoutService = inject(LayoutService);
592
+ this.sidenav = viewChild(MatSidenav);
593
+ this.sidenavMode = computed(() => this.layoutService.mode());
594
+ this.fixedBottomGap = computed(() => this.layoutService.fixedBottomGap());
595
+ this.fixedTopGap = computed(() => this.layoutService.fixedTopGap());
596
+ this.fixedInViewport = computed(() => this.layoutService.fixedInViewport());
597
+ this.pinned = computed(() => this.layoutService.pinned());
598
+ this.collapsed = computed(() => this.layoutService.collapsed());
599
+ this.collapsable = computed(() => this.layoutService.collapsable());
600
+ this.opened = computed(() => this.layoutService.opened());
601
+ this.sidenavFooterDirective = contentChild(SidenavFooterDirective);
602
+ this.sidenavHeaderDirective = contentChild(SidenavHeaderDirective);
603
+ }
604
+ togglePinned() {
605
+ this.layoutService.togglePinned();
606
+ }
607
+ async openSidenav() {
608
+ await this.sidenav()?.open();
609
+ this.layoutService.openSidenav();
610
610
  }
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' }); }
611
+ async closeSidenav() {
612
+ await this.sidenav()?.close();
613
+ this.layoutService.closeSidenav();
614
+ }
615
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: SidenavComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
616
+ 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
617
  }
614
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: ReplaceRouterPathsService, decorators: [{
615
- type: Injectable,
616
- args: [{ providedIn: 'root' }]
618
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: SidenavComponent, decorators: [{
619
+ type: Component,
620
+ args: [{ selector: 'rxap-sidenav', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
621
+ MatIcon,
622
+ MatIconButton,
623
+ MatSidenav,
624
+ MatSidenavContainer,
625
+ MatSidenavContent,
626
+ NavigationComponent,
627
+ NgIf,
628
+ RouterOutlet,
629
+ NgClass,
630
+ NgStyle,
631
+ MatDivider,
632
+ NgTemplateOutlet,
633
+ MatButton,
634
+ ], 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
635
  }] });
618
636
 
619
- class ReplaceRouterPathsPipe {
620
- constructor(rrp) {
621
- this.rrp = rrp;
637
+ class ReleaseInfoComponent {
638
+ constructor() {
639
+ this.modules = coerceArray(inject(RXAP_RELEASE_INFO_MODULE, { optional: true }));
640
+ this.release = DetermineReleaseName(inject(RXAP_ENVIRONMENT));
641
+ this.dialog = inject(MatDialog);
622
642
  }
623
- transform(routerLink) {
624
- return this.rrp.transform(routerLink);
643
+ openEnvironmentInfo() {
644
+ this.dialog.open(EnvironmentComponent, {
645
+ closeOnNavigation: true,
646
+ });
625
647
  }
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" }); }
648
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: ReleaseInfoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
649
+ 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
650
  }
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 }] });
651
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: ReleaseInfoComponent, decorators: [{
652
+ type: Component,
653
+ args: [{ selector: 'rxap-release-info', standalone: true, imports: [
654
+ MatButton,
655
+ ], 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" }]
656
+ }] });
636
657
 
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());
658
+ class NavigationProgressBarComponent {
659
+ constructor() {
660
+ this.router = inject(Router);
661
+ this.navigating = toSignal(this.router.events.pipe(filter(event => event instanceof NavigationStart ||
662
+ event instanceof NavigationEnd ||
663
+ event instanceof NavigationCancel), map(event => event instanceof NavigationStart)), { initialValue: true });
686
664
  }
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' }); }
665
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: NavigationProgressBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
666
+ 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
667
  }
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 }] });
668
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: NavigationProgressBarComponent, decorators: [{
669
+ type: Component,
670
+ args: [{ selector: 'rxap-navigation-progress-bar', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
671
+ MatProgressBar,
672
+ ], template: "@if (navigating()) {\n<mat-progress-bar color=\"accent\" mode=\"indeterminate\"></mat-progress-bar>\n}\n" }]
673
+ }] });
702
674
 
703
675
  class FooterComponent {
704
- constructor(footerService) {
705
- this.footerService = footerService;
676
+ constructor() {
677
+ this.footerService = inject(FooterService);
678
+ this.portals = computed(() => this.footerService.portals());
679
+ this.hasPortals = computed(() => this.portals().length > 0);
706
680
  }
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 }); }
681
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: FooterComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
682
+ 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
683
  }
710
684
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: FooterComponent, decorators: [{
711
685
  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 }] });
686
+ 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" }]
687
+ }] });
714
688
 
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', []);
689
+ class HeaderComponent {
690
+ constructor() {
691
+ this.color = input();
692
+ this.headerService = inject(HeaderService);
693
+ this.portals = computed(() => this.headerService.portals());
694
+ this.hasPortals = computed(() => this.portals().length > 0);
722
695
  }
723
- getApp(appId) {
724
- return this._apps.find(app => app.id === appId) ?? null;
696
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: HeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
697
+ 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 }); }
698
+ }
699
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: HeaderComponent, decorators: [{
700
+ type: Component,
701
+ args: [{ selector: 'rxap-header', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
702
+ MatToolbar,
703
+ MatToolbarRow,
704
+ CdkPortalOutlet,
705
+ ], 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" }]
706
+ }] });
707
+
708
+ class BaseLayoutComponent {
709
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: BaseLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
710
+ 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 }); }
711
+ }
712
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: BaseLayoutComponent, decorators: [{
713
+ type: Component,
714
+ args: [{ selector: 'rxap-base-layout', standalone: true, imports: [
715
+ HeaderComponent,
716
+ FooterComponent,
717
+ ], 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" }]
718
+ }] });
719
+
720
+ class MinimalLayoutComponent {
721
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: MinimalLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
722
+ 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 }); }
723
+ }
724
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: MinimalLayoutComponent, decorators: [{
725
+ type: Component,
726
+ 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" }]
727
+ }] });
728
+
729
+ class LogoService {
730
+ constructor() {
731
+ this.config = inject(ConfigService);
732
+ this.logo = signal(inject(RXAP_LOGO_CONFIG, { optional: true }) ??
733
+ this.config.get('logo', {
734
+ src: 'logo.png',
735
+ width: 192,
736
+ }));
737
+ this.src = computed(() => this.logo().src);
738
+ this.width = computed(() => this.logo().width);
739
+ this.height = computed(() => this.logo().height);
740
+ }
741
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: LogoService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
742
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: LogoService }); }
743
+ }
744
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: LogoService, decorators: [{
745
+ type: Injectable
746
+ }] });
747
+
748
+ class LayoutComponent {
749
+ constructor() {
750
+ this.userSettingsThemeService = inject(UserSettingsThemeService);
751
+ this.themeService = inject(ThemeService);
752
+ this.logoService = inject(LogoService);
753
+ this.logoSrc = computed(() => this.logoService.src());
754
+ this.logoWidth = computed(() => this.logoService.width());
755
+ this.logoHeight = computed(() => this.logoService.height());
725
756
  }
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;
757
+ ngOnDestroy() {
758
+ this.userSettingsThemeService.stopSync();
732
759
  }
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}"`);
760
+ ngOnInit() {
761
+ this.userSettingsThemeService.startSync().then(() => {
762
+ this.userSettingsThemeService.get().then(theme => {
763
+ if (theme.preset && theme.preset !== 'default') {
764
+ this.themeService.setTheme(theme.preset, true);
765
+ }
766
+ if (theme.density && IsThemeDensity(theme.density) && theme.density !== ThemeDensity.Normal) {
767
+ this.themeService.setDensity(theme.density, true);
768
+ }
769
+ if (theme.typography && theme.typography !== 'default') {
770
+ this.themeService.setTypography(theme.typography, true);
771
+ }
772
+ });
773
+ });
739
774
  }
740
- navigate(appId, path) {
741
- const url = this.getAppUrl(appId, path);
742
- if (url) {
743
- ClickOnLink(url);
744
- }
775
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: LayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
776
+ 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 }); }
777
+ }
778
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: LayoutComponent, decorators: [{
779
+ type: Component,
780
+ args: [{ selector: 'rxap-layout', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
781
+ HeaderComponent,
782
+ MatSidenavModule,
783
+ AsyncPipe,
784
+ MatIconModule,
785
+ MatButtonModule,
786
+ RouterLink,
787
+ NgIf,
788
+ FooterComponent,
789
+ MatMenuModule,
790
+ NgOptimizedImage,
791
+ NavigationComponent,
792
+ RouterOutlet,
793
+ NgStyle,
794
+ NgClass,
795
+ SidenavComponent,
796
+ ReleaseInfoComponent,
797
+ SidenavFooterDirective,
798
+ NavigationProgressBarComponent,
799
+ ], 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"] }]
800
+ }] });
801
+
802
+ class HeaderDirective {
803
+ constructor() {
804
+ this.headerService = inject(HeaderService);
805
+ this.template = inject(TemplateRef);
806
+ this.viewContainerRef = inject(ViewContainerRef);
745
807
  }
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;
808
+ ngOnInit() {
809
+ this._portal = new TemplatePortal(this.template, this.viewContainerRef);
810
+ this.headerService.pushPortal(this._portal);
761
811
  }
762
- getPathPrefix() {
763
- if (this.environment.production && this.localeId) {
764
- return this.localeId.replace(/-.+$/, '');
812
+ ngOnDestroy() {
813
+ if (this._portal) {
814
+ this.headerService.removePortal(this._portal);
765
815
  }
766
- return '';
767
816
  }
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' }); }
817
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: HeaderDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
818
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.0.1", type: HeaderDirective, isStandalone: true, selector: "[rxapHeader]", ngImport: i0 }); }
770
819
  }
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
- }] }] });
820
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: HeaderDirective, decorators: [{
821
+ type: Directive,
822
+ args: [{
823
+ selector: '[rxapHeader]',
824
+ standalone: true,
825
+ }]
826
+ }] });
781
827
 
782
- class AppsButtonComponent {
783
- constructor(grid, appUrlService, authenticationService) {
784
- this.appUrlService = appUrlService;
785
- this.authenticationService = authenticationService;
786
- this.isOpen = false;
787
- this.appList = signal([]);
828
+ class FooterDirective {
829
+ constructor() {
830
+ this.footerService = inject(FooterService);
831
+ this.template = inject(TemplateRef);
832
+ this.viewContainerRef = inject(ViewContainerRef);
788
833
  }
789
834
  ngOnInit() {
790
- this._subscription = this.authenticationService.isAuthenticated$.pipe(filter(Boolean), switchMap$1(() => this.appUrlService.getAppList()), tap((apps) => this.appList.set(apps))).subscribe();
835
+ this._portal = new TemplatePortal(this.template, this.viewContainerRef);
836
+ this.footerService.pushPortal(this._portal);
791
837
  }
792
838
  ngOnDestroy() {
793
- this._subscription?.unsubscribe();
839
+ if (this._portal) {
840
+ this.footerService.removePortal(this._portal);
841
+ }
794
842
  }
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 }); }
843
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: FooterDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
844
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.0.1", type: FooterDirective, isStandalone: true, selector: "[rxapFooter]", ngImport: i0 }); }
797
845
  }
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 }] });
846
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: FooterDirective, decorators: [{
847
+ type: Directive,
848
+ args: [{
849
+ selector: '[rxapFooter]',
850
+ standalone: true,
851
+ }]
852
+ }] });
813
853
 
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));
854
+ class UserProfileIconComponent {
855
+ constructor() {
856
+ this.extractUsernameFromProfile = inject(EXTRACT_USERNAME_FROM_PROFILE);
857
+ this.pubSubService = inject(PubSubService);
858
+ this.profile = input.required();
859
+ this.username = computed(() => {
860
+ const profile = this.profile();
861
+ if (profile) {
862
+ return this.extractUsernameFromProfile(profile);
863
+ }
864
+ return null;
865
+ });
866
+ }
867
+ logout() {
868
+ this.pubSubService.publish('authentication.logout');
820
869
  }
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 }); }
870
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: UserProfileIconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
871
+ 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
872
  }
824
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: NavigationProgressBarComponent, decorators: [{
873
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: UserProfileIconComponent, decorators: [{
825
874
  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
- }] }] });
875
+ args: [{ selector: 'rxap-user-profile-icon', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
876
+ MatMenuModule,
877
+ MatIconModule,
878
+ ], 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" }]
879
+ }] });
835
880
 
836
- class LanguageSelectorComponent {
837
- constructor(language) {
838
- this.language = language;
881
+ class SidenavToggleButtonComponent {
882
+ constructor() {
883
+ this.layoutComponentService = inject(LayoutService);
884
+ this.opened = computed(() => this.layoutComponentService.opened());
885
+ }
886
+ toggle() {
887
+ this.layoutComponentService.toggleOpened();
839
888
  }
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 }); }
889
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: SidenavToggleButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
890
+ 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
891
  }
843
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: LanguageSelectorComponent, decorators: [{
892
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: SidenavToggleButtonComponent, decorators: [{
844
893
  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 }] });
894
+ args: [{ selector: 'rxap-sidenav-toggle-button', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
895
+ MatIcon,
896
+ MatIconButton,
897
+ ], 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" }]
898
+ }] });
856
899
 
857
900
  class SettingsButtonComponent {
858
- constructor(theme, route, injector, changelogService) {
859
- this.theme = theme;
860
- this.route = route;
861
- this.injector = injector;
862
- this.changelogService = changelogService;
901
+ constructor() {
863
902
  this.isDevMode = isDevMode();
864
- this.items = signal([]);
903
+ this.theme = inject(ThemeService);
904
+ this.injector = inject(Injector);
905
+ this.customItemComponents = signal(coerceArray(inject(RXAP_SETTINGS_MENU_ITEM_COMPONENT, { optional: true }))
906
+ .map(item => new ComponentPortal(item, null, this.injector)));
907
+ this.customItems = signal(coerceArray(inject(RXAP_SETTINGS_MENU_ITEM, { optional: true })));
865
908
  this.savePreviewDensityValue = false;
866
909
  this.currentDensityValue = null;
867
910
  this.savePreviewTypographyValue = false;
868
911
  this.currentTypographyValue = null;
912
+ this.availableTypographies = this.theme.getAvailableTypographies();
869
913
  this.savePreviewThemeValue = false;
870
- this.currentThemeValue = null;
871
914
  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();
915
+ this.currentThemeValue = null;
888
916
  }
889
917
  previewDensity(density) {
890
918
  this.theme.applyDensity(density);
@@ -913,255 +941,239 @@ class SettingsButtonComponent {
913
941
  setTheme(theme) {
914
942
  this.theme.setTheme(theme);
915
943
  }
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"] }] }); }
944
+ clickItem(item) {
945
+ runInInjectionContext(this.injector, () => item.action());
946
+ }
947
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: SettingsButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
948
+ 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
949
  }
919
950
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: SettingsButtonComponent, decorators: [{
920
951
  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 }] });
952
+ args: [{ selector: 'rxap-settings-button', standalone: true, imports: [
953
+ MatIconButton,
954
+ MatIcon,
955
+ MatMenu,
956
+ MatMenuTrigger,
957
+ MatMenuItem,
958
+ CdkPortalOutlet,
959
+ IconDirective,
960
+ ], 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" }]
961
+ }] });
923
962
 
924
- class SidenavToggleButtonComponent {
925
- constructor(layoutComponentService) {
926
- this.layoutComponentService = layoutComponentService;
927
- this.opened = layoutComponentService.opened;
963
+ class ExternalAppsService {
964
+ constructor() {
965
+ this.appFilterList = coerceArray(inject(RXAP_EXTERNAL_APP_FILTER, { optional: true }));
966
+ this.config = inject(ConfigService);
967
+ this.localeId = inject(LOCALE_ID);
968
+ this.environment = inject(RXAP_ENVIRONMENT);
969
+ this.apps = this.config.get('navigation.apps', []);
970
+ /**
971
+ * The list of active apps that is processed by the getAppList method
972
+ */
973
+ this.activeAppList = signal([]);
974
+ }
975
+ hasApp(appId) {
976
+ return this.apps.some(app => app.id === appId);
928
977
  }
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);
978
+ getApp(appId) {
979
+ if (!this.hasApp(appId)) {
980
+ return null;
981
+ }
982
+ const app = this.apps.find(app => app.id === appId);
983
+ if (!app) {
984
+ throw new Error(`FATAL: App with id "${appId}" not found!`);
985
+ }
986
+ return structuredClone(app);
1035
987
  }
1036
- ngOnDestroy() {
1037
- this.userSettingsThemeService.stopSync();
988
+ getAppUrl(appId, path, infix = this.getPathPrefix()) {
989
+ const app = this.getApp(appId);
990
+ if (!app || !app.href) {
991
+ return null;
992
+ }
993
+ return JoinPath(app.href, infix, path);
1038
994
  }
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);
995
+ getAppRouterLink(appId, path) {
996
+ const app = this.getApp(appId);
997
+ if (!app || !app.routerLink) {
998
+ return null;
999
+ }
1000
+ return [...app.routerLink, path];
1001
+ }
1002
+ getAppUrlOrThrow(appId, path) {
1003
+ const url = this.getAppUrl(appId, path);
1004
+ if (url) {
1005
+ return url;
1006
+ }
1007
+ throw new Error(`Could not find url for app with id "${appId}"`);
1008
+ }
1009
+ getAppRouterLinkOrThrow(appId, path) {
1010
+ const routerLink = this.getAppRouterLink(appId, path);
1011
+ if (routerLink) {
1012
+ return routerLink;
1013
+ }
1014
+ throw new Error(`Could not find router link for app with id "${appId}"`);
1015
+ }
1016
+ navigate(appId, path) {
1017
+ const url = this.getAppUrl(appId, path);
1018
+ if (url) {
1019
+ ClickOnLink(url);
1020
+ }
1021
+ }
1022
+ async getAppList() {
1023
+ let appList = this
1024
+ .apps
1025
+ .filter(app => !app.hidden)
1026
+ .map(app => structuredClone(app));
1027
+ appList.forEach(app => {
1028
+ if (app.href) {
1029
+ app.href = JoinPath(app.href, this.getPathPrefix());
1050
1030
  }
1051
1031
  });
1032
+ for (const appFilter of this.appFilterList) {
1033
+ appList = await appFilter.call(structuredClone(appList));
1034
+ }
1035
+ appList = structuredClone(appList);
1036
+ this.activeAppList.set(appList);
1037
+ return appList;
1038
+ }
1039
+ getPathPrefix() {
1040
+ if (this.environment.production && this.localeId) {
1041
+ return this.localeId.replace(/-.+$/, '');
1042
+ }
1043
+ return '';
1052
1044
  }
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 }); }
1045
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: ExternalAppsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1046
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: ExternalAppsService }); }
1055
1047
  }
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
- }] } });
1048
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: ExternalAppsService, decorators: [{
1049
+ type: Injectable
1050
+ }] });
1082
1051
 
1083
- class SignOutComponent {
1084
- constructor(authenticationService) {
1085
- this.authenticationService = authenticationService;
1052
+ class AppsButtonComponent {
1053
+ constructor() {
1054
+ /**
1055
+ * The signal that indicates if the app list is open
1056
+ */
1057
+ this.isOpen = signal(false);
1058
+ this.externalAppsService = inject(ExternalAppsService);
1059
+ this.appList = computed(() => this.externalAppsService.activeAppList());
1060
+ this.hasApps = computed(() => this.appList().length > 0);
1086
1061
  }
1087
- async logout() {
1088
- await this.authenticationService.signOut();
1062
+ toggle() {
1063
+ this.isOpen.update(isOpen => !isOpen);
1089
1064
  }
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;
1065
+ ngOnInit() {
1066
+ this.externalAppsService.getAppList();
1101
1067
  }
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 }); }
1068
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: AppsButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1069
+ 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.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.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.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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1104
1070
  }
1105
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: ResetButtonComponent, decorators: [{
1071
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: AppsButtonComponent, decorators: [{
1106
1072
  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
- }] }] });
1073
+ args: [{ selector: 'rxap-apps-button', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [
1074
+ NgOptimizedImage,
1075
+ MatButton,
1076
+ RouterLink,
1077
+ MatAnchor,
1078
+ MatIconButton,
1079
+ MatIcon,
1080
+ ], 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.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.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.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" }]
1081
+ }] });
1112
1082
 
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 }); }
1083
+ class DefaultHeaderComponent {
1084
+ constructor() {
1085
+ this.layoutComponentService = inject(LayoutService);
1086
+ this.collapsable = computed(() => this.layoutComponentService.collapsable());
1087
+ this.opened = computed(() => this.layoutComponentService.opened());
1088
+ this.userProfileService = inject(UserProfileDataSource);
1089
+ this.profile = toSignal(this.userProfileService.connect('user-profile'), { initialValue: null });
1090
+ }
1091
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: DefaultHeaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1092
+ 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
1093
  }
1120
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: AuthenticationServiceMock, decorators: [{
1121
- type: Injectable
1094
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.1", ngImport: i0, type: DefaultHeaderComponent, decorators: [{
1095
+ type: Component,
1096
+ args: [{ selector: 'rxap-default-header', standalone: true, imports: [
1097
+ AppsButtonComponent,
1098
+ SettingsButtonComponent,
1099
+ SidenavToggleButtonComponent,
1100
+ UserProfileIconComponent,
1101
+ ], host: {
1102
+ 'class': 'grow',
1103
+ }, 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
1104
  }] });
1123
1105
 
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 }); }
1106
+ function provideLayout(...additionalProviders) {
1107
+ return [
1108
+ ExternalAppsService,
1109
+ LayoutService,
1110
+ LogoService,
1111
+ NavigationService,
1112
+ HeaderService,
1113
+ FooterService,
1114
+ ...additionalProviders,
1115
+ ];
1116
+ }
1117
+ function withNavigationConfig(config) {
1118
+ return [
1119
+ {
1120
+ provide: RXAP_NAVIGATION_CONFIG,
1121
+ useValue: config,
1122
+ },
1123
+ ];
1124
+ }
1125
+ function withNavigationInserts(inserts) {
1126
+ return [{
1127
+ provide: RXAP_NAVIGATION_CONFIG_INSERTS,
1128
+ useValue: inserts,
1129
+ }];
1130
+ }
1131
+ function withSettingsMenuItems(...items) {
1132
+ return [
1133
+ ...items.filter((item) => typeof item === 'function').map(component => ({
1134
+ provide: RXAP_SETTINGS_MENU_ITEM_COMPONENT,
1135
+ useValue: component,
1136
+ multi: true,
1137
+ })),
1138
+ ...items.filter((item) => typeof item !== 'function').map(item => ({
1139
+ provide: RXAP_SETTINGS_MENU_ITEM,
1140
+ useValue: item,
1141
+ multi: true,
1142
+ })),
1143
+ ];
1144
+ }
1145
+ function withReleaseInfoModules(...module) {
1146
+ return module.map(item => ({
1147
+ provide: RXAP_RELEASE_INFO_MODULE,
1148
+ useValue: item,
1149
+ multi: true,
1150
+ }));
1151
+ }
1152
+ function withHeaderComponents(components) {
1153
+ return components.map(component => ({
1154
+ provide: RXAP_HEADER_COMPONENT,
1155
+ useValue: component,
1156
+ }));
1157
+ }
1158
+ function withFooterComponents(components) {
1159
+ return components.map(component => ({
1160
+ provide: RXAP_FOOTER_COMPONENT,
1161
+ useValue: component,
1162
+ }));
1163
+ }
1164
+ function widthDefaultHeaderComponent() {
1165
+ return {
1166
+ provide: RXAP_HEADER_COMPONENT,
1167
+ useValue: DefaultHeaderComponent,
1168
+ };
1141
1169
  }
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
1170
 
1159
- // region window-container-sidenav
1171
+ // region sidenav
1160
1172
  // endregion
1161
1173
 
1162
1174
  /**
1163
1175
  * Generated bundle index. Do not edit.
1164
1176
  */
1165
1177
 
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 };
1178
+ 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_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, withFooterComponents, withHeaderComponents, withNavigationConfig, withNavigationInserts, withReleaseInfoModules, withSettingsMenuItems };
1167
1179
  //# sourceMappingURL=rxap-layout.mjs.map