@internetarchive/collection-browser 0.0.1-alpha.2 → 0.0.1-alpha.22

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 (183) hide show
  1. package/demo/app-root.ts +24 -158
  2. package/dist/demo/app-root.d.ts +2 -16
  3. package/dist/demo/app-root.js +23 -141
  4. package/dist/demo/app-root.js.map +1 -1
  5. package/dist/src/assets/img/icons/chevron.d.ts +2 -0
  6. package/dist/src/assets/img/icons/chevron.js +4 -0
  7. package/dist/src/assets/img/icons/chevron.js.map +1 -0
  8. package/dist/src/assets/img/icons/eye-closed.d.ts +2 -0
  9. package/dist/src/assets/img/icons/eye-closed.js +5 -0
  10. package/dist/src/assets/img/icons/eye-closed.js.map +1 -0
  11. package/dist/src/assets/img/icons/eye.d.ts +2 -0
  12. package/dist/src/assets/img/icons/eye.js +5 -0
  13. package/dist/src/assets/img/icons/eye.js.map +1 -0
  14. package/dist/src/assets/img/icons/mediatype/account.d.ts +1 -2
  15. package/dist/src/assets/img/icons/mediatype/account.js +5 -4
  16. package/dist/src/assets/img/icons/mediatype/account.js.map +1 -1
  17. package/dist/src/assets/img/icons/mediatype/audio.js +7 -4
  18. package/dist/src/assets/img/icons/mediatype/audio.js.map +1 -1
  19. package/dist/src/assets/img/icons/mediatype/collection.js +7 -4
  20. package/dist/src/assets/img/icons/mediatype/collection.js.map +1 -1
  21. package/dist/src/assets/img/icons/mediatype/etree.js +10 -5
  22. package/dist/src/assets/img/icons/mediatype/etree.js.map +1 -1
  23. package/dist/src/assets/img/icons/mediatype/film.js +2 -1
  24. package/dist/src/assets/img/icons/mediatype/film.js.map +1 -1
  25. package/dist/src/assets/img/icons/mediatype/images.js +9 -6
  26. package/dist/src/assets/img/icons/mediatype/images.js.map +1 -1
  27. package/dist/src/assets/img/icons/mediatype/software.js +9 -6
  28. package/dist/src/assets/img/icons/mediatype/software.js.map +1 -1
  29. package/dist/src/assets/img/icons/mediatype/texts.js +9 -6
  30. package/dist/src/assets/img/icons/mediatype/texts.js.map +1 -1
  31. package/dist/src/assets/img/icons/mediatype/tv.js +10 -5
  32. package/dist/src/assets/img/icons/mediatype/tv.js.map +1 -1
  33. package/dist/src/assets/img/icons/mediatype/video.js +10 -6
  34. package/dist/src/assets/img/icons/mediatype/video.js.map +1 -1
  35. package/dist/src/assets/img/icons/mediatype/web.js +9 -6
  36. package/dist/src/assets/img/icons/mediatype/web.js.map +1 -1
  37. package/dist/src/async-collection-name.d.ts +11 -0
  38. package/dist/src/async-collection-name.js +38 -0
  39. package/dist/src/async-collection-name.js.map +1 -0
  40. package/dist/src/collection-browser.d.ts +55 -17
  41. package/dist/src/collection-browser.js +466 -106
  42. package/dist/src/collection-browser.js.map +1 -1
  43. package/dist/src/collection-facets.d.ts +24 -5
  44. package/dist/src/collection-facets.js +300 -78
  45. package/dist/src/collection-facets.js.map +1 -1
  46. package/dist/src/collection-name-cache.d.ts +18 -0
  47. package/dist/src/collection-name-cache.js +89 -0
  48. package/dist/src/collection-name-cache.js.map +1 -0
  49. package/dist/src/mediatype-icon.js +10 -3
  50. package/dist/src/mediatype-icon.js.map +1 -1
  51. package/dist/src/models.d.ts +72 -14
  52. package/dist/src/models.js +57 -1
  53. package/dist/src/models.js.map +1 -1
  54. package/dist/src/restoration-state-handler.d.ts +37 -0
  55. package/dist/src/restoration-state-handler.js +177 -0
  56. package/dist/src/restoration-state-handler.js.map +1 -0
  57. package/dist/src/sort-filter-bar/alpha-bar.d.ts +1 -2
  58. package/dist/src/sort-filter-bar/alpha-bar.js +19 -9
  59. package/dist/src/sort-filter-bar/alpha-bar.js.map +1 -1
  60. package/dist/src/sort-filter-bar/img/compact.d.ts +1 -0
  61. package/dist/src/sort-filter-bar/img/compact.js +5 -0
  62. package/dist/src/sort-filter-bar/img/compact.js.map +1 -0
  63. package/dist/src/sort-filter-bar/img/grid.d.ts +1 -0
  64. package/dist/src/sort-filter-bar/img/grid.js +5 -0
  65. package/dist/src/sort-filter-bar/img/grid.js.map +1 -0
  66. package/dist/src/sort-filter-bar/img/list.d.ts +1 -0
  67. package/dist/src/sort-filter-bar/img/list.js +5 -0
  68. package/dist/src/sort-filter-bar/img/list.js.map +1 -0
  69. package/dist/src/sort-filter-bar/img/sort-triangle.d.ts +1 -0
  70. package/dist/src/sort-filter-bar/img/sort-triangle.js +5 -0
  71. package/dist/src/sort-filter-bar/img/sort-triangle.js.map +1 -0
  72. package/dist/src/sort-filter-bar/img/tile.d.ts +1 -0
  73. package/dist/src/sort-filter-bar/img/tile.js +5 -0
  74. package/dist/src/sort-filter-bar/img/tile.js.map +1 -0
  75. package/dist/src/sort-filter-bar/sort-filter-bar.d.ts +65 -11
  76. package/dist/src/sort-filter-bar/sort-filter-bar.js +453 -142
  77. package/dist/src/sort-filter-bar/sort-filter-bar.js.map +1 -1
  78. package/dist/src/tiles/grid/collection-tile.js +1 -2
  79. package/dist/src/tiles/grid/collection-tile.js.map +1 -1
  80. package/dist/src/tiles/grid/item-tile.d.ts +4 -0
  81. package/dist/src/tiles/grid/item-tile.js +134 -45
  82. package/dist/src/tiles/grid/item-tile.js.map +1 -1
  83. package/dist/src/tiles/list/tile-list-compact-header.d.ts +11 -0
  84. package/dist/src/tiles/list/tile-list-compact-header.js +79 -0
  85. package/dist/src/tiles/list/tile-list-compact-header.js.map +1 -0
  86. package/dist/src/tiles/list/tile-list-compact.d.ts +1 -0
  87. package/dist/src/tiles/list/tile-list-compact.js +122 -31
  88. package/dist/src/tiles/list/tile-list-compact.js.map +1 -1
  89. package/dist/src/tiles/list/tile-list-detail.d.ts +0 -10
  90. package/dist/src/tiles/list/tile-list-detail.js +6 -159
  91. package/dist/src/tiles/list/tile-list-detail.js.map +1 -1
  92. package/dist/src/tiles/list/tile-list.d.ts +19 -6
  93. package/dist/src/tiles/list/tile-list.js +240 -108
  94. package/dist/src/tiles/list/tile-list.js.map +1 -1
  95. package/dist/src/tiles/tile-dispatcher.d.ts +8 -1
  96. package/dist/src/tiles/tile-dispatcher.js +46 -11
  97. package/dist/src/tiles/tile-dispatcher.js.map +1 -1
  98. package/dist/src/utils/format-date.js +1 -2
  99. package/dist/src/utils/format-date.js.map +1 -1
  100. package/dist/test/{utils/format-string.test.d.ts → collection-name-cache.test.d.ts} +0 -0
  101. package/dist/test/collection-name-cache.test.js +158 -0
  102. package/dist/test/collection-name-cache.test.js.map +1 -0
  103. package/dist/test/mocks/mock-search-response.d.ts +5 -0
  104. package/dist/test/mocks/mock-search-response.js +62 -0
  105. package/dist/test/mocks/mock-search-response.js.map +1 -0
  106. package/dist/test/mocks/mock-search-service.d.ts +13 -0
  107. package/dist/test/mocks/mock-search-service.js +20 -0
  108. package/dist/test/mocks/mock-search-service.js.map +1 -0
  109. package/package.json +9 -4
  110. package/src/assets/img/icons/chevron.ts +4 -0
  111. package/src/assets/img/icons/eye-closed.ts +5 -0
  112. package/src/assets/img/icons/eye.ts +5 -0
  113. package/src/assets/img/icons/mediatype/account.ts +5 -4
  114. package/src/assets/img/icons/mediatype/audio.ts +7 -4
  115. package/src/assets/img/icons/mediatype/collection.ts +7 -4
  116. package/src/assets/img/icons/mediatype/etree.ts +10 -5
  117. package/src/assets/img/icons/mediatype/film.ts +2 -1
  118. package/src/assets/img/icons/mediatype/images.ts +9 -6
  119. package/src/assets/img/icons/mediatype/software.ts +9 -6
  120. package/src/assets/img/icons/mediatype/texts.ts +9 -6
  121. package/src/assets/img/icons/mediatype/tv.ts +10 -5
  122. package/src/assets/img/icons/mediatype/video.ts +10 -6
  123. package/src/assets/img/icons/mediatype/web.ts +9 -6
  124. package/src/collection-browser.ts +490 -105
  125. package/src/collection-facets.ts +325 -109
  126. package/src/mediatype-icon.ts +10 -3
  127. package/src/models.ts +139 -14
  128. package/src/restoration-state-handler.ts +234 -0
  129. package/src/sort-filter-bar/alpha-bar.ts +19 -9
  130. package/src/sort-filter-bar/img/compact.ts +5 -0
  131. package/src/sort-filter-bar/img/list.ts +5 -0
  132. package/src/sort-filter-bar/img/sort-triangle.ts +5 -0
  133. package/src/sort-filter-bar/img/tile.ts +5 -0
  134. package/src/sort-filter-bar/sort-filter-bar.ts +499 -149
  135. package/src/tiles/grid/collection-tile.ts +1 -2
  136. package/src/tiles/grid/item-tile.ts +138 -56
  137. package/src/tiles/list/tile-list-compact-header.ts +75 -0
  138. package/src/tiles/list/tile-list-compact.ts +209 -0
  139. package/src/tiles/list/tile-list.ts +261 -110
  140. package/src/tiles/tile-dispatcher.ts +51 -11
  141. package/src/utils/format-date.ts +1 -2
  142. package/dist/src/assets/img/icons/audio.d.ts +0 -1
  143. package/dist/src/assets/img/icons/audio.js +0 -9
  144. package/dist/src/assets/img/icons/audio.js.map +0 -1
  145. package/dist/src/assets/img/icons/collection.d.ts +0 -1
  146. package/dist/src/assets/img/icons/collection.js +0 -9
  147. package/dist/src/assets/img/icons/collection.js.map +0 -1
  148. package/dist/src/assets/img/icons/etree.d.ts +0 -1
  149. package/dist/src/assets/img/icons/etree.js +0 -9
  150. package/dist/src/assets/img/icons/etree.js.map +0 -1
  151. package/dist/src/assets/img/icons/images.d.ts +0 -1
  152. package/dist/src/assets/img/icons/images.js +0 -10
  153. package/dist/src/assets/img/icons/images.js.map +0 -1
  154. package/dist/src/assets/img/icons/mediatype/etree copy.d.ts +0 -1
  155. package/dist/src/assets/img/icons/mediatype/etree copy.js +0 -9
  156. package/dist/src/assets/img/icons/mediatype/etree copy.js.map +0 -1
  157. package/dist/src/assets/img/icons/mediatype/livemusic.d.ts +0 -1
  158. package/dist/src/assets/img/icons/mediatype/livemusic.js +0 -7
  159. package/dist/src/assets/img/icons/mediatype/livemusic.js.map +0 -1
  160. package/dist/src/assets/img/icons/mediatype/photos.d.ts +0 -1
  161. package/dist/src/assets/img/icons/mediatype/photos.js +0 -7
  162. package/dist/src/assets/img/icons/mediatype/photos.js.map +0 -1
  163. package/dist/src/assets/img/icons/software.d.ts +0 -1
  164. package/dist/src/assets/img/icons/software.js +0 -10
  165. package/dist/src/assets/img/icons/software.js.map +0 -1
  166. package/dist/src/assets/img/icons/texts.d.ts +0 -1
  167. package/dist/src/assets/img/icons/texts.js +0 -10
  168. package/dist/src/assets/img/icons/texts.js.map +0 -1
  169. package/dist/src/assets/img/icons/tv.d.ts +0 -1
  170. package/dist/src/assets/img/icons/tv.js +0 -9
  171. package/dist/src/assets/img/icons/tv.js.map +0 -1
  172. package/dist/src/assets/img/icons/video.d.ts +0 -1
  173. package/dist/src/assets/img/icons/video.js +0 -10
  174. package/dist/src/assets/img/icons/video.js.map +0 -1
  175. package/dist/src/assets/img/icons/web.d.ts +0 -1
  176. package/dist/src/assets/img/icons/web.js +0 -10
  177. package/dist/src/assets/img/icons/web.js.map +0 -1
  178. package/dist/src/utils/format-string.d.ts +0 -2
  179. package/dist/src/utils/format-string.js +0 -7
  180. package/dist/src/utils/format-string.js.map +0 -1
  181. package/dist/test/utils/format-string.test.js +0 -17
  182. package/dist/test/utils/format-string.test.js.map +0 -1
  183. package/src/assets/img/icons/mediatype/foo.svg +0 -5
