@internetarchive/collection-browser 0.0.1-alpha.7 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. package/README.md +8 -11
  2. package/demo/app-root.ts +30 -96
  3. package/dist/demo/app-root.d.ts +3 -5
  4. package/dist/demo/app-root.js +28 -87
  5. package/dist/demo/app-root.js.map +1 -1
  6. package/dist/index.d.ts +6 -0
  7. package/dist/index.js +6 -0
  8. package/dist/index.js.map +1 -1
  9. package/dist/src/assets/img/icons/chevron.d.ts +2 -0
  10. package/dist/src/assets/img/icons/chevron.js +4 -0
  11. package/dist/src/assets/img/icons/chevron.js.map +1 -0
  12. package/dist/src/assets/img/icons/eye-closed.d.ts +2 -0
  13. package/dist/src/assets/img/icons/eye-closed.js +5 -0
  14. package/dist/src/assets/img/icons/eye-closed.js.map +1 -0
  15. package/dist/src/assets/img/icons/eye.d.ts +2 -0
  16. package/dist/src/assets/img/icons/eye.js +5 -0
  17. package/dist/src/assets/img/icons/eye.js.map +1 -0
  18. package/dist/src/assets/img/icons/mediatype/account.d.ts +1 -2
  19. package/dist/src/assets/img/icons/mediatype/account.js +6 -4
  20. package/dist/src/assets/img/icons/mediatype/account.js.map +1 -1
  21. package/dist/src/assets/img/icons/mediatype/audio.js +7 -4
  22. package/dist/src/assets/img/icons/mediatype/audio.js.map +1 -1
  23. package/dist/src/assets/img/icons/mediatype/collection.js +7 -4
  24. package/dist/src/assets/img/icons/mediatype/collection.js.map +1 -1
  25. package/dist/src/assets/img/icons/mediatype/data.d.ts +1 -0
  26. package/dist/src/assets/img/icons/mediatype/data.js +15 -0
  27. package/dist/src/assets/img/icons/mediatype/data.js.map +1 -0
  28. package/dist/src/assets/img/icons/mediatype/etree.js +10 -5
  29. package/dist/src/assets/img/icons/mediatype/etree.js.map +1 -1
  30. package/dist/src/assets/img/icons/mediatype/film.js +2 -1
  31. package/dist/src/assets/img/icons/mediatype/film.js.map +1 -1
  32. package/dist/src/assets/img/icons/mediatype/images.js +9 -6
  33. package/dist/src/assets/img/icons/mediatype/images.js.map +1 -1
  34. package/dist/src/assets/img/icons/mediatype/radio.d.ts +1 -0
  35. package/dist/src/assets/img/icons/mediatype/radio.js +15 -0
  36. package/dist/src/assets/img/icons/mediatype/radio.js.map +1 -0
  37. package/dist/src/assets/img/icons/mediatype/software.js +9 -6
  38. package/dist/src/assets/img/icons/mediatype/software.js.map +1 -1
  39. package/dist/src/assets/img/icons/mediatype/texts.js +9 -6
  40. package/dist/src/assets/img/icons/mediatype/texts.js.map +1 -1
  41. package/dist/src/assets/img/icons/mediatype/tv.js +10 -5
  42. package/dist/src/assets/img/icons/mediatype/tv.js.map +1 -1
  43. package/dist/src/assets/img/icons/mediatype/video.js +10 -6
  44. package/dist/src/assets/img/icons/mediatype/video.js.map +1 -1
  45. package/dist/src/assets/img/icons/mediatype/web.js +9 -6
  46. package/dist/src/assets/img/icons/mediatype/web.js.map +1 -1
  47. package/dist/src/collection-browser.d.ts +57 -20
  48. package/dist/src/collection-browser.js +511 -128
  49. package/dist/src/collection-browser.js.map +1 -1
  50. package/dist/src/collection-facets.d.ts +27 -6
  51. package/dist/src/collection-facets.js +316 -100
  52. package/dist/src/collection-facets.js.map +1 -1
  53. package/dist/src/language-code-handler/language-code-handler.d.ts +37 -0
  54. package/dist/src/language-code-handler/language-code-handler.js +27 -0
  55. package/dist/src/language-code-handler/language-code-handler.js.map +1 -0
  56. package/dist/src/language-code-handler/language-code-mapping.d.ts +1 -0
  57. package/dist/src/language-code-handler/language-code-mapping.js +563 -0
  58. package/dist/src/language-code-handler/language-code-mapping.js.map +1 -0
  59. package/dist/src/mediatype/mediatype-config.d.ts +3 -0
  60. package/dist/src/mediatype/mediatype-config.js +86 -0
  61. package/dist/src/mediatype/mediatype-config.js.map +1 -0
  62. package/dist/src/models.d.ts +72 -13
  63. package/dist/src/models.js +57 -1
  64. package/dist/src/models.js.map +1 -1
  65. package/dist/src/restoration-state-handler.d.ts +38 -0
  66. package/dist/src/restoration-state-handler.js +204 -0
  67. package/dist/src/restoration-state-handler.js.map +1 -0
  68. package/dist/src/sort-filter-bar/alpha-bar.d.ts +1 -2
  69. package/dist/src/sort-filter-bar/alpha-bar.js +12 -8
  70. package/dist/src/sort-filter-bar/alpha-bar.js.map +1 -1
  71. package/dist/src/sort-filter-bar/img/compact.d.ts +1 -0
  72. package/dist/src/sort-filter-bar/img/compact.js +5 -0
  73. package/dist/src/sort-filter-bar/img/compact.js.map +1 -0
  74. package/dist/src/sort-filter-bar/img/list.d.ts +1 -0
  75. package/dist/src/sort-filter-bar/img/list.js +5 -0
  76. package/dist/src/sort-filter-bar/img/list.js.map +1 -0
  77. package/dist/src/sort-filter-bar/img/sort-triangle.d.ts +1 -0
  78. package/dist/src/sort-filter-bar/img/sort-triangle.js +5 -0
  79. package/dist/src/sort-filter-bar/img/sort-triangle.js.map +1 -0
  80. package/dist/src/sort-filter-bar/img/tile.d.ts +1 -0
  81. package/dist/src/sort-filter-bar/img/tile.js +5 -0
  82. package/dist/src/sort-filter-bar/img/tile.js.map +1 -0
  83. package/dist/src/sort-filter-bar/sort-filter-bar.d.ts +74 -13
  84. package/dist/src/sort-filter-bar/sort-filter-bar.js +547 -172
  85. package/dist/src/sort-filter-bar/sort-filter-bar.js.map +1 -1
  86. package/dist/src/tiles/{loading-tile.d.ts → collection-browser-loading-tile.d.ts} +1 -1
  87. package/dist/src/tiles/collection-browser-loading-tile.js +32 -0
  88. package/dist/src/tiles/collection-browser-loading-tile.js.map +1 -0
  89. package/dist/src/tiles/grid/account-tile.d.ts +1 -1
  90. package/dist/src/tiles/grid/account-tile.js +5 -5
  91. package/dist/src/tiles/grid/account-tile.js.map +1 -1
  92. package/dist/src/tiles/grid/collection-tile.js +1 -2
  93. package/dist/src/tiles/grid/collection-tile.js.map +1 -1
  94. package/dist/src/tiles/grid/icons/views.d.ts +1 -1
  95. package/dist/src/tiles/grid/icons/views.js +2 -2
  96. package/dist/src/tiles/grid/icons/views.js.map +1 -1
  97. package/dist/src/tiles/grid/item-tile.d.ts +2 -2
  98. package/dist/src/tiles/grid/item-tile.js +58 -150
  99. package/dist/src/tiles/grid/item-tile.js.map +1 -1
  100. package/dist/src/tiles/item-image.d.ts +19 -0
  101. package/dist/src/tiles/item-image.js +204 -0
  102. package/dist/src/tiles/item-image.js.map +1 -0
  103. package/dist/src/tiles/list/account-label.d.ts +1 -0
  104. package/dist/src/tiles/list/account-label.js +7 -0
  105. package/dist/src/tiles/list/account-label.js.map +1 -0
  106. package/dist/src/tiles/list/date-label.d.ts +1 -0
  107. package/dist/src/tiles/list/date-label.js +13 -0
  108. package/dist/src/tiles/list/date-label.js.map +1 -0
  109. package/dist/src/tiles/list/tile-list-compact-header.d.ts +12 -0
  110. package/dist/src/tiles/list/tile-list-compact-header.js +84 -0
  111. package/dist/src/tiles/list/tile-list-compact-header.js.map +1 -0
  112. package/dist/src/tiles/list/tile-list-compact.d.ts +12 -0
  113. package/dist/src/tiles/list/tile-list-compact.js +203 -6
  114. package/dist/src/tiles/list/tile-list-compact.js.map +1 -1
  115. package/dist/src/tiles/list/tile-list.d.ts +35 -10
  116. package/dist/src/tiles/list/tile-list.js +368 -104
  117. package/dist/src/tiles/list/tile-list.js.map +1 -1
  118. package/dist/src/{mediatype-icon.d.ts → tiles/mediatype-icon.d.ts} +2 -2
  119. package/dist/src/tiles/mediatype-icon.js +78 -0
  120. package/dist/src/tiles/mediatype-icon.js.map +1 -0
  121. package/dist/src/tiles/tile-dispatcher.d.ts +11 -4
  122. package/dist/src/tiles/tile-dispatcher.js +56 -19
  123. package/dist/src/tiles/tile-dispatcher.js.map +1 -1
  124. package/dist/src/utils/format-date.js +2 -2
  125. package/dist/src/utils/format-date.js.map +1 -1
  126. package/dist/test/collection-browser.test.d.ts +1 -0
  127. package/dist/test/collection-browser.test.js +16 -2
  128. package/dist/test/collection-browser.test.js.map +1 -1
  129. package/dist/test/{utils/format-string.test.d.ts → mediatype-config.test.d.ts} +0 -0
  130. package/dist/test/mediatype-config.test.js +17 -0
  131. package/dist/test/mediatype-config.test.js.map +1 -0
  132. package/dist/test/utils/format-date.test.js +1 -1
  133. package/dist/test/utils/format-date.test.js.map +1 -1
  134. package/index.ts +6 -0
  135. package/local.archive.org.cert +86 -0
  136. package/local.archive.org.key +27 -0
  137. package/package.json +9 -5
  138. package/src/assets/img/icons/chevron.ts +4 -0
  139. package/src/assets/img/icons/eye-closed.ts +5 -0
  140. package/src/assets/img/icons/eye.ts +5 -0
  141. package/src/assets/img/icons/mediatype/account.ts +6 -4
  142. package/src/assets/img/icons/mediatype/audio.ts +7 -4
  143. package/src/assets/img/icons/mediatype/collection.ts +7 -4
  144. package/src/assets/img/icons/mediatype/data.ts +15 -0
  145. package/src/assets/img/icons/mediatype/etree.ts +10 -5
  146. package/src/assets/img/icons/mediatype/film.ts +2 -1
  147. package/src/assets/img/icons/mediatype/images.ts +9 -6
  148. package/src/assets/img/icons/mediatype/radio.ts +15 -0
  149. package/src/assets/img/icons/mediatype/software.ts +9 -6
  150. package/src/assets/img/icons/mediatype/texts.ts +9 -6
  151. package/src/assets/img/icons/mediatype/tv.ts +10 -5
  152. package/src/assets/img/icons/mediatype/video.ts +10 -6
  153. package/src/assets/img/icons/mediatype/web.ts +9 -6
  154. package/src/collection-browser.ts +537 -123
  155. package/src/collection-facets.ts +352 -132
  156. package/src/language-code-handler/language-code-handler.ts +64 -0
  157. package/src/language-code-handler/language-code-mapping.ts +564 -0
  158. package/src/mediatype/mediatype-config.ts +86 -0
  159. package/src/models.ts +141 -13
  160. package/src/restoration-state-handler.ts +266 -0
  161. package/src/sort-filter-bar/alpha-bar.ts +12 -8
  162. package/src/sort-filter-bar/img/compact.ts +5 -0
  163. package/src/sort-filter-bar/img/list.ts +5 -0
  164. package/src/sort-filter-bar/img/sort-triangle.ts +5 -0
  165. package/src/sort-filter-bar/img/tile.ts +5 -0
  166. package/src/sort-filter-bar/sort-filter-bar.ts +604 -176
  167. package/src/tiles/collection-browser-loading-tile.ts +29 -0
  168. package/src/tiles/grid/account-tile.ts +1 -1
  169. package/src/tiles/grid/collection-tile.ts +1 -2
  170. package/src/tiles/grid/icons/views.ts +2 -2
  171. package/src/tiles/grid/item-tile.ts +57 -162
  172. package/src/tiles/item-image.ts +206 -0
  173. package/src/tiles/list/account-label.ts +6 -0
  174. package/src/tiles/list/date-label.ts +12 -0
  175. package/src/tiles/list/tile-list-compact-header.ts +77 -0
  176. package/src/tiles/list/tile-list-compact.ts +218 -0
  177. package/src/tiles/list/tile-list.ts +412 -107
  178. package/src/tiles/mediatype-icon.ts +75 -0
  179. package/src/tiles/tile-dispatcher.ts +66 -18
  180. package/src/utils/format-date.ts +2 -2
  181. package/test/collection-browser.test.ts +20 -1
  182. package/test/mediatype-config.test.ts +18 -0
  183. package/test/utils/format-date.test.ts +1 -1
  184. package/web-dev-server.config.mjs +3 -1
  185. package/dist/src/assets/img/icons/audio.d.ts +0 -1
  186. package/dist/src/assets/img/icons/audio.js +0 -9
  187. package/dist/src/assets/img/icons/audio.js.map +0 -1
  188. package/dist/src/assets/img/icons/collection.d.ts +0 -1
  189. package/dist/src/assets/img/icons/collection.js +0 -9
  190. package/dist/src/assets/img/icons/collection.js.map +0 -1
  191. package/dist/src/assets/img/icons/etree.d.ts +0 -1
  192. package/dist/src/assets/img/icons/etree.js +0 -9
  193. package/dist/src/assets/img/icons/etree.js.map +0 -1
  194. package/dist/src/assets/img/icons/images.d.ts +0 -1
  195. package/dist/src/assets/img/icons/images.js +0 -10
  196. package/dist/src/assets/img/icons/images.js.map +0 -1
  197. package/dist/src/assets/img/icons/mediatype/etree copy.d.ts +0 -1
  198. package/dist/src/assets/img/icons/mediatype/etree copy.js +0 -9
  199. package/dist/src/assets/img/icons/mediatype/etree copy.js.map +0 -1
  200. package/dist/src/assets/img/icons/mediatype/livemusic.d.ts +0 -1
  201. package/dist/src/assets/img/icons/mediatype/livemusic.js +0 -7
  202. package/dist/src/assets/img/icons/mediatype/livemusic.js.map +0 -1
  203. package/dist/src/assets/img/icons/mediatype/photos.d.ts +0 -1
  204. package/dist/src/assets/img/icons/mediatype/photos.js +0 -7
  205. package/dist/src/assets/img/icons/mediatype/photos.js.map +0 -1
  206. package/dist/src/assets/img/icons/software.d.ts +0 -1
  207. package/dist/src/assets/img/icons/software.js +0 -10
  208. package/dist/src/assets/img/icons/software.js.map +0 -1
  209. package/dist/src/assets/img/icons/texts.d.ts +0 -1
  210. package/dist/src/assets/img/icons/texts.js +0 -10
  211. package/dist/src/assets/img/icons/texts.js.map +0 -1
  212. package/dist/src/assets/img/icons/tv.d.ts +0 -1
  213. package/dist/src/assets/img/icons/tv.js +0 -9
  214. package/dist/src/assets/img/icons/tv.js.map +0 -1
  215. package/dist/src/assets/img/icons/video.d.ts +0 -1
  216. package/dist/src/assets/img/icons/video.js +0 -10
  217. package/dist/src/assets/img/icons/video.js.map +0 -1
  218. package/dist/src/assets/img/icons/web.d.ts +0 -1
  219. package/dist/src/assets/img/icons/web.js +0 -10
  220. package/dist/src/assets/img/icons/web.js.map +0 -1
  221. package/dist/src/mediatype-icon.js +0 -89
  222. package/dist/src/mediatype-icon.js.map +0 -1
  223. package/dist/src/search-handler.d.ts +0 -11
  224. package/dist/src/search-handler.js +0 -34
  225. package/dist/src/search-handler.js.map +0 -1
  226. package/dist/src/tiles/list/tile-list-detail.d.ts +0 -7
  227. package/dist/src/tiles/list/tile-list-detail.js +0 -28
  228. package/dist/src/tiles/list/tile-list-detail.js.map +0 -1
  229. package/dist/src/tiles/loading-tile.js +0 -73
  230. package/dist/src/tiles/loading-tile.js.map +0 -1
  231. package/dist/src/utils/format-string.d.ts +0 -2
  232. package/dist/src/utils/format-string.js +0 -7
  233. package/dist/src/utils/format-string.js.map +0 -1
  234. package/dist/test/utils/format-string.test.js +0 -17
  235. package/dist/test/utils/format-string.test.js.map +0 -1
  236. package/src/assets/img/icons/mediatype/foo.svg +0 -5
  237. package/src/mediatype-icon.ts +0 -83
  238. package/src/tiles/loading-tile.ts +0 -70
