@memberjunction/ng-search 5.23.0 → 5.25.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/__tests__/search-results.component.test.d.ts +2 -0
- package/dist/__tests__/search-results.component.test.d.ts.map +1 -0
- package/dist/__tests__/search-results.component.test.js +263 -0
- package/dist/__tests__/search-results.component.test.js.map +1 -0
- package/dist/__tests__/search-types.test.js +6 -2
- package/dist/__tests__/search-types.test.js.map +1 -1
- package/dist/__tests__/search.service.test.js +167 -13
- package/dist/__tests__/search.service.test.js.map +1 -1
- package/dist/lib/module.d.ts +7 -4
- package/dist/lib/module.d.ts.map +1 -1
- package/dist/lib/module.js +19 -4
- package/dist/lib/module.js.map +1 -1
- package/dist/lib/search-composite.component.d.ts +79 -0
- package/dist/lib/search-composite.component.d.ts.map +1 -0
- package/dist/lib/search-composite.component.js +258 -0
- package/dist/lib/search-composite.component.js.map +1 -0
- package/dist/lib/search-filter.component.d.ts +19 -1
- package/dist/lib/search-filter.component.d.ts.map +1 -1
- package/dist/lib/search-filter.component.js +195 -44
- package/dist/lib/search-filter.component.js.map +1 -1
- package/dist/lib/search-input.component.d.ts +61 -0
- package/dist/lib/search-input.component.d.ts.map +1 -0
- package/dist/lib/search-input.component.js +192 -0
- package/dist/lib/search-input.component.js.map +1 -0
- package/dist/lib/search-overlay.component.js +2 -2
- package/dist/lib/search-results.component.d.ts +59 -7
- package/dist/lib/search-results.component.d.ts.map +1 -1
- package/dist/lib/search-results.component.js +530 -176
- package/dist/lib/search-results.component.js.map +1 -1
- package/dist/lib/search-suggest.component.d.ts +95 -0
- package/dist/lib/search-suggest.component.d.ts.map +1 -0
- package/dist/lib/search-suggest.component.js +491 -0
- package/dist/lib/search-suggest.component.js.map +1 -0
- package/dist/lib/search-types.d.ts +29 -1
- package/dist/lib/search-types.d.ts.map +1 -1
- package/dist/lib/search-types.js.map +1 -1
- package/dist/lib/search.service.d.ts +27 -5
- package/dist/lib/search.service.d.ts.map +1 -1
- package/dist/lib/search.service.js +222 -91
- package/dist/lib/search.service.js.map +1 -1
- package/dist/public-api.d.ts +3 -0
- package/dist/public-api.d.ts.map +1 -1
- package/dist/public-api.js +3 -0
- package/dist/public-api.js.map +1 -1
- package/package.json +6 -4
|
@@ -15,8 +15,16 @@ export declare class SearchFilterComponent {
|
|
|
15
15
|
ActiveFilters: Record<string, string[]>;
|
|
16
16
|
/** Whether the filter panel is collapsible */
|
|
17
17
|
Collapsible: boolean;
|
|
18
|
+
/** Whether to show the min relevance slider */
|
|
19
|
+
ShowRelevanceSlider: boolean;
|
|
20
|
+
/** Current minimum score as a percentage (0-100) */
|
|
21
|
+
MinScorePercent: number;
|
|
22
|
+
/** The MinScore that was last sent to the server (for visual indicator) */
|
|
23
|
+
ServerMinScorePercent: number;
|
|
18
24
|
FilterChanged: EventEmitter<SearchFilterChangeEvent>;
|
|
19
25
|
FiltersCleared: EventEmitter<void>;
|
|
26
|
+
CloseRequested: EventEmitter<void>;
|
|
27
|
+
MinScoreChanged: EventEmitter<number>;
|
|
20
28
|
/** Collapsed state per category */
|
|
21
29
|
CollapsedCategories: Set<string>;
|
|
22
30
|
/** Toggle a filter option */
|
|
@@ -33,7 +41,17 @@ export declare class SearchFilterComponent {
|
|
|
33
41
|
GetActiveFilterCount(): number;
|
|
34
42
|
/** Clear all filters */
|
|
35
43
|
ClearAll(): void;
|
|
44
|
+
/** Select all options in a category, or clear all if already all selected */
|
|
45
|
+
SelectAll(category: string): void;
|
|
46
|
+
/** Check if all options in a category are selected */
|
|
47
|
+
IsAllSelected(category: string): boolean;
|
|
48
|
+
/** Handle relevance slider drag (preview only — updates display without triggering search) */
|
|
49
|
+
OnMinScorePreview(value: string): void;
|
|
50
|
+
/** Handle relevance slider release — commits the value and triggers re-query if needed */
|
|
51
|
+
OnMinScoreCommit(): void;
|
|
52
|
+
/** Handle relevance slider change (legacy — used when input event fires) */
|
|
53
|
+
OnMinScoreChange(value: string): void;
|
|
36
54
|
static ɵfac: i0.ɵɵFactoryDeclaration<SearchFilterComponent, never>;
|
|
37
|
-
static ɵcmp: i0.ɵɵComponentDeclaration<SearchFilterComponent, "mj-search-filter", never, { "Filters": { "alias": "Filters"; "required": false; }; "ActiveFilters": { "alias": "ActiveFilters"; "required": false; }; "Collapsible": { "alias": "Collapsible"; "required": false; }; }, { "FilterChanged": "FilterChanged"; "FiltersCleared": "FiltersCleared"; }, never, never, false, never>;
|
|
55
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<SearchFilterComponent, "mj-search-filter", never, { "Filters": { "alias": "Filters"; "required": false; }; "ActiveFilters": { "alias": "ActiveFilters"; "required": false; }; "Collapsible": { "alias": "Collapsible"; "required": false; }; "ShowRelevanceSlider": { "alias": "ShowRelevanceSlider"; "required": false; }; "MinScorePercent": { "alias": "MinScorePercent"; "required": false; }; "ServerMinScorePercent": { "alias": "ServerMinScorePercent"; "required": false; }; }, { "FilterChanged": "FilterChanged"; "FiltersCleared": "FiltersCleared"; "CloseRequested": "CloseRequested"; "MinScoreChanged": "MinScoreChanged"; }, never, never, false, never>;
|
|
38
56
|
}
|
|
39
57
|
//# sourceMappingURL=search-filter.component.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-filter.component.d.ts","sourceRoot":"","sources":["../../src/lib/search-filter.component.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAEH,YAAY,EAKf,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;;AAEvE,qBAMa,qBAAqB;IAC9B,OAAO,CAAC,GAAG,CAA6B;IAExC,mCAAmC;IAC1B,OAAO,EAAE,YAAY,EAAE,CAAM;IAEtC,yCAAyC;IAChC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAM;IAEtD,8CAA8C;IACrC,WAAW,UAAQ;
|
|
1
|
+
{"version":3,"file":"search-filter.component.d.ts","sourceRoot":"","sources":["../../src/lib/search-filter.component.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAEH,YAAY,EAKf,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;;AAEvE,qBAMa,qBAAqB;IAC9B,OAAO,CAAC,GAAG,CAA6B;IAExC,mCAAmC;IAC1B,OAAO,EAAE,YAAY,EAAE,CAAM;IAEtC,yCAAyC;IAChC,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAM;IAEtD,8CAA8C;IACrC,WAAW,UAAQ;IAE5B,+CAA+C;IACtC,mBAAmB,UAAQ;IAEpC,oDAAoD;IAC3C,eAAe,SAAK;IAE7B,2EAA2E;IAClE,qBAAqB,SAAK;IAEzB,aAAa,wCAA+C;IAC5D,cAAc,qBAA4B;IAC1C,cAAc,qBAA4B;IAC1C,eAAe,uBAA8B;IAEvD,mCAAmC;IAC5B,mBAAmB,cAAqB;IAE/C,6BAA6B;IACtB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAc1D,+BAA+B;IACxB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAU7C,uCAAuC;IAChC,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAIrD,qCAAqC;IAC9B,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO;IAIjE,sCAAsC;IAC/B,gBAAgB,IAAI,OAAO;IAIlC,oCAAoC;IAC7B,oBAAoB,IAAI,MAAM;IAIrC,wBAAwB;IACjB,QAAQ,IAAI,IAAI;IAMvB,6EAA6E;IACtE,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAgBxC,sDAAsD;IAC/C,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;IAO/C,8FAA8F;IACvF,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAI7C,0FAA0F;IACnF,gBAAgB,IAAI,IAAI;IAI/B,4EAA4E;IACrE,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;yCAtHnC,qBAAqB;2CAArB,qBAAqB;CA0HjC"}
|
|
@@ -8,10 +8,10 @@ import { Component, EventEmitter, Input, Output, ChangeDetectorRef, inject } fro
|
|
|
8
8
|
import * as i0 from "@angular/core";
|
|
9
9
|
const _forTrack0 = ($index, $item) => $item.Category;
|
|
10
10
|
const _forTrack1 = ($index, $item) => $item.Value;
|
|
11
|
-
function
|
|
11
|
+
function SearchFilterComponent_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
12
12
|
const _r1 = i0.ɵɵgetCurrentView();
|
|
13
|
-
i0.ɵɵelementStart(0, "button",
|
|
14
|
-
i0.ɵɵlistener("click", function
|
|
13
|
+
i0.ɵɵelementStart(0, "button", 10);
|
|
14
|
+
i0.ɵɵlistener("click", function SearchFilterComponent_Conditional_6_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.ClearAll()); });
|
|
15
15
|
i0.ɵɵtext(1);
|
|
16
16
|
i0.ɵɵelementEnd();
|
|
17
17
|
} if (rf & 2) {
|
|
@@ -19,38 +19,75 @@ function SearchFilterComponent_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
|
19
19
|
i0.ɵɵadvance();
|
|
20
20
|
i0.ɵɵtextInterpolate1(" Clear (", ctx_r1.GetActiveFilterCount(), ") ");
|
|
21
21
|
} }
|
|
22
|
-
function
|
|
23
|
-
i0.ɵɵelement(0, "i",
|
|
22
|
+
function SearchFilterComponent_For_10_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
23
|
+
i0.ɵɵelement(0, "i", 17);
|
|
24
24
|
} if (rf & 2) {
|
|
25
25
|
const filter_r4 = i0.ɵɵnextContext().$implicit;
|
|
26
26
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
27
27
|
i0.ɵɵclassProp("fa-chevron-down", ctx_r1.IsCategoryCollapsed(filter_r4.Category))("fa-chevron-up", !ctx_r1.IsCategoryCollapsed(filter_r4.Category));
|
|
28
28
|
} }
|
|
29
|
-
function
|
|
30
|
-
i0.ɵɵ
|
|
29
|
+
function SearchFilterComponent_For_10_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
30
|
+
const _r5 = i0.ɵɵgetCurrentView();
|
|
31
|
+
i0.ɵɵelementStart(0, "button", 18);
|
|
32
|
+
i0.ɵɵlistener("click", function SearchFilterComponent_For_10_Conditional_6_Template_button_click_0_listener($event) { i0.ɵɵrestoreView(_r5); const filter_r4 = i0.ɵɵnextContext().$implicit; const ctx_r1 = i0.ɵɵnextContext(); ctx_r1.SelectAll(filter_r4.Category); return i0.ɵɵresetView($event.stopPropagation()); });
|
|
33
|
+
i0.ɵɵtext(1);
|
|
34
|
+
i0.ɵɵelementEnd();
|
|
35
|
+
} if (rf & 2) {
|
|
36
|
+
const filter_r4 = i0.ɵɵnextContext().$implicit;
|
|
37
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
38
|
+
i0.ɵɵproperty("title", ctx_r1.IsAllSelected(filter_r4.Category) ? "Clear all" : "Select all");
|
|
39
|
+
i0.ɵɵadvance();
|
|
40
|
+
i0.ɵɵtextInterpolate1(" ", ctx_r1.IsAllSelected(filter_r4.Category) ? "Clear" : "All", " ");
|
|
31
41
|
} }
|
|
32
|
-
function
|
|
42
|
+
function SearchFilterComponent_For_10_Conditional_7_For_2_Conditional_0_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
33
43
|
i0.ɵɵelement(0, "i");
|
|
44
|
+
} if (rf & 2) {
|
|
45
|
+
const option_r6 = i0.ɵɵnextContext(2).$implicit;
|
|
46
|
+
i0.ɵɵclassMap(option_r6.Icon + " filter-option-icon");
|
|
47
|
+
} }
|
|
48
|
+
function SearchFilterComponent_For_10_Conditional_7_For_2_Conditional_0_Template(rf, ctx) { if (rf & 1) {
|
|
49
|
+
i0.ɵɵelementStart(0, "div", 19);
|
|
50
|
+
i0.ɵɵconditionalCreate(1, SearchFilterComponent_For_10_Conditional_7_For_2_Conditional_0_Conditional_1_Template, 1, 2, "i", 21);
|
|
51
|
+
i0.ɵɵelementStart(2, "span", 22);
|
|
52
|
+
i0.ɵɵtext(3);
|
|
53
|
+
i0.ɵɵelementEnd();
|
|
54
|
+
i0.ɵɵelementStart(4, "span", 23);
|
|
55
|
+
i0.ɵɵtext(5);
|
|
56
|
+
i0.ɵɵelementEnd()();
|
|
34
57
|
} if (rf & 2) {
|
|
35
58
|
const option_r6 = i0.ɵɵnextContext().$implicit;
|
|
59
|
+
i0.ɵɵadvance();
|
|
60
|
+
i0.ɵɵconditional(option_r6.Icon ? 1 : -1);
|
|
61
|
+
i0.ɵɵadvance(2);
|
|
62
|
+
i0.ɵɵtextInterpolate(option_r6.Label);
|
|
63
|
+
i0.ɵɵadvance(2);
|
|
64
|
+
i0.ɵɵtextInterpolate(option_r6.Count);
|
|
65
|
+
} }
|
|
66
|
+
function SearchFilterComponent_For_10_Conditional_7_For_2_Conditional_1_Conditional_2_Template(rf, ctx) { if (rf & 1) {
|
|
67
|
+
i0.ɵɵelement(0, "i", 26);
|
|
68
|
+
} }
|
|
69
|
+
function SearchFilterComponent_For_10_Conditional_7_For_2_Conditional_1_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
70
|
+
i0.ɵɵelement(0, "i");
|
|
71
|
+
} if (rf & 2) {
|
|
72
|
+
const option_r6 = i0.ɵɵnextContext(2).$implicit;
|
|
36
73
|
i0.ɵɵclassMap(option_r6.Icon + " filter-option-icon");
|
|
37
74
|
} }
|
|
38
|
-
function
|
|
39
|
-
const
|
|
40
|
-
i0.ɵɵelementStart(0, "label",
|
|
41
|
-
i0.ɵɵlistener("click", function
|
|
42
|
-
i0.ɵɵelementStart(1, "span",
|
|
43
|
-
i0.ɵɵconditionalCreate(2,
|
|
75
|
+
function SearchFilterComponent_For_10_Conditional_7_For_2_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
76
|
+
const _r7 = i0.ɵɵgetCurrentView();
|
|
77
|
+
i0.ɵɵelementStart(0, "label", 24);
|
|
78
|
+
i0.ɵɵlistener("click", function SearchFilterComponent_For_10_Conditional_7_For_2_Conditional_1_Template_label_click_0_listener($event) { i0.ɵɵrestoreView(_r7); const option_r6 = i0.ɵɵnextContext().$implicit; const filter_r4 = i0.ɵɵnextContext(2).$implicit; const ctx_r1 = i0.ɵɵnextContext(); ctx_r1.ToggleOption(filter_r4.Category, option_r6.Value); return i0.ɵɵresetView($event.preventDefault()); });
|
|
79
|
+
i0.ɵɵelementStart(1, "span", 25);
|
|
80
|
+
i0.ɵɵconditionalCreate(2, SearchFilterComponent_For_10_Conditional_7_For_2_Conditional_1_Conditional_2_Template, 1, 0, "i", 26);
|
|
44
81
|
i0.ɵɵelementEnd();
|
|
45
|
-
i0.ɵɵconditionalCreate(3,
|
|
46
|
-
i0.ɵɵelementStart(4, "span",
|
|
82
|
+
i0.ɵɵconditionalCreate(3, SearchFilterComponent_For_10_Conditional_7_For_2_Conditional_1_Conditional_3_Template, 1, 2, "i", 21);
|
|
83
|
+
i0.ɵɵelementStart(4, "span", 22);
|
|
47
84
|
i0.ɵɵtext(5);
|
|
48
85
|
i0.ɵɵelementEnd();
|
|
49
|
-
i0.ɵɵelementStart(6, "span",
|
|
86
|
+
i0.ɵɵelementStart(6, "span", 23);
|
|
50
87
|
i0.ɵɵtext(7);
|
|
51
88
|
i0.ɵɵelementEnd()();
|
|
52
89
|
} if (rf & 2) {
|
|
53
|
-
const option_r6 =
|
|
90
|
+
const option_r6 = i0.ɵɵnextContext().$implicit;
|
|
54
91
|
const filter_r4 = i0.ɵɵnextContext(2).$implicit;
|
|
55
92
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
56
93
|
i0.ɵɵadvance();
|
|
@@ -64,40 +101,91 @@ function SearchFilterComponent_For_7_Conditional_5_For_2_Template(rf, ctx) { if
|
|
|
64
101
|
i0.ɵɵadvance(2);
|
|
65
102
|
i0.ɵɵtextInterpolate(option_r6.Count);
|
|
66
103
|
} }
|
|
67
|
-
function
|
|
68
|
-
i0.ɵɵ
|
|
69
|
-
|
|
104
|
+
function SearchFilterComponent_For_10_Conditional_7_For_2_Template(rf, ctx) { if (rf & 1) {
|
|
105
|
+
i0.ɵɵconditionalCreate(0, SearchFilterComponent_For_10_Conditional_7_For_2_Conditional_0_Template, 6, 3, "div", 19)(1, SearchFilterComponent_For_10_Conditional_7_For_2_Conditional_1_Template, 8, 6, "label", 20);
|
|
106
|
+
} if (rf & 2) {
|
|
107
|
+
const filter_r4 = i0.ɵɵnextContext(2).$implicit;
|
|
108
|
+
i0.ɵɵconditional(filter_r4.Options.length === 1 ? 0 : 1);
|
|
109
|
+
} }
|
|
110
|
+
function SearchFilterComponent_For_10_Conditional_7_Template(rf, ctx) { if (rf & 1) {
|
|
111
|
+
i0.ɵɵelementStart(0, "div", 16);
|
|
112
|
+
i0.ɵɵrepeaterCreate(1, SearchFilterComponent_For_10_Conditional_7_For_2_Template, 2, 1, null, null, _forTrack1);
|
|
70
113
|
i0.ɵɵelementEnd();
|
|
71
114
|
} if (rf & 2) {
|
|
72
115
|
const filter_r4 = i0.ɵɵnextContext().$implicit;
|
|
73
116
|
i0.ɵɵadvance();
|
|
74
117
|
i0.ɵɵrepeater(filter_r4.Options);
|
|
75
118
|
} }
|
|
76
|
-
function
|
|
119
|
+
function SearchFilterComponent_For_10_Template(rf, ctx) { if (rf & 1) {
|
|
77
120
|
const _r3 = i0.ɵɵgetCurrentView();
|
|
78
|
-
i0.ɵɵelementStart(0, "div",
|
|
79
|
-
i0.ɵɵlistener("click", function
|
|
80
|
-
i0.ɵɵelementStart(
|
|
81
|
-
i0.ɵɵtext(
|
|
121
|
+
i0.ɵɵelementStart(0, "div", 8)(1, "div", 11)(2, "div", 12);
|
|
122
|
+
i0.ɵɵlistener("click", function SearchFilterComponent_For_10_Template_div_click_2_listener() { const filter_r4 = i0.ɵɵrestoreView(_r3).$implicit; const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.ToggleCategory(filter_r4.Category)); });
|
|
123
|
+
i0.ɵɵelementStart(3, "span", 13);
|
|
124
|
+
i0.ɵɵtext(4);
|
|
125
|
+
i0.ɵɵelementEnd();
|
|
126
|
+
i0.ɵɵconditionalCreate(5, SearchFilterComponent_For_10_Conditional_5_Template, 1, 4, "i", 14);
|
|
82
127
|
i0.ɵɵelementEnd();
|
|
83
|
-
i0.ɵɵconditionalCreate(
|
|
128
|
+
i0.ɵɵconditionalCreate(6, SearchFilterComponent_For_10_Conditional_6_Template, 2, 2, "button", 15);
|
|
84
129
|
i0.ɵɵelementEnd();
|
|
85
|
-
i0.ɵɵconditionalCreate(
|
|
130
|
+
i0.ɵɵconditionalCreate(7, SearchFilterComponent_For_10_Conditional_7_Template, 3, 0, "div", 16);
|
|
86
131
|
i0.ɵɵelementEnd();
|
|
87
132
|
} if (rf & 2) {
|
|
88
133
|
const filter_r4 = ctx.$implicit;
|
|
89
134
|
const ctx_r1 = i0.ɵɵnextContext();
|
|
90
|
-
i0.ɵɵadvance();
|
|
135
|
+
i0.ɵɵadvance(2);
|
|
91
136
|
i0.ɵɵclassProp("filter-category-collapsed", ctx_r1.IsCategoryCollapsed(filter_r4.Category));
|
|
92
137
|
i0.ɵɵadvance(2);
|
|
93
138
|
i0.ɵɵtextInterpolate(filter_r4.Category);
|
|
94
139
|
i0.ɵɵadvance();
|
|
95
|
-
i0.ɵɵconditional(ctx_r1.Collapsible ?
|
|
140
|
+
i0.ɵɵconditional(ctx_r1.Collapsible ? 5 : -1);
|
|
96
141
|
i0.ɵɵadvance();
|
|
97
|
-
i0.ɵɵconditional(!ctx_r1.IsCategoryCollapsed(filter_r4.Category) ?
|
|
142
|
+
i0.ɵɵconditional(!ctx_r1.IsCategoryCollapsed(filter_r4.Category) && filter_r4.Options.length > 1 ? 6 : -1);
|
|
143
|
+
i0.ɵɵadvance();
|
|
144
|
+
i0.ɵɵconditional(!ctx_r1.IsCategoryCollapsed(filter_r4.Category) ? 7 : -1);
|
|
98
145
|
} }
|
|
99
|
-
function
|
|
100
|
-
i0.ɵɵelementStart(0, "
|
|
146
|
+
function SearchFilterComponent_Conditional_11_Conditional_9_Conditional_3_Template(rf, ctx) { if (rf & 1) {
|
|
147
|
+
i0.ɵɵelementStart(0, "span", 33);
|
|
148
|
+
i0.ɵɵelement(1, "i", 34);
|
|
149
|
+
i0.ɵɵtext(2, " Will re-query ");
|
|
150
|
+
i0.ɵɵelementEnd();
|
|
151
|
+
} }
|
|
152
|
+
function SearchFilterComponent_Conditional_11_Conditional_9_Template(rf, ctx) { if (rf & 1) {
|
|
153
|
+
i0.ɵɵelementStart(0, "div", 31)(1, "span", 32);
|
|
154
|
+
i0.ɵɵtext(2);
|
|
155
|
+
i0.ɵɵelementEnd();
|
|
156
|
+
i0.ɵɵconditionalCreate(3, SearchFilterComponent_Conditional_11_Conditional_9_Conditional_3_Template, 3, 0, "span", 33);
|
|
157
|
+
i0.ɵɵelementEnd();
|
|
158
|
+
} if (rf & 2) {
|
|
159
|
+
const ctx_r1 = i0.ɵɵnextContext(2);
|
|
160
|
+
i0.ɵɵadvance(2);
|
|
161
|
+
i0.ɵɵtextInterpolate1("Server threshold: ", ctx_r1.ServerMinScorePercent, "%");
|
|
162
|
+
i0.ɵɵadvance();
|
|
163
|
+
i0.ɵɵconditional(ctx_r1.MinScorePercent < ctx_r1.ServerMinScorePercent ? 3 : -1);
|
|
164
|
+
} }
|
|
165
|
+
function SearchFilterComponent_Conditional_11_Template(rf, ctx) { if (rf & 1) {
|
|
166
|
+
const _r8 = i0.ɵɵgetCurrentView();
|
|
167
|
+
i0.ɵɵelementStart(0, "div", 8)(1, "div", 11)(2, "div", 27)(3, "span", 13);
|
|
168
|
+
i0.ɵɵtext(4, "Min Relevance");
|
|
169
|
+
i0.ɵɵelementEnd()()();
|
|
170
|
+
i0.ɵɵelementStart(5, "div", 28)(6, "input", 29);
|
|
171
|
+
i0.ɵɵlistener("input", function SearchFilterComponent_Conditional_11_Template_input_input_6_listener($event) { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnMinScorePreview($event.target.value)); })("mouseup", function SearchFilterComponent_Conditional_11_Template_input_mouseup_6_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnMinScoreCommit()); })("touchend", function SearchFilterComponent_Conditional_11_Template_input_touchend_6_listener() { i0.ɵɵrestoreView(_r8); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.OnMinScoreCommit()); });
|
|
172
|
+
i0.ɵɵelementEnd();
|
|
173
|
+
i0.ɵɵelementStart(7, "span", 30);
|
|
174
|
+
i0.ɵɵtext(8);
|
|
175
|
+
i0.ɵɵelementEnd()();
|
|
176
|
+
i0.ɵɵconditionalCreate(9, SearchFilterComponent_Conditional_11_Conditional_9_Template, 4, 2, "div", 31);
|
|
177
|
+
i0.ɵɵelementEnd();
|
|
178
|
+
} if (rf & 2) {
|
|
179
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
180
|
+
i0.ɵɵadvance(6);
|
|
181
|
+
i0.ɵɵproperty("value", ctx_r1.MinScorePercent);
|
|
182
|
+
i0.ɵɵadvance(2);
|
|
183
|
+
i0.ɵɵtextInterpolate1("", ctx_r1.MinScorePercent, "%");
|
|
184
|
+
i0.ɵɵadvance();
|
|
185
|
+
i0.ɵɵconditional(ctx_r1.ServerMinScorePercent > 0 ? 9 : -1);
|
|
186
|
+
} }
|
|
187
|
+
function SearchFilterComponent_Conditional_12_Template(rf, ctx) { if (rf & 1) {
|
|
188
|
+
i0.ɵɵelementStart(0, "div", 9)(1, "p");
|
|
101
189
|
i0.ɵɵtext(2, "No filters available");
|
|
102
190
|
i0.ɵɵelementEnd()();
|
|
103
191
|
} }
|
|
@@ -109,8 +197,16 @@ export class SearchFilterComponent {
|
|
|
109
197
|
ActiveFilters = {};
|
|
110
198
|
/** Whether the filter panel is collapsible */
|
|
111
199
|
Collapsible = true;
|
|
200
|
+
/** Whether to show the min relevance slider */
|
|
201
|
+
ShowRelevanceSlider = true;
|
|
202
|
+
/** Current minimum score as a percentage (0-100) */
|
|
203
|
+
MinScorePercent = 0;
|
|
204
|
+
/** The MinScore that was last sent to the server (for visual indicator) */
|
|
205
|
+
ServerMinScorePercent = 0;
|
|
112
206
|
FilterChanged = new EventEmitter();
|
|
113
207
|
FiltersCleared = new EventEmitter();
|
|
208
|
+
CloseRequested = new EventEmitter();
|
|
209
|
+
MinScoreChanged = new EventEmitter();
|
|
114
210
|
/** Collapsed state per category */
|
|
115
211
|
CollapsedCategories = new Set();
|
|
116
212
|
/** Toggle a filter option */
|
|
@@ -162,39 +258,94 @@ export class SearchFilterComponent {
|
|
|
162
258
|
this.FiltersCleared.emit();
|
|
163
259
|
this.cdr.detectChanges();
|
|
164
260
|
}
|
|
261
|
+
/** Select all options in a category, or clear all if already all selected */
|
|
262
|
+
SelectAll(category) {
|
|
263
|
+
const filter = this.Filters.find(f => f.Category === category);
|
|
264
|
+
if (!filter)
|
|
265
|
+
return;
|
|
266
|
+
const current = this.ActiveFilters[category] ?? [];
|
|
267
|
+
if (current.length === filter.Options.length) {
|
|
268
|
+
// All selected → clear
|
|
269
|
+
this.ActiveFilters[category] = [];
|
|
270
|
+
}
|
|
271
|
+
else {
|
|
272
|
+
// Select all
|
|
273
|
+
this.ActiveFilters[category] = filter.Options.map(o => o.Value);
|
|
274
|
+
}
|
|
275
|
+
this.FilterChanged.emit({ Category: category, SelectedValues: this.ActiveFilters[category] });
|
|
276
|
+
this.cdr.detectChanges();
|
|
277
|
+
}
|
|
278
|
+
/** Check if all options in a category are selected */
|
|
279
|
+
IsAllSelected(category) {
|
|
280
|
+
const filter = this.Filters.find(f => f.Category === category);
|
|
281
|
+
if (!filter)
|
|
282
|
+
return false;
|
|
283
|
+
const selection = this.ActiveFilters[category] ?? [];
|
|
284
|
+
return selection.length === filter.Options.length;
|
|
285
|
+
}
|
|
286
|
+
/** Handle relevance slider drag (preview only — updates display without triggering search) */
|
|
287
|
+
OnMinScorePreview(value) {
|
|
288
|
+
this.MinScorePercent = parseInt(value, 10);
|
|
289
|
+
}
|
|
290
|
+
/** Handle relevance slider release — commits the value and triggers re-query if needed */
|
|
291
|
+
OnMinScoreCommit() {
|
|
292
|
+
this.MinScoreChanged.emit(this.MinScorePercent);
|
|
293
|
+
}
|
|
294
|
+
/** Handle relevance slider change (legacy — used when input event fires) */
|
|
295
|
+
OnMinScoreChange(value) {
|
|
296
|
+
this.MinScorePercent = parseInt(value, 10);
|
|
297
|
+
this.MinScoreChanged.emit(this.MinScorePercent);
|
|
298
|
+
}
|
|
165
299
|
static ɵfac = function SearchFilterComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || SearchFilterComponent)(); };
|
|
166
|
-
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: SearchFilterComponent, selectors: [["mj-search-filter"]], inputs: { Filters: "Filters", ActiveFilters: "ActiveFilters", Collapsible: "Collapsible" }, outputs: { FilterChanged: "FilterChanged", FiltersCleared: "FiltersCleared" }, standalone: false, decls:
|
|
300
|
+
static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: SearchFilterComponent, selectors: [["mj-search-filter"]], inputs: { Filters: "Filters", ActiveFilters: "ActiveFilters", Collapsible: "Collapsible", ShowRelevanceSlider: "ShowRelevanceSlider", MinScorePercent: "MinScorePercent", ServerMinScorePercent: "ServerMinScorePercent" }, outputs: { FilterChanged: "FilterChanged", FiltersCleared: "FiltersCleared", CloseRequested: "CloseRequested", MinScoreChanged: "MinScoreChanged" }, standalone: false, decls: 13, vars: 3, consts: [[1, "filter-panel"], [1, "filter-panel-header"], [1, "filter-panel-title"], [1, "fa-solid", "fa-filter"], [1, "filter-header-actions"], [1, "filter-clear-all"], ["title", "Hide filters", 1, "filter-close-btn", 3, "click"], [1, "fa-solid", "fa-times"], [1, "filter-category"], [1, "filter-empty"], [1, "filter-clear-all", 3, "click"], [1, "filter-category-header-row"], [1, "filter-category-header", 3, "click"], [1, "filter-category-name"], [1, "fa-solid", "filter-category-chevron", 3, "fa-chevron-down", "fa-chevron-up"], [1, "filter-select-all", 3, "title"], [1, "filter-options"], [1, "fa-solid", "filter-category-chevron"], [1, "filter-select-all", 3, "click", "title"], [1, "filter-option", "filter-option-readonly"], [1, "filter-option"], [3, "class"], [1, "filter-option-label"], [1, "filter-option-count"], [1, "filter-option", 3, "click"], [1, "filter-checkbox"], [1, "fa-solid", "fa-check"], [1, "filter-category-header"], [1, "filter-relevance-slider"], ["type", "range", "min", "0", "max", "100", "step", "5", 1, "relevance-range", 3, "input", "mouseup", "touchend", "value"], [1, "relevance-value"], [1, "filter-server-threshold"], [1, "server-threshold-label"], [1, "server-threshold-warning"], [1, "fa-solid", "fa-arrow-rotate-right"]], template: function SearchFilterComponent_Template(rf, ctx) { if (rf & 1) {
|
|
167
301
|
i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "span", 2);
|
|
168
302
|
i0.ɵɵelement(3, "i", 3);
|
|
169
303
|
i0.ɵɵtext(4, " Filters ");
|
|
170
304
|
i0.ɵɵelementEnd();
|
|
171
|
-
i0.ɵɵ
|
|
172
|
-
i0.ɵɵ
|
|
173
|
-
i0.ɵɵ
|
|
174
|
-
i0.ɵɵ
|
|
305
|
+
i0.ɵɵelementStart(5, "div", 4);
|
|
306
|
+
i0.ɵɵconditionalCreate(6, SearchFilterComponent_Conditional_6_Template, 2, 1, "button", 5);
|
|
307
|
+
i0.ɵɵelementStart(7, "button", 6);
|
|
308
|
+
i0.ɵɵlistener("click", function SearchFilterComponent_Template_button_click_7_listener() { return ctx.CloseRequested.emit(); });
|
|
309
|
+
i0.ɵɵelement(8, "i", 7);
|
|
310
|
+
i0.ɵɵelementEnd()()();
|
|
311
|
+
i0.ɵɵrepeaterCreate(9, SearchFilterComponent_For_10_Template, 8, 6, "div", 8, _forTrack0);
|
|
312
|
+
i0.ɵɵconditionalCreate(11, SearchFilterComponent_Conditional_11_Template, 10, 3, "div", 8);
|
|
313
|
+
i0.ɵɵconditionalCreate(12, SearchFilterComponent_Conditional_12_Template, 3, 0, "div", 9);
|
|
175
314
|
i0.ɵɵelementEnd();
|
|
176
315
|
} if (rf & 2) {
|
|
177
|
-
i0.ɵɵadvance(
|
|
178
|
-
i0.ɵɵconditional(ctx.HasActiveFilters() ?
|
|
179
|
-
i0.ɵɵadvance();
|
|
316
|
+
i0.ɵɵadvance(6);
|
|
317
|
+
i0.ɵɵconditional(ctx.HasActiveFilters() ? 6 : -1);
|
|
318
|
+
i0.ɵɵadvance(3);
|
|
180
319
|
i0.ɵɵrepeater(ctx.Filters);
|
|
181
320
|
i0.ɵɵadvance(2);
|
|
182
|
-
i0.ɵɵconditional(ctx.
|
|
183
|
-
|
|
321
|
+
i0.ɵɵconditional(ctx.ShowRelevanceSlider ? 11 : -1);
|
|
322
|
+
i0.ɵɵadvance();
|
|
323
|
+
i0.ɵɵconditional(ctx.Filters.length === 0 && !ctx.ShowRelevanceSlider ? 12 : -1);
|
|
324
|
+
} }, styles: ["\n\n\n.filter-panel[_ngcontent-%COMP%] {\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n background: var(--mj-bg-surface);\n overflow: hidden;\n}\n\n.filter-panel-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.75rem 1rem;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.filter-panel-title[_ngcontent-%COMP%] {\n font-weight: 600;\n font-size: 0.85rem;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n\n.filter-clear-all[_ngcontent-%COMP%] {\n border: none;\n background: none;\n color: var(--mj-brand-primary);\n font-size: 0.78rem;\n cursor: pointer;\n padding: 0.15rem 0.4rem;\n border-radius: 4px;\n}\n\n.filter-clear-all[_ngcontent-%COMP%]:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.filter-header-actions[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.filter-close-btn[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n border: none;\n border-radius: 4px;\n background: none;\n color: var(--mj-text-muted);\n font-size: 0.75rem;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.filter-close-btn[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n\n\n.filter-category[_ngcontent-%COMP%] {\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.filter-category[_ngcontent-%COMP%]:last-child {\n border-bottom: none;\n}\n\n.filter-category-header-row[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n}\n\n.filter-category-header[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.6rem 1rem;\n cursor: pointer;\n transition: background 0.1s ease;\n flex: 1;\n}\n\n.filter-category-header[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.filter-select-all[_ngcontent-%COMP%] {\n padding: 2px 8px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n background: none;\n color: var(--mj-text-muted);\n font-size: 0.65rem;\n font-weight: 500;\n cursor: pointer;\n margin-right: 8px;\n transition: color 0.15s ease, border-color 0.15s ease;\n}\n\n.filter-select-all[_ngcontent-%COMP%]:hover {\n color: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.filter-category-name[_ngcontent-%COMP%] {\n font-weight: 500;\n font-size: 0.82rem;\n color: var(--mj-text-primary);\n}\n\n.filter-category-chevron[_ngcontent-%COMP%] {\n font-size: 0.65rem;\n color: var(--mj-text-muted);\n}\n\n\n\n.filter-options[_ngcontent-%COMP%] {\n padding: 0.25rem 0;\n}\n\n.filter-option[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.4rem 1rem;\n cursor: pointer;\n transition: background 0.1s ease;\n font-size: 0.82rem;\n}\n\n.filter-option[_ngcontent-%COMP%]:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.filter-option-readonly[_ngcontent-%COMP%] {\n cursor: default;\n opacity: 0.85;\n}\n.filter-option-readonly[_ngcontent-%COMP%]:hover {\n background: transparent;\n}\n\n.filter-checkbox[_ngcontent-%COMP%] {\n width: 1rem;\n height: 1rem;\n border: 1.5px solid var(--mj-border-strong);\n border-radius: 3px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n font-size: 0.6rem;\n transition: all 0.15s ease;\n}\n\n.filter-checkbox-checked[_ngcontent-%COMP%] {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.filter-option-icon[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: 0.78rem;\n width: 1rem;\n text-align: center;\n}\n\n.filter-option-label[_ngcontent-%COMP%] {\n flex: 1;\n color: var(--mj-text-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.filter-option-count[_ngcontent-%COMP%] {\n color: var(--mj-text-muted);\n font-size: 0.72rem;\n flex-shrink: 0;\n}\n\n\n\n.filter-empty[_ngcontent-%COMP%] {\n padding: 1.5rem 1rem;\n text-align: center;\n color: var(--mj-text-muted);\n font-size: 0.82rem;\n}\n\n\n\n.filter-relevance-slider[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px 12px;\n}\n.relevance-range[_ngcontent-%COMP%] {\n flex: 1;\n height: 4px;\n -webkit-appearance: none;\n appearance: none;\n background: var(--mj-border-default);\n border-radius: 2px;\n outline: none;\n cursor: pointer;\n}\n.relevance-range[_ngcontent-%COMP%]::-webkit-slider-thumb {\n -webkit-appearance: none;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: var(--mj-brand-primary);\n cursor: pointer;\n border: 2px solid var(--mj-bg-surface);\n box-shadow: 0 1px 3px rgba(0,0,0,0.2);\n}\n.relevance-range[_ngcontent-%COMP%]::-moz-range-thumb {\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: var(--mj-brand-primary);\n cursor: pointer;\n border: 2px solid var(--mj-bg-surface);\n box-shadow: 0 1px 3px rgba(0,0,0,0.2);\n}\n.relevance-value[_ngcontent-%COMP%] {\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-brand-primary);\n min-width: 36px;\n text-align: right;\n}\n\n\n\n.filter-server-threshold[_ngcontent-%COMP%] {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 2px 12px 6px;\n font-size: 10px;\n color: var(--mj-text-muted);\n}\n.server-threshold-warning[_ngcontent-%COMP%] {\n color: var(--mj-status-warning-text, var(--mj-status-warning));\n font-weight: 600;\n}"] });
|
|
184
325
|
}
|
|
185
326
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(SearchFilterComponent, [{
|
|
186
327
|
type: Component,
|
|
187
|
-
args: [{ standalone: false, selector: 'mj-search-filter', template: "<div class=\"filter-panel\">\n <div class=\"filter-panel-header\">\n <span class=\"filter-panel-title\">\n <i class=\"fa-solid fa-filter\"></i> Filters\n </span>\n @if (HasActiveFilters()) {\n <button class=\"filter-clear-all\" (click)=\"ClearAll()\">\n Clear ({{ GetActiveFilterCount() }})\n </button>\n }\n </div>\n\n @for (filter of Filters; track filter.Category) {\n <div class=\"filter-category\">\n <div\n class=\"filter-category-header\"\n (click)=\"ToggleCategory(filter.Category)\"\n [class.filter-category-collapsed]=\"IsCategoryCollapsed(filter.Category)\"\n >\n <span class=\"filter-category-name\">{{ filter.Category }}</span>\n @if (Collapsible) {\n <i class=\"fa-solid filter-category-chevron\"\n [class.fa-chevron-down]=\"IsCategoryCollapsed(filter.Category)\"\n [class.fa-chevron-up]=\"!IsCategoryCollapsed(filter.Category)\"></i>\n }\n </div>\n\n @if (!IsCategoryCollapsed(filter.Category)) {\n <div class=\"filter-options\">\n @for (option of filter.Options; track option.Value) {\n <label class=\"filter-option\" (click)=\"ToggleOption(filter.Category, option.Value); $event.preventDefault()\">\n <span class=\"filter-checkbox\" [class.filter-checkbox-checked]=\"IsOptionSelected(filter.Category, option.Value)\">\n @if (IsOptionSelected(filter.Category, option.Value)) {\n <i class=\"fa-solid fa-check\"></i>\n }\n </span>\n @if (option.Icon) {\n <i [class]=\"option.Icon + ' filter-option-icon'\"></i>\n }\n <span class=\"filter-option-label\">{{ option.Label }}</span>\n <span class=\"filter-option-count\">{{ option.Count }}</span>\n </label>\n }\n </div>\n }\n </div>\n }\n\n @if (Filters.length === 0) {\n <div class=\"filter-empty\">\n <p>No filters available</p>\n </div>\n }\n</div>\n", styles: ["/* Search Filter Panel */\n\n.filter-panel {\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n background: var(--mj-bg-surface);\n overflow: hidden;\n}\n\n.filter-panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.75rem 1rem;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.filter-panel-title {\n font-weight: 600;\n font-size: 0.85rem;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n\n.filter-clear-all {\n border: none;\n background: none;\n color: var(--mj-brand-primary);\n font-size: 0.78rem;\n cursor: pointer;\n padding: 0.15rem 0.4rem;\n border-radius: 4px;\n}\n\n.filter-clear-all:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n/* Category */\n.filter-category {\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.filter-category:last-child {\n border-bottom: none;\n}\n\n.filter-category-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.6rem 1rem;\n cursor: pointer;\n transition: background 0.1s ease;\n}\n\n.filter-category-header:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.filter-category-name {\n font-weight: 500;\n font-size: 0.82rem;\n color: var(--mj-text-primary);\n}\n\n.filter-category-chevron {\n font-size: 0.65rem;\n color: var(--mj-text-muted);\n}\n\n/* Options */\n.filter-options {\n padding: 0.25rem 0;\n}\n\n.filter-option {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.4rem 1rem;\n cursor: pointer;\n transition: background 0.1s ease;\n font-size: 0.82rem;\n}\n\n.filter-option:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.filter-checkbox {\n width: 1rem;\n height: 1rem;\n border: 1.5px solid var(--mj-border-strong);\n border-radius: 3px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n font-size: 0.6rem;\n transition: all 0.15s ease;\n}\n\n.filter-checkbox-checked {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.filter-option-icon {\n color: var(--mj-text-muted);\n font-size: 0.78rem;\n width: 1rem;\n text-align: center;\n}\n\n.filter-option-label {\n flex: 1;\n color: var(--mj-text-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.filter-option-count {\n color: var(--mj-text-muted);\n font-size: 0.72rem;\n flex-shrink: 0;\n}\n\n/* Empty state */\n.filter-empty {\n padding: 1.5rem 1rem;\n text-align: center;\n color: var(--mj-text-muted);\n font-size: 0.82rem;\n}\n"] }]
|
|
328
|
+
args: [{ standalone: false, selector: 'mj-search-filter', template: "<div class=\"filter-panel\">\n <div class=\"filter-panel-header\">\n <span class=\"filter-panel-title\">\n <i class=\"fa-solid fa-filter\"></i> Filters\n </span>\n <div class=\"filter-header-actions\">\n @if (HasActiveFilters()) {\n <button class=\"filter-clear-all\" (click)=\"ClearAll()\">\n Clear ({{ GetActiveFilterCount() }})\n </button>\n }\n <button class=\"filter-close-btn\" (click)=\"CloseRequested.emit()\" title=\"Hide filters\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n </div>\n\n @for (filter of Filters; track filter.Category) {\n <div class=\"filter-category\">\n <div class=\"filter-category-header-row\">\n <div\n class=\"filter-category-header\"\n (click)=\"ToggleCategory(filter.Category)\"\n [class.filter-category-collapsed]=\"IsCategoryCollapsed(filter.Category)\"\n >\n <span class=\"filter-category-name\">{{ filter.Category }}</span>\n @if (Collapsible) {\n <i class=\"fa-solid filter-category-chevron\"\n [class.fa-chevron-down]=\"IsCategoryCollapsed(filter.Category)\"\n [class.fa-chevron-up]=\"!IsCategoryCollapsed(filter.Category)\"></i>\n }\n </div>\n @if (!IsCategoryCollapsed(filter.Category) && filter.Options.length > 1) {\n <button class=\"filter-select-all\"\n (click)=\"SelectAll(filter.Category); $event.stopPropagation()\"\n [title]=\"IsAllSelected(filter.Category) ? 'Clear all' : 'Select all'\">\n {{ IsAllSelected(filter.Category) ? 'Clear' : 'All' }}\n </button>\n }\n </div>\n\n @if (!IsCategoryCollapsed(filter.Category)) {\n <div class=\"filter-options\">\n @for (option of filter.Options; track option.Value) {\n @if (filter.Options.length === 1) {\n <!-- Single option: read-only label (no checkbox, not interactive) -->\n <div class=\"filter-option filter-option-readonly\">\n @if (option.Icon) {\n <i [class]=\"option.Icon + ' filter-option-icon'\"></i>\n }\n <span class=\"filter-option-label\">{{ option.Label }}</span>\n <span class=\"filter-option-count\">{{ option.Count }}</span>\n </div>\n } @else {\n <label class=\"filter-option\" (click)=\"ToggleOption(filter.Category, option.Value); $event.preventDefault()\">\n <span class=\"filter-checkbox\" [class.filter-checkbox-checked]=\"IsOptionSelected(filter.Category, option.Value)\">\n @if (IsOptionSelected(filter.Category, option.Value)) {\n <i class=\"fa-solid fa-check\"></i>\n }\n </span>\n @if (option.Icon) {\n <i [class]=\"option.Icon + ' filter-option-icon'\"></i>\n }\n <span class=\"filter-option-label\">{{ option.Label }}</span>\n <span class=\"filter-option-count\">{{ option.Count }}</span>\n </label>\n }\n }\n </div>\n }\n </div>\n }\n\n <!-- Relevance Threshold Slider -->\n @if (ShowRelevanceSlider) {\n <div class=\"filter-category\">\n <div class=\"filter-category-header-row\">\n <div class=\"filter-category-header\">\n <span class=\"filter-category-name\">Min Relevance</span>\n </div>\n </div>\n <div class=\"filter-relevance-slider\">\n <input\n type=\"range\"\n min=\"0\" max=\"100\" step=\"5\"\n [value]=\"MinScorePercent\"\n (input)=\"OnMinScorePreview($any($event.target).value)\"\n (mouseup)=\"OnMinScoreCommit()\"\n (touchend)=\"OnMinScoreCommit()\"\n class=\"relevance-range\" />\n <span class=\"relevance-value\">{{ MinScorePercent }}%</span>\n </div>\n @if (ServerMinScorePercent > 0) {\n <div class=\"filter-server-threshold\">\n <span class=\"server-threshold-label\">Server threshold: {{ ServerMinScorePercent }}%</span>\n @if (MinScorePercent < ServerMinScorePercent) {\n <span class=\"server-threshold-warning\">\n <i class=\"fa-solid fa-arrow-rotate-right\"></i> Will re-query\n </span>\n }\n </div>\n }\n </div>\n }\n\n @if (Filters.length === 0 && !ShowRelevanceSlider) {\n <div class=\"filter-empty\">\n <p>No filters available</p>\n </div>\n }\n</div>\n", styles: ["/* Search Filter Panel */\n\n.filter-panel {\n border: 1px solid var(--mj-border-default);\n border-radius: 8px;\n background: var(--mj-bg-surface);\n overflow: hidden;\n}\n\n.filter-panel-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.75rem 1rem;\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.filter-panel-title {\n font-weight: 600;\n font-size: 0.85rem;\n color: var(--mj-text-primary);\n display: flex;\n align-items: center;\n gap: 0.5rem;\n}\n\n.filter-clear-all {\n border: none;\n background: none;\n color: var(--mj-brand-primary);\n font-size: 0.78rem;\n cursor: pointer;\n padding: 0.15rem 0.4rem;\n border-radius: 4px;\n}\n\n.filter-clear-all:hover {\n background: color-mix(in srgb, var(--mj-brand-primary) 10%, var(--mj-bg-surface));\n}\n\n.filter-header-actions {\n display: flex;\n align-items: center;\n gap: 6px;\n}\n\n.filter-close-btn {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 24px;\n border: none;\n border-radius: 4px;\n background: none;\n color: var(--mj-text-muted);\n font-size: 0.75rem;\n cursor: pointer;\n transition: all 0.15s;\n}\n\n.filter-close-btn:hover {\n background: var(--mj-bg-surface-hover);\n color: var(--mj-text-primary);\n}\n\n/* Category */\n.filter-category {\n border-bottom: 1px solid var(--mj-border-subtle);\n}\n\n.filter-category:last-child {\n border-bottom: none;\n}\n\n.filter-category-header-row {\n display: flex;\n align-items: center;\n}\n\n.filter-category-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 0.6rem 1rem;\n cursor: pointer;\n transition: background 0.1s ease;\n flex: 1;\n}\n\n.filter-category-header:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.filter-select-all {\n padding: 2px 8px;\n border: 1px solid var(--mj-border-default);\n border-radius: 4px;\n background: none;\n color: var(--mj-text-muted);\n font-size: 0.65rem;\n font-weight: 500;\n cursor: pointer;\n margin-right: 8px;\n transition: color 0.15s ease, border-color 0.15s ease;\n}\n\n.filter-select-all:hover {\n color: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n}\n\n.filter-category-name {\n font-weight: 500;\n font-size: 0.82rem;\n color: var(--mj-text-primary);\n}\n\n.filter-category-chevron {\n font-size: 0.65rem;\n color: var(--mj-text-muted);\n}\n\n/* Options */\n.filter-options {\n padding: 0.25rem 0;\n}\n\n.filter-option {\n display: flex;\n align-items: center;\n gap: 0.5rem;\n padding: 0.4rem 1rem;\n cursor: pointer;\n transition: background 0.1s ease;\n font-size: 0.82rem;\n}\n\n.filter-option:hover {\n background: var(--mj-bg-surface-hover);\n}\n\n.filter-option-readonly {\n cursor: default;\n opacity: 0.85;\n}\n.filter-option-readonly:hover {\n background: transparent;\n}\n\n.filter-checkbox {\n width: 1rem;\n height: 1rem;\n border: 1.5px solid var(--mj-border-strong);\n border-radius: 3px;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n font-size: 0.6rem;\n transition: all 0.15s ease;\n}\n\n.filter-checkbox-checked {\n background: var(--mj-brand-primary);\n border-color: var(--mj-brand-primary);\n color: var(--mj-text-inverse);\n}\n\n.filter-option-icon {\n color: var(--mj-text-muted);\n font-size: 0.78rem;\n width: 1rem;\n text-align: center;\n}\n\n.filter-option-label {\n flex: 1;\n color: var(--mj-text-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.filter-option-count {\n color: var(--mj-text-muted);\n font-size: 0.72rem;\n flex-shrink: 0;\n}\n\n/* Empty state */\n.filter-empty {\n padding: 1.5rem 1rem;\n text-align: center;\n color: var(--mj-text-muted);\n font-size: 0.82rem;\n}\n\n/* Relevance Slider */\n.filter-relevance-slider {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px 12px;\n}\n.relevance-range {\n flex: 1;\n height: 4px;\n -webkit-appearance: none;\n appearance: none;\n background: var(--mj-border-default);\n border-radius: 2px;\n outline: none;\n cursor: pointer;\n}\n.relevance-range::-webkit-slider-thumb {\n -webkit-appearance: none;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: var(--mj-brand-primary);\n cursor: pointer;\n border: 2px solid var(--mj-bg-surface);\n box-shadow: 0 1px 3px rgba(0,0,0,0.2);\n}\n.relevance-range::-moz-range-thumb {\n width: 16px;\n height: 16px;\n border-radius: 50%;\n background: var(--mj-brand-primary);\n cursor: pointer;\n border: 2px solid var(--mj-bg-surface);\n box-shadow: 0 1px 3px rgba(0,0,0,0.2);\n}\n.relevance-value {\n font-size: 12px;\n font-weight: 600;\n color: var(--mj-brand-primary);\n min-width: 36px;\n text-align: right;\n}\n\n/* Server threshold indicator */\n.filter-server-threshold {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 2px 12px 6px;\n font-size: 10px;\n color: var(--mj-text-muted);\n}\n.server-threshold-warning {\n color: var(--mj-status-warning-text, var(--mj-status-warning));\n font-weight: 600;\n}\n"] }]
|
|
188
329
|
}], null, { Filters: [{
|
|
189
330
|
type: Input
|
|
190
331
|
}], ActiveFilters: [{
|
|
191
332
|
type: Input
|
|
192
333
|
}], Collapsible: [{
|
|
193
334
|
type: Input
|
|
335
|
+
}], ShowRelevanceSlider: [{
|
|
336
|
+
type: Input
|
|
337
|
+
}], MinScorePercent: [{
|
|
338
|
+
type: Input
|
|
339
|
+
}], ServerMinScorePercent: [{
|
|
340
|
+
type: Input
|
|
194
341
|
}], FilterChanged: [{
|
|
195
342
|
type: Output
|
|
196
343
|
}], FiltersCleared: [{
|
|
197
344
|
type: Output
|
|
345
|
+
}], CloseRequested: [{
|
|
346
|
+
type: Output
|
|
347
|
+
}], MinScoreChanged: [{
|
|
348
|
+
type: Output
|
|
198
349
|
}] }); })();
|
|
199
350
|
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(SearchFilterComponent, { className: "SearchFilterComponent", filePath: "src/lib/search-filter.component.ts", lineNumber: 24 }); })();
|
|
200
351
|
//# sourceMappingURL=search-filter.component.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-filter.component.js","sourceRoot":"","sources":["../../src/lib/search-filter.component.ts","../../src/lib/search-filter.component.html"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Search Filter Component\n *\n * Faceted filter sidebar for narrowing search results.\n * Displays filter categories with checkable options and counts.\n */\n\nimport {\n Component,\n EventEmitter,\n Input,\n Output,\n ChangeDetectorRef,\n inject\n} from '@angular/core';\nimport { SearchFilter, SearchFilterChangeEvent } from './search-types';\n\n@Component({\n standalone: false,\n selector: 'mj-search-filter',\n templateUrl: './search-filter.component.html',\n styleUrls: ['./search-filter.component.css']\n})\nexport class SearchFilterComponent {\n private cdr = inject(ChangeDetectorRef);\n\n /** Available filters to display */\n @Input() Filters: SearchFilter[] = [];\n\n /** Currently active filter selections */\n @Input() ActiveFilters: Record<string, string[]> = {};\n\n /** Whether the filter panel is collapsible */\n @Input() Collapsible = true;\n\n @Output() FilterChanged = new EventEmitter<SearchFilterChangeEvent>();\n @Output() FiltersCleared = new EventEmitter<void>();\n\n /** Collapsed state per category */\n public CollapsedCategories = new Set<string>();\n\n /** Toggle a filter option */\n public ToggleOption(category: string, value: string): void {\n const current = this.ActiveFilters[category] ? [...this.ActiveFilters[category]] : [];\n const index = current.indexOf(value);\n if (index >= 0) {\n current.splice(index, 1);\n } else {\n current.push(value);\n }\n // Update local state to reflect change\n this.ActiveFilters = { ...this.ActiveFilters, [category]: current };\n this.FilterChanged.emit({ Category: category, SelectedValues: current });\n this.cdr.detectChanges();\n }\n\n /** Toggle category collapse */\n public ToggleCategory(category: string): void {\n if (!this.Collapsible) return;\n if (this.CollapsedCategories.has(category)) {\n this.CollapsedCategories.delete(category);\n } else {\n this.CollapsedCategories.add(category);\n }\n this.cdr.detectChanges();\n }\n\n /** Check if a category is collapsed */\n public IsCategoryCollapsed(category: string): boolean {\n return this.CollapsedCategories.has(category);\n }\n\n /** Check if an option is selected */\n public IsOptionSelected(category: string, value: string): boolean {\n return (this.ActiveFilters[category] ?? []).includes(value);\n }\n\n /** Check if any filters are active */\n public HasActiveFilters(): boolean {\n return Object.values(this.ActiveFilters).some(v => v.length > 0);\n }\n\n /** Get total active filter count */\n public GetActiveFilterCount(): number {\n return Object.values(this.ActiveFilters).reduce((sum, v) => sum + v.length, 0);\n }\n\n /** Clear all filters */\n public ClearAll(): void {\n this.ActiveFilters = {};\n this.FiltersCleared.emit();\n this.cdr.detectChanges();\n }\n}\n","<div class=\"filter-panel\">\n <div class=\"filter-panel-header\">\n <span class=\"filter-panel-title\">\n <i class=\"fa-solid fa-filter\"></i> Filters\n </span>\n @if (HasActiveFilters()) {\n <button class=\"filter-clear-all\" (click)=\"ClearAll()\">\n Clear ({{ GetActiveFilterCount() }})\n </button>\n }\n </div>\n\n @for (filter of Filters; track filter.Category) {\n <div class=\"filter-category\">\n <div\n class=\"filter-category-header\"\n (click)=\"ToggleCategory(filter.Category)\"\n [class.filter-category-collapsed]=\"IsCategoryCollapsed(filter.Category)\"\n >\n <span class=\"filter-category-name\">{{ filter.Category }}</span>\n @if (Collapsible) {\n <i class=\"fa-solid filter-category-chevron\"\n [class.fa-chevron-down]=\"IsCategoryCollapsed(filter.Category)\"\n [class.fa-chevron-up]=\"!IsCategoryCollapsed(filter.Category)\"></i>\n }\n </div>\n\n @if (!IsCategoryCollapsed(filter.Category)) {\n <div class=\"filter-options\">\n @for (option of filter.Options; track option.Value) {\n <label class=\"filter-option\" (click)=\"ToggleOption(filter.Category, option.Value); $event.preventDefault()\">\n <span class=\"filter-checkbox\" [class.filter-checkbox-checked]=\"IsOptionSelected(filter.Category, option.Value)\">\n @if (IsOptionSelected(filter.Category, option.Value)) {\n <i class=\"fa-solid fa-check\"></i>\n }\n </span>\n @if (option.Icon) {\n <i [class]=\"option.Icon + ' filter-option-icon'\"></i>\n }\n <span class=\"filter-option-label\">{{ option.Label }}</span>\n <span class=\"filter-option-count\">{{ option.Count }}</span>\n </label>\n }\n </div>\n }\n </div>\n }\n\n @if (Filters.length === 0) {\n <div class=\"filter-empty\">\n <p>No filters available</p>\n </div>\n }\n</div>\n"]}
|
|
1
|
+
{"version":3,"file":"search-filter.component.js","sourceRoot":"","sources":["../../src/lib/search-filter.component.ts","../../src/lib/search-filter.component.html"],"names":[],"mappings":"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","sourcesContent":["/**\n * @fileoverview Search Filter Component\n *\n * Faceted filter sidebar for narrowing search results.\n * Displays filter categories with checkable options and counts.\n */\n\nimport {\n Component,\n EventEmitter,\n Input,\n Output,\n ChangeDetectorRef,\n inject\n} from '@angular/core';\nimport { SearchFilter, SearchFilterChangeEvent } from './search-types';\n\n@Component({\n standalone: false,\n selector: 'mj-search-filter',\n templateUrl: './search-filter.component.html',\n styleUrls: ['./search-filter.component.css']\n})\nexport class SearchFilterComponent {\n private cdr = inject(ChangeDetectorRef);\n\n /** Available filters to display */\n @Input() Filters: SearchFilter[] = [];\n\n /** Currently active filter selections */\n @Input() ActiveFilters: Record<string, string[]> = {};\n\n /** Whether the filter panel is collapsible */\n @Input() Collapsible = true;\n\n /** Whether to show the min relevance slider */\n @Input() ShowRelevanceSlider = true;\n\n /** Current minimum score as a percentage (0-100) */\n @Input() MinScorePercent = 0;\n\n /** The MinScore that was last sent to the server (for visual indicator) */\n @Input() ServerMinScorePercent = 0;\n\n @Output() FilterChanged = new EventEmitter<SearchFilterChangeEvent>();\n @Output() FiltersCleared = new EventEmitter<void>();\n @Output() CloseRequested = new EventEmitter<void>();\n @Output() MinScoreChanged = new EventEmitter<number>();\n\n /** Collapsed state per category */\n public CollapsedCategories = new Set<string>();\n\n /** Toggle a filter option */\n public ToggleOption(category: string, value: string): void {\n const current = this.ActiveFilters[category] ? [...this.ActiveFilters[category]] : [];\n const index = current.indexOf(value);\n if (index >= 0) {\n current.splice(index, 1);\n } else {\n current.push(value);\n }\n // Update local state to reflect change\n this.ActiveFilters = { ...this.ActiveFilters, [category]: current };\n this.FilterChanged.emit({ Category: category, SelectedValues: current });\n this.cdr.detectChanges();\n }\n\n /** Toggle category collapse */\n public ToggleCategory(category: string): void {\n if (!this.Collapsible) return;\n if (this.CollapsedCategories.has(category)) {\n this.CollapsedCategories.delete(category);\n } else {\n this.CollapsedCategories.add(category);\n }\n this.cdr.detectChanges();\n }\n\n /** Check if a category is collapsed */\n public IsCategoryCollapsed(category: string): boolean {\n return this.CollapsedCategories.has(category);\n }\n\n /** Check if an option is selected */\n public IsOptionSelected(category: string, value: string): boolean {\n return (this.ActiveFilters[category] ?? []).includes(value);\n }\n\n /** Check if any filters are active */\n public HasActiveFilters(): boolean {\n return Object.values(this.ActiveFilters).some(v => v.length > 0);\n }\n\n /** Get total active filter count */\n public GetActiveFilterCount(): number {\n return Object.values(this.ActiveFilters).reduce((sum, v) => sum + v.length, 0);\n }\n\n /** Clear all filters */\n public ClearAll(): void {\n this.ActiveFilters = {};\n this.FiltersCleared.emit();\n this.cdr.detectChanges();\n }\n\n /** Select all options in a category, or clear all if already all selected */\n public SelectAll(category: string): void {\n const filter = this.Filters.find(f => f.Category === category);\n if (!filter) return;\n\n const current = this.ActiveFilters[category] ?? [];\n if (current.length === filter.Options.length) {\n // All selected → clear\n this.ActiveFilters[category] = [];\n } else {\n // Select all\n this.ActiveFilters[category] = filter.Options.map(o => o.Value);\n }\n this.FilterChanged.emit({ Category: category, SelectedValues: this.ActiveFilters[category] });\n this.cdr.detectChanges();\n }\n\n /** Check if all options in a category are selected */\n public IsAllSelected(category: string): boolean {\n const filter = this.Filters.find(f => f.Category === category);\n if (!filter) return false;\n const selection = this.ActiveFilters[category] ?? [];\n return selection.length === filter.Options.length;\n }\n\n /** Handle relevance slider drag (preview only — updates display without triggering search) */\n public OnMinScorePreview(value: string): void {\n this.MinScorePercent = parseInt(value, 10);\n }\n\n /** Handle relevance slider release — commits the value and triggers re-query if needed */\n public OnMinScoreCommit(): void {\n this.MinScoreChanged.emit(this.MinScorePercent);\n }\n\n /** Handle relevance slider change (legacy — used when input event fires) */\n public OnMinScoreChange(value: string): void {\n this.MinScorePercent = parseInt(value, 10);\n this.MinScoreChanged.emit(this.MinScorePercent);\n }\n}\n","<div class=\"filter-panel\">\n <div class=\"filter-panel-header\">\n <span class=\"filter-panel-title\">\n <i class=\"fa-solid fa-filter\"></i> Filters\n </span>\n <div class=\"filter-header-actions\">\n @if (HasActiveFilters()) {\n <button class=\"filter-clear-all\" (click)=\"ClearAll()\">\n Clear ({{ GetActiveFilterCount() }})\n </button>\n }\n <button class=\"filter-close-btn\" (click)=\"CloseRequested.emit()\" title=\"Hide filters\">\n <i class=\"fa-solid fa-times\"></i>\n </button>\n </div>\n </div>\n\n @for (filter of Filters; track filter.Category) {\n <div class=\"filter-category\">\n <div class=\"filter-category-header-row\">\n <div\n class=\"filter-category-header\"\n (click)=\"ToggleCategory(filter.Category)\"\n [class.filter-category-collapsed]=\"IsCategoryCollapsed(filter.Category)\"\n >\n <span class=\"filter-category-name\">{{ filter.Category }}</span>\n @if (Collapsible) {\n <i class=\"fa-solid filter-category-chevron\"\n [class.fa-chevron-down]=\"IsCategoryCollapsed(filter.Category)\"\n [class.fa-chevron-up]=\"!IsCategoryCollapsed(filter.Category)\"></i>\n }\n </div>\n @if (!IsCategoryCollapsed(filter.Category) && filter.Options.length > 1) {\n <button class=\"filter-select-all\"\n (click)=\"SelectAll(filter.Category); $event.stopPropagation()\"\n [title]=\"IsAllSelected(filter.Category) ? 'Clear all' : 'Select all'\">\n {{ IsAllSelected(filter.Category) ? 'Clear' : 'All' }}\n </button>\n }\n </div>\n\n @if (!IsCategoryCollapsed(filter.Category)) {\n <div class=\"filter-options\">\n @for (option of filter.Options; track option.Value) {\n @if (filter.Options.length === 1) {\n <!-- Single option: read-only label (no checkbox, not interactive) -->\n <div class=\"filter-option filter-option-readonly\">\n @if (option.Icon) {\n <i [class]=\"option.Icon + ' filter-option-icon'\"></i>\n }\n <span class=\"filter-option-label\">{{ option.Label }}</span>\n <span class=\"filter-option-count\">{{ option.Count }}</span>\n </div>\n } @else {\n <label class=\"filter-option\" (click)=\"ToggleOption(filter.Category, option.Value); $event.preventDefault()\">\n <span class=\"filter-checkbox\" [class.filter-checkbox-checked]=\"IsOptionSelected(filter.Category, option.Value)\">\n @if (IsOptionSelected(filter.Category, option.Value)) {\n <i class=\"fa-solid fa-check\"></i>\n }\n </span>\n @if (option.Icon) {\n <i [class]=\"option.Icon + ' filter-option-icon'\"></i>\n }\n <span class=\"filter-option-label\">{{ option.Label }}</span>\n <span class=\"filter-option-count\">{{ option.Count }}</span>\n </label>\n }\n }\n </div>\n }\n </div>\n }\n\n <!-- Relevance Threshold Slider -->\n @if (ShowRelevanceSlider) {\n <div class=\"filter-category\">\n <div class=\"filter-category-header-row\">\n <div class=\"filter-category-header\">\n <span class=\"filter-category-name\">Min Relevance</span>\n </div>\n </div>\n <div class=\"filter-relevance-slider\">\n <input\n type=\"range\"\n min=\"0\" max=\"100\" step=\"5\"\n [value]=\"MinScorePercent\"\n (input)=\"OnMinScorePreview($any($event.target).value)\"\n (mouseup)=\"OnMinScoreCommit()\"\n (touchend)=\"OnMinScoreCommit()\"\n class=\"relevance-range\" />\n <span class=\"relevance-value\">{{ MinScorePercent }}%</span>\n </div>\n @if (ServerMinScorePercent > 0) {\n <div class=\"filter-server-threshold\">\n <span class=\"server-threshold-label\">Server threshold: {{ ServerMinScorePercent }}%</span>\n @if (MinScorePercent < ServerMinScorePercent) {\n <span class=\"server-threshold-warning\">\n <i class=\"fa-solid fa-arrow-rotate-right\"></i> Will re-query\n </span>\n }\n </div>\n }\n </div>\n }\n\n @if (Filters.length === 0 && !ShowRelevanceSlider) {\n <div class=\"filter-empty\">\n <p>No filters available</p>\n </div>\n }\n</div>\n"]}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Search Input Component
|
|
3
|
+
*
|
|
4
|
+
* A reusable search text input for navbar/hero placement.
|
|
5
|
+
* Features debounced query emission, keyboard shortcut hint,
|
|
6
|
+
* clear button, and focus management.
|
|
7
|
+
*/
|
|
8
|
+
import { ElementRef, EventEmitter, OnDestroy, OnInit } from '@angular/core';
|
|
9
|
+
import * as i0 from "@angular/core";
|
|
10
|
+
export declare class SearchInputComponent implements OnInit, OnDestroy {
|
|
11
|
+
private cdr;
|
|
12
|
+
private destroy$;
|
|
13
|
+
private queryInput$;
|
|
14
|
+
inputRef: ElementRef<HTMLInputElement>;
|
|
15
|
+
/** Placeholder text shown in the input */
|
|
16
|
+
Placeholder: string;
|
|
17
|
+
/** Current query value (two-way bindable via QueryChange) */
|
|
18
|
+
private _Query;
|
|
19
|
+
set Query(value: string);
|
|
20
|
+
get Query(): string;
|
|
21
|
+
/** Whether to show the keyboard shortcut hint badge */
|
|
22
|
+
ShowShortcutHint: boolean;
|
|
23
|
+
/** Text to display in the shortcut hint badge */
|
|
24
|
+
ShortcutHint: string;
|
|
25
|
+
/** Debounce time in milliseconds before QueryChange emits */
|
|
26
|
+
DebounceMs: number;
|
|
27
|
+
/** Emitted after debounce when query text changes */
|
|
28
|
+
QueryChange: EventEmitter<string>;
|
|
29
|
+
/** Emitted immediately when the user presses Enter */
|
|
30
|
+
QuerySubmit: EventEmitter<string>;
|
|
31
|
+
/** Emitted when the input receives focus */
|
|
32
|
+
InputFocused: EventEmitter<void>;
|
|
33
|
+
/** Emitted when the input loses focus */
|
|
34
|
+
InputBlurred: EventEmitter<void>;
|
|
35
|
+
/** Emitted when the user presses Escape in the input */
|
|
36
|
+
InputEscaped: EventEmitter<void>;
|
|
37
|
+
/** Emitted when the user clears the input via the clear button */
|
|
38
|
+
InputCleared: EventEmitter<void>;
|
|
39
|
+
/** Whether the input currently has focus */
|
|
40
|
+
IsFocused: boolean;
|
|
41
|
+
ngOnInit(): void;
|
|
42
|
+
ngOnDestroy(): void;
|
|
43
|
+
/** Programmatically focus the input element */
|
|
44
|
+
Focus(): void;
|
|
45
|
+
/** Clear the query and emit InputCleared */
|
|
46
|
+
Clear(): void;
|
|
47
|
+
/** Handle native input event */
|
|
48
|
+
OnInput(value: string): void;
|
|
49
|
+
/** Handle keydown events on the input */
|
|
50
|
+
OnKeydown(event: KeyboardEvent): void;
|
|
51
|
+
/** Handle focus event */
|
|
52
|
+
OnFocus(): void;
|
|
53
|
+
/** Handle click — re-opens suggest when input already has focus */
|
|
54
|
+
OnClick(): void;
|
|
55
|
+
/** Handle blur event */
|
|
56
|
+
OnBlur(): void;
|
|
57
|
+
private setupDebounce;
|
|
58
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<SearchInputComponent, never>;
|
|
59
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<SearchInputComponent, "mj-search-input", never, { "Placeholder": { "alias": "Placeholder"; "required": false; }; "Query": { "alias": "Query"; "required": false; }; "ShowShortcutHint": { "alias": "ShowShortcutHint"; "required": false; }; "ShortcutHint": { "alias": "ShortcutHint"; "required": false; }; "DebounceMs": { "alias": "DebounceMs"; "required": false; }; }, { "QueryChange": "QueryChange"; "QuerySubmit": "QuerySubmit"; "InputFocused": "InputFocused"; "InputBlurred": "InputBlurred"; "InputEscaped": "InputEscaped"; "InputCleared": "InputCleared"; }, never, never, false, never>;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=search-input.component.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-input.component.d.ts","sourceRoot":"","sources":["../../src/lib/search-input.component.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAEH,UAAU,EACV,YAAY,EAEZ,SAAS,EACT,MAAM,EAKT,MAAM,eAAe,CAAC;;AAIvB,qBAMa,oBAAqB,YAAW,MAAM,EAAE,SAAS;IAC1D,OAAO,CAAC,GAAG,CAA6B;IACxC,OAAO,CAAC,QAAQ,CAAuB;IACvC,OAAO,CAAC,WAAW,CAAyB;IAEtB,QAAQ,EAAG,UAAU,CAAC,gBAAgB,CAAC,CAAC;IAI9D,0CAA0C;IACjC,WAAW,SAAe;IAEnC,6DAA6D;IAC7D,OAAO,CAAC,MAAM,CAAM;IAEpB,IACI,KAAK,CAAC,KAAK,EAAE,MAAM,EAKtB;IACD,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,uDAAuD;IAC9C,gBAAgB,UAAQ;IAEjC,iDAAiD;IACxC,YAAY,SAAY;IAEjC,6DAA6D;IACpD,UAAU,SAAO;IAI1B,qDAAqD;IAC3C,WAAW,uBAA8B;IAEnD,sDAAsD;IAC5C,WAAW,uBAA8B;IAEnD,4CAA4C;IAClC,YAAY,qBAA4B;IAElD,yCAAyC;IAC/B,YAAY,qBAA4B;IAElD,wDAAwD;IAC9C,YAAY,qBAA4B;IAElD,kEAAkE;IACxD,YAAY,qBAA4B;IAIlD,4CAA4C;IACrC,SAAS,UAAS;IAEzB,QAAQ,IAAI,IAAI;IAIhB,WAAW,IAAI,IAAI;IAOnB,+CAA+C;IACxC,KAAK,IAAI,IAAI;IAIpB,4CAA4C;IACrC,KAAK,IAAI,IAAI;IAWpB,gCAAgC;IACzB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAKnC,yCAAyC;IAClC,SAAS,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;IAa5C,yBAAyB;IAClB,OAAO,IAAI,IAAI;IAMtB,mEAAmE;IAC5D,OAAO,IAAI,IAAI;IAMtB,wBAAwB;IACjB,MAAM,IAAI,IAAI;IAQrB,OAAO,CAAC,aAAa;yCAnIZ,oBAAoB;2CAApB,oBAAoB;CA6IhC"}
|