@internetarchive/collection-browser 1.14.17-beta.5 → 1.14.18-alpha.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 (352) hide show
  1. package/.editorconfig +29 -29
  2. package/.husky/pre-commit +4 -4
  3. package/LICENSE +661 -661
  4. package/README.md +83 -83
  5. package/dist/index.d.ts +12 -11
  6. package/dist/index.js +12 -11
  7. package/dist/index.js.map +1 -1
  8. package/dist/src/app-root.d.ts +83 -83
  9. package/dist/src/app-root.js +438 -489
  10. package/dist/src/app-root.js.map +1 -1
  11. package/dist/src/assets/img/icons/arrow-left.d.ts +2 -2
  12. package/dist/src/assets/img/icons/arrow-left.js +2 -2
  13. package/dist/src/assets/img/icons/arrow-right.d.ts +2 -2
  14. package/dist/src/assets/img/icons/arrow-right.js +2 -2
  15. package/dist/src/assets/img/icons/chevron.d.ts +2 -2
  16. package/dist/src/assets/img/icons/chevron.js +2 -2
  17. package/dist/src/assets/img/icons/contract.d.ts +2 -2
  18. package/dist/src/assets/img/icons/contract.js +2 -2
  19. package/dist/src/assets/img/icons/empty-query.d.ts +2 -2
  20. package/dist/src/assets/img/icons/empty-query.js +2 -2
  21. package/dist/src/assets/img/icons/expand.d.ts +2 -2
  22. package/dist/src/assets/img/icons/expand.js +2 -2
  23. package/dist/src/assets/img/icons/eye-closed.d.ts +2 -2
  24. package/dist/src/assets/img/icons/eye-closed.js +2 -2
  25. package/dist/src/assets/img/icons/eye.d.ts +2 -2
  26. package/dist/src/assets/img/icons/eye.js +2 -2
  27. package/dist/src/assets/img/icons/favorite-filled.d.ts +1 -1
  28. package/dist/src/assets/img/icons/favorite-filled.js +2 -2
  29. package/dist/src/assets/img/icons/login-required.d.ts +1 -1
  30. package/dist/src/assets/img/icons/login-required.js +2 -2
  31. package/dist/src/assets/img/icons/mediatype/account.d.ts +1 -1
  32. package/dist/src/assets/img/icons/mediatype/account.js +2 -2
  33. package/dist/src/assets/img/icons/mediatype/audio.d.ts +1 -1
  34. package/dist/src/assets/img/icons/mediatype/audio.js +2 -2
  35. package/dist/src/assets/img/icons/mediatype/collection.d.ts +1 -1
  36. package/dist/src/assets/img/icons/mediatype/collection.js +2 -2
  37. package/dist/src/assets/img/icons/mediatype/data.d.ts +1 -1
  38. package/dist/src/assets/img/icons/mediatype/data.js +2 -2
  39. package/dist/src/assets/img/icons/mediatype/etree.d.ts +1 -1
  40. package/dist/src/assets/img/icons/mediatype/etree.js +2 -2
  41. package/dist/src/assets/img/icons/mediatype/film.d.ts +1 -1
  42. package/dist/src/assets/img/icons/mediatype/film.js +2 -2
  43. package/dist/src/assets/img/icons/mediatype/images.d.ts +1 -1
  44. package/dist/src/assets/img/icons/mediatype/images.js +2 -2
  45. package/dist/src/assets/img/icons/mediatype/radio.d.ts +1 -1
  46. package/dist/src/assets/img/icons/mediatype/radio.js +2 -2
  47. package/dist/src/assets/img/icons/mediatype/search.d.ts +1 -1
  48. package/dist/src/assets/img/icons/mediatype/search.js +2 -2
  49. package/dist/src/assets/img/icons/mediatype/software.d.ts +1 -1
  50. package/dist/src/assets/img/icons/mediatype/software.js +2 -2
  51. package/dist/src/assets/img/icons/mediatype/texts.d.ts +1 -1
  52. package/dist/src/assets/img/icons/mediatype/texts.js +2 -2
  53. package/dist/src/assets/img/icons/mediatype/tv.d.ts +1 -1
  54. package/dist/src/assets/img/icons/mediatype/tv.js +2 -2
  55. package/dist/src/assets/img/icons/mediatype/video.d.ts +1 -1
  56. package/dist/src/assets/img/icons/mediatype/video.js +2 -2
  57. package/dist/src/assets/img/icons/mediatype/web.d.ts +1 -1
  58. package/dist/src/assets/img/icons/mediatype/web.js +2 -2
  59. package/dist/src/assets/img/icons/null-result.d.ts +2 -2
  60. package/dist/src/assets/img/icons/null-result.js +2 -2
  61. package/dist/src/assets/img/icons/restricted.d.ts +1 -1
  62. package/dist/src/assets/img/icons/restricted.js +2 -2
  63. package/dist/src/assets/img/icons/reviews.d.ts +1 -1
  64. package/dist/src/assets/img/icons/reviews.js +2 -2
  65. package/dist/src/assets/img/icons/upload.d.ts +1 -1
  66. package/dist/src/assets/img/icons/upload.js +2 -2
  67. package/dist/src/assets/img/icons/views.d.ts +1 -1
  68. package/dist/src/assets/img/icons/views.js +2 -2
  69. package/dist/src/circular-activity-indicator.d.ts +5 -5
  70. package/dist/src/circular-activity-indicator.js +17 -17
  71. package/dist/src/collection-browser.d.ts +384 -406
  72. package/dist/src/collection-browser.js +1342 -1363
  73. package/dist/src/collection-browser.js.map +1 -1
  74. package/dist/src/collection-facets/facet-row.d.ts +30 -30
  75. package/dist/src/collection-facets/facet-row.js +114 -114
  76. package/dist/src/collection-facets/facet-tombstone-row.d.ts +5 -5
  77. package/dist/src/collection-facets/facet-tombstone-row.js +15 -15
  78. package/dist/src/collection-facets/facets-template.d.ts +17 -17
  79. package/dist/src/collection-facets/facets-template.js +114 -114
  80. package/dist/src/collection-facets/more-facets-content.d.ts +70 -70
  81. package/dist/src/collection-facets/more-facets-content.js +354 -369
  82. package/dist/src/collection-facets/more-facets-content.js.map +1 -1
  83. package/dist/src/collection-facets/more-facets-pagination.d.ts +36 -36
  84. package/dist/src/collection-facets/more-facets-pagination.js +196 -196
  85. package/dist/src/collection-facets/toggle-switch.d.ts +41 -41
  86. package/dist/src/collection-facets/toggle-switch.js +94 -94
  87. package/dist/src/collection-facets.d.ts +103 -103
  88. package/dist/src/collection-facets.js +513 -510
  89. package/dist/src/collection-facets.js.map +1 -1
  90. package/dist/src/data-source/collection-browser-data-source-interface.d.ts +217 -0
  91. package/dist/src/data-source/collection-browser-data-source-interface.js +2 -0
  92. package/dist/src/data-source/collection-browser-data-source-interface.js.map +1 -0
  93. package/dist/src/data-source/collection-browser-data-source.d.ts +352 -434
  94. package/dist/src/data-source/collection-browser-data-source.js +911 -800
  95. package/dist/src/data-source/collection-browser-data-source.js.map +1 -1
  96. package/dist/src/data-source/collection-browser-query-state.d.ts +43 -0
  97. package/dist/src/data-source/collection-browser-query-state.js +2 -0
  98. package/dist/src/data-source/collection-browser-query-state.js.map +1 -0
  99. package/dist/src/data-source/models.d.ts +28 -62
  100. package/dist/src/data-source/models.js +8 -1
  101. package/dist/src/data-source/models.js.map +1 -1
  102. package/dist/src/empty-placeholder.d.ts +23 -23
  103. package/dist/src/empty-placeholder.js +74 -74
  104. package/dist/src/expanded-date-picker.d.ts +43 -43
  105. package/dist/src/expanded-date-picker.js +109 -109
  106. package/dist/src/language-code-handler/language-code-handler.d.ts +37 -37
  107. package/dist/src/language-code-handler/language-code-handler.js +26 -26
  108. package/dist/src/language-code-handler/language-code-mapping.d.ts +1 -1
  109. package/dist/src/language-code-handler/language-code-mapping.js +562 -562
  110. package/dist/src/manage/manage-bar.d.ts +26 -26
  111. package/dist/src/manage/manage-bar.js +53 -53
  112. package/dist/src/manage/manage-bar.js.map +1 -1
  113. package/dist/src/mediatype/mediatype-config.d.ts +3 -3
  114. package/dist/src/mediatype/mediatype-config.js +91 -91
  115. package/dist/src/models.d.ts +197 -180
  116. package/dist/src/models.js +380 -269
  117. package/dist/src/models.js.map +1 -1
  118. package/dist/src/restoration-state-handler.d.ts +70 -70
  119. package/dist/src/restoration-state-handler.js +355 -355
  120. package/dist/src/sort-filter-bar/alpha-bar-tooltip.d.ts +6 -6
  121. package/dist/src/sort-filter-bar/alpha-bar-tooltip.js +24 -24
  122. package/dist/src/sort-filter-bar/alpha-bar.d.ts +21 -21
  123. package/dist/src/sort-filter-bar/alpha-bar.js +128 -128
  124. package/dist/src/sort-filter-bar/img/compact.d.ts +1 -1
  125. package/dist/src/sort-filter-bar/img/compact.js +2 -2
  126. package/dist/src/sort-filter-bar/img/list.d.ts +1 -1
  127. package/dist/src/sort-filter-bar/img/list.js +2 -2
  128. package/dist/src/sort-filter-bar/img/sort-toggle-disabled.d.ts +1 -1
  129. package/dist/src/sort-filter-bar/img/sort-toggle-disabled.js +2 -2
  130. package/dist/src/sort-filter-bar/img/sort-toggle-down.d.ts +1 -1
  131. package/dist/src/sort-filter-bar/img/sort-toggle-down.js +2 -2
  132. package/dist/src/sort-filter-bar/img/sort-toggle-up.d.ts +1 -1
  133. package/dist/src/sort-filter-bar/img/sort-toggle-up.js +2 -2
  134. package/dist/src/sort-filter-bar/img/sort-triangle.d.ts +1 -1
  135. package/dist/src/sort-filter-bar/img/sort-triangle.js +2 -2
  136. package/dist/src/sort-filter-bar/img/tile.d.ts +1 -1
  137. package/dist/src/sort-filter-bar/img/tile.js +2 -2
  138. package/dist/src/sort-filter-bar/sort-filter-bar.d.ts +210 -210
  139. package/dist/src/sort-filter-bar/sort-filter-bar.js +653 -652
  140. package/dist/src/sort-filter-bar/sort-filter-bar.js.map +1 -1
  141. package/dist/src/styles/item-image-styles.d.ts +8 -8
  142. package/dist/src/styles/item-image-styles.js +9 -9
  143. package/dist/src/styles/sr-only.d.ts +1 -1
  144. package/dist/src/styles/sr-only.js +2 -2
  145. package/dist/src/tiles/base-tile-component.d.ts +19 -19
  146. package/dist/src/tiles/base-tile-component.js +63 -63
  147. package/dist/src/tiles/collection-browser-loading-tile.d.ts +5 -5
  148. package/dist/src/tiles/collection-browser-loading-tile.js +15 -15
  149. package/dist/src/tiles/grid/account-tile.d.ts +18 -18
  150. package/dist/src/tiles/grid/account-tile.js +72 -72
  151. package/dist/src/tiles/grid/collection-tile.d.ts +15 -15
  152. package/dist/src/tiles/grid/collection-tile.js +80 -80
  153. package/dist/src/tiles/grid/item-tile.d.ts +28 -27
  154. package/dist/src/tiles/grid/item-tile.js +162 -135
  155. package/dist/src/tiles/grid/item-tile.js.map +1 -1
  156. package/dist/src/tiles/grid/search-tile.d.ts +10 -10
  157. package/dist/src/tiles/grid/search-tile.js +51 -51
  158. package/dist/src/tiles/grid/styles/tile-grid-shared-styles.d.ts +1 -1
  159. package/dist/src/tiles/grid/styles/tile-grid-shared-styles.js +8 -8
  160. package/dist/src/tiles/grid/tile-stats.d.ts +11 -11
  161. package/dist/src/tiles/grid/tile-stats.js +58 -53
  162. package/dist/src/tiles/grid/tile-stats.js.map +1 -1
  163. package/dist/src/tiles/hover/hover-pane-controller.d.ts +219 -219
  164. package/dist/src/tiles/hover/hover-pane-controller.js +352 -352
  165. package/dist/src/tiles/hover/tile-hover-pane.d.ts +15 -15
  166. package/dist/src/tiles/hover/tile-hover-pane.js +38 -38
  167. package/dist/src/tiles/image-block.d.ts +17 -17
  168. package/dist/src/tiles/image-block.js +73 -73
  169. package/dist/src/tiles/item-image.d.ts +39 -36
  170. package/dist/src/tiles/item-image.js +155 -127
  171. package/dist/src/tiles/item-image.js.map +1 -1
  172. package/dist/src/tiles/list/tile-list-compact-header.d.ts +6 -6
  173. package/dist/src/tiles/list/tile-list-compact-header.js +38 -38
  174. package/dist/src/tiles/list/tile-list-compact.d.ts +15 -15
  175. package/dist/src/tiles/list/tile-list-compact.js +115 -115
  176. package/dist/src/tiles/list/tile-list-compact.js.map +1 -1
  177. package/dist/src/tiles/list/tile-list.d.ts +47 -46
  178. package/dist/src/tiles/list/tile-list.js +327 -296
  179. package/dist/src/tiles/list/tile-list.js.map +1 -1
  180. package/dist/src/tiles/mediatype-icon.d.ts +9 -9
  181. package/dist/src/tiles/mediatype-icon.js +47 -47
  182. package/dist/src/tiles/overlay/icon-overlay.d.ts +10 -10
  183. package/dist/src/tiles/overlay/icon-overlay.js +40 -40
  184. package/dist/src/tiles/overlay/icon-text-overlay.d.ts +9 -9
  185. package/dist/src/tiles/overlay/icon-text-overlay.js +38 -38
  186. package/dist/src/tiles/overlay/text-overlay.d.ts +10 -10
  187. package/dist/src/tiles/overlay/text-overlay.js +42 -42
  188. package/dist/src/tiles/text-snippet-block.d.ts +27 -27
  189. package/dist/src/tiles/text-snippet-block.js +73 -73
  190. package/dist/src/tiles/tile-dispatcher.d.ts +64 -64
  191. package/dist/src/tiles/tile-dispatcher.js +232 -231
  192. package/dist/src/tiles/tile-dispatcher.js.map +1 -1
  193. package/dist/src/tiles/tile-display-value-provider.d.ts +47 -43
  194. package/dist/src/tiles/tile-display-value-provider.js +94 -80
  195. package/dist/src/tiles/tile-display-value-provider.js.map +1 -1
  196. package/dist/src/utils/analytics-events.d.ts +25 -25
  197. package/dist/src/utils/analytics-events.js +27 -27
  198. package/dist/src/utils/array-equals.d.ts +4 -4
  199. package/dist/src/utils/array-equals.js +10 -10
  200. package/dist/src/utils/collapse-repeated-quotes.d.ts +11 -0
  201. package/dist/src/utils/collapse-repeated-quotes.js +14 -0
  202. package/dist/src/utils/collapse-repeated-quotes.js.map +1 -0
  203. package/dist/src/utils/format-count.d.ts +7 -7
  204. package/dist/src/utils/format-count.js +76 -76
  205. package/dist/src/utils/format-date.d.ts +2 -2
  206. package/dist/src/utils/format-date.js +25 -25
  207. package/dist/src/utils/format-unit-size.d.ts +2 -2
  208. package/dist/src/utils/format-unit-size.js +33 -33
  209. package/dist/src/utils/local-date-from-utc.d.ts +9 -9
  210. package/dist/src/utils/local-date-from-utc.js +15 -15
  211. package/dist/src/utils/log.d.ts +7 -0
  212. package/dist/src/utils/log.js +16 -0
  213. package/dist/src/utils/log.js.map +1 -0
  214. package/dist/src/utils/resolve-mediatype.d.ts +8 -0
  215. package/dist/src/utils/resolve-mediatype.js +24 -0
  216. package/dist/src/utils/resolve-mediatype.js.map +1 -0
  217. package/dist/src/utils/sha1.d.ts +2 -2
  218. package/dist/src/utils/sha1.js +8 -8
  219. package/dist/test/collection-browser.test.d.ts +1 -1
  220. package/dist/test/collection-browser.test.js +1211 -1149
  221. package/dist/test/collection-browser.test.js.map +1 -1
  222. package/dist/test/collection-facets/facet-row.test.d.ts +1 -1
  223. package/dist/test/collection-facets/facet-row.test.js +203 -203
  224. package/dist/test/collection-facets/facets-template.test.d.ts +1 -1
  225. package/dist/test/collection-facets/facets-template.test.js +105 -105
  226. package/dist/test/collection-facets/more-facets-content.test.d.ts +1 -1
  227. package/dist/test/collection-facets/more-facets-content.test.js +133 -133
  228. package/dist/test/collection-facets/more-facets-content.test.js.map +1 -1
  229. package/dist/test/collection-facets/more-facets-pagination.test.d.ts +1 -1
  230. package/dist/test/collection-facets/more-facets-pagination.test.js +117 -117
  231. package/dist/test/collection-facets/toggle-switch.test.d.ts +1 -1
  232. package/dist/test/collection-facets/toggle-switch.test.js +73 -73
  233. package/dist/test/collection-facets.test.d.ts +2 -2
  234. package/dist/test/collection-facets.test.js +653 -648
  235. package/dist/test/collection-facets.test.js.map +1 -1
  236. package/dist/test/data-source/collection-browser-data-source.test.d.ts +1 -0
  237. package/dist/test/data-source/collection-browser-data-source.test.js +80 -0
  238. package/dist/test/data-source/collection-browser-data-source.test.js.map +1 -0
  239. package/dist/test/empty-placeholder.test.d.ts +1 -1
  240. package/dist/test/empty-placeholder.test.js +63 -63
  241. package/dist/test/expanded-date-picker.test.d.ts +1 -1
  242. package/dist/test/expanded-date-picker.test.js +95 -95
  243. package/dist/test/icon-overlay.test.d.ts +1 -1
  244. package/dist/test/icon-overlay.test.js +24 -24
  245. package/dist/test/image-block.test.d.ts +1 -1
  246. package/dist/test/image-block.test.js +48 -48
  247. package/dist/test/item-image.test.d.ts +1 -1
  248. package/dist/test/item-image.test.js +85 -86
  249. package/dist/test/item-image.test.js.map +1 -1
  250. package/dist/test/manage/manage-bar.test.d.ts +1 -1
  251. package/dist/test/manage/manage-bar.test.js +72 -72
  252. package/dist/test/mediatype-config.test.d.ts +1 -1
  253. package/dist/test/mediatype-config.test.js +16 -16
  254. package/dist/test/mocks/mock-analytics-handler.d.ts +10 -10
  255. package/dist/test/mocks/mock-analytics-handler.js +15 -15
  256. package/dist/test/mocks/mock-search-responses.d.ts +24 -21
  257. package/dist/test/mocks/mock-search-responses.js +840 -709
  258. package/dist/test/mocks/mock-search-responses.js.map +1 -1
  259. package/dist/test/mocks/mock-search-service.d.ts +15 -15
  260. package/dist/test/mocks/mock-search-service.js +53 -50
  261. package/dist/test/mocks/mock-search-service.js.map +1 -1
  262. package/dist/test/restoration-state-handler.test.d.ts +1 -1
  263. package/dist/test/restoration-state-handler.test.js +270 -270
  264. package/dist/test/sort-filter-bar/alpha-bar-tooltip.test.d.ts +1 -1
  265. package/dist/test/sort-filter-bar/alpha-bar-tooltip.test.js +12 -12
  266. package/dist/test/sort-filter-bar/alpha-bar.test.d.ts +1 -1
  267. package/dist/test/sort-filter-bar/alpha-bar.test.js +73 -73
  268. package/dist/test/sort-filter-bar/sort-filter-bar.test.d.ts +1 -1
  269. package/dist/test/sort-filter-bar/sort-filter-bar.test.js +418 -418
  270. package/dist/test/text-overlay.test.d.ts +1 -1
  271. package/dist/test/text-overlay.test.js +48 -48
  272. package/dist/test/text-snippet-block.test.d.ts +1 -1
  273. package/dist/test/text-snippet-block.test.js +57 -57
  274. package/dist/test/tile-stats.test.d.ts +1 -1
  275. package/dist/test/tile-stats.test.js +95 -33
  276. package/dist/test/tile-stats.test.js.map +1 -1
  277. package/dist/test/tiles/grid/account-tile.test.d.ts +1 -1
  278. package/dist/test/tiles/grid/account-tile.test.js +76 -76
  279. package/dist/test/tiles/grid/collection-tile.test.d.ts +1 -1
  280. package/dist/test/tiles/grid/collection-tile.test.js +73 -73
  281. package/dist/test/tiles/grid/item-tile.test.d.ts +1 -1
  282. package/dist/test/tiles/grid/item-tile.test.js +298 -254
  283. package/dist/test/tiles/grid/item-tile.test.js.map +1 -1
  284. package/dist/test/tiles/grid/search-tile.test.d.ts +1 -1
  285. package/dist/test/tiles/grid/search-tile.test.js +51 -51
  286. package/dist/test/tiles/hover/hover-pane-controller.test.d.ts +1 -1
  287. package/dist/test/tiles/hover/hover-pane-controller.test.js +259 -258
  288. package/dist/test/tiles/hover/hover-pane-controller.test.js.map +1 -1
  289. package/dist/test/tiles/hover/tile-hover-pane.test.d.ts +1 -1
  290. package/dist/test/tiles/hover/tile-hover-pane.test.js +13 -13
  291. package/dist/test/tiles/list/tile-list-compact.test.d.ts +1 -1
  292. package/dist/test/tiles/list/tile-list-compact.test.js +143 -143
  293. package/dist/test/tiles/list/tile-list.test.d.ts +1 -1
  294. package/dist/test/tiles/list/tile-list.test.js +283 -239
  295. package/dist/test/tiles/list/tile-list.test.js.map +1 -1
  296. package/dist/test/tiles/tile-dispatcher.test.d.ts +1 -1
  297. package/dist/test/tiles/tile-dispatcher.test.js +106 -94
  298. package/dist/test/tiles/tile-dispatcher.test.js.map +1 -1
  299. package/dist/test/tiles/tile-display-value-provider.test.d.ts +1 -1
  300. package/dist/test/tiles/tile-display-value-provider.test.js +141 -141
  301. package/dist/test/utils/array-equals.test.d.ts +1 -1
  302. package/dist/test/utils/array-equals.test.js +26 -26
  303. package/dist/test/utils/format-count.test.d.ts +1 -1
  304. package/dist/test/utils/format-count.test.js +23 -23
  305. package/dist/test/utils/format-date.test.d.ts +1 -1
  306. package/dist/test/utils/format-date.test.js +17 -17
  307. package/dist/test/utils/format-unit-size.test.d.ts +1 -1
  308. package/dist/test/utils/format-unit-size.test.js +17 -17
  309. package/dist/test/utils/local-date-from-utc.test.d.ts +1 -1
  310. package/dist/test/utils/local-date-from-utc.test.js +26 -26
  311. package/index.ts +3 -5
  312. package/local.archive.org.cert +86 -86
  313. package/local.archive.org.key +27 -27
  314. package/package.json +3 -4
  315. package/renovate.json +6 -6
  316. package/src/app-root.ts +30 -85
  317. package/src/collection-browser.ts +112 -139
  318. package/src/collection-facets/more-facets-content.ts +0 -19
  319. package/src/collection-facets.ts +6 -4
  320. package/src/data-source/collection-browser-data-source-interface.ts +272 -0
  321. package/src/data-source/collection-browser-data-source.ts +314 -379
  322. package/src/data-source/collection-browser-query-state.ts +54 -0
  323. package/src/data-source/models.ts +8 -45
  324. package/src/manage/manage-bar.ts +1 -1
  325. package/src/models.ts +164 -3
  326. package/src/sort-filter-bar/sort-filter-bar.ts +2 -1
  327. package/src/tiles/grid/item-tile.ts +36 -1
  328. package/src/tiles/grid/tile-stats.ts +12 -7
  329. package/src/tiles/item-image.ts +28 -0
  330. package/src/tiles/list/tile-list-compact.ts +1 -1
  331. package/src/tiles/list/tile-list.ts +43 -5
  332. package/src/tiles/tile-dispatcher.ts +2 -1
  333. package/src/tiles/tile-display-value-provider.ts +20 -2
  334. package/src/utils/collapse-repeated-quotes.ts +13 -0
  335. package/src/utils/log.ts +16 -0
  336. package/src/utils/resolve-mediatype.ts +26 -0
  337. package/test/collection-browser.test.ts +161 -50
  338. package/test/collection-facets/more-facets-content.test.ts +4 -2
  339. package/test/collection-facets.test.ts +5 -0
  340. package/test/data-source/collection-browser-data-source.test.ts +103 -0
  341. package/test/item-image.test.ts +34 -36
  342. package/test/mocks/mock-search-responses.ts +144 -0
  343. package/test/mocks/mock-search-service.ts +6 -0
  344. package/test/tile-stats.test.ts +104 -0
  345. package/test/tiles/grid/item-tile.test.ts +55 -0
  346. package/test/tiles/hover/hover-pane-controller.test.ts +19 -17
  347. package/test/tiles/list/tile-list.test.ts +55 -0
  348. package/test/tiles/tile-dispatcher.test.ts +13 -0
  349. package/tsconfig.json +21 -21
  350. package/web-dev-server.config.mjs +30 -30
  351. package/web-test-runner.config.mjs +41 -41
  352. package/types/sentry.d.ts +0 -1
