@internetarchive/collection-browser 0.3.1-alpha.2 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (214) hide show
  1. package/.editorconfig +29 -29
  2. package/.github/workflows/ci.yml +26 -26
  3. package/.github/workflows/gh-pages-main.yml +39 -39
  4. package/.github/workflows/npm-publish.yml +39 -39
  5. package/.github/workflows/pr-preview.yml +38 -38
  6. package/.husky/pre-commit +4 -4
  7. package/LICENSE +661 -661
  8. package/README.md +83 -83
  9. package/dist/index.d.ts +9 -9
  10. package/dist/index.js +9 -9
  11. package/dist/src/app-root.d.ts +43 -43
  12. package/dist/src/app-root.js +233 -233
  13. package/dist/src/assets/img/icons/arrow-left.d.ts +2 -2
  14. package/dist/src/assets/img/icons/arrow-left.js +2 -2
  15. package/dist/src/assets/img/icons/arrow-right.d.ts +2 -2
  16. package/dist/src/assets/img/icons/arrow-right.js +2 -2
  17. package/dist/src/assets/img/icons/chevron.d.ts +2 -2
  18. package/dist/src/assets/img/icons/chevron.js +2 -2
  19. package/dist/src/assets/img/icons/empty-query.d.ts +2 -2
  20. package/dist/src/assets/img/icons/empty-query.js +2 -2
  21. package/dist/src/assets/img/icons/eye-closed.d.ts +2 -2
  22. package/dist/src/assets/img/icons/eye-closed.js +2 -2
  23. package/dist/src/assets/img/icons/eye.d.ts +2 -2
  24. package/dist/src/assets/img/icons/eye.js +2 -2
  25. package/dist/src/assets/img/icons/favorite-filled.d.ts +1 -1
  26. package/dist/src/assets/img/icons/favorite-filled.js +2 -2
  27. package/dist/src/assets/img/icons/login-required.d.ts +1 -1
  28. package/dist/src/assets/img/icons/login-required.js +2 -2
  29. package/dist/src/assets/img/icons/mediatype/account.d.ts +1 -1
  30. package/dist/src/assets/img/icons/mediatype/account.js +2 -2
  31. package/dist/src/assets/img/icons/mediatype/audio.d.ts +1 -1
  32. package/dist/src/assets/img/icons/mediatype/audio.js +2 -2
  33. package/dist/src/assets/img/icons/mediatype/collection.d.ts +1 -1
  34. package/dist/src/assets/img/icons/mediatype/collection.js +2 -2
  35. package/dist/src/assets/img/icons/mediatype/data.d.ts +1 -1
  36. package/dist/src/assets/img/icons/mediatype/data.js +2 -2
  37. package/dist/src/assets/img/icons/mediatype/etree.d.ts +1 -1
  38. package/dist/src/assets/img/icons/mediatype/etree.js +2 -2
  39. package/dist/src/assets/img/icons/mediatype/film.d.ts +1 -1
  40. package/dist/src/assets/img/icons/mediatype/film.js +2 -2
  41. package/dist/src/assets/img/icons/mediatype/images.d.ts +1 -1
  42. package/dist/src/assets/img/icons/mediatype/images.js +2 -2
  43. package/dist/src/assets/img/icons/mediatype/radio.d.ts +1 -1
  44. package/dist/src/assets/img/icons/mediatype/radio.js +2 -2
  45. package/dist/src/assets/img/icons/mediatype/software.d.ts +1 -1
  46. package/dist/src/assets/img/icons/mediatype/software.js +2 -2
  47. package/dist/src/assets/img/icons/mediatype/texts.d.ts +1 -1
  48. package/dist/src/assets/img/icons/mediatype/texts.js +2 -2
  49. package/dist/src/assets/img/icons/mediatype/tv.d.ts +1 -1
  50. package/dist/src/assets/img/icons/mediatype/tv.js +2 -2
  51. package/dist/src/assets/img/icons/mediatype/video.d.ts +1 -1
  52. package/dist/src/assets/img/icons/mediatype/video.js +2 -2
  53. package/dist/src/assets/img/icons/mediatype/web.d.ts +1 -1
  54. package/dist/src/assets/img/icons/mediatype/web.js +2 -2
  55. package/dist/src/assets/img/icons/null-result.d.ts +2 -2
  56. package/dist/src/assets/img/icons/null-result.js +2 -2
  57. package/dist/src/assets/img/icons/restricted.d.ts +1 -1
  58. package/dist/src/assets/img/icons/restricted.js +2 -2
  59. package/dist/src/assets/img/icons/reviews.d.ts +1 -1
  60. package/dist/src/assets/img/icons/reviews.js +2 -2
  61. package/dist/src/assets/img/icons/upload.d.ts +1 -1
  62. package/dist/src/assets/img/icons/upload.js +2 -2
  63. package/dist/src/assets/img/icons/views.d.ts +1 -1
  64. package/dist/src/assets/img/icons/views.js +2 -2
  65. package/dist/src/circular-activity-indicator.d.ts +5 -5
  66. package/dist/src/circular-activity-indicator.js +17 -17
  67. package/dist/src/collection-browser.d.ts +236 -236
  68. package/dist/src/collection-browser.js +1406 -1402
  69. package/dist/src/collection-browser.js.map +1 -1
  70. package/dist/src/collection-facets/facets-template.d.ts +16 -16
  71. package/dist/src/collection-facets/facets-template.js +132 -130
  72. package/dist/src/collection-facets/facets-template.js.map +1 -1
  73. package/dist/src/collection-facets/more-facets-content.d.ts +74 -74
  74. package/dist/src/collection-facets/more-facets-content.js +350 -339
  75. package/dist/src/collection-facets/more-facets-content.js.map +1 -1
  76. package/dist/src/collection-facets/more-facets-pagination.d.ts +36 -36
  77. package/dist/src/collection-facets/more-facets-pagination.js +192 -192
  78. package/dist/src/collection-facets.d.ts +71 -71
  79. package/dist/src/collection-facets.js +496 -496
  80. package/dist/src/collection-facets.js.map +1 -1
  81. package/dist/src/empty-placeholder.d.ts +11 -11
  82. package/dist/src/empty-placeholder.js +42 -42
  83. package/dist/src/language-code-handler/language-code-handler.d.ts +37 -37
  84. package/dist/src/language-code-handler/language-code-handler.js +26 -26
  85. package/dist/src/language-code-handler/language-code-mapping.d.ts +1 -1
  86. package/dist/src/language-code-handler/language-code-mapping.js +562 -562
  87. package/dist/src/mediatype/mediatype-config.d.ts +3 -3
  88. package/dist/src/mediatype/mediatype-config.js +85 -85
  89. package/dist/src/models.d.ts +97 -97
  90. package/dist/src/models.js +100 -100
  91. package/dist/src/models.js.map +1 -1
  92. package/dist/src/restoration-state-handler.d.ts +45 -46
  93. package/dist/src/restoration-state-handler.js +220 -231
  94. package/dist/src/restoration-state-handler.js.map +1 -1
  95. package/dist/src/sort-filter-bar/alpha-bar.d.ts +9 -9
  96. package/dist/src/sort-filter-bar/alpha-bar.js +41 -41
  97. package/dist/src/sort-filter-bar/img/compact.d.ts +1 -1
  98. package/dist/src/sort-filter-bar/img/compact.js +2 -2
  99. package/dist/src/sort-filter-bar/img/list.d.ts +1 -1
  100. package/dist/src/sort-filter-bar/img/list.js +2 -2
  101. package/dist/src/sort-filter-bar/img/sort-triangle.d.ts +1 -1
  102. package/dist/src/sort-filter-bar/img/sort-triangle.js +2 -2
  103. package/dist/src/sort-filter-bar/img/tile.d.ts +1 -1
  104. package/dist/src/sort-filter-bar/img/tile.js +2 -2
  105. package/dist/src/sort-filter-bar/sort-filter-bar.d.ts +107 -107
  106. package/dist/src/sort-filter-bar/sort-filter-bar.js +423 -423
  107. package/dist/src/styles/item-image-styles.d.ts +8 -8
  108. package/dist/src/styles/item-image-styles.js +9 -9
  109. package/dist/src/tiles/collection-browser-loading-tile.d.ts +5 -5
  110. package/dist/src/tiles/collection-browser-loading-tile.js +15 -15
  111. package/dist/src/tiles/grid/account-tile.d.ts +8 -8
  112. package/dist/src/tiles/grid/account-tile.js +20 -20
  113. package/dist/src/tiles/grid/collection-tile.d.ts +7 -7
  114. package/dist/src/tiles/grid/collection-tile.js +23 -23
  115. package/dist/src/tiles/grid/item-tile.d.ts +24 -24
  116. package/dist/src/tiles/grid/item-tile.js +87 -87
  117. package/dist/src/tiles/grid/tile-stats.d.ts +10 -10
  118. package/dist/src/tiles/grid/tile-stats.js +35 -35
  119. package/dist/src/tiles/image-block.d.ts +17 -17
  120. package/dist/src/tiles/image-block.js +73 -73
  121. package/dist/src/tiles/item-image.d.ts +31 -31
  122. package/dist/src/tiles/item-image.js +103 -103
  123. package/dist/src/tiles/list/account-label.d.ts +1 -1
  124. package/dist/src/tiles/list/account-label.js +6 -6
  125. package/dist/src/tiles/list/date-label.d.ts +1 -1
  126. package/dist/src/tiles/list/date-label.js +12 -12
  127. package/dist/src/tiles/list/tile-list-compact-header.d.ts +12 -12
  128. package/dist/src/tiles/list/tile-list-compact-header.js +41 -41
  129. package/dist/src/tiles/list/tile-list-compact.d.ts +20 -20
  130. package/dist/src/tiles/list/tile-list-compact.js +87 -87
  131. package/dist/src/tiles/list/tile-list.d.ts +50 -50
  132. package/dist/src/tiles/list/tile-list.js +264 -263
  133. package/dist/src/tiles/list/tile-list.js.map +1 -1
  134. package/dist/src/tiles/mediatype-icon.d.ts +9 -9
  135. package/dist/src/tiles/mediatype-icon.js +47 -47
  136. package/dist/src/tiles/overlay/icon-overlay.d.ts +7 -7
  137. package/dist/src/tiles/overlay/icon-overlay.js +31 -31
  138. package/dist/src/tiles/overlay/text-overlay.d.ts +8 -8
  139. package/dist/src/tiles/overlay/text-overlay.js +31 -31
  140. package/dist/src/tiles/text-snippet-block.d.ts +29 -29
  141. package/dist/src/tiles/text-snippet-block.js +81 -81
  142. package/dist/src/tiles/tile-dispatcher.d.ts +36 -36
  143. package/dist/src/tiles/tile-dispatcher.js +128 -128
  144. package/dist/src/utils/analytics-events.d.ts +18 -18
  145. package/dist/src/utils/analytics-events.js +20 -20
  146. package/dist/src/utils/format-count.d.ts +7 -7
  147. package/dist/src/utils/format-count.js +76 -75
  148. package/dist/src/utils/format-count.js.map +1 -1
  149. package/dist/src/utils/format-date.d.ts +2 -2
  150. package/dist/src/utils/format-date.js +23 -23
  151. package/dist/test/collection-browser.test.d.ts +1 -1
  152. package/dist/test/collection-browser.test.js +344 -344
  153. package/dist/test/collection-browser.test.js.map +1 -1
  154. package/dist/test/collection-facets/facets-template.test.d.ts +1 -1
  155. package/dist/test/collection-facets/facets-template.test.js +62 -62
  156. package/dist/test/collection-facets/more-facets-content.test.d.ts +1 -1
  157. package/dist/test/collection-facets/more-facets-content.test.js +91 -91
  158. package/dist/test/collection-facets/more-facets-pagination.test.d.ts +1 -1
  159. package/dist/test/collection-facets/more-facets-pagination.test.js +117 -117
  160. package/dist/test/collection-facets.test.d.ts +2 -2
  161. package/dist/test/collection-facets.test.js +385 -182
  162. package/dist/test/collection-facets.test.js.map +1 -1
  163. package/dist/test/empty-placeholder.test.d.ts +1 -1
  164. package/dist/test/empty-placeholder.test.js +33 -33
  165. package/dist/test/icon-overlay.test.d.ts +1 -1
  166. package/dist/test/icon-overlay.test.js +24 -24
  167. package/dist/test/item-image.test.d.ts +1 -1
  168. package/dist/test/item-image.test.js +56 -56
  169. package/dist/test/mediatype-config.test.d.ts +1 -1
  170. package/dist/test/mediatype-config.test.js +16 -16
  171. package/dist/test/mocks/mock-analytics-handler.d.ts +10 -10
  172. package/dist/test/mocks/mock-analytics-handler.js +15 -15
  173. package/dist/test/mocks/mock-collection-name-cache.d.ts +7 -7
  174. package/dist/test/mocks/mock-collection-name-cache.js +13 -13
  175. package/dist/test/mocks/mock-search-responses.d.ts +5 -5
  176. package/dist/test/mocks/mock-search-responses.js +103 -103
  177. package/dist/test/mocks/mock-search-service.d.ts +13 -13
  178. package/dist/test/mocks/mock-search-service.js +25 -25
  179. package/dist/test/restoration-state-handler.test.d.ts +1 -1
  180. package/dist/test/restoration-state-handler.test.js +117 -117
  181. package/dist/test/sort-filter-bar/sort-filter-bar.test.d.ts +1 -1
  182. package/dist/test/sort-filter-bar/sort-filter-bar.test.js +113 -113
  183. package/dist/test/text-overlay.test.d.ts +1 -1
  184. package/dist/test/text-overlay.test.js +41 -41
  185. package/dist/test/text-snippet-block.test.d.ts +1 -1
  186. package/dist/test/text-snippet-block.test.js +57 -57
  187. package/dist/test/tile-stats.test.d.ts +1 -1
  188. package/dist/test/tile-stats.test.js +33 -33
  189. package/dist/test/tiles/grid/item-tile.test.d.ts +1 -1
  190. package/dist/test/tiles/grid/item-tile.test.js +107 -107
  191. package/dist/test/tiles/list/tile-list.test.d.ts +1 -1
  192. package/dist/test/tiles/list/tile-list.test.js +36 -36
  193. package/dist/test/utils/format-count.test.d.ts +1 -1
  194. package/dist/test/utils/format-count.test.js +23 -23
  195. package/dist/test/utils/format-date.test.d.ts +1 -1
  196. package/dist/test/utils/format-date.test.js +17 -17
  197. package/index.html +24 -24
  198. package/local.archive.org.cert +86 -86
  199. package/local.archive.org.key +27 -27
  200. package/package.json +115 -115
  201. package/renovate.json +6 -6
  202. package/src/collection-browser.ts +1530 -1526
  203. package/src/collection-facets/facets-template.ts +7 -5
  204. package/src/collection-facets/more-facets-content.ts +21 -10
  205. package/src/collection-facets.ts +569 -569
  206. package/src/models.ts +216 -216
  207. package/src/restoration-state-handler.ts +302 -314
  208. package/src/tiles/list/tile-list.ts +1 -0
  209. package/src/utils/format-count.ts +1 -0
  210. package/test/collection-browser.test.ts +490 -490
  211. package/test/collection-facets.test.ts +264 -1
  212. package/tsconfig.json +21 -21
  213. package/web-dev-server.config.mjs +30 -30
  214. package/web-test-runner.config.mjs +41 -41