@@ -8,36 +8,54 @@ import {
8
8
  nothing,
9
9
  } from 'lit';
10
10
  import { customElement, property, query, state } from 'lit/decorators.js';
11
+ import { ifDefined } from 'lit/directives/if-defined.js';
11
12
  import type {
12
13
  InfiniteScroller,
13
14
  InfiniteScrollerCellProviderInterface,
14
15
  } from '@internetarchive/infinite-scroller';
15
- import {
16
+ import type {
16
17
  Aggregation,
17
18
  Metadata,
18
19
  SearchParams,
19
20
  SearchServiceInterface,
21
+ SortDirection,
22
+ SortParam,
20
23
  } from '@internetarchive/search-service';
21
24
  import {
22
- AggregateSearchParams,
23
- SortParam,
24
- } from '@internetarchive/search-service/dist/src/search-params';
25
- import { SharedResizeObserverInterface } from '@internetarchive/shared-resize-observer';
26
- import type { TileModel, CollectionDisplayMode } from './models';
25
+ SharedResizeObserverInterface,
26
+ SharedResizeObserverResizeHandlerInterface,
27
+ } from '@internetarchive/shared-resize-observer';
27
28
  import '@internetarchive/infinite-scroller';
29
+ import type { CollectionNameCacheInterface } from '@internetarchive/collection-name-cache';
28
30
  import './tiles/tile-dispatcher';