@@ -0,0 +1,54 @@
1
+ import type {
2
+ CollectionExtraInfo,
3
+ PageElementName,
4
+ SearchServiceInterface,
5
+ SearchType,
6
+ SortDirection,
7
+ SortParam,
8
+ } from '@internetarchive/search-service';
9
+ import type { SelectedFacets, SortField } from '../models';
10
+ import type { CollectionBrowserDataSourceInterface } from './collection-browser-data-source-interface';
11
+
12
+ /**
13
+ * Properties of collection browser that affect the overall search query
14
+ */
15
+ export interface CollectionBrowserQueryState {
16
+ baseQuery?: string;
17
+ withinCollection?: string;
18
+ withinProfile?: string;
19
+ profileElement?: PageElementName;
20
+ searchType: SearchType;
21
+ selectedFacets?: SelectedFacets;
22
+ minSelectedDate?: string;
23
+ maxSelectedDate?: string;
24
+ selectedTitleFilter: string | null;
25
+ selectedCreatorFilter: string | null;
26
+ selectedSort?: SortField;
27
+ sortDirection: SortDirection | null;
28
+ }
29
+
30
+ /**
31
+ * Interface representing search-related state and operations required by the
32
+ * data source on its host component.
33
+ */
34
+ export interface CollectionBrowserSearchInterface
35
+ extends CollectionBrowserQueryState {
36
+ searchService?: SearchServiceInterface;
37
+ readonly sortParam: SortParam | null;
38
+ readonly defaultSortParam: SortParam | null;
39
+ readonly suppressFacets?: boolean;
40
+ readonly initialPageNumber: number;
41
+ readonly currentVisiblePageNumbers: number[];
42
+ readonly clearResultsOnEmptyQuery?: boolean;
43
+ readonly dataSource?: CollectionBrowserDataSourceInterface;
44
+
45
+ getSessionId(): Promise<string>;
46
+ setSearchResultsLoading(loading: boolean): void;
47
+ setFacetsLoading(loading: boolean): void;
48
+ setTotalResultCount(count: number): void;
49
+ setTileCount(count: number): void;
50
+ applyDefaultCollectionSort(collectionInfo?: CollectionExtraInfo): void;
51
+ emitEmptyResults(): void;
52
+ emitQueryStateChanged(): void;
53
+ refreshVisibleResults(): void;
54
+ }
@@ -1,12 +1,7 @@
1
1
  import type {
2
- CollectionExtraInfo,
2
+ PageElementName,
3
3
  PageType,
4
- SearchServiceInterface,
5
- SearchType,
6
- SortDirection,
7
- SortParam,
8
4
  } from '@internetarchive/search-service';
