@internetarchive/collection-browser 4.2.0-alpha-webdev8164.3 → 4.2.1-alpha-webdev7004.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/.claude/settings.local.json +11 -0
- package/.editorconfig +29 -29
- package/.github/workflows/ci.yml +27 -27
- package/.github/workflows/gh-pages-main.yml +39 -39
- package/.github/workflows/npm-publish.yml +39 -39
- package/.github/workflows/pr-preview.yml +38 -38
- package/.husky/pre-commit +1 -1
- package/.prettierignore +1 -1
- package/LICENSE +661 -661
- package/README.md +83 -83
- package/dist/src/app-root.js +4 -0
- package/dist/src/app-root.js.map +1 -1
- package/dist/src/collection-browser.js +32 -27
- package/dist/src/collection-browser.js.map +1 -1
- package/dist/src/collection-facets/facets-template.js +0 -5
- package/dist/src/collection-facets/facets-template.js.map +1 -1
- package/dist/src/collection-facets/more-facets-content.d.ts +8 -106
- package/dist/src/collection-facets/more-facets-content.js +103 -612
- package/dist/src/collection-facets/more-facets-content.js.map +1 -1
- package/dist/src/collection-facets/more-facets-pagination.d.ts +3 -12
- package/dist/src/collection-facets/more-facets-pagination.js +9 -71
- package/dist/src/collection-facets/more-facets-pagination.js.map +1 -1
- package/dist/src/collection-facets/toggle-switch.js +0 -1
- package/dist/src/collection-facets/toggle-switch.js.map +1 -1
- package/dist/src/collection-facets.js +9 -10
- package/dist/src/collection-facets.js.map +1 -1
- package/dist/src/data-source/collection-browser-data-source.d.ts +7 -0
- package/dist/src/data-source/collection-browser-data-source.js +27 -10
- package/dist/src/data-source/collection-browser-data-source.js.map +1 -1
- package/dist/src/mediatype/mediatype-config.js +1 -1
- package/dist/src/mediatype/mediatype-config.js.map +1 -1
- package/dist/src/models.d.ts +12 -2
- package/dist/src/models.js +13 -8
- package/dist/src/models.js.map +1 -1
- package/dist/src/restoration-state-handler.js +9 -3
- package/dist/src/restoration-state-handler.js.map +1 -1
- package/dist/src/tiles/hover/hover-pane-controller.js +2 -1
- package/dist/src/tiles/hover/hover-pane-controller.js.map +1 -1
- package/dist/src/tiles/tile-dispatcher.d.ts +6 -0
- package/dist/src/tiles/tile-dispatcher.js +11 -3
- package/dist/src/tiles/tile-dispatcher.js.map +1 -1
- package/dist/test/collection-browser.test.js +72 -0
- package/dist/test/collection-browser.test.js.map +1 -1
- package/dist/test/collection-facets/more-facets-content.test.js +3 -212
- package/dist/test/collection-facets/more-facets-content.test.js.map +1 -1
- package/dist/test/collection-facets/more-facets-pagination.test.js +3 -63
- package/dist/test/collection-facets/more-facets-pagination.test.js.map +1 -1
- package/dist/test/data-source/collection-browser-data-source.test.js +52 -0
- package/dist/test/data-source/collection-browser-data-source.test.js.map +1 -1
- package/dist/test/mocks/mock-search-responses.d.ts +0 -5
- package/dist/test/mocks/mock-search-responses.js +0 -44
- package/dist/test/mocks/mock-search-responses.js.map +1 -1
- package/dist/test/mocks/mock-search-service.js +1 -2
- package/dist/test/mocks/mock-search-service.js.map +1 -1
- package/dist/test/tiles/tile-dispatcher.test.js +14 -0
- package/dist/test/tiles/tile-dispatcher.test.js.map +1 -1
- package/dist/test/tiles/tile-mediatype-icon.test.js +4 -4
- package/dist/test/tiles/tile-mediatype-icon.test.js.map +1 -1
- package/eslint.config.mjs +53 -53
- package/index.html +24 -24
- package/local.archive.org.cert +86 -86
- package/local.archive.org.key +27 -27
- package/package.json +120 -121
- package/renovate.json +6 -6
- package/src/app-root.ts +4 -0
- package/src/collection-browser.ts +43 -36
- package/src/collection-facets/facets-template.ts +0 -5
- package/src/collection-facets/more-facets-content.ts +113 -662
- package/src/collection-facets/more-facets-pagination.ts +10 -84
- package/src/collection-facets/toggle-switch.ts +0 -1
- package/src/collection-facets.ts +13 -10
- package/src/data-source/collection-browser-data-source.ts +31 -10
- package/src/mediatype/mediatype-config.ts +1 -1
- package/src/models.ts +30 -8
- package/src/restoration-state-handler.ts +7 -3
- package/src/tiles/hover/hover-pane-controller.ts +2 -1
- package/src/tiles/tile-dispatcher.ts +12 -3
- package/test/collection-browser.test.ts +105 -0
- package/test/collection-facets/more-facets-content.test.ts +4 -326
- package/test/collection-facets/more-facets-pagination.test.ts +3 -87
- package/test/data-source/collection-browser-data-source.test.ts +62 -0
- package/test/mocks/mock-search-responses.ts +0 -48
- package/test/mocks/mock-search-service.ts +0 -2
- package/test/tiles/tile-dispatcher.test.ts +17 -0
- package/test/tiles/tile-mediatype-icon.test.ts +4 -4
- package/tsconfig.json +25 -25
- package/web-dev-server.config.mjs +30 -30
- package/web-test-runner.config.mjs +52 -52
|
@@ -7,9 +7,7 @@ import {
|
|
|
7
7
|
PropertyValues,
|
|
8
8
|
TemplateResult,
|
|
9
9
|
} from 'lit';
|
|
10
|
-
import { customElement, property,
|
|
11
|
-
import { classMap } from 'lit/directives/class-map.js';
|
|
12
|
-
import { when } from 'lit/directives/when.js';
|
|
10
|
+
import { customElement, property, state } from 'lit/decorators.js';
|
|
13
11
|
import {
|
|
14
12
|
Aggregation,
|
|
15
13
|
Bucket,
|
|
@@ -42,16 +40,13 @@ import type {
|
|
|
42
40
|
TVChannelAliases,
|
|
43
41
|
} from '../data-source/models';
|
|
44
42
|
import '@internetarchive/elements/ia-status-indicator/ia-status-indicator';
|
|
43
|
+
import './more-facets-pagination';
|
|
45
44
|
import './facets-template';
|
|
46
45
|
import {
|
|
47
46
|
analyticsActions,
|
|
48
47
|
analyticsCategories,
|
|
49
48
|
} from '../utils/analytics-events';
|
|
50
49
|
import './toggle-switch';
|
|
51
|
-
import './more-facets-pagination';
|
|
52
|
-
import '@internetarchive/ia-clearable-text-input';
|
|
53
|
-
import arrowLeftIcon from '../assets/img/icons/arrow-left';
|
|
54
|
-
import arrowRightIcon from '../assets/img/icons/arrow-right';
|
|
55
50
|
import { srOnlyStyle } from '../styles/sr-only';
|
|
56
51
|
import {
|
|
57
52
|
mergeSelectedFacets,
|
|
@@ -63,12 +58,6 @@ import {
|
|
|
63
58
|
MORE_FACETS__MAX_AGGREGATIONS,
|
|
64
59
|
} from './models';
|
|
65
60
|
|
|
66
|
-
/**
|
|
67
|
-
* Threshold for switching from horizontal scroll to pagination.
|
|
68
|
-
* If facet count >= this value, use pagination. Otherwise use horizontal scroll.
|
|
69
|
-
*/
|
|
70
|
-
const PAGINATION_THRESHOLD = 1000;
|
|
71
|
-
|
|
72
61
|
@customElement('more-facets-content')
|
|
73
62
|
export class MoreFacetsContent extends LitElement {
|
|
74
63
|
@property({ type: String }) facetKey?: FacetOption;
|
|
@@ -137,46 +126,10 @@ export class MoreFacetsContent extends LitElement {
|
|
|
137
126
|
getDefaultSelectedFacets();
|
|
138
127
|
|
|
139
128
|
/**
|
|
140
|
-
*
|
|
141
|
-
* Applied to bucket.key for case-insensitive matching.
|
|
142
|
-
*/
|
|
143
|
-
@state() private filterText = '';
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Current page number for pagination (when facet count >= PAGINATION_THRESHOLD).
|
|
129
|
+
* Which page of facets we are showing.
|
|
147
130
|
*/
|
|
148
131
|
@state() private pageNumber = 1;
|
|
149
132
|
|
|
150
|
-
/**
|
|
151
|
-
* Whether the component is narrow enough to warrant compact pagination.
|
|
152
|
-
* Updated via a ResizeObserver-based container query approach.
|
|
153
|
-
*/
|
|
154
|
-
@state() private isCompactView = false;
|
|
155
|
-
|
|
156
|
-
/** Column gap in px — matches the --facetsColumnGap default (never overridden). */
|
|
157
|
-
private static readonly COLUMN_GAP = 15;
|
|
158
|
-
|
|
159
|
-
/** Column count derived from the same breakpoint as the CSS media query. */
|
|
160
|
-
private get columnCount(): number {
|
|
161
|
-
return this.isCompactView ? 1 : 3;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Whether the horizontal scroll is at the leftmost position.
|
|
166
|
-
*/
|
|
167
|
-
@state() private atScrollStart = true;
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Whether the horizontal scroll is at the rightmost position.
|
|
171
|
-
*/
|
|
172
|
-
@state() private atScrollEnd = true;
|
|
173
|
-
|
|
174
|
-
@query('ia-clearable-text-input')
|
|
175
|
-
private filterInput!: HTMLElement;
|
|
176
|
-
|
|
177
|
-
@query('.facets-content')
|
|
178
|
-
private facetsContentEl!: HTMLElement;
|
|
179
|
-
|
|
180
133
|
willUpdate(changed: PropertyValues): void {
|
|
181
134
|
if (
|
|
182
135
|
changed.has('aggregations') ||
|
|
@@ -190,13 +143,6 @@ export class MoreFacetsContent extends LitElement {
|
|
|
190
143
|
this.facetGroup = this.mergedFacets;
|
|
191
144
|
}
|
|
192
145
|
|
|
193
|
-
// Reset to page 1 when filter text changes (only matters for pagination mode)
|
|
194
|
-
if (changed.has('filterText')) {
|
|
195
|
-
this.pageNumber = 1;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
updated(changed: PropertyValues): void {
|
|
200
146
|
// If any of the search properties change, it triggers a facet fetch
|
|
201
147
|
if (
|
|
202
148
|
changed.has('facetKey') ||
|
|
@@ -213,196 +159,24 @@ export class MoreFacetsContent extends LitElement {
|
|
|
213
159
|
|
|
214
160
|
this.updateSpecificFacets();
|
|
215
161
|
}
|
|
216
|
-
|
|
217
|
-
// Reset horizontal scroll when filter text changes (e.g., switching from
|
|
218
|
-
// horizontal-scroll mode back to pagination mode)
|
|
219
|
-
if (changed.has('filterText')) {
|
|
220
|
-
const facetsContent = this.shadowRoot?.querySelector('.facets-content');
|
|
221
|
-
if (facetsContent) {
|
|
222
|
-
facetsContent.scrollLeft = 0;
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// Manage scroll listener for horizontal scroll mode arrows.
|
|
227
|
-
// Only re-evaluate when properties that affect the displayed content change.
|
|
228
|
-
if (
|
|
229
|
-
changed.has('filterText') ||
|
|
230
|
-
changed.has('aggregations') ||
|
|
231
|
-
changed.has('facetKey') ||
|
|
232
|
-
changed.has('sortedBy') ||
|
|
233
|
-
changed.has('selectedFacets') ||
|
|
234
|
-
changed.has('unappliedFacetChanges')
|
|
235
|
-
) {
|
|
236
|
-
if (!this.usePagination) {
|
|
237
|
-
this.attachScrollListener();
|
|
238
|
-
// Refresh scroll state whenever content may have changed (e.g., filtering)
|
|
239
|
-
requestAnimationFrame(() => this.updateScrollState());
|
|
240
|
-
} else {
|
|
241
|
-
this.removeScrollListener();
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
162
|
}
|
|
245
163
|
|
|
246
|
-
private resizeObserver?: ResizeObserver;
|
|
247
|
-
|
|
248
164
|
firstUpdated(): void {
|
|
249
165
|
this.setupEscapeListeners();
|
|
250
|
-
this.setupCompactViewObserver();
|
|
251
|
-
this.constrainToScrollContainer();
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
disconnectedCallback(): void {
|
|
255
|
-
super.disconnectedCallback();
|
|
256
|
-
this.resizeObserver?.disconnect();
|
|
257
|
-
this.removeScrollListener();
|
|
258
|
-
document.removeEventListener('keydown', this.escapeHandler);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
private scrollHandler = () => this.updateScrollState();
|
|
262
|
-
|
|
263
|
-
private scrollListenerAttached = false;
|
|
264
|
-
|
|
265
|
-
private scrollListenerTarget?: HTMLElement;
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* Attaches a scroll event listener to the facets content element
|
|
269
|
-
* to track horizontal scroll position for arrow button states.
|
|
270
|
-
*/
|
|
271
|
-
private attachScrollListener(): void {
|
|
272
|
-
if (this.scrollListenerAttached || !this.facetsContentEl) return;
|
|
273
|
-
this.scrollListenerTarget = this.facetsContentEl;
|
|
274
|
-
this.scrollListenerTarget.addEventListener('scroll', this.scrollHandler, {
|
|
275
|
-
passive: true,
|
|
276
|
-
});
|
|
277
|
-
this.scrollListenerAttached = true;
|
|
278
|
-
// Defer initial state check until after browser layout, so scrollWidth
|
|
279
|
-
// reflects the actual content dimensions.
|
|
280
|
-
requestAnimationFrame(() => this.updateScrollState());
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
private removeScrollListener(): void {
|
|
284
|
-
if (!this.scrollListenerAttached || !this.scrollListenerTarget) return;
|
|
285
|
-
this.scrollListenerTarget.removeEventListener('scroll', this.scrollHandler);
|
|
286
|
-
this.scrollListenerTarget = undefined;
|
|
287
|
-
this.scrollListenerAttached = false;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
/**
|
|
291
|
-
* Updates the scroll arrow disabled states based on current scroll position.
|
|
292
|
-
*/
|
|
293
|
-
private updateScrollState(): void {
|
|
294
|
-
const el = this.facetsContentEl;
|
|
295
|
-
if (!el) return;
|
|
296
|
-
this.atScrollStart = el.scrollLeft <= 0;
|
|
297
|
-
this.atScrollEnd = el.scrollLeft + el.clientWidth >= el.scrollWidth - 1;
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
/**
|
|
301
|
-
* Calculates the width of one column step (column width + gap) based on
|
|
302
|
-
* the CSS multi-column layout of the scroll container.
|
|
303
|
-
*/
|
|
304
|
-
private getColumnStep(): number {
|
|
305
|
-
const el = this.facetsContentEl;
|
|
306
|
-
if (!el) return 0;
|
|
307
|
-
// Column step = column width + gap = (visible width + gap) / column count
|
|
308
|
-
return (el.clientWidth + MoreFacetsContent.COLUMN_GAP) / this.columnCount;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
/**
|
|
312
|
-
* Snaps a scroll target to the nearest column boundary.
|
|
313
|
-
*/
|
|
314
|
-
private snapToColumn(target: number): number {
|
|
315
|
-
const step = this.getColumnStep();
|
|
316
|
-
if (step <= 0) return target;
|
|
317
|
-
return Math.round(target / step) * step;
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
/**
|
|
321
|
-
* Scrolls the facet content left by approximately one page, snapping to
|
|
322
|
-
* the nearest column boundary.
|
|
323
|
-
*/
|
|
324
|
-
private onScrollLeft(): void {
|
|
325
|
-
const el = this.facetsContentEl;
|
|
326
|
-
if (!el) return;
|
|
327
|
-
const rawTarget = el.scrollLeft - el.clientWidth;
|
|
328
|
-
const snapped = Math.max(0, this.snapToColumn(rawTarget));
|
|
329
|
-
el.scrollTo({ left: snapped, behavior: 'smooth' });
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
/**
|
|
333
|
-
* Scrolls the facet content right by approximately one page, snapping to
|
|
334
|
-
* the nearest column boundary.
|
|
335
|
-
*/
|
|
336
|
-
private onScrollRight(): void {
|
|
337
|
-
const el = this.facetsContentEl;
|
|
338
|
-
if (!el) return;
|
|
339
|
-
const maxScroll = el.scrollWidth - el.clientWidth;
|
|
340
|
-
const rawTarget = el.scrollLeft + el.clientWidth;
|
|
341
|
-
const snapped = Math.min(maxScroll, this.snapToColumn(rawTarget));
|
|
342
|
-
el.scrollTo({ left: snapped, behavior: 'smooth' });
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
/**
|
|
346
|
-
* Sets up a ResizeObserver to toggle compact pagination based on component width.
|
|
347
|
-
*/
|
|
348
|
-
private setupCompactViewObserver(): void {
|
|
349
|
-
this.resizeObserver = new ResizeObserver(entries => {
|
|
350
|
-
for (const entry of entries) {
|
|
351
|
-
const compact = entry.contentRect.width <= 560;
|
|
352
|
-
if (this.isCompactView !== compact) this.isCompactView = compact;
|
|
353
|
-
}
|
|
354
|
-
});
|
|
355
|
-
this.resizeObserver.observe(this);
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
/**
|
|
359
|
-
* Constrains the section's max-height to fit within the nearest
|
|
360
|
-
* scroll-container ancestor (e.g., the modal's content area).
|
|
361
|
-
* This is a safety net for cases where the CSS max-height calculation
|
|
362
|
-
* doesn't perfectly match the container's available space.
|
|
363
|
-
*/
|
|
364
|
-
private constrainToScrollContainer(): void {
|
|
365
|
-
requestAnimationFrame(() => {
|
|
366
|
-
const section = this.shadowRoot?.querySelector(
|
|
367
|
-
'section#more-facets',
|
|
368
|
-
) as HTMLElement;
|
|
369
|
-
if (!section) return;
|
|
370
|
-
|
|
371
|
-
// Walk up from the assigned slot to find the nearest overflow container
|
|
372
|
-
let el = this.assignedSlot?.parentElement;
|
|
373
|
-
while (el) {
|
|
374
|
-
const cs = getComputedStyle(el);
|
|
375
|
-
if (
|
|
376
|
-
cs.overflowY === 'auto' ||
|
|
377
|
-
cs.overflowY === 'scroll' ||
|
|
378
|
-
cs.overflowY === 'hidden'
|
|
379
|
-
) {
|
|
380
|
-
const containerBottom = el.getBoundingClientRect().bottom;
|
|
381
|
-
const sectionTop = section.getBoundingClientRect().top;
|
|
382
|
-
const available = containerBottom - sectionTop;
|
|
383
|
-
// Compare against the CSS max-height rather than actual height,
|
|
384
|
-
// since content may not have loaded yet at firstUpdated time
|
|
385
|
-
const computedMax = parseFloat(getComputedStyle(section).maxHeight);
|
|
386
|
-
if (available > 0 && available < computedMax) {
|
|
387
|
-
section.style.maxHeight = `${available}px`;
|
|
388
|
-
}
|
|
389
|
-
return;
|
|
390
|
-
}
|
|
391
|
-
el = el.parentElement;
|
|
392
|
-
}
|
|
393
|
-
});
|
|
394
166
|
}
|
|
395
167
|
|
|
396
168
|
/**
|
|
397
169
|
* Close more facets modal on Escape click
|
|
398
170
|
*/
|
|
399
|
-
private escapeHandler = (e: KeyboardEvent) => {
|
|
400
|
-
if (e.key === 'Escape') this.modalManager?.closeModal();
|
|
401
|
-
};
|
|
402
|
-
|
|
403
171
|
private setupEscapeListeners() {
|
|
404
172
|
if (this.modalManager) {
|
|
405
|
-
document.addEventListener('keydown',
|
|
173
|
+
document.addEventListener('keydown', (e: KeyboardEvent) => {
|
|
174
|
+
if (e.key === 'Escape') {
|
|
175
|
+
this.modalManager?.closeModal();
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
} else {
|
|
179
|
+
document.removeEventListener('keydown', () => {});
|
|
406
180
|
}
|
|
407
181
|
}
|
|
408
182
|
|
|
@@ -441,21 +215,34 @@ export class MoreFacetsContent extends LitElement {
|
|
|
441
215
|
rows: 0, // todo - do we want server-side pagination with offset/page/limit flag?
|
|
442
216
|
};
|
|
443
217
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
218
|
+
const results = await this.searchService?.search(params, this.searchType);
|
|
219
|
+
this.aggregations = results?.success?.response.aggregations;
|
|
220
|
+
this.facetsLoading = false;
|
|
447
221
|
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
}
|
|
222
|
+
const collectionTitles = results?.success?.response?.collectionTitles;
|
|
223
|
+
if (collectionTitles) {
|
|
224
|
+
for (const [id, title] of Object.entries(collectionTitles)) {
|
|
225
|
+
this.collectionTitles?.set(id, title);
|
|
453
226
|
}
|
|
454
|
-
} finally {
|
|
455
|
-
this.facetsLoading = false;
|
|
456
227
|
}
|
|
457
228
|
}
|
|
458
229
|
|
|
230
|
+
/**
|
|
231
|
+
* Handler for page number changes from the pagination widget.
|
|
232
|
+
*/
|
|
233
|
+
private pageNumberClicked(e: CustomEvent<{ page: number }>) {
|
|
234
|
+
const page = e?.detail?.page;
|
|
235
|
+
if (page) {
|
|
236
|
+
this.pageNumber = Number(page);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
this.analyticsHandler?.sendEvent({
|
|
240
|
+
category: analyticsCategories.default,
|
|
241
|
+
action: analyticsActions.moreFacetsPageChange,
|
|
242
|
+
label: `${this.pageNumber}`,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
459
246
|
/**
|
|
460
247
|
* Combines the selected facets with the aggregations to create a single list of facets
|
|
461
248
|
*/
|
|
@@ -537,10 +324,7 @@ export class MoreFacetsContent extends LitElement {
|
|
|
537
324
|
|
|
538
325
|
const buckets: FacetBucket[] = Object.entries(selectedFacetsForKey).map(
|
|
539
326
|
([value, data]) => {
|
|
540
|
-
const displayText =
|
|
541
|
-
(this.facetKey === 'collection'
|
|
542
|
-
? this.collectionTitles?.get(value)
|
|
543
|
-
: undefined) ?? value;
|
|
327
|
+
const displayText: string = value;
|
|
544
328
|
return {
|
|
545
329
|
displayText,
|
|
546
330
|
key: value,
|
|
@@ -584,33 +368,17 @@ export class MoreFacetsContent extends LitElement {
|
|
|
584
368
|
});
|
|
585
369
|
}
|
|
586
370
|
|
|
587
|
-
// Construct the array of facet buckets from the aggregation buckets
|
|
588
|
-
// using collection display titles where available.
|
|
371
|
+
// Construct the array of facet buckets from the aggregation buckets
|
|
589
372
|
const facetBuckets: FacetBucket[] = sortedBuckets.map(bucket => {
|
|
590
373
|
const bucketKeyStr = `${bucket.key}`;
|
|
591
|
-
const displayText =
|
|
592
|
-
(this.facetKey === 'collection'
|
|
593
|
-
? this.collectionTitles?.get(bucketKeyStr)
|
|
594
|
-
: undefined) ?? bucketKeyStr;
|
|
595
374
|
return {
|
|
596
|
-
displayText
|
|
375
|
+
displayText: `${bucketKeyStr}`,
|
|
597
376
|
key: `${bucketKeyStr}`,
|
|
598
377
|
count: bucket.doc_count,
|
|
599
378
|
state: 'none',
|
|
600
379
|
};
|
|
601
380
|
});
|
|
602
381
|
|
|
603
|
-
// For collection facets sorted alphabetically, re-sort by display title
|
|
604
|
-
// instead of the raw identifier used by getSortedBuckets.
|
|
605
|
-
if (
|
|
606
|
-
this.facetKey === 'collection' &&
|
|
607
|
-
this.sortedBy === AggregationSortType.ALPHABETICAL
|
|
608
|
-
) {
|
|
609
|
-
facetBuckets.sort((a, b) =>
|
|
610
|
-
(a.displayText ?? a.key).localeCompare(b.displayText ?? b.key),
|
|
611
|
-
);
|
|
612
|
-
}
|
|
613
|
-
|
|
614
382
|
return {
|
|
615
383
|
title: facetGroupTitle,
|
|
616
384
|
key: this.facetKey,
|
|
@@ -619,81 +387,29 @@ export class MoreFacetsContent extends LitElement {
|
|
|
619
387
|
}
|
|
620
388
|
|
|
621
389
|
/**
|
|
622
|
-
* Returns
|
|
623
|
-
* Filters are applied to the full bucket list before pagination.
|
|
390
|
+
* Returns a FacetGroup representing only the current page of facet buckets to show.
|
|
624
391
|
*/
|
|
625
|
-
private get
|
|
626
|
-
const { facetGroup
|
|
392
|
+
private get facetGroupForCurrentPage(): FacetGroup | undefined {
|
|
393
|
+
const { facetGroup } = this;
|
|
627
394
|
if (!facetGroup) return undefined;
|
|
628
395
|
|
|
629
|
-
//
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
// For collections, match against the displayed collection title (not the identifier).
|
|
636
|
-
// For other facet types, match against the bucket key (which is also the display text).
|
|
637
|
-
const lowerFilter = filterText.toLowerCase().trim();
|
|
638
|
-
const filteredBuckets = facetGroup.buckets.filter(bucket => {
|
|
639
|
-
const displayText = this.collectionTitles?.get(bucket.key) ?? bucket.key;
|
|
640
|
-
return displayText.toLowerCase().includes(lowerFilter);
|
|
641
|
-
});
|
|
396
|
+
// Slice out only the current page of facet buckets
|
|
397
|
+
const firstBucketIndexOnPage = (this.pageNumber - 1) * this.facetsPerPage;
|
|
398
|
+
const truncatedBuckets = facetGroup.buckets.slice(
|
|
399
|
+
firstBucketIndexOnPage,
|
|
400
|
+
firstBucketIndexOnPage + this.facetsPerPage,
|
|
401
|
+
);
|
|
642
402
|
|
|
643
403
|
return {
|
|
644
404
|
...facetGroup,
|
|
645
|
-
buckets:
|
|
646
|
-
};
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
/**
|
|
650
|
-
* Determines whether to use pagination based on the number of filtered facets.
|
|
651
|
-
* Returns true if facet count >= PAGINATION_THRESHOLD, false otherwise.
|
|
652
|
-
*/
|
|
653
|
-
private get usePagination(): boolean {
|
|
654
|
-
const facetCount = this.filteredFacetGroup?.buckets.length ?? 0;
|
|
655
|
-
return facetCount >= PAGINATION_THRESHOLD;
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
/**
|
|
659
|
-
* Returns the facet group for the current page.
|
|
660
|
-
* If using pagination (>= 1000 facets), slices to show only the current page.
|
|
661
|
-
* Otherwise, returns all facets for horizontal scrolling.
|
|
662
|
-
*/
|
|
663
|
-
private get facetGroupForCurrentPage(): FacetGroup | undefined {
|
|
664
|
-
const filteredGroup = this.filteredFacetGroup;
|
|
665
|
-
if (!filteredGroup) return undefined;
|
|
666
|
-
|
|
667
|
-
// If facet count is below threshold, show all facets with horizontal scroll
|
|
668
|
-
if (!this.usePagination) {
|
|
669
|
-
return filteredGroup;
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
// Otherwise, use pagination - slice to current page
|
|
673
|
-
const startIndex = (this.pageNumber - 1) * this.facetsPerPage;
|
|
674
|
-
const endIndex = startIndex + this.facetsPerPage;
|
|
675
|
-
const slicedBuckets = filteredGroup.buckets.slice(startIndex, endIndex);
|
|
676
|
-
|
|
677
|
-
return {
|
|
678
|
-
...filteredGroup,
|
|
679
|
-
buckets: slicedBuckets,
|
|
405
|
+
buckets: truncatedBuckets,
|
|
680
406
|
};
|
|
681
407
|
}
|
|
682
408
|
|
|
683
409
|
private get moreFacetsTemplate(): TemplateResult {
|
|
684
|
-
const facetGroup = this.facetGroupForCurrentPage;
|
|
685
|
-
|
|
686
|
-
// Show empty state if filtering returned no results
|
|
687
|
-
if (
|
|
688
|
-
this.filterText.trim() &&
|
|
689
|
-
(!facetGroup || facetGroup.buckets.length === 0)
|
|
690
|
-
) {
|
|
691
|
-
return this.emptyFilterResultsTemplate;
|
|
692
|
-
}
|
|
693
|
-
|
|
694
410
|
return html`
|
|
695
411
|
<facets-template
|
|
696
|
-
.facetGroup=${
|
|
412
|
+
.facetGroup=${this.facetGroupForCurrentPage}
|
|
697
413
|
.selectedFacets=${this.selectedFacets}
|
|
698
414
|
.collectionTitles=${this.collectionTitles}
|
|
699
415
|
@facetClick=${(e: CustomEvent<FacetEventDetails>) => {
|
|
@@ -718,51 +434,50 @@ export class MoreFacetsContent extends LitElement {
|
|
|
718
434
|
`;
|
|
719
435
|
}
|
|
720
436
|
|
|
721
|
-
private get emptyFilterResultsTemplate(): TemplateResult {
|
|
722
|
-
return html`
|
|
723
|
-
<div class="empty-results">
|
|
724
|
-
<p>${msg('No matching values found.')}</p>
|
|
725
|
-
<p class="hint">${msg('Try a different search term.')}</p>
|
|
726
|
-
</div>
|
|
727
|
-
`;
|
|
728
|
-
}
|
|
729
|
-
|
|
730
437
|
/**
|
|
731
|
-
*
|
|
438
|
+
* How many pages of facets to show in the modal pagination widget
|
|
732
439
|
*/
|
|
733
440
|
private get paginationSize(): number {
|
|
734
|
-
|
|
735
|
-
|
|
441
|
+
if (!this.aggregations || !this.facetKey) return 0;
|
|
442
|
+
|
|
443
|
+
// Calculate the appropriate number of pages to show in the modal pagination widget
|
|
444
|
+
const length = this.aggregations[this.facetKey]?.buckets.length;
|
|
445
|
+
return Math.ceil(length / this.facetsPerPage);
|
|
736
446
|
}
|
|
737
447
|
|
|
738
|
-
|
|
739
|
-
* Template for pagination component.
|
|
740
|
-
*/
|
|
448
|
+
// render pagination if more then 1 page
|
|
741
449
|
private get facetsPaginationTemplate() {
|
|
742
|
-
return
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
450
|
+
return this.paginationSize > 1
|
|
451
|
+
? html`<more-facets-pagination
|
|
452
|
+
.size=${this.paginationSize}
|
|
453
|
+
.currentPage=${1}
|
|
454
|
+
@pageNumberClicked=${this.pageNumberClicked}
|
|
455
|
+
></more-facets-pagination>`
|
|
456
|
+
: nothing;
|
|
748
457
|
}
|
|
749
458
|
|
|
750
459
|
private get footerTemplate() {
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
460
|
+
if (this.paginationSize > 0) {
|
|
461
|
+
return html`${this.facetsPaginationTemplate}
|
|
462
|
+
<div class="footer">
|
|
463
|
+
<button
|
|
464
|
+
class="btn btn-cancel"
|
|
465
|
+
type="button"
|
|
466
|
+
@click=${this.cancelClick}
|
|
467
|
+
>
|
|
468
|
+
Cancel
|
|
469
|
+
</button>
|
|
470
|
+
<button
|
|
471
|
+
class="btn btn-submit"
|
|
472
|
+
type="button"
|
|
473
|
+
@click=${this.applySearchFacetsClicked}
|
|
474
|
+
>
|
|
475
|
+
Apply filters
|
|
476
|
+
</button>
|
|
477
|
+
</div> `;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
return nothing;
|
|
766
481
|
}
|
|
767
482
|
|
|
768
483
|
private sortFacetAggregation(facetSortType: AggregationSortType) {
|
|
@@ -772,44 +487,6 @@ export class MoreFacetsContent extends LitElement {
|
|
|
772
487
|
);
|
|
773
488
|
}
|
|
774
489
|
|
|
775
|
-
/**
|
|
776
|
-
* Handler for filter input changes. Updates the filter text and triggers re-render.
|
|
777
|
-
*/
|
|
778
|
-
private handleFilterInput(e: Event): void {
|
|
779
|
-
const input = e.target as HTMLElement & { value: string };
|
|
780
|
-
this.filterText = input.value;
|
|
781
|
-
}
|
|
782
|
-
|
|
783
|
-
/**
|
|
784
|
-
* Handler for when the filter input is cleared via the clear button.
|
|
785
|
-
*/
|
|
786
|
-
private handleFilterClear(): void {
|
|
787
|
-
this.filterText = '';
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
/**
|
|
791
|
-
* Handler for pagination page number clicks.
|
|
792
|
-
* Only used when facet count >= PAGINATION_THRESHOLD.
|
|
793
|
-
*/
|
|
794
|
-
private pageNumberClicked(e: CustomEvent<{ page: number }>) {
|
|
795
|
-
this.pageNumber = e.detail.page;
|
|
796
|
-
|
|
797
|
-
// Track page navigation in analytics
|
|
798
|
-
this.analyticsHandler?.sendEvent({
|
|
799
|
-
category: analyticsCategories.default,
|
|
800
|
-
action: analyticsActions.moreFacetsPageChange,
|
|
801
|
-
label: `${this.pageNumber}`,
|
|
802
|
-
});
|
|
803
|
-
|
|
804
|
-
this.dispatchEvent(
|
|
805
|
-
new CustomEvent('pageChanged', {
|
|
806
|
-
detail: this.pageNumber,
|
|
807
|
-
bubbles: true,
|
|
808
|
-
composed: true,
|
|
809
|
-
}),
|
|
810
|
-
);
|
|
811
|
-
}
|
|
812
|
-
|
|
813
490
|
private get modalHeaderTemplate(): TemplateResult {
|
|
814
491
|
const facetSort =
|
|
815
492
|
this.sortedBy ?? defaultFacetSort[this.facetKey as FacetOption];
|
|
@@ -817,103 +494,36 @@ export class MoreFacetsContent extends LitElement {
|
|
|
817
494
|
facetSort === AggregationSortType.COUNT ? 'left' : 'right';
|
|
818
495
|
|
|
819
496
|
return html`<span class="sr-only">${msg('More facets for:')}</span>
|
|
820
|
-
<span class="title">
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
</span>
|
|
840
|
-
|
|
841
|
-
<span class="filter-controls">
|
|
842
|
-
<label class="filter-label">${msg('Filter by:')}</label>
|
|
843
|
-
<ia-clearable-text-input
|
|
844
|
-
class="filter-input"
|
|
845
|
-
.value=${this.filterText}
|
|
846
|
-
.placeholder=${msg('Search...')}
|
|
847
|
-
.screenReaderLabel=${msg('Filter facets')}
|
|
848
|
-
.clearButtonScreenReaderLabel=${msg('Clear filter')}
|
|
849
|
-
@input=${this.handleFilterInput}
|
|
850
|
-
@clear=${this.handleFilterClear}
|
|
851
|
-
></ia-clearable-text-input>
|
|
852
|
-
</span>
|
|
497
|
+
<span class="title">
|
|
498
|
+
${this.facetGroup?.title}
|
|
499
|
+
|
|
500
|
+
<label class="sort-label">${msg('Sort by:')}</label>
|
|
501
|
+
${this.facetKey
|
|
502
|
+
? html`<toggle-switch
|
|
503
|
+
class="sort-toggle"
|
|
504
|
+
leftValue=${AggregationSortType.COUNT}
|
|
505
|
+
leftLabel="Count"
|
|
506
|
+
rightValue=${valueFacetSort[this.facetKey]}
|
|
507
|
+
.rightLabel=${this.facetGroup?.title}
|
|
508
|
+
side=${defaultSwitchSide}
|
|
509
|
+
@change=${(e: CustomEvent<string>) => {
|
|
510
|
+
this.sortFacetAggregation(
|
|
511
|
+
Number(e.detail) as AggregationSortType,
|
|
512
|
+
);
|
|
513
|
+
}}
|
|
514
|
+
></toggle-switch>`
|
|
515
|
+
: nothing}
|
|
853
516
|
</span>`;
|
|
854
517
|
}
|
|
855
518
|
|
|
856
|
-
private get horizontalScrollTemplate(): TemplateResult {
|
|
857
|
-
const contentClasses = classMap({
|
|
858
|
-
'facets-content': true,
|
|
859
|
-
'horizontal-scroll-mode': true,
|
|
860
|
-
});
|
|
861
|
-
const showArrows = !this.atScrollStart || !this.atScrollEnd;
|
|
862
|
-
|
|
863
|
-
return html`<div class="scroll-nav-container">
|
|
864
|
-
${when(
|
|
865
|
-
showArrows,
|
|
866
|
-
() =>
|
|
867
|
-
html`<button
|
|
868
|
-
class="scroll-arrow scroll-left"
|
|
869
|
-
@click=${this.onScrollLeft}
|
|
870
|
-
?disabled=${this.atScrollStart}
|
|
871
|
-
aria-label="Scroll facets left"
|
|
872
|
-
>
|
|
873
|
-
${arrowLeftIcon}
|
|
874
|
-
</button>`,
|
|
875
|
-
)}
|
|
876
|
-
<div class=${contentClasses}>
|
|
877
|
-
<div class="facets-horizontal-container">
|
|
878
|
-
${this.moreFacetsTemplate}
|
|
879
|
-
</div>
|
|
880
|
-
</div>
|
|
881
|
-
${when(
|
|
882
|
-
showArrows,
|
|
883
|
-
() =>
|
|
884
|
-
html`<button
|
|
885
|
-
class="scroll-arrow scroll-right"
|
|
886
|
-
@click=${this.onScrollRight}
|
|
887
|
-
?disabled=${this.atScrollEnd}
|
|
888
|
-
aria-label="Scroll facets right"
|
|
889
|
-
>
|
|
890
|
-
${arrowRightIcon}
|
|
891
|
-
</button>`,
|
|
892
|
-
)}
|
|
893
|
-
</div>`;
|
|
894
|
-
}
|
|
895
|
-
|
|
896
519
|
render() {
|
|
897
|
-
const sectionClasses = classMap({
|
|
898
|
-
'pagination-mode': this.usePagination,
|
|
899
|
-
'horizontal-scroll-mode': !this.usePagination,
|
|
900
|
-
});
|
|
901
|
-
const contentClasses = classMap({
|
|
902
|
-
'facets-content': true,
|
|
903
|
-
'pagination-mode': this.usePagination,
|
|
904
|
-
});
|
|
905
|
-
|
|
906
520
|
return html`
|
|
907
521
|
${this.facetsLoading
|
|
908
522
|
? this.loaderTemplate
|
|
909
523
|
: html`
|
|
910
|
-
<section id="more-facets"
|
|
524
|
+
<section id="more-facets">
|
|
911
525
|
<div class="header-content">${this.modalHeaderTemplate}</div>
|
|
912
|
-
|
|
913
|
-
? html`<div class=${contentClasses}>
|
|
914
|
-
${this.moreFacetsTemplate}
|
|
915
|
-
</div>`
|
|
916
|
-
: this.horizontalScrollTemplate}
|
|
526
|
+
<div class="facets-content">${this.moreFacetsTemplate}</div>
|
|
917
527
|
${this.footerTemplate}
|
|
918
528
|
</section>
|
|
919
529
|
`}
|
|
@@ -936,9 +546,6 @@ export class MoreFacetsContent extends LitElement {
|
|
|
936
546
|
// Reset the unapplied changes back to default, now that they have been applied
|
|
937
547
|
this.unappliedFacetChanges = getDefaultSelectedFacets();
|
|
938
548
|
|
|
939
|
-
// Reset filter text
|
|
940
|
-
this.filterText = '';
|
|
941
|
-
|
|
942
549
|
this.modalManager?.closeModal();
|
|
943
550
|
this.analyticsHandler?.sendEvent({
|
|
944
551
|
category: analyticsCategories.default,
|
|
@@ -951,9 +558,6 @@ export class MoreFacetsContent extends LitElement {
|
|
|
951
558
|
// Reset the unapplied changes back to default
|
|
952
559
|
this.unappliedFacetChanges = getDefaultSelectedFacets();
|
|
953
560
|
|
|
954
|
-
// Reset filter text
|
|
955
|
-
this.filterText = '';
|
|
956
|
-
|
|
957
561
|
this.modalManager?.closeModal();
|
|
958
562
|
this.analyticsHandler?.sendEvent({
|
|
959
563
|
category: analyticsCategories.default,
|
|
@@ -969,26 +573,10 @@ export class MoreFacetsContent extends LitElement {
|
|
|
969
573
|
srOnlyStyle,
|
|
970
574
|
css`
|
|
971
575
|
section#more-facets {
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
max-height: calc(100vh - 16.5rem - var(--modalBottomMargin, 2.5rem));
|
|
975
|
-
padding: 10px;
|
|
976
|
-
box-sizing: border-box;
|
|
576
|
+
overflow: auto;
|
|
577
|
+
padding: 10px; /* leaves room for scroll bar to appear without overlaying on content */
|
|
977
578
|
--facetsColumnCount: 3;
|
|
978
579
|
}
|
|
979
|
-
|
|
980
|
-
/* Both modes need a height constraint for proper column flow */
|
|
981
|
-
section#more-facets.horizontal-scroll-mode,
|
|
982
|
-
section#more-facets.pagination-mode {
|
|
983
|
-
--facetsMaxHeight: 280px;
|
|
984
|
-
}
|
|
985
|
-
.header-content {
|
|
986
|
-
flex-shrink: 0;
|
|
987
|
-
position: relative;
|
|
988
|
-
z-index: 1;
|
|
989
|
-
background: #fff;
|
|
990
|
-
}
|
|
991
|
-
|
|
992
580
|
.header-content .title {
|
|
993
581
|
display: block;
|
|
994
582
|
text-align: left;
|
|
@@ -997,22 +585,8 @@ export class MoreFacetsContent extends LitElement {
|
|
|
997
585
|
font-weight: bold;
|
|
998
586
|
}
|
|
999
587
|
|
|
1000
|
-
.header-controls {
|
|
1001
|
-
display: flex;
|
|
1002
|
-
flex-wrap: wrap;
|
|
1003
|
-
align-items: center;
|
|
1004
|
-
gap: 8px 20px;
|
|
1005
|
-
padding: 0 10px 8px;
|
|
1006
|
-
}
|
|
1007
|
-
|
|
1008
|
-
.sort-controls {
|
|
1009
|
-
display: inline-flex;
|
|
1010
|
-
align-items: center;
|
|
1011
|
-
white-space: nowrap;
|
|
1012
|
-
gap: 5px;
|
|
1013
|
-
}
|
|
1014
|
-
|
|
1015
588
|
.sort-label {
|
|
589
|
+
margin-left: 20px;
|
|
1016
590
|
font-size: 1.3rem;
|
|
1017
591
|
}
|
|
1018
592
|
|
|
@@ -1020,115 +594,11 @@ export class MoreFacetsContent extends LitElement {
|
|
|
1020
594
|
font-weight: normal;
|
|
1021
595
|
}
|
|
1022
596
|
|
|
1023
|
-
.filter-controls {
|
|
1024
|
-
display: inline-flex;
|
|
1025
|
-
align-items: center;
|
|
1026
|
-
white-space: nowrap;
|
|
1027
|
-
}
|
|
1028
|
-
|
|
1029
|
-
.filter-label {
|
|
1030
|
-
font-size: 1.3rem;
|
|
1031
|
-
}
|
|
1032
|
-
|
|
1033
|
-
.filter-input {
|
|
1034
|
-
--input-height: 2.5rem;
|
|
1035
|
-
--input-font-size: 1.3rem;
|
|
1036
|
-
--input-border-radius: 4px;
|
|
1037
|
-
--input-padding: 4px 8px;
|
|
1038
|
-
--input-focused-border-color: ${modalSubmitButton};
|
|
1039
|
-
width: 150px;
|
|
1040
|
-
margin-left: 5px;
|
|
1041
|
-
}
|
|
1042
|
-
|
|
1043
|
-
.empty-results {
|
|
1044
|
-
text-align: center;
|
|
1045
|
-
padding: 40px 20px;
|
|
1046
|
-
color: #666;
|
|
1047
|
-
}
|
|
1048
|
-
|
|
1049
|
-
.empty-results .hint {
|
|
1050
|
-
margin-top: 10px;
|
|
1051
|
-
}
|
|
1052
|
-
|
|
1053
597
|
.facets-content {
|
|
1054
598
|
font-size: 1.2rem;
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
overflow-y: auto;
|
|
1058
|
-
overflow-x: hidden;
|
|
599
|
+
max-height: 300px;
|
|
600
|
+
overflow: auto;
|
|
1059
601
|
padding: 10px;
|
|
1060
|
-
/* Force scrollbar to always be visible */
|
|
1061
|
-
scrollbar-width: thin; /* Firefox */
|
|
1062
|
-
scrollbar-color: #888 #f1f1f1; /* Firefox - thumb and track colors */
|
|
1063
|
-
}
|
|
1064
|
-
|
|
1065
|
-
/* Horizontal scroll mode: horizontal scrolling only */
|
|
1066
|
-
.facets-content.horizontal-scroll-mode {
|
|
1067
|
-
overflow-x: auto;
|
|
1068
|
-
overflow-y: hidden;
|
|
1069
|
-
}
|
|
1070
|
-
|
|
1071
|
-
/* Webkit browsers scrollbar styling - always visible */
|
|
1072
|
-
.facets-content::-webkit-scrollbar {
|
|
1073
|
-
width: 12px; /* Vertical scrollbar width */
|
|
1074
|
-
height: 12px; /* Horizontal scrollbar height */
|
|
1075
|
-
}
|
|
1076
|
-
|
|
1077
|
-
.facets-content::-webkit-scrollbar-track {
|
|
1078
|
-
background: #f1f1f1;
|
|
1079
|
-
border-radius: 6px;
|
|
1080
|
-
}
|
|
1081
|
-
|
|
1082
|
-
.facets-content::-webkit-scrollbar-thumb {
|
|
1083
|
-
background: #888;
|
|
1084
|
-
border-radius: 6px;
|
|
1085
|
-
min-height: 30px; /* Ensure thumb is always visible when scrolling is possible */
|
|
1086
|
-
}
|
|
1087
|
-
|
|
1088
|
-
.facets-content::-webkit-scrollbar-thumb:hover {
|
|
1089
|
-
background: #555;
|
|
1090
|
-
}
|
|
1091
|
-
|
|
1092
|
-
/* Force corner to match track color */
|
|
1093
|
-
.facets-content::-webkit-scrollbar-corner {
|
|
1094
|
-
background: #f1f1f1;
|
|
1095
|
-
}
|
|
1096
|
-
|
|
1097
|
-
.facets-horizontal-container {
|
|
1098
|
-
display: inline-block;
|
|
1099
|
-
min-width: 100%;
|
|
1100
|
-
/* Allow natural width expansion based on content */
|
|
1101
|
-
width: fit-content;
|
|
1102
|
-
}
|
|
1103
|
-
|
|
1104
|
-
.scroll-nav-container {
|
|
1105
|
-
display: flex;
|
|
1106
|
-
align-items: center;
|
|
1107
|
-
flex: 1 1 auto;
|
|
1108
|
-
min-height: 0;
|
|
1109
|
-
}
|
|
1110
|
-
|
|
1111
|
-
.scroll-nav-container .facets-content {
|
|
1112
|
-
flex: 1 1 auto;
|
|
1113
|
-
min-width: 0;
|
|
1114
|
-
}
|
|
1115
|
-
|
|
1116
|
-
.scroll-arrow {
|
|
1117
|
-
background: none;
|
|
1118
|
-
border: none;
|
|
1119
|
-
cursor: pointer;
|
|
1120
|
-
padding: 5px;
|
|
1121
|
-
flex-shrink: 0;
|
|
1122
|
-
}
|
|
1123
|
-
|
|
1124
|
-
.scroll-arrow svg {
|
|
1125
|
-
height: 14px;
|
|
1126
|
-
fill: #2c2c2c;
|
|
1127
|
-
}
|
|
1128
|
-
|
|
1129
|
-
.scroll-arrow:disabled {
|
|
1130
|
-
opacity: 0.3;
|
|
1131
|
-
cursor: default;
|
|
1132
602
|
}
|
|
1133
603
|
.facets-loader {
|
|
1134
604
|
--icon-width: 70px;
|
|
@@ -1144,7 +614,6 @@ export class MoreFacetsContent extends LitElement {
|
|
|
1144
614
|
width: auto;
|
|
1145
615
|
border-radius: 4px;
|
|
1146
616
|
cursor: pointer;
|
|
1147
|
-
font-family: inherit;
|
|
1148
617
|
}
|
|
1149
618
|
.btn-cancel {
|
|
1150
619
|
background-color: #2c2c2c;
|
|
@@ -1154,37 +623,19 @@ export class MoreFacetsContent extends LitElement {
|
|
|
1154
623
|
background-color: ${modalSubmitButton};
|
|
1155
624
|
color: white;
|
|
1156
625
|
}
|
|
1157
|
-
more-facets-pagination {
|
|
1158
|
-
flex-shrink: 0;
|
|
1159
|
-
}
|
|
1160
|
-
|
|
1161
626
|
.footer {
|
|
1162
627
|
text-align: center;
|
|
1163
628
|
margin-top: 10px;
|
|
1164
|
-
flex-shrink: 0;
|
|
1165
629
|
}
|
|
1166
630
|
|
|
1167
631
|
@media (max-width: 560px) {
|
|
1168
|
-
section#more-facets
|
|
1169
|
-
|
|
1170
|
-
--facetsColumnCount: 1;
|
|
1171
|
-
--facetsMaxHeight: none; /* Remove fixed height for vertical scrolling */
|
|
632
|
+
section#more-facets {
|
|
633
|
+
max-height: 450px;
|
|
634
|
+
--facetsColumnCount: 1;
|
|
1172
635
|
}
|
|
1173
|
-
|
|
1174
|
-
.facets-content,
|
|
1175
|
-
.facets-content.horizontal-scroll-mode {
|
|
636
|
+
.facets-content {
|
|
1176
637
|
overflow-y: auto;
|
|
1177
|
-
|
|
1178
|
-
}
|
|
1179
|
-
.scroll-nav-container {
|
|
1180
|
-
display: contents; /* Remove wrapper from layout so section flex-column works */
|
|
1181
|
-
}
|
|
1182
|
-
.scroll-arrow {
|
|
1183
|
-
display: none;
|
|
1184
|
-
}
|
|
1185
|
-
.filter-input {
|
|
1186
|
-
width: 120px;
|
|
1187
|
-
--input-font-size: 1.2rem;
|
|
638
|
+
height: 300px;
|
|
1188
639
|
}
|
|
1189
640
|
}
|
|
1190
641
|
`,
|