@memberjunction/ng-dashboards 6.2.0-edge.4 → 6.2.0-edge.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/dist/AI/components/vectors/sensitive-fields.d.ts +53 -0
  2. package/dist/AI/components/vectors/sensitive-fields.d.ts.map +1 -0
  3. package/dist/AI/components/vectors/sensitive-fields.js +226 -0
  4. package/dist/AI/components/vectors/sensitive-fields.js.map +1 -0
  5. package/dist/AI/components/vectors/vector-document-rules.d.ts +126 -0
  6. package/dist/AI/components/vectors/vector-document-rules.d.ts.map +1 -0
  7. package/dist/AI/components/vectors/vector-document-rules.js +168 -0
  8. package/dist/AI/components/vectors/vector-document-rules.js.map +1 -0
  9. package/dist/AI/components/vectors/vector-management-resource.component.d.ts +49 -0
  10. package/dist/AI/components/vectors/vector-management-resource.component.d.ts.map +1 -1
  11. package/dist/AI/components/vectors/vector-management-resource.component.js +428 -230
  12. package/dist/AI/components/vectors/vector-management-resource.component.js.map +1 -1
  13. package/dist/Communication/communication-agent-context.d.ts +11 -1
  14. package/dist/Communication/communication-agent-context.d.ts.map +1 -1
  15. package/dist/Communication/communication-agent-context.js +15 -0
  16. package/dist/Communication/communication-agent-context.js.map +1 -1
  17. package/dist/Communication/communication-dashboard.component.d.ts.map +1 -1
  18. package/dist/Communication/communication-dashboard.component.js +5 -0
  19. package/dist/Communication/communication-dashboard.component.js.map +1 -1
  20. package/dist/Communication/communication-providers-resource.component.d.ts +27 -1
  21. package/dist/Communication/communication-providers-resource.component.d.ts.map +1 -1
  22. package/dist/Communication/communication-providers-resource.component.js +722 -78
  23. package/dist/Communication/communication-providers-resource.component.js.map +1 -1
  24. package/dist/DataExplorer/data-explorer-dashboard.component.d.ts +25 -0
  25. package/dist/DataExplorer/data-explorer-dashboard.component.d.ts.map +1 -1
  26. package/dist/DataExplorer/data-explorer-dashboard.component.js +74 -5
  27. package/dist/DataExplorer/data-explorer-dashboard.component.js.map +1 -1
  28. package/dist/DevTools/app-state-inspector.component.d.ts.map +1 -1
  29. package/dist/DevTools/app-state-inspector.component.js +1 -0
  30. package/dist/DevTools/app-state-inspector.component.js.map +1 -1
  31. package/dist/DevTools/class-registry.component.d.ts.map +1 -1
  32. package/dist/DevTools/class-registry.component.js +1 -0
  33. package/dist/DevTools/class-registry.component.js.map +1 -1
  34. package/dist/DevTools/event-monitor.component.d.ts.map +1 -1
  35. package/dist/DevTools/event-monitor.component.js +2 -0
  36. package/dist/DevTools/event-monitor.component.js.map +1 -1
  37. package/dist/DevTools/graphql-console.component.d.ts.map +1 -1
  38. package/dist/DevTools/graphql-console.component.js.map +1 -1
  39. package/dist/DevTools/grid-width-lab.component.d.ts.map +1 -1
  40. package/dist/DevTools/grid-width-lab.component.js +1 -0
  41. package/dist/DevTools/grid-width-lab.component.js.map +1 -1
  42. package/dist/DevTools/layout-inspector.component.d.ts.map +1 -1
  43. package/dist/DevTools/layout-inspector.component.js +1 -0
  44. package/dist/DevTools/layout-inspector.component.js.map +1 -1
  45. package/dist/DevTools/lazy-module-status.component.d.ts.map +1 -1
  46. package/dist/DevTools/lazy-module-status.component.js +1 -0
  47. package/dist/DevTools/lazy-module-status.component.js.map +1 -1
  48. package/dist/DevTools/settings-explorer.component.d.ts.map +1 -1
  49. package/dist/DevTools/settings-explorer.component.js +1 -0
  50. package/dist/DevTools/settings-explorer.component.js.map +1 -1
  51. package/dist/DevTools/tab-strip-lab.component.d.ts.map +1 -1
  52. package/dist/DevTools/tab-strip-lab.component.js +1 -0
  53. package/dist/DevTools/tab-strip-lab.component.js.map +1 -1
  54. package/dist/EntityAdmin/entity-admin-dashboard.component.d.ts +5 -0
  55. package/dist/EntityAdmin/entity-admin-dashboard.component.d.ts.map +1 -1
  56. package/dist/EntityAdmin/entity-admin-dashboard.component.js +8 -5
  57. package/dist/EntityAdmin/entity-admin-dashboard.component.js.map +1 -1
  58. package/dist/Integration/components/overview/overview.component.js +2 -2
  59. package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js +2 -2
  60. package/dist/KnowledgeHub/components/config/knowledge-config-resource.component.js.map +1 -1
  61. package/dist/KnowledgeHub/components/feature-pipelines/feature-pipeline.engine.d.ts +11 -1
  62. package/dist/KnowledgeHub/components/feature-pipelines/feature-pipeline.engine.d.ts.map +1 -1
  63. package/dist/KnowledgeHub/components/feature-pipelines/feature-pipeline.engine.js +24 -2
  64. package/dist/KnowledgeHub/components/feature-pipelines/feature-pipeline.engine.js.map +1 -1
  65. package/dist/KnowledgeHub/components/feature-pipelines/feature-pipelines-resource.component.d.ts +16 -2
  66. package/dist/KnowledgeHub/components/feature-pipelines/feature-pipelines-resource.component.d.ts.map +1 -1
  67. package/dist/KnowledgeHub/components/feature-pipelines/feature-pipelines-resource.component.js +87 -33
  68. package/dist/KnowledgeHub/components/feature-pipelines/feature-pipelines-resource.component.js.map +1 -1
  69. package/dist/LoginStudio/login-studio-inspector.component.d.ts +130 -0
  70. package/dist/LoginStudio/login-studio-inspector.component.d.ts.map +1 -0
  71. package/dist/LoginStudio/login-studio-inspector.component.js +781 -0
  72. package/dist/LoginStudio/login-studio-inspector.component.js.map +1 -0
  73. package/dist/LoginStudio/login-studio-resource.component.d.ts +153 -0
  74. package/dist/LoginStudio/login-studio-resource.component.d.ts.map +1 -0
  75. package/dist/LoginStudio/login-studio-resource.component.js +857 -0
  76. package/dist/LoginStudio/login-studio-resource.component.js.map +1 -0
  77. package/dist/Workflows/components/workflow-runs-resource.component.js +4 -4
  78. package/dist/Workflows/components/workflow-runs-resource.component.js.map +1 -1
  79. package/dist/core-dashboards.module.d.ts +2 -1
  80. package/dist/core-dashboards.module.d.ts.map +1 -1
  81. package/dist/core-dashboards.module.js +11 -3
  82. package/dist/core-dashboards.module.js.map +1 -1
  83. package/dist/public-api.d.ts +1 -0
  84. package/dist/public-api.d.ts.map +1 -1
  85. package/dist/public-api.js +1 -0
  86. package/dist/public-api.js.map +1 -1
  87. package/package.json +72 -69