9
- import type { SelectedFacets, SortField } from '../models';
10
5
 
11
6
  /**
12
7
  * A Map from collection identifiers to their corresponding collection titles.
@@ -30,46 +25,14 @@ export type PageSpecifierParams = {
30
25
  * Which specific elements of a profile page to fetch. Corresponds to individual tab data
31
26
  * (e.g., "uploads", "reviews", ...)
32
27
  */
33
- pageElements?: string[];
28
+ pageElements?: PageElementName[];
34
29
  };
35
30
 
36
31
  /**
37
- * Properties of collection browser that affect the overall search query
32
+ * List of profile page elements that do not currently allow faceting
38
33
  */
39
- export interface CollectionBrowserQueryState {
40
- baseQuery?: string;
41
- withinCollection?: string;
42
- withinProfile?: string;
43
- profileElement?: string;
44
- searchType: SearchType;
45
- selectedFacets?: SelectedFacets;
46
- minSelectedDate?: string;
47
- maxSelectedDate?: string;
48
- selectedTitleFilter: string | null;
49
- selectedCreatorFilter: string | null;
50
- selectedSort?: SortField;
51
- sortDirection: SortDirection | null;
52
- }
53
-
54
- /**
55
- * Interface representing search-related state and operations required by the
56
- * data source on its host component.
57
- */
58
- export interface CollectionBrowserSearchInterface
59
- extends CollectionBrowserQueryState {
60
- searchService?: SearchServiceInterface;
61
- queryErrorMessage?: string;
62
- readonly sortParam: SortParam | null;
63
- readonly suppressFacets?: boolean;
64
- readonly initialPageNumber: number;
65
- readonly currentVisiblePageNumbers: number[];
66
-
67
- getSessionId(): Promise<string>;
68
- setSearchResultsLoading(loading: boolean): void;
69
- setFacetsLoading(loading: boolean): void;
70
- setTotalResultCount(count: number): void;
71
- setTileCount(count: number): void;
72
- applyDefaultCollectionSort(collectionInfo?: CollectionExtraInfo): void;
73
- emitEmptyResults(): void;
74
- refreshVisibleResults(): void;
75
- }
34
+ export const FACETLESS_PAGE_ELEMENTS: PageElementName[] = [
35
+ 'forum_posts',
36
+ 'lending',
37
+ 'web_archives',
38
+ ];
@@ -6,7 +6,7 @@ import { when } from 'lit/directives/when.js';
6
6
  export interface ManageableItem {
7
7
  identifier: string;
8
8
  title?: string;
9
- date?: string;
9
+ dateStr?: string;
10
10
  }