package/src/models.ts CHANGED
@@ -1,25 +1,150 @@
1
1
  import type { MediaType } from '@internetarchive/field-parsers';
2
2
 
3
3
  export interface TileModel {
4
- identifier: string;
5
- title: string;
6
4
  averageRating?: number;
5
+ collectionIdentifier?: string;
6
+ collectionName?: string;
7
+ collections: string[];
8
+ commentCount: number;
9
+ creator?: string;
10
+ creators: string[];
7
11
  dateAdded?: Date; // Date added to public search (software-defined) [from: addeddate]
8
12
  dateArchived?: Date; // Date archived (software-defined) item created on archive.org [from: publicdate]
9
- dateReviewed?: Date; // Date reviewed (user-created) most recent review [from: reviewdate]
10
13
  datePublished?: Date; // Date work published in the world (user-defined) [from: date]
11
- mediatype: MediaType;
12
- viewCount: number;
13
- itemCount: number;
14
- favCount: number;
15
- commentCount: number;
14
+ dateReviewed?: Date; // Date reviewed (user-created) most recent review [from: reviewdate]
16
15
  description?: string;
17
- collectionIdentifier?: string;
18
- collectionName?: string;
19
- creator?: string;
20
- subject?: string;
16
+ favCount: number;
17
+ identifier: string;
18
+ issue?: string;
19
+ itemCount: number;
20
+ mediatype: MediaType;
21
21
  source?: string;
22
- collection: string[];
22
+ subjects: string[];
23
+ title: string;
24
+ viewCount: number;
25
+ volume?: string;
26
+ }
27
+
28
+ export type CollectionDisplayMode =
29
+ | 'grid'
30
+ | 'list-compact'
31
+ | 'list-detail'
32
+ | 'list-header';
33
+
34
+ /**
35
+ * This is mainly used to set the cookies for the collection display mode.
36
+ *
37
+ * It allows the user to set different modes for different contexts (collection page, search page, etc).
38
+ */
39
+ export type CollectionBrowserContext = 'collection' | 'search';
40
+
41
+ /**
42
+ * The sort fields shown in the sort filter bar
43
+ */
44
+ export enum SortField {
45
+ 'relevance' = 'relevance',
46
+ 'views' = 'views',
47
+ 'title' = 'title',
48
+ 'datearchived' = 'datearchived',
49
+ 'datepublished' = 'datepublished',
50
+ 'datereviewed' = 'datereviewed',
51
+ 'dateadded' = 'dateadded',
52
+ 'creator' = 'creator',
23
53
  }