29
- import './tiles/loading-tile';
31
+ import './tiles/collection-browser-loading-tile';
30
32
  import './sort-filter-bar/sort-filter-bar';
31
33
  import './collection-facets';
32
- import { CollectionFacets } from './collection-facets';
33
34
  import './circular-activity-indicator';
34
35
  import './sort-filter-bar/sort-filter-bar';
35
- import { SortFilterBar } from './sort-filter-bar/sort-filter-bar';
36
+ import {
37
+ SelectedFacets,
38
+ SortField,
39
+ SortFieldToMetadataField,
40
+ CollectionBrowserContext,
41
+ defaultSelectedFacets,
42
+ TileModel,
43
+ CollectionDisplayMode,
44
+ } from './models';
45
+ import {
46
+ RestorationStateHandlerInterface,
47
+ RestorationStateHandler,
48
+ RestorationState,
49
+ } from './restoration-state-handler';
50
+ import chevronIcon from './assets/img/icons/chevron';
51
+ import { LanguageCodeHandler } from './language-code-handler/language-code-handler';
36
52
 
37
53
  @customElement('collection-browser')
38
54
  export class CollectionBrowser
39
55
  extends LitElement
40
- implements InfiniteScrollerCellProviderInterface
56
+ implements
57
+ InfiniteScrollerCellProviderInterface,
58
+ SharedResizeObserverResizeHandlerInterface
41
59
  {
42
60
  @property({ type: String }) baseNavigationUrl?: string;
43
61
 
@@ -45,11 +63,17 @@ export class CollectionBrowser
45
63
 
46
64
  @property({ type: String }) baseQuery?: string;
47
65
 
48
- @property({ type: Boolean }) showDeleteButtons = false;
66
+ @property({ type: String }) displayMode?: CollectionDisplayMode;
49
67
 
50
- @property({ type: String }) displayMode: CollectionDisplayMode = 'grid';
68
+ @property({ type: Object }) sortParam: SortParam | null = null;
51
69
 
52
- @property({ type: Object }) sortParam?: SortParam;
70
+ @property({ type: String }) selectedSort: SortField = SortField.relevance;
71
+
72
+ @property({ type: String }) selectedTitleFilter: string | null = null;
73
+
74
+ @property({ type: String }) selectedCreatorFilter: string | null = null;
75
+
76
+ @property({ type: String }) sortDirection: SortDirection | null = null;
53
77
 
54
78
  @property({ type: String }) dateRangeQueryClause?: string;
55
79
 
@@ -57,9 +81,33 @@ export class CollectionBrowser
57
81
 
58
82
  @property({ type: Object }) resizeObserver?: SharedResizeObserverInterface;
59
83
 
60
- @query('collection-facets') private collectionFacets!: CollectionFacets;
84
+ @property({ type: String }) titleQuery?: string;
85
+
86
+ @property({ type: String }) creatorQuery?: string;
87
+
88
+ @property({ type: Number }) currentPage?: number;
89
+
90
+ @property({ type: String }) minSelectedDate?: string;
61
91
 
62
- @query('sort-filter-bar') private sortFilterBar!: SortFilterBar;
92
+ @property({ type: String }) maxSelectedDate?: string;
93
+
94
+ @property({ type: Object }) selectedFacets?: SelectedFacets;
95
+
96
+ @property({ type: Boolean }) showHistogramDatePicker = false;
97
+
98
+ @property({ type: Object })
99
+ collectionNameCache?: CollectionNameCacheInterface;
100
+
101
+ @property({ type: String }) pageContext: CollectionBrowserContext = 'search';
102
+
103
+ @property({ type: Object })
104
+ restorationStateHandler: RestorationStateHandlerInterface = new RestorationStateHandler(
105
+ {
106
+ context: this.pageContext,
107
+ }
108
+ );
109
+
110
+ @property({ type: Number }) mobileBreakpoint = 600;
63
111
 
64
112
  /**
65
113
  * The page that the consumer wants to load.
@@ -76,8 +124,6 @@ export class CollectionBrowser
76
124
 
77
125
  @state() private searchResultsLoading = false;
78
126
 
79
- @state() private selectedFacets: Record<string, string[]> = {};
80
-
81
127
  @state() private facetsLoading = false;
82
128
 
83
129
  @state() private fullYearAggregationLoading = false;
@@ -88,11 +134,13 @@ export class CollectionBrowser
88
134
 
89
135
  @state() private totalResults?: number;
90
136
 
91
- @state() private titleQuery?: string;
137
+ @state() private mobileView = false;
138
+
139
+ @state() private mobileFacetsVisible = false;
92
140
 
93
- @state() private creatorQuery?: string;
141
+ @query('#content-container') private contentContainer!: HTMLDivElement;
94
142
 
95
- @state() private currentPage?: number;
143
+ private languageCodeHandler = new LanguageCodeHandler();
96
144
 
97
145
  /**
98
146
  * When we're animated scrolling to the page, we don't want to fetch
@@ -105,7 +153,7 @@ export class CollectionBrowser
105
153
  */
106
154
  private endOfDataReached = false;
107
155
 
108
- private placeholderCellTemplate = html`<loading-tile></loading-tile>`;
156
+ private placeholderCellTemplate = html`<collection-browser-loading-tile></collection-browser-loading-tile>`;
109
157
 
110
158
  private tileModelAtCellIndex(index: number): TileModel | undefined {
111
159
  const pageNumber = Math.floor(index / this.pageSize) + 1;
@@ -160,9 +208,9 @@ export class CollectionBrowser
160
208
  private infiniteScroller!: InfiniteScroller;
161
209
 
162
210
  /**
211
+ * Go to the given page of results
163
212
  *
164
213
  * @param pageNumber
165
- * @param scroll
166
214
  */
167
215
  goToPage(pageNumber: number) {
168
216
  this.initialPageNumber = pageNumber;
@@ -170,42 +218,92 @@ export class CollectionBrowser
170
218
  this.scrollToPage(pageNumber);
171
219
  }
172
220
 
221
+ clearFilters() {
222
+ this.selectedFacets = defaultSelectedFacets;
223
+ this.sortParam = null;
224
+ this.selectedTitleFilter = null;
225
+ this.selectedCreatorFilter = null;
226
+ this.titleQuery = undefined;
227
+ this.creatorQuery = undefined;
228
+ this.selectedSort = SortField.relevance;
229
+ this.sortDirection = null;
230
+ }
231
+
173
232
  render() {
174
233
  return html`
175
- <div id="content-container">
176
- <div id="left-column">
177
- <div id="results-total">
178
- <span id="big-results-count"
179
- >${this.totalResults
180
- ? this.totalResults.toLocaleString()
181
- : '-'}</span
182
- >
183
- <span id="big-results-label">Results</span>
234
+ <div id="content-container" class=${this.mobileView ? 'mobile' : ''}>
235
+ <div id="left-column" class="column">
236
+ <div id="mobile-header-container">
237
+ ${this.mobileView
238
+ ? html`
239
+ <div id="mobile-filter-collapse">
240
+ <h1
241
+ @click=${() => {
242
+ this.mobileFacetsVisible = !this.mobileFacetsVisible;
243
+ }}
244
+ @keyup=${() => {
245
+ this.mobileFacetsVisible = !this.mobileFacetsVisible;
246
+ }}
247
+ >
248
+ <span
249
+ class="collapser ${this.mobileFacetsVisible
250
+ ? 'open'
251
+ : ''}"
252
+ >
253
+ ${chevronIcon}
254
+ </span>
255
+ Filters
256
+ </h1>
257
+ </div>
258
+ `
259
+ : nothing}
260
+ <div id="results-total">
261
+ <span id="big-results-count"
262
+ >${this.totalResults !== undefined
263
+ ? this.totalResults.toLocaleString()
264
+ : '-'}</span
265
+ >
266
+ <span id="big-results-label">Results</span>
267
+ </div>
184
268
  </div>
185
- <div id="facets-container">
186
- ${this.facetsLoading ? this.loadingTemplate : nothing}
187
- <collection-facets
188
- @facetsChanged=${this.facetsChanged}
189
- @histogramDateRangeUpdated=${this.histogramDateRangeUpdated}
190
- .aggregations=${this.aggregations}
191
- .fullYearsHistogramAggregation=${this
192
- .fullYearsHistogramAggregation}
193
- ?facetsLoading=${this.facetDataLoading}
194
- ?fullYearAggregationLoading=${this.fullYearAggregationLoading}
195
- ></collection-facets>
269
+ <div
270
+ id="facets-container"
271
+ class=${!this.mobileView || this.mobileFacetsVisible
272
+ ? 'expanded'
273
+ : ''}
274
+ >
275
+ ${this.facetsTemplate}
196
276
  </div>
197
277
  </div>
198
- <div id="right-column">
278
+ <div id="right-column" class="column">
199
279
  ${this.searchResultsLoading ? this.loadingTemplate : nothing}
200
280
  <sort-filter-bar
201
- @sortChanged=${this.sortChanged}
281
+ .selectedSort=${this.selectedSort}
282
+ .sortDirection=${this.sortDirection}
283
+ .displayMode=${this.displayMode}
284
+ .selectedTitleFilter=${this.selectedTitleFilter}
285
+ .selectedCreatorFilter=${this.selectedCreatorFilter}
286
+ .resizeObserver=${this.resizeObserver}
287
+ @sortChanged=${this.userChangedSort}
202
288
  @displayModeChanged=${this.displayModeChanged}
203
- @titleLetterChanged=${this.titleLetterChanged}
204
- @creatorLetterChanged=${this.creatorLetterChanged}
289
+ @titleLetterChanged=${this.titleLetterSelected}
290
+ @creatorLetterChanged=${this.creatorLetterSelected}
205
291
  ></sort-filter-bar>
206
292
 
293
+ ${this.displayMode === `list-compact`
294
+ ? this.listHeaderTemplate
295
+ : nothing}
296
+ ${!this.searchResultsLoading && this.totalResults === 0
297
+ ? html`
298
+ <h2>
299
+ Your search did not match any items in the Archive. Try
300
+ different keywords or a more general search.
301
+ </h2>
302
+ `
303
+ : nothing}
304
+
207
305
  <infinite-scroller
208
- class="${this.displayMode}"
306
+ class="${ifDefined(this.displayMode)}"
209
307
  .cellProvider=${this}
210
308
  .placeholderCellTemplate=${this.placeholderCellTemplate}
211
309
  @scrollThresholdReached=${this.scrollThresholdReached}
@@ -217,42 +315,85 @@ export class CollectionBrowser
217
315
  `;
218
316
  }
219
317
 
220
- private sortChanged(e: CustomEvent<{ sort: SortParam }>) {
221
- this.sortParam = e.detail.sort;
318
+ private userChangedSort(
319
+ e: CustomEvent<{
320
+ selectedSort: SortField;
321
+ sortDirection: SortDirection | null;
322
+ }>
323
+ ) {
324
+ const { selectedSort, sortDirection } = e.detail;
325
+ this.selectedSort = selectedSort;
326
+ this.sortDirection = sortDirection;
327
+
222
328
  if ((this.currentPage ?? 1) > 1) {
223
329
  this.goToPage(1);
224
330
  }
225
331
  this.currentPage = 1;
226
332
  }
227
333
 
334
+ private selectedSortChanged() {
335
+ if (this.selectedSort === 'relevance' || this.sortDirection === null) {
336
+ this.sortParam = null;
337
+ return;
338
+ }
339
+ const sortField = SortFieldToMetadataField[this.selectedSort];
340
+ if (!sortField) return;
341
+ this.sortParam = { field: sortField, direction: this.sortDirection };
342
+ }
343
+
228
344
  private displayModeChanged(
229
345
  e: CustomEvent<{ displayMode: CollectionDisplayMode }>
230
346
  ) {
231
347
  this.displayMode = e.detail.displayMode;
232
348
  }
233
349
 
234
- private titleLetterChanged(e: CustomEvent<{ selectedLetter: string }>) {
235
- const letter = e.detail.selectedLetter;
236
- if (letter) {
237
- this.titleQuery = `firstTitle:${letter}`;
238
- } else {
239
- this.titleQuery = undefined;
240
- }
350
+ private selectedTitleLetterChanged() {
351
+ this.titleQuery = this.selectedTitleFilter
352
+ ? `firstTitle:${this.selectedTitleFilter}`
353
+ : undefined;
241
354
  }
242
355
 
243
- private creatorLetterChanged(e: CustomEvent<{ selectedLetter: string }>) {
244
- const letter = e.detail.selectedLetter;
245
- if (letter) {
246
- this.creatorQuery = `firstCreator:${letter}`;
247
- } else {
248
- this.creatorQuery = undefined;
249
- }
356
+ private selectedCreatorLetterChanged() {
357
+ this.creatorQuery = this.selectedCreatorFilter
358
+ ? `firstCreator:${this.selectedCreatorFilter}`
359
+ : undefined;
360
+ }
361
+
362
+ private titleLetterSelected(e: CustomEvent<{ selectedLetter: string }>) {
363
+ this.selectedCreatorFilter = null;
364
+ this.selectedTitleFilter = e.detail.selectedLetter;
365
+ }
366
+
367
+ private creatorLetterSelected(e: CustomEvent<{ selectedLetter: string }>) {
368
+ this.selectedTitleFilter = null;
369
+ this.selectedCreatorFilter = e.detail.selectedLetter;
250
370
  }
251
371
 
252
372
  private get facetDataLoading(): boolean {
253
373
  return this.facetsLoading || this.fullYearAggregationLoading;
254
374
  }
255
375
 
376
+ private get facetsTemplate() {
377
+ return html`
378
+ ${this.facetsLoading ? this.loadingTemplate : nothing}
379
+ <collection-facets
380
+ @facetsChanged=${this.facetsChanged}
381
+ @histogramDateRangeUpdated=${this.histogramDateRangeUpdated}
382
+ .aggregations=${this.aggregations}
383
+ .fullYearsHistogramAggregation=${this.fullYearsHistogramAggregation}
384
+ .minSelectedDate=${this.minSelectedDate}
385
+ .maxSelectedDate=${this.maxSelectedDate}
386
+ .selectedFacets=${this.selectedFacets}
387
+ .collectionNameCache=${this.collectionNameCache}
388
+ .languageCodeHandler=${this.languageCodeHandler}
389
+ .showHistogramDatePicker=${this.showHistogramDatePicker}
390
+ ?collapsableFacets=${this.mobileView}
391
+ ?facetsLoading=${this.facetDataLoading}
392
+ ?fullYearAggregationLoading=${this.fullYearAggregationLoading}
393
+ ></collection-facets>
394
+ `;
395
+ }
396
+
256
397
  private get loadingTemplate() {
257
398
  return html`
258
399
  <div class="loading-cover">
@@ -261,6 +402,20 @@ export class CollectionBrowser
261
402
  `;
262
403
  }
263
404
 
405
+ private get listHeaderTemplate() {
406
+ return html`
407
+ <div id="list-header">
408
+ <tile-dispatcher
409
+ .tileDisplayMode=${'list-header'}
410
+ .resizeObserver=${this.resizeObserver}
411
+ .sortParam=${this.sortParam}
412
+ .mobileBreakpoint=${this.mobileBreakpoint}
413
+ >
414
+ </tile-dispatcher>
415
+ </div>
416
+ `;
417
+ }
418
+
264
419
  private get queryDebuggingTemplate() {
265
420
  return html`
266
421
  <div>
@@ -286,14 +441,21 @@ export class CollectionBrowser
286
441
  this.dateRangeQueryClause = `year:[${minDate} TO ${maxDate}]`;
287
442
  }
288
443
 
444
+ firstUpdated(): void {
445
+ this.setupStateRestorationObserver();
446
+ this.restoreState();
447
+ }
448
+
289
449
  updated(changed: PropertyValues) {
290
- if (
291
- changed.has('displayMode') ||
292
- changed.has('showDeleteButtons') ||
293
- changed.has('baseNavigationUrl')
294
- ) {
450
+ if (changed.has('displayMode') || changed.has('baseNavigationUrl')) {
295
451
  this.infiniteScroller.reload();
296
452
  }
453
+ if (changed.has('baseQuery')) {
454
+ this.emitBaseQueryChanged();
455
+ }
456
+ if (changed.has('currentPage') || changed.has('displayMode')) {
457
+ this.persistState();
458
+ }
297
459
  if (
298
460
  changed.has('baseQuery') ||
299
461
  changed.has('titleQuery') ||
@@ -305,11 +467,69 @@ export class CollectionBrowser
305
467
  ) {
306
468
  this.handleQueryChange();
307
469
  }
470
+ if (changed.has('selectedSort') || changed.has('sortDirection')) {
471
+ this.selectedSortChanged();
472
+ }
473
+ if (changed.has('selectedTitleFilter')) {
474
+ this.selectedTitleLetterChanged();
475
+ }
476
+ if (changed.has('selectedCreatorFilter')) {
477
+ this.selectedCreatorLetterChanged();
478
+ }
308
479
  if (changed.has('pagesToRender')) {
309
480
  if (!this.endOfDataReached) {
310
481
  this.infiniteScroller.itemCount = this.estimatedTileCount;
311
482
  }
312
483
  }
484
+ if (changed.has('resizeObserver')) {
485
+ const oldObserver = changed.get(
486
+ 'resizeObserver'
487
+ ) as SharedResizeObserverInterface;
488
+ if (oldObserver) this.disconnectResizeObserver(oldObserver);
489
+ this.setupResizeObserver();
490
+ }
491
+ }
492
+
493
+ disconnectedCallback(): void {
494
+ if (this.resizeObserver) {
495
+ this.disconnectResizeObserver(this.resizeObserver);
496
+ }
497
+ if (this.boundNavigationHandler) {
498
+ window.removeEventListener('popstate', this.boundNavigationHandler);
499
+ }
500
+ }
501
+
502
+ handleResize(entry: ResizeObserverEntry): void {
503
+ if (entry.target === this.contentContainer) {
504
+ this.mobileView = entry.contentRect.width < 600;
505
+ }
506
+ }
507
+
508
+ private emitBaseQueryChanged() {
509
+ this.dispatchEvent(
510
+ new CustomEvent<{ baseQuery?: string }>('baseQueryChanged', {
511
+ detail: {
512
+ baseQuery: this.baseQuery,
513
+ },
514
+ })
515
+ );
516
+ }
517
+
518
+ private disconnectResizeObserver(
519
+ resizeObserver: SharedResizeObserverInterface
520
+ ) {
521
+ resizeObserver.removeObserver({
522
+ target: this.contentContainer,
523
+ handler: this,
524
+ });
525
+ }
526
+
527
+ private setupResizeObserver() {
528
+ if (!this.resizeObserver) return;
529
+ this.resizeObserver.addObserver({
530
+ target: this.contentContainer,
531
+ handler: this,
532
+ });
313
533
  }
314
534
 
315
535
  /**
@@ -329,6 +549,9 @@ export class CollectionBrowser
329
549
  visibleCellIndices[visibleCellIndices.length - 1];
330
550
  const lastVisibleCellPage =
331
551
  Math.floor(lastVisibleCellIndex / this.pageSize) + 1;
552
+ if (this.currentPage !== lastVisibleCellPage) {
553
+ this.currentPage = lastVisibleCellPage;
554
+ }
332
555
  const event = new CustomEvent('visiblePageChanged', {
333
556
  detail: {
334
557
  pageNumber: lastVisibleCellPage,
@@ -341,6 +564,8 @@ export class CollectionBrowser
341
564
  // so this keeps track of whether we've already set the initial query
342
565
  private initialQueryChangeHappened = false;
343
566
 
567
+ private historyPopOccurred = false;
568
+
344
569
  // this lets us store the query key so we know if it's actually changed or not
345
570
  private previousQueryKey?: string;
346
571
 
@@ -358,6 +583,12 @@ export class CollectionBrowser
358
583
  this.scrollToPage(this.initialPageNumber);
359
584
  }
360
585
  this.initialQueryChangeHappened = true;
586
+ // if the query changed as part of a window.history pop event, we don't want to
587
+ // persist the state because it overwrites the forward history
588
+ if (!this.historyPopOccurred) {
589
+ this.persistState();
590
+ this.historyPopOccurred = false;
591
+ }
361
592
 
362
593
  await Promise.all([
363
594
  this.doInitialPageFetch(),
@@ -366,6 +597,61 @@ export class CollectionBrowser
366
597
  ]);
367
598
  }
368
599
 
600
+ private setupStateRestorationObserver() {
601
+ if (this.boundNavigationHandler) return;
602
+ this.boundNavigationHandler = this.historyNavigationHandler.bind(this);
603
+ // when the user navigates back, we want to update the UI to match the URL
604
+ window.addEventListener('popstate', this.boundNavigationHandler);
605
+ }
606
+
607
+ private boundNavigationHandler?: () => void;
608
+
609
+ private historyNavigationHandler() {
610
+ this.historyPopOccurred = true;
611
+ this.restoreState();
612
+ }
613
+
614
+ private restoreState() {
615
+ const restorationState = this.restorationStateHandler.getRestorationState();
616
+ this.displayMode = restorationState.displayMode;
617
+ this.selectedSort = restorationState.selectedSort ?? SortField.relevance;
618
+ this.sortDirection = restorationState.sortDirection ?? null;
619
+ this.selectedTitleFilter = restorationState.selectedTitleFilter ?? null;
620
+ this.selectedCreatorFilter = restorationState.selectedCreatorFilter ?? null;
621
+ this.selectedFacets = restorationState.selectedFacets;
622
+ this.baseQuery = restorationState.baseQuery;
623
+ this.titleQuery = restorationState.titleQuery;
624
+ this.creatorQuery = restorationState.creatorQuery;
625
+ this.dateRangeQueryClause = restorationState.dateRangeQueryClause;
626
+ this.sortParam = restorationState.sortParam ?? null;
627
+ this.currentPage = restorationState.currentPage ?? 1;
628
+ this.minSelectedDate = restorationState.minSelectedDate;
629
+ this.maxSelectedDate = restorationState.maxSelectedDate;
630
+ if (this.currentPage > 1) {
631
+ this.goToPage(this.currentPage);
632
+ }
633
+ }
634
+
635
+ private persistState() {
636
+ const restorationState: RestorationState = {
637
+ displayMode: this.displayMode,
638
+ sortParam: this.sortParam ?? undefined,
639
+ selectedSort: this.selectedSort,
640
+ sortDirection: this.sortDirection ?? undefined,
641
+ selectedFacets: this.selectedFacets ?? defaultSelectedFacets,
642
+ baseQuery: this.baseQuery,
643
+ currentPage: this.currentPage,
644
+ dateRangeQueryClause: this.dateRangeQueryClause,
645
+ titleQuery: this.titleQuery,
646
+ creatorQuery: this.creatorQuery,
647
+ minSelectedDate: this.minSelectedDate,
648
+ maxSelectedDate: this.maxSelectedDate,
649
+ selectedTitleFilter: this.selectedTitleFilter ?? undefined,
650
+ selectedCreatorFilter: this.selectedCreatorFilter ?? undefined,
651
+ };
652
+ this.restorationStateHandler.persistState(restorationState);
653
+ }
654
+
369
655
  private async doInitialPageFetch() {
370
656
  this.searchResultsLoading = true;
371
657
  await this.fetchPage(this.initialPageNumber);
@@ -394,29 +680,48 @@ export class CollectionBrowser
394
680
  return fullQuery;
395
681
  }
396
682
 
683
+ /**
684
+ * Generates a query string for the given facets
685
+ *
686
+ * Example: `mediatype:("collection" OR "audio" OR -"etree") AND year:("2000" OR "2001")`
687
+ */
397
688
  private get facetQuery(): string | undefined {
689
+ if (!this.selectedFacets) return undefined;
398
690
  const facetQuery = [];
399
- for (const [facetName, selectedValues] of Object.entries(
691
+ for (const [facetName, facetValues] of Object.entries(
400
692
  this.selectedFacets
401
693
  )) {
402
- const values: string[] = [];
403
- for (const value of selectedValues) {
404
- values.push(`${facetName}:"${value}"`);
694
+ const facetEntries = Object.entries(facetValues);
695
+ // eslint-disable-next-line no-continue
696
+ if (facetEntries.length === 0) continue;
697
+ const facetValuesArray: string[] = [];
698
+ for (const [key, facetState] of facetEntries) {
699
+ const plusMinusPrefix = facetState === 'hidden' ? '-' : '';
700
+
701
+ if (facetName === 'language') {
702
+ const languages =
703
+ this.languageCodeHandler.getCodeArrayFromCodeString(key);
704
+ for (const language of languages) {
705
+ facetValuesArray.push(`${plusMinusPrefix}"${language}"`);
706
+ }
707
+ } else {
708
+ facetValuesArray.push(`${plusMinusPrefix}"${key}"`);
709
+ }
405
710
  }
406
- const valueQuery = values.join(' OR ');
407
- facetQuery.push(`(${valueQuery})`);
711
+ const valueQuery = facetValuesArray.join(` OR `);
712
+ facetQuery.push(`${facetName}:(${valueQuery})`);
408
713
  }
409
714
  return facetQuery.length > 0 ? `(${facetQuery.join(' AND ')})` : undefined;
410
715
  }
411
716
 
412
- facetsChanged(e: CustomEvent<Record<string, string[]>>) {
717
+ facetsChanged(e: CustomEvent<SelectedFacets>) {
413
718
  this.selectedFacets = e.detail;
414
719
  }
415
720
 
416
721
  private async fetchFacets() {
417
722
  if (!this.fullQuery) return;
418
723
 
419
- const aggregations = new AggregateSearchParams({
724
+ const aggregations = {
420
725
  advancedParams: [
421
726
  {
422
727
  field: 'subjectSorter',
@@ -443,14 +748,14 @@ export class CollectionBrowser
443
748
  size: 50,
444
749
  },
445
750
  ],
446
- });
751
+ };
447
752
 
448
- const params = new SearchParams({
753
+ const params: SearchParams = {
449
754
  query: this.fullQuery,
450
755
  fields: ['identifier'],
451
756
  aggregations,
452
757
  rows: 1,
453
- });
758
+ };
454
759
  this.facetsLoading = true;
455
760
  const results = await this.searchService?.search(params);
456
761
  this.facetsLoading = false;
@@ -474,7 +779,7 @@ export class CollectionBrowser
474
779
  * If this doesn't change, we don't need to re-fetch the histogram date range
475
780
  */
476
781
  private get fullQueryNoDateKey() {
477
- return `${this.fullQueryWithoutDate}-${this.sortParam?.asString}`;
782
+ return `${this.fullQueryWithoutDate}-${this.sortParam?.field}-${this.sortParam?.direction}`;
478
783
  }
479
784
 
480
785
  /**
@@ -493,16 +798,16 @@ export class CollectionBrowser
493
798
  return;
494
799
  this.previousFullQueryNoDate = fullQueryNoDateKey;
495
800
 
496
- const aggregations = new AggregateSearchParams({
801
+ const aggregations = {
497
802
  simpleParams: ['year'],
498
- });
803
+ };
499
804
 
500
- const params = new SearchParams({
805
+ const params = {
501
806
  query: this.fullQueryWithoutDate,
502
807
  fields: ['identifier'],
503
808
  aggregations,
504
809
  rows: 1,
505
- });
810
+ };
506
811
 
507
812
  this.fullYearAggregationLoading = true;
508
813
  const results = await this.searchService?.search(params);
@@ -537,7 +842,7 @@ export class CollectionBrowser
537
842
  * no longer relevant.
538
843
  */
539
844
  private get pageFetchQueryKey() {
540
- return `${this.fullQuery}-${this.sortParam?.asString}`;
845
+ return `${this.fullQuery}-${this.sortParam?.field}-${this.sortParam?.direction}`;
541
846
  }
542
847
 
543
848
  // this maps the query to the pages being fetched for that query
@@ -560,31 +865,33 @@ export class CollectionBrowser
560
865
  this.pageFetchesInProgress[pageFetchQueryKey] = pageFetches;
561
866
 
562
867
  const sortParams = this.sortParam ? [this.sortParam] : [];
563
- const params = new SearchParams({
868
+ const params = {
564
869
  query: this.fullQuery,
565
870
  fields: [
871
+ 'addeddate',
872
+ 'avg_rating',
873
+ 'collections_raw',
874
+ 'creator',
875
+ 'date',
876
+ 'description',
877
+ 'downloads',
566
878
  'identifier',
567
- 'title',
879
+ 'issue',
880
+ 'item_count',
568
881
  'mediatype',
569
- 'downloads',
570
- 'avg_rating',
571
882
  'num_favorites',
572
883
  'num_reviews',
573
- 'item_count',
574
- 'description',
575
- 'date',
576
- 'addeddate',
577
884
  'publicdate',
578
885
  'reviewdate',
579
- 'creator',
580
- 'subject', // topic
581
886
  'source',
582
- 'collections_raw',
887
+ 'subject', // topic
888
+ 'title',
889
+ 'volume',
583
890
  ],
584
891
  page: pageNumber,
585
892
  rows: this.pageSize,
586
893
  sort: sortParams,
587
- });
894
+ };
588
895
  const results = await this.searchService?.search(params);
589
896
  const success = results?.success;
590
897
 
@@ -597,12 +904,33 @@ export class CollectionBrowser
597
904
  // right behind it
598
905
  const searchQuery = success.responseHeader.params.qin;
599
906
  const searchSort = success.responseHeader.params.sort;
907
+ let sortChanged = false;
908
+ if (!searchSort) {
909
+ // if we went from no sort to sort, the sort has changed
910
+ if (this.sortParam) {
911
+ sortChanged = true;
912
+ }
913
+ } else {
914
+ // check if the sort has changed
915
+ const split = searchSort.split(' ');
916
+ if (split.length > 1) {
917
+ const field = searchSort.split(' ')[0];
918
+ const direction = searchSort.split(' ')[1];
919
+ if (
920
+ field !== this.sortParam?.field ||
921
+ direction !== this.sortParam?.direction
922
+ ) {
923
+ sortChanged = true;
924
+ }
925
+ }
926
+ }
600
927
  const queryChangedSinceFetch =
601
- searchQuery !== this.fullQuery || searchSort !== this.sortParam?.asString;
928
+ searchQuery !== this.fullQuery || sortChanged;
602
929
  if (queryChangedSinceFetch) return;
603
930
 
604
931
  const { docs } = success.response;
605
932
  if (docs && docs.length > 0) {
933
+ this.preloadCollectionNames(docs);
606
934
  this.updateDataSource(pageNumber, docs);
607
935
  }
608
936
  if (docs.length < this.pageSize) {
@@ -614,6 +942,12 @@ export class CollectionBrowser
614
942
  this.searchResultsLoading = false;
615
943
  }
616
944
 
945
+ private preloadCollectionNames(docs: Metadata[]) {
946
+ const collectionIds = docs.map(doc => doc.collections_raw?.values).flat();
947
+ const collectionIdsArray = Array.from(new Set(collectionIds)) as string[];
948
+ this.collectionNameCache?.preloadIdentifiers(collectionIdsArray);
949
+ }
950
+
617
951
  /**
618
952
  * This is useful for determining whether we need to reload the scroller.
619
953
  *
@@ -645,23 +979,30 @@ export class CollectionBrowser
645
979
  docs?.forEach(doc => {
646
980
  if (!doc.identifier) return;
647
981
  tiles.push({
648
- identifier: doc.identifier,
649
- title: this.etreeTitle(doc.title?.value, doc.mediatype?.value),
650
- mediatype: doc.mediatype?.value ?? 'data',
651
- viewCount: doc.downloads?.value ?? 0,
652
- favCount: doc.num_favorites?.value ?? 0,
982
+ averageRating: doc.avg_rating?.value,
983
+ collections: doc.collections_raw?.values ?? [],
653
984
  commentCount: doc.num_reviews?.value ?? 0,
654
- itemCount: doc.item_count?.value ?? 0,
655
- description: doc.description?.value,
985
+ creator: doc.creator?.value,
986
+ creators: doc.creator?.values ?? [],
656
987
  dateAdded: doc.addeddate?.value,
657
988
  dateArchived: doc.publicdate?.value,
658
- dateReviewed: doc.reviewdate?.value,
659
989
  datePublished: doc.date?.value,
660
- creator: doc.creator?.value,
661
- averageRating: doc.avg_rating?.value,
662
- subject: doc.subject?.value,
990
+ dateReviewed: doc.reviewdate?.value,
991
+ description: doc.description?.value,
992
+ favCount: doc.num_favorites?.value ?? 0,
993
+ identifier: doc.identifier,
994
+ issue: doc.issue?.value,
995
+ itemCount: doc.item_count?.value ?? 0,
996
+ mediatype: doc.mediatype?.value ?? 'data',
663
997
  source: doc.source?.value,
664
- collections: doc.collections_raw?.values ?? [],
998
+ subjects: doc.subject?.values ?? [],
999
+ title: this.etreeTitle(
1000
+ doc.title?.value,
1001
+ doc.mediatype?.value,
1002
+ doc.collection?.values
1003
+ ),
1004
+ volume: doc.volume?.value,
1005
+ viewCount: doc.downloads?.value ?? 0,
665
1006
  });
666
1007
  });
667
1008
  datasource[pageNumber] = tiles;
@@ -682,10 +1023,10 @@ export class CollectionBrowser
682
1023
  */
683
1024
  private etreeTitle(
684
1025
  title: string | undefined,
685
- mediatype: string | undefined
1026
+ mediatype: string | undefined,
1027
+ collections: string[] | undefined
686
1028
  ): string {
687
- if (mediatype === 'etree') {
688
- // || collections.includes('etree')) {
1029
+ if (mediatype === 'etree' || collections?.includes('etree')) {
689
1030
  const regex = /^(.*) Live at (.*) on (\d\d\d\d-\d\d-\d\d)$/;
690
1031
  const newTitle = title?.replace(regex, '$3: $2');
691
1032
  if (newTitle) {
@@ -702,10 +1043,11 @@ export class CollectionBrowser
702
1043
  return html` <tile-dispatcher
703
1044
  .baseNavigationUrl=${this.baseNavigationUrl}
704
1045
  .model=${model}
705
- .displayMode=${this.displayMode}
1046
+ .tileDisplayMode=${this.displayMode}
706
1047
  .resizeObserver=${this.resizeObserver}
1048
+ .collectionNameCache=${this.collectionNameCache}
707
1049
  .sortParam=${this.sortParam}
708
- ?showDeleteButton=${this.showDeleteButtons}
1050
+ .mobileBreakpoint=${this.mobileBreakpoint}
709
1051
  ></tile-dispatcher>`;
710
1052
  }
711
1053
 
@@ -727,19 +1069,73 @@ export class CollectionBrowser
727
1069
  display: flex;
728
1070
  }
729
1071
 
1072
+ .collapser {
1073
+ display: inline-block;
1074
+ }
1075
+
1076
+ .collapser svg {
1077
+ width: 10px;
1078
+ height: 10px;
1079
+ transition: transform 0.2s ease-out;
1080
+ }
1081
+
1082
+ .collapser.open svg {
1083
+ transform: rotate(90deg);
1084
+ }
1085
+
1086
+ #mobile-filter-collapse h1 {
1087
+ cursor: pointer;
1088
+ }
1089
+
1090
+ #content-container.mobile {
1091
+ display: block;
1092
+ }
1093
+
1094
+ .column {
1095
+ padding-top: 2rem;
1096
+ }
1097
+
730
1098
  #right-column {
731
1099
  flex: 1;
732
1100
  position: relative;
733
1101
  border-left: 1px solid rgb(232, 232, 232);
1102
+ padding-left: 1rem;
1103
+ }
1104
+
1105
+ .mobile #right-column {
1106
+ border-left: none;
1107
+ padding: 0;
734
1108
  }
735
1109
 
736
1110
  #left-column {
737
1111
  width: 18rem;
738
1112
  padding-right: 12px;
1113
+ padding-right: 1rem;
1114
+ }
1115
+
1116
+ .mobile #left-column {
1117
+ width: 100%;
1118
+ padding: 0;
1119
+ }
1120
+
1121
+ #mobile-header-container {
1122
+ display: flex;
1123
+ justify-content: space-between;
739
1124
  }
740
1125
 
741
1126
  #facets-container {
742
1127
  position: relative;
1128
+ max-height: 0;
1129
+ transition: max-height 0.2s ease-in-out;
1130
+ z-index: 1;
1131
+ }
1132
+
1133
+ .mobile #facets-container {
1134
+ overflow: hidden;
1135
+ }
1136
+
1137
+ #facets-container.expanded {
1138
+ max-height: 2000px;
743
1139
  }
744
1140
 
745
1141
  #results-total {
@@ -748,6 +1144,10 @@ export class CollectionBrowser
748
1144
  margin-bottom: 5rem;
749
1145
  }
750
1146
 
1147
+ .mobile #results-total {
1148
+ margin-bottom: 0;
1149
+ }
1150
+
751
1151
  #big-results-count {
752
1152
  font-size: 2.4rem;
753
1153
  font-weight: 500;
@@ -760,6 +1160,10 @@ export class CollectionBrowser
760
1160
  text-transform: uppercase;
761
1161
  }
762
1162
 
1163
+ #list-header {
1164
+ max-height: 4.2rem;
1165
+ }
1166
+
763
1167
  .loading-cover {
764
1168
  position: absolute;
765
1169
  top: 0;
@@ -777,6 +1181,11 @@ export class CollectionBrowser
777
1181
  height: 30px;
778
1182
  }
779
1183
 
1184
+ sort-filter-bar {
1185
+ display: block;
1186
+ margin-bottom: 4rem;
1187
+ }
1188
+
780
1189
  infinite-scroller {
781
1190
  display: block;
782
1191
  --infiniteScrollerRowGap: var(--collectionBrowserRowGap, 1.7rem);
@@ -788,14 +1197,9 @@ export class CollectionBrowser
788
1197
  --collectionBrowserCellMinWidth,
789
1198
  100%
790
1199
  );
791
- --infiniteScrollerCellMinHeight: var(
792
- --collectionBrowserCellMinHeight,
793
- 2rem
794
- );
795
- --infiniteScrollerCellMaxHeight: var(
796
- --collectionBrowserCellMaxHeight,
797
- 2rem
798
- );
1200
+ --infiniteScrollerCellMinHeight: 34px; /* override infinite scroller component */
1201
+ --infiniteScrollerCellMaxHeight: 56px;
1202
+ --infiniteScrollerRowGap: 0px;
799
1203
  }
800
1204
 
801
1205
  infinite-scroller.list-detail {
@@ -807,6 +1211,16 @@ export class CollectionBrowser
807
1211
  --collectionBrowserCellMinHeight,
808
1212
  5rem
809
1213
  );
1214
+ /*
1215
+ 30px in spec, compensating for a -4px margin
1216
+ to align title with top of item image
1217
+ src/tiles/list/tile-list.ts
1218
+ */
1219
+ --infiniteScrollerRowGap: 34px;
1220
+ }
1221
+
1222
+ .mobile infinite-scroller.list-detail {
1223
+ --infiniteScrollerRowGap: 24px;
810
1224
  }
811
1225
 
812
1226
  infinite-scroller.grid {