11
11
 
12
12
  @customElement('manage-bar')
package/src/models.ts CHANGED
@@ -1,42 +1,193 @@
1
1
  import type { MediaType } from '@internetarchive/field-parsers';
2
2
  import {
3
3
  AggregationSortType,
4
+ SearchResult,
4
5
  SortDirection,
5
6
  } from '@internetarchive/search-service';
7
+ import { collapseRepeatedQuotes } from './utils/collapse-repeated-quotes';
8
+ import { resolveMediatype } from './utils/resolve-mediatype';
6
9
 
7
- export interface TileModel {
10
+ /**
11
+ * Flags that can affect the visibility of content on a tile
12
+ */
13
+ interface TileFlags {
14
+ loginRequired: boolean;
15
+ contentWarning: boolean;
16
+ }
17
+
18
+ /**
19
+ * Class for converting & storing raw search results in the correct format for UI tiles.
20
+ */
21
+ export class TileModel {
8
22
  averageRating?: number;
23
+
24
+ captureDates?: Date[]; // List of capture dates for a URL, used on profile Web Archives tiles
25
+
9
26
  checked: boolean; // Whether this tile is currently checked for item management functions
27
+
10
28
  collectionIdentifier?: string;
29
+
11
30
  collectionName?: string;
31
+
12
32
  collectionFilesCount: number;
33
+
13
34
  collections: string[];
35
+
14
36
  collectionSize: number;
37
+
15
38
  commentCount: number;
39
+
16
40
  creator?: string;
41
+
17
42
  creators: string[];
43
+
44
+ dateStr?: string; // A string representation of the publication date, used strictly for passing preformatted dates to the parent
45
+
18
46
  dateAdded?: Date; // Date added to public search (software-defined) [from: addeddate]
47
+
19
48
  dateArchived?: Date; // Date archived (software-defined) item created on archive.org [from: publicdate]
49
+
20
50
  datePublished?: Date; // Date work published in the world (user-defined) [from: date]
51
+
21
52
  dateReviewed?: Date; // Date reviewed (user-created) most recent review [from: reviewdate]
53
+
22
54
  description?: string;
55
+
23
56
  favCount: number;
57
+
24
58
  href?: string;
25
- identifier: string;
59
+
60
+ identifier?: string;
61
+
26
62
  issue?: string;
63
+
27
64
  itemCount: number;
65
+
28
66
  mediatype: MediaType;
67
+
29
68
  source?: string;
69
+
30
70
  snippets?: string[];
71
+
31
72
  subjects: string[];
73
+
32
74
  title: string;
33
- viewCount: number;
75
+
76
+ viewCount?: number;
77
+
34
78
  volume?: string;
79
+
35
80
  weeklyViewCount?: number;
81
+
36
82
  loginRequired: boolean;
83
+
37
84
  contentWarning: boolean;
85
+
86
+ constructor(result: SearchResult) {
87
+ const flags = this.getFlags(result);
88
+
89
+ this.averageRating = result.avg_rating?.value;
90
+ this.captureDates = result.capture_dates?.values;
91
+ this.checked = false;
92
+ this.collections = result.collection?.values ?? [];
93
+ this.collectionFilesCount = result.collection_files_count?.value ?? 0;
94
+ this.collectionSize = result.collection_size?.value ?? 0;
95
+ this.commentCount = result.num_reviews?.value ?? 0;
96
+ this.creator = result.creator?.value;
97
+ this.creators = result.creator?.values ?? [];
98
+ this.dateAdded = result.addeddate?.value;
99
+ this.dateArchived = result.publicdate?.value;
100
+ this.datePublished = result.date?.value;
101
+ this.dateReviewed = result.reviewdate?.value;
102
+ this.description = result.description?.values.join('\n');
103
+ this.favCount = result.num_favorites?.value ?? 0;
104
+ this.href = collapseRepeatedQuotes(result.__href__?.value);
105
+ this.identifier = result.identifier;
106
+ this.issue = result.issue?.value;
107
+ this.itemCount = result.item_count?.value ?? 0;
108
+ this.mediatype = resolveMediatype(result);
109
+ this.snippets = result.highlight?.values ?? [];
110
+ this.source = result.source?.value;
111
+ this.subjects = result.subject?.values ?? [];
112
+ this.title = result.title?.value ?? '';
113
+ this.volume = result.volume?.value;
114
+ this.viewCount = result.downloads?.value;
115
+ this.weeklyViewCount = result.week?.value;
116
+ this.loginRequired = flags.loginRequired;
117
+ this.contentWarning = flags.contentWarning;
118
+ }
119
+
120
+ /**
121
+ * Copies the contents of this TileModel onto a new instance
122
+ */
123
+ clone(): TileModel {
124
+ const cloned = new TileModel({});
125
+ cloned.averageRating = this.averageRating;
126
+ cloned.captureDates = this.captureDates;
127
+ cloned.checked = this.checked;
128
+ cloned.collections = this.collections;
129
+ cloned.collectionFilesCount = this.collectionFilesCount;
130
+ cloned.collectionSize = this.collectionSize;
131
+ cloned.commentCount = this.commentCount;
132
+ cloned.creator = this.creator;
133
+ cloned.creators = this.creators;
134
+ cloned.dateStr = this.dateStr;
135
+ cloned.dateAdded = this.dateAdded;
136
+ cloned.dateArchived = this.dateArchived;
137
+ cloned.datePublished = this.datePublished;
138
+ cloned.dateReviewed = this.dateReviewed;
139
+ cloned.description = this.description;
140
+ cloned.favCount = this.favCount;
141
+ cloned.href = this.href;
142
+ cloned.identifier = this.identifier;
143
+ cloned.issue = this.issue;
144
+ cloned.itemCount = this.itemCount;
145
+ cloned.mediatype = this.mediatype;
146
+ cloned.snippets = this.snippets;
147
+ cloned.source = this.source;
148
+ cloned.subjects = this.subjects;
149
+ cloned.title = this.title;
150
+ cloned.volume = this.volume;
151
+ cloned.viewCount = this.viewCount;
152
+ cloned.weeklyViewCount = this.weeklyViewCount;
153
+ cloned.loginRequired = this.loginRequired;
154
+ cloned.contentWarning = this.contentWarning;
155
+ return cloned;
156
+ }
157
+
158
+ /**
159
+ * Determines the appropriate tile flags for the given search result
160
+ * (login required and/or content warning)
161
+ */
162
+ private getFlags(result: SearchResult): TileFlags {
163
+ const flags: TileFlags = {
164
+ loginRequired: false,
165
+ contentWarning: false,
166
+ };
167
+
168
+ // Check if item and item in "modifying" collection, setting above flags
169
+ if (
170
+ result.collection?.values.length &&
171
+ result.mediatype?.value !== 'collection'
172
+ ) {
173
+ for (const collection of result.collection?.values ?? []) {
174
+ if (collection === 'loggedin') {
175
+ flags.loginRequired = true;
176
+ if (flags.contentWarning) break;
177
+ }
178
+ if (collection === 'no-preview') {
179
+ flags.contentWarning = true;
180
+ if (flags.loginRequired) break;
181
+ }
182
+ }
183
+ }
184
+
185
+ return flags;
186
+ }
38
187
  }
39
188
 
189
+ export type RequestKind = 'full' | 'hits' | 'aggregations';
190
+
40
191
  export type CollectionDisplayMode = 'grid' | 'list-compact' | 'list-detail';
41
192
 
42
193
  export type TileDisplayMode =
@@ -280,6 +431,16 @@ export function sortOptionFromAPIString(sortName?: string | null): SortOption {
280
431
  );
281
432
  }
