phoenix-ui-components 4.0.0 → 4.1.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.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Component, EventEmitter, Output, Input, ViewEncapsulation, ViewChild, Injectable, ContentChild, Pipe, ViewChildren, Inject, ErrorHandler, NgModule } from '@angular/core';
2
+ import { Component, EventEmitter, Output, Input, ViewEncapsulation, ViewChild, Injectable, Inject, ContentChild, Pipe, ViewChildren, ErrorHandler, NgModule } from '@angular/core';
3
3
  import * as i1 from '@angular/router';
4
4
  import { RouterModule } from '@angular/router';
5
5
  import * as i2 from '@angular/common';
@@ -14,27 +14,33 @@ import * as i4$1 from '@angular/material/slide-toggle';
14
14
  import { MatSlideToggleModule } from '@angular/material/slide-toggle';
15
15
  import * as i5 from '@angular/material/checkbox';
16
16
  import { MatCheckboxModule } from '@angular/material/checkbox';
17
- import { EventDisplay, SceneManager, PrettySymbols, Edm4hepJsonLoader, JiveXMLLoader, PHYSLITELoader, CMSLoader, readZipFile, VRManager, XRSessionType, ARManager, phoenixURLOptions, ActiveVariable, getAvailableColumns, DEFAULT_ETA_PHI_CONFIG, ATLAS_KINEMATICS, ATLAS_MASTERCLASS_CONFIG, invariantMass, fourMomentumFromCluster, fourMomentumFromTrack } from 'phoenix-event-display';
18
- import * as i3$2 from '@angular/material/menu';
19
- import { MatMenuTrigger, MatMenuModule } from '@angular/material/menu';
17
+ import * as i1$1 from '@angular/material/dialog';
18
+ import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
19
+ import * as i2$2 from '@angular/material/icon';
20
+ import { MatIconModule } from '@angular/material/icon';
21
+ import { ActiveVariable, EventDisplay, SceneManager, PrettySymbols, Edm4hepJsonLoader, JiveXMLLoader, PHYSLITELoader, ATLASESDLoader, CMSLoader, readZipFile, VRManager, XRSessionType, ARManager, phoenixURLOptions, getAvailableColumns, DEFAULT_ETA_PHI_CONFIG, ATLAS_KINEMATICS, ATLAS_MASTERCLASS_CONFIG, invariantMass, fourMomentumFromCluster, fourMomentumFromTrack } from 'phoenix-event-display';
22
+ import * as i2$3 from '@angular/material/snack-bar';
23
+ import { MatSnackBarModule } from '@angular/material/snack-bar';
24
+ import RecordRTC from 'recordrtc';
25
+ import * as i1$2 from '@angular/material/progress-bar';
26
+ import { MatProgressBarModule } from '@angular/material/progress-bar';
27
+ import { BehaviorSubject } from 'rxjs';
20
28
  import * as i3$1 from '@angular/material/tooltip';
21
29
  import { MatTooltipModule } from '@angular/material/tooltip';
22
- import { ComponentPortal } from '@angular/cdk/portal';
30
+ import * as i4$2 from '@angular/material/menu';
31
+ import { MatMenuTrigger, MatMenuModule } from '@angular/material/menu';
23
32
  import { ResizeSensor } from 'css-element-queries';
24
- import * as i3$3 from '@angular/cdk/drag-drop';
33
+ import * as i3$2 from '@angular/cdk/drag-drop';
25
34
  import { DragDropModule } from '@angular/cdk/drag-drop';
26
- import * as i1$1 from '@angular/cdk/overlay';
35
+ import { ComponentPortal } from '@angular/cdk/portal';
36
+ import * as i1$3 from '@angular/cdk/overlay';
27
37
  import { OverlayModule } from '@angular/cdk/overlay';
28
38
  import packageJson from 'phoenix-event-display/package.json';
29
- import * as i1$2 from '@angular/material/dialog';
30
- import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
31
- import * as i4$2 from '@angular/material/icon';
32
- import { MatIconModule } from '@angular/material/icon';
33
39
  import { Vector3 } from 'three';
34
40
  import * as i5$1 from '@angular/material/radio';
35
41
  import { MatRadioModule } from '@angular/material/radio';
36
42
  import QRCode from 'qrcode';
37
- import * as i2$2 from '@angular/cdk/tree';
43
+ import * as i2$4 from '@angular/cdk/tree';
38
44
  import { NestedTreeControl, CdkTreeModule } from '@angular/cdk/tree';
39
45
  import { MatTreeNestedDataSource } from '@angular/material/tree';
40
46
  import JSZip from 'jszip';
@@ -45,7 +51,7 @@ class NavComponent {
45
51
  constructor() { }
46
52
  ngOnInit() { }
47
53
  static ɵfac = function NavComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || NavComponent)(); };
48
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: NavComponent, selectors: [["app-nav"]], standalone: false, decls: 2, vars: 0, consts: [["id", "mainLogo", "routerLink", "/", 1, "main-logo", "fixed-top", "p-2", "mx-auto", "mt-2"], ["src", "assets/images/logo-text.svg"]], template: function NavComponent_Template(rf, ctx) { if (rf & 1) {
54
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: NavComponent, selectors: [["app-nav"]], standalone: false, decls: 2, vars: 0, consts: [["id", "mainLogo", "routerLink", "/", "aria-label", "Phoenix home", 1, "main-logo", "fixed-top", "p-2", "mx-auto", "mt-2"], ["src", "assets/images/logo-text.svg", "alt", "Phoenix logo"]], template: function NavComponent_Template(rf, ctx) { if (rf & 1) {
49
55
  i0.ɵɵelementStart(0, "a", 0);
50
56
  i0.ɵɵelement(1, "img", 1);
51
57
  i0.ɵɵelementEnd();
@@ -53,7 +59,7 @@ class NavComponent {
53
59
  }
54
60
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(NavComponent, [{
55
61
  type: Component,
56
- args: [{ standalone: false, selector: 'app-nav', template: "<a id=\"mainLogo\" class=\"main-logo fixed-top p-2 mx-auto mt-2\" routerLink=\"/\">\n <img src=\"assets/images/logo-text.svg\" />\n</a>\n", styles: [".main-logo{width:140px;z-index:9999}.main-logo img{transition:all .5s}.main-logo:hover img{filter:drop-shadow(0px 0px 10px var(--phoenix-text-color));transition:all .5s}\n"] }]
62
+ args: [{ standalone: false, selector: 'app-nav', template: "<a\n id=\"mainLogo\"\n class=\"main-logo fixed-top p-2 mx-auto mt-2\"\n routerLink=\"/\"\n aria-label=\"Phoenix home\"\n>\n <img src=\"assets/images/logo-text.svg\" alt=\"Phoenix logo\" />\n</a>\n", styles: [".main-logo{width:140px;z-index:9999}.main-logo img{transition:all .5s}.main-logo:hover img{filter:drop-shadow(0px 0px 10px var(--phoenix-text-color));transition:all .5s}\n"] }]
57
63
  }], () => [], null); })();
58
64
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(NavComponent, { className: "NavComponent", filePath: "components/nav/nav.component.ts", lineNumber: 9 }); })();
59
65
 
@@ -136,48 +142,80 @@ class ConfigSliderComponent {
136
142
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ConfigSliderComponent, { className: "ConfigSliderComponent", filePath: "components/phoenix-menu/config/config-slider/config-slider.component.ts", lineNumber: 11 }); })();
137
143
 
138
144
  const _c0$e = ["phoenixMenuItem"];
139
- const _c1$7 = a0 => ({ "top.px": a0 });
140
- const _c2$3 = a0 => ({ "font-weight-bold w-100": a0 });
141
- const _c3$2 = a0 => ({ "p-0": a0 });
142
- const _c4$2 = a0 => ({ expanded: a0 });
143
- function PhoenixMenuItemComponent_ng_container_3_ng_container_2_Template(rf, ctx) { if (rf & 1) {
145
+ const _c1$7 = a0 => ({ expanded: a0 });
146
+ const _c2$3 = a0 => ({ "top.px": a0 });
147
+ const _c3$2 = a0 => ({ "range-slider-row": a0 });
148
+ const _c4$2 = a0 => ({ "font-weight-bold w-100": a0 });
149
+ const _c5$2 = a0 => ({ "p-0": a0 });
150
+ function PhoenixMenuItemComponent_div_0_ng_container_8_Template(rf, ctx) { if (rf & 1) {
144
151
  i0.ɵɵelementContainer(0);
145
152
  } }
146
- function PhoenixMenuItemComponent_ng_container_3_Template(rf, ctx) { if (rf & 1) {
153
+ function PhoenixMenuItemComponent_div_0_Template(rf, ctx) { if (rf & 1) {
147
154
  const _r1 = i0.ɵɵgetCurrentView();
155
+ i0.ɵɵelementStart(0, "div", 6, 2)(2, "button", 7);
156
+ i0.ɵɵlistener("click", function PhoenixMenuItemComponent_div_0_Template_button_click_2_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); ctx_r1.calculateConfigTop(); return i0.ɵɵresetView(ctx_r1.currentNode.configActive = !ctx_r1.currentNode.configActive); });
157
+ i0.ɵɵelementStart(3, "span", 8);
158
+ i0.ɵɵnamespaceSVG();
159
+ i0.ɵɵelementStart(4, "svg");
160
+ i0.ɵɵelement(5, "use");
161
+ i0.ɵɵelementEnd()();
162
+ i0.ɵɵnamespaceHTML();
163
+ i0.ɵɵelementStart(6, "span", 9);
164
+ i0.ɵɵtext(7);
165
+ i0.ɵɵelementEnd()();
166
+ i0.ɵɵtemplate(8, PhoenixMenuItemComponent_div_0_ng_container_8_Template, 1, 0, "ng-container", 10);
167
+ i0.ɵɵelementEnd();
168
+ } if (rf & 2) {
169
+ const ctx_r1 = i0.ɵɵnextContext();
170
+ const configPopup_r3 = i0.ɵɵreference(5);
171
+ i0.ɵɵadvance(2);
172
+ i0.ɵɵproperty("title", ctx_r1.currentNode.name);
173
+ i0.ɵɵadvance(3);
174
+ i0.ɵɵattribute("href", i0.ɵɵinterpolate2("assets/icons/", ctx_r1.currentNode.icon, ".svg#", ctx_r1.currentNode.icon));
175
+ i0.ɵɵadvance(2);
176
+ i0.ɵɵtextInterpolate(ctx_r1.compactLabel);
177
+ i0.ɵɵadvance();
178
+ i0.ɵɵproperty("ngTemplateOutlet", configPopup_r3);
179
+ } }
180
+ function PhoenixMenuItemComponent_ng_template_1_ng_container_3_ng_container_2_Template(rf, ctx) { if (rf & 1) {
181
+ i0.ɵɵelementContainer(0);
182
+ } }
183
+ function PhoenixMenuItemComponent_ng_template_1_ng_container_3_Template(rf, ctx) { if (rf & 1) {
184
+ const _r4 = i0.ɵɵgetCurrentView();
148
185
  i0.ɵɵelementContainerStart(0);
149
- i0.ɵɵelementStart(1, "mat-slide-toggle", 9);
150
- i0.ɵɵlistener("change", function PhoenixMenuItemComponent_ng_container_3_Template_mat_slide_toggle_change_1_listener($event) { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.currentNode.toggleSelfAndDescendants($event.checked)); });
151
- i0.ɵɵtemplate(2, PhoenixMenuItemComponent_ng_container_3_ng_container_2_Template, 1, 0, "ng-container", 10);
186
+ i0.ɵɵelementStart(1, "mat-slide-toggle", 17);
187
+ i0.ɵɵlistener("change", function PhoenixMenuItemComponent_ng_template_1_ng_container_3_Template_mat_slide_toggle_change_1_listener($event) { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.currentNode.toggleSelfAndDescendants($event.checked)); });
188
+ i0.ɵɵtemplate(2, PhoenixMenuItemComponent_ng_template_1_ng_container_3_ng_container_2_Template, 1, 0, "ng-container", 10);
152
189
  i0.ɵɵelementEnd();
153
190
  i0.ɵɵelementContainerEnd();
154
191
  } if (rf & 2) {
192
+ i0.ɵɵnextContext();
193
+ const nodeName_r5 = i0.ɵɵreference(5);
155
194
  const ctx_r1 = i0.ɵɵnextContext();
156
- const nodeName_r3 = i0.ɵɵreference(5);
157
195
  i0.ɵɵadvance();
158
196
  i0.ɵɵproperty("checked", ctx_r1.currentNode.toggleState);
159
197
  i0.ɵɵadvance();
160
- i0.ɵɵproperty("ngTemplateOutlet", nodeName_r3);
198
+ i0.ɵɵproperty("ngTemplateOutlet", nodeName_r5);
161
199
  } }
162
- function PhoenixMenuItemComponent_ng_template_4_span_1_Template(rf, ctx) { if (rf & 1) {
163
- i0.ɵɵelementStart(0, "span", 14);
200
+ function PhoenixMenuItemComponent_ng_template_1_ng_template_4_span_1_Template(rf, ctx) { if (rf & 1) {
201
+ i0.ɵɵelementStart(0, "span", 21);
164
202
  i0.ɵɵnamespaceSVG();
165
203
  i0.ɵɵelementStart(1, "svg");
166
204
  i0.ɵɵelement(2, "use");
167
205
  i0.ɵɵelementEnd()();
168
206
  } if (rf & 2) {
169
- const ctx_r1 = i0.ɵɵnextContext(2);
207
+ const ctx_r1 = i0.ɵɵnextContext(3);
170
208
  i0.ɵɵadvance(2);
171
209
  i0.ɵɵattribute("href", i0.ɵɵinterpolate2("assets/icons/", ctx_r1.currentNode.icon, ".svg#", ctx_r1.currentNode.icon));
172
210
  } }
173
- function PhoenixMenuItemComponent_ng_template_4_Template(rf, ctx) { if (rf & 1) {
174
- i0.ɵɵelementStart(0, "span", 11);
175
- i0.ɵɵtemplate(1, PhoenixMenuItemComponent_ng_template_4_span_1_Template, 3, 3, "span", 12);
176
- i0.ɵɵelementStart(2, "span", 13);
211
+ function PhoenixMenuItemComponent_ng_template_1_ng_template_4_Template(rf, ctx) { if (rf & 1) {
212
+ i0.ɵɵelementStart(0, "span", 18);
213
+ i0.ɵɵtemplate(1, PhoenixMenuItemComponent_ng_template_1_ng_template_4_span_1_Template, 3, 3, "span", 19);
214
+ i0.ɵɵelementStart(2, "span", 20);
177
215
  i0.ɵɵtext(3);
178
216
  i0.ɵɵelementEnd()();
179
217
  } if (rf & 2) {
180
- const ctx_r1 = i0.ɵɵnextContext();
218
+ const ctx_r1 = i0.ɵɵnextContext(2);
181
219
  i0.ɵɵadvance();
182
220
  i0.ɵɵproperty("ngIf", ctx_r1.currentNode.icon);
183
221
  i0.ɵɵadvance();
@@ -185,117 +223,200 @@ function PhoenixMenuItemComponent_ng_template_4_Template(rf, ctx) { if (rf & 1)
185
223
  i0.ɵɵadvance();
186
224
  i0.ɵɵtextInterpolate(ctx_r1.currentNode.name);
187
225
  } }
188
- function PhoenixMenuItemComponent_div_7_div_4_Template(rf, ctx) { if (rf & 1) {
189
- const _r5 = i0.ɵɵgetCurrentView();
190
- i0.ɵɵelementStart(0, "div", 20);
191
- i0.ɵɵlistener("click", function PhoenixMenuItemComponent_div_7_div_4_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.currentNode.configActive = false); });
226
+ function PhoenixMenuItemComponent_ng_template_1_div_7_ng_container_4_Template(rf, ctx) { if (rf & 1) {
227
+ i0.ɵɵelementContainer(0);
228
+ } }
229
+ function PhoenixMenuItemComponent_ng_template_1_div_7_Template(rf, ctx) { if (rf & 1) {
230
+ const _r6 = i0.ɵɵgetCurrentView();
231
+ i0.ɵɵelementStart(0, "div")(1, "button", 22);
232
+ i0.ɵɵlistener("click", function PhoenixMenuItemComponent_ng_template_1_div_7_Template_button_click_1_listener() { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(2); ctx_r1.calculateConfigTop(); return i0.ɵɵresetView(ctx_r1.currentNode.configActive = !ctx_r1.currentNode.configActive); });
233
+ i0.ɵɵnamespaceSVG();
234
+ i0.ɵɵelementStart(2, "svg");
235
+ i0.ɵɵelement(3, "use", 23);
236
+ i0.ɵɵelementEnd()();
237
+ i0.ɵɵtemplate(4, PhoenixMenuItemComponent_ng_template_1_div_7_ng_container_4_Template, 1, 0, "ng-container", 10);
192
238
  i0.ɵɵelementEnd();
239
+ } if (rf & 2) {
240
+ i0.ɵɵnextContext(2);
241
+ const configPopup_r3 = i0.ɵɵreference(5);
242
+ i0.ɵɵadvance(4);
243
+ i0.ɵɵproperty("ngTemplateOutlet", configPopup_r3);
193
244
  } }
194
- function PhoenixMenuItemComponent_div_7_ng_container_6_div_1_label_1_Template(rf, ctx) { if (rf & 1) {
195
- i0.ɵɵelementStart(0, "label", 26);
196
- i0.ɵɵtext(1);
245
+ function PhoenixMenuItemComponent_ng_template_1_button_8_Template(rf, ctx) { if (rf & 1) {
246
+ const _r7 = i0.ɵɵgetCurrentView();
247
+ i0.ɵɵelementStart(0, "button", 24);
248
+ i0.ɵɵlistener("click", function PhoenixMenuItemComponent_ng_template_1_button_8_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r7); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.currentNode.childrenActive = !ctx_r1.currentNode.childrenActive); });
249
+ i0.ɵɵnamespaceSVG();
250
+ i0.ɵɵelementStart(1, "svg");
251
+ i0.ɵɵelement(2, "use", 25);
252
+ i0.ɵɵelementEnd()();
253
+ } if (rf & 2) {
254
+ const ctx_r1 = i0.ɵɵnextContext(2);
255
+ i0.ɵɵproperty("ngClass", i0.ɵɵpureFunction1(1, _c1$7, ctx_r1.currentNode.childrenActive));
256
+ } }
257
+ function PhoenixMenuItemComponent_ng_template_1_Template(rf, ctx) { if (rf & 1) {
258
+ i0.ɵɵelementStart(0, "div", 11, 2)(2, "div", 12);
259
+ i0.ɵɵtemplate(3, PhoenixMenuItemComponent_ng_template_1_ng_container_3_Template, 3, 2, "ng-container", 13)(4, PhoenixMenuItemComponent_ng_template_1_ng_template_4_Template, 4, 3, "ng-template", null, 3, i0.ɵɵtemplateRefExtractor);
197
260
  i0.ɵɵelementEnd();
261
+ i0.ɵɵelementStart(6, "div", 14);
262
+ i0.ɵɵtemplate(7, PhoenixMenuItemComponent_ng_template_1_div_7_Template, 5, 1, "div", 15)(8, PhoenixMenuItemComponent_ng_template_1_button_8_Template, 3, 3, "button", 16);
263
+ i0.ɵɵelementEnd()();
198
264
  } if (rf & 2) {
199
- const config_r6 = i0.ɵɵnextContext(2).$implicit;
200
- i0.ɵɵproperty("ngClass", i0.ɵɵpureFunction1(2, _c2$3, config_r6.type === "label"));
265
+ const nodeName_r5 = i0.ɵɵreference(5);
266
+ const ctx_r1 = i0.ɵɵnextContext();
267
+ i0.ɵɵadvance(3);
268
+ i0.ɵɵproperty("ngIf", ctx_r1.currentNode.onToggle)("ngIfElse", nodeName_r5);
269
+ i0.ɵɵadvance(4);
270
+ i0.ɵɵproperty("ngIf", ctx_r1.currentNode.configs.length > 0);
201
271
  i0.ɵɵadvance();
202
- i0.ɵɵtextInterpolate1(" ", config_r6.label, " ");
272
+ i0.ɵɵproperty("ngIf", ctx_r1.currentNode.children.length > 0);
203
273
  } }
204
- function PhoenixMenuItemComponent_div_7_ng_container_6_div_1_div_2_mat_checkbox_1_Template(rf, ctx) { if (rf & 1) {
205
- const _r7 = i0.ɵɵgetCurrentView();
206
- i0.ɵɵelementStart(0, "mat-checkbox", 9);
207
- i0.ɵɵlistener("change", function PhoenixMenuItemComponent_div_7_ng_container_6_div_1_div_2_mat_checkbox_1_Template_mat_checkbox_change_0_listener($event) { i0.ɵɵrestoreView(_r7); const config_r6 = i0.ɵɵnextContext(3).$implicit; config_r6.onChange($event.checked); return i0.ɵɵresetView(config_r6.isChecked = $event.checked); });
274
+ function PhoenixMenuItemComponent_div_3_div_1_app_phoenix_menu_item_1_Template(rf, ctx) { if (rf & 1) {
275
+ i0.ɵɵelement(0, "app-phoenix-menu-item", 30);
276
+ } if (rf & 2) {
277
+ const childNode_r8 = ctx.$implicit;
278
+ i0.ɵɵproperty("currentNode", childNode_r8);
279
+ } }
280
+ function PhoenixMenuItemComponent_div_3_div_1_Template(rf, ctx) { if (rf & 1) {
281
+ i0.ɵɵelementStart(0, "div", 29);
282
+ i0.ɵɵtemplate(1, PhoenixMenuItemComponent_div_3_div_1_app_phoenix_menu_item_1_Template, 1, 1, "app-phoenix-menu-item", 28);
208
283
  i0.ɵɵelementEnd();
209
284
  } if (rf & 2) {
210
- const config_r6 = i0.ɵɵnextContext(3).$implicit;
211
- i0.ɵɵproperty("checked", config_r6.isChecked);
285
+ const ctx_r1 = i0.ɵɵnextContext(2);
286
+ i0.ɵɵadvance();
287
+ i0.ɵɵproperty("ngForOf", ctx_r1.compactChildren);
212
288
  } }
213
- function PhoenixMenuItemComponent_div_7_ng_container_6_div_1_div_2_app_config_slider_2_Template(rf, ctx) { if (rf & 1) {
214
- const _r8 = i0.ɵɵgetCurrentView();
215
- i0.ɵɵelementStart(0, "app-config-slider", 34);
216
- i0.ɵɵlistener("onChange", function PhoenixMenuItemComponent_div_7_ng_container_6_div_1_div_2_app_config_slider_2_Template_app_config_slider_onChange_0_listener($event) { i0.ɵɵrestoreView(_r8); const config_r6 = i0.ɵɵnextContext(3).$implicit; config_r6.onChange($event); return i0.ɵɵresetView(config_r6.value = $event); });
289
+ function PhoenixMenuItemComponent_div_3_app_phoenix_menu_item_2_Template(rf, ctx) { if (rf & 1) {
290
+ i0.ɵɵelement(0, "app-phoenix-menu-item", 30);
291
+ } if (rf & 2) {
292
+ const childNode_r9 = ctx.$implicit;
293
+ i0.ɵɵproperty("currentNode", childNode_r9);
294
+ } }
295
+ function PhoenixMenuItemComponent_div_3_Template(rf, ctx) { if (rf & 1) {
296
+ i0.ɵɵelementStart(0, "div", 26);
297
+ i0.ɵɵtemplate(1, PhoenixMenuItemComponent_div_3_div_1_Template, 2, 1, "div", 27)(2, PhoenixMenuItemComponent_div_3_app_phoenix_menu_item_2_Template, 1, 1, "app-phoenix-menu-item", 28);
217
298
  i0.ɵɵelementEnd();
218
299
  } if (rf & 2) {
219
- const config_r6 = i0.ɵɵnextContext(3).$implicit;
220
- i0.ɵɵproperty("value", config_r6.value)("min", config_r6.min)("max", config_r6.max)("step", config_r6.step)("allowCustomValue", config_r6.allowCustomValue);
300
+ const ctx_r1 = i0.ɵɵnextContext();
301
+ i0.ɵɵadvance();
302
+ i0.ɵɵproperty("ngIf", ctx_r1.compactChildren.length > 0);
303
+ i0.ɵɵadvance();
304
+ i0.ɵɵproperty("ngForOf", ctx_r1.regularChildren);
221
305
  } }
222
- function PhoenixMenuItemComponent_div_7_ng_container_6_div_1_div_2_button_3_Template(rf, ctx) { if (rf & 1) {
223
- const _r9 = i0.ɵɵgetCurrentView();
224
- i0.ɵɵelementStart(0, "button", 35);
225
- i0.ɵɵlistener("click", function PhoenixMenuItemComponent_div_7_ng_container_6_div_1_div_2_button_3_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r9); const config_r6 = i0.ɵɵnextContext(3).$implicit; return i0.ɵɵresetView(config_r6.onClick()); });
306
+ function PhoenixMenuItemComponent_ng_template_4_div_0_Template(rf, ctx) { if (rf & 1) {
307
+ const _r10 = i0.ɵɵgetCurrentView();
308
+ i0.ɵɵelementStart(0, "div", 34);
309
+ i0.ɵɵlistener("click", function PhoenixMenuItemComponent_ng_template_4_div_0_Template_div_click_0_listener() { i0.ɵɵrestoreView(_r10); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.currentNode.configActive = false); });
310
+ i0.ɵɵelementEnd();
311
+ } }
312
+ function PhoenixMenuItemComponent_ng_template_4_ng_container_2_div_1_label_1_Template(rf, ctx) { if (rf & 1) {
313
+ i0.ɵɵelementStart(0, "label", 40);
226
314
  i0.ɵɵtext(1);
227
315
  i0.ɵɵelementEnd();
228
316
  } if (rf & 2) {
229
- const config_r6 = i0.ɵɵnextContext(3).$implicit;
317
+ const config_r11 = i0.ɵɵnextContext(2).$implicit;
318
+ i0.ɵɵproperty("ngClass", i0.ɵɵpureFunction1(2, _c4$2, config_r11.type === "label"));
230
319
  i0.ɵɵadvance();
231
- i0.ɵɵtextInterpolate1(" ", config_r6.label, " ");
320
+ i0.ɵɵtextInterpolate1(" ", config_r11.label, " ");
232
321
  } }
233
- function PhoenixMenuItemComponent_div_7_ng_container_6_div_1_div_2_input_4_Template(rf, ctx) { if (rf & 1) {
234
- const _r10 = i0.ɵɵgetCurrentView();
235
- i0.ɵɵelementStart(0, "input", 36);
236
- i0.ɵɵlistener("input", function PhoenixMenuItemComponent_div_7_ng_container_6_div_1_div_2_input_4_Template_input_input_0_listener($event) { i0.ɵɵrestoreView(_r10); const config_r6 = i0.ɵɵnextContext(3).$implicit; config_r6.onChange($event.target.value); return i0.ɵɵresetView(config_r6.color = $event.target.value); });
322
+ function PhoenixMenuItemComponent_ng_template_4_ng_container_2_div_1_div_2_mat_checkbox_1_Template(rf, ctx) { if (rf & 1) {
323
+ const _r12 = i0.ɵɵgetCurrentView();
324
+ i0.ɵɵelementStart(0, "mat-checkbox", 17);
325
+ i0.ɵɵlistener("change", function PhoenixMenuItemComponent_ng_template_4_ng_container_2_div_1_div_2_mat_checkbox_1_Template_mat_checkbox_change_0_listener($event) { i0.ɵɵrestoreView(_r12); const config_r11 = i0.ɵɵnextContext(3).$implicit; config_r11.onChange($event.checked); return i0.ɵɵresetView(config_r11.isChecked = $event.checked); });
237
326
  i0.ɵɵelementEnd();
238
327
  } if (rf & 2) {
239
- const config_r6 = i0.ɵɵnextContext(3).$implicit;
240
- i0.ɵɵproperty("value", config_r6.color);
328
+ const config_r11 = i0.ɵɵnextContext(3).$implicit;
329
+ i0.ɵɵproperty("checked", config_r11.isChecked);
241
330
  } }
242
- function PhoenixMenuItemComponent_div_7_ng_container_6_div_1_div_2_div_5_Template(rf, ctx) { if (rf & 1) {
243
- const _r11 = i0.ɵɵgetCurrentView();
244
- i0.ɵɵelementStart(0, "div", 37)(1, "div", 38)(2, "mat-checkbox", 39);
245
- i0.ɵɵtwoWayListener("ngModelChange", function PhoenixMenuItemComponent_div_7_ng_container_6_div_1_div_2_div_5_Template_mat_checkbox_ngModelChange_2_listener($event) { i0.ɵɵrestoreView(_r11); const config_r6 = i0.ɵɵnextContext(3).$implicit; i0.ɵɵtwoWayBindingSet(config_r6.enableMin, $event) || (config_r6.enableMin = $event); return i0.ɵɵresetView($event); });
246
- i0.ɵɵlistener("change", function PhoenixMenuItemComponent_div_7_ng_container_6_div_1_div_2_div_5_Template_mat_checkbox_change_2_listener($event) { i0.ɵɵrestoreView(_r11); const config_r6 = i0.ɵɵnextContext(3).$implicit; return i0.ɵɵresetView(config_r6.setEnableMin($event.checked)); });
331
+ function PhoenixMenuItemComponent_ng_template_4_ng_container_2_div_1_div_2_app_config_slider_2_Template(rf, ctx) { if (rf & 1) {
332
+ const _r13 = i0.ɵɵgetCurrentView();
333
+ i0.ɵɵelementStart(0, "app-config-slider", 48);
334
+ i0.ɵɵlistener("onChange", function PhoenixMenuItemComponent_ng_template_4_ng_container_2_div_1_div_2_app_config_slider_2_Template_app_config_slider_onChange_0_listener($event) { i0.ɵɵrestoreView(_r13); const config_r11 = i0.ɵɵnextContext(3).$implicit; config_r11.onChange($event); return i0.ɵɵresetView(config_r11.value = $event); });
335
+ i0.ɵɵelementEnd();
336
+ } if (rf & 2) {
337
+ const config_r11 = i0.ɵɵnextContext(3).$implicit;
338
+ i0.ɵɵproperty("value", config_r11.value)("min", config_r11.min)("max", config_r11.max)("step", config_r11.step)("allowCustomValue", config_r11.allowCustomValue);
339
+ } }
340
+ function PhoenixMenuItemComponent_ng_template_4_ng_container_2_div_1_div_2_button_3_Template(rf, ctx) { if (rf & 1) {
341
+ const _r14 = i0.ɵɵgetCurrentView();
342
+ i0.ɵɵelementStart(0, "button", 49);
343
+ i0.ɵɵlistener("click", function PhoenixMenuItemComponent_ng_template_4_ng_container_2_div_1_div_2_button_3_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r14); const config_r11 = i0.ɵɵnextContext(3).$implicit; return i0.ɵɵresetView(config_r11.onClick()); });
344
+ i0.ɵɵtext(1);
247
345
  i0.ɵɵelementEnd();
248
- i0.ɵɵelementStart(3, "mat-checkbox", 39);
249
- i0.ɵɵtwoWayListener("ngModelChange", function PhoenixMenuItemComponent_div_7_ng_container_6_div_1_div_2_div_5_Template_mat_checkbox_ngModelChange_3_listener($event) { i0.ɵɵrestoreView(_r11); const config_r6 = i0.ɵɵnextContext(3).$implicit; i0.ɵɵtwoWayBindingSet(config_r6.enableMax, $event) || (config_r6.enableMax = $event); return i0.ɵɵresetView($event); });
250
- i0.ɵɵlistener("change", function PhoenixMenuItemComponent_div_7_ng_container_6_div_1_div_2_div_5_Template_mat_checkbox_change_3_listener($event) { i0.ɵɵrestoreView(_r11); const config_r6 = i0.ɵɵnextContext(3).$implicit; return i0.ɵɵresetView(config_r6.setEnableMax($event.checked)); });
346
+ } if (rf & 2) {
347
+ const config_r11 = i0.ɵɵnextContext(3).$implicit;
348
+ i0.ɵɵadvance();
349
+ i0.ɵɵtextInterpolate1(" ", config_r11.label, " ");
350
+ } }
351
+ function PhoenixMenuItemComponent_ng_template_4_ng_container_2_div_1_div_2_input_4_Template(rf, ctx) { if (rf & 1) {
352
+ const _r15 = i0.ɵɵgetCurrentView();
353
+ i0.ɵɵelementStart(0, "input", 50);
354
+ i0.ɵɵlistener("input", function PhoenixMenuItemComponent_ng_template_4_ng_container_2_div_1_div_2_input_4_Template_input_input_0_listener($event) { i0.ɵɵrestoreView(_r15); const config_r11 = i0.ɵɵnextContext(3).$implicit; config_r11.onChange($event.target.value); return i0.ɵɵresetView(config_r11.color = $event.target.value); });
355
+ i0.ɵɵelementEnd();
356
+ } if (rf & 2) {
357
+ const config_r11 = i0.ɵɵnextContext(3).$implicit;
358
+ i0.ɵɵproperty("value", config_r11.color);
359
+ } }
360
+ function PhoenixMenuItemComponent_ng_template_4_ng_container_2_div_1_div_2_div_5_Template(rf, ctx) { if (rf & 1) {
361
+ const _r16 = i0.ɵɵgetCurrentView();
362
+ i0.ɵɵelementStart(0, "div", 51)(1, "div", 52)(2, "div", 53)(3, "mat-checkbox", 54);
363
+ i0.ɵɵtwoWayListener("ngModelChange", function PhoenixMenuItemComponent_ng_template_4_ng_container_2_div_1_div_2_div_5_Template_mat_checkbox_ngModelChange_3_listener($event) { i0.ɵɵrestoreView(_r16); const config_r11 = i0.ɵɵnextContext(3).$implicit; i0.ɵɵtwoWayBindingSet(config_r11.enableMin, $event) || (config_r11.enableMin = $event); return i0.ɵɵresetView($event); });
364
+ i0.ɵɵlistener("change", function PhoenixMenuItemComponent_ng_template_4_ng_container_2_div_1_div_2_div_5_Template_mat_checkbox_change_3_listener($event) { i0.ɵɵrestoreView(_r16); const config_r11 = i0.ɵɵnextContext(3).$implicit; return i0.ɵɵresetView(config_r11.setEnableMin($event.checked)); });
365
+ i0.ɵɵelementEnd();
366
+ i0.ɵɵelementStart(4, "input", 55);
367
+ i0.ɵɵtwoWayListener("ngModelChange", function PhoenixMenuItemComponent_ng_template_4_ng_container_2_div_1_div_2_div_5_Template_input_ngModelChange_4_listener($event) { i0.ɵɵrestoreView(_r16); const config_r11 = i0.ɵɵnextContext(3).$implicit; i0.ɵɵtwoWayBindingSet(config_r11.value, $event) || (config_r11.value = $event); return i0.ɵɵresetView($event); });
368
+ i0.ɵɵlistener("input", function PhoenixMenuItemComponent_ng_template_4_ng_container_2_div_1_div_2_div_5_Template_input_input_4_listener($event) { i0.ɵɵrestoreView(_r16); const config_r11 = i0.ɵɵnextContext(3).$implicit; config_r11.value = $event.target.value; return i0.ɵɵresetView(config_r11.onChange(config_r11)); });
251
369
  i0.ɵɵelementEnd()();
252
- i0.ɵɵelementStart(4, "div", 38)(5, "input", 40);
253
- i0.ɵɵtwoWayListener("ngModelChange", function PhoenixMenuItemComponent_div_7_ng_container_6_div_1_div_2_div_5_Template_input_ngModelChange_5_listener($event) { i0.ɵɵrestoreView(_r11); const config_r6 = i0.ɵɵnextContext(3).$implicit; i0.ɵɵtwoWayBindingSet(config_r6.value, $event) || (config_r6.value = $event); return i0.ɵɵresetView($event); });
254
- i0.ɵɵlistener("input", function PhoenixMenuItemComponent_div_7_ng_container_6_div_1_div_2_div_5_Template_input_input_5_listener($event) { i0.ɵɵrestoreView(_r11); const config_r6 = i0.ɵɵnextContext(3).$implicit; config_r6.value = $event.target.value; return i0.ɵɵresetView(config_r6.onChange(config_r6)); });
370
+ i0.ɵɵelementStart(5, "div", 53)(6, "mat-checkbox", 54);
371
+ i0.ɵɵtwoWayListener("ngModelChange", function PhoenixMenuItemComponent_ng_template_4_ng_container_2_div_1_div_2_div_5_Template_mat_checkbox_ngModelChange_6_listener($event) { i0.ɵɵrestoreView(_r16); const config_r11 = i0.ɵɵnextContext(3).$implicit; i0.ɵɵtwoWayBindingSet(config_r11.enableMax, $event) || (config_r11.enableMax = $event); return i0.ɵɵresetView($event); });
372
+ i0.ɵɵlistener("change", function PhoenixMenuItemComponent_ng_template_4_ng_container_2_div_1_div_2_div_5_Template_mat_checkbox_change_6_listener($event) { i0.ɵɵrestoreView(_r16); const config_r11 = i0.ɵɵnextContext(3).$implicit; return i0.ɵɵresetView(config_r11.setEnableMax($event.checked)); });
255
373
  i0.ɵɵelementEnd();
256
- i0.ɵɵelementStart(6, "input", 41);
257
- i0.ɵɵtwoWayListener("ngModelChange", function PhoenixMenuItemComponent_div_7_ng_container_6_div_1_div_2_div_5_Template_input_ngModelChange_6_listener($event) { i0.ɵɵrestoreView(_r11); const config_r6 = i0.ɵɵnextContext(3).$implicit; i0.ɵɵtwoWayBindingSet(config_r6.highValue, $event) || (config_r6.highValue = $event); return i0.ɵɵresetView($event); });
258
- i0.ɵɵlistener("input", function PhoenixMenuItemComponent_div_7_ng_container_6_div_1_div_2_div_5_Template_input_input_6_listener($event) { i0.ɵɵrestoreView(_r11); const config_r6 = i0.ɵɵnextContext(3).$implicit; config_r6.highValue = $event.target.value; return i0.ɵɵresetView(config_r6.onChange(config_r6)); });
259
- i0.ɵɵelementEnd()()();
374
+ i0.ɵɵelementStart(7, "input", 56);
375
+ i0.ɵɵtwoWayListener("ngModelChange", function PhoenixMenuItemComponent_ng_template_4_ng_container_2_div_1_div_2_div_5_Template_input_ngModelChange_7_listener($event) { i0.ɵɵrestoreView(_r16); const config_r11 = i0.ɵɵnextContext(3).$implicit; i0.ɵɵtwoWayBindingSet(config_r11.highValue, $event) || (config_r11.highValue = $event); return i0.ɵɵresetView($event); });
376
+ i0.ɵɵlistener("input", function PhoenixMenuItemComponent_ng_template_4_ng_container_2_div_1_div_2_div_5_Template_input_input_7_listener($event) { i0.ɵɵrestoreView(_r16); const config_r11 = i0.ɵɵnextContext(3).$implicit; config_r11.highValue = $event.target.value; return i0.ɵɵresetView(config_r11.onChange(config_r11)); });
377
+ i0.ɵɵelementEnd()()()();
260
378
  } if (rf & 2) {
261
- const config_r6 = i0.ɵɵnextContext(3).$implicit;
262
- i0.ɵɵadvance(2);
263
- i0.ɵɵtwoWayProperty("ngModel", config_r6.enableMin);
379
+ const config_r11 = i0.ɵɵnextContext(3).$implicit;
380
+ i0.ɵɵadvance(3);
381
+ i0.ɵɵtwoWayProperty("ngModel", config_r11.enableMin);
264
382
  i0.ɵɵadvance();
265
- i0.ɵɵtwoWayProperty("ngModel", config_r6.enableMax);
383
+ i0.ɵɵtwoWayProperty("ngModel", config_r11.value);
384
+ i0.ɵɵproperty("step", config_r11.step);
266
385
  i0.ɵɵadvance(2);
267
- i0.ɵɵtwoWayProperty("ngModel", config_r6.value);
386
+ i0.ɵɵtwoWayProperty("ngModel", config_r11.enableMax);
268
387
  i0.ɵɵadvance();
269
- i0.ɵɵtwoWayProperty("ngModel", config_r6.highValue);
388
+ i0.ɵɵtwoWayProperty("ngModel", config_r11.highValue);
389
+ i0.ɵɵproperty("step", config_r11.step);
270
390
  } }
271
- function PhoenixMenuItemComponent_div_7_ng_container_6_div_1_div_2_select_6_option_1_Template(rf, ctx) { if (rf & 1) {
272
- i0.ɵɵelementStart(0, "option", 44);
391
+ function PhoenixMenuItemComponent_ng_template_4_ng_container_2_div_1_div_2_select_6_option_1_Template(rf, ctx) { if (rf & 1) {
392
+ i0.ɵɵelementStart(0, "option", 59);
273
393
  i0.ɵɵtext(1);
274
394
  i0.ɵɵelementEnd();
275
395
  } if (rf & 2) {
276
- const singleOption_r13 = ctx.$implicit;
277
- i0.ɵɵproperty("value", singleOption_r13);
396
+ const singleOption_r18 = ctx.$implicit;
397
+ i0.ɵɵproperty("value", singleOption_r18);
278
398
  i0.ɵɵadvance();
279
- i0.ɵɵtextInterpolate1(" ", singleOption_r13, " ");
399
+ i0.ɵɵtextInterpolate1(" ", singleOption_r18, " ");
280
400
  } }
281
- function PhoenixMenuItemComponent_div_7_ng_container_6_div_1_div_2_select_6_Template(rf, ctx) { if (rf & 1) {
282
- const _r12 = i0.ɵɵgetCurrentView();
283
- i0.ɵɵelementStart(0, "select", 42);
284
- i0.ɵɵlistener("change", function PhoenixMenuItemComponent_div_7_ng_container_6_div_1_div_2_select_6_Template_select_change_0_listener($event) { i0.ɵɵrestoreView(_r12); const config_r6 = i0.ɵɵnextContext(3).$implicit; return i0.ɵɵresetView(config_r6.onChange($event.target.value)); });
285
- i0.ɵɵtemplate(1, PhoenixMenuItemComponent_div_7_ng_container_6_div_1_div_2_select_6_option_1_Template, 2, 2, "option", 43);
401
+ function PhoenixMenuItemComponent_ng_template_4_ng_container_2_div_1_div_2_select_6_Template(rf, ctx) { if (rf & 1) {
402
+ const _r17 = i0.ɵɵgetCurrentView();
403
+ i0.ɵɵelementStart(0, "select", 57);
404
+ i0.ɵɵlistener("change", function PhoenixMenuItemComponent_ng_template_4_ng_container_2_div_1_div_2_select_6_Template_select_change_0_listener($event) { i0.ɵɵrestoreView(_r17); const config_r11 = i0.ɵɵnextContext(3).$implicit; return i0.ɵɵresetView(config_r11.onChange($event.target.value)); });
405
+ i0.ɵɵtemplate(1, PhoenixMenuItemComponent_ng_template_4_ng_container_2_div_1_div_2_select_6_option_1_Template, 2, 2, "option", 58);
286
406
  i0.ɵɵelementEnd();
287
407
  } if (rf & 2) {
288
- const config_r6 = i0.ɵɵnextContext(3).$implicit;
408
+ const config_r11 = i0.ɵɵnextContext(3).$implicit;
409
+ i0.ɵɵproperty("value", config_r11.value ?? config_r11.options[0]);
289
410
  i0.ɵɵadvance();
290
- i0.ɵɵproperty("ngForOf", config_r6.options);
411
+ i0.ɵɵproperty("ngForOf", config_r11.options);
291
412
  } }
292
- function PhoenixMenuItemComponent_div_7_ng_container_6_div_1_div_2_Template(rf, ctx) { if (rf & 1) {
293
- i0.ɵɵelementStart(0, "div", 27);
294
- i0.ɵɵtemplate(1, PhoenixMenuItemComponent_div_7_ng_container_6_div_1_div_2_mat_checkbox_1_Template, 1, 1, "mat-checkbox", 28)(2, PhoenixMenuItemComponent_div_7_ng_container_6_div_1_div_2_app_config_slider_2_Template, 1, 5, "app-config-slider", 29)(3, PhoenixMenuItemComponent_div_7_ng_container_6_div_1_div_2_button_3_Template, 2, 1, "button", 30)(4, PhoenixMenuItemComponent_div_7_ng_container_6_div_1_div_2_input_4_Template, 1, 1, "input", 31)(5, PhoenixMenuItemComponent_div_7_ng_container_6_div_1_div_2_div_5_Template, 7, 4, "div", 32)(6, PhoenixMenuItemComponent_div_7_ng_container_6_div_1_div_2_select_6_Template, 2, 1, "select", 33);
413
+ function PhoenixMenuItemComponent_ng_template_4_ng_container_2_div_1_div_2_Template(rf, ctx) { if (rf & 1) {
414
+ i0.ɵɵelementStart(0, "div", 41);
415
+ i0.ɵɵtemplate(1, PhoenixMenuItemComponent_ng_template_4_ng_container_2_div_1_div_2_mat_checkbox_1_Template, 1, 1, "mat-checkbox", 42)(2, PhoenixMenuItemComponent_ng_template_4_ng_container_2_div_1_div_2_app_config_slider_2_Template, 1, 5, "app-config-slider", 43)(3, PhoenixMenuItemComponent_ng_template_4_ng_container_2_div_1_div_2_button_3_Template, 2, 1, "button", 44)(4, PhoenixMenuItemComponent_ng_template_4_ng_container_2_div_1_div_2_input_4_Template, 1, 1, "input", 45)(5, PhoenixMenuItemComponent_ng_template_4_ng_container_2_div_1_div_2_div_5_Template, 8, 6, "div", 46)(6, PhoenixMenuItemComponent_ng_template_4_ng_container_2_div_1_div_2_select_6_Template, 2, 2, "select", 47);
295
416
  i0.ɵɵelementEnd();
296
417
  } if (rf & 2) {
297
- const config_r6 = i0.ɵɵnextContext(2).$implicit;
298
- i0.ɵɵproperty("ngClass", i0.ɵɵpureFunction1(7, _c3$2, config_r6.type === "button"));
418
+ const config_r11 = i0.ɵɵnextContext(2).$implicit;
419
+ i0.ɵɵproperty("ngClass", i0.ɵɵpureFunction1(7, _c5$2, config_r11.type === "button"));
299
420
  i0.ɵɵadvance();
300
421
  i0.ɵɵproperty("ngSwitchCase", "checkbox");
301
422
  i0.ɵɵadvance();
@@ -309,76 +430,41 @@ function PhoenixMenuItemComponent_div_7_ng_container_6_div_1_div_2_Template(rf,
309
430
  i0.ɵɵadvance();
310
431
  i0.ɵɵproperty("ngSwitchCase", "select");
311
432
  } }
312
- function PhoenixMenuItemComponent_div_7_ng_container_6_div_1_Template(rf, ctx) { if (rf & 1) {
313
- i0.ɵɵelementStart(0, "div", 23);
314
- i0.ɵɵtemplate(1, PhoenixMenuItemComponent_div_7_ng_container_6_div_1_label_1_Template, 2, 4, "label", 24)(2, PhoenixMenuItemComponent_div_7_ng_container_6_div_1_div_2_Template, 7, 9, "div", 25);
433
+ function PhoenixMenuItemComponent_ng_template_4_ng_container_2_div_1_Template(rf, ctx) { if (rf & 1) {
434
+ i0.ɵɵelementStart(0, "div", 37);
435
+ i0.ɵɵtemplate(1, PhoenixMenuItemComponent_ng_template_4_ng_container_2_div_1_label_1_Template, 2, 4, "label", 38)(2, PhoenixMenuItemComponent_ng_template_4_ng_container_2_div_1_div_2_Template, 7, 9, "div", 39);
315
436
  i0.ɵɵelementEnd();
316
437
  } if (rf & 2) {
317
- const config_r6 = i0.ɵɵnextContext().$implicit;
438
+ const config_r11 = i0.ɵɵnextContext().$implicit;
439
+ i0.ɵɵproperty("ngClass", i0.ɵɵpureFunction1(3, _c3$2, config_r11.type === "rangeSlider"));
318
440
  i0.ɵɵadvance();
319
- i0.ɵɵproperty("ngIf", config_r6.type !== "button");
441
+ i0.ɵɵproperty("ngIf", config_r11.type !== "button");
320
442
  i0.ɵɵadvance();
321
- i0.ɵɵproperty("ngIf", config_r6.type !== "label");
443
+ i0.ɵɵproperty("ngIf", config_r11.type !== "label");
322
444
  } }
323
- function PhoenixMenuItemComponent_div_7_ng_container_6_Template(rf, ctx) { if (rf & 1) {
324
- i0.ɵɵelementContainerStart(0, 21);
325
- i0.ɵɵtemplate(1, PhoenixMenuItemComponent_div_7_ng_container_6_div_1_Template, 3, 2, "div", 22);
445
+ function PhoenixMenuItemComponent_ng_template_4_ng_container_2_Template(rf, ctx) { if (rf & 1) {
446
+ i0.ɵɵelementContainerStart(0, 35);
447
+ i0.ɵɵtemplate(1, PhoenixMenuItemComponent_ng_template_4_ng_container_2_div_1_Template, 3, 5, "div", 36);
326
448
  i0.ɵɵelementContainerEnd();
327
449
  } if (rf & 2) {
328
- const config_r6 = ctx.$implicit;
329
- i0.ɵɵproperty("ngSwitch", config_r6.type);
450
+ const config_r11 = ctx.$implicit;
451
+ i0.ɵɵproperty("ngSwitch", config_r11.type);
330
452
  i0.ɵɵadvance();
331
- i0.ɵɵproperty("ngIf", !config_r6.hidden);
453
+ i0.ɵɵproperty("ngIf", !config_r11.hidden);
332
454
  } }
333
- function PhoenixMenuItemComponent_div_7_Template(rf, ctx) { if (rf & 1) {
334
- const _r4 = i0.ɵɵgetCurrentView();
335
- i0.ɵɵelementStart(0, "div")(1, "button", 15);
336
- i0.ɵɵlistener("click", function PhoenixMenuItemComponent_div_7_Template_button_click_1_listener() { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(); ctx_r1.calculateConfigTop(); return i0.ɵɵresetView(ctx_r1.currentNode.configActive = !ctx_r1.currentNode.configActive); });
337
- i0.ɵɵnamespaceSVG();
338
- i0.ɵɵelementStart(2, "svg");
339
- i0.ɵɵelement(3, "use", 16);
340
- i0.ɵɵelementEnd()();
341
- i0.ɵɵtemplate(4, PhoenixMenuItemComponent_div_7_div_4_Template, 1, 0, "div", 17);
342
- i0.ɵɵnamespaceHTML();
343
- i0.ɵɵelementStart(5, "div", 18);
344
- i0.ɵɵtemplate(6, PhoenixMenuItemComponent_div_7_ng_container_6_Template, 2, 2, "ng-container", 19);
345
- i0.ɵɵelementEnd()();
455
+ function PhoenixMenuItemComponent_ng_template_4_Template(rf, ctx) { if (rf & 1) {
456
+ i0.ɵɵtemplate(0, PhoenixMenuItemComponent_ng_template_4_div_0_Template, 1, 0, "div", 31);
457
+ i0.ɵɵelementStart(1, "div", 32);
458
+ i0.ɵɵtemplate(2, PhoenixMenuItemComponent_ng_template_4_ng_container_2_Template, 2, 2, "ng-container", 33);
459
+ i0.ɵɵelementEnd();
346
460
  } if (rf & 2) {
347
461
  const ctx_r1 = i0.ɵɵnextContext();
348
- i0.ɵɵadvance(4);
349
462
  i0.ɵɵproperty("ngIf", ctx_r1.currentNode.configActive);
350
463
  i0.ɵɵadvance();
351
- i0.ɵɵproperty("hidden", !ctx_r1.currentNode.configActive)("ngStyle", i0.ɵɵpureFunction1(4, _c1$7, ctx_r1.configTop));
464
+ i0.ɵɵproperty("hidden", !ctx_r1.currentNode.configActive)("ngStyle", i0.ɵɵpureFunction1(4, _c2$3, ctx_r1.configTop));
352
465
  i0.ɵɵadvance();
353
466
  i0.ɵɵproperty("ngForOf", ctx_r1.castConfigsToAny(ctx_r1.currentNode.configs));
354
467
  } }
355
- function PhoenixMenuItemComponent_button_8_Template(rf, ctx) { if (rf & 1) {
356
- const _r14 = i0.ɵɵgetCurrentView();
357
- i0.ɵɵelementStart(0, "button", 45);
358
- i0.ɵɵlistener("click", function PhoenixMenuItemComponent_button_8_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r14); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.currentNode.childrenActive = !ctx_r1.currentNode.childrenActive); });
359
- i0.ɵɵnamespaceSVG();
360
- i0.ɵɵelementStart(1, "svg");
361
- i0.ɵɵelement(2, "use", 46);
362
- i0.ɵɵelementEnd()();
363
- } if (rf & 2) {
364
- const ctx_r1 = i0.ɵɵnextContext();
365
- i0.ɵɵproperty("ngClass", i0.ɵɵpureFunction1(1, _c4$2, ctx_r1.currentNode.childrenActive));
366
- } }
367
- function PhoenixMenuItemComponent_div_9_app_phoenix_menu_item_1_Template(rf, ctx) { if (rf & 1) {
368
- i0.ɵɵelement(0, "app-phoenix-menu-item", 49);
369
- } if (rf & 2) {
370
- const childNode_r15 = ctx.$implicit;
371
- i0.ɵɵproperty("currentNode", childNode_r15);
372
- } }
373
- function PhoenixMenuItemComponent_div_9_Template(rf, ctx) { if (rf & 1) {
374
- i0.ɵɵelementStart(0, "div", 47);
375
- i0.ɵɵtemplate(1, PhoenixMenuItemComponent_div_9_app_phoenix_menu_item_1_Template, 1, 1, "app-phoenix-menu-item", 48);
376
- i0.ɵɵelementEnd();
377
- } if (rf & 2) {
378
- const ctx_r1 = i0.ɵɵnextContext();
379
- i0.ɵɵadvance();
380
- i0.ɵɵproperty("ngForOf", ctx_r1.currentNode.children);
381
- } }
382
468
  class PhoenixMenuItemComponent {
383
469
  cdr;
384
470
  currentNode;
@@ -387,10 +473,41 @@ class PhoenixMenuItemComponent {
387
473
  constructor(cdr) {
388
474
  this.cdr = cdr;
389
475
  }
476
+ /**
477
+ * Whether a node is a leaf holding only configs (like the collections'
478
+ * "Draw/Cut/Color Options"), which is displayed as a compact icon button
479
+ * in a toolbar instead of a full menu row.
480
+ */
481
+ isCompactOptionsNode(node) {
482
+ return (!!node.icon &&
483
+ !node.onToggle &&
484
+ node.children.length === 0 &&
485
+ node.configs.length > 0);
486
+ }
487
+ get isCompact() {
488
+ return this.isCompactOptionsNode(this.currentNode);
489
+ }
490
+ /** Label for the compact icon button, e.g. "Draw Options" -> "Draw". */
491
+ get compactLabel() {
492
+ return this.currentNode.name.replace(/\s+Options$/, '');
493
+ }
494
+ get compactChildren() {
495
+ return this.currentNode.children.filter((child) => this.isCompactOptionsNode(child));
496
+ }
497
+ get regularChildren() {
498
+ return this.currentNode.children.filter((child) => !this.isCompactOptionsNode(child));
499
+ }
390
500
  calculateConfigTop() {
391
501
  if (this.phoenixMenuItem) {
392
- this.configTop =
393
- this.phoenixMenuItem.nativeElement.getBoundingClientRect().top;
502
+ const itemRect = this.phoenixMenuItem.nativeElement.getBoundingClientRect();
503
+ const dragContainer = document.querySelector('.phoenix-menu-drag-container');
504
+ if (dragContainer) {
505
+ const containerRect = dragContainer.getBoundingClientRect();
506
+ this.configTop = itemRect.top - containerRect.top;
507
+ }
508
+ else {
509
+ this.configTop = itemRect.top;
510
+ }
394
511
  this.cdr.detectChanges();
395
512
  }
396
513
  }
@@ -404,29 +521,18 @@ class PhoenixMenuItemComponent {
404
521
  } if (rf & 2) {
405
522
  let _t;
406
523
  i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.phoenixMenuItem = _t.first);
407
- } }, inputs: { currentNode: "currentNode" }, standalone: false, decls: 10, vars: 5, consts: [["phoenixMenuItem", ""], ["nodeName", ""], [1, "phoenix-menu-item"], [1, "phoenix-menu-item-left", "align-items-center"], [4, "ngIf", "ngIfElse"], [1, "phoenix-menu-item-right"], [4, "ngIf"], ["class", "icon-wrapper icon-button btn-blank item-expand", "data-testid", "dropdown", 3, "ngClass", "click", 4, "ngIf"], ["class", "phoenix-menu-children", 4, "ngIf"], [3, "change", "checked"], [4, "ngTemplateOutlet"], [1, "d-flex", "w-100", "align-items-center"], ["class", "icon-wrapper item-icon", 4, "ngIf"], [1, "item-name", 3, "title"], [1, "icon-wrapper", "item-icon"], [1, "icon-wrapper", "icon-button", "btn-blank", "item-settings", 3, "click"], ["href", "assets/icons/gear.svg#gear"], ["class", "item-config-backdrop", 3, "click", 4, "ngIf"], [1, "item-config", 3, "hidden", "ngStyle"], [3, "ngSwitch", 4, "ngFor", "ngForOf"], [1, "item-config-backdrop", 3, "click"], [3, "ngSwitch"], ["class", "item-config-single", 4, "ngIf"], [1, "item-config-single"], ["class", "item-config-label", "for", "item-config-field", 3, "ngClass", 4, "ngIf"], ["class", "item-config-data", 3, "ngClass", 4, "ngIf"], ["for", "item-config-field", 1, "item-config-label", 3, "ngClass"], [1, "item-config-data", 3, "ngClass"], [3, "checked", "change", 4, "ngSwitchCase"], [3, "value", "min", "max", "step", "allowCustomValue", "onChange", 4, "ngSwitchCase"], ["class", "w-100", "mat-button", "", "mat-stroked-button", "", 3, "click", 4, "ngSwitchCase"], ["id", "item-config-field", "type", "color", 3, "value", "input", 4, "ngSwitchCase"], ["class", "range-slider", 4, "ngSwitchCase"], ["id", "item-config-field", "class", "w-100", 3, "change", 4, "ngSwitchCase"], [3, "onChange", "value", "min", "max", "step", "allowCustomValue"], ["mat-button", "", "mat-stroked-button", "", 1, "w-100", 3, "click"], ["id", "item-config-field", "type", "color", 3, "input", "value"], [1, "range-slider"], [1, "range-slider-inputs", "d-flex", "justify-content-between"], [3, "ngModelChange", "change", "ngModel"], ["type", "number", "placeholder", "Min", "step", "config.step", 1, "form-control", "form-control-sm", 3, "ngModelChange", "input", "ngModel"], ["type", "number", "placeholder", "Max", "step", "config.step", 1, "form-control", "form-control-sm", 3, "ngModelChange", "input", "ngModel"], ["id", "item-config-field", 1, "w-100", 3, "change"], [3, "value", 4, "ngFor", "ngForOf"], [3, "value"], ["data-testid", "dropdown", 1, "icon-wrapper", "icon-button", "btn-blank", "item-expand", 3, "click", "ngClass"], ["href", "assets/icons/expand.svg#expand"], [1, "phoenix-menu-children"], [3, "currentNode", 4, "ngFor", "ngForOf"], [3, "currentNode"]], template: function PhoenixMenuItemComponent_Template(rf, ctx) { if (rf & 1) {
408
- i0.ɵɵelementStart(0, "div", 2, 0)(2, "div", 3);
409
- i0.ɵɵtemplate(3, PhoenixMenuItemComponent_ng_container_3_Template, 3, 2, "ng-container", 4)(4, PhoenixMenuItemComponent_ng_template_4_Template, 4, 3, "ng-template", null, 1, i0.ɵɵtemplateRefExtractor);
410
- i0.ɵɵelementEnd();
411
- i0.ɵɵelementStart(6, "div", 5);
412
- i0.ɵɵtemplate(7, PhoenixMenuItemComponent_div_7_Template, 7, 6, "div", 6)(8, PhoenixMenuItemComponent_button_8_Template, 3, 3, "button", 7);
413
- i0.ɵɵelementEnd()();
414
- i0.ɵɵtemplate(9, PhoenixMenuItemComponent_div_9_Template, 2, 1, "div", 8);
524
+ } }, inputs: { currentNode: "currentNode" }, standalone: false, decls: 6, vars: 3, consts: [["fullItem", ""], ["configPopup", ""], ["phoenixMenuItem", ""], ["nodeName", ""], ["class", "phoenix-menu-item-compact", 4, "ngIf", "ngIfElse"], ["class", "phoenix-menu-children", 4, "ngIf"], [1, "phoenix-menu-item-compact"], [1, "btn-blank", "compact-option-button", 3, "click", "title"], [1, "icon-wrapper"], [1, "compact-option-label"], [4, "ngTemplateOutlet"], [1, "phoenix-menu-item"], [1, "phoenix-menu-item-left", "align-items-center"], [4, "ngIf", "ngIfElse"], [1, "phoenix-menu-item-right"], [4, "ngIf"], ["class", "icon-wrapper icon-button btn-blank item-expand", "data-testid", "dropdown", 3, "ngClass", "click", 4, "ngIf"], [3, "change", "checked"], [1, "d-flex", "w-100", "align-items-center"], ["class", "icon-wrapper item-icon", 4, "ngIf"], [1, "item-name", 3, "title"], [1, "icon-wrapper", "item-icon"], [1, "icon-wrapper", "icon-button", "btn-blank", "item-settings", 3, "click"], ["href", "assets/icons/gear.svg#gear"], ["data-testid", "dropdown", 1, "icon-wrapper", "icon-button", "btn-blank", "item-expand", 3, "click", "ngClass"], ["href", "assets/icons/expand.svg#expand"], [1, "phoenix-menu-children"], ["class", "phoenix-menu-options-bar", 4, "ngIf"], [3, "currentNode", 4, "ngFor", "ngForOf"], [1, "phoenix-menu-options-bar"], [3, "currentNode"], ["class", "item-config-backdrop", 3, "click", 4, "ngIf"], [1, "item-config", 3, "hidden", "ngStyle"], [3, "ngSwitch", 4, "ngFor", "ngForOf"], [1, "item-config-backdrop", 3, "click"], [3, "ngSwitch"], ["class", "item-config-single", 3, "ngClass", 4, "ngIf"], [1, "item-config-single", 3, "ngClass"], ["class", "item-config-label", "for", "item-config-field", 3, "ngClass", 4, "ngIf"], ["class", "item-config-data", 3, "ngClass", 4, "ngIf"], ["for", "item-config-field", 1, "item-config-label", 3, "ngClass"], [1, "item-config-data", 3, "ngClass"], [3, "checked", "change", 4, "ngSwitchCase"], [3, "value", "min", "max", "step", "allowCustomValue", "onChange", 4, "ngSwitchCase"], ["class", "w-100", "mat-button", "", "mat-stroked-button", "", 3, "click", 4, "ngSwitchCase"], ["id", "item-config-field", "type", "color", 3, "value", "input", 4, "ngSwitchCase"], ["class", "range-slider", 4, "ngSwitchCase"], ["id", "item-config-field", "class", "w-100", 3, "value", "change", 4, "ngSwitchCase"], [3, "onChange", "value", "min", "max", "step", "allowCustomValue"], ["mat-button", "", "mat-stroked-button", "", 1, "w-100", 3, "click"], ["id", "item-config-field", "type", "color", 3, "input", "value"], [1, "range-slider"], [1, "range-slider-inputs", "d-flex", "align-items-center"], [1, "range-slider-side"], [3, "ngModelChange", "change", "ngModel"], ["type", "number", "placeholder", "Min", 1, "form-control", "form-control-sm", 3, "ngModelChange", "input", "ngModel", "step"], ["type", "number", "placeholder", "Max", 1, "form-control", "form-control-sm", 3, "ngModelChange", "input", "ngModel", "step"], ["id", "item-config-field", 1, "w-100", 3, "change", "value"], [3, "value", 4, "ngFor", "ngForOf"], [3, "value"]], template: function PhoenixMenuItemComponent_Template(rf, ctx) { if (rf & 1) {
525
+ i0.ɵɵtemplate(0, PhoenixMenuItemComponent_div_0_Template, 9, 6, "div", 4)(1, PhoenixMenuItemComponent_ng_template_1_Template, 9, 4, "ng-template", null, 0, i0.ɵɵtemplateRefExtractor)(3, PhoenixMenuItemComponent_div_3_Template, 3, 2, "div", 5)(4, PhoenixMenuItemComponent_ng_template_4_Template, 3, 6, "ng-template", null, 1, i0.ɵɵtemplateRefExtractor);
415
526
  } if (rf & 2) {
416
- const nodeName_r3 = i0.ɵɵreference(5);
527
+ const fullItem_r19 = i0.ɵɵreference(2);
528
+ i0.ɵɵproperty("ngIf", ctx.isCompact)("ngIfElse", fullItem_r19);
417
529
  i0.ɵɵadvance(3);
418
- i0.ɵɵproperty("ngIf", ctx.currentNode.onToggle)("ngIfElse", nodeName_r3);
419
- i0.ɵɵadvance(4);
420
- i0.ɵɵproperty("ngIf", ctx.currentNode.configs.length > 0);
421
- i0.ɵɵadvance();
422
- i0.ɵɵproperty("ngIf", ctx.currentNode.children.length > 0);
423
- i0.ɵɵadvance();
424
530
  i0.ɵɵproperty("ngIf", ctx.currentNode.childrenActive);
425
- } }, dependencies: [i2.NgClass, i2.NgForOf, i2.NgIf, i2.NgTemplateOutlet, i2.NgStyle, i2.NgSwitch, i2.NgSwitchCase, i3.MatButton, i4.NgSelectOption, i4.ɵNgSelectMultipleOption, i4.DefaultValueAccessor, i4.NumberValueAccessor, i4.NgControlStatus, i4.NgModel, i4$1.MatSlideToggle, i5.MatCheckbox, PhoenixMenuItemComponent, ConfigSliderComponent], styles: [".phoenix-menu-item{width:100%;padding:.6rem;background:var(--phoenix-background-color-secondary);color:var(--phoenix-text-color);font-size:.8rem;transition:all .5s;display:flex;justify-content:space-between;align-items:center}.phoenix-menu-item-left{display:flex;justify-content:flex-start;min-width:0;padding-right:.5rem;overflow:hidden}.phoenix-menu-item-left .item-name{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.phoenix-menu-item-left .item-icon{margin-right:.2rem}.phoenix-menu-item-right{display:flex;justify-content:flex-end}.phoenix-menu-item-right .item-expand.expanded{transform:scaleY(-1)}.phoenix-menu-item-right .item-settings{margin-right:.2rem}.phoenix-menu-item-right .item-config-backdrop{position:fixed;top:0;left:0;width:100vw;height:100vh;z-index:110}.phoenix-menu-item-right .item-config{position:absolute;margin-top:-5rem;right:100%;width:14rem;padding:.5rem;background:var(--phoenix-background-color-secondary);color:var(--phoenix-text-color-secondary);box-shadow:var(--phoenix-box-shadow);display:flex;flex-direction:column;z-index:120}.phoenix-menu-item-right .item-config>*{margin-bottom:.4rem}.phoenix-menu-item-right .item-config>*:last-child{margin-bottom:0}.phoenix-menu-item-right .item-config .item-config-single{display:flex;flex-direction:row}.phoenix-menu-item-right .item-config .item-config-single .item-config-label{width:30%}.phoenix-menu-item-right .item-config .item-config-single .item-config-data{flex-grow:1;padding-left:.5rem}.phoenix-menu-item .icon-wrapper{display:inline-block;width:1.3rem;height:1.3rem;padding:.23rem;transition:all .4s}.phoenix-menu-item .icon-wrapper.icon-button:hover{background:var(--phoenix-options-icon-bg);border-radius:40%;cursor:pointer}.phoenix-menu-item .icon-wrapper svg{width:100%;height:100%;vertical-align:top}.phoenix-menu-item .mat-slide-toggle-bar{width:30px!important}.phoenix-menu-item .mat-slide-toggle-thumb{width:15px!important;height:15px!important;position:absolute;top:2px}.phoenix-menu-item .mat-slider-horizontal{min-width:0;width:100%;height:20px}.phoenix-menu-item .mat-slider-horizontal .mat-slider-wrapper{top:10px}.phoenix-menu-item label.mat-checkbox-layout{margin:0}@media screen and (max-width: 768px){.phoenix-menu-item{font-size:.75rem;padding:.5rem}.phoenix-menu-item .icon-wrapper{width:1rem;height:1rem;padding:.15rem}}.phoenix-menu-children{margin-left:.5rem;border-left:1px solid var(--phoenix-accent)}.range-slider .range-slider-inputs{gap:20%}\n"], encapsulation: 2 });
531
+ } }, dependencies: [i2.NgClass, i2.NgForOf, i2.NgIf, i2.NgTemplateOutlet, i2.NgStyle, i2.NgSwitch, i2.NgSwitchCase, i3.MatButton, i4.NgSelectOption, i4.ɵNgSelectMultipleOption, i4.DefaultValueAccessor, i4.NumberValueAccessor, i4.NgControlStatus, i4.NgModel, i4$1.MatSlideToggle, i5.MatCheckbox, PhoenixMenuItemComponent, ConfigSliderComponent], styles: [".phoenix-menu-item{width:100%;padding:.6rem;background:var(--phoenix-background-color-secondary);color:var(--phoenix-text-color);font-size:.8rem;transition:all .5s;display:flex;justify-content:space-between;align-items:center}.phoenix-menu-item-left{display:flex;justify-content:flex-start;min-width:0;padding-right:.5rem;overflow:hidden}.phoenix-menu-item-left .item-name{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.phoenix-menu-item-left .item-icon{margin-right:.2rem}.phoenix-menu-item-right{display:flex;justify-content:flex-end}.phoenix-menu-item-right .item-expand.expanded{transform:scaleY(-1)}.phoenix-menu-item-right .item-settings{margin-right:.2rem}@media screen and (max-width:768px){.phoenix-menu-item{font-size:.75rem;padding:.5rem}}.phoenix-menu-item-compact{flex:1;min-width:0;color:var(--phoenix-text-color)}.phoenix-menu-item-compact .compact-option-button{width:100%;display:flex;flex-direction:column;align-items:center;gap:.15rem;padding:.3rem .2rem;color:inherit;border-radius:.3rem;transition:all .4s}.phoenix-menu-item-compact .compact-option-button:hover{background:var(--phoenix-options-icon-bg);cursor:pointer}.phoenix-menu-item-compact .compact-option-button .compact-option-label{font-size:.65rem;line-height:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}.phoenix-menu-options-bar{display:flex;align-items:stretch;gap:.25rem;padding:.25rem .4rem;background:var(--phoenix-background-color-secondary)}.phoenix-menu-options-bar app-phoenix-menu-item{display:flex;flex:1;min-width:0}.phoenix-menu-item .item-config-backdrop,.phoenix-menu-item-compact .item-config-backdrop{position:fixed;top:0;left:0;width:100vw;height:100vh;z-index:110}.phoenix-menu-item .item-config,.phoenix-menu-item-compact .item-config{position:absolute;right:100%;width:14rem;padding:.5rem;background:var(--phoenix-background-color-secondary);color:var(--phoenix-text-color-secondary);box-shadow:var(--phoenix-box-shadow);display:flex;flex-direction:column;z-index:120;max-height:60vh;overflow-y:auto;font-size:.8rem}.phoenix-menu-item .item-config::-webkit-scrollbar,.phoenix-menu-item-compact .item-config::-webkit-scrollbar{width:4px}.phoenix-menu-item .item-config::-webkit-scrollbar-thumb,.phoenix-menu-item-compact .item-config::-webkit-scrollbar-thumb{background:var(--phoenix-text-color-secondary, #999);border-radius:4px}.phoenix-menu-item .item-config>*,.phoenix-menu-item-compact .item-config>*{margin-bottom:.4rem}.phoenix-menu-item .item-config>*:last-child,.phoenix-menu-item-compact .item-config>*:last-child{margin-bottom:0}.phoenix-menu-item .item-config .item-config-single,.phoenix-menu-item-compact .item-config .item-config-single{display:flex;flex-direction:row}.phoenix-menu-item .item-config .item-config-single .item-config-label,.phoenix-menu-item-compact .item-config .item-config-single .item-config-label{width:30%}.phoenix-menu-item .item-config .item-config-single .item-config-data,.phoenix-menu-item-compact .item-config .item-config-single .item-config-data{flex-grow:1;padding-left:.5rem;min-width:0}.phoenix-menu-item .item-config .item-config-single.range-slider-row,.phoenix-menu-item-compact .item-config .item-config-single.range-slider-row{align-items:center}.phoenix-menu-item .item-config .item-config-single.range-slider-row .item-config-label,.phoenix-menu-item-compact .item-config .item-config-single.range-slider-row .item-config-label{width:auto;min-width:1.6rem;flex-shrink:0;margin-bottom:0}.phoenix-menu-item .icon-wrapper,.phoenix-menu-item-compact .icon-wrapper{display:inline-block;width:1.3rem;height:1.3rem;padding:.23rem;transition:all .4s}.phoenix-menu-item .icon-wrapper.icon-button:hover,.phoenix-menu-item-compact .icon-wrapper.icon-button:hover{background:var(--phoenix-options-icon-bg);border-radius:40%;cursor:pointer}.phoenix-menu-item .icon-wrapper svg,.phoenix-menu-item-compact .icon-wrapper svg{width:100%;height:100%;vertical-align:top}.phoenix-menu-item .mat-slide-toggle-bar,.phoenix-menu-item-compact .mat-slide-toggle-bar{width:30px!important}.phoenix-menu-item .mat-slide-toggle-thumb,.phoenix-menu-item-compact .mat-slide-toggle-thumb{width:15px!important;height:15px!important;position:absolute;top:2px}.phoenix-menu-item .mat-slider-horizontal,.phoenix-menu-item-compact .mat-slider-horizontal{min-width:0;width:100%;height:20px}.phoenix-menu-item .mat-slider-horizontal .mat-slider-wrapper,.phoenix-menu-item-compact .mat-slider-horizontal .mat-slider-wrapper{top:10px}.phoenix-menu-item label.mat-checkbox-layout,.phoenix-menu-item-compact label.mat-checkbox-layout{margin:0}@media screen and (max-width:768px){.phoenix-menu-item .icon-wrapper,.phoenix-menu-item-compact .icon-wrapper{width:1rem;height:1rem;padding:.15rem}}.phoenix-menu-children{margin-left:.5rem;border-left:1px solid var(--phoenix-accent);max-height:35vh;overflow-y:auto}.phoenix-menu-children::-webkit-scrollbar{width:4px}.phoenix-menu-children::-webkit-scrollbar-thumb{background:var(--phoenix-text-color-secondary, #999);border-radius:4px}.range-slider .range-slider-inputs{gap:4px}.range-slider .range-slider-side{display:flex;align-items:center;flex:1;gap:3px;min-width:0}.range-slider .range-slider-side mat-checkbox{flex-shrink:0;--mdc-checkbox-state-layer-size: 24px}.range-slider .range-slider-side input[type=number]{min-width:0;width:100%;padding:.15rem .25rem;font-size:.75rem;appearance:textfield;-moz-appearance:textfield}.range-slider .range-slider-side input[type=number]::-webkit-outer-spin-button,.range-slider .range-slider-side input[type=number]::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}\n"], encapsulation: 2 });
426
532
  }
427
533
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(PhoenixMenuItemComponent, [{
428
534
  type: Component,
429
- args: [{ standalone: false, selector: 'app-phoenix-menu-item', encapsulation: ViewEncapsulation.None, template: "<div class=\"phoenix-menu-item\" #phoenixMenuItem>\n <div class=\"phoenix-menu-item-left align-items-center\">\n <!-- If the item has some toggle function -->\n <ng-container *ngIf=\"currentNode.onToggle; else nodeName\">\n <mat-slide-toggle\n [checked]=\"currentNode.toggleState\"\n (change)=\"currentNode.toggleSelfAndDescendants($event.checked)\"\n >\n <ng-container *ngTemplateOutlet=\"nodeName\"></ng-container>\n </mat-slide-toggle>\n </ng-container>\n <!-- If the item has no toggle function -->\n <ng-template #nodeName>\n <span class=\"d-flex w-100 align-items-center\">\n <span *ngIf=\"currentNode.icon\" class=\"icon-wrapper item-icon\">\n <svg>\n <use\n attr.href=\"assets/icons/{{ currentNode.icon }}.svg#{{\n currentNode.icon\n }}\"\n ></use>\n </svg>\n </span>\n <span class=\"item-name\" [title]=\"currentNode.name\">{{\n currentNode.name\n }}</span>\n </span>\n </ng-template>\n </div>\n <div class=\"phoenix-menu-item-right\">\n <div *ngIf=\"currentNode.configs.length > 0\">\n <button\n class=\"icon-wrapper icon-button btn-blank item-settings\"\n (click)=\"\n calculateConfigTop();\n currentNode.configActive = !currentNode.configActive\n \"\n >\n <svg>\n <use href=\"assets/icons/gear.svg#gear\"></use>\n </svg>\n </button>\n <div\n class=\"item-config-backdrop\"\n *ngIf=\"currentNode.configActive\"\n (click)=\"currentNode.configActive = false\"\n ></div>\n <div\n class=\"item-config\"\n [hidden]=\"!currentNode.configActive\"\n [ngStyle]=\"{ 'top.px': configTop }\"\n >\n <ng-container\n *ngFor=\"let config of castConfigsToAny(currentNode.configs)\"\n [ngSwitch]=\"config.type\"\n >\n <!-- Config types -->\n <div class=\"item-config-single\" *ngIf=\"!config.hidden\">\n <label\n class=\"item-config-label\"\n for=\"item-config-field\"\n *ngIf=\"config.type !== 'button'\"\n [ngClass]=\"{ 'font-weight-bold w-100': config.type === 'label' }\"\n >\n {{ config.label }}\n </label>\n <div\n class=\"item-config-data\"\n [ngClass]=\"{ 'p-0': config.type === 'button' }\"\n *ngIf=\"config.type !== 'label'\"\n >\n <mat-checkbox\n *ngSwitchCase=\"'checkbox'\"\n [checked]=\"config.isChecked\"\n (change)=\"\n config.onChange($event.checked);\n config.isChecked = $event.checked\n \"\n ></mat-checkbox>\n\n <app-config-slider\n *ngSwitchCase=\"'slider'\"\n [value]=\"config.value\"\n (onChange)=\"config.onChange($event); config.value = $event\"\n [min]=\"config.min\"\n [max]=\"config.max\"\n [step]=\"config.step\"\n [allowCustomValue]=\"config.allowCustomValue\"\n >\n </app-config-slider>\n\n <button\n *ngSwitchCase=\"'button'\"\n class=\"w-100\"\n (click)=\"config.onClick()\"\n mat-button\n mat-stroked-button\n >\n {{ config.label }}\n </button>\n\n <input\n *ngSwitchCase=\"'color'\"\n id=\"item-config-field\"\n type=\"color\"\n [value]=\"config.color\"\n (input)=\"\n config.onChange($event.target.value);\n config.color = $event.target.value\n \"\n />\n\n <div *ngSwitchCase=\"'rangeSlider'\" class=\"range-slider\">\n <div class=\"range-slider-inputs d-flex justify-content-between\">\n <mat-checkbox\n [(ngModel)]=\"config.enableMin\"\n (change)=\"config.setEnableMin($event.checked)\"\n ></mat-checkbox>\n <mat-checkbox\n [(ngModel)]=\"config.enableMax\"\n (change)=\"config.setEnableMax($event.checked)\"\n ></mat-checkbox>\n </div>\n <div class=\"range-slider-inputs d-flex justify-content-between\">\n <input\n type=\"number\"\n placeholder=\"Min\"\n class=\"form-control form-control-sm\"\n [(ngModel)]=\"config.value\"\n (input)=\"\n config.value = $event.target.value;\n config.onChange(config)\n \"\n step=\"config.step\"\n />\n <input\n type=\"number\"\n placeholder=\"Max\"\n class=\"form-control form-control-sm\"\n [(ngModel)]=\"config.highValue\"\n (input)=\"\n config.highValue = $event.target.value;\n config.onChange(config)\n \"\n step=\"config.step\"\n />\n </div>\n </div>\n\n <select\n *ngSwitchCase=\"'select'\"\n id=\"item-config-field\"\n class=\"w-100\"\n (change)=\"config.onChange($event.target.value)\"\n >\n <option\n *ngFor=\"let singleOption of config.options\"\n [value]=\"singleOption\"\n >\n {{ singleOption }}\n </option>\n </select>\n </div>\n </div>\n <!-- Config types END -->\n </ng-container>\n </div>\n </div>\n <button\n class=\"icon-wrapper icon-button btn-blank item-expand\"\n *ngIf=\"currentNode.children.length > 0\"\n (click)=\"currentNode.childrenActive = !currentNode.childrenActive\"\n [ngClass]=\"{ expanded: currentNode.childrenActive }\"\n data-testid=\"dropdown\"\n >\n <svg>\n <use href=\"assets/icons/expand.svg#expand\"></use>\n </svg>\n </button>\n </div>\n</div>\n<div class=\"phoenix-menu-children\" *ngIf=\"currentNode.childrenActive\">\n <app-phoenix-menu-item\n *ngFor=\"let childNode of currentNode.children\"\n [currentNode]=\"childNode\"\n >\n </app-phoenix-menu-item>\n</div>\n", styles: [".phoenix-menu-item{width:100%;padding:.6rem;background:var(--phoenix-background-color-secondary);color:var(--phoenix-text-color);font-size:.8rem;transition:all .5s;display:flex;justify-content:space-between;align-items:center}.phoenix-menu-item-left{display:flex;justify-content:flex-start;min-width:0;padding-right:.5rem;overflow:hidden}.phoenix-menu-item-left .item-name{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.phoenix-menu-item-left .item-icon{margin-right:.2rem}.phoenix-menu-item-right{display:flex;justify-content:flex-end}.phoenix-menu-item-right .item-expand.expanded{transform:scaleY(-1)}.phoenix-menu-item-right .item-settings{margin-right:.2rem}.phoenix-menu-item-right .item-config-backdrop{position:fixed;top:0;left:0;width:100vw;height:100vh;z-index:110}.phoenix-menu-item-right .item-config{position:absolute;margin-top:-5rem;right:100%;width:14rem;padding:.5rem;background:var(--phoenix-background-color-secondary);color:var(--phoenix-text-color-secondary);box-shadow:var(--phoenix-box-shadow);display:flex;flex-direction:column;z-index:120}.phoenix-menu-item-right .item-config>*{margin-bottom:.4rem}.phoenix-menu-item-right .item-config>*:last-child{margin-bottom:0}.phoenix-menu-item-right .item-config .item-config-single{display:flex;flex-direction:row}.phoenix-menu-item-right .item-config .item-config-single .item-config-label{width:30%}.phoenix-menu-item-right .item-config .item-config-single .item-config-data{flex-grow:1;padding-left:.5rem}.phoenix-menu-item .icon-wrapper{display:inline-block;width:1.3rem;height:1.3rem;padding:.23rem;transition:all .4s}.phoenix-menu-item .icon-wrapper.icon-button:hover{background:var(--phoenix-options-icon-bg);border-radius:40%;cursor:pointer}.phoenix-menu-item .icon-wrapper svg{width:100%;height:100%;vertical-align:top}.phoenix-menu-item .mat-slide-toggle-bar{width:30px!important}.phoenix-menu-item .mat-slide-toggle-thumb{width:15px!important;height:15px!important;position:absolute;top:2px}.phoenix-menu-item .mat-slider-horizontal{min-width:0;width:100%;height:20px}.phoenix-menu-item .mat-slider-horizontal .mat-slider-wrapper{top:10px}.phoenix-menu-item label.mat-checkbox-layout{margin:0}@media screen and (max-width: 768px){.phoenix-menu-item{font-size:.75rem;padding:.5rem}.phoenix-menu-item .icon-wrapper{width:1rem;height:1rem;padding:.15rem}}.phoenix-menu-children{margin-left:.5rem;border-left:1px solid var(--phoenix-accent)}.range-slider .range-slider-inputs{gap:20%}\n"] }]
535
+ args: [{ standalone: false, selector: 'app-phoenix-menu-item', encapsulation: ViewEncapsulation.None, template: "<!-- Leaf nodes holding only configs (Draw/Cut/Color Options) are shown as a\n compact icon button; everything else as a full menu row. -->\n<div\n *ngIf=\"isCompact; else fullItem\"\n class=\"phoenix-menu-item-compact\"\n #phoenixMenuItem\n>\n <button\n class=\"btn-blank compact-option-button\"\n [title]=\"currentNode.name\"\n (click)=\"\n calculateConfigTop(); currentNode.configActive = !currentNode.configActive\n \"\n >\n <span class=\"icon-wrapper\">\n <svg>\n <use\n attr.href=\"assets/icons/{{ currentNode.icon }}.svg#{{\n currentNode.icon\n }}\"\n ></use>\n </svg>\n </span>\n <span class=\"compact-option-label\">{{ compactLabel }}</span>\n </button>\n <ng-container *ngTemplateOutlet=\"configPopup\"></ng-container>\n</div>\n\n<ng-template #fullItem>\n <div class=\"phoenix-menu-item\" #phoenixMenuItem>\n <div class=\"phoenix-menu-item-left align-items-center\">\n <!-- If the item has some toggle function -->\n <ng-container *ngIf=\"currentNode.onToggle; else nodeName\">\n <mat-slide-toggle\n [checked]=\"currentNode.toggleState\"\n (change)=\"currentNode.toggleSelfAndDescendants($event.checked)\"\n >\n <ng-container *ngTemplateOutlet=\"nodeName\"></ng-container>\n </mat-slide-toggle>\n </ng-container>\n <!-- If the item has no toggle function -->\n <ng-template #nodeName>\n <span class=\"d-flex w-100 align-items-center\">\n <span *ngIf=\"currentNode.icon\" class=\"icon-wrapper item-icon\">\n <svg>\n <use\n attr.href=\"assets/icons/{{ currentNode.icon }}.svg#{{\n currentNode.icon\n }}\"\n ></use>\n </svg>\n </span>\n <span class=\"item-name\" [title]=\"currentNode.name\">{{\n currentNode.name\n }}</span>\n </span>\n </ng-template>\n </div>\n <div class=\"phoenix-menu-item-right\">\n <div *ngIf=\"currentNode.configs.length > 0\">\n <button\n class=\"icon-wrapper icon-button btn-blank item-settings\"\n (click)=\"\n calculateConfigTop();\n currentNode.configActive = !currentNode.configActive\n \"\n >\n <svg>\n <use href=\"assets/icons/gear.svg#gear\"></use>\n </svg>\n </button>\n <ng-container *ngTemplateOutlet=\"configPopup\"></ng-container>\n </div>\n <button\n class=\"icon-wrapper icon-button btn-blank item-expand\"\n *ngIf=\"currentNode.children.length > 0\"\n (click)=\"currentNode.childrenActive = !currentNode.childrenActive\"\n [ngClass]=\"{ expanded: currentNode.childrenActive }\"\n data-testid=\"dropdown\"\n >\n <svg>\n <use href=\"assets/icons/expand.svg#expand\"></use>\n </svg>\n </button>\n </div>\n </div>\n</ng-template>\n\n<div class=\"phoenix-menu-children\" *ngIf=\"currentNode.childrenActive\">\n <div class=\"phoenix-menu-options-bar\" *ngIf=\"compactChildren.length > 0\">\n <app-phoenix-menu-item\n *ngFor=\"let childNode of compactChildren\"\n [currentNode]=\"childNode\"\n >\n </app-phoenix-menu-item>\n </div>\n <app-phoenix-menu-item\n *ngFor=\"let childNode of regularChildren\"\n [currentNode]=\"childNode\"\n >\n </app-phoenix-menu-item>\n</div>\n\n<!-- Config popup shared by the full row (gear button) and the compact icon button -->\n<ng-template #configPopup>\n <div\n class=\"item-config-backdrop\"\n *ngIf=\"currentNode.configActive\"\n (click)=\"currentNode.configActive = false\"\n ></div>\n <div\n class=\"item-config\"\n [hidden]=\"!currentNode.configActive\"\n [ngStyle]=\"{ 'top.px': configTop }\"\n >\n <ng-container\n *ngFor=\"let config of castConfigsToAny(currentNode.configs)\"\n [ngSwitch]=\"config.type\"\n >\n <!-- Config types -->\n <div\n class=\"item-config-single\"\n [ngClass]=\"{ 'range-slider-row': config.type === 'rangeSlider' }\"\n *ngIf=\"!config.hidden\"\n >\n <label\n class=\"item-config-label\"\n for=\"item-config-field\"\n *ngIf=\"config.type !== 'button'\"\n [ngClass]=\"{ 'font-weight-bold w-100': config.type === 'label' }\"\n >\n {{ config.label }}\n </label>\n <div\n class=\"item-config-data\"\n [ngClass]=\"{ 'p-0': config.type === 'button' }\"\n *ngIf=\"config.type !== 'label'\"\n >\n <mat-checkbox\n *ngSwitchCase=\"'checkbox'\"\n [checked]=\"config.isChecked\"\n (change)=\"\n config.onChange($event.checked); config.isChecked = $event.checked\n \"\n ></mat-checkbox>\n\n <app-config-slider\n *ngSwitchCase=\"'slider'\"\n [value]=\"config.value\"\n (onChange)=\"config.onChange($event); config.value = $event\"\n [min]=\"config.min\"\n [max]=\"config.max\"\n [step]=\"config.step\"\n [allowCustomValue]=\"config.allowCustomValue\"\n >\n </app-config-slider>\n\n <button\n *ngSwitchCase=\"'button'\"\n class=\"w-100\"\n (click)=\"config.onClick()\"\n mat-button\n mat-stroked-button\n >\n {{ config.label }}\n </button>\n\n <input\n *ngSwitchCase=\"'color'\"\n id=\"item-config-field\"\n type=\"color\"\n [value]=\"config.color\"\n (input)=\"\n config.onChange($event.target.value);\n config.color = $event.target.value\n \"\n />\n\n <div *ngSwitchCase=\"'rangeSlider'\" class=\"range-slider\">\n <div class=\"range-slider-inputs d-flex align-items-center\">\n <div class=\"range-slider-side\">\n <mat-checkbox\n [(ngModel)]=\"config.enableMin\"\n (change)=\"config.setEnableMin($event.checked)\"\n ></mat-checkbox>\n <input\n type=\"number\"\n placeholder=\"Min\"\n class=\"form-control form-control-sm\"\n [(ngModel)]=\"config.value\"\n (input)=\"\n config.value = $event.target.value; config.onChange(config)\n \"\n [step]=\"config.step\"\n />\n </div>\n <div class=\"range-slider-side\">\n <mat-checkbox\n [(ngModel)]=\"config.enableMax\"\n (change)=\"config.setEnableMax($event.checked)\"\n ></mat-checkbox>\n <input\n type=\"number\"\n placeholder=\"Max\"\n class=\"form-control form-control-sm\"\n [(ngModel)]=\"config.highValue\"\n (input)=\"\n config.highValue = $event.target.value;\n config.onChange(config)\n \"\n [step]=\"config.step\"\n />\n </div>\n </div>\n </div>\n\n <select\n *ngSwitchCase=\"'select'\"\n id=\"item-config-field\"\n class=\"w-100\"\n [value]=\"config.value ?? config.options[0]\"\n (change)=\"config.onChange($event.target.value)\"\n >\n <option\n *ngFor=\"let singleOption of config.options\"\n [value]=\"singleOption\"\n >\n {{ singleOption }}\n </option>\n </select>\n </div>\n </div>\n <!-- Config types END -->\n </ng-container>\n </div>\n</ng-template>\n", styles: [".phoenix-menu-item{width:100%;padding:.6rem;background:var(--phoenix-background-color-secondary);color:var(--phoenix-text-color);font-size:.8rem;transition:all .5s;display:flex;justify-content:space-between;align-items:center}.phoenix-menu-item-left{display:flex;justify-content:flex-start;min-width:0;padding-right:.5rem;overflow:hidden}.phoenix-menu-item-left .item-name{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.phoenix-menu-item-left .item-icon{margin-right:.2rem}.phoenix-menu-item-right{display:flex;justify-content:flex-end}.phoenix-menu-item-right .item-expand.expanded{transform:scaleY(-1)}.phoenix-menu-item-right .item-settings{margin-right:.2rem}@media screen and (max-width:768px){.phoenix-menu-item{font-size:.75rem;padding:.5rem}}.phoenix-menu-item-compact{flex:1;min-width:0;color:var(--phoenix-text-color)}.phoenix-menu-item-compact .compact-option-button{width:100%;display:flex;flex-direction:column;align-items:center;gap:.15rem;padding:.3rem .2rem;color:inherit;border-radius:.3rem;transition:all .4s}.phoenix-menu-item-compact .compact-option-button:hover{background:var(--phoenix-options-icon-bg);cursor:pointer}.phoenix-menu-item-compact .compact-option-button .compact-option-label{font-size:.65rem;line-height:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}.phoenix-menu-options-bar{display:flex;align-items:stretch;gap:.25rem;padding:.25rem .4rem;background:var(--phoenix-background-color-secondary)}.phoenix-menu-options-bar app-phoenix-menu-item{display:flex;flex:1;min-width:0}.phoenix-menu-item .item-config-backdrop,.phoenix-menu-item-compact .item-config-backdrop{position:fixed;top:0;left:0;width:100vw;height:100vh;z-index:110}.phoenix-menu-item .item-config,.phoenix-menu-item-compact .item-config{position:absolute;right:100%;width:14rem;padding:.5rem;background:var(--phoenix-background-color-secondary);color:var(--phoenix-text-color-secondary);box-shadow:var(--phoenix-box-shadow);display:flex;flex-direction:column;z-index:120;max-height:60vh;overflow-y:auto;font-size:.8rem}.phoenix-menu-item .item-config::-webkit-scrollbar,.phoenix-menu-item-compact .item-config::-webkit-scrollbar{width:4px}.phoenix-menu-item .item-config::-webkit-scrollbar-thumb,.phoenix-menu-item-compact .item-config::-webkit-scrollbar-thumb{background:var(--phoenix-text-color-secondary, #999);border-radius:4px}.phoenix-menu-item .item-config>*,.phoenix-menu-item-compact .item-config>*{margin-bottom:.4rem}.phoenix-menu-item .item-config>*:last-child,.phoenix-menu-item-compact .item-config>*:last-child{margin-bottom:0}.phoenix-menu-item .item-config .item-config-single,.phoenix-menu-item-compact .item-config .item-config-single{display:flex;flex-direction:row}.phoenix-menu-item .item-config .item-config-single .item-config-label,.phoenix-menu-item-compact .item-config .item-config-single .item-config-label{width:30%}.phoenix-menu-item .item-config .item-config-single .item-config-data,.phoenix-menu-item-compact .item-config .item-config-single .item-config-data{flex-grow:1;padding-left:.5rem;min-width:0}.phoenix-menu-item .item-config .item-config-single.range-slider-row,.phoenix-menu-item-compact .item-config .item-config-single.range-slider-row{align-items:center}.phoenix-menu-item .item-config .item-config-single.range-slider-row .item-config-label,.phoenix-menu-item-compact .item-config .item-config-single.range-slider-row .item-config-label{width:auto;min-width:1.6rem;flex-shrink:0;margin-bottom:0}.phoenix-menu-item .icon-wrapper,.phoenix-menu-item-compact .icon-wrapper{display:inline-block;width:1.3rem;height:1.3rem;padding:.23rem;transition:all .4s}.phoenix-menu-item .icon-wrapper.icon-button:hover,.phoenix-menu-item-compact .icon-wrapper.icon-button:hover{background:var(--phoenix-options-icon-bg);border-radius:40%;cursor:pointer}.phoenix-menu-item .icon-wrapper svg,.phoenix-menu-item-compact .icon-wrapper svg{width:100%;height:100%;vertical-align:top}.phoenix-menu-item .mat-slide-toggle-bar,.phoenix-menu-item-compact .mat-slide-toggle-bar{width:30px!important}.phoenix-menu-item .mat-slide-toggle-thumb,.phoenix-menu-item-compact .mat-slide-toggle-thumb{width:15px!important;height:15px!important;position:absolute;top:2px}.phoenix-menu-item .mat-slider-horizontal,.phoenix-menu-item-compact .mat-slider-horizontal{min-width:0;width:100%;height:20px}.phoenix-menu-item .mat-slider-horizontal .mat-slider-wrapper,.phoenix-menu-item-compact .mat-slider-horizontal .mat-slider-wrapper{top:10px}.phoenix-menu-item label.mat-checkbox-layout,.phoenix-menu-item-compact label.mat-checkbox-layout{margin:0}@media screen and (max-width:768px){.phoenix-menu-item .icon-wrapper,.phoenix-menu-item-compact .icon-wrapper{width:1rem;height:1rem;padding:.15rem}}.phoenix-menu-children{margin-left:.5rem;border-left:1px solid var(--phoenix-accent);max-height:35vh;overflow-y:auto}.phoenix-menu-children::-webkit-scrollbar{width:4px}.phoenix-menu-children::-webkit-scrollbar-thumb{background:var(--phoenix-text-color-secondary, #999);border-radius:4px}.range-slider .range-slider-inputs{gap:4px}.range-slider .range-slider-side{display:flex;align-items:center;flex:1;gap:3px;min-width:0}.range-slider .range-slider-side mat-checkbox{flex-shrink:0;--mdc-checkbox-state-layer-size: 24px}.range-slider .range-slider-side input[type=number]{min-width:0;width:100%;padding:.15rem .25rem;font-size:.75rem;appearance:textfield;-moz-appearance:textfield}.range-slider .range-slider-side input[type=number]::-webkit-outer-spin-button,.range-slider .range-slider-side input[type=number]::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}\n"] }]
430
536
  }], () => [{ type: i0.ChangeDetectorRef }], { currentNode: [{
431
537
  type: Input
432
538
  }], phoenixMenuItem: [{
@@ -435,25 +541,304 @@ class PhoenixMenuItemComponent {
435
541
  }] }); })();
436
542
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(PhoenixMenuItemComponent, { className: "PhoenixMenuItemComponent", filePath: "components/phoenix-menu/phoenix-menu-item/phoenix-menu-item.component.ts", lineNumber: 18 }); })();
437
543
 
544
+ class ShortcutsDialogComponent {
545
+ dialogRef;
546
+ constructor(dialogRef) {
547
+ this.dialogRef = dialogRef;
548
+ }
549
+ onClose() {
550
+ this.dialogRef.close();
551
+ }
552
+ static ɵfac = function ShortcutsDialogComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ShortcutsDialogComponent)(i0.ɵɵdirectiveInject(i1$1.MatDialogRef)); };
553
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ShortcutsDialogComponent, selectors: [["app-shortcuts-dialog"]], standalone: false, decls: 68, vars: 0, consts: [[1, "dialog"], ["mat-dialog-title", ""], ["mat-dialog-content", "", 1, "dialog-content", "pb-3"], [1, "text-center", "mt-2", "mb-3"], [1, "d-flex", "justify-content-between", "mb-2"], [1, "badge", "badge-secondary", "p-2"], [1, "text-center", "mb-3"], ["mat-dialog-actions", "", 1, "d-flex", "justify-content-end"], ["mat-button", "", 3, "click"]], template: function ShortcutsDialogComponent_Template(rf, ctx) { if (rf & 1) {
554
+ i0.ɵɵelementStart(0, "div", 0)(1, "h1", 1);
555
+ i0.ɵɵtext(2, "Keyboard Shortcuts");
556
+ i0.ɵɵelementEnd();
557
+ i0.ɵɵelementStart(3, "div", 2)(4, "p", 3)(5, "b");
558
+ i0.ɵɵtext(6, "Event & Session Controls");
559
+ i0.ɵɵelementEnd()();
560
+ i0.ɵɵelementStart(7, "div", 4)(8, "span");
561
+ i0.ɵɵtext(9, "Next event");
562
+ i0.ɵɵelementEnd();
563
+ i0.ɵɵelementStart(10, "span", 5);
564
+ i0.ɵɵtext(11, "Shift + ArrowRight");
565
+ i0.ɵɵelementEnd()();
566
+ i0.ɵɵelementStart(12, "div", 4)(13, "span");
567
+ i0.ɵɵtext(14, "Previous event");
568
+ i0.ɵɵelementEnd();
569
+ i0.ɵɵelementStart(15, "span", 5);
570
+ i0.ɵɵtext(16, "Shift + ArrowLeft");
571
+ i0.ɵɵelementEnd()();
572
+ i0.ɵɵelementStart(17, "div", 4)(18, "span");
573
+ i0.ɵɵtext(19, "Toggle session recording");
574
+ i0.ɵɵelementEnd();
575
+ i0.ɵɵelementStart(20, "span", 5);
576
+ i0.ɵɵtext(21, "Shift + S");
577
+ i0.ɵɵelementEnd()();
578
+ i0.ɵɵelement(22, "hr");
579
+ i0.ɵɵelementStart(23, "p", 6)(24, "b");
580
+ i0.ɵɵtext(25, "Camera & Viewport Controls");
581
+ i0.ɵɵelementEnd()();
582
+ i0.ɵɵelementStart(26, "div", 4)(27, "span");
583
+ i0.ɵɵtext(28, "Toggle auto-rotation");
584
+ i0.ɵɵelementEnd();
585
+ i0.ɵɵelementStart(29, "span", 5);
586
+ i0.ɵɵtext(30, "Shift + R");
587
+ i0.ɵɵelementEnd()();
588
+ i0.ɵɵelementStart(31, "div", 4)(32, "span");
589
+ i0.ɵɵtext(33, "Zoom in");
590
+ i0.ɵɵelementEnd();
591
+ i0.ɵɵelementStart(34, "span", 5);
592
+ i0.ɵɵtext(35, "Shift + +");
593
+ i0.ɵɵelementEnd()();
594
+ i0.ɵɵelementStart(36, "div", 4)(37, "span");
595
+ i0.ɵɵtext(38, "Zoom out");
596
+ i0.ɵɵelementEnd();
597
+ i0.ɵɵelementStart(39, "span", 5);
598
+ i0.ɵɵtext(40, "Shift + -");
599
+ i0.ɵɵelementEnd()();
600
+ i0.ɵɵelementStart(41, "div", 4)(42, "span");
601
+ i0.ɵɵtext(43, "Revert main camera");
602
+ i0.ɵɵelementEnd();
603
+ i0.ɵɵelementStart(44, "span", 5);
604
+ i0.ɵɵtext(45, "Shift + V");
605
+ i0.ɵɵelementEnd()();
606
+ i0.ɵɵelementStart(46, "div", 4)(47, "span");
607
+ i0.ɵɵtext(48, "Toggle local clipping");
608
+ i0.ɵɵelementEnd();
609
+ i0.ɵɵelementStart(49, "span", 5);
610
+ i0.ɵɵtext(50, "Shift + C");
611
+ i0.ɵɵelementEnd()();
612
+ i0.ɵɵelement(51, "hr");
613
+ i0.ɵɵelementStart(52, "p", 6)(53, "b");
614
+ i0.ɵɵtext(54, "UI & Theming Controls");
615
+ i0.ɵɵelementEnd()();
616
+ i0.ɵɵelementStart(55, "div", 4)(56, "span");
617
+ i0.ɵɵtext(57, "Toggle dark theme");
618
+ i0.ɵɵelementEnd();
619
+ i0.ɵɵelementStart(58, "span", 5);
620
+ i0.ɵɵtext(59, "Shift + T");
621
+ i0.ɵɵelementEnd()();
622
+ i0.ɵɵelementStart(60, "div", 4)(61, "span");
623
+ i0.ɵɵtext(62, "Preset views (if configured)");
624
+ i0.ɵɵelementEnd();
625
+ i0.ɵɵelementStart(63, "span", 5);
626
+ i0.ɵɵtext(64, "Shift + 1-9");
627
+ i0.ɵɵelementEnd()()();
628
+ i0.ɵɵelementStart(65, "div", 7)(66, "button", 8);
629
+ i0.ɵɵlistener("click", function ShortcutsDialogComponent_Template_button_click_66_listener() { return ctx.onClose(); });
630
+ i0.ɵɵtext(67, "Close");
631
+ i0.ɵɵelementEnd()()();
632
+ } }, dependencies: [i1$1.MatDialogTitle, i1$1.MatDialogActions, i1$1.MatDialogContent, i3.MatButton], styles: [".dialog[_ngcontent-%COMP%]{min-width:400px;max-height:80vh;background-color:var(--phoenix-background-color-secondary, #222);color:var(--phoenix-text-color, #fff)}.dialog[_ngcontent-%COMP%] .dialog-content[_ngcontent-%COMP%]{overflow-y:auto;max-height:calc(80vh - 120px)}.dialog[_ngcontent-%COMP%] .dialog-content[_ngcontent-%COMP%] span[_ngcontent-%COMP%]{display:flex;align-items:center}"] });
633
+ }
634
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ShortcutsDialogComponent, [{
635
+ type: Component,
636
+ args: [{ standalone: false, selector: 'app-shortcuts-dialog', template: "<div class=\"dialog\">\n <h1 mat-dialog-title>Keyboard Shortcuts</h1>\n <div mat-dialog-content class=\"dialog-content pb-3\">\n <p class=\"text-center mt-2 mb-3\"><b>Event & Session Controls</b></p>\n <div class=\"d-flex justify-content-between mb-2\">\n <span>Next event</span>\n <span class=\"badge badge-secondary p-2\">Shift + ArrowRight</span>\n </div>\n <div class=\"d-flex justify-content-between mb-2\">\n <span>Previous event</span>\n <span class=\"badge badge-secondary p-2\">Shift + ArrowLeft</span>\n </div>\n <div class=\"d-flex justify-content-between mb-2\">\n <span>Toggle session recording</span>\n <span class=\"badge badge-secondary p-2\">Shift + S</span>\n </div>\n\n <hr />\n <p class=\"text-center mb-3\"><b>Camera & Viewport Controls</b></p>\n <div class=\"d-flex justify-content-between mb-2\">\n <span>Toggle auto-rotation</span>\n <span class=\"badge badge-secondary p-2\">Shift + R</span>\n </div>\n <div class=\"d-flex justify-content-between mb-2\">\n <span>Zoom in</span>\n <span class=\"badge badge-secondary p-2\">Shift + +</span>\n </div>\n <div class=\"d-flex justify-content-between mb-2\">\n <span>Zoom out</span>\n <span class=\"badge badge-secondary p-2\">Shift + -</span>\n </div>\n <div class=\"d-flex justify-content-between mb-2\">\n <span>Revert main camera</span>\n <span class=\"badge badge-secondary p-2\">Shift + V</span>\n </div>\n <div class=\"d-flex justify-content-between mb-2\">\n <span>Toggle local clipping</span>\n <span class=\"badge badge-secondary p-2\">Shift + C</span>\n </div>\n\n <hr />\n <p class=\"text-center mb-3\"><b>UI & Theming Controls</b></p>\n <div class=\"d-flex justify-content-between mb-2\">\n <span>Toggle dark theme</span>\n <span class=\"badge badge-secondary p-2\">Shift + T</span>\n </div>\n <div class=\"d-flex justify-content-between mb-2\">\n <span>Preset views (if configured)</span>\n <span class=\"badge badge-secondary p-2\">Shift + 1-9</span>\n </div>\n </div>\n <div mat-dialog-actions class=\"d-flex justify-content-end\">\n <button mat-button (click)=\"onClose()\">Close</button>\n </div>\n</div>\n", styles: [".dialog{min-width:400px;max-height:80vh;background-color:var(--phoenix-background-color-secondary, #222);color:var(--phoenix-text-color, #fff)}.dialog .dialog-content{overflow-y:auto;max-height:calc(80vh - 120px)}.dialog .dialog-content span{display:flex;align-items:center}\n"] }]
637
+ }], () => [{ type: i1$1.MatDialogRef }], null); })();
638
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ShortcutsDialogComponent, { className: "ShortcutsDialogComponent", filePath: "components/phoenix-menu/shortcuts-dialog/shortcuts-dialog.component.ts", lineNumber: 10 }); })();
639
+
438
640
  class PhoenixMenuComponent {
641
+ dialog;
439
642
  rootNode;
440
- static ɵfac = function PhoenixMenuComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || PhoenixMenuComponent)(); };
441
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: PhoenixMenuComponent, selectors: [["app-phoenix-menu"]], inputs: { rootNode: "rootNode" }, standalone: false, decls: 2, vars: 1, consts: [["id", "phoenixMenu"], [3, "currentNode"]], template: function PhoenixMenuComponent_Template(rf, ctx) { if (rf & 1) {
442
- i0.ɵɵelementStart(0, "div", 0);
443
- i0.ɵɵelement(1, "app-phoenix-menu-item", 1);
643
+ constructor(dialog) {
644
+ this.dialog = dialog;
645
+ }
646
+ openShortcutsDialog() {
647
+ this.dialog.open(ShortcutsDialogComponent, {
648
+ panelClass: 'dialog',
649
+ });
650
+ }
651
+ static ɵfac = function PhoenixMenuComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || PhoenixMenuComponent)(i0.ɵɵdirectiveInject(i1$1.MatDialog)); };
652
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: PhoenixMenuComponent, selectors: [["app-phoenix-menu"]], inputs: { rootNode: "rootNode" }, standalone: false, decls: 9, vars: 1, consts: [[1, "phoenix-menu-drag-container"], ["id", "phoenixMenu"], [3, "currentNode"], [1, "shortcuts-button-wrapper", "mt-2"], [1, "shortcuts-btn", 3, "click"], [2, "font-size", "16px", "width", "16px", "height", "16px", "vertical-align", "middle"], [2, "vertical-align", "middle"]], template: function PhoenixMenuComponent_Template(rf, ctx) { if (rf & 1) {
653
+ i0.ɵɵelementStart(0, "div", 0)(1, "div", 1);
654
+ i0.ɵɵelement(2, "app-phoenix-menu-item", 2);
655
+ i0.ɵɵelementEnd()();
656
+ i0.ɵɵelementStart(3, "div", 3)(4, "button", 4);
657
+ i0.ɵɵlistener("click", function PhoenixMenuComponent_Template_button_click_4_listener() { return ctx.openShortcutsDialog(); });
658
+ i0.ɵɵelementStart(5, "mat-icon", 5);
659
+ i0.ɵɵtext(6, "keyboard");
444
660
  i0.ɵɵelementEnd();
661
+ i0.ɵɵelementStart(7, "span", 6);
662
+ i0.ɵɵtext(8, "Shortcuts");
663
+ i0.ɵɵelementEnd()()();
445
664
  } if (rf & 2) {
446
- i0.ɵɵadvance();
665
+ i0.ɵɵadvance(2);
447
666
  i0.ɵɵproperty("currentNode", ctx.rootNode);
448
- } }, dependencies: [PhoenixMenuItemComponent], styles: ["[_nghost-%COMP%]{width:15rem;max-width:45%;position:absolute;top:5rem;right:1rem}#phoenixMenu[_ngcontent-%COMP%]{background:var(--phoenix-background-color-secondary);max-height:75vh;overflow-y:auto;box-shadow:var(--phoenix-box-shadow);z-index:100}@media screen and (max-width: 768px){#phoenixMenu[_ngcontent-%COMP%]{top:4rem}}"] });
667
+ } }, dependencies: [i2$2.MatIcon, PhoenixMenuItemComponent], styles: ["[_nghost-%COMP%]{width:15rem;max-width:45%;position:absolute;top:5rem;right:1rem}#phoenixMenu[_ngcontent-%COMP%]{background:var(--phoenix-background-color-secondary);max-height:75vh;overflow-y:auto;box-shadow:var(--phoenix-box-shadow);z-index:100}@media screen and (max-width:768px){#phoenixMenu[_ngcontent-%COMP%]{top:4rem}}.shortcuts-button-wrapper[_ngcontent-%COMP%]{text-align:right;pointer-events:auto}.shortcuts-btn[_ngcontent-%COMP%]{background-color:var(--phoenix-background-color-secondary);color:var(--phoenix-text-color);border:none;padding:5px 10px;border-radius:3px;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;box-shadow:var(--phoenix-box-shadow);transition:background-color .2s ease;font-family:inherit;font-size:.8rem}.shortcuts-btn[_ngcontent-%COMP%]:hover{background-color:var(--phoenix-menu-item-hover-color, #444)}"] });
449
668
  }
450
669
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(PhoenixMenuComponent, [{
451
670
  type: Component,
452
- args: [{ standalone: false, selector: 'app-phoenix-menu', template: "<div id=\"phoenixMenu\">\n <app-phoenix-menu-item [currentNode]=\"rootNode\"></app-phoenix-menu-item>\n</div>\n", styles: [":host{width:15rem;max-width:45%;position:absolute;top:5rem;right:1rem}#phoenixMenu{background:var(--phoenix-background-color-secondary);max-height:75vh;overflow-y:auto;box-shadow:var(--phoenix-box-shadow);z-index:100}@media screen and (max-width: 768px){#phoenixMenu{top:4rem}}\n"] }]
453
- }], null, { rootNode: [{
671
+ args: [{ standalone: false, selector: 'app-phoenix-menu', template: "<div class=\"phoenix-menu-drag-container\">\n <div id=\"phoenixMenu\">\n <app-phoenix-menu-item [currentNode]=\"rootNode\"></app-phoenix-menu-item>\n </div>\n</div>\n<div class=\"shortcuts-button-wrapper mt-2\">\n <button class=\"shortcuts-btn\" (click)=\"openShortcutsDialog()\">\n <mat-icon\n style=\"font-size: 16px; width: 16px; height: 16px; vertical-align: middle\"\n >keyboard</mat-icon\n >\n <span style=\"vertical-align: middle\">Shortcuts</span>\n </button>\n</div>\n", styles: [":host{width:15rem;max-width:45%;position:absolute;top:5rem;right:1rem}#phoenixMenu{background:var(--phoenix-background-color-secondary);max-height:75vh;overflow-y:auto;box-shadow:var(--phoenix-box-shadow);z-index:100}@media screen and (max-width:768px){#phoenixMenu{top:4rem}}.shortcuts-button-wrapper{text-align:right;pointer-events:auto}.shortcuts-btn{background-color:var(--phoenix-background-color-secondary);color:var(--phoenix-text-color);border:none;padding:5px 10px;border-radius:3px;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;box-shadow:var(--phoenix-box-shadow);transition:background-color .2s ease;font-family:inherit;font-size:.8rem}.shortcuts-btn:hover{background-color:var(--phoenix-menu-item-hover-color, #444)}\n"] }]
672
+ }], () => [{ type: i1$1.MatDialog }], { rootNode: [{
454
673
  type: Input
455
674
  }] }); })();
456
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(PhoenixMenuComponent, { className: "PhoenixMenuComponent", filePath: "components/phoenix-menu/phoenix-menu.component.ts", lineNumber: 10 }); })();
675
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(PhoenixMenuComponent, { className: "PhoenixMenuComponent", filePath: "components/phoenix-menu/phoenix-menu.component.ts", lineNumber: 12 }); })();
676
+
677
+ /**
678
+ * Service for displaying user-facing notifications with severity levels.
679
+ * Provides success, info, warning, and error notifications with
680
+ * configurable auto-dismiss durations. Replaces silent console errors
681
+ * with actionable user feedback across all Phoenix components.
682
+ */
683
+ class NotificationService {
684
+ /** Default auto-dismiss durations in milliseconds per severity level. */
685
+ defaultDurations = {
686
+ success: 5000,
687
+ info: 5000,
688
+ warning: 8000,
689
+ error: 0,
690
+ };
691
+ /** Active variable that stores the latest notification. */
692
+ notification = new ActiveVariable();
693
+ /**
694
+ * Subscribe to incoming notifications.
695
+ * @param callback Function called when a notification is emitted.
696
+ * @returns A function that can be called to unsubscribe.
697
+ */
698
+ subscribeToNotifications(callback) {
699
+ return this.notification.onUpdate(callback);
700
+ }
701
+ /**
702
+ * Display a success notification.
703
+ * Auto-dismisses after 5 seconds by default.
704
+ * @param message The message to display.
705
+ * @param duration Optional custom duration in ms. 0 means no auto-dismiss.
706
+ */
707
+ success(message, duration) {
708
+ this.notify(message, 'success', duration);
709
+ }
710
+ /**
711
+ * Display an info notification.
712
+ * Auto-dismisses after 5 seconds by default.
713
+ * @param message The message to display.
714
+ * @param duration Optional custom duration in ms. 0 means no auto-dismiss.
715
+ */
716
+ info(message, duration) {
717
+ this.notify(message, 'info', duration);
718
+ }
719
+ /**
720
+ * Display a warning notification.
721
+ * Auto-dismisses after 8 seconds by default.
722
+ * @param message The message to display.
723
+ * @param duration Optional custom duration in ms. 0 means no auto-dismiss.
724
+ */
725
+ warning(message, duration) {
726
+ this.notify(message, 'warning', duration);
727
+ }
728
+ /**
729
+ * Display an error notification.
730
+ * Does not auto-dismiss by default — requires manual dismissal.
731
+ * @param message The message to display.
732
+ * @param duration Optional custom duration in ms. 0 means no auto-dismiss.
733
+ */
734
+ error(message, duration) {
735
+ this.notify(message, 'error', duration);
736
+ }
737
+ /**
738
+ * Internal method to emit a notification.
739
+ * @param message The message to display.
740
+ * @param severity The severity level.
741
+ * @param duration Optional custom duration override.
742
+ */
743
+ notify(message, severity, duration) {
744
+ this.notification.update({
745
+ message,
746
+ severity,
747
+ duration: duration ?? this.defaultDurations[severity],
748
+ });
749
+ }
750
+ static ɵfac = function NotificationService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || NotificationService)(); };
751
+ static ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: NotificationService, factory: NotificationService.ɵfac, providedIn: 'root' });
752
+ }
753
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(NotificationService, [{
754
+ type: Injectable,
755
+ args: [{
756
+ providedIn: 'root',
757
+ }]
758
+ }], null, null); })();
759
+
760
+ /**
761
+ * Component that subscribes to NotificationService and displays
762
+ * transient toast notifications via MatSnackBar.
763
+ *
764
+ * Severity levels map to CSS panel classes:
765
+ * - success → notification-success
766
+ * - info → notification-info
767
+ * - warning → notification-warning
768
+ * - error → notification-error
769
+ */
770
+ class NotificationToastComponent {
771
+ notificationService;
772
+ snackBar;
773
+ unsubscribe;
774
+ constructor(notificationService, snackBar) {
775
+ this.notificationService = notificationService;
776
+ this.snackBar = snackBar;
777
+ }
778
+ ngOnInit() {
779
+ this.unsubscribe = this.notificationService.subscribeToNotifications((notification) => {
780
+ this.snackBar.open(notification.message, 'Close', {
781
+ duration: notification.duration,
782
+ panelClass: [`notification-${notification.severity}`],
783
+ horizontalPosition: 'right',
784
+ verticalPosition: 'bottom',
785
+ });
786
+ });
787
+ }
788
+ ngOnDestroy() {
789
+ this.unsubscribe?.();
790
+ }
791
+ static ɵfac = function NotificationToastComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || NotificationToastComponent)(i0.ɵɵdirectiveInject(NotificationService), i0.ɵɵdirectiveInject(i2$3.MatSnackBar)); };
792
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: NotificationToastComponent, selectors: [["app-notification-toast"]], standalone: false, decls: 0, vars: 0, template: function NotificationToastComponent_Template(rf, ctx) { }, encapsulation: 2 });
793
+ }
794
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(NotificationToastComponent, [{
795
+ type: Component,
796
+ args: [{ standalone: false, selector: 'app-notification-toast', template: "<!-- NotificationToastComponent renders no visible DOM.\n It subscribes to NotificationService and delegates\n display to MatSnackBar. -->\n" }]
797
+ }], () => [{ type: NotificationService }, { type: i2$3.MatSnackBar }], null); })();
798
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(NotificationToastComponent, { className: "NotificationToastComponent", filePath: "components/ui-menu/notification-toast/notification-toast.component.ts", lineNumber: 21 }); })();
799
+
800
+ class DownloadAnimationDialogComponent {
801
+ data;
802
+ progress = 0;
803
+ constructor(data) {
804
+ this.data = data;
805
+ }
806
+ ngOnInit() {
807
+ this.data.progress$.subscribe((val) => {
808
+ this.progress = val;
809
+ });
810
+ }
811
+ static ɵfac = function DownloadAnimationDialogComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || DownloadAnimationDialogComponent)(i0.ɵɵdirectiveInject(MAT_DIALOG_DATA)); };
812
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: DownloadAnimationDialogComponent, selectors: [["app-download-animation-dialog"]], standalone: false, decls: 12, vars: 5, consts: [[1, "loader-wrapper", "d-flex", "flex-column", "justify-content-center", "align-items-center", "w-100", "h-100", "p-5", "text-center"], ["src", "assets/images/logo-small.svg", "alt", "Loader"], [1, "mt-5", "text-light"], [1, "text-muted"], [1, "loading-bar-container"], ["mode", "determinate", 3, "value"], [1, "progress-text", "text-light", "mt-2"]], template: function DownloadAnimationDialogComponent_Template(rf, ctx) { if (rf & 1) {
813
+ i0.ɵɵelementStart(0, "div", 0);
814
+ i0.ɵɵelement(1, "img", 1);
815
+ i0.ɵɵelementStart(2, "p", 2);
816
+ i0.ɵɵtext(3, " Generating Video...");
817
+ i0.ɵɵelement(4, "br");
818
+ i0.ɵɵelementStart(5, "small", 3);
819
+ i0.ɵɵtext(6, "(This may take a while)");
820
+ i0.ɵɵelementEnd()();
821
+ i0.ɵɵelementStart(7, "div", 4);
822
+ i0.ɵɵelement(8, "mat-progress-bar", 5);
823
+ i0.ɵɵelementStart(9, "div", 6);
824
+ i0.ɵɵtext(10);
825
+ i0.ɵɵpipe(11, "number");
826
+ i0.ɵɵelementEnd()()();
827
+ } if (rf & 2) {
828
+ i0.ɵɵadvance(8);
829
+ i0.ɵɵproperty("value", ctx.progress);
830
+ i0.ɵɵadvance(2);
831
+ i0.ɵɵtextInterpolate1(" ", i0.ɵɵpipeBind2(11, 2, ctx.progress, "1.0-0"), "% ");
832
+ } }, dependencies: [i1$2.MatProgressBar, i2.DecimalPipe], styles: [".loader-wrapper[_ngcontent-%COMP%]{background-color:#212529f2;border-radius:8px}.loader-wrapper[_ngcontent-%COMP%] img[_ngcontent-%COMP%]{width:100px;height:auto;animation:_ngcontent-%COMP%_pulse 2s infinite}.loader-wrapper[_ngcontent-%COMP%] .loading-bar-container[_ngcontent-%COMP%]{width:80%;margin-top:1rem}.loader-wrapper[_ngcontent-%COMP%] .loading-bar-container[_ngcontent-%COMP%] mat-progress-bar[_ngcontent-%COMP%]{height:10px;border-radius:5px}.loader-wrapper[_ngcontent-%COMP%] p[_ngcontent-%COMP%]{font-size:1.1rem;margin-bottom:0}@keyframes _ngcontent-%COMP%_pulse{0%{transform:scale(1);opacity:1}50%{transform:scale(1.1);opacity:.8}to{transform:scale(1);opacity:1}}"] });
833
+ }
834
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(DownloadAnimationDialogComponent, [{
835
+ type: Component,
836
+ args: [{ standalone: false, selector: 'app-download-animation-dialog', template: "<div\n class=\"loader-wrapper d-flex flex-column justify-content-center align-items-center w-100 h-100 p-5 text-center\"\n>\n <img src=\"assets/images/logo-small.svg\" alt=\"Loader\" />\n <p class=\"mt-5 text-light\">\n Generating Video...<br />\n <small class=\"text-muted\">(This may take a while)</small>\n </p>\n <div class=\"loading-bar-container\">\n <mat-progress-bar mode=\"determinate\" [value]=\"progress\"></mat-progress-bar>\n <div class=\"progress-text text-light mt-2\">\n {{ progress | number: '1.0-0' }}%\n </div>\n </div>\n</div>\n", styles: [".loader-wrapper{background-color:#212529f2;border-radius:8px}.loader-wrapper img{width:100px;height:auto;animation:pulse 2s infinite}.loader-wrapper .loading-bar-container{width:80%;margin-top:1rem}.loader-wrapper .loading-bar-container mat-progress-bar{height:10px;border-radius:5px}.loader-wrapper p{font-size:1.1rem;margin-bottom:0}@keyframes pulse{0%{transform:scale(1);opacity:1}50%{transform:scale(1.1);opacity:.8}to{transform:scale(1);opacity:1}}\n"] }]
837
+ }], () => [{ type: undefined, decorators: [{
838
+ type: Inject,
839
+ args: [MAT_DIALOG_DATA]
840
+ }] }], null); })();
841
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(DownloadAnimationDialogComponent, { className: "DownloadAnimationDialogComponent", filePath: "components/ui-menu/animate-camera/download-animation-dialog/download-animation-dialog.component.ts", lineNumber: 11 }); })();
457
842
 
458
843
  /**
459
844
  * Service for all event display related functions.
@@ -538,16 +923,27 @@ class MenuToggleComponent {
538
923
  }] }); })();
539
924
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MenuToggleComponent, { className: "MenuToggleComponent", filePath: "components/ui-menu/menu-toggle/menu-toggle.component.ts", lineNumber: 9 }); })();
540
925
 
541
- function AnimateCameraComponent_button_2_Template(rf, ctx) { if (rf & 1) {
926
+ function AnimateCameraComponent_div_2_Template(rf, ctx) { if (rf & 1) {
542
927
  const _r2 = i0.ɵɵgetCurrentView();
543
- i0.ɵɵelementStart(0, "button", 2);
544
- i0.ɵɵlistener("click", function AnimateCameraComponent_button_2_Template_button_click_0_listener() { const preset_r3 = i0.ɵɵrestoreView(_r2).$implicit; const ctx_r3 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r3.animatePreset(preset_r3)); });
545
- i0.ɵɵtext(1);
928
+ i0.ɵɵelementStart(0, "div", 3);
929
+ i0.ɵɵlistener("click", function AnimateCameraComponent_div_2_Template_div_click_0_listener($event) { i0.ɵɵrestoreView(_r2); return i0.ɵɵresetView($event.stopPropagation()); });
930
+ i0.ɵɵelementStart(1, "span", 4);
931
+ i0.ɵɵtext(2);
546
932
  i0.ɵɵelementEnd();
933
+ i0.ɵɵelementStart(3, "span", 5)(4, "button", 6);
934
+ i0.ɵɵlistener("click", function AnimateCameraComponent_div_2_Template_button_click_4_listener() { const preset_r3 = i0.ɵɵrestoreView(_r2).$implicit; const ctx_r3 = i0.ɵɵnextContext(); const menuTrigger_r5 = i0.ɵɵreference(14); ctx_r3.playPreset(preset_r3); return i0.ɵɵresetView(menuTrigger_r5.closeMenu()); });
935
+ i0.ɵɵelementStart(5, "mat-icon");
936
+ i0.ɵɵtext(6, "play_arrow");
937
+ i0.ɵɵelementEnd()();
938
+ i0.ɵɵelementStart(7, "button", 7);
939
+ i0.ɵɵlistener("click", function AnimateCameraComponent_div_2_Template_button_click_7_listener() { const preset_r3 = i0.ɵɵrestoreView(_r2).$implicit; const ctx_r3 = i0.ɵɵnextContext(); const menuTrigger_r5 = i0.ɵɵreference(14); ctx_r3.downloadAnimation(preset_r3); return i0.ɵɵresetView(menuTrigger_r5.closeMenu()); });
940
+ i0.ɵɵelementStart(8, "mat-icon");
941
+ i0.ɵɵtext(9, "download");
942
+ i0.ɵɵelementEnd()()()();
547
943
  } if (rf & 2) {
548
944
  const preset_r3 = ctx.$implicit;
549
- i0.ɵɵadvance();
550
- i0.ɵɵtextInterpolate1(" ", preset_r3, " ");
945
+ i0.ɵɵadvance(2);
946
+ i0.ɵɵtextInterpolate(preset_r3);
551
947
  } }
552
948
  const defaultAnimationPresets = {
553
949
  'Cavern to ID': {
@@ -596,27 +992,78 @@ const defaultAnimationPresets = {
596
992
  };
597
993
  class AnimateCameraComponent {
598
994
  eventDisplay;
995
+ dialog;
599
996
  animationPresets = defaultAnimationPresets;
600
997
  animationPresetsKeys = Object.keys(this.animationPresets);
601
998
  isAnimating = false;
602
- constructor(eventDisplay) {
999
+ constructor(eventDisplay, dialog) {
603
1000
  this.eventDisplay = eventDisplay;
604
- // this.animationPresets = this.eventDisplay
605
- // .getUIManager()
606
- // .getPresetAnimations();
607
- // This is too late to fill the UI! FIXME. EJWM
1001
+ this.dialog = dialog;
1002
+ }
1003
+ playPreset(preset) {
1004
+ this.animatePreset(preset);
1005
+ }
1006
+ playAnimateCamera() {
1007
+ this.animateCamera();
1008
+ }
1009
+ downloadAnimation(preset) {
1010
+ let totalDuration = 3000;
1011
+ if (preset && this.animationPresets[preset]) {
1012
+ totalDuration = this.animationPresets[preset].positions.reduce((acc, pos) => acc + pos.duration, 0);
1013
+ }
1014
+ const progress$ = new BehaviorSubject(0);
1015
+ const dialogRef = this.dialog.open(DownloadAnimationDialogComponent, {
1016
+ data: { progress$ },
1017
+ disableClose: true,
1018
+ panelClass: 'dialog-no-padding',
1019
+ });
1020
+ const startTime = Date.now();
1021
+ const interval = setInterval(() => {
1022
+ const elapsed = Date.now() - startTime;
1023
+ const progress = Math.min(100, Math.round((elapsed / totalDuration) * 100));
1024
+ progress$.next(progress);
1025
+ }, 100);
1026
+ const rendererManager = this.eventDisplay
1027
+ .getThreeManager()
1028
+ .getRendererManager();
1029
+ const canvas = rendererManager.getMainRenderer().domElement;
1030
+ const stream = canvas.captureStream(60);
1031
+ const recorder = new RecordRTC(stream, {
1032
+ type: 'video',
1033
+ mimeType: 'video/webm',
1034
+ });
1035
+ recorder.startRecording();
1036
+ const onEnd = () => {
1037
+ clearInterval(interval);
1038
+ progress$.next(100);
1039
+ recorder.stopRecording(() => {
1040
+ const blob = recorder.getBlob();
1041
+ RecordRTC.invokeSaveAsDialog(blob, `${preset || 'animation'}.webm`);
1042
+ dialogRef.close();
1043
+ });
1044
+ };
1045
+ if (preset) {
1046
+ this.animatePreset(preset, onEnd);
1047
+ }
1048
+ else {
1049
+ this.animateCamera(onEnd);
1050
+ }
608
1051
  }
609
- animatePreset(preset) {
1052
+ animatePreset(preset, onEnd) {
610
1053
  this.setDetectorOpacity(0.2);
611
1054
  this.eventDisplay.animatePreset(this.animationPresets[preset], () => {
612
1055
  this.setDetectorOpacity(1);
1056
+ if (onEnd)
1057
+ onEnd();
613
1058
  });
614
1059
  }
615
- animateCamera() {
1060
+ animateCamera(onEnd) {
616
1061
  if (!this.isAnimating) {
617
1062
  this.isAnimating = true;
618
1063
  this.eventDisplay.animateThroughEvent([11976, 7262, 11927], 3000, () => {
619
1064
  this.isAnimating = false;
1065
+ if (onEnd)
1066
+ onEnd();
620
1067
  });
621
1068
  }
622
1069
  }
@@ -625,31 +1072,42 @@ class AnimateCameraComponent {
625
1072
  const geometriesGroup = sceneManager.getObjectByName(SceneManager.GEOMETRIES_ID);
626
1073
  sceneManager.setGeometryOpacity(geometriesGroup, opacity);
627
1074
  }
628
- static ɵfac = function AnimateCameraComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || AnimateCameraComponent)(i0.ɵɵdirectiveInject(EventDisplayService)); };
629
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: AnimateCameraComponent, selectors: [["app-animate-camera"]], inputs: { animationPresets: "animationPresets" }, standalone: false, decls: 6, vars: 2, consts: [["animationPresets", ""], ["mat-menu-item", "", 3, "click", 4, "ngFor", "ngForOf"], ["mat-menu-item", "", 3, "click"], ["tooltip", "Preset animations", "icon", "animate-camera", 3, "matMenuTriggerFor"]], template: function AnimateCameraComponent_Template(rf, ctx) { if (rf & 1) {
1075
+ static ɵfac = function AnimateCameraComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || AnimateCameraComponent)(i0.ɵɵdirectiveInject(EventDisplayService), i0.ɵɵdirectiveInject(i1$1.MatDialog)); };
1076
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: AnimateCameraComponent, selectors: [["app-animate-camera"]], inputs: { animationPresets: "animationPresets" }, standalone: false, decls: 15, vars: 2, consts: [["animationPresets", ""], ["menuTrigger", "matMenuTrigger"], ["mat-menu-item", "", "class", "preset-row", 3, "click", 4, "ngFor", "ngForOf"], ["mat-menu-item", "", 1, "preset-row", 3, "click"], [1, "preset-name"], [1, "preset-actions"], ["mat-icon-button", "", "matTooltip", "Play", 3, "click"], ["mat-icon-button", "", "matTooltip", "Download", 3, "click"], ["tooltip", "Preset animations", "icon", "animate-camera", 3, "matMenuTriggerFor"]], template: function AnimateCameraComponent_Template(rf, ctx) { if (rf & 1) {
630
1077
  const _r1 = i0.ɵɵgetCurrentView();
631
1078
  i0.ɵɵelementStart(0, "mat-menu", null, 0);
632
- i0.ɵɵtemplate(2, AnimateCameraComponent_button_2_Template, 2, 1, "button", 1);
633
- i0.ɵɵelementStart(3, "button", 2);
634
- i0.ɵɵlistener("click", function AnimateCameraComponent_Template_button_click_3_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.animateCamera()); });
635
- i0.ɵɵtext(4, "Animate camera");
1079
+ i0.ɵɵtemplate(2, AnimateCameraComponent_div_2_Template, 10, 1, "div", 2);
1080
+ i0.ɵɵelementStart(3, "div", 3);
1081
+ i0.ɵɵlistener("click", function AnimateCameraComponent_Template_div_click_3_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView($event.stopPropagation()); });
1082
+ i0.ɵɵelementStart(4, "span", 4);
1083
+ i0.ɵɵtext(5, "Animate camera");
1084
+ i0.ɵɵelementEnd();
1085
+ i0.ɵɵelementStart(6, "span", 5)(7, "button", 6);
1086
+ i0.ɵɵlistener("click", function AnimateCameraComponent_Template_button_click_7_listener() { i0.ɵɵrestoreView(_r1); const menuTrigger_r5 = i0.ɵɵreference(14); ctx.playAnimateCamera(); return i0.ɵɵresetView(menuTrigger_r5.closeMenu()); });
1087
+ i0.ɵɵelementStart(8, "mat-icon");
1088
+ i0.ɵɵtext(9, "play_arrow");
636
1089
  i0.ɵɵelementEnd()();
637
- i0.ɵɵelement(5, "app-menu-toggle", 3);
1090
+ i0.ɵɵelementStart(10, "button", 7);
1091
+ i0.ɵɵlistener("click", function AnimateCameraComponent_Template_button_click_10_listener() { i0.ɵɵrestoreView(_r1); const menuTrigger_r5 = i0.ɵɵreference(14); ctx.downloadAnimation(); return i0.ɵɵresetView(menuTrigger_r5.closeMenu()); });
1092
+ i0.ɵɵelementStart(11, "mat-icon");
1093
+ i0.ɵɵtext(12, "download");
1094
+ i0.ɵɵelementEnd()()()()();
1095
+ i0.ɵɵelement(13, "app-menu-toggle", 8, 1);
638
1096
  } if (rf & 2) {
639
- const animationPresets_r5 = i0.ɵɵreference(1);
1097
+ const animationPresets_r6 = i0.ɵɵreference(1);
640
1098
  i0.ɵɵadvance(2);
641
1099
  i0.ɵɵproperty("ngForOf", ctx.animationPresetsKeys);
642
- i0.ɵɵadvance(3);
643
- i0.ɵɵproperty("matMenuTriggerFor", animationPresets_r5);
644
- } }, dependencies: [i2.NgForOf, i3$2.MatMenu, i3$2.MatMenuItem, i3$2.MatMenuTrigger, MenuToggleComponent], encapsulation: 2 });
1100
+ i0.ɵɵadvance(11);
1101
+ i0.ɵɵproperty("matMenuTriggerFor", animationPresets_r6);
1102
+ } }, dependencies: [i2.NgForOf, i3.MatIconButton, i3$1.MatTooltip, i4$2.MatMenu, i4$2.MatMenuItem, i4$2.MatMenuTrigger, i2$2.MatIcon, MenuToggleComponent], styles: [".preset-row[_ngcontent-%COMP%]{display:flex;justify-content:space-between;align-items:center;width:100%;padding-right:8px;cursor:default}.preset-row[_ngcontent-%COMP%] .preset-name[_ngcontent-%COMP%]{flex:1;cursor:pointer}.preset-row[_ngcontent-%COMP%] .preset-actions[_ngcontent-%COMP%]{display:flex;gap:4px}.preset-row[_ngcontent-%COMP%] .preset-actions[_ngcontent-%COMP%] button[_ngcontent-%COMP%]{width:32px;height:32px;line-height:32px;padding:0}.preset-row[_ngcontent-%COMP%] .preset-actions[_ngcontent-%COMP%] button[_ngcontent-%COMP%] mat-icon[_ngcontent-%COMP%]{font-size:18px;width:18px;height:18px;line-height:18px}"] });
645
1103
  }
646
1104
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(AnimateCameraComponent, [{
647
1105
  type: Component,
648
- args: [{ standalone: false, selector: 'app-animate-camera', template: "<mat-menu #animationPresets>\n <button\n mat-menu-item\n *ngFor=\"let preset of animationPresetsKeys\"\n (click)=\"animatePreset(preset)\"\n >\n {{ preset }}\n </button>\n <button mat-menu-item (click)=\"animateCamera()\">Animate camera</button>\n</mat-menu>\n\n<app-menu-toggle\n [matMenuTriggerFor]=\"animationPresets\"\n tooltip=\"Preset animations\"\n icon=\"animate-camera\"\n>\n</app-menu-toggle>\n" }]
649
- }], () => [{ type: EventDisplayService }], { animationPresets: [{
1106
+ args: [{ standalone: false, selector: 'app-animate-camera', template: "<mat-menu #animationPresets>\n <div\n mat-menu-item\n *ngFor=\"let preset of animationPresetsKeys\"\n class=\"preset-row\"\n (click)=\"$event.stopPropagation()\"\n >\n <span class=\"preset-name\">{{ preset }}</span>\n <span class=\"preset-actions\">\n <button\n mat-icon-button\n (click)=\"playPreset(preset); menuTrigger.closeMenu()\"\n matTooltip=\"Play\"\n >\n <mat-icon>play_arrow</mat-icon>\n </button>\n <button\n mat-icon-button\n (click)=\"downloadAnimation(preset); menuTrigger.closeMenu()\"\n matTooltip=\"Download\"\n >\n <mat-icon>download</mat-icon>\n </button>\n </span>\n </div>\n <div mat-menu-item class=\"preset-row\" (click)=\"$event.stopPropagation()\">\n <span class=\"preset-name\">Animate camera</span>\n <span class=\"preset-actions\">\n <button\n mat-icon-button\n (click)=\"playAnimateCamera(); menuTrigger.closeMenu()\"\n matTooltip=\"Play\"\n >\n <mat-icon>play_arrow</mat-icon>\n </button>\n <button\n mat-icon-button\n (click)=\"downloadAnimation(); menuTrigger.closeMenu()\"\n matTooltip=\"Download\"\n >\n <mat-icon>download</mat-icon>\n </button>\n </span>\n </div>\n</mat-menu>\n\n<app-menu-toggle\n #menuTrigger=\"matMenuTrigger\"\n [matMenuTriggerFor]=\"animationPresets\"\n tooltip=\"Preset animations\"\n icon=\"animate-camera\"\n>\n</app-menu-toggle>\n", styles: [".preset-row{display:flex;justify-content:space-between;align-items:center;width:100%;padding-right:8px;cursor:default}.preset-row .preset-name{flex:1;cursor:pointer}.preset-row .preset-actions{display:flex;gap:4px}.preset-row .preset-actions button{width:32px;height:32px;line-height:32px;padding:0}.preset-row .preset-actions button mat-icon{font-size:18px;width:18px;height:18px;line-height:18px}\n"] }]
1107
+ }], () => [{ type: EventDisplayService }, { type: i1$1.MatDialog }], { animationPresets: [{
650
1108
  type: Input
651
1109
  }] }); })();
652
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AnimateCameraComponent, { className: "AnimateCameraComponent", filePath: "components/ui-menu/animate-camera/animate-camera.component.ts", lineNumber: 60 }); })();
1110
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(AnimateCameraComponent, { className: "AnimateCameraComponent", filePath: "components/ui-menu/animate-camera/animate-camera.component.ts", lineNumber: 64 }); })();
653
1111
 
654
1112
  class AnimateEventComponent {
655
1113
  eventDisplay;
@@ -719,59 +1177,70 @@ function OverlayComponent_div_2_div_1_Template(rf, ctx) { if (rf & 1) {
719
1177
  i0.ɵɵelement(2, "use");
720
1178
  i0.ɵɵelementEnd()();
721
1179
  } if (rf & 2) {
722
- const ctx_r1 = i0.ɵɵnextContext(2);
1180
+ const ctx_r2 = i0.ɵɵnextContext(2);
723
1181
  i0.ɵɵadvance(2);
724
- i0.ɵɵattribute("href", i0.ɵɵinterpolate2("assets/icons/", ctx_r1.icon, ".svg#", ctx_r1.icon));
1182
+ i0.ɵɵattribute("href", i0.ɵɵinterpolate2("assets/icons/", ctx_r2.icon, ".svg#", ctx_r2.icon));
725
1183
  } }
726
1184
  function OverlayComponent_div_2_Template(rf, ctx) { if (rf & 1) {
727
- const _r1 = i0.ɵɵgetCurrentView();
1185
+ const _r2 = i0.ɵɵgetCurrentView();
728
1186
  i0.ɵɵelementStart(0, "div", 6);
729
1187
  i0.ɵɵtemplate(1, OverlayComponent_div_2_div_1_Template, 3, 3, "div", 7);
730
1188
  i0.ɵɵelementStart(2, "h5", 8);
731
1189
  i0.ɵɵtext(3);
732
1190
  i0.ɵɵelementEnd();
733
1191
  i0.ɵɵelementStart(4, "button", 9);
734
- i0.ɵɵlistener("click", function OverlayComponent_div_2_Template_button_click_4_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.showBody = !ctx_r1.showBody); });
1192
+ i0.ɵɵlistener("click", function OverlayComponent_div_2_Template_button_click_4_listener() { i0.ɵɵrestoreView(_r2); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.toggleBodyAndEmit()); });
735
1193
  i0.ɵɵnamespaceSVG();
736
1194
  i0.ɵɵelementStart(5, "svg");
737
1195
  i0.ɵɵelement(6, "use", 10);
738
1196
  i0.ɵɵelementEnd()()();
739
1197
  } if (rf & 2) {
740
- const ctx_r1 = i0.ɵɵnextContext();
741
- i0.ɵɵproperty("ngClass", i0.ɵɵpureFunction1(4, _c4$1, ctx_r1.showBody));
1198
+ const ctx_r2 = i0.ɵɵnextContext();
1199
+ i0.ɵɵproperty("ngClass", i0.ɵɵpureFunction1(4, _c4$1, ctx_r2.showBody));
742
1200
  i0.ɵɵadvance();
743
- i0.ɵɵproperty("ngIf", ctx_r1.icon);
1201
+ i0.ɵɵproperty("ngIf", ctx_r2.icon);
744
1202
  i0.ɵɵadvance(2);
745
- i0.ɵɵtextInterpolate(ctx_r1.overlayTitle);
1203
+ i0.ɵɵtextInterpolate(ctx_r2.overlayTitle);
746
1204
  i0.ɵɵadvance();
747
- i0.ɵɵproperty("ngClass", i0.ɵɵpureFunction1(6, _c5$1, ctx_r1.showBody));
1205
+ i0.ɵɵproperty("ngClass", i0.ɵɵpureFunction1(6, _c5$1, ctx_r2.showBody));
748
1206
  } }
749
1207
  function OverlayComponent_div_3_Template(rf, ctx) { if (rf & 1) {
750
1208
  i0.ɵɵelementStart(0, "div", 12);
751
1209
  i0.ɵɵprojection(1);
752
1210
  i0.ɵɵelementEnd();
753
1211
  } if (rf & 2) {
754
- const ctx_r1 = i0.ɵɵnextContext();
755
- i0.ɵɵproperty("ngClass", i0.ɵɵpureFunction1(1, _c6, ctx_r1.transparentBody));
1212
+ const ctx_r2 = i0.ɵɵnextContext();
1213
+ i0.ɵɵproperty("ngClass", i0.ɵɵpureFunction1(1, _c6, ctx_r2.transparentBody));
756
1214
  } }
757
1215
  function OverlayComponent_span_4_Template(rf, ctx) { if (rf & 1) {
758
- const _r3 = i0.ɵɵgetCurrentView();
1216
+ const _r4 = i0.ɵɵgetCurrentView();
759
1217
  i0.ɵɵelementStart(0, "span", 13, 1);
760
- i0.ɵɵlistener("cdkDragMoved", function OverlayComponent_span_4_Template_span_cdkDragMoved_0_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.onResize()); });
1218
+ i0.ɵɵlistener("cdkDragMoved", function OverlayComponent_span_4_Template_span_cdkDragMoved_0_listener() { i0.ɵɵrestoreView(_r4); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.onResize()); });
761
1219
  i0.ɵɵelementEnd();
762
1220
  } if (rf & 2) {
763
- const ctx_r1 = i0.ɵɵnextContext();
764
- i0.ɵɵproperty("hidden", !ctx_r1.showBody);
1221
+ const ctx_r2 = i0.ɵɵnextContext();
1222
+ i0.ɵɵproperty("hidden", !ctx_r2.showBody);
765
1223
  } }
1224
+ let maxZIndex = 100;
766
1225
  /**
767
1226
  * Component for overlay panel.
768
1227
  */
769
1228
  class OverlayComponent {
770
1229
  eventDisplay;
1230
+ elementRef;
771
1231
  /** Title of the overlay. */
772
1232
  overlayTitle;
773
1233
  /** If the overlay is open or not. */
774
- active = false;
1234
+ _active = false;
1235
+ set active(value) {
1236
+ this._active = value;
1237
+ if (value) {
1238
+ setTimeout(() => this.bringToFront(), 0);
1239
+ }
1240
+ }
1241
+ get active() {
1242
+ return this._active;
1243
+ }
775
1244
  /** Icon of the overlay header. */
776
1245
  icon;
777
1246
  /** If the overlay is resizable. */
@@ -799,13 +1268,31 @@ class OverlayComponent {
799
1268
  MIN_RES_WIDTH = 300;
800
1269
  /** Minimum resizable height */
801
1270
  MIN_RES_HEIGHT = 100;
802
- constructor(eventDisplay) {
1271
+ constructor(eventDisplay, elementRef) {
803
1272
  this.eventDisplay = eventDisplay;
1273
+ this.elementRef = elementRef;
1274
+ }
1275
+ ngOnInit() { }
1276
+ toggleBodyAndEmit() {
1277
+ this.showBody = !this.showBody;
1278
+ }
1279
+ /** Bring the overlay to the front. */
1280
+ bringToFront() {
1281
+ maxZIndex++;
1282
+ const wrapper = this.elementRef.nativeElement.closest('.cdk-global-overlay-wrapper');
1283
+ if (wrapper) {
1284
+ wrapper.style.zIndex = maxZIndex.toString();
1285
+ }
1286
+ const pane = this.elementRef.nativeElement.closest('.cdk-overlay-pane');
1287
+ if (pane) {
1288
+ pane.style.zIndex = maxZIndex.toString();
1289
+ }
804
1290
  }
805
1291
  /**
806
1292
  * Move the resizable handle to the bottom right after the component is created.
807
1293
  */
808
1294
  ngAfterViewInit() {
1295
+ this.bringToFront();
809
1296
  if (this.resizable) {
810
1297
  const resizeHandleElement = this.resizeHandleCorner.nativeElement;
811
1298
  resizeHandleElement.style.bottom = '0';
@@ -837,15 +1324,35 @@ class OverlayComponent {
837
1324
  if (this.keepAspectRatioFixed) {
838
1325
  height = width / this.aspectRatio;
839
1326
  }
840
- const oldratioW = width / this.overlayWindow.nativeElement.width;
841
- const oldratioH = height / this.overlayWindow.nativeElement.height;
842
- this.eventDisplay
843
- .getThreeManager()
844
- .getOverlayRenderer()
845
- .setSize(width, height);
846
- this.eventDisplay
847
- .getThreeManager()
848
- .syncOverlayViewPort(oldratioW, oldratioH);
1327
+ if (this.overlayWindow?.nativeElement) {
1328
+ const oldratioW = width / this.overlayWindow.nativeElement.width;
1329
+ const oldratioH = height / this.overlayWindow.nativeElement.height;
1330
+ this.eventDisplay
1331
+ .getThreeManager()
1332
+ .getOverlayRenderer()
1333
+ .setSize(width, height);
1334
+ this.eventDisplay
1335
+ .getThreeManager()
1336
+ .syncOverlayViewPort(oldratioW, oldratioH);
1337
+ }
1338
+ else {
1339
+ // Fallback for generic content that does not have a 3D canvas
1340
+ this.overlayCard.nativeElement.style.width = width + 'px';
1341
+ this.overlayCard.nativeElement.style.height = height + 'px';
1342
+ const contentWrapper = this.overlayCard.nativeElement.querySelector('.overlay-card-content');
1343
+ if (contentWrapper) {
1344
+ contentWrapper.style.flex = '1';
1345
+ contentWrapper.style.overflow = 'hidden';
1346
+ contentWrapper.style.maxHeight = 'none';
1347
+ const contentBody = contentWrapper.firstElementChild;
1348
+ if (contentBody) {
1349
+ contentBody.style.width = '100%';
1350
+ contentBody.style.height = '100%';
1351
+ contentBody.style.maxWidth = 'none';
1352
+ contentBody.style.maxHeight = 'none';
1353
+ }
1354
+ }
1355
+ }
849
1356
  }
850
1357
  }
851
1358
  /**
@@ -867,7 +1374,7 @@ class OverlayComponent {
867
1374
  const translateY = overlayRect.height - dragRect.height;
868
1375
  this.resizeHandleCorner.nativeElement.style.transform = `translate3d(${translateX}px, ${translateY}px, 0)`;
869
1376
  }
870
- static ɵfac = function OverlayComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || OverlayComponent)(i0.ɵɵdirectiveInject(EventDisplayService)); };
1377
+ static ɵfac = function OverlayComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || OverlayComponent)(i0.ɵɵdirectiveInject(EventDisplayService), i0.ɵɵdirectiveInject(i0.ElementRef)); };
871
1378
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: OverlayComponent, selectors: [["app-overlay"]], contentQueries: function OverlayComponent_ContentQueries(rf, ctx, dirIndex) { if (rf & 1) {
872
1379
  i0.ɵɵcontentQuery(dirIndex, _c0$c, 5);
873
1380
  } if (rf & 2) {
@@ -880,9 +1387,11 @@ class OverlayComponent {
880
1387
  let _t;
881
1388
  i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.overlayCard = _t.first);
882
1389
  i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.resizeHandleCorner = _t.first);
883
- } }, inputs: { overlayTitle: "overlayTitle", active: "active", icon: "icon", resizable: "resizable", transparentBody: "transparentBody", keepAspectRatioFixed: "keepAspectRatioFixed" }, standalone: false, ngContentSelectors: _c3$1, decls: 5, vars: 4, consts: [["overlayCard", ""], ["resizeHandleCorner", ""], ["cdkDrag", "", "cdkDragBoundary", "body", 1, "overlay-card", "card", 3, "hidden"], ["class", "card-header d-flex justify-content-between", "cdkDragHandle", "", 3, "ngClass", 4, "ngIf"], ["class", "overlay-card-content", 3, "ngClass", 4, "ngIf"], ["class", "resize-handle corner", "cdkDrag", "", 3, "hidden", "cdkDragMoved", 4, "ngIf"], ["cdkDragHandle", "", 1, "card-header", "d-flex", "justify-content-between", 3, "ngClass"], ["class", "align-self-center card-icon", 4, "ngIf"], [1, "align-self-center", "m-0", "px-2"], ["matTooltip", "Expand / Collapse", "matTooltipPosition", "right", 1, "align-self-center", "card-icon", "btn-blank", "expandCollapse", 3, "click", "ngClass"], ["href", "assets/icons/expand.svg#expand"], [1, "align-self-center", "card-icon"], [1, "overlay-card-content", 3, "ngClass"], ["cdkDrag", "", 1, "resize-handle", "corner", 3, "cdkDragMoved", "hidden"]], template: function OverlayComponent_Template(rf, ctx) { if (rf & 1) {
1390
+ } }, inputs: { overlayTitle: "overlayTitle", active: "active", icon: "icon", resizable: "resizable", transparentBody: "transparentBody", keepAspectRatioFixed: "keepAspectRatioFixed" }, standalone: false, ngContentSelectors: _c3$1, decls: 5, vars: 4, consts: [["overlayCard", ""], ["resizeHandleCorner", ""], ["cdkDrag", "", "cdkDragRootElement", ".cdk-overlay-pane", "cdkDragBoundary", "body", 1, "overlay-card", "card", 3, "mousedown", "touchstart", "hidden"], ["class", "card-header d-flex justify-content-between", "cdkDragHandle", "", 3, "ngClass", 4, "ngIf"], ["class", "overlay-card-content", 3, "ngClass", 4, "ngIf"], ["class", "resize-handle corner", "cdkDrag", "", 3, "hidden", "cdkDragMoved", 4, "ngIf"], ["cdkDragHandle", "", 1, "card-header", "d-flex", "justify-content-between", 3, "ngClass"], ["class", "align-self-center card-icon", 4, "ngIf"], [1, "align-self-center", "m-0", "px-2"], ["matTooltip", "Expand / Collapse", "matTooltipPosition", "right", 1, "align-self-center", "card-icon", "btn-blank", "expandCollapse", 3, "click", "ngClass"], ["href", "assets/icons/expand.svg#expand"], [1, "align-self-center", "card-icon"], [1, "overlay-card-content", 3, "ngClass"], ["cdkDrag", "", 1, "resize-handle", "corner", 3, "cdkDragMoved", "hidden"]], template: function OverlayComponent_Template(rf, ctx) { if (rf & 1) {
1391
+ const _r1 = i0.ɵɵgetCurrentView();
884
1392
  i0.ɵɵprojectionDef();
885
1393
  i0.ɵɵelementStart(0, "div", 2, 0);
1394
+ i0.ɵɵlistener("mousedown", function OverlayComponent_Template_div_mousedown_0_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.bringToFront()); })("touchstart", function OverlayComponent_Template_div_touchstart_0_listener() { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.bringToFront()); });
886
1395
  i0.ɵɵtemplate(2, OverlayComponent_div_2_Template, 7, 8, "div", 3)(3, OverlayComponent_div_3_Template, 2, 3, "div", 4)(4, OverlayComponent_span_4_Template, 2, 1, "span", 5);
887
1396
  i0.ɵɵelementEnd();
888
1397
  } if (rf & 2) {
@@ -893,12 +1402,12 @@ class OverlayComponent {
893
1402
  i0.ɵɵproperty("ngIf", ctx.showBody);
894
1403
  i0.ɵɵadvance();
895
1404
  i0.ɵɵproperty("ngIf", ctx.resizable);
896
- } }, dependencies: [i2.NgClass, i2.NgIf, i3$3.CdkDrag, i3$3.CdkDragHandle, i3$1.MatTooltip], styles: [".overlay-card.card{color:var(--phoenix-text-color);background:none;max-width:100vw;font-size:12px;min-width:300px;height:100%;box-shadow:none;border:none;position:relative;z-index:200}.overlay-card.card .card-header{width:12rem;background:var(--phoenix-background-color-secondary);box-shadow:var(--phoenix-box-shadow);padding:.4rem .8rem;border-radius:10px;border:none;cursor:move;text-align:center;transition:all .2s}.overlay-card.card .card-header.with-body{border-bottom-left-radius:0;border-bottom-right-radius:0}.overlay-card.card .card-header .card-icon{display:flex;height:.7rem;width:.7rem}.overlay-card.card .card-header h5{font-size:.9rem}.overlay-card.card .card-header .expandCollapse{cursor:pointer;transition:all .2s}.overlay-card.card .card-header .expandCollapse.expand{transform:scaleY(-1)}.overlay-card.card .card-header .expandCollapse svg{width:100%;height:100%}.overlay-card.card .overlay-card-content{background:var(--phoenix-background-color-secondary);box-shadow:var(--phoenix-box-shadow);border-radius:0 10px 10px;overflow:auto;height:100%}.overlay-card.card .overlay-card-content.transparent-bg{background:none}.overlay-card.card .list-group{color:var(--phoenix-text-color-secondary);background:var(--phoenix-background-color-secondary);max-height:40vh;overflow:auto}.overlay-card.card .list-group .list-group-item{background-color:var(--phoenix-background-color-secondary);border-color:var(--phoenix-border)}.overlay-card.card .resize-handle{width:1rem;height:1rem;cursor:nwse-resize;position:absolute}.overlay-card.card .resize-handle.corner{border-right:.2rem solid var(--phoenix-text-color);border-bottom:.2rem solid var(--phoenix-text-color)}\n"], encapsulation: 2 });
1405
+ } }, dependencies: [i2.NgClass, i2.NgIf, i3$2.CdkDrag, i3$2.CdkDragHandle, i3$1.MatTooltip], styles: [".overlay-card.card{color:var(--phoenix-text-color);background:none;max-width:95vw;font-size:12px;min-width:300px;height:auto;display:flex;flex-direction:column;box-shadow:none;border:none;position:relative;z-index:200}.overlay-card.card .card-header{width:12rem;background:var(--phoenix-background-color-secondary);box-shadow:var(--phoenix-box-shadow);padding:.4rem .8rem;border-radius:10px;border:none;cursor:move;text-align:center;transition:all .2s}.overlay-card.card .card-header.with-body{border-bottom-left-radius:0;border-bottom-right-radius:0}.overlay-card.card .card-header .card-icon{display:flex;height:.7rem;width:.7rem}.overlay-card.card .card-header h5{font-size:.9rem}.overlay-card.card .card-header .expandCollapse{cursor:pointer;transition:all .2s}.overlay-card.card .card-header .expandCollapse.expand{transform:scaleY(-1)}.overlay-card.card .card-header .expandCollapse svg{width:100%;height:100%}.overlay-card.card .overlay-card-content{background:var(--phoenix-background-color-secondary);box-shadow:var(--phoenix-box-shadow);border-radius:0 10px 10px;overflow:auto;height:100%;max-height:40vh}.overlay-card.card .overlay-card-content.transparent-bg{background:none}.overlay-card.card .list-group{color:var(--phoenix-text-color-secondary);background:var(--phoenix-background-color-secondary);max-height:40vh;overflow:auto}.overlay-card.card .list-group .list-group-item{background-color:var(--phoenix-background-color-secondary);border-color:var(--phoenix-border)}.overlay-card.card .resize-handle{width:1rem;height:1rem;cursor:nwse-resize;position:absolute}.overlay-card.card .resize-handle.corner{border-right:.2rem solid var(--phoenix-text-color);border-bottom:.2rem solid var(--phoenix-text-color)}\n"], encapsulation: 2 });
897
1406
  }
898
1407
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(OverlayComponent, [{
899
1408
  type: Component,
900
- args: [{ standalone: false, selector: 'app-overlay', encapsulation: ViewEncapsulation.None, template: "<div\n #overlayCard\n class=\"overlay-card card\"\n [hidden]=\"!active\"\n cdkDrag\n cdkDragBoundary=\"body\"\n>\n <div\n class=\"card-header d-flex justify-content-between\"\n [ngClass]=\"{ 'with-body': showBody }\"\n cdkDragHandle\n *ngIf=\"overlayTitle\"\n >\n <div class=\"align-self-center card-icon\" *ngIf=\"icon\">\n <svg>\n <use attr.href=\"assets/icons/{{ icon }}.svg#{{ icon }}\"></use>\n </svg>\n </div>\n <h5 class=\"align-self-center m-0 px-2\">{{ overlayTitle }}</h5>\n <button\n class=\"align-self-center card-icon btn-blank expandCollapse\"\n matTooltip=\"Expand / Collapse\"\n matTooltipPosition=\"right\"\n [ngClass]=\"{ expand: showBody }\"\n (click)=\"showBody = !showBody\"\n >\n <svg>\n <use href=\"assets/icons/expand.svg#expand\"></use>\n </svg>\n </button>\n </div>\n <div\n class=\"overlay-card-content\"\n *ngIf=\"showBody\"\n [ngClass]=\"{ 'transparent-bg': transparentBody }\"\n >\n <ng-content></ng-content>\n </div>\n <!-- Making the overlay resizable -->\n <span\n #resizeHandleCorner\n class=\"resize-handle corner\"\n *ngIf=\"resizable\"\n [hidden]=\"!showBody\"\n cdkDrag\n (cdkDragMoved)=\"onResize()\"\n ></span>\n</div>\n", styles: [".overlay-card.card{color:var(--phoenix-text-color);background:none;max-width:100vw;font-size:12px;min-width:300px;height:100%;box-shadow:none;border:none;position:relative;z-index:200}.overlay-card.card .card-header{width:12rem;background:var(--phoenix-background-color-secondary);box-shadow:var(--phoenix-box-shadow);padding:.4rem .8rem;border-radius:10px;border:none;cursor:move;text-align:center;transition:all .2s}.overlay-card.card .card-header.with-body{border-bottom-left-radius:0;border-bottom-right-radius:0}.overlay-card.card .card-header .card-icon{display:flex;height:.7rem;width:.7rem}.overlay-card.card .card-header h5{font-size:.9rem}.overlay-card.card .card-header .expandCollapse{cursor:pointer;transition:all .2s}.overlay-card.card .card-header .expandCollapse.expand{transform:scaleY(-1)}.overlay-card.card .card-header .expandCollapse svg{width:100%;height:100%}.overlay-card.card .overlay-card-content{background:var(--phoenix-background-color-secondary);box-shadow:var(--phoenix-box-shadow);border-radius:0 10px 10px;overflow:auto;height:100%}.overlay-card.card .overlay-card-content.transparent-bg{background:none}.overlay-card.card .list-group{color:var(--phoenix-text-color-secondary);background:var(--phoenix-background-color-secondary);max-height:40vh;overflow:auto}.overlay-card.card .list-group .list-group-item{background-color:var(--phoenix-background-color-secondary);border-color:var(--phoenix-border)}.overlay-card.card .resize-handle{width:1rem;height:1rem;cursor:nwse-resize;position:absolute}.overlay-card.card .resize-handle.corner{border-right:.2rem solid var(--phoenix-text-color);border-bottom:.2rem solid var(--phoenix-text-color)}\n"] }]
901
- }], () => [{ type: EventDisplayService }], { overlayTitle: [{
1409
+ args: [{ standalone: false, selector: 'app-overlay', encapsulation: ViewEncapsulation.None, template: "<div\n #overlayCard\n class=\"overlay-card card\"\n [hidden]=\"!active\"\n (mousedown)=\"bringToFront()\"\n (touchstart)=\"bringToFront()\"\n cdkDrag\n cdkDragRootElement=\".cdk-overlay-pane\"\n cdkDragBoundary=\"body\"\n>\n <div\n class=\"card-header d-flex justify-content-between\"\n [ngClass]=\"{ 'with-body': showBody }\"\n cdkDragHandle\n *ngIf=\"overlayTitle\"\n >\n <div class=\"align-self-center card-icon\" *ngIf=\"icon\">\n <svg>\n <use attr.href=\"assets/icons/{{ icon }}.svg#{{ icon }}\"></use>\n </svg>\n </div>\n <h5 class=\"align-self-center m-0 px-2\">{{ overlayTitle }}</h5>\n <button\n class=\"align-self-center card-icon btn-blank expandCollapse\"\n matTooltip=\"Expand / Collapse\"\n matTooltipPosition=\"right\"\n [ngClass]=\"{ expand: showBody }\"\n (click)=\"toggleBodyAndEmit()\"\n >\n <svg>\n <use href=\"assets/icons/expand.svg#expand\"></use>\n </svg>\n </button>\n </div>\n <div\n class=\"overlay-card-content\"\n *ngIf=\"showBody\"\n [ngClass]=\"{ 'transparent-bg': transparentBody }\"\n >\n <ng-content></ng-content>\n </div>\n <!-- Making the overlay resizable -->\n <span\n #resizeHandleCorner\n class=\"resize-handle corner\"\n *ngIf=\"resizable\"\n [hidden]=\"!showBody\"\n cdkDrag\n (cdkDragMoved)=\"onResize()\"\n ></span>\n</div>\n", styles: [".overlay-card.card{color:var(--phoenix-text-color);background:none;max-width:95vw;font-size:12px;min-width:300px;height:auto;display:flex;flex-direction:column;box-shadow:none;border:none;position:relative;z-index:200}.overlay-card.card .card-header{width:12rem;background:var(--phoenix-background-color-secondary);box-shadow:var(--phoenix-box-shadow);padding:.4rem .8rem;border-radius:10px;border:none;cursor:move;text-align:center;transition:all .2s}.overlay-card.card .card-header.with-body{border-bottom-left-radius:0;border-bottom-right-radius:0}.overlay-card.card .card-header .card-icon{display:flex;height:.7rem;width:.7rem}.overlay-card.card .card-header h5{font-size:.9rem}.overlay-card.card .card-header .expandCollapse{cursor:pointer;transition:all .2s}.overlay-card.card .card-header .expandCollapse.expand{transform:scaleY(-1)}.overlay-card.card .card-header .expandCollapse svg{width:100%;height:100%}.overlay-card.card .overlay-card-content{background:var(--phoenix-background-color-secondary);box-shadow:var(--phoenix-box-shadow);border-radius:0 10px 10px;overflow:auto;height:100%;max-height:40vh}.overlay-card.card .overlay-card-content.transparent-bg{background:none}.overlay-card.card .list-group{color:var(--phoenix-text-color-secondary);background:var(--phoenix-background-color-secondary);max-height:40vh;overflow:auto}.overlay-card.card .list-group .list-group-item{background-color:var(--phoenix-background-color-secondary);border-color:var(--phoenix-border)}.overlay-card.card .resize-handle{width:1rem;height:1rem;cursor:nwse-resize;position:absolute}.overlay-card.card .resize-handle.corner{border-right:.2rem solid var(--phoenix-text-color);border-bottom:.2rem solid var(--phoenix-text-color)}\n"] }]
1410
+ }], () => [{ type: EventDisplayService }, { type: i0.ElementRef }], { overlayTitle: [{
902
1411
  type: Input
903
1412
  }], active: [{
904
1413
  type: Input
@@ -920,7 +1429,7 @@ class OverlayComponent {
920
1429
  type: ContentChild,
921
1430
  args: ['overlayWindow']
922
1431
  }] }); })();
923
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(OverlayComponent, { className: "OverlayComponent", filePath: "components/ui-menu/overlay/overlay.component.ts", lineNumber: 25 }); })();
1432
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(OverlayComponent, { className: "OverlayComponent", filePath: "components/ui-menu/overlay/overlay.component.ts", lineNumber: 28 }); })();
924
1433
 
925
1434
  const _c0$b = (a0, a1, a2) => ({ "active-object": a0, "is-cut": a1, "d-none": a2 });
926
1435
  function CollectionsInfoOverlayComponent_div_1_div_1_optgroup_10_option_1_Template(rf, ctx) { if (rf & 1) {
@@ -1024,7 +1533,7 @@ function CollectionsInfoOverlayComponent_div_1_table_3_tr_11_td_13_Template(rf,
1024
1533
  const ctx_r1 = i0.ɵɵnextContext(3);
1025
1534
  i0.ɵɵattribute("data-label", ctx_r1.getPrettySymbol(column_r13));
1026
1535
  i0.ɵɵadvance();
1027
- i0.ɵɵtextInterpolate1(" ", object_r10[column_r13], " ");
1536
+ i0.ɵɵtextInterpolate1(" ", ctx_r1.formatValue(object_r10[column_r13]), " ");
1028
1537
  } }
1029
1538
  function CollectionsInfoOverlayComponent_div_1_table_3_tr_11_Template(rf, ctx) { if (rf & 1) {
1030
1539
  const _r8 = i0.ɵɵgetCurrentView();
@@ -1114,6 +1623,7 @@ class CollectionsInfoOverlayComponent {
1114
1623
  'labelText',
1115
1624
  '_instanceId',
1116
1625
  '_position',
1626
+ 'index',
1117
1627
  ];
1118
1628
  hideInvisible;
1119
1629
  collections;
@@ -1128,13 +1638,17 @@ class CollectionsInfoOverlayComponent {
1128
1638
  this.eventDisplay = eventDisplay;
1129
1639
  }
1130
1640
  ngOnInit() {
1131
- this.unsubscribes.push(this.eventDisplay.listenToDisplayedEventChange(() => {
1641
+ const updateCollections = () => {
1132
1642
  const collectionsGrouped = this.eventDisplay.getCollections();
1133
- this.collections = Object.entries(collectionsGrouped).map(([type, collections]) => ({
1134
- type,
1135
- collections,
1136
- }));
1137
- }));
1643
+ if (collectionsGrouped) {
1644
+ this.collections = Object.entries(collectionsGrouped).map(([type, collections]) => ({
1645
+ type,
1646
+ collections,
1647
+ }));
1648
+ }
1649
+ };
1650
+ updateCollections();
1651
+ this.unsubscribes.push(this.eventDisplay.listenToDisplayedEventChange(() => updateCollections()));
1138
1652
  this.activeObject = this.eventDisplay.getActiveObjectId();
1139
1653
  this.unsubscribes.push(this.activeObject.onUpdate((value) => {
1140
1654
  if (document.getElementById(value)) {
@@ -1204,6 +1718,26 @@ class CollectionsInfoOverlayComponent {
1204
1718
  toggleInvisible(checked) {
1205
1719
  this.hideInvisible = checked;
1206
1720
  }
1721
+ formatValue(value) {
1722
+ if (typeof value === 'number') {
1723
+ return Number.isInteger(value) ? String(value) : value.toFixed(2);
1724
+ }
1725
+ if (Array.isArray(value)) {
1726
+ // Handles nested arrays too, e.g. track `pos`: an array of [x, y, z]
1727
+ // points, so each element is itself an array, not a number.
1728
+ return `[${value.map((v) => this.formatValue(v)).join(', ')}]`;
1729
+ }
1730
+ // Vector-like objects (e.g. THREE.Vector3), which otherwise stringify
1731
+ // to the unhelpful "[object Object]".
1732
+ if (value &&
1733
+ typeof value === 'object' &&
1734
+ typeof value.x === 'number' &&
1735
+ typeof value.y === 'number') {
1736
+ const parts = [value.x, value.y, value.z].filter((v) => typeof v === 'number');
1737
+ return `[${parts.map((v) => this.formatValue(v)).join(', ')}]`;
1738
+ }
1739
+ return String(value);
1740
+ }
1207
1741
  addLabel(index, uuid) {
1208
1742
  const labelValue = this.elementRef.nativeElement.querySelector(`#label${index}`).value;
1209
1743
  if (this.selectedCollection) {
@@ -1219,7 +1753,7 @@ class CollectionsInfoOverlayComponent {
1219
1753
  .getObjectByName(SceneManager.EVENT_DATA_ID);
1220
1754
  }
1221
1755
  static ɵfac = function CollectionsInfoOverlayComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || CollectionsInfoOverlayComponent)(i0.ɵɵdirectiveInject(i0.ElementRef), i0.ɵɵdirectiveInject(EventDisplayService)); };
1222
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: CollectionsInfoOverlayComponent, selectors: [["app-collections-info-overlay"]], inputs: { showObjectsInfo: "showObjectsInfo", excludedColumns: "excludedColumns" }, standalone: false, decls: 2, vars: 3, consts: [["overlayTitle", "Collections Info", "icon", "eventData", 3, "resizable", "active"], ["class", "collectionsInfo m-2", 4, "ngIf"], [1, "collectionsInfo", "m-2"], ["class", "collectionSelector mb-2 d-flex align-items-center", 4, "ngIf"], [1, "boxBody", "table-responsive"], ["id", "collectionTable", "class", "table table-borderless table-sm", 4, "ngIf"], ["class", "emptyBox", 4, "ngIf"], [1, "collectionSelector", "mb-2", "d-flex", "align-items-center"], [1, "d-flex", "align-items-center"], [1, "eventSelector"], ["for", "event"], ["id", "collection", "name", "collection", 3, "change"], ["value", "", "selected", "", "disabled", "", "hidden", ""], [3, "label", 4, "ngFor", "ngForOf"], [3, "change", 4, "ngIf"], [3, "label"], [3, "value", 4, "ngFor", "ngForOf"], [3, "value"], [3, "change"], ["id", "collectionTable", 1, "table", "table-borderless", "table-sm"], [4, "ngFor", "ngForOf"], [3, "ngClass", 4, "ngFor", "ngForOf"], [1, "head-wrapper"], [1, "sort-options"], [1, "icon-wrapper", "icon-button", "btn-blank", "up", 3, "click"], ["href", "assets/icons/expand.svg#expand"], [1, "icon-wrapper", "icon-button", "btn-blank", 3, "click"], [3, "ngClass"], ["data-label", "No."], ["data-label", "Selection"], ["class", "row justify-content-center icon-wrapper", 4, "ngIf"], ["data-label", "Label"], [1, "row", "m-0", "add-label"], [1, "col-10", "p-0"], ["type", "text", 1, "form-control", "form-control-sm", 3, "value", "id"], [1, "col-2", "p-0", "pl-2", "text-center", "icon-wrapper"], ["matTooltip", "Add, update or remove object label", 1, "object-select", "btn-blank", 3, "click"], ["href", "assets/icons/update.svg#update"], [1, "row", "justify-content-center", "icon-wrapper"], ["matTooltip", "Move camera to object", 1, "object-select", "btn-blank", 3, "click"], ["href", "assets/icons/views.svg#views"], ["matTooltip", "Highlight object", 1, "object-select", "btn-blank", 3, "click"], ["href", "assets/icons/cursor.svg#cursor"], [1, "emptyBox"]], template: function CollectionsInfoOverlayComponent_Template(rf, ctx) { if (rf & 1) {
1756
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: CollectionsInfoOverlayComponent, selectors: [["app-collections-info-overlay"]], inputs: { showObjectsInfo: "showObjectsInfo", excludedColumns: "excludedColumns" }, standalone: false, decls: 2, vars: 3, consts: [["overlayTitle", "Collections Info", "icon", "eventData", "accordionId", "right-dock", 3, "resizable", "active"], ["class", "collectionsInfo m-2", 4, "ngIf"], [1, "collectionsInfo", "m-2"], ["class", "collectionSelector mb-2 d-flex align-items-center", 4, "ngIf"], [1, "boxBody", "table-responsive"], ["id", "collectionTable", "class", "table table-borderless table-sm", 4, "ngIf"], ["class", "emptyBox", 4, "ngIf"], [1, "collectionSelector", "mb-2", "d-flex", "align-items-center"], [1, "d-flex", "align-items-center"], [1, "eventSelector"], ["for", "event"], ["id", "collection", "name", "collection", 3, "change"], ["value", "", "selected", "", "disabled", "", "hidden", ""], [3, "label", 4, "ngFor", "ngForOf"], [3, "change", 4, "ngIf"], [3, "label"], [3, "value", 4, "ngFor", "ngForOf"], [3, "value"], [3, "change"], ["id", "collectionTable", 1, "table", "table-borderless", "table-sm"], [4, "ngFor", "ngForOf"], [3, "ngClass", 4, "ngFor", "ngForOf"], [1, "head-wrapper"], [1, "sort-options"], [1, "icon-wrapper", "icon-button", "btn-blank", "up", 3, "click"], ["href", "assets/icons/expand.svg#expand"], [1, "icon-wrapper", "icon-button", "btn-blank", 3, "click"], [3, "ngClass"], ["data-label", "No."], ["data-label", "Selection"], ["class", "row justify-content-center icon-wrapper", 4, "ngIf"], ["data-label", "Label"], [1, "row", "m-0", "add-label"], [1, "col-10", "p-0"], ["type", "text", 1, "form-control", "form-control-sm", 3, "value", "id"], [1, "col-2", "p-0", "pl-2", "text-center", "icon-wrapper"], ["matTooltip", "Add, update or remove object label", 1, "object-select", "btn-blank", 3, "click"], ["href", "assets/icons/update.svg#update"], [1, "row", "justify-content-center", "icon-wrapper"], ["matTooltip", "Move camera to object", 1, "object-select", "btn-blank", 3, "click"], ["href", "assets/icons/views.svg#views"], ["matTooltip", "Highlight object", 1, "object-select", "btn-blank", 3, "click"], ["href", "assets/icons/cursor.svg#cursor"], [1, "emptyBox"]], template: function CollectionsInfoOverlayComponent_Template(rf, ctx) { if (rf & 1) {
1223
1757
  i0.ɵɵelementStart(0, "app-overlay", 0);
1224
1758
  i0.ɵɵtemplate(1, CollectionsInfoOverlayComponent_div_1_Template, 5, 3, "div", 1);
1225
1759
  i0.ɵɵelementEnd();
@@ -1227,11 +1761,11 @@ class CollectionsInfoOverlayComponent {
1227
1761
  i0.ɵɵproperty("resizable", true)("active", ctx.showObjectsInfo);
1228
1762
  i0.ɵɵadvance();
1229
1763
  i0.ɵɵproperty("ngIf", ctx.showObjectsInfo);
1230
- } }, dependencies: [i2.NgClass, i2.NgForOf, i2.NgIf, i3$1.MatTooltip, i4.NgSelectOption, i4.ɵNgSelectMultipleOption, i5.MatCheckbox, OverlayComponent], styles: ["@media screen and (max-width: 400px){.collectionsInfo[_ngcontent-%COMP%] table[_ngcontent-%COMP%], .collectionsInfo[_ngcontent-%COMP%] thead[_ngcontent-%COMP%], .collectionsInfo[_ngcontent-%COMP%] tbody[_ngcontent-%COMP%], .collectionsInfo[_ngcontent-%COMP%] th[_ngcontent-%COMP%], .collectionsInfo[_ngcontent-%COMP%] td[_ngcontent-%COMP%], .collectionsInfo[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]{display:block}.collectionsInfo[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]{position:absolute;top:-9999px;left:-9999px}.collectionsInfo[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]{margin:0 0 1rem}.collectionsInfo[_ngcontent-%COMP%] td[_ngcontent-%COMP%]{border:none;position:relative;padding-left:50%;text-align:left}.collectionsInfo[_ngcontent-%COMP%] td[_ngcontent-%COMP%]:before{position:absolute;top:0;left:0;width:45%;padding-right:10px;white-space:nowrap;content:attr(data-label);font-weight:700}}.collectionsInfo[_ngcontent-%COMP%]{height:95%}.collectionsInfo[_ngcontent-%COMP%] .collectionSelector[_ngcontent-%COMP%]{height:15%;min-height:2rem}.collectionsInfo[_ngcontent-%COMP%] .collectionSelector[_ngcontent-%COMP%] span[_ngcontent-%COMP%]{color:var(--phoenix-text-color-secondary);margin-right:1rem}.collectionsInfo[_ngcontent-%COMP%] .collectionSelector[_ngcontent-%COMP%] mat-checkbox[_ngcontent-%COMP%]{margin-left:1rem}.boxBody[_ngcontent-%COMP%]{height:85%;overflow:scroll}.boxBody[_ngcontent-%COMP%] p.emptyBox[_ngcontent-%COMP%]{max-width:21em}.boxBody[_ngcontent-%COMP%] .add-label[_ngcontent-%COMP%]{min-width:8rem}.boxBody[_ngcontent-%COMP%] .add-label[_ngcontent-%COMP%] input[_ngcontent-%COMP%]{padding:.1rem .3rem;font-size:.75rem}#collectionTable[_ngcontent-%COMP%]{position:relative;color:var(--phoenix-text-color-secondary)}#collectionTable[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] th[_ngcontent-%COMP%]{position:sticky;top:0;z-index:100;background:var(--phoenix-background-color-secondary)}#collectionTable[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] th[_ngcontent-%COMP%] .head-wrapper[_ngcontent-%COMP%]{display:flex;align-items:center}#collectionTable[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] th[_ngcontent-%COMP%] .head-wrapper[_ngcontent-%COMP%] .sort-options[_ngcontent-%COMP%]{display:flex;flex-direction:row}#collectionTable[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] th[_ngcontent-%COMP%] .head-wrapper[_ngcontent-%COMP%] .sort-options[_ngcontent-%COMP%] .icon-wrapper[_ngcontent-%COMP%]{display:flex;width:1rem;height:1rem;padding:.2rem}#collectionTable[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] th[_ngcontent-%COMP%] .head-wrapper[_ngcontent-%COMP%] .sort-options[_ngcontent-%COMP%] .icon-wrapper.up[_ngcontent-%COMP%]{transform:rotate(180deg)}#collectionTable[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] th[_ngcontent-%COMP%] .head-wrapper[_ngcontent-%COMP%] .sort-options[_ngcontent-%COMP%] .icon-wrapper[_ngcontent-%COMP%] svg[_ngcontent-%COMP%]{width:100%;height:100%}#collectionTable[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] *[_ngcontent-%COMP%]{padding-right:1.2rem}#collectionTable[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] *[_ngcontent-%COMP%]:last-child{padding-right:0}#collectionTable[_ngcontent-%COMP%] tr.is-cut[_ngcontent-%COMP%]{opacity:.5}#collectionTable[_ngcontent-%COMP%] tr.active-object[_ngcontent-%COMP%]{color:var(--phoenix-background-color);background:var(--phoenix-text-color);box-shadow:0 0 15px var(--phoenix-text-color)}#collectionTable[_ngcontent-%COMP%] tr.active-object[_ngcontent-%COMP%] div.icon-wrapper[_ngcontent-%COMP%]{--phoenix-options-icon-path: var(--phoenix-background-color);--phoenix-options-icon-bg: var(--phoenix-text-color-hover)}#collectionTable[_ngcontent-%COMP%] tr.active-object[_ngcontent-%COMP%] .add-label[_ngcontent-%COMP%] input[_ngcontent-%COMP%]{--phoenix-text-color: var(--phoenix-background-color);--phoenix-background-color-tertiary: var( --phoenix-text-color-secondary );--phoenix-border: var(--phoenix-background-color)}#collectionTable[_ngcontent-%COMP%] td[_ngcontent-%COMP%]{min-height:20px}#collectionTable[_ngcontent-%COMP%] td[_ngcontent-%COMP%] .object-select[_ngcontent-%COMP%]{position:relative;width:1.6rem;height:1.6rem;margin-right:.4em;text-align:center;background-color:var(--phoenix-options-icon-bg);border-radius:10px;cursor:pointer}#collectionTable[_ngcontent-%COMP%] td[_ngcontent-%COMP%] .object-select[_ngcontent-%COMP%]:last-child{margin-right:0}#collectionTable[_ngcontent-%COMP%] td[_ngcontent-%COMP%] .object-select[_ngcontent-%COMP%]:hover{border:1px solid var(--phoenix-options-icon-path)}#collectionTable[_ngcontent-%COMP%] td[_ngcontent-%COMP%] .object-select[_ngcontent-%COMP%] svg[_ngcontent-%COMP%]{position:absolute;top:0;left:0;padding:.4rem;width:100%;height:100%;vertical-align:top}.eventSelector[_ngcontent-%COMP%]{display:flex}.eventSelector[_ngcontent-%COMP%] label[_ngcontent-%COMP%]{display:none;color:var(--phoenix-text-color-secondary)}.eventSelector[_ngcontent-%COMP%] select[_ngcontent-%COMP%]{width:9rem;padding:5px 10px;font-size:12px;border:1px solid rgba(88,88,88,.08);box-shadow:var(--phoenix-icon-shadow);background-color:var(--phoenix-background-color-tertiary);color:var(--phoenix-text-color-secondary)}"] });
1764
+ } }, dependencies: [i2.NgClass, i2.NgForOf, i2.NgIf, i3$1.MatTooltip, i4.NgSelectOption, i4.ɵNgSelectMultipleOption, i5.MatCheckbox, OverlayComponent], styles: ["@media screen and (max-width:400px){.collectionsInfo[_ngcontent-%COMP%] table[_ngcontent-%COMP%], .collectionsInfo[_ngcontent-%COMP%] thead[_ngcontent-%COMP%], .collectionsInfo[_ngcontent-%COMP%] tbody[_ngcontent-%COMP%], .collectionsInfo[_ngcontent-%COMP%] th[_ngcontent-%COMP%], .collectionsInfo[_ngcontent-%COMP%] td[_ngcontent-%COMP%], .collectionsInfo[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]{display:block}.collectionsInfo[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]{position:absolute;top:-9999px;left:-9999px}.collectionsInfo[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]{margin:0 0 1rem}.collectionsInfo[_ngcontent-%COMP%] td[_ngcontent-%COMP%]{border:none;position:relative;padding-left:50%;text-align:left}.collectionsInfo[_ngcontent-%COMP%] td[_ngcontent-%COMP%]:before{position:absolute;top:0;left:0;width:45%;padding-right:10px;white-space:nowrap;content:attr(data-label);font-weight:700}}.collectionsInfo[_ngcontent-%COMP%]{height:95%}.collectionsInfo[_ngcontent-%COMP%] .collectionSelector[_ngcontent-%COMP%]{height:15%;min-height:2rem}.collectionsInfo[_ngcontent-%COMP%] .collectionSelector[_ngcontent-%COMP%] span[_ngcontent-%COMP%]{color:var(--phoenix-text-color-secondary);margin-right:1rem}.collectionsInfo[_ngcontent-%COMP%] .collectionSelector[_ngcontent-%COMP%] mat-checkbox[_ngcontent-%COMP%]{margin-left:1rem}.boxBody[_ngcontent-%COMP%]{height:85%;overflow:scroll}.boxBody[_ngcontent-%COMP%] p.emptyBox[_ngcontent-%COMP%]{max-width:21em}.boxBody[_ngcontent-%COMP%] .add-label[_ngcontent-%COMP%]{min-width:8rem}.boxBody[_ngcontent-%COMP%] .add-label[_ngcontent-%COMP%] input[_ngcontent-%COMP%]{padding:.1rem .3rem;font-size:.75rem}#collectionTable[_ngcontent-%COMP%]{position:relative;color:var(--phoenix-text-color-secondary)}#collectionTable[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] th[_ngcontent-%COMP%]{position:sticky;top:0;z-index:100;background:var(--phoenix-background-color-secondary)}#collectionTable[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] th[_ngcontent-%COMP%] .head-wrapper[_ngcontent-%COMP%]{display:flex;align-items:center}#collectionTable[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] th[_ngcontent-%COMP%] .head-wrapper[_ngcontent-%COMP%] .sort-options[_ngcontent-%COMP%]{display:flex;flex-direction:row}#collectionTable[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] th[_ngcontent-%COMP%] .head-wrapper[_ngcontent-%COMP%] .sort-options[_ngcontent-%COMP%] .icon-wrapper[_ngcontent-%COMP%]{display:flex;width:1rem;height:1rem;padding:.2rem}#collectionTable[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] th[_ngcontent-%COMP%] .head-wrapper[_ngcontent-%COMP%] .sort-options[_ngcontent-%COMP%] .icon-wrapper.up[_ngcontent-%COMP%]{transform:rotate(180deg)}#collectionTable[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] th[_ngcontent-%COMP%] .head-wrapper[_ngcontent-%COMP%] .sort-options[_ngcontent-%COMP%] .icon-wrapper[_ngcontent-%COMP%] svg[_ngcontent-%COMP%]{width:100%;height:100%}#collectionTable[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] *[_ngcontent-%COMP%]{padding-right:1.2rem}#collectionTable[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] *[_ngcontent-%COMP%]:last-child{padding-right:0}#collectionTable[_ngcontent-%COMP%] tr.is-cut[_ngcontent-%COMP%]{opacity:.5}#collectionTable[_ngcontent-%COMP%] tr.active-object[_ngcontent-%COMP%]{color:var(--phoenix-background-color);background:var(--phoenix-text-color);box-shadow:0 0 15px var(--phoenix-text-color)}#collectionTable[_ngcontent-%COMP%] tr.active-object[_ngcontent-%COMP%] div.icon-wrapper[_ngcontent-%COMP%]{--phoenix-options-icon-path: var(--phoenix-background-color);--phoenix-options-icon-bg: var(--phoenix-text-color-hover)}#collectionTable[_ngcontent-%COMP%] tr.active-object[_ngcontent-%COMP%] .add-label[_ngcontent-%COMP%] input[_ngcontent-%COMP%]{--phoenix-text-color: var(--phoenix-background-color);--phoenix-background-color-tertiary: var( --phoenix-text-color-secondary );--phoenix-border: var(--phoenix-background-color)}#collectionTable[_ngcontent-%COMP%] td[_ngcontent-%COMP%]{min-height:20px}#collectionTable[_ngcontent-%COMP%] td[_ngcontent-%COMP%] .object-select[_ngcontent-%COMP%]{position:relative;width:1.6rem;height:1.6rem;margin-right:.4em;text-align:center;background-color:var(--phoenix-options-icon-bg);border-radius:10px;cursor:pointer}#collectionTable[_ngcontent-%COMP%] td[_ngcontent-%COMP%] .object-select[_ngcontent-%COMP%]:last-child{margin-right:0}#collectionTable[_ngcontent-%COMP%] td[_ngcontent-%COMP%] .object-select[_ngcontent-%COMP%]:hover{border:1px solid var(--phoenix-options-icon-path)}#collectionTable[_ngcontent-%COMP%] td[_ngcontent-%COMP%] .object-select[_ngcontent-%COMP%] svg[_ngcontent-%COMP%]{position:absolute;top:0;left:0;padding:.4rem;width:100%;height:100%;vertical-align:top}.eventSelector[_ngcontent-%COMP%]{display:flex}.eventSelector[_ngcontent-%COMP%] label[_ngcontent-%COMP%]{display:none;color:var(--phoenix-text-color-secondary)}.eventSelector[_ngcontent-%COMP%] select[_ngcontent-%COMP%]{width:9rem;padding:5px 10px;font-size:12px;border:1px solid rgba(88,88,88,.08);box-shadow:var(--phoenix-icon-shadow);background-color:var(--phoenix-background-color-tertiary);color:var(--phoenix-text-color-secondary)}"] });
1231
1765
  }
1232
1766
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(CollectionsInfoOverlayComponent, [{
1233
1767
  type: Component,
1234
- args: [{ standalone: false, selector: 'app-collections-info-overlay', template: "<!-- Show objects -->\n<app-overlay\n overlayTitle=\"Collections Info\"\n icon=\"eventData\"\n [resizable]=\"true\"\n [active]=\"showObjectsInfo\"\n>\n <!-- Using ngIf to remove it from DOM since this panel requires heavy computing -->\n <div *ngIf=\"showObjectsInfo\" class=\"collectionsInfo m-2\">\n <div\n class=\"collectionSelector mb-2 d-flex align-items-center\"\n *ngIf=\"collections != null\"\n >\n <div class=\"d-flex align-items-center\">\n <span>Choose a collection: </span>\n <div class=\"eventSelector\">\n <label for=\"event\">Event</label>\n <select\n id=\"collection\"\n name=\"collection\"\n (change)=\"changeCollection($event.target.value)\"\n >\n <option value=\"\" selected disabled hidden>Choose Collection</option>\n <optgroup *ngFor=\"let group of collections\" [label]=\"group.type\">\n <option\n *ngFor=\"let collection of group.collections\"\n [value]=\"collection\"\n >\n {{ collection }}\n </option>\n </optgroup>\n </select>\n </div>\n <mat-checkbox\n *ngIf=\"showingCollection\"\n (change)=\"toggleInvisible($event.checked)\"\n >\n Hide Invisible Objects\n </mat-checkbox>\n </div>\n </div>\n\n <div class=\"boxBody table-responsive\">\n <table\n id=\"collectionTable\"\n class=\"table table-borderless table-sm\"\n *ngIf=\"showingCollection\"\n >\n <thead>\n <tr>\n <th>No.</th>\n <th>Selection</th>\n <th>Label</th>\n <th *ngFor=\"let column of collectionColumns\">\n <div class=\"head-wrapper\">\n <div>\n {{ getPrettySymbol(column) }}\n </div>\n <div class=\"sort-options\">\n <button\n class=\"icon-wrapper icon-button btn-blank up\"\n (click)=\"sort(column, 'dec')\"\n >\n <svg>\n <use href=\"assets/icons/expand.svg#expand\"></use>\n </svg>\n </button>\n <button\n class=\"icon-wrapper icon-button btn-blank\"\n (click)=\"sort(column, 'asc')\"\n >\n <svg>\n <use href=\"assets/icons/expand.svg#expand\"></use>\n </svg>\n </button>\n </div>\n </div>\n </th>\n </tr>\n </thead>\n <tbody>\n <tr\n *ngFor=\"let object of showingCollection; index as i\"\n [attr.id]=\"object.uuid\"\n [ngClass]=\"{\n 'active-object':\n activeObject && activeObject.value === object.uuid,\n 'is-cut': object.isCut,\n 'd-none': object.isCut && hideInvisible,\n }\"\n >\n <td data-label=\"No.\">#{{ i }}</td>\n <td data-label=\"Selection\">\n <div\n *ngIf=\"object.uuid\"\n class=\"row justify-content-center icon-wrapper\"\n >\n <button\n class=\"object-select btn-blank\"\n matTooltip=\"Move camera to object\"\n (click)=\"lookAtObject(object.uuid)\"\n >\n <svg>\n <use href=\"assets/icons/views.svg#views\"></use>\n </svg>\n </button>\n <button\n class=\"object-select btn-blank\"\n matTooltip=\"Highlight object\"\n (click)=\"highlightObject(object.uuid)\"\n >\n <svg>\n <use href=\"assets/icons/cursor.svg#cursor\"></use>\n </svg>\n </button>\n </div>\n </td>\n <td data-label=\"Label\">\n <div class=\"row m-0 add-label\">\n <div class=\"col-10 p-0\">\n <input\n class=\"form-control form-control-sm\"\n type=\"text\"\n value=\"{{ object.labelText }}\"\n [id]=\"'label' + i\"\n />\n </div>\n <div class=\"col-2 p-0 pl-2 text-center icon-wrapper\">\n <button\n class=\"object-select btn-blank\"\n matTooltip=\"Add, update or remove object label\"\n (click)=\"addLabel(i, object.uuid)\"\n >\n <svg>\n <use href=\"assets/icons/update.svg#update\"></use>\n </svg>\n </button>\n </div>\n </div>\n </td>\n <td\n *ngFor=\"let column of collectionColumns\"\n [attr.data-label]=\"getPrettySymbol(column)\"\n >\n {{ object[column] }}\n </td>\n </tr>\n </tbody>\n </table>\n <p class=\"emptyBox\" *ngIf=\"!collections\">\n Load event data to be able to display information about the collections\n here.\n </p>\n </div>\n </div>\n</app-overlay>\n", styles: ["@media screen and (max-width: 400px){.collectionsInfo table,.collectionsInfo thead,.collectionsInfo tbody,.collectionsInfo th,.collectionsInfo td,.collectionsInfo tr{display:block}.collectionsInfo thead tr{position:absolute;top:-9999px;left:-9999px}.collectionsInfo tr{margin:0 0 1rem}.collectionsInfo td{border:none;position:relative;padding-left:50%;text-align:left}.collectionsInfo td:before{position:absolute;top:0;left:0;width:45%;padding-right:10px;white-space:nowrap;content:attr(data-label);font-weight:700}}.collectionsInfo{height:95%}.collectionsInfo .collectionSelector{height:15%;min-height:2rem}.collectionsInfo .collectionSelector span{color:var(--phoenix-text-color-secondary);margin-right:1rem}.collectionsInfo .collectionSelector mat-checkbox{margin-left:1rem}.boxBody{height:85%;overflow:scroll}.boxBody p.emptyBox{max-width:21em}.boxBody .add-label{min-width:8rem}.boxBody .add-label input{padding:.1rem .3rem;font-size:.75rem}#collectionTable{position:relative;color:var(--phoenix-text-color-secondary)}#collectionTable thead tr th{position:sticky;top:0;z-index:100;background:var(--phoenix-background-color-secondary)}#collectionTable thead tr th .head-wrapper{display:flex;align-items:center}#collectionTable thead tr th .head-wrapper .sort-options{display:flex;flex-direction:row}#collectionTable thead tr th .head-wrapper .sort-options .icon-wrapper{display:flex;width:1rem;height:1rem;padding:.2rem}#collectionTable thead tr th .head-wrapper .sort-options .icon-wrapper.up{transform:rotate(180deg)}#collectionTable thead tr th .head-wrapper .sort-options .icon-wrapper svg{width:100%;height:100%}#collectionTable tr *{padding-right:1.2rem}#collectionTable tr *:last-child{padding-right:0}#collectionTable tr.is-cut{opacity:.5}#collectionTable tr.active-object{color:var(--phoenix-background-color);background:var(--phoenix-text-color);box-shadow:0 0 15px var(--phoenix-text-color)}#collectionTable tr.active-object div.icon-wrapper{--phoenix-options-icon-path: var(--phoenix-background-color);--phoenix-options-icon-bg: var(--phoenix-text-color-hover)}#collectionTable tr.active-object .add-label input{--phoenix-text-color: var(--phoenix-background-color);--phoenix-background-color-tertiary: var( --phoenix-text-color-secondary );--phoenix-border: var(--phoenix-background-color)}#collectionTable td{min-height:20px}#collectionTable td .object-select{position:relative;width:1.6rem;height:1.6rem;margin-right:.4em;text-align:center;background-color:var(--phoenix-options-icon-bg);border-radius:10px;cursor:pointer}#collectionTable td .object-select:last-child{margin-right:0}#collectionTable td .object-select:hover{border:1px solid var(--phoenix-options-icon-path)}#collectionTable td .object-select svg{position:absolute;top:0;left:0;padding:.4rem;width:100%;height:100%;vertical-align:top}.eventSelector{display:flex}.eventSelector label{display:none;color:var(--phoenix-text-color-secondary)}.eventSelector select{width:9rem;padding:5px 10px;font-size:12px;border:1px solid rgba(88,88,88,.08);box-shadow:var(--phoenix-icon-shadow);background-color:var(--phoenix-background-color-tertiary);color:var(--phoenix-text-color-secondary)}\n"] }]
1768
+ args: [{ standalone: false, selector: 'app-collections-info-overlay', template: "<!-- Show objects -->\n<app-overlay\n overlayTitle=\"Collections Info\"\n icon=\"eventData\"\n [resizable]=\"true\"\n [active]=\"showObjectsInfo\"\n accordionId=\"right-dock\"\n>\n <!-- Using ngIf to remove it from DOM since this panel requires heavy computing -->\n <div *ngIf=\"showObjectsInfo\" class=\"collectionsInfo m-2\">\n <div\n class=\"collectionSelector mb-2 d-flex align-items-center\"\n *ngIf=\"collections != null\"\n >\n <div class=\"d-flex align-items-center\">\n <span>Choose a collection: </span>\n <div class=\"eventSelector\">\n <label for=\"event\">Event</label>\n <select\n id=\"collection\"\n name=\"collection\"\n (change)=\"changeCollection($event.target.value)\"\n >\n <option value=\"\" selected disabled hidden>Choose Collection</option>\n <optgroup *ngFor=\"let group of collections\" [label]=\"group.type\">\n <option\n *ngFor=\"let collection of group.collections\"\n [value]=\"collection\"\n >\n {{ collection }}\n </option>\n </optgroup>\n </select>\n </div>\n <mat-checkbox\n *ngIf=\"showingCollection\"\n (change)=\"toggleInvisible($event.checked)\"\n >\n Hide Invisible Objects\n </mat-checkbox>\n </div>\n </div>\n\n <div class=\"boxBody table-responsive\">\n <table\n id=\"collectionTable\"\n class=\"table table-borderless table-sm\"\n *ngIf=\"showingCollection\"\n >\n <thead>\n <tr>\n <th>No.</th>\n <th>Selection</th>\n <th>Label</th>\n <th *ngFor=\"let column of collectionColumns\">\n <div class=\"head-wrapper\">\n <div>\n {{ getPrettySymbol(column) }}\n </div>\n <div class=\"sort-options\">\n <button\n class=\"icon-wrapper icon-button btn-blank up\"\n (click)=\"sort(column, 'dec')\"\n >\n <svg>\n <use href=\"assets/icons/expand.svg#expand\"></use>\n </svg>\n </button>\n <button\n class=\"icon-wrapper icon-button btn-blank\"\n (click)=\"sort(column, 'asc')\"\n >\n <svg>\n <use href=\"assets/icons/expand.svg#expand\"></use>\n </svg>\n </button>\n </div>\n </div>\n </th>\n </tr>\n </thead>\n <tbody>\n <tr\n *ngFor=\"let object of showingCollection; index as i\"\n [attr.id]=\"object.uuid\"\n [ngClass]=\"{\n 'active-object':\n activeObject && activeObject.value === object.uuid,\n 'is-cut': object.isCut,\n 'd-none': object.isCut && hideInvisible,\n }\"\n >\n <td data-label=\"No.\">#{{ i }}</td>\n <td data-label=\"Selection\">\n <div\n *ngIf=\"object.uuid\"\n class=\"row justify-content-center icon-wrapper\"\n >\n <button\n class=\"object-select btn-blank\"\n matTooltip=\"Move camera to object\"\n (click)=\"lookAtObject(object.uuid)\"\n >\n <svg>\n <use href=\"assets/icons/views.svg#views\"></use>\n </svg>\n </button>\n <button\n class=\"object-select btn-blank\"\n matTooltip=\"Highlight object\"\n (click)=\"highlightObject(object.uuid)\"\n >\n <svg>\n <use href=\"assets/icons/cursor.svg#cursor\"></use>\n </svg>\n </button>\n </div>\n </td>\n <td data-label=\"Label\">\n <div class=\"row m-0 add-label\">\n <div class=\"col-10 p-0\">\n <input\n class=\"form-control form-control-sm\"\n type=\"text\"\n value=\"{{ object.labelText }}\"\n [id]=\"'label' + i\"\n />\n </div>\n <div class=\"col-2 p-0 pl-2 text-center icon-wrapper\">\n <button\n class=\"object-select btn-blank\"\n matTooltip=\"Add, update or remove object label\"\n (click)=\"addLabel(i, object.uuid)\"\n >\n <svg>\n <use href=\"assets/icons/update.svg#update\"></use>\n </svg>\n </button>\n </div>\n </div>\n </td>\n <td\n *ngFor=\"let column of collectionColumns\"\n [attr.data-label]=\"getPrettySymbol(column)\"\n >\n {{ formatValue(object[column]) }}\n </td>\n </tr>\n </tbody>\n </table>\n <p class=\"emptyBox\" *ngIf=\"!collections\">\n Load event data to be able to display information about the collections\n here.\n </p>\n </div>\n </div>\n</app-overlay>\n", styles: ["@media screen and (max-width:400px){.collectionsInfo table,.collectionsInfo thead,.collectionsInfo tbody,.collectionsInfo th,.collectionsInfo td,.collectionsInfo tr{display:block}.collectionsInfo thead tr{position:absolute;top:-9999px;left:-9999px}.collectionsInfo tr{margin:0 0 1rem}.collectionsInfo td{border:none;position:relative;padding-left:50%;text-align:left}.collectionsInfo td:before{position:absolute;top:0;left:0;width:45%;padding-right:10px;white-space:nowrap;content:attr(data-label);font-weight:700}}.collectionsInfo{height:95%}.collectionsInfo .collectionSelector{height:15%;min-height:2rem}.collectionsInfo .collectionSelector span{color:var(--phoenix-text-color-secondary);margin-right:1rem}.collectionsInfo .collectionSelector mat-checkbox{margin-left:1rem}.boxBody{height:85%;overflow:scroll}.boxBody p.emptyBox{max-width:21em}.boxBody .add-label{min-width:8rem}.boxBody .add-label input{padding:.1rem .3rem;font-size:.75rem}#collectionTable{position:relative;color:var(--phoenix-text-color-secondary)}#collectionTable thead tr th{position:sticky;top:0;z-index:100;background:var(--phoenix-background-color-secondary)}#collectionTable thead tr th .head-wrapper{display:flex;align-items:center}#collectionTable thead tr th .head-wrapper .sort-options{display:flex;flex-direction:row}#collectionTable thead tr th .head-wrapper .sort-options .icon-wrapper{display:flex;width:1rem;height:1rem;padding:.2rem}#collectionTable thead tr th .head-wrapper .sort-options .icon-wrapper.up{transform:rotate(180deg)}#collectionTable thead tr th .head-wrapper .sort-options .icon-wrapper svg{width:100%;height:100%}#collectionTable tr *{padding-right:1.2rem}#collectionTable tr *:last-child{padding-right:0}#collectionTable tr.is-cut{opacity:.5}#collectionTable tr.active-object{color:var(--phoenix-background-color);background:var(--phoenix-text-color);box-shadow:0 0 15px var(--phoenix-text-color)}#collectionTable tr.active-object div.icon-wrapper{--phoenix-options-icon-path: var(--phoenix-background-color);--phoenix-options-icon-bg: var(--phoenix-text-color-hover)}#collectionTable tr.active-object .add-label input{--phoenix-text-color: var(--phoenix-background-color);--phoenix-background-color-tertiary: var( --phoenix-text-color-secondary );--phoenix-border: var(--phoenix-background-color)}#collectionTable td{min-height:20px}#collectionTable td .object-select{position:relative;width:1.6rem;height:1.6rem;margin-right:.4em;text-align:center;background-color:var(--phoenix-options-icon-bg);border-radius:10px;cursor:pointer}#collectionTable td .object-select:last-child{margin-right:0}#collectionTable td .object-select:hover{border:1px solid var(--phoenix-options-icon-path)}#collectionTable td .object-select svg{position:absolute;top:0;left:0;padding:.4rem;width:100%;height:100%;vertical-align:top}.eventSelector{display:flex}.eventSelector label{display:none;color:var(--phoenix-text-color-secondary)}.eventSelector select{width:9rem;padding:5px 10px;font-size:12px;border:1px solid rgba(88,88,88,.08);box-shadow:var(--phoenix-icon-shadow);background-color:var(--phoenix-background-color-tertiary);color:var(--phoenix-text-color-secondary)}\n"] }]
1235
1769
  }], () => [{ type: i0.ElementRef }, { type: EventDisplayService }], { showObjectsInfo: [{
1236
1770
  type: Input
1237
1771
  }], excludedColumns: [{
@@ -1247,7 +1781,12 @@ class CollectionsInfoComponent {
1247
1781
  this.overlay = overlay;
1248
1782
  }
1249
1783
  ngOnInit() {
1250
- const overlayRef = this.overlay.create();
1784
+ const positionStrategy = this.overlay
1785
+ .position()
1786
+ .global()
1787
+ .bottom('80px')
1788
+ .right('15px');
1789
+ const overlayRef = this.overlay.create({ positionStrategy });
1251
1790
  const overlayPortal = new ComponentPortal(CollectionsInfoOverlayComponent);
1252
1791
  this.overlayWindow = overlayRef.attach(overlayPortal);
1253
1792
  this.overlayWindow.instance.showObjectsInfo = this.showObjectsInfo;
@@ -1265,8 +1804,8 @@ class CollectionsInfoComponent {
1265
1804
  this.overlayWindow.instance.disableHighlighting();
1266
1805
  }
1267
1806
  }
1268
- static ɵfac = function CollectionsInfoComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || CollectionsInfoComponent)(i0.ɵɵdirectiveInject(i1$1.Overlay)); };
1269
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: CollectionsInfoComponent, selectors: [["app-collections-info"]], standalone: false, decls: 1, vars: 1, consts: [["tooltip", "Event data collections info", "icon", "eventData", 3, "click", "active"]], template: function CollectionsInfoComponent_Template(rf, ctx) { if (rf & 1) {
1807
+ static ɵfac = function CollectionsInfoComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || CollectionsInfoComponent)(i0.ɵɵdirectiveInject(i1$3.Overlay)); };
1808
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: CollectionsInfoComponent, selectors: [["app-collections-info"]], standalone: false, decls: 1, vars: 1, consts: [["tooltip", "Collections Info", "icon", "eventData", 3, "click", "active"]], template: function CollectionsInfoComponent_Template(rf, ctx) { if (rf & 1) {
1270
1809
  i0.ɵɵelementStart(0, "app-menu-toggle", 0);
1271
1810
  i0.ɵɵlistener("click", function CollectionsInfoComponent_Template_app_menu_toggle_click_0_listener() { return ctx.toggleOverlay(); });
1272
1811
  i0.ɵɵelementEnd();
@@ -1276,8 +1815,8 @@ class CollectionsInfoComponent {
1276
1815
  }
1277
1816
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(CollectionsInfoComponent, [{
1278
1817
  type: Component,
1279
- args: [{ standalone: false, selector: 'app-collections-info', template: "<app-menu-toggle\n tooltip=\"Event data collections info\"\n icon=\"eventData\"\n [active]=\"showObjectsInfo\"\n (click)=\"toggleOverlay()\"\n>\n</app-menu-toggle>\n" }]
1280
- }], () => [{ type: i1$1.Overlay }], null); })();
1818
+ args: [{ standalone: false, selector: 'app-collections-info', template: "<app-menu-toggle\n tooltip=\"Collections Info\"\n icon=\"eventData\"\n [active]=\"showObjectsInfo\"\n (click)=\"toggleOverlay()\"\n>\n</app-menu-toggle>\n" }]
1819
+ }], () => [{ type: i1$3.Overlay }], null); })();
1281
1820
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(CollectionsInfoComponent, { className: "CollectionsInfoComponent", filePath: "components/ui-menu/collections-info/collections-info.component.ts", lineNumber: 17 }); })();
1282
1821
 
1283
1822
  const _c0$a = a0 => ({ "active-object": a0 });
@@ -1431,7 +1970,7 @@ class GeometryBrowserOverlayComponent {
1431
1970
  this.eventDisplay.disableHighlighting();
1432
1971
  }
1433
1972
  static ɵfac = function GeometryBrowserOverlayComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || GeometryBrowserOverlayComponent)(i0.ɵɵdirectiveInject(EventDisplayService)); };
1434
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: GeometryBrowserOverlayComponent, selectors: [["app-geometry-browser-overlay"]], inputs: { browseDetectorParts: "browseDetectorParts" }, standalone: false, decls: 2, vars: 3, consts: [["overlayTitle", "Browse Geometry", "icon", "info", 3, "resizable", "active"], ["class", "collectionsInfo m-2", 4, "ngIf"], [1, "collectionsInfo", "m-2"], ["class", "collectionSelector mb-2 d-flex align-items-center", 4, "ngIf"], [1, "boxBody", "table-responsive"], ["id", "collectionTable", "class", "table table-borderless table-sm", 4, "ngIf"], ["class", "emptyBox", 4, "ngIf"], [1, "collectionSelector", "mb-2", "d-flex", "align-items-center"], [1, "d-flex", "align-items-center"], [1, "eventSelector"], ["id", "detectorCollection", "name", "detectorCollection", 3, "change"], ["value", "", "selected", "", "disabled", "", "hidden", ""], [3, "value", 4, "ngFor", "ngForOf"], [3, "value"], ["id", "collectionTable", 1, "table", "table-borderless", "table-sm"], [3, "ngClass", 4, "ngFor", "ngForOf"], [3, "ngClass"], ["class", "row justify-content-center icon-wrapper", 4, "ngIf"], [1, "row", "justify-content-center", "icon-wrapper"], ["matTooltip", "Move camera to object", 1, "object-select", "btn-blank", 3, "click"], ["href", "assets/icons/views.svg#views"], ["matTooltip", "Highlight object", 1, "object-select", "btn-blank", 3, "click"], ["href", "assets/icons/cursor.svg#cursor"], [1, "emptyBox"]], template: function GeometryBrowserOverlayComponent_Template(rf, ctx) { if (rf & 1) {
1973
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: GeometryBrowserOverlayComponent, selectors: [["app-geometry-browser-overlay"]], inputs: { browseDetectorParts: "browseDetectorParts" }, standalone: false, decls: 2, vars: 3, consts: [["overlayTitle", "Browse Geometry", "icon", "info", "accordionId", "right-dock", 3, "resizable", "active"], ["class", "collectionsInfo m-2", 4, "ngIf"], [1, "collectionsInfo", "m-2"], ["class", "collectionSelector mb-2 d-flex align-items-center", 4, "ngIf"], [1, "boxBody", "table-responsive"], ["id", "collectionTable", "class", "table table-borderless table-sm", 4, "ngIf"], ["class", "emptyBox", 4, "ngIf"], [1, "collectionSelector", "mb-2", "d-flex", "align-items-center"], [1, "d-flex", "align-items-center"], [1, "eventSelector"], ["id", "detectorCollection", "name", "detectorCollection", 3, "change"], ["value", "", "selected", "", "disabled", "", "hidden", ""], [3, "value", 4, "ngFor", "ngForOf"], [3, "value"], ["id", "collectionTable", 1, "table", "table-borderless", "table-sm"], [3, "ngClass", 4, "ngFor", "ngForOf"], [3, "ngClass"], ["class", "row justify-content-center icon-wrapper", 4, "ngIf"], [1, "row", "justify-content-center", "icon-wrapper"], ["matTooltip", "Move camera to object", 1, "object-select", "btn-blank", 3, "click"], ["href", "assets/icons/views.svg#views"], ["matTooltip", "Highlight object", 1, "object-select", "btn-blank", 3, "click"], ["href", "assets/icons/cursor.svg#cursor"], [1, "emptyBox"]], template: function GeometryBrowserOverlayComponent_Template(rf, ctx) { if (rf & 1) {
1435
1974
  i0.ɵɵelementStart(0, "app-overlay", 0);
1436
1975
  i0.ɵɵtemplate(1, GeometryBrowserOverlayComponent_div_1_Template, 5, 3, "div", 1);
1437
1976
  i0.ɵɵelementEnd();
@@ -1443,7 +1982,7 @@ class GeometryBrowserOverlayComponent {
1443
1982
  }
1444
1983
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(GeometryBrowserOverlayComponent, [{
1445
1984
  type: Component,
1446
- args: [{ standalone: false, selector: 'app-geometry-browser-overlay', template: "<!-- Show objects -->\n<app-overlay\n overlayTitle=\"Browse Geometry\"\n icon=\"info\"\n [resizable]=\"true\"\n [active]=\"browseDetectorParts\"\n>\n <!-- Using ngIf to remove it from DOM since this panel requires heavy computing -->\n <div *ngIf=\"browseDetectorParts\" class=\"collectionsInfo m-2\">\n <div\n class=\"collectionSelector mb-2 d-flex align-items-center\"\n *ngIf=\"children != null\"\n >\n <div class=\"d-flex align-items-center\">\n <span>Choose a collection: </span>\n <div class=\"eventSelector\">\n <select\n id=\"detectorCollection\"\n name=\"detectorCollection\"\n (change)=\"changeCollection($event.target.value)\"\n >\n <option value=\"\" selected disabled hidden>Choose Collection</option>\n <option *ngFor=\"let child of children\" [value]=\"child.name\">\n {{ child.name }}\n </option>\n </select>\n </div>\n </div>\n </div>\n\n <div class=\"boxBody table-responsive\">\n <table\n id=\"collectionTable\"\n class=\"table table-borderless table-sm\"\n *ngIf=\"showingCollection\"\n >\n <thead>\n <tr>\n <th>No.</th>\n <th>Selection</th>\n </tr>\n </thead>\n <tbody>\n <tr\n *ngFor=\"let object of showingCollection; index as i\"\n [attr.id]=\"object.uuid\"\n [ngClass]=\"{\n 'active-object':\n activeObject && activeObject.value === object.uuid,\n }\"\n >\n <td>#{{ i }}</td>\n <td>\n <div\n *ngIf=\"object.uuid\"\n class=\"row justify-content-center icon-wrapper\"\n >\n <button\n class=\"object-select btn-blank\"\n matTooltip=\"Move camera to object\"\n (click)=\"lookAtObject(object.uuid)\"\n >\n <svg>\n <use href=\"assets/icons/views.svg#views\"></use>\n </svg>\n </button>\n <button\n class=\"object-select btn-blank\"\n matTooltip=\"Highlight object\"\n (click)=\"highlightObject(object.uuid)\"\n >\n <svg>\n <use href=\"assets/icons/cursor.svg#cursor\"></use>\n </svg>\n </button>\n </div>\n </td>\n </tr>\n </tbody>\n </table>\n <p class=\"emptyBox\" *ngIf=\"!children\">\n Load event data to be able to display information about the collections\n here.\n </p>\n </div>\n </div>\n</app-overlay>\n", styles: [".collectionsInfo{height:95%}.collectionsInfo .collectionSelector{height:15%;min-height:2rem}.collectionsInfo .collectionSelector span{color:var(--phoenix-text-color-secondary);margin-right:1rem}.boxBody{height:85%;overflow:scroll}.boxBody p.emptyBox{max-width:21em}#collectionTable{position:relative;color:var(--phoenix-text-color-secondary)}#collectionTable thead tr th{position:sticky;top:0;z-index:100;background:var(--phoenix-background-color-secondary)}#collectionTable thead tr th .row{margin-right:10px;margin-left:-92px}#collectionTable thead tr th .icon-wrapper{display:flex;width:1rem;height:1rem;padding:.2rem}#collectionTable thead tr th .icon-wrapper svg{width:100%;height:100%}#collectionTable tr *{padding-right:1.2rem}#collectionTable tr *:last-child{padding-right:0}#collectionTable tr.active-object{color:var(--phoenix-background-color);background:var(--phoenix-text-color);box-shadow:0 0 15px var(--phoenix-text-color)}#collectionTable tr.active-object div.icon-wrapper{--phoenix-options-icon-path: var(--phoenix-background-color);--phoenix-options-icon-bg: var(--phoenix-text-color-hover)}#collectionTable td .object-select{position:relative;width:1.6rem;height:1.6rem;margin-right:.4em;text-align:center;background-color:var(--phoenix-options-icon-bg);border-radius:10px;cursor:pointer}#collectionTable td .object-select:last-child{margin-right:0}#collectionTable td .object-select:hover{border:1px solid var(--phoenix-options-icon-path)}#collectionTable td .object-select svg{position:absolute;top:0;left:0;padding:.4rem;width:100%;height:100%;vertical-align:top}.eventSelector{display:flex}.eventSelector label{display:none;color:var(--phoenix-text-color-secondary)}.eventSelector select{width:9rem;padding:5px 10px;font-size:12px;border:1px solid rgba(88,88,88,.08);box-shadow:var(--phoenix-icon-shadow);background-color:var(--phoenix-background-color-tertiary);color:var(--phoenix-text-color-secondary)}\n"] }]
1985
+ args: [{ standalone: false, selector: 'app-geometry-browser-overlay', template: "<!-- Show objects -->\n<app-overlay\n overlayTitle=\"Browse Geometry\"\n icon=\"info\"\n [resizable]=\"true\"\n [active]=\"browseDetectorParts\"\n accordionId=\"right-dock\"\n>\n <!-- Using ngIf to remove it from DOM since this panel requires heavy computing -->\n <div *ngIf=\"browseDetectorParts\" class=\"collectionsInfo m-2\">\n <div\n class=\"collectionSelector mb-2 d-flex align-items-center\"\n *ngIf=\"children != null\"\n >\n <div class=\"d-flex align-items-center\">\n <span>Choose a collection: </span>\n <div class=\"eventSelector\">\n <select\n id=\"detectorCollection\"\n name=\"detectorCollection\"\n (change)=\"changeCollection($event.target.value)\"\n >\n <option value=\"\" selected disabled hidden>Choose Collection</option>\n <option *ngFor=\"let child of children\" [value]=\"child.name\">\n {{ child.name }}\n </option>\n </select>\n </div>\n </div>\n </div>\n\n <div class=\"boxBody table-responsive\">\n <table\n id=\"collectionTable\"\n class=\"table table-borderless table-sm\"\n *ngIf=\"showingCollection\"\n >\n <thead>\n <tr>\n <th>No.</th>\n <th>Selection</th>\n </tr>\n </thead>\n <tbody>\n <tr\n *ngFor=\"let object of showingCollection; index as i\"\n [attr.id]=\"object.uuid\"\n [ngClass]=\"{\n 'active-object':\n activeObject && activeObject.value === object.uuid,\n }\"\n >\n <td>#{{ i }}</td>\n <td>\n <div\n *ngIf=\"object.uuid\"\n class=\"row justify-content-center icon-wrapper\"\n >\n <button\n class=\"object-select btn-blank\"\n matTooltip=\"Move camera to object\"\n (click)=\"lookAtObject(object.uuid)\"\n >\n <svg>\n <use href=\"assets/icons/views.svg#views\"></use>\n </svg>\n </button>\n <button\n class=\"object-select btn-blank\"\n matTooltip=\"Highlight object\"\n (click)=\"highlightObject(object.uuid)\"\n >\n <svg>\n <use href=\"assets/icons/cursor.svg#cursor\"></use>\n </svg>\n </button>\n </div>\n </td>\n </tr>\n </tbody>\n </table>\n <p class=\"emptyBox\" *ngIf=\"!children\">\n Load event data to be able to display information about the collections\n here.\n </p>\n </div>\n </div>\n</app-overlay>\n", styles: [".collectionsInfo{height:95%}.collectionsInfo .collectionSelector{height:15%;min-height:2rem}.collectionsInfo .collectionSelector span{color:var(--phoenix-text-color-secondary);margin-right:1rem}.boxBody{height:85%;overflow:scroll}.boxBody p.emptyBox{max-width:21em}#collectionTable{position:relative;color:var(--phoenix-text-color-secondary)}#collectionTable thead tr th{position:sticky;top:0;z-index:100;background:var(--phoenix-background-color-secondary)}#collectionTable thead tr th .row{margin-right:10px;margin-left:-92px}#collectionTable thead tr th .icon-wrapper{display:flex;width:1rem;height:1rem;padding:.2rem}#collectionTable thead tr th .icon-wrapper svg{width:100%;height:100%}#collectionTable tr *{padding-right:1.2rem}#collectionTable tr *:last-child{padding-right:0}#collectionTable tr.active-object{color:var(--phoenix-background-color);background:var(--phoenix-text-color);box-shadow:0 0 15px var(--phoenix-text-color)}#collectionTable tr.active-object div.icon-wrapper{--phoenix-options-icon-path: var(--phoenix-background-color);--phoenix-options-icon-bg: var(--phoenix-text-color-hover)}#collectionTable td .object-select{position:relative;width:1.6rem;height:1.6rem;margin-right:.4em;text-align:center;background-color:var(--phoenix-options-icon-bg);border-radius:10px;cursor:pointer}#collectionTable td .object-select:last-child{margin-right:0}#collectionTable td .object-select:hover{border:1px solid var(--phoenix-options-icon-path)}#collectionTable td .object-select svg{position:absolute;top:0;left:0;padding:.4rem;width:100%;height:100%;vertical-align:top}.eventSelector{display:flex}.eventSelector label{display:none;color:var(--phoenix-text-color-secondary)}.eventSelector select{width:9rem;padding:5px 10px;font-size:12px;border:1px solid rgba(88,88,88,.08);box-shadow:var(--phoenix-icon-shadow);background-color:var(--phoenix-background-color-tertiary);color:var(--phoenix-text-color-secondary)}\n"] }]
1447
1986
  }], () => [{ type: EventDisplayService }], { browseDetectorParts: [{
1448
1987
  type: Input
1449
1988
  }] }); })();
@@ -1457,7 +1996,12 @@ class GeometryBrowserComponent {
1457
1996
  this.overlay = overlay;
1458
1997
  }
1459
1998
  ngOnInit() {
1460
- const overlayRef = this.overlay.create();
1999
+ const positionStrategy = this.overlay
2000
+ .position()
2001
+ .global()
2002
+ .bottom('150px')
2003
+ .right('15px');
2004
+ const overlayRef = this.overlay.create({ positionStrategy });
1461
2005
  const overlayPortal = new ComponentPortal(GeometryBrowserOverlayComponent);
1462
2006
  this.overlayWindow = overlayRef.attach(overlayPortal);
1463
2007
  this.overlayWindow.instance.browseDetectorParts = this.browseDetectorParts;
@@ -1468,12 +2012,14 @@ class GeometryBrowserComponent {
1468
2012
  toggleOverlay() {
1469
2013
  this.browseDetectorParts = !this.browseDetectorParts;
1470
2014
  this.overlayWindow.instance.browseDetectorParts = this.browseDetectorParts;
1471
- // eslint-disable-next-line
1472
- this.browseDetectorParts
1473
- ? this.overlayWindow.instance.enableHighlighting()
1474
- : this.overlayWindow.instance.disableHighlighting();
2015
+ if (this.browseDetectorParts) {
2016
+ this.overlayWindow.instance.enableHighlighting();
2017
+ }
2018
+ else {
2019
+ this.overlayWindow.instance.disableHighlighting();
2020
+ }
1475
2021
  }
1476
- static ɵfac = function GeometryBrowserComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || GeometryBrowserComponent)(i0.ɵɵdirectiveInject(i1$1.Overlay)); };
2022
+ static ɵfac = function GeometryBrowserComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || GeometryBrowserComponent)(i0.ɵɵdirectiveInject(i1$3.Overlay)); };
1477
2023
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: GeometryBrowserComponent, selectors: [["app-geometry-browser"]], standalone: false, decls: 1, vars: 1, consts: [["tooltip", "Browse geometry", "icon", "top-cube", 3, "click", "active"]], template: function GeometryBrowserComponent_Template(rf, ctx) { if (rf & 1) {
1478
2024
  i0.ɵɵelementStart(0, "app-menu-toggle", 0);
1479
2025
  i0.ɵɵlistener("click", function GeometryBrowserComponent_Template_app_menu_toggle_click_0_listener() { return ctx.toggleOverlay(); });
@@ -1485,7 +2031,7 @@ class GeometryBrowserComponent {
1485
2031
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(GeometryBrowserComponent, [{
1486
2032
  type: Component,
1487
2033
  args: [{ standalone: false, selector: 'app-geometry-browser', template: "<app-menu-toggle\n tooltip=\"Browse geometry\"\n icon=\"top-cube\"\n [active]=\"browseDetectorParts\"\n (click)=\"toggleOverlay()\"\n>\n</app-menu-toggle>\n" }]
1488
- }], () => [{ type: i1$1.Overlay }], null); })();
2034
+ }], () => [{ type: i1$3.Overlay }], null); })();
1489
2035
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(GeometryBrowserComponent, { className: "GeometryBrowserComponent", filePath: "components/ui-menu/geometry-browser/geometry-browser.component.ts", lineNumber: 17 }); })();
1490
2036
 
1491
2037
  class DarkThemeComponent {
@@ -1502,7 +2048,7 @@ class DarkThemeComponent {
1502
2048
  this.eventDisplay.getUIManager().setDarkTheme(this.darkTheme);
1503
2049
  }
1504
2050
  static ɵfac = function DarkThemeComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || DarkThemeComponent)(i0.ɵɵdirectiveInject(EventDisplayService)); };
1505
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: DarkThemeComponent, selectors: [["app-dark-theme"]], standalone: false, decls: 1, vars: 1, consts: [["tooltip", "Dark theme", "icon", "dark", 3, "click", "active"]], template: function DarkThemeComponent_Template(rf, ctx) { if (rf & 1) {
2051
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: DarkThemeComponent, selectors: [["app-dark-theme"]], standalone: false, decls: 1, vars: 1, consts: [["tooltip", "Switch Dark/Light theme", "icon", "dark", 3, "click", "active"]], template: function DarkThemeComponent_Template(rf, ctx) { if (rf & 1) {
1506
2052
  i0.ɵɵelementStart(0, "app-menu-toggle", 0);
1507
2053
  i0.ɵɵlistener("click", function DarkThemeComponent_Template_app_menu_toggle_click_0_listener() { return ctx.setDarkTheme(); });
1508
2054
  i0.ɵɵelementEnd();
@@ -1512,7 +2058,7 @@ class DarkThemeComponent {
1512
2058
  }
1513
2059
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(DarkThemeComponent, [{
1514
2060
  type: Component,
1515
- args: [{ standalone: false, selector: 'app-dark-theme', template: "<app-menu-toggle\n tooltip=\"Dark theme\"\n [active]=\"darkTheme\"\n icon=\"dark\"\n (click)=\"setDarkTheme()\"\n>\n</app-menu-toggle>\n" }]
2061
+ args: [{ standalone: false, selector: 'app-dark-theme', template: "<app-menu-toggle\n tooltip=\"Switch Dark/Light theme\"\n [active]=\"darkTheme\"\n icon=\"dark\"\n (click)=\"setDarkTheme()\"\n>\n</app-menu-toggle>\n" }]
1516
2062
  }], () => [{ type: EventDisplayService }], null); })();
1517
2063
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(DarkThemeComponent, { className: "DarkThemeComponent", filePath: "components/ui-menu/dark-theme/dark-theme.component.ts", lineNumber: 10 }); })();
1518
2064
 
@@ -1660,11 +2206,11 @@ class ExperimentInfoComponent {
1660
2206
  i0.ɵɵproperty("ngIf", ctx.tagline);
1661
2207
  i0.ɵɵadvance();
1662
2208
  i0.ɵɵproperty("ngForOf", ctx.experimentInfo);
1663
- } }, dependencies: [i2.NgForOf, i2.NgIf, i3$3.CdkDrag], styles: [".experimentInfo[_ngcontent-%COMP%]{position:absolute;top:5rem;left:1rem;display:flex;flex-direction:row;justify-items:flex-end;justify-content:flex-end;align-items:center;align-content:center;font-family:Courier New,Lucida Console,monospace;cursor:move}.experimentLogoWrapper[_ngcontent-%COMP%]{width:6rem}.experimentLogoWrapper[_ngcontent-%COMP%] .experimentLogo[_ngcontent-%COMP%]{width:100%;height:100%}.textInfo[_ngcontent-%COMP%]{margin-left:1rem}.textInfo[_ngcontent-%COMP%] p[_ngcontent-%COMP%]{color:var(--phoenix-text-color-secondary);font-size:.8rem;margin-bottom:.5rem;-webkit-user-select:none;user-select:none}@media screen and (max-width: 768px){.experimentInfo[_ngcontent-%COMP%]{top:4rem;max-width:40%}.experimentLogoWrapper[_ngcontent-%COMP%]{height:4rem}.textInfo[_ngcontent-%COMP%]{display:none}}"] });
2209
+ } }, dependencies: [i2.NgForOf, i2.NgIf, i3$2.CdkDrag], styles: [".experimentInfo[_ngcontent-%COMP%]{position:absolute;top:5rem;left:1rem;display:flex;flex-direction:row;justify-items:flex-end;justify-content:flex-end;align-items:center;align-content:center;font-family:Courier New,Lucida Console,monospace;cursor:move}.experimentLogoWrapper[_ngcontent-%COMP%]{width:6rem}.experimentLogoWrapper[_ngcontent-%COMP%] .experimentLogo[_ngcontent-%COMP%]{width:100%;height:100%}.textInfo[_ngcontent-%COMP%]{margin-left:1rem}.textInfo[_ngcontent-%COMP%] p[_ngcontent-%COMP%]{color:var(--phoenix-text-color-secondary);font-size:.8rem;margin-bottom:.5rem;-webkit-user-select:none;user-select:none}@media screen and (max-width:768px){.experimentInfo[_ngcontent-%COMP%]{top:4rem;max-width:40%}.experimentLogoWrapper[_ngcontent-%COMP%]{height:4rem}.textInfo[_ngcontent-%COMP%]{display:none}}"] });
1664
2210
  }
1665
2211
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ExperimentInfoComponent, [{
1666
2212
  type: Component,
1667
- args: [{ standalone: false, selector: 'app-experiment-info', template: "<div id=\"experimentInfo\" class=\"experimentInfo\" cdkDrag cdkDragBoundary=\"body\">\n <a\n class=\"experimentLogoWrapper\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n *ngIf=\"url\"\n [href]=\"url\"\n >\n <img class=\"experimentLogo\" [src]=\"logo\" alt=\"\" />\n </a>\n <div class=\"textInfo\">\n <p *ngIf=\"tagline\">\n <b>{{ tagline }}</b>\n </p>\n <p *ngFor=\"let infoField of experimentInfo\">\n <ng-container *ngIf=\"infoField.label\">\n <b>{{ infoField.label }}: </b>{{ infoField.value }}\n </ng-container>\n <ng-container *ngIf=\"!infoField.label\">\n {{ infoField }}\n </ng-container>\n </p>\n </div>\n</div>\n", styles: [".experimentInfo{position:absolute;top:5rem;left:1rem;display:flex;flex-direction:row;justify-items:flex-end;justify-content:flex-end;align-items:center;align-content:center;font-family:Courier New,Lucida Console,monospace;cursor:move}.experimentLogoWrapper{width:6rem}.experimentLogoWrapper .experimentLogo{width:100%;height:100%}.textInfo{margin-left:1rem}.textInfo p{color:var(--phoenix-text-color-secondary);font-size:.8rem;margin-bottom:.5rem;-webkit-user-select:none;user-select:none}@media screen and (max-width: 768px){.experimentInfo{top:4rem;max-width:40%}.experimentLogoWrapper{height:4rem}.textInfo{display:none}}\n"] }]
2213
+ args: [{ standalone: false, selector: 'app-experiment-info', template: "<div id=\"experimentInfo\" class=\"experimentInfo\" cdkDrag cdkDragBoundary=\"body\">\n <a\n class=\"experimentLogoWrapper\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n *ngIf=\"url\"\n [href]=\"url\"\n >\n <img class=\"experimentLogo\" [src]=\"logo\" alt=\"\" />\n </a>\n <div class=\"textInfo\">\n <p *ngIf=\"tagline\">\n <b>{{ tagline }}</b>\n </p>\n <p *ngFor=\"let infoField of experimentInfo\">\n <ng-container *ngIf=\"infoField.label\">\n <b>{{ infoField.label }}: </b>{{ infoField.value }}\n </ng-container>\n <ng-container *ngIf=\"!infoField.label\">\n {{ infoField }}\n </ng-container>\n </p>\n </div>\n</div>\n", styles: [".experimentInfo{position:absolute;top:5rem;left:1rem;display:flex;flex-direction:row;justify-items:flex-end;justify-content:flex-end;align-items:center;align-content:center;font-family:Courier New,Lucida Console,monospace;cursor:move}.experimentLogoWrapper{width:6rem}.experimentLogoWrapper .experimentLogo{width:100%;height:100%}.textInfo{margin-left:1rem}.textInfo p{color:var(--phoenix-text-color-secondary);font-size:.8rem;margin-bottom:.5rem;-webkit-user-select:none;user-select:none}@media screen and (max-width:768px){.experimentInfo{top:4rem;max-width:40%}.experimentLogoWrapper{height:4rem}.textInfo{display:none}}\n"] }]
1668
2214
  }], () => [{ type: EventDisplayService }], { url: [{
1669
2215
  type: Input
1670
2216
  }], logo: [{
@@ -1737,11 +2283,40 @@ class InfoPanelOverlayComponent {
1737
2283
  }] }); })();
1738
2284
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(InfoPanelOverlayComponent, { className: "InfoPanelOverlayComponent", filePath: "components/ui-menu/info-panel/info-panel-overlay/info-panel-overlay.component.ts", lineNumber: 14 }); })();
1739
2285
 
2286
+ class OverlayCascadeService {
2287
+ overlay;
2288
+ cascadeCount = 0;
2289
+ topOffset = 130;
2290
+ leftOffset = 15;
2291
+ step = 40;
2292
+ constructor(overlay) {
2293
+ this.overlay = overlay;
2294
+ }
2295
+ getCascadePositionStrategy() {
2296
+ const strategy = this.overlay
2297
+ .position()
2298
+ .global()
2299
+ .top(`${this.topOffset + this.cascadeCount * this.step}px`)
2300
+ .left(`${this.leftOffset + this.cascadeCount * this.step}px`);
2301
+ this.cascadeCount++;
2302
+ return strategy;
2303
+ }
2304
+ static ɵfac = function OverlayCascadeService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || OverlayCascadeService)(i0.ɵɵinject(i1$3.Overlay)); };
2305
+ static ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: OverlayCascadeService, factory: OverlayCascadeService.ɵfac, providedIn: 'root' });
2306
+ }
2307
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(OverlayCascadeService, [{
2308
+ type: Injectable,
2309
+ args: [{
2310
+ providedIn: 'root',
2311
+ }]
2312
+ }], () => [{ type: i1$3.Overlay }], null); })();
2313
+
1740
2314
  /**
1741
2315
  * Component for toggling info panel overlay
1742
2316
  */
1743
2317
  class InfoPanelComponent {
1744
2318
  overlay;
2319
+ overlayCascade;
1745
2320
  /** @ignore */
1746
2321
  showInfoPanel = false;
1747
2322
  /** Information panel overlay window */
@@ -1750,14 +2325,16 @@ class InfoPanelComponent {
1750
2325
  * Create the info panel toggle
1751
2326
  * @param overlay Info panel overlay containing logger data
1752
2327
  */
1753
- constructor(overlay) {
2328
+ constructor(overlay, overlayCascade) {
1754
2329
  this.overlay = overlay;
2330
+ this.overlayCascade = overlayCascade;
1755
2331
  }
1756
2332
  /**
1757
2333
  * Create the info panel overlay
1758
2334
  */
1759
2335
  ngOnInit() {
1760
- const overlayRef = this.overlay.create();
2336
+ const positionStrategy = this.overlayCascade.getCascadePositionStrategy();
2337
+ const overlayRef = this.overlay.create({ positionStrategy });
1761
2338
  const overlayPortal = new ComponentPortal(InfoPanelOverlayComponent);
1762
2339
  this.overlayWindow = overlayRef.attach(overlayPortal);
1763
2340
  this.overlayWindow.instance.showInfoPanel = this.showInfoPanel;
@@ -1775,7 +2352,7 @@ class InfoPanelComponent {
1775
2352
  this.showInfoPanel = !this.showInfoPanel;
1776
2353
  this.overlayWindow.instance.showInfoPanel = this.showInfoPanel;
1777
2354
  }
1778
- static ɵfac = function InfoPanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || InfoPanelComponent)(i0.ɵɵdirectiveInject(i1$1.Overlay)); };
2355
+ static ɵfac = function InfoPanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || InfoPanelComponent)(i0.ɵɵdirectiveInject(i1$3.Overlay), i0.ɵɵdirectiveInject(OverlayCascadeService)); };
1779
2356
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: InfoPanelComponent, selectors: [["app-info-panel"]], standalone: false, decls: 1, vars: 1, consts: [["tooltip", "Info panel", "icon", "info-panel", 3, "click", "active"]], template: function InfoPanelComponent_Template(rf, ctx) { if (rf & 1) {
1780
2357
  i0.ɵɵelementStart(0, "app-menu-toggle", 0);
1781
2358
  i0.ɵɵlistener("click", function InfoPanelComponent_Template_app_menu_toggle_click_0_listener() { return ctx.toggleOverlay(); });
@@ -1787,8 +2364,8 @@ class InfoPanelComponent {
1787
2364
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(InfoPanelComponent, [{
1788
2365
  type: Component,
1789
2366
  args: [{ standalone: false, selector: 'app-info-panel', template: "<app-menu-toggle\n tooltip=\"Info panel\"\n icon=\"info-panel\"\n [active]=\"showInfoPanel\"\n (click)=\"toggleOverlay()\"\n>\n</app-menu-toggle>\n" }]
1790
- }], () => [{ type: i1$1.Overlay }], null); })();
1791
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(InfoPanelComponent, { className: "InfoPanelComponent", filePath: "components/ui-menu/info-panel/info-panel.component.ts", lineNumber: 20 }); })();
2367
+ }], () => [{ type: i1$3.Overlay }, { type: OverlayCascadeService }], null); })();
2368
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(InfoPanelComponent, { className: "InfoPanelComponent", filePath: "components/ui-menu/info-panel/info-panel.component.ts", lineNumber: 21 }); })();
1792
2369
 
1793
2370
  var EventDataFormat;
1794
2371
  (function (EventDataFormat) {
@@ -1796,6 +2373,7 @@ var EventDataFormat;
1796
2373
  EventDataFormat["EDM4HEPJSON"] = "EDM4HEPJSON";
1797
2374
  EventDataFormat["JIVEXML"] = "JIVEXML";
1798
2375
  EventDataFormat["PHYSLITE"] = "PHYSLITE";
2376
+ EventDataFormat["ATLASESD"] = "ATLASESD";
1799
2377
  EventDataFormat["IG"] = "IG";
1800
2378
  EventDataFormat["ZIP"] = "ZIP";
1801
2379
  })(EventDataFormat || (EventDataFormat = {}));
@@ -1820,15 +2398,18 @@ function IOOptionsDialogComponent_div_4_ng_container_5_Template(rf, ctx) { if (r
1820
2398
  i0.ɵɵelementEnd();
1821
2399
  i0.ɵɵelementStart(3, "button", 13);
1822
2400
  i0.ɵɵlistener("click", function IOOptionsDialogComponent_div_4_ng_container_5_Template_button_click_3_listener() { i0.ɵɵrestoreView(_r2); const eventDataFileInput_r4 = i0.ɵɵreference(2); return i0.ɵɵresetView(eventDataFileInput_r4.click()); });
1823
- i0.ɵɵelement(4, "img", 31);
1824
- i0.ɵɵtext(5);
2401
+ i0.ɵɵnamespaceSVG();
2402
+ i0.ɵɵelementStart(4, "svg", 31);
2403
+ i0.ɵɵelement(5, "use", 32);
2404
+ i0.ɵɵelementEnd();
2405
+ i0.ɵɵtext(6);
1825
2406
  i0.ɵɵelementEnd();
1826
2407
  i0.ɵɵelementContainerEnd();
1827
2408
  } if (rf & 2) {
1828
2409
  const eventDataImportOption_r3 = ctx.$implicit;
1829
2410
  i0.ɵɵadvance();
1830
2411
  i0.ɵɵproperty("accept", eventDataImportOption_r3.accept);
1831
- i0.ɵɵadvance(4);
2412
+ i0.ɵɵadvance(5);
1832
2413
  i0.ɵɵtextInterpolate1(" Load ", eventDataImportOption_r3.fileType, " ");
1833
2414
  } }
1834
2415
  function IOOptionsDialogComponent_div_4_Template(rf, ctx) { if (rf & 1) {
@@ -1836,7 +2417,7 @@ function IOOptionsDialogComponent_div_4_Template(rf, ctx) { if (rf & 1) {
1836
2417
  i0.ɵɵtext(3, "Event data");
1837
2418
  i0.ɵɵelementEnd()();
1838
2419
  i0.ɵɵelementStart(4, "div", 11);
1839
- i0.ɵɵtemplate(5, IOOptionsDialogComponent_div_4_ng_container_5_Template, 6, 2, "ng-container", 29);
2420
+ i0.ɵɵtemplate(5, IOOptionsDialogComponent_div_4_ng_container_5_Template, 7, 2, "ng-container", 29);
1840
2421
  i0.ɵɵelementEnd()();
1841
2422
  } if (rf & 2) {
1842
2423
  const ctx_r4 = i0.ɵɵnextContext();
@@ -1846,6 +2427,7 @@ function IOOptionsDialogComponent_div_4_Template(rf, ctx) { if (rf & 1) {
1846
2427
  class IOOptionsDialogComponent {
1847
2428
  eventDisplay;
1848
2429
  dialogRef;
2430
+ notificationService;
1849
2431
  eventDataImportOptions = [EventDataFormat.JSON];
1850
2432
  eventDataOptionsWithHandler;
1851
2433
  supportedEventDataFormats = [
@@ -1853,12 +2435,16 @@ class IOOptionsDialogComponent {
1853
2435
  new ImportOption(EventDataFormat.EDM4HEPJSON, '.edm4hep.json', this.handleEDM4HEPJSONEventDataInput.bind(this), 'application/json'),
1854
2436
  new ImportOption(EventDataFormat.JIVEXML, '.xml', this.handleJiveXMLDataInput.bind(this), 'text/xml'),
1855
2437
  new ImportOption(EventDataFormat.ZIP, '.zip', this.handleZipEventDataInput.bind(this), '.zip'),
1856
- new ImportOption(EventDataFormat.PHYSLITE, '.root', this.handlePHYSLITEInput.bind(this), '.root'),
2438
+ // Both ROOT formats accept '.root', so the button labels have to say which
2439
+ // is which — the template renders "Load {{ fileType }}".
2440
+ new ImportOption(EventDataFormat.PHYSLITE, 'PHYSLITE (.root)', this.handlePHYSLITEInput.bind(this), '.root'),
2441
+ new ImportOption(EventDataFormat.ATLASESD, 'ATLAS ESD (.root)', this.handleATLASESDInput.bind(this), '.root'),
1857
2442
  new ImportOption(EventDataFormat.IG, '.ig', this.handleIgEventDataInput.bind(this), '.ig'),
1858
2443
  ];
1859
- constructor(eventDisplay, dialogRef) {
2444
+ constructor(eventDisplay, dialogRef, notificationService) {
1860
2445
  this.eventDisplay = eventDisplay;
1861
2446
  this.dialogRef = dialogRef;
2447
+ this.notificationService = notificationService;
1862
2448
  }
1863
2449
  ngOnInit() {
1864
2450
  this.eventDataOptionsWithHandler = this.supportedEventDataFormats.filter((eventDataFormat) => this.eventDataImportOptions.includes(eventDataFormat.format));
@@ -1897,6 +2483,7 @@ class IOOptionsDialogComponent {
1897
2483
  this.eventDisplay
1898
2484
  .getInfoLogger()
1899
2485
  .add('Could not parse JSON event file. Please ensure it is valid JSON.', 'Error');
2486
+ this.notificationService.error('Could not parse JSON event file. Please ensure it is valid JSON.');
1900
2487
  console.error('Error parsing JSON event file:', error);
1901
2488
  }
1902
2489
  };
@@ -1915,6 +2502,7 @@ class IOOptionsDialogComponent {
1915
2502
  this.eventDisplay
1916
2503
  .getInfoLogger()
1917
2504
  .add('Could not parse EDM4HEP JSON file. Please ensure it is valid JSON.', 'Error');
2505
+ this.notificationService.error('Could not parse EDM4HEP JSON file. Please ensure it is valid JSON.');
1918
2506
  console.error('Error parsing EDM4HEP JSON file:', error);
1919
2507
  }
1920
2508
  };
@@ -2002,6 +2590,24 @@ class IOOptionsDialogComponent {
2002
2590
  this.eventDisplay
2003
2591
  .getInfoLogger()
2004
2592
  .add('Failed to load PHYSLITE file: ' + error.message, 'Error');
2593
+ this.notificationService.error('Failed to load PHYSLITE file: ' + error.message);
2594
+ }
2595
+ this.onClose();
2596
+ }
2597
+ async handleATLASESDInput(files) {
2598
+ if (!this.isFileOfExtension(files[0].name, 'root,root.1,pool.root,pool.root.1')) {
2599
+ return;
2600
+ }
2601
+ const loader = new ATLASESDLoader();
2602
+ try {
2603
+ const eventsData = await loader.getEventData(files[0]);
2604
+ this.eventDisplay.parsePhoenixEvents(eventsData);
2605
+ }
2606
+ catch (error) {
2607
+ this.eventDisplay
2608
+ .getInfoLogger()
2609
+ .add('Failed to load ATLAS ESD file: ' + error.message, 'Error');
2610
+ this.notificationService.error('Failed to load ATLAS ESD file: ' + error.message);
2005
2611
  }
2006
2612
  this.onClose();
2007
2613
  }
@@ -2026,6 +2632,7 @@ class IOOptionsDialogComponent {
2026
2632
  catch (error) {
2027
2633
  console.error('Error while reading zip', error);
2028
2634
  this.eventDisplay.getInfoLogger().add('Could not read zip file', 'Error');
2635
+ this.notificationService.error('Could not read zip file.');
2029
2636
  return;
2030
2637
  }
2031
2638
  // JSON event data
@@ -2059,6 +2666,7 @@ class IOOptionsDialogComponent {
2059
2666
  const errorMessage = `Failed to read file "${file.name}". The file may be corrupted, too large, or inaccessible.`;
2060
2667
  console.error('FileReader error:', reader.error);
2061
2668
  this.eventDisplay.getInfoLogger().add(errorMessage, 'Error');
2669
+ this.notificationService.error(errorMessage);
2062
2670
  };
2063
2671
  reader.readAsText(file);
2064
2672
  }
@@ -2078,6 +2686,7 @@ class IOOptionsDialogComponent {
2078
2686
  accepted;
2079
2687
  console.error('Error: ' + msg);
2080
2688
  this.eventDisplay.getInfoLogger().add(msg, 'Error');
2689
+ this.notificationService.error(msg);
2081
2690
  return false;
2082
2691
  }
2083
2692
  saveScene() {
@@ -2086,8 +2695,8 @@ class IOOptionsDialogComponent {
2086
2695
  exportOBJ() {
2087
2696
  this.eventDisplay.exportToOBJ();
2088
2697
  }
2089
- static ɵfac = function IOOptionsDialogComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || IOOptionsDialogComponent)(i0.ɵɵdirectiveInject(EventDisplayService), i0.ɵɵdirectiveInject(i1$2.MatDialogRef)); };
2090
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: IOOptionsDialogComponent, selectors: [["app-io-options-dialog"]], inputs: { eventDataImportOptions: "eventDataImportOptions" }, standalone: false, decls: 47, vars: 1, consts: [["objFileInput", ""], ["gltfFileInput", ""], ["rootFileInput", ""], ["rootJSONFileInput", ""], ["loadSceneInput", ""], ["eventDataFileInput", ""], [1, "dialog"], ["mat-dialog-title", ""], ["mat-dialog-content", "", 1, "dialog-content"], [4, "ngIf"], [1, "text-center"], [1, "row", "centered"], ["type", "file", "tabindex", "-1", "accept", ".obj", "name", "image", 1, "file-input", 3, "change"], [1, "file-input-button", 3, "click"], ["src", "assets/icons/obj.svg", "alt", "OBJ file format icon"], ["type", "file", "tabindex", "-1", "accept", ".gltf,.glb,.gltf.zip,.glb.zip", "name", "image", 1, "file-input", 3, "change"], ["src", "assets/icons/gltf.svg", "alt", "GLTF file format icon"], ["type", "file", "tabindex", "-1", "accept", ".root", 1, "file-input", 3, "change"], ["src", "assets/icons/file-import.svg", "alt", ""], ["type", "file", "tabindex", "-1", "accept", ".json.gz", 1, "file-input", 3, "change"], ["id", "exportScene", 1, "file-input-button", "load-export", 3, "click"], ["src", "assets/icons/save.svg", "alt", ""], ["type", "file", "tabindex", "-1", "accept", ".phnx", "name", "image", 1, "file-input", 3, "change"], ["id", "importScene", 1, "file-input-button", "load-export", 3, "click"], ["src", "assets/icons/upload.svg", "alt", ""], ["id", "exportOBJ", 1, "file-input-button", "export-button", 3, "click"], ["src", "assets/icons/obj.svg", "alt", ""], ["mat-dialog-actions", "", "align", "end"], ["mat-flat-button", "", "color", "primary", "cdkFocusInitial", "", 3, "click"], [4, "ngFor", "ngForOf"], ["type", "file", "tabindex", "-1", 1, "file-input", 3, "change", "accept"], ["src", "assets/icons/eventData.svg", "alt", "Event data icon"]], template: function IOOptionsDialogComponent_Template(rf, ctx) { if (rf & 1) {
2698
+ static ɵfac = function IOOptionsDialogComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || IOOptionsDialogComponent)(i0.ɵɵdirectiveInject(EventDisplayService), i0.ɵɵdirectiveInject(i1$1.MatDialogRef), i0.ɵɵdirectiveInject(NotificationService)); };
2699
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: IOOptionsDialogComponent, selectors: [["app-io-options-dialog"]], inputs: { eventDataImportOptions: "eventDataImportOptions" }, standalone: false, decls: 47, vars: 1, consts: [["objFileInput", ""], ["gltfFileInput", ""], ["rootFileInput", ""], ["rootJSONFileInput", ""], ["loadSceneInput", ""], ["eventDataFileInput", ""], [1, "dialog"], ["mat-dialog-title", ""], ["mat-dialog-content", "", 1, "dialog-content"], [4, "ngIf"], [1, "text-center"], [1, "row", "centered"], ["type", "file", "tabindex", "-1", "accept", ".obj", "name", "image", 1, "file-input", 3, "change"], [1, "file-input-button", 3, "click"], ["src", "assets/icons/obj.svg", "alt", "OBJ file format icon"], ["type", "file", "tabindex", "-1", "accept", ".gltf,.glb,.gltf.zip,.glb.zip", "name", "image", 1, "file-input", 3, "change"], ["src", "assets/icons/gltf.svg", "alt", "GLTF file format icon"], ["type", "file", "tabindex", "-1", "accept", ".root", 1, "file-input", 3, "change"], ["src", "assets/icons/file-import.svg", "alt", ""], ["type", "file", "tabindex", "-1", "accept", ".json.gz", 1, "file-input", 3, "change"], ["id", "exportScene", 1, "file-input-button", "load-export", 3, "click"], ["src", "assets/icons/save.svg", "alt", ""], ["type", "file", "tabindex", "-1", "accept", ".phnx", "name", "image", 1, "file-input", 3, "change"], ["id", "importScene", 1, "file-input-button", "load-export", 3, "click"], ["src", "assets/icons/upload.svg", "alt", ""], ["id", "exportOBJ", 1, "file-input-button", "export-button", 3, "click"], ["src", "assets/icons/obj.svg", "alt", ""], ["mat-dialog-actions", "", "align", "end"], ["mat-flat-button", "", "color", "primary", "cdkFocusInitial", "", 3, "click"], [4, "ngFor", "ngForOf"], ["type", "file", "tabindex", "-1", 1, "file-input", 3, "change", "accept"], [1, "item-icon"], ["href", "assets/icons/eventData.svg#eventData"]], template: function IOOptionsDialogComponent_Template(rf, ctx) { if (rf & 1) {
2091
2700
  const _r1 = i0.ɵɵgetCurrentView();
2092
2701
  i0.ɵɵelementStart(0, "div", 6)(1, "h1", 7);
2093
2702
  i0.ɵɵtext(2, "Import and export");
@@ -2157,15 +2766,15 @@ class IOOptionsDialogComponent {
2157
2766
  } if (rf & 2) {
2158
2767
  i0.ɵɵadvance(4);
2159
2768
  i0.ɵɵproperty("ngIf", ctx.eventDataImportOptions.length > 0);
2160
- } }, dependencies: [i2.NgForOf, i2.NgIf, i1$2.MatDialogTitle, i1$2.MatDialogActions, i1$2.MatDialogContent, i3.MatButton], styles: [".row[_ngcontent-%COMP%]{justify-content:center;margin:1rem 0}.file-input[_ngcontent-%COMP%]{width:.1px;height:.1px;opacity:0;overflow:hidden;position:absolute;z-index:-1}.file-input-button[_ngcontent-%COMP%]{font-size:1em;font-weight:700;color:#fff;background-color:#6eaece;padding:1em .5em;border:none;border-radius:10px;width:8rem;margin:0 .4rem}.file-input-button.load-export[_ngcontent-%COMP%]{padding:.8em .2em;width:7rem}.file-input-button.load-export[_ngcontent-%COMP%] img[_ngcontent-%COMP%]{max-height:1.2em}.file-input-button.export-button[_ngcontent-%COMP%]{background-color:#cb7133}.file-input-button.export-button[_ngcontent-%COMP%]:hover{background-color:#ad5b2d}.file-input-button[_ngcontent-%COMP%] img[_ngcontent-%COMP%]{max-height:2em;display:block;width:100%}.file-input-button[_ngcontent-%COMP%]:hover{background-color:#118ab2}#exportScene[_ngcontent-%COMP%]{background-color:#5bd99e}#exportScene[_ngcontent-%COMP%]:hover{background-color:#05c292}#importScene[_ngcontent-%COMP%]{background-color:#ecc25e}#importScene[_ngcontent-%COMP%]:hover{background-color:#d6b44d}"] });
2769
+ } }, dependencies: [i2.NgForOf, i2.NgIf, i1$1.MatDialogTitle, i1$1.MatDialogActions, i1$1.MatDialogContent, i3.MatButton], styles: [".row[_ngcontent-%COMP%]{justify-content:center;margin:1rem 0}.file-input[_ngcontent-%COMP%]{width:.1px;height:.1px;opacity:0;overflow:hidden;position:absolute;z-index:-1}.file-input-button[_ngcontent-%COMP%]{font-size:1em;font-weight:700;color:#fff;background-color:#6eaece;padding:1em .5em;border:none;border-radius:10px;width:8rem;margin:0 .4rem}.file-input-button.load-export[_ngcontent-%COMP%]{padding:.8em .2em;width:7rem}.file-input-button.load-export[_ngcontent-%COMP%] img[_ngcontent-%COMP%]{max-height:1.2em}.file-input-button.export-button[_ngcontent-%COMP%]{background-color:#cb7133}.file-input-button.export-button[_ngcontent-%COMP%]:hover{background-color:#ad5b2d}.file-input-button[_ngcontent-%COMP%] img[_ngcontent-%COMP%], .file-input-button[_ngcontent-%COMP%] svg[_ngcontent-%COMP%]{max-height:2em;display:block;width:100%}.file-input-button[_ngcontent-%COMP%]:hover{background-color:#118ab2}#exportScene[_ngcontent-%COMP%]{background-color:#5bd99e}#exportScene[_ngcontent-%COMP%]:hover{background-color:#05c292}#importScene[_ngcontent-%COMP%]{background-color:#ecc25e}#importScene[_ngcontent-%COMP%]:hover{background-color:#d6b44d}"] });
2161
2770
  }
2162
2771
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(IOOptionsDialogComponent, [{
2163
2772
  type: Component,
2164
- args: [{ standalone: false, selector: 'app-io-options-dialog', template: "<div class=\"dialog\">\n <h1 mat-dialog-title>Import and export</h1>\n <div mat-dialog-content class=\"dialog-content\">\n <div *ngIf=\"eventDataImportOptions.length > 0\">\n <p class=\"text-center\"><b>Event data</b></p>\n\n <div class=\"row centered\">\n <ng-container\n *ngFor=\"let eventDataImportOption of eventDataOptionsWithHandler\"\n >\n <input\n #eventDataFileInput\n type=\"file\"\n tabindex=\"-1\"\n class=\"file-input\"\n [accept]=\"eventDataImportOption.accept\"\n (change)=\"eventDataImportOption.handler($event.target.files)\"\n />\n <button\n class=\"file-input-button\"\n (click)=\"eventDataFileInput.click()\"\n >\n <img src=\"assets/icons/eventData.svg\" alt=\"Event data icon\" />\n Load {{ eventDataImportOption.fileType }}\n </button>\n </ng-container>\n </div>\n </div>\n\n <p class=\"text-center\"><b>Geometries</b></p>\n\n <div class=\"row centered\">\n <input\n #objFileInput\n type=\"file\"\n tabindex=\"-1\"\n class=\"file-input\"\n accept=\".obj\"\n name=\"image\"\n (change)=\"handleOBJInput($event.target.files)\"\n />\n <button class=\"file-input-button\" (click)=\"objFileInput.click()\">\n <img src=\"assets/icons/obj.svg\" alt=\"OBJ file format icon\" /> Load .obj\n </button>\n\n <input\n #gltfFileInput\n type=\"file\"\n tabindex=\"-1\"\n class=\"file-input\"\n accept=\".gltf,.glb,.gltf.zip,.glb.zip\"\n name=\"image\"\n (change)=\"handleGLTFInput($event.target.files)\"\n />\n <button class=\"file-input-button\" (click)=\"gltfFileInput.click()\">\n <img src=\"assets/icons/gltf.svg\" alt=\"GLTF file format icon\" /> Load\n .gltf/.glb\n </button>\n\n <input\n #rootFileInput\n type=\"file\"\n tabindex=\"-1\"\n class=\"file-input\"\n accept=\".root\"\n (change)=\"handleROOTInput($event.target.files)\"\n />\n <button class=\"file-input-button\" (click)=\"rootFileInput.click()\">\n <img src=\"assets/icons/file-import.svg\" alt=\"\" /> Load .root\n </button>\n\n <input\n #rootJSONFileInput\n type=\"file\"\n tabindex=\"-1\"\n class=\"file-input\"\n accept=\".json.gz\"\n (change)=\"handleRootJSONInput($event.target.files)\"\n />\n <button class=\"file-input-button\" (click)=\"rootJSONFileInput.click()\">\n <img src=\"assets/icons/file-import.svg\" alt=\"\" /> Load .json.gz\n </button>\n </div>\n\n <p class=\"text-center\"><b>Scene</b></p>\n\n <div class=\"row centered\">\n <button\n class=\"file-input-button load-export\"\n id=\"exportScene\"\n (click)=\"saveScene()\"\n >\n <img src=\"assets/icons/save.svg\" alt=\"\" /> Save scene\n </button>\n\n <input\n #loadSceneInput\n type=\"file\"\n tabindex=\"-1\"\n class=\"file-input\"\n accept=\".phnx\"\n name=\"image\"\n (change)=\"handlePhoenixInput($event.target.files)\"\n />\n <button\n class=\"file-input-button load-export\"\n id=\"importScene\"\n (click)=\"loadSceneInput.click()\"\n >\n <img src=\"assets/icons/upload.svg\" alt=\"\" /> Load scene\n </button>\n\n <button\n class=\"file-input-button export-button\"\n id=\"exportOBJ\"\n (click)=\"exportOBJ()\"\n >\n <img src=\"assets/icons/obj.svg\" alt=\"\" /> Save OBJ\n </button>\n </div>\n </div>\n\n <div mat-dialog-actions align=\"end\">\n <button mat-flat-button color=\"primary\" (click)=\"onClose()\" cdkFocusInitial>\n Close\n </button>\n </div>\n</div>\n", styles: [".row{justify-content:center;margin:1rem 0}.file-input{width:.1px;height:.1px;opacity:0;overflow:hidden;position:absolute;z-index:-1}.file-input-button{font-size:1em;font-weight:700;color:#fff;background-color:#6eaece;padding:1em .5em;border:none;border-radius:10px;width:8rem;margin:0 .4rem}.file-input-button.load-export{padding:.8em .2em;width:7rem}.file-input-button.load-export img{max-height:1.2em}.file-input-button.export-button{background-color:#cb7133}.file-input-button.export-button:hover{background-color:#ad5b2d}.file-input-button img{max-height:2em;display:block;width:100%}.file-input-button:hover{background-color:#118ab2}#exportScene{background-color:#5bd99e}#exportScene:hover{background-color:#05c292}#importScene{background-color:#ecc25e}#importScene:hover{background-color:#d6b44d}\n"] }]
2165
- }], () => [{ type: EventDisplayService }, { type: i1$2.MatDialogRef }], { eventDataImportOptions: [{
2773
+ args: [{ standalone: false, selector: 'app-io-options-dialog', template: "<div class=\"dialog\">\n <h1 mat-dialog-title>Import and export</h1>\n <div mat-dialog-content class=\"dialog-content\">\n <div *ngIf=\"eventDataImportOptions.length > 0\">\n <p class=\"text-center\"><b>Event data</b></p>\n\n <div class=\"row centered\">\n <ng-container\n *ngFor=\"let eventDataImportOption of eventDataOptionsWithHandler\"\n >\n <input\n #eventDataFileInput\n type=\"file\"\n tabindex=\"-1\"\n class=\"file-input\"\n [accept]=\"eventDataImportOption.accept\"\n (change)=\"eventDataImportOption.handler($event.target.files)\"\n />\n <button\n class=\"file-input-button\"\n (click)=\"eventDataFileInput.click()\"\n >\n <svg class=\"item-icon\">\n <use href=\"assets/icons/eventData.svg#eventData\"></use>\n </svg>\n Load {{ eventDataImportOption.fileType }}\n </button>\n </ng-container>\n </div>\n </div>\n\n <p class=\"text-center\"><b>Geometries</b></p>\n\n <div class=\"row centered\">\n <input\n #objFileInput\n type=\"file\"\n tabindex=\"-1\"\n class=\"file-input\"\n accept=\".obj\"\n name=\"image\"\n (change)=\"handleOBJInput($event.target.files)\"\n />\n <button class=\"file-input-button\" (click)=\"objFileInput.click()\">\n <img src=\"assets/icons/obj.svg\" alt=\"OBJ file format icon\" /> Load .obj\n </button>\n\n <input\n #gltfFileInput\n type=\"file\"\n tabindex=\"-1\"\n class=\"file-input\"\n accept=\".gltf,.glb,.gltf.zip,.glb.zip\"\n name=\"image\"\n (change)=\"handleGLTFInput($event.target.files)\"\n />\n <button class=\"file-input-button\" (click)=\"gltfFileInput.click()\">\n <img src=\"assets/icons/gltf.svg\" alt=\"GLTF file format icon\" /> Load\n .gltf/.glb\n </button>\n\n <input\n #rootFileInput\n type=\"file\"\n tabindex=\"-1\"\n class=\"file-input\"\n accept=\".root\"\n (change)=\"handleROOTInput($event.target.files)\"\n />\n <button class=\"file-input-button\" (click)=\"rootFileInput.click()\">\n <img src=\"assets/icons/file-import.svg\" alt=\"\" /> Load .root\n </button>\n\n <input\n #rootJSONFileInput\n type=\"file\"\n tabindex=\"-1\"\n class=\"file-input\"\n accept=\".json.gz\"\n (change)=\"handleRootJSONInput($event.target.files)\"\n />\n <button class=\"file-input-button\" (click)=\"rootJSONFileInput.click()\">\n <img src=\"assets/icons/file-import.svg\" alt=\"\" /> Load .json.gz\n </button>\n </div>\n\n <p class=\"text-center\"><b>Scene</b></p>\n\n <div class=\"row centered\">\n <button\n class=\"file-input-button load-export\"\n id=\"exportScene\"\n (click)=\"saveScene()\"\n >\n <img src=\"assets/icons/save.svg\" alt=\"\" /> Save scene\n </button>\n\n <input\n #loadSceneInput\n type=\"file\"\n tabindex=\"-1\"\n class=\"file-input\"\n accept=\".phnx\"\n name=\"image\"\n (change)=\"handlePhoenixInput($event.target.files)\"\n />\n <button\n class=\"file-input-button load-export\"\n id=\"importScene\"\n (click)=\"loadSceneInput.click()\"\n >\n <img src=\"assets/icons/upload.svg\" alt=\"\" /> Load scene\n </button>\n\n <button\n class=\"file-input-button export-button\"\n id=\"exportOBJ\"\n (click)=\"exportOBJ()\"\n >\n <img src=\"assets/icons/obj.svg\" alt=\"\" /> Save OBJ\n </button>\n </div>\n </div>\n\n <div mat-dialog-actions align=\"end\">\n <button mat-flat-button color=\"primary\" (click)=\"onClose()\" cdkFocusInitial>\n Close\n </button>\n </div>\n</div>\n", styles: [".row{justify-content:center;margin:1rem 0}.file-input{width:.1px;height:.1px;opacity:0;overflow:hidden;position:absolute;z-index:-1}.file-input-button{font-size:1em;font-weight:700;color:#fff;background-color:#6eaece;padding:1em .5em;border:none;border-radius:10px;width:8rem;margin:0 .4rem}.file-input-button.load-export{padding:.8em .2em;width:7rem}.file-input-button.load-export img{max-height:1.2em}.file-input-button.export-button{background-color:#cb7133}.file-input-button.export-button:hover{background-color:#ad5b2d}.file-input-button img,.file-input-button svg{max-height:2em;display:block;width:100%}.file-input-button:hover{background-color:#118ab2}#exportScene{background-color:#5bd99e}#exportScene:hover{background-color:#05c292}#importScene{background-color:#ecc25e}#importScene:hover{background-color:#d6b44d}\n"] }]
2774
+ }], () => [{ type: EventDisplayService }, { type: i1$1.MatDialogRef }, { type: NotificationService }], { eventDataImportOptions: [{
2166
2775
  type: Input
2167
2776
  }] }); })();
2168
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(IOOptionsDialogComponent, { className: "IOOptionsDialogComponent", filePath: "components/ui-menu/io-options/io-options-dialog/io-options-dialog.component.ts", lineNumber: 23 }); })();
2777
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(IOOptionsDialogComponent, { className: "IOOptionsDialogComponent", filePath: "components/ui-menu/io-options/io-options-dialog/io-options-dialog.component.ts", lineNumber: 25 }); })();
2169
2778
 
2170
2779
  class IoOptionsComponent {
2171
2780
  dialog;
@@ -2180,7 +2789,7 @@ class IoOptionsComponent {
2180
2789
  dialogRef.componentInstance.eventDataImportOptions =
2181
2790
  this.eventDataImportOptions;
2182
2791
  }
2183
- static ɵfac = function IoOptionsComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || IoOptionsComponent)(i0.ɵɵdirectiveInject(i1$2.MatDialog)); };
2792
+ static ɵfac = function IoOptionsComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || IoOptionsComponent)(i0.ɵɵdirectiveInject(i1$1.MatDialog)); };
2184
2793
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: IoOptionsComponent, selectors: [["app-io-options"]], inputs: { eventDataImportOptions: "eventDataImportOptions" }, standalone: false, decls: 1, vars: 1, consts: [["tooltip", "Import and export options", "icon", "import", 3, "click", "active"]], template: function IoOptionsComponent_Template(rf, ctx) { if (rf & 1) {
2185
2794
  i0.ɵɵelementStart(0, "app-menu-toggle", 0);
2186
2795
  i0.ɵɵlistener("click", function IoOptionsComponent_Template_app_menu_toggle_click_0_listener() { return ctx.openIODialog(); });
@@ -2192,7 +2801,7 @@ class IoOptionsComponent {
2192
2801
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(IoOptionsComponent, [{
2193
2802
  type: Component,
2194
2803
  args: [{ standalone: false, selector: 'app-io-options', template: "<app-menu-toggle\n tooltip=\"Import and export options\"\n icon=\"import\"\n [active]=\"false\"\n (click)=\"openIODialog()\"\n>\n</app-menu-toggle>\n" }]
2195
- }], () => [{ type: i1$2.MatDialog }], { eventDataImportOptions: [{
2804
+ }], () => [{ type: i1$1.MatDialog }], { eventDataImportOptions: [{
2196
2805
  type: Input
2197
2806
  }] }); })();
2198
2807
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(IoOptionsComponent, { className: "IoOptionsComponent", filePath: "components/ui-menu/io-options/io-options.component.ts", lineNumber: 15 }); })();
@@ -2253,44 +2862,56 @@ class ObjectClippingComponent {
2253
2862
  this.clippingEnabled = value;
2254
2863
  }
2255
2864
  static ɵfac = function ObjectClippingComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ObjectClippingComponent)(i0.ɵɵdirectiveInject(EventDisplayService)); };
2256
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ObjectClippingComponent, selectors: [["app-object-clipping"]], standalone: false, decls: 17, vars: 5, consts: [["menu", ""], ["clippingCheckbox", ""], ["startingAngleSlider", ""], ["openingAngleSlider", ""], [1, "mat-menu"], ["mat-menu-item", "", 3, "click"], [3, "click", "change", "checked"], ["mat-menu-item", "", 1, "slider-btn", 3, "focus"], ["min", "0", "max", "360", "step", "1", "thumbLabel", ""], ["matSliderThumb", "", 3, "valueChange", "value"], ["tooltip", "Geometry clipping", "icon", "clipping", 3, "matMenuTriggerFor", "active"]], template: function ObjectClippingComponent_Template(rf, ctx) { if (rf & 1) {
2865
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ObjectClippingComponent, selectors: [["app-object-clipping"]], standalone: false, decls: 23, vars: 7, consts: [["menu", ""], ["clippingCheckbox", ""], ["startingAngleSlider", ""], ["startAngleInput", ""], ["openingAngleSlider", ""], ["openingAngleInput", ""], [1, "mat-menu"], ["mat-menu-item", "", 3, "click"], [3, "click", "change", "checked"], [1, "angle-label"], ["mat-menu-item", "", 1, "slider-btn", 3, "click", "focus"], ["min", "0", "max", "360", "step", "1", "thumbLabel", ""], ["matSliderThumb", "", 3, "valueChange", "value"], ["type", "number", "min", "0", "max", "360", "step", "1", 1, "angle-input", 3, "click", "keydown", "change", "value"], ["tooltip", "Geometry clipping", "icon", "clipping", 3, "matMenuTriggerFor", "active"]], template: function ObjectClippingComponent_Template(rf, ctx) { if (rf & 1) {
2257
2866
  const _r1 = i0.ɵɵgetCurrentView();
2258
- i0.ɵɵelementStart(0, "mat-menu", 4, 0)(2, "button", 5);
2867
+ i0.ɵɵelementStart(0, "mat-menu", 6, 0)(2, "button", 7);
2259
2868
  i0.ɵɵlistener("click", function ObjectClippingComponent_Template_button_click_2_listener($event) { i0.ɵɵrestoreView(_r1); const clippingCheckbox_r2 = i0.ɵɵreference(4); $event.stopPropagation(); return i0.ɵɵresetView(clippingCheckbox_r2._inputElement.nativeElement.click()); });
2260
- i0.ɵɵelementStart(3, "mat-checkbox", 6, 1);
2869
+ i0.ɵɵelementStart(3, "mat-checkbox", 8, 1);
2261
2870
  i0.ɵɵlistener("click", function ObjectClippingComponent_Template_mat_checkbox_click_3_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView($event.stopPropagation()); })("change", function ObjectClippingComponent_Template_mat_checkbox_change_3_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.toggleClipping($event)); });
2262
- i0.ɵɵtext(5, " Clipping ");
2871
+ i0.ɵɵtext(5, " Clipping Enabled ");
2872
+ i0.ɵɵelementEnd()();
2873
+ i0.ɵɵelementStart(6, "div", 9);
2874
+ i0.ɵɵtext(7, "Start Angle");
2875
+ i0.ɵɵelementEnd();
2876
+ i0.ɵɵelementStart(8, "button", 10);
2877
+ i0.ɵɵlistener("click", function ObjectClippingComponent_Template_button_click_8_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView($event.stopPropagation()); })("focus", function ObjectClippingComponent_Template_button_focus_8_listener() { i0.ɵɵrestoreView(_r1); const startingAngleSlider_r3 = i0.ɵɵreference(11); return i0.ɵɵresetView(startingAngleSlider_r3.focus()); });
2878
+ i0.ɵɵelementStart(9, "mat-slider", 11)(10, "input", 12, 2);
2879
+ i0.ɵɵlistener("valueChange", function ObjectClippingComponent_Template_input_valueChange_10_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.changeStartClippingAngle($event)); });
2263
2880
  i0.ɵɵelementEnd()();
2264
- i0.ɵɵelementStart(6, "button", 7);
2265
- i0.ɵɵlistener("focus", function ObjectClippingComponent_Template_button_focus_6_listener() { i0.ɵɵrestoreView(_r1); const startingAngleSlider_r3 = i0.ɵɵreference(9); return i0.ɵɵresetView(startingAngleSlider_r3.focus()); });
2266
- i0.ɵɵelementStart(7, "mat-slider", 8)(8, "input", 9, 2);
2267
- i0.ɵɵlistener("valueChange", function ObjectClippingComponent_Template_input_valueChange_8_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.changeStartClippingAngle($event)); });
2881
+ i0.ɵɵelementStart(12, "input", 13, 3);
2882
+ i0.ɵɵlistener("click", function ObjectClippingComponent_Template_input_click_12_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView($event.stopPropagation()); })("keydown", function ObjectClippingComponent_Template_input_keydown_12_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView($event.stopPropagation()); })("change", function ObjectClippingComponent_Template_input_change_12_listener() { i0.ɵɵrestoreView(_r1); const startAngleInput_r4 = i0.ɵɵreference(13); return i0.ɵɵresetView(ctx.changeStartClippingAngle(startAngleInput_r4.valueAsNumber)); });
2268
2883
  i0.ɵɵelementEnd()();
2269
- i0.ɵɵtext(10, " Start Angle ");
2884
+ i0.ɵɵelementStart(14, "div", 9);
2885
+ i0.ɵɵtext(15, "Opening Angle");
2270
2886
  i0.ɵɵelementEnd();
2271
- i0.ɵɵelementStart(11, "button", 7);
2272
- i0.ɵɵlistener("focus", function ObjectClippingComponent_Template_button_focus_11_listener() { i0.ɵɵrestoreView(_r1); const openingAngleSlider_r4 = i0.ɵɵreference(14); return i0.ɵɵresetView(openingAngleSlider_r4.focus()); });
2273
- i0.ɵɵelementStart(12, "mat-slider", 8)(13, "input", 9, 3);
2274
- i0.ɵɵlistener("valueChange", function ObjectClippingComponent_Template_input_valueChange_13_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.changeOpeningClippingAngle($event)); });
2887
+ i0.ɵɵelementStart(16, "button", 10);
2888
+ i0.ɵɵlistener("click", function ObjectClippingComponent_Template_button_click_16_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView($event.stopPropagation()); })("focus", function ObjectClippingComponent_Template_button_focus_16_listener() { i0.ɵɵrestoreView(_r1); const openingAngleSlider_r5 = i0.ɵɵreference(19); return i0.ɵɵresetView(openingAngleSlider_r5.focus()); });
2889
+ i0.ɵɵelementStart(17, "mat-slider", 11)(18, "input", 12, 4);
2890
+ i0.ɵɵlistener("valueChange", function ObjectClippingComponent_Template_input_valueChange_18_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView(ctx.changeOpeningClippingAngle($event)); });
2275
2891
  i0.ɵɵelementEnd()();
2276
- i0.ɵɵtext(15, " Opening Angle ");
2277
- i0.ɵɵelementEnd()();
2278
- i0.ɵɵelement(16, "app-menu-toggle", 10);
2892
+ i0.ɵɵelementStart(20, "input", 13, 5);
2893
+ i0.ɵɵlistener("click", function ObjectClippingComponent_Template_input_click_20_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView($event.stopPropagation()); })("keydown", function ObjectClippingComponent_Template_input_keydown_20_listener($event) { i0.ɵɵrestoreView(_r1); return i0.ɵɵresetView($event.stopPropagation()); })("change", function ObjectClippingComponent_Template_input_change_20_listener() { i0.ɵɵrestoreView(_r1); const openingAngleInput_r6 = i0.ɵɵreference(21); return i0.ɵɵresetView(ctx.changeOpeningClippingAngle(openingAngleInput_r6.valueAsNumber)); });
2894
+ i0.ɵɵelementEnd()()();
2895
+ i0.ɵɵelement(22, "app-menu-toggle", 14);
2279
2896
  } if (rf & 2) {
2280
- const menu_r5 = i0.ɵɵreference(1);
2897
+ const menu_r7 = i0.ɵɵreference(1);
2281
2898
  i0.ɵɵadvance(3);
2282
2899
  i0.ɵɵproperty("checked", ctx.clippingEnabled);
2283
- i0.ɵɵadvance(5);
2900
+ i0.ɵɵadvance(7);
2284
2901
  i0.ɵɵproperty("value", ctx.startClippingAngle);
2285
- i0.ɵɵadvance(5);
2902
+ i0.ɵɵadvance(2);
2903
+ i0.ɵɵproperty("value", ctx.startClippingAngle);
2904
+ i0.ɵɵadvance(6);
2286
2905
  i0.ɵɵproperty("value", ctx.openingClippingAngle);
2287
- i0.ɵɵadvance(3);
2288
- i0.ɵɵproperty("matMenuTriggerFor", menu_r5)("active", ctx.clippingEnabled);
2289
- } }, dependencies: [i3$2.MatMenu, i3$2.MatMenuItem, i3$2.MatMenuTrigger, i2$1.MatSlider, i2$1.MatSliderThumb, i5.MatCheckbox, MenuToggleComponent], styles: [".slider-btn[_ngcontent-%COMP%]{overflow:visible}mat-slider[_ngcontent-%COMP%]{margin-left:.75rem;margin-right:.75rem}"] });
2906
+ i0.ɵɵadvance(2);
2907
+ i0.ɵɵproperty("value", ctx.openingClippingAngle);
2908
+ i0.ɵɵadvance(2);
2909
+ i0.ɵɵproperty("matMenuTriggerFor", menu_r7)("active", ctx.clippingEnabled);
2910
+ } }, dependencies: [i4$2.MatMenu, i4$2.MatMenuItem, i4$2.MatMenuTrigger, i2$1.MatSlider, i2$1.MatSliderThumb, i5.MatCheckbox, MenuToggleComponent], styles: [".slider-btn[_ngcontent-%COMP%]{overflow:visible}.angle-label[_ngcontent-%COMP%]{padding:.5rem 1rem 0;font-size:.75rem;opacity:.6}mat-slider[_ngcontent-%COMP%]{margin-left:.75rem;margin-right:.75rem}.angle-input[_ngcontent-%COMP%]{width:4.5rem;margin-right:.5rem;padding:.25rem .35rem;text-align:right;box-sizing:border-box}"] });
2290
2911
  }
2291
2912
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ObjectClippingComponent, [{
2292
2913
  type: Component,
2293
- args: [{ standalone: false, selector: 'app-object-clipping', template: "<mat-menu class=\"mat-menu\" #menu>\n <button\n mat-menu-item\n (click)=\"\n $event.stopPropagation();\n clippingCheckbox._inputElement.nativeElement.click()\n \"\n >\n <mat-checkbox\n #clippingCheckbox\n [checked]=\"clippingEnabled\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleClipping($event)\"\n >\n Clipping\n </mat-checkbox>\n </button>\n <button\n class=\"slider-btn\"\n mat-menu-item\n (focus)=\"startingAngleSlider.focus()\"\n >\n <mat-slider min=\"0\" max=\"360\" step=\"1\" thumbLabel>\n <input\n #startingAngleSlider\n matSliderThumb\n [value]=\"startClippingAngle\"\n (valueChange)=\"changeStartClippingAngle($event)\"\n />\n </mat-slider>\n Start Angle\n </button>\n <button class=\"slider-btn\" mat-menu-item (focus)=\"openingAngleSlider.focus()\">\n <mat-slider min=\"0\" max=\"360\" step=\"1\" thumbLabel>\n <input\n #openingAngleSlider\n matSliderThumb\n [value]=\"openingClippingAngle\"\n (valueChange)=\"changeOpeningClippingAngle($event)\"\n />\n </mat-slider>\n Opening Angle\n </button>\n</mat-menu>\n\n<app-menu-toggle\n [matMenuTriggerFor]=\"menu\"\n tooltip=\"Geometry clipping\"\n icon=\"clipping\"\n [active]=\"clippingEnabled\"\n>\n</app-menu-toggle>\n", styles: [".slider-btn{overflow:visible}mat-slider{margin-left:.75rem;margin-right:.75rem}\n"] }]
2914
+ args: [{ standalone: false, selector: 'app-object-clipping', template: "<mat-menu class=\"mat-menu\" #menu>\n <button\n mat-menu-item\n (click)=\"\n $event.stopPropagation();\n clippingCheckbox._inputElement.nativeElement.click()\n \"\n >\n <mat-checkbox\n #clippingCheckbox\n [checked]=\"clippingEnabled\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleClipping($event)\"\n >\n Clipping Enabled\n </mat-checkbox>\n </button>\n <div class=\"angle-label\">Start Angle</div>\n <button\n class=\"slider-btn\"\n mat-menu-item\n (click)=\"$event.stopPropagation()\"\n (focus)=\"startingAngleSlider.focus()\"\n >\n <mat-slider min=\"0\" max=\"360\" step=\"1\" thumbLabel>\n <input\n #startingAngleSlider\n matSliderThumb\n [value]=\"startClippingAngle\"\n (valueChange)=\"changeStartClippingAngle($event)\"\n />\n </mat-slider>\n <input\n #startAngleInput\n class=\"angle-input\"\n type=\"number\"\n min=\"0\"\n max=\"360\"\n step=\"1\"\n [value]=\"startClippingAngle\"\n (click)=\"$event.stopPropagation()\"\n (keydown)=\"$event.stopPropagation()\"\n (change)=\"changeStartClippingAngle(startAngleInput.valueAsNumber)\"\n />\n </button>\n\n <div class=\"angle-label\">Opening Angle</div>\n <button\n class=\"slider-btn\"\n mat-menu-item\n (click)=\"$event.stopPropagation()\"\n (focus)=\"openingAngleSlider.focus()\"\n >\n <mat-slider min=\"0\" max=\"360\" step=\"1\" thumbLabel>\n <input\n #openingAngleSlider\n matSliderThumb\n [value]=\"openingClippingAngle\"\n (valueChange)=\"changeOpeningClippingAngle($event)\"\n />\n </mat-slider>\n <input\n #openingAngleInput\n class=\"angle-input\"\n type=\"number\"\n min=\"0\"\n max=\"360\"\n step=\"1\"\n [value]=\"openingClippingAngle\"\n (click)=\"$event.stopPropagation()\"\n (keydown)=\"$event.stopPropagation()\"\n (change)=\"changeOpeningClippingAngle(openingAngleInput.valueAsNumber)\"\n />\n </button>\n</mat-menu>\n\n<app-menu-toggle\n [matMenuTriggerFor]=\"menu\"\n tooltip=\"Geometry clipping\"\n icon=\"clipping\"\n [active]=\"clippingEnabled\"\n>\n</app-menu-toggle>\n", styles: [".slider-btn{overflow:visible}.angle-label{padding:.5rem 1rem 0;font-size:.75rem;opacity:.6}mat-slider{margin-left:.75rem;margin-right:.75rem}.angle-input{width:4.5rem;margin-right:.5rem;padding:.25rem .35rem;text-align:right;box-sizing:border-box}\n"] }]
2294
2915
  }], () => [{ type: EventDisplayService }], null); })();
2295
2916
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ObjectClippingComponent, { className: "ObjectClippingComponent", filePath: "components/ui-menu/object-clipping/object-clipping.component.ts", lineNumber: 11 }); })();
2296
2917
 
@@ -2402,7 +3023,7 @@ class ObjectSelectionComponent {
2402
3023
  this.overlayWindow.instance.hiddenSelectedInfo = this.hiddenSelectedInfo;
2403
3024
  this.eventDisplay.enableSelecting(!this.hiddenSelectedInfo);
2404
3025
  }
2405
- static ɵfac = function ObjectSelectionComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ObjectSelectionComponent)(i0.ɵɵdirectiveInject(i1$1.Overlay), i0.ɵɵdirectiveInject(EventDisplayService)); };
3026
+ static ɵfac = function ObjectSelectionComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ObjectSelectionComponent)(i0.ɵɵdirectiveInject(i1$3.Overlay), i0.ɵɵdirectiveInject(EventDisplayService)); };
2406
3027
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ObjectSelectionComponent, selectors: [["app-object-selection"]], standalone: false, decls: 1, vars: 1, consts: [["tooltip", "Object selection", "icon", "cursor", 3, "click", "active"]], template: function ObjectSelectionComponent_Template(rf, ctx) { if (rf & 1) {
2407
3028
  i0.ɵɵelementStart(0, "app-menu-toggle", 0);
2408
3029
  i0.ɵɵlistener("click", function ObjectSelectionComponent_Template_app_menu_toggle_click_0_listener() { return ctx.toggleOverlay(); });
@@ -2414,7 +3035,7 @@ class ObjectSelectionComponent {
2414
3035
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ObjectSelectionComponent, [{
2415
3036
  type: Component,
2416
3037
  args: [{ standalone: false, selector: 'app-object-selection', template: "<app-menu-toggle\n tooltip=\"Object selection\"\n icon=\"cursor\"\n [active]=\"!hiddenSelectedInfo\"\n (click)=\"toggleOverlay()\"\n>\n</app-menu-toggle>\n" }]
2417
- }], () => [{ type: i1$1.Overlay }, { type: EventDisplayService }], null); })();
3038
+ }], () => [{ type: i1$3.Overlay }, { type: EventDisplayService }], null); })();
2418
3039
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ObjectSelectionComponent, { className: "ObjectSelectionComponent", filePath: "components/ui-menu/object-selection/object-selection.component.ts", lineNumber: 18 }); })();
2419
3040
 
2420
3041
  const _c0$9 = ["overlayWindow"];
@@ -2542,7 +3163,7 @@ class OverlayViewComponent {
2542
3163
  this.showOverlay = !this.showOverlay;
2543
3164
  this.overlayWindow.instance.showOverlay = this.showOverlay;
2544
3165
  }
2545
- static ɵfac = function OverlayViewComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || OverlayViewComponent)(i0.ɵɵdirectiveInject(i1$1.Overlay)); };
3166
+ static ɵfac = function OverlayViewComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || OverlayViewComponent)(i0.ɵɵdirectiveInject(i1$3.Overlay)); };
2546
3167
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: OverlayViewComponent, selectors: [["app-overlay-view"]], standalone: false, decls: 1, vars: 1, consts: [["tooltip", "Overlay view", "icon", "overlay", 3, "click", "active"]], template: function OverlayViewComponent_Template(rf, ctx) { if (rf & 1) {
2547
3168
  i0.ɵɵelementStart(0, "app-menu-toggle", 0);
2548
3169
  i0.ɵɵlistener("click", function OverlayViewComponent_Template_app_menu_toggle_click_0_listener() { return ctx.toggleOverlay(); });
@@ -2554,7 +3175,7 @@ class OverlayViewComponent {
2554
3175
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(OverlayViewComponent, [{
2555
3176
  type: Component,
2556
3177
  args: [{ standalone: false, selector: 'app-overlay-view', template: "<app-menu-toggle\n tooltip=\"Overlay view\"\n icon=\"overlay\"\n [active]=\"showOverlay\"\n (click)=\"toggleOverlay()\"\n>\n</app-menu-toggle>\n" }]
2557
- }], () => [{ type: i1$1.Overlay }], null); })();
3178
+ }], () => [{ type: i1$3.Overlay }], null); })();
2558
3179
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(OverlayViewComponent, { className: "OverlayViewComponent", filePath: "components/ui-menu/overlay-view/overlay-view.component.ts", lineNumber: 17 }); })();
2559
3180
 
2560
3181
  const _c0$8 = a0 => ({ visible: a0 });
@@ -2632,7 +3253,7 @@ class TreeMenuItemComponent {
2632
3253
  i0.ɵɵtemplate(0, TreeMenuItemComponent_ng_container_0_Template, 8, 7, "ng-container", 0);
2633
3254
  } if (rf & 2) {
2634
3255
  i0.ɵɵproperty("ngIf", ctx.node);
2635
- } }, dependencies: [i2.NgClass, i2.NgForOf, i2.NgIf, i3.MatIconButton, i4$2.MatIcon, TreeMenuItemComponent], styles: [".header[_ngcontent-%COMP%]{cursor:pointer;user-select:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;display:flex;flex-direction:row;align-items:center}.header[_ngcontent-%COMP%] .node-name[_ngcontent-%COMP%], .header[_ngcontent-%COMP%] .mat-icon-rtl-mirror[_ngcontent-%COMP%]{color:var(--phoenix-text-color-secondary)}.header.visible[_ngcontent-%COMP%] .node-name[_ngcontent-%COMP%], .header.visible[_ngcontent-%COMP%] .mat-icon-rtl-mirror[_ngcontent-%COMP%]{color:var(--phoenix-accent)}.children[_ngcontent-%COMP%] li[_ngcontent-%COMP%]{list-style-type:none}"] });
3256
+ } }, dependencies: [i2.NgClass, i2.NgForOf, i2.NgIf, i3.MatIconButton, i2$2.MatIcon, TreeMenuItemComponent], styles: [".header[_ngcontent-%COMP%]{cursor:pointer;user-select:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;display:flex;flex-direction:row;align-items:center}.header[_ngcontent-%COMP%] .node-name[_ngcontent-%COMP%], .header[_ngcontent-%COMP%] .mat-icon-rtl-mirror[_ngcontent-%COMP%]{color:var(--phoenix-text-color-secondary)}.header.visible[_ngcontent-%COMP%] .node-name[_ngcontent-%COMP%], .header.visible[_ngcontent-%COMP%] .mat-icon-rtl-mirror[_ngcontent-%COMP%]{color:var(--phoenix-accent)}.children[_ngcontent-%COMP%] li[_ngcontent-%COMP%]{list-style-type:none}"] });
2636
3257
  }
2637
3258
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(TreeMenuItemComponent, [{
2638
3259
  type: Component,
@@ -2818,7 +3439,7 @@ class CartesianGridConfigComponent {
2818
3439
  calcPlanes(dis) {
2819
3440
  return Math.max(0, 1 + 2 * Math.floor((dis * 10) / (this.scale * this.gridConfig.sparsity)));
2820
3441
  }
2821
- static ɵfac = function CartesianGridConfigComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || CartesianGridConfigComponent)(i0.ɵɵdirectiveInject(MAT_DIALOG_DATA), i0.ɵɵdirectiveInject(i1$2.MatDialogRef), i0.ɵɵdirectiveInject(EventDisplayService)); };
3442
+ static ɵfac = function CartesianGridConfigComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || CartesianGridConfigComponent)(i0.ɵɵdirectiveInject(MAT_DIALOG_DATA), i0.ɵɵdirectiveInject(i1$1.MatDialogRef), i0.ɵɵdirectiveInject(EventDisplayService)); };
2822
3443
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: CartesianGridConfigComponent, selectors: [["app-cartesian-grid-config"]], standalone: false, decls: 65, vars: 28, consts: [["xPos", ""], ["yPos", ""], ["zPos", ""], ["showXYPlanesCheckbox", ""], ["xyPlaneSlider", ""], ["showYZPlanesCheckbox", ""], ["yzPlaneSlider", ""], ["showZXPlanesCheckbox", ""], ["zxPlaneSlider", ""], ["sparsitySlider", ""], ["mat-dialog-title", ""], ["mat-dialog-content", "", 1, "container", "dialog-content"], [1, "item-config-single"], [1, "item-config-group"], ["for", "xPos", 1, "item-config-label"], ["type", "number", "placeholder", "Origin X", "name", "xPos", "id", "xPos", 1, "form-control", 3, "value"], ["for", "yPos", 1, "item-config-label"], ["type", "number", "placeholder", "Origin Y", "name", "yPos", "id", "yPos", 1, "form-control", 3, "value"], ["for", "zPos", 1, "item-config-label"], ["type", "number", "placeholder", "Origin Z", "name", "zPos", "id", "zPos", 1, "form-control", 3, "value"], ["mat-stroked-button", "", 3, "click", "disabled"], ["mat-menu-item", "", 1, "explain-button", 2, "margin", "0.5rem 0", 3, "click", "disabled"], [1, "explain-text"], ["mat-menu-item", "", 3, "click"], [3, "ngModelChange", "click", "change", "ngModel"], ["mat-menu-item", "", 1, "slider-btn", 3, "focus"], ["min", "-300", "step", "300", "thumbLabel", "", 3, "max"], ["matSliderThumb", "", 3, "input", "value"], ["min", "1", "max", "5", "step", "1", "thumbLabel", ""], ["mat-dialog-actions", "", "align", "end"], ["mat-flat-button", "", "color", "primary", "cdkFocusInitial", "", 3, "click"]], template: function CartesianGridConfigComponent_Template(rf, ctx) { if (rf & 1) {
2823
3444
  const _r1 = i0.ɵɵgetCurrentView();
2824
3445
  i0.ɵɵelementStart(0, "div")(1, "h1", 10);
@@ -2944,7 +3565,7 @@ class CartesianGridConfigComponent {
2944
3565
  i0.ɵɵproperty("value", ctx.gridConfig.sparsity);
2945
3566
  i0.ɵɵadvance(2);
2946
3567
  i0.ɵɵtextInterpolate1(" Sparsity (", ctx.gridConfig.sparsity, ") ");
2947
- } }, dependencies: [i1$2.MatDialogTitle, i1$2.MatDialogActions, i1$2.MatDialogContent, i3.MatButton, i4.NgControlStatus, i4.NgModel, i3$2.MatMenuItem, i2$1.MatSlider, i2$1.MatSliderThumb, i5.MatCheckbox, i2.DecimalPipe], styles: [".container[_ngcontent-%COMP%]{display:flex;flex-direction:row}.item-config-single[_ngcontent-%COMP%]{display:flex;flex-direction:column}.item-config-single[_ngcontent-%COMP%] .item-config-group[_ngcontent-%COMP%]{margin:.1rem 2rem}.item-config-single[_ngcontent-%COMP%] .item-config-group[_ngcontent-%COMP%] .item-config-label[_ngcontent-%COMP%]{display:inline;margin:1rem}.item-config-single[_ngcontent-%COMP%] .item-config-group[_ngcontent-%COMP%] .form-control[_ngcontent-%COMP%]{width:60%;display:inline}.item-config-single[_ngcontent-%COMP%] button[_ngcontent-%COMP%]{margin:.5rem 4rem}.item-config-single[_ngcontent-%COMP%] .explain-button[_ngcontent-%COMP%]{padding-top:1rem}.item-config-single[_ngcontent-%COMP%] .explain-text[_ngcontent-%COMP%]{width:20rem;opacity:.7;margin-top:.5rem;font-size:.9rem}"] });
3568
+ } }, dependencies: [i1$1.MatDialogTitle, i1$1.MatDialogActions, i1$1.MatDialogContent, i3.MatButton, i4.NgControlStatus, i4.NgModel, i4$2.MatMenuItem, i2$1.MatSlider, i2$1.MatSliderThumb, i5.MatCheckbox, i2.DecimalPipe], styles: [".container[_ngcontent-%COMP%]{display:flex;flex-direction:row}.item-config-single[_ngcontent-%COMP%]{display:flex;flex-direction:column}.item-config-single[_ngcontent-%COMP%] .item-config-group[_ngcontent-%COMP%]{margin:.1rem 2rem}.item-config-single[_ngcontent-%COMP%] .item-config-group[_ngcontent-%COMP%] .item-config-label[_ngcontent-%COMP%]{display:inline;margin:1rem}.item-config-single[_ngcontent-%COMP%] .item-config-group[_ngcontent-%COMP%] .form-control[_ngcontent-%COMP%]{width:60%;display:inline}.item-config-single[_ngcontent-%COMP%] button[_ngcontent-%COMP%]{margin:.5rem 4rem}.item-config-single[_ngcontent-%COMP%] .explain-button[_ngcontent-%COMP%]{padding-top:1rem}.item-config-single[_ngcontent-%COMP%] .explain-text[_ngcontent-%COMP%]{width:20rem;opacity:.7;margin-top:.5rem;font-size:.9rem}"] });
2948
3569
  }
2949
3570
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(CartesianGridConfigComponent, [{
2950
3571
  type: Component,
@@ -2952,7 +3573,7 @@ class CartesianGridConfigComponent {
2952
3573
  }], () => [{ type: undefined, decorators: [{
2953
3574
  type: Inject,
2954
3575
  args: [MAT_DIALOG_DATA]
2955
- }] }, { type: i1$2.MatDialogRef }, { type: EventDisplayService }], null); })();
3576
+ }] }, { type: i1$1.MatDialogRef }, { type: EventDisplayService }], null); })();
2956
3577
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(CartesianGridConfigComponent, { className: "CartesianGridConfigComponent", filePath: "components/ui-menu/view-options/cartesian-grid-config/cartesian-grid-config.component.ts", lineNumber: 14 }); })();
2957
3578
 
2958
3579
  function ViewOptionsComponent_button_29__svg_svg_1_Template(rf, ctx) { if (rf & 1) {
@@ -3045,7 +3666,7 @@ class ViewOptionsComponent {
3045
3666
  ngOnDestroy() {
3046
3667
  this.sub.unsubscribe();
3047
3668
  }
3048
- static ɵfac = function ViewOptionsComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ViewOptionsComponent)(i0.ɵɵdirectiveInject(EventDisplayService), i0.ɵɵdirectiveInject(i1$2.MatDialog)); };
3669
+ static ɵfac = function ViewOptionsComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ViewOptionsComponent)(i0.ɵɵdirectiveInject(EventDisplayService), i0.ɵɵdirectiveInject(i1$1.MatDialog)); };
3049
3670
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ViewOptionsComponent, selectors: [["app-view-options"]], viewQuery: function ViewOptionsComponent_Query(rf, ctx) { if (rf & 1) {
3050
3671
  i0.ɵɵviewQuery(MatMenuTrigger, 5);
3051
3672
  } if (rf & 2) {
@@ -3103,12 +3724,12 @@ class ViewOptionsComponent {
3103
3724
  i0.ɵɵproperty("ngForOf", ctx.views);
3104
3725
  i0.ɵɵadvance();
3105
3726
  i0.ɵɵproperty("matMenuTriggerFor", viewOptions_r10)("active", false);
3106
- } }, dependencies: [i2.NgForOf, i2.NgIf, i3$2.MatMenu, i3$2.MatMenuItem, i3$2.MatMenuTrigger, i5.MatCheckbox, MenuToggleComponent], styles: [".view-icon[_ngcontent-%COMP%]{width:1.2rem;height:1.2rem;margin-right:.5rem}.icon-wrapper[_ngcontent-%COMP%]{display:inline-block;width:1.5rem;height:1.5rem;padding:.23rem;transition:all .4s;transform:translateY(27%)}.icon-wrapper.icon-button[_ngcontent-%COMP%]:hover{background:var(--phoenix-options-icon-bg);border-radius:40%;cursor:pointer}.icon-wrapper[_ngcontent-%COMP%] svg[_ngcontent-%COMP%]{width:100%;height:100%;vertical-align:top}.item-settings[_ngcontent-%COMP%]{margin-right:.2rem;margin-left:.5rem}"] });
3727
+ } }, dependencies: [i2.NgForOf, i2.NgIf, i4$2.MatMenu, i4$2.MatMenuItem, i4$2.MatMenuTrigger, i5.MatCheckbox, MenuToggleComponent], styles: [".view-icon[_ngcontent-%COMP%]{width:1.2rem;height:1.2rem;margin-right:.5rem}.icon-wrapper[_ngcontent-%COMP%]{display:inline-block;width:1.5rem;height:1.5rem;padding:.23rem;transition:all .4s;transform:translateY(27%)}.icon-wrapper.icon-button[_ngcontent-%COMP%]:hover{background:var(--phoenix-options-icon-bg);border-radius:40%;cursor:pointer}.icon-wrapper[_ngcontent-%COMP%] svg[_ngcontent-%COMP%]{width:100%;height:100%;vertical-align:top}.item-settings[_ngcontent-%COMP%]{margin-right:.2rem;margin-left:.5rem}"] });
3107
3728
  }
3108
3729
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ViewOptionsComponent, [{
3109
3730
  type: Component,
3110
3731
  args: [{ standalone: false, selector: 'app-view-options', template: "<mat-menu #viewOptions>\n <button mat-menu-item>\n <mat-checkbox\n #showCartesianGridCheckbox\n (click)=\"$event.stopPropagation()\"\n (change)=\"setCartesianGrid($event)\"\n >Show Cartesian Grid\n </mat-checkbox>\n <button\n class=\"icon-wrapper icon-button btn-blank item-settings\"\n (click)=\"openCartesianGridConfigDialog()\"\n >\n <svg>\n <use href=\"assets/icons/gear.svg#gear\"></use>\n </svg>\n </button>\n </button>\n <button\n mat-menu-item\n (click)=\"\n $event.stopPropagation();\n showEtaPhiGridCheckbox._inputElement.nativeElement.click()\n \"\n >\n <mat-checkbox\n #showEtaPhiGridCheckbox\n (click)=\"$event.stopPropagation()\"\n (change)=\"setEtaPhiGrid($event)\"\n >Show Eta Phi Grid\n </mat-checkbox>\n </button>\n <button\n mat-menu-item\n (click)=\"\n $event.stopPropagation();\n showAxisCheckbox._inputElement.nativeElement.click()\n \"\n >\n <mat-checkbox\n #showAxisCheckbox\n (click)=\"$event.stopPropagation()\"\n (change)=\"setAxis($event)\"\n >Show Axis\n </mat-checkbox>\n </button>\n <button\n mat-menu-item\n (click)=\"showLabelsCheckbox._inputElement.nativeElement.click()\"\n >\n <mat-checkbox\n #showLabelsCheckbox\n (click)=\"$event.stopPropagation()\"\n (change)=\"showLabels($event)\"\n >Show Labels\n </mat-checkbox>\n </button>\n <button\n mat-menu-item\n (click)=\"\n $event.stopPropagation();\n showMouse3DPointsCheckbox._inputElement.nativeElement.click()\n \"\n >\n <mat-checkbox\n #showMouse3DPointsCheckbox\n (click)=\"$event.stopPropagation()\"\n (change)=\"show3DMousePoints($event)\"\n >Show 3D Coordinates\n </mat-checkbox>\n </button>\n <button\n mat-menu-item\n (click)=\"\n $event.stopPropagation();\n show3DDistanceCheckbox._inputElement.nativeElement.click()\n \"\n >\n <mat-checkbox\n #show3DDistanceCheckbox\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleShowDistance($event)\"\n >Show 3D Distance\n </mat-checkbox>\n </button>\n <button\n mat-menu-item\n *ngFor=\"let view of views\"\n (click)=\"displayView($event, view)\"\n >\n <svg class=\"view-icon\" *ngIf=\"view.icon\">\n <use attr.href=\"assets/icons/{{ view.icon }}.svg#{{ view.icon }}\"></use>\n </svg>\n {{ view.name }}\n </button>\n</mat-menu>\n\n<app-menu-toggle\n [matMenuTriggerFor]=\"viewOptions\"\n tooltip=\"View options and Tools\"\n icon=\"views\"\n [active]=\"false\"\n>\n</app-menu-toggle>\n", styles: [".view-icon{width:1.2rem;height:1.2rem;margin-right:.5rem}.icon-wrapper{display:inline-block;width:1.5rem;height:1.5rem;padding:.23rem;transition:all .4s;transform:translateY(27%)}.icon-wrapper.icon-button:hover{background:var(--phoenix-options-icon-bg);border-radius:40%;cursor:pointer}.icon-wrapper svg{width:100%;height:100%;vertical-align:top}.item-settings{margin-right:.2rem;margin-left:.5rem}\n"] }]
3111
- }], () => [{ type: EventDisplayService }, { type: i1$2.MatDialog }], { trigger: [{
3732
+ }], () => [{ type: EventDisplayService }, { type: i1$1.MatDialog }], { trigger: [{
3112
3733
  type: ViewChild,
3113
3734
  args: [MatMenuTrigger]
3114
3735
  }] }); })();
@@ -3229,7 +3850,7 @@ class ArToggleComponent {
3229
3850
  i0.ɵɵproperty("ngIf", !ctx.arSupported);
3230
3851
  i0.ɵɵadvance();
3231
3852
  i0.ɵɵproperty("matMenuTriggerFor", arToggleOptions_r4)("disabled", !ctx.arSupported)("active", ctx.arActive)("tooltip", ctx.arSupported ? ctx.arActive ? "Exit AR" : "Enter AR" : "AR not supported");
3232
- } }, dependencies: [i2.NgIf, i3$2.MatMenu, i3$2.MatMenuItem, i3$2.MatMenuTrigger, MenuToggleComponent], encapsulation: 2 });
3853
+ } }, dependencies: [i2.NgIf, i4$2.MatMenu, i4$2.MatMenuItem, i4$2.MatMenuTrigger, MenuToggleComponent], encapsulation: 2 });
3233
3854
  }
3234
3855
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ArToggleComponent, [{
3235
3856
  type: Component,
@@ -3521,7 +4142,7 @@ class MakePictureComponent {
3521
4142
  i0.ɵɵtextInterpolate1(" ", ctx.buttonText(), " ");
3522
4143
  i0.ɵɵadvance();
3523
4144
  i0.ɵɵproperty("matMenuTriggerFor", menu_r5)("active", ctx.ssMode);
3524
- } }, dependencies: [i2.NgForOf, i4.NgControlStatus, i4.NgModel, i3$2.MatMenu, i3$2.MatMenuItem, i3$2.MatMenuTrigger, i5$1.MatRadioGroup, i5$1.MatRadioButton, MenuToggleComponent], styles: [".size-input{background:transparent;color:var(--phoenix-text-color);text-align:center}.size-input label{width:60px}.size-input input{background:transparent;color:var(--phoenix-text-color);width:80px}.badSize{border-color:red}.make-picture{text-align:center;display:block}.screenshot-mode span{padding:4px 8px;border:2px solid var(--phoenix-text-color);border-radius:8px;display:inline-block}.make-picture span{padding:5px 25px;border:2px solid var(--phoenix-text-color);border-radius:8px}#uiMenu,#phoenixMenu,#mainLogo,#statsElement{transition:opacity .4s}.ss-mode #uiMenu,.ss-mode #phoenixMenu,.ss-mode #mainLogo,.ss-mode #statsElement{visibility:hidden;opacity:0}\n"], encapsulation: 2 });
4145
+ } }, dependencies: [i2.NgForOf, i4.NgControlStatus, i4.NgModel, i4$2.MatMenu, i4$2.MatMenuItem, i4$2.MatMenuTrigger, i5$1.MatRadioGroup, i5$1.MatRadioButton, MenuToggleComponent], styles: [".size-input{background:transparent;color:var(--phoenix-text-color);text-align:center}.size-input label{width:60px}.size-input input{background:transparent;color:var(--phoenix-text-color);width:80px}.badSize{border-color:red}.make-picture{text-align:center;display:block}.screenshot-mode span{padding:4px 8px;border:2px solid var(--phoenix-text-color);border-radius:8px;display:inline-block}.make-picture span{padding:5px 25px;border:2px solid var(--phoenix-text-color);border-radius:8px}#uiMenu,#phoenixMenu,#mainLogo,#statsElement{transition:opacity .4s}.ss-mode #uiMenu,.ss-mode #phoenixMenu,.ss-mode #mainLogo,.ss-mode #statsElement{visibility:hidden;opacity:0}\n"], encapsulation: 2 });
3525
4146
  }
3526
4147
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MakePictureComponent, [{
3527
4148
  type: Component,
@@ -3766,7 +4387,7 @@ class ShareLinkDialogComponent {
3766
4387
  updateQRCode(link) {
3767
4388
  QRCode.toCanvas(this.qrcodeCanvas.nativeElement, link);
3768
4389
  }
3769
- static ɵfac = function ShareLinkDialogComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ShareLinkDialogComponent)(i0.ɵɵdirectiveInject(i1$2.MatDialogRef), i0.ɵɵdirectiveInject(EventDisplayService)); };
4390
+ static ɵfac = function ShareLinkDialogComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ShareLinkDialogComponent)(i0.ɵɵdirectiveInject(i1$1.MatDialogRef), i0.ɵɵdirectiveInject(EventDisplayService)); };
3770
4391
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ShareLinkDialogComponent, selectors: [["app-share-link-dialog"]], viewQuery: function ShareLinkDialogComponent_Query(rf, ctx) { if (rf & 1) {
3771
4392
  i0.ɵɵviewQuery(_c0$6, 5);
3772
4393
  } if (rf & 2) {
@@ -3855,12 +4476,12 @@ class ShareLinkDialogComponent {
3855
4476
  i0.ɵɵtextInterpolate(ctx.shareLink.value);
3856
4477
  i0.ɵɵadvance(7);
3857
4478
  i0.ɵɵtextInterpolate(ctx.embedLink);
3858
- } }, dependencies: [i1$2.MatDialogTitle, i1$2.MatDialogActions, i1$2.MatDialogContent, i3.MatButton, i4.NgSelectOption, i4.ɵNgSelectMultipleOption, i5.MatCheckbox], styles: [".share-box[_ngcontent-%COMP%]{width:30rem;max-width:100%;position:relative;background:var(--phoenix-background-color-tertiary);border:1px solid var(--phoenix-border);border-radius:.5rem;padding:1.25rem;word-wrap:break-word}.share-box[_ngcontent-%COMP%] .share-box-copy[_ngcontent-%COMP%]{position:absolute;top:-1px;right:-1px;background:transparent;color:inherit;cursor:pointer;padding:.25rem .5rem;font-size:.75rem;border:1px solid var(--phoenix-border);border-radius:.5rem}.share-box[_ngcontent-%COMP%] .share-box-copy[_ngcontent-%COMP%]:hover{background:var(--phoenix-border)}"] });
4479
+ } }, dependencies: [i1$1.MatDialogTitle, i1$1.MatDialogActions, i1$1.MatDialogContent, i3.MatButton, i4.NgSelectOption, i4.ɵNgSelectMultipleOption, i5.MatCheckbox], styles: [".share-box[_ngcontent-%COMP%]{width:30rem;max-width:100%;position:relative;background:var(--phoenix-background-color-tertiary);border:1px solid var(--phoenix-border);border-radius:.5rem;padding:1.25rem;word-wrap:break-word}.share-box[_ngcontent-%COMP%] .share-box-copy[_ngcontent-%COMP%]{position:absolute;top:-1px;right:-1px;background:transparent;color:inherit;cursor:pointer;padding:.25rem .5rem;font-size:.75rem;border:1px solid var(--phoenix-border);border-radius:.5rem}.share-box[_ngcontent-%COMP%] .share-box-copy[_ngcontent-%COMP%]:hover{background:var(--phoenix-border)}"] });
3859
4480
  }
3860
4481
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ShareLinkDialogComponent, [{
3861
4482
  type: Component,
3862
4483
  args: [{ standalone: false, selector: 'app-share-link-dialog', template: "<div class=\"dialog\">\n <h1 mat-dialog-title>Create shareable link</h1>\n <div mat-dialog-content class=\"dialog-content\">\n <h5>URL options</h5>\n <div class=\"form-group mt-2\">\n <label for=\"eventDataFile\">Event data file (URL or path)</label>\n <input\n type=\"text\"\n class=\"form-control\"\n id=\"eventDataFile\"\n placeholder=\"assets/files/event_data/atlaseventdump2.json\"\n [value]=\"urlOptions.file\"\n (input)=\"setOptionValue('file', $event.target.value)\"\n />\n </div>\n <div class=\"form-group\">\n <label for=\"eventDataType\">Event data type</label>\n <select\n class=\"form-control\"\n id=\"eventDataType\"\n (input)=\"setOptionValue('type', $event.target.value)\"\n >\n <option selected value=\"\">Select</option>\n <option value=\"jivexml\">JiveXML</option>\n <option value=\"json\">JSON</option>\n </select>\n </div>\n <div class=\"form-group\">\n <label for=\"configuration\">Configuration (URL or path)</label>\n <input\n type=\"text\"\n class=\"form-control\"\n id=\"configuration\"\n placeholder=\"assets/files/config/phoenix-config.json\"\n [value]=\"urlOptions.config\"\n (input)=\"setOptionValue('config', $event.target.value)\"\n />\n </div>\n <div class=\"form-group\">\n <mat-checkbox\n [checked]=\"urlOptions.hideWidgets\"\n (change)=\"setOptionValue('hideWidgets', $event.checked)\"\n >\n Hide all widgets\n </mat-checkbox>\n </div>\n <div class=\"form-group\">\n <mat-checkbox (change)=\"toggleViewState($event.checked)\">\n Include current view state (camera, visibility, clipping)\n </mat-checkbox>\n </div>\n\n <h5>Share</h5>\n <div class=\"share-box my-2\">\n <span>{{ shareLink.value }}</span>\n <button\n class=\"share-box-copy\"\n (click)=\"copyText(shareLink.value, $event.target)\"\n >\n COPY\n </button>\n </div>\n <h5>Embed</h5>\n <div class=\"share-box my-2\">\n <span>{{ embedLink }}</span>\n <button\n class=\"share-box-copy\"\n (click)=\"copyText(embedLink, $event.target)\"\n >\n COPY\n </button>\n </div>\n <h5>QR Code</h5>\n <div class=\"qrcode d-flex justify-content-center\">\n <canvas #qrcodeCanvas></canvas>\n </div>\n </div>\n <div mat-dialog-actions>\n <button mat-button (click)=\"onClose()\" cdkFocusInitial>Close</button>\n </div>\n</div>\n", styles: [".share-box{width:30rem;max-width:100%;position:relative;background:var(--phoenix-background-color-tertiary);border:1px solid var(--phoenix-border);border-radius:.5rem;padding:1.25rem;word-wrap:break-word}.share-box .share-box-copy{position:absolute;top:-1px;right:-1px;background:transparent;color:inherit;cursor:pointer;padding:.25rem .5rem;font-size:.75rem;border:1px solid var(--phoenix-border);border-radius:.5rem}.share-box .share-box-copy:hover{background:var(--phoenix-border)}\n"] }]
3863
- }], () => [{ type: i1$2.MatDialogRef }, { type: EventDisplayService }], { qrcodeCanvas: [{
4484
+ }], () => [{ type: i1$1.MatDialogRef }, { type: EventDisplayService }], { qrcodeCanvas: [{
3864
4485
  type: ViewChild,
3865
4486
  args: ['qrcodeCanvas']
3866
4487
  }] }); })();
@@ -3874,7 +4495,7 @@ class ShareLinkComponent {
3874
4495
  openShareLinkDialog() {
3875
4496
  this.dialog.open(ShareLinkDialogComponent);
3876
4497
  }
3877
- static ɵfac = function ShareLinkComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ShareLinkComponent)(i0.ɵɵdirectiveInject(i1$2.MatDialog)); };
4498
+ static ɵfac = function ShareLinkComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || ShareLinkComponent)(i0.ɵɵdirectiveInject(i1$1.MatDialog)); };
3878
4499
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: ShareLinkComponent, selectors: [["app-share-link"]], standalone: false, decls: 1, vars: 1, consts: [["tooltip", "Create shareable link", "icon", "share", 3, "click", "active"]], template: function ShareLinkComponent_Template(rf, ctx) { if (rf & 1) {
3879
4500
  i0.ɵɵelementStart(0, "app-menu-toggle", 0);
3880
4501
  i0.ɵɵlistener("click", function ShareLinkComponent_Template_app_menu_toggle_click_0_listener() { return ctx.openShareLinkDialog(); });
@@ -3886,7 +4507,7 @@ class ShareLinkComponent {
3886
4507
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(ShareLinkComponent, [{
3887
4508
  type: Component,
3888
4509
  args: [{ standalone: false, selector: 'app-share-link', template: "<app-menu-toggle\n tooltip=\"Create shareable link\"\n icon=\"share\"\n [active]=\"false\"\n (click)=\"openShareLinkDialog()\"\n>\n</app-menu-toggle>\n" }]
3889
- }], () => [{ type: i1$2.MatDialog }], null); })();
4510
+ }], () => [{ type: i1$1.MatDialog }], null); })();
3890
4511
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(ShareLinkComponent, { className: "ShareLinkComponent", filePath: "components/ui-menu/share-link/share-link.component.ts", lineNumber: 11 }); })();
3891
4512
 
3892
4513
  function FileExplorerComponent_cdk_tree_node_1_Template(rf, ctx) { if (rf & 1) {
@@ -3980,7 +4601,7 @@ class FileExplorerComponent {
3980
4601
  i0.ɵɵproperty("dataSource", ctx.dataSource)("treeControl", ctx.treeControl);
3981
4602
  i0.ɵɵadvance(2);
3982
4603
  i0.ɵɵproperty("cdkTreeNodeDefWhen", ctx.hasChildren);
3983
- } }, dependencies: [i3.MatButton, i2$2.CdkNestedTreeNode, i2$2.CdkTreeNodeDef, i2$2.CdkTreeNodeToggle, i2$2.CdkTree, i2$2.CdkTreeNode, i2$2.CdkTreeNodeOutlet], styles: [".file-tree-invisible[_ngcontent-%COMP%]{display:none}.tree-node[_ngcontent-%COMP%]{display:block;margin:.25rem 0}.tree-node[_ngcontent-%COMP%] .tree-node[_ngcontent-%COMP%]{padding-left:1rem}.tree-node-button[_ngcontent-%COMP%]{outline:none;padding:0 .75rem}.node-icon[_ngcontent-%COMP%]{width:1rem;height:1rem;margin-right:.25rem;margin-top:-2px}.node-icon.node-icon-filled[_ngcontent-%COMP%]{--icon-fill: var(--phoenix-options-icon-path, #fff)}"] });
4604
+ } }, dependencies: [i3.MatButton, i2$4.CdkNestedTreeNode, i2$4.CdkTreeNodeDef, i2$4.CdkTreeNodeToggle, i2$4.CdkTree, i2$4.CdkTreeNode, i2$4.CdkTreeNodeOutlet], styles: [".file-tree-invisible[_ngcontent-%COMP%]{display:none}.tree-node[_ngcontent-%COMP%]{display:block;margin:.25rem 0}.tree-node[_ngcontent-%COMP%] .tree-node[_ngcontent-%COMP%]{padding-left:1rem}.tree-node-button[_ngcontent-%COMP%]{outline:none;padding:0 .75rem}.node-icon[_ngcontent-%COMP%]{width:1rem;height:1rem;margin-right:.25rem;margin-top:-2px}.node-icon.node-icon-filled[_ngcontent-%COMP%]{--icon-fill: var(--phoenix-options-icon-path, #fff)}"] });
3984
4605
  }
3985
4606
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(FileExplorerComponent, [{
3986
4607
  type: Component,
@@ -4187,7 +4808,7 @@ class EventDataExplorerDialogComponent {
4187
4808
  }
4188
4809
  return rootNode;
4189
4810
  }
4190
- static ɵfac = function EventDataExplorerDialogComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || EventDataExplorerDialogComponent)(i0.ɵɵdirectiveInject(EventDisplayService), i0.ɵɵdirectiveInject(FileLoaderService), i0.ɵɵdirectiveInject(i1$2.MatDialogRef), i0.ɵɵdirectiveInject(MAT_DIALOG_DATA)); };
4811
+ static ɵfac = function EventDataExplorerDialogComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || EventDataExplorerDialogComponent)(i0.ɵɵdirectiveInject(EventDisplayService), i0.ɵɵdirectiveInject(FileLoaderService), i0.ɵɵdirectiveInject(i1$1.MatDialogRef), i0.ɵɵdirectiveInject(MAT_DIALOG_DATA)); };
4191
4812
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: EventDataExplorerDialogComponent, selectors: [["app-event-data-explorer-dialog"]], standalone: false, decls: 11, vars: 3, consts: [[1, "dialog"], [1, "d-flex"], ["mat-dialog-title", ""], [4, "ngIf"], ["mat-dialog-content", "", 1, "dialog-content"], ["mat-align-tabs", "start", "animationDuration", "0ms", "disableRipple", "", "opacity", "transparent", 4, "ngIf"], ["mat-dialog-actions", ""], ["mat-button", "", "cdkFocusInitial", "", 3, "click"], ["mat-align-tabs", "start", "animationDuration", "0ms", "disableRipple", "", "opacity", "transparent"], ["label", "Event data"], [1, "py-3"], [3, "onFileSelect", "rootFileNode"], ["label", "Config"]], template: function EventDataExplorerDialogComponent_Template(rf, ctx) { if (rf & 1) {
4192
4813
  i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "h1", 2);
4193
4814
  i0.ɵɵtext(3, "Event data from directory");
@@ -4208,12 +4829,12 @@ class EventDataExplorerDialogComponent {
4208
4829
  i0.ɵɵproperty("ngIf", ctx.error);
4209
4830
  i0.ɵɵadvance();
4210
4831
  i0.ɵɵproperty("ngIf", !ctx.error);
4211
- } }, dependencies: [i2.NgIf, i1$2.MatDialogTitle, i1$2.MatDialogActions, i1$2.MatDialogContent, i3.MatButton, i6.MatTab, i6.MatTabGroup, FileExplorerComponent, RingLoaderComponent], styles: [".dialog[_ngcontent-%COMP%]{width:30rem;max-width:95%}.file-path-button[_ngcontent-%COMP%]{width:100%;color:var(--phoenix-text-color);background:var(--phoenix-background-color-tertiary);text-align:left;border-radius:1rem;margin-bottom:.5rem;padding:.5rem 1rem}.file-path-button[_ngcontent-%COMP%]:last-child{margin-bottom:0}.file-path-button[_ngcontent-%COMP%]:hover{background:var(--phoenix-background-color-secondary)}.file-path-button[_ngcontent-%COMP%]:focus{border:1px solid var(--phoenix-text-color-secondary);box-shadow:none}"] });
4832
+ } }, dependencies: [i2.NgIf, i1$1.MatDialogTitle, i1$1.MatDialogActions, i1$1.MatDialogContent, i3.MatButton, i6.MatTab, i6.MatTabGroup, FileExplorerComponent, RingLoaderComponent], styles: [".dialog[_ngcontent-%COMP%]{width:30rem;max-width:95%}.file-path-button[_ngcontent-%COMP%]{width:100%;color:var(--phoenix-text-color);background:var(--phoenix-background-color-tertiary);text-align:left;border-radius:1rem;margin-bottom:.5rem;padding:.5rem 1rem}.file-path-button[_ngcontent-%COMP%]:last-child{margin-bottom:0}.file-path-button[_ngcontent-%COMP%]:hover{background:var(--phoenix-background-color-secondary)}.file-path-button[_ngcontent-%COMP%]:focus{border:1px solid var(--phoenix-text-color-secondary);box-shadow:none}"] });
4212
4833
  }
4213
4834
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(EventDataExplorerDialogComponent, [{
4214
4835
  type: Component,
4215
4836
  args: [{ standalone: false, selector: 'app-event-data-explorer-dialog', template: "<div class=\"dialog\">\n <div class=\"d-flex\">\n <h1 mat-dialog-title>Event data from directory</h1>\n <app-ring-loader *ngIf=\"loading\"></app-ring-loader>\n </div>\n <div mat-dialog-content class=\"dialog-content\">\n <div *ngIf=\"error\">Error processing request.</div>\n <mat-tab-group\n *ngIf=\"!error\"\n mat-align-tabs=\"start\"\n animationDuration=\"0ms\"\n disableRipple\n opacity=\"transparent\"\n >\n <mat-tab label=\"Event data\">\n <div class=\"py-3\">\n <app-file-explorer\n [rootFileNode]=\"eventDataFileNode\"\n (onFileSelect)=\"loadEvent($event)\"\n ></app-file-explorer>\n </div>\n </mat-tab>\n <mat-tab label=\"Config\">\n <div class=\"py-3\">\n <app-file-explorer\n [rootFileNode]=\"configFileNode\"\n (onFileSelect)=\"loadConfig($event)\"\n ></app-file-explorer>\n </div>\n </mat-tab>\n </mat-tab-group>\n </div>\n <div mat-dialog-actions>\n <button mat-button (click)=\"onClose()\" cdkFocusInitial>Close</button>\n </div>\n</div>\n", styles: [".dialog{width:30rem;max-width:95%}.file-path-button{width:100%;color:var(--phoenix-text-color);background:var(--phoenix-background-color-tertiary);text-align:left;border-radius:1rem;margin-bottom:.5rem;padding:.5rem 1rem}.file-path-button:last-child{margin-bottom:0}.file-path-button:hover{background:var(--phoenix-background-color-secondary)}.file-path-button:focus{border:1px solid var(--phoenix-text-color-secondary);box-shadow:none}\n"] }]
4216
- }], () => [{ type: EventDisplayService }, { type: FileLoaderService }, { type: i1$2.MatDialogRef }, { type: undefined, decorators: [{
4837
+ }], () => [{ type: EventDisplayService }, { type: FileLoaderService }, { type: i1$1.MatDialogRef }, { type: undefined, decorators: [{
4217
4838
  type: Inject,
4218
4839
  args: [MAT_DIALOG_DATA]
4219
4840
  }] }], null); })();
@@ -4232,7 +4853,7 @@ class EventDataExplorerComponent {
4232
4853
  },
4233
4854
  });
4234
4855
  }
4235
- static ɵfac = function EventDataExplorerComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || EventDataExplorerComponent)(i0.ɵɵdirectiveInject(i1$2.MatDialog)); };
4856
+ static ɵfac = function EventDataExplorerComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || EventDataExplorerComponent)(i0.ɵɵdirectiveInject(i1$1.MatDialog)); };
4236
4857
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: EventDataExplorerComponent, selectors: [["app-event-data-explorer"]], inputs: { apiURL: "apiURL" }, standalone: false, decls: 1, vars: 1, consts: [["tooltip", "Browse events in data directory", "icon", "server", 3, "click", "active"]], template: function EventDataExplorerComponent_Template(rf, ctx) { if (rf & 1) {
4237
4858
  i0.ɵɵelementStart(0, "app-menu-toggle", 0);
4238
4859
  i0.ɵɵlistener("click", function EventDataExplorerComponent_Template_app_menu_toggle_click_0_listener() { return ctx.openEventDataExplorerDialog(); });
@@ -4244,7 +4865,7 @@ class EventDataExplorerComponent {
4244
4865
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(EventDataExplorerComponent, [{
4245
4866
  type: Component,
4246
4867
  args: [{ standalone: false, selector: 'app-event-data-explorer', template: "<app-menu-toggle\n tooltip=\"Browse events in data directory\"\n icon=\"server\"\n [active]=\"false\"\n (click)=\"openEventDataExplorerDialog()\"\n>\n</app-menu-toggle>\n" }]
4247
- }], () => [{ type: i1$2.MatDialog }], { apiURL: [{
4868
+ }], () => [{ type: i1$1.MatDialog }], { apiURL: [{
4248
4869
  type: Input
4249
4870
  }] }); })();
4250
4871
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(EventDataExplorerComponent, { className: "EventDataExplorerComponent", filePath: "components/ui-menu/event-data-explorer/event-data-explorer.component.ts", lineNumber: 15 }); })();
@@ -4974,19 +5595,19 @@ class EventBrowserOverlayComponent {
4974
5595
  return this.loadingEventKey === summary.eventKey;
4975
5596
  }
4976
5597
  static ɵfac = function EventBrowserOverlayComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || EventBrowserOverlayComponent)(i0.ɵɵdirectiveInject(EventDisplayService)); };
4977
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: EventBrowserOverlayComponent, selectors: [["app-event-browser-overlay"]], inputs: { showEventBrowser: "showEventBrowser" }, standalone: false, decls: 2, vars: 2, consts: [["overlayTitle", "Event Browser", "icon", "event-browser", 3, "active"], ["class", "event-browser m-2", 4, "ngIf"], [1, "event-browser", "m-2"], ["class", "search-box mb-2 d-flex align-items-center", 4, "ngIf"], ["class", "filter-controls mb-2", 4, "ngIf"], ["class", "summary-count mb-1", 4, "ngIf"], ["tabindex", "0", 1, "boxBody", "table-responsive", 3, "keydown"], ["class", "table table-borderless table-sm", 4, "ngIf"], ["class", "emptyBox", 4, "ngIf"], ["class", "keyboard-hint mt-1", 4, "ngIf"], [1, "search-box", "mb-2", "d-flex", "align-items-center"], ["type", "text", "placeholder", "Jump to event number...", 1, "search-input", 3, "ngModelChange", "keydown.enter", "ngModel"], ["class", "search-hint", 4, "ngIf"], [1, "search-hint"], [1, "filter-controls", "mb-2"], [1, "d-flex", "align-items-center", "flex-wrap", "gap-1"], [1, "filter-label"], [1, "filter-select", 3, "ngModelChange", "ngModel"], ["value", "", "disabled", ""], [3, "value", 4, "ngFor", "ngForOf"], ["value", ">="], ["value", "<="], ["value", "="], ["type", "number", "placeholder", "value", "min", "0", 1, "filter-input", 3, "ngModelChange", "ngModel"], [1, "btn-filter", "btn-blank", 3, "click"], [1, "filter-separator"], ["type", "number", "placeholder", "GeV", 1, "filter-input", 3, "input"], ["class", "btn-filter btn-blank", 3, "click", 4, "ngIf"], ["class", "active-filters mt-1", 4, "ngIf"], [3, "value"], [1, "active-filters", "mt-1"], ["class", "filter-tag", 4, "ngFor", "ngForOf"], [1, "filter-tag"], [1, "btn-blank", "filter-remove", 3, "click"], [1, "summary-count", "mb-1"], [1, "table", "table-borderless", "table-sm"], [4, "ngFor", "ngForOf"], [1, "head-wrapper"], ["matTooltip", "Reconstructed physics objects (excl. detector readouts)"], [1, "sort-options"], [1, "icon-wrapper", "icon-button", "btn-blank", "up", 3, "click", "ngClass"], ["href", "assets/icons/expand.svg#expand"], [1, "icon-wrapper", "icon-button", "btn-blank", 3, "click", "ngClass"], [3, "id", "ngClass", "click", "dblclick", 4, "ngFor", "ngForOf"], [3, "click", "dblclick", "id", "ngClass"], [1, "event-cell"], [1, "event-label"], ["class", "run-label", 4, "ngIf"], [3, "ngClass", 4, "ngFor", "ngForOf"], [3, "ngClass"], [1, "btn-blank", "btn-load", 3, "click", "matTooltip"], ["class", "loading-spinner", 4, "ngIf"], ["class", "load-icon", 4, "ngIf"], [1, "run-label"], [1, "loading-spinner"], [1, "load-icon"], ["href", "assets/icons/views.svg#views"], [1, "emptyBox"], [1, "keyboard-hint", "mt-1"]], template: function EventBrowserOverlayComponent_Template(rf, ctx) { if (rf & 1) {
5598
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: EventBrowserOverlayComponent, selectors: [["app-event-browser-overlay"]], inputs: { showEventBrowser: "showEventBrowser" }, standalone: false, decls: 2, vars: 3, consts: [["overlayTitle", "Event Browser", "icon", "event-browser", "accordionId", "right-dock", 3, "resizable", "active"], ["class", "event-browser m-2", 4, "ngIf"], [1, "event-browser", "m-2"], ["class", "search-box mb-2 d-flex align-items-center", 4, "ngIf"], ["class", "filter-controls mb-2", 4, "ngIf"], ["class", "summary-count mb-1", 4, "ngIf"], ["tabindex", "0", 1, "boxBody", "table-responsive", 3, "keydown"], ["class", "table table-borderless table-sm", 4, "ngIf"], ["class", "emptyBox", 4, "ngIf"], ["class", "keyboard-hint mt-1", 4, "ngIf"], [1, "search-box", "mb-2", "d-flex", "align-items-center"], ["type", "text", "placeholder", "Jump to event number...", 1, "search-input", 3, "ngModelChange", "keydown.enter", "ngModel"], ["class", "search-hint", 4, "ngIf"], [1, "search-hint"], [1, "filter-controls", "mb-2"], [1, "d-flex", "align-items-center", "flex-wrap", "gap-1"], [1, "filter-label"], [1, "filter-select", 3, "ngModelChange", "ngModel"], ["value", "", "disabled", ""], [3, "value", 4, "ngFor", "ngForOf"], ["value", ">="], ["value", "<="], ["value", "="], ["type", "number", "placeholder", "value", "min", "0", 1, "filter-input", 3, "ngModelChange", "ngModel"], [1, "btn-filter", "btn-blank", 3, "click"], [1, "filter-separator"], ["type", "number", "placeholder", "GeV", 1, "filter-input", 3, "input"], ["class", "btn-filter btn-blank", 3, "click", 4, "ngIf"], ["class", "active-filters mt-1", 4, "ngIf"], [3, "value"], [1, "active-filters", "mt-1"], ["class", "filter-tag", 4, "ngFor", "ngForOf"], [1, "filter-tag"], [1, "btn-blank", "filter-remove", 3, "click"], [1, "summary-count", "mb-1"], [1, "table", "table-borderless", "table-sm"], [4, "ngFor", "ngForOf"], [1, "head-wrapper"], ["matTooltip", "Reconstructed physics objects (excl. detector readouts)"], [1, "sort-options"], [1, "icon-wrapper", "icon-button", "btn-blank", "up", 3, "click", "ngClass"], ["href", "assets/icons/expand.svg#expand"], [1, "icon-wrapper", "icon-button", "btn-blank", 3, "click", "ngClass"], [3, "id", "ngClass", "click", "dblclick", 4, "ngFor", "ngForOf"], [3, "click", "dblclick", "id", "ngClass"], [1, "event-cell"], [1, "event-label"], ["class", "run-label", 4, "ngIf"], [3, "ngClass", 4, "ngFor", "ngForOf"], [3, "ngClass"], [1, "btn-blank", "btn-load", 3, "click", "matTooltip"], ["class", "loading-spinner", 4, "ngIf"], ["class", "load-icon", 4, "ngIf"], [1, "run-label"], [1, "loading-spinner"], [1, "load-icon"], ["href", "assets/icons/views.svg#views"], [1, "emptyBox"], [1, "keyboard-hint", "mt-1"]], template: function EventBrowserOverlayComponent_Template(rf, ctx) { if (rf & 1) {
4978
5599
  i0.ɵɵelementStart(0, "app-overlay", 0);
4979
5600
  i0.ɵɵtemplate(1, EventBrowserOverlayComponent_div_1_Template, 8, 6, "div", 1);
4980
5601
  i0.ɵɵelementEnd();
4981
5602
  } if (rf & 2) {
4982
- i0.ɵɵproperty("active", ctx.showEventBrowser);
5603
+ i0.ɵɵproperty("resizable", true)("active", ctx.showEventBrowser);
4983
5604
  i0.ɵɵadvance();
4984
5605
  i0.ɵɵproperty("ngIf", ctx.showEventBrowser);
4985
5606
  } }, dependencies: [i2.NgClass, i2.NgForOf, i2.NgIf, i3$1.MatTooltip, i4.NgSelectOption, i4.ɵNgSelectMultipleOption, i4.DefaultValueAccessor, i4.NumberValueAccessor, i4.SelectControlValueAccessor, i4.NgControlStatus, i4.MinValidator, i4.NgModel, OverlayComponent], styles: [".event-browser[_ngcontent-%COMP%]{height:95%}.event-browser[_ngcontent-%COMP%] .search-box[_ngcontent-%COMP%] .search-input[_ngcontent-%COMP%]{flex:1;padding:4px 8px;font-size:12px;border:1px solid rgba(88,88,88,.15);box-shadow:var(--phoenix-icon-shadow);background-color:var(--phoenix-background-color-tertiary);color:var(--phoenix-text-color-secondary);border-radius:4px}.event-browser[_ngcontent-%COMP%] .search-box[_ngcontent-%COMP%] .search-input[_ngcontent-%COMP%]::placeholder{opacity:.5}.event-browser[_ngcontent-%COMP%] .search-box[_ngcontent-%COMP%] .search-hint[_ngcontent-%COMP%]{font-size:10px;color:var(--phoenix-text-color-secondary);opacity:.5;margin-left:.4rem;white-space:nowrap}.event-browser[_ngcontent-%COMP%] .filter-controls[_ngcontent-%COMP%] .filter-select[_ngcontent-%COMP%], .event-browser[_ngcontent-%COMP%] .filter-controls[_ngcontent-%COMP%] .filter-input[_ngcontent-%COMP%]{padding:3px 6px;font-size:11px;border:1px solid rgba(88,88,88,.08);box-shadow:var(--phoenix-icon-shadow);background-color:var(--phoenix-background-color-tertiary);color:var(--phoenix-text-color-secondary);border-radius:3px}.event-browser[_ngcontent-%COMP%] .filter-controls[_ngcontent-%COMP%] .filter-select[_ngcontent-%COMP%]{width:7rem}.event-browser[_ngcontent-%COMP%] .filter-controls[_ngcontent-%COMP%] .filter-input[_ngcontent-%COMP%]{width:4rem}.event-browser[_ngcontent-%COMP%] .filter-controls[_ngcontent-%COMP%] .btn-filter[_ngcontent-%COMP%]{padding:3px 8px;font-size:11px;color:var(--phoenix-text-color-secondary);border:1px solid rgba(88,88,88,.2);border-radius:3px;cursor:pointer}.event-browser[_ngcontent-%COMP%] .filter-controls[_ngcontent-%COMP%] .btn-filter[_ngcontent-%COMP%]:hover{background:#ffffff1a}.event-browser[_ngcontent-%COMP%] .filter-controls[_ngcontent-%COMP%] .filter-separator[_ngcontent-%COMP%]{color:var(--phoenix-text-color-secondary);opacity:.4;margin:0 .2rem}.event-browser[_ngcontent-%COMP%] .filter-controls[_ngcontent-%COMP%] .filter-label[_ngcontent-%COMP%]{font-size:11px;color:var(--phoenix-text-color-secondary)}.event-browser[_ngcontent-%COMP%] .filter-controls[_ngcontent-%COMP%] .gap-1[_ngcontent-%COMP%]{gap:.3rem}.event-browser[_ngcontent-%COMP%] .active-filters[_ngcontent-%COMP%] .filter-tag[_ngcontent-%COMP%]{display:inline-flex;align-items:center;padding:1px 6px;margin-right:.3rem;font-size:10px;color:var(--phoenix-text-color-secondary);background:#ffffff14;border-radius:3px}.event-browser[_ngcontent-%COMP%] .active-filters[_ngcontent-%COMP%] .filter-tag[_ngcontent-%COMP%] .filter-remove[_ngcontent-%COMP%]{margin-left:4px;font-size:12px;line-height:1;cursor:pointer;color:var(--phoenix-text-color-secondary);opacity:.6}.event-browser[_ngcontent-%COMP%] .active-filters[_ngcontent-%COMP%] .filter-tag[_ngcontent-%COMP%] .filter-remove[_ngcontent-%COMP%]:hover{opacity:1}.event-browser[_ngcontent-%COMP%] .summary-count[_ngcontent-%COMP%]{font-size:11px;color:var(--phoenix-text-color-secondary);opacity:.7}.boxBody[_ngcontent-%COMP%]{height:80%;overflow:auto;outline:none}.boxBody[_ngcontent-%COMP%] p.emptyBox[_ngcontent-%COMP%]{max-width:21em;color:var(--phoenix-text-color-secondary)}.event-browser[_ngcontent-%COMP%] table[_ngcontent-%COMP%]{position:relative;color:var(--phoenix-text-color-secondary);font-size:12px}.event-browser[_ngcontent-%COMP%] table[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] th[_ngcontent-%COMP%]{position:sticky;top:0;z-index:100;background:var(--phoenix-background-color-secondary);white-space:nowrap;font-size:11px}.event-browser[_ngcontent-%COMP%] table[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] th[_ngcontent-%COMP%] .head-wrapper[_ngcontent-%COMP%]{display:flex;align-items:center}.event-browser[_ngcontent-%COMP%] table[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] th[_ngcontent-%COMP%] .head-wrapper[_ngcontent-%COMP%] .sort-options[_ngcontent-%COMP%]{display:flex;flex-direction:row}.event-browser[_ngcontent-%COMP%] table[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] th[_ngcontent-%COMP%] .head-wrapper[_ngcontent-%COMP%] .sort-options[_ngcontent-%COMP%] .icon-wrapper[_ngcontent-%COMP%]{display:flex;width:.85rem;height:.85rem;padding:.15rem;opacity:.5;transition:opacity .15s}.event-browser[_ngcontent-%COMP%] table[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] th[_ngcontent-%COMP%] .head-wrapper[_ngcontent-%COMP%] .sort-options[_ngcontent-%COMP%] .icon-wrapper[_ngcontent-%COMP%]:hover, .event-browser[_ngcontent-%COMP%] table[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] th[_ngcontent-%COMP%] .head-wrapper[_ngcontent-%COMP%] .sort-options[_ngcontent-%COMP%] .icon-wrapper.sort-active[_ngcontent-%COMP%]{opacity:1}.event-browser[_ngcontent-%COMP%] table[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] th[_ngcontent-%COMP%] .head-wrapper[_ngcontent-%COMP%] .sort-options[_ngcontent-%COMP%] .icon-wrapper.up[_ngcontent-%COMP%]{transform:rotate(180deg)}.event-browser[_ngcontent-%COMP%] table[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] th[_ngcontent-%COMP%] .head-wrapper[_ngcontent-%COMP%] .sort-options[_ngcontent-%COMP%] .icon-wrapper[_ngcontent-%COMP%] svg[_ngcontent-%COMP%]{width:100%;height:100%}.event-browser[_ngcontent-%COMP%] table[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] *[_ngcontent-%COMP%]{padding-right:.8rem}.event-browser[_ngcontent-%COMP%] table[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] *[_ngcontent-%COMP%]:last-child{padding-right:0}.event-browser[_ngcontent-%COMP%] table[_ngcontent-%COMP%] tbody[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]{cursor:pointer;transition:background .1s}.event-browser[_ngcontent-%COMP%] table[_ngcontent-%COMP%] tbody[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]:hover{background:#ffffff0d}.event-browser[_ngcontent-%COMP%] table[_ngcontent-%COMP%] tbody[_ngcontent-%COMP%] tr.selected-event[_ngcontent-%COMP%]{color:var(--phoenix-background-color);background:var(--phoenix-text-color);box-shadow:0 0 10px var(--phoenix-text-color)}.event-browser[_ngcontent-%COMP%] table[_ngcontent-%COMP%] tbody[_ngcontent-%COMP%] tr.loaded-event[_ngcontent-%COMP%]:not(.selected-event){background:#ffffff08}.event-browser[_ngcontent-%COMP%] table[_ngcontent-%COMP%] tbody[_ngcontent-%COMP%] tr.loaded-event[_ngcontent-%COMP%]:not(.selected-event) .event-label[_ngcontent-%COMP%]{font-weight:600}.event-browser[_ngcontent-%COMP%] table[_ngcontent-%COMP%] td[_ngcontent-%COMP%]{min-height:20px;white-space:nowrap}.event-browser[_ngcontent-%COMP%] table[_ngcontent-%COMP%] td.dim-zero[_ngcontent-%COMP%]{opacity:.25}.event-browser[_ngcontent-%COMP%] table[_ngcontent-%COMP%] .event-cell[_ngcontent-%COMP%] .event-label[_ngcontent-%COMP%]{font-size:12px;line-height:1.3}.event-browser[_ngcontent-%COMP%] table[_ngcontent-%COMP%] .event-cell[_ngcontent-%COMP%] .run-label[_ngcontent-%COMP%]{font-size:10px;opacity:.55;line-height:1.2}.event-browser[_ngcontent-%COMP%] table[_ngcontent-%COMP%] .btn-load[_ngcontent-%COMP%]{position:relative;width:1.4rem;height:1.4rem;text-align:center;background-color:var(--phoenix-options-icon-bg);border-radius:8px;cursor:pointer}.event-browser[_ngcontent-%COMP%] table[_ngcontent-%COMP%] .btn-load[_ngcontent-%COMP%]:hover{border:1px solid var(--phoenix-options-icon-path)}.event-browser[_ngcontent-%COMP%] table[_ngcontent-%COMP%] .btn-load[_ngcontent-%COMP%] .load-icon[_ngcontent-%COMP%]{position:absolute;top:0;left:0;padding:.3rem;width:100%;height:100%}.event-browser[_ngcontent-%COMP%] table[_ngcontent-%COMP%] .btn-load[_ngcontent-%COMP%] .loading-spinner[_ngcontent-%COMP%]{display:inline-block;width:10px;height:10px;border:2px solid rgba(255,255,255,.2);border-top-color:var(--phoenix-text-color-secondary);border-radius:50%;animation:_ngcontent-%COMP%_spin .7s linear infinite}@keyframes _ngcontent-%COMP%_spin{to{transform:rotate(360deg)}}.keyboard-hint[_ngcontent-%COMP%]{font-size:10px;color:var(--phoenix-text-color-secondary);opacity:.5}"] });
4986
5607
  }
4987
5608
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(EventBrowserOverlayComponent, [{
4988
5609
  type: Component,
4989
- args: [{ standalone: false, selector: 'app-event-browser-overlay', template: "<app-overlay\n overlayTitle=\"Event Browser\"\n icon=\"event-browser\"\n [active]=\"showEventBrowser\"\n>\n <div *ngIf=\"showEventBrowser\" class=\"event-browser m-2\">\n <!-- Search box -->\n <div\n class=\"search-box mb-2 d-flex align-items-center\"\n *ngIf=\"allSummaries.length > 0\"\n >\n <input\n type=\"text\"\n class=\"search-input\"\n placeholder=\"Jump to event number...\"\n [ngModel]=\"searchQuery\"\n (ngModelChange)=\"updateSearch($event)\"\n (keydown.enter)=\"jumpToSearch()\"\n />\n <span class=\"search-hint\" *ngIf=\"searchQuery\">Enter to load</span>\n </div>\n\n <!-- Filter controls -->\n <div class=\"filter-controls mb-2\" *ngIf=\"allSummaries.length > 0\">\n <div class=\"d-flex align-items-center flex-wrap gap-1\">\n <span class=\"filter-label\">Filter:</span>\n <select class=\"filter-select\" [(ngModel)]=\"filterColumn\">\n <option value=\"\" disabled>Column</option>\n <option *ngFor=\"let col of columns\" [value]=\"col\">{{ col }}</option>\n </select>\n <select class=\"filter-select\" [(ngModel)]=\"filterOperator\">\n <option value=\">=\">&gt;=</option>\n <option value=\"<=\">&lt;=</option>\n <option value=\"=\">=</option>\n </select>\n <input\n type=\"number\"\n class=\"filter-input\"\n placeholder=\"value\"\n [(ngModel)]=\"filterValue\"\n min=\"0\"\n />\n <button class=\"btn-filter btn-blank\" (click)=\"addFilter()\">Add</button>\n <span class=\"filter-separator\">|</span>\n <span class=\"filter-label\">MET &gt;=</span>\n <input\n type=\"number\"\n class=\"filter-input\"\n placeholder=\"GeV\"\n (input)=\"updateMETFilter($event.target.value)\"\n />\n <button\n class=\"btn-filter btn-blank\"\n (click)=\"clearFilters()\"\n *ngIf=\"filters.length > 0 || metFilterMin !== null || searchQuery\"\n >\n Clear\n </button>\n </div>\n <!-- Active filters -->\n <div class=\"active-filters mt-1\" *ngIf=\"filters.length > 0\">\n <span class=\"filter-tag\" *ngFor=\"let filter of filters; index as i\">\n {{ getFilterLabel(filter) }}\n <button class=\"btn-blank filter-remove\" (click)=\"removeFilter(i)\">\n &times;\n </button>\n </span>\n </div>\n </div>\n\n <!-- Summary count -->\n <div class=\"summary-count mb-1\" *ngIf=\"allSummaries.length > 0\">\n {{ displayedSummaries.length }} of {{ allSummaries.length }} events\n </div>\n\n <!-- Event table -->\n <div\n class=\"boxBody table-responsive\"\n (keydown)=\"onTableKeydown($event)\"\n tabindex=\"0\"\n >\n <table\n class=\"table table-borderless table-sm\"\n *ngIf=\"allSummaries.length > 0\"\n >\n <thead>\n <tr>\n <th>Event</th>\n <th *ngFor=\"let col of columns\">\n <div class=\"head-wrapper\">\n <div>{{ col }}</div>\n <div class=\"sort-options\">\n <button\n class=\"icon-wrapper icon-button btn-blank up\"\n [ngClass]=\"{ 'sort-active': isSortActive(col, 'desc') }\"\n (click)=\"sort(col, 'desc')\"\n >\n <svg>\n <use href=\"assets/icons/expand.svg#expand\"></use>\n </svg>\n </button>\n <button\n class=\"icon-wrapper icon-button btn-blank\"\n [ngClass]=\"{ 'sort-active': isSortActive(col, 'asc') }\"\n (click)=\"sort(col, 'asc')\"\n >\n <svg>\n <use href=\"assets/icons/expand.svg#expand\"></use>\n </svg>\n </button>\n </div>\n </div>\n </th>\n <th>\n <div class=\"head-wrapper\">\n <div\n matTooltip=\"Reconstructed physics objects (excl. detector readouts)\"\n >\n Reco\n </div>\n <div class=\"sort-options\">\n <button\n class=\"icon-wrapper icon-button btn-blank up\"\n [ngClass]=\"{ 'sort-active': isSortActive('_reco', 'desc') }\"\n (click)=\"sortByReco('desc')\"\n >\n <svg>\n <use href=\"assets/icons/expand.svg#expand\"></use>\n </svg>\n </button>\n <button\n class=\"icon-wrapper icon-button btn-blank\"\n [ngClass]=\"{ 'sort-active': isSortActive('_reco', 'asc') }\"\n (click)=\"sortByReco('asc')\"\n >\n <svg>\n <use href=\"assets/icons/expand.svg#expand\"></use>\n </svg>\n </button>\n </div>\n </div>\n </th>\n <th>\n <div class=\"head-wrapper\">\n <div>MET</div>\n <div class=\"sort-options\">\n <button\n class=\"icon-wrapper icon-button btn-blank up\"\n [ngClass]=\"{ 'sort-active': isSortActive('_met', 'desc') }\"\n (click)=\"sortByMET('desc')\"\n >\n <svg>\n <use href=\"assets/icons/expand.svg#expand\"></use>\n </svg>\n </button>\n <button\n class=\"icon-wrapper icon-button btn-blank\"\n [ngClass]=\"{ 'sort-active': isSortActive('_met', 'asc') }\"\n (click)=\"sortByMET('asc')\"\n >\n <svg>\n <use href=\"assets/icons/expand.svg#expand\"></use>\n </svg>\n </button>\n </div>\n </div>\n </th>\n <th></th>\n </tr>\n </thead>\n <tbody>\n <tr\n *ngFor=\"let summary of displayedSummaries\"\n [id]=\"'event-row-' + summary.eventKey\"\n [ngClass]=\"{\n 'selected-event': selectedEventKey === summary.eventKey,\n 'loaded-event': isLoadedEvent(summary),\n }\"\n (click)=\"selectedEventKey = summary.eventKey\"\n (dblclick)=\"selectEvent(summary)\"\n >\n <td class=\"event-cell\">\n <div class=\"event-label\">{{ getEventLabel(summary) }}</div>\n <div class=\"run-label\" *ngIf=\"getRunLabel(summary)\">\n {{ getRunLabel(summary) }}\n </div>\n </td>\n <td\n *ngFor=\"let col of columns\"\n [ngClass]=\"{ 'dim-zero': getCount(summary, col) === 0 }\"\n >\n {{ formatNumber(getCount(summary, col)) }}\n </td>\n <td [ngClass]=\"{ 'dim-zero': getRecoTotal(summary) === 0 }\">\n {{ formatNumber(getRecoTotal(summary)) }}\n </td>\n <td>{{ formatMET(summary.met) }}</td>\n <td>\n <button\n class=\"btn-blank btn-load\"\n [matTooltip]=\"\n isLoadingEvent(summary) ? 'Loading...' : 'Load this event'\n \"\n (click)=\"selectEvent(summary); $event.stopPropagation()\"\n >\n <span\n *ngIf=\"isLoadingEvent(summary)\"\n class=\"loading-spinner\"\n ></span>\n <svg *ngIf=\"!isLoadingEvent(summary)\" class=\"load-icon\">\n <use href=\"assets/icons/views.svg#views\"></use>\n </svg>\n </button>\n </td>\n </tr>\n </tbody>\n </table>\n <p class=\"emptyBox\" *ngIf=\"allSummaries.length === 0\">\n Load event data to browse events here.\n </p>\n </div>\n\n <!-- Keyboard hint -->\n <div class=\"keyboard-hint mt-1\" *ngIf=\"allSummaries.length > 0\">\n Arrow keys to navigate, Enter to load, Shift+Left/Right for prev/next\n </div>\n </div>\n</app-overlay>\n", styles: [".event-browser{height:95%}.event-browser .search-box .search-input{flex:1;padding:4px 8px;font-size:12px;border:1px solid rgba(88,88,88,.15);box-shadow:var(--phoenix-icon-shadow);background-color:var(--phoenix-background-color-tertiary);color:var(--phoenix-text-color-secondary);border-radius:4px}.event-browser .search-box .search-input::placeholder{opacity:.5}.event-browser .search-box .search-hint{font-size:10px;color:var(--phoenix-text-color-secondary);opacity:.5;margin-left:.4rem;white-space:nowrap}.event-browser .filter-controls .filter-select,.event-browser .filter-controls .filter-input{padding:3px 6px;font-size:11px;border:1px solid rgba(88,88,88,.08);box-shadow:var(--phoenix-icon-shadow);background-color:var(--phoenix-background-color-tertiary);color:var(--phoenix-text-color-secondary);border-radius:3px}.event-browser .filter-controls .filter-select{width:7rem}.event-browser .filter-controls .filter-input{width:4rem}.event-browser .filter-controls .btn-filter{padding:3px 8px;font-size:11px;color:var(--phoenix-text-color-secondary);border:1px solid rgba(88,88,88,.2);border-radius:3px;cursor:pointer}.event-browser .filter-controls .btn-filter:hover{background:#ffffff1a}.event-browser .filter-controls .filter-separator{color:var(--phoenix-text-color-secondary);opacity:.4;margin:0 .2rem}.event-browser .filter-controls .filter-label{font-size:11px;color:var(--phoenix-text-color-secondary)}.event-browser .filter-controls .gap-1{gap:.3rem}.event-browser .active-filters .filter-tag{display:inline-flex;align-items:center;padding:1px 6px;margin-right:.3rem;font-size:10px;color:var(--phoenix-text-color-secondary);background:#ffffff14;border-radius:3px}.event-browser .active-filters .filter-tag .filter-remove{margin-left:4px;font-size:12px;line-height:1;cursor:pointer;color:var(--phoenix-text-color-secondary);opacity:.6}.event-browser .active-filters .filter-tag .filter-remove:hover{opacity:1}.event-browser .summary-count{font-size:11px;color:var(--phoenix-text-color-secondary);opacity:.7}.boxBody{height:80%;overflow:auto;outline:none}.boxBody p.emptyBox{max-width:21em;color:var(--phoenix-text-color-secondary)}.event-browser table{position:relative;color:var(--phoenix-text-color-secondary);font-size:12px}.event-browser table thead tr th{position:sticky;top:0;z-index:100;background:var(--phoenix-background-color-secondary);white-space:nowrap;font-size:11px}.event-browser table thead tr th .head-wrapper{display:flex;align-items:center}.event-browser table thead tr th .head-wrapper .sort-options{display:flex;flex-direction:row}.event-browser table thead tr th .head-wrapper .sort-options .icon-wrapper{display:flex;width:.85rem;height:.85rem;padding:.15rem;opacity:.5;transition:opacity .15s}.event-browser table thead tr th .head-wrapper .sort-options .icon-wrapper:hover,.event-browser table thead tr th .head-wrapper .sort-options .icon-wrapper.sort-active{opacity:1}.event-browser table thead tr th .head-wrapper .sort-options .icon-wrapper.up{transform:rotate(180deg)}.event-browser table thead tr th .head-wrapper .sort-options .icon-wrapper svg{width:100%;height:100%}.event-browser table tr *{padding-right:.8rem}.event-browser table tr *:last-child{padding-right:0}.event-browser table tbody tr{cursor:pointer;transition:background .1s}.event-browser table tbody tr:hover{background:#ffffff0d}.event-browser table tbody tr.selected-event{color:var(--phoenix-background-color);background:var(--phoenix-text-color);box-shadow:0 0 10px var(--phoenix-text-color)}.event-browser table tbody tr.loaded-event:not(.selected-event){background:#ffffff08}.event-browser table tbody tr.loaded-event:not(.selected-event) .event-label{font-weight:600}.event-browser table td{min-height:20px;white-space:nowrap}.event-browser table td.dim-zero{opacity:.25}.event-browser table .event-cell .event-label{font-size:12px;line-height:1.3}.event-browser table .event-cell .run-label{font-size:10px;opacity:.55;line-height:1.2}.event-browser table .btn-load{position:relative;width:1.4rem;height:1.4rem;text-align:center;background-color:var(--phoenix-options-icon-bg);border-radius:8px;cursor:pointer}.event-browser table .btn-load:hover{border:1px solid var(--phoenix-options-icon-path)}.event-browser table .btn-load .load-icon{position:absolute;top:0;left:0;padding:.3rem;width:100%;height:100%}.event-browser table .btn-load .loading-spinner{display:inline-block;width:10px;height:10px;border:2px solid rgba(255,255,255,.2);border-top-color:var(--phoenix-text-color-secondary);border-radius:50%;animation:spin .7s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.keyboard-hint{font-size:10px;color:var(--phoenix-text-color-secondary);opacity:.5}\n"] }]
5610
+ args: [{ standalone: false, selector: 'app-event-browser-overlay', template: "<app-overlay\n overlayTitle=\"Event Browser\"\n icon=\"event-browser\"\n [resizable]=\"true\"\n [active]=\"showEventBrowser\"\n accordionId=\"right-dock\"\n>\n <div *ngIf=\"showEventBrowser\" class=\"event-browser m-2\">\n <!-- Search box -->\n <div\n class=\"search-box mb-2 d-flex align-items-center\"\n *ngIf=\"allSummaries.length > 0\"\n >\n <input\n type=\"text\"\n class=\"search-input\"\n placeholder=\"Jump to event number...\"\n [ngModel]=\"searchQuery\"\n (ngModelChange)=\"updateSearch($event)\"\n (keydown.enter)=\"jumpToSearch()\"\n />\n <span class=\"search-hint\" *ngIf=\"searchQuery\">Enter to load</span>\n </div>\n\n <!-- Filter controls -->\n <div class=\"filter-controls mb-2\" *ngIf=\"allSummaries.length > 0\">\n <div class=\"d-flex align-items-center flex-wrap gap-1\">\n <span class=\"filter-label\">Filter:</span>\n <select class=\"filter-select\" [(ngModel)]=\"filterColumn\">\n <option value=\"\" disabled>Column</option>\n <option *ngFor=\"let col of columns\" [value]=\"col\">{{ col }}</option>\n </select>\n <select class=\"filter-select\" [(ngModel)]=\"filterOperator\">\n <option value=\">=\">&gt;=</option>\n <option value=\"<=\">&lt;=</option>\n <option value=\"=\">=</option>\n </select>\n <input\n type=\"number\"\n class=\"filter-input\"\n placeholder=\"value\"\n [(ngModel)]=\"filterValue\"\n min=\"0\"\n />\n <button class=\"btn-filter btn-blank\" (click)=\"addFilter()\">Add</button>\n <span class=\"filter-separator\">|</span>\n <span class=\"filter-label\">MET &gt;=</span>\n <input\n type=\"number\"\n class=\"filter-input\"\n placeholder=\"GeV\"\n (input)=\"updateMETFilter($event.target.value)\"\n />\n <button\n class=\"btn-filter btn-blank\"\n (click)=\"clearFilters()\"\n *ngIf=\"filters.length > 0 || metFilterMin !== null || searchQuery\"\n >\n Clear\n </button>\n </div>\n <!-- Active filters -->\n <div class=\"active-filters mt-1\" *ngIf=\"filters.length > 0\">\n <span class=\"filter-tag\" *ngFor=\"let filter of filters; index as i\">\n {{ getFilterLabel(filter) }}\n <button class=\"btn-blank filter-remove\" (click)=\"removeFilter(i)\">\n &times;\n </button>\n </span>\n </div>\n </div>\n\n <!-- Summary count -->\n <div class=\"summary-count mb-1\" *ngIf=\"allSummaries.length > 0\">\n {{ displayedSummaries.length }} of {{ allSummaries.length }} events\n </div>\n\n <!-- Event table -->\n <div\n class=\"boxBody table-responsive\"\n (keydown)=\"onTableKeydown($event)\"\n tabindex=\"0\"\n >\n <table\n class=\"table table-borderless table-sm\"\n *ngIf=\"allSummaries.length > 0\"\n >\n <thead>\n <tr>\n <th>Event</th>\n <th *ngFor=\"let col of columns\">\n <div class=\"head-wrapper\">\n <div>{{ col }}</div>\n <div class=\"sort-options\">\n <button\n class=\"icon-wrapper icon-button btn-blank up\"\n [ngClass]=\"{ 'sort-active': isSortActive(col, 'desc') }\"\n (click)=\"sort(col, 'desc')\"\n >\n <svg>\n <use href=\"assets/icons/expand.svg#expand\"></use>\n </svg>\n </button>\n <button\n class=\"icon-wrapper icon-button btn-blank\"\n [ngClass]=\"{ 'sort-active': isSortActive(col, 'asc') }\"\n (click)=\"sort(col, 'asc')\"\n >\n <svg>\n <use href=\"assets/icons/expand.svg#expand\"></use>\n </svg>\n </button>\n </div>\n </div>\n </th>\n <th>\n <div class=\"head-wrapper\">\n <div\n matTooltip=\"Reconstructed physics objects (excl. detector readouts)\"\n >\n Reco\n </div>\n <div class=\"sort-options\">\n <button\n class=\"icon-wrapper icon-button btn-blank up\"\n [ngClass]=\"{ 'sort-active': isSortActive('_reco', 'desc') }\"\n (click)=\"sortByReco('desc')\"\n >\n <svg>\n <use href=\"assets/icons/expand.svg#expand\"></use>\n </svg>\n </button>\n <button\n class=\"icon-wrapper icon-button btn-blank\"\n [ngClass]=\"{ 'sort-active': isSortActive('_reco', 'asc') }\"\n (click)=\"sortByReco('asc')\"\n >\n <svg>\n <use href=\"assets/icons/expand.svg#expand\"></use>\n </svg>\n </button>\n </div>\n </div>\n </th>\n <th>\n <div class=\"head-wrapper\">\n <div>MET</div>\n <div class=\"sort-options\">\n <button\n class=\"icon-wrapper icon-button btn-blank up\"\n [ngClass]=\"{ 'sort-active': isSortActive('_met', 'desc') }\"\n (click)=\"sortByMET('desc')\"\n >\n <svg>\n <use href=\"assets/icons/expand.svg#expand\"></use>\n </svg>\n </button>\n <button\n class=\"icon-wrapper icon-button btn-blank\"\n [ngClass]=\"{ 'sort-active': isSortActive('_met', 'asc') }\"\n (click)=\"sortByMET('asc')\"\n >\n <svg>\n <use href=\"assets/icons/expand.svg#expand\"></use>\n </svg>\n </button>\n </div>\n </div>\n </th>\n <th></th>\n </tr>\n </thead>\n <tbody>\n <tr\n *ngFor=\"let summary of displayedSummaries\"\n [id]=\"'event-row-' + summary.eventKey\"\n [ngClass]=\"{\n 'selected-event': selectedEventKey === summary.eventKey,\n 'loaded-event': isLoadedEvent(summary),\n }\"\n (click)=\"selectedEventKey = summary.eventKey\"\n (dblclick)=\"selectEvent(summary)\"\n >\n <td class=\"event-cell\">\n <div class=\"event-label\">{{ getEventLabel(summary) }}</div>\n <div class=\"run-label\" *ngIf=\"getRunLabel(summary)\">\n {{ getRunLabel(summary) }}\n </div>\n </td>\n <td\n *ngFor=\"let col of columns\"\n [ngClass]=\"{ 'dim-zero': getCount(summary, col) === 0 }\"\n >\n {{ formatNumber(getCount(summary, col)) }}\n </td>\n <td [ngClass]=\"{ 'dim-zero': getRecoTotal(summary) === 0 }\">\n {{ formatNumber(getRecoTotal(summary)) }}\n </td>\n <td>{{ formatMET(summary.met) }}</td>\n <td>\n <button\n class=\"btn-blank btn-load\"\n [matTooltip]=\"\n isLoadingEvent(summary) ? 'Loading...' : 'Load this event'\n \"\n (click)=\"selectEvent(summary); $event.stopPropagation()\"\n >\n <span\n *ngIf=\"isLoadingEvent(summary)\"\n class=\"loading-spinner\"\n ></span>\n <svg *ngIf=\"!isLoadingEvent(summary)\" class=\"load-icon\">\n <use href=\"assets/icons/views.svg#views\"></use>\n </svg>\n </button>\n </td>\n </tr>\n </tbody>\n </table>\n <p class=\"emptyBox\" *ngIf=\"allSummaries.length === 0\">\n Load event data to browse events here.\n </p>\n </div>\n\n <!-- Keyboard hint -->\n <div class=\"keyboard-hint mt-1\" *ngIf=\"allSummaries.length > 0\">\n Arrow keys to navigate, Enter to load, Shift+Left/Right for prev/next\n </div>\n </div>\n</app-overlay>\n", styles: [".event-browser{height:95%}.event-browser .search-box .search-input{flex:1;padding:4px 8px;font-size:12px;border:1px solid rgba(88,88,88,.15);box-shadow:var(--phoenix-icon-shadow);background-color:var(--phoenix-background-color-tertiary);color:var(--phoenix-text-color-secondary);border-radius:4px}.event-browser .search-box .search-input::placeholder{opacity:.5}.event-browser .search-box .search-hint{font-size:10px;color:var(--phoenix-text-color-secondary);opacity:.5;margin-left:.4rem;white-space:nowrap}.event-browser .filter-controls .filter-select,.event-browser .filter-controls .filter-input{padding:3px 6px;font-size:11px;border:1px solid rgba(88,88,88,.08);box-shadow:var(--phoenix-icon-shadow);background-color:var(--phoenix-background-color-tertiary);color:var(--phoenix-text-color-secondary);border-radius:3px}.event-browser .filter-controls .filter-select{width:7rem}.event-browser .filter-controls .filter-input{width:4rem}.event-browser .filter-controls .btn-filter{padding:3px 8px;font-size:11px;color:var(--phoenix-text-color-secondary);border:1px solid rgba(88,88,88,.2);border-radius:3px;cursor:pointer}.event-browser .filter-controls .btn-filter:hover{background:#ffffff1a}.event-browser .filter-controls .filter-separator{color:var(--phoenix-text-color-secondary);opacity:.4;margin:0 .2rem}.event-browser .filter-controls .filter-label{font-size:11px;color:var(--phoenix-text-color-secondary)}.event-browser .filter-controls .gap-1{gap:.3rem}.event-browser .active-filters .filter-tag{display:inline-flex;align-items:center;padding:1px 6px;margin-right:.3rem;font-size:10px;color:var(--phoenix-text-color-secondary);background:#ffffff14;border-radius:3px}.event-browser .active-filters .filter-tag .filter-remove{margin-left:4px;font-size:12px;line-height:1;cursor:pointer;color:var(--phoenix-text-color-secondary);opacity:.6}.event-browser .active-filters .filter-tag .filter-remove:hover{opacity:1}.event-browser .summary-count{font-size:11px;color:var(--phoenix-text-color-secondary);opacity:.7}.boxBody{height:80%;overflow:auto;outline:none}.boxBody p.emptyBox{max-width:21em;color:var(--phoenix-text-color-secondary)}.event-browser table{position:relative;color:var(--phoenix-text-color-secondary);font-size:12px}.event-browser table thead tr th{position:sticky;top:0;z-index:100;background:var(--phoenix-background-color-secondary);white-space:nowrap;font-size:11px}.event-browser table thead tr th .head-wrapper{display:flex;align-items:center}.event-browser table thead tr th .head-wrapper .sort-options{display:flex;flex-direction:row}.event-browser table thead tr th .head-wrapper .sort-options .icon-wrapper{display:flex;width:.85rem;height:.85rem;padding:.15rem;opacity:.5;transition:opacity .15s}.event-browser table thead tr th .head-wrapper .sort-options .icon-wrapper:hover,.event-browser table thead tr th .head-wrapper .sort-options .icon-wrapper.sort-active{opacity:1}.event-browser table thead tr th .head-wrapper .sort-options .icon-wrapper.up{transform:rotate(180deg)}.event-browser table thead tr th .head-wrapper .sort-options .icon-wrapper svg{width:100%;height:100%}.event-browser table tr *{padding-right:.8rem}.event-browser table tr *:last-child{padding-right:0}.event-browser table tbody tr{cursor:pointer;transition:background .1s}.event-browser table tbody tr:hover{background:#ffffff0d}.event-browser table tbody tr.selected-event{color:var(--phoenix-background-color);background:var(--phoenix-text-color);box-shadow:0 0 10px var(--phoenix-text-color)}.event-browser table tbody tr.loaded-event:not(.selected-event){background:#ffffff08}.event-browser table tbody tr.loaded-event:not(.selected-event) .event-label{font-weight:600}.event-browser table td{min-height:20px;white-space:nowrap}.event-browser table td.dim-zero{opacity:.25}.event-browser table .event-cell .event-label{font-size:12px;line-height:1.3}.event-browser table .event-cell .run-label{font-size:10px;opacity:.55;line-height:1.2}.event-browser table .btn-load{position:relative;width:1.4rem;height:1.4rem;text-align:center;background-color:var(--phoenix-options-icon-bg);border-radius:8px;cursor:pointer}.event-browser table .btn-load:hover{border:1px solid var(--phoenix-options-icon-path)}.event-browser table .btn-load .load-icon{position:absolute;top:0;left:0;padding:.3rem;width:100%;height:100%}.event-browser table .btn-load .loading-spinner{display:inline-block;width:10px;height:10px;border:2px solid rgba(255,255,255,.2);border-top-color:var(--phoenix-text-color-secondary);border-radius:50%;animation:spin .7s linear infinite}@keyframes spin{to{transform:rotate(360deg)}}.keyboard-hint{font-size:10px;color:var(--phoenix-text-color-secondary);opacity:.5}\n"] }]
4990
5611
  }], () => [{ type: EventDisplayService }], { showEventBrowser: [{
4991
5612
  type: Input
4992
5613
  }] }); })();
@@ -5000,7 +5621,12 @@ class EventBrowserComponent {
5000
5621
  this.overlay = overlay;
5001
5622
  }
5002
5623
  ngOnInit() {
5003
- const overlayRef = this.overlay.create();
5624
+ const positionStrategy = this.overlay
5625
+ .position()
5626
+ .global()
5627
+ .bottom('15px')
5628
+ .right('15px');
5629
+ const overlayRef = this.overlay.create({ positionStrategy });
5004
5630
  const overlayPortal = new ComponentPortal(EventBrowserOverlayComponent);
5005
5631
  this.overlayWindow = overlayRef.attach(overlayPortal);
5006
5632
  this.overlayWindow.instance.showEventBrowser = this.showEventBrowser;
@@ -5012,7 +5638,7 @@ class EventBrowserComponent {
5012
5638
  this.showEventBrowser = !this.showEventBrowser;
5013
5639
  this.overlayWindow.instance.showEventBrowser = this.showEventBrowser;
5014
5640
  }
5015
- static ɵfac = function EventBrowserComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || EventBrowserComponent)(i0.ɵɵdirectiveInject(i1$1.Overlay)); };
5641
+ static ɵfac = function EventBrowserComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || EventBrowserComponent)(i0.ɵɵdirectiveInject(i1$3.Overlay)); };
5016
5642
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: EventBrowserComponent, selectors: [["app-event-browser"]], standalone: false, decls: 1, vars: 1, consts: [["tooltip", "Event browser", "icon", "event-browser", 3, "click", "active"]], template: function EventBrowserComponent_Template(rf, ctx) { if (rf & 1) {
5017
5643
  i0.ɵɵelementStart(0, "app-menu-toggle", 0);
5018
5644
  i0.ɵɵlistener("click", function EventBrowserComponent_Template_app_menu_toggle_click_0_listener() { return ctx.toggleOverlay(); });
@@ -5024,7 +5650,7 @@ class EventBrowserComponent {
5024
5650
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(EventBrowserComponent, [{
5025
5651
  type: Component,
5026
5652
  args: [{ standalone: false, selector: 'app-event-browser', template: "<app-menu-toggle\n tooltip=\"Event browser\"\n icon=\"event-browser\"\n [active]=\"showEventBrowser\"\n (click)=\"toggleOverlay()\"\n>\n</app-menu-toggle>\n" }]
5027
- }], () => [{ type: i1$1.Overlay }], null); })();
5653
+ }], () => [{ type: i1$3.Overlay }], null); })();
5028
5654
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(EventBrowserComponent, { className: "EventBrowserComponent", filePath: "components/ui-menu/event-browser/event-browser.component.ts", lineNumber: 17 }); })();
5029
5655
 
5030
5656
  const _c0$3 = ["etaPhiCanvas"];
@@ -5062,6 +5688,8 @@ class EtaPhiPanelOverlayComponent {
5062
5688
  ngOnInit() {
5063
5689
  this.unsubscribes.push(this.eventDisplay.listenToDisplayedEventChange(() => {
5064
5690
  this.rebuildData();
5691
+ }), this.eventDisplay.listenToStateChange?.(() => {
5692
+ this.rebuildData();
5065
5693
  }));
5066
5694
  }
5067
5695
  ngAfterViewInit() {
@@ -5185,6 +5813,9 @@ class EtaPhiPanelOverlayComponent {
5185
5813
  if (!collections[caloType])
5186
5814
  continue;
5187
5815
  for (const collName of collections[caloType]) {
5816
+ if (this.eventDisplay.isCollectionVisible?.(collName) === false) {
5817
+ continue;
5818
+ }
5188
5819
  const items = this.eventDisplay.getCollection(collName);
5189
5820
  if (!items)
5190
5821
  continue;
@@ -5194,6 +5825,9 @@ class EtaPhiPanelOverlayComponent {
5194
5825
  }
5195
5826
  if (cell.energy <= energyThreshold)
5196
5827
  continue;
5828
+ if (this.eventDisplay.isItemVisible?.(collName, cell) === false) {
5829
+ continue;
5830
+ }
5197
5831
  const ei = Math.floor(((cell.eta - etaRange[0]) / (etaRange[1] - etaRange[0])) * etaBins);
5198
5832
  const pi = Math.floor(((cell.phi - phiRange[0]) / (phiRange[1] - phiRange[0])) * phiBins);
5199
5833
  if (ei >= 0 && ei < etaBins && pi >= 0 && pi < phiBins) {
@@ -5218,12 +5852,18 @@ class EtaPhiPanelOverlayComponent {
5218
5852
  // Jets
5219
5853
  if (collections['Jets']) {
5220
5854
  for (const collName of collections['Jets']) {
5855
+ if (this.eventDisplay.isCollectionVisible?.(collName) === false) {
5856
+ continue;
5857
+ }
5221
5858
  const jets = this.eventDisplay.getCollection(collName);
5222
5859
  if (!jets)
5223
5860
  continue;
5224
5861
  jets.forEach((jet, i) => {
5225
5862
  if (jet.eta == null || jet.phi == null)
5226
5863
  return;
5864
+ if (this.eventDisplay.isItemVisible?.(collName, jet) === false) {
5865
+ return;
5866
+ }
5227
5867
  this.markers.push({
5228
5868
  eta: jet.eta,
5229
5869
  phi: jet.phi,
@@ -5239,12 +5879,18 @@ class EtaPhiPanelOverlayComponent {
5239
5879
  // Muons
5240
5880
  if (collections['Muons']) {
5241
5881
  for (const collName of collections['Muons']) {
5882
+ if (this.eventDisplay.isCollectionVisible?.(collName) === false) {
5883
+ continue;
5884
+ }
5242
5885
  const muons = this.eventDisplay.getCollection(collName);
5243
5886
  if (!muons)
5244
5887
  continue;
5245
5888
  muons.forEach((mu, i) => {
5246
5889
  if (mu.eta == null || mu.phi == null)
5247
5890
  return;
5891
+ if (this.eventDisplay.isItemVisible?.(collName, mu) === false) {
5892
+ return;
5893
+ }
5248
5894
  this.markers.push({
5249
5895
  eta: mu.eta,
5250
5896
  phi: mu.phi,
@@ -5259,12 +5905,18 @@ class EtaPhiPanelOverlayComponent {
5259
5905
  // Electrons
5260
5906
  if (collections['Electrons']) {
5261
5907
  for (const collName of collections['Electrons']) {
5908
+ if (this.eventDisplay.isCollectionVisible?.(collName) === false) {
5909
+ continue;
5910
+ }
5262
5911
  const electrons = this.eventDisplay.getCollection(collName);
5263
5912
  if (!electrons)
5264
5913
  continue;
5265
5914
  electrons.forEach((el, i) => {
5266
5915
  if (el.eta == null || el.phi == null)
5267
5916
  return;
5917
+ if (this.eventDisplay.isItemVisible?.(collName, el) === false) {
5918
+ return;
5919
+ }
5268
5920
  this.markers.push({
5269
5921
  eta: el.eta,
5270
5922
  phi: el.phi,
@@ -5279,12 +5931,18 @@ class EtaPhiPanelOverlayComponent {
5279
5931
  // Photons
5280
5932
  if (collections['Photons']) {
5281
5933
  for (const collName of collections['Photons']) {
5934
+ if (this.eventDisplay.isCollectionVisible?.(collName) === false) {
5935
+ continue;
5936
+ }
5282
5937
  const photons = this.eventDisplay.getCollection(collName);
5283
5938
  if (!photons)
5284
5939
  continue;
5285
5940
  photons.forEach((ph, i) => {
5286
5941
  if (ph.eta == null || ph.phi == null)
5287
5942
  return;
5943
+ if (this.eventDisplay.isItemVisible?.(collName, ph) === false) {
5944
+ return;
5945
+ }
5288
5946
  this.markers.push({
5289
5947
  eta: ph.eta,
5290
5948
  phi: ph.phi,
@@ -5299,6 +5957,9 @@ class EtaPhiPanelOverlayComponent {
5299
5957
  // Tracks (derive eta/phi from dparams if needed)
5300
5958
  if (collections['Tracks']) {
5301
5959
  for (const collName of collections['Tracks']) {
5960
+ if (this.eventDisplay.isCollectionVisible?.(collName) === false) {
5961
+ continue;
5962
+ }
5302
5963
  const tracks = this.eventDisplay.getCollection(collName);
5303
5964
  if (!tracks)
5304
5965
  continue;
@@ -5312,6 +5973,9 @@ class EtaPhiPanelOverlayComponent {
5312
5973
  }
5313
5974
  if (eta == null || phi == null)
5314
5975
  return;
5976
+ if (this.eventDisplay.isItemVisible?.(collName, trk) === false) {
5977
+ return;
5978
+ }
5315
5979
  this.markers.push({
5316
5980
  eta,
5317
5981
  phi,
@@ -5326,12 +5990,18 @@ class EtaPhiPanelOverlayComponent {
5326
5990
  // MET
5327
5991
  if (collections['MissingEnergy']) {
5328
5992
  for (const collName of collections['MissingEnergy']) {
5993
+ if (this.eventDisplay.isCollectionVisible?.(collName) === false) {
5994
+ continue;
5995
+ }
5329
5996
  const metItems = this.eventDisplay.getCollection(collName);
5330
5997
  if (!metItems)
5331
5998
  continue;
5332
5999
  for (const met of metItems) {
5333
6000
  if (met.etx == null || met.ety == null)
5334
6001
  continue;
6002
+ if (this.eventDisplay.isItemVisible?.(collName, met) === false) {
6003
+ continue;
6004
+ }
5335
6005
  const metPhi = Math.atan2(met.ety, met.etx);
5336
6006
  const metMag = Math.sqrt(met.etx * met.etx + met.ety * met.ety);
5337
6007
  this.markers.push({
@@ -5666,13 +6336,16 @@ class EtaPhiPanelOverlayComponent {
5666
6336
 
5667
6337
  class EtaPhiPanelComponent {
5668
6338
  overlay;
6339
+ overlayCascade;
5669
6340
  showPanel = false;
5670
6341
  overlayWindow;
5671
- constructor(overlay) {
6342
+ constructor(overlay, overlayCascade) {
5672
6343
  this.overlay = overlay;
6344
+ this.overlayCascade = overlayCascade;
5673
6345
  }
5674
6346
  ngOnInit() {
5675
- const overlayRef = this.overlay.create();
6347
+ const positionStrategy = this.overlayCascade.getCascadePositionStrategy();
6348
+ const overlayRef = this.overlay.create({ positionStrategy });
5676
6349
  const overlayPortal = new ComponentPortal(EtaPhiPanelOverlayComponent);
5677
6350
  this.overlayWindow = overlayRef.attach(overlayPortal);
5678
6351
  this.overlayWindow.instance.showPanel = this.showPanel;
@@ -5684,7 +6357,7 @@ class EtaPhiPanelComponent {
5684
6357
  this.showPanel = !this.showPanel;
5685
6358
  this.overlayWindow.instance.showPanel = this.showPanel;
5686
6359
  }
5687
- static ɵfac = function EtaPhiPanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || EtaPhiPanelComponent)(i0.ɵɵdirectiveInject(i1$1.Overlay)); };
6360
+ static ɵfac = function EtaPhiPanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || EtaPhiPanelComponent)(i0.ɵɵdirectiveInject(i1$3.Overlay), i0.ɵɵdirectiveInject(OverlayCascadeService)); };
5688
6361
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: EtaPhiPanelComponent, selectors: [["app-eta-phi-panel"]], standalone: false, decls: 1, vars: 1, consts: [["tooltip", "Eta-phi energy map", "icon", "eta-phi", 3, "click", "active"]], template: function EtaPhiPanelComponent_Template(rf, ctx) { if (rf & 1) {
5689
6362
  i0.ɵɵelementStart(0, "app-menu-toggle", 0);
5690
6363
  i0.ɵɵlistener("click", function EtaPhiPanelComponent_Template_app_menu_toggle_click_0_listener() { return ctx.toggleOverlay(); });
@@ -5696,8 +6369,8 @@ class EtaPhiPanelComponent {
5696
6369
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(EtaPhiPanelComponent, [{
5697
6370
  type: Component,
5698
6371
  args: [{ standalone: false, selector: 'app-eta-phi-panel', template: "<app-menu-toggle\n tooltip=\"Eta-phi energy map\"\n icon=\"eta-phi\"\n [active]=\"showPanel\"\n (click)=\"toggleOverlay()\"\n>\n</app-menu-toggle>\n" }]
5699
- }], () => [{ type: i1$1.Overlay }], null); })();
5700
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(EtaPhiPanelComponent, { className: "EtaPhiPanelComponent", filePath: "components/ui-menu/eta-phi-panel/eta-phi-panel.component.ts", lineNumber: 17 }); })();
6372
+ }], () => [{ type: i1$3.Overlay }, { type: OverlayCascadeService }], null); })();
6373
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(EtaPhiPanelComponent, { className: "EtaPhiPanelComponent", filePath: "components/ui-menu/eta-phi-panel/eta-phi-panel.component.ts", lineNumber: 18 }); })();
5701
6374
 
5702
6375
  function KinematicsPanelOverlayComponent_div_1_div_1_div_2_option_2_Template(rf, ctx) { if (rf & 1) {
5703
6376
  i0.ɵɵelementStart(0, "option", 17);
@@ -6227,11 +6900,11 @@ class KinematicsPanelOverlayComponent {
6227
6900
  i0.ɵɵproperty("overlayTitle", ctx.config.title)("resizable", true)("active", ctx.showKinematics);
6228
6901
  i0.ɵɵadvance();
6229
6902
  i0.ɵɵproperty("ngIf", ctx.showKinematics);
6230
- } }, dependencies: [i2.NgClass, i2.NgForOf, i2.NgIf, i3$1.MatTooltip, i4.NgSelectOption, i4.ɵNgSelectMultipleOption, OverlayComponent], styles: [".kinematics-panel[_ngcontent-%COMP%]{height:95%;display:flex;flex-direction:column}.panel-header[_ngcontent-%COMP%]{flex-shrink:0;padding:.5rem .75rem .25rem}.panel-header[_ngcontent-%COMP%] .header-top[_ngcontent-%COMP%]{display:flex;align-items:center;gap:.8rem;min-height:2rem}.panel-header[_ngcontent-%COMP%] .collection-selector[_ngcontent-%COMP%] select[_ngcontent-%COMP%]{padding:4px 8px;font-size:12px;border:1px solid rgba(88,88,88,.08);box-shadow:var(--phoenix-icon-shadow);background-color:var(--phoenix-background-color-tertiary);color:var(--phoenix-text-color-secondary)}.panel-header[_ngcontent-%COMP%] .collection-name[_ngcontent-%COMP%]{color:var(--phoenix-text-color-secondary);font-size:.85rem;font-weight:500}.panel-header[_ngcontent-%COMP%] .track-count[_ngcontent-%COMP%]{color:var(--phoenix-text-color-secondary);font-size:.75rem;opacity:.6;margin-left:auto}.panel-header[_ngcontent-%COMP%] .export-btn[_ngcontent-%COMP%]{display:flex;align-items:center;justify-content:center;width:1.5rem;height:1.5rem;padding:.3rem;border:none;background:var(--phoenix-options-icon-bg);border-radius:8px;cursor:pointer;flex-shrink:0}.panel-header[_ngcontent-%COMP%] .export-btn[_ngcontent-%COMP%]:hover{outline:1px solid var(--phoenix-options-icon-path)}.panel-header[_ngcontent-%COMP%] .export-btn[_ngcontent-%COMP%] svg[_ngcontent-%COMP%]{width:100%;height:100%}.filter-row[_ngcontent-%COMP%]{padding:.3rem 0}.filter-row[_ngcontent-%COMP%] label[_ngcontent-%COMP%]{display:flex;align-items:center;gap:.4rem;color:var(--phoenix-text-color-secondary);font-size:.75rem;opacity:.8}.filter-row[_ngcontent-%COMP%] .filter-input[_ngcontent-%COMP%]{width:4rem;padding:2px 6px;font-size:.75rem;border:1px solid rgba(255,255,255,.12);border-radius:4px;background:var(--phoenix-background-color-tertiary);color:var(--phoenix-text-color-secondary)}.filter-row[_ngcontent-%COMP%] .filter-input[_ngcontent-%COMP%]:focus{outline:1px solid var(--phoenix-text-color-secondary)}.filter-row[_ngcontent-%COMP%] .filter-unit[_ngcontent-%COMP%]{opacity:.5;font-size:.7rem}.table-container[_ngcontent-%COMP%]{flex:1;overflow:auto;outline:none}.kinematics-table[_ngcontent-%COMP%]{width:100%;border-collapse:collapse;color:var(--phoenix-text-color-secondary)}.kinematics-table[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] th[_ngcontent-%COMP%]{position:sticky;top:0;z-index:10;background:var(--phoenix-background-color-secondary);padding:.4rem .7rem;font-size:.78rem;font-weight:600;white-space:nowrap;text-align:left;border-bottom:1px solid rgba(255,255,255,.08)}.kinematics-table[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] th.sortable[_ngcontent-%COMP%]{cursor:pointer;-webkit-user-select:none;user-select:none}.kinematics-table[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] th.sortable[_ngcontent-%COMP%]:hover, .kinematics-table[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] th.sorted[_ngcontent-%COMP%]{color:var(--phoenix-text-color)}.kinematics-table[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] th[_ngcontent-%COMP%] .col-unit[_ngcontent-%COMP%]{opacity:.5;font-weight:400;font-size:.68rem;margin-left:.15rem}.kinematics-table[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] th[_ngcontent-%COMP%] .sort-arrow[_ngcontent-%COMP%]{font-size:.55rem;margin-left:.2rem;opacity:.7}.kinematics-table[_ngcontent-%COMP%] tbody[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]{cursor:pointer;transition:background .12s ease}.kinematics-table[_ngcontent-%COMP%] tbody[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]:hover{background:#ffffff0a}.kinematics-table[_ngcontent-%COMP%] tbody[_ngcontent-%COMP%] tr.active-object[_ngcontent-%COMP%]{color:var(--phoenix-background-color);background:var(--phoenix-text-color);box-shadow:0 0 12px var(--phoenix-text-color)}.kinematics-table[_ngcontent-%COMP%] tbody[_ngcontent-%COMP%] tr.active-object[_ngcontent-%COMP%] .icon-btn[_ngcontent-%COMP%]{--phoenix-options-icon-path: var(--phoenix-background-color);--phoenix-options-icon-bg: var(--phoenix-text-color-hover)}.kinematics-table[_ngcontent-%COMP%] tbody[_ngcontent-%COMP%] tr.is-cut[_ngcontent-%COMP%]{opacity:.35}.kinematics-table[_ngcontent-%COMP%] td[_ngcontent-%COMP%]{padding:.3rem .7rem;font-size:.78rem;font-variant-numeric:tabular-nums}.kinematics-table[_ngcontent-%COMP%] td.col-index[_ngcontent-%COMP%]{color:#fff6;width:2.5rem;text-align:right;padding-right:.4rem;white-space:nowrap}.kinematics-table[_ngcontent-%COMP%] td.col-action[_ngcontent-%COMP%]{width:2rem;padding:.2rem}.kinematics-table[_ngcontent-%COMP%] td.col-data[_ngcontent-%COMP%]{text-align:right}.charge-pos[_ngcontent-%COMP%]{color:#ff7b7b;font-weight:600}.charge-pos[_ngcontent-%COMP%]:before{content:\"+\"}.charge-neg[_ngcontent-%COMP%]{color:#7bb5ff;font-weight:600}.icon-btn[_ngcontent-%COMP%]{display:flex;align-items:center;justify-content:center;width:1.4rem;height:1.4rem;padding:.3rem;border:none;background:var(--phoenix-options-icon-bg);border-radius:8px;cursor:pointer}.icon-btn[_ngcontent-%COMP%]:hover{outline:1px solid var(--phoenix-options-icon-path)}.icon-btn[_ngcontent-%COMP%] svg[_ngcontent-%COMP%]{width:100%;height:100%}.empty-state[_ngcontent-%COMP%]{color:var(--phoenix-text-color-secondary);opacity:.5;text-align:center;padding:2rem;max-width:18em;margin:2rem auto;font-size:.85rem}"] });
6903
+ } }, dependencies: [i2.NgClass, i2.NgForOf, i2.NgIf, i3$1.MatTooltip, i4.NgSelectOption, i4.ɵNgSelectMultipleOption, OverlayComponent], styles: [".kinematics-panel[_ngcontent-%COMP%]{width:620px;height:450px;display:flex;flex-direction:column}.panel-header[_ngcontent-%COMP%]{flex-shrink:0;padding:.5rem .75rem .25rem}.panel-header[_ngcontent-%COMP%] .header-top[_ngcontent-%COMP%]{display:flex;align-items:center;gap:.8rem;min-height:2rem}.panel-header[_ngcontent-%COMP%] .collection-selector[_ngcontent-%COMP%] select[_ngcontent-%COMP%]{padding:4px 8px;font-size:12px;border:1px solid rgba(88,88,88,.08);box-shadow:var(--phoenix-icon-shadow);background-color:var(--phoenix-background-color-tertiary);color:var(--phoenix-text-color-secondary)}.panel-header[_ngcontent-%COMP%] .collection-name[_ngcontent-%COMP%]{color:var(--phoenix-text-color-secondary);font-size:.85rem;font-weight:500}.panel-header[_ngcontent-%COMP%] .track-count[_ngcontent-%COMP%]{color:var(--phoenix-text-color-secondary);font-size:.75rem;opacity:.6;margin-left:auto}.panel-header[_ngcontent-%COMP%] .export-btn[_ngcontent-%COMP%]{display:flex;align-items:center;justify-content:center;width:1.5rem;height:1.5rem;padding:.3rem;border:none;background:var(--phoenix-options-icon-bg);border-radius:8px;cursor:pointer;flex-shrink:0}.panel-header[_ngcontent-%COMP%] .export-btn[_ngcontent-%COMP%]:hover{outline:1px solid var(--phoenix-options-icon-path)}.panel-header[_ngcontent-%COMP%] .export-btn[_ngcontent-%COMP%] svg[_ngcontent-%COMP%]{width:100%;height:100%}.filter-row[_ngcontent-%COMP%]{padding:.3rem 0}.filter-row[_ngcontent-%COMP%] label[_ngcontent-%COMP%]{display:flex;align-items:center;gap:.4rem;color:var(--phoenix-text-color-secondary);font-size:.75rem;opacity:.8}.filter-row[_ngcontent-%COMP%] .filter-input[_ngcontent-%COMP%]{width:4rem;padding:2px 6px;font-size:.75rem;border:1px solid rgba(255,255,255,.12);border-radius:4px;background:var(--phoenix-background-color-tertiary);color:var(--phoenix-text-color-secondary)}.filter-row[_ngcontent-%COMP%] .filter-input[_ngcontent-%COMP%]:focus{outline:1px solid var(--phoenix-text-color-secondary)}.filter-row[_ngcontent-%COMP%] .filter-unit[_ngcontent-%COMP%]{opacity:.5;font-size:.7rem}.table-container[_ngcontent-%COMP%]{flex:1;overflow:auto;outline:none}.kinematics-table[_ngcontent-%COMP%]{width:100%;border-collapse:collapse;color:var(--phoenix-text-color-secondary)}.kinematics-table[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] th[_ngcontent-%COMP%]{position:sticky;top:0;z-index:10;background:var(--phoenix-background-color-secondary);padding:.4rem .7rem;font-size:.78rem;font-weight:600;white-space:nowrap;text-align:left;border-bottom:1px solid rgba(255,255,255,.08)}.kinematics-table[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] th.sortable[_ngcontent-%COMP%]{cursor:pointer;-webkit-user-select:none;user-select:none}.kinematics-table[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] th.sortable[_ngcontent-%COMP%]:hover, .kinematics-table[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] th.sorted[_ngcontent-%COMP%]{color:var(--phoenix-text-color)}.kinematics-table[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] th[_ngcontent-%COMP%] .col-unit[_ngcontent-%COMP%]{opacity:.5;font-weight:400;font-size:.68rem;margin-left:.15rem}.kinematics-table[_ngcontent-%COMP%] thead[_ngcontent-%COMP%] tr[_ngcontent-%COMP%] th[_ngcontent-%COMP%] .sort-arrow[_ngcontent-%COMP%]{font-size:.55rem;margin-left:.2rem;opacity:.7}.kinematics-table[_ngcontent-%COMP%] tbody[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]{cursor:pointer;transition:background .12s ease}.kinematics-table[_ngcontent-%COMP%] tbody[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]:hover{background:#ffffff0a}.kinematics-table[_ngcontent-%COMP%] tbody[_ngcontent-%COMP%] tr.active-object[_ngcontent-%COMP%]{color:var(--phoenix-background-color);background:var(--phoenix-text-color);box-shadow:0 0 12px var(--phoenix-text-color)}.kinematics-table[_ngcontent-%COMP%] tbody[_ngcontent-%COMP%] tr.active-object[_ngcontent-%COMP%] .icon-btn[_ngcontent-%COMP%]{--phoenix-options-icon-path: var(--phoenix-background-color);--phoenix-options-icon-bg: var(--phoenix-text-color-hover)}.kinematics-table[_ngcontent-%COMP%] tbody[_ngcontent-%COMP%] tr.is-cut[_ngcontent-%COMP%]{opacity:.35}.kinematics-table[_ngcontent-%COMP%] td[_ngcontent-%COMP%]{padding:.3rem .7rem;font-size:.78rem;font-variant-numeric:tabular-nums}.kinematics-table[_ngcontent-%COMP%] td.col-index[_ngcontent-%COMP%]{color:#fff6;width:2.5rem;text-align:right;padding-right:.4rem;white-space:nowrap}.kinematics-table[_ngcontent-%COMP%] td.col-action[_ngcontent-%COMP%]{width:2rem;padding:.2rem}.kinematics-table[_ngcontent-%COMP%] td.col-data[_ngcontent-%COMP%]{text-align:right}.charge-pos[_ngcontent-%COMP%]{color:#ff7b7b;font-weight:600}.charge-pos[_ngcontent-%COMP%]:before{content:\"+\"}.charge-neg[_ngcontent-%COMP%]{color:#7bb5ff;font-weight:600}.icon-btn[_ngcontent-%COMP%]{display:flex;align-items:center;justify-content:center;width:1.4rem;height:1.4rem;padding:.3rem;border:none;background:var(--phoenix-options-icon-bg);border-radius:8px;cursor:pointer}.icon-btn[_ngcontent-%COMP%]:hover{outline:1px solid var(--phoenix-options-icon-path)}.icon-btn[_ngcontent-%COMP%] svg[_ngcontent-%COMP%]{width:100%;height:100%}.empty-state[_ngcontent-%COMP%]{color:var(--phoenix-text-color-secondary);opacity:.5;text-align:center;padding:2rem;max-width:18em;margin:2rem auto;font-size:.85rem}"] });
6231
6904
  }
6232
6905
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(KinematicsPanelOverlayComponent, [{
6233
6906
  type: Component,
6234
- args: [{ standalone: false, selector: 'app-kinematics-panel-overlay', template: "<app-overlay\n [overlayTitle]=\"config.title\"\n icon=\"kinematics\"\n [resizable]=\"true\"\n [active]=\"showKinematics\"\n>\n <div *ngIf=\"showKinematics\" class=\"kinematics-panel\">\n <!-- Header: collection selector + filter + count + export -->\n <div class=\"panel-header\" *ngIf=\"collections?.length > 0\">\n <div class=\"header-top\">\n <div class=\"collection-selector\" *ngIf=\"collections.length > 1\">\n <select (change)=\"selectCollection($event.target.value)\">\n <option\n *ngFor=\"let c of collections\"\n [value]=\"c\"\n [selected]=\"c === selectedCollection\"\n >\n {{ c }}\n </option>\n </select>\n </div>\n <span class=\"collection-name\" *ngIf=\"collections.length === 1\">\n {{ selectedCollection }}\n </span>\n <span class=\"track-count\">\n {{ rows.length\n }}<span *ngIf=\"filterValue > 0\"> / {{ allRows.length }}</span> tracks\n </span>\n <button\n class=\"export-btn\"\n matTooltip=\"Export as TSV\"\n (click)=\"exportTSV()\"\n *ngIf=\"rows.length > 0\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 20 20\"\n fill=\"var(--phoenix-options-icon-path, #fff)\"\n >\n <path\n d=\"M10 3a.75.75 0 0 1 .75.75v7.69l2.22-2.22a.75.75 0 1 1 1.06 1.06l-3.5 3.5a.75.75 0 0 1-1.06 0l-3.5-3.5a.75.75 0 1 1 1.06-1.06l2.22 2.22V3.75A.75.75 0 0 1 10 3Z\"\n />\n <path\n d=\"M3 15.75a.75.75 0 0 1 .75-.75h12.5a.75.75 0 0 1 0 1.5H3.75a.75.75 0 0 1-.75-.75Z\"\n />\n </svg>\n </button>\n </div>\n\n <!-- Filter row -->\n <div class=\"filter-row\" *ngIf=\"filterCol\">\n <label>\n {{ filterCol.label }} &ge;\n <input\n type=\"number\"\n class=\"filter-input\"\n [value]=\"filterValue\"\n (input)=\"onFilterChange($event.target.value)\"\n step=\"1\"\n min=\"0\"\n />\n <span class=\"filter-unit\" *ngIf=\"filterCol.unit\">{{\n filterCol.unit\n }}</span>\n </label>\n </div>\n </div>\n\n <!-- Table with keyboard navigation -->\n <div\n class=\"table-container\"\n *ngIf=\"rows.length > 0\"\n tabindex=\"0\"\n (keydown)=\"onKeyDown($event)\"\n >\n <table class=\"kinematics-table\">\n <thead>\n <tr>\n <th class=\"col-index\">#</th>\n <th class=\"col-action\"></th>\n <th\n *ngFor=\"let col of config.columns\"\n class=\"col-data sortable\"\n [class.sorted]=\"sortColumn === col.id\"\n [matTooltip]=\"col.tooltip\"\n (click)=\"sort(col.id)\"\n >\n <span class=\"col-label\">{{ col.label }}</span>\n <span *ngIf=\"col.unit\" class=\"col-unit\">({{ col.unit }})</span>\n <span class=\"sort-arrow\" *ngIf=\"sortColumn === col.id\">\n {{ sortDirection === 'asc' ? '\\u25B2' : '\\u25BC' }}\n </span>\n </th>\n </tr>\n </thead>\n <tbody>\n <tr\n *ngFor=\"let row of rows; index as i\"\n [id]=\"'kin-' + row.uuid\"\n [class.active-object]=\"activeRowUuid === row.uuid\"\n [class.is-cut]=\"row.isCut\"\n (click)=\"selectTrack(row)\"\n >\n <td class=\"col-index\" [style.color]=\"getChargeColor(row)\">\n {{ i + 1 }}\n </td>\n <td class=\"col-action\">\n <button\n *ngIf=\"row.uuid\"\n class=\"icon-btn\"\n matTooltip=\"Look at track\"\n (click)=\"lookAtTrack(row.uuid, $event)\"\n >\n <svg>\n <use href=\"assets/icons/views.svg#views\"></use>\n </svg>\n </button>\n </td>\n <td\n *ngFor=\"let col of config.columns\"\n class=\"col-data\"\n [ngClass]=\"getChargeClass(col, row.values[col.id])\"\n >\n {{ formatValue(row.values[col.id], col) }}\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n\n <!-- Empty states -->\n <p\n class=\"empty-state\"\n *ngIf=\"collections?.length > 0 && rows.length === 0 && allRows.length > 0\"\n >\n No tracks above {{ filterCol?.label }} &ge; {{ filterValue }}\n {{ filterCol?.unit }}.\n </p>\n <p\n class=\"empty-state\"\n *ngIf=\"collections?.length > 0 && allRows.length === 0\"\n >\n No objects in this collection.\n </p>\n <p class=\"empty-state\" *ngIf=\"!collections || collections.length === 0\">\n Load event data to view track kinematics.\n </p>\n </div>\n</app-overlay>\n", styles: [".kinematics-panel{height:95%;display:flex;flex-direction:column}.panel-header{flex-shrink:0;padding:.5rem .75rem .25rem}.panel-header .header-top{display:flex;align-items:center;gap:.8rem;min-height:2rem}.panel-header .collection-selector select{padding:4px 8px;font-size:12px;border:1px solid rgba(88,88,88,.08);box-shadow:var(--phoenix-icon-shadow);background-color:var(--phoenix-background-color-tertiary);color:var(--phoenix-text-color-secondary)}.panel-header .collection-name{color:var(--phoenix-text-color-secondary);font-size:.85rem;font-weight:500}.panel-header .track-count{color:var(--phoenix-text-color-secondary);font-size:.75rem;opacity:.6;margin-left:auto}.panel-header .export-btn{display:flex;align-items:center;justify-content:center;width:1.5rem;height:1.5rem;padding:.3rem;border:none;background:var(--phoenix-options-icon-bg);border-radius:8px;cursor:pointer;flex-shrink:0}.panel-header .export-btn:hover{outline:1px solid var(--phoenix-options-icon-path)}.panel-header .export-btn svg{width:100%;height:100%}.filter-row{padding:.3rem 0}.filter-row label{display:flex;align-items:center;gap:.4rem;color:var(--phoenix-text-color-secondary);font-size:.75rem;opacity:.8}.filter-row .filter-input{width:4rem;padding:2px 6px;font-size:.75rem;border:1px solid rgba(255,255,255,.12);border-radius:4px;background:var(--phoenix-background-color-tertiary);color:var(--phoenix-text-color-secondary)}.filter-row .filter-input:focus{outline:1px solid var(--phoenix-text-color-secondary)}.filter-row .filter-unit{opacity:.5;font-size:.7rem}.table-container{flex:1;overflow:auto;outline:none}.kinematics-table{width:100%;border-collapse:collapse;color:var(--phoenix-text-color-secondary)}.kinematics-table thead tr th{position:sticky;top:0;z-index:10;background:var(--phoenix-background-color-secondary);padding:.4rem .7rem;font-size:.78rem;font-weight:600;white-space:nowrap;text-align:left;border-bottom:1px solid rgba(255,255,255,.08)}.kinematics-table thead tr th.sortable{cursor:pointer;-webkit-user-select:none;user-select:none}.kinematics-table thead tr th.sortable:hover,.kinematics-table thead tr th.sorted{color:var(--phoenix-text-color)}.kinematics-table thead tr th .col-unit{opacity:.5;font-weight:400;font-size:.68rem;margin-left:.15rem}.kinematics-table thead tr th .sort-arrow{font-size:.55rem;margin-left:.2rem;opacity:.7}.kinematics-table tbody tr{cursor:pointer;transition:background .12s ease}.kinematics-table tbody tr:hover{background:#ffffff0a}.kinematics-table tbody tr.active-object{color:var(--phoenix-background-color);background:var(--phoenix-text-color);box-shadow:0 0 12px var(--phoenix-text-color)}.kinematics-table tbody tr.active-object .icon-btn{--phoenix-options-icon-path: var(--phoenix-background-color);--phoenix-options-icon-bg: var(--phoenix-text-color-hover)}.kinematics-table tbody tr.is-cut{opacity:.35}.kinematics-table td{padding:.3rem .7rem;font-size:.78rem;font-variant-numeric:tabular-nums}.kinematics-table td.col-index{color:#fff6;width:2.5rem;text-align:right;padding-right:.4rem;white-space:nowrap}.kinematics-table td.col-action{width:2rem;padding:.2rem}.kinematics-table td.col-data{text-align:right}.charge-pos{color:#ff7b7b;font-weight:600}.charge-pos:before{content:\"+\"}.charge-neg{color:#7bb5ff;font-weight:600}.icon-btn{display:flex;align-items:center;justify-content:center;width:1.4rem;height:1.4rem;padding:.3rem;border:none;background:var(--phoenix-options-icon-bg);border-radius:8px;cursor:pointer}.icon-btn:hover{outline:1px solid var(--phoenix-options-icon-path)}.icon-btn svg{width:100%;height:100%}.empty-state{color:var(--phoenix-text-color-secondary);opacity:.5;text-align:center;padding:2rem;max-width:18em;margin:2rem auto;font-size:.85rem}\n"] }]
6907
+ args: [{ standalone: false, selector: 'app-kinematics-panel-overlay', template: "<app-overlay\n [overlayTitle]=\"config.title\"\n icon=\"kinematics\"\n [resizable]=\"true\"\n [active]=\"showKinematics\"\n>\n <div *ngIf=\"showKinematics\" class=\"kinematics-panel\">\n <!-- Header: collection selector + filter + count + export -->\n <div class=\"panel-header\" *ngIf=\"collections?.length > 0\">\n <div class=\"header-top\">\n <div class=\"collection-selector\" *ngIf=\"collections.length > 1\">\n <select (change)=\"selectCollection($event.target.value)\">\n <option\n *ngFor=\"let c of collections\"\n [value]=\"c\"\n [selected]=\"c === selectedCollection\"\n >\n {{ c }}\n </option>\n </select>\n </div>\n <span class=\"collection-name\" *ngIf=\"collections.length === 1\">\n {{ selectedCollection }}\n </span>\n <span class=\"track-count\">\n {{ rows.length\n }}<span *ngIf=\"filterValue > 0\"> / {{ allRows.length }}</span> tracks\n </span>\n <button\n class=\"export-btn\"\n matTooltip=\"Export as TSV\"\n (click)=\"exportTSV()\"\n *ngIf=\"rows.length > 0\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 20 20\"\n fill=\"var(--phoenix-options-icon-path, #fff)\"\n >\n <path\n d=\"M10 3a.75.75 0 0 1 .75.75v7.69l2.22-2.22a.75.75 0 1 1 1.06 1.06l-3.5 3.5a.75.75 0 0 1-1.06 0l-3.5-3.5a.75.75 0 1 1 1.06-1.06l2.22 2.22V3.75A.75.75 0 0 1 10 3Z\"\n />\n <path\n d=\"M3 15.75a.75.75 0 0 1 .75-.75h12.5a.75.75 0 0 1 0 1.5H3.75a.75.75 0 0 1-.75-.75Z\"\n />\n </svg>\n </button>\n </div>\n\n <!-- Filter row -->\n <div class=\"filter-row\" *ngIf=\"filterCol\">\n <label>\n {{ filterCol.label }} &ge;\n <input\n type=\"number\"\n class=\"filter-input\"\n [value]=\"filterValue\"\n (input)=\"onFilterChange($event.target.value)\"\n step=\"1\"\n min=\"0\"\n />\n <span class=\"filter-unit\" *ngIf=\"filterCol.unit\">{{\n filterCol.unit\n }}</span>\n </label>\n </div>\n </div>\n\n <!-- Table with keyboard navigation -->\n <div\n class=\"table-container\"\n *ngIf=\"rows.length > 0\"\n tabindex=\"0\"\n (keydown)=\"onKeyDown($event)\"\n >\n <table class=\"kinematics-table\">\n <thead>\n <tr>\n <th class=\"col-index\">#</th>\n <th class=\"col-action\"></th>\n <th\n *ngFor=\"let col of config.columns\"\n class=\"col-data sortable\"\n [class.sorted]=\"sortColumn === col.id\"\n [matTooltip]=\"col.tooltip\"\n (click)=\"sort(col.id)\"\n >\n <span class=\"col-label\">{{ col.label }}</span>\n <span *ngIf=\"col.unit\" class=\"col-unit\">({{ col.unit }})</span>\n <span class=\"sort-arrow\" *ngIf=\"sortColumn === col.id\">\n {{ sortDirection === 'asc' ? '\\u25B2' : '\\u25BC' }}\n </span>\n </th>\n </tr>\n </thead>\n <tbody>\n <tr\n *ngFor=\"let row of rows; index as i\"\n [id]=\"'kin-' + row.uuid\"\n [class.active-object]=\"activeRowUuid === row.uuid\"\n [class.is-cut]=\"row.isCut\"\n (click)=\"selectTrack(row)\"\n >\n <td class=\"col-index\" [style.color]=\"getChargeColor(row)\">\n {{ i + 1 }}\n </td>\n <td class=\"col-action\">\n <button\n *ngIf=\"row.uuid\"\n class=\"icon-btn\"\n matTooltip=\"Look at track\"\n (click)=\"lookAtTrack(row.uuid, $event)\"\n >\n <svg>\n <use href=\"assets/icons/views.svg#views\"></use>\n </svg>\n </button>\n </td>\n <td\n *ngFor=\"let col of config.columns\"\n class=\"col-data\"\n [ngClass]=\"getChargeClass(col, row.values[col.id])\"\n >\n {{ formatValue(row.values[col.id], col) }}\n </td>\n </tr>\n </tbody>\n </table>\n </div>\n\n <!-- Empty states -->\n <p\n class=\"empty-state\"\n *ngIf=\"collections?.length > 0 && rows.length === 0 && allRows.length > 0\"\n >\n No tracks above {{ filterCol?.label }} &ge; {{ filterValue }}\n {{ filterCol?.unit }}.\n </p>\n <p\n class=\"empty-state\"\n *ngIf=\"collections?.length > 0 && allRows.length === 0\"\n >\n No objects in this collection.\n </p>\n <p class=\"empty-state\" *ngIf=\"!collections || collections.length === 0\">\n Load event data to view track kinematics.\n </p>\n </div>\n</app-overlay>\n", styles: [".kinematics-panel{width:620px;height:450px;display:flex;flex-direction:column}.panel-header{flex-shrink:0;padding:.5rem .75rem .25rem}.panel-header .header-top{display:flex;align-items:center;gap:.8rem;min-height:2rem}.panel-header .collection-selector select{padding:4px 8px;font-size:12px;border:1px solid rgba(88,88,88,.08);box-shadow:var(--phoenix-icon-shadow);background-color:var(--phoenix-background-color-tertiary);color:var(--phoenix-text-color-secondary)}.panel-header .collection-name{color:var(--phoenix-text-color-secondary);font-size:.85rem;font-weight:500}.panel-header .track-count{color:var(--phoenix-text-color-secondary);font-size:.75rem;opacity:.6;margin-left:auto}.panel-header .export-btn{display:flex;align-items:center;justify-content:center;width:1.5rem;height:1.5rem;padding:.3rem;border:none;background:var(--phoenix-options-icon-bg);border-radius:8px;cursor:pointer;flex-shrink:0}.panel-header .export-btn:hover{outline:1px solid var(--phoenix-options-icon-path)}.panel-header .export-btn svg{width:100%;height:100%}.filter-row{padding:.3rem 0}.filter-row label{display:flex;align-items:center;gap:.4rem;color:var(--phoenix-text-color-secondary);font-size:.75rem;opacity:.8}.filter-row .filter-input{width:4rem;padding:2px 6px;font-size:.75rem;border:1px solid rgba(255,255,255,.12);border-radius:4px;background:var(--phoenix-background-color-tertiary);color:var(--phoenix-text-color-secondary)}.filter-row .filter-input:focus{outline:1px solid var(--phoenix-text-color-secondary)}.filter-row .filter-unit{opacity:.5;font-size:.7rem}.table-container{flex:1;overflow:auto;outline:none}.kinematics-table{width:100%;border-collapse:collapse;color:var(--phoenix-text-color-secondary)}.kinematics-table thead tr th{position:sticky;top:0;z-index:10;background:var(--phoenix-background-color-secondary);padding:.4rem .7rem;font-size:.78rem;font-weight:600;white-space:nowrap;text-align:left;border-bottom:1px solid rgba(255,255,255,.08)}.kinematics-table thead tr th.sortable{cursor:pointer;-webkit-user-select:none;user-select:none}.kinematics-table thead tr th.sortable:hover,.kinematics-table thead tr th.sorted{color:var(--phoenix-text-color)}.kinematics-table thead tr th .col-unit{opacity:.5;font-weight:400;font-size:.68rem;margin-left:.15rem}.kinematics-table thead tr th .sort-arrow{font-size:.55rem;margin-left:.2rem;opacity:.7}.kinematics-table tbody tr{cursor:pointer;transition:background .12s ease}.kinematics-table tbody tr:hover{background:#ffffff0a}.kinematics-table tbody tr.active-object{color:var(--phoenix-background-color);background:var(--phoenix-text-color);box-shadow:0 0 12px var(--phoenix-text-color)}.kinematics-table tbody tr.active-object .icon-btn{--phoenix-options-icon-path: var(--phoenix-background-color);--phoenix-options-icon-bg: var(--phoenix-text-color-hover)}.kinematics-table tbody tr.is-cut{opacity:.35}.kinematics-table td{padding:.3rem .7rem;font-size:.78rem;font-variant-numeric:tabular-nums}.kinematics-table td.col-index{color:#fff6;width:2.5rem;text-align:right;padding-right:.4rem;white-space:nowrap}.kinematics-table td.col-action{width:2rem;padding:.2rem}.kinematics-table td.col-data{text-align:right}.charge-pos{color:#ff7b7b;font-weight:600}.charge-pos:before{content:\"+\"}.charge-neg{color:#7bb5ff;font-weight:600}.icon-btn{display:flex;align-items:center;justify-content:center;width:1.4rem;height:1.4rem;padding:.3rem;border:none;background:var(--phoenix-options-icon-bg);border-radius:8px;cursor:pointer}.icon-btn:hover{outline:1px solid var(--phoenix-options-icon-path)}.icon-btn svg{width:100%;height:100%}.empty-state{color:var(--phoenix-text-color-secondary);opacity:.5;text-align:center;padding:2rem;max-width:18em;margin:2rem auto;font-size:.85rem}\n"] }]
6235
6908
  }], () => [{ type: EventDisplayService }, { type: i0.ChangeDetectorRef }], { showKinematics: [{
6236
6909
  type: Input
6237
6910
  }], config: [{
@@ -6241,14 +6914,17 @@ class KinematicsPanelOverlayComponent {
6241
6914
 
6242
6915
  class KinematicsPanelComponent {
6243
6916
  overlay;
6917
+ overlayCascade;
6244
6918
  showKinematics = false;
6245
6919
  overlayWindow;
6246
6920
  config;
6247
- constructor(overlay) {
6921
+ constructor(overlay, overlayCascade) {
6248
6922
  this.overlay = overlay;
6923
+ this.overlayCascade = overlayCascade;
6249
6924
  }
6250
6925
  ngOnInit() {
6251
- const overlayRef = this.overlay.create();
6926
+ const positionStrategy = this.overlayCascade.getCascadePositionStrategy();
6927
+ const overlayRef = this.overlay.create({ positionStrategy });
6252
6928
  const overlayPortal = new ComponentPortal(KinematicsPanelOverlayComponent);
6253
6929
  this.overlayWindow = overlayRef.attach(overlayPortal);
6254
6930
  this.overlayWindow.instance.showKinematics = this.showKinematics;
@@ -6270,16 +6946,16 @@ class KinematicsPanelComponent {
6270
6946
  this.showKinematics = !this.showKinematics;
6271
6947
  this.overlayWindow.instance.showKinematics = this.showKinematics;
6272
6948
  }
6273
- static ɵfac = function KinematicsPanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || KinematicsPanelComponent)(i0.ɵɵdirectiveInject(i1$1.Overlay)); };
6949
+ static ɵfac = function KinematicsPanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || KinematicsPanelComponent)(i0.ɵɵdirectiveInject(i1$3.Overlay), i0.ɵɵdirectiveInject(OverlayCascadeService)); };
6274
6950
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: KinematicsPanelComponent, selectors: [["app-kinematics-panel"]], inputs: { config: "config" }, standalone: false, features: [i0.ɵɵNgOnChangesFeature], decls: 0, vars: 0, template: function KinematicsPanelComponent_Template(rf, ctx) { }, styles: ["@charset \"UTF-8\";"] });
6275
6951
  }
6276
6952
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(KinematicsPanelComponent, [{
6277
6953
  type: Component,
6278
6954
  args: [{ standalone: false, selector: 'app-kinematics-panel', template: "", styles: ["@charset \"UTF-8\";\n"] }]
6279
- }], () => [{ type: i1$1.Overlay }], { config: [{
6955
+ }], () => [{ type: i1$3.Overlay }, { type: OverlayCascadeService }], { config: [{
6280
6956
  type: Input
6281
6957
  }] }); })();
6282
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(KinematicsPanelComponent, { className: "KinematicsPanelComponent", filePath: "components/ui-menu/kinematics-panel/kinematics-panel.component.ts", lineNumber: 21 }); })();
6958
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(KinematicsPanelComponent, { className: "KinematicsPanelComponent", filePath: "components/ui-menu/kinematics-panel/kinematics-panel.component.ts", lineNumber: 22 }); })();
6283
6959
 
6284
6960
  const _c0$2 = ["infoPanel"];
6285
6961
  const _c1$2 = ["eventBrowser"];
@@ -6423,114 +7099,571 @@ class MoreInfoComponent {
6423
7099
  this.showInfoPanel = !this.showInfoPanel;
6424
7100
  this.infoPanel?.toggleOverlay();
6425
7101
  }
6426
- toggleEventBrowser() {
6427
- this.showEventBrowser = !this.showEventBrowser;
6428
- this.eventBrowser?.toggleOverlay();
7102
+ toggleEventBrowser() {
7103
+ this.showEventBrowser = !this.showEventBrowser;
7104
+ this.eventBrowser?.toggleOverlay();
7105
+ }
7106
+ toggleCollectionsInfo() {
7107
+ this.showCollectionsInfo = !this.showCollectionsInfo;
7108
+ this.collectionsInfo?.toggleOverlay();
7109
+ }
7110
+ toggleEtaPhiPanel() {
7111
+ this.showEtaPhiPanel = !this.showEtaPhiPanel;
7112
+ this.etaPhiPanel?.toggleOverlay();
7113
+ }
7114
+ toggleGeometryBrowser() {
7115
+ this.showGeometryBrowser = !this.showGeometryBrowser;
7116
+ this.geometryBrowser?.toggleOverlay();
7117
+ }
7118
+ toggleKinematicsPanel() {
7119
+ this.showKinematicsPanel = !this.showKinematicsPanel;
7120
+ this.kinematicsPanel?.toggleOverlay();
7121
+ }
7122
+ static ɵfac = function MoreInfoComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MoreInfoComponent)(); };
7123
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MoreInfoComponent, selectors: [["app-more-info"]], viewQuery: function MoreInfoComponent_Query(rf, ctx) { if (rf & 1) {
7124
+ i0.ɵɵviewQuery(_c0$2, 5);
7125
+ i0.ɵɵviewQuery(_c1$2, 5);
7126
+ i0.ɵɵviewQuery(_c2, 5);
7127
+ i0.ɵɵviewQuery(_c3, 5);
7128
+ i0.ɵɵviewQuery(_c4, 5);
7129
+ i0.ɵɵviewQuery(_c5, 5);
7130
+ } if (rf & 2) {
7131
+ let _t;
7132
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.infoPanel = _t.first);
7133
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.eventBrowser = _t.first);
7134
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.collectionsInfo = _t.first);
7135
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.etaPhiPanel = _t.first);
7136
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.geometryBrowser = _t.first);
7137
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.kinematicsPanel = _t.first);
7138
+ } }, inputs: { uiConfig: "uiConfig", kinematicsConfig: "kinematicsConfig" }, standalone: false, decls: 16, vars: 14, consts: [["moreInfo", ""], ["infoPanel", ""], ["eventBrowser", ""], ["collectionsInfo", ""], ["etaPhiPanel", ""], ["geometryBrowser", ""], ["kinematicsPanel", ""], [1, "hidden-panels"], [4, "ngIf"], [3, "config", 4, "ngIf"], ["mat-menu-item", "", 4, "ngIf"], ["tooltip", "More information", "icon", "info", 3, "matMenuTriggerFor", "active"], [3, "config"], ["mat-menu-item", ""], [3, "click", "change", "checked"], [1, "item-content"], [1, "item-icon"], ["href", "assets/icons/info-panel.svg#info-panel"], ["href", "assets/icons/event-browser.svg#event-browser"], ["href", "assets/icons/eventData.svg#eventData"], ["href", "assets/icons/eta-phi.svg#eta-phi"], ["href", "assets/icons/top-cube.svg#top-cube"], ["href", "assets/icons/kinematics.svg#kinematics"]], template: function MoreInfoComponent_Template(rf, ctx) { if (rf & 1) {
7139
+ i0.ɵɵelementStart(0, "div", 7);
7140
+ i0.ɵɵtemplate(1, MoreInfoComponent_app_info_panel_1_Template, 2, 0, "app-info-panel", 8)(2, MoreInfoComponent_app_event_browser_2_Template, 2, 0, "app-event-browser", 8)(3, MoreInfoComponent_app_collections_info_3_Template, 2, 0, "app-collections-info", 8)(4, MoreInfoComponent_app_eta_phi_panel_4_Template, 2, 0, "app-eta-phi-panel", 8)(5, MoreInfoComponent_app_geometry_browser_5_Template, 2, 0, "app-geometry-browser", 8)(6, MoreInfoComponent_app_kinematics_panel_6_Template, 2, 1, "app-kinematics-panel", 9);
7141
+ i0.ɵɵelementEnd();
7142
+ i0.ɵɵelementStart(7, "mat-menu", null, 0);
7143
+ i0.ɵɵtemplate(9, MoreInfoComponent_button_9_Template, 6, 1, "button", 10)(10, MoreInfoComponent_button_10_Template, 6, 1, "button", 10)(11, MoreInfoComponent_button_11_Template, 6, 1, "button", 10)(12, MoreInfoComponent_button_12_Template, 6, 1, "button", 10)(13, MoreInfoComponent_button_13_Template, 6, 1, "button", 10)(14, MoreInfoComponent_button_14_Template, 6, 1, "button", 10);
7144
+ i0.ɵɵelementEnd();
7145
+ i0.ɵɵelement(15, "app-menu-toggle", 11);
7146
+ } if (rf & 2) {
7147
+ const moreInfo_r8 = i0.ɵɵreference(8);
7148
+ i0.ɵɵadvance();
7149
+ i0.ɵɵproperty("ngIf", ctx.uiConfig == null ? null : ctx.uiConfig.showInfoPanel);
7150
+ i0.ɵɵadvance();
7151
+ i0.ɵɵproperty("ngIf", ctx.uiConfig == null ? null : ctx.uiConfig.showEventBrowser);
7152
+ i0.ɵɵadvance();
7153
+ i0.ɵɵproperty("ngIf", ctx.uiConfig == null ? null : ctx.uiConfig.showCollectionsInfo);
7154
+ i0.ɵɵadvance();
7155
+ i0.ɵɵproperty("ngIf", ctx.uiConfig == null ? null : ctx.uiConfig.showEtaPhiPanel);
7156
+ i0.ɵɵadvance();
7157
+ i0.ɵɵproperty("ngIf", ctx.uiConfig == null ? null : ctx.uiConfig.showGeometryBrowser);
7158
+ i0.ɵɵadvance();
7159
+ i0.ɵɵproperty("ngIf", ctx.uiConfig == null ? null : ctx.uiConfig.showKinematicsPanel);
7160
+ i0.ɵɵadvance(3);
7161
+ i0.ɵɵproperty("ngIf", ctx.uiConfig == null ? null : ctx.uiConfig.showInfoPanel);
7162
+ i0.ɵɵadvance();
7163
+ i0.ɵɵproperty("ngIf", ctx.uiConfig == null ? null : ctx.uiConfig.showEventBrowser);
7164
+ i0.ɵɵadvance();
7165
+ i0.ɵɵproperty("ngIf", ctx.uiConfig == null ? null : ctx.uiConfig.showCollectionsInfo);
7166
+ i0.ɵɵadvance();
7167
+ i0.ɵɵproperty("ngIf", ctx.uiConfig == null ? null : ctx.uiConfig.showEtaPhiPanel);
7168
+ i0.ɵɵadvance();
7169
+ i0.ɵɵproperty("ngIf", ctx.uiConfig == null ? null : ctx.uiConfig.showGeometryBrowser);
7170
+ i0.ɵɵadvance();
7171
+ i0.ɵɵproperty("ngIf", ctx.uiConfig == null ? null : ctx.uiConfig.showKinematicsPanel);
7172
+ i0.ɵɵadvance();
7173
+ i0.ɵɵproperty("matMenuTriggerFor", moreInfo_r8)("active", false);
7174
+ } }, dependencies: [i2.NgIf, i4$2.MatMenu, i4$2.MatMenuItem, i4$2.MatMenuTrigger, i5.MatCheckbox, CollectionsInfoComponent, GeometryBrowserComponent, MenuToggleComponent, InfoPanelComponent, EventBrowserComponent, EtaPhiPanelComponent, KinematicsPanelComponent], styles: [".hidden-panels[_ngcontent-%COMP%]{display:none}.item-content[_ngcontent-%COMP%]{display:inline-flex;align-items:center}.item-icon[_ngcontent-%COMP%]{inline-size:1.2rem;block-size:1.2rem;margin-inline-end:.5rem;fill:currentColor} .cdk-overlay-pane:has(.mat-mdc-menu-panel), .cdk-overlay-pane:has(.mat-menu-panel){z-index:99999!important}"] });
7175
+ }
7176
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MoreInfoComponent, [{
7177
+ type: Component,
7178
+ args: [{ standalone: false, selector: 'app-more-info', template: "<div class=\"hidden-panels\">\n <app-info-panel #infoPanel *ngIf=\"uiConfig?.showInfoPanel\"></app-info-panel>\n <app-event-browser\n #eventBrowser\n *ngIf=\"uiConfig?.showEventBrowser\"\n ></app-event-browser>\n <app-collections-info\n #collectionsInfo\n *ngIf=\"uiConfig?.showCollectionsInfo\"\n ></app-collections-info>\n <app-eta-phi-panel\n #etaPhiPanel\n *ngIf=\"uiConfig?.showEtaPhiPanel\"\n ></app-eta-phi-panel>\n <app-geometry-browser\n #geometryBrowser\n *ngIf=\"uiConfig?.showGeometryBrowser\"\n ></app-geometry-browser>\n <app-kinematics-panel\n #kinematicsPanel\n *ngIf=\"uiConfig?.showKinematicsPanel\"\n [config]=\"kinematicsConfig\"\n ></app-kinematics-panel>\n</div>\n\n<mat-menu #moreInfo>\n <button mat-menu-item *ngIf=\"uiConfig?.showInfoPanel\">\n <mat-checkbox\n [checked]=\"showInfoPanel\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleInfoPanel()\"\n >\n <span class=\"item-content\">\n <svg class=\"item-icon\">\n <use href=\"assets/icons/info-panel.svg#info-panel\"></use>\n </svg>\n Info Panel\n </span>\n </mat-checkbox>\n </button>\n <button mat-menu-item *ngIf=\"uiConfig?.showEventBrowser\">\n <mat-checkbox\n [checked]=\"showEventBrowser\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleEventBrowser()\"\n >\n <span class=\"item-content\">\n <svg class=\"item-icon\">\n <use href=\"assets/icons/event-browser.svg#event-browser\"></use>\n </svg>\n Event Browser\n </span>\n </mat-checkbox>\n </button>\n <button mat-menu-item *ngIf=\"uiConfig?.showCollectionsInfo\">\n <mat-checkbox\n [checked]=\"showCollectionsInfo\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleCollectionsInfo()\"\n >\n <span class=\"item-content\">\n <svg class=\"item-icon\">\n <use href=\"assets/icons/eventData.svg#eventData\"></use>\n </svg>\n Collections Info\n </span>\n </mat-checkbox>\n </button>\n <button mat-menu-item *ngIf=\"uiConfig?.showEtaPhiPanel\">\n <mat-checkbox\n [checked]=\"showEtaPhiPanel\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleEtaPhiPanel()\"\n >\n <span class=\"item-content\">\n <svg class=\"item-icon\">\n <use href=\"assets/icons/eta-phi.svg#eta-phi\"></use>\n </svg>\n Eta-Phi Panel\n </span>\n </mat-checkbox>\n </button>\n <button mat-menu-item *ngIf=\"uiConfig?.showGeometryBrowser\">\n <mat-checkbox\n [checked]=\"showGeometryBrowser\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleGeometryBrowser()\"\n >\n <span class=\"item-content\">\n <svg class=\"item-icon\">\n <use href=\"assets/icons/top-cube.svg#top-cube\"></use>\n </svg>\n Geometry Browser\n </span>\n </mat-checkbox>\n </button>\n <button mat-menu-item *ngIf=\"uiConfig?.showKinematicsPanel\">\n <mat-checkbox\n [checked]=\"showKinematicsPanel\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleKinematicsPanel()\"\n >\n <span class=\"item-content\">\n <svg class=\"item-icon\">\n <use href=\"assets/icons/kinematics.svg#kinematics\"></use>\n </svg>\n Track Kinematics\n </span>\n </mat-checkbox>\n </button>\n</mat-menu>\n\n<app-menu-toggle\n [matMenuTriggerFor]=\"moreInfo\"\n tooltip=\"More information\"\n icon=\"info\"\n [active]=\"false\"\n>\n</app-menu-toggle>\n", styles: [".hidden-panels{display:none}.item-content{display:inline-flex;align-items:center}.item-icon{inline-size:1.2rem;block-size:1.2rem;margin-inline-end:.5rem;fill:currentColor}::ng-deep .cdk-overlay-pane:has(.mat-mdc-menu-panel),::ng-deep .cdk-overlay-pane:has(.mat-menu-panel){z-index:99999!important}\n"] }]
7179
+ }], null, { uiConfig: [{
7180
+ type: Input
7181
+ }], kinematicsConfig: [{
7182
+ type: Input
7183
+ }], infoPanel: [{
7184
+ type: ViewChild,
7185
+ args: ['infoPanel']
7186
+ }], eventBrowser: [{
7187
+ type: ViewChild,
7188
+ args: ['eventBrowser']
7189
+ }], collectionsInfo: [{
7190
+ type: ViewChild,
7191
+ args: ['collectionsInfo']
7192
+ }], etaPhiPanel: [{
7193
+ type: ViewChild,
7194
+ args: ['etaPhiPanel']
7195
+ }], geometryBrowser: [{
7196
+ type: ViewChild,
7197
+ args: ['geometryBrowser']
7198
+ }], kinematicsPanel: [{
7199
+ type: ViewChild,
7200
+ args: ['kinematicsPanel']
7201
+ }] }); })();
7202
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MoreInfoComponent, { className: "MoreInfoComponent", filePath: "components/ui-menu/more-info/more-info.component.ts", lineNumber: 17 }); })();
7203
+
7204
+ function SessionPillComponent_div_0_ng_container_1_Template(rf, ctx) { if (rf & 1) {
7205
+ const _r1 = i0.ɵɵgetCurrentView();
7206
+ i0.ɵɵelementContainerStart(0);
7207
+ i0.ɵɵelement(1, "span", 3);
7208
+ i0.ɵɵelementStart(2, "span", 4);
7209
+ i0.ɵɵtext(3, "REC");
7210
+ i0.ɵɵelementEnd();
7211
+ i0.ɵɵelementStart(4, "span", 5);
7212
+ i0.ɵɵtext(5);
7213
+ i0.ɵɵelementEnd();
7214
+ i0.ɵɵelementStart(6, "span", 6);
7215
+ i0.ɵɵtext(7, "\u00B7");
7216
+ i0.ɵɵelementEnd();
7217
+ i0.ɵɵelementStart(8, "span", 7);
7218
+ i0.ɵɵtext(9);
7219
+ i0.ɵɵelementEnd();
7220
+ i0.ɵɵelementStart(10, "button", 8);
7221
+ i0.ɵɵlistener("click", function SessionPillComponent_div_0_ng_container_1_Template_button_click_10_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onStopRecording()); });
7222
+ i0.ɵɵtext(11, " \u25A0 ");
7223
+ i0.ɵɵelementEnd();
7224
+ i0.ɵɵelementContainerEnd();
7225
+ } if (rf & 2) {
7226
+ const ctx_r1 = i0.ɵɵnextContext(2);
7227
+ i0.ɵɵadvance(5);
7228
+ i0.ɵɵtextInterpolate(ctx_r1.durationLabel);
7229
+ i0.ɵɵadvance(4);
7230
+ i0.ɵɵtextInterpolate1("", ctx_r1.eventCount, " events");
7231
+ } }
7232
+ function SessionPillComponent_div_0_ng_container_2_Template(rf, ctx) { if (rf & 1) {
7233
+ const _r3 = i0.ɵɵgetCurrentView();
7234
+ i0.ɵɵelementContainerStart(0);
7235
+ i0.ɵɵelementStart(1, "span", 4);
7236
+ i0.ɵɵtext(2, "Saved");
7237
+ i0.ɵɵelementEnd();
7238
+ i0.ɵɵelementStart(3, "span", 5);
7239
+ i0.ɵɵtext(4);
7240
+ i0.ɵɵelementEnd();
7241
+ i0.ɵɵelementStart(5, "span", 6);
7242
+ i0.ɵɵtext(6, "\u00B7");
7243
+ i0.ɵɵelementEnd();
7244
+ i0.ɵɵelementStart(7, "span", 7);
7245
+ i0.ɵɵtext(8);
7246
+ i0.ɵɵelementEnd();
7247
+ i0.ɵɵelementStart(9, "button", 9);
7248
+ i0.ɵɵlistener("click", function SessionPillComponent_div_0_ng_container_2_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onDownload()); });
7249
+ i0.ɵɵtext(10, " Download ");
7250
+ i0.ɵɵelementEnd();
7251
+ i0.ɵɵelementStart(11, "button", 10);
7252
+ i0.ɵɵlistener("click", function SessionPillComponent_div_0_ng_container_2_Template_button_click_11_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onCopyLink()); });
7253
+ i0.ɵɵtext(12);
7254
+ i0.ɵɵelementEnd();
7255
+ i0.ɵɵelementStart(13, "button", 11);
7256
+ i0.ɵɵlistener("click", function SessionPillComponent_div_0_ng_container_2_Template_button_click_13_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onDismiss()); });
7257
+ i0.ɵɵtext(14, " \u2715 ");
7258
+ i0.ɵɵelementEnd();
7259
+ i0.ɵɵelementContainerEnd();
7260
+ } if (rf & 2) {
7261
+ const ctx_r1 = i0.ɵɵnextContext(2);
7262
+ i0.ɵɵadvance(4);
7263
+ i0.ɵɵtextInterpolate(ctx_r1.durationLabel);
7264
+ i0.ɵɵadvance(4);
7265
+ i0.ɵɵtextInterpolate1("", ctx_r1.eventCount, " events");
7266
+ i0.ɵɵadvance(3);
7267
+ i0.ɵɵproperty("disabled", ctx_r1.linkCopied);
7268
+ i0.ɵɵadvance();
7269
+ i0.ɵɵtextInterpolate1(" ", ctx_r1.linkCopied ? "Copied" : "Copy link", " ");
7270
+ } }
7271
+ function SessionPillComponent_div_0_ng_container_3_Template(rf, ctx) { if (rf & 1) {
7272
+ const _r4 = i0.ɵɵgetCurrentView();
7273
+ i0.ɵɵelementContainerStart(0);
7274
+ i0.ɵɵelementStart(1, "span", 4);
7275
+ i0.ɵɵtext(2, "Shared session");
7276
+ i0.ɵɵelementEnd();
7277
+ i0.ɵɵelementStart(3, "span", 5);
7278
+ i0.ɵɵtext(4);
7279
+ i0.ɵɵelementEnd();
7280
+ i0.ɵɵelementStart(5, "span", 6);
7281
+ i0.ɵɵtext(6, "\u00B7");
7282
+ i0.ɵɵelementEnd();
7283
+ i0.ɵɵelementStart(7, "span", 7);
7284
+ i0.ɵɵtext(8);
7285
+ i0.ɵɵelementEnd();
7286
+ i0.ɵɵelementStart(9, "button", 12);
7287
+ i0.ɵɵlistener("click", function SessionPillComponent_div_0_ng_container_3_Template_button_click_9_listener() { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onPlayPending()); });
7288
+ i0.ɵɵtext(10, " Play ");
7289
+ i0.ɵɵelementEnd();
7290
+ i0.ɵɵelementStart(11, "button", 13);
7291
+ i0.ɵɵlistener("click", function SessionPillComponent_div_0_ng_container_3_Template_button_click_11_listener() { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onDismiss()); });
7292
+ i0.ɵɵtext(12, " \u2715 ");
7293
+ i0.ɵɵelementEnd();
7294
+ i0.ɵɵelementContainerEnd();
7295
+ } if (rf & 2) {
7296
+ const ctx_r1 = i0.ɵɵnextContext(2);
7297
+ i0.ɵɵadvance(4);
7298
+ i0.ɵɵtextInterpolate(ctx_r1.pendingSummary);
7299
+ i0.ɵɵadvance(4);
7300
+ i0.ɵɵtextInterpolate1("from ", ctx_r1.state.sourceLabel);
7301
+ } }
7302
+ function SessionPillComponent_div_0_ng_container_4_button_9_Template(rf, ctx) { if (rf & 1) {
7303
+ const _r6 = i0.ɵɵgetCurrentView();
7304
+ i0.ɵɵelementStart(0, "button", 19);
7305
+ i0.ɵɵlistener("click", function SessionPillComponent_div_0_ng_container_4_button_9_Template_button_click_0_listener() { const s_r7 = i0.ɵɵrestoreView(_r6).$implicit; const ctx_r1 = i0.ɵɵnextContext(3); return i0.ɵɵresetView(ctx_r1.onSpeed(s_r7)); });
7306
+ i0.ɵɵtext(1);
7307
+ i0.ɵɵelementEnd();
7308
+ } if (rf & 2) {
7309
+ const s_r7 = ctx.$implicit;
7310
+ const ctx_r1 = i0.ɵɵnextContext(3);
7311
+ i0.ɵɵclassProp("selected", ctx_r1.currentSpeed === s_r7);
7312
+ i0.ɵɵattribute("aria-label", "Speed " + s_r7 + "x")("aria-pressed", ctx_r1.currentSpeed === s_r7);
7313
+ i0.ɵɵadvance();
7314
+ i0.ɵɵtextInterpolate1(" ", s_r7, "\u00D7 ");
7315
+ } }
7316
+ function SessionPillComponent_div_0_ng_container_4_Template(rf, ctx) { if (rf & 1) {
7317
+ const _r5 = i0.ɵɵgetCurrentView();
7318
+ i0.ɵɵelementContainerStart(0);
7319
+ i0.ɵɵelementStart(1, "button", 14);
7320
+ i0.ɵɵlistener("click", function SessionPillComponent_div_0_ng_container_4_Template_button_click_1_listener() { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onTogglePlayback()); });
7321
+ i0.ɵɵtext(2);
7322
+ i0.ɵɵelementEnd();
7323
+ i0.ɵɵelementStart(3, "span", 4);
7324
+ i0.ɵɵtext(4, "Replay");
7325
+ i0.ɵɵelementEnd();
7326
+ i0.ɵɵelementStart(5, "span", 5);
7327
+ i0.ɵɵtext(6);
7328
+ i0.ɵɵelementEnd();
7329
+ i0.ɵɵelementStart(7, "input", 15);
7330
+ i0.ɵɵlistener("input", function SessionPillComponent_div_0_ng_container_4_Template_input_input_7_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onScrub(+$event.target.value)); });
7331
+ i0.ɵɵelementEnd();
7332
+ i0.ɵɵelementStart(8, "span", 16);
7333
+ i0.ɵɵtemplate(9, SessionPillComponent_div_0_ng_container_4_button_9_Template, 2, 5, "button", 17);
7334
+ i0.ɵɵelementEnd();
7335
+ i0.ɵɵelementStart(10, "button", 18);
7336
+ i0.ɵɵlistener("click", function SessionPillComponent_div_0_ng_container_4_Template_button_click_10_listener() { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onDismiss()); });
7337
+ i0.ɵɵtext(11, " \u2715 ");
7338
+ i0.ɵɵelementEnd();
7339
+ i0.ɵɵelementContainerEnd();
7340
+ } if (rf & 2) {
7341
+ const ctx_r1 = i0.ɵɵnextContext(2);
7342
+ i0.ɵɵadvance();
7343
+ i0.ɵɵproperty("title", ctx_r1.state.kind === "playing" ? "Pause" : "Play");
7344
+ i0.ɵɵattribute("aria-label", ctx_r1.state.kind === "playing" ? "Pause" : "Play");
7345
+ i0.ɵɵadvance();
7346
+ i0.ɵɵtextInterpolate1(" ", ctx_r1.state.kind === "playing" ? "\u275A\u275A" : "\u25BA", " ");
7347
+ i0.ɵɵadvance(4);
7348
+ i0.ɵɵtextInterpolate(ctx_r1.playbackLabel);
7349
+ i0.ɵɵadvance();
7350
+ i0.ɵɵproperty("max", ctx_r1.playerDuration)("value", ctx_r1.state.kind === "finished" ? ctx_r1.playerDuration : ctx_r1.state.currentTime ?? 0);
7351
+ i0.ɵɵadvance(2);
7352
+ i0.ɵɵproperty("ngForOf", ctx_r1.speeds);
7353
+ } }
7354
+ function SessionPillComponent_div_0_ng_container_5_Template(rf, ctx) { if (rf & 1) {
7355
+ const _r8 = i0.ɵɵgetCurrentView();
7356
+ i0.ɵɵelementContainerStart(0);
7357
+ i0.ɵɵelementStart(1, "span", 20);
7358
+ i0.ɵɵtext(2, "Session error");
7359
+ i0.ɵɵelementEnd();
7360
+ i0.ɵɵelementStart(3, "span", 5);
7361
+ i0.ɵɵtext(4);
7362
+ i0.ɵɵelementEnd();
7363
+ i0.ɵɵelementStart(5, "button", 11);
7364
+ i0.ɵɵlistener("click", function SessionPillComponent_div_0_ng_container_5_Template_button_click_5_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.onDismiss()); });
7365
+ i0.ɵɵtext(6, " \u2715 ");
7366
+ i0.ɵɵelementEnd();
7367
+ i0.ɵɵelementContainerEnd();
7368
+ } if (rf & 2) {
7369
+ const ctx_r1 = i0.ɵɵnextContext(2);
7370
+ i0.ɵɵadvance(4);
7371
+ i0.ɵɵtextInterpolate(ctx_r1.state.message);
7372
+ } }
7373
+ function SessionPillComponent_div_0_Template(rf, ctx) { if (rf & 1) {
7374
+ i0.ɵɵelementStart(0, "div", 1);
7375
+ i0.ɵɵtemplate(1, SessionPillComponent_div_0_ng_container_1_Template, 12, 2, "ng-container", 2)(2, SessionPillComponent_div_0_ng_container_2_Template, 15, 4, "ng-container", 2)(3, SessionPillComponent_div_0_ng_container_3_Template, 13, 2, "ng-container", 2)(4, SessionPillComponent_div_0_ng_container_4_Template, 12, 7, "ng-container", 2)(5, SessionPillComponent_div_0_ng_container_5_Template, 7, 1, "ng-container", 2);
7376
+ i0.ɵɵelementEnd();
7377
+ } if (rf & 2) {
7378
+ const ctx_r1 = i0.ɵɵnextContext();
7379
+ i0.ɵɵattribute("data-kind", ctx_r1.state.kind);
7380
+ i0.ɵɵadvance();
7381
+ i0.ɵɵproperty("ngIf", ctx_r1.state.kind === "recording");
7382
+ i0.ɵɵadvance();
7383
+ i0.ɵɵproperty("ngIf", ctx_r1.state.kind === "recorded");
7384
+ i0.ɵɵadvance();
7385
+ i0.ɵɵproperty("ngIf", ctx_r1.state.kind === "pending");
7386
+ i0.ɵɵadvance();
7387
+ i0.ɵɵproperty("ngIf", ctx_r1.state.kind === "playing" || ctx_r1.state.kind === "paused" || ctx_r1.state.kind === "finished");
7388
+ i0.ɵɵadvance();
7389
+ i0.ɵɵproperty("ngIf", ctx_r1.state.kind === "error");
7390
+ } }
7391
+ const SPEEDS = [0.5, 1, 2, 4];
7392
+ /**
7393
+ * Floating session pill (#883). Renders only while the session manager is
7394
+ * recording, paused, finished, or playing a replay. Idle state hides the
7395
+ * pill entirely so it adds zero footprint to the toolbar.
7396
+ */
7397
+ class SessionPillComponent {
7398
+ eventDisplay;
7399
+ cdr;
7400
+ /** Current session-manager state, kept in component for template binding. */
7401
+ state = { kind: 'idle' };
7402
+ /** Cached duration label for the recording elapsed clock. */
7403
+ durationLabel = '00:00';
7404
+ /** Cached current/total label for the playback clock. */
7405
+ playbackLabel = '00:00 / 00:00';
7406
+ /** Cached event count for the recording badge. */
7407
+ eventCount = 0;
7408
+ /** Last computed scrub percent (0-100). */
7409
+ scrubPercent = 0;
7410
+ /** Saved copy-link feedback flag (resets after a tick). */
7411
+ linkCopied = false;
7412
+ /** Available playback speeds for the speed selector. */
7413
+ speeds = SPEEDS;
7414
+ sessionManager;
7415
+ unsubscribeState = null;
7416
+ recordingClockId = null;
7417
+ copiedResetTimer = null;
7418
+ constructor(eventDisplay, cdr) {
7419
+ this.eventDisplay = eventDisplay;
7420
+ this.cdr = cdr;
7421
+ }
7422
+ ngOnInit() {
7423
+ this.sessionManager = this.eventDisplay.getSessionManager();
7424
+ this.state = this.sessionManager.state.value ?? { kind: 'idle' };
7425
+ this.unsubscribeState = this.sessionManager.state.onUpdate((next) => {
7426
+ this.state = next;
7427
+ this.refreshDerived();
7428
+ this.cdr.detectChanges();
7429
+ });
7430
+ this.refreshDerived();
7431
+ }
7432
+ ngOnDestroy() {
7433
+ if (this.unsubscribeState) {
7434
+ this.unsubscribeState();
7435
+ this.unsubscribeState = null;
7436
+ }
7437
+ if (this.recordingClockId) {
7438
+ clearInterval(this.recordingClockId);
7439
+ this.recordingClockId = null;
7440
+ }
7441
+ if (this.copiedResetTimer) {
7442
+ clearTimeout(this.copiedResetTimer);
7443
+ this.copiedResetTimer = null;
7444
+ }
7445
+ }
7446
+ /** True when the pill should be visible. Idle state hides it. */
7447
+ get visible() {
7448
+ return this.state.kind !== 'idle';
6429
7449
  }
6430
- toggleCollectionsInfo() {
6431
- this.showCollectionsInfo = !this.showCollectionsInfo;
6432
- this.collectionsInfo?.toggleOverlay();
7450
+ /** Stop an active recording from the pill's stop button. */
7451
+ onStopRecording() {
7452
+ this.sessionManager.stopRecording();
6433
7453
  }
6434
- toggleEtaPhiPanel() {
6435
- this.showEtaPhiPanel = !this.showEtaPhiPanel;
6436
- this.etaPhiPanel?.toggleOverlay();
7454
+ /** Dismiss a recorded/finished/errored state and return to idle. */
7455
+ onDismiss() {
7456
+ if (this.state.kind === 'recorded') {
7457
+ this.sessionManager.clearRecorded();
7458
+ }
7459
+ else {
7460
+ this.sessionManager.stopPlayback();
7461
+ }
6437
7462
  }
6438
- toggleGeometryBrowser() {
6439
- this.showGeometryBrowser = !this.showGeometryBrowser;
6440
- this.geometryBrowser?.toggleOverlay();
7463
+ /** Start a pending (link-supplied) session after explicit user confirmation. */
7464
+ onPlayPending() {
7465
+ this.sessionManager.playPending();
6441
7466
  }
6442
- toggleKinematicsPanel() {
6443
- this.showKinematicsPanel = !this.showKinematicsPanel;
6444
- this.kinematicsPanel?.toggleOverlay();
7467
+ /** Source label + duration/event summary for the pending confirm prompt. */
7468
+ get pendingSummary() {
7469
+ if (this.state.kind !== 'pending')
7470
+ return '';
7471
+ const { session } = this.state;
7472
+ return `${formatClock(session.duration)} · ${session.events.length} events`;
6445
7473
  }
6446
- static ɵfac = function MoreInfoComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MoreInfoComponent)(); };
6447
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MoreInfoComponent, selectors: [["app-more-info"]], viewQuery: function MoreInfoComponent_Query(rf, ctx) { if (rf & 1) {
6448
- i0.ɵɵviewQuery(_c0$2, 5);
6449
- i0.ɵɵviewQuery(_c1$2, 5);
6450
- i0.ɵɵviewQuery(_c2, 5);
6451
- i0.ɵɵviewQuery(_c3, 5);
6452
- i0.ɵɵviewQuery(_c4, 5);
6453
- i0.ɵɵviewQuery(_c5, 5);
6454
- } if (rf & 2) {
6455
- let _t;
6456
- i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.infoPanel = _t.first);
6457
- i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.eventBrowser = _t.first);
6458
- i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.collectionsInfo = _t.first);
6459
- i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.etaPhiPanel = _t.first);
6460
- i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.geometryBrowser = _t.first);
6461
- i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.kinematicsPanel = _t.first);
6462
- } }, inputs: { uiConfig: "uiConfig", kinematicsConfig: "kinematicsConfig" }, standalone: false, decls: 16, vars: 14, consts: [["moreInfo", ""], ["infoPanel", ""], ["eventBrowser", ""], ["collectionsInfo", ""], ["etaPhiPanel", ""], ["geometryBrowser", ""], ["kinematicsPanel", ""], [1, "hidden-panels"], [4, "ngIf"], [3, "config", 4, "ngIf"], ["mat-menu-item", "", 4, "ngIf"], ["tooltip", "More information", "icon", "info", 3, "matMenuTriggerFor", "active"], [3, "config"], ["mat-menu-item", ""], [3, "click", "change", "checked"], [1, "item-content"], [1, "item-icon"], ["href", "assets/icons/info-panel.svg#info-panel"], ["href", "assets/icons/event-browser.svg#event-browser"], ["href", "assets/icons/eventData.svg#eventData"], ["href", "assets/icons/eta-phi.svg#eta-phi"], ["href", "assets/icons/top-cube.svg#top-cube"], ["href", "assets/icons/kinematics.svg#kinematics"]], template: function MoreInfoComponent_Template(rf, ctx) { if (rf & 1) {
6463
- i0.ɵɵelementStart(0, "div", 7);
6464
- i0.ɵɵtemplate(1, MoreInfoComponent_app_info_panel_1_Template, 2, 0, "app-info-panel", 8)(2, MoreInfoComponent_app_event_browser_2_Template, 2, 0, "app-event-browser", 8)(3, MoreInfoComponent_app_collections_info_3_Template, 2, 0, "app-collections-info", 8)(4, MoreInfoComponent_app_eta_phi_panel_4_Template, 2, 0, "app-eta-phi-panel", 8)(5, MoreInfoComponent_app_geometry_browser_5_Template, 2, 0, "app-geometry-browser", 8)(6, MoreInfoComponent_app_kinematics_panel_6_Template, 2, 1, "app-kinematics-panel", 9);
6465
- i0.ɵɵelementEnd();
6466
- i0.ɵɵelementStart(7, "mat-menu", null, 0);
6467
- i0.ɵɵtemplate(9, MoreInfoComponent_button_9_Template, 6, 1, "button", 10)(10, MoreInfoComponent_button_10_Template, 6, 1, "button", 10)(11, MoreInfoComponent_button_11_Template, 6, 1, "button", 10)(12, MoreInfoComponent_button_12_Template, 6, 1, "button", 10)(13, MoreInfoComponent_button_13_Template, 6, 1, "button", 10)(14, MoreInfoComponent_button_14_Template, 6, 1, "button", 10);
6468
- i0.ɵɵelementEnd();
6469
- i0.ɵɵelement(15, "app-menu-toggle", 11);
7474
+ /** Toggle play/pause on the active player. */
7475
+ onTogglePlayback() {
7476
+ if (this.state.kind === 'playing') {
7477
+ this.sessionManager.pause();
7478
+ }
7479
+ else if (this.state.kind === 'paused' || this.state.kind === 'finished') {
7480
+ this.sessionManager.play();
7481
+ }
7482
+ }
7483
+ /** Scrub to the playhead position the user clicked. */
7484
+ onScrub(value) {
7485
+ this.sessionManager.seek(value);
7486
+ }
7487
+ /** Change the active player's speed. */
7488
+ onSpeed(speed) {
7489
+ this.sessionManager.setSpeed(speed);
7490
+ }
7491
+ /** Download the recorded session as a .phnxreplay JSON file. */
7492
+ onDownload() {
7493
+ const blob = this.sessionManager.getDownloadBlob();
7494
+ if (!blob)
7495
+ return;
7496
+ const url = URL.createObjectURL(blob);
7497
+ const a = document.createElement('a');
7498
+ a.href = url;
7499
+ a.download = `phoenix-session-${Date.now()}.phnxreplay`;
7500
+ document.body.appendChild(a);
7501
+ a.click();
7502
+ document.body.removeChild(a);
7503
+ URL.revokeObjectURL(url);
7504
+ }
7505
+ /**
7506
+ * Copy a ?replay=... share link to the clipboard. The base64 is precomputed
7507
+ * when recording stops, so the common path writes synchronously inside the
7508
+ * click gesture (the async Clipboard API rejects writes that happen after an
7509
+ * await, which expires the user activation). Falls back to execCommand.
7510
+ */
7511
+ onCopyLink() {
7512
+ const cached = this.sessionManager.getCachedSharableBase64();
7513
+ if (cached) {
7514
+ this.copyShareLink(cached);
7515
+ return;
7516
+ }
7517
+ // Encode not finished yet (very fast click): compute then copy via the
7518
+ // synchronous execCommand fallback, which tolerates the post-await case.
7519
+ this.sessionManager.getSharableBase64().then((base64) => {
7520
+ if (base64)
7521
+ this.copyShareLink(base64);
7522
+ });
7523
+ }
7524
+ /** Build the share URL for a base64 payload and copy it to the clipboard. */
7525
+ copyShareLink(base64) {
7526
+ const url = new URL(window.location.href);
7527
+ url.searchParams.set('replay', base64);
7528
+ const text = url.toString();
7529
+ const onCopied = () => {
7530
+ this.linkCopied = true;
7531
+ if (this.copiedResetTimer)
7532
+ clearTimeout(this.copiedResetTimer);
7533
+ this.copiedResetTimer = setTimeout(() => {
7534
+ this.linkCopied = false;
7535
+ this.cdr.detectChanges();
7536
+ }, 2000);
7537
+ this.cdr.detectChanges();
7538
+ };
7539
+ if (navigator.clipboard?.writeText) {
7540
+ navigator.clipboard.writeText(text).then(onCopied, () => {
7541
+ if (this.legacyCopy(text))
7542
+ onCopied();
7543
+ });
7544
+ }
7545
+ else if (this.legacyCopy(text)) {
7546
+ onCopied();
7547
+ }
7548
+ }
7549
+ /**
7550
+ * Legacy clipboard copy via a temporary textarea + execCommand. Used as a
7551
+ * fallback when the async Clipboard API is unavailable or rejected. Mirrors
7552
+ * the share-link dialog's proven approach.
7553
+ * @param text The text to copy.
7554
+ * @returns True if the copy command reported success.
7555
+ */
7556
+ legacyCopy(text) {
7557
+ const el = document.createElement('textarea');
7558
+ el.value = text;
7559
+ el.setAttribute('readonly', '');
7560
+ el.style.position = 'fixed';
7561
+ el.style.opacity = '0';
7562
+ document.body.appendChild(el);
7563
+ el.select();
7564
+ let ok = false;
7565
+ try {
7566
+ ok = document.execCommand('copy');
7567
+ }
7568
+ catch {
7569
+ ok = false;
7570
+ }
7571
+ document.body.removeChild(el);
7572
+ return ok;
7573
+ }
7574
+ /** Active player duration (ms) for the scrub bar max value. */
7575
+ get playerDuration() {
7576
+ if ('player' in this.state && this.state.player) {
7577
+ return this.state.player.duration;
7578
+ }
7579
+ if (this.state.kind === 'recorded')
7580
+ return this.state.session.duration;
7581
+ return 0;
7582
+ }
7583
+ /** Active player current speed for the selector highlight. */
7584
+ get currentSpeed() {
7585
+ if ('player' in this.state && this.state.player) {
7586
+ return this.state.player.speed;
7587
+ }
7588
+ return 1;
7589
+ }
7590
+ refreshDerived() {
7591
+ if (this.state.kind === 'recording') {
7592
+ this.startRecordingClock();
7593
+ this.updateRecordingDerived();
7594
+ return;
7595
+ }
7596
+ this.stopRecordingClock();
7597
+ if (this.state.kind === 'recorded') {
7598
+ this.eventCount = this.state.session.events.length;
7599
+ this.durationLabel = formatClock(this.state.session.duration);
7600
+ this.playbackLabel = '';
7601
+ this.scrubPercent = 0;
7602
+ return;
7603
+ }
7604
+ if (this.state.kind === 'playing' ||
7605
+ this.state.kind === 'paused' ||
7606
+ this.state.kind === 'finished') {
7607
+ const player = this.state.player;
7608
+ const current = this.state.kind === 'finished' ? player.duration : player.currentTime;
7609
+ this.eventCount = player.eventCount;
7610
+ this.playbackLabel = `${formatClock(current)} / ${formatClock(player.duration)}`;
7611
+ this.scrubPercent =
7612
+ player.duration > 0 ? (current / player.duration) * 100 : 0;
7613
+ return;
7614
+ }
7615
+ }
7616
+ startRecordingClock() {
7617
+ if (this.recordingClockId)
7618
+ return;
7619
+ this.recordingClockId = setInterval(() => {
7620
+ this.updateRecordingDerived();
7621
+ this.cdr.detectChanges();
7622
+ }, 250);
7623
+ }
7624
+ stopRecordingClock() {
7625
+ if (this.recordingClockId) {
7626
+ clearInterval(this.recordingClockId);
7627
+ this.recordingClockId = null;
7628
+ }
7629
+ }
7630
+ updateRecordingDerived() {
7631
+ if (this.state.kind !== 'recording')
7632
+ return;
7633
+ const recorder = this.state.recorder;
7634
+ this.durationLabel = formatClock(recorder.duration);
7635
+ this.eventCount = recorder.eventCount;
7636
+ }
7637
+ static ɵfac = function SessionPillComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || SessionPillComponent)(i0.ɵɵdirectiveInject(EventDisplayService), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
7638
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: SessionPillComponent, selectors: [["app-session-pill"]], standalone: false, decls: 1, vars: 1, consts: [["class", "session-pill", 4, "ngIf"], [1, "session-pill"], [4, "ngIf"], ["aria-label", "Recording", 1, "rec-dot"], [1, "label"], [1, "time"], [1, "dot-sep"], [1, "count"], ["type", "button", "title", "Stop recording (Shift+S)", "aria-label", "Stop recording", 1, "action", "stop", 3, "click"], ["type", "button", "title", "Download .phnxreplay file", "aria-label", "Download session", 1, "action", 3, "click"], ["type", "button", "title", "Copy a ?replay= share link", "aria-label", "Copy share link", 1, "action", 3, "click", "disabled"], ["type", "button", "title", "Dismiss", "aria-label", "Dismiss", 1, "action", "close", 3, "click"], ["type", "button", "title", "Play this shared session", "aria-label", "Play shared session", 1, "action", "play-pending", 3, "click"], ["type", "button", "title", "Dismiss", "aria-label", "Dismiss shared session", 1, "action", "close", 3, "click"], ["type", "button", 1, "action", "play", 3, "click", "title"], ["type", "range", "min", "0", "step", "50", "aria-label", "Replay scrub bar", 1, "scrub", 3, "input", "max", "value"], [1, "speeds"], ["type", "button", "class", "speed", 3, "selected", "click", 4, "ngFor", "ngForOf"], ["type", "button", "title", "Stop replay", "aria-label", "Stop replay", 1, "action", "close", 3, "click"], ["type", "button", 1, "speed", 3, "click"], [1, "label", "error"]], template: function SessionPillComponent_Template(rf, ctx) { if (rf & 1) {
7639
+ i0.ɵɵtemplate(0, SessionPillComponent_div_0_Template, 6, 6, "div", 0);
6470
7640
  } if (rf & 2) {
6471
- const moreInfo_r8 = i0.ɵɵreference(8);
6472
- i0.ɵɵadvance();
6473
- i0.ɵɵproperty("ngIf", ctx.uiConfig == null ? null : ctx.uiConfig.showInfoPanel);
6474
- i0.ɵɵadvance();
6475
- i0.ɵɵproperty("ngIf", ctx.uiConfig == null ? null : ctx.uiConfig.showEventBrowser);
6476
- i0.ɵɵadvance();
6477
- i0.ɵɵproperty("ngIf", ctx.uiConfig == null ? null : ctx.uiConfig.showCollectionsInfo);
6478
- i0.ɵɵadvance();
6479
- i0.ɵɵproperty("ngIf", ctx.uiConfig == null ? null : ctx.uiConfig.showEtaPhiPanel);
6480
- i0.ɵɵadvance();
6481
- i0.ɵɵproperty("ngIf", ctx.uiConfig == null ? null : ctx.uiConfig.showGeometryBrowser);
6482
- i0.ɵɵadvance();
6483
- i0.ɵɵproperty("ngIf", ctx.uiConfig == null ? null : ctx.uiConfig.showKinematicsPanel);
6484
- i0.ɵɵadvance(3);
6485
- i0.ɵɵproperty("ngIf", ctx.uiConfig == null ? null : ctx.uiConfig.showInfoPanel);
6486
- i0.ɵɵadvance();
6487
- i0.ɵɵproperty("ngIf", ctx.uiConfig == null ? null : ctx.uiConfig.showEventBrowser);
6488
- i0.ɵɵadvance();
6489
- i0.ɵɵproperty("ngIf", ctx.uiConfig == null ? null : ctx.uiConfig.showCollectionsInfo);
6490
- i0.ɵɵadvance();
6491
- i0.ɵɵproperty("ngIf", ctx.uiConfig == null ? null : ctx.uiConfig.showEtaPhiPanel);
6492
- i0.ɵɵadvance();
6493
- i0.ɵɵproperty("ngIf", ctx.uiConfig == null ? null : ctx.uiConfig.showGeometryBrowser);
6494
- i0.ɵɵadvance();
6495
- i0.ɵɵproperty("ngIf", ctx.uiConfig == null ? null : ctx.uiConfig.showKinematicsPanel);
6496
- i0.ɵɵadvance();
6497
- i0.ɵɵproperty("matMenuTriggerFor", moreInfo_r8)("active", false);
6498
- } }, dependencies: [i2.NgIf, i3$2.MatMenu, i3$2.MatMenuItem, i3$2.MatMenuTrigger, i5.MatCheckbox, CollectionsInfoComponent, GeometryBrowserComponent, MenuToggleComponent, InfoPanelComponent, EventBrowserComponent, EtaPhiPanelComponent, KinematicsPanelComponent], styles: [".hidden-panels[_ngcontent-%COMP%]{display:none}.item-content[_ngcontent-%COMP%]{display:inline-flex;align-items:center}.item-icon[_ngcontent-%COMP%]{inline-size:1.2rem;block-size:1.2rem;margin-inline-end:.5rem;fill:currentColor}"] });
7641
+ i0.ɵɵproperty("ngIf", ctx.visible);
7642
+ } }, dependencies: [i2.NgForOf, i2.NgIf], styles: [".session-pill[_ngcontent-%COMP%]{position:fixed;bottom:80px;left:16px;z-index:1100;display:flex;align-items:center;gap:10px;padding:8px 14px;background:#14161ed1;color:#e8eaf2;border-radius:999px;border:1px solid rgba(255,255,255,.08);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);box-shadow:0 6px 18px #00000059;font-size:13px;font-weight:500;letter-spacing:.2px;-webkit-user-select:none;user-select:none;max-width:80vw}.session-pill[_ngcontent-%COMP%] .label[_ngcontent-%COMP%]{font-weight:600;letter-spacing:.4px}.session-pill[_ngcontent-%COMP%] .label.error[_ngcontent-%COMP%]{color:#ff7676}.session-pill[_ngcontent-%COMP%] .time[_ngcontent-%COMP%], .session-pill[_ngcontent-%COMP%] .count[_ngcontent-%COMP%]{font-variant-numeric:tabular-nums;opacity:.9}.session-pill[_ngcontent-%COMP%] .dot-sep[_ngcontent-%COMP%]{opacity:.4}.session-pill[_ngcontent-%COMP%] .rec-dot[_ngcontent-%COMP%]{width:10px;height:10px;border-radius:50%;background:#ff4040;box-shadow:0 0 6px #ff404099;animation:_ngcontent-%COMP%_phoenixSessionPulse 1.2s infinite ease-in-out}.session-pill[_ngcontent-%COMP%] .action[_ngcontent-%COMP%]{background:#ffffff0f;color:inherit;border:1px solid rgba(255,255,255,.1);border-radius:999px;padding:4px 12px;cursor:pointer;font-size:12px;font-weight:600;letter-spacing:.3px;transition:background .12s ease,border-color .12s ease}.session-pill[_ngcontent-%COMP%] .action[_ngcontent-%COMP%]:hover{background:#ffffff1f;border-color:#ffffff2e}.session-pill[_ngcontent-%COMP%] .action[_ngcontent-%COMP%]:disabled{opacity:.6;cursor:default}.session-pill[_ngcontent-%COMP%] .action.stop[_ngcontent-%COMP%]{background:#ff40402e;border-color:#ff404066}.session-pill[_ngcontent-%COMP%] .action.stop[_ngcontent-%COMP%]:hover{background:#ff404047}.session-pill[_ngcontent-%COMP%] .action.close[_ngcontent-%COMP%]{width:24px;height:24px;padding:0;display:inline-flex;align-items:center;justify-content:center}.session-pill[_ngcontent-%COMP%] .action.play[_ngcontent-%COMP%]{width:28px;height:28px;padding:0;display:inline-flex;align-items:center;justify-content:center;font-size:11px}.session-pill[_ngcontent-%COMP%] .scrub[_ngcontent-%COMP%]{width:180px;accent-color:#80c1ff}.session-pill[_ngcontent-%COMP%] .speeds[_ngcontent-%COMP%]{display:inline-flex;gap:4px}.session-pill[_ngcontent-%COMP%] .speeds[_ngcontent-%COMP%] .speed[_ngcontent-%COMP%]{background:transparent;color:inherit;border:1px solid rgba(255,255,255,.12);border-radius:999px;padding:3px 8px;cursor:pointer;font-size:11px;font-weight:600;opacity:.65;transition:opacity .12s ease,background .12s ease}.session-pill[_ngcontent-%COMP%] .speeds[_ngcontent-%COMP%] .speed[_ngcontent-%COMP%]:hover{opacity:1}.session-pill[_ngcontent-%COMP%] .speeds[_ngcontent-%COMP%] .speed.selected[_ngcontent-%COMP%]{background:#80c1ff2e;border-color:#80c1ff80;opacity:1}@keyframes _ngcontent-%COMP%_phoenixSessionPulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.65;transform:scale(.85)}}"] });
6499
7643
  }
6500
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MoreInfoComponent, [{
7644
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(SessionPillComponent, [{
6501
7645
  type: Component,
6502
- args: [{ standalone: false, selector: 'app-more-info', template: "<!-- Sub-components kept outside the mat-menu so their overlays persist when the menu closes -->\n<div class=\"hidden-panels\">\n <app-info-panel #infoPanel *ngIf=\"uiConfig?.showInfoPanel\"></app-info-panel>\n <app-event-browser\n #eventBrowser\n *ngIf=\"uiConfig?.showEventBrowser\"\n ></app-event-browser>\n <app-collections-info\n #collectionsInfo\n *ngIf=\"uiConfig?.showCollectionsInfo\"\n ></app-collections-info>\n <app-eta-phi-panel\n #etaPhiPanel\n *ngIf=\"uiConfig?.showEtaPhiPanel\"\n ></app-eta-phi-panel>\n <app-geometry-browser\n #geometryBrowser\n *ngIf=\"uiConfig?.showGeometryBrowser\"\n ></app-geometry-browser>\n <app-kinematics-panel\n #kinematicsPanel\n *ngIf=\"uiConfig?.showKinematicsPanel\"\n [config]=\"kinematicsConfig\"\n ></app-kinematics-panel>\n</div>\n\n<mat-menu #moreInfo>\n <button mat-menu-item *ngIf=\"uiConfig?.showInfoPanel\">\n <mat-checkbox\n [checked]=\"showInfoPanel\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleInfoPanel()\"\n >\n <span class=\"item-content\">\n <svg class=\"item-icon\">\n <use href=\"assets/icons/info-panel.svg#info-panel\"></use>\n </svg>\n Info Panel\n </span>\n </mat-checkbox>\n </button>\n <button mat-menu-item *ngIf=\"uiConfig?.showEventBrowser\">\n <mat-checkbox\n [checked]=\"showEventBrowser\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleEventBrowser()\"\n >\n <span class=\"item-content\">\n <svg class=\"item-icon\">\n <use href=\"assets/icons/event-browser.svg#event-browser\"></use>\n </svg>\n Event Browser\n </span>\n </mat-checkbox>\n </button>\n <button mat-menu-item *ngIf=\"uiConfig?.showCollectionsInfo\">\n <mat-checkbox\n [checked]=\"showCollectionsInfo\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleCollectionsInfo()\"\n >\n <span class=\"item-content\">\n <svg class=\"item-icon\">\n <use href=\"assets/icons/eventData.svg#eventData\"></use>\n </svg>\n Collections Info\n </span>\n </mat-checkbox>\n </button>\n <button mat-menu-item *ngIf=\"uiConfig?.showEtaPhiPanel\">\n <mat-checkbox\n [checked]=\"showEtaPhiPanel\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleEtaPhiPanel()\"\n >\n <span class=\"item-content\">\n <svg class=\"item-icon\">\n <use href=\"assets/icons/eta-phi.svg#eta-phi\"></use>\n </svg>\n Eta-Phi Panel\n </span>\n </mat-checkbox>\n </button>\n <button mat-menu-item *ngIf=\"uiConfig?.showGeometryBrowser\">\n <mat-checkbox\n [checked]=\"showGeometryBrowser\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleGeometryBrowser()\"\n >\n <span class=\"item-content\">\n <svg class=\"item-icon\">\n <use href=\"assets/icons/top-cube.svg#top-cube\"></use>\n </svg>\n Geometry Browser\n </span>\n </mat-checkbox>\n </button>\n <button mat-menu-item *ngIf=\"uiConfig?.showKinematicsPanel\">\n <mat-checkbox\n [checked]=\"showKinematicsPanel\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleKinematicsPanel()\"\n >\n <span class=\"item-content\">\n <svg class=\"item-icon\">\n <use href=\"assets/icons/kinematics.svg#kinematics\"></use>\n </svg>\n Track Kinematics\n </span>\n </mat-checkbox>\n </button>\n</mat-menu>\n\n<app-menu-toggle\n [matMenuTriggerFor]=\"moreInfo\"\n tooltip=\"More information\"\n icon=\"info\"\n [active]=\"false\"\n>\n</app-menu-toggle>\n", styles: [".hidden-panels{display:none}.item-content{display:inline-flex;align-items:center}.item-icon{inline-size:1.2rem;block-size:1.2rem;margin-inline-end:.5rem;fill:currentColor}\n"] }]
6503
- }], null, { uiConfig: [{
6504
- type: Input
6505
- }], kinematicsConfig: [{
6506
- type: Input
6507
- }], infoPanel: [{
6508
- type: ViewChild,
6509
- args: ['infoPanel']
6510
- }], eventBrowser: [{
6511
- type: ViewChild,
6512
- args: ['eventBrowser']
6513
- }], collectionsInfo: [{
6514
- type: ViewChild,
6515
- args: ['collectionsInfo']
6516
- }], etaPhiPanel: [{
6517
- type: ViewChild,
6518
- args: ['etaPhiPanel']
6519
- }], geometryBrowser: [{
6520
- type: ViewChild,
6521
- args: ['geometryBrowser']
6522
- }], kinematicsPanel: [{
6523
- type: ViewChild,
6524
- args: ['kinematicsPanel']
6525
- }] }); })();
6526
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MoreInfoComponent, { className: "MoreInfoComponent", filePath: "components/ui-menu/more-info/more-info.component.ts", lineNumber: 17 }); })();
7646
+ args: [{ standalone: false, selector: 'app-session-pill', template: "<div class=\"session-pill\" *ngIf=\"visible\" [attr.data-kind]=\"state.kind\">\n <!-- Recording -->\n <ng-container *ngIf=\"state.kind === 'recording'\">\n <span class=\"rec-dot\" aria-label=\"Recording\"></span>\n <span class=\"label\">REC</span>\n <span class=\"time\">{{ durationLabel }}</span>\n <span class=\"dot-sep\">\u00B7</span>\n <span class=\"count\">{{ eventCount }} events</span>\n <button\n type=\"button\"\n class=\"action stop\"\n (click)=\"onStopRecording()\"\n title=\"Stop recording (Shift+S)\"\n aria-label=\"Stop recording\"\n >\n \u25A0\n </button>\n </ng-container>\n\n <!-- Recorded (offer download / share) -->\n <ng-container *ngIf=\"state.kind === 'recorded'\">\n <span class=\"label\">Saved</span>\n <span class=\"time\">{{ durationLabel }}</span>\n <span class=\"dot-sep\">\u00B7</span>\n <span class=\"count\">{{ eventCount }} events</span>\n <button\n type=\"button\"\n class=\"action\"\n (click)=\"onDownload()\"\n title=\"Download .phnxreplay file\"\n aria-label=\"Download session\"\n >\n Download\n </button>\n <button\n type=\"button\"\n class=\"action\"\n (click)=\"onCopyLink()\"\n [disabled]=\"linkCopied\"\n title=\"Copy a ?replay= share link\"\n aria-label=\"Copy share link\"\n >\n {{ linkCopied ? 'Copied' : 'Copy link' }}\n </button>\n <button\n type=\"button\"\n class=\"action close\"\n (click)=\"onDismiss()\"\n title=\"Dismiss\"\n aria-label=\"Dismiss\"\n >\n \u2715\n </button>\n </ng-container>\n\n <!-- Pending: link-supplied session awaiting explicit user confirmation -->\n <ng-container *ngIf=\"state.kind === 'pending'\">\n <span class=\"label\">Shared session</span>\n <span class=\"time\">{{ pendingSummary }}</span>\n <span class=\"dot-sep\">\u00B7</span>\n <span class=\"count\">from {{ state.sourceLabel }}</span>\n <button\n type=\"button\"\n class=\"action play-pending\"\n (click)=\"onPlayPending()\"\n title=\"Play this shared session\"\n aria-label=\"Play shared session\"\n >\n Play\n </button>\n <button\n type=\"button\"\n class=\"action close\"\n (click)=\"onDismiss()\"\n title=\"Dismiss\"\n aria-label=\"Dismiss shared session\"\n >\n \u2715\n </button>\n </ng-container>\n\n <!-- Playing / Paused / Finished -->\n <ng-container\n *ngIf=\"\n state.kind === 'playing' ||\n state.kind === 'paused' ||\n state.kind === 'finished'\n \"\n >\n <button\n type=\"button\"\n class=\"action play\"\n (click)=\"onTogglePlayback()\"\n [title]=\"state.kind === 'playing' ? 'Pause' : 'Play'\"\n [attr.aria-label]=\"state.kind === 'playing' ? 'Pause' : 'Play'\"\n >\n {{ state.kind === 'playing' ? '\u275A\u275A' : '\u25BA' }}\n </button>\n <span class=\"label\">Replay</span>\n <span class=\"time\">{{ playbackLabel }}</span>\n <input\n type=\"range\"\n class=\"scrub\"\n min=\"0\"\n [max]=\"playerDuration\"\n step=\"50\"\n [value]=\"\n state.kind === 'finished' ? playerDuration : (state.currentTime ?? 0)\n \"\n (input)=\"onScrub(+$any($event.target).value)\"\n aria-label=\"Replay scrub bar\"\n />\n <span class=\"speeds\">\n <button\n type=\"button\"\n class=\"speed\"\n *ngFor=\"let s of speeds\"\n [class.selected]=\"currentSpeed === s\"\n (click)=\"onSpeed(s)\"\n [attr.aria-label]=\"'Speed ' + s + 'x'\"\n [attr.aria-pressed]=\"currentSpeed === s\"\n >\n {{ s }}\u00D7\n </button>\n </span>\n <button\n type=\"button\"\n class=\"action close\"\n (click)=\"onDismiss()\"\n title=\"Stop replay\"\n aria-label=\"Stop replay\"\n >\n \u2715\n </button>\n </ng-container>\n\n <!-- Error -->\n <ng-container *ngIf=\"state.kind === 'error'\">\n <span class=\"label error\">Session error</span>\n <span class=\"time\">{{ state.message }}</span>\n <button\n type=\"button\"\n class=\"action close\"\n (click)=\"onDismiss()\"\n title=\"Dismiss\"\n aria-label=\"Dismiss\"\n >\n \u2715\n </button>\n </ng-container>\n</div>\n", styles: [".session-pill{position:fixed;bottom:80px;left:16px;z-index:1100;display:flex;align-items:center;gap:10px;padding:8px 14px;background:#14161ed1;color:#e8eaf2;border-radius:999px;border:1px solid rgba(255,255,255,.08);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);box-shadow:0 6px 18px #00000059;font-size:13px;font-weight:500;letter-spacing:.2px;-webkit-user-select:none;user-select:none;max-width:80vw}.session-pill .label{font-weight:600;letter-spacing:.4px}.session-pill .label.error{color:#ff7676}.session-pill .time,.session-pill .count{font-variant-numeric:tabular-nums;opacity:.9}.session-pill .dot-sep{opacity:.4}.session-pill .rec-dot{width:10px;height:10px;border-radius:50%;background:#ff4040;box-shadow:0 0 6px #ff404099;animation:phoenixSessionPulse 1.2s infinite ease-in-out}.session-pill .action{background:#ffffff0f;color:inherit;border:1px solid rgba(255,255,255,.1);border-radius:999px;padding:4px 12px;cursor:pointer;font-size:12px;font-weight:600;letter-spacing:.3px;transition:background .12s ease,border-color .12s ease}.session-pill .action:hover{background:#ffffff1f;border-color:#ffffff2e}.session-pill .action:disabled{opacity:.6;cursor:default}.session-pill .action.stop{background:#ff40402e;border-color:#ff404066}.session-pill .action.stop:hover{background:#ff404047}.session-pill .action.close{width:24px;height:24px;padding:0;display:inline-flex;align-items:center;justify-content:center}.session-pill .action.play{width:28px;height:28px;padding:0;display:inline-flex;align-items:center;justify-content:center;font-size:11px}.session-pill .scrub{width:180px;accent-color:#80c1ff}.session-pill .speeds{display:inline-flex;gap:4px}.session-pill .speeds .speed{background:transparent;color:inherit;border:1px solid rgba(255,255,255,.12);border-radius:999px;padding:3px 8px;cursor:pointer;font-size:11px;font-weight:600;opacity:.65;transition:opacity .12s ease,background .12s ease}.session-pill .speeds .speed:hover{opacity:1}.session-pill .speeds .speed.selected{background:#80c1ff2e;border-color:#80c1ff80;opacity:1}@keyframes phoenixSessionPulse{0%,to{opacity:1;transform:scale(1)}50%{opacity:.65;transform:scale(.85)}}\n"] }]
7647
+ }], () => [{ type: EventDisplayService }, { type: i0.ChangeDetectorRef }], null); })();
7648
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(SessionPillComponent, { className: "SessionPillComponent", filePath: "components/session-pill/session-pill.component.ts", lineNumber: 23 }); })();
7649
+ function formatClock(ms) {
7650
+ if (!isFinite(ms) || ms < 0)
7651
+ return '00:00';
7652
+ const totalSeconds = Math.floor(ms / 1000);
7653
+ const minutes = Math.floor(totalSeconds / 60);
7654
+ const seconds = totalSeconds % 60;
7655
+ return `${pad(minutes)}:${pad(seconds)}`;
7656
+ }
7657
+ function pad(n) {
7658
+ return n < 10 ? `0${n}` : String(n);
7659
+ }
6527
7660
 
6528
7661
  const _c0$1 = ["*"];
6529
7662
  const _c1$1 = a0 => ({ "ui-menu-hidden": a0 });
6530
7663
  class UiMenuWrapperComponent {
6531
7664
  hideUIMenu = false;
6532
7665
  static ɵfac = function UiMenuWrapperComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || UiMenuWrapperComponent)(); };
6533
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: UiMenuWrapperComponent, selectors: [["app-ui-menu-wrapper"]], standalone: false, ngContentSelectors: _c0$1, decls: 6, vars: 5, consts: [["id", "uiMenu"], ["id", "hideUIMenu", "matTooltipPosition", "above", 3, "click", "matTooltip", "ngClass"], ["href", "assets/icons/expand.svg#expand"], ["id", "optionsPanel", 3, "hidden"]], template: function UiMenuWrapperComponent_Template(rf, ctx) { if (rf & 1) {
7666
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: UiMenuWrapperComponent, selectors: [["app-ui-menu-wrapper"]], standalone: false, ngContentSelectors: _c0$1, decls: 7, vars: 5, consts: [["id", "uiMenu"], ["id", "hideUIMenu", "type", "button", "aria-label", "Toggle toolbar visibility", "matTooltipPosition", "above", 3, "click", "matTooltip", "ngClass"], ["href", "assets/icons/expand.svg#expand"], ["id", "optionsPanel", 3, "hidden"]], template: function UiMenuWrapperComponent_Template(rf, ctx) { if (rf & 1) {
6534
7667
  i0.ɵɵprojectionDef();
6535
7668
  i0.ɵɵelementStart(0, "div", 0)(1, "button", 1);
6536
7669
  i0.ɵɵlistener("click", function UiMenuWrapperComponent_Template_button_click_1_listener() { return ctx.hideUIMenu = !ctx.hideUIMenu; });
@@ -6542,16 +7675,17 @@ class UiMenuWrapperComponent {
6542
7675
  i0.ɵɵelementStart(4, "div", 3);
6543
7676
  i0.ɵɵprojection(5);
6544
7677
  i0.ɵɵelementEnd()();
7678
+ i0.ɵɵelement(6, "app-session-pill");
6545
7679
  } if (rf & 2) {
6546
7680
  i0.ɵɵadvance();
6547
7681
  i0.ɵɵproperty("matTooltip", ctx.hideUIMenu ? "Show toolbar" : "Hide toolbar")("ngClass", i0.ɵɵpureFunction1(3, _c1$1, ctx.hideUIMenu));
6548
7682
  i0.ɵɵadvance(3);
6549
7683
  i0.ɵɵproperty("hidden", ctx.hideUIMenu);
6550
- } }, dependencies: [i2.NgClass, i3$1.MatTooltip], styles: ["#uiMenu[_ngcontent-%COMP%]{position:absolute;bottom:1rem;width:100%;box-sizing:border-box;display:flex;flex-direction:column;align-items:center}#optionsPanel[_ngcontent-%COMP%]{display:flex;align-items:center;background:var(--phoenix-background-color-secondary);border:1px solid var(--phoenix-background-color-tertiary);box-shadow:var(--phoenix-box-shadow);border-radius:30px;max-width:95%;padding:.3rem 1rem;overflow-x:scroll;z-index:90}#hideUIMenu[_ngcontent-%COMP%]{background:var(--phoenix-background-color-secondary);height:1.2rem;width:3rem;border:1px solid var(--phoenix-border);border-bottom:none;box-shadow:var(--phoenix-box-shadow);border-top-left-radius:15px;border-top-right-radius:15px;padding:3px}#hideUIMenu[_ngcontent-%COMP%] svg[_ngcontent-%COMP%]{height:100%;width:100%;vertical-align:top;transition:all .3s}#hideUIMenu.ui-menu-hidden[_ngcontent-%COMP%] svg[_ngcontent-%COMP%]{transform:scaleY(-1);transition:all .3s}"] });
7684
+ } }, dependencies: [i2.NgClass, i3$1.MatTooltip, SessionPillComponent], styles: ["#uiMenu[_ngcontent-%COMP%]{position:absolute;bottom:1rem;width:100%;box-sizing:border-box;display:flex;flex-direction:column;align-items:center}#optionsPanel[_ngcontent-%COMP%]{display:flex;align-items:center;background:var(--phoenix-background-color-secondary);border:1px solid var(--phoenix-background-color-tertiary);box-shadow:var(--phoenix-box-shadow);border-radius:30px;max-width:95%;padding:.3rem 1rem;overflow-x:scroll;z-index:90}#hideUIMenu[_ngcontent-%COMP%]{background:var(--phoenix-background-color-secondary);height:1.2rem;width:3rem;border:1px solid var(--phoenix-border);border-bottom:none;box-shadow:var(--phoenix-box-shadow);border-top-left-radius:15px;border-top-right-radius:15px;padding:3px}#hideUIMenu[_ngcontent-%COMP%] svg[_ngcontent-%COMP%]{height:100%;width:100%;vertical-align:top;transition:all .3s}#hideUIMenu.ui-menu-hidden[_ngcontent-%COMP%] svg[_ngcontent-%COMP%]{transform:scaleY(-1);transition:all .3s}"] });
6551
7685
  }
6552
7686
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(UiMenuWrapperComponent, [{
6553
7687
  type: Component,
6554
- args: [{ standalone: false, selector: 'app-ui-menu-wrapper', template: "<div id=\"uiMenu\">\n <button\n id=\"hideUIMenu\"\n [matTooltip]=\"hideUIMenu ? 'Show toolbar' : 'Hide toolbar'\"\n matTooltipPosition=\"above\"\n (click)=\"hideUIMenu = !hideUIMenu\"\n [ngClass]=\"{ 'ui-menu-hidden': hideUIMenu }\"\n >\n <svg>\n <use href=\"assets/icons/expand.svg#expand\"></use>\n </svg>\n </button>\n <div id=\"optionsPanel\" [hidden]=\"hideUIMenu\">\n <ng-content></ng-content>\n </div>\n</div>\n", styles: ["#uiMenu{position:absolute;bottom:1rem;width:100%;box-sizing:border-box;display:flex;flex-direction:column;align-items:center}#optionsPanel{display:flex;align-items:center;background:var(--phoenix-background-color-secondary);border:1px solid var(--phoenix-background-color-tertiary);box-shadow:var(--phoenix-box-shadow);border-radius:30px;max-width:95%;padding:.3rem 1rem;overflow-x:scroll;z-index:90}#hideUIMenu{background:var(--phoenix-background-color-secondary);height:1.2rem;width:3rem;border:1px solid var(--phoenix-border);border-bottom:none;box-shadow:var(--phoenix-box-shadow);border-top-left-radius:15px;border-top-right-radius:15px;padding:3px}#hideUIMenu svg{height:100%;width:100%;vertical-align:top;transition:all .3s}#hideUIMenu.ui-menu-hidden svg{transform:scaleY(-1);transition:all .3s}\n"] }]
7688
+ args: [{ standalone: false, selector: 'app-ui-menu-wrapper', template: "<div id=\"uiMenu\">\n <button\n id=\"hideUIMenu\"\n type=\"button\"\n aria-label=\"Toggle toolbar visibility\"\n [matTooltip]=\"hideUIMenu ? 'Show toolbar' : 'Hide toolbar'\"\n matTooltipPosition=\"above\"\n (click)=\"hideUIMenu = !hideUIMenu\"\n [ngClass]=\"{ 'ui-menu-hidden': hideUIMenu }\"\n >\n <svg>\n <use href=\"assets/icons/expand.svg#expand\"></use>\n </svg>\n </button>\n <div id=\"optionsPanel\" [hidden]=\"hideUIMenu\">\n <ng-content></ng-content>\n </div>\n</div>\n<app-session-pill></app-session-pill>\n", styles: ["#uiMenu{position:absolute;bottom:1rem;width:100%;box-sizing:border-box;display:flex;flex-direction:column;align-items:center}#optionsPanel{display:flex;align-items:center;background:var(--phoenix-background-color-secondary);border:1px solid var(--phoenix-background-color-tertiary);box-shadow:var(--phoenix-box-shadow);border-radius:30px;max-width:95%;padding:.3rem 1rem;overflow-x:scroll;z-index:90}#hideUIMenu{background:var(--phoenix-background-color-secondary);height:1.2rem;width:3rem;border:1px solid var(--phoenix-border);border-bottom:none;box-shadow:var(--phoenix-box-shadow);border-top-left-radius:15px;border-top-right-radius:15px;padding:3px}#hideUIMenu svg{height:100%;width:100%;vertical-align:top;transition:all .3s}#hideUIMenu.ui-menu-hidden svg{transform:scaleY(-1);transition:all .3s}\n"] }]
6555
7689
  }], null, null); })();
6556
7690
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(UiMenuWrapperComponent, { className: "UiMenuWrapperComponent", filePath: "components/ui-menu/ui-menu-wrapper/ui-menu-wrapper.component.ts", lineNumber: 9 }); })();
6557
7691
 
@@ -6979,13 +8113,27 @@ class MasterclassPanelOverlayComponent {
6979
8113
  // ── Step 1: Collection ──────────────────────────────────
6980
8114
  loadCollections() {
6981
8115
  const grouped = this.eventDisplay.getCollections();
8116
+ // Restrict to taggable types (default 'Tracks') so detector-level
8117
+ // collections (hits like CSCs, calo cells) do not show up. See #923.
8118
+ const types = this.config?.collectionTypes ?? ['Tracks'];
6982
8119
  this.collectionNames = [];
6983
- for (const [, names] of Object.entries(grouped)) {
6984
- this.collectionNames.push(...names);
8120
+ for (const type of types) {
8121
+ if (grouped[type]) {
8122
+ this.collectionNames.push(...grouped[type]);
8123
+ }
6985
8124
  }
6986
- if (this.collectionNames.length > 0 && !this.selectedCollection) {
8125
+ if (this.collectionNames.length === 0) {
8126
+ this.selectedCollection = '';
8127
+ this.collectionItems = [];
8128
+ return;
8129
+ }
8130
+ if (!this.selectedCollection ||
8131
+ !this.collectionNames.includes(this.selectedCollection)) {
6987
8132
  this.selectCollection(this.collectionNames[0]);
6988
8133
  }
8134
+ else {
8135
+ this.selectCollection(this.selectedCollection);
8136
+ }
6989
8137
  }
6990
8138
  selectCollection(name) {
6991
8139
  this.selectedCollection = name;
@@ -7166,7 +8314,7 @@ class MasterclassPanelComponent {
7166
8314
  this.showPanel = !this.showPanel;
7167
8315
  this.overlayWindow.instance.showPanel = this.showPanel;
7168
8316
  }
7169
- static ɵfac = function MasterclassPanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MasterclassPanelComponent)(i0.ɵɵdirectiveInject(i1$1.Overlay)); };
8317
+ static ɵfac = function MasterclassPanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || MasterclassPanelComponent)(i0.ɵɵdirectiveInject(i1$3.Overlay)); };
7170
8318
  static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: MasterclassPanelComponent, selectors: [["app-masterclass-panel"]], inputs: { config: "config" }, standalone: false, features: [i0.ɵɵNgOnChangesFeature], decls: 1, vars: 1, consts: [["tooltip", "Masterclass: tag particles and calculate invariant mass", "icon", "physics", 3, "click", "active"]], template: function MasterclassPanelComponent_Template(rf, ctx) { if (rf & 1) {
7171
8319
  i0.ɵɵelementStart(0, "app-menu-toggle", 0);
7172
8320
  i0.ɵɵlistener("click", function MasterclassPanelComponent_Template_app_menu_toggle_click_0_listener() { return ctx.toggleOverlay(); });
@@ -7178,7 +8326,7 @@ class MasterclassPanelComponent {
7178
8326
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(MasterclassPanelComponent, [{
7179
8327
  type: Component,
7180
8328
  args: [{ standalone: false, selector: 'app-masterclass-panel', template: "<app-menu-toggle\n tooltip=\"Masterclass: tag particles and calculate invariant mass\"\n icon=\"physics\"\n [active]=\"showPanel\"\n (click)=\"toggleOverlay()\"\n>\n</app-menu-toggle>\n" }]
7181
- }], () => [{ type: i1$1.Overlay }], { config: [{
8329
+ }], () => [{ type: i1$3.Overlay }], { config: [{
7182
8330
  type: Input
7183
8331
  }] }); })();
7184
8332
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MasterclassPanelComponent, { className: "MasterclassPanelComponent", filePath: "components/ui-menu/masterclass-panel/masterclass-panel.component.ts", lineNumber: 21 }); })();
@@ -7213,36 +8361,15 @@ class ErrorMessageService {
7213
8361
 
7214
8362
  const _c0 = a0 => ({ "load-complete": a0 });
7215
8363
  const _c1 = a0 => ({ width: a0 });
7216
- function LoaderComponent_ng_container_1_div_7_Template(rf, ctx) { if (rf & 1) {
7217
- i0.ɵɵelementStart(0, "div", 7);
8364
+ function LoaderComponent_div_7_Template(rf, ctx) { if (rf & 1) {
8365
+ i0.ɵɵelementStart(0, "div", 5);
7218
8366
  i0.ɵɵelement(1, "span");
7219
8367
  i0.ɵɵelementEnd();
7220
8368
  } if (rf & 2) {
7221
- const ctx_r0 = i0.ɵɵnextContext(2);
8369
+ const ctx_r0 = i0.ɵɵnextContext();
7222
8370
  i0.ɵɵadvance();
7223
8371
  i0.ɵɵstyleMap(i0.ɵɵpureFunction1(2, _c1, ctx_r0.progress + "%"));
7224
8372
  } }
7225
- function LoaderComponent_ng_container_1_Template(rf, ctx) { if (rf & 1) {
7226
- i0.ɵɵelementContainerStart(0);
7227
- i0.ɵɵelement(1, "img", 3);
7228
- i0.ɵɵelementStart(2, "p", 4);
7229
- i0.ɵɵtext(3, " Loading...");
7230
- i0.ɵɵelement(4, "br");
7231
- i0.ɵɵelementStart(5, "small", 5);
7232
- i0.ɵɵtext(6, "(This may take a while)");
7233
- i0.ɵɵelementEnd()();
7234
- i0.ɵɵtemplate(7, LoaderComponent_ng_container_1_div_7_Template, 2, 4, "div", 6);
7235
- i0.ɵɵelementContainerEnd();
7236
- } if (rf & 2) {
7237
- const ctx_r0 = i0.ɵɵnextContext();
7238
- i0.ɵɵadvance(7);
7239
- i0.ɵɵproperty("ngIf", ctx_r0.progress !== undefined);
7240
- } }
7241
- function LoaderComponent_ng_template_2_Template(rf, ctx) { if (rf & 1) {
7242
- i0.ɵɵelementStart(0, "p");
7243
- i0.ɵɵtext(1, " An error occurred while loading the application. Please try refreshing the page. ");
7244
- i0.ɵɵelementEnd();
7245
- } }
7246
8373
  class LoaderComponent {
7247
8374
  errorMessageService;
7248
8375
  loaded = false;
@@ -7261,20 +8388,26 @@ class LoaderComponent {
7261
8388
  this.unsubscribeError();
7262
8389
  }
7263
8390
  static ɵfac = function LoaderComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || LoaderComponent)(i0.ɵɵdirectiveInject(ErrorMessageService)); };
7264
- static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: LoaderComponent, selectors: [["app-loader"]], inputs: { loaded: "loaded", progress: "progress" }, standalone: false, decls: 4, vars: 5, consts: [["errorContainer", ""], [1, "loader-wrapper", "d-flex", "position-absolute", "flex-column", "justify-content-center", "align-items-center", "w-100", "h-100", "p-5", "text-center", 3, "ngClass"], [4, "ngIf", "ngIfElse"], ["src", "assets/images/logo-small.svg", "alt", "Loader"], [1, "mt-5"], [1, "text-muted"], ["class", "loading-bar", 4, "ngIf"], [1, "loading-bar"]], template: function LoaderComponent_Template(rf, ctx) { if (rf & 1) {
7265
- i0.ɵɵelementStart(0, "div", 1);
7266
- i0.ɵɵtemplate(1, LoaderComponent_ng_container_1_Template, 8, 1, "ng-container", 2)(2, LoaderComponent_ng_template_2_Template, 2, 0, "ng-template", null, 0, i0.ɵɵtemplateRefExtractor);
8391
+ static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: LoaderComponent, selectors: [["app-loader"]], inputs: { loaded: "loaded", progress: "progress" }, standalone: false, decls: 8, vars: 4, consts: [[1, "loader-wrapper", "d-flex", "position-absolute", "flex-column", "justify-content-center", "align-items-center", "w-100", "h-100", "p-5", "text-center", 3, "ngClass"], ["src", "assets/images/logo-small.svg", "alt", "Loader"], [1, "mt-5"], [1, "text-muted"], ["class", "loading-bar", 4, "ngIf"], [1, "loading-bar"]], template: function LoaderComponent_Template(rf, ctx) { if (rf & 1) {
8392
+ i0.ɵɵelementStart(0, "div", 0);
8393
+ i0.ɵɵelement(1, "img", 1);
8394
+ i0.ɵɵelementStart(2, "p", 2);
8395
+ i0.ɵɵtext(3, " Loading...");
8396
+ i0.ɵɵelement(4, "br");
8397
+ i0.ɵɵelementStart(5, "small", 3);
8398
+ i0.ɵɵtext(6, "(This may take a while)");
8399
+ i0.ɵɵelementEnd()();
8400
+ i0.ɵɵtemplate(7, LoaderComponent_div_7_Template, 2, 4, "div", 4);
7267
8401
  i0.ɵɵelementEnd();
7268
8402
  } if (rf & 2) {
7269
- const errorContainer_r2 = i0.ɵɵreference(3);
7270
- i0.ɵɵproperty("ngClass", i0.ɵɵpureFunction1(3, _c0, ctx.loaded));
7271
- i0.ɵɵadvance();
7272
- i0.ɵɵproperty("ngIf", ctx.error === undefined)("ngIfElse", errorContainer_r2);
8403
+ i0.ɵɵproperty("ngClass", i0.ɵɵpureFunction1(2, _c0, ctx.loaded));
8404
+ i0.ɵɵadvance(7);
8405
+ i0.ɵɵproperty("ngIf", ctx.progress !== undefined);
7273
8406
  } }, dependencies: [i2.NgClass, i2.NgIf], styles: [".loader-wrapper[_ngcontent-%COMP%]{background:var(--phoenix-background-color);z-index:9998}.loader-wrapper.load-complete[_ngcontent-%COMP%]{display:none!important}.loader-wrapper[_ngcontent-%COMP%] img[_ngcontent-%COMP%]{width:5rem;height:5rem;animation:loader 2s infinite}.loader-wrapper[_ngcontent-%COMP%] p[_ngcontent-%COMP%]{color:var(--phoenix-text-color)}.loader-wrapper[_ngcontent-%COMP%] .loading-bar[_ngcontent-%COMP%]{width:15rem;max-width:90%;height:.5rem;background:var(--phoenix-background-color-tertiary);border-radius:2.5rem;overflow:hidden}.loader-wrapper[_ngcontent-%COMP%] .loading-bar[_ngcontent-%COMP%] span[_ngcontent-%COMP%]{display:block;height:100%;border-radius:2.5rem;background:linear-gradient(to right,var(--phoenix-primary),var(--phoenix-secondary));transition:all .5s}@keyframes _ngcontent-%COMP%_app-loader_loader{0%,to{transform:scale(.1) rotate(0)}95%{transform:scale(1) rotate(15deg)}}"] });
7274
8407
  }
7275
8408
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(LoaderComponent, [{
7276
8409
  type: Component,
7277
- args: [{ standalone: false, selector: 'app-loader', template: "<div\n class=\"loader-wrapper d-flex position-absolute flex-column justify-content-center align-items-center w-100 h-100 p-5 text-center\"\n [ngClass]=\"{ 'load-complete': loaded }\"\n>\n <ng-container *ngIf=\"error === undefined; else errorContainer\">\n <img src=\"assets/images/logo-small.svg\" alt=\"Loader\" />\n <p class=\"mt-5\">\n Loading...<br />\n <small class=\"text-muted\">(This may take a while)</small>\n </p>\n <div class=\"loading-bar\" *ngIf=\"progress !== undefined\">\n <span [style]=\"{ width: progress + '%' }\"></span>\n </div>\n </ng-container>\n <ng-template #errorContainer>\n <p>\n An error occurred while loading the application. Please try refreshing the\n page.\n </p>\n </ng-template>\n</div>\n", styles: [".loader-wrapper{background:var(--phoenix-background-color);z-index:9998}.loader-wrapper.load-complete{display:none!important}.loader-wrapper img{width:5rem;height:5rem;animation:loader 2s infinite}.loader-wrapper p{color:var(--phoenix-text-color)}.loader-wrapper .loading-bar{width:15rem;max-width:90%;height:.5rem;background:var(--phoenix-background-color-tertiary);border-radius:2.5rem;overflow:hidden}.loader-wrapper .loading-bar span{display:block;height:100%;border-radius:2.5rem;background:linear-gradient(to right,var(--phoenix-primary),var(--phoenix-secondary));transition:all .5s}@keyframes app-loader_loader{0%,to{transform:scale(.1) rotate(0)}95%{transform:scale(1) rotate(15deg)}}\n"] }]
8410
+ args: [{ standalone: false, selector: 'app-loader', template: "<div\n class=\"loader-wrapper d-flex position-absolute flex-column justify-content-center align-items-center w-100 h-100 p-5 text-center\"\n [ngClass]=\"{ 'load-complete': loaded }\"\n>\n <img src=\"assets/images/logo-small.svg\" alt=\"Loader\" />\n <p class=\"mt-5\">\n Loading...<br />\n <small class=\"text-muted\">(This may take a while)</small>\n </p>\n <div class=\"loading-bar\" *ngIf=\"progress !== undefined\">\n <span [style]=\"{ width: progress + '%' }\"></span>\n </div>\n</div>\n", styles: [".loader-wrapper{background:var(--phoenix-background-color);z-index:9998}.loader-wrapper.load-complete{display:none!important}.loader-wrapper img{width:5rem;height:5rem;animation:loader 2s infinite}.loader-wrapper p{color:var(--phoenix-text-color)}.loader-wrapper .loading-bar{width:15rem;max-width:90%;height:.5rem;background:var(--phoenix-background-color-tertiary);border-radius:2.5rem;overflow:hidden}.loader-wrapper .loading-bar span{display:block;height:100%;border-radius:2.5rem;background:linear-gradient(to right,var(--phoenix-primary),var(--phoenix-secondary));transition:all .5s}@keyframes app-loader_loader{0%,to{transform:scale(.1) rotate(0)}95%{transform:scale(1) rotate(15deg)}}\n"] }]
7278
8411
  }], () => [{ type: ErrorMessageService }], { loaded: [{
7279
8412
  type: Input
7280
8413
  }], progress: [{
@@ -7348,6 +8481,7 @@ class EmbedMenuComponent {
7348
8481
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(EmbedMenuComponent, { className: "EmbedMenuComponent", filePath: "components/embed-menu/embed-menu.component.ts", lineNumber: 9 }); })();
7349
8482
 
7350
8483
  const PHOENIX_COMPONENTS = [
8484
+ NotificationToastComponent,
7351
8485
  NavComponent,
7352
8486
  UiMenuWrapperComponent,
7353
8487
  UiMenuComponent,
@@ -7381,6 +8515,7 @@ const PHOENIX_COMPONENTS = [
7381
8515
  PhoenixMenuItemComponent,
7382
8516
  ConfigSliderComponent,
7383
8517
  AnimateCameraComponent,
8518
+ DownloadAnimationDialogComponent,
7384
8519
  AnimateEventComponent,
7385
8520
  VrToggleComponent,
7386
8521
  ArToggleComponent,
@@ -7405,18 +8540,21 @@ const PHOENIX_COMPONENTS = [
7405
8540
  KinematicsPanelOverlayComponent,
7406
8541
  MasterclassPanelComponent,
7407
8542
  MasterclassPanelOverlayComponent,
8543
+ SessionPillComponent,
8544
+ ShortcutsDialogComponent,
7408
8545
  ];
7409
8546
  class PhoenixUIModule {
7410
8547
  static ɵfac = function PhoenixUIModule_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || PhoenixUIModule)(); };
7411
8548
  static ɵmod = /*@__PURE__*/ i0.ɵɵdefineNgModule({ type: PhoenixUIModule });
7412
8549
  static ɵinj = /*@__PURE__*/ i0.ɵɵdefineInjector({ providers: [
8550
+ NotificationService,
7413
8551
  EventDisplayService,
7414
8552
  ErrorMessageService,
7415
8553
  {
7416
8554
  provide: ErrorHandler,
7417
8555
  useClass: GlobalErrorHandler,
7418
8556
  },
7419
- ], imports: [// Correct: standalone items must be in imports
8557
+ ], imports: [MatSnackBarModule, // Correct: standalone items must be in imports
7420
8558
  CommonModule,
7421
8559
  RouterModule,
7422
8560
  DragDropModule,
@@ -7433,13 +8571,15 @@ class PhoenixUIModule {
7433
8571
  MatCheckboxModule,
7434
8572
  MatIconModule,
7435
8573
  CdkTreeModule,
7436
- MatTabsModule] });
8574
+ MatTabsModule,
8575
+ MatProgressBarModule] });
7437
8576
  }
7438
8577
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(PhoenixUIModule, [{
7439
8578
  type: NgModule,
7440
8579
  args: [{
7441
8580
  declarations: PHOENIX_COMPONENTS,
7442
8581
  imports: [
8582
+ MatSnackBarModule,
7443
8583
  AttributePipe, // Correct: standalone items must be in imports
7444
8584
  CommonModule,
7445
8585
  RouterModule,
@@ -7458,12 +8598,14 @@ class PhoenixUIModule {
7458
8598
  MatIconModule,
7459
8599
  CdkTreeModule,
7460
8600
  MatTabsModule,
8601
+ MatProgressBarModule,
7461
8602
  ],
7462
8603
  exports: [
7463
8604
  ...PHOENIX_COMPONENTS,
7464
8605
  AttributePipe, // Export it so components in other modules can use it
7465
8606
  ],
7466
8607
  providers: [
8608
+ NotificationService,
7467
8609
  EventDisplayService,
7468
8610
  ErrorMessageService,
7469
8611
  {
@@ -7473,7 +8615,8 @@ class PhoenixUIModule {
7473
8615
  ],
7474
8616
  }]
7475
8617
  }], null, null); })();
7476
- (function () { (typeof ngJitMode === "undefined" || ngJitMode) && i0.ɵɵsetNgModuleScope(PhoenixUIModule, { declarations: [NavComponent,
8618
+ (function () { (typeof ngJitMode === "undefined" || ngJitMode) && i0.ɵɵsetNgModuleScope(PhoenixUIModule, { declarations: [NotificationToastComponent,
8619
+ NavComponent,
7477
8620
  UiMenuWrapperComponent,
7478
8621
  UiMenuComponent,
7479
8622
  MoreInfoComponent,
@@ -7506,6 +8649,7 @@ class PhoenixUIModule {
7506
8649
  PhoenixMenuItemComponent,
7507
8650
  ConfigSliderComponent,
7508
8651
  AnimateCameraComponent,
8652
+ DownloadAnimationDialogComponent,
7509
8653
  AnimateEventComponent,
7510
8654
  VrToggleComponent,
7511
8655
  ArToggleComponent,
@@ -7529,7 +8673,10 @@ class PhoenixUIModule {
7529
8673
  KinematicsPanelComponent,
7530
8674
  KinematicsPanelOverlayComponent,
7531
8675
  MasterclassPanelComponent,
7532
- MasterclassPanelOverlayComponent], imports: [AttributePipe, // Correct: standalone items must be in imports
8676
+ MasterclassPanelOverlayComponent,
8677
+ SessionPillComponent,
8678
+ ShortcutsDialogComponent], imports: [MatSnackBarModule,
8679
+ AttributePipe, // Correct: standalone items must be in imports
7533
8680
  CommonModule,
7534
8681
  RouterModule,
7535
8682
  DragDropModule,
@@ -7546,7 +8693,9 @@ class PhoenixUIModule {
7546
8693
  MatCheckboxModule,
7547
8694
  MatIconModule,
7548
8695
  CdkTreeModule,
7549
- MatTabsModule], exports: [NavComponent,
8696
+ MatTabsModule,
8697
+ MatProgressBarModule], exports: [NotificationToastComponent,
8698
+ NavComponent,
7550
8699
  UiMenuWrapperComponent,
7551
8700
  UiMenuComponent,
7552
8701
  MoreInfoComponent,
@@ -7579,6 +8728,7 @@ class PhoenixUIModule {
7579
8728
  PhoenixMenuItemComponent,
7580
8729
  ConfigSliderComponent,
7581
8730
  AnimateCameraComponent,
8731
+ DownloadAnimationDialogComponent,
7582
8732
  AnimateEventComponent,
7583
8733
  VrToggleComponent,
7584
8734
  ArToggleComponent,
@@ -7602,7 +8752,9 @@ class PhoenixUIModule {
7602
8752
  KinematicsPanelComponent,
7603
8753
  KinematicsPanelOverlayComponent,
7604
8754
  MasterclassPanelComponent,
7605
- MasterclassPanelOverlayComponent, AttributePipe] }); })();
8755
+ MasterclassPanelOverlayComponent,
8756
+ SessionPillComponent,
8757
+ ShortcutsDialogComponent, AttributePipe] }); })();
7606
8758
  i0.ɵɵsetComponentScope(UiMenuComponent, [i2.NgIf, UiMenuWrapperComponent,
7607
8759
  MoreInfoComponent,
7608
8760
  IoOptionsComponent,
@@ -7624,94 +8776,11 @@ i0.ɵɵsetComponentScope(UiMenuComponent, [i2.NgIf, UiMenuWrapperComponent,
7624
8776
  ShareLinkComponent,
7625
8777
  MasterclassPanelComponent], []);
7626
8778
 
7627
- /**
7628
- * Service for displaying user-facing notifications with severity levels.
7629
- * Provides success, info, warning, and error notifications with
7630
- * configurable auto-dismiss durations. Replaces silent console errors
7631
- * with actionable user feedback across all Phoenix components.
7632
- */
7633
- class NotificationService {
7634
- /** Default auto-dismiss durations in milliseconds per severity level. */
7635
- defaultDurations = {
7636
- success: 5000,
7637
- info: 5000,
7638
- warning: 8000,
7639
- error: 0,
7640
- };
7641
- /** Active variable that stores the latest notification. */
7642
- notification = new ActiveVariable();
7643
- /**
7644
- * Subscribe to incoming notifications.
7645
- * @param callback Function called when a notification is emitted.
7646
- * @returns A function that can be called to unsubscribe.
7647
- */
7648
- subscribeToNotifications(callback) {
7649
- return this.notification.onUpdate(callback);
7650
- }
7651
- /**
7652
- * Display a success notification.
7653
- * Auto-dismisses after 5 seconds by default.
7654
- * @param message The message to display.
7655
- * @param duration Optional custom duration in ms. 0 means no auto-dismiss.
7656
- */
7657
- success(message, duration) {
7658
- this.notify(message, 'success', duration);
7659
- }
7660
- /**
7661
- * Display an info notification.
7662
- * Auto-dismisses after 5 seconds by default.
7663
- * @param message The message to display.
7664
- * @param duration Optional custom duration in ms. 0 means no auto-dismiss.
7665
- */
7666
- info(message, duration) {
7667
- this.notify(message, 'info', duration);
7668
- }
7669
- /**
7670
- * Display a warning notification.
7671
- * Auto-dismisses after 8 seconds by default.
7672
- * @param message The message to display.
7673
- * @param duration Optional custom duration in ms. 0 means no auto-dismiss.
7674
- */
7675
- warning(message, duration) {
7676
- this.notify(message, 'warning', duration);
7677
- }
7678
- /**
7679
- * Display an error notification.
7680
- * Does not auto-dismiss by default — requires manual dismissal.
7681
- * @param message The message to display.
7682
- * @param duration Optional custom duration in ms. 0 means no auto-dismiss.
7683
- */
7684
- error(message, duration) {
7685
- this.notify(message, 'error', duration);
7686
- }
7687
- /**
7688
- * Internal method to emit a notification.
7689
- * @param message The message to display.
7690
- * @param severity The severity level.
7691
- * @param duration Optional custom duration override.
7692
- */
7693
- notify(message, severity, duration) {
7694
- this.notification.update({
7695
- message,
7696
- severity,
7697
- duration: duration ?? this.defaultDurations[severity],
7698
- });
7699
- }
7700
- static ɵfac = function NotificationService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || NotificationService)(); };
7701
- static ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: NotificationService, factory: NotificationService.ɵfac, providedIn: 'root' });
7702
- }
7703
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(NotificationService, [{
7704
- type: Injectable,
7705
- args: [{
7706
- providedIn: 'root',
7707
- }]
7708
- }], null, null); })();
7709
-
7710
8779
  // Components
7711
8780
 
7712
8781
  /**
7713
8782
  * Generated bundle index. Do not edit.
7714
8783
  */
7715
8784
 
7716
- export { AnimateCameraComponent, AnimateEventComponent, ArToggleComponent, AttributePipe, AutoRotateComponent, CartesianGridConfigComponent, CollectionsInfoComponent, CollectionsInfoOverlayComponent, ConfigSliderComponent, CycleEventsComponent, DarkThemeComponent, EmbedMenuComponent, EtaPhiPanelComponent, EtaPhiPanelOverlayComponent, EventBrowserComponent, EventBrowserOverlayComponent, EventDataExplorerComponent, EventDataExplorerDialogComponent, EventDataFormat, EventDisplayService, EventSelectorComponent, ExperimentInfoComponent, ExperimentLinkComponent, FileEvent, FileExplorerComponent, FileNode, GeometryBrowserComponent, GeometryBrowserOverlayComponent, IOOptionsDialogComponent, ImportOption, InfoPanelComponent, InfoPanelOverlayComponent, IoOptionsComponent, KinematicsPanelComponent, KinematicsPanelOverlayComponent, LoaderComponent, MainViewToggleComponent, MakePictureComponent, MasterclassPanelComponent, MasterclassPanelOverlayComponent, MenuToggleComponent, MoreInfoComponent, NavComponent, NotificationService, ObjectClippingComponent, ObjectSelectionComponent, ObjectSelectionOverlayComponent, OverlayComponent, OverlayViewComponent, OverlayViewWindowComponent, PerformanceToggleComponent, PhoenixMenuComponent, PhoenixMenuItemComponent, PhoenixUIModule, RingLoaderComponent, SSModeComponent, ShareLinkComponent, ShareLinkDialogComponent, TreeMenuComponent, TreeMenuItemComponent, UiMenuComponent, UiMenuWrapperComponent, ViewOptionsComponent, VrToggleComponent, ZoomControlsComponent, defaultAnimationPresets, defaultUIMenuConfig };
8785
+ export { AnimateCameraComponent, AnimateEventComponent, ArToggleComponent, AttributePipe, AutoRotateComponent, CartesianGridConfigComponent, CollectionsInfoComponent, CollectionsInfoOverlayComponent, ConfigSliderComponent, CycleEventsComponent, DarkThemeComponent, DownloadAnimationDialogComponent, EmbedMenuComponent, EtaPhiPanelComponent, EtaPhiPanelOverlayComponent, EventBrowserComponent, EventBrowserOverlayComponent, EventDataExplorerComponent, EventDataExplorerDialogComponent, EventDataFormat, EventDisplayService, EventSelectorComponent, ExperimentInfoComponent, ExperimentLinkComponent, FileEvent, FileExplorerComponent, FileNode, GeometryBrowserComponent, GeometryBrowserOverlayComponent, IOOptionsDialogComponent, ImportOption, InfoPanelComponent, InfoPanelOverlayComponent, IoOptionsComponent, KinematicsPanelComponent, KinematicsPanelOverlayComponent, LoaderComponent, MainViewToggleComponent, MakePictureComponent, MasterclassPanelComponent, MasterclassPanelOverlayComponent, MenuToggleComponent, MoreInfoComponent, NavComponent, NotificationService, NotificationToastComponent, ObjectClippingComponent, ObjectSelectionComponent, ObjectSelectionOverlayComponent, OverlayCascadeService, OverlayComponent, OverlayViewComponent, OverlayViewWindowComponent, PerformanceToggleComponent, PhoenixMenuComponent, PhoenixMenuItemComponent, PhoenixUIModule, RingLoaderComponent, SSModeComponent, SessionPillComponent, ShareLinkComponent, ShareLinkDialogComponent, ShortcutsDialogComponent, TreeMenuComponent, TreeMenuItemComponent, UiMenuComponent, UiMenuWrapperComponent, ViewOptionsComponent, VrToggleComponent, ZoomControlsComponent, defaultAnimationPresets, defaultUIMenuConfig };
7717
8786
  //# sourceMappingURL=phoenix-ui-components.mjs.map