24
54
 
25
- export type CollectionDisplayMode = 'grid' | 'list-compact' | 'list-detail';
55
+ /**
56
+ * The metadata fields we sort by that map to the SortFields above
57
+ */
58
+ export type MetadataSortField =
59
+ | 'week'
60
+ | 'titleSorter'
61
+ | 'date'
62
+ | 'creatorSorter'
63
+ | 'publicdate'
64
+ | 'reviewdate'
65
+ | 'addeddate';
66
+
67
+ export const SortFieldDisplayName: {
68
+ [key in SortField]: string;
69
+ } = {
70
+ relevance: 'Relevance',
71
+ views: 'Views',
72
+ title: 'Title',
73
+ datearchived: 'Date Archived',
74
+ datepublished: 'Date Published',
75
+ datereviewed: 'Date Reviewed',
76
+ dateadded: 'Date Added',
77
+ creator: 'Creator',
78
+ };
79
+
80
+ /**
81
+ * Maps the SortField above to the corresponding Metadata field in the API.
82
+ */
83
+ export const SortFieldToMetadataField: {
84
+ [key in SortField]: MetadataSortField | null;
85
+ } = {
86
+ relevance: null,
87
+ views: 'week',
88
+ title: 'titleSorter',
89
+ datearchived: 'date',
90
+ datepublished: 'publicdate',
91
+ datereviewed: 'reviewdate',
92
+ dateadded: 'addeddate',
93
+ creator: 'creatorSorter',
94
+ };
95
+
96
+ /**
97
+ * Maps the Metadata field to the corresponding SortField field in the API.
98
+ */
99
+ export const MetadataFieldToSortField: {
100
+ [key in MetadataSortField]: SortField;
101
+ } = {
102
+ titleSorter: SortField.title,
103
+ date: SortField.datearchived,
104
+ publicdate: SortField.datepublished,
105
+ reviewdate: SortField.datereviewed,
106
+ addeddate: SortField.dateadded,
107
+ creatorSorter: SortField.creator,
108
+ week: SortField.views,
109
+ };
110
+
111
+ export type FacetOption =
112
+ | 'subject'
113
+ | 'mediatype'
114
+ | 'language'
115
+ | 'creator'
116
+ | 'collection'
117
+ | 'year';
118
+
119
+ export type SelectedFacetState = 'selected' | 'hidden';
120
+
121
+ export type FacetState = SelectedFacetState | 'none';
122
+ export interface FacetBucket {
123
+ // for some facets, we augment the key with a display value
124
+ displayText?: string;
125
+ key: string;
126
+ count: number;
127
+ state: FacetState;
128
+ }
129
+
130
+ export interface FacetGroup {
131
+ title: string;
132
+ key: FacetOption;
133
+ buckets: FacetBucket[];
134
+ }
135
+
136
+ export type FacetValue = string;
137
+
138
+ export type SelectedFacets = Record<
139
+ FacetOption,
140
+ Record<FacetValue, SelectedFacetState>
141
+ >;
142
+
143
+ export const defaultSelectedFacets: SelectedFacets = {
144
+ subject: {},
145
+ mediatype: {},
146
+ language: {},
147
+ creator: {},
148
+ collection: {},
149
+ year: {},
150
+ };
@@ -0,0 +1,234 @@
1
+ import { SortDirection, SortParam } from '@internetarchive/search-service';
2
+ import { getCookie, setCookie } from 'typescript-cookie';
3
+ import {
4
+ MetadataFieldToSortField,
5
+ MetadataSortField,
6
+ FacetOption,
7
+ CollectionBrowserContext,
8
+ CollectionDisplayMode,
9
+ SelectedFacets,
10
+ SortField,
11
+ } from './models';
12
+
13
+ export interface RestorationState {
14
+ displayMode?: CollectionDisplayMode;
15
+ sortParam?: SortParam;
16
+ selectedSort?: SortField;
17
+ sortDirection?: SortDirection;
18
+ selectedFacets: SelectedFacets;
19
+ baseQuery?: string;
20
+ currentPage?: number;
21
+ dateRangeQueryClause?: string;
22
+ titleQuery?: string;
23
+ creatorQuery?: string;
24
+ minSelectedDate?: string;
25
+ maxSelectedDate?: string;
26
+ selectedTitleFilter?: string;
27
+ selectedCreatorFilter?: string;
28
+ }
29
+
30
+ export interface RestorationStateHandlerInterface {
31
+ persistState(state: RestorationState): void;
32
+ getRestorationState(): RestorationState;
33
+ }
34
+
35
+ export class RestorationStateHandler
36
+ implements RestorationStateHandlerInterface
37
+ {
38
+ private context: CollectionBrowserContext;
39
+
40
+ private cookieDomain = '.archive.org';
41
+
42
+ private cookieExpiration = 30;
43
+
44
+ private cookiePath = '/';
45
+
46
+ constructor(options: { context: CollectionBrowserContext }) {
47
+ this.context = options.context;
48
+ }
49
+
50
+ persistState(state: RestorationState): void {
51
+ if (state.displayMode) this.persistViewStateToCookies(state.displayMode);
52
+ this.persistQueryStateToUrl(state);
53
+ }
54
+
55
+ getRestorationState(): RestorationState {
56
+ const restorationState = this.loadQueryStateFromUrl();
57
+ const displayMode = this.loadTileViewStateFromCookies();
58
+ restorationState.displayMode = displayMode;
59
+ return restorationState;
60
+ }
61
+
62
+ private persistViewStateToCookies(displayMode: CollectionDisplayMode) {
63
+ const gridState = displayMode === 'grid' ? 'tiles' : 'lists';
64
+ setCookie(`view-${this.context}`, gridState, {
65
+ domain: this.cookieDomain,
66
+ expires: this.cookieExpiration,
67
+ path: this.cookiePath,
68
+ });
69
+ const detailsState = displayMode === 'list-detail' ? 'showdetails' : '';
70
+ setCookie(`showdetails-${this.context}`, detailsState, {
71
+ domain: this.cookieDomain,
72
+ expires: this.cookieExpiration,
73
+ path: this.cookiePath,
74
+ });
75
+ }
76
+
77
+ private loadTileViewStateFromCookies(): CollectionDisplayMode {
78
+ const viewState = getCookie(`view-${this.context}`);
79
+ const detailsState = getCookie(`showdetails-${this.context}`);
80
+ if (viewState === 'tiles' || viewState === undefined) return 'grid';
81
+ if (detailsState === 'showdetails') return 'list-detail';
82
+ return 'list-compact';
83
+ }
84
+
85
+ private persistQueryStateToUrl(state: RestorationState) {
86
+ const url = new URL(window.location.href);
87
+ const { searchParams } = url;
88
+ searchParams.delete('sort');
89
+ searchParams.delete('query');
90
+ searchParams.delete('page');
91
+ searchParams.delete('and[]');
92
+ searchParams.delete('not[]');
93
+
94
+ if (state.sortParam) {
95
+ url.searchParams.set('sort', state.sortParam.asString);
96
+ }
97
+
98
+ if (state.baseQuery) {
99
+ url.searchParams.set('query', state.baseQuery);
100
+ }
101
+
102
+ if (state.currentPage) {
103
+ if (state.currentPage > 1) {
104
+ url.searchParams.set('page', state.currentPage.toString());
105
+ } else {
106
+ url.searchParams.delete('page');
107
+ }
108
+ }
109
+
110
+ if (state.selectedFacets) {
111
+ for (const [facetName, facetValues] of Object.entries(
112
+ state.selectedFacets
113
+ )) {
114
+ const facetEntries = Object.entries(facetValues);
115
+ // eslint-disable-next-line no-continue
116
+ if (facetEntries.length === 0) continue;
117
+ for (const [key, facetState] of facetEntries) {
118
+ const notValue = facetState === 'hidden';
119
+ const paramValue = `${facetName}:${key}`;
120
+ if (notValue) {
121
+ url.searchParams.append('not[]', paramValue);
122
+ } else {
123
+ url.searchParams.append('and[]', paramValue);
124
+ }
125
+ }
126
+ }
127
+ }
128
+
129
+ if (state.dateRangeQueryClause) {
130
+ url.searchParams.append('and[]', state.dateRangeQueryClause);
131
+ }
132
+ if (state.titleQuery) {
133
+ url.searchParams.append('and[]', state.titleQuery);
134
+ }
135
+ if (state.creatorQuery) {
136
+ url.searchParams.append('and[]', state.creatorQuery);
137
+ }
138
+
139
+ window.history.pushState(
140
+ {
141
+ page: state.currentPage,
142
+ query: state.baseQuery,
143
+ },
144
+ '',
145
+ url
146
+ );
147
+ }
148
+
149
+ private loadQueryStateFromUrl(): RestorationState {
150
+ const url = new URL(window.location.href);
151
+ const pageNumber = url.searchParams.get('page');
152
+ const searchQuery = url.searchParams.get('query');
153
+ const sortQuery = url.searchParams.get('sort');
154
+ const facetAnds = url.searchParams.getAll('and[]');
155
+ const facetNots = url.searchParams.getAll('not[]');
156
+
157
+ const restorationState: RestorationState = {
158
+ selectedFacets: {
159
+ subject: {},
160
+ creator: {},
161
+ mediatype: {},
162
+ language: {},
163
+ collection: {},
164
+ year: {},
165
+ },
166
+ };
167
+
168
+ if (pageNumber) {
169
+ const parsed = parseInt(pageNumber, 10);
170
+ restorationState.currentPage = parsed;
171
+ } else {
172
+ restorationState.currentPage = 1;
173
+ }
174
+ if (searchQuery) {
175
+ restorationState.baseQuery = searchQuery;
176
+ }
177
+ if (sortQuery) {
178
+ const [field, direction] = sortQuery.split(' ');
179
+ const metadataField =
180
+ MetadataFieldToSortField[field as MetadataSortField];
181
+ if (metadataField) {
182
+ restorationState.selectedSort = metadataField;
183
+ }
184
+ if (direction === 'desc' || direction === 'asc') {
185
+ restorationState.sortDirection = direction as SortDirection;
186
+ }
187
+ }
188
+ if (facetAnds) {
189
+ facetAnds.forEach(and => {
190
+ const [field, value] = and.split(':');
191
+ switch (field) {
192
+ case 'year': {
193
+ const [minDate, maxDate] = value.split(' TO ');
194
+ // we have two potential ways of filtering by date:
195
+ // the range with "date TO date" or the single date with "date"
196
+ // this is checking for the range case and if we don't have those, fall
197
+ // back to the single date case
198
+ if (minDate && maxDate) {
199
+ restorationState.minSelectedDate = minDate.substring(
200
+ 1,
201
+ minDate.length
202
+ );
203
+ restorationState.maxSelectedDate = maxDate.substring(
204
+ 0,
205
+ maxDate.length - 1
206
+ );
207
+ restorationState.dateRangeQueryClause = `year:${value}`;
208
+ } else {
209
+ restorationState.selectedFacets[field as FacetOption][value] =
210
+ 'selected';
211
+ }
212
+ break;
213
+ }
214
+ case 'firstTitle':
215
+ restorationState.selectedTitleFilter = value;
216
+ break;
217
+ case 'firstCreator':
218
+ restorationState.selectedCreatorFilter = value;
219
+ break;
220
+ default:
221
+ restorationState.selectedFacets[field as FacetOption][value] =
222
+ 'selected';
223
+ }
224
+ });
225
+ }
226
+ if (facetNots) {
227
+ facetNots.forEach(not => {
228
+ const [field, value] = not.split(':');
229
+ restorationState.selectedFacets[field as FacetOption][value] = 'hidden';
230
+ });
231
+ }
232
+ return restorationState;
233
+ }
234
+ }
@@ -1,11 +1,9 @@
1
- import { LitElement, html, css, nothing } from 'lit';
1
+ import { LitElement, html, css } from 'lit';
2
2
  import { customElement, property } from 'lit/decorators.js';