282
433
 
434
+ export const defaultProfileElementSorts: Record<
435
+ string,
436
+ Exclude<SortField, SortField.default>
437
+ > = {
438
+ uploads: SortField.datearchived,
439
+ reviews: SortField.datereviewed,
440
+ collections: SortField.datearchived,
441
+ web_archives: SortField.datearchived,
442
+ };
443
+
283
444
  /** A union of the fields that permit prefix filtering (e.g., alphabetical filtering) */
284
445
  export type PrefixFilterType = 'title' | 'creator';
285
446
 
@@ -178,7 +178,7 @@ export class SortFilterBar
178
178
  this.setupEscapeListeners();
179
179
  }
180
180
 
181
- if (changed.has('resizeObserver')) {
181
+ if (changed.has('resizeObserver') || changed.has('showLoansTopBar')) {
182
182
  const oldObserver = changed.get(
183
183
  'resizeObserver'
184
184
  ) as SharedResizeObserverInterface;
@@ -1116,6 +1116,7 @@ export class SortFilterBar
1116
1116
  height: 100%;
1117
1117
  padding-left: 5px;
1118
1118
  font-size: 1.4rem;
1119
+ font-family: var(--ia-theme-base-font-family);
1119
1120
  line-height: 2;
1120
1121
  color: var(--ia-theme-primary-text-color, #2c2c2c);
1121
1122
  white-space: nowrap;
@@ -4,6 +4,7 @@ import { customElement, property } from 'lit/decorators.js';
4
4
  import { ifDefined } from 'lit/directives/if-defined.js';
5
5
  import { msg } from '@lit/localize';
6
6
 
7
+ import { map } from 'lit/directives/map.js';
7
8
  import { DateFormat, formatDate } from '../../utils/format-date';
8
9
  import { isFirstMillisecondOfUTCYear } from '../../utils/local-date-from-utc';
9
10
  import { BaseTileComponent } from '../base-tile-component';
@@ -57,7 +58,7 @@ export class ItemTile extends BaseTileComponent {
57
58
  ${this.isSortedByDate
58
59
  ? this.sortedDateInfoTemplate
59
60
  : this.creatorTemplate}
60
- ${this.textSnippetsTemplate}
61
+ ${this.webArchivesCaptureDatesTemplate} ${this.textSnippetsTemplate}
61
62
  </div>
62
63
 
63
64
  <tile-stats
@@ -172,6 +173,26 @@ export class ItemTile extends BaseTileComponent {
172
173
  `;
173
174
  }
174
175
 
176
+ private get webArchivesCaptureDatesTemplate():
177
+ | TemplateResult
178
+ | typeof nothing {
179
+ if (!this.model?.captureDates || !this.model.title) return nothing;
180
+
181
+ return html`
182
+ <ul class="capture-dates">
183
+ ${map(
184
+ this.model.captureDates,
185
+ date => html`<li>
186
+ ${this.displayValueProvider.webArchivesCaptureLink(
187
+ this.model!.title,
188
+ date
189
+ )}
190
+ </li>`
191
+ )}
192
+ </ul>
193
+ `;
194
+ }
195
+
175
196
  private get isSortedByDate(): boolean {
176
197
  return ['date', 'reviewdate', 'addeddate', 'publicdate'].includes(
177
198
  this.sortParam?.field as string
@@ -200,10 +221,24 @@ export class ItemTile extends BaseTileComponent {
200
221
  return [
201
222
  baseTileStyles,
202
223
  css`
224
+ a:link {
225
+ text-decoration: none;
226
+ color: var(--ia-theme-link-color, #4b64ff);
227
+ }
228
+ a:hover {
229
+ text-decoration: underline;
230
+ }
231
+
203
232
  .container {
204
233
  border: 1px solid ${tileBorderColor};
205
234
  }
206
235
 
236
+ .capture-dates {
237
+ margin: 0;
238
+ padding: 0 5px;
239
+ list-style-type: none;
240
+ }
241
+
207
242
  text-snippet-block {
208
243
  --containerLeftMargin: 5px;
209
244
  --containerTopMargin: 5px;
@@ -1,6 +1,7 @@
1
1
  import { css, CSSResultGroup, html, LitElement } from 'lit';
2
2
  import { customElement, property } from 'lit/decorators.js';
3
3
 
4
+ import { msg } from '@lit/localize';
4
5
  import { favoriteFilledIcon } from '../../assets/img/icons/favorite-filled';
5
6
  import { reviewsIcon } from '../../assets/img/icons/reviews';
6
7
  import { uploadIcon } from '../../assets/img/icons/upload';
@@ -33,8 +34,8 @@ export class TileStats extends LitElement {
33
34
 
34
35
  const uploadsOrViewsTitle =
35
36
  this.mediatype === 'account'
36
- ? `${this.itemCount} uploads`
37
- : `${this.viewCount} ${this.viewLabel ?? 'all-time views'}`;
37
+ ? `${this.itemCount ?? 0} uploads`
38
+ : `${this.viewCount ?? 0} ${this.viewLabel ?? 'all-time views'}`;
38
39
 
39
40
  return html`
40
41
  <div class="item-stats">
@@ -43,17 +44,21 @@ export class TileStats extends LitElement {
43
44
  </p>
44
45
  <ul id="stats-row">
45
46
  <li class="col">
46
- <p class="sr-only">Mediatype:</p>
47
+ <p class="sr-only">${msg('Mediatype:')}</p>
47
48
  <mediatype-icon .mediatype=${this.mediatype}></mediatype-icon>
48
49
  </li>
49
50
  <li class="col" title="${uploadsOrViewsTitle}">
50
51
  ${this.mediatype === 'account' ? uploadIcon : viewsIcon}
51
52
  <p class="status-text">
52
53
  <span class="sr-only">
53
- ${this.mediatype === 'account' ? 'Uploads:' : 'Views:'}
54
+ ${this.mediatype === 'account'
55
+ ? msg('Uploads:')
56
+ : msg('Views:')}
54
57
  </span>
55
58
  ${formatCount(
56
- this.mediatype === 'account' ? this.itemCount : this.viewCount,
59
+ this.mediatype === 'account'
60
+ ? this.itemCount ?? 0
61
+ : this.viewCount ?? 0,
57
62
  'short',
58
63
  'short'
59
64
  )}
@@ -62,14 +67,14 @@ export class TileStats extends LitElement {
62
67
  <li class="col" title="${formattedFavCount} favorites">
63
68
  ${favoriteFilledIcon}
64
69
  <p class="status-text">
65
- <span class="sr-only">Favorites:</span>
70
+ <span class="sr-only">${msg('Favorites:')}</span>
66
71
  ${formattedFavCount}
67
72
  </p>
68
73
  </li>
69
74
  <li class="col reviews" title="${formattedReviewCount} reviews">
70
75
  ${reviewsIcon}
71
76
  <p class="status-text">
72
- <span class="sr-only">Reviews:</span>
77
+ <span class="sr-only">${msg('Reviews:')}</span>
73
78
  ${formattedReviewCount}
74
79
  </p>
75
80
  </li>
@@ -24,6 +24,8 @@ export class ItemImage extends LitElement {
24
24
 
25
25
  @state() private isWaveform = false;
26
26
 
27
+ @state() private isNotFound = false;
28
+
27
29
  @query('img') private baseImage!: HTMLImageElement;
28
30
 
29
31
  render() {
@@ -43,6 +45,7 @@ export class ItemImage extends LitElement {
43
45
  src="${this.imageSrc}"
44
46
  alt=""
45
47
  @load=${this.onLoad}
48
+ @error=${this.onError}
46
49
  />
47
50
  `;
48
51
  }
@@ -51,12 +54,33 @@ export class ItemImage extends LitElement {
51
54
  * Helpers
52
55
  */
53
56
  private get imageSrc() {
57
+ if (this.isNotFound) return this.notFoundSrc;
58
+
59
+ // Use the correct image for web capture tiles, if possible
60
+ if (this.model?.captureDates && this.model.identifier) {
61
+ try {
62
+ const url = new URL(this.model.identifier);
63
+ const domain = encodeURIComponent(url.hostname);
64
+ return this.baseImageUrl
65
+ ? `https://web.archive.org/thumb/${domain}?generate=1`
66
+ : nothing;
67
+ } catch (err) {
68
+ return `${this.baseImageUrl}/images/notfound.png`;
69
+ }
70
+ }
71
+
54
72
  // Don't try to load invalid image URLs
55
73
  return this.baseImageUrl && this.model?.identifier
56
74
  ? `${this.baseImageUrl}/services/img/${this.model.identifier}`
57
75
  : nothing;
58
76
  }
59
77
 
78
+ private get notFoundSrc() {
79
+ return this.baseImageUrl
80
+ ? `${this.baseImageUrl}/images/notfound.png`
81
+ : nothing;
82
+ }
83
+
60
84
  private get hashBasedGradient() {
61
85
  if (!this.model?.identifier) {
62
86
  return 'waveform-grad0';
@@ -120,6 +144,10 @@ export class ItemImage extends LitElement {
120
144
  }
121
145
  }
122
146
 
147
+ private onError() {
148
+ this.isNotFound = true;
149
+ }
150
+
123
151
  /**
124
152
  * CSS
125
153
  */
@@ -167,7 +167,7 @@ export class TileListCompact extends BaseTileComponent {
167
167
  align-items: center;
168
168
  line-height: 20px;
169
169
  padding-top: 5px;
170
- padding-bottom: 5px;
170
+ margin-bottom: -5px;
171
171
  }
172
172
 
173
173
  #list-line.mobile {
@@ -37,7 +37,7 @@ export class TileList extends BaseTileComponent {
37
37
  @property({ type: Object })
38
38
  collectionTitles?: CollectionTitles;
39
39
 
40
- @state() private collectionLinks: TemplateResult[] = [];
40
+ @state() private collectionLinks: (TemplateResult | typeof nothing)[] = [];
41
41
 
42
42
  render() {
43
43
  return html`
@@ -107,6 +107,7 @@ export class TileList extends BaseTileComponent {
107
107
  ${this.itemLineTemplate} ${this.creatorTemplate}
108
108
  <div id="dates-line">
109
109
  ${this.datePublishedTemplate} ${this.dateSortByTemplate}
110
+ ${this.webArchivesCaptureDatesTemplate}
110
111
  </div>
111
112
  <div id="views-line">
112
113
  ${this.viewsTemplate} ${this.ratingTemplate} ${this.reviewsTemplate}
@@ -238,6 +239,7 @@ export class TileList extends BaseTileComponent {
238
239
  this.sortParam?.field === 'week'
239
240
  ? this.model?.weeklyViewCount // weekly views
240
241
  : this.model?.viewCount; // all-time views
242
+ if (viewCount == null) return nothing;
241
243
 
242
244
  // when its a search-tile, we don't have any stats to show
243
245
  if (this.model?.mediatype === 'search') {
@@ -245,7 +247,7 @@ export class TileList extends BaseTileComponent {
245
247
  }
246
248
 
247
249
  return this.metadataTemplate(
248
- `${formatCount(viewCount ?? 0, this.formatSize)}`,
250
+ `${formatCount(viewCount, this.formatSize)}`,
249
251
  msg('Views')
250
252
  );
251
253
  }
@@ -309,6 +311,26 @@ export class TileList extends BaseTileComponent {
309
311
  return !!this.model?.snippets?.length;
310
312
  }
311
313
 
314
+ private get webArchivesCaptureDatesTemplate():
315
+ | TemplateResult
316
+ | typeof nothing {
317
+ if (!this.model?.captureDates || !this.model.title) return nothing;
318
+
319
+ return html`
320
+ <ul class="capture-dates">
321
+ ${map(
322
+ this.model.captureDates,
323
+ date => html`<li>
324
+ ${this.displayValueProvider.webArchivesCaptureLink(
325
+ this.model!.title,
326
+ date
327
+ )}
328
+ </li>`
329
+ )}
330
+ </ul>
331
+ `;
332
+ }
333
+
312
334
  // Utility functions
313
335
  // eslint-disable-next-line default-param-last
314
336
  private metadataTemplate(text: any, label = '', id?: string) {
@@ -345,10 +367,12 @@ export class TileList extends BaseTileComponent {
345
367
  }
346
368
 
347
369
  private detailsLink(
348
- identifier: string,
370
+ identifier?: string,
349
371
  text?: string,
350
372
  isCollection = false
351
- ): TemplateResult {
373
+ ): TemplateResult | typeof nothing {
374
+ if (!identifier) return nothing;
375
+
352
376
  const linkText = text ?? identifier;
353
377
  const linkHref = this.displayValueProvider.itemPageUrl(
354
378
  identifier,
@@ -392,7 +416,7 @@ export class TileList extends BaseTileComponent {
392
416
  // Note: quirk of Lit: need to replace collectionLinks array,
393
417
  // otherwise it will not re-render. Can't simply alter the array.
394
418
  this.collectionLinks = [];
395
- const newCollectionLinks: TemplateResult[] = [];
419
+ const newCollectionLinks: (TemplateResult | typeof nothing)[] = [];
396
420
  for (const collection of this.model.collections) {
397
421
  // Don't include favorites or collections that are meant to be suppressed
398
422
  if (
@@ -622,6 +646,20 @@ export class TileList extends BaseTileComponent {
622
646
  #views-line {
623
647
  flex-wrap: wrap;
624
648
  }
649
+
650
+ .capture-dates {
651
+ margin: 0;
652
+ padding: 0;
653
+ list-style-type: none;
654
+ }
655
+
656
+ .capture-dates a:link {
657
+ text-decoration: none;
658
+ color: var(--ia-theme-link-color, #4b64ff);
659
+ }
660
+ .capture-dates a:hover {
661
+ text-decoration: underline;
662
+ }
625
663
  `;
626
664
  }
627
665
  }
@@ -184,7 +184,8 @@ export class TileDispatcher
184
184
  this.enableHoverPane &&
185
185
  !!this.tileDisplayMode &&
186
186
  TileDispatcher.HOVER_PANE_DISPLAY_MODES[this.tileDisplayMode] &&
187
- this.model?.mediatype !== 'search' // don't show hover panes on search tiles
187
+ this.model?.mediatype !== 'search' && // don't show hover panes on search tiles
188
+ !this.model?.captureDates // don't show hover panes on web archive tiles
188
189
  );
189
190
  }
190
191