@@ -0,0 +1,857 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ /**
8
+ * @fileoverview Login Studio: design the Explorer sign-in page as data, on the default theme.
9
+ * @module LoginStudio
10
+ */
11
+ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostListener, inject } from '@angular/core';
12
+ import { DOCUMENT } from '@angular/common';
13
+ import { CdkDrag, CdkDropList, CdkDropListGroup, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';
14
+ import { takeUntil } from 'rxjs';
15
+ import { LogError, RunView } from '@memberjunction/core';
16
+ import { RegisterClass } from '@memberjunction/global';
17
+ import { BaseResourceComponent, ThemeService } from '@memberjunction/ng-shared';
18
+ import { SharedGenericModule } from '@memberjunction/ng-shared-generic';
19
+ import { MJAlertComponent, MJButtonDirective, MJConfirmService, MJEmptyStateComponent, MJPageBodyComponent, MJPageHeaderComponent, MJPageLayoutComponent, MJStatBadgeComponent, MJViewToggleComponent, } from '@memberjunction/ng-ui-components';
20
+ import { MJLoginRegionComponent } from '@memberjunction/ng-auth-services';
21
+ import { CloneLoginBlock, DefaultLoginDesign, IsLoginHexColor, IsSafeLoginImageURL, LOGIN_BLOCK_META, LOGIN_BLOCK_TYPES, LOGIN_LIMITS, LOGIN_REGION_LABEL, LOGIN_REGIONS, LocateLoginBlock, LoginDesignProblems, LoginDesignTokens, LoginThemeTokens, NewLoginBlock, ParseLoginDesign, PublicLoginScreenFromTheme, } from '@memberjunction/theme-engine';
22
+ import { LoginStudioInspectorComponent } from './login-studio-inspector.component';
23
+ import * as i0 from "@angular/core";
24
+ import * as i1 from "@memberjunction/ng-shared-generic";
25
+ const _forTrack0 = ($index, $item) => $item.Type;
26
+ function LoginStudioResourceComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
27
+ i0.ɵɵelement(0, "mj-stat-badge", 1);
28
+ } if (rf & 2) {
29
+ const ctx_r0 = i0.ɵɵnextContext();
30
+ i0.ɵɵproperty("Label", ctx_r0.StatusLabel)("Variant", ctx_r0.StatusVariant);
31
+ } }
32
+ function LoginStudioResourceComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
33
+ const _r2 = i0.ɵɵgetCurrentView();
34
+ i0.ɵɵelementStart(0, "div", 2)(1, "button", 8);
35
+ i0.ɵɵlistener("click", function LoginStudioResourceComponent_Conditional_3_Template_button_click_1_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.Undo()); });
36
+ i0.ɵɵelement(2, "i", 9);
37
+ i0.ɵɵelementEnd();
38
+ i0.ɵɵelementStart(3, "button", 10);
39
+ i0.ɵɵlistener("click", function LoginStudioResourceComponent_Conditional_3_Template_button_click_3_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.Redo()); });
40
+ i0.ɵɵelement(4, "i", 11);
41
+ i0.ɵɵelementEnd();
42
+ i0.ɵɵelementStart(5, "button", 12);
43
+ i0.ɵɵlistener("click", function LoginStudioResourceComponent_Conditional_3_Template_button_click_5_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.Discard()); });
44
+ i0.ɵɵtext(6, "Discard changes");
45
+ i0.ɵɵelementEnd();
46
+ i0.ɵɵelementStart(7, "button", 12);
47
+ i0.ɵɵlistener("click", function LoginStudioResourceComponent_Conditional_3_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.SaveDraft()); });
48
+ i0.ɵɵelement(8, "i", 13);
49
+ i0.ɵɵtext(9, " Save draft ");
50
+ i0.ɵɵelementEnd();
51
+ i0.ɵɵelementStart(10, "button", 14);
52
+ i0.ɵɵlistener("click", function LoginStudioResourceComponent_Conditional_3_Template_button_click_10_listener() { i0.ɵɵrestoreView(_r2); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.Publish()); });
53
+ i0.ɵɵelement(11, "i", 15);
54
+ i0.ɵɵtext(12, " Publish ");
55
+ i0.ɵɵelementEnd()();
56
+ } if (rf & 2) {
57
+ const ctx_r0 = i0.ɵɵnextContext();
58
+ i0.ɵɵadvance();
59
+ i0.ɵɵproperty("disabled", !ctx_r0.CanUndo);
60
+ i0.ɵɵadvance(2);
61
+ i0.ɵɵproperty("disabled", !ctx_r0.CanRedo);
62
+ i0.ɵɵadvance(2);
63
+ i0.ɵɵproperty("disabled", !ctx_r0.Unsaved || ctx_r0.Saving);
64
+ i0.ɵɵadvance(2);
65
+ i0.ɵɵproperty("disabled", ctx_r0.Saving || !ctx_r0.Unsaved);
66
+ i0.ɵɵadvance(3);
67
+ i0.ɵɵproperty("disabled", ctx_r0.Saving || !ctx_r0.Unsaved && !ctx_r0.Unpublished && ctx_r0.IsLive);
68
+ } }
69
+ function LoginStudioResourceComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) {
70
+ const _r3 = i0.ɵɵgetCurrentView();
71
+ i0.ɵɵelementStart(0, "mj-alert", 16);
72
+ i0.ɵɵlistener("Dismissed", function LoginStudioResourceComponent_Conditional_5_Template_mj_alert_Dismissed_0_listener() { i0.ɵɵrestoreView(_r3); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.DismissError()); });
73
+ i0.ɵɵelementEnd();
74
+ } if (rf & 2) {
75
+ const ctx_r0 = i0.ɵɵnextContext();
76
+ i0.ɵɵproperty("Message", ctx_r0.ErrorMessage);
77
+ } }
78
+ function LoginStudioResourceComponent_Conditional_6_Template(rf, ctx) { if (rf & 1) {
79
+ const _r4 = i0.ɵɵgetCurrentView();
80
+ i0.ɵɵelementStart(0, "mj-alert", 17);
81
+ i0.ɵɵlistener("Dismissed", function LoginStudioResourceComponent_Conditional_6_Template_mj_alert_Dismissed_0_listener() { i0.ɵɵrestoreView(_r4); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.DismissNotice()); });
82
+ i0.ɵɵelementEnd();
83
+ } if (rf & 2) {
84
+ const ctx_r0 = i0.ɵɵnextContext();
85
+ i0.ɵɵproperty("Message", ctx_r0.NoticeMessage);
86
+ } }
87
+ function LoginStudioResourceComponent_Conditional_7_Template(rf, ctx) { if (rf & 1) {
88
+ i0.ɵɵelement(0, "mj-loading", 5);
89
+ } }
90
+ function LoginStudioResourceComponent_Conditional_8_Template(rf, ctx) { if (rf & 1) {
91
+ i0.ɵɵelement(0, "mj-empty-state", 6);
92
+ } }
93
+ function LoginStudioResourceComponent_Conditional_9_For_8_Template(rf, ctx) { if (rf & 1) {
94
+ const _r6 = i0.ɵɵgetCurrentView();
95
+ i0.ɵɵelementStart(0, "button", 46);
96
+ i0.ɵɵlistener("click", function LoginStudioResourceComponent_Conditional_9_For_8_Template_button_click_0_listener() { const t_r7 = i0.ɵɵrestoreView(_r6).$implicit; const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.AddBlock(t_r7.Type)); });
97
+ i0.ɵɵelement(1, "i", 42);
98
+ i0.ɵɵelementStart(2, "span");
99
+ i0.ɵɵtext(3);
100
+ i0.ɵɵelementEnd()();
101
+ } if (rf & 2) {
102
+ const t_r7 = ctx.$implicit;
103
+ i0.ɵɵproperty("cdkDragData", t_r7.Type)("title", t_r7.Hint);
104
+ i0.ɵɵadvance();
105
+ i0.ɵɵclassMap(t_r7.Icon);
106
+ i0.ɵɵadvance(2);
107
+ i0.ɵɵtextInterpolate(t_r7.Label);
108
+ } }
109
+ function LoginStudioResourceComponent_Conditional_9_Conditional_21_Template(rf, ctx) { if (rf & 1) {
110
+ i0.ɵɵelementStart(0, "p", 32);
111
+ i0.ɵɵtext(1, "Empty: visitors see the stock logo and \"Welcome back\" here.");
112
+ i0.ɵɵelementEnd();
113
+ } }
114
+ function LoginStudioResourceComponent_Conditional_9_Conditional_28_Template(rf, ctx) { if (rf & 1) {
115
+ i0.ɵɵelementStart(0, "span", 37);
116
+ i0.ɵɵtext(1);
117
+ i0.ɵɵelementEnd();
118
+ } if (rf & 2) {
119
+ const ctx_r0 = i0.ɵɵnextContext(2);
120
+ i0.ɵɵadvance();
121
+ i0.ɵɵtextInterpolate(ctx_r0.Design.Heading);
122
+ } }
123
+ function LoginStudioResourceComponent_Conditional_9_Conditional_39_Template(rf, ctx) { if (rf & 1) {
124
+ const _r8 = i0.ɵɵgetCurrentView();
125
+ i0.ɵɵelementStart(0, "button", 47);
126
+ i0.ɵɵlistener("click", function LoginStudioResourceComponent_Conditional_9_Conditional_39_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r8); const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.Select(null)); });
127
+ i0.ɵɵelement(1, "i", 48);
128
+ i0.ɵɵelementEnd();
129
+ } }
130
+ function LoginStudioResourceComponent_Conditional_9_Template(rf, ctx) { if (rf & 1) {
131
+ const _r5 = i0.ɵɵgetCurrentView();
132
+ i0.ɵɵelementStart(0, "div", 7)(1, "aside", 18)(2, "h2", 19);
133
+ i0.ɵɵtext(3, "Blocks");
134
+ i0.ɵɵelementEnd();
135
+ i0.ɵɵelementStart(4, "p", 20);
136
+ i0.ɵɵtext(5, "Drag a block onto the page, or click one to add it after the selected block.");
137
+ i0.ɵɵelementEnd();
138
+ i0.ɵɵelementStart(6, "div", 21);
139
+ i0.ɵɵrepeaterCreate(7, LoginStudioResourceComponent_Conditional_9_For_8_Template, 4, 5, "button", 22, _forTrack0);
140
+ i0.ɵɵelementEnd()();
141
+ i0.ɵɵelementStart(9, "section", 23);
142
+ i0.ɵɵlistener("click", function LoginStudioResourceComponent_Conditional_9_Template_section_click_9_listener() { i0.ɵɵrestoreView(_r5); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.OnStageClick()); });
143
+ i0.ɵɵelementStart(10, "div", 24);
144
+ i0.ɵɵlistener("click", function LoginStudioResourceComponent_Conditional_9_Template_div_click_10_listener($event) { return $event.stopPropagation(); });
145
+ i0.ɵɵelementStart(11, "mj-view-toggle", 25);
146
+ i0.ɵɵlistener("KeyChange", function LoginStudioResourceComponent_Conditional_9_Template_mj_view_toggle_KeyChange_11_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.SetDevice($event)); });
147
+ i0.ɵɵelementEnd();
148
+ i0.ɵɵelementStart(12, "span", 20);
149
+ i0.ɵɵtext(13, "The sign-in button is a stand-in. The real one opens your sign-in provider.");
150
+ i0.ɵɵelementEnd()();
151
+ i0.ɵɵelementStart(14, "div", 26)(15, "div", 27);
152
+ i0.ɵɵlistener("click", function LoginStudioResourceComponent_Conditional_9_Template_div_click_15_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.SelectSurface("Banner", $event)); });
153
+ i0.ɵɵelementStart(16, "div", 28)(17, "div", 29)(18, "span", 30);
154
+ i0.ɵɵtext(19);
155
+ i0.ɵɵelementEnd();
156
+ i0.ɵɵelementStart(20, "mj-login-region", 31);
157
+ i0.ɵɵlistener("Dropped", function LoginStudioResourceComponent_Conditional_9_Template_mj_login_region_Dropped_20_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.OnDrop($event)); })("SelectRequested", function LoginStudioResourceComponent_Conditional_9_Template_mj_login_region_SelectRequested_20_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.Select($event)); })("CommandRequested", function LoginStudioResourceComponent_Conditional_9_Template_mj_login_region_CommandRequested_20_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.OnCommand($event)); });
158
+ i0.ɵɵelementEnd();
159
+ i0.ɵɵconditionalCreate(21, LoginStudioResourceComponent_Conditional_9_Conditional_21_Template, 2, 0, "p", 32);
160
+ i0.ɵɵelementEnd()();
161
+ i0.ɵɵelementStart(22, "div", 33);
162
+ i0.ɵɵlistener("click", function LoginStudioResourceComponent_Conditional_9_Template_div_click_22_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.SelectSurface("Panel", $event)); });
163
+ i0.ɵɵelementStart(23, "div", 34)(24, "span", 30);
164
+ i0.ɵɵtext(25);
165
+ i0.ɵɵelementEnd();
166
+ i0.ɵɵelementStart(26, "mj-login-region", 35);
167
+ i0.ɵɵlistener("Dropped", function LoginStudioResourceComponent_Conditional_9_Template_mj_login_region_Dropped_26_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.OnDrop($event)); })("SelectRequested", function LoginStudioResourceComponent_Conditional_9_Template_mj_login_region_SelectRequested_26_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.Select($event)); })("CommandRequested", function LoginStudioResourceComponent_Conditional_9_Template_mj_login_region_CommandRequested_26_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.OnCommand($event)); });
168
+ i0.ɵɵelementEnd();
169
+ i0.ɵɵelementStart(27, "div", 36);
170
+ i0.ɵɵconditionalCreate(28, LoginStudioResourceComponent_Conditional_9_Conditional_28_Template, 2, 1, "span", 37);
171
+ i0.ɵɵelementStart(29, "span", 38);
172
+ i0.ɵɵtext(30, "Log in");
173
+ i0.ɵɵelementEnd()();
174
+ i0.ɵɵelementStart(31, "span", 30);
175
+ i0.ɵɵtext(32);
176
+ i0.ɵɵelementEnd();
177
+ i0.ɵɵelementStart(33, "mj-login-region", 39);
178
+ i0.ɵɵlistener("Dropped", function LoginStudioResourceComponent_Conditional_9_Template_mj_login_region_Dropped_33_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.OnDrop($event)); })("SelectRequested", function LoginStudioResourceComponent_Conditional_9_Template_mj_login_region_SelectRequested_33_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.Select($event)); })("CommandRequested", function LoginStudioResourceComponent_Conditional_9_Template_mj_login_region_CommandRequested_33_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.OnCommand($event)); });
179
+ i0.ɵɵelementEnd()()()()()();
180
+ i0.ɵɵelementStart(34, "aside", 40)(35, "div", 41);
181
+ i0.ɵɵelement(36, "i", 42);
182
+ i0.ɵɵelementStart(37, "h2", 43);
183
+ i0.ɵɵtext(38);
184
+ i0.ɵɵelementEnd();
185
+ i0.ɵɵconditionalCreate(39, LoginStudioResourceComponent_Conditional_9_Conditional_39_Template, 2, 0, "button", 44);
186
+ i0.ɵɵelementEnd();
187
+ i0.ɵɵelementStart(40, "mj-login-studio-inspector", 45);
188
+ i0.ɵɵlistener("EditRequested", function LoginStudioResourceComponent_Conditional_9_Template_mj_login_studio_inspector_EditRequested_40_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.ApplyEdit($event)); })("CommandRequested", function LoginStudioResourceComponent_Conditional_9_Template_mj_login_studio_inspector_CommandRequested_40_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.OnCommand($event)); })("StockPageRequested", function LoginStudioResourceComponent_Conditional_9_Template_mj_login_studio_inspector_StockPageRequested_40_listener() { i0.ɵɵrestoreView(_r5); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.UseStockPage()); })("SurfaceSelectRequested", function LoginStudioResourceComponent_Conditional_9_Template_mj_login_studio_inspector_SurfaceSelectRequested_40_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r0 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r0.SelectSurface($event)); });
189
+ i0.ɵɵelementEnd()()();
190
+ } if (rf & 2) {
191
+ const ctx_r0 = i0.ɵɵnextContext();
192
+ i0.ɵɵadvance(6);
193
+ i0.ɵɵproperty("cdkDropListData", ctx_r0.PaletteListID)("cdkDropListEnterPredicate", ctx_r0.NoEnter);
194
+ i0.ɵɵadvance();
195
+ i0.ɵɵrepeater(ctx_r0.Palette);
196
+ i0.ɵɵadvance(4);
197
+ i0.ɵɵproperty("Options", ctx_r0.DeviceOptions)("ActiveKey", ctx_r0.Device);
198
+ i0.ɵɵadvance(3);
199
+ i0.ɵɵstyleMap(ctx_r0.FrameStyle);
200
+ i0.ɵɵclassProp("ls__frame--phone", ctx_r0.Stacked);
201
+ i0.ɵɵadvance();
202
+ i0.ɵɵclassProp("lp--reverse", ctx_r0.Design.Layout === "split-reverse")("lp--centered", ctx_r0.Design.Layout === "centered")("lp--stacked", ctx_r0.Stacked)("lp--surface-on", ctx_r0.Surface === "Banner" && ctx_r0.Design.Layout === "centered");
203
+ i0.ɵɵadvance();
204
+ i0.ɵɵclassProp("lp__banner--center", ctx_r0.Design.Alignment === "center" || ctx_r0.Stacked)("lp__surface-on", ctx_r0.Surface === "Banner" && ctx_r0.Design.Layout !== "centered");
205
+ i0.ɵɵadvance(3);
206
+ i0.ɵɵtextInterpolate(ctx_r0.RegionLabel.Banner);
207
+ i0.ɵɵadvance();
208
+ i0.ɵɵproperty("Blocks", ctx_r0.Design.Regions.Banner)("Logos", ctx_r0.Logos)("BrandName", ctx_r0.Theme.Name)("Stacked", ctx_r0.Stacked)("Center", ctx_r0.Design.Alignment === "center" || ctx_r0.Stacked)("Editable", true)("SelectedID", ctx_r0.SelectedID);
209
+ i0.ɵɵadvance();
210
+ i0.ɵɵconditional(!ctx_r0.Design.Regions.Banner.length ? 21 : -1);
211
+ i0.ɵɵadvance();
212
+ i0.ɵɵclassProp("lp__surface-on", ctx_r0.Surface === "Panel");
213
+ i0.ɵɵadvance(3);
214
+ i0.ɵɵtextInterpolate(ctx_r0.RegionLabel.PanelTop);
215
+ i0.ɵɵadvance();
216
+ i0.ɵɵproperty("Blocks", ctx_r0.Design.Regions.PanelTop)("Logos", ctx_r0.Logos)("BrandName", ctx_r0.Theme.Name)("Stacked", ctx_r0.Stacked)("Editable", true)("SelectedID", ctx_r0.SelectedID);
217
+ i0.ɵɵadvance(2);
218
+ i0.ɵɵconditional(ctx_r0.Design.Heading ? 28 : -1);
219
+ i0.ɵɵadvance(4);
220
+ i0.ɵɵtextInterpolate(ctx_r0.RegionLabel.PanelBottom);
221
+ i0.ɵɵadvance();
222
+ i0.ɵɵproperty("Blocks", ctx_r0.Design.Regions.PanelBottom)("Logos", ctx_r0.Logos)("BrandName", ctx_r0.Theme.Name)("Stacked", ctx_r0.Stacked)("Editable", true)("SelectedID", ctx_r0.SelectedID);
223
+ i0.ɵɵadvance(3);
224
+ i0.ɵɵclassMap(ctx_r0.SideIcon);
225
+ i0.ɵɵadvance(2);
226
+ i0.ɵɵtextInterpolate(ctx_r0.SideTitle);
227
+ i0.ɵɵadvance();
228
+ i0.ɵɵconditional(ctx_r0.Selected || ctx_r0.Surface ? 39 : -1);
229
+ i0.ɵɵadvance();
230
+ i0.ɵɵproperty("Design", ctx_r0.Design)("Selected", ctx_r0.Selected)("SelectedRegion", ctx_r0.SelectedRegion)("Surface", ctx_r0.Surface)("CanReset", ctx_r0.IsLive || ctx_r0.Unpublished)("Saving", ctx_r0.Saving);
231
+ } }
232
+ /** The drop list the palette's tiles come from. Not a region, so a drop from it CREATES a block. */
233
+ const PALETTE = 'palette';
234
+ /** A run of edits to one field within this window is one undo step, not one per keystroke. */
235
+ const COALESCE_MS = 800;
236
+ const HISTORY_CAP = 60;
237
+ /** The click a browser fires as a drag ends; ignored so a drop keeps its selection. */
238
+ const DROP_CLICK_MS = 400;
239
+ const SURFACE_LABEL = { Banner: 'Story panel', Panel: 'Sign-in column' };
240
+ const SURFACE_ICON = { Banner: 'fa-solid fa-image', Panel: 'fa-solid fa-right-to-bracket' };
241
+ /**
242
+ * LOGIN STUDIO: an administrator designs the page visitors see before they sign in. The design lives on
243
+ * the default Active theme (`LoginScreenDraft` while edited, `LoginScreen` once published), because a
244
+ * sign-in page belongs to a brand. The preview is drawn by `<mj-login-region>`, the renderer the live
245
+ * login screen uses; every drag also has a click or key (Add, Alt+Arrow, Delete).
246
+ *
247
+ * SAFETY BOUNDARY (agent): the agent reads the design and its problems (GetSignInPageDesign). Save draft,
248
+ * Publish and "Use the stock sign-in page" are human-only: the published page is what every visitor meets
249
+ * before signing in.
250
+ */
251
+ let LoginStudioResourceComponent = class LoginStudioResourceComponent extends BaseResourceComponent {
252
+ cdr = inject(ChangeDetectorRef);
253
+ confirm = inject(MJConfirmService);
254
+ themeService = inject(ThemeService);
255
+ doc = inject(DOCUMENT);
256
+ Palette = LOGIN_BLOCK_TYPES.map((type) => ({ Type: type, ...LOGIN_BLOCK_META[type] }));
257
+ PaletteListID = PALETTE;
258
+ RegionLabel = LOGIN_REGION_LABEL;
259
+ DeviceOptions = [
260
+ { key: 'desktop', label: 'Desktop', icon: 'fa-solid fa-desktop' },
261
+ { key: 'mobile', label: 'Phone', icon: 'fa-solid fa-mobile-screen' },
262
+ ];
263
+ Loading = true;
264
+ Saving = false;
265
+ /** A failure to show, or null. */
266
+ ErrorMessage = null;
267
+ /** A confirmation to show, or null. */
268
+ NoticeMessage = null;
269
+ /** The theme being designed for: the default Active theme, or null when there is none. */
270
+ Theme = null;
271
+ Design = DefaultLoginDesign();
272
+ SelectedID = null;
273
+ /** The story panel or the sign-in column, when one is selected instead of a block. */
274
+ SelectedSurface = null;
275
+ Device = 'desktop';
276
+ Logos = {};
277
+ /** The default theme's look, as custom properties on the preview frame. */
278
+ FrameStyle = {};
279
+ /** The problems that stopped the last save; re-checked as you edit, so the alert goes once they are fixed. */
280
+ problems = [];
281
+ /** What is stored, as JSON, so "unsaved" and "unpublished" are comparisons rather than flags. */
282
+ savedDraft = null;
283
+ published = null;
284
+ /** The design as it stands in storage (or the starter, before anything is saved). */
285
+ baseline = JSON.stringify(this.Design);
286
+ seeds = null;
287
+ undo = [];
288
+ redo = [];
289
+ lastEdit = null;
290
+ droppedAt = 0;
291
+ reportedEditing = false;
292
+ ngOnInit() {
293
+ super.ngOnInit();
294
+ // The preview restates the stock gradient per color mode, so it follows a light/dark switch.
295
+ this.themeService.AppliedTheme$.pipe(takeUntil(this.destroy$)).subscribe(() => this.changed());
296
+ void this.Reload();
297
+ }
298
+ ngAfterViewInit() {
299
+ this.registerAgentTools();
300
+ }
301
+ async GetResourceDisplayName(_data) {
302
+ return 'Sign-in Page';
303
+ }
304
+ async GetResourceIconClass(_data) {
305
+ return 'fa-solid fa-right-to-bracket';
306
+ }
307
+ /** Unsaved edits: the shell keeps this tab rather than replace it. */
308
+ IsEditing() {
309
+ return this.Unsaved;
310
+ }
311
+ // ── Loading ─────────────────────────────────────────────────────────────────────────────────
312
+ /** Re-read the default theme and its sign-in page. */
313
+ async Reload() {
314
+ this.Loading = true;
315
+ this.ErrorMessage = null;
316
+ this.cdr.markForCheck();
317
+ try {
318
+ // The theme GET /auth/login-screen serves: the default Active one, most recently changed first.
319
+ const rv = await RunView.FromMetadataProvider(this.ProviderToUse).RunView({
320
+ EntityName: 'MJ: Themes',
321
+ ExtraFilter: `IsDefault = 1 AND Status = 'Active'`,
322
+ OrderBy: '__mj_UpdatedAt DESC',
323
+ MaxRows: 1,
324
+ ResultType: 'entity_object',
325
+ });
326
+ if (rv.Success) {
327
+ this.adoptTheme(rv.Results[0] ?? null);
328
+ }
329
+ else {
330
+ this.ErrorMessage = rv.ErrorMessage || 'Could not read the default theme.';
331
+ }
332
+ }
333
+ catch (e) {
334
+ LogError(e);
335
+ this.ErrorMessage = e instanceof Error ? e.message : String(e);
336
+ }
337
+ finally {
338
+ this.Loading = false;
339
+ this.changed();
340
+ this.NotifyLoadComplete();
341
+ }
342
+ }
343
+ /** Take the stored state from the theme, and edit its draft (else its live page, else the starter). */
344
+ adoptTheme(theme) {
345
+ this.readStored(theme);
346
+ this.Design = ParseLoginDesign(this.savedDraft ?? this.published) ?? DefaultLoginDesign();
347
+ this.baseline = this.CurrentJson;
348
+ this.undo = [];
349
+ this.redo = [];
350
+ this.SelectedID = null;
351
+ this.SelectedSurface = null;
352
+ this.problems = [];
353
+ }
354
+ /** What is stored on the theme: what is saved, what is live, and its seeds and logos. */
355
+ readStored(theme) {
356
+ this.Theme = theme;
357
+ // Seeds and logos as the live page gets them, so the preview wears exactly what visitors will see.
358
+ const pub = theme ? PublicLoginScreenFromTheme(theme) : null;
359
+ this.Logos = pub?.Logos ?? {};
360
+ this.seeds = pub?.Seeds ?? null;
361
+ const published = ParseLoginDesign(theme?.LoginScreen);
362
+ const draft = ParseLoginDesign(theme?.LoginScreenDraft);
363
+ this.published = published ? JSON.stringify(published) : null;
364
+ this.savedDraft = draft ? JSON.stringify(draft) : null;
365
+ }
366
+ // ── State ───────────────────────────────────────────────────────────────────────────────────
367
+ get CurrentJson() {
368
+ return JSON.stringify(this.Design);
369
+ }
370
+ /** Edits not yet saved as the draft. */
371
+ get Unsaved() {
372
+ return this.CurrentJson !== this.baseline;
373
+ }
374
+ /** The saved draft differs from what visitors see. */
375
+ get Unpublished() {
376
+ return this.savedDraft !== null && this.savedDraft !== this.published;
377
+ }
378
+ get IsLive() {
379
+ return this.published !== null;
380
+ }
381
+ get CanUndo() {
382
+ return this.undo.length > 0;
383
+ }
384
+ get CanRedo() {
385
+ return this.redo.length > 0;
386
+ }
387
+ get Stacked() {
388
+ return this.Device === 'mobile';
389
+ }
390
+ get StatusLabel() {
391
+ if (this.Unsaved)
392
+ return 'Unsaved changes';
393
+ if (this.Unpublished)
394
+ return 'Draft not published';
395
+ if (this.IsLive)
396
+ return 'Published';
397
+ return 'Stock sign-in page';
398
+ }
399
+ /** The header pill: shown only when there is something to say (live, or work waiting on you). */
400
+ get StatusVariant() {
401
+ if (this.Unsaved || this.Unpublished)
402
+ return 'warning';
403
+ return this.IsLive ? 'success' : null;
404
+ }
405
+ get Selected() {
406
+ const hit = this.SelectedID ? LocateLoginBlock(this.Design, this.SelectedID) : null;
407
+ return hit ? this.Design.Regions[hit.Region][hit.Index] : null;
408
+ }
409
+ /** The region of the selected block: a card's colors depend on which side of the page it is on. */
410
+ get SelectedRegion() {
411
+ return this.SelectedID ? LocateLoginBlock(this.Design, this.SelectedID)?.Region ?? null : null;
412
+ }
413
+ /** The selected surface; a selected block always wins. */
414
+ get Surface() {
415
+ return this.SelectedID ? null : this.SelectedSurface;
416
+ }
417
+ get SideTitle() {
418
+ if (this.Selected)
419
+ return LOGIN_BLOCK_META[this.Selected.Type].Label;
420
+ return this.Surface ? SURFACE_LABEL[this.Surface] : 'Page';
421
+ }
422
+ get SideIcon() {
423
+ if (this.Selected)
424
+ return 'fa-solid fa-sliders';
425
+ return this.Surface ? SURFACE_ICON[this.Surface] : 'fa-solid fa-table-columns';
426
+ }
427
+ /** Closing or reloading the browser with unsaved edits asks first. */
428
+ OnBeforeUnload(e) {
429
+ if (this.Unsaved)
430
+ e.preventDefault();
431
+ }
432
+ // ── Saving ──────────────────────────────────────────────────────────────────────────────────
433
+ async SaveDraft() {
434
+ if (!this.checkBeforeWrite())
435
+ return;
436
+ const json = this.CurrentJson;
437
+ if (await this.write((t) => { t.LoginScreenDraft = json; })) {
438
+ this.baseline = json;
439
+ this.done('Draft saved. Visitors still see the published page until you publish.');
440
+ }
441
+ }
442
+ async Publish() {
443
+ if (!this.checkBeforeWrite())
444
+ return;
445
+ const json = this.CurrentJson;
446
+ if (await this.write((t) => { t.LoginScreenDraft = json; t.LoginScreen = json; })) {
447
+ this.baseline = json;
448
+ // GET /auth/login-screen lets browsers keep its answer for a minute.
449
+ this.done('Published. Visitors see the new sign-in page within a minute.');
450
+ }
451
+ }
452
+ /** Back to what is stored (the saved draft, the live page, or the starter), dropping unsaved edits. */
453
+ Discard() {
454
+ this.pushHistory();
455
+ this.lastEdit = null;
456
+ this.Design = JSON.parse(this.baseline);
457
+ this.SelectedID = null;
458
+ this.problems = [];
459
+ this.ErrorMessage = null;
460
+ this.NoticeMessage = null;
461
+ this.changed();
462
+ }
463
+ /** Remove the custom page: visitors get the stock sign-in page again. */
464
+ async UseStockPage() {
465
+ const ok = await this.confirm.ConfirmDelete({
466
+ title: 'Use the stock sign-in page?',
467
+ message: 'Visitors will see the stock sign-in page, and this design and its draft are removed.',
468
+ confirmText: 'Remove the custom page',
469
+ cancelText: 'Keep it',
470
+ });
471
+ if (!ok)
472
+ return;
473
+ if (await this.write((t) => { t.LoginScreenDraft = null; t.LoginScreen = null; })) {
474
+ this.pushHistory();
475
+ this.lastEdit = null;
476
+ this.Design = DefaultLoginDesign();
477
+ this.baseline = this.CurrentJson;
478
+ this.SelectedID = null;
479
+ this.done('Visitors now see the stock sign-in page.');
480
+ }
481
+ }
482
+ DismissError() {
483
+ this.ErrorMessage = null;
484
+ this.cdr.markForCheck();
485
+ }
486
+ DismissNotice() {
487
+ this.NoticeMessage = null;
488
+ this.cdr.markForCheck();
489
+ }
490
+ done(notice) {
491
+ this.NoticeMessage = notice;
492
+ this.changed();
493
+ }
494
+ /** The editor's own list of problems, in its words. The entity's Validate runs the full check on save. */
495
+ checkBeforeWrite() {
496
+ this.NoticeMessage = null;
497
+ this.problems = LoginDesignProblems(this.Design);
498
+ this.ErrorMessage = this.problems.length ? this.problemsMessage() : null;
499
+ this.cdr.markForCheck();
500
+ return this.problems.length === 0;
501
+ }
502
+ problemsMessage() {
503
+ return `Fix these before saving: ${this.problems.join(' ')}`;
504
+ }
505
+ /**
506
+ * Writes the sign-in page columns to a FRESH copy of the theme, so a save never carries back a stale
507
+ * copy of the theme's other columns (another admin may have changed its colors or the default meanwhile).
508
+ */
509
+ async write(apply) {
510
+ if (!this.Theme)
511
+ return false;
512
+ this.Saving = true;
513
+ this.cdr.markForCheck();
514
+ try {
515
+ const theme = await this.ProviderToUse.GetEntityObject('MJ: Themes');
516
+ if (!(await theme.Load(this.Theme.ID))) {
517
+ this.ErrorMessage = 'The theme could not be read, so nothing was saved. Try again.';
518
+ return false;
519
+ }
520
+ if (!theme.IsDefault || theme.Status !== 'Active') {
521
+ this.ErrorMessage = `${theme.Name} is no longer the default theme, so nothing was saved. Close and reopen Login Studio to design the current one.`;
522
+ return false;
523
+ }
524
+ apply(theme);
525
+ if (!(await theme.Save())) {
526
+ this.ErrorMessage = theme.LatestResult?.CompleteMessage || 'The save was refused.';
527
+ return false;
528
+ }
529
+ // What is stored now, which another admin may have changed since this page loaded.
530
+ this.readStored(theme);
531
+ return true;
532
+ }
533
+ catch (e) {
534
+ LogError(e);
535
+ this.ErrorMessage = e instanceof Error ? e.message : String(e);
536
+ return false;
537
+ }
538
+ finally {
539
+ this.Saving = false;
540
+ this.cdr.markForCheck();
541
+ }
542
+ }
543
+ // ── Editing ─────────────────────────────────────────────────────────────────────────────────
544
+ /** Every change goes through here: one undo step (or one per run of typing into a field) and a fresh object for OnPush. */
545
+ mutate(fn, coalesceKey) {
546
+ const now = Date.now();
547
+ const coalesce = !!coalesceKey && this.lastEdit?.key === coalesceKey && now - this.lastEdit.at < COALESCE_MS;
548
+ if (!coalesce)
549
+ this.pushHistory();
550
+ this.lastEdit = coalesceKey ? { key: coalesceKey, at: now } : null;
551
+ const next = JSON.parse(this.CurrentJson);
552
+ fn(next);
553
+ this.Design = next;
554
+ this.changed();
555
+ }
556
+ /** What the inspector asks for, applied as one undoable step. */
557
+ ApplyEdit(e) {
558
+ switch (e.Kind) {
559
+ case 'Block':
560
+ return this.editSelected((b) => { Object.assign(b, { [e.Field]: e.Value }); }, e.Field);
561
+ case 'Link':
562
+ return this.editSelected((b) => { if (b.Type === 'links' && b.Links[e.Index])
563
+ b.Links[e.Index][e.Field] = e.Value; }, `link${e.Index}:${e.Field}`);
564
+ case 'AddLink':
565
+ return this.editSelected((b) => { if (b.Type === 'links' && b.Links.length < LOGIN_LIMITS.Links)
566
+ b.Links.push({ Label: '', Href: 'https://' }); });
567
+ case 'RemoveLink':
568
+ return this.editSelected((b) => { if (b.Type === 'links')
569
+ b.Links.splice(e.Index, 1); });
570
+ case 'Page':
571
+ return this.mutate((d) => { Object.assign(d, { [e.Field]: e.Value }); });
572
+ case 'Heading':
573
+ return this.mutate((d) => { d.Heading = e.Value.trim() ? e.Value.slice(0, LOGIN_LIMITS.Heading) : null; }, 'heading');
574
+ case 'Background':
575
+ return this.editBackground(e.Field, e.Value);
576
+ case 'Color':
577
+ return this.mutate((d) => {
578
+ const v = typeof e.Value === 'string' ? e.Value.trim() : '';
579
+ if (v)
580
+ d.Colors[e.Key] = v;
581
+ else
582
+ delete d.Colors[e.Key];
583
+ }, `color:${e.Key}`);
584
+ }
585
+ }
586
+ editSelected(fn, coalesceField) {
587
+ const id = this.SelectedID;
588
+ if (!id)
589
+ return;
590
+ this.mutate((d) => {
591
+ const hit = LocateLoginBlock(d, id);
592
+ if (hit)
593
+ fn(d.Regions[hit.Region][hit.Index]);
594
+ }, coalesceField ? `${id}:${coalesceField}` : undefined);
595
+ }
596
+ editBackground(field, value) {
597
+ this.mutate((d) => {
598
+ const bg = d.Background;
599
+ if (field === 'Kind') {
600
+ bg.Kind = value;
601
+ // A half-typed value would block saving from a field this kind no longer shows.
602
+ if (bg.Color && !IsLoginHexColor(bg.Color))
603
+ bg.Color = null;
604
+ if (bg.Color2 && !IsLoginHexColor(bg.Color2))
605
+ bg.Color2 = null;
606
+ if (bg.Kind !== 'image' && bg.ImageURL && !IsSafeLoginImageURL(bg.ImageURL))
607
+ bg.ImageURL = null;
608
+ // Start a color choice from the theme's own brand colors rather than an empty picker.
609
+ const primary = IsLoginHexColor(this.seeds?.primary) ? this.seeds.primary : null;
610
+ const accent = IsLoginHexColor(this.seeds?.accent) ? this.seeds.accent : primary;
611
+ if ((bg.Kind === 'color' || bg.Kind === 'gradient') && !bg.Color)
612
+ bg.Color = primary;
613
+ if (bg.Kind === 'gradient' && !bg.Color2)
614
+ bg.Color2 = accent;
615
+ }
616
+ else if (field === 'Overlay') {
617
+ bg.Overlay = Math.max(0, Math.min(LOGIN_LIMITS.OverlayMax, Math.round(Number(value) || 0)));
618
+ }
619
+ else {
620
+ bg[field] = typeof value === 'string' && value.trim() ? value.trim() : null;
621
+ }
622
+ }, `bg:${field}`);
623
+ }
624
+ pushHistory() {
625
+ this.undo.push(this.CurrentJson);
626
+ if (this.undo.length > HISTORY_CAP)
627
+ this.undo.shift();
628
+ this.redo = [];
629
+ }
630
+ Undo() {
631
+ const prev = this.undo.pop();
632
+ if (prev === undefined)
633
+ return;
634
+ this.redo.push(this.CurrentJson);
635
+ this.restore(prev);
636
+ }
637
+ Redo() {
638
+ const next = this.redo.pop();
639
+ if (next === undefined)
640
+ return;
641
+ this.undo.push(this.CurrentJson);
642
+ this.restore(next);
643
+ }
644
+ /** A snapshot this editor took itself, so it comes back exactly as it was, half-typed values included. */
645
+ restore(json) {
646
+ this.Design = JSON.parse(json);
647
+ this.lastEdit = null;
648
+ if (this.SelectedID && !LocateLoginBlock(this.Design, this.SelectedID))
649
+ this.SelectedID = null;
650
+ this.changed();
651
+ }
652
+ /** Ctrl/Cmd+Z and Shift+Ctrl/Cmd+Z while focus is in the studio, except in a field being typed in. */
653
+ OnKeydown(e) {
654
+ const target = e.target;
655
+ if (target && (/^(INPUT|TEXTAREA|SELECT)$/.test(target.tagName) || target.isContentEditable))
656
+ return;
657
+ if (!(e.metaKey || e.ctrlKey) || e.key.toLowerCase() !== 'z')
658
+ return;
659
+ e.preventDefault();
660
+ if (e.shiftKey)
661
+ this.Redo();
662
+ else
663
+ this.Undo();
664
+ }
665
+ // ── Blocks ──────────────────────────────────────────────────────────────────────────────────
666
+ /** A click on the empty preview deselects, except the click that ends a drag. */
667
+ OnStageClick() {
668
+ if (Date.now() - this.droppedAt < DROP_CLICK_MS)
669
+ return;
670
+ this.Select(null);
671
+ }
672
+ OnDrop(e) {
673
+ this.droppedAt = Date.now();
674
+ const to = e.To;
675
+ if (typeof e.Item === 'string') {
676
+ this.AddBlock(e.Item, to, e.CurrentIndex);
677
+ return;
678
+ }
679
+ const from = LOGIN_REGIONS.find((r) => r === e.From);
680
+ if (!from || (from === to && e.PreviousIndex === e.CurrentIndex))
681
+ return;
682
+ if (from !== to && this.regionFull(to))
683
+ return;
684
+ this.mutate((d) => {
685
+ if (from === to)
686
+ moveItemInArray(d.Regions[to], e.PreviousIndex, e.CurrentIndex);
687
+ else
688
+ transferArrayItem(d.Regions[from], d.Regions[to], e.PreviousIndex, e.CurrentIndex);
689
+ });
690
+ }
691
+ /** The palette never accepts a drop: dragging a tile back onto it cancels. */
692
+ NoEnter = () => false;
693
+ /**
694
+ * Add a block: dropped at a spot, or (clicked in the palette) just after the selected block, else at
695
+ * the end of the selected surface's first region, else of the story panel.
696
+ */
697
+ AddBlock(type, region, index) {
698
+ const sel = !region && this.SelectedID ? LocateLoginBlock(this.Design, this.SelectedID) : null;
699
+ const where = region ?? sel?.Region ?? (this.Surface === 'Panel' ? 'PanelTop' : 'Banner');
700
+ if (this.regionFull(where))
701
+ return;
702
+ const at = index ?? (sel ? sel.Index + 1 : this.Design.Regions[where].length);
703
+ const block = NewLoginBlock(type);
704
+ this.SelectedID = block.ID;
705
+ this.SelectedSurface = null;
706
+ this.mutate((d) => d.Regions[where].splice(at, 0, block));
707
+ }
708
+ OnCommand(c) {
709
+ const hit = LocateLoginBlock(this.Design, c.ID);
710
+ if (!hit)
711
+ return;
712
+ const { Region: region, Index: index } = hit;
713
+ switch (c.Kind) {
714
+ case 'up':
715
+ case 'down': {
716
+ const to = index + (c.Kind === 'up' ? -1 : 1);
717
+ if (to < 0 || to >= this.Design.Regions[region].length)
718
+ return;
719
+ this.mutate((d) => moveItemInArray(d.Regions[region], index, to));
720
+ break;
721
+ }
722
+ case 'duplicate': {
723
+ if (this.regionFull(region))
724
+ return;
725
+ const copy = CloneLoginBlock(this.Design.Regions[region][index]);
726
+ this.SelectedID = copy.ID;
727
+ this.mutate((d) => d.Regions[region].splice(index + 1, 0, copy));
728
+ break;
729
+ }
730
+ case 'delete':
731
+ this.SelectedID = null;
732
+ this.mutate((d) => d.Regions[region].splice(index, 1));
733
+ break;
734
+ }
735
+ }
736
+ /** True, with a notice, when a region has no room for another block. */
737
+ regionFull(region) {
738
+ if (this.Design.Regions[region].length < LOGIN_LIMITS.BlocksPerRegion)
739
+ return false;
740
+ this.NoticeMessage = `${LOGIN_REGION_LABEL[region]} already has ${LOGIN_LIMITS.BlocksPerRegion} blocks.`;
741
+ this.cdr.markForCheck();
742
+ return true;
743
+ }
744
+ Select(id) {
745
+ this.SelectedID = id;
746
+ this.SelectedSurface = null;
747
+ this.publishAgentContext();
748
+ this.cdr.markForCheck();
749
+ }
750
+ /** Select the story panel or the sign-in column (a click on it in the preview, or the inspector's buttons). */
751
+ SelectSurface(surface, e) {
752
+ if (e) {
753
+ e.stopPropagation();
754
+ if (Date.now() - this.droppedAt < DROP_CLICK_MS)
755
+ return;
756
+ }
757
+ this.SelectedID = null;
758
+ this.SelectedSurface = surface;
759
+ this.publishAgentContext();
760
+ this.cdr.markForCheck();
761
+ }
762
+ SetDevice(device) {
763
+ this.Device = device === 'mobile' ? 'mobile' : 'desktop';
764
+ this.cdr.markForCheck();
765
+ }
766
+ // ── Preview, agent, shell ───────────────────────────────────────────────────────────────────
767
+ /** After any change: the problems alert, the preview, the agent's view, the shell's edit state, and the view. */
768
+ changed() {
769
+ // A save refused for problems re-checks as you edit (or undo), and its alert goes once they are fixed.
770
+ if (this.problems.length) {
771
+ this.problems = LoginDesignProblems(this.Design);
772
+ this.ErrorMessage = this.problems.length ? this.problemsMessage() : null;
773
+ }
774
+ // The frame wears the DEFAULT theme's look, which is not necessarily the viewer's, as the live login screen does.
775
+ const dark = this.doc.documentElement.getAttribute('data-theme') === 'dark';
776
+ this.FrameStyle = { ...LoginThemeTokens(this.seeds, dark), ...LoginDesignTokens(this.Design) };
777
+ this.publishAgentContext();
778
+ if (this.Unsaved !== this.reportedEditing) {
779
+ this.reportedEditing = this.Unsaved;
780
+ this.NotifyEditModeChanged(this.reportedEditing);
781
+ }
782
+ this.cdr.markForCheck();
783
+ }
784
+ publishAgentContext() {
785
+ this.navigationService.SetAgentContext(this, {
786
+ Surface: 'Login Studio',
787
+ ThemeName: this.Theme?.Name ?? null,
788
+ Status: this.StatusLabel,
789
+ Layout: this.Design.Layout,
790
+ BlockCounts: Object.fromEntries(LOGIN_REGIONS.map((r) => [r, this.Design.Regions[r].length])),
791
+ Selected: this.Selected ? LOGIN_BLOCK_META[this.Selected.Type].Label : this.Surface,
792
+ Problems: LoginDesignProblems(this.Design),
793
+ });
794
+ }
795
+ registerAgentTools() {
796
+ this.navigationService.SetAgentClientTools(this, [
797
+ {
798
+ Name: 'GetSignInPageDesign',
799
+ Description: 'Return the sign-in page design being edited (JSON), its status, and anything that would stop it being saved.',
800
+ ParameterSchema: { type: 'object', properties: {} },
801
+ Handler: async () => ({
802
+ Success: true,
803
+ Data: { Status: this.StatusLabel, Design: this.Design, Problems: LoginDesignProblems(this.Design) },
804
+ }),
805
+ },
806
+ ]);
807
+ }
808
+ static ɵfac = /*@__PURE__*/ (() => { let ɵLoginStudioResourceComponent_BaseFactory; return function LoginStudioResourceComponent_Factory(__ngFactoryType__) { return (ɵLoginStudioResourceComponent_BaseFactory || (ɵLoginStudioResourceComponent_BaseFactory = i0.ɵɵgetInheritedFactory(LoginStudioResourceComponent)))(__ngFactoryType__ || LoginStudioResourceComponent); }; })();
809
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: LoginStudioResourceComponent, selectors: [["mj-login-studio-resource"]], hostBindings: function LoginStudioResourceComponent_HostBindings(rf, ctx) { if (rf & 1) {
810
+ i0.ɵɵlistener("beforeunload", function LoginStudioResourceComponent_beforeunload_HostBindingHandler($event) { return ctx.OnBeforeUnload($event); }, i0.ɵɵresolveWindow)("keydown", function LoginStudioResourceComponent_keydown_HostBindingHandler($event) { return ctx.OnKeydown($event); });
811
+ } }, features: [i0.ɵɵInheritDefinitionFeature], decls: 10, vars: 6, consts: [["Title", "Sign-in Page", "Icon", "fa-solid fa-right-to-bracket", 3, "Subtitle"], ["meta", "", 3, "Label", "Variant"], ["actions", "", 1, "ls__actions"], ["Variant", "error", "Dismissible", "", 1, "ls__alert", 3, "Message"], ["Variant", "success", "Dismissible", "", 1, "ls__alert", 3, "Message"], ["Text", "Reading the sign-in page...", "Size", "medium"], ["Icon", "fa-solid fa-palette", "Title", "No default theme", "Message", "The sign-in page is designed on the default theme. Set one in Theme Studio, under Manage Themes."], ["cdkDropListGroup", "", 1, "ls"], ["type", "button", "mjButton", "", "Variant", "icon", "Size", "sm", "title", "Undo (Ctrl/Cmd Z)", "AriaLabel", "Undo", 3, "click", "disabled"], [1, "fa-solid", "fa-rotate-left"], ["type", "button", "mjButton", "", "Variant", "icon", "Size", "sm", "title", "Redo (Shift Ctrl/Cmd Z)", "AriaLabel", "Redo", 3, "click", "disabled"], [1, "fa-solid", "fa-rotate-right"], ["type", "button", "mjButton", "", "Variant", "outline", "Size", "sm", 3, "click", "disabled"], [1, "fa-regular", "fa-floppy-disk"], ["type", "button", "mjButton", "", "Variant", "primary", "Size", "sm", "title", "Save and show this page to everyone signing in", 3, "click", "disabled"], [1, "fa-solid", "fa-upload"], ["Variant", "error", "Dismissible", "", 1, "ls__alert", 3, "Dismissed", "Message"], ["Variant", "success", "Dismissible", "", 1, "ls__alert", 3, "Dismissed", "Message"], ["aria-label", "Blocks", 1, "ls__palette"], [1, "ls__heading"], [1, "ls__hint"], ["cdkDropList", "", "cdkDropListSortingDisabled", "", 1, "ls__palette-list", 3, "cdkDropListData", "cdkDropListEnterPredicate"], ["type", "button", "mjButton", "", "Variant", "outline", "Size", "sm", "cdkDrag", "", 1, "ls__tile", 3, "cdkDragData", "title"], ["aria-label", "Preview", 1, "ls__stage", 3, "click"], [1, "ls__stage-bar", 3, "click"], ["role", "group", "aria-label", "Preview size", 3, "KeyChange", "Options", "ActiveKey"], [1, "ls__frame"], [1, "lp", 3, "click"], [1, "lp__banner"], [1, "lp__brand"], [1, "lp__region-label"], ["Region", "Banner", 3, "Dropped", "SelectRequested", "CommandRequested", "Blocks", "Logos", "BrandName", "Stacked", "Center", "Editable", "SelectedID"], [1, "lp__default-note"], [1, "lp__panel", 3, "click"], [1, "lp__stack"], ["Region", "PanelTop", 3, "Dropped", "SelectRequested", "CommandRequested", "Blocks", "Logos", "BrandName", "Stacked", "Editable", "SelectedID"], ["aria-hidden", "true", 1, "lp__picker"], [1, "lp__heading"], [1, "lp__signin"], ["Region", "PanelBottom", 3, "Dropped", "SelectRequested", "CommandRequested", "Blocks", "Logos", "BrandName", "Stacked", "Editable", "SelectedID"], ["aria-label", "Settings", 1, "ls__side"], [1, "ls__side-head"], ["aria-hidden", "true"], [1, "ls__side-title"], ["type", "button", "mjButton", "", "Variant", "icon", "Size", "sm", "title", "Page settings", "AriaLabel", "Back to page settings"], [3, "EditRequested", "CommandRequested", "StockPageRequested", "SurfaceSelectRequested", "Design", "Selected", "SelectedRegion", "Surface", "CanReset", "Saving"], ["type", "button", "mjButton", "", "Variant", "outline", "Size", "sm", "cdkDrag", "", 1, "ls__tile", 3, "click", "cdkDragData", "title"], ["type", "button", "mjButton", "", "Variant", "icon", "Size", "sm", "title", "Page settings", "AriaLabel", "Back to page settings", 3, "click"], [1, "fa-solid", "fa-table-columns"]], template: function LoginStudioResourceComponent_Template(rf, ctx) { if (rf & 1) {
812
+ i0.ɵɵelementStart(0, "mj-page-layout")(1, "mj-page-header", 0);
813
+ i0.ɵɵconditionalCreate(2, LoginStudioResourceComponent_Conditional_2_Template, 1, 2, "mj-stat-badge", 1);
814
+ i0.ɵɵconditionalCreate(3, LoginStudioResourceComponent_Conditional_3_Template, 13, 5, "div", 2);
815
+ i0.ɵɵelementEnd();
816
+ i0.ɵɵelementStart(4, "mj-page-body");
817
+ i0.ɵɵconditionalCreate(5, LoginStudioResourceComponent_Conditional_5_Template, 1, 1, "mj-alert", 3);
818
+ i0.ɵɵconditionalCreate(6, LoginStudioResourceComponent_Conditional_6_Template, 1, 1, "mj-alert", 4);
819
+ i0.ɵɵconditionalCreate(7, LoginStudioResourceComponent_Conditional_7_Template, 1, 0, "mj-loading", 5)(8, LoginStudioResourceComponent_Conditional_8_Template, 1, 0, "mj-empty-state", 6)(9, LoginStudioResourceComponent_Conditional_9_Template, 41, 56, "div", 7);
820
+ i0.ɵɵelementEnd()();
821
+ } if (rf & 2) {
822
+ i0.ɵɵadvance();
823
+ i0.ɵɵproperty("Subtitle", ctx.Theme ? "What visitors see before they sign in. Designed on the default theme, " + ctx.Theme.Name + "." : "What visitors see before they sign in.");
824
+ i0.ɵɵadvance();
825
+ i0.ɵɵconditional(ctx.Theme && !ctx.Loading && ctx.StatusVariant ? 2 : -1);
826
+ i0.ɵɵadvance();
827
+ i0.ɵɵconditional(ctx.Theme && !ctx.Loading ? 3 : -1);
828
+ i0.ɵɵadvance(2);
829
+ i0.ɵɵconditional(ctx.ErrorMessage ? 5 : -1);
830
+ i0.ɵɵadvance();
831
+ i0.ɵɵconditional(ctx.NoticeMessage ? 6 : -1);
832
+ i0.ɵɵadvance();
833
+ i0.ɵɵconditional(ctx.Loading ? 7 : !ctx.Theme ? 8 : 9);
834
+ } }, dependencies: [CdkDropListGroup, CdkDropList, CdkDrag, SharedGenericModule, i1.LoadingComponent, MJAlertComponent, MJButtonDirective, MJEmptyStateComponent,
835
+ MJPageLayoutComponent, MJPageHeaderComponent, MJPageBodyComponent, MJStatBadgeComponent, MJViewToggleComponent,
836
+ MJLoginRegionComponent, LoginStudioInspectorComponent], styles: ["\n\n\n[_nghost-%COMP%] {\n display: block;\n width: 100%;\n height: 100%;\n}\n\n.ls__alert[_ngcontent-%COMP%] { margin-bottom: var(--mj-space-4); }\n\n.ls__actions[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--mj-space-2);\n}\n\n.ls__hint[_ngcontent-%COMP%] {\n margin: 0;\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n}\n\n\n\n.ls[_ngcontent-%COMP%] {\n display: grid;\n grid-template-columns: 11rem minmax(0, 1fr) 20rem;\n grid-template-areas: 'palette stage side';\n gap: var(--mj-space-4);\n align-items: start;\n}\n\n.ls__heading[_ngcontent-%COMP%] {\n margin: 0;\n font-size: var(--mj-text-xs);\n font-weight: var(--mj-font-semibold);\n letter-spacing: 0.08em;\n text-transform: uppercase;\n color: var(--mj-text-secondary);\n}\n\n\n.ls__palette[_ngcontent-%COMP%] {\n grid-area: palette;\n position: sticky;\n top: 0;\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-2);\n min-width: 0;\n}\n.ls__palette-list[_ngcontent-%COMP%] {\n display: grid;\n gap: var(--mj-space-2);\n}\n\n.ls__tile[_ngcontent-%COMP%] {\n justify-content: flex-start;\n width: 100%;\n cursor: grab;\n}\n.ls__tile[_ngcontent-%COMP%] i[_ngcontent-%COMP%] {\n width: 1.25rem;\n text-align: center;\n}\n\n.ls__tile.cdk-drag-placeholder[_ngcontent-%COMP%] { opacity: 0.4; }\n.ls__tile.cdk-drag-preview[_ngcontent-%COMP%] {\n width: 10rem;\n box-shadow: var(--mj-shadow-lg);\n}\n\n\n.ls__stage[_ngcontent-%COMP%] {\n grid-area: stage;\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-3);\n min-width: 0;\n}\n.ls__stage-bar[_ngcontent-%COMP%] {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--mj-space-3);\n}\n\n\n.ls__frame[_ngcontent-%COMP%] {\n position: relative;\n overflow: hidden;\n width: 100%;\n height: clamp(30rem, 62vh, 44rem);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n background: var(--mj-login-panel-bg);\n}\n.ls__frame--phone[_ngcontent-%COMP%] {\n width: 24rem;\n max-width: 100%;\n height: 46rem;\n margin-inline: auto;\n border-radius: var(--mj-radius-xl);\n}\n\n\n.ls__side[_ngcontent-%COMP%] {\n grid-area: side;\n position: sticky;\n top: 0;\n max-height: calc(100vh - 10rem);\n overflow-y: auto;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n background: var(--mj-bg-surface);\n}\n.ls__side-head[_ngcontent-%COMP%] {\n position: sticky;\n top: 0;\n z-index: 1;\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n padding: var(--mj-space-3) var(--mj-space-4);\n border-bottom: 1px solid var(--mj-border-subtle);\n background: var(--mj-bg-surface);\n}\n.ls__side-head[_ngcontent-%COMP%] > i[_ngcontent-%COMP%] { color: var(--mj-text-secondary); }\n.ls__side-title[_ngcontent-%COMP%] {\n flex: 1;\n margin: 0;\n font-size: var(--mj-text-sm);\n font-weight: var(--mj-font-semibold);\n color: var(--mj-text-primary);\n}\n\n\n\n.lp[_ngcontent-%COMP%] {\n display: flex;\n height: 100%;\n}\n.lp--reverse[_ngcontent-%COMP%] { flex-direction: row-reverse; }\n\n.lp__banner[_ngcontent-%COMP%] {\n box-sizing: border-box;\n display: flex;\n flex: var(--mj-login-banner-flex) 1 0;\n flex-direction: column;\n align-items: flex-start;\n overflow-y: auto;\n padding: var(--mj-space-10) var(--mj-space-8);\n background: var(--mj-login-banner-bg);\n color: var(--mj-login-banner-text);\n}\n.lp__banner--center[_ngcontent-%COMP%] { align-items: center; }\n.lp__brand[_ngcontent-%COMP%] {\n width: 100%;\n margin-block: auto;\n}\n\n.lp__panel[_ngcontent-%COMP%] {\n box-sizing: border-box;\n display: flex;\n flex: var(--mj-login-panel-flex) 1 0;\n flex-direction: column;\n align-items: center;\n overflow-y: auto;\n padding: var(--mj-space-8) var(--mj-space-6);\n background: var(--mj-login-panel-bg);\n color: var(--mj-login-panel-text);\n}\n.lp__stack[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-3);\n width: 100%;\n max-width: var(--mj-login-picker-max-width);\n margin-block: auto;\n}\n\n.lp__picker[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n gap: var(--mj-space-3);\n padding-block: var(--mj-space-2);\n}\n\n.lp__heading[_ngcontent-%COMP%] {\n font-size: var(--mj-text-2xl);\n font-weight: var(--mj-font-bold);\n color: var(--mj-login-panel-text);\n}\n.lp__signin[_ngcontent-%COMP%] {\n display: block;\n padding: var(--mj-space-3);\n border-radius: var(--mj-radius-md);\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-weight: var(--mj-font-semibold);\n text-align: center;\n}\n\n.lp__region-label[_ngcontent-%COMP%] {\n display: block;\n margin-bottom: calc(-1 * var(--mj-space-2));\n font-size: var(--mj-text-xs);\n font-weight: var(--mj-font-semibold);\n letter-spacing: 0.08em;\n text-transform: uppercase;\n opacity: 0.55;\n}\n.lp__banner[_ngcontent-%COMP%] .lp__region-label[_ngcontent-%COMP%] { margin-bottom: var(--mj-space-1); }\n.lp__default-note[_ngcontent-%COMP%] {\n margin: var(--mj-space-2) 0 0;\n font-size: var(--mj-text-xs);\n opacity: 0.75;\n}\n\n\n.lp--centered[_ngcontent-%COMP%] {\n flex-direction: column;\n align-items: center;\n overflow-y: auto;\n padding: var(--mj-space-8) var(--mj-space-4);\n background: var(--mj-login-banner-bg);\n}\n.lp--centered[_ngcontent-%COMP%] .lp__banner[_ngcontent-%COMP%] {\n flex: 0 0 auto;\n width: 100%;\n overflow: visible;\n padding: 0 0 var(--mj-space-6);\n background: none;\n align-items: center;\n}\n.lp--centered[_ngcontent-%COMP%] .lp__panel[_ngcontent-%COMP%] {\n flex: 0 0 auto;\n width: 100%;\n max-width: var(--mj-login-centered-card-width);\n overflow: visible;\n border-radius: var(--mj-radius-lg);\n box-shadow: var(--mj-shadow-lg);\n}\n\n\n.lp--stacked[_ngcontent-%COMP%] { flex-direction: column; }\n.lp--stacked[_ngcontent-%COMP%]:not(.lp--centered) .lp__banner[_ngcontent-%COMP%] {\n flex: 0 0 auto;\n height: 35%;\n padding: var(--mj-space-5);\n align-items: center;\n}\n.lp--stacked[_ngcontent-%COMP%]:not(.lp--centered) .lp__brand[_ngcontent-%COMP%] { margin-block: auto 0; }\n.lp--stacked[_ngcontent-%COMP%]:not(.lp--centered) .lp__panel[_ngcontent-%COMP%] {\n flex: 1 1 auto;\n padding: var(--mj-space-6) var(--mj-space-4);\n}\n\n\n\n.lp__banner[_ngcontent-%COMP%], \n.lp__panel[_ngcontent-%COMP%], \n.lp--centered[_ngcontent-%COMP%] { cursor: pointer; }\n.lp__surface-on[_ngcontent-%COMP%], \n.lp--surface-on[_ngcontent-%COMP%] { box-shadow: inset 0 0 0 2px var(--mj-brand-primary); }\n.lp--centered[_ngcontent-%COMP%] .lp__panel.lp__surface-on[_ngcontent-%COMP%] { box-shadow: var(--mj-shadow-lg), 0 0 0 2px var(--mj-brand-primary); }\n\n\n\n@media (max-width: 1280px) {\n .ls[_ngcontent-%COMP%] {\n grid-template-columns: minmax(0, 1fr) 19rem;\n grid-template-areas:\n 'palette palette'\n 'stage side';\n }\n .ls__palette[_ngcontent-%COMP%] { position: static; }\n .ls__palette-list[_ngcontent-%COMP%] { grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr)); }\n}\n\n@media (max-width: 900px) {\n .ls[_ngcontent-%COMP%] {\n grid-template-columns: minmax(0, 1fr);\n grid-template-areas: 'palette' 'stage' 'side';\n }\n .ls__side[_ngcontent-%COMP%] {\n position: static;\n max-height: none;\n }\n}"], changeDetection: 0 });
837
+ };
838
+ LoginStudioResourceComponent = __decorate([
839
+ RegisterClass(BaseResourceComponent, 'LoginStudioResource')
840
+ ], LoginStudioResourceComponent);
841
+ export { LoginStudioResourceComponent };
842
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(LoginStudioResourceComponent, [{
843
+ type: Component,
844
+ args: [{ standalone: true, selector: 'mj-login-studio-resource', imports: [
845
+ CdkDropListGroup, CdkDropList, CdkDrag, SharedGenericModule, MJAlertComponent, MJButtonDirective, MJEmptyStateComponent,
846
+ MJPageLayoutComponent, MJPageHeaderComponent, MJPageBodyComponent, MJStatBadgeComponent, MJViewToggleComponent,
847
+ MJLoginRegionComponent, LoginStudioInspectorComponent,
848
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<mj-page-layout>\n <mj-page-header Title=\"Sign-in Page\" Icon=\"fa-solid fa-right-to-bracket\"\n [Subtitle]=\"Theme ? 'What visitors see before they sign in. Designed on the default theme, ' + Theme.Name + '.' : 'What visitors see before they sign in.'\">\n <!-- One root element per block: a control-flow block is projected by its single root's selector. -->\n @if (Theme && !Loading && StatusVariant) {\n <mj-stat-badge meta [Label]=\"StatusLabel\" [Variant]=\"StatusVariant\"></mj-stat-badge>\n }\n @if (Theme && !Loading) {\n <div actions class=\"ls__actions\">\n <button type=\"button\" mjButton Variant=\"icon\" Size=\"sm\" (click)=\"Undo()\" [disabled]=\"!CanUndo\" title=\"Undo (Ctrl/Cmd Z)\" AriaLabel=\"Undo\"><i class=\"fa-solid fa-rotate-left\"></i></button>\n <button type=\"button\" mjButton Variant=\"icon\" Size=\"sm\" (click)=\"Redo()\" [disabled]=\"!CanRedo\" title=\"Redo (Shift Ctrl/Cmd Z)\" AriaLabel=\"Redo\"><i class=\"fa-solid fa-rotate-right\"></i></button>\n <button type=\"button\" mjButton Variant=\"outline\" Size=\"sm\" (click)=\"Discard()\" [disabled]=\"!Unsaved || Saving\">Discard changes</button>\n <button type=\"button\" mjButton Variant=\"outline\" Size=\"sm\" (click)=\"SaveDraft()\" [disabled]=\"Saving || !Unsaved\">\n <i class=\"fa-regular fa-floppy-disk\"></i> Save draft\n </button>\n <button type=\"button\" mjButton Variant=\"primary\" Size=\"sm\" (click)=\"Publish()\"\n [disabled]=\"Saving || (!Unsaved && !Unpublished && IsLive)\" title=\"Save and show this page to everyone signing in\">\n <i class=\"fa-solid fa-upload\"></i> Publish\n </button>\n </div>\n }\n </mj-page-header>\n\n <mj-page-body>\n @if (ErrorMessage) {\n <mj-alert class=\"ls__alert\" Variant=\"error\" [Message]=\"ErrorMessage\" Dismissible (Dismissed)=\"DismissError()\"></mj-alert>\n }\n @if (NoticeMessage) {\n <mj-alert class=\"ls__alert\" Variant=\"success\" [Message]=\"NoticeMessage\" Dismissible (Dismissed)=\"DismissNotice()\"></mj-alert>\n }\n\n @if (Loading) {\n <mj-loading Text=\"Reading the sign-in page...\" Size=\"medium\"></mj-loading>\n } @else if (!Theme) {\n <mj-empty-state Icon=\"fa-solid fa-palette\" Title=\"No default theme\"\n Message=\"The sign-in page is designed on the default theme. Set one in Theme Studio, under Manage Themes.\"></mj-empty-state>\n } @else {\n <div class=\"ls\" cdkDropListGroup>\n <!-- PALETTE -->\n <aside class=\"ls__palette\" aria-label=\"Blocks\">\n <h2 class=\"ls__heading\">Blocks</h2>\n <p class=\"ls__hint\">Drag a block onto the page, or click one to add it after the selected block.</p>\n <div class=\"ls__palette-list\" cdkDropList [cdkDropListData]=\"PaletteListID\" cdkDropListSortingDisabled\n [cdkDropListEnterPredicate]=\"NoEnter\">\n @for (t of Palette; track t.Type) {\n <button type=\"button\" mjButton Variant=\"outline\" Size=\"sm\" class=\"ls__tile\" cdkDrag [cdkDragData]=\"t.Type\" (click)=\"AddBlock(t.Type)\" [title]=\"t.Hint\">\n <i [class]=\"t.Icon\" aria-hidden=\"true\"></i>\n <span>{{ t.Label }}</span>\n </button>\n }\n </div>\n </aside>\n\n <!-- PREVIEW -->\n <section class=\"ls__stage\" (click)=\"OnStageClick()\" aria-label=\"Preview\">\n <div class=\"ls__stage-bar\" (click)=\"$event.stopPropagation()\">\n <mj-view-toggle role=\"group\" aria-label=\"Preview size\" [Options]=\"DeviceOptions\" [ActiveKey]=\"Device\" (KeyChange)=\"SetDevice($event)\"></mj-view-toggle>\n <span class=\"ls__hint\">The sign-in button is a stand-in. The real one opens your sign-in provider.</span>\n </div>\n\n <div class=\"ls__frame\" [class.ls__frame--phone]=\"Stacked\" [style]=\"FrameStyle\">\n <!-- Clicking the page selects what was clicked: a block (it stops the click), the sign-in column,\n or else the story panel, which in the centered layout is the whole background. -->\n <div class=\"lp\" [class.lp--reverse]=\"Design.Layout === 'split-reverse'\" [class.lp--centered]=\"Design.Layout === 'centered'\"\n [class.lp--stacked]=\"Stacked\" [class.lp--surface-on]=\"Surface === 'Banner' && Design.Layout === 'centered'\"\n (click)=\"SelectSurface('Banner', $event)\">\n <div class=\"lp__banner\" [class.lp__banner--center]=\"Design.Alignment === 'center' || Stacked\"\n [class.lp__surface-on]=\"Surface === 'Banner' && Design.Layout !== 'centered'\">\n <div class=\"lp__brand\">\n <span class=\"lp__region-label\">{{ RegionLabel.Banner }}</span>\n <mj-login-region Region=\"Banner\" [Blocks]=\"Design.Regions.Banner\" [Logos]=\"Logos\" [BrandName]=\"Theme.Name\"\n [Stacked]=\"Stacked\" [Center]=\"Design.Alignment === 'center' || Stacked\" [Editable]=\"true\"\n [SelectedID]=\"SelectedID\"\n (Dropped)=\"OnDrop($event)\" (SelectRequested)=\"Select($event)\" (CommandRequested)=\"OnCommand($event)\"></mj-login-region>\n @if (!Design.Regions.Banner.length) {\n <p class=\"lp__default-note\">Empty: visitors see the stock logo and \"Welcome back\" here.</p>\n }\n </div>\n </div>\n <div class=\"lp__panel\" [class.lp__surface-on]=\"Surface === 'Panel'\" (click)=\"SelectSurface('Panel', $event)\">\n <div class=\"lp__stack\">\n <span class=\"lp__region-label\">{{ RegionLabel.PanelTop }}</span>\n <mj-login-region Region=\"PanelTop\" [Blocks]=\"Design.Regions.PanelTop\" [Logos]=\"Logos\" [BrandName]=\"Theme.Name\"\n [Stacked]=\"Stacked\" [Editable]=\"true\" [SelectedID]=\"SelectedID\"\n (Dropped)=\"OnDrop($event)\" (SelectRequested)=\"Select($event)\" (CommandRequested)=\"OnCommand($event)\"></mj-login-region>\n <div class=\"lp__picker\" aria-hidden=\"true\">\n @if (Design.Heading) {\n <span class=\"lp__heading\">{{ Design.Heading }}</span>\n }\n <span class=\"lp__signin\">Log in</span>\n </div>\n <span class=\"lp__region-label\">{{ RegionLabel.PanelBottom }}</span>\n <mj-login-region Region=\"PanelBottom\" [Blocks]=\"Design.Regions.PanelBottom\" [Logos]=\"Logos\" [BrandName]=\"Theme.Name\"\n [Stacked]=\"Stacked\" [Editable]=\"true\" [SelectedID]=\"SelectedID\"\n (Dropped)=\"OnDrop($event)\" (SelectRequested)=\"Select($event)\" (CommandRequested)=\"OnCommand($event)\"></mj-login-region>\n </div>\n </div>\n </div>\n </div>\n </section>\n\n <!-- INSPECTOR -->\n <aside class=\"ls__side\" aria-label=\"Settings\">\n <div class=\"ls__side-head\">\n <i [class]=\"SideIcon\" aria-hidden=\"true\"></i>\n <h2 class=\"ls__side-title\">{{ SideTitle }}</h2>\n @if (Selected || Surface) {\n <button type=\"button\" mjButton Variant=\"icon\" Size=\"sm\" (click)=\"Select(null)\" title=\"Page settings\" AriaLabel=\"Back to page settings\">\n <i class=\"fa-solid fa-table-columns\"></i>\n </button>\n }\n </div>\n <mj-login-studio-inspector [Design]=\"Design\" [Selected]=\"Selected\" [SelectedRegion]=\"SelectedRegion\" [Surface]=\"Surface\"\n [CanReset]=\"IsLive || Unpublished\" [Saving]=\"Saving\"\n (EditRequested)=\"ApplyEdit($event)\" (CommandRequested)=\"OnCommand($event)\"\n (StockPageRequested)=\"UseStockPage()\" (SurfaceSelectRequested)=\"SelectSurface($event)\"></mj-login-studio-inspector>\n </aside>\n </div>\n }\n </mj-page-body>\n</mj-page-layout>\n", styles: ["/* Login Studio: the editor's three columns (blocks | preview | settings), then a picture of the Explorer\n login screen inside the preview frame, drawn with this screen's own classes and the --mj-login-* tokens. */\n\n:host {\n display: block;\n width: 100%;\n height: 100%;\n}\n\n.ls__alert { margin-bottom: var(--mj-space-4); }\n\n.ls__actions {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--mj-space-2);\n}\n\n.ls__hint {\n margin: 0;\n font-size: var(--mj-text-xs);\n color: var(--mj-text-muted);\n}\n\n/* ============================== THE EDITOR ============================== */\n\n.ls {\n display: grid;\n grid-template-columns: 11rem minmax(0, 1fr) 20rem;\n grid-template-areas: 'palette stage side';\n gap: var(--mj-space-4);\n align-items: start;\n}\n\n.ls__heading {\n margin: 0;\n font-size: var(--mj-text-xs);\n font-weight: var(--mj-font-semibold);\n letter-spacing: 0.08em;\n text-transform: uppercase;\n color: var(--mj-text-secondary);\n}\n\n/* \u2500\u2500 blocks \u2500\u2500 */\n.ls__palette {\n grid-area: palette;\n position: sticky;\n top: 0;\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-2);\n min-width: 0;\n}\n.ls__palette-list {\n display: grid;\n gap: var(--mj-space-2);\n}\n/* Layout only: the tile's look is mjButton's. */\n.ls__tile {\n justify-content: flex-start;\n width: 100%;\n cursor: grab;\n}\n.ls__tile i {\n width: 1.25rem;\n text-align: center;\n}\n/* Dragged out, the tile keeps its place in the palette (a drop creates a block; it moves nothing). */\n.ls__tile.cdk-drag-placeholder { opacity: 0.4; }\n.ls__tile.cdk-drag-preview {\n width: 10rem;\n box-shadow: var(--mj-shadow-lg);\n}\n\n/* \u2500\u2500 preview \u2500\u2500 */\n.ls__stage {\n grid-area: stage;\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-3);\n min-width: 0;\n}\n.ls__stage-bar {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--mj-space-3);\n}\n\n/* A desktop-proportioned page, or a phone. */\n.ls__frame {\n position: relative;\n overflow: hidden;\n width: 100%;\n height: clamp(30rem, 62vh, 44rem);\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n background: var(--mj-login-panel-bg);\n}\n.ls__frame--phone {\n width: 24rem;\n max-width: 100%;\n height: 46rem;\n margin-inline: auto;\n border-radius: var(--mj-radius-xl);\n}\n\n/* \u2500\u2500 settings \u2500\u2500 */\n.ls__side {\n grid-area: side;\n position: sticky;\n top: 0;\n max-height: calc(100vh - 10rem);\n overflow-y: auto;\n border: 1px solid var(--mj-border-default);\n border-radius: var(--mj-radius-lg);\n background: var(--mj-bg-surface);\n}\n.ls__side-head {\n position: sticky;\n top: 0;\n z-index: 1;\n display: flex;\n align-items: center;\n gap: var(--mj-space-2);\n padding: var(--mj-space-3) var(--mj-space-4);\n border-bottom: 1px solid var(--mj-border-subtle);\n background: var(--mj-bg-surface);\n}\n.ls__side-head > i { color: var(--mj-text-secondary); }\n.ls__side-title {\n flex: 1;\n margin: 0;\n font-size: var(--mj-text-sm);\n font-weight: var(--mj-font-semibold);\n color: var(--mj-text-primary);\n}\n\n/* ============================== THE PICTURE OF THE LOGIN SCREEN ============================== */\n\n.lp {\n display: flex;\n height: 100%;\n}\n.lp--reverse { flex-direction: row-reverse; }\n\n.lp__banner {\n box-sizing: border-box;\n display: flex;\n flex: var(--mj-login-banner-flex) 1 0;\n flex-direction: column;\n align-items: flex-start;\n overflow-y: auto;\n padding: var(--mj-space-10) var(--mj-space-8);\n background: var(--mj-login-banner-bg);\n color: var(--mj-login-banner-text);\n}\n.lp__banner--center { align-items: center; }\n.lp__brand {\n width: 100%;\n margin-block: auto;\n}\n\n.lp__panel {\n box-sizing: border-box;\n display: flex;\n flex: var(--mj-login-panel-flex) 1 0;\n flex-direction: column;\n align-items: center;\n overflow-y: auto;\n padding: var(--mj-space-8) var(--mj-space-6);\n background: var(--mj-login-panel-bg);\n color: var(--mj-login-panel-text);\n}\n.lp__stack {\n display: flex;\n flex-direction: column;\n gap: var(--mj-space-3);\n width: 100%;\n max-width: var(--mj-login-picker-max-width);\n margin-block: auto;\n}\n\n.lp__picker {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n gap: var(--mj-space-3);\n padding-block: var(--mj-space-2);\n}\n/* As <mj-login-picker> draws its heading. */\n.lp__heading {\n font-size: var(--mj-text-2xl);\n font-weight: var(--mj-font-bold);\n color: var(--mj-login-panel-text);\n}\n.lp__signin {\n display: block;\n padding: var(--mj-space-3);\n border-radius: var(--mj-radius-md);\n background: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n font-weight: var(--mj-font-semibold);\n text-align: center;\n}\n\n.lp__region-label {\n display: block;\n margin-bottom: calc(-1 * var(--mj-space-2));\n font-size: var(--mj-text-xs);\n font-weight: var(--mj-font-semibold);\n letter-spacing: 0.08em;\n text-transform: uppercase;\n opacity: 0.55;\n}\n.lp__banner .lp__region-label { margin-bottom: var(--mj-space-1); }\n.lp__default-note {\n margin: var(--mj-space-2) 0 0;\n font-size: var(--mj-text-xs);\n opacity: 0.75;\n}\n\n/* Centered: one column on the banner background, the sign-in options a card on top of it. */\n.lp--centered {\n flex-direction: column;\n align-items: center;\n overflow-y: auto;\n padding: var(--mj-space-8) var(--mj-space-4);\n background: var(--mj-login-banner-bg);\n}\n.lp--centered .lp__banner {\n flex: 0 0 auto;\n width: 100%;\n overflow: visible;\n padding: 0 0 var(--mj-space-6);\n background: none;\n align-items: center;\n}\n.lp--centered .lp__panel {\n flex: 0 0 auto;\n width: 100%;\n max-width: var(--mj-login-centered-card-width);\n overflow: visible;\n border-radius: var(--mj-radius-lg);\n box-shadow: var(--mj-shadow-lg);\n}\n\n/* Stacked (the login screen's 900px layout, where the banner is 35dvh): the banner shortens above the sign-in column. */\n.lp--stacked { flex-direction: column; }\n.lp--stacked:not(.lp--centered) .lp__banner {\n flex: 0 0 auto;\n height: 35%;\n padding: var(--mj-space-5);\n align-items: center;\n}\n.lp--stacked:not(.lp--centered) .lp__brand { margin-block: auto 0; }\n.lp--stacked:not(.lp--centered) .lp__panel {\n flex: 1 1 auto;\n padding: var(--mj-space-6) var(--mj-space-4);\n}\n\n/* The story panel and the sign-in column are selectable (their settings and colors open in the\n inspector): a pointer says so, and the selected one is outlined. Inset, because both scroll. */\n.lp__banner,\n.lp__panel,\n.lp--centered { cursor: pointer; }\n.lp__surface-on,\n.lp--surface-on { box-shadow: inset 0 0 0 2px var(--mj-brand-primary); }\n.lp--centered .lp__panel.lp__surface-on { box-shadow: var(--mj-shadow-lg), 0 0 0 2px var(--mj-brand-primary); }\n\n/* ============================== NARROWER ============================== */\n\n@media (max-width: 1280px) {\n .ls {\n grid-template-columns: minmax(0, 1fr) 19rem;\n grid-template-areas:\n 'palette palette'\n 'stage side';\n }\n .ls__palette { position: static; }\n .ls__palette-list { grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr)); }\n}\n\n@media (max-width: 900px) {\n .ls {\n grid-template-columns: minmax(0, 1fr);\n grid-template-areas: 'palette' 'stage' 'side';\n }\n .ls__side {\n position: static;\n max-height: none;\n }\n}\n"] }]
849
+ }], null, { OnBeforeUnload: [{
850
+ type: HostListener,
851
+ args: ['window:beforeunload', ['$event']]
852
+ }], OnKeydown: [{
853
+ type: HostListener,
854
+ args: ['keydown', ['$event']]
855
+ }] }); })();
856
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(LoginStudioResourceComponent, { className: "LoginStudioResourceComponent", filePath: "src/LoginStudio/login-studio-resource.component.ts", lineNumber: 61 }); })();
857
+ //# sourceMappingURL=login-studio-resource.component.js.map