@memberjunction/ng-explorer-core 5.50.0 → 6.1.0-edge.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +7 -0
- package/dist/app-routing.module.d.ts.map +1 -1
- package/dist/app-routing.module.js +5 -5
- package/dist/app-routing.module.js.map +1 -1
- package/dist/generated/lazy-feature-config.d.ts +11 -2
- package/dist/generated/lazy-feature-config.d.ts.map +1 -1
- package/dist/generated/lazy-feature-config.js +79 -23
- package/dist/generated/lazy-feature-config.js.map +1 -1
- package/dist/lib/resource-wrappers/dashboard-resource.component.d.ts.map +1 -1
- package/dist/lib/resource-wrappers/dashboard-resource.component.js +28 -0
- package/dist/lib/resource-wrappers/dashboard-resource.component.js.map +1 -1
- package/dist/lib/services/lazy-module-registry.d.ts +48 -8
- package/dist/lib/services/lazy-module-registry.d.ts.map +1 -1
- package/dist/lib/services/lazy-module-registry.js +103 -23
- package/dist/lib/services/lazy-module-registry.js.map +1 -1
- package/dist/lib/shell/components/header/app-nav.component.d.ts +2 -1
- package/dist/lib/shell/components/header/app-nav.component.d.ts.map +1 -1
- package/dist/lib/shell/components/header/app-nav.component.js +58 -42
- package/dist/lib/shell/components/header/app-nav.component.js.map +1 -1
- package/dist/lib/shell/components/record-open/record-bar.component.d.ts +29 -0
- package/dist/lib/shell/components/record-open/record-bar.component.d.ts.map +1 -0
- package/dist/lib/shell/components/record-open/record-bar.component.js +72 -0
- package/dist/lib/shell/components/record-open/record-bar.component.js.map +1 -0
- package/dist/lib/shell/components/record-open/record-origin-crumb.component.d.ts +26 -0
- package/dist/lib/shell/components/record-open/record-origin-crumb.component.d.ts.map +1 -0
- package/dist/lib/shell/components/record-open/record-origin-crumb.component.js +140 -0
- package/dist/lib/shell/components/record-open/record-origin-crumb.component.js.map +1 -0
- package/dist/lib/shell/components/record-open/record-switcher-sheet.component.d.ts +43 -0
- package/dist/lib/shell/components/record-open/record-switcher-sheet.component.d.ts.map +1 -0
- package/dist/lib/shell/components/record-open/record-switcher-sheet.component.js +102 -0
- package/dist/lib/shell/components/record-open/record-switcher-sheet.component.js.map +1 -0
- package/dist/lib/shell/components/record-open/record-switcher.service.d.ts +21 -0
- package/dist/lib/shell/components/record-open/record-switcher.service.d.ts.map +1 -0
- package/dist/lib/shell/components/record-open/record-switcher.service.js +30 -0
- package/dist/lib/shell/components/record-open/record-switcher.service.js.map +1 -0
- package/dist/lib/shell/components/record-open/records-hub-pill.component.d.ts +63 -0
- package/dist/lib/shell/components/record-open/records-hub-pill.component.d.ts.map +1 -0
- package/dist/lib/shell/components/record-open/records-hub-pill.component.js +143 -0
- package/dist/lib/shell/components/record-open/records-hub-pill.component.js.map +1 -0
- package/dist/lib/shell/components/tabs/tab-container.component.d.ts +228 -2
- package/dist/lib/shell/components/tabs/tab-container.component.d.ts.map +1 -1
- package/dist/lib/shell/components/tabs/tab-container.component.js +1073 -113
- package/dist/lib/shell/components/tabs/tab-container.component.js.map +1 -1
- package/dist/lib/shell/services/sharing-center-dialog-host.component.d.ts.map +1 -1
- package/dist/lib/shell/services/sharing-center-dialog-host.component.js +2 -0
- package/dist/lib/shell/services/sharing-center-dialog-host.component.js.map +1 -1
- package/dist/lib/shell/shell.component.d.ts +41 -4
- package/dist/lib/shell/shell.component.d.ts.map +1 -1
- package/dist/lib/shell/shell.component.js +400 -240
- package/dist/lib/shell/shell.component.js.map +1 -1
- package/dist/lib/shell/shell.module.d.ts +4 -1
- package/dist/lib/shell/shell.module.d.ts.map +1 -1
- package/dist/lib/shell/shell.module.js +14 -3
- package/dist/lib/shell/shell.module.js.map +1 -1
- package/package.json +62 -59
|
@@ -4,7 +4,7 @@ import { combineLatest, Subject } from 'rxjs';
|
|
|
4
4
|
import { filter, takeUntil } from 'rxjs/operators';
|
|
5
5
|
import { LogStatus, LogError, StartupManager, CompositeKey } from '@memberjunction/core';
|
|
6
6
|
import { MJEventType, MJGlobal, uuidv4, UUIDsEqual } from '@memberjunction/global';
|
|
7
|
-
import { EventCodes, SharedService, SYSTEM_APP_ID } from '@memberjunction/ng-shared';
|
|
7
|
+
import { EventCodes, SharedService, SYSTEM_APP_ID, SetRecordOpenStyle, IsRecordsRegionTab, IsRecordsTabConfiguration } from '@memberjunction/ng-shared';
|
|
8
8
|
import { MJNotificationService } from '@memberjunction/ng-notifications';
|
|
9
9
|
import { IsOmnibarAvailable, IsOmnibarEnabledForUser, OMNIBAR_PROMO_DISMISSED_KEY, OMNIBAR_USER_SETTING_KEY } from '../omnibar/omnibar-user-setting';
|
|
10
10
|
import { GetOmnibarShortcutLabel } from '../omnibar/omnibar-shortcut';
|
|
@@ -31,12 +31,13 @@ import * as i13 from "@angular/forms";
|
|
|
31
31
|
import * as i14 from "@memberjunction/ng-ui-components";
|
|
32
32
|
import * as i15 from "@memberjunction/ng-shared-generic";
|
|
33
33
|
import * as i16 from "@memberjunction/ng-search";
|
|
34
|
-
import * as i17 from "./components/
|
|
35
|
-
import * as i18 from "./components/header/app-
|
|
36
|
-
import * as i19 from "./components/
|
|
37
|
-
import * as i20 from "./components/
|
|
38
|
-
import * as i21 from "
|
|
39
|
-
import * as i22 from "../
|
|
34
|
+
import * as i17 from "./components/record-open/records-hub-pill.component";
|
|
35
|
+
import * as i18 from "./components/header/app-switcher.component";
|
|
36
|
+
import * as i19 from "./components/header/app-nav.component";
|
|
37
|
+
import * as i20 from "./components/tabs/tab-container.component";
|
|
38
|
+
import * as i21 from "./components/dialogs/app-access-dialog.component";
|
|
39
|
+
import * as i22 from "../command-palette/command-palette.component";
|
|
40
|
+
import * as i23 from "../omnibar/omnibar-palette.component";
|
|
40
41
|
const _c0 = ["searchInput"];
|
|
41
42
|
const _c1 = ["omnibarPalette"];
|
|
42
43
|
const _c2 = ["shellSearchComposite"];
|
|
@@ -44,7 +45,7 @@ const _c3 = ["appAccessDialog"];
|
|
|
44
45
|
const _forTrack0 = ($index, $item) => $item.ID;
|
|
45
46
|
function ShellComponent_Conditional_5_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
46
47
|
const _r2 = i0.ɵɵgetCurrentView();
|
|
47
|
-
i0.ɵɵelementStart(0, "button",
|
|
48
|
+
i0.ɵɵelementStart(0, "button", 48);
|
|
48
49
|
i0.ɵɵlistener("click", function ShellComponent_Conditional_5_For_2_Template_button_click_0_listener($event) { const app_r3 = i0.ɵɵrestoreView(_r2).$implicit; const ctx_r3 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r3.onNavBarAppClick(app_r3, $event)); })("dblclick", function ShellComponent_Conditional_5_For_2_Template_button_dblclick_0_listener($event) { const app_r3 = i0.ɵɵrestoreView(_r2).$implicit; const ctx_r3 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r3.onNavBarAppDblClick(app_r3, $event)); });
|
|
49
50
|
i0.ɵɵelement(1, "i");
|
|
50
51
|
i0.ɵɵelementEnd();
|
|
@@ -60,7 +61,7 @@ function ShellComponent_Conditional_5_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
|
60
61
|
} }
|
|
61
62
|
function ShellComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
62
63
|
i0.ɵɵelementStart(0, "div", 9);
|
|
63
|
-
i0.ɵɵrepeaterCreate(1, ShellComponent_Conditional_5_For_2_Template, 2, 8, "button",
|
|
64
|
+
i0.ɵɵrepeaterCreate(1, ShellComponent_Conditional_5_For_2_Template, 2, 8, "button", 47, i0.ɵɵrepeaterTrackByIdentity);
|
|
64
65
|
i0.ɵɵelementEnd();
|
|
65
66
|
} if (rf & 2) {
|
|
66
67
|
const ctx_r3 = i0.ɵɵnextContext();
|
|
@@ -69,31 +70,40 @@ function ShellComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
|
69
70
|
} }
|
|
70
71
|
function ShellComponent_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
71
72
|
const _r5 = i0.ɵɵgetCurrentView();
|
|
72
|
-
i0.ɵɵelementStart(0, "mj-app-switcher",
|
|
73
|
+
i0.ɵɵelementStart(0, "mj-app-switcher", 49);
|
|
73
74
|
i0.ɵɵlistener("appSelected", function ShellComponent_Conditional_6_Template_mj_app_switcher_appSelected_0_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.onAppSwitch($event)); });
|
|
74
75
|
i0.ɵɵelementEnd();
|
|
75
76
|
} if (rf & 2) {
|
|
76
77
|
const ctx_r3 = i0.ɵɵnextContext();
|
|
77
78
|
i0.ɵɵproperty("activeApp", ctx_r3.activeApp)("isViewingSystemTab", ctx_r3.isViewingSystemTab)("loadingAppId", ctx_r3.loadingAppId)("SwitcherStyle", ctx_r3.AppSwitcherStyle)("Provider", ctx_r3.Provider);
|
|
78
79
|
} }
|
|
80
|
+
function ShellComponent_Conditional_7_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
81
|
+
i0.ɵɵelement(0, "mj-records-hub-pill");
|
|
82
|
+
} }
|
|
79
83
|
function ShellComponent_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
80
84
|
const _r6 = i0.ɵɵgetCurrentView();
|
|
81
|
-
i0.ɵɵelementStart(0, "mj-app-nav",
|
|
85
|
+
i0.ɵɵelementStart(0, "mj-app-nav", 50);
|
|
82
86
|
i0.ɵɵlistener("navItemClick", function ShellComponent_Conditional_7_Template_mj_app_nav_navItemClick_0_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.onNavItemClick($event)); })("navItemDismiss", function ShellComponent_Conditional_7_Template_mj_app_nav_navItemDismiss_0_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.onNavItemDismiss($event)); });
|
|
87
|
+
i0.ɵɵconditionalCreate(1, ShellComponent_Conditional_7_Conditional_1_Template, 1, 0, "mj-records-hub-pill");
|
|
83
88
|
i0.ɵɵelementEnd();
|
|
84
89
|
} if (rf & 2) {
|
|
85
90
|
const ctx_r3 = i0.ɵɵnextContext();
|
|
86
91
|
i0.ɵɵproperty("app", ctx_r3.activeApp)("OverflowEnabled", true);
|
|
92
|
+
i0.ɵɵadvance();
|
|
93
|
+
i0.ɵɵconditional(ctx_r3.RecordTabsStyle ? 1 : -1);
|
|
87
94
|
} }
|
|
88
|
-
function
|
|
95
|
+
function ShellComponent_Conditional_8_Template(rf, ctx) { if (rf & 1) {
|
|
96
|
+
i0.ɵɵelement(0, "mj-records-hub-pill", 12);
|
|
97
|
+
} }
|
|
98
|
+
function ShellComponent_Conditional_11_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
89
99
|
const _r7 = i0.ɵɵgetCurrentView();
|
|
90
|
-
i0.ɵɵelementStart(0, "button",
|
|
91
|
-
i0.ɵɵlistener("click", function
|
|
92
|
-
i0.ɵɵelement(1, "i",
|
|
93
|
-
i0.ɵɵelementStart(2, "span",
|
|
100
|
+
i0.ɵɵelementStart(0, "button", 52);
|
|
101
|
+
i0.ɵɵlistener("click", function ShellComponent_Conditional_11_Conditional_0_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r7); const ctx_r3 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r3.OnHeaderSearchClick()); });
|
|
102
|
+
i0.ɵɵelement(1, "i", 53);
|
|
103
|
+
i0.ɵɵelementStart(2, "span", 54);
|
|
94
104
|
i0.ɵɵtext(3, "Search everything");
|
|
95
105
|
i0.ɵɵelementEnd();
|
|
96
|
-
i0.ɵɵelementStart(4, "kbd",
|
|
106
|
+
i0.ɵɵelementStart(4, "kbd", 55);
|
|
97
107
|
i0.ɵɵtext(5);
|
|
98
108
|
i0.ɵɵelementEnd()();
|
|
99
109
|
} if (rf & 2) {
|
|
@@ -102,14 +112,14 @@ function ShellComponent_Conditional_10_Conditional_0_Template(rf, ctx) { if (rf
|
|
|
102
112
|
i0.ɵɵadvance(5);
|
|
103
113
|
i0.ɵɵtextInterpolate(ctx_r3.OmnibarShortcutLabel);
|
|
104
114
|
} }
|
|
105
|
-
function
|
|
115
|
+
function ShellComponent_Conditional_11_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
106
116
|
const _r8 = i0.ɵɵgetCurrentView();
|
|
107
|
-
i0.ɵɵelementStart(0, "div",
|
|
108
|
-
i0.ɵɵlistener("ResultSelected", function
|
|
117
|
+
i0.ɵɵelementStart(0, "div", 56)(1, "mj-search-composite", 57, 3);
|
|
118
|
+
i0.ɵɵlistener("ResultSelected", function ShellComponent_Conditional_11_Conditional_1_Template_mj_search_composite_ResultSelected_1_listener($event) { i0.ɵɵrestoreView(_r8); const ctx_r3 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r3.OnSearchResultSelected($event)); })("SearchSubmitted", function ShellComponent_Conditional_11_Conditional_1_Template_mj_search_composite_SearchSubmitted_1_listener($event) { i0.ɵɵrestoreView(_r8); const ctx_r3 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r3.OnSearchSubmitted($event)); })("SeeAllRequested", function ShellComponent_Conditional_11_Conditional_1_Template_mj_search_composite_SeeAllRequested_1_listener($event) { i0.ɵɵrestoreView(_r8); const ctx_r3 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r3.OnSeeAllSearch($event)); })("RecentRecordSelected", function ShellComponent_Conditional_11_Conditional_1_Template_mj_search_composite_RecentRecordSelected_1_listener($event) { i0.ɵɵrestoreView(_r8); const ctx_r3 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r3.OnSearchResultSelected($event)); })("PromoAccepted", function ShellComponent_Conditional_11_Conditional_1_Template_mj_search_composite_PromoAccepted_1_listener($event) { i0.ɵɵrestoreView(_r8); const ctx_r3 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r3.OnOmnibarPromoAccepted($event)); })("PromoDismissed", function ShellComponent_Conditional_11_Conditional_1_Template_mj_search_composite_PromoDismissed_1_listener() { i0.ɵɵrestoreView(_r8); const ctx_r3 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r3.OnOmnibarPromoDismissed()); });
|
|
109
119
|
i0.ɵɵelementEnd()();
|
|
110
|
-
i0.ɵɵelementStart(3, "button",
|
|
111
|
-
i0.ɵɵlistener("click", function
|
|
112
|
-
i0.ɵɵelement(4, "i",
|
|
120
|
+
i0.ɵɵelementStart(3, "button", 58);
|
|
121
|
+
i0.ɵɵlistener("click", function ShellComponent_Conditional_11_Conditional_1_Template_button_click_3_listener() { i0.ɵɵrestoreView(_r8); const ctx_r3 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r3.OnHeaderSearchClick()); });
|
|
122
|
+
i0.ɵɵelement(4, "i", 53);
|
|
113
123
|
i0.ɵɵelementEnd();
|
|
114
124
|
} if (rf & 2) {
|
|
115
125
|
const ctx_r3 = i0.ɵɵnextContext(2);
|
|
@@ -118,14 +128,14 @@ function ShellComponent_Conditional_10_Conditional_1_Template(rf, ctx) { if (rf
|
|
|
118
128
|
i0.ɵɵadvance(2);
|
|
119
129
|
i0.ɵɵattribute("aria-label", "Search everything (" + ctx_r3.OmnibarShortcutLabel + ")");
|
|
120
130
|
} }
|
|
121
|
-
function
|
|
122
|
-
i0.ɵɵconditionalCreate(0,
|
|
131
|
+
function ShellComponent_Conditional_11_Template(rf, ctx) { if (rf & 1) {
|
|
132
|
+
i0.ɵɵconditionalCreate(0, ShellComponent_Conditional_11_Conditional_0_Template, 6, 2, "button", 51)(1, ShellComponent_Conditional_11_Conditional_1_Template, 5, 7);
|
|
123
133
|
} if (rf & 2) {
|
|
124
134
|
const ctx_r3 = i0.ɵɵnextContext();
|
|
125
135
|
i0.ɵɵconditional(ctx_r3.UseOmnibar ? 0 : 1);
|
|
126
136
|
} }
|
|
127
|
-
function
|
|
128
|
-
i0.ɵɵelementStart(0, "span",
|
|
137
|
+
function ShellComponent_Conditional_12_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
138
|
+
i0.ɵɵelementStart(0, "span", 61);
|
|
129
139
|
i0.ɵɵtext(1);
|
|
130
140
|
i0.ɵɵelementEnd();
|
|
131
141
|
} if (rf & 2) {
|
|
@@ -133,8 +143,8 @@ function ShellComponent_Conditional_11_Conditional_3_Template(rf, ctx) { if (rf
|
|
|
133
143
|
i0.ɵɵadvance();
|
|
134
144
|
i0.ɵɵtextInterpolate(ctx_r3.activityRunningCount);
|
|
135
145
|
} }
|
|
136
|
-
function
|
|
137
|
-
i0.ɵɵelementStart(0, "div",
|
|
146
|
+
function ShellComponent_Conditional_12_Conditional_4_For_8_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
147
|
+
i0.ɵɵelementStart(0, "div", 73);
|
|
138
148
|
i0.ɵɵtext(1);
|
|
139
149
|
i0.ɵɵelementEnd();
|
|
140
150
|
} if (rf & 2) {
|
|
@@ -142,23 +152,23 @@ function ShellComponent_Conditional_11_Conditional_4_For_8_Conditional_5_Templat
|
|
|
142
152
|
i0.ɵɵadvance();
|
|
143
153
|
i0.ɵɵtextInterpolate(a_r11.Detail);
|
|
144
154
|
} }
|
|
145
|
-
function
|
|
146
|
-
i0.ɵɵelementStart(0, "div",
|
|
147
|
-
i0.ɵɵelement(1, "div",
|
|
155
|
+
function ShellComponent_Conditional_12_Conditional_4_For_8_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
156
|
+
i0.ɵɵelementStart(0, "div", 74);
|
|
157
|
+
i0.ɵɵelement(1, "div", 75);
|
|
148
158
|
i0.ɵɵelementEnd();
|
|
149
159
|
} if (rf & 2) {
|
|
150
160
|
const a_r11 = i0.ɵɵnextContext().$implicit;
|
|
151
161
|
i0.ɵɵadvance();
|
|
152
162
|
i0.ɵɵstyleProp("width", a_r11.Progress, "%");
|
|
153
163
|
} }
|
|
154
|
-
function
|
|
155
|
-
i0.ɵɵelementStart(0, "div",
|
|
156
|
-
i0.ɵɵelement(1, "i",
|
|
157
|
-
i0.ɵɵelementStart(2, "div",
|
|
164
|
+
function ShellComponent_Conditional_12_Conditional_4_For_8_Template(rf, ctx) { if (rf & 1) {
|
|
165
|
+
i0.ɵɵelementStart(0, "div", 69);
|
|
166
|
+
i0.ɵɵelement(1, "i", 70);
|
|
167
|
+
i0.ɵɵelementStart(2, "div", 71)(3, "div", 72);
|
|
158
168
|
i0.ɵɵtext(4);
|
|
159
169
|
i0.ɵɵelementEnd();
|
|
160
|
-
i0.ɵɵconditionalCreate(5,
|
|
161
|
-
i0.ɵɵconditionalCreate(6,
|
|
170
|
+
i0.ɵɵconditionalCreate(5, ShellComponent_Conditional_12_Conditional_4_For_8_Conditional_5_Template, 2, 1, "div", 73);
|
|
171
|
+
i0.ɵɵconditionalCreate(6, ShellComponent_Conditional_12_Conditional_4_For_8_Conditional_6_Template, 2, 2, "div", 74);
|
|
162
172
|
i0.ɵɵelementEnd()();
|
|
163
173
|
} if (rf & 2) {
|
|
164
174
|
const a_r11 = ctx.$implicit;
|
|
@@ -172,33 +182,33 @@ function ShellComponent_Conditional_11_Conditional_4_For_8_Template(rf, ctx) { i
|
|
|
172
182
|
i0.ɵɵadvance();
|
|
173
183
|
i0.ɵɵconditional(a_r11.Status === "running" && a_r11.Progress != null ? 6 : -1);
|
|
174
184
|
} }
|
|
175
|
-
function
|
|
185
|
+
function ShellComponent_Conditional_12_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
176
186
|
const _r10 = i0.ɵɵgetCurrentView();
|
|
177
|
-
i0.ɵɵelementStart(0, "div",
|
|
178
|
-
i0.ɵɵlistener("click", function
|
|
179
|
-
i0.ɵɵelementStart(1, "div",
|
|
187
|
+
i0.ɵɵelementStart(0, "div", 63);
|
|
188
|
+
i0.ɵɵlistener("click", function ShellComponent_Conditional_12_Conditional_4_Template_div_click_0_listener($event) { i0.ɵɵrestoreView(_r10); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
189
|
+
i0.ɵɵelementStart(1, "div", 64)(2, "span");
|
|
180
190
|
i0.ɵɵtext(3, "Activity");
|
|
181
191
|
i0.ɵɵelementEnd();
|
|
182
|
-
i0.ɵɵelementStart(4, "button",
|
|
183
|
-
i0.ɵɵlistener("click", function
|
|
184
|
-
i0.ɵɵelement(5, "i",
|
|
192
|
+
i0.ɵɵelementStart(4, "button", 65);
|
|
193
|
+
i0.ɵɵlistener("click", function ShellComponent_Conditional_12_Conditional_4_Template_button_click_4_listener() { i0.ɵɵrestoreView(_r10); const ctx_r3 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r3.clearFinishedActivity()); });
|
|
194
|
+
i0.ɵɵelement(5, "i", 66);
|
|
185
195
|
i0.ɵɵelementEnd()();
|
|
186
|
-
i0.ɵɵelementStart(6, "div",
|
|
187
|
-
i0.ɵɵrepeaterCreate(7,
|
|
196
|
+
i0.ɵɵelementStart(6, "div", 67);
|
|
197
|
+
i0.ɵɵrepeaterCreate(7, ShellComponent_Conditional_12_Conditional_4_For_8_Template, 7, 7, "div", 68, _forTrack0);
|
|
188
198
|
i0.ɵɵelementEnd()();
|
|
189
199
|
} if (rf & 2) {
|
|
190
200
|
const ctx_r3 = i0.ɵɵnextContext(2);
|
|
191
201
|
i0.ɵɵadvance(7);
|
|
192
202
|
i0.ɵɵrepeater(ctx_r3.activityItems);
|
|
193
203
|
} }
|
|
194
|
-
function
|
|
204
|
+
function ShellComponent_Conditional_12_Template(rf, ctx) { if (rf & 1) {
|
|
195
205
|
const _r9 = i0.ɵɵgetCurrentView();
|
|
196
|
-
i0.ɵɵelementStart(0, "div",
|
|
197
|
-
i0.ɵɵlistener("click", function
|
|
198
|
-
i0.ɵɵelement(2, "i",
|
|
199
|
-
i0.ɵɵconditionalCreate(3,
|
|
206
|
+
i0.ɵɵelementStart(0, "div", 15)(1, "button", 59);
|
|
207
|
+
i0.ɵɵlistener("click", function ShellComponent_Conditional_12_Template_button_click_1_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.toggleActivity($event)); });
|
|
208
|
+
i0.ɵɵelement(2, "i", 60);
|
|
209
|
+
i0.ɵɵconditionalCreate(3, ShellComponent_Conditional_12_Conditional_3_Template, 2, 1, "span", 61);
|
|
200
210
|
i0.ɵɵelementEnd();
|
|
201
|
-
i0.ɵɵconditionalCreate(4,
|
|
211
|
+
i0.ɵɵconditionalCreate(4, ShellComponent_Conditional_12_Conditional_4_Template, 9, 0, "div", 62);
|
|
202
212
|
i0.ɵɵelementEnd();
|
|
203
213
|
} if (rf & 2) {
|
|
204
214
|
const ctx_r3 = i0.ɵɵnextContext();
|
|
@@ -209,8 +219,8 @@ function ShellComponent_Conditional_11_Template(rf, ctx) { if (rf & 1) {
|
|
|
209
219
|
i0.ɵɵadvance();
|
|
210
220
|
i0.ɵɵconditional(ctx_r3.activityOpen ? 4 : -1);
|
|
211
221
|
} }
|
|
212
|
-
function
|
|
213
|
-
i0.ɵɵelementStart(0, "span",
|
|
222
|
+
function ShellComponent_Conditional_13_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
223
|
+
i0.ɵɵelementStart(0, "span", 78);
|
|
214
224
|
i0.ɵɵtext(1);
|
|
215
225
|
i0.ɵɵelementEnd();
|
|
216
226
|
} if (rf & 2) {
|
|
@@ -218,22 +228,22 @@ function ShellComponent_Conditional_12_Conditional_2_Template(rf, ctx) { if (rf
|
|
|
218
228
|
i0.ɵɵadvance();
|
|
219
229
|
i0.ɵɵtextInterpolate1(" ", ctx_r3.unreadNotificationCount > 99 ? "99+" : ctx_r3.unreadNotificationCount, " ");
|
|
220
230
|
} }
|
|
221
|
-
function
|
|
231
|
+
function ShellComponent_Conditional_13_Template(rf, ctx) { if (rf & 1) {
|
|
222
232
|
const _r12 = i0.ɵɵgetCurrentView();
|
|
223
|
-
i0.ɵɵelementStart(0, "button",
|
|
224
|
-
i0.ɵɵlistener("click", function
|
|
225
|
-
i0.ɵɵelement(1, "i",
|
|
226
|
-
i0.ɵɵconditionalCreate(2,
|
|
233
|
+
i0.ɵɵelementStart(0, "button", 76);
|
|
234
|
+
i0.ɵɵlistener("click", function ShellComponent_Conditional_13_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r12); const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.showNotifications()); });
|
|
235
|
+
i0.ɵɵelement(1, "i", 77);
|
|
236
|
+
i0.ɵɵconditionalCreate(2, ShellComponent_Conditional_13_Conditional_2_Template, 2, 1, "span", 78);
|
|
227
237
|
i0.ɵɵelementEnd();
|
|
228
238
|
} if (rf & 2) {
|
|
229
239
|
const ctx_r3 = i0.ɵɵnextContext();
|
|
230
240
|
i0.ɵɵadvance(2);
|
|
231
241
|
i0.ɵɵconditional(ctx_r3.unreadNotificationCount > 0 ? 2 : -1);
|
|
232
242
|
} }
|
|
233
|
-
function
|
|
243
|
+
function ShellComponent_Conditional_14_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
234
244
|
const _r13 = i0.ɵɵgetCurrentView();
|
|
235
|
-
i0.ɵɵelementStart(0, "button",
|
|
236
|
-
i0.ɵɵlistener("click", function
|
|
245
|
+
i0.ɵɵelementStart(0, "button", 48);
|
|
246
|
+
i0.ɵɵlistener("click", function ShellComponent_Conditional_14_For_2_Template_button_click_0_listener($event) { const app_r14 = i0.ɵɵrestoreView(_r13).$implicit; const ctx_r3 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r3.onNavBarAppClick(app_r14, $event)); })("dblclick", function ShellComponent_Conditional_14_For_2_Template_button_dblclick_0_listener($event) { const app_r14 = i0.ɵɵrestoreView(_r13).$implicit; const ctx_r3 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r3.onNavBarAppDblClick(app_r14, $event)); });
|
|
237
247
|
i0.ɵɵelement(1, "i");
|
|
238
248
|
i0.ɵɵelementEnd();
|
|
239
249
|
} if (rf & 2) {
|
|
@@ -246,23 +256,23 @@ function ShellComponent_Conditional_13_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
|
246
256
|
i0.ɵɵadvance();
|
|
247
257
|
i0.ɵɵclassMap(app_r14.Icon);
|
|
248
258
|
} }
|
|
249
|
-
function
|
|
250
|
-
i0.ɵɵelementStart(0, "div",
|
|
251
|
-
i0.ɵɵrepeaterCreate(1,
|
|
259
|
+
function ShellComponent_Conditional_14_Template(rf, ctx) { if (rf & 1) {
|
|
260
|
+
i0.ɵɵelementStart(0, "div", 17);
|
|
261
|
+
i0.ɵɵrepeaterCreate(1, ShellComponent_Conditional_14_For_2_Template, 2, 8, "button", 47, i0.ɵɵrepeaterTrackByIdentity);
|
|
252
262
|
i0.ɵɵelementEnd();
|
|
253
263
|
} if (rf & 2) {
|
|
254
264
|
const ctx_r3 = i0.ɵɵnextContext();
|
|
255
265
|
i0.ɵɵadvance();
|
|
256
266
|
i0.ɵɵrepeater(ctx_r3.leftOfUserMenuApps);
|
|
257
267
|
} }
|
|
258
|
-
function
|
|
259
|
-
i0.ɵɵelement(0, "img",
|
|
268
|
+
function ShellComponent_Conditional_17_Template(rf, ctx) { if (rf & 1) {
|
|
269
|
+
i0.ɵɵelement(0, "img", 20);
|
|
260
270
|
} if (rf & 2) {
|
|
261
271
|
const ctx_r3 = i0.ɵɵnextContext();
|
|
262
272
|
i0.ɵɵproperty("src", ctx_r3.userImageURL, i0.ɵɵsanitizeUrl);
|
|
263
273
|
} }
|
|
264
|
-
function
|
|
265
|
-
i0.ɵɵelementStart(0, "div",
|
|
274
|
+
function ShellComponent_Conditional_18_Template(rf, ctx) { if (rf & 1) {
|
|
275
|
+
i0.ɵɵelementStart(0, "div", 21);
|
|
266
276
|
i0.ɵɵelement(1, "i");
|
|
267
277
|
i0.ɵɵelementEnd();
|
|
268
278
|
} if (rf & 2) {
|
|
@@ -270,8 +280,8 @@ function ShellComponent_Conditional_17_Template(rf, ctx) { if (rf & 1) {
|
|
|
270
280
|
i0.ɵɵadvance();
|
|
271
281
|
i0.ɵɵclassMap(ctx_r3.userIconClass || "fa-solid fa-user");
|
|
272
282
|
} }
|
|
273
|
-
function
|
|
274
|
-
i0.ɵɵelementStart(0, "span",
|
|
283
|
+
function ShellComponent_Conditional_19_Conditional_1_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
284
|
+
i0.ɵɵelementStart(0, "span", 83);
|
|
275
285
|
i0.ɵɵtext(1);
|
|
276
286
|
i0.ɵɵelementEnd();
|
|
277
287
|
} if (rf & 2) {
|
|
@@ -280,8 +290,8 @@ function ShellComponent_Conditional_18_Conditional_1_Conditional_4_Template(rf,
|
|
|
280
290
|
i0.ɵɵadvance();
|
|
281
291
|
i0.ɵɵtextInterpolate1(" ", (tmp_6_0 = ctx_r3.getUserDisplayInfo()) == null ? null : tmp_6_0.email, " ");
|
|
282
292
|
} }
|
|
283
|
-
function
|
|
284
|
-
i0.ɵɵelementStart(0, "span",
|
|
293
|
+
function ShellComponent_Conditional_19_Conditional_1_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
294
|
+
i0.ɵɵelementStart(0, "span", 84);
|
|
285
295
|
i0.ɵɵtext(1);
|
|
286
296
|
i0.ɵɵelementEnd();
|
|
287
297
|
} if (rf & 2) {
|
|
@@ -290,14 +300,14 @@ function ShellComponent_Conditional_18_Conditional_1_Conditional_5_Template(rf,
|
|
|
290
300
|
i0.ɵɵadvance();
|
|
291
301
|
i0.ɵɵtextInterpolate((tmp_6_0 = ctx_r3.getUserDisplayInfo()) == null ? null : tmp_6_0.subtitle);
|
|
292
302
|
} }
|
|
293
|
-
function
|
|
294
|
-
i0.ɵɵelementStart(0, "div",
|
|
303
|
+
function ShellComponent_Conditional_19_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
304
|
+
i0.ɵɵelementStart(0, "div", 80)(1, "div", 81)(2, "span", 82);
|
|
295
305
|
i0.ɵɵtext(3);
|
|
296
306
|
i0.ɵɵelementEnd();
|
|
297
|
-
i0.ɵɵconditionalCreate(4,
|
|
298
|
-
i0.ɵɵconditionalCreate(5,
|
|
307
|
+
i0.ɵɵconditionalCreate(4, ShellComponent_Conditional_19_Conditional_1_Conditional_4_Template, 2, 1, "span", 83);
|
|
308
|
+
i0.ɵɵconditionalCreate(5, ShellComponent_Conditional_19_Conditional_1_Conditional_5_Template, 2, 1, "span", 84);
|
|
299
309
|
i0.ɵɵelementEnd()();
|
|
300
|
-
i0.ɵɵelement(6, "div",
|
|
310
|
+
i0.ɵɵelement(6, "div", 85);
|
|
301
311
|
} if (rf & 2) {
|
|
302
312
|
let tmp_5_0;
|
|
303
313
|
let tmp_6_0;
|
|
@@ -310,19 +320,19 @@ function ShellComponent_Conditional_18_Conditional_1_Template(rf, ctx) { if (rf
|
|
|
310
320
|
i0.ɵɵadvance();
|
|
311
321
|
i0.ɵɵconditional(((tmp_7_0 = ctx_r3.getUserDisplayInfo()) == null ? null : tmp_7_0.subtitle) ? 5 : -1);
|
|
312
322
|
} }
|
|
313
|
-
function
|
|
314
|
-
i0.ɵɵelement(0, "div",
|
|
323
|
+
function ShellComponent_Conditional_19_For_3_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
324
|
+
i0.ɵɵelement(0, "div", 85);
|
|
315
325
|
} }
|
|
316
|
-
function
|
|
326
|
+
function ShellComponent_Conditional_19_For_3_Conditional_1_Conditional_0_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
317
327
|
const _r15 = i0.ɵɵgetCurrentView();
|
|
318
|
-
i0.ɵɵelementStart(0, "div",
|
|
319
|
-
i0.ɵɵlistener("click", function
|
|
328
|
+
i0.ɵɵelementStart(0, "div", 88);
|
|
329
|
+
i0.ɵɵlistener("click", function ShellComponent_Conditional_19_For_3_Conditional_1_Conditional_0_Conditional_0_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r15); const item_r16 = i0.ɵɵnextContext(); const ctx_r3 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(ctx_r3.onUserMenuItemClick(item_r16.id)); });
|
|
320
330
|
i0.ɵɵelement(1, "i");
|
|
321
|
-
i0.ɵɵelementStart(2, "span",
|
|
331
|
+
i0.ɵɵelementStart(2, "span", 89);
|
|
322
332
|
i0.ɵɵtext(3);
|
|
323
333
|
i0.ɵɵelementEnd();
|
|
324
|
-
i0.ɵɵelementStart(4, "div",
|
|
325
|
-
i0.ɵɵelement(6, "i",
|
|
334
|
+
i0.ɵɵelementStart(4, "div", 90)(5, "div", 91);
|
|
335
|
+
i0.ɵɵelement(6, "i", 92);
|
|
326
336
|
i0.ɵɵelementEnd()()();
|
|
327
337
|
} if (rf & 2) {
|
|
328
338
|
const item_r16 = i0.ɵɵnextContext();
|
|
@@ -337,8 +347,8 @@ function ShellComponent_Conditional_18_For_3_Conditional_1_Conditional_0_Conditi
|
|
|
337
347
|
i0.ɵɵadvance(2);
|
|
338
348
|
i0.ɵɵclassMap(ctx_r3.IsDarkMode ? "fa-solid fa-moon" : "fa-solid fa-sun");
|
|
339
349
|
} }
|
|
340
|
-
function
|
|
341
|
-
i0.ɵɵelementStart(0, "span",
|
|
350
|
+
function ShellComponent_Conditional_19_For_3_Conditional_1_Conditional_0_Conditional_1_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
351
|
+
i0.ɵɵelementStart(0, "span", 94);
|
|
342
352
|
i0.ɵɵtext(1);
|
|
343
353
|
i0.ɵɵelementEnd();
|
|
344
354
|
} if (rf & 2) {
|
|
@@ -346,15 +356,15 @@ function ShellComponent_Conditional_18_For_3_Conditional_1_Conditional_0_Conditi
|
|
|
346
356
|
i0.ɵɵadvance();
|
|
347
357
|
i0.ɵɵtextInterpolate(item_r16.shortcut);
|
|
348
358
|
} }
|
|
349
|
-
function
|
|
359
|
+
function ShellComponent_Conditional_19_For_3_Conditional_1_Conditional_0_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
350
360
|
const _r17 = i0.ɵɵgetCurrentView();
|
|
351
|
-
i0.ɵɵelementStart(0, "div",
|
|
352
|
-
i0.ɵɵlistener("click", function
|
|
361
|
+
i0.ɵɵelementStart(0, "div", 93);
|
|
362
|
+
i0.ɵɵlistener("click", function ShellComponent_Conditional_19_For_3_Conditional_1_Conditional_0_Conditional_1_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r17); const item_r16 = i0.ɵɵnextContext(); const ctx_r3 = i0.ɵɵnextContext(4); return i0.ɵɵresetView(item_r16.enabled && ctx_r3.onUserMenuItemClick(item_r16.id)); });
|
|
353
363
|
i0.ɵɵelement(1, "i");
|
|
354
|
-
i0.ɵɵelementStart(2, "span",
|
|
364
|
+
i0.ɵɵelementStart(2, "span", 89);
|
|
355
365
|
i0.ɵɵtext(3);
|
|
356
366
|
i0.ɵɵelementEnd();
|
|
357
|
-
i0.ɵɵconditionalCreate(4,
|
|
367
|
+
i0.ɵɵconditionalCreate(4, ShellComponent_Conditional_19_For_3_Conditional_1_Conditional_0_Conditional_1_Conditional_4_Template, 2, 1, "span", 94);
|
|
358
368
|
i0.ɵɵelementEnd();
|
|
359
369
|
} if (rf & 2) {
|
|
360
370
|
const item_r16 = i0.ɵɵnextContext();
|
|
@@ -368,22 +378,22 @@ function ShellComponent_Conditional_18_For_3_Conditional_1_Conditional_0_Conditi
|
|
|
368
378
|
i0.ɵɵadvance();
|
|
369
379
|
i0.ɵɵconditional(item_r16.shortcut ? 4 : -1);
|
|
370
380
|
} }
|
|
371
|
-
function
|
|
372
|
-
i0.ɵɵconditionalCreate(0,
|
|
381
|
+
function ShellComponent_Conditional_19_For_3_Conditional_1_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
382
|
+
i0.ɵɵconditionalCreate(0, ShellComponent_Conditional_19_For_3_Conditional_1_Conditional_0_Conditional_0_Template, 7, 8, "div", 86)(1, ShellComponent_Conditional_19_For_3_Conditional_1_Conditional_0_Conditional_1_Template, 5, 11, "div", 87);
|
|
373
383
|
} if (rf & 2) {
|
|
374
384
|
i0.ɵɵconditional(ctx.id === "toggle-theme" ? 0 : 1);
|
|
375
385
|
} }
|
|
376
|
-
function
|
|
377
|
-
i0.ɵɵconditionalCreate(0,
|
|
386
|
+
function ShellComponent_Conditional_19_For_3_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
387
|
+
i0.ɵɵconditionalCreate(0, ShellComponent_Conditional_19_For_3_Conditional_1_Conditional_0_Template, 2, 1);
|
|
378
388
|
} if (rf & 2) {
|
|
379
389
|
let tmp_15_0;
|
|
380
390
|
const element_r18 = i0.ɵɵnextContext().$implicit;
|
|
381
391
|
const ctx_r3 = i0.ɵɵnextContext(2);
|
|
382
392
|
i0.ɵɵconditional((tmp_15_0 = ctx_r3.asMenuItem(element_r18)) ? 0 : -1, tmp_15_0);
|
|
383
393
|
} }
|
|
384
|
-
function
|
|
385
|
-
i0.ɵɵconditionalCreate(0,
|
|
386
|
-
i0.ɵɵconditionalCreate(1,
|
|
394
|
+
function ShellComponent_Conditional_19_For_3_Template(rf, ctx) { if (rf & 1) {
|
|
395
|
+
i0.ɵɵconditionalCreate(0, ShellComponent_Conditional_19_For_3_Conditional_0_Template, 1, 0, "div", 85);
|
|
396
|
+
i0.ɵɵconditionalCreate(1, ShellComponent_Conditional_19_For_3_Conditional_1_Template, 1, 1);
|
|
387
397
|
} if (rf & 2) {
|
|
388
398
|
const element_r18 = ctx.$implicit;
|
|
389
399
|
const ctx_r3 = i0.ɵɵnextContext(2);
|
|
@@ -391,10 +401,10 @@ function ShellComponent_Conditional_18_For_3_Template(rf, ctx) { if (rf & 1) {
|
|
|
391
401
|
i0.ɵɵadvance();
|
|
392
402
|
i0.ɵɵconditional(!ctx_r3.isMenuDivider(element_r18) ? 1 : -1);
|
|
393
403
|
} }
|
|
394
|
-
function
|
|
395
|
-
i0.ɵɵelementStart(0, "div",
|
|
396
|
-
i0.ɵɵconditionalCreate(1,
|
|
397
|
-
i0.ɵɵrepeaterCreate(2,
|
|
404
|
+
function ShellComponent_Conditional_19_Template(rf, ctx) { if (rf & 1) {
|
|
405
|
+
i0.ɵɵelementStart(0, "div", 79);
|
|
406
|
+
i0.ɵɵconditionalCreate(1, ShellComponent_Conditional_19_Conditional_1_Template, 7, 3);
|
|
407
|
+
i0.ɵɵrepeaterCreate(2, ShellComponent_Conditional_19_For_3_Template, 2, 2, null, null, i0.ɵɵrepeaterTrackByIdentity);
|
|
398
408
|
i0.ɵɵelementEnd();
|
|
399
409
|
} if (rf & 2) {
|
|
400
410
|
let tmp_4_0;
|
|
@@ -407,25 +417,25 @@ function ShellComponent_Conditional_18_Template(rf, ctx) { if (rf & 1) {
|
|
|
407
417
|
i0.ɵɵadvance();
|
|
408
418
|
i0.ɵɵrepeater(ctx_r3.userMenuElements);
|
|
409
419
|
} }
|
|
410
|
-
function
|
|
420
|
+
function ShellComponent_Conditional_20_Template(rf, ctx) { if (rf & 1) {
|
|
411
421
|
const _r19 = i0.ɵɵgetCurrentView();
|
|
412
|
-
i0.ɵɵelementStart(0, "div",
|
|
413
|
-
i0.ɵɵlistener("click", function
|
|
422
|
+
i0.ɵɵelementStart(0, "div", 95);
|
|
423
|
+
i0.ɵɵlistener("click", function ShellComponent_Conditional_20_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r19); const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.closeSearch()); });
|
|
414
424
|
i0.ɵɵelementEnd();
|
|
415
425
|
} }
|
|
416
|
-
function
|
|
426
|
+
function ShellComponent_Conditional_28_Template(rf, ctx) { if (rf & 1) {
|
|
417
427
|
const _r20 = i0.ɵɵgetCurrentView();
|
|
418
|
-
i0.ɵɵelementStart(0, "div",
|
|
419
|
-
i0.ɵɵlistener("click", function
|
|
428
|
+
i0.ɵɵelementStart(0, "div", 96);
|
|
429
|
+
i0.ɵɵlistener("click", function ShellComponent_Conditional_28_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r20); const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.closeMobileNav()); });
|
|
420
430
|
i0.ɵɵelementEnd();
|
|
421
431
|
} }
|
|
422
|
-
function
|
|
432
|
+
function ShellComponent_Conditional_35_Template(rf, ctx) { if (rf & 1) {
|
|
423
433
|
const _r21 = i0.ɵɵgetCurrentView();
|
|
424
|
-
i0.ɵɵelementStart(0, "div",
|
|
434
|
+
i0.ɵɵelementStart(0, "div", 35)(1, "div", 97);
|
|
425
435
|
i0.ɵɵtext(2);
|
|
426
436
|
i0.ɵɵelementEnd();
|
|
427
|
-
i0.ɵɵelementStart(3, "mj-app-nav",
|
|
428
|
-
i0.ɵɵlistener("navItemClick", function
|
|
437
|
+
i0.ɵɵelementStart(3, "mj-app-nav", 98);
|
|
438
|
+
i0.ɵɵlistener("navItemClick", function ShellComponent_Conditional_35_Template_mj_app_nav_navItemClick_3_listener($event) { i0.ɵɵrestoreView(_r21); const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.onNavItemClick($event)); })("navItemDismiss", function ShellComponent_Conditional_35_Template_mj_app_nav_navItemDismiss_3_listener($event) { i0.ɵɵrestoreView(_r21); const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.onNavItemDismiss($event)); });
|
|
429
439
|
i0.ɵɵelementEnd()();
|
|
430
440
|
} if (rf & 2) {
|
|
431
441
|
const ctx_r3 = i0.ɵɵnextContext();
|
|
@@ -434,8 +444,14 @@ function ShellComponent_Conditional_34_Template(rf, ctx) { if (rf & 1) {
|
|
|
434
444
|
i0.ɵɵadvance();
|
|
435
445
|
i0.ɵɵproperty("app", ctx_r3.activeApp)("OverflowEnabled", false);
|
|
436
446
|
} }
|
|
437
|
-
function
|
|
438
|
-
i0.ɵɵ
|
|
447
|
+
function ShellComponent_Conditional_36_Template(rf, ctx) { if (rf & 1) {
|
|
448
|
+
const _r22 = i0.ɵɵgetCurrentView();
|
|
449
|
+
i0.ɵɵelementStart(0, "div", 36)(1, "mj-records-hub-pill", 99);
|
|
450
|
+
i0.ɵɵlistener("Activated", function ShellComponent_Conditional_36_Template_mj_records_hub_pill_Activated_1_listener() { i0.ɵɵrestoreView(_r22); const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.closeMobileNav()); });
|
|
451
|
+
i0.ɵɵelementEnd()();
|
|
452
|
+
} }
|
|
453
|
+
function ShellComponent_Conditional_42_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
454
|
+
i0.ɵɵelementStart(0, "span", 101);
|
|
439
455
|
i0.ɵɵtext(1);
|
|
440
456
|
i0.ɵɵelementEnd();
|
|
441
457
|
} if (rf & 2) {
|
|
@@ -443,38 +459,38 @@ function ShellComponent_Conditional_40_Conditional_4_Template(rf, ctx) { if (rf
|
|
|
443
459
|
i0.ɵɵadvance();
|
|
444
460
|
i0.ɵɵtextInterpolate1(" ", ctx_r3.unreadNotificationCount > 99 ? "99+" : ctx_r3.unreadNotificationCount, " ");
|
|
445
461
|
} }
|
|
446
|
-
function
|
|
447
|
-
const
|
|
448
|
-
i0.ɵɵelementStart(0, "button",
|
|
449
|
-
i0.ɵɵlistener("click", function
|
|
450
|
-
i0.ɵɵelement(1, "i",
|
|
462
|
+
function ShellComponent_Conditional_42_Template(rf, ctx) { if (rf & 1) {
|
|
463
|
+
const _r23 = i0.ɵɵgetCurrentView();
|
|
464
|
+
i0.ɵɵelementStart(0, "button", 100);
|
|
465
|
+
i0.ɵɵlistener("click", function ShellComponent_Conditional_42_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r23); const ctx_r3 = i0.ɵɵnextContext(); ctx_r3.showNotifications(); return i0.ɵɵresetView(ctx_r3.closeMobileNav()); });
|
|
466
|
+
i0.ɵɵelement(1, "i", 77);
|
|
451
467
|
i0.ɵɵelementStart(2, "span");
|
|
452
468
|
i0.ɵɵtext(3, "Notifications");
|
|
453
469
|
i0.ɵɵelementEnd();
|
|
454
|
-
i0.ɵɵconditionalCreate(4,
|
|
470
|
+
i0.ɵɵconditionalCreate(4, ShellComponent_Conditional_42_Conditional_4_Template, 2, 1, "span", 101);
|
|
455
471
|
i0.ɵɵelementEnd();
|
|
456
472
|
} if (rf & 2) {
|
|
457
473
|
const ctx_r3 = i0.ɵɵnextContext();
|
|
458
474
|
i0.ɵɵadvance(4);
|
|
459
475
|
i0.ɵɵconditional(ctx_r3.unreadNotificationCount > 0 ? 4 : -1);
|
|
460
476
|
} }
|
|
461
|
-
function
|
|
462
|
-
const
|
|
463
|
-
i0.ɵɵelementStart(0, "div",
|
|
464
|
-
i0.ɵɵelement(2, "i",
|
|
477
|
+
function ShellComponent_Conditional_44_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
478
|
+
const _r24 = i0.ɵɵgetCurrentView();
|
|
479
|
+
i0.ɵɵelementStart(0, "div", 103)(1, "p", 105);
|
|
480
|
+
i0.ɵɵelement(2, "i", 106);
|
|
465
481
|
i0.ɵɵtext(3, " Taking longer than expected ");
|
|
466
482
|
i0.ɵɵelementEnd();
|
|
467
|
-
i0.ɵɵelementStart(4, "p",
|
|
483
|
+
i0.ɵɵelementStart(4, "p", 107);
|
|
468
484
|
i0.ɵɵtext(5, " This can happen after updates or due to cached data issues. ");
|
|
469
485
|
i0.ɵɵelementEnd();
|
|
470
|
-
i0.ɵɵelementStart(6, "button",
|
|
471
|
-
i0.ɵɵlistener("click", function
|
|
472
|
-
i0.ɵɵelement(7, "i",
|
|
486
|
+
i0.ɵɵelementStart(6, "button", 108);
|
|
487
|
+
i0.ɵɵlistener("click", function ShellComponent_Conditional_44_Conditional_2_Template_button_click_6_listener() { i0.ɵɵrestoreView(_r24); const ctx_r3 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r3.ResetApplication()); });
|
|
488
|
+
i0.ɵɵelement(7, "i", 109);
|
|
473
489
|
i0.ɵɵtext(8, " Reset ");
|
|
474
490
|
i0.ɵɵelementEnd()();
|
|
475
491
|
} }
|
|
476
|
-
function
|
|
477
|
-
i0.ɵɵelementStart(0, "div",
|
|
492
|
+
function ShellComponent_Conditional_44_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
493
|
+
i0.ɵɵelementStart(0, "div", 104);
|
|
478
494
|
i0.ɵɵtext(1);
|
|
479
495
|
i0.ɵɵelementEnd();
|
|
480
496
|
} if (rf & 2) {
|
|
@@ -482,10 +498,10 @@ function ShellComponent_Conditional_42_Conditional_3_Template(rf, ctx) { if (rf
|
|
|
482
498
|
i0.ɵɵadvance();
|
|
483
499
|
i0.ɵɵtextInterpolate1("MemberJunction \u00B7 v", ctx_r3.MJVersion);
|
|
484
500
|
} }
|
|
485
|
-
function
|
|
486
|
-
i0.ɵɵelementStart(0, "div",
|
|
487
|
-
i0.ɵɵelement(1, "mj-loading",
|
|
488
|
-
i0.ɵɵconditionalCreate(2,
|
|
501
|
+
function ShellComponent_Conditional_44_Template(rf, ctx) { if (rf & 1) {
|
|
502
|
+
i0.ɵɵelementStart(0, "div", 41);
|
|
503
|
+
i0.ɵɵelement(1, "mj-loading", 102);
|
|
504
|
+
i0.ɵɵconditionalCreate(2, ShellComponent_Conditional_44_Conditional_2_Template, 9, 0, "div", 103)(3, ShellComponent_Conditional_44_Conditional_3_Template, 2, 1, "div", 104);
|
|
489
505
|
i0.ɵɵelementEnd();
|
|
490
506
|
} if (rf & 2) {
|
|
491
507
|
const ctx_r3 = i0.ɵɵnextContext();
|
|
@@ -494,21 +510,21 @@ function ShellComponent_Conditional_42_Template(rf, ctx) { if (rf & 1) {
|
|
|
494
510
|
i0.ɵɵadvance();
|
|
495
511
|
i0.ɵɵconditional(ctx_r3.ShowResetOption ? 2 : 3);
|
|
496
512
|
} }
|
|
497
|
-
function
|
|
498
|
-
const
|
|
499
|
-
i0.ɵɵelementStart(0, "mj-search-overlay",
|
|
500
|
-
i0.ɵɵtwoWayListener("IsOpenChange", function
|
|
501
|
-
i0.ɵɵlistener("ResultSelected", function
|
|
513
|
+
function ShellComponent_Conditional_50_Template(rf, ctx) { if (rf & 1) {
|
|
514
|
+
const _r25 = i0.ɵɵgetCurrentView();
|
|
515
|
+
i0.ɵɵelementStart(0, "mj-search-overlay", 110);
|
|
516
|
+
i0.ɵɵtwoWayListener("IsOpenChange", function ShellComponent_Conditional_50_Template_mj_search_overlay_IsOpenChange_0_listener($event) { i0.ɵɵrestoreView(_r25); const ctx_r3 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r3.LegacySearchOpen, $event) || (ctx_r3.LegacySearchOpen = $event); return i0.ɵɵresetView($event); });
|
|
517
|
+
i0.ɵɵlistener("ResultSelected", function ShellComponent_Conditional_50_Template_mj_search_overlay_ResultSelected_0_listener($event) { i0.ɵɵrestoreView(_r25); const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.OnOverlayResultSelected($event)); })("SeeAllRequested", function ShellComponent_Conditional_50_Template_mj_search_overlay_SeeAllRequested_0_listener($event) { i0.ɵɵrestoreView(_r25); const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.OnOverlaySeeAll($event)); })("PromoAccepted", function ShellComponent_Conditional_50_Template_mj_search_overlay_PromoAccepted_0_listener($event) { i0.ɵɵrestoreView(_r25); const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.OnOmnibarPromoAccepted($event)); })("PromoDismissed", function ShellComponent_Conditional_50_Template_mj_search_overlay_PromoDismissed_0_listener() { i0.ɵɵrestoreView(_r25); const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.OnOmnibarPromoDismissed()); });
|
|
502
518
|
i0.ɵɵelementEnd();
|
|
503
519
|
} if (rf & 2) {
|
|
504
520
|
const ctx_r3 = i0.ɵɵnextContext();
|
|
505
521
|
i0.ɵɵtwoWayProperty("IsOpen", ctx_r3.LegacySearchOpen);
|
|
506
522
|
i0.ɵɵproperty("EnableGlobalShortcut", false)("ShowPromo", ctx_r3.ShowOmnibarPromo)("PromoText", ctx_r3.OmnibarPromoText);
|
|
507
523
|
} }
|
|
508
|
-
function
|
|
509
|
-
i0.ɵɵelementStart(0, "div",
|
|
510
|
-
i0.ɵɵelement(2, "mj-loading",
|
|
511
|
-
i0.ɵɵelementStart(3, "span",
|
|
524
|
+
function ShellComponent_Conditional_51_Template(rf, ctx) { if (rf & 1) {
|
|
525
|
+
i0.ɵɵelementStart(0, "div", 46)(1, "div", 111);
|
|
526
|
+
i0.ɵɵelement(2, "mj-loading", 112);
|
|
527
|
+
i0.ɵɵelementStart(3, "span", 113);
|
|
512
528
|
i0.ɵɵtext(4);
|
|
513
529
|
i0.ɵɵelementEnd()()();
|
|
514
530
|
} if (rf & 2) {
|
|
@@ -545,12 +561,24 @@ export class ShellComponent extends BaseAngularComponent {
|
|
|
545
561
|
activityService;
|
|
546
562
|
subscriptions = [];
|
|
547
563
|
urlBasedNavigation = false; // Track if we're loading from a URL
|
|
564
|
+
/** Newest workspace configuration emission — see the staleness guard in the Configuration subscription */
|
|
565
|
+
latestSyncedConfig = null;
|
|
548
566
|
initialNavigationComplete = false; // Track if initial navigation has completed
|
|
549
567
|
activeApp = null;
|
|
550
568
|
loading = true;
|
|
551
569
|
initialized = false;
|
|
552
570
|
waitingForFirstResource = false;
|
|
553
571
|
tabBarVisible = true; // Controlled by workspace manager
|
|
572
|
+
/**
|
|
573
|
+
* True when the deployment uses the records-as-tabs record-open style
|
|
574
|
+
* (`Shell.RecordOpen.Style` != 'classic'): records open as native Golden
|
|
575
|
+
* Layout tabs in the app the user is standing in, and the Records pill in
|
|
576
|
+
* the nav is the global entry point (count + resume-last-viewed). The GL
|
|
577
|
+
* tab header is the tab UI — native close/drag/pin apply to records too.
|
|
578
|
+
*/
|
|
579
|
+
get RecordTabsStyle() {
|
|
580
|
+
return this.chromeFlags.recordOpenStyle === 'records';
|
|
581
|
+
}
|
|
554
582
|
userMenuVisible = false; // User avatar context menu
|
|
555
583
|
mobileNavOpen = false; // Mobile navigation drawer
|
|
556
584
|
unreadNotificationCount = 0; // Notification badge count
|
|
@@ -633,12 +661,47 @@ export class ShellComponent extends BaseAngularComponent {
|
|
|
633
661
|
// to 'auto' (compact under a handful of apps, launcher otherwise)
|
|
634
662
|
appSwitcherStyle: rawStyle === 'launcher' || rawStyle === 'compact' ? rawStyle : 'auto',
|
|
635
663
|
appNav: engine.GetBoolean('Shell.AppNav.Enabled', true),
|
|
664
|
+
// Resolved (and pushed to collaborators) in resolveRecordOpenStyle()
|
|
665
|
+
// during initializeShell — NEVER as a getter side effect; getters
|
|
666
|
+
// run at change detection's whim and startup correctness must not
|
|
667
|
+
// depend on when a template happens to be evaluated.
|
|
668
|
+
recordOpenStyle: this.resolvedRecordOpenStyle,
|
|
636
669
|
};
|
|
637
670
|
if (engine.Loaded) {
|
|
638
671
|
this._chromeFlags = flags;
|
|
639
672
|
}
|
|
640
673
|
return flags;
|
|
641
674
|
}
|
|
675
|
+
/** The record-open style resolved at startup ('records' until resolved) */
|
|
676
|
+
resolvedRecordOpenStyle = 'records';
|
|
677
|
+
/**
|
|
678
|
+
* Resolve `Shell.RecordOpen.Style` from instance config and push it to the
|
|
679
|
+
* two collaborators that partition tabs by it: the ng-shared style module
|
|
680
|
+
* (NavigationService forks record opens on it) and the workspace manager's
|
|
681
|
+
* main-layout filter (record tabs must never count toward — or be consumed
|
|
682
|
+
* by — main-layout semantics). Called ONCE from initializeShell, after the
|
|
683
|
+
* InstanceConfigEngine load attempt and BEFORE workspace initialization.
|
|
684
|
+
*/
|
|
685
|
+
resolveRecordOpenStyle() {
|
|
686
|
+
const raw = InstanceConfigEngine.Instance.Get('Shell.RecordOpen.Style');
|
|
687
|
+
// Case/whitespace-insensitive: this compare is the ONLY opt-out for a
|
|
688
|
+
// default-behavior flip — an admin typing 'Classic' or 'classic ' must
|
|
689
|
+
// not silently get records anyway (GetBoolean parses insensitively;
|
|
690
|
+
// this value deserves the same tolerance).
|
|
691
|
+
this.resolvedRecordOpenStyle = raw?.trim().toLowerCase() === 'classic' ? 'classic' : 'records';
|
|
692
|
+
SetRecordOpenStyle(this.resolvedRecordOpenStyle);
|
|
693
|
+
// Region membership, not record identity: a record DOCKED to the
|
|
694
|
+
// workspace ("Move to Workspace") is a main-layout tab.
|
|
695
|
+
this.workspaceManager.MainLayoutTabFilter = this.resolvedRecordOpenStyle === 'records'
|
|
696
|
+
? (tab) => !IsRecordsRegionTab(tab.configuration)
|
|
697
|
+
: null;
|
|
698
|
+
// But NO record tab — docked included — may be consumed as the
|
|
699
|
+
// replaceable nav temp tab: the next nav click must never silently
|
|
700
|
+
// destroy an open record.
|
|
701
|
+
this.workspaceManager.TempTabConsumptionFilter = this.resolvedRecordOpenStyle === 'records'
|
|
702
|
+
? (tab) => !IsRecordsTabConfiguration(tab.configuration)
|
|
703
|
+
: null;
|
|
704
|
+
}
|
|
642
705
|
get ShowSearchBar() {
|
|
643
706
|
return this.chromeFlags.searchBar;
|
|
644
707
|
}
|
|
@@ -859,6 +922,15 @@ export class ShellComponent extends BaseAngularComponent {
|
|
|
859
922
|
await InstanceConfigEngine.Instance.Config(false).catch(() => {
|
|
860
923
|
LogStatus('InstanceConfigEngine initialization skipped (not critical)');
|
|
861
924
|
});
|
|
925
|
+
// Resolve the record-open style EAGERLY, before workspace initialization.
|
|
926
|
+
// The first workspace configuration emission fires synchronously inside
|
|
927
|
+
// Initialize() below, and everything that partitions tabs between the
|
|
928
|
+
// main layout and the records region reads this style. Resolving it
|
|
929
|
+
// lazily (e.g. in a getter evaluated by change detection) leaves a
|
|
930
|
+
// startup window where a 'classic' deployment runs records-style —
|
|
931
|
+
// wiping saved main layouts on every boot and potentially hiding the
|
|
932
|
+
// main region permanently. This MUST happen here, awaited, first.
|
|
933
|
+
this.resolveRecordOpenStyle();
|
|
862
934
|
// Get current user
|
|
863
935
|
const md = this.ProviderToUse;
|
|
864
936
|
const user = md.CurrentUser;
|
|
@@ -975,10 +1047,13 @@ export class ShellComponent extends BaseAngularComponent {
|
|
|
975
1047
|
return;
|
|
976
1048
|
}
|
|
977
1049
|
}
|
|
978
|
-
//
|
|
1050
|
+
// Bare-root landing: URL names no app and nothing is active yet. Land on the
|
|
1051
|
+
// declared-default app (lowest Application.DefaultSequence — Home ships at -1),
|
|
1052
|
+
// NOT apps[0]: the user-owned Sequence order is a display preference for the
|
|
1053
|
+
// app switcher, and reordering it must never change where a session lands.
|
|
979
1054
|
const currentActiveApp = this.appManager.GetActiveApp();
|
|
980
1055
|
if (!appMatch && !currentActiveApp) {
|
|
981
|
-
await this.
|
|
1056
|
+
await this.openLandingApp(apps);
|
|
982
1057
|
}
|
|
983
1058
|
}));
|
|
984
1059
|
// Subscribe to tab open requests from TabService
|
|
@@ -1004,8 +1079,20 @@ export class ShellComponent extends BaseAngularComponent {
|
|
|
1004
1079
|
// Subscribe to workspace configuration changes to sync URL and active app
|
|
1005
1080
|
this.subscriptions.push(this.workspaceManager.Configuration.subscribe(async (config) => {
|
|
1006
1081
|
if (config && this.initialized) {
|
|
1082
|
+
this.latestSyncedConfig = config;
|
|
1007
1083
|
// Sync active app with active tab's application
|
|
1008
1084
|
await this.syncActiveAppWithTab(config);
|
|
1085
|
+
// STALENESS GUARD: rapid multi-step flows (e.g. the origin crumb's
|
|
1086
|
+
// apply-params-then-activate) emit several configurations in one
|
|
1087
|
+
// tick, and each handler suspends at the await above. A handler
|
|
1088
|
+
// resuming with an OLD snapshot must NOT sync the URL: it would
|
|
1089
|
+
// navigate the browser to the previous active tab's URL, and
|
|
1090
|
+
// syncWorkspaceWithUrl would then make that stale URL real by
|
|
1091
|
+
// re-activating its tab (the "crumb click bounces back to the
|
|
1092
|
+
// record" bug). Only the newest emission drives URL and title.
|
|
1093
|
+
if (this.latestSyncedConfig !== config) {
|
|
1094
|
+
return;
|
|
1095
|
+
}
|
|
1009
1096
|
this.syncUrlWithWorkspace(config);
|
|
1010
1097
|
// Update browser tab title
|
|
1011
1098
|
this.updateBrowserTitle(config);
|
|
@@ -1158,6 +1245,17 @@ export class ShellComponent extends BaseAngularComponent {
|
|
|
1158
1245
|
// Not a system tab - clear the flag
|
|
1159
1246
|
this.isViewingSystemTab = false;
|
|
1160
1247
|
this.cdr.detectChanges();
|
|
1248
|
+
// Records style: records-REGION tabs are a GLOBAL
|
|
1249
|
+
// surface — viewing one must never flip the user's app context. Without
|
|
1250
|
+
// this guard, resuming a record opened from another app yanked the whole
|
|
1251
|
+
// header to that app (the "clicked Records in AI, landed in Data
|
|
1252
|
+
// Explorer" bug). The Records pill carries the active state; the nav
|
|
1253
|
+
// stays wherever the user is. Records DOCKED to the workspace fall
|
|
1254
|
+
// through: they are ordinary main-layout tabs and DO flip app context.
|
|
1255
|
+
if (this.RecordTabsStyle && IsRecordsRegionTab(activeTab.configuration)) {
|
|
1256
|
+
this.titleService.setContext(this.activeApp?.Name || null, activeTab.title || null);
|
|
1257
|
+
return;
|
|
1258
|
+
}
|
|
1161
1259
|
// Check if active app needs to be updated
|
|
1162
1260
|
const currentActiveApp = this.appManager.GetActiveApp();
|
|
1163
1261
|
if (!UUIDsEqual(currentActiveApp?.ID, tabAppId)) {
|
|
@@ -1284,7 +1382,10 @@ export class ShellComponent extends BaseAngularComponent {
|
|
|
1284
1382
|
const recordId = decodeURIComponent(appRecordMatch[3]);
|
|
1285
1383
|
const compositeKey = new CompositeKey();
|
|
1286
1384
|
compositeKey.SimpleLoadFromURLSegment(recordId);
|
|
1287
|
-
|
|
1385
|
+
// Recreating a closed tab from browser history — the user's CURRENT
|
|
1386
|
+
// page is not where this record came from, so don't stamp it as the
|
|
1387
|
+
// origin (recordSource 'none' = no crumb rather than a false one).
|
|
1388
|
+
this.navigationService.OpenEntityRecord(entityName, compositeKey, { recordSource: 'none' });
|
|
1288
1389
|
return;
|
|
1289
1390
|
}
|
|
1290
1391
|
// Check for app-scoped view URL: /app/:appName/view/:viewId
|
|
@@ -1396,7 +1497,9 @@ export class ShellComponent extends BaseAngularComponent {
|
|
|
1396
1497
|
const recordId = decodeURIComponent(legacyRecordMatch[2]);
|
|
1397
1498
|
const compositeKey = new CompositeKey();
|
|
1398
1499
|
compositeKey.SimpleLoadFromURLSegment(recordId);
|
|
1399
|
-
|
|
1500
|
+
// Same as the app-scoped branch above: history recreation has no
|
|
1501
|
+
// truthful origin — suppress the crumb instead of inventing one.
|
|
1502
|
+
this.navigationService.OpenEntityRecord(entityName, compositeKey, { recordSource: 'none' });
|
|
1400
1503
|
return;
|
|
1401
1504
|
}
|
|
1402
1505
|
// Check for legacy view URL: /resource/view/:viewId
|
|
@@ -2353,13 +2456,15 @@ export class ShellComponent extends BaseAngularComponent {
|
|
|
2353
2456
|
event.stopPropagation();
|
|
2354
2457
|
this.userMenuVisible = !this.userMenuVisible;
|
|
2355
2458
|
if (this.userMenuVisible) {
|
|
2356
|
-
// Close menu when clicking outside
|
|
2459
|
+
// Close menu when clicking outside. CAPTURE phase so clicks whose
|
|
2460
|
+
// bubbling something stopped (e.g. the origin crumb's GL-focus
|
|
2461
|
+
// stoppers) still dismiss the menu.
|
|
2357
2462
|
const closeHandler = () => {
|
|
2358
2463
|
this.userMenuVisible = false;
|
|
2359
|
-
document.removeEventListener('click', closeHandler);
|
|
2464
|
+
document.removeEventListener('click', closeHandler, true);
|
|
2360
2465
|
};
|
|
2361
2466
|
setTimeout(() => {
|
|
2362
|
-
document.addEventListener('click', closeHandler);
|
|
2467
|
+
document.addEventListener('click', closeHandler, true);
|
|
2363
2468
|
}, 0);
|
|
2364
2469
|
}
|
|
2365
2470
|
}
|
|
@@ -2980,7 +3085,11 @@ export class ShellComponent extends BaseAngularComponent {
|
|
|
2980
3085
|
}
|
|
2981
3086
|
if (!result.EntityName || !result.RecordID)
|
|
2982
3087
|
return;
|
|
2983
|
-
// Entity records — open via NavigationService
|
|
3088
|
+
// Entity records — open via NavigationService. Search is a TRANSIENT
|
|
3089
|
+
// launcher: it dismisses on selection, so the page behind it is the
|
|
3090
|
+
// truthful origin (default capture) — "back" returns the user there.
|
|
3091
|
+
// Contrast the chat overlay, a persistent surface whose true origin is
|
|
3092
|
+
// the conversation (it passes an explicit recordSource).
|
|
2984
3093
|
const pkey = new CompositeKey([{ FieldName: 'ID', Value: result.RecordID }]);
|
|
2985
3094
|
this.navigationService.OpenEntityRecord(result.EntityName, pkey);
|
|
2986
3095
|
}
|
|
@@ -3133,9 +3242,9 @@ export class ShellComponent extends BaseAngularComponent {
|
|
|
3133
3242
|
this.appAccessDialog.show(dialogConfig);
|
|
3134
3243
|
}
|
|
3135
3244
|
else {
|
|
3136
|
-
// Fallback if dialog not available - redirect to
|
|
3137
|
-
console.warn('App access dialog not available, redirecting to
|
|
3138
|
-
this.
|
|
3245
|
+
// Fallback if dialog not available - redirect to a working app
|
|
3246
|
+
console.warn('App access dialog not available, redirecting to fallback app');
|
|
3247
|
+
this.redirectToFallbackApp(availableApps);
|
|
3139
3248
|
}
|
|
3140
3249
|
}, 0);
|
|
3141
3250
|
}
|
|
@@ -3209,7 +3318,7 @@ export class ShellComponent extends BaseAngularComponent {
|
|
|
3209
3318
|
}
|
|
3210
3319
|
else {
|
|
3211
3320
|
// Direct redirect if dialog not available
|
|
3212
|
-
this.
|
|
3321
|
+
this.redirectToFallbackApp(availableApps);
|
|
3213
3322
|
}
|
|
3214
3323
|
}, 0);
|
|
3215
3324
|
}
|
|
@@ -3233,7 +3342,7 @@ export class ShellComponent extends BaseAngularComponent {
|
|
|
3233
3342
|
case 'redirect':
|
|
3234
3343
|
case 'dismissed':
|
|
3235
3344
|
default:
|
|
3236
|
-
this.
|
|
3345
|
+
this.redirectToFallbackApp(availableApps);
|
|
3237
3346
|
break;
|
|
3238
3347
|
}
|
|
3239
3348
|
}
|
|
@@ -3254,13 +3363,13 @@ export class ShellComponent extends BaseAngularComponent {
|
|
|
3254
3363
|
else {
|
|
3255
3364
|
console.error('[ShellComponent] Failed to add application');
|
|
3256
3365
|
this.appAccessDialog?.completeProcessing();
|
|
3257
|
-
this.
|
|
3366
|
+
this.redirectToFallbackApp(this.appManager.GetAllApps());
|
|
3258
3367
|
}
|
|
3259
3368
|
}
|
|
3260
3369
|
catch (error) {
|
|
3261
3370
|
console.error('Error adding app:', error);
|
|
3262
3371
|
this.appAccessDialog?.completeProcessing();
|
|
3263
|
-
this.
|
|
3372
|
+
this.redirectToFallbackApp(this.appManager.GetAllApps());
|
|
3264
3373
|
}
|
|
3265
3374
|
}
|
|
3266
3375
|
/**
|
|
@@ -3275,13 +3384,13 @@ export class ShellComponent extends BaseAngularComponent {
|
|
|
3275
3384
|
}
|
|
3276
3385
|
else {
|
|
3277
3386
|
this.appAccessDialog?.completeProcessing();
|
|
3278
|
-
this.
|
|
3387
|
+
this.redirectToFallbackApp(this.appManager.GetAllApps());
|
|
3279
3388
|
}
|
|
3280
3389
|
}
|
|
3281
3390
|
catch (error) {
|
|
3282
3391
|
console.error('Error enabling app:', error);
|
|
3283
3392
|
this.appAccessDialog?.completeProcessing();
|
|
3284
|
-
this.
|
|
3393
|
+
this.redirectToFallbackApp(this.appManager.GetAllApps());
|
|
3285
3394
|
}
|
|
3286
3395
|
}
|
|
3287
3396
|
/**
|
|
@@ -3309,9 +3418,9 @@ export class ShellComponent extends BaseAngularComponent {
|
|
|
3309
3418
|
this.appAccessDialog?.completeProcessing();
|
|
3310
3419
|
}
|
|
3311
3420
|
else {
|
|
3312
|
-
console.warn(`[ShellComponent] App ${appId} not found after waiting, redirecting to
|
|
3421
|
+
console.warn(`[ShellComponent] App ${appId} not found after waiting, redirecting to fallback app`);
|
|
3313
3422
|
this.appAccessDialog?.completeProcessing();
|
|
3314
|
-
this.
|
|
3423
|
+
this.redirectToFallbackApp(this.appManager.GetAllApps());
|
|
3315
3424
|
}
|
|
3316
3425
|
}
|
|
3317
3426
|
/**
|
|
@@ -3329,23 +3438,71 @@ export class ShellComponent extends BaseAngularComponent {
|
|
|
3329
3438
|
// Update URL to reflect the new app
|
|
3330
3439
|
this.router.navigateByUrl(this.appManager.GetAppUrl(app));
|
|
3331
3440
|
}
|
|
3332
|
-
/**
|
|
3333
|
-
* Redirect to the first available app (fallback)
|
|
3334
|
-
*/
|
|
3335
3441
|
/** Case-insensitive UUID check whether an app is the currently active app. */
|
|
3336
3442
|
IsActiveApp(app) {
|
|
3337
3443
|
return UUIDsEqual(app.ID, this.activeApp?.ID);
|
|
3338
3444
|
}
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3445
|
+
/**
|
|
3446
|
+
* Candidate order for landing and fallback navigation: the declared-default app
|
|
3447
|
+
* first (lowest Application.DefaultSequence — Home ships at -1), then the rest of
|
|
3448
|
+
* the user's apps in their Sequence order.
|
|
3449
|
+
*/
|
|
3450
|
+
landingCandidates(apps) {
|
|
3451
|
+
const landingApp = this.appManager.GetDefaultLandingApp();
|
|
3452
|
+
if (!landingApp) {
|
|
3453
|
+
return [...apps];
|
|
3343
3454
|
}
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3455
|
+
return [landingApp, ...apps.filter(a => !UUIDsEqual(a.ID, landingApp.ID))];
|
|
3456
|
+
}
|
|
3457
|
+
/**
|
|
3458
|
+
* Open the app a bare-root session should land on, falling through to the next
|
|
3459
|
+
* candidate when one cannot open. Each candidate must produce a default tab BEFORE
|
|
3460
|
+
* it is activated — activation hands the session to that app, and an app whose
|
|
3461
|
+
* default tab cannot be built would otherwise become a dead entry point with no way
|
|
3462
|
+
* back (the loading screen never clears and the user cannot navigate away). The
|
|
3463
|
+
* actual tab opening still happens in the ActiveApp subscription.
|
|
3464
|
+
*/
|
|
3465
|
+
async openLandingApp(apps) {
|
|
3466
|
+
for (const candidate of this.landingCandidates(apps)) {
|
|
3467
|
+
try {
|
|
3468
|
+
// CreateDefaultTab() runs TWICE on this path by design: once here as a pure
|
|
3469
|
+
// validation probe (the result is discarded), and again in the ActiveApp
|
|
3470
|
+
// subscription, which opens the tab. That's safe while CreateDefaultTab stays
|
|
3471
|
+
// a side-effect-free builder over cached nav items — if it ever gains side
|
|
3472
|
+
// effects, this validate-then-rebuild pattern must change with it.
|
|
3473
|
+
const tabRequest = await candidate.CreateDefaultTab();
|
|
3474
|
+
if (!tabRequest) {
|
|
3475
|
+
LogError(`Landing app "${candidate.Name}" could not create a default tab, trying next candidate`);
|
|
3476
|
+
continue;
|
|
3477
|
+
}
|
|
3478
|
+
await this.appManager.SetActiveApp(candidate.ID);
|
|
3479
|
+
return;
|
|
3480
|
+
}
|
|
3481
|
+
catch (error) {
|
|
3482
|
+
LogError(`Landing app "${candidate.Name}" failed to activate, trying next candidate:`, undefined, error instanceof Error ? error.message : String(error));
|
|
3483
|
+
}
|
|
3348
3484
|
}
|
|
3485
|
+
// Every candidate failed — surface a terminal dialog instead of hanging the loading screen
|
|
3486
|
+
LogError('No application could be opened as the landing app');
|
|
3487
|
+
await this.handleNoAppsAvailable();
|
|
3488
|
+
}
|
|
3489
|
+
/**
|
|
3490
|
+
* Redirect to a working app (fallback used by the app-access dialogs): declared-default
|
|
3491
|
+
* app first, then the rest of the user's apps in order.
|
|
3492
|
+
*/
|
|
3493
|
+
async redirectToFallbackApp(apps) {
|
|
3494
|
+
for (const app of this.landingCandidates(apps)) {
|
|
3495
|
+
try {
|
|
3496
|
+
await this.navigateToApp(app);
|
|
3497
|
+
return;
|
|
3498
|
+
}
|
|
3499
|
+
catch (error) {
|
|
3500
|
+
LogError(`Fallback navigation to "${app.Name}" failed, trying next candidate:`, undefined, error instanceof Error ? error.message : String(error));
|
|
3501
|
+
}
|
|
3502
|
+
}
|
|
3503
|
+
// No apps available - this shouldn't happen, but handle gracefully
|
|
3504
|
+
this.loading = false;
|
|
3505
|
+
this.cdr.detectChanges();
|
|
3349
3506
|
}
|
|
3350
3507
|
static ɵfac = function ShellComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ShellComponent)(i0.ɵɵdirectiveInject(i1.ApplicationManager), i0.ɵɵdirectiveInject(i1.WorkspaceStateManager), i0.ɵɵdirectiveInject(i1.GoldenLayoutManager), i0.ɵɵdirectiveInject(i1.TabService), i0.ɵɵdirectiveInject(i2.NavigationService), i0.ɵɵdirectiveInject(i3.ActivatedRoute), i0.ɵɵdirectiveInject(i3.Router), i0.ɵɵdirectiveInject(i4.MJAuthBase), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i5.UserAvatarService), i0.ɵɵdirectiveInject(i6.UserSharingCenterDialogService), i0.ɵɵdirectiveInject(i7.AboutDialogService), i0.ɵɵdirectiveInject(i8.ProfileDialogService), i0.ɵɵdirectiveInject(i0.ViewContainerRef), i0.ɵɵdirectiveInject(i2.TitleService), i0.ɵɵdirectiveInject(i2.DeveloperModeService), i0.ɵɵdirectiveInject(i9.StartupValidationService), i0.ɵɵdirectiveInject(i10.CommandPaletteService), i0.ɵɵdirectiveInject(i2.ThemeService), i0.ɵɵdirectiveInject(i2.HomeAppPinService), i0.ɵɵdirectiveInject(i11.FileOpenService), i0.ɵɵdirectiveInject(i12.FeedbackDialogService), i0.ɵɵdirectiveInject(i12.FeedbackService), i0.ɵɵdirectiveInject(i2.ActivityService)); };
|
|
3351
3508
|
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ShellComponent, selectors: [["mj-shell"]], viewQuery: function ShellComponent_Query(rf, ctx) { if (rf & 1) {
|
|
@@ -3359,7 +3516,7 @@ export class ShellComponent extends BaseAngularComponent {
|
|
|
3359
3516
|
i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.appAccessDialog = _t.first);
|
|
3360
3517
|
} }, hostBindings: function ShellComponent_HostBindings(rf, ctx) { if (rf & 1) {
|
|
3361
3518
|
i0.ɵɵlistener("keydown", function ShellComponent_keydown_HostBindingHandler($event) { return ctx.OnGlobalKeydown($event); }, i0.ɵɵresolveDocument)("click", function ShellComponent_click_HostBindingHandler() { return ctx.onDocumentClickCloseActivity(); }, i0.ɵɵresolveDocument);
|
|
3362
|
-
} }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls:
|
|
3519
|
+
} }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature], decls: 52, vars: 29, consts: [["searchInput", ""], ["appAccessDialog", ""], ["omnibarPalette", ""], ["shellSearchComposite", ""], [1, "shell-container"], [1, "shell-header"], ["title", "MemberJunction", 1, "mj-logo"], ["title", "Menu", 1, "hamburger-btn", 3, "click"], [1, "fa-solid", "fa-bars"], [1, "nav-bar-apps", "left-of-switcher"], [3, "activeApp", "isViewingSystemTab", "loadingAppId", "SwitcherStyle", "Provider"], [1, "desktop-nav", 3, "app", "OverflowEnabled"], [1, "desktop-nav"], [1, "spacer"], [1, "header-actions"], [1, "activity-wrap"], ["title", "Notifications", 1, "icon-btn", "desktop-only", "notification-btn"], [1, "nav-bar-apps", "left-of-user-menu"], [1, "user-menu"], [1, "avatar-btn", 3, "click"], ["alt", "User avatar", 1, "avatar-img", 3, "src"], [1, "icon-fallback"], [1, "user-context-menu", 3, "menu-fade", "menu-slide"], [1, "search-popup-overlay"], [1, "search-popup"], [1, "search-popup-content", 3, "click"], ["TextField", "Name", "ValueField", "ID", 1, "search-entity-dropdown", 3, "ngModelChange", "Data", "ngModel"], ["type", "text", "placeholder", "Search...", 1, "mj-input", "search-input", 3, "keydown.enter"], ["title", "Search", 1, "search-submit-btn", 3, "click"], [1, "fa-solid", "fa-search"], [1, "mobile-nav-overlay"], [1, "mobile-nav-drawer"], [1, "mobile-nav-header"], [1, "close-btn", 3, "click"], [1, "fa-solid", "fa-xmark"], [1, "mobile-nav-content"], [1, "mobile-nav-records"], [1, "mobile-nav-footer"], ["title", "Search", 1, "mobile-nav-action", 3, "click"], ["title", "Notifications", 1, "mobile-nav-action"], [3, "firstResourceLoadComplete", "layoutInitError"], [1, "shell-loading"], [3, "result"], [3, "AppSelected"], [3, "SettingsRequested"], ["Placeholder", "Search everything...", 3, "IsOpen", "EnableGlobalShortcut", "ShowPromo", "PromoText"], [1, "pin-progress-backdrop"], [1, "nav-bar-app-btn", 3, "active", "title", "--app-color"], [1, "nav-bar-app-btn", 3, "click", "dblclick", "title"], [3, "appSelected", "activeApp", "isViewingSystemTab", "loadingAppId", "SwitcherStyle", "Provider"], [1, "desktop-nav", 3, "navItemClick", "navItemDismiss", "app", "OverflowEnabled"], ["title", "Search everything", 1, "search-btn"], ["title", "Search everything", 1, "search-btn", 3, "click"], [1, "fa-solid", "fa-magnifying-glass"], [1, "search-btn-text", "desktop-only"], ["aria-hidden", "true", 1, "search-btn-kbd", "desktop-only"], [1, "shell-search-bar", "desktop-only"], ["Placeholder", "Search everything...", 3, "ResultSelected", "SearchSubmitted", "SeeAllRequested", "RecentRecordSelected", "PromoAccepted", "PromoDismissed", "ShowShortcutHint", "EnablePreview", "EnableRecent", "MaxPreviewResults", "ShowPromo", "PromoText"], ["title", "Search everything", 1, "search-btn", "search-btn-mobile", 3, "click"], ["title", "Activity", 1, "icon-btn", "desktop-only", "activity-btn", 3, "click"], [1, "fa-solid", "fa-wave-square"], [1, "activity-badge"], [1, "activity-drawer"], [1, "activity-drawer", 3, "click"], [1, "activity-drawer-head"], ["title", "Clear finished", 1, "activity-clear", 3, "click"], [1, "fa-solid", "fa-broom"], [1, "activity-list"], [1, "activity-row", 3, "is-error"], [1, "activity-row"], [1, "activity-row-icon"], [1, "activity-row-body"], [1, "activity-row-label"], [1, "activity-row-detail"], [1, "activity-bar"], [1, "activity-bar-fill"], ["title", "Notifications", 1, "icon-btn", "desktop-only", "notification-btn", 3, "click"], [1, "fa-solid", "fa-bell"], [1, "notification-badge"], [1, "user-context-menu"], [1, "user-menu-header"], [1, "user-info"], [1, "user-name"], [1, "user-email"], [1, "user-subtitle"], [1, "user-menu-divider"], [1, "user-menu-item", "theme-toggle-item", 3, "title"], [1, "user-menu-item", 3, "disabled", "danger", "color", "title"], [1, "user-menu-item", "theme-toggle-item", 3, "click", "title"], [1, "menu-label"], [1, "theme-toggle-track"], [1, "theme-toggle-thumb"], [1, "theme-toggle-icon"], [1, "user-menu-item", 3, "click", "title"], [1, "menu-shortcut"], [1, "search-popup-overlay", 3, "click"], [1, "mobile-nav-overlay", 3, "click"], [1, "mobile-nav-section-title"], [3, "navItemClick", "navItemDismiss", "app", "OverflowEnabled"], [3, "Activated"], ["title", "Notifications", 1, "mobile-nav-action", 3, "click"], [1, "notification-badge-mobile"], ["size", "large", 3, "text", "textColor", "logoColor", "logoGradient", "animation"], [1, "loading-reset-panel"], [1, "loading-version"], [1, "loading-reset-message"], [1, "fa-regular", "fa-clock"], [1, "loading-reset-hint"], [1, "loading-reset-btn", 3, "click"], [1, "fa-solid", "fa-arrows-rotate"], ["Placeholder", "Search everything...", 3, "IsOpenChange", "ResultSelected", "SeeAllRequested", "PromoAccepted", "PromoDismissed", "IsOpen", "EnableGlobalShortcut", "ShowPromo", "PromoText"], [1, "pin-progress-modal"], ["size", "small", 3, "showText"], [1, "pin-progress-text"]], template: function ShellComponent_Template(rf, ctx) { if (rf & 1) {
|
|
3363
3520
|
const _r1 = i0.ɵɵgetCurrentView();
|
|
3364
3521
|
i0.ɵɵelementStart(0, "div", 4)(1, "header", 5);
|
|
3365
3522
|
i0.ɵɵelement(2, "div", 6);
|
|
@@ -3369,64 +3526,65 @@ export class ShellComponent extends BaseAngularComponent {
|
|
|
3369
3526
|
i0.ɵɵelementEnd();
|
|
3370
3527
|
i0.ɵɵconditionalCreate(5, ShellComponent_Conditional_5_Template, 3, 0, "div", 9);
|
|
3371
3528
|
i0.ɵɵconditionalCreate(6, ShellComponent_Conditional_6_Template, 1, 5, "mj-app-switcher", 10);
|
|
3372
|
-
i0.ɵɵconditionalCreate(7, ShellComponent_Conditional_7_Template,
|
|
3373
|
-
i0.ɵɵelement(
|
|
3374
|
-
i0.ɵɵelementStart(
|
|
3375
|
-
i0.ɵɵconditionalCreate(
|
|
3376
|
-
i0.ɵɵconditionalCreate(
|
|
3377
|
-
i0.ɵɵconditionalCreate(
|
|
3378
|
-
i0.ɵɵconditionalCreate(
|
|
3379
|
-
i0.ɵɵelementStart(
|
|
3380
|
-
i0.ɵɵlistener("click", function
|
|
3381
|
-
i0.ɵɵconditionalCreate(
|
|
3529
|
+
i0.ɵɵconditionalCreate(7, ShellComponent_Conditional_7_Template, 2, 3, "mj-app-nav", 11)(8, ShellComponent_Conditional_8_Template, 1, 0, "mj-records-hub-pill", 12);
|
|
3530
|
+
i0.ɵɵelement(9, "div", 13);
|
|
3531
|
+
i0.ɵɵelementStart(10, "div", 14);
|
|
3532
|
+
i0.ɵɵconditionalCreate(11, ShellComponent_Conditional_11_Template, 2, 1);
|
|
3533
|
+
i0.ɵɵconditionalCreate(12, ShellComponent_Conditional_12_Template, 5, 4, "div", 15);
|
|
3534
|
+
i0.ɵɵconditionalCreate(13, ShellComponent_Conditional_13_Template, 3, 1, "button", 16);
|
|
3535
|
+
i0.ɵɵconditionalCreate(14, ShellComponent_Conditional_14_Template, 3, 0, "div", 17);
|
|
3536
|
+
i0.ɵɵelementStart(15, "div", 18)(16, "button", 19);
|
|
3537
|
+
i0.ɵɵlistener("click", function ShellComponent_Template_button_click_16_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.toggleUserMenu($event)); });
|
|
3538
|
+
i0.ɵɵconditionalCreate(17, ShellComponent_Conditional_17_Template, 1, 1, "img", 20)(18, ShellComponent_Conditional_18_Template, 2, 2, "div", 21);
|
|
3382
3539
|
i0.ɵɵelementEnd();
|
|
3383
|
-
i0.ɵɵconditionalCreate(
|
|
3540
|
+
i0.ɵɵconditionalCreate(19, ShellComponent_Conditional_19_Template, 4, 5, "div", 22);
|
|
3384
3541
|
i0.ɵɵelementEnd()()();
|
|
3385
|
-
i0.ɵɵconditionalCreate(
|
|
3386
|
-
i0.ɵɵelementStart(
|
|
3387
|
-
i0.ɵɵlistener("click", function
|
|
3388
|
-
i0.ɵɵelementStart(
|
|
3389
|
-
i0.ɵɵtwoWayListener("ngModelChange", function
|
|
3542
|
+
i0.ɵɵconditionalCreate(20, ShellComponent_Conditional_20_Template, 1, 0, "div", 23);
|
|
3543
|
+
i0.ɵɵelementStart(21, "div", 24)(22, "div", 25);
|
|
3544
|
+
i0.ɵɵlistener("click", function ShellComponent_Template_div_click_22_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
3545
|
+
i0.ɵɵelementStart(23, "mj-dropdown", 26);
|
|
3546
|
+
i0.ɵɵtwoWayListener("ngModelChange", function ShellComponent_Template_mj_dropdown_ngModelChange_23_listener($event) { i0.ɵɵrestoreView(_r1); i0.ɵɵtwoWayBindingSet(ctx.selectedEntity, $event) || (ctx.selectedEntity = $event); return i0.ɵɵresetView($event); });
|
|
3390
3547
|
i0.ɵɵelementEnd();
|
|
3391
|
-
i0.ɵɵelementStart(
|
|
3392
|
-
i0.ɵɵlistener("keydown.enter", function
|
|
3548
|
+
i0.ɵɵelementStart(24, "input", 27, 0);
|
|
3549
|
+
i0.ɵɵlistener("keydown.enter", function ShellComponent_Template_input_keydown_enter_24_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onSearch($event)); });
|
|
3393
3550
|
i0.ɵɵelementEnd();
|
|
3394
|
-
i0.ɵɵelementStart(
|
|
3395
|
-
i0.ɵɵlistener("click", function
|
|
3396
|
-
i0.ɵɵelement(
|
|
3551
|
+
i0.ɵɵelementStart(26, "button", 28);
|
|
3552
|
+
i0.ɵɵlistener("click", function ShellComponent_Template_button_click_26_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onSearch($event)); });
|
|
3553
|
+
i0.ɵɵelement(27, "i", 29);
|
|
3397
3554
|
i0.ɵɵelementEnd()()();
|
|
3398
|
-
i0.ɵɵconditionalCreate(
|
|
3399
|
-
i0.ɵɵelementStart(
|
|
3400
|
-
i0.ɵɵtext(
|
|
3555
|
+
i0.ɵɵconditionalCreate(28, ShellComponent_Conditional_28_Template, 1, 0, "div", 30);
|
|
3556
|
+
i0.ɵɵelementStart(29, "div", 31)(30, "div", 32)(31, "span");
|
|
3557
|
+
i0.ɵɵtext(32, "Navigation");
|
|
3401
3558
|
i0.ɵɵelementEnd();
|
|
3402
|
-
i0.ɵɵelementStart(
|
|
3403
|
-
i0.ɵɵlistener("click", function
|
|
3404
|
-
i0.ɵɵelement(
|
|
3559
|
+
i0.ɵɵelementStart(33, "button", 33);
|
|
3560
|
+
i0.ɵɵlistener("click", function ShellComponent_Template_button_click_33_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.closeMobileNav()); });
|
|
3561
|
+
i0.ɵɵelement(34, "i", 34);
|
|
3405
3562
|
i0.ɵɵelementEnd()();
|
|
3406
|
-
i0.ɵɵconditionalCreate(
|
|
3407
|
-
i0.ɵɵ
|
|
3408
|
-
i0.ɵɵ
|
|
3409
|
-
i0.ɵɵ
|
|
3410
|
-
i0.ɵɵ
|
|
3411
|
-
i0.ɵɵ
|
|
3563
|
+
i0.ɵɵconditionalCreate(35, ShellComponent_Conditional_35_Template, 4, 3, "div", 35);
|
|
3564
|
+
i0.ɵɵconditionalCreate(36, ShellComponent_Conditional_36_Template, 2, 0, "div", 36);
|
|
3565
|
+
i0.ɵɵelementStart(37, "div", 37)(38, "button", 38);
|
|
3566
|
+
i0.ɵɵlistener("click", function ShellComponent_Template_button_click_38_listener() { i0.ɵɵrestoreView(_r1); ctx.toggleSearch(); return i0.ɵɵresetView(ctx.closeMobileNav()); });
|
|
3567
|
+
i0.ɵɵelement(39, "i", 29);
|
|
3568
|
+
i0.ɵɵelementStart(40, "span");
|
|
3569
|
+
i0.ɵɵtext(41, "Search");
|
|
3412
3570
|
i0.ɵɵelementEnd()();
|
|
3413
|
-
i0.ɵɵconditionalCreate(
|
|
3571
|
+
i0.ɵɵconditionalCreate(42, ShellComponent_Conditional_42_Template, 5, 1, "button", 39);
|
|
3414
3572
|
i0.ɵɵelementEnd()();
|
|
3415
|
-
i0.ɵɵelementStart(
|
|
3416
|
-
i0.ɵɵlistener("firstResourceLoadComplete", function
|
|
3573
|
+
i0.ɵɵelementStart(43, "mj-tab-container", 40);
|
|
3574
|
+
i0.ɵɵlistener("firstResourceLoadComplete", function ShellComponent_Template_mj_tab_container_firstResourceLoadComplete_43_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onFirstResourceLoadComplete()); })("layoutInitError", function ShellComponent_Template_mj_tab_container_layoutInitError_43_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.handleLayoutError()); });
|
|
3417
3575
|
i0.ɵɵelementEnd()();
|
|
3418
|
-
i0.ɵɵconditionalCreate(
|
|
3419
|
-
i0.ɵɵelementStart(
|
|
3420
|
-
i0.ɵɵlistener("result", function
|
|
3576
|
+
i0.ɵɵconditionalCreate(44, ShellComponent_Conditional_44_Template, 4, 6, "div", 41);
|
|
3577
|
+
i0.ɵɵelementStart(45, "mj-app-access-dialog", 42, 1);
|
|
3578
|
+
i0.ɵɵlistener("result", function ShellComponent_Template_mj_app_access_dialog_result_45_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onAppAccessDialogResult($event)); });
|
|
3421
3579
|
i0.ɵɵelementEnd();
|
|
3422
|
-
i0.ɵɵelementStart(
|
|
3423
|
-
i0.ɵɵlistener("AppSelected", function
|
|
3580
|
+
i0.ɵɵelementStart(47, "mj-command-palette", 43);
|
|
3581
|
+
i0.ɵɵlistener("AppSelected", function ShellComponent_Template_mj_command_palette_AppSelected_47_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.onAppSwitch($event)); });
|
|
3424
3582
|
i0.ɵɵelementEnd();
|
|
3425
|
-
i0.ɵɵelementStart(
|
|
3426
|
-
i0.ɵɵlistener("SettingsRequested", function
|
|
3583
|
+
i0.ɵɵelementStart(48, "mj-omnibar-palette", 44, 2);
|
|
3584
|
+
i0.ɵɵlistener("SettingsRequested", function ShellComponent_Template_mj_omnibar_palette_SettingsRequested_48_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.OnPaletteSettingsRequested()); });
|
|
3427
3585
|
i0.ɵɵelementEnd();
|
|
3428
|
-
i0.ɵɵconditionalCreate(
|
|
3429
|
-
i0.ɵɵconditionalCreate(
|
|
3586
|
+
i0.ɵɵconditionalCreate(50, ShellComponent_Conditional_50_Template, 1, 4, "mj-search-overlay", 45);
|
|
3587
|
+
i0.ɵɵconditionalCreate(51, ShellComponent_Conditional_51_Template, 5, 2, "div", 46);
|
|
3430
3588
|
} if (rf & 2) {
|
|
3431
3589
|
i0.ɵɵclassProp("hidden", ctx.loading)("tabs-visible", ctx.tabBarVisible);
|
|
3432
3590
|
i0.ɵɵadvance(5);
|
|
@@ -3434,47 +3592,49 @@ export class ShellComponent extends BaseAngularComponent {
|
|
|
3434
3592
|
i0.ɵɵadvance();
|
|
3435
3593
|
i0.ɵɵconditional(!ctx.appSwitchingLocked && ctx.ShowAppSwitcher ? 6 : -1);
|
|
3436
3594
|
i0.ɵɵadvance();
|
|
3437
|
-
i0.ɵɵconditional(ctx.activeApp && ctx.ShowAppNav ? 7 : -1);
|
|
3438
|
-
i0.ɵɵadvance(
|
|
3439
|
-
i0.ɵɵconditional(ctx.ShowSearchBar ?
|
|
3595
|
+
i0.ɵɵconditional(ctx.activeApp && ctx.ShowAppNav ? 7 : ctx.RecordTabsStyle ? 8 : -1);
|
|
3596
|
+
i0.ɵɵadvance(4);
|
|
3597
|
+
i0.ɵɵconditional(ctx.ShowSearchBar ? 11 : -1);
|
|
3440
3598
|
i0.ɵɵadvance();
|
|
3441
|
-
i0.ɵɵconditional(ctx.activityItems.length > 0 ?
|
|
3599
|
+
i0.ɵɵconditional(ctx.activityItems.length > 0 ? 12 : -1);
|
|
3442
3600
|
i0.ɵɵadvance();
|
|
3443
|
-
i0.ɵɵconditional(ctx.ShowNotifications ?
|
|
3601
|
+
i0.ɵɵconditional(ctx.ShowNotifications ? 13 : -1);
|
|
3444
3602
|
i0.ɵɵadvance();
|
|
3445
|
-
i0.ɵɵconditional(ctx.leftOfUserMenuApps.length > 0 ?
|
|
3603
|
+
i0.ɵɵconditional(ctx.leftOfUserMenuApps.length > 0 ? 14 : -1);
|
|
3446
3604
|
i0.ɵɵadvance(3);
|
|
3447
|
-
i0.ɵɵconditional(ctx.userImageURL ?
|
|
3605
|
+
i0.ɵɵconditional(ctx.userImageURL ? 17 : 18);
|
|
3448
3606
|
i0.ɵɵadvance(2);
|
|
3449
|
-
i0.ɵɵconditional(ctx.userMenuVisible ?
|
|
3607
|
+
i0.ɵɵconditional(ctx.userMenuVisible ? 19 : -1);
|
|
3450
3608
|
i0.ɵɵadvance();
|
|
3451
|
-
i0.ɵɵconditional(ctx.isSearchOpen ?
|
|
3609
|
+
i0.ɵɵconditional(ctx.isSearchOpen ? 20 : -1);
|
|
3452
3610
|
i0.ɵɵadvance();
|
|
3453
3611
|
i0.ɵɵclassProp("open", ctx.isSearchOpen);
|
|
3454
3612
|
i0.ɵɵadvance(2);
|
|
3455
3613
|
i0.ɵɵproperty("Data", ctx.searchableEntities);
|
|
3456
3614
|
i0.ɵɵtwoWayProperty("ngModel", ctx.selectedEntity);
|
|
3457
3615
|
i0.ɵɵadvance(5);
|
|
3458
|
-
i0.ɵɵconditional(ctx.mobileNavOpen ?
|
|
3616
|
+
i0.ɵɵconditional(ctx.mobileNavOpen ? 28 : -1);
|
|
3459
3617
|
i0.ɵɵadvance();
|
|
3460
3618
|
i0.ɵɵclassProp("open", ctx.mobileNavOpen);
|
|
3461
3619
|
i0.ɵɵadvance(6);
|
|
3462
|
-
i0.ɵɵconditional(ctx.activeApp && ctx.ShowAppNav ?
|
|
3620
|
+
i0.ɵɵconditional(ctx.activeApp && ctx.ShowAppNav ? 35 : -1);
|
|
3621
|
+
i0.ɵɵadvance();
|
|
3622
|
+
i0.ɵɵconditional(ctx.RecordTabsStyle ? 36 : -1);
|
|
3463
3623
|
i0.ɵɵadvance(6);
|
|
3464
|
-
i0.ɵɵconditional(ctx.ShowNotifications ?
|
|
3624
|
+
i0.ɵɵconditional(ctx.ShowNotifications ? 42 : -1);
|
|
3465
3625
|
i0.ɵɵadvance();
|
|
3466
3626
|
i0.ɵɵclassProp("hide-tab-bar", !ctx.tabBarVisible);
|
|
3467
3627
|
i0.ɵɵadvance();
|
|
3468
|
-
i0.ɵɵconditional(ctx.loading ?
|
|
3628
|
+
i0.ɵɵconditional(ctx.loading ? 44 : -1);
|
|
3469
3629
|
i0.ɵɵadvance(6);
|
|
3470
|
-
i0.ɵɵconditional(ctx.ShowSearchBar && !ctx.UseOmnibar ?
|
|
3630
|
+
i0.ɵɵconditional(ctx.ShowSearchBar && !ctx.UseOmnibar ? 50 : -1);
|
|
3471
3631
|
i0.ɵɵadvance();
|
|
3472
|
-
i0.ɵɵconditional(ctx.PinProgressVisible ?
|
|
3473
|
-
} }, dependencies: [i13.NgControlStatus, i13.NgModel, i14.MJDropdownComponent, i15.LoadingComponent, i16.SearchOverlayComponent, i16.SearchCompositeComponent, i17.AppSwitcherComponent, i18.AppNavComponent, i19.TabContainerComponent, i20.AppAccessDialogComponent, i21.CommandPaletteComponent, i22.OmnibarPaletteComponent], styles: ["[_nghost-%COMP%] {\n display: block;\n height: 100%;\n width: 100%;\n overflow: hidden;\n}\n\n\n\n\n\n\n.mj-logo[_ngcontent-%COMP%] {\n width: var(--mj-logo-width, 32px);\n height: var(--mj-logo-height, 18px);\n background-image: var(--mj-logo-mark);\n background-color: var(--mj-logo-plate-bg, transparent);\n background-repeat: no-repeat;\n background-position: center;\n background-size: contain;\n border-radius: var(--mj-radius-sm, 4px);\n flex-shrink: 0;\n}\n\n.shell-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n overflow: hidden;\n position: relative;\n}\n\n\n\n\n.shell-container.hidden[_ngcontent-%COMP%] {\n visibility: hidden;\n position: absolute;\n pointer-events: none;\n}\n\nmj-tab-container[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n transition: all 0.2s ease-in-out;\n}\n\n\n\nmj-tab-container.hide-tab-bar[_ngcontent-%COMP%] .lm_header {\n display: none;\n}\n\n\n\nmj-tab-container[_ngcontent-%COMP%]:not(.hide-tab-bar) .lm_header {\n opacity: 1;\n max-height: 40px;\n transition: opacity 0.2s ease-in-out, max-height 0.2s ease-in-out;\n}\n\n\n\nmj-tab-container.hide-tab-bar[_ngcontent-%COMP%] .lm_content {\n height: 100% !important;\n}\n\n\n\nmj-tab-container[_ngcontent-%COMP%] .lm_stack {\n transition: all 0.2s ease-in-out;\n}\n\n.shell-header[_ngcontent-%COMP%] {\n height: 60px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n display: flex;\n align-items: center;\n padding: 0 var(--mj-space-4);\n gap: var(--mj-space-4);\n box-shadow: var(--mj-shadow-sm);\n flex-shrink: 0;\n \n\n\n position: relative;\n z-index: 500;\n}\n\n\n\n.nav-bar-apps[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: var(--mj-space-1);\n}\n\n.nav-bar-apps.left-of-switcher[_ngcontent-%COMP%] {\n \n\n \n\n}\n\n.nav-bar-apps.left-of-user-menu[_ngcontent-%COMP%] {\n margin-right: var(--mj-space-2);\n}\n\n.nav-bar-app-btn[_ngcontent-%COMP%] {\n --app-color: var(--mj-text-muted);\n width: 40px;\n height: 40px;\n border-radius: var(--mj-radius-md);\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n font-size: var(--mj-text-lg);\n transition: all var(--mj-transition-fast);\n position: relative;\n}\n\n.nav-bar-app-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n\n\n\n\n.nav-bar-app-btn.active[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n color: var(--mj-brand-primary);\n}\n\n.nav-bar-app-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n transition: transform var(--mj-transition-fast);\n margin-top: var(--mj-space-0-5); \n\n}\n\n.nav-bar-app-btn[_ngcontent-%COMP%]:hover i[_ngcontent-%COMP%] {\n transform: scale(1.1);\n}\n\n.spacer[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n\n\n\n\n\n\n\n@media (min-width: 769px) {\n mj-app-nav.desktop-nav[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n min-width: 0;\n }\n mj-app-nav.desktop-nav[_ngcontent-%COMP%] + .spacer[_ngcontent-%COMP%] {\n flex: 0 0 0px;\n }\n}\n\n.header-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n}\n\n.icon-btn[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n font-size: var(--mj-text-lg);\n transition: background var(--mj-transition-fast);\n}\n\n.icon-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n\n\n\n.nav-bar-app-btn[_ngcontent-%COMP%]:focus-visible, \n.icon-btn[_ngcontent-%COMP%]:focus-visible, \n.hamburger-btn[_ngcontent-%COMP%]:focus-visible, \n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%]:focus-visible {\n outline: 2px solid var(--mj-border-focus);\n outline-offset: 2px;\n}\n\n\n\n\n\n\n.search-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n width: 260px;\n height: 36px;\n padding: 0 var(--mj-space-2-5) 0 var(--mj-space-3-5);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n font-size: var(--mj-text-sm);\n font-family: inherit;\n cursor: pointer;\n transition: var(--mj-transition-colors);\n}\n\n.search-btn[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-border-strong);\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n}\n\n.search-btn[_ngcontent-%COMP%]:focus-visible {\n outline: none;\n border-color: var(--mj-border-focus);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n\n\n\n.search-btn-mobile[_ngcontent-%COMP%] {\n display: none;\n}\n\n\n\n\n.shell-search-bar[_ngcontent-%COMP%] {\n position: relative;\n width: 260px;\n z-index: 99999;\n}\n\n\n\n\n\n.shell-search-bar[_ngcontent-%COMP%] .suggest-dropdown {\n left: auto;\n right: 0;\n width: min(560px, calc(100vw - var(--mj-space-6)));\n}\n\n.search-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: var(--mj-text-sm);\n flex-shrink: 0;\n}\n\n.search-btn[_ngcontent-%COMP%] .search-btn-text[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n text-align: left;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n\n\n\n\n.search-btn[_ngcontent-%COMP%] .search-btn-kbd[_ngcontent-%COMP%] {\n flex-shrink: 0;\n white-space: nowrap;\n font-family: inherit;\n font-size: 10.5px;\n font-weight: var(--mj-font-semibold);\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-strong);\n border-bottom-width: 2px;\n border-radius: 5px;\n padding: 1.5px var(--mj-space-1-5);\n}\n\n\n\n.notification-btn[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.notification-badge[_ngcontent-%COMP%] {\n position: absolute;\n top: 4px;\n right: 4px;\n min-width: 16px;\n height: 16px;\n padding: 0 var(--mj-space-1);\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: var(--mj-font-semibold);\n border-radius: var(--mj-radius-full);\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: var(--mj-leading-none);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.user-menu[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: box-shadow var(--mj-transition-fast), transform var(--mj-transition-fast);\n padding: 0;\n overflow: hidden;\n}\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%]:hover {\n transform: scale(1.05);\n}\n\n\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%] .icon-fallback[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n border: 2px solid var(--mj-border-default);\n background: var(--mj-bg-surface-hover);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: border-color var(--mj-transition-fast);\n}\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%]:hover .icon-fallback[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary);\n}\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%] .icon-fallback[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: var(--mj-text-base);\n}\n\n\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%] .avatar-img[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n object-fit: cover;\n box-shadow: var(--mj-shadow-sm);\n}\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%]:hover .avatar-img[_ngcontent-%COMP%] {\n box-shadow: var(--mj-shadow-md);\n}\n\n\n\n.user-menu-header[_ngcontent-%COMP%] {\n padding: var(--mj-space-3) var(--mj-space-4);\n background: var(--mj-bg-surface-sunken);\n}\n\n.user-menu-header[_ngcontent-%COMP%] .user-info[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-0-5);\n}\n\n.user-menu-header[_ngcontent-%COMP%] .user-name[_ngcontent-%COMP%] {\n font-weight: var(--mj-font-semibold);\n font-size: var(--mj-text-sm);\n color: var(--mj-text-primary);\n}\n\n.user-menu-header[_ngcontent-%COMP%] .user-email[_ngcontent-%COMP%] {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n}\n\n.user-menu-header[_ngcontent-%COMP%] .user-subtitle[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n\n\n.user-context-menu[_ngcontent-%COMP%] {\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: var(--mj-space-2);\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n box-shadow: var(--mj-shadow-lg);\n min-width: 180px;\n z-index: 10000;\n overflow: hidden;\n}\n\n.user-menu-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: var(--mj-space-3);\n padding: var(--mj-space-3) var(--mj-space-4);\n cursor: pointer;\n font-size: var(--mj-text-sm);\n color: var(--mj-text-primary);\n transition: background var(--mj-transition-fast);\n}\n\n.user-menu-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n width: 18px;\n text-align: center;\n color: var(--mj-text-muted);\n font-size: var(--mj-text-sm);\n}\n\n.user-menu-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.user-menu-item.danger[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.user-menu-item.danger[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.user-menu-item.danger[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface-elevated));\n}\n\n.user-menu-divider[_ngcontent-%COMP%] {\n height: 1px;\n background: var(--mj-border-default);\n margin: var(--mj-space-1) 0;\n}\n\n\n\n.user-menu-item.disabled[_ngcontent-%COMP%] {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.user-menu-item.disabled[_ngcontent-%COMP%]:hover {\n background: transparent;\n}\n\n\n\n.theme-toggle-item[_ngcontent-%COMP%] {\n cursor: pointer;\n}\n\n.theme-toggle-track[_ngcontent-%COMP%] {\n position: relative;\n width: 40px;\n height: 22px;\n border-radius: var(--mj-radius-full);\n background: var(--mj-bg-surface-active);\n margin-left: auto;\n transition: background var(--mj-transition-base);\n flex-shrink: 0;\n}\n\n.theme-toggle-track.dark[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n}\n\n.theme-toggle-thumb[_ngcontent-%COMP%] {\n position: absolute;\n top: 2px;\n left: 2px;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n background: var(--mj-bg-surface);\n box-shadow: var(--mj-shadow-sm);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: transform var(--mj-transition-base);\n}\n\n.theme-toggle-track.dark[_ngcontent-%COMP%] .theme-toggle-thumb[_ngcontent-%COMP%] {\n transform: translateX(18px);\n}\n\n.theme-toggle-icon[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--mj-text-muted);\n}\n\n.theme-toggle-track.dark[_ngcontent-%COMP%] .theme-toggle-icon[_ngcontent-%COMP%] {\n color: var(--mj-text-inverse);\n}\n\n\n\n.user-menu-item[_ngcontent-%COMP%] .menu-shortcut[_ngcontent-%COMP%] {\n margin-left: auto;\n font-size: 11px;\n color: var(--mj-text-disabled);\n font-family: monospace;\n}\n\n\n\n.user-context-menu.menu-fade[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_menuFadeIn 0.15s ease-out;\n}\n\n.user-context-menu.menu-slide[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_menuSlideIn 0.2s ease-out;\n}\n\n@keyframes _ngcontent-%COMP%_menuFadeIn {\n from {\n opacity: 0;\n transform: translateY(-8px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes _ngcontent-%COMP%_menuSlideIn {\n from {\n opacity: 0;\n transform: translateY(-16px) scale(0.95);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n}\n\n.shell-loading[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n z-index: 99999;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding-bottom: 15vh;\n background: var(--mj-bg-page);\n}\n\n.loading-version[_ngcontent-%COMP%] {\n margin-top: var(--mj-space-8, 24px);\n font-size: 11px;\n color: var(--mj-text-muted);\n letter-spacing: 0.4px;\n opacity: 0.6;\n user-select: none;\n}\n\n\n\n.loading-reset-panel[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--mj-space-3);\n margin-top: var(--mj-space-10);\n padding: var(--mj-space-8);\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n box-shadow: var(--mj-shadow-md);\n max-width: 420px;\n animation: _ngcontent-%COMP%_resetPanelFadeIn 0.4s ease-out;\n}\n\n.loading-reset-message[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n margin: 0;\n font-size: var(--mj-text-base);\n font-weight: var(--mj-font-semibold);\n color: var(--mj-text-primary);\n}\n\n.loading-reset-message[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: var(--mj-text-lg);\n color: var(--mj-status-warning);\n}\n\n.loading-reset-hint[_ngcontent-%COMP%] {\n margin: 0;\n font-size: var(--mj-text-sm);\n color: var(--mj-text-secondary);\n text-align: center;\n line-height: var(--mj-leading-relaxed);\n}\n\n.loading-reset-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: var(--mj-space-2);\n margin-top: var(--mj-space-3);\n padding: var(--mj-space-3) var(--mj-space-6);\n font-size: var(--mj-text-base);\n font-weight: var(--mj-font-medium);\n font-family: var(--mj-font-family);\n color: var(--mj-text-inverse);\n background: var(--mj-brand-primary);\n border: 1px solid var(--mj-brand-primary);\n border-radius: var(--mj-radius-md);\n cursor: pointer;\n transition: var(--mj-transition-colors);\n}\n\n.loading-reset-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary-hover);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary-hover);\n box-shadow: var(--mj-shadow-md);\n}\n\n.loading-reset-btn[_ngcontent-%COMP%]:active {\n background: var(--mj-brand-primary-active);\n color: var(--mj-text-inverse);\n transform: scale(0.98);\n}\n\n.loading-reset-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: var(--mj-text-sm);\n}\n\n@keyframes _ngcontent-%COMP%_resetPanelFadeIn {\n from {\n opacity: 0;\n transform: translateY(12px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n\n\n.hamburger-btn[_ngcontent-%COMP%] {\n display: none;\n width: 40px;\n height: 40px;\n border-radius: var(--mj-radius-md);\n border: none;\n background: none;\n cursor: pointer;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n font-size: var(--mj-text-xl);\n transition: background var(--mj-transition-fast);\n}\n.hamburger-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n\n\n.mobile-nav-overlay[_ngcontent-%COMP%] {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-overlay);\n z-index: 9998;\n}\n\n\n\n.mobile-nav-drawer[_ngcontent-%COMP%] {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n bottom: 0;\n width: 280px;\n max-width: 85vw;\n background: var(--mj-bg-surface);\n box-shadow: var(--mj-shadow-xl);\n z-index: 9999;\n flex-direction: column;\n transform: translateX(-100%);\n transition: transform var(--mj-transition-slow);\n}\n.mobile-nav-drawer.open[_ngcontent-%COMP%] {\n transform: translateX(0);\n}\n\n.mobile-nav-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--mj-space-4) var(--mj-space-5);\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n}\n.mobile-nav-header[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-weight: var(--mj-font-semibold);\n font-size: var(--mj-text-base);\n color: var(--mj-text-primary);\n}\n.mobile-nav-header[_ngcontent-%COMP%] .close-btn[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n font-size: var(--mj-text-lg);\n transition: background var(--mj-transition-fast);\n}\n.mobile-nav-header[_ngcontent-%COMP%] .close-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-active);\n}\n\n.mobile-nav-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: var(--mj-space-4) 0;\n}\n\n.mobile-nav-section-title[_ngcontent-%COMP%] {\n padding: var(--mj-space-2) var(--mj-space-5);\n font-size: var(--mj-text-xs);\n font-weight: var(--mj-font-semibold);\n color: var(--mj-text-disabled);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.mobile-nav-footer[_ngcontent-%COMP%] {\n border-top: 1px solid var(--mj-border-default);\n padding: var(--mj-space-3) var(--mj-space-4);\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-1);\n}\n\n.mobile-nav-action[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: center;\n gap: var(--mj-space-3);\n padding: var(--mj-space-3) var(--mj-space-4);\n border: none;\n background: none;\n cursor: pointer;\n border-radius: var(--mj-radius-md);\n color: var(--mj-text-secondary);\n font-size: var(--mj-text-sm);\n font-weight: var(--mj-font-medium);\n transition: background var(--mj-transition-fast);\n width: 100%;\n text-align: left;\n}\n.mobile-nav-action[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n.mobile-nav-action[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: var(--mj-text-base);\n width: 20px;\n text-align: center;\n}\n\n\n\n@media (max-width: 768px) {\n .hamburger-btn[_ngcontent-%COMP%] {\n display: flex;\n }\n\n .desktop-nav[_ngcontent-%COMP%] {\n display: none !important;\n }\n\n .desktop-only[_ngcontent-%COMP%] {\n display: none !important;\n }\n\n .mobile-nav-overlay[_ngcontent-%COMP%] {\n display: block;\n }\n\n .mobile-nav-drawer[_ngcontent-%COMP%] {\n display: flex;\n }\n\n .shell-header[_ngcontent-%COMP%] {\n padding: 0 var(--mj-space-3);\n gap: var(--mj-space-2);\n }\n\n \n\n\n\n .header-actions[_ngcontent-%COMP%] {\n flex-direction: row;\n flex-wrap: nowrap;\n }\n .header-actions[_ngcontent-%COMP%] .user-menu[_ngcontent-%COMP%], \n .header-actions[_ngcontent-%COMP%] .nav-bar-apps[_ngcontent-%COMP%], \n .header-actions[_ngcontent-%COMP%] .search-btn[_ngcontent-%COMP%] {\n flex-shrink: 0;\n }\n\n \n\n\n\n\n .search-btn[_ngcontent-%COMP%] {\n display: flex;\n width: 40px;\n height: 40px;\n padding: 0;\n justify-content: center;\n border: none;\n border-radius: 50%;\n background: none;\n }\n .search-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: var(--mj-text-lg);\n }\n .search-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n border: none;\n }\n}\n\n\n\n .settings-fullscreen-window {\n \n\n box-shadow: none !important;\n border: none !important;\n}\n\n .settings-fullscreen-window .k-window-titlebar {\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n padding: var(--mj-space-3) var(--mj-space-4);\n}\n\n .settings-fullscreen-window .k-window-title {\n font-size: var(--mj-text-lg);\n font-weight: var(--mj-font-semibold);\n color: var(--mj-text-primary);\n}\n\n .settings-fullscreen-window .k-window-titlebar-actions {\n gap: var(--mj-space-1);\n}\n\n .settings-fullscreen-window .k-window-titlebar-action {\n width: 32px;\n height: 32px;\n border-radius: var(--mj-radius-md);\n}\n\n .settings-fullscreen-window .k-window-titlebar-action:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n .settings-fullscreen-window .k-window-content {\n padding: 0;\n overflow: auto;\n background: var(--mj-bg-page);\n}\n\n\n\n .settings-fullscreen-window .k-window-titlebar-action[title=\"Minimize\"], \n .settings-fullscreen-window .k-window-titlebar-action[title=\"Maximize\"], \n .settings-fullscreen-window .k-window-titlebar-action .k-i-window-minimize, \n .settings-fullscreen-window .k-window-titlebar-action .k-i-window-maximize, \n .settings-fullscreen-window .k-window-titlebar-action .k-i-window {\n display: none !important;\n}\n\n\n\n\n\n\n\n\n\n\n\n.search-popup-overlay[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-overlay);\n z-index: 9999;\n animation: _ngcontent-%COMP%_fadeIn 0.15s ease;\n}\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n.search-popup[_ngcontent-%COMP%] {\n position: absolute;\n top: 60px; \n\n right: 16px;\n width: 480px;\n max-width: calc(100vw - 32px);\n background: var(--mj-bg-surface-elevated);\n border-radius: var(--mj-radius-lg);\n box-shadow: var(--mj-shadow-xl);\n z-index: 10000;\n opacity: 0;\n transform: translateY(-10px);\n pointer-events: none;\n transition: opacity var(--mj-transition-base), transform var(--mj-transition-base);\n}\n\n.search-popup.open[_ngcontent-%COMP%] {\n opacity: 1;\n transform: translateY(0);\n pointer-events: all;\n}\n\n.search-popup-content[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n padding: var(--mj-space-3);\n}\n\n.search-entity-dropdown[_ngcontent-%COMP%] {\n min-width: 140px;\n max-width: 180px;\n flex-shrink: 0;\n}\n\n.search-input[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n height: 40px;\n padding: var(--mj-space-2) var(--mj-space-3);\n font-size: var(--mj-text-sm);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n outline: none;\n display: block !important;\n box-sizing: border-box;\n}\n\n.search-input[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.search-submit-btn[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n border-radius: var(--mj-radius-md);\n border: none;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: var(--mj-text-base);\n transition: background var(--mj-transition-fast);\n flex-shrink: 0;\n}\n\n.search-submit-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary-hover);\n}\n\n.search-submit-btn[_ngcontent-%COMP%]:active {\n background: var(--mj-brand-primary-hover);\n}\n\n\n\n.notification-badge-mobile[_ngcontent-%COMP%] {\n position: absolute;\n top: 8px;\n right: 8px;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n font-size: 11px;\n font-weight: var(--mj-font-semibold);\n border-radius: var(--mj-radius-full);\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: var(--mj-leading-none);\n box-shadow: var(--mj-shadow-sm);\n}\n\n\n\n@media (max-width: 768px) {\n .search-popup[_ngcontent-%COMP%] {\n top: 60px;\n left: 16px;\n right: 16px;\n width: auto;\n max-width: none;\n }\n\n .search-popup-content[_ngcontent-%COMP%] {\n flex-wrap: wrap;\n }\n\n .search-entity-dropdown[_ngcontent-%COMP%] {\n width: 100%;\n }\n\n .search-input[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n }\n}\n\n\n\n\n\n.pin-progress-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: color-mix(in srgb, var(--mj-text-primary) 40%, transparent);\n z-index: 100000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: _ngcontent-%COMP%_pinBackdropIn 0.2s ease;\n}\n\n@keyframes _ngcontent-%COMP%_pinBackdropIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n.pin-progress-modal[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border-radius: var(--mj-radius-xl);\n padding: var(--mj-space-7) var(--mj-space-10);\n display: flex;\n align-items: center;\n gap: var(--mj-space-4);\n box-shadow: 0 16px 48px color-mix(in srgb, var(--mj-text-primary) 30%, transparent);\n animation: _ngcontent-%COMP%_pinModalIn 0.25s ease;\n}\n\n@keyframes _ngcontent-%COMP%_pinModalIn {\n from { opacity: 0; transform: scale(0.9) translateY(8px); }\n to { opacity: 1; transform: scale(1) translateY(0); }\n}\n\n.pin-progress-text[_ngcontent-%COMP%] {\n font-size: var(--mj-text-sm);\n font-weight: var(--mj-font-medium);\n color: var(--mj-text-secondary);\n white-space: nowrap;\n}\n\n\n\n\n.activity-wrap[_ngcontent-%COMP%] { position: relative; display: inline-flex; }\n.activity-btn[_ngcontent-%COMP%] { position: relative; }\n.activity-btn[_ngcontent-%COMP%] .activity-pulse[_ngcontent-%COMP%] { color: var(--mj-brand-primary); }\n.activity-badge[_ngcontent-%COMP%] {\n position: absolute;\n top: 2px;\n right: 2px;\n min-width: 16px;\n height: 16px;\n padding: 0 var(--mj-space-1);\n border-radius: var(--mj-radius-md);\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: var(--mj-font-bold);\n line-height: 16px;\n text-align: center;\n}\n.activity-drawer[_ngcontent-%COMP%] {\n position: absolute;\n top: calc(100% + 8px);\n right: 0;\n width: 320px;\n max-height: 420px;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n box-shadow: 0 8px 28px color-mix(in srgb, var(--mj-text-primary) 18%, transparent);\n z-index: 1000;\n overflow: hidden;\n}\n.activity-drawer-head[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--mj-space-2-5) var(--mj-space-3);\n font-weight: var(--mj-font-bold);\n font-size: 0.85rem;\n color: var(--mj-text-primary);\n border-bottom: 1px solid var(--mj-border-default);\n}\n.activity-clear[_ngcontent-%COMP%] {\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 0.8rem;\n padding: var(--mj-space-1) var(--mj-space-1-5);\n border-radius: var(--mj-radius-md);\n}\n.activity-clear[_ngcontent-%COMP%]:hover { color: var(--mj-text-primary); background: var(--mj-bg-surface-hover); }\n.activity-list[_ngcontent-%COMP%] { overflow-y: auto; padding: var(--mj-space-1-5); }\n.activity-row[_ngcontent-%COMP%] {\n display: flex;\n gap: var(--mj-space-2-5);\n padding: var(--mj-space-2);\n border-radius: var(--mj-radius-md);\n}\n.activity-row[_ngcontent-%COMP%]:hover { background: var(--mj-bg-surface-hover); }\n.activity-row-icon[_ngcontent-%COMP%] { margin-top: var(--mj-space-0-5); color: var(--mj-brand-primary); font-size: 0.85rem; }\n.activity-row.is-error[_ngcontent-%COMP%] .activity-row-icon[_ngcontent-%COMP%] { color: var(--mj-status-error); }\n.activity-row-body[_ngcontent-%COMP%] { flex: 1; min-width: 0; }\n.activity-row-label[_ngcontent-%COMP%] { font-size: 0.82rem; font-weight: var(--mj-font-semibold); color: var(--mj-text-primary); }\n.activity-row-detail[_ngcontent-%COMP%] { font-size: 0.72rem; color: var(--mj-text-muted); margin-top: var(--mj-space-px); }\n.activity-bar[_ngcontent-%COMP%] {\n margin-top: var(--mj-space-1-5);\n height: 4px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 2px;\n overflow: hidden;\n}\n.activity-bar-fill[_ngcontent-%COMP%] { height: 100%; background: var(--mj-brand-primary); transition: width var(--mj-transition-slow); }"] });
|
|
3632
|
+
i0.ɵɵconditional(ctx.PinProgressVisible ? 51 : -1);
|
|
3633
|
+
} }, dependencies: [i13.NgControlStatus, i13.NgModel, i14.MJDropdownComponent, i15.LoadingComponent, i16.SearchOverlayComponent, i16.SearchCompositeComponent, i17.RecordsHubPillComponent, i18.AppSwitcherComponent, i19.AppNavComponent, i20.TabContainerComponent, i21.AppAccessDialogComponent, i22.CommandPaletteComponent, i23.OmnibarPaletteComponent], styles: ["[_nghost-%COMP%] {\n display: block;\n height: 100%;\n width: 100%;\n overflow: hidden;\n}\n\n\n\n\n\n\n.mj-logo[_ngcontent-%COMP%] {\n width: var(--mj-logo-width, 32px);\n height: var(--mj-logo-height, 18px);\n background-image: var(--mj-logo-mark);\n background-color: var(--mj-logo-plate-bg, transparent);\n background-repeat: no-repeat;\n background-position: center;\n background-size: contain;\n border-radius: var(--mj-radius-sm, 4px);\n flex-shrink: 0;\n}\n\n.shell-container[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n overflow: hidden;\n position: relative;\n}\n\n\n\n\n.shell-container.hidden[_ngcontent-%COMP%] {\n visibility: hidden;\n position: absolute;\n pointer-events: none;\n}\n\nmj-tab-container[_ngcontent-%COMP%] {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n transition: all 0.2s ease-in-out;\n}\n\n\n\n\n\n\nmj-tab-container.hide-tab-bar[_ngcontent-%COMP%] .main-region .lm_header {\n display: none;\n}\n\n\n\nmj-tab-container[_ngcontent-%COMP%]:not(.hide-tab-bar) .main-region .lm_header {\n opacity: 1;\n max-height: 40px;\n transition: opacity 0.2s ease-in-out, max-height 0.2s ease-in-out;\n}\n\n\n\nmj-tab-container.hide-tab-bar[_ngcontent-%COMP%] .main-region .lm_content {\n height: 100% !important;\n}\n\n\n\nmj-tab-container[_ngcontent-%COMP%] .lm_stack {\n transition: all 0.2s ease-in-out;\n}\n\n.shell-header[_ngcontent-%COMP%] {\n height: 60px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n display: flex;\n align-items: center;\n padding: 0 var(--mj-space-4);\n gap: var(--mj-space-4);\n box-shadow: var(--mj-shadow-sm);\n flex-shrink: 0;\n \n\n\n position: relative;\n z-index: 500;\n}\n\n\n\n.nav-bar-apps[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: var(--mj-space-1);\n}\n\n.nav-bar-apps.left-of-switcher[_ngcontent-%COMP%] {\n \n\n \n\n}\n\n.nav-bar-apps.left-of-user-menu[_ngcontent-%COMP%] {\n margin-right: var(--mj-space-2);\n}\n\n.nav-bar-app-btn[_ngcontent-%COMP%] {\n --app-color: var(--mj-text-muted);\n width: 40px;\n height: 40px;\n border-radius: var(--mj-radius-md);\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n font-size: var(--mj-text-lg);\n transition: all var(--mj-transition-fast);\n position: relative;\n}\n\n.nav-bar-app-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n\n\n\n\n.nav-bar-app-btn.active[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n color: var(--mj-brand-primary);\n}\n\n.nav-bar-app-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n transition: transform var(--mj-transition-fast);\n margin-top: var(--mj-space-0-5); \n\n}\n\n.nav-bar-app-btn[_ngcontent-%COMP%]:hover i[_ngcontent-%COMP%] {\n transform: scale(1.1);\n}\n\n.spacer[_ngcontent-%COMP%] {\n flex: 1;\n}\n\n\n\n\n\n\n\n\n@media (min-width: 769px) {\n mj-app-nav.desktop-nav[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n min-width: 0;\n }\n mj-app-nav.desktop-nav[_ngcontent-%COMP%] + .spacer[_ngcontent-%COMP%] {\n flex: 0 0 0px;\n }\n}\n\n.header-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n}\n\n.icon-btn[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n font-size: var(--mj-text-lg);\n transition: background var(--mj-transition-fast);\n}\n\n.icon-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n\n\n\n.nav-bar-app-btn[_ngcontent-%COMP%]:focus-visible, \n.icon-btn[_ngcontent-%COMP%]:focus-visible, \n.hamburger-btn[_ngcontent-%COMP%]:focus-visible, \n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%]:focus-visible {\n outline: 2px solid var(--mj-border-focus);\n outline-offset: 2px;\n}\n\n\n\n\n\n\n.search-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n width: 260px;\n height: 36px;\n padding: 0 var(--mj-space-2-5) 0 var(--mj-space-3-5);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n font-size: var(--mj-text-sm);\n font-family: inherit;\n cursor: pointer;\n transition: var(--mj-transition-colors);\n}\n\n.search-btn[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-border-strong);\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n}\n\n.search-btn[_ngcontent-%COMP%]:focus-visible {\n outline: none;\n border-color: var(--mj-border-focus);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n\n\n\n.search-btn-mobile[_ngcontent-%COMP%] {\n display: none;\n}\n\n\n\n\n.shell-search-bar[_ngcontent-%COMP%] {\n position: relative;\n width: 260px;\n z-index: 99999;\n}\n\n\n\n\n\n.shell-search-bar[_ngcontent-%COMP%] .suggest-dropdown {\n left: auto;\n right: 0;\n width: min(560px, calc(100vw - var(--mj-space-6)));\n}\n\n.search-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: var(--mj-text-sm);\n flex-shrink: 0;\n}\n\n.search-btn[_ngcontent-%COMP%] .search-btn-text[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n text-align: left;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n\n\n\n\n.search-btn[_ngcontent-%COMP%] .search-btn-kbd[_ngcontent-%COMP%] {\n flex-shrink: 0;\n white-space: nowrap;\n font-family: inherit;\n font-size: 10.5px;\n font-weight: var(--mj-font-semibold);\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-strong);\n border-bottom-width: 2px;\n border-radius: 5px;\n padding: 1.5px var(--mj-space-1-5);\n}\n\n\n\n.notification-btn[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.notification-badge[_ngcontent-%COMP%] {\n position: absolute;\n top: 4px;\n right: 4px;\n min-width: 16px;\n height: 16px;\n padding: 0 var(--mj-space-1);\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: var(--mj-font-semibold);\n border-radius: var(--mj-radius-full);\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: var(--mj-leading-none);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.user-menu[_ngcontent-%COMP%] {\n position: relative;\n}\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: box-shadow var(--mj-transition-fast), transform var(--mj-transition-fast);\n padding: 0;\n overflow: hidden;\n}\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%]:hover {\n transform: scale(1.05);\n}\n\n\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%] .icon-fallback[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n border: 2px solid var(--mj-border-default);\n background: var(--mj-bg-surface-hover);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: border-color var(--mj-transition-fast);\n}\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%]:hover .icon-fallback[_ngcontent-%COMP%] {\n border-color: var(--mj-brand-primary);\n}\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%] .icon-fallback[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: var(--mj-text-base);\n}\n\n\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%] .avatar-img[_ngcontent-%COMP%] {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n object-fit: cover;\n box-shadow: var(--mj-shadow-sm);\n}\n\n.user-menu[_ngcontent-%COMP%] .avatar-btn[_ngcontent-%COMP%]:hover .avatar-img[_ngcontent-%COMP%] {\n box-shadow: var(--mj-shadow-md);\n}\n\n\n\n.user-menu-header[_ngcontent-%COMP%] {\n padding: var(--mj-space-3) var(--mj-space-4);\n background: var(--mj-bg-surface-sunken);\n}\n\n.user-menu-header[_ngcontent-%COMP%] .user-info[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-0-5);\n}\n\n.user-menu-header[_ngcontent-%COMP%] .user-name[_ngcontent-%COMP%] {\n font-weight: var(--mj-font-semibold);\n font-size: var(--mj-text-sm);\n color: var(--mj-text-primary);\n}\n\n.user-menu-header[_ngcontent-%COMP%] .user-email[_ngcontent-%COMP%] {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n}\n\n.user-menu-header[_ngcontent-%COMP%] .user-subtitle[_ngcontent-%COMP%] {\n font-size: 11px;\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n\n\n.user-context-menu[_ngcontent-%COMP%] {\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: var(--mj-space-2);\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n box-shadow: var(--mj-shadow-lg);\n min-width: 180px;\n z-index: 10000;\n overflow: hidden;\n}\n\n.user-menu-item[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: var(--mj-space-3);\n padding: var(--mj-space-3) var(--mj-space-4);\n cursor: pointer;\n font-size: var(--mj-text-sm);\n color: var(--mj-text-primary);\n transition: background var(--mj-transition-fast);\n}\n\n.user-menu-item[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n width: 18px;\n text-align: center;\n color: var(--mj-text-muted);\n font-size: var(--mj-text-sm);\n}\n\n.user-menu-item[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.user-menu-item.danger[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.user-menu-item.danger[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.user-menu-item.danger[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface-elevated));\n}\n\n.user-menu-divider[_ngcontent-%COMP%] {\n height: 1px;\n background: var(--mj-border-default);\n margin: var(--mj-space-1) 0;\n}\n\n\n\n.user-menu-item.disabled[_ngcontent-%COMP%] {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.user-menu-item.disabled[_ngcontent-%COMP%]:hover {\n background: transparent;\n}\n\n\n\n.theme-toggle-item[_ngcontent-%COMP%] {\n cursor: pointer;\n}\n\n.theme-toggle-track[_ngcontent-%COMP%] {\n position: relative;\n width: 40px;\n height: 22px;\n border-radius: var(--mj-radius-full);\n background: var(--mj-bg-surface-active);\n margin-left: auto;\n transition: background var(--mj-transition-base);\n flex-shrink: 0;\n}\n\n.theme-toggle-track.dark[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n}\n\n.theme-toggle-thumb[_ngcontent-%COMP%] {\n position: absolute;\n top: 2px;\n left: 2px;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n background: var(--mj-bg-surface);\n box-shadow: var(--mj-shadow-sm);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: transform var(--mj-transition-base);\n}\n\n.theme-toggle-track.dark[_ngcontent-%COMP%] .theme-toggle-thumb[_ngcontent-%COMP%] {\n transform: translateX(18px);\n}\n\n.theme-toggle-icon[_ngcontent-%COMP%] {\n font-size: 10px;\n color: var(--mj-text-muted);\n}\n\n.theme-toggle-track.dark[_ngcontent-%COMP%] .theme-toggle-icon[_ngcontent-%COMP%] {\n color: var(--mj-text-inverse);\n}\n\n\n\n.user-menu-item[_ngcontent-%COMP%] .menu-shortcut[_ngcontent-%COMP%] {\n margin-left: auto;\n font-size: 11px;\n color: var(--mj-text-disabled);\n font-family: monospace;\n}\n\n\n\n.user-context-menu.menu-fade[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_menuFadeIn 0.15s ease-out;\n}\n\n.user-context-menu.menu-slide[_ngcontent-%COMP%] {\n animation: _ngcontent-%COMP%_menuSlideIn 0.2s ease-out;\n}\n\n@keyframes _ngcontent-%COMP%_menuFadeIn {\n from {\n opacity: 0;\n transform: translateY(-8px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes _ngcontent-%COMP%_menuSlideIn {\n from {\n opacity: 0;\n transform: translateY(-16px) scale(0.95);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n}\n\n.shell-loading[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n z-index: 99999;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding-bottom: 15vh;\n background: var(--mj-bg-page);\n}\n\n.loading-version[_ngcontent-%COMP%] {\n margin-top: var(--mj-space-8, 24px);\n font-size: 11px;\n color: var(--mj-text-muted);\n letter-spacing: 0.4px;\n opacity: 0.6;\n user-select: none;\n}\n\n\n\n.loading-reset-panel[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--mj-space-3);\n margin-top: var(--mj-space-10);\n padding: var(--mj-space-8);\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n box-shadow: var(--mj-shadow-md);\n max-width: 420px;\n animation: _ngcontent-%COMP%_resetPanelFadeIn 0.4s ease-out;\n}\n\n.loading-reset-message[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n margin: 0;\n font-size: var(--mj-text-base);\n font-weight: var(--mj-font-semibold);\n color: var(--mj-text-primary);\n}\n\n.loading-reset-message[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: var(--mj-text-lg);\n color: var(--mj-status-warning);\n}\n\n.loading-reset-hint[_ngcontent-%COMP%] {\n margin: 0;\n font-size: var(--mj-text-sm);\n color: var(--mj-text-secondary);\n text-align: center;\n line-height: var(--mj-leading-relaxed);\n}\n\n.loading-reset-btn[_ngcontent-%COMP%] {\n display: inline-flex;\n align-items: center;\n gap: var(--mj-space-2);\n margin-top: var(--mj-space-3);\n padding: var(--mj-space-3) var(--mj-space-6);\n font-size: var(--mj-text-base);\n font-weight: var(--mj-font-medium);\n font-family: var(--mj-font-family);\n color: var(--mj-text-inverse);\n background: var(--mj-brand-primary);\n border: 1px solid var(--mj-brand-primary);\n border-radius: var(--mj-radius-md);\n cursor: pointer;\n transition: var(--mj-transition-colors);\n}\n\n.loading-reset-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary-hover);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary-hover);\n box-shadow: var(--mj-shadow-md);\n}\n\n.loading-reset-btn[_ngcontent-%COMP%]:active {\n background: var(--mj-brand-primary-active);\n color: var(--mj-text-inverse);\n transform: scale(0.98);\n}\n\n.loading-reset-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: var(--mj-text-sm);\n}\n\n@keyframes _ngcontent-%COMP%_resetPanelFadeIn {\n from {\n opacity: 0;\n transform: translateY(12px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n\n\n.hamburger-btn[_ngcontent-%COMP%] {\n display: none;\n width: 40px;\n height: 40px;\n border-radius: var(--mj-radius-md);\n border: none;\n background: none;\n cursor: pointer;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n font-size: var(--mj-text-xl);\n transition: background var(--mj-transition-fast);\n}\n.hamburger-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n\n\n.mobile-nav-overlay[_ngcontent-%COMP%] {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-overlay);\n z-index: 9998;\n}\n\n\n\n.mobile-nav-drawer[_ngcontent-%COMP%] {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n bottom: 0;\n width: 280px;\n max-width: 85vw;\n background: var(--mj-bg-surface);\n box-shadow: var(--mj-shadow-xl);\n z-index: 9999;\n flex-direction: column;\n transform: translateX(-100%);\n transition: transform var(--mj-transition-slow);\n}\n.mobile-nav-drawer.open[_ngcontent-%COMP%] {\n transform: translateX(0);\n}\n\n.mobile-nav-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--mj-space-4) var(--mj-space-5);\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n}\n.mobile-nav-header[_ngcontent-%COMP%] span[_ngcontent-%COMP%] {\n font-weight: var(--mj-font-semibold);\n font-size: var(--mj-text-base);\n color: var(--mj-text-primary);\n}\n.mobile-nav-header[_ngcontent-%COMP%] .close-btn[_ngcontent-%COMP%] {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n font-size: var(--mj-text-lg);\n transition: background var(--mj-transition-fast);\n}\n.mobile-nav-header[_ngcontent-%COMP%] .close-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-active);\n}\n\n.mobile-nav-content[_ngcontent-%COMP%] {\n flex: 1;\n overflow-y: auto;\n padding: var(--mj-space-4) 0;\n}\n\n.mobile-nav-section-title[_ngcontent-%COMP%] {\n padding: var(--mj-space-2) var(--mj-space-5);\n font-size: var(--mj-text-xs);\n font-weight: var(--mj-font-semibold);\n color: var(--mj-text-disabled);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n\n\n\n\n.mobile-nav-records[_ngcontent-%COMP%] {\n padding: var(--mj-space-2) var(--mj-space-3);\n border-top: 1px solid var(--mj-border-default);\n}\n.mobile-nav-records[_ngcontent-%COMP%] .records-pill[_ngcontent-%COMP%] {\n width: 100%;\n min-height: 48px; \n\n justify-content: flex-start;\n}\n\n.mobile-nav-footer[_ngcontent-%COMP%] {\n border-top: 1px solid var(--mj-border-default);\n padding: var(--mj-space-3) var(--mj-space-4);\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-1);\n}\n\n.mobile-nav-action[_ngcontent-%COMP%] {\n position: relative;\n display: flex;\n align-items: center;\n gap: var(--mj-space-3);\n padding: var(--mj-space-3) var(--mj-space-4);\n border: none;\n background: none;\n cursor: pointer;\n border-radius: var(--mj-radius-md);\n color: var(--mj-text-secondary);\n font-size: var(--mj-text-sm);\n font-weight: var(--mj-font-medium);\n transition: background var(--mj-transition-fast);\n width: 100%;\n text-align: left;\n}\n.mobile-nav-action[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n.mobile-nav-action[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: var(--mj-text-base);\n width: 20px;\n text-align: center;\n}\n\n\n\n@media (max-width: 768px) {\n .hamburger-btn[_ngcontent-%COMP%] {\n display: flex;\n }\n\n .desktop-nav[_ngcontent-%COMP%] {\n display: none !important;\n }\n\n .desktop-only[_ngcontent-%COMP%] {\n display: none !important;\n }\n\n .mobile-nav-overlay[_ngcontent-%COMP%] {\n display: block;\n }\n\n .mobile-nav-drawer[_ngcontent-%COMP%] {\n display: flex;\n }\n\n .shell-header[_ngcontent-%COMP%] {\n padding: 0 var(--mj-space-3);\n gap: var(--mj-space-2);\n }\n\n \n\n\n\n .header-actions[_ngcontent-%COMP%] {\n flex-direction: row;\n flex-wrap: nowrap;\n }\n .header-actions[_ngcontent-%COMP%] .user-menu[_ngcontent-%COMP%], \n .header-actions[_ngcontent-%COMP%] .nav-bar-apps[_ngcontent-%COMP%], \n .header-actions[_ngcontent-%COMP%] .search-btn[_ngcontent-%COMP%] {\n flex-shrink: 0;\n }\n\n \n\n\n\n\n .search-btn[_ngcontent-%COMP%] {\n display: flex;\n width: 40px;\n height: 40px;\n padding: 0;\n justify-content: center;\n border: none;\n border-radius: 50%;\n background: none;\n }\n .search-btn[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n font-size: var(--mj-text-lg);\n }\n .search-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n border: none;\n }\n}\n\n\n\n .settings-fullscreen-window {\n \n\n box-shadow: none !important;\n border: none !important;\n}\n\n .settings-fullscreen-window .k-window-titlebar {\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n padding: var(--mj-space-3) var(--mj-space-4);\n}\n\n .settings-fullscreen-window .k-window-title {\n font-size: var(--mj-text-lg);\n font-weight: var(--mj-font-semibold);\n color: var(--mj-text-primary);\n}\n\n .settings-fullscreen-window .k-window-titlebar-actions {\n gap: var(--mj-space-1);\n}\n\n .settings-fullscreen-window .k-window-titlebar-action {\n width: 32px;\n height: 32px;\n border-radius: var(--mj-radius-md);\n}\n\n .settings-fullscreen-window .k-window-titlebar-action:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n .settings-fullscreen-window .k-window-content {\n padding: 0;\n overflow: auto;\n background: var(--mj-bg-page);\n}\n\n\n\n .settings-fullscreen-window .k-window-titlebar-action[title=\"Minimize\"], \n .settings-fullscreen-window .k-window-titlebar-action[title=\"Maximize\"], \n .settings-fullscreen-window .k-window-titlebar-action .k-i-window-minimize, \n .settings-fullscreen-window .k-window-titlebar-action .k-i-window-maximize, \n .settings-fullscreen-window .k-window-titlebar-action .k-i-window {\n display: none !important;\n}\n\n\n\n\n\n\n\n\n\n\n\n.search-popup-overlay[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-overlay);\n z-index: 9999;\n animation: _ngcontent-%COMP%_fadeIn 0.15s ease;\n}\n\n@keyframes _ngcontent-%COMP%_fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n.search-popup[_ngcontent-%COMP%] {\n position: absolute;\n top: 60px; \n\n right: 16px;\n width: 480px;\n max-width: calc(100vw - 32px);\n background: var(--mj-bg-surface-elevated);\n border-radius: var(--mj-radius-lg);\n box-shadow: var(--mj-shadow-xl);\n z-index: 10000;\n opacity: 0;\n transform: translateY(-10px);\n pointer-events: none;\n transition: opacity var(--mj-transition-base), transform var(--mj-transition-base);\n}\n\n.search-popup.open[_ngcontent-%COMP%] {\n opacity: 1;\n transform: translateY(0);\n pointer-events: all;\n}\n\n.search-popup-content[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n padding: var(--mj-space-3);\n}\n\n.search-entity-dropdown[_ngcontent-%COMP%] {\n min-width: 140px;\n max-width: 180px;\n flex-shrink: 0;\n}\n\n.search-input[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n height: 40px;\n padding: var(--mj-space-2) var(--mj-space-3);\n font-size: var(--mj-text-sm);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n outline: none;\n display: block !important;\n box-sizing: border-box;\n}\n\n.search-input[_ngcontent-%COMP%]:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.search-submit-btn[_ngcontent-%COMP%] {\n width: 40px;\n height: 40px;\n border-radius: var(--mj-radius-md);\n border: none;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: var(--mj-text-base);\n transition: background var(--mj-transition-fast);\n flex-shrink: 0;\n}\n\n.search-submit-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-brand-primary-hover);\n}\n\n.search-submit-btn[_ngcontent-%COMP%]:active {\n background: var(--mj-brand-primary-hover);\n}\n\n\n\n.notification-badge-mobile[_ngcontent-%COMP%] {\n position: absolute;\n top: 8px;\n right: 8px;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n font-size: 11px;\n font-weight: var(--mj-font-semibold);\n border-radius: var(--mj-radius-full);\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: var(--mj-leading-none);\n box-shadow: var(--mj-shadow-sm);\n}\n\n\n\n@media (max-width: 768px) {\n .search-popup[_ngcontent-%COMP%] {\n top: 60px;\n left: 16px;\n right: 16px;\n width: auto;\n max-width: none;\n }\n\n .search-popup-content[_ngcontent-%COMP%] {\n flex-wrap: wrap;\n }\n\n .search-entity-dropdown[_ngcontent-%COMP%] {\n width: 100%;\n }\n\n .search-input[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n }\n}\n\n\n\n\n\n.pin-progress-backdrop[_ngcontent-%COMP%] {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: color-mix(in srgb, var(--mj-text-primary) 40%, transparent);\n z-index: 100000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: _ngcontent-%COMP%_pinBackdropIn 0.2s ease;\n}\n\n@keyframes _ngcontent-%COMP%_pinBackdropIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n.pin-progress-modal[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface);\n border-radius: var(--mj-radius-xl);\n padding: var(--mj-space-7) var(--mj-space-10);\n display: flex;\n align-items: center;\n gap: var(--mj-space-4);\n box-shadow: 0 16px 48px color-mix(in srgb, var(--mj-text-primary) 30%, transparent);\n animation: _ngcontent-%COMP%_pinModalIn 0.25s ease;\n}\n\n@keyframes _ngcontent-%COMP%_pinModalIn {\n from { opacity: 0; transform: scale(0.9) translateY(8px); }\n to { opacity: 1; transform: scale(1) translateY(0); }\n}\n\n.pin-progress-text[_ngcontent-%COMP%] {\n font-size: var(--mj-text-sm);\n font-weight: var(--mj-font-medium);\n color: var(--mj-text-secondary);\n white-space: nowrap;\n}\n\n\n\n\n.activity-wrap[_ngcontent-%COMP%] { position: relative; display: inline-flex; }\n.activity-btn[_ngcontent-%COMP%] { position: relative; }\n.activity-btn[_ngcontent-%COMP%] .activity-pulse[_ngcontent-%COMP%] { color: var(--mj-brand-primary); }\n.activity-badge[_ngcontent-%COMP%] {\n position: absolute;\n top: 2px;\n right: 2px;\n min-width: 16px;\n height: 16px;\n padding: 0 var(--mj-space-1);\n border-radius: var(--mj-radius-md);\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: var(--mj-font-bold);\n line-height: 16px;\n text-align: center;\n}\n.activity-drawer[_ngcontent-%COMP%] {\n position: absolute;\n top: calc(100% + 8px);\n right: 0;\n width: 320px;\n max-height: 420px;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n box-shadow: 0 8px 28px color-mix(in srgb, var(--mj-text-primary) 18%, transparent);\n z-index: 1000;\n overflow: hidden;\n}\n.activity-drawer-head[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--mj-space-2-5) var(--mj-space-3);\n font-weight: var(--mj-font-bold);\n font-size: 0.85rem;\n color: var(--mj-text-primary);\n border-bottom: 1px solid var(--mj-border-default);\n}\n.activity-clear[_ngcontent-%COMP%] {\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 0.8rem;\n padding: var(--mj-space-1) var(--mj-space-1-5);\n border-radius: var(--mj-radius-md);\n}\n.activity-clear[_ngcontent-%COMP%]:hover { color: var(--mj-text-primary); background: var(--mj-bg-surface-hover); }\n.activity-list[_ngcontent-%COMP%] { overflow-y: auto; padding: var(--mj-space-1-5); }\n.activity-row[_ngcontent-%COMP%] {\n display: flex;\n gap: var(--mj-space-2-5);\n padding: var(--mj-space-2);\n border-radius: var(--mj-radius-md);\n}\n.activity-row[_ngcontent-%COMP%]:hover { background: var(--mj-bg-surface-hover); }\n.activity-row-icon[_ngcontent-%COMP%] { margin-top: var(--mj-space-0-5); color: var(--mj-brand-primary); font-size: 0.85rem; }\n.activity-row.is-error[_ngcontent-%COMP%] .activity-row-icon[_ngcontent-%COMP%] { color: var(--mj-status-error); }\n.activity-row-body[_ngcontent-%COMP%] { flex: 1; min-width: 0; }\n.activity-row-label[_ngcontent-%COMP%] { font-size: 0.82rem; font-weight: var(--mj-font-semibold); color: var(--mj-text-primary); }\n.activity-row-detail[_ngcontent-%COMP%] { font-size: 0.72rem; color: var(--mj-text-muted); margin-top: var(--mj-space-px); }\n.activity-bar[_ngcontent-%COMP%] {\n margin-top: var(--mj-space-1-5);\n height: 4px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 2px;\n overflow: hidden;\n}\n.activity-bar-fill[_ngcontent-%COMP%] { height: 100%; background: var(--mj-brand-primary); transition: width var(--mj-transition-slow); }"] });
|
|
3474
3634
|
}
|
|
3475
3635
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ShellComponent, [{
|
|
3476
3636
|
type: Component,
|
|
3477
|
-
args: [{ standalone: false, selector: 'mj-shell', template: "<div class=\"shell-container\" [class.hidden]=\"loading\" [class.tabs-visible]=\"tabBarVisible\">\n <!-- Header -->\n <header class=\"shell-header\">\n <!-- MJ Logo -->\n <div class=\"mj-logo\" title=\"MemberJunction\"></div>\n\n <!-- Mobile Hamburger Button -->\n <button class=\"hamburger-btn\" (click)=\"toggleMobileNav()\" title=\"Menu\">\n <i class=\"fa-solid fa-bars\"></i>\n </button>\n\n <!-- Nav Bar Apps: Left of App Switcher -->\n @if (leftOfSwitcherApps.length > 0 && !appSwitchingLocked) {\n <div class=\"nav-bar-apps left-of-switcher\">\n @for (app of leftOfSwitcherApps; track app) {\n <button\n class=\"nav-bar-app-btn\"\n [class.active]=\"IsActiveApp(app)\"\n [attr.aria-current]=\"IsActiveApp(app) ? 'true' : null\"\n [title]=\"app.Name\"\n [style.--app-color]=\"app.GetColor()\"\n (click)=\"onNavBarAppClick(app, $event)\"\n (dblclick)=\"onNavBarAppDblClick(app, $event)\">\n <i [class]=\"app.Icon\"></i>\n </button>\n }\n </div>\n }\n\n <!-- App Switcher (hidden for app-locked sessions, e.g. magic-link, and\n removable per deployment via 'Shell.AppSwitcher.Enabled') -->\n @if (!appSwitchingLocked && ShowAppSwitcher) {\n <mj-app-switcher\n [activeApp]=\"activeApp\"\n [isViewingSystemTab]=\"isViewingSystemTab\"\n [loadingAppId]=\"loadingAppId\"\n [SwitcherStyle]=\"AppSwitcherStyle\"\n [Provider]=\"Provider\"\n (appSelected)=\"onAppSwitch($event)\">\n </mj-app-switcher>\n }\n\n <!-- App Navigation (desktop only; removable per deployment via 'Shell.AppNav.Enabled') -->\n @if (activeApp && ShowAppNav) {\n <mj-app-nav\n class=\"desktop-nav\"\n [app]=\"activeApp\"\n [OverflowEnabled]=\"true\"\n (navItemClick)=\"onNavItemClick($event)\"\n (navItemDismiss)=\"onNavItemDismiss($event)\">\n </mj-app-nav>\n }\n\n <!-- Spacer -->\n <div class=\"spacer\"></div>\n <!-- Actions (activity, notifications, user menu) -->\n <div class=\"header-actions\">\n <!-- Universal Search \u2014 right-anchored with the action cluster, static width\n (2026-07 review consensus: visible when space permits, never resizes).\n Omnibar ON: a button styled as an input \u2014 clicking (or Ctrl/Cmd+K) opens\n the modal palette; typing happens there. Collapses to the icon circle at\n the mobile breakpoint.\n Omnibar OFF: a REAL inline input (mj-search-composite) \u2014 results attach\n beneath it as a suggest dropdown with a \"See all results\" footer. On\n mobile the composite hides and an icon button opens the Spotlight\n overlay instead (same slot, same collapse point). -->\n @if (ShowSearchBar) {\n @if (UseOmnibar) {\n <button class=\"search-btn\" title=\"Search everything\"\n [attr.aria-label]=\"'Search everything (' + OmnibarShortcutLabel + ')'\"\n (click)=\"OnHeaderSearchClick()\">\n <i class=\"fa-solid fa-magnifying-glass\"></i>\n <span class=\"search-btn-text desktop-only\">Search everything</span>\n <kbd class=\"search-btn-kbd desktop-only\" aria-hidden=\"true\">{{ OmnibarShortcutLabel }}</kbd>\n </button>\n } @else {\n <div class=\"shell-search-bar desktop-only\">\n <mj-search-composite\n #shellSearchComposite\n Placeholder=\"Search everything...\"\n [ShowShortcutHint]=\"true\"\n [EnablePreview]=\"ShowSearchPreview\"\n [EnableRecent]=\"true\"\n [MaxPreviewResults]=\"8\"\n [ShowPromo]=\"ShowOmnibarPromo\"\n [PromoText]=\"OmnibarPromoText\"\n (ResultSelected)=\"OnSearchResultSelected($event)\"\n (SearchSubmitted)=\"OnSearchSubmitted($event)\"\n (SeeAllRequested)=\"OnSeeAllSearch($event)\"\n (RecentRecordSelected)=\"OnSearchResultSelected($event)\"\n (PromoAccepted)=\"OnOmnibarPromoAccepted($event)\"\n (PromoDismissed)=\"OnOmnibarPromoDismissed()\">\n </mj-search-composite>\n </div>\n <button class=\"search-btn search-btn-mobile\" title=\"Search everything\"\n [attr.aria-label]=\"'Search everything (' + OmnibarShortcutLabel + ')'\"\n (click)=\"OnHeaderSearchClick()\">\n <i class=\"fa-solid fa-magnifying-glass\"></i>\n </button>\n }\n }\n <!-- Global Activity indicator -->\n @if (activityItems.length > 0) {\n <div class=\"activity-wrap\">\n <button class=\"icon-btn desktop-only activity-btn\" title=\"Activity\" (click)=\"toggleActivity($event)\">\n <i class=\"fa-solid fa-wave-square\" [class.activity-pulse]=\"activityRunningCount > 0\"></i>\n @if (activityRunningCount > 0) {\n <span class=\"activity-badge\">{{ activityRunningCount }}</span>\n }\n </button>\n @if (activityOpen) {\n <div class=\"activity-drawer\" (click)=\"$event.stopPropagation()\">\n <div class=\"activity-drawer-head\">\n <span>Activity</span>\n <button class=\"activity-clear\" (click)=\"clearFinishedActivity()\" title=\"Clear finished\">\n <i class=\"fa-solid fa-broom\"></i>\n </button>\n </div>\n <div class=\"activity-list\">\n @for (a of activityItems; track a.ID) {\n <div class=\"activity-row\" [class.is-error]=\"a.Status === 'error'\">\n <i class=\"activity-row-icon\"\n [class]=\"a.Status === 'running' ? 'fa-solid fa-spinner fa-spin'\n : a.Status === 'error' ? 'fa-solid fa-circle-exclamation'\n : 'fa-solid fa-circle-check'\"></i>\n <div class=\"activity-row-body\">\n <div class=\"activity-row-label\">{{ a.Label }}</div>\n @if (a.Detail) { <div class=\"activity-row-detail\">{{ a.Detail }}</div> }\n @if (a.Status === 'running' && a.Progress != null) {\n <div class=\"activity-bar\"><div class=\"activity-bar-fill\" [style.width.%]=\"a.Progress\"></div></div>\n }\n </div>\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n @if (ShowNotifications) {\n <button class=\"icon-btn desktop-only notification-btn\" title=\"Notifications\" (click)=\"showNotifications()\">\n <i class=\"fa-solid fa-bell\"></i>\n @if (unreadNotificationCount > 0) {\n <span class=\"notification-badge\">\n {{ unreadNotificationCount > 99 ? '99+' : unreadNotificationCount }}\n </span>\n }\n </button>\n }\n <!-- Nav Bar Apps: Left of User Menu -->\n @if (leftOfUserMenuApps.length > 0) {\n <div class=\"nav-bar-apps left-of-user-menu\">\n @for (app of leftOfUserMenuApps; track app) {\n <button\n class=\"nav-bar-app-btn\"\n [class.active]=\"IsActiveApp(app)\"\n [attr.aria-current]=\"IsActiveApp(app) ? 'true' : null\"\n [title]=\"app.Name\"\n [style.--app-color]=\"app.GetColor()\"\n (click)=\"onNavBarAppClick(app, $event)\"\n (dblclick)=\"onNavBarAppDblClick(app, $event)\">\n <i [class]=\"app.Icon\"></i>\n </button>\n }\n </div>\n }\n\n <div class=\"user-menu\">\n <button class=\"avatar-btn\" (click)=\"toggleUserMenu($event)\">\n @if (userImageURL) {\n <img [src]=\"userImageURL\" alt=\"User avatar\" class=\"avatar-img\" />\n } @else {\n <div class=\"icon-fallback\">\n <i [class]=\"userIconClass || 'fa-solid fa-user'\"></i>\n </div>\n }\n </button>\n <!-- User Context Menu (Dynamic) -->\n @if (userMenuVisible) {\n <div class=\"user-context-menu\"\n [class.menu-fade]=\"getUserMenuOptions()?.animationStyle === 'fade'\"\n [class.menu-slide]=\"getUserMenuOptions()?.animationStyle === 'slide'\">\n <!-- User Header -->\n @if (getUserMenuOptions()?.showUserName) {\n <div class=\"user-menu-header\">\n <div class=\"user-info\">\n <span class=\"user-name\">{{ getUserDisplayInfo()?.name || userName }}</span>\n @if (getUserMenuOptions()?.showUserEmail && getUserDisplayInfo()?.email) {\n <span class=\"user-email\">\n {{ getUserDisplayInfo()?.email }}\n </span>\n }\n @if (getUserDisplayInfo()?.subtitle) {\n <span class=\"user-subtitle\">{{ getUserDisplayInfo()?.subtitle }}</span>\n }\n </div>\n </div>\n <div class=\"user-menu-divider\"></div>\n }\n <!-- Dynamic Menu Items -->\n @for (element of userMenuElements; track element) {\n <!-- Divider -->\n @if (isMenuDivider(element)) {\n <div class=\"user-menu-divider\"></div>\n }\n <!-- Menu Item -->\n @if (!isMenuDivider(element)) {\n @if (asMenuItem(element); as item) {\n @if (item.id === 'toggle-theme') {\n <div class=\"user-menu-item theme-toggle-item\"\n [title]=\"item.tooltip || ''\"\n (click)=\"onUserMenuItemClick(item.id)\">\n <i [class]=\"item.icon\"></i>\n <span class=\"menu-label\">{{ item.label }}</span>\n <div class=\"theme-toggle-track\" [class.dark]=\"IsDarkMode\">\n <div class=\"theme-toggle-thumb\">\n <i [class]=\"IsDarkMode ? 'fa-solid fa-moon' : 'fa-solid fa-sun'\" class=\"theme-toggle-icon\"></i>\n </div>\n </div>\n </div>\n } @else {\n <div class=\"user-menu-item\"\n [class.disabled]=\"!item.enabled\"\n [class.danger]=\"item.cssClass === 'danger'\"\n [style.color]=\"item.color || null\"\n [title]=\"item.tooltip || ''\"\n (click)=\"item.enabled && onUserMenuItemClick(item.id)\">\n <i [class]=\"item.icon\"></i>\n <span class=\"menu-label\">{{ item.label }}</span>\n @if (item.shortcut) {\n <span class=\"menu-shortcut\">{{ item.shortcut }}</span>\n }\n </div>\n }\n }\n }\n }\n </div>\n }\n </div>\n </div>\n </header>\n\n <!-- Search Popup -->\n @if (isSearchOpen) {\n <div class=\"search-popup-overlay\" (click)=\"closeSearch()\"></div>\n }\n <div class=\"search-popup\" [class.open]=\"isSearchOpen\">\n <div class=\"search-popup-content\" (click)=\"$event.stopPropagation()\">\n <mj-dropdown\n [Data]=\"searchableEntities\"\n TextField=\"Name\"\n ValueField=\"ID\"\n class=\"search-entity-dropdown\"\n [(ngModel)]=\"selectedEntity\">\n </mj-dropdown>\n <input\n type=\"text\"\n #searchInput\n placeholder=\"Search...\"\n class=\"mj-input search-input\"\n (keydown.enter)=\"onSearch($event)\"\n />\n <button class=\"search-submit-btn\" (click)=\"onSearch($event)\" title=\"Search\">\n <i class=\"fa-solid fa-search\"></i>\n </button>\n </div>\n </div>\n\n <!-- Mobile Navigation Drawer -->\n @if (mobileNavOpen) {\n <div class=\"mobile-nav-overlay\" (click)=\"closeMobileNav()\"></div>\n }\n <div class=\"mobile-nav-drawer\" [class.open]=\"mobileNavOpen\">\n <div class=\"mobile-nav-header\">\n <span>Navigation</span>\n <button class=\"close-btn\" (click)=\"closeMobileNav()\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n @if (activeApp && ShowAppNav) {\n <div class=\"mobile-nav-content\">\n <div class=\"mobile-nav-section-title\">{{ activeApp.Name }}</div>\n <mj-app-nav\n [app]=\"activeApp\"\n [OverflowEnabled]=\"false\"\n (navItemClick)=\"onNavItemClick($event)\"\n (navItemDismiss)=\"onNavItemDismiss($event)\">\n </mj-app-nav>\n </div>\n }\n <div class=\"mobile-nav-footer\">\n <button class=\"mobile-nav-action\" title=\"Search\" (click)=\"toggleSearch(); closeMobileNav()\">\n <i class=\"fa-solid fa-search\"></i>\n <span>Search</span>\n </button>\n @if (ShowNotifications) {\n <button class=\"mobile-nav-action\" title=\"Notifications\" (click)=\"showNotifications(); closeMobileNav()\">\n <i class=\"fa-solid fa-bell\"></i>\n <span>Notifications</span>\n @if (unreadNotificationCount > 0) {\n <span class=\"notification-badge-mobile\">\n {{ unreadNotificationCount > 99 ? '99+' : unreadNotificationCount }}\n </span>\n }\n </button>\n }\n </div>\n </div>\n\n <!-- Tab Container - with dynamic tab bar visibility -->\n <mj-tab-container\n [class.hide-tab-bar]=\"!tabBarVisible\"\n (firstResourceLoadComplete)=\"onFirstResourceLoadComplete()\"\n (layoutInitError)=\"handleLayoutError()\">\n </mj-tab-container>\n</div>\n\n<!-- Loading State -->\n@if (loading) {\n <div class=\"shell-loading\">\n <mj-loading\n [text]=\"currentLoadingText\"\n [textColor]=\"currentLoadingTextColor\"\n [logoColor]=\"currentLoadingColor\"\n [logoGradient]=\"currentLoadingGradient\"\n [animation]=\"currentLoadingAnimation\"\n size=\"large\">\n </mj-loading>\n @if (ShowResetOption) {\n <div class=\"loading-reset-panel\">\n <p class=\"loading-reset-message\">\n <i class=\"fa-regular fa-clock\"></i>\n Taking longer than expected\n </p>\n <p class=\"loading-reset-hint\">\n This can happen after updates or due to cached data issues.\n </p>\n <button class=\"loading-reset-btn\" (click)=\"ResetApplication()\">\n <i class=\"fa-solid fa-arrows-rotate\"></i>\n Reset\n </button>\n </div>\n } @else {\n <div class=\"loading-version\">MemberJunction \u00B7 v{{ MJVersion }}</div>\n }\n </div>\n}\n\n<!-- App Access Error Dialog -->\n<mj-app-access-dialog\n #appAccessDialog\n (result)=\"onAppAccessDialogResult($event)\">\n</mj-app-access-dialog>\n\n<!-- Command Palette -->\n<mj-command-palette (AppSelected)=\"onAppSwitch($event)\"></mj-command-palette>\n\n<!-- Unified command palette (Shell.Omnibar.Enabled) -->\n<mj-omnibar-palette #omnibarPalette (SettingsRequested)=\"OnPaletteSettingsRequested()\"></mj-omnibar-palette>\n\n<!-- Legacy universal search as a Spotlight-style overlay \u2014 omnibar-off MOBILE only\n (on desktop the inline header composite owns the experience; this opens from\n the mobile icon or Ctrl/Cmd+K when the composite isn't visible).\n The shell owns the Ctrl/Cmd+K chord, so the overlay's own global shortcut is off. -->\n@if (ShowSearchBar && !UseOmnibar) {\n <mj-search-overlay\n [(IsOpen)]=\"LegacySearchOpen\"\n Placeholder=\"Search everything...\"\n [EnableGlobalShortcut]=\"false\"\n [ShowPromo]=\"ShowOmnibarPromo\"\n [PromoText]=\"OmnibarPromoText\"\n (ResultSelected)=\"OnOverlayResultSelected($event)\"\n (SeeAllRequested)=\"OnOverlaySeeAll($event)\"\n (PromoAccepted)=\"OnOmnibarPromoAccepted($event)\"\n (PromoDismissed)=\"OnOmnibarPromoDismissed()\">\n </mj-search-overlay>\n}\n\n<!-- Pin Progress Overlay -->\n@if (PinProgressVisible) {\n <div class=\"pin-progress-backdrop\">\n <div class=\"pin-progress-modal\">\n <mj-loading [showText]=\"false\" size=\"small\"></mj-loading>\n <span class=\"pin-progress-text\">{{ PinProgressText }}</span>\n </div>\n </div>\n}\n", styles: [":host {\n display: block;\n height: 100%;\n width: 100%;\n overflow: hidden;\n}\n\n/* MJ Logo - uses design tokens for theme switching & white-labeling.\n Geometry follows --mj-logo-width/-height so a differently-shaped org mark fits;\n --mj-logo-plate-bg is set by the theme engine only when a single-variant logo needs\n a legibility plate in the mode it wasn't designed for (org-theming Phase 4). */\n.mj-logo {\n width: var(--mj-logo-width, 32px);\n height: var(--mj-logo-height, 18px);\n background-image: var(--mj-logo-mark);\n background-color: var(--mj-logo-plate-bg, transparent);\n background-repeat: no-repeat;\n background-position: center;\n background-size: contain;\n border-radius: var(--mj-radius-sm, 4px);\n flex-shrink: 0;\n}\n\n.shell-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n overflow: hidden;\n position: relative;\n}\n\n/* Hide shell container while loading - allows tab container to render and load\n first resource in background while shell loading indicator is visible */\n.shell-container.hidden {\n visibility: hidden;\n position: absolute;\n pointer-events: none;\n}\n\nmj-tab-container {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n transition: all 0.2s ease-in-out;\n}\n\n/* Hide Golden Layout tab headers when only one tab */\nmj-tab-container.hide-tab-bar ::ng-deep .lm_header {\n display: none;\n}\n\n/* Show tab headers when multiple tabs */\nmj-tab-container:not(.hide-tab-bar) ::ng-deep .lm_header {\n opacity: 1;\n max-height: 40px;\n transition: opacity 0.2s ease-in-out, max-height 0.2s ease-in-out;\n}\n\n/* Adjust content area height when tabs hidden */\nmj-tab-container.hide-tab-bar ::ng-deep .lm_content {\n height: 100% !important;\n}\n\n/* Ensure smooth transitions */\nmj-tab-container ::ng-deep .lm_stack {\n transition: all 0.2s ease-in-out;\n}\n\n.shell-header {\n height: 60px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n display: flex;\n align-items: center;\n padding: 0 var(--mj-space-4);\n gap: var(--mj-space-4);\n box-shadow: var(--mj-shadow-sm);\n flex-shrink: 0;\n /* Creates a stacking context so children (search bar z-index: 99999, dropdown)\n are contained within this level. Modal overlays (z-index: 1000+) sit above. */\n position: relative;\n z-index: 500;\n}\n\n/* Nav Bar Apps - permanent app icons in the header */\n.nav-bar-apps {\n display: flex;\n align-items: center;\n gap: var(--mj-space-1);\n}\n\n.nav-bar-apps.left-of-switcher {\n /* No extra margin - header gap handles spacing */\n /* This prevents the app switcher from shifting when icons are hidden */\n}\n\n.nav-bar-apps.left-of-user-menu {\n margin-right: var(--mj-space-2);\n}\n\n.nav-bar-app-btn {\n --app-color: var(--mj-text-muted);\n width: 40px;\n height: 40px;\n border-radius: var(--mj-radius-md);\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n font-size: var(--mj-text-lg);\n transition: all var(--mj-transition-fast);\n position: relative;\n}\n\n.nav-bar-app-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n/* Active = brand-primary (matches nav pills + switcher items); the app's\n metadata color is reserved for identity accents, never state.\n Shared active-tint recipe. */\n.nav-bar-app-btn.active {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n color: var(--mj-brand-primary);\n}\n\n.nav-bar-app-btn i {\n transition: transform var(--mj-transition-fast);\n margin-top: var(--mj-space-0-5); /* Align with app switcher icon */\n}\n\n.nav-bar-app-btn:hover i {\n transform: scale(1.1);\n}\n\n.spacer {\n flex: 1;\n}\n\n/* Priority+ overflow support: on desktop the app nav owns the header's free\n middle space (so it knows exactly how much room its items have) and the\n spacer stands down. On mobile the nav is display:none'd, so the spacer's\n flex: 1 keeps the action cluster right-aligned. When the nav isn't rendered\n at all (app-locked sessions, Shell.AppNav.Enabled off), the sibling selector\n doesn't match and the spacer behaves as before. */\n@media (min-width: 769px) {\n mj-app-nav.desktop-nav {\n flex: 1 1 auto;\n min-width: 0;\n }\n mj-app-nav.desktop-nav + .spacer {\n flex: 0 0 0px;\n }\n}\n\n.header-actions {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n}\n\n.icon-btn {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n font-size: var(--mj-text-lg);\n transition: background var(--mj-transition-fast);\n}\n\n.icon-btn:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n/* Keyboard focus parity for all header controls (the search bar already has\n its own ring at .search-btn:focus-visible). */\n.nav-bar-app-btn:focus-visible,\n.icon-btn:focus-visible,\n.hamburger-btn:focus-visible,\n.user-menu .avatar-btn:focus-visible {\n outline: 2px solid var(--mj-border-focus);\n outline-offset: 2px;\n}\n\n/* Universal search: a static-width bar styled as an input, anchored on the\n right with the action cluster. Deliberately NOT resizable on hover/focus \u2014\n chrome that shifts on interaction was rejected in the 2026-07 review. It's a\n button (typing happens in the overlay it opens), so no focus/caret styling. */\n.search-btn {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n width: 260px;\n height: 36px;\n padding: 0 var(--mj-space-2-5) 0 var(--mj-space-3-5);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n font-size: var(--mj-text-sm);\n font-family: inherit;\n cursor: pointer;\n transition: var(--mj-transition-colors);\n}\n\n.search-btn:hover {\n border-color: var(--mj-border-strong);\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n}\n\n.search-btn:focus-visible {\n outline: none;\n border-color: var(--mj-border-focus);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n/* Omnibar-off mobile trigger: hidden on desktop (the inline composite renders\n instead); the 768px block flips it on as the icon circle. */\n.search-btn-mobile {\n display: none;\n}\n\n/* Omnibar-off desktop: the inline search composite, same slot + width as the\n omnibar bar so the opt-in toggle doesn't move the header. */\n.shell-search-bar {\n position: relative;\n width: 260px;\n z-index: 99999;\n}\n\n/* The suggest dropdown needs more width than its 260px anchor. Pin it to the\n anchor's right edge and let it grow leftward \u2014 the bar is right-anchored, so\n leftward growth stays on screen. */\n.shell-search-bar ::ng-deep .suggest-dropdown {\n left: auto;\n right: 0;\n width: min(560px, calc(100vw - var(--mj-space-6)));\n}\n\n.search-btn i {\n font-size: var(--mj-text-sm);\n flex-shrink: 0;\n}\n\n.search-btn .search-btn-text {\n flex: 1;\n min-width: 0;\n text-align: left;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* kbd chip: deliberately mirrors the omnibar palette's .ob-kbd chrome\n (10.5px / 5px radius / bottom-heavy border) so the affordance and the\n surface it summons read as one system. */\n.search-btn .search-btn-kbd {\n flex-shrink: 0;\n white-space: nowrap;\n font-family: inherit;\n font-size: 10.5px;\n font-weight: var(--mj-font-semibold);\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-strong);\n border-bottom-width: 2px;\n border-radius: 5px;\n padding: 1.5px var(--mj-space-1-5);\n}\n\n/* Notification button with badge */\n.notification-btn {\n position: relative;\n}\n\n.notification-badge {\n position: absolute;\n top: 4px;\n right: 4px;\n min-width: 16px;\n height: 16px;\n padding: 0 var(--mj-space-1);\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: var(--mj-font-semibold);\n border-radius: var(--mj-radius-full);\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: var(--mj-leading-none);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.user-menu {\n position: relative;\n}\n\n.user-menu .avatar-btn {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: box-shadow var(--mj-transition-fast), transform var(--mj-transition-fast);\n padding: 0;\n overflow: hidden;\n}\n\n.user-menu .avatar-btn:hover {\n transform: scale(1.05);\n}\n\n/* Icon fallback styling - shows gray circle with icon */\n.user-menu .avatar-btn .icon-fallback {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n border: 2px solid var(--mj-border-default);\n background: var(--mj-bg-surface-hover);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: border-color var(--mj-transition-fast);\n}\n\n.user-menu .avatar-btn:hover .icon-fallback {\n border-color: var(--mj-brand-primary);\n}\n\n.user-menu .avatar-btn .icon-fallback i {\n color: var(--mj-text-muted);\n font-size: var(--mj-text-base);\n}\n\n/* Avatar image - replaces the gray circle entirely */\n.user-menu .avatar-btn .avatar-img {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n object-fit: cover;\n box-shadow: var(--mj-shadow-sm);\n}\n\n.user-menu .avatar-btn:hover .avatar-img {\n box-shadow: var(--mj-shadow-md);\n}\n\n/* User Menu Header */\n.user-menu-header {\n padding: var(--mj-space-3) var(--mj-space-4);\n background: var(--mj-bg-surface-sunken);\n}\n\n.user-menu-header .user-info {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-0-5);\n}\n\n.user-menu-header .user-name {\n font-weight: var(--mj-font-semibold);\n font-size: var(--mj-text-sm);\n color: var(--mj-text-primary);\n}\n\n.user-menu-header .user-email {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n}\n\n.user-menu-header .user-subtitle {\n font-size: 11px;\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n/* User Context Menu */\n.user-context-menu {\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: var(--mj-space-2);\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n box-shadow: var(--mj-shadow-lg);\n min-width: 180px;\n z-index: 10000;\n overflow: hidden;\n}\n\n.user-menu-item {\n display: flex;\n align-items: center;\n gap: var(--mj-space-3);\n padding: var(--mj-space-3) var(--mj-space-4);\n cursor: pointer;\n font-size: var(--mj-text-sm);\n color: var(--mj-text-primary);\n transition: background var(--mj-transition-fast);\n}\n\n.user-menu-item i {\n width: 18px;\n text-align: center;\n color: var(--mj-text-muted);\n font-size: var(--mj-text-sm);\n}\n\n.user-menu-item:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.user-menu-item.danger {\n color: var(--mj-status-error);\n}\n\n.user-menu-item.danger i {\n color: var(--mj-status-error);\n}\n\n.user-menu-item.danger:hover {\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface-elevated));\n}\n\n.user-menu-divider {\n height: 1px;\n background: var(--mj-border-default);\n margin: var(--mj-space-1) 0;\n}\n\n/* Menu item disabled state */\n.user-menu-item.disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.user-menu-item.disabled:hover {\n background: transparent;\n}\n\n/* Theme Toggle Switch */\n.theme-toggle-item {\n cursor: pointer;\n}\n\n.theme-toggle-track {\n position: relative;\n width: 40px;\n height: 22px;\n border-radius: var(--mj-radius-full);\n background: var(--mj-bg-surface-active);\n margin-left: auto;\n transition: background var(--mj-transition-base);\n flex-shrink: 0;\n}\n\n.theme-toggle-track.dark {\n background: var(--mj-brand-primary);\n}\n\n.theme-toggle-thumb {\n position: absolute;\n top: 2px;\n left: 2px;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n background: var(--mj-bg-surface);\n box-shadow: var(--mj-shadow-sm);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: transform var(--mj-transition-base);\n}\n\n.theme-toggle-track.dark .theme-toggle-thumb {\n transform: translateX(18px);\n}\n\n.theme-toggle-icon {\n font-size: 10px;\n color: var(--mj-text-muted);\n}\n\n.theme-toggle-track.dark .theme-toggle-icon {\n color: var(--mj-text-inverse);\n}\n\n/* Menu shortcut hint */\n.user-menu-item .menu-shortcut {\n margin-left: auto;\n font-size: 11px;\n color: var(--mj-text-disabled);\n font-family: monospace;\n}\n\n/* Menu animations */\n.user-context-menu.menu-fade {\n animation: menuFadeIn 0.15s ease-out;\n}\n\n.user-context-menu.menu-slide {\n animation: menuSlideIn 0.2s ease-out;\n}\n\n@keyframes menuFadeIn {\n from {\n opacity: 0;\n transform: translateY(-8px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes menuSlideIn {\n from {\n opacity: 0;\n transform: translateY(-16px) scale(0.95);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n}\n\n.shell-loading {\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n z-index: 99999;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding-bottom: 15vh;\n background: var(--mj-bg-page);\n}\n\n.loading-version {\n margin-top: var(--mj-space-8, 24px);\n font-size: 11px;\n color: var(--mj-text-muted);\n letter-spacing: 0.4px;\n opacity: 0.6;\n user-select: none;\n}\n\n/* Loading Recovery Reset Panel */\n.loading-reset-panel {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--mj-space-3);\n margin-top: var(--mj-space-10);\n padding: var(--mj-space-8);\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n box-shadow: var(--mj-shadow-md);\n max-width: 420px;\n animation: resetPanelFadeIn 0.4s ease-out;\n}\n\n.loading-reset-message {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n margin: 0;\n font-size: var(--mj-text-base);\n font-weight: var(--mj-font-semibold);\n color: var(--mj-text-primary);\n}\n\n.loading-reset-message i {\n font-size: var(--mj-text-lg);\n color: var(--mj-status-warning);\n}\n\n.loading-reset-hint {\n margin: 0;\n font-size: var(--mj-text-sm);\n color: var(--mj-text-secondary);\n text-align: center;\n line-height: var(--mj-leading-relaxed);\n}\n\n.loading-reset-btn {\n display: inline-flex;\n align-items: center;\n gap: var(--mj-space-2);\n margin-top: var(--mj-space-3);\n padding: var(--mj-space-3) var(--mj-space-6);\n font-size: var(--mj-text-base);\n font-weight: var(--mj-font-medium);\n font-family: var(--mj-font-family);\n color: var(--mj-text-inverse);\n background: var(--mj-brand-primary);\n border: 1px solid var(--mj-brand-primary);\n border-radius: var(--mj-radius-md);\n cursor: pointer;\n transition: var(--mj-transition-colors);\n}\n\n.loading-reset-btn:hover {\n background: var(--mj-brand-primary-hover);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary-hover);\n box-shadow: var(--mj-shadow-md);\n}\n\n.loading-reset-btn:active {\n background: var(--mj-brand-primary-active);\n color: var(--mj-text-inverse);\n transform: scale(0.98);\n}\n\n.loading-reset-btn i {\n font-size: var(--mj-text-sm);\n}\n\n@keyframes resetPanelFadeIn {\n from {\n opacity: 0;\n transform: translateY(12px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n/* Hamburger button - hidden on desktop */\n.hamburger-btn {\n display: none;\n width: 40px;\n height: 40px;\n border-radius: var(--mj-radius-md);\n border: none;\n background: none;\n cursor: pointer;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n font-size: var(--mj-text-xl);\n transition: background var(--mj-transition-fast);\n}\n.hamburger-btn:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n/* Mobile Navigation Overlay */\n.mobile-nav-overlay {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-overlay);\n z-index: 9998;\n}\n\n/* Mobile Navigation Drawer */\n.mobile-nav-drawer {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n bottom: 0;\n width: 280px;\n max-width: 85vw;\n background: var(--mj-bg-surface);\n box-shadow: var(--mj-shadow-xl);\n z-index: 9999;\n flex-direction: column;\n transform: translateX(-100%);\n transition: transform var(--mj-transition-slow);\n}\n.mobile-nav-drawer.open {\n transform: translateX(0);\n}\n\n.mobile-nav-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--mj-space-4) var(--mj-space-5);\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n}\n.mobile-nav-header span {\n font-weight: var(--mj-font-semibold);\n font-size: var(--mj-text-base);\n color: var(--mj-text-primary);\n}\n.mobile-nav-header .close-btn {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n font-size: var(--mj-text-lg);\n transition: background var(--mj-transition-fast);\n}\n.mobile-nav-header .close-btn:hover {\n background: var(--mj-bg-surface-active);\n}\n\n.mobile-nav-content {\n flex: 1;\n overflow-y: auto;\n padding: var(--mj-space-4) 0;\n}\n\n.mobile-nav-section-title {\n padding: var(--mj-space-2) var(--mj-space-5);\n font-size: var(--mj-text-xs);\n font-weight: var(--mj-font-semibold);\n color: var(--mj-text-disabled);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n.mobile-nav-footer {\n border-top: 1px solid var(--mj-border-default);\n padding: var(--mj-space-3) var(--mj-space-4);\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-1);\n}\n\n.mobile-nav-action {\n position: relative;\n display: flex;\n align-items: center;\n gap: var(--mj-space-3);\n padding: var(--mj-space-3) var(--mj-space-4);\n border: none;\n background: none;\n cursor: pointer;\n border-radius: var(--mj-radius-md);\n color: var(--mj-text-secondary);\n font-size: var(--mj-text-sm);\n font-weight: var(--mj-font-medium);\n transition: background var(--mj-transition-fast);\n width: 100%;\n text-align: left;\n}\n.mobile-nav-action:hover {\n background: var(--mj-bg-surface-hover);\n}\n.mobile-nav-action i {\n font-size: var(--mj-text-base);\n width: 20px;\n text-align: center;\n}\n\n/* Mobile Responsive Styles */\n@media (max-width: 768px) {\n .hamburger-btn {\n display: flex;\n }\n\n .desktop-nav {\n display: none !important;\n }\n\n .desktop-only {\n display: none !important;\n }\n\n .mobile-nav-overlay {\n display: block;\n }\n\n .mobile-nav-drawer {\n display: flex;\n }\n\n .shell-header {\n padding: 0 var(--mj-space-3);\n gap: var(--mj-space-2);\n }\n\n /* Keep the right-edge cluster (chat/nav-bar app icons + avatar) on one row.\n Without pinning this, the icons can wrap and the avatar drops onto a second\n line, stacking under the chat icon. */\n .header-actions {\n flex-direction: row;\n flex-wrap: nowrap;\n }\n .header-actions .user-menu,\n .header-actions .nav-bar-apps,\n .header-actions .search-btn {\n flex-shrink: 0;\n }\n\n /* Search bar collapses to the icon-only circle on small viewports \u2014\n the placeholder text + kbd chip are already hidden via .desktop-only.\n The omnibar-off mobile trigger (.search-btn-mobile) becomes visible here;\n its .desktop-only composite sibling is hidden by the rule above. */\n .search-btn {\n display: flex;\n width: 40px;\n height: 40px;\n padding: 0;\n justify-content: center;\n border: none;\n border-radius: 50%;\n background: none;\n }\n .search-btn i {\n font-size: var(--mj-text-lg);\n }\n .search-btn:hover {\n background: var(--mj-bg-surface-hover);\n border: none;\n }\n}\n\n/* Settings Full-Screen Window Styles */\n::ng-deep .settings-fullscreen-window {\n /* Remove window chrome for full-screen feel */\n box-shadow: none !important;\n border: none !important;\n}\n\n::ng-deep .settings-fullscreen-window .k-window-titlebar {\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n padding: var(--mj-space-3) var(--mj-space-4);\n}\n\n::ng-deep .settings-fullscreen-window .k-window-title {\n font-size: var(--mj-text-lg);\n font-weight: var(--mj-font-semibold);\n color: var(--mj-text-primary);\n}\n\n::ng-deep .settings-fullscreen-window .k-window-titlebar-actions {\n gap: var(--mj-space-1);\n}\n\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action {\n width: 32px;\n height: 32px;\n border-radius: var(--mj-radius-md);\n}\n\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n::ng-deep .settings-fullscreen-window .k-window-content {\n padding: 0;\n overflow: auto;\n background: var(--mj-bg-page);\n}\n\n/* Hide minimize/maximize buttons - only show close */\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action[title=\"Minimize\"],\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action[title=\"Maximize\"],\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action .k-i-window-minimize,\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action .k-i-window-maximize,\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action .k-i-window {\n display: none !important;\n}\n\n/* Universal search is a right-anchored bar affordance in header-actions\n (2026-07 design review round 2): both experiences still open as overlays \u2014\n the bar is a trigger, not an inline input. Icon-only under 768px. */\n\n/* ========================================\n SEARCH POPUP\n ======================================== */\n\n.search-popup-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-overlay);\n z-index: 9999;\n animation: fadeIn 0.15s ease;\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n.search-popup {\n position: absolute;\n top: 60px; /* Below header */\n right: 16px;\n width: 480px;\n max-width: calc(100vw - 32px);\n background: var(--mj-bg-surface-elevated);\n border-radius: var(--mj-radius-lg);\n box-shadow: var(--mj-shadow-xl);\n z-index: 10000;\n opacity: 0;\n transform: translateY(-10px);\n pointer-events: none;\n transition: opacity var(--mj-transition-base), transform var(--mj-transition-base);\n}\n\n.search-popup.open {\n opacity: 1;\n transform: translateY(0);\n pointer-events: all;\n}\n\n.search-popup-content {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n padding: var(--mj-space-3);\n}\n\n.search-entity-dropdown {\n min-width: 140px;\n max-width: 180px;\n flex-shrink: 0;\n}\n\n.search-input {\n flex: 1;\n min-width: 0;\n height: 40px;\n padding: var(--mj-space-2) var(--mj-space-3);\n font-size: var(--mj-text-sm);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n outline: none;\n display: block !important;\n box-sizing: border-box;\n}\n\n.search-input:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.search-submit-btn {\n width: 40px;\n height: 40px;\n border-radius: var(--mj-radius-md);\n border: none;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: var(--mj-text-base);\n transition: background var(--mj-transition-fast);\n flex-shrink: 0;\n}\n\n.search-submit-btn:hover {\n background: var(--mj-brand-primary-hover);\n}\n\n.search-submit-btn:active {\n background: var(--mj-brand-primary-hover);\n}\n\n/* Mobile notification badge */\n.notification-badge-mobile {\n position: absolute;\n top: 8px;\n right: 8px;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n font-size: 11px;\n font-weight: var(--mj-font-semibold);\n border-radius: var(--mj-radius-full);\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: var(--mj-leading-none);\n box-shadow: var(--mj-shadow-sm);\n}\n\n/* Mobile-specific search popup adjustments */\n@media (max-width: 768px) {\n .search-popup {\n top: 60px;\n left: 16px;\n right: 16px;\n width: auto;\n max-width: none;\n }\n\n .search-popup-content {\n flex-wrap: wrap;\n }\n\n .search-entity-dropdown {\n width: 100%;\n }\n\n .search-input {\n flex: 1;\n min-width: 0;\n }\n}\n\n/* ========================================\n PIN PROGRESS OVERLAY\n ======================================== */\n.pin-progress-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: color-mix(in srgb, var(--mj-text-primary) 40%, transparent);\n z-index: 100000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: pinBackdropIn 0.2s ease;\n}\n\n@keyframes pinBackdropIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n.pin-progress-modal {\n background: var(--mj-bg-surface);\n border-radius: var(--mj-radius-xl);\n padding: var(--mj-space-7) var(--mj-space-10);\n display: flex;\n align-items: center;\n gap: var(--mj-space-4);\n box-shadow: 0 16px 48px color-mix(in srgb, var(--mj-text-primary) 30%, transparent);\n animation: pinModalIn 0.25s ease;\n}\n\n@keyframes pinModalIn {\n from { opacity: 0; transform: scale(0.9) translateY(8px); }\n to { opacity: 1; transform: scale(1) translateY(0); }\n}\n\n.pin-progress-text {\n font-size: var(--mj-text-sm);\n font-weight: var(--mj-font-medium);\n color: var(--mj-text-secondary);\n white-space: nowrap;\n}\n/* ============================================================\n Global Activity indicator (P3)\n ============================================================ */\n.activity-wrap { position: relative; display: inline-flex; }\n.activity-btn { position: relative; }\n.activity-btn .activity-pulse { color: var(--mj-brand-primary); }\n.activity-badge {\n position: absolute;\n top: 2px;\n right: 2px;\n min-width: 16px;\n height: 16px;\n padding: 0 var(--mj-space-1);\n border-radius: var(--mj-radius-md);\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: var(--mj-font-bold);\n line-height: 16px;\n text-align: center;\n}\n.activity-drawer {\n position: absolute;\n top: calc(100% + 8px);\n right: 0;\n width: 320px;\n max-height: 420px;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n box-shadow: 0 8px 28px color-mix(in srgb, var(--mj-text-primary) 18%, transparent);\n z-index: 1000;\n overflow: hidden;\n}\n.activity-drawer-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--mj-space-2-5) var(--mj-space-3);\n font-weight: var(--mj-font-bold);\n font-size: 0.85rem;\n color: var(--mj-text-primary);\n border-bottom: 1px solid var(--mj-border-default);\n}\n.activity-clear {\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 0.8rem;\n padding: var(--mj-space-1) var(--mj-space-1-5);\n border-radius: var(--mj-radius-md);\n}\n.activity-clear:hover { color: var(--mj-text-primary); background: var(--mj-bg-surface-hover); }\n.activity-list { overflow-y: auto; padding: var(--mj-space-1-5); }\n.activity-row {\n display: flex;\n gap: var(--mj-space-2-5);\n padding: var(--mj-space-2);\n border-radius: var(--mj-radius-md);\n}\n.activity-row:hover { background: var(--mj-bg-surface-hover); }\n.activity-row-icon { margin-top: var(--mj-space-0-5); color: var(--mj-brand-primary); font-size: 0.85rem; }\n.activity-row.is-error .activity-row-icon { color: var(--mj-status-error); }\n.activity-row-body { flex: 1; min-width: 0; }\n.activity-row-label { font-size: 0.82rem; font-weight: var(--mj-font-semibold); color: var(--mj-text-primary); }\n.activity-row-detail { font-size: 0.72rem; color: var(--mj-text-muted); margin-top: var(--mj-space-px); }\n.activity-bar {\n margin-top: var(--mj-space-1-5);\n height: 4px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 2px;\n overflow: hidden;\n}\n.activity-bar-fill { height: 100%; background: var(--mj-brand-primary); transition: width var(--mj-transition-slow); }\n\n"] }]
|
|
3637
|
+
args: [{ standalone: false, selector: 'mj-shell', template: "<div class=\"shell-container\" [class.hidden]=\"loading\" [class.tabs-visible]=\"tabBarVisible\">\n <!-- Header -->\n <header class=\"shell-header\">\n <!-- MJ Logo -->\n <div class=\"mj-logo\" title=\"MemberJunction\"></div>\n\n <!-- Mobile Hamburger Button -->\n <button class=\"hamburger-btn\" (click)=\"toggleMobileNav()\" title=\"Menu\">\n <i class=\"fa-solid fa-bars\"></i>\n </button>\n\n <!-- Nav Bar Apps: Left of App Switcher -->\n @if (leftOfSwitcherApps.length > 0 && !appSwitchingLocked) {\n <div class=\"nav-bar-apps left-of-switcher\">\n @for (app of leftOfSwitcherApps; track app) {\n <button\n class=\"nav-bar-app-btn\"\n [class.active]=\"IsActiveApp(app)\"\n [attr.aria-current]=\"IsActiveApp(app) ? 'true' : null\"\n [title]=\"app.Name\"\n [style.--app-color]=\"app.GetColor()\"\n (click)=\"onNavBarAppClick(app, $event)\"\n (dblclick)=\"onNavBarAppDblClick(app, $event)\">\n <i [class]=\"app.Icon\"></i>\n </button>\n }\n </div>\n }\n\n <!-- App Switcher (hidden for app-locked sessions, e.g. magic-link, and\n removable per deployment via 'Shell.AppSwitcher.Enabled') -->\n @if (!appSwitchingLocked && ShowAppSwitcher) {\n <mj-app-switcher\n [activeApp]=\"activeApp\"\n [isViewingSystemTab]=\"isViewingSystemTab\"\n [loadingAppId]=\"loadingAppId\"\n [SwitcherStyle]=\"AppSwitcherStyle\"\n [Provider]=\"Provider\"\n (appSelected)=\"onAppSwitch($event)\">\n </mj-app-switcher>\n }\n\n <!-- App Navigation (desktop only; removable per deployment via 'Shell.AppNav.Enabled') -->\n @if (activeApp && ShowAppNav) {\n <mj-app-nav\n class=\"desktop-nav\"\n [app]=\"activeApp\"\n [OverflowEnabled]=\"true\"\n (navItemClick)=\"onNavItemClick($event)\"\n (navItemDismiss)=\"onNavItemDismiss($event)\">\n <!-- Records style: persistent Records pill \u2014 projected into the nav\n row's trailing slot so it sits pipe-separated right after the\n app's own items, styled as a nav pill. Appears only while any\n record is open; resumes the last-viewed record on click. -->\n @if (RecordTabsStyle) {\n <mj-records-hub-pill></mj-records-hub-pill>\n }\n </mj-app-nav>\n } @else if (RecordTabsStyle) {\n <!-- Reachability: when the app nav doesn't render (AppNav disabled per\n deployment, or no active app), open records must STILL have a way\n back \u2014 render the pill standalone in the header. -->\n <mj-records-hub-pill class=\"desktop-nav\"></mj-records-hub-pill>\n }\n\n <!-- Spacer -->\n <div class=\"spacer\"></div>\n <!-- Actions (activity, notifications, user menu) -->\n <div class=\"header-actions\">\n <!-- Universal Search \u2014 right-anchored with the action cluster, static width\n (2026-07 review consensus: visible when space permits, never resizes).\n Omnibar ON: a button styled as an input \u2014 clicking (or Ctrl/Cmd+K) opens\n the modal palette; typing happens there. Collapses to the icon circle at\n the mobile breakpoint.\n Omnibar OFF: a REAL inline input (mj-search-composite) \u2014 results attach\n beneath it as a suggest dropdown with a \"See all results\" footer. On\n mobile the composite hides and an icon button opens the Spotlight\n overlay instead (same slot, same collapse point). -->\n @if (ShowSearchBar) {\n @if (UseOmnibar) {\n <button class=\"search-btn\" title=\"Search everything\"\n [attr.aria-label]=\"'Search everything (' + OmnibarShortcutLabel + ')'\"\n (click)=\"OnHeaderSearchClick()\">\n <i class=\"fa-solid fa-magnifying-glass\"></i>\n <span class=\"search-btn-text desktop-only\">Search everything</span>\n <kbd class=\"search-btn-kbd desktop-only\" aria-hidden=\"true\">{{ OmnibarShortcutLabel }}</kbd>\n </button>\n } @else {\n <div class=\"shell-search-bar desktop-only\">\n <mj-search-composite\n #shellSearchComposite\n Placeholder=\"Search everything...\"\n [ShowShortcutHint]=\"true\"\n [EnablePreview]=\"ShowSearchPreview\"\n [EnableRecent]=\"true\"\n [MaxPreviewResults]=\"8\"\n [ShowPromo]=\"ShowOmnibarPromo\"\n [PromoText]=\"OmnibarPromoText\"\n (ResultSelected)=\"OnSearchResultSelected($event)\"\n (SearchSubmitted)=\"OnSearchSubmitted($event)\"\n (SeeAllRequested)=\"OnSeeAllSearch($event)\"\n (RecentRecordSelected)=\"OnSearchResultSelected($event)\"\n (PromoAccepted)=\"OnOmnibarPromoAccepted($event)\"\n (PromoDismissed)=\"OnOmnibarPromoDismissed()\">\n </mj-search-composite>\n </div>\n <button class=\"search-btn search-btn-mobile\" title=\"Search everything\"\n [attr.aria-label]=\"'Search everything (' + OmnibarShortcutLabel + ')'\"\n (click)=\"OnHeaderSearchClick()\">\n <i class=\"fa-solid fa-magnifying-glass\"></i>\n </button>\n }\n }\n <!-- Global Activity indicator -->\n @if (activityItems.length > 0) {\n <div class=\"activity-wrap\">\n <button class=\"icon-btn desktop-only activity-btn\" title=\"Activity\" (click)=\"toggleActivity($event)\">\n <i class=\"fa-solid fa-wave-square\" [class.activity-pulse]=\"activityRunningCount > 0\"></i>\n @if (activityRunningCount > 0) {\n <span class=\"activity-badge\">{{ activityRunningCount }}</span>\n }\n </button>\n @if (activityOpen) {\n <div class=\"activity-drawer\" (click)=\"$event.stopPropagation()\">\n <div class=\"activity-drawer-head\">\n <span>Activity</span>\n <button class=\"activity-clear\" (click)=\"clearFinishedActivity()\" title=\"Clear finished\">\n <i class=\"fa-solid fa-broom\"></i>\n </button>\n </div>\n <div class=\"activity-list\">\n @for (a of activityItems; track a.ID) {\n <div class=\"activity-row\" [class.is-error]=\"a.Status === 'error'\">\n <i class=\"activity-row-icon\"\n [class]=\"a.Status === 'running' ? 'fa-solid fa-spinner fa-spin'\n : a.Status === 'error' ? 'fa-solid fa-circle-exclamation'\n : 'fa-solid fa-circle-check'\"></i>\n <div class=\"activity-row-body\">\n <div class=\"activity-row-label\">{{ a.Label }}</div>\n @if (a.Detail) { <div class=\"activity-row-detail\">{{ a.Detail }}</div> }\n @if (a.Status === 'running' && a.Progress != null) {\n <div class=\"activity-bar\"><div class=\"activity-bar-fill\" [style.width.%]=\"a.Progress\"></div></div>\n }\n </div>\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n @if (ShowNotifications) {\n <button class=\"icon-btn desktop-only notification-btn\" title=\"Notifications\" (click)=\"showNotifications()\">\n <i class=\"fa-solid fa-bell\"></i>\n @if (unreadNotificationCount > 0) {\n <span class=\"notification-badge\">\n {{ unreadNotificationCount > 99 ? '99+' : unreadNotificationCount }}\n </span>\n }\n </button>\n }\n <!-- Nav Bar Apps: Left of User Menu -->\n @if (leftOfUserMenuApps.length > 0) {\n <div class=\"nav-bar-apps left-of-user-menu\">\n @for (app of leftOfUserMenuApps; track app) {\n <button\n class=\"nav-bar-app-btn\"\n [class.active]=\"IsActiveApp(app)\"\n [attr.aria-current]=\"IsActiveApp(app) ? 'true' : null\"\n [title]=\"app.Name\"\n [style.--app-color]=\"app.GetColor()\"\n (click)=\"onNavBarAppClick(app, $event)\"\n (dblclick)=\"onNavBarAppDblClick(app, $event)\">\n <i [class]=\"app.Icon\"></i>\n </button>\n }\n </div>\n }\n\n <div class=\"user-menu\">\n <button class=\"avatar-btn\" (click)=\"toggleUserMenu($event)\">\n @if (userImageURL) {\n <img [src]=\"userImageURL\" alt=\"User avatar\" class=\"avatar-img\" />\n } @else {\n <div class=\"icon-fallback\">\n <i [class]=\"userIconClass || 'fa-solid fa-user'\"></i>\n </div>\n }\n </button>\n <!-- User Context Menu (Dynamic) -->\n @if (userMenuVisible) {\n <div class=\"user-context-menu\"\n [class.menu-fade]=\"getUserMenuOptions()?.animationStyle === 'fade'\"\n [class.menu-slide]=\"getUserMenuOptions()?.animationStyle === 'slide'\">\n <!-- User Header -->\n @if (getUserMenuOptions()?.showUserName) {\n <div class=\"user-menu-header\">\n <div class=\"user-info\">\n <span class=\"user-name\">{{ getUserDisplayInfo()?.name || userName }}</span>\n @if (getUserMenuOptions()?.showUserEmail && getUserDisplayInfo()?.email) {\n <span class=\"user-email\">\n {{ getUserDisplayInfo()?.email }}\n </span>\n }\n @if (getUserDisplayInfo()?.subtitle) {\n <span class=\"user-subtitle\">{{ getUserDisplayInfo()?.subtitle }}</span>\n }\n </div>\n </div>\n <div class=\"user-menu-divider\"></div>\n }\n <!-- Dynamic Menu Items -->\n @for (element of userMenuElements; track element) {\n <!-- Divider -->\n @if (isMenuDivider(element)) {\n <div class=\"user-menu-divider\"></div>\n }\n <!-- Menu Item -->\n @if (!isMenuDivider(element)) {\n @if (asMenuItem(element); as item) {\n @if (item.id === 'toggle-theme') {\n <div class=\"user-menu-item theme-toggle-item\"\n [title]=\"item.tooltip || ''\"\n (click)=\"onUserMenuItemClick(item.id)\">\n <i [class]=\"item.icon\"></i>\n <span class=\"menu-label\">{{ item.label }}</span>\n <div class=\"theme-toggle-track\" [class.dark]=\"IsDarkMode\">\n <div class=\"theme-toggle-thumb\">\n <i [class]=\"IsDarkMode ? 'fa-solid fa-moon' : 'fa-solid fa-sun'\" class=\"theme-toggle-icon\"></i>\n </div>\n </div>\n </div>\n } @else {\n <div class=\"user-menu-item\"\n [class.disabled]=\"!item.enabled\"\n [class.danger]=\"item.cssClass === 'danger'\"\n [style.color]=\"item.color || null\"\n [title]=\"item.tooltip || ''\"\n (click)=\"item.enabled && onUserMenuItemClick(item.id)\">\n <i [class]=\"item.icon\"></i>\n <span class=\"menu-label\">{{ item.label }}</span>\n @if (item.shortcut) {\n <span class=\"menu-shortcut\">{{ item.shortcut }}</span>\n }\n </div>\n }\n }\n }\n }\n </div>\n }\n </div>\n </div>\n </header>\n\n <!-- Search Popup -->\n @if (isSearchOpen) {\n <div class=\"search-popup-overlay\" (click)=\"closeSearch()\"></div>\n }\n <div class=\"search-popup\" [class.open]=\"isSearchOpen\">\n <div class=\"search-popup-content\" (click)=\"$event.stopPropagation()\">\n <mj-dropdown\n [Data]=\"searchableEntities\"\n TextField=\"Name\"\n ValueField=\"ID\"\n class=\"search-entity-dropdown\"\n [(ngModel)]=\"selectedEntity\">\n </mj-dropdown>\n <input\n type=\"text\"\n #searchInput\n placeholder=\"Search...\"\n class=\"mj-input search-input\"\n (keydown.enter)=\"onSearch($event)\"\n />\n <button class=\"search-submit-btn\" (click)=\"onSearch($event)\" title=\"Search\">\n <i class=\"fa-solid fa-search\"></i>\n </button>\n </div>\n </div>\n\n <!-- Mobile Navigation Drawer -->\n @if (mobileNavOpen) {\n <div class=\"mobile-nav-overlay\" (click)=\"closeMobileNav()\"></div>\n }\n <div class=\"mobile-nav-drawer\" [class.open]=\"mobileNavOpen\">\n <div class=\"mobile-nav-header\">\n <span>Navigation</span>\n <button class=\"close-btn\" (click)=\"closeMobileNav()\">\n <i class=\"fa-solid fa-xmark\"></i>\n </button>\n </div>\n @if (activeApp && ShowAppNav) {\n <div class=\"mobile-nav-content\">\n <div class=\"mobile-nav-section-title\">{{ activeApp.Name }}</div>\n <mj-app-nav\n [app]=\"activeApp\"\n [OverflowEnabled]=\"false\"\n (navItemClick)=\"onNavItemClick($event)\"\n (navItemDismiss)=\"onNavItemDismiss($event)\">\n </mj-app-nav>\n </div>\n }\n <!-- Records style: the desktop pill lives in the (mobile-hidden) app nav,\n so the drawer carries its own entry \u2014 without it, open records are\n unreachable on mobile except by re-opening them. Resumes the\n last-viewed record and closes the drawer. -->\n @if (RecordTabsStyle) {\n <div class=\"mobile-nav-records\">\n <mj-records-hub-pill (Activated)=\"closeMobileNav()\"></mj-records-hub-pill>\n </div>\n }\n <div class=\"mobile-nav-footer\">\n <button class=\"mobile-nav-action\" title=\"Search\" (click)=\"toggleSearch(); closeMobileNav()\">\n <i class=\"fa-solid fa-search\"></i>\n <span>Search</span>\n </button>\n @if (ShowNotifications) {\n <button class=\"mobile-nav-action\" title=\"Notifications\" (click)=\"showNotifications(); closeMobileNav()\">\n <i class=\"fa-solid fa-bell\"></i>\n <span>Notifications</span>\n @if (unreadNotificationCount > 0) {\n <span class=\"notification-badge-mobile\">\n {{ unreadNotificationCount > 99 ? '99+' : unreadNotificationCount }}\n </span>\n }\n </button>\n }\n </div>\n </div>\n\n <!-- Tab Container - with dynamic tab bar visibility -->\n <mj-tab-container\n [class.hide-tab-bar]=\"!tabBarVisible\"\n (firstResourceLoadComplete)=\"onFirstResourceLoadComplete()\"\n (layoutInitError)=\"handleLayoutError()\">\n </mj-tab-container>\n</div>\n\n<!-- Loading State -->\n@if (loading) {\n <div class=\"shell-loading\">\n <mj-loading\n [text]=\"currentLoadingText\"\n [textColor]=\"currentLoadingTextColor\"\n [logoColor]=\"currentLoadingColor\"\n [logoGradient]=\"currentLoadingGradient\"\n [animation]=\"currentLoadingAnimation\"\n size=\"large\">\n </mj-loading>\n @if (ShowResetOption) {\n <div class=\"loading-reset-panel\">\n <p class=\"loading-reset-message\">\n <i class=\"fa-regular fa-clock\"></i>\n Taking longer than expected\n </p>\n <p class=\"loading-reset-hint\">\n This can happen after updates or due to cached data issues.\n </p>\n <button class=\"loading-reset-btn\" (click)=\"ResetApplication()\">\n <i class=\"fa-solid fa-arrows-rotate\"></i>\n Reset\n </button>\n </div>\n } @else {\n <div class=\"loading-version\">MemberJunction \u00B7 v{{ MJVersion }}</div>\n }\n </div>\n}\n\n<!-- App Access Error Dialog -->\n<mj-app-access-dialog\n #appAccessDialog\n (result)=\"onAppAccessDialogResult($event)\">\n</mj-app-access-dialog>\n\n<!-- Command Palette -->\n<mj-command-palette (AppSelected)=\"onAppSwitch($event)\"></mj-command-palette>\n\n<!-- Unified command palette (Shell.Omnibar.Enabled) -->\n<mj-omnibar-palette #omnibarPalette (SettingsRequested)=\"OnPaletteSettingsRequested()\"></mj-omnibar-palette>\n\n<!-- Legacy universal search as a Spotlight-style overlay \u2014 omnibar-off MOBILE only\n (on desktop the inline header composite owns the experience; this opens from\n the mobile icon or Ctrl/Cmd+K when the composite isn't visible).\n The shell owns the Ctrl/Cmd+K chord, so the overlay's own global shortcut is off. -->\n@if (ShowSearchBar && !UseOmnibar) {\n <mj-search-overlay\n [(IsOpen)]=\"LegacySearchOpen\"\n Placeholder=\"Search everything...\"\n [EnableGlobalShortcut]=\"false\"\n [ShowPromo]=\"ShowOmnibarPromo\"\n [PromoText]=\"OmnibarPromoText\"\n (ResultSelected)=\"OnOverlayResultSelected($event)\"\n (SeeAllRequested)=\"OnOverlaySeeAll($event)\"\n (PromoAccepted)=\"OnOmnibarPromoAccepted($event)\"\n (PromoDismissed)=\"OnOmnibarPromoDismissed()\">\n </mj-search-overlay>\n}\n\n<!-- Pin Progress Overlay -->\n@if (PinProgressVisible) {\n <div class=\"pin-progress-backdrop\">\n <div class=\"pin-progress-modal\">\n <mj-loading [showText]=\"false\" size=\"small\"></mj-loading>\n <span class=\"pin-progress-text\">{{ PinProgressText }}</span>\n </div>\n </div>\n}\n", styles: [":host {\n display: block;\n height: 100%;\n width: 100%;\n overflow: hidden;\n}\n\n/* MJ Logo - uses design tokens for theme switching & white-labeling.\n Geometry follows --mj-logo-width/-height so a differently-shaped org mark fits;\n --mj-logo-plate-bg is set by the theme engine only when a single-variant logo needs\n a legibility plate in the mode it wasn't designed for (org-theming Phase 4). */\n.mj-logo {\n width: var(--mj-logo-width, 32px);\n height: var(--mj-logo-height, 18px);\n background-image: var(--mj-logo-mark);\n background-color: var(--mj-logo-plate-bg, transparent);\n background-repeat: no-repeat;\n background-position: center;\n background-size: contain;\n border-radius: var(--mj-radius-sm, 4px);\n flex-shrink: 0;\n}\n\n.shell-container {\n display: flex;\n flex-direction: column;\n height: 100%;\n width: 100%;\n overflow: hidden;\n position: relative;\n}\n\n/* Hide shell container while loading - allows tab container to render and load\n first resource in background while shell loading indicator is visible */\n.shell-container.hidden {\n visibility: hidden;\n position: absolute;\n pointer-events: none;\n}\n\nmj-tab-container {\n flex: 1;\n min-height: 0;\n overflow: hidden;\n display: flex;\n flex-direction: column;\n transition: all 0.2s ease-in-out;\n}\n\n/* Hide Golden Layout tab headers when only one tab \u2014 scoped to the MAIN\n region: the RECORDS region is a separate Golden Layout whose tab strip is\n its whole point (switching between open records) and must never be hidden\n by the main bar's visibility policy. */\nmj-tab-container.hide-tab-bar ::ng-deep .main-region .lm_header {\n display: none;\n}\n\n/* Show tab headers when multiple tabs */\nmj-tab-container:not(.hide-tab-bar) ::ng-deep .main-region .lm_header {\n opacity: 1;\n max-height: 40px;\n transition: opacity 0.2s ease-in-out, max-height 0.2s ease-in-out;\n}\n\n/* Adjust content area height when tabs hidden */\nmj-tab-container.hide-tab-bar ::ng-deep .main-region .lm_content {\n height: 100% !important;\n}\n\n/* Ensure smooth transitions */\nmj-tab-container ::ng-deep .lm_stack {\n transition: all 0.2s ease-in-out;\n}\n\n.shell-header {\n height: 60px;\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n display: flex;\n align-items: center;\n padding: 0 var(--mj-space-4);\n gap: var(--mj-space-4);\n box-shadow: var(--mj-shadow-sm);\n flex-shrink: 0;\n /* Creates a stacking context so children (search bar z-index: 99999, dropdown)\n are contained within this level. Modal overlays (z-index: 1000+) sit above. */\n position: relative;\n z-index: 500;\n}\n\n/* Nav Bar Apps - permanent app icons in the header */\n.nav-bar-apps {\n display: flex;\n align-items: center;\n gap: var(--mj-space-1);\n}\n\n.nav-bar-apps.left-of-switcher {\n /* No extra margin - header gap handles spacing */\n /* This prevents the app switcher from shifting when icons are hidden */\n}\n\n.nav-bar-apps.left-of-user-menu {\n margin-right: var(--mj-space-2);\n}\n\n.nav-bar-app-btn {\n --app-color: var(--mj-text-muted);\n width: 40px;\n height: 40px;\n border-radius: var(--mj-radius-md);\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n font-size: var(--mj-text-lg);\n transition: all var(--mj-transition-fast);\n position: relative;\n}\n\n.nav-bar-app-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n/* Active = brand-primary (matches nav pills + switcher items); the app's\n metadata color is reserved for identity accents, never state.\n Shared active-tint recipe. */\n.nav-bar-app-btn.active {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n color: var(--mj-brand-primary);\n}\n\n.nav-bar-app-btn i {\n transition: transform var(--mj-transition-fast);\n margin-top: var(--mj-space-0-5); /* Align with app switcher icon */\n}\n\n.nav-bar-app-btn:hover i {\n transform: scale(1.1);\n}\n\n.spacer {\n flex: 1;\n}\n\n/* Priority+ overflow support: on desktop the app nav owns the header's free\n middle space (so it knows exactly how much room its items have) and the\n spacer stands down. On mobile the nav is display:none'd, so the spacer's\n flex: 1 keeps the action cluster right-aligned. When the nav isn't rendered\n at all (app-locked sessions, Shell.AppNav.Enabled off), the sibling selector\n doesn't match and the spacer behaves as before. */\n@media (min-width: 769px) {\n mj-app-nav.desktop-nav {\n flex: 1 1 auto;\n min-width: 0;\n }\n mj-app-nav.desktop-nav + .spacer {\n flex: 0 0 0px;\n }\n}\n\n.header-actions {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n}\n\n.icon-btn {\n width: 40px;\n height: 40px;\n border-radius: 50%;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n font-size: var(--mj-text-lg);\n transition: background var(--mj-transition-fast);\n}\n\n.icon-btn:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n/* Keyboard focus parity for all header controls (the search bar already has\n its own ring at .search-btn:focus-visible). */\n.nav-bar-app-btn:focus-visible,\n.icon-btn:focus-visible,\n.hamburger-btn:focus-visible,\n.user-menu .avatar-btn:focus-visible {\n outline: 2px solid var(--mj-border-focus);\n outline-offset: 2px;\n}\n\n/* Universal search: a static-width bar styled as an input, anchored on the\n right with the action cluster. Deliberately NOT resizable on hover/focus \u2014\n chrome that shifts on interaction was rejected in the 2026-07 review. It's a\n button (typing happens in the overlay it opens), so no focus/caret styling. */\n.search-btn {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n width: 260px;\n height: 36px;\n padding: 0 var(--mj-space-2-5) 0 var(--mj-space-3-5);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n font-size: var(--mj-text-sm);\n font-family: inherit;\n cursor: pointer;\n transition: var(--mj-transition-colors);\n}\n\n.search-btn:hover {\n border-color: var(--mj-border-strong);\n background: var(--mj-bg-surface-card);\n color: var(--mj-text-secondary);\n}\n\n.search-btn:focus-visible {\n outline: none;\n border-color: var(--mj-border-focus);\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n}\n\n/* Omnibar-off mobile trigger: hidden on desktop (the inline composite renders\n instead); the 768px block flips it on as the icon circle. */\n.search-btn-mobile {\n display: none;\n}\n\n/* Omnibar-off desktop: the inline search composite, same slot + width as the\n omnibar bar so the opt-in toggle doesn't move the header. */\n.shell-search-bar {\n position: relative;\n width: 260px;\n z-index: 99999;\n}\n\n/* The suggest dropdown needs more width than its 260px anchor. Pin it to the\n anchor's right edge and let it grow leftward \u2014 the bar is right-anchored, so\n leftward growth stays on screen. */\n.shell-search-bar ::ng-deep .suggest-dropdown {\n left: auto;\n right: 0;\n width: min(560px, calc(100vw - var(--mj-space-6)));\n}\n\n.search-btn i {\n font-size: var(--mj-text-sm);\n flex-shrink: 0;\n}\n\n.search-btn .search-btn-text {\n flex: 1;\n min-width: 0;\n text-align: left;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* kbd chip: deliberately mirrors the omnibar palette's .ob-kbd chrome\n (10.5px / 5px radius / bottom-heavy border) so the affordance and the\n surface it summons read as one system. */\n.search-btn .search-btn-kbd {\n flex-shrink: 0;\n white-space: nowrap;\n font-family: inherit;\n font-size: 10.5px;\n font-weight: var(--mj-font-semibold);\n color: var(--mj-text-muted);\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-strong);\n border-bottom-width: 2px;\n border-radius: 5px;\n padding: 1.5px var(--mj-space-1-5);\n}\n\n/* Notification button with badge */\n.notification-btn {\n position: relative;\n}\n\n.notification-badge {\n position: absolute;\n top: 4px;\n right: 4px;\n min-width: 16px;\n height: 16px;\n padding: 0 var(--mj-space-1);\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: var(--mj-font-semibold);\n border-radius: var(--mj-radius-full);\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: var(--mj-leading-none);\n box-shadow: var(--mj-shadow-sm);\n}\n\n.user-menu {\n position: relative;\n}\n\n.user-menu .avatar-btn {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: none;\n background: transparent;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n transition: box-shadow var(--mj-transition-fast), transform var(--mj-transition-fast);\n padding: 0;\n overflow: hidden;\n}\n\n.user-menu .avatar-btn:hover {\n transform: scale(1.05);\n}\n\n/* Icon fallback styling - shows gray circle with icon */\n.user-menu .avatar-btn .icon-fallback {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n border: 2px solid var(--mj-border-default);\n background: var(--mj-bg-surface-hover);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: border-color var(--mj-transition-fast);\n}\n\n.user-menu .avatar-btn:hover .icon-fallback {\n border-color: var(--mj-brand-primary);\n}\n\n.user-menu .avatar-btn .icon-fallback i {\n color: var(--mj-text-muted);\n font-size: var(--mj-text-base);\n}\n\n/* Avatar image - replaces the gray circle entirely */\n.user-menu .avatar-btn .avatar-img {\n width: 100%;\n height: 100%;\n border-radius: 50%;\n object-fit: cover;\n box-shadow: var(--mj-shadow-sm);\n}\n\n.user-menu .avatar-btn:hover .avatar-img {\n box-shadow: var(--mj-shadow-md);\n}\n\n/* User Menu Header */\n.user-menu-header {\n padding: var(--mj-space-3) var(--mj-space-4);\n background: var(--mj-bg-surface-sunken);\n}\n\n.user-menu-header .user-info {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-0-5);\n}\n\n.user-menu-header .user-name {\n font-weight: var(--mj-font-semibold);\n font-size: var(--mj-text-sm);\n color: var(--mj-text-primary);\n}\n\n.user-menu-header .user-email {\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n}\n\n.user-menu-header .user-subtitle {\n font-size: 11px;\n color: var(--mj-text-muted);\n font-style: italic;\n}\n\n/* User Context Menu */\n.user-context-menu {\n position: absolute;\n top: 100%;\n right: 0;\n margin-top: var(--mj-space-2);\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n box-shadow: var(--mj-shadow-lg);\n min-width: 180px;\n z-index: 10000;\n overflow: hidden;\n}\n\n.user-menu-item {\n display: flex;\n align-items: center;\n gap: var(--mj-space-3);\n padding: var(--mj-space-3) var(--mj-space-4);\n cursor: pointer;\n font-size: var(--mj-text-sm);\n color: var(--mj-text-primary);\n transition: background var(--mj-transition-fast);\n}\n\n.user-menu-item i {\n width: 18px;\n text-align: center;\n color: var(--mj-text-muted);\n font-size: var(--mj-text-sm);\n}\n\n.user-menu-item:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.user-menu-item.danger {\n color: var(--mj-status-error);\n}\n\n.user-menu-item.danger i {\n color: var(--mj-status-error);\n}\n\n.user-menu-item.danger:hover {\n background: color-mix(in srgb, var(--mj-status-error) 10%, var(--mj-bg-surface-elevated));\n}\n\n.user-menu-divider {\n height: 1px;\n background: var(--mj-border-default);\n margin: var(--mj-space-1) 0;\n}\n\n/* Menu item disabled state */\n.user-menu-item.disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n\n.user-menu-item.disabled:hover {\n background: transparent;\n}\n\n/* Theme Toggle Switch */\n.theme-toggle-item {\n cursor: pointer;\n}\n\n.theme-toggle-track {\n position: relative;\n width: 40px;\n height: 22px;\n border-radius: var(--mj-radius-full);\n background: var(--mj-bg-surface-active);\n margin-left: auto;\n transition: background var(--mj-transition-base);\n flex-shrink: 0;\n}\n\n.theme-toggle-track.dark {\n background: var(--mj-brand-primary);\n}\n\n.theme-toggle-thumb {\n position: absolute;\n top: 2px;\n left: 2px;\n width: 18px;\n height: 18px;\n border-radius: 50%;\n background: var(--mj-bg-surface);\n box-shadow: var(--mj-shadow-sm);\n display: flex;\n align-items: center;\n justify-content: center;\n transition: transform var(--mj-transition-base);\n}\n\n.theme-toggle-track.dark .theme-toggle-thumb {\n transform: translateX(18px);\n}\n\n.theme-toggle-icon {\n font-size: 10px;\n color: var(--mj-text-muted);\n}\n\n.theme-toggle-track.dark .theme-toggle-icon {\n color: var(--mj-text-inverse);\n}\n\n/* Menu shortcut hint */\n.user-menu-item .menu-shortcut {\n margin-left: auto;\n font-size: 11px;\n color: var(--mj-text-disabled);\n font-family: monospace;\n}\n\n/* Menu animations */\n.user-context-menu.menu-fade {\n animation: menuFadeIn 0.15s ease-out;\n}\n\n.user-context-menu.menu-slide {\n animation: menuSlideIn 0.2s ease-out;\n}\n\n@keyframes menuFadeIn {\n from {\n opacity: 0;\n transform: translateY(-8px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n@keyframes menuSlideIn {\n from {\n opacity: 0;\n transform: translateY(-16px) scale(0.95);\n }\n to {\n opacity: 1;\n transform: translateY(0) scale(1);\n }\n}\n\n.shell-loading {\n position: fixed;\n top: 0;\n left: 0;\n width: 100vw;\n height: 100vh;\n z-index: 99999;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding-bottom: 15vh;\n background: var(--mj-bg-page);\n}\n\n.loading-version {\n margin-top: var(--mj-space-8, 24px);\n font-size: 11px;\n color: var(--mj-text-muted);\n letter-spacing: 0.4px;\n opacity: 0.6;\n user-select: none;\n}\n\n/* Loading Recovery Reset Panel */\n.loading-reset-panel {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: var(--mj-space-3);\n margin-top: var(--mj-space-10);\n padding: var(--mj-space-8);\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n box-shadow: var(--mj-shadow-md);\n max-width: 420px;\n animation: resetPanelFadeIn 0.4s ease-out;\n}\n\n.loading-reset-message {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n margin: 0;\n font-size: var(--mj-text-base);\n font-weight: var(--mj-font-semibold);\n color: var(--mj-text-primary);\n}\n\n.loading-reset-message i {\n font-size: var(--mj-text-lg);\n color: var(--mj-status-warning);\n}\n\n.loading-reset-hint {\n margin: 0;\n font-size: var(--mj-text-sm);\n color: var(--mj-text-secondary);\n text-align: center;\n line-height: var(--mj-leading-relaxed);\n}\n\n.loading-reset-btn {\n display: inline-flex;\n align-items: center;\n gap: var(--mj-space-2);\n margin-top: var(--mj-space-3);\n padding: var(--mj-space-3) var(--mj-space-6);\n font-size: var(--mj-text-base);\n font-weight: var(--mj-font-medium);\n font-family: var(--mj-font-family);\n color: var(--mj-text-inverse);\n background: var(--mj-brand-primary);\n border: 1px solid var(--mj-brand-primary);\n border-radius: var(--mj-radius-md);\n cursor: pointer;\n transition: var(--mj-transition-colors);\n}\n\n.loading-reset-btn:hover {\n background: var(--mj-brand-primary-hover);\n color: var(--mj-text-inverse);\n border-color: var(--mj-brand-primary-hover);\n box-shadow: var(--mj-shadow-md);\n}\n\n.loading-reset-btn:active {\n background: var(--mj-brand-primary-active);\n color: var(--mj-text-inverse);\n transform: scale(0.98);\n}\n\n.loading-reset-btn i {\n font-size: var(--mj-text-sm);\n}\n\n@keyframes resetPanelFadeIn {\n from {\n opacity: 0;\n transform: translateY(12px);\n }\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n/* Hamburger button - hidden on desktop */\n.hamburger-btn {\n display: none;\n width: 40px;\n height: 40px;\n border-radius: var(--mj-radius-md);\n border: none;\n background: none;\n cursor: pointer;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-secondary);\n font-size: var(--mj-text-xl);\n transition: background var(--mj-transition-fast);\n}\n.hamburger-btn:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n/* Mobile Navigation Overlay */\n.mobile-nav-overlay {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-overlay);\n z-index: 9998;\n}\n\n/* Mobile Navigation Drawer */\n.mobile-nav-drawer {\n display: none;\n position: fixed;\n top: 0;\n left: 0;\n bottom: 0;\n width: 280px;\n max-width: 85vw;\n background: var(--mj-bg-surface);\n box-shadow: var(--mj-shadow-xl);\n z-index: 9999;\n flex-direction: column;\n transform: translateX(-100%);\n transition: transform var(--mj-transition-slow);\n}\n.mobile-nav-drawer.open {\n transform: translateX(0);\n}\n\n.mobile-nav-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--mj-space-4) var(--mj-space-5);\n border-bottom: 1px solid var(--mj-border-default);\n background: var(--mj-bg-surface-sunken);\n}\n.mobile-nav-header span {\n font-weight: var(--mj-font-semibold);\n font-size: var(--mj-text-base);\n color: var(--mj-text-primary);\n}\n.mobile-nav-header .close-btn {\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: none;\n background: none;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n font-size: var(--mj-text-lg);\n transition: background var(--mj-transition-fast);\n}\n.mobile-nav-header .close-btn:hover {\n background: var(--mj-bg-surface-active);\n}\n\n.mobile-nav-content {\n flex: 1;\n overflow-y: auto;\n padding: var(--mj-space-4) 0;\n}\n\n.mobile-nav-section-title {\n padding: var(--mj-space-2) var(--mj-space-5);\n font-size: var(--mj-text-xs);\n font-weight: var(--mj-font-semibold);\n color: var(--mj-text-disabled);\n text-transform: uppercase;\n letter-spacing: 0.5px;\n}\n\n/* Records entry in the mobile drawer (records-style record opens) \u2014\n the desktop pill lives in the mobile-hidden app nav, so the drawer\n carries its own touch-friendly instance. */\n.mobile-nav-records {\n padding: var(--mj-space-2) var(--mj-space-3);\n border-top: 1px solid var(--mj-border-default);\n}\n.mobile-nav-records .records-pill {\n width: 100%;\n min-height: 48px; /* Touch-target parity with drawer nav items */\n justify-content: flex-start;\n}\n\n.mobile-nav-footer {\n border-top: 1px solid var(--mj-border-default);\n padding: var(--mj-space-3) var(--mj-space-4);\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-1);\n}\n\n.mobile-nav-action {\n position: relative;\n display: flex;\n align-items: center;\n gap: var(--mj-space-3);\n padding: var(--mj-space-3) var(--mj-space-4);\n border: none;\n background: none;\n cursor: pointer;\n border-radius: var(--mj-radius-md);\n color: var(--mj-text-secondary);\n font-size: var(--mj-text-sm);\n font-weight: var(--mj-font-medium);\n transition: background var(--mj-transition-fast);\n width: 100%;\n text-align: left;\n}\n.mobile-nav-action:hover {\n background: var(--mj-bg-surface-hover);\n}\n.mobile-nav-action i {\n font-size: var(--mj-text-base);\n width: 20px;\n text-align: center;\n}\n\n/* Mobile Responsive Styles */\n@media (max-width: 768px) {\n .hamburger-btn {\n display: flex;\n }\n\n .desktop-nav {\n display: none !important;\n }\n\n .desktop-only {\n display: none !important;\n }\n\n .mobile-nav-overlay {\n display: block;\n }\n\n .mobile-nav-drawer {\n display: flex;\n }\n\n .shell-header {\n padding: 0 var(--mj-space-3);\n gap: var(--mj-space-2);\n }\n\n /* Keep the right-edge cluster (chat/nav-bar app icons + avatar) on one row.\n Without pinning this, the icons can wrap and the avatar drops onto a second\n line, stacking under the chat icon. */\n .header-actions {\n flex-direction: row;\n flex-wrap: nowrap;\n }\n .header-actions .user-menu,\n .header-actions .nav-bar-apps,\n .header-actions .search-btn {\n flex-shrink: 0;\n }\n\n /* Search bar collapses to the icon-only circle on small viewports \u2014\n the placeholder text + kbd chip are already hidden via .desktop-only.\n The omnibar-off mobile trigger (.search-btn-mobile) becomes visible here;\n its .desktop-only composite sibling is hidden by the rule above. */\n .search-btn {\n display: flex;\n width: 40px;\n height: 40px;\n padding: 0;\n justify-content: center;\n border: none;\n border-radius: 50%;\n background: none;\n }\n .search-btn i {\n font-size: var(--mj-text-lg);\n }\n .search-btn:hover {\n background: var(--mj-bg-surface-hover);\n border: none;\n }\n}\n\n/* Settings Full-Screen Window Styles */\n::ng-deep .settings-fullscreen-window {\n /* Remove window chrome for full-screen feel */\n box-shadow: none !important;\n border: none !important;\n}\n\n::ng-deep .settings-fullscreen-window .k-window-titlebar {\n background: var(--mj-bg-surface);\n border-bottom: 1px solid var(--mj-border-default);\n padding: var(--mj-space-3) var(--mj-space-4);\n}\n\n::ng-deep .settings-fullscreen-window .k-window-title {\n font-size: var(--mj-text-lg);\n font-weight: var(--mj-font-semibold);\n color: var(--mj-text-primary);\n}\n\n::ng-deep .settings-fullscreen-window .k-window-titlebar-actions {\n gap: var(--mj-space-1);\n}\n\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action {\n width: 32px;\n height: 32px;\n border-radius: var(--mj-radius-md);\n}\n\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n::ng-deep .settings-fullscreen-window .k-window-content {\n padding: 0;\n overflow: auto;\n background: var(--mj-bg-page);\n}\n\n/* Hide minimize/maximize buttons - only show close */\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action[title=\"Minimize\"],\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action[title=\"Maximize\"],\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action .k-i-window-minimize,\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action .k-i-window-maximize,\n::ng-deep .settings-fullscreen-window .k-window-titlebar-action .k-i-window {\n display: none !important;\n}\n\n/* Universal search is a right-anchored bar affordance in header-actions\n (2026-07 design review round 2): both experiences still open as overlays \u2014\n the bar is a trigger, not an inline input. Icon-only under 768px. */\n\n/* ========================================\n SEARCH POPUP\n ======================================== */\n\n.search-popup-overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: var(--mj-bg-overlay);\n z-index: 9999;\n animation: fadeIn 0.15s ease;\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n\n.search-popup {\n position: absolute;\n top: 60px; /* Below header */\n right: 16px;\n width: 480px;\n max-width: calc(100vw - 32px);\n background: var(--mj-bg-surface-elevated);\n border-radius: var(--mj-radius-lg);\n box-shadow: var(--mj-shadow-xl);\n z-index: 10000;\n opacity: 0;\n transform: translateY(-10px);\n pointer-events: none;\n transition: opacity var(--mj-transition-base), transform var(--mj-transition-base);\n}\n\n.search-popup.open {\n opacity: 1;\n transform: translateY(0);\n pointer-events: all;\n}\n\n.search-popup-content {\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n padding: var(--mj-space-3);\n}\n\n.search-entity-dropdown {\n min-width: 140px;\n max-width: 180px;\n flex-shrink: 0;\n}\n\n.search-input {\n flex: 1;\n min-width: 0;\n height: 40px;\n padding: var(--mj-space-2) var(--mj-space-3);\n font-size: var(--mj-text-sm);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-sm);\n outline: none;\n display: block !important;\n box-sizing: border-box;\n}\n\n.search-input:focus {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 0 0 2px color-mix(in srgb, var(--mj-brand-primary) 10%, transparent);\n}\n\n.search-submit-btn {\n width: 40px;\n height: 40px;\n border-radius: var(--mj-radius-md);\n border: none;\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: var(--mj-text-base);\n transition: background var(--mj-transition-fast);\n flex-shrink: 0;\n}\n\n.search-submit-btn:hover {\n background: var(--mj-brand-primary-hover);\n}\n\n.search-submit-btn:active {\n background: var(--mj-brand-primary-hover);\n}\n\n/* Mobile notification badge */\n.notification-badge-mobile {\n position: absolute;\n top: 8px;\n right: 8px;\n min-width: 18px;\n height: 18px;\n padding: 0 5px;\n background: var(--mj-status-error);\n color: var(--mj-text-inverse);\n font-size: 11px;\n font-weight: var(--mj-font-semibold);\n border-radius: var(--mj-radius-full);\n display: flex;\n align-items: center;\n justify-content: center;\n line-height: var(--mj-leading-none);\n box-shadow: var(--mj-shadow-sm);\n}\n\n/* Mobile-specific search popup adjustments */\n@media (max-width: 768px) {\n .search-popup {\n top: 60px;\n left: 16px;\n right: 16px;\n width: auto;\n max-width: none;\n }\n\n .search-popup-content {\n flex-wrap: wrap;\n }\n\n .search-entity-dropdown {\n width: 100%;\n }\n\n .search-input {\n flex: 1;\n min-width: 0;\n }\n}\n\n/* ========================================\n PIN PROGRESS OVERLAY\n ======================================== */\n.pin-progress-backdrop {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n background: color-mix(in srgb, var(--mj-text-primary) 40%, transparent);\n z-index: 100000;\n display: flex;\n align-items: center;\n justify-content: center;\n animation: pinBackdropIn 0.2s ease;\n}\n\n@keyframes pinBackdropIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n.pin-progress-modal {\n background: var(--mj-bg-surface);\n border-radius: var(--mj-radius-xl);\n padding: var(--mj-space-7) var(--mj-space-10);\n display: flex;\n align-items: center;\n gap: var(--mj-space-4);\n box-shadow: 0 16px 48px color-mix(in srgb, var(--mj-text-primary) 30%, transparent);\n animation: pinModalIn 0.25s ease;\n}\n\n@keyframes pinModalIn {\n from { opacity: 0; transform: scale(0.9) translateY(8px); }\n to { opacity: 1; transform: scale(1) translateY(0); }\n}\n\n.pin-progress-text {\n font-size: var(--mj-text-sm);\n font-weight: var(--mj-font-medium);\n color: var(--mj-text-secondary);\n white-space: nowrap;\n}\n/* ============================================================\n Global Activity indicator (P3)\n ============================================================ */\n.activity-wrap { position: relative; display: inline-flex; }\n.activity-btn { position: relative; }\n.activity-btn .activity-pulse { color: var(--mj-brand-primary); }\n.activity-badge {\n position: absolute;\n top: 2px;\n right: 2px;\n min-width: 16px;\n height: 16px;\n padding: 0 var(--mj-space-1);\n border-radius: var(--mj-radius-md);\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-size: 10px;\n font-weight: var(--mj-font-bold);\n line-height: 16px;\n text-align: center;\n}\n.activity-drawer {\n position: absolute;\n top: calc(100% + 8px);\n right: 0;\n width: 320px;\n max-height: 420px;\n display: flex;\n flex-direction: column;\n background: var(--mj-bg-surface-elevated);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-md);\n box-shadow: 0 8px 28px color-mix(in srgb, var(--mj-text-primary) 18%, transparent);\n z-index: 1000;\n overflow: hidden;\n}\n.activity-drawer-head {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: var(--mj-space-2-5) var(--mj-space-3);\n font-weight: var(--mj-font-bold);\n font-size: 0.85rem;\n color: var(--mj-text-primary);\n border-bottom: 1px solid var(--mj-border-default);\n}\n.activity-clear {\n background: none;\n border: none;\n color: var(--mj-text-muted);\n cursor: pointer;\n font-size: 0.8rem;\n padding: var(--mj-space-1) var(--mj-space-1-5);\n border-radius: var(--mj-radius-md);\n}\n.activity-clear:hover { color: var(--mj-text-primary); background: var(--mj-bg-surface-hover); }\n.activity-list { overflow-y: auto; padding: var(--mj-space-1-5); }\n.activity-row {\n display: flex;\n gap: var(--mj-space-2-5);\n padding: var(--mj-space-2);\n border-radius: var(--mj-radius-md);\n}\n.activity-row:hover { background: var(--mj-bg-surface-hover); }\n.activity-row-icon { margin-top: var(--mj-space-0-5); color: var(--mj-brand-primary); font-size: 0.85rem; }\n.activity-row.is-error .activity-row-icon { color: var(--mj-status-error); }\n.activity-row-body { flex: 1; min-width: 0; }\n.activity-row-label { font-size: 0.82rem; font-weight: var(--mj-font-semibold); color: var(--mj-text-primary); }\n.activity-row-detail { font-size: 0.72rem; color: var(--mj-text-muted); margin-top: var(--mj-space-px); }\n.activity-bar {\n margin-top: var(--mj-space-1-5);\n height: 4px;\n background: var(--mj-bg-surface-sunken);\n border-radius: 2px;\n overflow: hidden;\n}\n.activity-bar-fill { height: 100%; background: var(--mj-brand-primary); transition: width var(--mj-transition-slow); }\n\n"] }]
|
|
3478
3638
|
}], () => [{ type: i1.ApplicationManager }, { type: i1.WorkspaceStateManager }, { type: i1.GoldenLayoutManager }, { type: i1.TabService }, { type: i2.NavigationService }, { type: i3.ActivatedRoute }, { type: i3.Router }, { type: i4.MJAuthBase }, { type: i0.ChangeDetectorRef }, { type: i5.UserAvatarService }, { type: i6.UserSharingCenterDialogService }, { type: i7.AboutDialogService }, { type: i8.ProfileDialogService }, { type: i0.ViewContainerRef }, { type: i2.TitleService }, { type: i2.DeveloperModeService }, { type: i9.StartupValidationService }, { type: i10.CommandPaletteService }, { type: i2.ThemeService }, { type: i2.HomeAppPinService }, { type: i11.FileOpenService }, { type: i12.FeedbackDialogService }, { type: i12.FeedbackService }, { type: i2.ActivityService }], { searchInput: [{
|
|
3479
3639
|
type: ViewChild,
|
|
3480
3640
|
args: ['searchInput']
|
|
@@ -3500,5 +3660,5 @@ export class ShellComponent extends BaseAngularComponent {
|
|
|
3500
3660
|
type: HostListener,
|
|
3501
3661
|
args: ['document:click']
|
|
3502
3662
|
}] }); })();
|
|
3503
|
-
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ShellComponent, { className: "ShellComponent", filePath: "src/lib/shell/shell.component.ts", lineNumber:
|
|
3663
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ShellComponent, { className: "ShellComponent", filePath: "src/lib/shell/shell.component.ts", lineNumber: 72 }); })();
|
|
3504
3664
|
//# sourceMappingURL=shell.component.js.map
|