@memberjunction/ng-entity-viewer 5.43.0 → 5.45.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/aggregate-panel/aggregate-panel.component.d.ts +5 -0
- package/dist/lib/aggregate-panel/aggregate-panel.component.d.ts.map +1 -1
- package/dist/lib/aggregate-panel/aggregate-panel.component.js +45 -47
- package/dist/lib/aggregate-panel/aggregate-panel.component.js.map +1 -1
- package/dist/lib/entity-cards/entity-cards.component.js +7 -10
- package/dist/lib/entity-cards/entity-cards.component.js.map +1 -1
- package/dist/lib/entity-data-grid/entity-data-grid.component.d.ts +10 -1
- package/dist/lib/entity-data-grid/entity-data-grid.component.d.ts.map +1 -1
- package/dist/lib/entity-data-grid/entity-data-grid.component.js +35 -34
- package/dist/lib/entity-data-grid/entity-data-grid.component.js.map +1 -1
- package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.d.ts +0 -4
- package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.d.ts.map +1 -1
- package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.js +166 -207
- package/dist/lib/entity-record-detail-panel/entity-record-detail-panel.component.js.map +1 -1
- package/dist/lib/entity-viewer/entity-viewer.component.d.ts +109 -5
- package/dist/lib/entity-viewer/entity-viewer.component.d.ts.map +1 -1
- package/dist/lib/entity-viewer/entity-viewer.component.js +287 -42
- package/dist/lib/entity-viewer/entity-viewer.component.js.map +1 -1
- package/dist/lib/recycle-bin/recycle-bin.component.js +21 -44
- package/dist/lib/recycle-bin/recycle-bin.component.js.map +1 -1
- package/dist/lib/shared-view-warning-dialog/shared-view-warning-dialog.component.js +19 -20
- package/dist/lib/shared-view-warning-dialog/shared-view-warning-dialog.component.js.map +1 -1
- package/dist/lib/view-config-panel/view-config-panel.component.js +268 -301
- package/dist/lib/view-config-panel/view-config-panel.component.js.map +1 -1
- package/dist/lib/view-selector/view-selector.component.d.ts +26 -1
- package/dist/lib/view-selector/view-selector.component.d.ts.map +1 -1
- package/dist/lib/view-selector/view-selector.component.js +118 -76
- package/dist/lib/view-selector/view-selector.component.js.map +1 -1
- package/dist/lib/view-types/descriptors/grid-view-type.d.ts +7 -0
- package/dist/lib/view-types/descriptors/grid-view-type.d.ts.map +1 -1
- package/dist/lib/view-types/descriptors/grid-view-type.js +7 -0
- package/dist/lib/view-types/descriptors/grid-view-type.js.map +1 -1
- package/dist/lib/view-types/renderers/grid-view-renderer.component.d.ts +18 -1
- package/dist/lib/view-types/renderers/grid-view-renderer.component.d.ts.map +1 -1
- package/dist/lib/view-types/renderers/grid-view-renderer.component.js +29 -3
- package/dist/lib/view-types/renderers/grid-view-renderer.component.js.map +1 -1
- package/dist/lib/view-types/renderers/map-view-renderer.component.d.ts.map +1 -1
- package/dist/lib/view-types/renderers/map-view-renderer.component.js +11 -14
- package/dist/lib/view-types/renderers/map-view-renderer.component.js.map +1 -1
- package/dist/lib/view-types/renderers/timeline-view-renderer.component.d.ts.map +1 -1
- package/dist/lib/view-types/renderers/timeline-view-renderer.component.js +12 -14
- package/dist/lib/view-types/renderers/timeline-view-renderer.component.js.map +1 -1
- package/dist/lib/view-types/view-type.contracts.d.ts +44 -0
- package/dist/lib/view-types/view-type.contracts.d.ts.map +1 -1
- package/dist/lib/view-types/view-type.contracts.js +6 -0
- package/dist/lib/view-types/view-type.contracts.js.map +1 -1
- package/dist/lib/view-workspace/view-workspace.component.d.ts +32 -1
- package/dist/lib/view-workspace/view-workspace.component.d.ts.map +1 -1
- package/dist/lib/view-workspace/view-workspace.component.js +68 -7
- package/dist/lib/view-workspace/view-workspace.component.js.map +1 -1
- package/dist/module.d.ts +1 -1
- package/dist/module.d.ts.map +1 -1
- package/dist/module.js +10 -1
- package/dist/module.js.map +1 -1
- package/package.json +18 -17
- package/dist/__tests__/entity-cards-selection.test.d.ts +0 -2
- package/dist/__tests__/entity-cards-selection.test.d.ts.map +0 -1
- package/dist/__tests__/entity-cards-selection.test.js +0 -149
- package/dist/__tests__/entity-cards-selection.test.js.map +0 -1
- package/dist/__tests__/entity-cards-viewmodel.test.d.ts +0 -2
- package/dist/__tests__/entity-cards-viewmodel.test.d.ts.map +0 -1
- package/dist/__tests__/entity-cards-viewmodel.test.js +0 -208
- package/dist/__tests__/entity-cards-viewmodel.test.js.map +0 -1
- package/dist/__tests__/highlight.test.d.ts +0 -2
- package/dist/__tests__/highlight.test.d.ts.map +0 -1
- package/dist/__tests__/highlight.test.js +0 -67
- package/dist/__tests__/highlight.test.js.map +0 -1
- package/dist/__tests__/index.test.d.ts +0 -2
- package/dist/__tests__/index.test.d.ts.map +0 -1
- package/dist/__tests__/index.test.js +0 -7
- package/dist/__tests__/index.test.js.map +0 -1
- package/dist/__tests__/view-types.test.d.ts +0 -2
- package/dist/__tests__/view-types.test.d.ts.map +0 -1
- package/dist/__tests__/view-types.test.js +0 -102
- package/dist/__tests__/view-types.test.js.map +0 -1
|
@@ -68,6 +68,11 @@ export declare class AggregatePanelComponent implements OnInit {
|
|
|
68
68
|
* Toggle panel collapsed state
|
|
69
69
|
*/
|
|
70
70
|
ToggleCollapse(): void;
|
|
71
|
+
/**
|
|
72
|
+
* Handle the accordion panel's ExpandedChange. Accordion `Expanded` is the
|
|
73
|
+
* inverse of our `IsCollapsed`; preserves the CollapsedChange emit side-effect.
|
|
74
|
+
*/
|
|
75
|
+
OnPanelExpandedChange(expanded: boolean): void;
|
|
71
76
|
/**
|
|
72
77
|
* Handle click on an aggregate card
|
|
73
78
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aggregate-panel.component.d.ts","sourceRoot":"","sources":["../../../src/lib/aggregate-panel/aggregate-panel.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,YAAY,EACZ,MAAM,EACP,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,+BAA+B,IAAI,iBAAiB,EAGrD,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;;AAEtD;;;;;;;;;;GAUG;AACH,qBAMa,uBAAwB,YAAW,MAAM;IACpD;;OAEG;IACM,UAAU,EAAE,iBAAiB,EAAE,CAAM;IAE9C;;OAEG;IACM,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAa;IAEzD;;OAEG;IACM,QAAQ,EAAE,OAAO,GAAG,QAAQ,CAAW;IAEhD;;OAEG;IACM,KAAK,EAAE,MAAM,CAAO;IAE7B;;OAEG;IACM,MAAM,EAAE,YAAY,GAAG,UAAU,GAAG,MAAM,CAAc;IAEjE;;OAEG;IACM,WAAW,EAAE,MAAM,CAAK;IAEjC;;OAEG;IACM,KAAK,EAAE,MAAM,CAAa;IAEnC;;OAEG;IACM,WAAW,EAAE,OAAO,CAAQ;IAErC;;OAEG;IACM,cAAc,EAAE,OAAO,CAAS;IAEzC;;OAEG;IACM,OAAO,EAAE,OAAO,CAAS;IAElC;;OAEG;IACO,eAAe,wBAA+B;IAExD;;OAEG;IACO,cAAc,kCAAyC;IAEjE,WAAW,UAAS;IAEpB,QAAQ,IAAI,IAAI;IAIhB;;OAEG;IACH,cAAc,IAAI,IAAI;IAOtB;;OAEG;IACH,gBAAgB,CAAC,GAAG,EAAE,iBAAiB,GAAG,IAAI;IAI9C;;OAEG;IACH,WAAW,CAAC,GAAG,EAAE,iBAAiB,GAAG,MAAM;IAU3C;;OAEG;IACH,aAAa,CAAC,GAAG,EAAE,iBAAiB,GAAG,MAAM;IAc7C;;OAEG;IACH,IAAI,iBAAiB,IAAI,iBAAiB,EAAE,CAE3C;IAED;;OAEG;IACH,IAAI,cAAc,IAAI,iBAAiB,EAAE,CAIxC;IAED;;OAEG;IACH,IAAI,UAAU,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQvC;IAED;;OAEG;IACH,IAAI,mBAAmB,IAAI,MAAM,CAKhC;IAED;;OAEG;IACH,OAAO,CAAC,YAAY;IAyBpB;;OAEG;IACH,OAAO,CAAC,YAAY;IAoBpB;;OAEG;IACH,OAAO,CAAC,UAAU;IAyBlB;;OAEG;IACH,OAAO,CAAC,iBAAiB;
|
|
1
|
+
{"version":3,"file":"aggregate-panel.component.d.ts","sourceRoot":"","sources":["../../../src/lib/aggregate-panel/aggregate-panel.component.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,YAAY,EACZ,MAAM,EACP,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,+BAA+B,IAAI,iBAAiB,EAGrD,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;;AAEtD;;;;;;;;;;GAUG;AACH,qBAMa,uBAAwB,YAAW,MAAM;IACpD;;OAEG;IACM,UAAU,EAAE,iBAAiB,EAAE,CAAM;IAE9C;;OAEG;IACM,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAa;IAEzD;;OAEG;IACM,QAAQ,EAAE,OAAO,GAAG,QAAQ,CAAW;IAEhD;;OAEG;IACM,KAAK,EAAE,MAAM,CAAO;IAE7B;;OAEG;IACM,MAAM,EAAE,YAAY,GAAG,UAAU,GAAG,MAAM,CAAc;IAEjE;;OAEG;IACM,WAAW,EAAE,MAAM,CAAK;IAEjC;;OAEG;IACM,KAAK,EAAE,MAAM,CAAa;IAEnC;;OAEG;IACM,WAAW,EAAE,OAAO,CAAQ;IAErC;;OAEG;IACM,cAAc,EAAE,OAAO,CAAS;IAEzC;;OAEG;IACM,OAAO,EAAE,OAAO,CAAS;IAElC;;OAEG;IACO,eAAe,wBAA+B;IAExD;;OAEG;IACO,cAAc,kCAAyC;IAEjE,WAAW,UAAS;IAEpB,QAAQ,IAAI,IAAI;IAIhB;;OAEG;IACH,cAAc,IAAI,IAAI;IAOtB;;;OAGG;IACH,qBAAqB,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI;IAK9C;;OAEG;IACH,gBAAgB,CAAC,GAAG,EAAE,iBAAiB,GAAG,IAAI;IAI9C;;OAEG;IACH,WAAW,CAAC,GAAG,EAAE,iBAAiB,GAAG,MAAM;IAU3C;;OAEG;IACH,aAAa,CAAC,GAAG,EAAE,iBAAiB,GAAG,MAAM;IAc7C;;OAEG;IACH,IAAI,iBAAiB,IAAI,iBAAiB,EAAE,CAE3C;IAED;;OAEG;IACH,IAAI,cAAc,IAAI,iBAAiB,EAAE,CAIxC;IAED;;OAEG;IACH,IAAI,UAAU,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQvC;IAED;;OAEG;IACH,IAAI,mBAAmB,IAAI,MAAM,CAKhC;IAED;;OAEG;IACH,OAAO,CAAC,YAAY;IAyBpB;;OAEG;IACH,OAAO,CAAC,YAAY;IAoBpB;;OAEG;IACH,OAAO,CAAC,UAAU;IAyBlB;;OAEG;IACH,OAAO,CAAC,iBAAiB;yCApPd,uBAAuB;2CAAvB,uBAAuB;CA0QnC"}
|
|
@@ -1,31 +1,34 @@
|
|
|
1
1
|
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
|
2
2
|
import * as i0 from "@angular/core";
|
|
3
3
|
import * as i1 from "@angular/common";
|
|
4
|
+
import * as i2 from "@memberjunction/ng-ui-components";
|
|
4
5
|
const _c0 = a0 => ({ "grid-template-columns": a0 });
|
|
5
6
|
const _c1 = () => ({});
|
|
6
|
-
function
|
|
7
|
-
i0.ɵɵelementStart(0, "span",
|
|
8
|
-
i0.ɵɵ
|
|
7
|
+
function AggregatePanelComponent_ng_template_2_Template(rf, ctx) { if (rf & 1) {
|
|
8
|
+
i0.ɵɵelementStart(0, "span", 5);
|
|
9
|
+
i0.ɵɵtext(1);
|
|
9
10
|
i0.ɵɵelementEnd();
|
|
11
|
+
} if (rf & 2) {
|
|
12
|
+
const ctx_r0 = i0.ɵɵnextContext();
|
|
13
|
+
i0.ɵɵadvance();
|
|
14
|
+
i0.ɵɵtextInterpolate(ctx_r0.Title);
|
|
10
15
|
} }
|
|
11
|
-
function
|
|
12
|
-
i0.ɵɵelementStart(0, "
|
|
13
|
-
i0.ɵɵelement(1, "i",
|
|
16
|
+
function AggregatePanelComponent_ng_template_3_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
17
|
+
i0.ɵɵelementStart(0, "span", 6);
|
|
18
|
+
i0.ɵɵelement(1, "i", 7);
|
|
14
19
|
i0.ɵɵelementEnd();
|
|
20
|
+
} }
|
|
21
|
+
function AggregatePanelComponent_ng_template_3_Template(rf, ctx) { if (rf & 1) {
|
|
22
|
+
i0.ɵɵconditionalCreate(0, AggregatePanelComponent_ng_template_3_Conditional_0_Template, 2, 0, "span", 6);
|
|
15
23
|
} if (rf & 2) {
|
|
16
24
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
17
|
-
i0.ɵɵ
|
|
18
|
-
i0.ɵɵclassProp("fa-chevron-up", !ctx_r0.IsCollapsed)("fa-chevron-down", ctx_r0.IsCollapsed);
|
|
25
|
+
i0.ɵɵconditional(ctx_r0.Loading ? 0 : -1);
|
|
19
26
|
} }
|
|
20
|
-
function
|
|
21
|
-
i0.ɵɵ
|
|
22
|
-
i0.ɵɵelement(1, "i", 12);
|
|
23
|
-
i0.ɵɵelementStart(2, "p");
|
|
24
|
-
i0.ɵɵtext(3, "No summaries configured");
|
|
25
|
-
i0.ɵɵelementEnd()();
|
|
27
|
+
function AggregatePanelComponent_ng_template_4_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
28
|
+
i0.ɵɵelement(0, "mj-empty-state", 9);
|
|
26
29
|
} }
|
|
27
|
-
function
|
|
28
|
-
i0.ɵɵelementStart(0, "div",
|
|
30
|
+
function AggregatePanelComponent_ng_template_4_For_4_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
31
|
+
i0.ɵɵelementStart(0, "div", 13);
|
|
29
32
|
i0.ɵɵelement(1, "i");
|
|
30
33
|
i0.ɵɵelementEnd();
|
|
31
34
|
} if (rf & 2) {
|
|
@@ -33,15 +36,15 @@ function AggregatePanelComponent_Conditional_7_For_4_Conditional_1_Template(rf,
|
|
|
33
36
|
i0.ɵɵadvance();
|
|
34
37
|
i0.ɵɵclassMap(agg_r3.icon);
|
|
35
38
|
} }
|
|
36
|
-
function
|
|
39
|
+
function AggregatePanelComponent_ng_template_4_For_4_Template(rf, ctx) { if (rf & 1) {
|
|
37
40
|
const _r2 = i0.ɵɵgetCurrentView();
|
|
38
|
-
i0.ɵɵelementStart(0, "div",
|
|
39
|
-
i0.ɵɵlistener("click", function
|
|
40
|
-
i0.ɵɵconditionalCreate(1,
|
|
41
|
-
i0.ɵɵelementStart(2, "div",
|
|
41
|
+
i0.ɵɵelementStart(0, "div", 12);
|
|
42
|
+
i0.ɵɵlistener("click", function AggregatePanelComponent_ng_template_4_For_4_Template_div_click_0_listener() { const agg_r3 = i0.ɵɵrestoreView(_r2).$implicit; const ctx_r0 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r0.OnAggregateClick(agg_r3)); });
|
|
43
|
+
i0.ɵɵconditionalCreate(1, AggregatePanelComponent_ng_template_4_For_4_Conditional_1_Template, 2, 2, "div", 13);
|
|
44
|
+
i0.ɵɵelementStart(2, "div", 14)(3, "div", 15);
|
|
42
45
|
i0.ɵɵtext(4);
|
|
43
46
|
i0.ɵɵelementEnd();
|
|
44
|
-
i0.ɵɵelementStart(5, "div",
|
|
47
|
+
i0.ɵɵelementStart(5, "div", 16);
|
|
45
48
|
i0.ɵɵtext(6);
|
|
46
49
|
i0.ɵɵelementEnd()()();
|
|
47
50
|
} if (rf & 2) {
|
|
@@ -58,11 +61,11 @@ function AggregatePanelComponent_Conditional_7_For_4_Template(rf, ctx) { if (rf
|
|
|
58
61
|
i0.ɵɵadvance(2);
|
|
59
62
|
i0.ɵɵtextInterpolate(agg_r3.label);
|
|
60
63
|
} }
|
|
61
|
-
function
|
|
62
|
-
i0.ɵɵelementStart(0, "div",
|
|
63
|
-
i0.ɵɵconditionalCreate(1,
|
|
64
|
+
function AggregatePanelComponent_ng_template_4_Template(rf, ctx) { if (rf & 1) {
|
|
65
|
+
i0.ɵɵelementStart(0, "div", 8);
|
|
66
|
+
i0.ɵɵconditionalCreate(1, AggregatePanelComponent_ng_template_4_Conditional_1_Template, 1, 0, "mj-empty-state", 9);
|
|
64
67
|
i0.ɵɵelementStart(2, "div", 10);
|
|
65
|
-
i0.ɵɵrepeaterCreate(3,
|
|
68
|
+
i0.ɵɵrepeaterCreate(3, AggregatePanelComponent_ng_template_4_For_4_Template, 7, 8, "div", 11, i0.ɵɵrepeaterTrackByIdentity);
|
|
66
69
|
i0.ɵɵelementEnd()();
|
|
67
70
|
} if (rf & 2) {
|
|
68
71
|
const ctx_r0 = i0.ɵɵnextContext();
|
|
@@ -147,6 +150,14 @@ export class AggregatePanelComponent {
|
|
|
147
150
|
this.CollapsedChange.emit(this.IsCollapsed);
|
|
148
151
|
}
|
|
149
152
|
}
|
|
153
|
+
/**
|
|
154
|
+
* Handle the accordion panel's ExpandedChange. Accordion `Expanded` is the
|
|
155
|
+
* inverse of our `IsCollapsed`; preserves the CollapsedChange emit side-effect.
|
|
156
|
+
*/
|
|
157
|
+
OnPanelExpandedChange(expanded) {
|
|
158
|
+
this.IsCollapsed = !expanded;
|
|
159
|
+
this.CollapsedChange.emit(this.IsCollapsed);
|
|
160
|
+
}
|
|
150
161
|
/**
|
|
151
162
|
* Handle click on an aggregate card
|
|
152
163
|
*/
|
|
@@ -310,34 +321,21 @@ export class AggregatePanelComponent {
|
|
|
310
321
|
}
|
|
311
322
|
}
|
|
312
323
|
static ɵfac = function AggregatePanelComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || AggregatePanelComponent)(); };
|
|
313
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: AggregatePanelComponent, selectors: [["mj-aggregate-panel"]], inputs: { Aggregates: "Aggregates", Values: "Values", Position: "Position", Width: "Width", Layout: "Layout", GridColumns: "GridColumns", Title: "Title", Collapsible: "Collapsible", StartCollapsed: "StartCollapsed", Loading: "Loading" }, outputs: { CollapsedChange: "CollapsedChange", AggregateClick: "AggregateClick" }, standalone: false, decls:
|
|
314
|
-
i0.ɵɵelementStart(0, "div", 0)(1, "
|
|
315
|
-
i0.ɵɵlistener("
|
|
316
|
-
i0.ɵɵ
|
|
317
|
-
i0.ɵɵtext(3);
|
|
318
|
-
i0.ɵɵelementEnd();
|
|
319
|
-
i0.ɵɵelementStart(4, "div", 3);
|
|
320
|
-
i0.ɵɵconditionalCreate(5, AggregatePanelComponent_Conditional_5_Template, 2, 0, "span", 4);
|
|
321
|
-
i0.ɵɵconditionalCreate(6, AggregatePanelComponent_Conditional_6_Template, 2, 4, "button", 5);
|
|
324
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: AggregatePanelComponent, selectors: [["mj-aggregate-panel"]], inputs: { Aggregates: "Aggregates", Values: "Values", Position: "Position", Width: "Width", Layout: "Layout", GridColumns: "GridColumns", Title: "Title", Collapsible: "Collapsible", StartCollapsed: "StartCollapsed", Loading: "Loading" }, outputs: { CollapsedChange: "CollapsedChange", AggregateClick: "AggregateClick" }, standalone: false, decls: 5, vars: 8, consts: [[1, "aggregate-panel", 3, "ngStyle"], ["Size", "sm", 3, "ExpandedChange", "FlushBody", "Expanded", "Disabled"], ["mjAccordionTitle", ""], ["mjAccordionActions", ""], ["mjAccordionBody", ""], [1, "panel-title"], [1, "loading-indicator"], [1, "fa-solid", "fa-spinner", "fa-spin"], [1, "panel-content"], ["Size", "compact", "Icon", "fa-solid fa-chart-simple", "Title", "No summaries configured"], [1, "cards-container", 3, "ngStyle"], [1, "aggregate-card", 3, "class", "title"], [1, "aggregate-card", 3, "click", "title"], [1, "card-icon"], [1, "card-content"], [1, "card-value"], [1, "card-label"]], template: function AggregatePanelComponent_Template(rf, ctx) { if (rf & 1) {
|
|
325
|
+
i0.ɵɵelementStart(0, "div", 0)(1, "mj-accordion-panel", 1);
|
|
326
|
+
i0.ɵɵlistener("ExpandedChange", function AggregatePanelComponent_Template_mj_accordion_panel_ExpandedChange_1_listener($event) { return ctx.OnPanelExpandedChange($event); });
|
|
327
|
+
i0.ɵɵtemplate(2, AggregatePanelComponent_ng_template_2_Template, 2, 1, "ng-template", 2)(3, AggregatePanelComponent_ng_template_3_Template, 1, 1, "ng-template", 3)(4, AggregatePanelComponent_ng_template_4_Template, 5, 11, "ng-template", 4);
|
|
322
328
|
i0.ɵɵelementEnd()();
|
|
323
|
-
i0.ɵɵconditionalCreate(7, AggregatePanelComponent_Conditional_7_Template, 5, 11, "div", 6);
|
|
324
|
-
i0.ɵɵelementEnd();
|
|
325
329
|
} if (rf & 2) {
|
|
326
|
-
i0.ɵɵclassProp("position-right", ctx.Position === "right")("position-bottom", ctx.Position === "bottom")
|
|
330
|
+
i0.ɵɵclassProp("position-right", ctx.Position === "right")("position-bottom", ctx.Position === "bottom");
|
|
327
331
|
i0.ɵɵproperty("ngStyle", ctx.PanelStyle);
|
|
328
|
-
i0.ɵɵadvance(3);
|
|
329
|
-
i0.ɵɵtextInterpolate(ctx.Title);
|
|
330
|
-
i0.ɵɵadvance(2);
|
|
331
|
-
i0.ɵɵconditional(ctx.Loading ? 5 : -1);
|
|
332
|
-
i0.ɵɵadvance();
|
|
333
|
-
i0.ɵɵconditional(ctx.Collapsible ? 6 : -1);
|
|
334
332
|
i0.ɵɵadvance();
|
|
335
|
-
i0.ɵɵ
|
|
336
|
-
} }, dependencies: [i1.NgStyle], styles: ["\n\n\n.aggregate-panel[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n
|
|
333
|
+
i0.ɵɵproperty("FlushBody", true)("Expanded", !ctx.IsCollapsed)("Disabled", !ctx.Collapsible);
|
|
334
|
+
} }, dependencies: [i1.NgStyle, i2.MJAccordionPanelComponent, i2.MJAccordionTitleDirective, i2.MJAccordionActionsDirective, i2.MJAccordionBodyDirective, i2.MJEmptyStateComponent], styles: ["\n\n\n\n\n\n.aggregate-panel[_ngcontent-%COMP%] {\n display: flex;\n flex-direction: column;\n}\n\n\n\n.position-right[_ngcontent-%COMP%] {\n height: 100%;\n}\n\n.position-bottom[_ngcontent-%COMP%] {\n width: 100%;\n}\n\n\n\n.panel-title[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: 14px;\n color: var(--mj-text-primary);\n}\n\n\n\n.loading-indicator[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n font-size: 14px;\n}\n\n\n\n.panel-content[_ngcontent-%COMP%] {\n padding: 16px;\n overflow-y: auto;\n flex: 1;\n}\n\n\n\n.cards-container[_ngcontent-%COMP%] {\n display: flex;\n gap: 12px;\n}\n\n.layout-horizontal[_ngcontent-%COMP%] {\n flex-direction: row;\n flex-wrap: wrap;\n}\n\n.layout-vertical[_ngcontent-%COMP%] {\n flex-direction: column;\n}\n\n.layout-grid[_ngcontent-%COMP%] {\n display: grid;\n gap: 12px;\n}\n\n\n\n.aggregate-card[_ngcontent-%COMP%] {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 12px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n transition: border-color 0.2s, box-shadow 0.2s, transform 0.2s;\n}\n\n.aggregate-card[_ngcontent-%COMP%]:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n transform: translateY(-1px);\n}\n\n\n\n.card-icon[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n color: var(--mj-brand-primary);\n font-size: 18px;\n flex-shrink: 0;\n}\n\n\n\n.card-content[_ngcontent-%COMP%] {\n flex: 1;\n min-width: 0;\n}\n\n.card-value[_ngcontent-%COMP%] {\n font-size: 20px;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1.2;\n margin-bottom: 4px;\n word-break: break-word;\n}\n\n.card-value.loading[_ngcontent-%COMP%] {\n color: var(--mj-text-disabled);\n}\n\n.card-label[_ngcontent-%COMP%] {\n font-size: 12px;\n color: var(--mj-text-secondary);\n line-height: 1.3;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n\n\n.style-success[_ngcontent-%COMP%] {\n border-left: 4px solid var(--mj-status-success);\n}\n\n.style-success[_ngcontent-%COMP%] .card-value[_ngcontent-%COMP%] {\n color: var(--mj-status-success);\n}\n\n.style-success[_ngcontent-%COMP%] .card-icon[_ngcontent-%COMP%] {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success);\n}\n\n.style-warning[_ngcontent-%COMP%] {\n border-left: 4px solid var(--mj-status-warning);\n}\n\n.style-warning[_ngcontent-%COMP%] .card-value[_ngcontent-%COMP%] {\n color: var(--mj-status-warning-text);\n}\n\n.style-warning[_ngcontent-%COMP%] .card-icon[_ngcontent-%COMP%] {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n}\n\n.style-danger[_ngcontent-%COMP%] {\n border-left: 4px solid var(--mj-status-error);\n}\n\n.style-danger[_ngcontent-%COMP%] .card-value[_ngcontent-%COMP%] {\n color: var(--mj-status-error);\n}\n\n.style-danger[_ngcontent-%COMP%] .card-icon[_ngcontent-%COMP%] {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error);\n}\n\n.style-info[_ngcontent-%COMP%] {\n border-left: 4px solid var(--mj-brand-primary);\n}\n\n.style-info[_ngcontent-%COMP%] .card-value[_ngcontent-%COMP%] {\n color: var(--mj-brand-primary);\n}\n\n.style-info[_ngcontent-%COMP%] .card-icon[_ngcontent-%COMP%] {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.style-muted[_ngcontent-%COMP%] {\n border-left: 4px solid var(--mj-text-muted);\n}\n\n.style-muted[_ngcontent-%COMP%] .card-value[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n}\n\n.style-muted[_ngcontent-%COMP%] .card-icon[_ngcontent-%COMP%] {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n}\n\n\n\n.position-bottom[_ngcontent-%COMP%] .cards-container.layout-vertical[_ngcontent-%COMP%] {\n flex-direction: row;\n flex-wrap: wrap;\n}\n\n.position-bottom[_ngcontent-%COMP%] .cards-container.layout-vertical[_ngcontent-%COMP%] .aggregate-card[_ngcontent-%COMP%] {\n flex: 1 1 200px;\n max-width: 300px;\n}"] });
|
|
337
335
|
}
|
|
338
336
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(AggregatePanelComponent, [{
|
|
339
337
|
type: Component,
|
|
340
|
-
args: [{ standalone: false, selector: 'mj-aggregate-panel', template: "<div class=\"aggregate-panel\"\n [class.position-right]=\"Position === 'right'\"\n [class.position-bottom]=\"Position === 'bottom'\"\n [
|
|
338
|
+
args: [{ standalone: false, selector: 'mj-aggregate-panel', template: "<div class=\"aggregate-panel\"\n [class.position-right]=\"Position === 'right'\"\n [class.position-bottom]=\"Position === 'bottom'\"\n [ngStyle]=\"PanelStyle\">\n\n <!-- Migrated to <mj-accordion-panel>. The bespoke .panel-header / .collapse-toggle\n and the @if(!IsCollapsed) body gate are replaced by the accordion's own header,\n chevron, and lazy/animated body. Expanded is the inverse of IsCollapsed; the\n (ExpandedChange) handler preserves the CollapsedChange emit side-effect. -->\n <mj-accordion-panel\n Size=\"sm\"\n [FlushBody]=\"true\"\n [Expanded]=\"!IsCollapsed\"\n [Disabled]=\"!Collapsible\"\n (ExpandedChange)=\"OnPanelExpandedChange($event)\">\n\n <ng-template mjAccordionTitle>\n <span class=\"panel-title\">{{ Title }}</span>\n </ng-template>\n\n <!-- Loading indicator lives in the header actions slot (sibling of the chevron). -->\n <ng-template mjAccordionActions>\n @if (Loading) {\n <span class=\"loading-indicator\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n </span>\n }\n </ng-template>\n\n <ng-template mjAccordionBody>\n <div class=\"panel-content\">\n <!-- Empty state -->\n @if (CardAggregates.length === 0) {\n <mj-empty-state\n Size=\"compact\"\n Icon=\"fa-solid fa-chart-simple\"\n Title=\"No summaries configured\" />\n }\n <!-- Cards Container -->\n <div class=\"cards-container\"\n [class.layout-horizontal]=\"Layout === 'horizontal'\"\n [class.layout-vertical]=\"Layout === 'vertical'\"\n [class.layout-grid]=\"Layout === 'grid'\"\n [ngStyle]=\"Layout === 'grid' ? {'grid-template-columns': GridTemplateColumns} : {}\">\n <!-- Individual Aggregate Cards -->\n @for (agg of CardAggregates; track agg) {\n <div class=\"aggregate-card\"\n [class]=\"GetStyleClass(agg)\"\n (click)=\"OnAggregateClick(agg)\"\n [title]=\"agg.description || agg.label\">\n <!-- Icon -->\n @if (agg.icon) {\n <div class=\"card-icon\">\n <i [class]=\"agg.icon\"></i>\n </div>\n }\n <!-- Content -->\n <div class=\"card-content\">\n <div class=\"card-value\" [class.loading]=\"Loading\">\n {{ Loading ? '...' : FormatValue(agg) }}\n </div>\n <div class=\"card-label\">{{ agg.label }}</div>\n </div>\n </div>\n }\n </div>\n </div>\n </ng-template>\n </mj-accordion-panel>\n</div>\n", styles: ["/* Aggregate Panel Component Styles */\n\n/* Layout/positioning only \u2014 visual chrome (border, radius, shadow, header,\n chevron, and .collapsed body-hiding) is now owned by <mj-accordion-panel>. */\n.aggregate-panel {\n display: flex;\n flex-direction: column;\n}\n\n/* Position variants */\n.position-right {\n height: 100%;\n}\n\n.position-bottom {\n width: 100%;\n}\n\n/* Title (projected into the accordion title slot) */\n.panel-title {\n font-weight: 600;\n font-size: 14px;\n color: var(--mj-text-primary);\n}\n\n/* Loading indicator (projected into the accordion actions slot) */\n.loading-indicator {\n color: var(--mj-brand-primary);\n font-size: 14px;\n}\n\n/* Panel Content */\n.panel-content {\n padding: 16px;\n overflow-y: auto;\n flex: 1;\n}\n\n/* Cards Container */\n.cards-container {\n display: flex;\n gap: 12px;\n}\n\n.layout-horizontal {\n flex-direction: row;\n flex-wrap: wrap;\n}\n\n.layout-vertical {\n flex-direction: column;\n}\n\n.layout-grid {\n display: grid;\n gap: 12px;\n}\n\n/* Aggregate Card */\n.aggregate-card {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 12px;\n background: var(--mj-bg-surface);\n border: 1px solid var(--mj-border-default);\n border-radius: 6px;\n cursor: pointer;\n transition: border-color 0.2s, box-shadow 0.2s, transform 0.2s;\n}\n\n.aggregate-card:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 2px 8px color-mix(in srgb, var(--mj-brand-primary) 15%, transparent);\n transform: translateY(-1px);\n}\n\n/* Card Icon */\n.card-icon {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 40px;\n height: 40px;\n background: var(--mj-bg-surface-card);\n border-radius: 8px;\n color: var(--mj-brand-primary);\n font-size: 18px;\n flex-shrink: 0;\n}\n\n/* Card Content */\n.card-content {\n flex: 1;\n min-width: 0;\n}\n\n.card-value {\n font-size: 20px;\n font-weight: 700;\n color: var(--mj-text-primary);\n line-height: 1.2;\n margin-bottom: 4px;\n word-break: break-word;\n}\n\n.card-value.loading {\n color: var(--mj-text-disabled);\n}\n\n.card-label {\n font-size: 12px;\n color: var(--mj-text-secondary);\n line-height: 1.3;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n/* Conditional Style Classes */\n.style-success {\n border-left: 4px solid var(--mj-status-success);\n}\n\n.style-success .card-value {\n color: var(--mj-status-success);\n}\n\n.style-success .card-icon {\n background: var(--mj-status-success-bg);\n color: var(--mj-status-success);\n}\n\n.style-warning {\n border-left: 4px solid var(--mj-status-warning);\n}\n\n.style-warning .card-value {\n color: var(--mj-status-warning-text);\n}\n\n.style-warning .card-icon {\n background: var(--mj-status-warning-bg);\n color: var(--mj-status-warning-text);\n}\n\n.style-danger {\n border-left: 4px solid var(--mj-status-error);\n}\n\n.style-danger .card-value {\n color: var(--mj-status-error);\n}\n\n.style-danger .card-icon {\n background: var(--mj-status-error-bg);\n color: var(--mj-status-error);\n}\n\n.style-info {\n border-left: 4px solid var(--mj-brand-primary);\n}\n\n.style-info .card-value {\n color: var(--mj-brand-primary);\n}\n\n.style-info .card-icon {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n color: var(--mj-brand-primary);\n}\n\n.style-muted {\n border-left: 4px solid var(--mj-text-muted);\n}\n\n.style-muted .card-value {\n color: var(--mj-text-muted);\n}\n\n.style-muted .card-icon {\n background: var(--mj-bg-surface-sunken);\n color: var(--mj-text-muted);\n}\n\n/* Responsive adjustments for bottom position */\n.position-bottom .cards-container.layout-vertical {\n flex-direction: row;\n flex-wrap: wrap;\n}\n\n.position-bottom .cards-container.layout-vertical .aggregate-card {\n flex: 1 1 200px;\n max-width: 300px;\n}\n"] }]
|
|
341
339
|
}], null, { Aggregates: [{
|
|
342
340
|
type: Input
|
|
343
341
|
}], Values: [{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aggregate-panel.component.js","sourceRoot":"","sources":["../../../src/lib/aggregate-panel/aggregate-panel.component.ts","../../../src/lib/aggregate-panel/aggregate-panel.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Input,\n Output,\n EventEmitter,\n OnInit\n} from '@angular/core';\nimport {\n MJUserViewEntity_IGridAggregate as ViewGridAggregate,\n MJUserViewEntity_IAggregateValueFormat as AggregateValueFormat,\n MJUserViewEntity_IAggregateConditionalStyle as AggregateConditionalStyle\n} from '@memberjunction/core-entities';\nimport { AggregateValue } from '@memberjunction/core';\n\n/**\n * AggregatePanelComponent displays aggregate values in a card-based panel.\n * Can be positioned to the right or bottom of the grid, with various layout options.\n *\n * Features:\n * - Collapsible panel with customizable title\n * - Multiple layout options (horizontal, vertical, grid)\n * - Value formatting (number, currency, percent, date)\n * - Conditional styling (green/yellow/red based on value thresholds)\n * - Icon support for visual indicators\n */\n@Component({\n standalone: false,\n selector: 'mj-aggregate-panel',\n templateUrl: './aggregate-panel.component.html',\n styleUrls: ['./aggregate-panel.component.css']\n})\nexport class AggregatePanelComponent implements OnInit {\n /**\n * Array of aggregate configurations to display\n */\n @Input() Aggregates: ViewGridAggregate[] = [];\n\n /**\n * Map of aggregate values, keyed by expression or id\n */\n @Input() Values: Map<string, AggregateValue> = new Map();\n\n /**\n * Panel position relative to the grid\n */\n @Input() Position: 'right' | 'bottom' = 'right';\n\n /**\n * Panel width in pixels (only applies when Position is 'right')\n */\n @Input() Width: number = 280;\n\n /**\n * Layout style for aggregate cards\n */\n @Input() Layout: 'horizontal' | 'vertical' | 'grid' = 'vertical';\n\n /**\n * Number of columns when Layout is 'grid'\n */\n @Input() GridColumns: number = 2;\n\n /**\n * Panel title\n */\n @Input() Title: string = 'Summary';\n\n /**\n * Whether the panel can be collapsed\n */\n @Input() Collapsible: boolean = true;\n\n /**\n * Whether the panel starts in collapsed state\n */\n @Input() StartCollapsed: boolean = false;\n\n /**\n * Whether aggregates are currently loading\n */\n @Input() Loading: boolean = false;\n\n /**\n * Emitted when panel collapsed state changes\n */\n @Output() CollapsedChange = new EventEmitter<boolean>();\n\n /**\n * Emitted when user clicks an aggregate card (for editing/details)\n */\n @Output() AggregateClick = new EventEmitter<ViewGridAggregate>();\n\n IsCollapsed = false;\n\n ngOnInit(): void {\n this.IsCollapsed = this.StartCollapsed;\n }\n\n /**\n * Toggle panel collapsed state\n */\n ToggleCollapse(): void {\n if (this.Collapsible) {\n this.IsCollapsed = !this.IsCollapsed;\n this.CollapsedChange.emit(this.IsCollapsed);\n }\n }\n\n /**\n * Handle click on an aggregate card\n */\n OnAggregateClick(agg: ViewGridAggregate): void {\n this.AggregateClick.emit(agg);\n }\n\n /**\n * Get the formatted value for an aggregate\n */\n FormatValue(agg: ViewGridAggregate): string {\n const key = agg.id || agg.expression;\n const value = this.Values.get(key);\n\n if (value == null) return '—';\n\n const format = agg.format || {};\n return this.formatByType(value, format);\n }\n\n /**\n * Get the CSS class for conditional styling\n */\n GetStyleClass(agg: ViewGridAggregate): string {\n const key = agg.id || agg.expression;\n const value = this.Values.get(key);\n\n if (value == null || !agg.conditionalStyles?.length) return '';\n\n for (const rule of agg.conditionalStyles) {\n if (this.evaluateCondition(value, rule)) {\n return `style-${rule.style}`;\n }\n }\n return '';\n }\n\n /**\n * Get enabled aggregates (filter out disabled ones)\n */\n get EnabledAggregates(): ViewGridAggregate[] {\n return this.Aggregates.filter(a => a.enabled !== false);\n }\n\n /**\n * Get card aggregates sorted by order\n */\n get CardAggregates(): ViewGridAggregate[] {\n return this.EnabledAggregates\n .filter(a => a.displayType === 'card')\n .sort((a, b) => (a.order || 0) - (b.order || 0));\n }\n\n /**\n * Get panel style for right position\n */\n get PanelStyle(): Record<string, string> {\n if (this.Position === 'right') {\n return {\n width: `${this.Width}px`,\n minWidth: `${this.Width}px`\n };\n }\n return {};\n }\n\n /**\n * Get grid template columns for grid layout\n */\n get GridTemplateColumns(): string {\n if (this.Layout === 'grid') {\n return `repeat(${this.GridColumns}, 1fr)`;\n }\n return '';\n }\n\n /**\n * Format value based on type configuration\n */\n private formatByType(value: AggregateValue, format: AggregateValueFormat): string {\n if (value == null) return '—';\n\n // Handle prefix/suffix\n const prefix = format.prefix || '';\n const suffix = format.suffix || '';\n\n // Handle different value types\n if (typeof value === 'number') {\n const formatted = this.formatNumber(value, format);\n return `${prefix}${formatted}${suffix}`;\n }\n\n if (value instanceof Date) {\n return this.formatDate(value, format.dateFormat);\n }\n\n if (typeof value === 'boolean') {\n return value ? 'Yes' : 'No';\n }\n\n // String or unknown type\n return `${prefix}${String(value)}${suffix}`;\n }\n\n /**\n * Format a number value\n */\n private formatNumber(value: number, format: AggregateValueFormat): string {\n const options: Intl.NumberFormatOptions = {\n minimumFractionDigits: format.decimals ?? 0,\n maximumFractionDigits: format.decimals ?? 2,\n useGrouping: format.thousandsSeparator !== false\n };\n\n // Handle currency\n if (format.currencyCode) {\n options.style = 'currency';\n options.currency = format.currencyCode;\n }\n\n try {\n return new Intl.NumberFormat('en-US', options).format(value);\n } catch {\n return String(value);\n }\n }\n\n /**\n * Format a date value\n */\n private formatDate(value: Date, dateFormat?: string): string {\n try {\n // Simple format presets\n const options: Intl.DateTimeFormatOptions = {};\n\n switch (dateFormat) {\n case 'short':\n options.dateStyle = 'short';\n break;\n case 'medium':\n options.dateStyle = 'medium';\n break;\n case 'long':\n options.dateStyle = 'long';\n break;\n default:\n options.dateStyle = 'medium';\n }\n\n return new Intl.DateTimeFormat('en-US', options).format(value);\n } catch {\n return String(value);\n }\n }\n\n /**\n * Evaluate a conditional styling rule\n */\n private evaluateCondition(value: AggregateValue, rule: AggregateConditionalStyle): boolean {\n // For non-numeric values, only support equality checks\n if (typeof value !== 'number') {\n if (rule.operator === 'eq') return value === rule.value;\n if (rule.operator === 'neq') return value !== rule.value;\n return false;\n }\n\n const numValue = Number(rule.value);\n const numValue2 = rule.value2 != null ? Number(rule.value2) : numValue;\n\n switch (rule.operator) {\n case 'gt': return value > numValue;\n case 'gte': return value >= numValue;\n case 'lt': return value < numValue;\n case 'lte': return value <= numValue;\n case 'eq': return value === numValue;\n case 'neq': return value !== numValue;\n case 'between': return value >= numValue && value <= numValue2;\n default: return false;\n }\n }\n}\n","<div class=\"aggregate-panel\"\n [class.position-right]=\"Position === 'right'\"\n [class.position-bottom]=\"Position === 'bottom'\"\n [class.collapsed]=\"IsCollapsed\"\n [ngStyle]=\"PanelStyle\">\n\n <!-- Panel Header -->\n <div class=\"panel-header\" (click)=\"ToggleCollapse()\">\n <span class=\"panel-title\">{{ Title }}</span>\n\n <div class=\"panel-header-right\">\n <!-- Loading indicator -->\n @if (Loading) {\n <span class=\"loading-indicator\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n </span>\n }\n\n <!-- Collapse toggle -->\n @if (Collapsible) {\n <button class=\"collapse-toggle\" type=\"button\">\n <i class=\"fa-solid\" [class.fa-chevron-up]=\"!IsCollapsed\" [class.fa-chevron-down]=\"IsCollapsed\"></i>\n </button>\n }\n </div>\n </div>\n\n <!-- Panel Content -->\n @if (!IsCollapsed) {\n <div class=\"panel-content\">\n <!-- Empty state -->\n @if (CardAggregates.length === 0) {\n <div class=\"empty-state\">\n <i class=\"fa-solid fa-chart-simple\"></i>\n <p>No summaries configured</p>\n </div>\n }\n <!-- Cards Container -->\n <div class=\"cards-container\"\n [class.layout-horizontal]=\"Layout === 'horizontal'\"\n [class.layout-vertical]=\"Layout === 'vertical'\"\n [class.layout-grid]=\"Layout === 'grid'\"\n [ngStyle]=\"Layout === 'grid' ? {'grid-template-columns': GridTemplateColumns} : {}\">\n <!-- Individual Aggregate Cards -->\n @for (agg of CardAggregates; track agg) {\n <div class=\"aggregate-card\"\n [class]=\"GetStyleClass(agg)\"\n (click)=\"OnAggregateClick(agg)\"\n [title]=\"agg.description || agg.label\">\n <!-- Icon -->\n @if (agg.icon) {\n <div class=\"card-icon\">\n <i [class]=\"agg.icon\"></i>\n </div>\n }\n <!-- Content -->\n <div class=\"card-content\">\n <div class=\"card-value\" [class.loading]=\"Loading\">\n {{ Loading ? '...' : FormatValue(agg) }}\n </div>\n <div class=\"card-label\">{{ agg.label }}</div>\n </div>\n </div>\n }\n </div>\n </div>\n }\n</div>\n"]}
|
|
1
|
+
{"version":3,"file":"aggregate-panel.component.js","sourceRoot":"","sources":["../../../src/lib/aggregate-panel/aggregate-panel.component.ts","../../../src/lib/aggregate-panel/aggregate-panel.component.html"],"names":[],"mappings":"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","sourcesContent":["import {\n Component,\n Input,\n Output,\n EventEmitter,\n OnInit\n} from '@angular/core';\nimport {\n MJUserViewEntity_IGridAggregate as ViewGridAggregate,\n MJUserViewEntity_IAggregateValueFormat as AggregateValueFormat,\n MJUserViewEntity_IAggregateConditionalStyle as AggregateConditionalStyle\n} from '@memberjunction/core-entities';\nimport { AggregateValue } from '@memberjunction/core';\n\n/**\n * AggregatePanelComponent displays aggregate values in a card-based panel.\n * Can be positioned to the right or bottom of the grid, with various layout options.\n *\n * Features:\n * - Collapsible panel with customizable title\n * - Multiple layout options (horizontal, vertical, grid)\n * - Value formatting (number, currency, percent, date)\n * - Conditional styling (green/yellow/red based on value thresholds)\n * - Icon support for visual indicators\n */\n@Component({\n standalone: false,\n selector: 'mj-aggregate-panel',\n templateUrl: './aggregate-panel.component.html',\n styleUrls: ['./aggregate-panel.component.css']\n})\nexport class AggregatePanelComponent implements OnInit {\n /**\n * Array of aggregate configurations to display\n */\n @Input() Aggregates: ViewGridAggregate[] = [];\n\n /**\n * Map of aggregate values, keyed by expression or id\n */\n @Input() Values: Map<string, AggregateValue> = new Map();\n\n /**\n * Panel position relative to the grid\n */\n @Input() Position: 'right' | 'bottom' = 'right';\n\n /**\n * Panel width in pixels (only applies when Position is 'right')\n */\n @Input() Width: number = 280;\n\n /**\n * Layout style for aggregate cards\n */\n @Input() Layout: 'horizontal' | 'vertical' | 'grid' = 'vertical';\n\n /**\n * Number of columns when Layout is 'grid'\n */\n @Input() GridColumns: number = 2;\n\n /**\n * Panel title\n */\n @Input() Title: string = 'Summary';\n\n /**\n * Whether the panel can be collapsed\n */\n @Input() Collapsible: boolean = true;\n\n /**\n * Whether the panel starts in collapsed state\n */\n @Input() StartCollapsed: boolean = false;\n\n /**\n * Whether aggregates are currently loading\n */\n @Input() Loading: boolean = false;\n\n /**\n * Emitted when panel collapsed state changes\n */\n @Output() CollapsedChange = new EventEmitter<boolean>();\n\n /**\n * Emitted when user clicks an aggregate card (for editing/details)\n */\n @Output() AggregateClick = new EventEmitter<ViewGridAggregate>();\n\n IsCollapsed = false;\n\n ngOnInit(): void {\n this.IsCollapsed = this.StartCollapsed;\n }\n\n /**\n * Toggle panel collapsed state\n */\n ToggleCollapse(): void {\n if (this.Collapsible) {\n this.IsCollapsed = !this.IsCollapsed;\n this.CollapsedChange.emit(this.IsCollapsed);\n }\n }\n\n /**\n * Handle the accordion panel's ExpandedChange. Accordion `Expanded` is the\n * inverse of our `IsCollapsed`; preserves the CollapsedChange emit side-effect.\n */\n OnPanelExpandedChange(expanded: boolean): void {\n this.IsCollapsed = !expanded;\n this.CollapsedChange.emit(this.IsCollapsed);\n }\n\n /**\n * Handle click on an aggregate card\n */\n OnAggregateClick(agg: ViewGridAggregate): void {\n this.AggregateClick.emit(agg);\n }\n\n /**\n * Get the formatted value for an aggregate\n */\n FormatValue(agg: ViewGridAggregate): string {\n const key = agg.id || agg.expression;\n const value = this.Values.get(key);\n\n if (value == null) return '—';\n\n const format = agg.format || {};\n return this.formatByType(value, format);\n }\n\n /**\n * Get the CSS class for conditional styling\n */\n GetStyleClass(agg: ViewGridAggregate): string {\n const key = agg.id || agg.expression;\n const value = this.Values.get(key);\n\n if (value == null || !agg.conditionalStyles?.length) return '';\n\n for (const rule of agg.conditionalStyles) {\n if (this.evaluateCondition(value, rule)) {\n return `style-${rule.style}`;\n }\n }\n return '';\n }\n\n /**\n * Get enabled aggregates (filter out disabled ones)\n */\n get EnabledAggregates(): ViewGridAggregate[] {\n return this.Aggregates.filter(a => a.enabled !== false);\n }\n\n /**\n * Get card aggregates sorted by order\n */\n get CardAggregates(): ViewGridAggregate[] {\n return this.EnabledAggregates\n .filter(a => a.displayType === 'card')\n .sort((a, b) => (a.order || 0) - (b.order || 0));\n }\n\n /**\n * Get panel style for right position\n */\n get PanelStyle(): Record<string, string> {\n if (this.Position === 'right') {\n return {\n width: `${this.Width}px`,\n minWidth: `${this.Width}px`\n };\n }\n return {};\n }\n\n /**\n * Get grid template columns for grid layout\n */\n get GridTemplateColumns(): string {\n if (this.Layout === 'grid') {\n return `repeat(${this.GridColumns}, 1fr)`;\n }\n return '';\n }\n\n /**\n * Format value based on type configuration\n */\n private formatByType(value: AggregateValue, format: AggregateValueFormat): string {\n if (value == null) return '—';\n\n // Handle prefix/suffix\n const prefix = format.prefix || '';\n const suffix = format.suffix || '';\n\n // Handle different value types\n if (typeof value === 'number') {\n const formatted = this.formatNumber(value, format);\n return `${prefix}${formatted}${suffix}`;\n }\n\n if (value instanceof Date) {\n return this.formatDate(value, format.dateFormat);\n }\n\n if (typeof value === 'boolean') {\n return value ? 'Yes' : 'No';\n }\n\n // String or unknown type\n return `${prefix}${String(value)}${suffix}`;\n }\n\n /**\n * Format a number value\n */\n private formatNumber(value: number, format: AggregateValueFormat): string {\n const options: Intl.NumberFormatOptions = {\n minimumFractionDigits: format.decimals ?? 0,\n maximumFractionDigits: format.decimals ?? 2,\n useGrouping: format.thousandsSeparator !== false\n };\n\n // Handle currency\n if (format.currencyCode) {\n options.style = 'currency';\n options.currency = format.currencyCode;\n }\n\n try {\n return new Intl.NumberFormat('en-US', options).format(value);\n } catch {\n return String(value);\n }\n }\n\n /**\n * Format a date value\n */\n private formatDate(value: Date, dateFormat?: string): string {\n try {\n // Simple format presets\n const options: Intl.DateTimeFormatOptions = {};\n\n switch (dateFormat) {\n case 'short':\n options.dateStyle = 'short';\n break;\n case 'medium':\n options.dateStyle = 'medium';\n break;\n case 'long':\n options.dateStyle = 'long';\n break;\n default:\n options.dateStyle = 'medium';\n }\n\n return new Intl.DateTimeFormat('en-US', options).format(value);\n } catch {\n return String(value);\n }\n }\n\n /**\n * Evaluate a conditional styling rule\n */\n private evaluateCondition(value: AggregateValue, rule: AggregateConditionalStyle): boolean {\n // For non-numeric values, only support equality checks\n if (typeof value !== 'number') {\n if (rule.operator === 'eq') return value === rule.value;\n if (rule.operator === 'neq') return value !== rule.value;\n return false;\n }\n\n const numValue = Number(rule.value);\n const numValue2 = rule.value2 != null ? Number(rule.value2) : numValue;\n\n switch (rule.operator) {\n case 'gt': return value > numValue;\n case 'gte': return value >= numValue;\n case 'lt': return value < numValue;\n case 'lte': return value <= numValue;\n case 'eq': return value === numValue;\n case 'neq': return value !== numValue;\n case 'between': return value >= numValue && value <= numValue2;\n default: return false;\n }\n }\n}\n","<div class=\"aggregate-panel\"\n [class.position-right]=\"Position === 'right'\"\n [class.position-bottom]=\"Position === 'bottom'\"\n [ngStyle]=\"PanelStyle\">\n\n <!-- Migrated to <mj-accordion-panel>. The bespoke .panel-header / .collapse-toggle\n and the @if(!IsCollapsed) body gate are replaced by the accordion's own header,\n chevron, and lazy/animated body. Expanded is the inverse of IsCollapsed; the\n (ExpandedChange) handler preserves the CollapsedChange emit side-effect. -->\n <mj-accordion-panel\n Size=\"sm\"\n [FlushBody]=\"true\"\n [Expanded]=\"!IsCollapsed\"\n [Disabled]=\"!Collapsible\"\n (ExpandedChange)=\"OnPanelExpandedChange($event)\">\n\n <ng-template mjAccordionTitle>\n <span class=\"panel-title\">{{ Title }}</span>\n </ng-template>\n\n <!-- Loading indicator lives in the header actions slot (sibling of the chevron). -->\n <ng-template mjAccordionActions>\n @if (Loading) {\n <span class=\"loading-indicator\">\n <i class=\"fa-solid fa-spinner fa-spin\"></i>\n </span>\n }\n </ng-template>\n\n <ng-template mjAccordionBody>\n <div class=\"panel-content\">\n <!-- Empty state -->\n @if (CardAggregates.length === 0) {\n <mj-empty-state\n Size=\"compact\"\n Icon=\"fa-solid fa-chart-simple\"\n Title=\"No summaries configured\" />\n }\n <!-- Cards Container -->\n <div class=\"cards-container\"\n [class.layout-horizontal]=\"Layout === 'horizontal'\"\n [class.layout-vertical]=\"Layout === 'vertical'\"\n [class.layout-grid]=\"Layout === 'grid'\"\n [ngStyle]=\"Layout === 'grid' ? {'grid-template-columns': GridTemplateColumns} : {}\">\n <!-- Individual Aggregate Cards -->\n @for (agg of CardAggregates; track agg) {\n <div class=\"aggregate-card\"\n [class]=\"GetStyleClass(agg)\"\n (click)=\"OnAggregateClick(agg)\"\n [title]=\"agg.description || agg.label\">\n <!-- Icon -->\n @if (agg.icon) {\n <div class=\"card-icon\">\n <i [class]=\"agg.icon\"></i>\n </div>\n }\n <!-- Content -->\n <div class=\"card-content\">\n <div class=\"card-value\" [class.loading]=\"Loading\">\n {{ Loading ? '...' : FormatValue(agg) }}\n </div>\n <div class=\"card-label\">{{ agg.label }}</div>\n </div>\n </div>\n }\n </div>\n </div>\n </ng-template>\n </mj-accordion-panel>\n</div>\n"]}
|
|
@@ -6,7 +6,8 @@ import { PillColorUtil } from '../pill/pill.component';
|
|
|
6
6
|
import { HighlightUtil } from '../utils/highlight.util';
|
|
7
7
|
import * as i0 from "@angular/core";
|
|
8
8
|
import * as i1 from "@memberjunction/ng-shared-generic";
|
|
9
|
-
import * as i2 from "
|
|
9
|
+
import * as i2 from "@memberjunction/ng-ui-components";
|
|
10
|
+
import * as i3 from "../pill/pill.component";
|
|
10
11
|
const _forTrack0 = ($index, $item) => $item.trackId;
|
|
11
12
|
const _forTrack1 = ($index, $item) => $item.field.name;
|
|
12
13
|
function EntityCardsComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
@@ -201,16 +202,12 @@ function EntityCardsComponent_Conditional_2_For_2_Template(rf, ctx) { if (rf & 1
|
|
|
201
202
|
i0.ɵɵconditional(vm_r2.hasHiddenFieldMatch ? 14 : -1);
|
|
202
203
|
} }
|
|
203
204
|
function EntityCardsComponent_Conditional_2_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
204
|
-
i0.ɵɵ
|
|
205
|
-
i0.ɵɵelement(1, "i", 31);
|
|
206
|
-
i0.ɵɵelementStart(2, "p");
|
|
207
|
-
i0.ɵɵtext(3, "No records to display");
|
|
208
|
-
i0.ɵɵelementEnd()();
|
|
205
|
+
i0.ɵɵelement(0, "mj-empty-state", 5);
|
|
209
206
|
} }
|
|
210
207
|
function EntityCardsComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
211
208
|
i0.ɵɵelementStart(0, "div", 2);
|
|
212
209
|
i0.ɵɵrepeaterCreate(1, EntityCardsComponent_Conditional_2_For_2_Template, 15, 9, "div", 4, _forTrack0);
|
|
213
|
-
i0.ɵɵconditionalCreate(3, EntityCardsComponent_Conditional_2_Conditional_3_Template,
|
|
210
|
+
i0.ɵɵconditionalCreate(3, EntityCardsComponent_Conditional_2_Conditional_3_Template, 1, 0, "mj-empty-state", 5);
|
|
214
211
|
i0.ɵɵelementEnd();
|
|
215
212
|
} if (rf & 2) {
|
|
216
213
|
const ctx_r2 = i0.ɵɵnextContext();
|
|
@@ -917,18 +914,18 @@ export class EntityCardsComponent extends BaseAngularComponent {
|
|
|
917
914
|
return HighlightUtil.highlight(text, this.filterText, false);
|
|
918
915
|
}
|
|
919
916
|
static ɵfac = function EntityCardsComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || EntityCardsComponent)(i0.ɵɵdirectiveInject(i0.ElementRef), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
|
|
920
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: EntityCardsComponent, selectors: [["mj-entity-cards"]], inputs: { entity: "entity", records: "records", selectedRecordId: "selectedRecordId", cardTemplate: "cardTemplate", hiddenFieldMatches: "hiddenFieldMatches", filterText: "filterText", pageSize: "pageSize" }, outputs: { recordSelected: "recordSelected", recordOpened: "recordOpened" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 3, vars: 1, consts: [[1, "cards-view-wrapper"], [1, "loading-container"], [1, "cards-container"], ["text", "Loading records..."], [1, "data-card", 3, "selected"], [1, "no-results"], [1, "data-card", 3, "click"], [1, "card-header"], [1, "card-thumbnail"], [1, "card-avatar", 3, "background-color"], [1, "card-header-content"], [1, "card-title", 3, "innerHTML"], ["title", "Open Record", 1, "card-open-btn", 3, "click"], [1, "fa-solid", "fa-external-link-alt"], [1, "card-body"], [1, "card-description", 3, "innerHTML"], [1, "card-fields"], [1, "card-footer"], [1, "hidden-match-indicator", 3, "title"], ["alt", "", 3, "src"], [1, "card-avatar"], [3, "value"], [1, "card-subtitle", 3, "innerHTML"], [1, "field-item", 3, "field-boolean", "field-text"], [1, "field-item"], [1, "field-icon"], [1, "field-label"], [1, "field-value"], [1, "field-value", "field-date"], [1, "field-text-value", 3, "innerHTML"], [1, "fa-solid", "fa-magnifying-glass"]
|
|
917
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: EntityCardsComponent, selectors: [["mj-entity-cards"]], inputs: { entity: "entity", records: "records", selectedRecordId: "selectedRecordId", cardTemplate: "cardTemplate", hiddenFieldMatches: "hiddenFieldMatches", filterText: "filterText", pageSize: "pageSize" }, outputs: { recordSelected: "recordSelected", recordOpened: "recordOpened" }, standalone: false, features: [i0.ɵɵInheritDefinitionFeature, i0.ɵɵNgOnChangesFeature], decls: 3, vars: 1, consts: [[1, "cards-view-wrapper"], [1, "loading-container"], [1, "cards-container"], ["text", "Loading records..."], [1, "data-card", 3, "selected"], ["Variant", "no-results", "Title", "No records to display", 1, "no-results"], [1, "data-card", 3, "click"], [1, "card-header"], [1, "card-thumbnail"], [1, "card-avatar", 3, "background-color"], [1, "card-header-content"], [1, "card-title", 3, "innerHTML"], ["title", "Open Record", 1, "card-open-btn", 3, "click"], [1, "fa-solid", "fa-external-link-alt"], [1, "card-body"], [1, "card-description", 3, "innerHTML"], [1, "card-fields"], [1, "card-footer"], [1, "hidden-match-indicator", 3, "title"], ["alt", "", 3, "src"], [1, "card-avatar"], [3, "value"], [1, "card-subtitle", 3, "innerHTML"], [1, "field-item", 3, "field-boolean", "field-text"], [1, "field-item"], [1, "field-icon"], [1, "field-label"], [1, "field-value"], [1, "field-value", "field-date"], [1, "field-text-value", 3, "innerHTML"], [1, "fa-solid", "fa-magnifying-glass"]], template: function EntityCardsComponent_Template(rf, ctx) { if (rf & 1) {
|
|
921
918
|
i0.ɵɵelementStart(0, "div", 0);
|
|
922
919
|
i0.ɵɵconditionalCreate(1, EntityCardsComponent_Conditional_1_Template, 2, 0, "div", 1)(2, EntityCardsComponent_Conditional_2_Template, 4, 1, "div", 2);
|
|
923
920
|
i0.ɵɵelementEnd();
|
|
924
921
|
} if (rf & 2) {
|
|
925
922
|
i0.ɵɵadvance();
|
|
926
923
|
i0.ɵɵconditional(ctx.isLoading && ctx.effectiveRecords.length === 0 ? 1 : 2);
|
|
927
|
-
} }, dependencies: [i1.LoadingComponent, i2.PillComponent], styles: ["/* Scoped to mj-entity-cards to prevent style leakage with ViewEncapsulation.None */\nmj-entity-cards .cards-view-wrapper {\n height: 100%;\n overflow-y: auto;\n overflow-x: hidden;\n}\n\nmj-entity-cards .cards-container {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));\n gap: 20px;\n padding: 4px;\n}\n\nmj-entity-cards .data-card {\n background: var(--mj-bg-surface);\n border-radius: 12px;\n border: 1px solid var(--mj-border-default);\n overflow: hidden;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n/* Hover state for unselected cards */\nmj-entity-cards .data-card:hover:not(.selected) {\n border-color: var(--mj-border-strong);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n transform: translateY(-2px);\n}\nmj-entity-cards .data-card:hover .card-open-btn {\n opacity: 1;\n}\n\n/* Selected state - subtle but clear */\nmj-entity-cards .data-card.selected {\n border-color: var(--mj-brand-primary);\n}\n\nmj-entity-cards .data-card.selected .card-title {\n color: var(--mj-brand-primary-hover);\n}\n\n/* Selected + hover state - same as regular hover */\nmj-entity-cards .data-card.selected:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n transform: translateY(-2px);\n}\n\nmj-entity-cards .card-header {\n display: flex;\n align-items: flex-start;\n padding: 16px;\n gap: 12px;\n}\n\nmj-entity-cards .card-thumbnail {\n width: 48px;\n height: 48px;\n border-radius: 8px;\n overflow: hidden;\n flex-shrink: 0;\n}\nmj-entity-cards .card-thumbnail img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\nmj-entity-cards .card-avatar {\n width: 48px;\n height: 48px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-inverse);\n flex-shrink: 0;\n}\n\nmj-entity-cards .card-header-content {\n flex: 1;\n min-width: 0;\n}\n\nmj-entity-cards .card-title {\n margin: 0;\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n line-height: 1.3;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\nmj-entity-cards .card-subtitle {\n display: block;\n margin-top: 2px;\n font-size: 12px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\nmj-entity-cards .card-open-btn {\n width: 32px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n opacity: 0;\n transition: all 0.15s ease;\n flex-shrink: 0;\n}\nmj-entity-cards .card-open-btn:hover {\n background: var(--mj-bg-surface-card);\n color: var(--mj-brand-primary);\n}\n\nmj-entity-cards .card-body {\n padding: 0 16px 16px 16px;\n}\n\nmj-entity-cards .card-description {\n margin: 0 0 12px 0;\n font-size: 13px;\n color: var(--mj-text-secondary);\n line-height: 1.5;\n}\n\n/* Card Display Fields */\nmj-entity-cards .card-fields {\n display: flex;\n flex-wrap: wrap;\n gap: 12px;\n padding-top: 12px;\n border-top: 1px solid var(--mj-border-subtle);\n}\n\nmj-entity-cards .field-item {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 60px;\n}\n\nmj-entity-cards .field-item .field-value {\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\nmj-entity-cards .field-item .field-label {\n font-size: 10px;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n/* Boolean fields */\nmj-entity-cards .field-item.field-boolean {\n flex-direction: row;\n align-items: center;\n gap: 6px;\n min-width: auto;\n}\n\nmj-entity-cards .field-item.field-boolean .field-icon {\n font-size: 14px;\n}\n\nmj-entity-cards .field-item.field-boolean .field-icon.bool-true {\n color: var(--mj-status-success);\n}\n\nmj-entity-cards .field-item.field-boolean .field-icon.bool-false {\n color: var(--mj-text-muted);\n}\n\nmj-entity-cards .field-item.field-boolean .field-label {\n font-size: 12px;\n text-transform: none;\n color: var(--mj-text-secondary);\n}\n\n/* Text fields */\nmj-entity-cards .field-item.field-text {\n flex: 1 1 100%;\n max-width: 100%;\n}\n\nmj-entity-cards .field-item .field-text-value {\n font-size: 13px;\n color: var(--mj-text-secondary);\n line-height: 1.4;\n word-break: break-word;\n}\n\n/* Date fields */\nmj-entity-cards .field-item .field-date {\n font-size: 13px;\n font-weight: 500;\n}\n\nmj-entity-cards .card-footer {\n padding: 12px 16px;\n background: var(--mj-bg-surface-card);\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n/* Highlight matches - scoped to work with innerHTML */\nmj-entity-cards .highlight-match {\n background-color: color-mix(in srgb, var(--mj-status-warning) 40%, var(--mj-bg-surface));\n border-radius: 2px;\n}\n\n/* Pill spacing when used as subtitle */\nmj-entity-cards .card-header-content mj-pill {\n display: block;\n margin-top: 4px;\n}\n\n/* Hidden field match indicator */\nmj-entity-cards .hidden-match-indicator {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n background: var(--mj-status-warning-bg);\n border-top: 1px solid var(--mj-status-warning-border);\n font-size: 11px;\n color: var(--mj-status-warning);\n}\n\nmj-entity-cards .hidden-match-indicator i {\n font-size: 10px;\n}\n\nmj-entity-cards .hidden-match-indicator span {\n font-weight: 500;\n}\n\n/* Loading state */\nmj-entity-cards .loading-container {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 200px;\n padding: 40px;\n}\n\n/* No results state
|
|
924
|
+
} }, dependencies: [i1.LoadingComponent, i2.MJEmptyStateComponent, i3.PillComponent], styles: ["/* Scoped to mj-entity-cards to prevent style leakage with ViewEncapsulation.None */\nmj-entity-cards .cards-view-wrapper {\n height: 100%;\n overflow-y: auto;\n overflow-x: hidden;\n}\n\nmj-entity-cards .cards-container {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));\n gap: 20px;\n padding: 4px;\n}\n\nmj-entity-cards .data-card {\n background: var(--mj-bg-surface);\n border-radius: 12px;\n border: 1px solid var(--mj-border-default);\n overflow: hidden;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n/* Hover state for unselected cards */\nmj-entity-cards .data-card:hover:not(.selected) {\n border-color: var(--mj-border-strong);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n transform: translateY(-2px);\n}\nmj-entity-cards .data-card:hover .card-open-btn {\n opacity: 1;\n}\n\n/* Selected state - subtle but clear */\nmj-entity-cards .data-card.selected {\n border-color: var(--mj-brand-primary);\n}\n\nmj-entity-cards .data-card.selected .card-title {\n color: var(--mj-brand-primary-hover);\n}\n\n/* Selected + hover state - same as regular hover */\nmj-entity-cards .data-card.selected:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n transform: translateY(-2px);\n}\n\nmj-entity-cards .card-header {\n display: flex;\n align-items: flex-start;\n padding: 16px;\n gap: 12px;\n}\n\nmj-entity-cards .card-thumbnail {\n width: 48px;\n height: 48px;\n border-radius: 8px;\n overflow: hidden;\n flex-shrink: 0;\n}\nmj-entity-cards .card-thumbnail img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\nmj-entity-cards .card-avatar {\n width: 48px;\n height: 48px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-inverse);\n flex-shrink: 0;\n}\n\nmj-entity-cards .card-header-content {\n flex: 1;\n min-width: 0;\n}\n\nmj-entity-cards .card-title {\n margin: 0;\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n line-height: 1.3;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\nmj-entity-cards .card-subtitle {\n display: block;\n margin-top: 2px;\n font-size: 12px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\nmj-entity-cards .card-open-btn {\n width: 32px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n opacity: 0;\n transition: all 0.15s ease;\n flex-shrink: 0;\n}\nmj-entity-cards .card-open-btn:hover {\n background: var(--mj-bg-surface-card);\n color: var(--mj-brand-primary);\n}\n\nmj-entity-cards .card-body {\n padding: 0 16px 16px 16px;\n}\n\nmj-entity-cards .card-description {\n margin: 0 0 12px 0;\n font-size: 13px;\n color: var(--mj-text-secondary);\n line-height: 1.5;\n}\n\n/* Card Display Fields */\nmj-entity-cards .card-fields {\n display: flex;\n flex-wrap: wrap;\n gap: 12px;\n padding-top: 12px;\n border-top: 1px solid var(--mj-border-subtle);\n}\n\nmj-entity-cards .field-item {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 60px;\n}\n\nmj-entity-cards .field-item .field-value {\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\nmj-entity-cards .field-item .field-label {\n font-size: 10px;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n/* Boolean fields */\nmj-entity-cards .field-item.field-boolean {\n flex-direction: row;\n align-items: center;\n gap: 6px;\n min-width: auto;\n}\n\nmj-entity-cards .field-item.field-boolean .field-icon {\n font-size: 14px;\n}\n\nmj-entity-cards .field-item.field-boolean .field-icon.bool-true {\n color: var(--mj-status-success);\n}\n\nmj-entity-cards .field-item.field-boolean .field-icon.bool-false {\n color: var(--mj-text-muted);\n}\n\nmj-entity-cards .field-item.field-boolean .field-label {\n font-size: 12px;\n text-transform: none;\n color: var(--mj-text-secondary);\n}\n\n/* Text fields */\nmj-entity-cards .field-item.field-text {\n flex: 1 1 100%;\n max-width: 100%;\n}\n\nmj-entity-cards .field-item .field-text-value {\n font-size: 13px;\n color: var(--mj-text-secondary);\n line-height: 1.4;\n word-break: break-word;\n}\n\n/* Date fields */\nmj-entity-cards .field-item .field-date {\n font-size: 13px;\n font-weight: 500;\n}\n\nmj-entity-cards .card-footer {\n padding: 12px 16px;\n background: var(--mj-bg-surface-card);\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n/* Highlight matches - scoped to work with innerHTML */\nmj-entity-cards .highlight-match {\n background-color: color-mix(in srgb, var(--mj-status-warning) 40%, var(--mj-bg-surface));\n border-radius: 2px;\n}\n\n/* Pill spacing when used as subtitle */\nmj-entity-cards .card-header-content mj-pill {\n display: block;\n margin-top: 4px;\n}\n\n/* Hidden field match indicator */\nmj-entity-cards .hidden-match-indicator {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n background: var(--mj-status-warning-bg);\n border-top: 1px solid var(--mj-status-warning-border);\n font-size: 11px;\n color: var(--mj-status-warning);\n}\n\nmj-entity-cards .hidden-match-indicator i {\n font-size: 10px;\n}\n\nmj-entity-cards .hidden-match-indicator span {\n font-weight: 500;\n}\n\n/* Loading state */\nmj-entity-cards .loading-container {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 200px;\n padding: 40px;\n}\n\n/* No results state \u2014 span the full grid width */\nmj-entity-cards .no-results {\n grid-column: 1 / -1;\n}\n"], encapsulation: 2 });
|
|
928
925
|
}
|
|
929
926
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(EntityCardsComponent, [{
|
|
930
927
|
type: Component,
|
|
931
|
-
args: [{ standalone: false, selector: 'mj-entity-cards', encapsulation: ViewEncapsulation.None, template: "<div class=\"cards-view-wrapper\">\n @if (isLoading && effectiveRecords.length === 0) {\n <div class=\"loading-container\">\n <mj-loading text=\"Loading records...\"></mj-loading>\n </div>\n } @else {\n <div class=\"cards-container\">\n @for (vm of cardViewModels; track vm.trackId) {\n <div\n class=\"data-card\"\n [class.selected]=\"vm.isSelected\"\n (click)=\"onCardClick(vm.record)\">\n\n <!-- Card Header with Avatar/Icon -->\n <div class=\"card-header\">\n @switch (vm.thumbnailType) {\n @case ('image') {\n <div class=\"card-thumbnail\">\n <img [src]=\"vm.thumbnailUrl\" alt=\"\" />\n </div>\n }\n @case ('icon') {\n <div class=\"card-avatar\" [style.background-color]=\"vm.color\">\n <i [class]=\"vm.thumbnailUrl\"></i>\n </div>\n }\n @default {\n <div class=\"card-avatar\" [style.background-color]=\"vm.color\">\n {{ vm.initials }}\n </div>\n }\n }\n\n <div class=\"card-header-content\">\n <h3 class=\"card-title\" [innerHTML]=\"vm.highlightedTitle\"></h3>\n @if (effectiveTemplate?.subtitleField) {\n @if (subtitleIsPill) {\n <mj-pill [value]=\"vm.subtitleValue\"></mj-pill>\n } @else {\n <span class=\"card-subtitle\" [innerHTML]=\"vm.highlightedSubtitle\"></span>\n }\n }\n </div>\n\n <button class=\"card-open-btn\" (click)=\"onOpenClick($event, vm.record)\" title=\"Open Record\">\n <i class=\"fa-solid fa-external-link-alt\"></i>\n </button>\n </div>\n\n <!-- Card Body -->\n <div class=\"card-body\">\n @if (effectiveTemplate?.descriptionField) {\n <p class=\"card-description\" [innerHTML]=\"vm.highlightedDescription\"></p>\n }\n\n <!-- Display Fields -->\n @if (vm.displayFields.length > 0) {\n <div class=\"card-fields\">\n @for (df of vm.displayFields; track df.field.name) {\n <div class=\"field-item\" [class.field-boolean]=\"df.field.type === 'boolean'\" [class.field-text]=\"df.field.type === 'text'\">\n @switch (df.field.type) {\n @case ('boolean') {\n <i class=\"field-icon\" [class.fa-solid]=\"true\"\n [class.fa-check]=\"df.booleanValue\"\n [class.fa-minus]=\"!df.booleanValue\"\n [class.bool-true]=\"df.booleanValue\"\n [class.bool-false]=\"!df.booleanValue\"></i>\n <span class=\"field-label\">{{ df.field.label }}</span>\n }\n @case ('number') {\n <span class=\"field-value\">{{ df.numericValue }}</span>\n <span class=\"field-label\">{{ df.field.label }}</span>\n }\n @case ('date') {\n <span class=\"field-value field-date\">{{ df.dateValue }}</span>\n <span class=\"field-label\">{{ df.field.label }}</span>\n }\n @default {\n <span class=\"field-label\">{{ df.field.label }}</span>\n <span class=\"field-text-value\" [innerHTML]=\"df.highlightedText\"></span>\n }\n }\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Card Footer with Badge -->\n @if (effectiveTemplate?.badgeField) {\n <div class=\"card-footer\">\n <mj-pill [value]=\"vm.badgeValue\"></mj-pill>\n </div>\n }\n\n <!-- Hidden field match indicator -->\n @if (vm.hasHiddenFieldMatch) {\n <div class=\"hidden-match-indicator\" [title]=\"'Matched in: ' + vm.hiddenMatchFieldName\">\n <i class=\"fa-solid fa-magnifying-glass\"></i>\n <span>{{ vm.hiddenMatchFieldName }}</span>\n </div>\n }\n </div>\n }\n\n @if (effectiveRecords.length === 0) {\n <div class=\"no-results\">\n <i class=\"fa-solid fa-inbox\"></i>\n <p>No records to display</p>\n </div>\n }\n </div>\n }\n</div>\n", styles: ["/* Scoped to mj-entity-cards to prevent style leakage with ViewEncapsulation.None */\nmj-entity-cards .cards-view-wrapper {\n height: 100%;\n overflow-y: auto;\n overflow-x: hidden;\n}\n\nmj-entity-cards .cards-container {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));\n gap: 20px;\n padding: 4px;\n}\n\nmj-entity-cards .data-card {\n background: var(--mj-bg-surface);\n border-radius: 12px;\n border: 1px solid var(--mj-border-default);\n overflow: hidden;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n/* Hover state for unselected cards */\nmj-entity-cards .data-card:hover:not(.selected) {\n border-color: var(--mj-border-strong);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n transform: translateY(-2px);\n}\nmj-entity-cards .data-card:hover .card-open-btn {\n opacity: 1;\n}\n\n/* Selected state - subtle but clear */\nmj-entity-cards .data-card.selected {\n border-color: var(--mj-brand-primary);\n}\n\nmj-entity-cards .data-card.selected .card-title {\n color: var(--mj-brand-primary-hover);\n}\n\n/* Selected + hover state - same as regular hover */\nmj-entity-cards .data-card.selected:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n transform: translateY(-2px);\n}\n\nmj-entity-cards .card-header {\n display: flex;\n align-items: flex-start;\n padding: 16px;\n gap: 12px;\n}\n\nmj-entity-cards .card-thumbnail {\n width: 48px;\n height: 48px;\n border-radius: 8px;\n overflow: hidden;\n flex-shrink: 0;\n}\nmj-entity-cards .card-thumbnail img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\nmj-entity-cards .card-avatar {\n width: 48px;\n height: 48px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-inverse);\n flex-shrink: 0;\n}\n\nmj-entity-cards .card-header-content {\n flex: 1;\n min-width: 0;\n}\n\nmj-entity-cards .card-title {\n margin: 0;\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n line-height: 1.3;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\nmj-entity-cards .card-subtitle {\n display: block;\n margin-top: 2px;\n font-size: 12px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\nmj-entity-cards .card-open-btn {\n width: 32px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n opacity: 0;\n transition: all 0.15s ease;\n flex-shrink: 0;\n}\nmj-entity-cards .card-open-btn:hover {\n background: var(--mj-bg-surface-card);\n color: var(--mj-brand-primary);\n}\n\nmj-entity-cards .card-body {\n padding: 0 16px 16px 16px;\n}\n\nmj-entity-cards .card-description {\n margin: 0 0 12px 0;\n font-size: 13px;\n color: var(--mj-text-secondary);\n line-height: 1.5;\n}\n\n/* Card Display Fields */\nmj-entity-cards .card-fields {\n display: flex;\n flex-wrap: wrap;\n gap: 12px;\n padding-top: 12px;\n border-top: 1px solid var(--mj-border-subtle);\n}\n\nmj-entity-cards .field-item {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 60px;\n}\n\nmj-entity-cards .field-item .field-value {\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\nmj-entity-cards .field-item .field-label {\n font-size: 10px;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n/* Boolean fields */\nmj-entity-cards .field-item.field-boolean {\n flex-direction: row;\n align-items: center;\n gap: 6px;\n min-width: auto;\n}\n\nmj-entity-cards .field-item.field-boolean .field-icon {\n font-size: 14px;\n}\n\nmj-entity-cards .field-item.field-boolean .field-icon.bool-true {\n color: var(--mj-status-success);\n}\n\nmj-entity-cards .field-item.field-boolean .field-icon.bool-false {\n color: var(--mj-text-muted);\n}\n\nmj-entity-cards .field-item.field-boolean .field-label {\n font-size: 12px;\n text-transform: none;\n color: var(--mj-text-secondary);\n}\n\n/* Text fields */\nmj-entity-cards .field-item.field-text {\n flex: 1 1 100%;\n max-width: 100%;\n}\n\nmj-entity-cards .field-item .field-text-value {\n font-size: 13px;\n color: var(--mj-text-secondary);\n line-height: 1.4;\n word-break: break-word;\n}\n\n/* Date fields */\nmj-entity-cards .field-item .field-date {\n font-size: 13px;\n font-weight: 500;\n}\n\nmj-entity-cards .card-footer {\n padding: 12px 16px;\n background: var(--mj-bg-surface-card);\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n/* Highlight matches - scoped to work with innerHTML */\nmj-entity-cards .highlight-match {\n background-color: color-mix(in srgb, var(--mj-status-warning) 40%, var(--mj-bg-surface));\n border-radius: 2px;\n}\n\n/* Pill spacing when used as subtitle */\nmj-entity-cards .card-header-content mj-pill {\n display: block;\n margin-top: 4px;\n}\n\n/* Hidden field match indicator */\nmj-entity-cards .hidden-match-indicator {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n background: var(--mj-status-warning-bg);\n border-top: 1px solid var(--mj-status-warning-border);\n font-size: 11px;\n color: var(--mj-status-warning);\n}\n\nmj-entity-cards .hidden-match-indicator i {\n font-size: 10px;\n}\n\nmj-entity-cards .hidden-match-indicator span {\n font-weight: 500;\n}\n\n/* Loading state */\nmj-entity-cards .loading-container {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 200px;\n padding: 40px;\n}\n\n/* No results state */\nmj-entity-cards .no-results {\n grid-column: 1 / -1;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n padding: 60px 20px;\n color: var(--mj-text-muted);\n text-align: center;\n}\nmj-entity-cards .no-results i {\n font-size: 48px;\n margin-bottom: 16px;\n opacity: 0.5;\n}\nmj-entity-cards .no-results p {\n margin: 0;\n font-size: 14px;\n}\n"] }]
|
|
928
|
+
args: [{ standalone: false, selector: 'mj-entity-cards', encapsulation: ViewEncapsulation.None, template: "<div class=\"cards-view-wrapper\">\n @if (isLoading && effectiveRecords.length === 0) {\n <div class=\"loading-container\">\n <mj-loading text=\"Loading records...\"></mj-loading>\n </div>\n } @else {\n <div class=\"cards-container\">\n @for (vm of cardViewModels; track vm.trackId) {\n <div\n class=\"data-card\"\n [class.selected]=\"vm.isSelected\"\n (click)=\"onCardClick(vm.record)\">\n\n <!-- Card Header with Avatar/Icon -->\n <div class=\"card-header\">\n @switch (vm.thumbnailType) {\n @case ('image') {\n <div class=\"card-thumbnail\">\n <img [src]=\"vm.thumbnailUrl\" alt=\"\" />\n </div>\n }\n @case ('icon') {\n <div class=\"card-avatar\" [style.background-color]=\"vm.color\">\n <i [class]=\"vm.thumbnailUrl\"></i>\n </div>\n }\n @default {\n <div class=\"card-avatar\" [style.background-color]=\"vm.color\">\n {{ vm.initials }}\n </div>\n }\n }\n\n <div class=\"card-header-content\">\n <h3 class=\"card-title\" [innerHTML]=\"vm.highlightedTitle\"></h3>\n @if (effectiveTemplate?.subtitleField) {\n @if (subtitleIsPill) {\n <mj-pill [value]=\"vm.subtitleValue\"></mj-pill>\n } @else {\n <span class=\"card-subtitle\" [innerHTML]=\"vm.highlightedSubtitle\"></span>\n }\n }\n </div>\n\n <button class=\"card-open-btn\" (click)=\"onOpenClick($event, vm.record)\" title=\"Open Record\">\n <i class=\"fa-solid fa-external-link-alt\"></i>\n </button>\n </div>\n\n <!-- Card Body -->\n <div class=\"card-body\">\n @if (effectiveTemplate?.descriptionField) {\n <p class=\"card-description\" [innerHTML]=\"vm.highlightedDescription\"></p>\n }\n\n <!-- Display Fields -->\n @if (vm.displayFields.length > 0) {\n <div class=\"card-fields\">\n @for (df of vm.displayFields; track df.field.name) {\n <div class=\"field-item\" [class.field-boolean]=\"df.field.type === 'boolean'\" [class.field-text]=\"df.field.type === 'text'\">\n @switch (df.field.type) {\n @case ('boolean') {\n <i class=\"field-icon\" [class.fa-solid]=\"true\"\n [class.fa-check]=\"df.booleanValue\"\n [class.fa-minus]=\"!df.booleanValue\"\n [class.bool-true]=\"df.booleanValue\"\n [class.bool-false]=\"!df.booleanValue\"></i>\n <span class=\"field-label\">{{ df.field.label }}</span>\n }\n @case ('number') {\n <span class=\"field-value\">{{ df.numericValue }}</span>\n <span class=\"field-label\">{{ df.field.label }}</span>\n }\n @case ('date') {\n <span class=\"field-value field-date\">{{ df.dateValue }}</span>\n <span class=\"field-label\">{{ df.field.label }}</span>\n }\n @default {\n <span class=\"field-label\">{{ df.field.label }}</span>\n <span class=\"field-text-value\" [innerHTML]=\"df.highlightedText\"></span>\n }\n }\n </div>\n }\n </div>\n }\n </div>\n\n <!-- Card Footer with Badge -->\n @if (effectiveTemplate?.badgeField) {\n <div class=\"card-footer\">\n <mj-pill [value]=\"vm.badgeValue\"></mj-pill>\n </div>\n }\n\n <!-- Hidden field match indicator -->\n @if (vm.hasHiddenFieldMatch) {\n <div class=\"hidden-match-indicator\" [title]=\"'Matched in: ' + vm.hiddenMatchFieldName\">\n <i class=\"fa-solid fa-magnifying-glass\"></i>\n <span>{{ vm.hiddenMatchFieldName }}</span>\n </div>\n }\n </div>\n }\n\n @if (effectiveRecords.length === 0) {\n <mj-empty-state\n class=\"no-results\"\n Variant=\"no-results\"\n Title=\"No records to display\" />\n }\n </div>\n }\n</div>\n", styles: ["/* Scoped to mj-entity-cards to prevent style leakage with ViewEncapsulation.None */\nmj-entity-cards .cards-view-wrapper {\n height: 100%;\n overflow-y: auto;\n overflow-x: hidden;\n}\n\nmj-entity-cards .cards-container {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));\n gap: 20px;\n padding: 4px;\n}\n\nmj-entity-cards .data-card {\n background: var(--mj-bg-surface);\n border-radius: 12px;\n border: 1px solid var(--mj-border-default);\n overflow: hidden;\n cursor: pointer;\n transition: all 0.2s ease;\n}\n/* Hover state for unselected cards */\nmj-entity-cards .data-card:hover:not(.selected) {\n border-color: var(--mj-border-strong);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n transform: translateY(-2px);\n}\nmj-entity-cards .data-card:hover .card-open-btn {\n opacity: 1;\n}\n\n/* Selected state - subtle but clear */\nmj-entity-cards .data-card.selected {\n border-color: var(--mj-brand-primary);\n}\n\nmj-entity-cards .data-card.selected .card-title {\n color: var(--mj-brand-primary-hover);\n}\n\n/* Selected + hover state - same as regular hover */\nmj-entity-cards .data-card.selected:hover {\n border-color: var(--mj-brand-primary);\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);\n transform: translateY(-2px);\n}\n\nmj-entity-cards .card-header {\n display: flex;\n align-items: flex-start;\n padding: 16px;\n gap: 12px;\n}\n\nmj-entity-cards .card-thumbnail {\n width: 48px;\n height: 48px;\n border-radius: 8px;\n overflow: hidden;\n flex-shrink: 0;\n}\nmj-entity-cards .card-thumbnail img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n}\n\nmj-entity-cards .card-avatar {\n width: 48px;\n height: 48px;\n border-radius: 8px;\n display: flex;\n align-items: center;\n justify-content: center;\n font-size: 16px;\n font-weight: 600;\n color: var(--mj-text-inverse);\n flex-shrink: 0;\n}\n\nmj-entity-cards .card-header-content {\n flex: 1;\n min-width: 0;\n}\n\nmj-entity-cards .card-title {\n margin: 0;\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n line-height: 1.3;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\nmj-entity-cards .card-subtitle {\n display: block;\n margin-top: 2px;\n font-size: 12px;\n color: var(--mj-text-muted);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\nmj-entity-cards .card-open-btn {\n width: 32px;\n height: 32px;\n border: none;\n background: transparent;\n border-radius: 6px;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n color: var(--mj-text-muted);\n opacity: 0;\n transition: all 0.15s ease;\n flex-shrink: 0;\n}\nmj-entity-cards .card-open-btn:hover {\n background: var(--mj-bg-surface-card);\n color: var(--mj-brand-primary);\n}\n\nmj-entity-cards .card-body {\n padding: 0 16px 16px 16px;\n}\n\nmj-entity-cards .card-description {\n margin: 0 0 12px 0;\n font-size: 13px;\n color: var(--mj-text-secondary);\n line-height: 1.5;\n}\n\n/* Card Display Fields */\nmj-entity-cards .card-fields {\n display: flex;\n flex-wrap: wrap;\n gap: 12px;\n padding-top: 12px;\n border-top: 1px solid var(--mj-border-subtle);\n}\n\nmj-entity-cards .field-item {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 60px;\n}\n\nmj-entity-cards .field-item .field-value {\n font-size: 15px;\n font-weight: 600;\n color: var(--mj-text-primary);\n}\n\nmj-entity-cards .field-item .field-label {\n font-size: 10px;\n color: var(--mj-text-muted);\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n/* Boolean fields */\nmj-entity-cards .field-item.field-boolean {\n flex-direction: row;\n align-items: center;\n gap: 6px;\n min-width: auto;\n}\n\nmj-entity-cards .field-item.field-boolean .field-icon {\n font-size: 14px;\n}\n\nmj-entity-cards .field-item.field-boolean .field-icon.bool-true {\n color: var(--mj-status-success);\n}\n\nmj-entity-cards .field-item.field-boolean .field-icon.bool-false {\n color: var(--mj-text-muted);\n}\n\nmj-entity-cards .field-item.field-boolean .field-label {\n font-size: 12px;\n text-transform: none;\n color: var(--mj-text-secondary);\n}\n\n/* Text fields */\nmj-entity-cards .field-item.field-text {\n flex: 1 1 100%;\n max-width: 100%;\n}\n\nmj-entity-cards .field-item .field-text-value {\n font-size: 13px;\n color: var(--mj-text-secondary);\n line-height: 1.4;\n word-break: break-word;\n}\n\n/* Date fields */\nmj-entity-cards .field-item .field-date {\n font-size: 13px;\n font-weight: 500;\n}\n\nmj-entity-cards .card-footer {\n padding: 12px 16px;\n background: var(--mj-bg-surface-card);\n border-top: 1px solid var(--mj-border-subtle);\n}\n\n/* Highlight matches - scoped to work with innerHTML */\nmj-entity-cards .highlight-match {\n background-color: color-mix(in srgb, var(--mj-status-warning) 40%, var(--mj-bg-surface));\n border-radius: 2px;\n}\n\n/* Pill spacing when used as subtitle */\nmj-entity-cards .card-header-content mj-pill {\n display: block;\n margin-top: 4px;\n}\n\n/* Hidden field match indicator */\nmj-entity-cards .hidden-match-indicator {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 16px;\n background: var(--mj-status-warning-bg);\n border-top: 1px solid var(--mj-status-warning-border);\n font-size: 11px;\n color: var(--mj-status-warning);\n}\n\nmj-entity-cards .hidden-match-indicator i {\n font-size: 10px;\n}\n\nmj-entity-cards .hidden-match-indicator span {\n font-weight: 500;\n}\n\n/* Loading state */\nmj-entity-cards .loading-container {\n display: flex;\n align-items: center;\n justify-content: center;\n min-height: 200px;\n padding: 40px;\n}\n\n/* No results state \u2014 span the full grid width */\nmj-entity-cards .no-results {\n grid-column: 1 / -1;\n}\n"] }]
|
|
932
929
|
}], () => [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }], { entity: [{
|
|
933
930
|
type: Input
|
|
934
931
|
}], records: [{
|