@@ -1,569 +1,569 @@
1
- /* eslint-disable import/no-duplicates */
2
- import {
3
- css,
4
- html,
5
- LitElement,
6
- PropertyValues,
7
- nothing,
8
- TemplateResult,
9
- } from 'lit';
10
- import { customElement, property, state } from 'lit/decorators.js';
11
- import {
12
- Aggregation,
13
- Bucket,
14
- SearchServiceInterface,
15
- SearchType,
16
- } from '@internetarchive/search-service';
17
- import '@internetarchive/histogram-date-range';
18
- import '@internetarchive/feature-feedback';
19
- import '@internetarchive/collection-name-cache';
20
- import type { CollectionNameCacheInterface } from '@internetarchive/collection-name-cache';
21
- import {
22
- ModalConfig,
23
- ModalManagerInterface,
24
- } from '@internetarchive/modal-manager';
25
- import chevronIcon from './assets/img/icons/chevron';
26
- import {
27
- FacetOption,
28
- SelectedFacets,
29
- FacetGroup,
30
- FacetBucket,
31
- facetDisplayOrder,
32
- facetTitles,
33
- lendingFacetDisplayNames,
34
- lendingFacetKeysVisibility,
35
- LendingFacetKey,
36
- } from './models';
37
- import type { LanguageCodeHandlerInterface } from './language-code-handler/language-code-handler';
38
- import './collection-facets/more-facets-content';
39
- import './collection-facets/facets-template';
40
-
41
- @customElement('collection-facets')
42
- export class CollectionFacets extends LitElement {
43
- @property({ type: Object }) searchService?: SearchServiceInterface;
44
-
45
- @property({ type: String }) searchType?: SearchType;
46
-
47
- @property({ type: Object }) aggregations?: Record<string, Aggregation>;
48
-
49
- @property({ type: Object }) fullYearsHistogramAggregation?: Aggregation;
50
-
51
- @property({ type: String }) minSelectedDate?: string;
52
-
53
- @property({ type: String }) maxSelectedDate?: string;
54
-
55
- @property({ type: Boolean }) facetsLoading = false;
56
-
57
- @property({ type: Boolean }) fullYearAggregationLoading = false;
58
-
59
- @property({ type: Object }) selectedFacets?: SelectedFacets;
60
-
61
- @property({ type: Boolean }) collapsableFacets = false;
62
-
63
- @property({ type: Boolean }) showHistogramDatePicker = false;
64
-
65
- @property({ type: String }) fullQuery?: string;
66
-
67
- @property({ type: Object }) modalManager?: ModalManagerInterface;
68
-
69
- @property({ type: Object })
70
- languageCodeHandler?: LanguageCodeHandlerInterface;
71
-
72
- @property({ type: Object })
73
- collectionNameCache?: CollectionNameCacheInterface;
74
-
75
- /** Fires when a facet is clicked */
76
- @property({ type: Function }) onFacetClick?: (
77
- name: FacetOption,
78
- facetChecked: boolean,
79
- negative: boolean
80
- ) => void;
81
-
82
- @state() openFacets: Record<FacetOption, boolean> = {
83
- subject: false,
84
- lending: false,
85
- mediatype: false,
86
- language: false,
87
- creator: false,
88
- collection: false,
89
- year: false,
90
- };
91
-
92
- @property({ type: Object, attribute: false })
93
-
94
- /**
95
- * render number of facet items
96
- */
97
- private allowedFacetCount = 6;
98
-
99
- render() {
100
- return html`
101
- <div id="container" class="${this.facetsLoading ? 'loading' : ''}">
102
- ${this.showHistogramDatePicker && this.fullYearsHistogramAggregation
103
- ? html`
104
- <div class="facet-group">
105
- <h1>Year Published <feature-feedback></feature-feedback></h1>
106
- ${this.histogramTemplate}
107
- </div>
108
- `
109
- : nothing}
110
- ${this.mergedFacets.map(facetGroup =>
111
- this.getFacetGroupTemplate(facetGroup)
112
- )}
113
- </div>
114
- `;
115
- }
116
-
117
- updated(changed: PropertyValues) {
118
- if (changed.has('selectedFacets')) {
119
- this.dispatchFacetsChangedEvent();
120
- }
121
- }
122
-
123
- // TODO: want to fire analytics?
124
- private dispatchFacetsChangedEvent() {
125
- const event = new CustomEvent<SelectedFacets>('facetsChanged', {
126
- detail: this.selectedFacets,
127
- });
128
- this.dispatchEvent(event);
129
- }
130
-
131
- private get currentYearsHistogramAggregation(): Aggregation | undefined {
132
- return this.aggregations?.year_histogram;
133
- }
134
-
135
- private get histogramTemplate() {
136
- const { fullYearsHistogramAggregation } = this;
137
- return html`
138
- <histogram-date-range
139
- .minDate=${fullYearsHistogramAggregation?.first_bucket_key}
140
- .maxDate=${fullYearsHistogramAggregation?.last_bucket_key}
141
- .minSelectedDate=${this.minSelectedDate}
142
- .maxSelectedDate=${this.maxSelectedDate}
143
- .updateDelay=${100}
144
- missingDataMessage="..."
145
- .width=${180}
146
- .bins=${fullYearsHistogramAggregation?.buckets as number[]}
147
- @histogramDateRangeUpdated=${this.histogramDateRangeUpdated}
148
- ></histogram-date-range>
149
- `;
150
- }
151
-
152
- private histogramDateRangeUpdated(
153
- e: CustomEvent<{
154
- minDate: string;
155
- maxDate: string;
156
- }>
157
- ) {
158
- const { minDate, maxDate } = e.detail;
159
- const event = new CustomEvent('histogramDateRangeUpdated', {
160
- detail: { minDate, maxDate },
161
- });
162
- this.dispatchEvent(event);
163
- }
164
-
165
- /**
166
- * Combines the selected facets with the aggregations to create a single list of facets
167
- */
168
- private get mergedFacets(): FacetGroup[] {
169
- const facetGroups: FacetGroup[] = [];
170
-
171
- facetDisplayOrder.forEach(facetKey => {
172
- const selectedFacetGroup = this.selectedFacetGroups.find(
173
- group => group.key === facetKey
174
- );
175
- const aggregateFacetGroup = this.aggregationFacetGroups.find(
176
- group => group.key === facetKey
177
- );
178
-
179
- // if the user selected a facet, but it's not in the aggregation, we add it as-is
180
- if (selectedFacetGroup && !aggregateFacetGroup) {
181
- facetGroups.push(selectedFacetGroup);
182
- return;
183
- }
184
-
185
- // if we don't have an aggregate facet group, don't add this to the list
186
- if (!aggregateFacetGroup) return;
187
-
188
- // start with either the selected group if we have one, or the aggregate group
189
- const facetGroup = selectedFacetGroup ?? aggregateFacetGroup;
190
-
191
- // attach the counts to the selected buckets
192
- let bucketsWithCount =
193
- selectedFacetGroup?.buckets.map(bucket => {
194
- const selectedBucket = aggregateFacetGroup.buckets.find(
195
- b => b.key === bucket.key
196
- );
197
- return selectedBucket
198
- ? {
199
- ...bucket,
200
- count: selectedBucket.count,
201
- }
202
- : bucket;
203
- }) ?? [];
204
-
205
- // append any additional buckets that were not selected
206
- aggregateFacetGroup.buckets.forEach(bucket => {
207
- const existingBucket = bucketsWithCount.find(b => b.key === bucket.key);
208
- if (existingBucket) return;
209
- bucketsWithCount.push(bucket);
210
- });
211
-
212
- // For lending facets, only include a specific subset of buckets
213
- if (facetKey === 'lending') {
214
- bucketsWithCount = bucketsWithCount.filter(
215
- bucket => lendingFacetKeysVisibility[bucket.key as LendingFacetKey]
216
- );
217
- }
218
-
219
- /**
220
- * render limited facet items on page facet area
221
- *
222
- * - by-default we are showing 6 items
223
- * - additionally want to show all items (selected/suppressed) in page facet area
224
- */
225
- let allowedFacetCount = Object.keys(
226
- (selectedFacetGroup?.buckets as []) || []
227
- )?.length;
228
- if (allowedFacetCount < this.allowedFacetCount) {
229
- allowedFacetCount = this.allowedFacetCount; // splice start index from 0th
230
- }
231
-
232
- // splice how many items we want to show in page facet area
233
- facetGroup.buckets = bucketsWithCount.splice(0, allowedFacetCount);
234
-
235
- facetGroups.push(facetGroup);
236
- });
237
-
238
- return facetGroups;
239
- }
240
-
241
- /**
242
- * Converts the selected facets to a `FacetGroup` array,
243
- * which is easier to work with
244
- */
245
- private get selectedFacetGroups(): FacetGroup[] {
246
- if (!this.selectedFacets) return [];
247
-
248
- const facetGroups: FacetGroup[] = Object.entries(this.selectedFacets).map(
249
- ([key, selectedFacets]) => {
250
- const option = key as FacetOption;
251
- const title = facetTitles[option];
252
-
253
- const buckets: FacetBucket[] = Object.entries(selectedFacets).map(
254
- ([value, facetData]) => {
255
- let displayText = value;
256
- // for selected languages, we store the language code instead of the
257
- // display name, so look up the name from the mapping
258
- if (option === 'language') {
259
- displayText =
260
- this.languageCodeHandler?.getLanguageNameFromCodeString(
261
- value
262
- ) ?? value;
263
- }
264
- // for lending facets, convert the key to a readable format
265
- if (option === 'lending') {
266
- displayText =
267
- lendingFacetDisplayNames[value as LendingFacetKey] ?? value;
268
- }
269
- return {
270
- displayText,
271
- key: value,
272
- count: facetData.count,
273
- state: facetData.state,
274
- };
275
- }
276
- );
277
-
278
- return {
279
- title,
280
- key: option,
281
- buckets,
282
- };
283
- }
284
- );
285
-
286
- return facetGroups;
287
- }
288
-
289
- /**
290
- * Converts the raw `aggregations` to `FacetGroups`, which are easier to use
291
- */
292
- private get aggregationFacetGroups(): FacetGroup[] {
293
- const facetGroups: FacetGroup[] = [];
294
- Object.entries(this.aggregations ?? []).forEach(([key, buckets]) => {
295
- // the year_histogram data is in a different format so can't be handled here
296
- if (key === 'year_histogram') return;
297
-
298
- const option = key as FacetOption;
299
- const title = facetTitles[option];
300
- if (!title) return;
301
-
302
- const castedBuckets = buckets.buckets as Bucket[];
303
-
304
- // we are not showing fav- items in facets
305
- castedBuckets?.filter(
306
- bucket => bucket?.key?.toString()?.startsWith('fav-') === false
307
- );
308
-
309
- const facetBuckets: FacetBucket[] = castedBuckets.map(bucket => {
310
- let bucketKey = bucket.key;
311
- let displayText = `${bucket.key}`;
312
- // for languages, we need to search by language code instead of the
313
- // display name, which is what we get from the search engine result
314
- if (option === 'language') {
315
- // const languageCodeKey = languageToCodeMap[bucket.key];
316
- bucketKey =
317
- this.languageCodeHandler?.getCodeStringFromLanguageName(
318
- `${bucket.key}`
319
- ) ?? bucket.key;
320
- // bucketKey = languageCodeKey ?? bucket.key;
321
- }
322
- // for lending facets, convert the bucket key to a readable format
323
- if (option === 'lending') {
324
- displayText =
325
- lendingFacetDisplayNames[bucket.key as LendingFacetKey] ??
326
- `${bucket.key}`;
327
- }
328
- return {
329
- displayText,
330
- key: `${bucketKey}`,
331
- count: bucket.doc_count,
332
- state: 'none',
333
- };
334
- });
335
- const group: FacetGroup = {
336
- title,
337
- key: option,
338
- buckets: facetBuckets,
339
- };
340
- facetGroups.push(group);
341
- });
342
- return facetGroups;
343
- }
344
-
345
- /**
346
- * Generate the template for a facet group with a header and the collapsible
347
- * chevron for the mobile view
348
- */
349
- private getFacetGroupTemplate(
350
- facetGroup: FacetGroup
351
- ): TemplateResult | typeof nothing {
352
- if (facetGroup.buckets.length === 0) return nothing;
353
- const { key } = facetGroup;
354
- const isOpen = this.openFacets[key];
355
- const collapser = html`
356
- <span class="collapser ${isOpen ? 'open' : ''}"> ${chevronIcon} </span>
357
- `;
358
-
359
- return html`
360
- <div class="facet-group ${this.collapsableFacets ? 'mobile' : ''}">
361
- <div class="facet-group-header">
362
- <h1
363
- @click=${() => {
364
- const newOpenFacets = { ...this.openFacets };
365
- newOpenFacets[key] = !isOpen;
366
- this.openFacets = newOpenFacets;
367
- }}
368
- @keyup=${() => {
369
- const newOpenFacets = { ...this.openFacets };
370
- newOpenFacets[key] = !isOpen;
371
- this.openFacets = newOpenFacets;
372
- }}
373
- >
374
- ${this.collapsableFacets ? collapser : nothing} ${facetGroup.title}
375
- </h1>
376
- <input
377
- class="sorting-icon"
378
- type="image"
379
- @click=${() => this.showMoreFacetsModal(facetGroup, 'alpha')}
380
- src="https://archive.org/images/filter-count.png"
381
- alt="Sort by alphabetically"
382
- />
383
- </div>
384
- <div class="facet-group-content ${isOpen ? 'open' : ''}">
385
- ${this.getFacetTemplate(facetGroup)}
386
- ${this.searchMoreFacetsLink(facetGroup)}
387
- </div>
388
- </div>
389
- `;
390
- }
391
-
392
- /**
393
- * Generate the More... link button just below the facets group
394
- *
395
- * TODO: want to fire analytics?
396
- */
397
- private searchMoreFacetsLink(
398
- facetGroup: FacetGroup
399
- ): TemplateResult | typeof nothing {
400
- // Don't render More... links for FTS searches
401
- if (this.searchType === SearchType.FULLTEXT) {
402
- return nothing;
403
- }
404
-
405
- // Don't render More... links for lending facets
406
- if (facetGroup.key === 'lending') {
407
- return nothing;
408
- }
409
-
410
- // Don't render More... link if the number of facets < this.allowedFacetCount
411
- if (Object.keys(facetGroup.buckets).length < this.allowedFacetCount) {
412
- return nothing;
413
- }
414
-
415
- return html`<button
416
- class="more-link"
417
- @click=${() => {
418
- this.showMoreFacetsModal(facetGroup, 'count');
419
- this.dispatchEvent(
420
- new CustomEvent('showMoreFacets', { detail: facetGroup.key })
421
- );
422
- }}
423
- >
424
- More...
425
- </button>`;
426
- }
427
-
428
- async showMoreFacetsModal(
429
- facetGroup: FacetGroup,
430
- sortedBy: string
431
- ): Promise<void> {
432
- const facetAggrKey = facetGroup.key;
433
-
434
- const customModalContent = html`
435
- <more-facets-content
436
- .facetKey=${facetGroup.key}
437
- .facetAggregationKey=${facetAggrKey}
438
- .fullQuery=${this.fullQuery}
439
- .modalManager=${this.modalManager}
440
- .searchService=${this.searchService}
441
- .searchType=${this.searchType}
442
- .collectionNameCache=${this.collectionNameCache}
443
- .languageCodeHandler=${this.languageCodeHandler}
444
- .selectedFacets=${this.selectedFacets}
445
- .sortedBy=${sortedBy}
446
- @facetsChanged=${(e: CustomEvent) => {
447
- const event = new CustomEvent<SelectedFacets>('facetsChanged', {
448
- detail: e.detail,
449
- bubbles: true,
450
- composed: true,
451
- });
452
- this.dispatchEvent(event);
453
- }}
454
- >
455
- </more-facets-content>
456
- `;
457
-
458
- const config = new ModalConfig({
459
- bodyColor: '#fff',
460
- headerColor: '#194880',
461
- showHeaderLogo: false,
462
- closeOnBackdropClick: true, // TODO: want to fire analytics
463
- title: html`Select filters`,
464
- });
465
- this.modalManager?.classList.add('more-search-facets');
466
- this.modalManager?.showModal({
467
- config,
468
- customModalContent,
469
- });
470
- }
471
-
472
- /**
473
- * Generate the list template for each bucket in a facet group
474
- */
475
- private getFacetTemplate(facetGroup: FacetGroup): TemplateResult {
476
- return html`
477
- <facets-template
478
- .facetGroup=${facetGroup}
479
- .selectedFacets=${this.selectedFacets}
480
- .renderOn=${'page'}
481
- .collectionNameCache=${this.collectionNameCache}
482
- @selectedFacetsChanged=${(e: CustomEvent) => {
483
- const event = new CustomEvent<SelectedFacets>('facetsChanged', {
484
- detail: e.detail,
485
- bubbles: true,
486
- composed: true,
487
- });
488
- this.dispatchEvent(event);
489
- }}
490
- ></facets-template>
491
- `;
492
- }
493
-
494
- static get styles() {
495
- return css`
496
- #container.loading {
497
- opacity: 0.5;
498
- }
499
-
500
- .collapser {
501
- display: inline-block;
502
- cursor: pointer;
503
- width: 10px;
504
- height: 10px;
505
- }
506
-
507
- .collapser svg {
508
- transition: transform 0.2s ease-in-out;
509
- }
510
-
511
- .collapser.open svg {
512
- transform: rotate(90deg);
513
- }
514
-
515
- .facet-group {
516
- margin-bottom: 2rem;
517
- }
518
-
519
- .facet-group h1 {
520
- margin-bottom: 0.7rem;
521
- }
522
-
523
- .facet-group.mobile h1 {
524
- cursor: pointer;
525
- }
526
-
527
- .facet-group-header {
528
- display: flex;
529
- margin-bottom: 0.7rem;
530
- justify-content: space-between;
531
- border-bottom: 1px solid rgb(232, 232, 232);
532
- }
533
-
534
- .facet-group-content {
535
- transition: max-height 0.2s ease-in-out;
536
- }
537
-
538
- .facet-group.mobile .facet-group-content {
539
- max-height: 0;
540
- overflow: hidden;
541
- }
542
-
543
- .facet-group.mobile .facet-group-content.open {
544
- max-height: 2000px;
545
- }
546
-
547
- h1 {
548
- font-size: 1.4rem;
549
- font-weight: 200
550
- padding-bottom: 3px;
551
- margin: 0;
552
- }
553
-
554
- .more-link {
555
- font-size: 1.2rem;
556
- text-decoration: none;
557
- padding: 0;
558
- background: inherit;
559
- border: 0;
560
- color: blue;
561
- cursor: pointer;
562
- }
563
- .sorting-icon {
564
- height: 15px;
565
- cursor: pointer;
566
- }
567
- `;
568
- }
569
- }
1
+ /* eslint-disable import/no-duplicates */
2
+ import {
3
+ css,
4
+ html,
5
+ LitElement,
6
+ PropertyValues,
7
+ nothing,
8
+ TemplateResult,
9
+ } from 'lit';
10
+ import { customElement, property, state } from 'lit/decorators.js';
11
+ import {
12
+ Aggregation,
13
+ Bucket,
14
+ SearchServiceInterface,
15
+ SearchType,
16
+ } from '@internetarchive/search-service';
17
+ import '@internetarchive/histogram-date-range';
18
+ import '@internetarchive/feature-feedback';
19
+ import '@internetarchive/collection-name-cache';
20
+ import type { CollectionNameCacheInterface } from '@internetarchive/collection-name-cache';
21
+ import {
22
+ ModalConfig,
23
+ ModalManagerInterface,
24
+ } from '@internetarchive/modal-manager';
25
+ import chevronIcon from './assets/img/icons/chevron';
26
+ import {
27
+ FacetOption,
28
+ SelectedFacets,
29
+ FacetGroup,
30
+ FacetBucket,
31
+ facetDisplayOrder,
32
+ facetTitles,
33
+ lendingFacetDisplayNames,
34
+ lendingFacetKeysVisibility,
35
+ LendingFacetKey,
36
+ } from './models';
37
+ import type { LanguageCodeHandlerInterface } from './language-code-handler/language-code-handler';
38
+ import './collection-facets/more-facets-content';
39
+ import './collection-facets/facets-template';
40
+
41
+ @customElement('collection-facets')
42
+ export class CollectionFacets extends LitElement {
43
+ @property({ type: Object }) searchService?: SearchServiceInterface;
44
+
45
+ @property({ type: String }) searchType?: SearchType;
46
+
47
+ @property({ type: Object }) aggregations?: Record<string, Aggregation>;
48
+
49
+ @property({ type: Object }) fullYearsHistogramAggregation?: Aggregation;
50
+
51
+ @property({ type: String }) minSelectedDate?: string;
52
+
53
+ @property({ type: String }) maxSelectedDate?: string;
54
+
55
+ @property({ type: Boolean }) facetsLoading = false;
56
+
57
+ @property({ type: Boolean }) fullYearAggregationLoading = false;
58
+
59
+ @property({ type: Object }) selectedFacets?: SelectedFacets;
60
+
61
+ @property({ type: Boolean }) collapsableFacets = false;
62
+
63
+ @property({ type: Boolean }) showHistogramDatePicker = false;
64
+
65
+ @property({ type: String }) fullQuery?: string;
66
+
67
+ @property({ type: Object }) modalManager?: ModalManagerInterface;
68
+
69
+ @property({ type: Object })
70
+ languageCodeHandler?: LanguageCodeHandlerInterface;
71
+
72
+ @property({ type: Object })
73
+ collectionNameCache?: CollectionNameCacheInterface;
74
+
75
+ /** Fires when a facet is clicked */
76
+ @property({ type: Function }) onFacetClick?: (
77
+ name: FacetOption,
78
+ facetChecked: boolean,
79
+ negative: boolean
80
+ ) => void;
81
+
82
+ @state() openFacets: Record<FacetOption, boolean> = {
83
+ subject: false,
84
+ lending: false,
85
+ mediatype: false,
86
+ language: false,
87
+ creator: false,
88
+ collection: false,
89
+ year: false,
90
+ };
91
+
92
+ @property({ type: Object, attribute: false })
93
+
94
+ /**
95
+ * render number of facet items
96
+ */
97
+ private allowedFacetCount = 6;
98
+
99
+ render() {
100
+ return html`
101
+ <div id="container" class="${this.facetsLoading ? 'loading' : ''}">
102
+ ${this.showHistogramDatePicker && this.fullYearsHistogramAggregation
103
+ ? html`
104
+ <div class="facet-group">
105
+ <h1>Year Published <feature-feedback></feature-feedback></h1>
106
+ ${this.histogramTemplate}
107
+ </div>
108
+ `
109
+ : nothing}
110
+ ${this.mergedFacets.map(facetGroup =>
111
+ this.getFacetGroupTemplate(facetGroup)
112
+ )}
113
+ </div>
114
+ `;
115
+ }
116
+
117
+ updated(changed: PropertyValues) {
118
+ if (changed.has('selectedFacets')) {
119
+ this.dispatchFacetsChangedEvent();
120
+ }
121
+ }
122
+
123
+ // TODO: want to fire analytics?
124
+ private dispatchFacetsChangedEvent() {
125
+ const event = new CustomEvent<SelectedFacets>('facetsChanged', {
126
+ detail: this.selectedFacets,
127
+ });
128
+ this.dispatchEvent(event);
129
+ }
130
+
131
+ private get currentYearsHistogramAggregation(): Aggregation | undefined {
132
+ return this.aggregations?.year_histogram;
133
+ }
134
+
135
+ private get histogramTemplate() {
136
+ const { fullYearsHistogramAggregation } = this;
137
+ return html`
138
+ <histogram-date-range
139
+ .minDate=${fullYearsHistogramAggregation?.first_bucket_key}
140
+ .maxDate=${fullYearsHistogramAggregation?.last_bucket_key}
141
+ .minSelectedDate=${this.minSelectedDate}
142
+ .maxSelectedDate=${this.maxSelectedDate}
143
+ .updateDelay=${100}
144
+ missingDataMessage="..."
145
+ .width=${180}
146
+ .bins=${fullYearsHistogramAggregation?.buckets as number[]}
147
+ @histogramDateRangeUpdated=${this.histogramDateRangeUpdated}
148
+ ></histogram-date-range>
149
+ `;
150
+ }
151
+
152
+ private histogramDateRangeUpdated(
153
+ e: CustomEvent<{
154
+ minDate: string;
155
+ maxDate: string;
156
+ }>
157
+ ) {
158
+ const { minDate, maxDate } = e.detail;
159
+ const event = new CustomEvent('histogramDateRangeUpdated', {
160
+ detail: { minDate, maxDate },
161
+ });
162
+ this.dispatchEvent(event);
163
+ }
164
+
165
+ /**
166
+ * Combines the selected facets with the aggregations to create a single list of facets
167
+ */
168
+ private get mergedFacets(): FacetGroup[] {
169
+ const facetGroups: FacetGroup[] = [];
170
+
171
+ facetDisplayOrder.forEach(facetKey => {
172
+ const selectedFacetGroup = this.selectedFacetGroups.find(
173
+ group => group.key === facetKey
174
+ );
175
+ const aggregateFacetGroup = this.aggregationFacetGroups.find(
176
+ group => group.key === facetKey
177
+ );
178
+
179
+ // if the user selected a facet, but it's not in the aggregation, we add it as-is
180
+ if (selectedFacetGroup && !aggregateFacetGroup) {
181
+ facetGroups.push(selectedFacetGroup);
182
+ return;
183
+ }
184
+
185
+ // if we don't have an aggregate facet group, don't add this to the list
186
+ if (!aggregateFacetGroup) return;
187
+
188
+ // start with either the selected group if we have one, or the aggregate group
189
+ const facetGroup = selectedFacetGroup ?? aggregateFacetGroup;
190
+
191
+ // attach the counts to the selected buckets
192
+ let bucketsWithCount =
193
+ selectedFacetGroup?.buckets.map(bucket => {
194
+ const selectedBucket = aggregateFacetGroup.buckets.find(
195
+ b => b.key === bucket.key
196
+ );
197
+ return selectedBucket
198
+ ? {
199
+ ...bucket,
200
+ count: selectedBucket.count,
201
+ }
202
+ : bucket;
203
+ }) ?? [];
204
+
205
+ // append any additional buckets that were not selected
206
+ aggregateFacetGroup.buckets.forEach(bucket => {
207
+ const existingBucket = bucketsWithCount.find(b => b.key === bucket.key);
208
+ if (existingBucket) return;
209
+ bucketsWithCount.push(bucket);
210
+ });
211
+
212
+ // For lending facets, only include a specific subset of buckets
213
+ if (facetKey === 'lending') {
214
+ bucketsWithCount = bucketsWithCount.filter(
215
+ bucket => lendingFacetKeysVisibility[bucket.key as LendingFacetKey]
216
+ );
217
+ }
218
+
219
+ /**
220
+ * render limited facet items on page facet area
221
+ *
222
+ * - by-default we are showing 6 items
223
+ * - additionally want to show all items (selected/suppressed) in page facet area
224
+ */
225
+ let allowedFacetCount = Object.keys(
226
+ (selectedFacetGroup?.buckets as []) || []
227
+ )?.length;
228
+ if (allowedFacetCount < this.allowedFacetCount) {
229
+ allowedFacetCount = this.allowedFacetCount; // splice start index from 0th
230
+ }
231
+
232
+ // splice how many items we want to show in page facet area
233
+ facetGroup.buckets = bucketsWithCount.splice(0, allowedFacetCount);
234
+
235
+ facetGroups.push(facetGroup);
236
+ });
237
+
238
+ return facetGroups;
239
+ }
240
+
241
+ /**
242
+ * Converts the selected facets to a `FacetGroup` array,
243
+ * which is easier to work with
244
+ */
245
+ private get selectedFacetGroups(): FacetGroup[] {
246
+ if (!this.selectedFacets) return [];
247
+
248
+ const facetGroups: FacetGroup[] = Object.entries(this.selectedFacets).map(
249
+ ([key, selectedFacets]) => {
250
+ const option = key as FacetOption;
251
+ const title = facetTitles[option];
252
+
253
+ const buckets: FacetBucket[] = Object.entries(selectedFacets).map(
254
+ ([value, facetData]) => {
255
+ let displayText = value;
256
+ // for selected languages, we store the language code instead of the
257
+ // display name, so look up the name from the mapping
258
+ if (option === 'language') {
259
+ displayText =
260
+ this.languageCodeHandler?.getLanguageNameFromCodeString(
261
+ value
262
+ ) ?? value;
263
+ }
264
+ // for lending facets, convert the key to a readable format
265
+ if (option === 'lending') {
266
+ displayText =
267
+ lendingFacetDisplayNames[value as LendingFacetKey] ?? value;
268
+ }
269
+ return {
270
+ displayText,
271
+ key: value,
272
+ count: facetData.count,
273
+ state: facetData.state,
274
+ };
275
+ }
276
+ );
277
+
278
+ return {
279
+ title,
280
+ key: option,
281
+ buckets,
282
+ };
283
+ }
284
+ );
285
+
286
+ return facetGroups;
287
+ }
288
+
289
+ /**
290
+ * Converts the raw `aggregations` to `FacetGroups`, which are easier to use
291
+ */
292
+ private get aggregationFacetGroups(): FacetGroup[] {
293
+ const facetGroups: FacetGroup[] = [];
294
+ Object.entries(this.aggregations ?? []).forEach(([key, buckets]) => {
295
+ // the year_histogram data is in a different format so can't be handled here
296
+ if (key === 'year_histogram') return;
297
+
298
+ const option = key as FacetOption;
299
+ const title = facetTitles[option];
300
+ if (!title) return;
301
+
302
+ const castedBuckets = buckets.buckets as Bucket[];
303
+
304
+ // we are not showing fav- items in facets
305
+ castedBuckets?.filter(
306
+ bucket => bucket?.key?.toString()?.startsWith('fav-') === false
307
+ );
308
+
309
+ const facetBuckets: FacetBucket[] = castedBuckets.map(bucket => {
310
+ let bucketKey = bucket.key;
311
+ let displayText = `${bucket.key}`;
312
+ // for languages, we need to search by language code instead of the
313
+ // display name, which is what we get from the search engine result
314
+ if (option === 'language') {
315
+ // const languageCodeKey = languageToCodeMap[bucket.key];
316
+ bucketKey =
317
+ this.languageCodeHandler?.getCodeStringFromLanguageName(
318
+ `${bucket.key}`
319
+ ) ?? bucket.key;
320
+ // bucketKey = languageCodeKey ?? bucket.key;
321
+ }
322
+ // for lending facets, convert the bucket key to a readable format
323
+ if (option === 'lending') {
324
+ displayText =
325
+ lendingFacetDisplayNames[bucket.key as LendingFacetKey] ??
326
+ `${bucket.key}`;
327
+ }
328
+ return {
329
+ displayText,
330
+ key: `${bucketKey}`,
331
+ count: bucket.doc_count,
332
+ state: 'none',
333
+ };
334
+ });
335
+ const group: FacetGroup = {
336
+ title,
337
+ key: option,
338
+ buckets: facetBuckets,
339
+ };
340
+ facetGroups.push(group);
341
+ });
342
+ return facetGroups;
343
+ }
344
+
345
+ /**
346
+ * Generate the template for a facet group with a header and the collapsible
347
+ * chevron for the mobile view
348
+ */
349
+ private getFacetGroupTemplate(
350
+ facetGroup: FacetGroup
351
+ ): TemplateResult | typeof nothing {
352
+ if (facetGroup.buckets.length === 0) return nothing;
353
+ const { key } = facetGroup;
354
+ const isOpen = this.openFacets[key];
355
+ const collapser = html`
356
+ <span class="collapser ${isOpen ? 'open' : ''}"> ${chevronIcon} </span>
357
+ `;
358
+
359
+ return html`
360
+ <div class="facet-group ${this.collapsableFacets ? 'mobile' : ''}">
361
+ <div class="facet-group-header">
362
+ <h1
363
+ @click=${() => {
364
+ const newOpenFacets = { ...this.openFacets };
365
+ newOpenFacets[key] = !isOpen;
366
+ this.openFacets = newOpenFacets;
367
+ }}
368
+ @keyup=${() => {
369
+ const newOpenFacets = { ...this.openFacets };
370
+ newOpenFacets[key] = !isOpen;
371
+ this.openFacets = newOpenFacets;
372
+ }}
373
+ >
374
+ ${this.collapsableFacets ? collapser : nothing} ${facetGroup.title}
375
+ </h1>
376
+ <input
377
+ class="sorting-icon"
378
+ type="image"
379
+ @click=${() => this.showMoreFacetsModal(facetGroup, 'alpha')}
380
+ src="https://archive.org/images/filter-count.png"
381
+ alt="Sort by alphabetically"
382
+ />
383
+ </div>
384
+ <div class="facet-group-content ${isOpen ? 'open' : ''}">
385
+ ${this.getFacetTemplate(facetGroup)}
386
+ ${this.searchMoreFacetsLink(facetGroup)}
387
+ </div>
388
+ </div>
389
+ `;
390
+ }
391
+
392
+ /**
393
+ * Generate the More... link button just below the facets group
394
+ *
395
+ * TODO: want to fire analytics?
396
+ */
397
+ private searchMoreFacetsLink(
398
+ facetGroup: FacetGroup
399
+ ): TemplateResult | typeof nothing {
400
+ // Don't render More... links for FTS searches
401
+ if (this.searchType === SearchType.FULLTEXT) {
402
+ return nothing;
403
+ }
404
+
405
+ // Don't render More... links for lending facets
406
+ if (facetGroup.key === 'lending') {
407
+ return nothing;
408
+ }
409
+
410
+ // Don't render More... link if the number of facets < this.allowedFacetCount
411
+ if (Object.keys(facetGroup.buckets).length < this.allowedFacetCount) {
412
+ return nothing;
413
+ }
414
+
415
+ return html`<button
416
+ class="more-link"
417
+ @click=${() => {
418
+ this.showMoreFacetsModal(facetGroup, 'count');
419
+ this.dispatchEvent(
420
+ new CustomEvent('showMoreFacets', { detail: facetGroup.key })
421
+ );
422
+ }}
423
+ >
424
+ More...
425
+ </button>`;
426
+ }
427
+
428
+ async showMoreFacetsModal(
429
+ facetGroup: FacetGroup,
430
+ sortedBy: string
431
+ ): Promise<void> {
432
+ const facetAggrKey = facetGroup.key;
433
+
434
+ const customModalContent = html`
435
+ <more-facets-content
436
+ .facetKey=${facetGroup.key}
437
+ .facetAggregationKey=${facetAggrKey}
438
+ .fullQuery=${this.fullQuery}
439
+ .modalManager=${this.modalManager}
440
+ .searchService=${this.searchService}
441
+ .searchType=${this.searchType}
442
+ .collectionNameCache=${this.collectionNameCache}
443
+ .languageCodeHandler=${this.languageCodeHandler}
444
+ .selectedFacets=${this.selectedFacets}
445
+ .sortedBy=${sortedBy}
446
+ @facetsChanged=${(e: CustomEvent) => {
447
+ const event = new CustomEvent<SelectedFacets>('facetsChanged', {
448
+ detail: e.detail,
449
+ bubbles: true,
450
+ composed: true,
451
+ });
452
+ this.dispatchEvent(event);
453
+ }}
454
+ >
455
+ </more-facets-content>
456
+ `;
457
+
458
+ const config = new ModalConfig({
459
+ bodyColor: '#fff',
460
+ headerColor: '#194880',
461
+ showHeaderLogo: false,
462
+ closeOnBackdropClick: true, // TODO: want to fire analytics
463
+ title: html`Select filters`,
464
+ });
465
+ this.modalManager?.classList.add('more-search-facets');
466
+ this.modalManager?.showModal({
467
+ config,
468
+ customModalContent,
469
+ });
470
+ }
471
+
472
+ /**
473
+ * Generate the list template for each bucket in a facet group
474
+ */
475
+ private getFacetTemplate(facetGroup: FacetGroup): TemplateResult {
476
+ return html`
477
+ <facets-template
478
+ .facetGroup=${facetGroup}
479
+ .selectedFacets=${this.selectedFacets}
480
+ .renderOn=${'page'}
481
+ .collectionNameCache=${this.collectionNameCache}
482
+ @selectedFacetsChanged=${(e: CustomEvent) => {
483
+ const event = new CustomEvent<SelectedFacets>('facetsChanged', {
484
+ detail: e.detail,
485
+ bubbles: true,
486
+ composed: true,
487
+ });
488
+ this.dispatchEvent(event);
489
+ }}
490
+ ></facets-template>
491
+ `;
492
+ }
493
+
494
+ static get styles() {
495
+ return css`
496
+ #container.loading {
497
+ opacity: 0.5;
498
+ }
499
+
500
+ .collapser {
501
+ display: inline-block;
502
+ cursor: pointer;
503
+ width: 10px;
504
+ height: 10px;
505
+ }
506
+
507
+ .collapser svg {
508
+ transition: transform 0.2s ease-in-out;
509
+ }
510
+
511
+ .collapser.open svg {
512
+ transform: rotate(90deg);
513
+ }
514
+
515
+ .facet-group {
516
+ margin-bottom: 2rem;
517
+ }
518
+
519
+ .facet-group h1 {
520
+ margin-bottom: 0.7rem;
521
+ }
522
+
523
+ .facet-group.mobile h1 {
524
+ cursor: pointer;
525
+ }
526
+
527
+ .facet-group-header {
528
+ display: flex;
529
+ margin-bottom: 0.7rem;
530
+ justify-content: space-between;
531
+ border-bottom: 1px solid rgb(232, 232, 232);
532
+ }
533
+
534
+ .facet-group-content {
535
+ transition: max-height 0.2s ease-in-out;
536
+ }
537
+
538
+ .facet-group.mobile .facet-group-content {
539
+ max-height: 0;
540
+ overflow: hidden;
541
+ }
542
+
543
+ .facet-group.mobile .facet-group-content.open {
544
+ max-height: 2000px;
545
+ }
546
+
547
+ h1 {
548
+ font-size: 1.4rem;
549
+ font-weight: 200
550
+ padding-bottom: 3px;
551
+ margin: 0;
552
+ }
553
+
554
+ .more-link {
555
+ font-size: 1.2rem;
556
+ text-decoration: none;
557
+ padding: 0;
558
+ background: inherit;
559
+ border: 0;
560
+ color: blue;
561
+ cursor: pointer;
562
+ }
563
+ .sorting-icon {
564
+ height: 15px;
565
+ cursor: pointer;
566
+ }
567
+ `;
568
+ }
569
+ }