3
3
 
4
4
  @customElement('alpha-bar')
5
5
  export class AlphaBar extends LitElement {
6
- @property({ type: String }) headline?: string;
7
-
8
- @property({ type: String }) selectedLetter?: string;
6
+ @property({ type: String }) selectedLetter: string | null = null;
9
7
 
10
8
  private get selectedUppercaseLetter(): string | undefined {
11
9
  return this.selectedLetter?.toUpperCase();
@@ -13,7 +11,6 @@ export class AlphaBar extends LitElement {
13
11
 
14
12
  render() {
15
13
  return html`
16
- <h1>${this.headline}</h1>
17
14
  <div id="container">
18
15
  <ul>
19
16
  ${this.alphabet.map(
@@ -22,9 +19,15 @@ export class AlphaBar extends LitElement {
22
19
  <li
23
20
  class=${letter === this.selectedUppercaseLetter
24
21
  ? 'selected'
25
- : nothing}
22
+ : ''}
26
23
  >
27
- <a href="#" @click=${() => this.letterClicked(letter)}>
24
+ <a
25
+ href="#"
26
+ @click=${(e: Event) => {
27
+ e.preventDefault();
28
+ this.letterClicked(letter);
29
+ }}
30
+ >
28
31
  ${letter}
29
32
  </a>
30
33
  </li>
@@ -37,7 +40,7 @@ export class AlphaBar extends LitElement {
37
40
 
38
41
  private letterClicked(letter: string) {
39
42
  if (letter === this.selectedUppercaseLetter) {
40
- this.selectedLetter = undefined;
43
+ this.selectedLetter = null;
41
44
  } else {
42
45
  this.selectedLetter = letter;
43
46
  }
@@ -58,6 +61,7 @@ export class AlphaBar extends LitElement {
58
61
  #container {
59
62
  background-color: #ddd;
60
63
  color: #333;
64
+ box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.5);
61
65
  }
62
66
 
63
67
  ul {
@@ -68,10 +72,16 @@ export class AlphaBar extends LitElement {
68
72
  justify-content: space-between;
69
73
  }
70
74
 
75
+ ul li {
76
+ flex: 1;
77
+ text-align: center;
78
+ max-width: 2.5rem;
79
+ }
80
+
71
81
  a {
72
82
  color: #333;
73
83
  text-decoration: none;
74
- padding: 0.5rem 0.7rem;
84
+ padding: 0.5rem 0;
75
85
  display: block;
76
86
  }
77
87
 
@@ -0,0 +1,5 @@
1
+ import { svg } from 'lit';
2
+
3
+ export const compactIcon = svg`
4
+ <svg viewBox="0 0 100 100" xmlns = "http://www.w3.org/2000/svg" > <path d="m96.9964435 6h-93.90621462c-.91561615 0-1.65899868-.29021372-2.23014758-.87064117-.57114891-.58042745-.85783455-1.3048369-.86005692-2.17322835 0-.81214848.28668564-1.50731158.86005692-2.08548931.57337127-.57817773 1.3167538-.86839145 2.23014758-.87064117h93.90621462c.800053 0 1.5012105.29021372 2.1034726.87064117.602262.58042745.9022819 1.27559055.9000718 2.08548931 0 .86839145-.3000321 1.5928009-.9000718 2.17322835-.6000398.58042745-1.3011973.87064117-2.1034726.87064117zm-93.90621462 9.6666667h93.90621462c.800053 0 1.5012105.2861891 2.1034726.8585673.602262.5723782.9022819 1.2579009.9000718 2.0565682 0 .8563487-.3000321 1.5851326-.9000718 2.1863516-.6000398.6012189-1.3011973.9007192-2.1034726.8985129h-93.90621462c-.91561615 0-1.65899868-.2995125-2.23014758-.8985129-.57114891-.5990005-.85783455-1.3277843-.86005692-2.1863516 0-.8008858.28668564-1.4864086.86005692-2.0565682.57337127-.5701597 1.3167538-.8563488 2.23014758-.8585673zm0 15.6700431h93.90621462c.800053 0 1.5012105.303883 2.1034726.9116489.602262.6077659.9022819 1.2886888.9000718 2.0427687-.0022346.7540799-.3022545 1.4496342-.9000718 2.0866629-.5978174.6370287-1.2989749.955543-2.1034726.955543h-93.90621462c-.85783454 0-1.58788286-.3038829-2.19014494-.9116488s-.90228193-1.3179516-.90007182-2.1305571c.00223463-.8126055.30225448-1.5081599.90007182-2.0866629.59781734-.5785031 1.32786566-.8688802 2.19014494-.8711312zm0 15.6632902h93.90621462c.800053 0 1.5012105.2861892 2.1034726.8585675.602262.5723783.9022819 1.2290603.9000718 1.9700462 0 .7986674-.3144775 1.5274514-.943408 2.186352-.6289306.6589006-1.3156427.9872417-2.0601364.9850343h-93.90621462c-.85783454 0-1.58788286-.3139318-2.19014494-.9417731-.60226208-.6278414-.90228193-1.3699365-.90007182-2.2262854 0-.7986674.2866979-1.4697699.86006918-2.0133074.57337127-.5435376 1.3167538-.8153063 2.23014758-.8153063zm0 15.6666667h93.90621462c.800053 0 1.5012105.3038947 2.1034726.9116593.602262.6077647.9022819 1.3472117.9000718 2.218341 0 .7540783-.3000321 1.4203685-.9000718 1.9988703-.6000398.5785019-1.3011973.8688784-2.1034726.8711294h-93.90621462c-.91561615 0-1.65899868-.2757451-2.23014758-.8272352-.57114891-.5514902-.85783455-1.2324117-.86005692-2.0427645 0-.8688784.28668564-1.6083253.86005692-2.218341.57337127-.6100156 1.3167538-.9138979 2.23014758-.9116593zm0 15.6666666h93.90621462c.800053 0 1.5012105.3038948 2.1034726.9116594.602262.6077646.9022819 1.3472116.9000718 2.2183409 0 .7540784-.3000321 1.4203685-.9000718 1.9988704-.6000398.5785019-1.3011973.8688784-2.1034726.8711293h-93.90621462c-.91561615 0-1.65899868-.275745-2.23014758-.8272352-.57114891-.5514901-.85783455-1.2324116-.86005692-2.0427645 0-.8688783.28668564-1.6083253.86005692-2.2183409.57337127-.6100156 1.3167538-.9138979 2.23014758-.9116594zm0 15.6666667h93.90621462c.800053 0 1.5012105.3038947 2.1034726.9116594.602262.6077646.9022819 1.3472116.9000718 2.2183409 0 .7540784-.3000321 1.4203685-.9000718 1.9988704-.6000398.5785019-1.3011973.8688783-2.1034726.8711293h-93.90621462c-.91561615 0-1.65899868-.2757451-2.23014758-.8272352-.57114891-.5514901-.85783455-1.2324116-.86005692-2.0427645 0-.8688783.28668564-1.6083253.86005692-2.2183409.57337127-.6100156 1.3167538-.913898 2.23014758-.9116594z" /> </svg>
5
+ `;
@@ -0,0 +1,5 @@
1
+ import { svg } from 'lit';
2
+
3
+ export const listIcon = svg`
4
+ <svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><g fill="#000" fill-rule="nonzero"><path d="m97.8975061 6h-65.7343743c-.6409315 0-1.1612995-.29021372-1.5611039-.87064117-.3998043-.58042745-.6004844-1.3048369-.60204-2.17322835 0-.81214848.20068-1.50731158.60204-2.08548931.4013601-.57817773.921728-.86839145 1.5611039-.87064117h65.7343743c.5600372 0 1.0508477.29021372 1.4724313.87064117s.6315976 1.27559055.6300505 2.08548931c0 .86839145-.2100226 1.5928009-.6300505 2.17322835-.420028.58042745-.9108384.87064117-1.4724313.87064117z"/><path d="m97.8975061 65h-65.7343743c-.6409315 0-1.1612995-.2902137-1.5611039-.8706412-.3998043-.5804274-.6004844-1.3048369-.60204-2.1732283 0-.8121485.20068-1.5073116.60204-2.0854893.4013601-.5781778.921728-.8683915 1.5611039-.8706412h65.7343743c.5600372 0 1.0508477.2902137 1.4724313.8706412.4215836.5804274.6315976 1.2755905.6300505 2.0854893 0 .8683914-.2100226 1.5928009-.6300505 2.1732283-.420028.5804275-.9108384.8706412-1.4724313.8706412z"/><path d="m97.8975061 13h-65.7343743c-.6409315 0-1.1612995-.0967379-1.5611039-.2902137-.3998043-.1934758-.6004844-.4349457-.60204-.7244095 0-.2707161.20068-.5024372.60204-.6951631.4013601-.1927259.921728-.2894638 1.5611039-.2902137h65.7343743c.5600372 0 1.0508477.0967379 1.4724313.2902137s.6315976.4251969.6300505.6951631c0 .2894638-.2100226.5309337-.6300505.7244095-.420028.1934758-.9108384.2902137-1.4724313.2902137z"/><path d="m97.8975061 72h-65.7343743c-.6409315 0-1.1612995-.0967379-1.5611039-.2902137-.3998043-.1934758-.6004844-.4349457-.60204-.7244095 0-.2707161.20068-.5024372.60204-.6951631.4013601-.1927259.921728-.2894638 1.5611039-.2902137h65.7343743c.5600372 0 1.0508477.0967379 1.4724313.2902137s.6315976.4251969.6300505.6951631c0 .2894638-.2100226.5309337-.6300505.7244095-.420028.1934758-.9108384.2902137-1.4724313.2902137z"/><path d="m97.8975061 20h-65.7343743c-.6409315 0-1.1612995-.0967379-1.5611039-.2902137-.3998043-.1934758-.6004844-.4349457-.60204-.7244095 0-.2707161.20068-.5024372.60204-.6951631.4013601-.1927259.921728-.2894638 1.5611039-.2902137h65.7343743c.5600372 0 1.0508477.0967379 1.4724313.2902137s.6315976.4251969.6300505.6951631c0 .2894638-.2100226.5309337-.6300505.7244095-.420028.1934758-.9108384.2902137-1.4724313.2902137z"/><path d="m97.8975061 79h-65.7343743c-.6409315 0-1.1612995-.0967379-1.5611039-.2902137-.3998043-.1934758-.6004844-.4349457-.60204-.7244095 0-.2707161.20068-.5024372.60204-.6951631.4013601-.1927259.921728-.2894638 1.5611039-.2902137h65.7343743c.5600372 0 1.0508477.0967379 1.4724313.2902137s.6315976.4251969.6300505.6951631c0 .2894638-.2100226.5309337-.6300505.7244095-.420028.1934758-.9108384.2902137-1.4724313.2902137z"/><path d="m97.8975061 27h-65.7343743c-.6409315 0-1.1612995-.0967379-1.5611039-.2902137-.3998043-.1934758-.6004844-.4349457-.60204-.7244095 0-.2707161.20068-.5024372.60204-.6951631.4013601-.1927259.921728-.2894638 1.5611039-.2902137h65.7343743c.5600372 0 1.0508477.0967379 1.4724313.2902137s.6315976.4251969.6300505.6951631c0 .2894638-.2100226.5309337-.6300505.7244095-.420028.1934758-.9108384.2902137-1.4724313.2902137z"/><path d="m97.8975061 86h-65.7343743c-.6409315 0-1.1612995-.0967379-1.5611039-.2902137-.3998043-.1934758-.6004844-.4349457-.60204-.7244095 0-.2707161.20068-.5024372.60204-.6951631.4013601-.1927259.921728-.2894638 1.5611039-.2902137h65.7343743c.5600372 0 1.0508477.0967379 1.4724313.2902137s.6315976.4251969.6300505.6951631c0 .2894638-.2100226.5309337-.6300505.7244095-.420028.1934758-.9108384.2902137-1.4724313.2902137z"/><path d="m97.8975061 34h-65.7343743c-.6409315 0-1.1612995-.0967379-1.5611039-.2902137-.3998043-.1934758-.6004844-.4349457-.60204-.7244095 0-.2707161.20068-.5024372.60204-.6951631.4013601-.1927259.921728-.2894638 1.5611039-.2902137h65.7343743c.5600372 0 1.0508477.0967379 1.4724313.2902137s.6315976.4251969.6300505.6951631c0 .2894638-.2100226.5309337-.6300505.7244095-.420028.1934758-.9108384.2902137-1.4724313.2902137z"/><path d="m97.8975061 93h-65.7343743c-.6409315 0-1.1612995-.0967379-1.5611039-.2902137-.3998043-.1934758-.6004844-.4349457-.60204-.7244095 0-.2707161.20068-.5024372.60204-.6951631.4013601-.1927259.921728-.2894638 1.5611039-.2902137h65.7343743c.5600372 0 1.0508477.0967379 1.4724313.2902137s.6315976.4251969.6300505.6951631c0 .2894638-.2100226.5309337-.6300505.7244095-.420028.1934758-.9108384.2902137-1.4724313.2902137z"/><path d="m97.8975061 41h-65.7343743c-.6409315 0-1.1612995-.0967379-1.5611039-.2902137-.3998043-.1934758-.6004844-.4349457-.60204-.7244095 0-.2707161.20068-.5024372.60204-.6951631.4013601-.1927259.921728-.2894638 1.5611039-.2902137h65.7343743c.5600372 0 1.0508477.0967379 1.4724313.2902137s.6315976.4251969.6300505.6951631c0 .2894638-.2100226.5309337-.6300505.7244095-.420028.1934758-.9108384.2902137-1.4724313.2902137z"/><path d="m97.8975061 100h-65.7343743c-.6409315 0-1.1612995-.0967379-1.5611039-.2902137-.3998043-.1934758-.6004844-.4349457-.60204-.7244095 0-.2707161.20068-.5024372.60204-.6951631.4013601-.1927259.921728-.2894638 1.5611039-.2902137h65.7343743c.5600372 0 1.0508477.0967379 1.4724313.2902137s.6315976.4251969.6300505.6951631c0 .2894638-.2100226.5309337-.6300505.7244095-.420028.1934758-.9108384.2902137-1.4724313.2902137z"/><path d="m0 0h25v25h-25z"/><path d="m0 59h25v25h-25z"/></g></svg>
5
+ `;
@@ -0,0 +1,5 @@
1
+ import { svg } from 'lit';
2
+
3
+ export const sortIcon = svg`
4
+ <svg viewBox="0 0 100 55" xmlns="http://www.w3.org/2000/svg"><path d="m50 0 50 55h-100z"/></svg>
5
+ `;
@@ -0,0 +1,5 @@
1
+ import { svg } from 'lit';
2
+
3
+ export const tileIcon = svg`
4
+ <svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path d="m64 54v46h-28v-46zm36 0v46h-28v-46zm-72 0v46h-28v-46zm36-54v46h-28v-46zm36 0v46h-28v-46zm-72 0v46h-28v-46z"/></svg>
5
+ `;