@internetarchive/collection-browser 4.8.1-webdev-9227.4 → 4.9.1-webdev-9670.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 (105) hide show
  1. package/README.md +11 -33
  2. package/dist/src/app-root.d.ts +11 -0
  3. package/dist/src/app-root.js +95 -1
  4. package/dist/src/app-root.js.map +1 -1
  5. package/dist/src/collection-browser.d.ts +43 -2
  6. package/dist/src/collection-browser.js +221 -15
  7. package/dist/src/collection-browser.js.map +1 -1
  8. package/dist/src/collection-facets/facet-row-template.d.ts +1 -1
  9. package/dist/src/collection-facets/facet-row-template.js +7 -14
  10. package/dist/src/collection-facets/facet-row-template.js.map +1 -1
  11. package/dist/src/collection-facets/facet-row.js +1 -3
  12. package/dist/src/collection-facets/facet-row.js.map +1 -1
  13. package/dist/src/collection-facets/more-facets-content.js +5 -6
  14. package/dist/src/collection-facets/more-facets-content.js.map +1 -1
  15. package/dist/src/collection-facets/more-facets-scroller.js +2 -3
  16. package/dist/src/collection-facets/more-facets-scroller.js.map +1 -1
  17. package/dist/src/collection-facets/smart-facets/heuristics/wikidata/wikidata-entity-map.js +4 -13
  18. package/dist/src/collection-facets/smart-facets/heuristics/wikidata/wikidata-entity-map.js.map +1 -1
  19. package/dist/src/collection-facets/smart-facets/smart-facet-bar.js +2 -6
  20. package/dist/src/collection-facets/smart-facets/smart-facet-bar.js.map +1 -1
  21. package/dist/src/collection-facets.js +5 -6
  22. package/dist/src/collection-facets.js.map +1 -1
  23. package/dist/src/empty-placeholder.d.ts +7 -7
  24. package/dist/src/empty-placeholder.js +15 -29
  25. package/dist/src/empty-placeholder.js.map +1 -1
  26. package/dist/src/expanded-date-picker.js +2 -3
  27. package/dist/src/expanded-date-picker.js.map +1 -1
  28. package/dist/src/manage/manage-bar.d.ts +2 -3
  29. package/dist/src/manage/manage-bar.js +16 -15
  30. package/dist/src/manage/manage-bar.js.map +1 -1
  31. package/dist/src/manage/remove-items-modal-content.js +2 -3
  32. package/dist/src/manage/remove-items-modal-content.js.map +1 -1
  33. package/dist/src/mediatype/mediatype-config.js +18 -55
  34. package/dist/src/mediatype/mediatype-config.js.map +1 -1
  35. package/dist/src/models.js +40 -120
  36. package/dist/src/models.js.map +1 -1
  37. package/dist/src/sort-filter-bar/alpha-bar-tooltip.js +2 -8
  38. package/dist/src/sort-filter-bar/alpha-bar-tooltip.js.map +1 -1
  39. package/dist/src/sort-filter-bar/alpha-bar.js +2 -7
  40. package/dist/src/sort-filter-bar/alpha-bar.js.map +1 -1
  41. package/dist/src/sort-filter-bar/sort-filter-bar.d.ts +12 -0
  42. package/dist/src/sort-filter-bar/sort-filter-bar.js +109 -28
  43. package/dist/src/sort-filter-bar/sort-filter-bar.js.map +1 -1
  44. package/dist/src/tiles/grid/account-tile.js +2 -3
  45. package/dist/src/tiles/grid/account-tile.js.map +1 -1
  46. package/dist/src/tiles/grid/collection-tile.js +11 -12
  47. package/dist/src/tiles/grid/collection-tile.js.map +1 -1
  48. package/dist/src/tiles/grid/item-tile.d.ts +4 -0
  49. package/dist/src/tiles/grid/item-tile.js +23 -8
  50. package/dist/src/tiles/grid/item-tile.js.map +1 -1
  51. package/dist/src/tiles/grid/tile-stats.js +3 -6
  52. package/dist/src/tiles/grid/tile-stats.js.map +1 -1
  53. package/dist/src/tiles/hover/hover-pane-controller.d.ts +2 -1
  54. package/dist/src/tiles/hover/hover-pane-controller.js +1 -1
  55. package/dist/src/tiles/hover/hover-pane-controller.js.map +1 -1
  56. package/dist/src/tiles/image-block.d.ts +5 -0
  57. package/dist/src/tiles/image-block.js +29 -0
  58. package/dist/src/tiles/image-block.js.map +1 -1
  59. package/dist/src/tiles/list/tile-list-compact-header.js +2 -3
  60. package/dist/src/tiles/list/tile-list-compact-header.js.map +1 -1
  61. package/dist/src/tiles/list/tile-list-compact.js +1 -3
  62. package/dist/src/tiles/list/tile-list-compact.js.map +1 -1
  63. package/dist/src/tiles/list/tile-list.js +5 -15
  64. package/dist/src/tiles/list/tile-list.js.map +1 -1
  65. package/dist/src/tiles/models.d.ts +2 -1
  66. package/dist/src/tiles/models.js.map +1 -1
  67. package/dist/src/tiles/overlay/text-overlay.js +1 -3
  68. package/dist/src/tiles/overlay/text-overlay.js.map +1 -1
  69. package/dist/src/tiles/preview/tile-preview-controller.d.ts +61 -0
  70. package/dist/src/tiles/preview/tile-preview-controller.js +216 -0
  71. package/dist/src/tiles/preview/tile-preview-controller.js.map +1 -0
  72. package/dist/src/tiles/preview/tile-preview-media.d.ts +44 -0
  73. package/dist/src/tiles/preview/tile-preview-media.js +151 -0
  74. package/dist/src/tiles/preview/tile-preview-media.js.map +1 -0
  75. package/dist/src/tiles/preview/tile-preview.d.ts +66 -0
  76. package/dist/src/tiles/preview/tile-preview.js +494 -0
  77. package/dist/src/tiles/preview/tile-preview.js.map +1 -0
  78. package/dist/src/tiles/review-block.js +2 -3
  79. package/dist/src/tiles/review-block.js.map +1 -1
  80. package/dist/src/tiles/tile-dispatcher.d.ts +8 -2
  81. package/dist/src/tiles/tile-dispatcher.js +36 -6
  82. package/dist/src/tiles/tile-dispatcher.js.map +1 -1
  83. package/dist/src/tiles/tile-mediatype-icon.js +1 -3
  84. package/dist/src/tiles/tile-mediatype-icon.js.map +1 -1
  85. package/dist/src/utils/format-count.d.ts +1 -3
  86. package/dist/src/utils/format-count.js +59 -19
  87. package/dist/src/utils/format-count.js.map +1 -1
  88. package/dist/src/utils/format-unit-size.d.ts +1 -1
  89. package/dist/src/utils/format-unit-size.js +18 -21
  90. package/dist/src/utils/format-unit-size.js.map +1 -1
  91. package/dist/src/utils/grid-zoom-controller.d.ts +69 -0
  92. package/dist/src/utils/grid-zoom-controller.js +261 -0
  93. package/dist/src/utils/grid-zoom-controller.js.map +1 -0
  94. package/dist/src/utils/grid-zoom.d.ts +31 -0
  95. package/dist/src/utils/grid-zoom.js +109 -0
  96. package/dist/src/utils/grid-zoom.js.map +1 -0
  97. package/package.json +2 -6
  98. package/dist/src/locales/es.d.ts +0 -200
  99. package/dist/src/locales/es.js +0 -215
  100. package/dist/src/locales/es.js.map +0 -1
  101. package/dist/src/utils/get-locale.d.ts +0 -14
  102. package/dist/src/utils/get-locale.js +0 -20
  103. package/dist/src/utils/get-locale.js.map +0 -1
  104. package/locales/es.d.ts +0 -1
  105. package/locales/es.js +0 -1
@@ -0,0 +1,494 @@
1
+ import { __decorate } from "tslib";
2
+ import { css, html, LitElement, nothing } from 'lit';
3
+ import { msg } from '@lit/localize';
4
+ import { ifDefined } from 'lit/directives/if-defined.js';
5
+ import { customElement, property, query, state } from 'lit/decorators.js';
6
+ import { PREVIEW_CLIP_SECONDS, resolvePreviewMedia, } from './tile-preview-media';
7
+ const SLIDE_INTERVAL_MS = 700;
8
+ /** How long the first video frame may take before the frames take over. */
9
+ const FIRST_FRAME_TIMEOUT_MS = 2500;
10
+ const MAX_VOLUME = 0.5;
11
+ const FADE_IN_MS = 250;
12
+ const FADE_OUT_MS = 120;
13
+ /**
14
+ * Fills a tile's image area with a live preview of the item while `active`:
15
+ * a muted clip for movies, a few page images for texts, a waveform for audio,
16
+ * cycling images for images, and a slow pan over the thumbnail for anything
17
+ * else. It is absolutely positioned over the existing thumbnail, so showing
18
+ * and hiding it never moves the layout.
19
+ */
20
+ let TilePreview = class TilePreview extends LitElement {
21
+ constructor() {
22
+ super(...arguments);
23
+ this.baseUrl = 'https://archive.org';
24
+ this.active = false;
25
+ this.options = {};
26
+ this.slideUrls = [];
27
+ this.slide = 0;
28
+ this.ready = false;
29
+ /** Whether sound is audibly playing, as opposed to muted or refused. */
30
+ this.audible = false;
31
+ /** Pending fade animation frame per element, so one element's fade never cancels another's. */
32
+ this.fadeFrames = new WeakMap();
33
+ /** Bumped on every activation so a slow resolve can't show a stale preview. */
34
+ this.activation = 0;
35
+ }
36
+ willUpdate(changed) {
37
+ // Release while the media elements are still in the DOM.
38
+ if (changed.has('active') && !this.active)
39
+ this.stop();
40
+ }
41
+ updated(changed) {
42
+ if (changed.has('active') || changed.has('identifier')) {
43
+ if (this.active) {
44
+ this.stop();
45
+ this.start();
46
+ }
47
+ }
48
+ }
49
+ disconnectedCallback() {
50
+ super.disconnectedCallback();
51
+ this.stop();
52
+ }
53
+ async start() {
54
+ if (!this.identifier || !this.mediatype)
55
+ return;
56
+ const activation = ++this.activation;
57
+ const media = await resolvePreviewMedia(this.identifier, this.mediatype, this.baseUrl, this.options);
58
+ if (activation !== this.activation || !this.active)
59
+ return;
60
+ this.media = media;
61
+ this.slideUrls = media.kind === 'slides' ? media.urls : [];
62
+ this.slide = 0;
63
+ this.ready = media.kind === 'zoom' || media.kind === 'audio';
64
+ await this.updateComplete;
65
+ if (activation !== this.activation)
66
+ return;
67
+ if (media.kind === 'slides')
68
+ this.startSlides();
69
+ if (media.kind === 'audio' && this.options.sound)
70
+ this.playSnippet();
71
+ if (media.kind === 'video') {
72
+ this.frameTimer = window.setTimeout(() => this.useFallbackFrames(), FIRST_FRAME_TIMEOUT_MS);
73
+ }
74
+ }
75
+ stop() {
76
+ this.activation += 1;
77
+ window.clearInterval(this.slideTimer);
78
+ window.clearTimeout(this.frameTimer);
79
+ this.releaseMedia(this.video);
80
+ this.releaseMedia(this.audio);
81
+ this.media = undefined;
82
+ this.slideUrls = [];
83
+ this.ready = false;
84
+ this.audible = false;
85
+ }
86
+ /**
87
+ * Stops a media element: a short fade-out when it is audible, then pause and
88
+ * drop the source so the browser stops downloading it.
89
+ */
90
+ releaseMedia(el) {
91
+ if (!el)
92
+ return;
93
+ this.cancelFade(el);
94
+ const finish = () => {
95
+ el.pause();
96
+ el.removeAttribute('src');
97
+ el.load();
98
+ };
99
+ if (el.paused || el.muted || el.volume === 0) {
100
+ finish();
101
+ return;
102
+ }
103
+ this.fade(el, 0, FADE_OUT_MS, finish);
104
+ }
105
+ cancelFade(el) {
106
+ const frame = this.fadeFrames.get(el);
107
+ if (frame !== undefined)
108
+ window.cancelAnimationFrame(frame);
109
+ this.fadeFrames.delete(el);
110
+ }
111
+ /** Ramps a media element's volume to `target` over `ms`. */
112
+ fade(el, target, ms, done) {
113
+ this.cancelFade(el);
114
+ const from = el.volume;
115
+ const t0 = performance.now();
116
+ const step = (now) => {
117
+ const t = Math.min(1, (now - t0) / ms);
118
+ el.volume = from + (target - from) * t;
119
+ if (t < 1)
120
+ this.fadeFrames.set(el, window.requestAnimationFrame(step));
121
+ else {
122
+ this.fadeFrames.delete(el);
123
+ done?.();
124
+ }
125
+ };
126
+ this.fadeFrames.set(el, window.requestAnimationFrame(step));
127
+ }
128
+ /**
129
+ * Starts a media element, with sound when the options ask for it. A browser
130
+ * that refuses audible playback gets a muted one instead.
131
+ */
132
+ async playMedia(el, activation) {
133
+ if (this.options.sound) {
134
+ try {
135
+ el.muted = false;
136
+ el.volume = 0;
137
+ await el.play();
138
+ if (activation !== this.activation)
139
+ return true;
140
+ this.audible = true;
141
+ this.fade(el, MAX_VOLUME, FADE_IN_MS);
142
+ return true;
143
+ }
144
+ catch {
145
+ // Refused, so play it muted below.
146
+ }
147
+ }
148
+ try {
149
+ el.muted = true;
150
+ await el.play();
151
+ return true;
152
+ }
153
+ catch {
154
+ // A stopped preview isn't a failure; only a current one needs the frames.
155
+ return activation !== this.activation;
156
+ }
157
+ }
158
+ /** Swaps a clip that is slow or unplayable for the item's frame thumbnails. */
159
+ useFallbackFrames() {
160
+ window.clearTimeout(this.frameTimer);
161
+ if (this.media?.kind !== 'video')
162
+ return;
163
+ const urls = this.media.fallbackUrls;
164
+ this.releaseMedia(this.video);
165
+ this.audible = false;
166
+ if (urls.length > 1) {
167
+ this.media = { kind: 'slides', fit: 'cover', urls };
168
+ this.slideUrls = urls;
169
+ this.slide = 0;
170
+ this.ready = false;
171
+ const { activation } = this;
172
+ this.updateComplete.then(() => {
173
+ if (activation === this.activation)
174
+ this.startSlides();
175
+ });
176
+ }
177
+ else {
178
+ this.media = { kind: 'zoom' };
179
+ this.ready = true;
180
+ }
181
+ }
182
+ startSlides() {
183
+ window.clearInterval(this.slideTimer);
184
+ this.slideTimer = window.setInterval(() => {
185
+ const loaded = this.loadedSlides();
186
+ if (loaded.length < 2)
187
+ return;
188
+ let next = this.slide;
189
+ do {
190
+ next = (next + 1) % this.slideUrls.length;
191
+ } while (!loaded.includes(next));
192
+ this.slide = next;
193
+ }, SLIDE_INTERVAL_MS);
194
+ }
195
+ loadedSlides() {
196
+ const imgs = [...(this.shadowRoot?.querySelectorAll('.slides img') ?? [])];
197
+ return imgs.flatMap((img, i) => img.complete &&
198
+ img.naturalWidth
199
+ ? [i]
200
+ : []);
201
+ }
202
+ onSlideError(url) {
203
+ this.slideUrls = this.slideUrls.filter(u => u !== url);
204
+ this.slide = 0;
205
+ if (this.slideUrls.length < 2) {
206
+ window.clearInterval(this.slideTimer);
207
+ this.media = { kind: 'zoom' };
208
+ this.ready = true;
209
+ }
210
+ }
211
+ onSlideLoad() {
212
+ this.ready = true;
213
+ }
214
+ onVideoPlaying() {
215
+ window.clearTimeout(this.frameTimer);
216
+ this.ready = true;
217
+ }
218
+ /** Loops the clip within its start-to-start+clip-length window. */
219
+ onVideoTimeUpdate() {
220
+ const video = this.video;
221
+ if (this.media?.kind === 'video' &&
222
+ video &&
223
+ video.currentTime >= this.media.start + PREVIEW_CLIP_SECONDS) {
224
+ video.currentTime = this.media.start;
225
+ }
226
+ }
227
+ async onVideoLoaded() {
228
+ const { video, activation } = this;
229
+ if (video && !(await this.playMedia(video, activation))) {
230
+ this.useFallbackFrames();
231
+ }
232
+ }
233
+ async playSnippet() {
234
+ if (this.audio)
235
+ await this.playMedia(this.audio, this.activation);
236
+ }
237
+ render() {
238
+ if (!this.active || !this.media)
239
+ return nothing;
240
+ return html `<div
241
+ class="layer ${this.media.kind} ${this.ready ? 'ready' : ''}"
242
+ aria-hidden="true"
243
+ >
244
+ ${this.mediaTemplate(this.media)} ${this.soundBadgeTemplate}
245
+ </div>`;
246
+ }
247
+ /** A muted-speaker hint, so people know a clip or snippet could have sound. */
248
+ get soundBadgeTemplate() {
249
+ const kind = this.media?.kind;
250
+ if ((kind !== 'video' && kind !== 'audio') || this.audible)
251
+ return nothing;
252
+ return html `<span class="badge" title=${msg('Sound is off')}>
253
+ <svg viewBox="0 0 24 24" width="14" height="14" aria-hidden="true">
254
+ <path
255
+ fill="currentColor"
256
+ d="M3 9v6h4l5 5V4L7 9H3zm13.6 3 2.7-2.7-1.4-1.4-2.7 2.7-2.7-2.7-1.4 1.4 2.7 2.7-2.7 2.7 1.4 1.4 2.7-2.7 2.7 2.7 1.4-1.4-2.7-2.7z"
257
+ />
258
+ </svg>
259
+ </span>`;
260
+ }
261
+ mediaTemplate(media) {
262
+ switch (media.kind) {
263
+ case 'video':
264
+ return html `<video
265
+ muted
266
+ loop
267
+ playsinline
268
+ preload="auto"
269
+ src="${media.src}#t=${media.start}"
270
+ @loadeddata=${this.onVideoLoaded}
271
+ @error=${this.useFallbackFrames}
272
+ @playing=${this.onVideoPlaying}
273
+ @timeupdate=${this.onVideoTimeUpdate}
274
+ ></video>`;
275
+ case 'slides':
276
+ return html `<div class="slides ${media.fit}">
277
+ ${this.slideUrls.map((url, i) => html `<img
278
+ src=${url}
279
+ alt=""
280
+ class=${i === this.slide ? 'on' : ''}
281
+ @load=${this.onSlideLoad}
282
+ @error=${() => this.onSlideError(url)}
283
+ />`)}
284
+ </div>`;
285
+ case 'audio':
286
+ return html `
287
+ ${media.waveform
288
+ ? html `<img class="waveform" src=${media.waveform} alt="" />`
289
+ : html `<div class="bars">
290
+ ${Array.from({ length: 12 }, (_, i) => html `<span style="animation-delay:${i * -97}ms"></span>`)}
291
+ </div>`}
292
+ <div class="playhead"></div>
293
+ ${this.options.sound
294
+ ? html `<audio
295
+ preload="auto"
296
+ src="${media.src}#t=${media.start}"
297
+ ></audio>`
298
+ : nothing}
299
+ `;
300
+ default:
301
+ return html `<img
302
+ class="pan"
303
+ src=${ifDefined(this.thumbnailUrl)}
304
+ alt=""
305
+ />`;
306
+ }
307
+ }
308
+ static { this.styles = css `
309
+ :host {
310
+ position: absolute;
311
+ inset: 0;
312
+ pointer-events: none;
313
+ overflow: hidden;
314
+ border-radius: inherit;
315
+ }
316
+
317
+ .layer {
318
+ position: absolute;
319
+ inset: 0;
320
+ opacity: 0;
321
+ transition: opacity 200ms ease-out;
322
+ }
323
+
324
+ .layer.ready {
325
+ opacity: 1;
326
+ }
327
+
328
+ video,
329
+ .slides img {
330
+ position: absolute;
331
+ inset: 0;
332
+ width: 100%;
333
+ height: 100%;
334
+ object-fit: cover;
335
+ }
336
+
337
+ .slides {
338
+ position: absolute;
339
+ inset: 0;
340
+ background: #fff;
341
+ }
342
+
343
+ .slides.contain img {
344
+ object-fit: contain;
345
+ }
346
+
347
+ .slides img {
348
+ opacity: 0;
349
+ }
350
+
351
+ .slides img.on {
352
+ opacity: 1;
353
+ }
354
+
355
+ .audio {
356
+ background: #10161b;
357
+ }
358
+
359
+ .waveform {
360
+ position: absolute;
361
+ inset: 0;
362
+ width: 100%;
363
+ height: 100%;
364
+ object-fit: fill;
365
+ filter: invert(1) hue-rotate(180deg);
366
+ opacity: 0.85;
367
+ }
368
+
369
+ .badge {
370
+ position: absolute;
371
+ left: 6px;
372
+ bottom: 6px;
373
+ display: flex;
374
+ padding: 3px;
375
+ border-radius: 4px;
376
+ color: #fff;
377
+ background: rgb(0 0 0 / 0.65);
378
+ }
379
+
380
+ .playhead {
381
+ position: absolute;
382
+ top: 0;
383
+ bottom: 0;
384
+ width: 2px;
385
+ background: #f0a500;
386
+ box-shadow: 0 0 8px #f0a500;
387
+ animation: scan 2.4s linear infinite;
388
+ }
389
+
390
+ .bars {
391
+ position: absolute;
392
+ inset: 20% 10%;
393
+ display: flex;
394
+ gap: 4px;
395
+ align-items: end;
396
+ }
397
+
398
+ .bars span {
399
+ flex: 1;
400
+ height: 30%;
401
+ background: #5bb8e0;
402
+ animation: bounce 700ms ease-in-out infinite alternate;
403
+ }
404
+
405
+ .pan {
406
+ position: absolute;
407
+ inset: 0;
408
+ width: 100%;
409
+ height: 100%;
410
+ object-fit: contain;
411
+ animation: pan 6s ease-in-out infinite alternate;
412
+ }
413
+
414
+ @keyframes pan {
415
+ from {
416
+ transform: scale(1) translate(0, 0);
417
+ }
418
+ to {
419
+ transform: scale(1.3) translate(-5%, -4%);
420
+ }
421
+ }
422
+
423
+ @keyframes scan {
424
+ from {
425
+ left: 0;
426
+ }
427
+ to {
428
+ left: 100%;
429
+ }
430
+ }
431
+
432
+ @keyframes bounce {
433
+ to {
434
+ height: 95%;
435
+ }
436
+ }
437
+
438
+ @media (prefers-reduced-motion: reduce) {
439
+ .layer {
440
+ transition: none;
441
+ }
442
+
443
+ .playhead,
444
+ .pan,
445
+ .bars span {
446
+ animation: none;
447
+ }
448
+ }
449
+ `; }
450
+ };
451
+ __decorate([
452
+ property({ type: String })
453
+ ], TilePreview.prototype, "identifier", void 0);
454
+ __decorate([
455
+ property({ type: String })
456
+ ], TilePreview.prototype, "mediatype", void 0);
457
+ __decorate([
458
+ property({ type: String })
459
+ ], TilePreview.prototype, "baseUrl", void 0);
460
+ __decorate([
461
+ property({ type: String })
462
+ ], TilePreview.prototype, "thumbnailUrl", void 0);
463
+ __decorate([
464
+ property({ type: Boolean, reflect: true })
465
+ ], TilePreview.prototype, "active", void 0);
466
+ __decorate([
467
+ property({ type: Object })
468
+ ], TilePreview.prototype, "options", void 0);
469
+ __decorate([
470
+ state()
471
+ ], TilePreview.prototype, "media", void 0);
472
+ __decorate([
473
+ state()
474
+ ], TilePreview.prototype, "slideUrls", void 0);
475
+ __decorate([
476
+ state()
477
+ ], TilePreview.prototype, "slide", void 0);
478
+ __decorate([
479
+ state()
480
+ ], TilePreview.prototype, "ready", void 0);
481
+ __decorate([
482
+ state()
483
+ ], TilePreview.prototype, "audible", void 0);
484
+ __decorate([
485
+ query('video')
486
+ ], TilePreview.prototype, "video", void 0);
487
+ __decorate([
488
+ query('audio')
489
+ ], TilePreview.prototype, "audio", void 0);
490
+ TilePreview = __decorate([
491
+ customElement('tile-preview')
492
+ ], TilePreview);
493
+ export { TilePreview };
494
+ //# sourceMappingURL=tile-preview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tile-preview.js","sourceRoot":"","sources":["../../../../src/tiles/preview/tile-preview.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAkB,MAAM,KAAK,CAAC;AACrE,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC1E,OAAO,EACL,oBAAoB,EACpB,mBAAmB,GAGpB,MAAM,sBAAsB,CAAC;AAE9B,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAC9B,2EAA2E;AAC3E,MAAM,sBAAsB,GAAG,IAAI,CAAC;AACpC,MAAM,UAAU,GAAG,GAAG,CAAC;AACvB,MAAM,UAAU,GAAG,GAAG,CAAC;AACvB,MAAM,WAAW,GAAG,GAAG,CAAC;AAExB;;;;;;GAMG;AAEI,IAAM,WAAW,GAAjB,MAAM,WAAY,SAAQ,UAAU;IAApC;;QAKuB,YAAO,GAAG,qBAAqB,CAAC;QAKhB,WAAM,GAAG,KAAK,CAAC;QAE/B,YAAO,GAAuB,EAAE,CAAC;QAI5C,cAAS,GAAa,EAAE,CAAC;QAEzB,UAAK,GAAG,CAAC,CAAC;QAEV,UAAK,GAAG,KAAK,CAAC;QAE/B,wEAAwE;QACvD,YAAO,GAAG,KAAK,CAAC;QAUjC,+FAA+F;QACvF,eAAU,GAAG,IAAI,OAAO,EAA4B,CAAC;QAE7D,+EAA+E;QACvE,eAAU,GAAG,CAAC,CAAC;IA+bzB,CAAC;IA7bW,UAAU,CAAC,OAA6B;QAChD,yDAAyD;QACzD,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,IAAI,CAAC,IAAI,EAAE,CAAC;IACzD,CAAC;IAES,OAAO,CAAC,OAA6B;QAC7C,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC;YACvD,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBAChB,IAAI,CAAC,IAAI,EAAE,CAAC;gBACZ,IAAI,CAAC,KAAK,EAAE,CAAC;YACf,CAAC;QACH,CAAC;IACH,CAAC;IAED,oBAAoB;QAClB,KAAK,CAAC,oBAAoB,EAAE,CAAC;QAC7B,IAAI,CAAC,IAAI,EAAE,CAAC;IACd,CAAC;IAEO,KAAK,CAAC,KAAK;QACjB,IAAI,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,SAAS;YAAE,OAAO;QAChD,MAAM,UAAU,GAAG,EAAE,IAAI,CAAC,UAAU,CAAC;QACrC,MAAM,KAAK,GAAG,MAAM,mBAAmB,CACrC,IAAI,CAAC,UAAU,EACf,IAAI,CAAC,SAAS,EACd,IAAI,CAAC,OAAO,EACZ,IAAI,CAAC,OAAO,CACb,CAAC;QACF,IAAI,UAAU,KAAK,IAAI,CAAC,UAAU,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO;QAE3D,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,SAAS,GAAG,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3D,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QACf,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,CAAC;QAC7D,MAAM,IAAI,CAAC,cAAc,CAAC;QAC1B,IAAI,UAAU,KAAK,IAAI,CAAC,UAAU;YAAE,OAAO;QAE3C,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ;YAAE,IAAI,CAAC,WAAW,EAAE,CAAC;QAChD,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK;YAAE,IAAI,CAAC,WAAW,EAAE,CAAC;QACrE,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YAC3B,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CACjC,GAAG,EAAE,CAAC,IAAI,CAAC,iBAAiB,EAAE,EAC9B,sBAAsB,CACvB,CAAC;QACJ,CAAC;IACH,CAAC;IAEO,IAAI;QACV,IAAI,CAAC,UAAU,IAAI,CAAC,CAAC;QACrB,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACtC,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACrC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9B,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9B,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC;QACvB,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC;QACpB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;IACvB,CAAC;IAED;;;OAGG;IACK,YAAY,CAAC,EAAqB;QACxC,IAAI,CAAC,EAAE;YAAE,OAAO;QAChB,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QACpB,MAAM,MAAM,GAAG,GAAG,EAAE;YAClB,EAAE,CAAC,KAAK,EAAE,CAAC;YACX,EAAE,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;YAC1B,EAAE,CAAC,IAAI,EAAE,CAAC;QACZ,CAAC,CAAC;QACF,IAAI,EAAE,CAAC,MAAM,IAAI,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7C,MAAM,EAAE,CAAC;YACT,OAAO;QACT,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,EAAE,WAAW,EAAE,MAAM,CAAC,CAAC;IACxC,CAAC;IAEO,UAAU,CAAC,EAAoB;QACrC,MAAM,KAAK,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACtC,IAAI,KAAK,KAAK,SAAS;YAAE,MAAM,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC;QAC5D,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IAC7B,CAAC;IAED,4DAA4D;IACpD,IAAI,CACV,EAAoB,EACpB,MAAc,EACd,EAAU,EACV,IAAiB;QAEjB,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;QACpB,MAAM,IAAI,GAAG,EAAE,CAAC,MAAM,CAAC;QACvB,MAAM,EAAE,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,CAAC,GAAW,EAAE,EAAE;YAC3B,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;YACvC,EAAE,CAAC,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;YACvC,IAAI,CAAC,GAAG,CAAC;gBAAE,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC;iBAClE,CAAC;gBACJ,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBAC3B,IAAI,EAAE,EAAE,CAAC;YACX,CAAC;QACH,CAAC,CAAC;QACF,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC;IAC9D,CAAC;IAED;;;OAGG;IACK,KAAK,CAAC,SAAS,CACrB,EAAoB,EACpB,UAAkB;QAElB,IAAI,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YACvB,IAAI,CAAC;gBACH,EAAE,CAAC,KAAK,GAAG,KAAK,CAAC;gBACjB,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;gBACd,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC;gBAChB,IAAI,UAAU,KAAK,IAAI,CAAC,UAAU;oBAAE,OAAO,IAAI,CAAC;gBAChD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;gBACpB,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,UAAU,EAAE,UAAU,CAAC,CAAC;gBACtC,OAAO,IAAI,CAAC;YACd,CAAC;YAAC,MAAM,CAAC;gBACP,mCAAmC;YACrC,CAAC;QACH,CAAC;QACD,IAAI,CAAC;YACH,EAAE,CAAC,KAAK,GAAG,IAAI,CAAC;YAChB,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC;YAChB,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,MAAM,CAAC;YACP,0EAA0E;YAC1E,OAAO,UAAU,KAAK,IAAI,CAAC,UAAU,CAAC;QACxC,CAAC;IACH,CAAC;IAED,+EAA+E;IACvE,iBAAiB;QACvB,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACrC,IAAI,IAAI,CAAC,KAAK,EAAE,IAAI,KAAK,OAAO;YAAE,OAAO;QACzC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC;QACrC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9B,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;QACrB,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpB,IAAI,CAAC,KAAK,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;YACpD,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC;YACtB,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;YACf,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;YACnB,MAAM,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC;YAC5B,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,EAAE;gBAC5B,IAAI,UAAU,KAAK,IAAI,CAAC,UAAU;oBAAE,IAAI,CAAC,WAAW,EAAE,CAAC;YACzD,CAAC,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,KAAK,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;YAC9B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QACpB,CAAC;IACH,CAAC;IAEO,WAAW;QACjB,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACtC,IAAI,CAAC,UAAU,GAAG,MAAM,CAAC,WAAW,CAAC,GAAG,EAAE;YACxC,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,EAAE,CAAC;YACnC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;gBAAE,OAAO;YAC9B,IAAI,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC;YACtB,GAAG,CAAC;gBACF,IAAI,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;YAC5C,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;YACjC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QACpB,CAAC,EAAE,iBAAiB,CAAC,CAAC;IACxB,CAAC;IAEO,YAAY;QAClB,MAAM,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,gBAAgB,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QAC3E,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAC5B,GAAwB,CAAC,QAAQ;YACjC,GAAwB,CAAC,YAAY;YACpC,CAAC,CAAC,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,EAAE,CACP,CAAC;IACJ,CAAC;IAEO,YAAY,CAAC,GAAW;QAC9B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC;QACvD,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;QACf,IAAI,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9B,MAAM,CAAC,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YACtC,IAAI,CAAC,KAAK,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;YAC9B,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;QACpB,CAAC;IACH,CAAC;IAEO,WAAW;QACjB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACpB,CAAC;IAEO,cAAc;QACpB,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACrC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC;IACpB,CAAC;IAED,mEAAmE;IAC3D,iBAAiB;QACvB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACzB,IACE,IAAI,CAAC,KAAK,EAAE,IAAI,KAAK,OAAO;YAC5B,KAAK;YACL,KAAK,CAAC,WAAW,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,oBAAoB,EAC5D,CAAC;YACD,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC;QACvC,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,aAAa;QACzB,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,IAAI,CAAC;QACnC,IAAI,KAAK,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC;YACxD,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAC3B,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,WAAW;QACvB,IAAI,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;IACpE,CAAC;IAED,MAAM;QACJ,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK;YAAE,OAAO,OAAO,CAAC;QAChD,OAAO,IAAI,CAAA;qBACM,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE;;;QAGzD,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,kBAAkB;WACtD,CAAC;IACV,CAAC;IAED,+EAA+E;IAC/E,IAAY,kBAAkB;QAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC;QAC9B,IAAI,CAAC,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,OAAO,CAAC,IAAI,IAAI,CAAC,OAAO;YAAE,OAAO,OAAO,CAAC;QAC3E,OAAO,IAAI,CAAA,6BAA6B,GAAG,CAAC,cAAc,CAAC;;;;;;;YAOnD,CAAC;IACX,CAAC;IAEO,aAAa,CAAC,KAAuB;QAC3C,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;YACnB,KAAK,OAAO;gBACV,OAAO,IAAI,CAAA;;;;;iBAKF,KAAK,CAAC,GAAG,MAAM,KAAK,CAAC,KAAK;wBACnB,IAAI,CAAC,aAAa;mBACvB,IAAI,CAAC,iBAAiB;qBACpB,IAAI,CAAC,cAAc;wBAChB,IAAI,CAAC,iBAAiB;kBAC5B,CAAC;YACb,KAAK,QAAQ;gBACX,OAAO,IAAI,CAAA,sBAAsB,KAAK,CAAC,GAAG;YACtC,IAAI,CAAC,SAAS,CAAC,GAAG,CAClB,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CACT,IAAI,CAAA;sBACI,GAAG;;wBAED,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;wBAC5B,IAAI,CAAC,WAAW;yBACf,GAAG,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC;iBACpC,CACN;eACI,CAAC;YACV,KAAK,OAAO;gBACV,OAAO,IAAI,CAAA;YACP,KAAK,CAAC,QAAQ;oBACd,CAAC,CAAC,IAAI,CAAA,6BAA6B,KAAK,CAAC,QAAQ,YAAY;oBAC7D,CAAC,CAAC,IAAI,CAAA;kBACA,KAAK,CAAC,IAAI,CACV,EAAE,MAAM,EAAE,EAAE,EAAE,EACd,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACP,IAAI,CAAA,gCAAgC,CAAC,GAAG,CAAC,EAAE,aAAa,CAC3D;qBACI;;YAET,IAAI,CAAC,OAAO,CAAC,KAAK;oBAClB,CAAC,CAAC,IAAI,CAAA;;uBAEK,KAAK,CAAC,GAAG,MAAM,KAAK,CAAC,KAAK;wBACzB;oBACZ,CAAC,CAAC,OAAO;SACZ,CAAC;YACJ;gBACE,OAAO,IAAI,CAAA;;gBAEH,SAAS,CAAC,IAAI,CAAC,YAAY,CAAC;;WAEjC,CAAC;QACR,CAAC;IACH,CAAC;aAEM,WAAM,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6IlB,AA7IY,CA6IX;;AAle0B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;+CAAqB;AAEpB;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;8CAAoB;AAEnB;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;4CAAiC;AAGhC;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;iDAAuB;AAEN;IAA3C,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;2CAAgB;AAE/B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;4CAAkC;AAE5C;IAAhB,KAAK,EAAE;0CAAkC;AAEzB;IAAhB,KAAK,EAAE;8CAAkC;AAEzB;IAAhB,KAAK,EAAE;0CAAmB;AAEV;IAAhB,KAAK,EAAE;0CAAuB;AAGd;IAAhB,KAAK,EAAE;4CAAyB;AAET;IAAvB,KAAK,CAAC,OAAO,CAAC;0CAAkC;AAEzB;IAAvB,KAAK,CAAC,OAAO,CAAC;0CAAkC;AA3BtC,WAAW;IADvB,aAAa,CAAC,cAAc,CAAC;GACjB,WAAW,CAoevB","sourcesContent":["import { css, html, LitElement, nothing, PropertyValues } from 'lit';\nimport { msg } from '@lit/localize';\nimport { ifDefined } from 'lit/directives/if-defined.js';\nimport { customElement, property, query, state } from 'lit/decorators.js';\nimport {\n PREVIEW_CLIP_SECONDS,\n resolvePreviewMedia,\n type TilePreviewMedia,\n type TilePreviewOptions,\n} from './tile-preview-media';\n\nconst SLIDE_INTERVAL_MS = 700;\n/** How long the first video frame may take before the frames take over. */\nconst FIRST_FRAME_TIMEOUT_MS = 2500;\nconst MAX_VOLUME = 0.5;\nconst FADE_IN_MS = 250;\nconst FADE_OUT_MS = 120;\n\n/**\n * Fills a tile's image area with a live preview of the item while `active`:\n * a muted clip for movies, a few page images for texts, a waveform for audio,\n * cycling images for images, and a slow pan over the thumbnail for anything\n * else. It is absolutely positioned over the existing thumbnail, so showing\n * and hiding it never moves the layout.\n */\n@customElement('tile-preview')\nexport class TilePreview extends LitElement {\n @property({ type: String }) identifier?: string;\n\n @property({ type: String }) mediatype?: string;\n\n @property({ type: String }) baseUrl = 'https://archive.org';\n\n /** The tile's thumbnail, panned slowly when there is nothing richer to show. */\n @property({ type: String }) thumbnailUrl?: string;\n\n @property({ type: Boolean, reflect: true }) active = false;\n\n @property({ type: Object }) options: TilePreviewOptions = {};\n\n @state() private media?: TilePreviewMedia;\n\n @state() private slideUrls: string[] = [];\n\n @state() private slide = 0;\n\n @state() private ready = false;\n\n /** Whether sound is audibly playing, as opposed to muted or refused. */\n @state() private audible = false;\n\n @query('video') private video?: HTMLVideoElement;\n\n @query('audio') private audio?: HTMLAudioElement;\n\n private slideTimer?: number;\n\n private frameTimer?: number;\n\n /** Pending fade animation frame per element, so one element's fade never cancels another's. */\n private fadeFrames = new WeakMap<HTMLMediaElement, number>();\n\n /** Bumped on every activation so a slow resolve can't show a stale preview. */\n private activation = 0;\n\n protected willUpdate(changed: PropertyValues<this>): void {\n // Release while the media elements are still in the DOM.\n if (changed.has('active') && !this.active) this.stop();\n }\n\n protected updated(changed: PropertyValues<this>): void {\n if (changed.has('active') || changed.has('identifier')) {\n if (this.active) {\n this.stop();\n this.start();\n }\n }\n }\n\n disconnectedCallback(): void {\n super.disconnectedCallback();\n this.stop();\n }\n\n private async start(): Promise<void> {\n if (!this.identifier || !this.mediatype) return;\n const activation = ++this.activation;\n const media = await resolvePreviewMedia(\n this.identifier,\n this.mediatype,\n this.baseUrl,\n this.options,\n );\n if (activation !== this.activation || !this.active) return;\n\n this.media = media;\n this.slideUrls = media.kind === 'slides' ? media.urls : [];\n this.slide = 0;\n this.ready = media.kind === 'zoom' || media.kind === 'audio';\n await this.updateComplete;\n if (activation !== this.activation) return;\n\n if (media.kind === 'slides') this.startSlides();\n if (media.kind === 'audio' && this.options.sound) this.playSnippet();\n if (media.kind === 'video') {\n this.frameTimer = window.setTimeout(\n () => this.useFallbackFrames(),\n FIRST_FRAME_TIMEOUT_MS,\n );\n }\n }\n\n private stop(): void {\n this.activation += 1;\n window.clearInterval(this.slideTimer);\n window.clearTimeout(this.frameTimer);\n this.releaseMedia(this.video);\n this.releaseMedia(this.audio);\n this.media = undefined;\n this.slideUrls = [];\n this.ready = false;\n this.audible = false;\n }\n\n /**\n * Stops a media element: a short fade-out when it is audible, then pause and\n * drop the source so the browser stops downloading it.\n */\n private releaseMedia(el?: HTMLMediaElement): void {\n if (!el) return;\n this.cancelFade(el);\n const finish = () => {\n el.pause();\n el.removeAttribute('src');\n el.load();\n };\n if (el.paused || el.muted || el.volume === 0) {\n finish();\n return;\n }\n this.fade(el, 0, FADE_OUT_MS, finish);\n }\n\n private cancelFade(el: HTMLMediaElement): void {\n const frame = this.fadeFrames.get(el);\n if (frame !== undefined) window.cancelAnimationFrame(frame);\n this.fadeFrames.delete(el);\n }\n\n /** Ramps a media element's volume to `target` over `ms`. */\n private fade(\n el: HTMLMediaElement,\n target: number,\n ms: number,\n done?: () => void,\n ): void {\n this.cancelFade(el);\n const from = el.volume;\n const t0 = performance.now();\n const step = (now: number) => {\n const t = Math.min(1, (now - t0) / ms);\n el.volume = from + (target - from) * t;\n if (t < 1) this.fadeFrames.set(el, window.requestAnimationFrame(step));\n else {\n this.fadeFrames.delete(el);\n done?.();\n }\n };\n this.fadeFrames.set(el, window.requestAnimationFrame(step));\n }\n\n /**\n * Starts a media element, with sound when the options ask for it. A browser\n * that refuses audible playback gets a muted one instead.\n */\n private async playMedia(\n el: HTMLMediaElement,\n activation: number,\n ): Promise<boolean> {\n if (this.options.sound) {\n try {\n el.muted = false;\n el.volume = 0;\n await el.play();\n if (activation !== this.activation) return true;\n this.audible = true;\n this.fade(el, MAX_VOLUME, FADE_IN_MS);\n return true;\n } catch {\n // Refused, so play it muted below.\n }\n }\n try {\n el.muted = true;\n await el.play();\n return true;\n } catch {\n // A stopped preview isn't a failure; only a current one needs the frames.\n return activation !== this.activation;\n }\n }\n\n /** Swaps a clip that is slow or unplayable for the item's frame thumbnails. */\n private useFallbackFrames(): void {\n window.clearTimeout(this.frameTimer);\n if (this.media?.kind !== 'video') return;\n const urls = this.media.fallbackUrls;\n this.releaseMedia(this.video);\n this.audible = false;\n if (urls.length > 1) {\n this.media = { kind: 'slides', fit: 'cover', urls };\n this.slideUrls = urls;\n this.slide = 0;\n this.ready = false;\n const { activation } = this;\n this.updateComplete.then(() => {\n if (activation === this.activation) this.startSlides();\n });\n } else {\n this.media = { kind: 'zoom' };\n this.ready = true;\n }\n }\n\n private startSlides(): void {\n window.clearInterval(this.slideTimer);\n this.slideTimer = window.setInterval(() => {\n const loaded = this.loadedSlides();\n if (loaded.length < 2) return;\n let next = this.slide;\n do {\n next = (next + 1) % this.slideUrls.length;\n } while (!loaded.includes(next));\n this.slide = next;\n }, SLIDE_INTERVAL_MS);\n }\n\n private loadedSlides(): number[] {\n const imgs = [...(this.shadowRoot?.querySelectorAll('.slides img') ?? [])];\n return imgs.flatMap((img, i) =>\n (img as HTMLImageElement).complete &&\n (img as HTMLImageElement).naturalWidth\n ? [i]\n : [],\n );\n }\n\n private onSlideError(url: string): void {\n this.slideUrls = this.slideUrls.filter(u => u !== url);\n this.slide = 0;\n if (this.slideUrls.length < 2) {\n window.clearInterval(this.slideTimer);\n this.media = { kind: 'zoom' };\n this.ready = true;\n }\n }\n\n private onSlideLoad(): void {\n this.ready = true;\n }\n\n private onVideoPlaying(): void {\n window.clearTimeout(this.frameTimer);\n this.ready = true;\n }\n\n /** Loops the clip within its start-to-start+clip-length window. */\n private onVideoTimeUpdate(): void {\n const video = this.video;\n if (\n this.media?.kind === 'video' &&\n video &&\n video.currentTime >= this.media.start + PREVIEW_CLIP_SECONDS\n ) {\n video.currentTime = this.media.start;\n }\n }\n\n private async onVideoLoaded(): Promise<void> {\n const { video, activation } = this;\n if (video && !(await this.playMedia(video, activation))) {\n this.useFallbackFrames();\n }\n }\n\n private async playSnippet(): Promise<void> {\n if (this.audio) await this.playMedia(this.audio, this.activation);\n }\n\n render() {\n if (!this.active || !this.media) return nothing;\n return html`<div\n class=\"layer ${this.media.kind} ${this.ready ? 'ready' : ''}\"\n aria-hidden=\"true\"\n >\n ${this.mediaTemplate(this.media)} ${this.soundBadgeTemplate}\n </div>`;\n }\n\n /** A muted-speaker hint, so people know a clip or snippet could have sound. */\n private get soundBadgeTemplate() {\n const kind = this.media?.kind;\n if ((kind !== 'video' && kind !== 'audio') || this.audible) return nothing;\n return html`<span class=\"badge\" title=${msg('Sound is off')}>\n <svg viewBox=\"0 0 24 24\" width=\"14\" height=\"14\" aria-hidden=\"true\">\n <path\n fill=\"currentColor\"\n d=\"M3 9v6h4l5 5V4L7 9H3zm13.6 3 2.7-2.7-1.4-1.4-2.7 2.7-2.7-2.7-1.4 1.4 2.7 2.7-2.7 2.7 1.4 1.4 2.7-2.7 2.7 2.7 1.4-1.4-2.7-2.7z\"\n />\n </svg>\n </span>`;\n }\n\n private mediaTemplate(media: TilePreviewMedia) {\n switch (media.kind) {\n case 'video':\n return html`<video\n muted\n loop\n playsinline\n preload=\"auto\"\n src=\"${media.src}#t=${media.start}\"\n @loadeddata=${this.onVideoLoaded}\n @error=${this.useFallbackFrames}\n @playing=${this.onVideoPlaying}\n @timeupdate=${this.onVideoTimeUpdate}\n ></video>`;\n case 'slides':\n return html`<div class=\"slides ${media.fit}\">\n ${this.slideUrls.map(\n (url, i) =>\n html`<img\n src=${url}\n alt=\"\"\n class=${i === this.slide ? 'on' : ''}\n @load=${this.onSlideLoad}\n @error=${() => this.onSlideError(url)}\n />`,\n )}\n </div>`;\n case 'audio':\n return html`\n ${media.waveform\n ? html`<img class=\"waveform\" src=${media.waveform} alt=\"\" />`\n : html`<div class=\"bars\">\n ${Array.from(\n { length: 12 },\n (_, i) =>\n html`<span style=\"animation-delay:${i * -97}ms\"></span>`,\n )}\n </div>`}\n <div class=\"playhead\"></div>\n ${this.options.sound\n ? html`<audio\n preload=\"auto\"\n src=\"${media.src}#t=${media.start}\"\n ></audio>`\n : nothing}\n `;\n default:\n return html`<img\n class=\"pan\"\n src=${ifDefined(this.thumbnailUrl)}\n alt=\"\"\n />`;\n }\n }\n\n static styles = css`\n :host {\n position: absolute;\n inset: 0;\n pointer-events: none;\n overflow: hidden;\n border-radius: inherit;\n }\n\n .layer {\n position: absolute;\n inset: 0;\n opacity: 0;\n transition: opacity 200ms ease-out;\n }\n\n .layer.ready {\n opacity: 1;\n }\n\n video,\n .slides img {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n object-fit: cover;\n }\n\n .slides {\n position: absolute;\n inset: 0;\n background: #fff;\n }\n\n .slides.contain img {\n object-fit: contain;\n }\n\n .slides img {\n opacity: 0;\n }\n\n .slides img.on {\n opacity: 1;\n }\n\n .audio {\n background: #10161b;\n }\n\n .waveform {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n object-fit: fill;\n filter: invert(1) hue-rotate(180deg);\n opacity: 0.85;\n }\n\n .badge {\n position: absolute;\n left: 6px;\n bottom: 6px;\n display: flex;\n padding: 3px;\n border-radius: 4px;\n color: #fff;\n background: rgb(0 0 0 / 0.65);\n }\n\n .playhead {\n position: absolute;\n top: 0;\n bottom: 0;\n width: 2px;\n background: #f0a500;\n box-shadow: 0 0 8px #f0a500;\n animation: scan 2.4s linear infinite;\n }\n\n .bars {\n position: absolute;\n inset: 20% 10%;\n display: flex;\n gap: 4px;\n align-items: end;\n }\n\n .bars span {\n flex: 1;\n height: 30%;\n background: #5bb8e0;\n animation: bounce 700ms ease-in-out infinite alternate;\n }\n\n .pan {\n position: absolute;\n inset: 0;\n width: 100%;\n height: 100%;\n object-fit: contain;\n animation: pan 6s ease-in-out infinite alternate;\n }\n\n @keyframes pan {\n from {\n transform: scale(1) translate(0, 0);\n }\n to {\n transform: scale(1.3) translate(-5%, -4%);\n }\n }\n\n @keyframes scan {\n from {\n left: 0;\n }\n to {\n left: 100%;\n }\n }\n\n @keyframes bounce {\n to {\n height: 95%;\n }\n }\n\n @media (prefers-reduced-motion: reduce) {\n .layer {\n transition: none;\n }\n\n .playhead,\n .pan,\n .bars span {\n animation: none;\n }\n }\n `;\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  import { __decorate } from "tslib";
2
2
  import { css, html, LitElement, nothing, } from 'lit';
3
3
  import { customElement, property } from 'lit/decorators.js';
4
- import { localized, msg } from '@lit/localize';
4
+ import { msg } from '@lit/localize';
5
5
  import { favoriteFilledIcon } from '../assets/img/icons/favorite-filled';
6
6
  import { favoriteUnfilledIcon } from '../assets/img/icons/favorite-unfilled';
7
7
  import { srOnlyStyle } from '../styles/sr-only';
@@ -128,8 +128,7 @@ __decorate([
128
128
  property({ type: String })
129
129
  ], ReviewBlock.prototype, "viewSize", void 0);
130
130
  ReviewBlock = __decorate([
131
- customElement('review-block'),
132
- localized()
131
+ customElement('review-block')
133
132
  ], ReviewBlock);
134
133
  export { ReviewBlock };
135
134
  //# sourceMappingURL=review-block.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"review-block.js","sourceRoot":"","sources":["../../../src/tiles/review-block.ts"],"names":[],"mappings":";AAAA,OAAO,EACL,GAAG,EAEH,IAAI,EACJ,UAAU,EACV,OAAO,GAER,MAAM,KAAK,CAAC;AACb,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AACzE,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAC7E,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIzC,IAAM,WAAW,GAAjB,MAAM,WAAY,SAAQ,UAAU;IAApC;;QACuB,UAAK,GAAG,EAAE,CAAC;QAEX,SAAI,GAAG,EAAE,CAAC;QAEV,eAAU,GAAG,CAAC,CAAC;QAEf,aAAQ,GAAG,SAAS,CAAC;IA2GnD,CAAC;IAzGC,MAAM;QACJ,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU;YAAE,OAAO,OAAO,CAAC;QAElE,OAAO,IAAI,CAAA;;mCAEoB,IAAI,CAAC,QAAQ;YACpC,IAAI,CAAC,aAAa;oCACM,IAAI,CAAC,KAAK;mCACX,IAAI,CAAC,IAAI;;;KAGvC,CAAC;IACJ,CAAC;IAED,IAAY,aAAa;QACvB,IAAI,IAAI,CAAC,UAAU,IAAI,CAAC;YAAE,OAAO,OAAO,CAAC;QAEzC,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QACpD,MAAM,gBAAgB,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC;QAC1D,OAAO,IAAI,CAAA;;gCAEiB,IAAI,CAAC,UAAU,IAAI,GAAG,CAAC,gBAAgB,CAAC;UAC9D,KAAK,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC;UACnD,KAAK,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,oBAAoB,CAAC;;KAE5D,CAAC;IACJ,CAAC;IAED,IAAY,kBAAkB;QAC5B,OAAO,IAAI,CAAA,4BAA4B,kBAAkB,SAAS,CAAC;IACrE,CAAC;IAED,IAAY,oBAAoB;QAC9B,OAAO,IAAI,CAAA;;UAEL,oBAAoB;;KAEzB,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,MAAM;QACf,OAAO;YACL,WAAW;YACX,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2DF;SACF,CAAC;IACJ,CAAC;CACF,CAAA;AAjH6B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;0CAAY;AAEX;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;yCAAW;AAEV;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;+CAAgB;AAEf;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;6CAAsB;AAPtC,WAAW;IAFvB,aAAa,CAAC,cAAc,CAAC;IAC7B,SAAS,EAAE;GACC,WAAW,CAkHvB","sourcesContent":["import {\n css,\n CSSResultGroup,\n html,\n LitElement,\n nothing,\n TemplateResult,\n} from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { localized, msg } from '@lit/localize';\nimport { favoriteFilledIcon } from '../assets/img/icons/favorite-filled';\nimport { favoriteUnfilledIcon } from '../assets/img/icons/favorite-unfilled';\nimport { srOnlyStyle } from '../styles/sr-only';\n\n@customElement('review-block')\n@localized()\nexport class ReviewBlock extends LitElement {\n @property({ type: String }) title = '';\n\n @property({ type: String }) body = '';\n\n @property({ type: Number }) starRating = 0;\n\n @property({ type: String }) viewSize = 'desktop';\n\n render() {\n if (!this.title && !this.body && !this.starRating) return nothing;\n\n return html`\n <div class=\"review-container\">\n <div class=\"snippet-view ${this.viewSize}\">\n ${this.starsTemplate}\n <p class=\"review-title\">${this.title}</p>\n <p class=\"review-body\">${this.body}</p>\n </div>\n </div>\n `;\n }\n\n private get starsTemplate(): TemplateResult | typeof nothing {\n if (this.starRating <= 0) return nothing;\n\n const numFilledStars = Math.min(5, this.starRating);\n const numUnfilledStars = Math.min(5, 5 - this.starRating);\n return html`\n <div class=\"star-rating\">\n <span class=\"sr-only\">${this.starRating} ${msg('out of 5 stars')}</span>\n ${Array(numFilledStars).fill(this.filledStarTemplate)}\n ${Array(numUnfilledStars).fill(this.unfilledStarTemplate)}\n </div>\n `;\n }\n\n private get filledStarTemplate(): TemplateResult {\n return html`<span aria-hidden=\"true\">${favoriteFilledIcon}</span>`;\n }\n\n private get unfilledStarTemplate(): TemplateResult {\n return html`\n <span class=\"unfilled-star\" aria-hidden=\"true\">\n ${favoriteUnfilledIcon}\n </span>\n `;\n }\n\n static get styles(): CSSResultGroup {\n return [\n srOnlyStyle,\n css`\n .review-container {\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n width: calc(100% - 10px);\n border: 1px solid #ccc;\n margin-top: var(--containerTopMargin, 10px);\n margin-left: var(--containerLeftMargin, 0px);\n padding: 5px;\n box-sizing: border-box;\n }\n\n .review-title,\n .review-body {\n display: -webkit-box;\n font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;\n overflow: hidden;\n overflow-wrap: break-word;\n word-break: break-word;\n -webkit-line-clamp: var(--maxLines, 3);\n -webkit-box-orient: vertical;\n margin: 0;\n }\n\n .review-title {\n font-size: 1.4rem;\n line-height: 2rem;\n max-height: 6rem;\n }\n\n .review-title > a[href] {\n color: inherit;\n text-decoration: none;\n }\n\n .review-title > a[href]:hover {\n text-decoration: underline;\n }\n\n .review-body {\n font-size: 1rem;\n line-height: 1.4rem;\n max-height: 4.2rem;\n }\n\n .star-rating svg {\n width: 10px;\n height: 10px;\n }\n\n .unfilled-star {\n fill: #ccc;\n }\n\n .list {\n margin: 0;\n padding-left: 5px;\n }\n `,\n ];\n }\n}\n"]}
1
+ {"version":3,"file":"review-block.js","sourceRoot":"","sources":["../../../src/tiles/review-block.ts"],"names":[],"mappings":";AAAA,OAAO,EACL,GAAG,EAEH,IAAI,EACJ,UAAU,EACV,OAAO,GAER,MAAM,KAAK,CAAC;AACb,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC5D,OAAO,EAAE,GAAG,EAAE,MAAM,eAAe,CAAC;AACpC,OAAO,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AACzE,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAC7E,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGzC,IAAM,WAAW,GAAjB,MAAM,WAAY,SAAQ,UAAU;IAApC;;QACuB,UAAK,GAAG,EAAE,CAAC;QAEX,SAAI,GAAG,EAAE,CAAC;QAEV,eAAU,GAAG,CAAC,CAAC;QAEf,aAAQ,GAAG,SAAS,CAAC;IA2GnD,CAAC;IAzGC,MAAM;QACJ,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU;YAAE,OAAO,OAAO,CAAC;QAElE,OAAO,IAAI,CAAA;;mCAEoB,IAAI,CAAC,QAAQ;YACpC,IAAI,CAAC,aAAa;oCACM,IAAI,CAAC,KAAK;mCACX,IAAI,CAAC,IAAI;;;KAGvC,CAAC;IACJ,CAAC;IAED,IAAY,aAAa;QACvB,IAAI,IAAI,CAAC,UAAU,IAAI,CAAC;YAAE,OAAO,OAAO,CAAC;QAEzC,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QACpD,MAAM,gBAAgB,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC;QAC1D,OAAO,IAAI,CAAA;;gCAEiB,IAAI,CAAC,UAAU,IAAI,GAAG,CAAC,gBAAgB,CAAC;UAC9D,KAAK,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,kBAAkB,CAAC;UACnD,KAAK,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,oBAAoB,CAAC;;KAE5D,CAAC;IACJ,CAAC;IAED,IAAY,kBAAkB;QAC5B,OAAO,IAAI,CAAA,4BAA4B,kBAAkB,SAAS,CAAC;IACrE,CAAC;IAED,IAAY,oBAAoB;QAC9B,OAAO,IAAI,CAAA;;UAEL,oBAAoB;;KAEzB,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,MAAM;QACf,OAAO;YACL,WAAW;YACX,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2DF;SACF,CAAC;IACJ,CAAC;CACF,CAAA;AAjH6B;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;0CAAY;AAEX;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;yCAAW;AAEV;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;+CAAgB;AAEf;IAA3B,QAAQ,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;6CAAsB;AAPtC,WAAW;IADvB,aAAa,CAAC,cAAc,CAAC;GACjB,WAAW,CAkHvB","sourcesContent":["import {\n css,\n CSSResultGroup,\n html,\n LitElement,\n nothing,\n TemplateResult,\n} from 'lit';\nimport { customElement, property } from 'lit/decorators.js';\nimport { msg } from '@lit/localize';\nimport { favoriteFilledIcon } from '../assets/img/icons/favorite-filled';\nimport { favoriteUnfilledIcon } from '../assets/img/icons/favorite-unfilled';\nimport { srOnlyStyle } from '../styles/sr-only';\n\n@customElement('review-block')\nexport class ReviewBlock extends LitElement {\n @property({ type: String }) title = '';\n\n @property({ type: String }) body = '';\n\n @property({ type: Number }) starRating = 0;\n\n @property({ type: String }) viewSize = 'desktop';\n\n render() {\n if (!this.title && !this.body && !this.starRating) return nothing;\n\n return html`\n <div class=\"review-container\">\n <div class=\"snippet-view ${this.viewSize}\">\n ${this.starsTemplate}\n <p class=\"review-title\">${this.title}</p>\n <p class=\"review-body\">${this.body}</p>\n </div>\n </div>\n `;\n }\n\n private get starsTemplate(): TemplateResult | typeof nothing {\n if (this.starRating <= 0) return nothing;\n\n const numFilledStars = Math.min(5, this.starRating);\n const numUnfilledStars = Math.min(5, 5 - this.starRating);\n return html`\n <div class=\"star-rating\">\n <span class=\"sr-only\">${this.starRating} ${msg('out of 5 stars')}</span>\n ${Array(numFilledStars).fill(this.filledStarTemplate)}\n ${Array(numUnfilledStars).fill(this.unfilledStarTemplate)}\n </div>\n `;\n }\n\n private get filledStarTemplate(): TemplateResult {\n return html`<span aria-hidden=\"true\">${favoriteFilledIcon}</span>`;\n }\n\n private get unfilledStarTemplate(): TemplateResult {\n return html`\n <span class=\"unfilled-star\" aria-hidden=\"true\">\n ${favoriteUnfilledIcon}\n </span>\n `;\n }\n\n static get styles(): CSSResultGroup {\n return [\n srOnlyStyle,\n css`\n .review-container {\n display: flex;\n flex-direction: row;\n flex-wrap: wrap;\n width: calc(100% - 10px);\n border: 1px solid #ccc;\n margin-top: var(--containerTopMargin, 10px);\n margin-left: var(--containerLeftMargin, 0px);\n padding: 5px;\n box-sizing: border-box;\n }\n\n .review-title,\n .review-body {\n display: -webkit-box;\n font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;\n overflow: hidden;\n overflow-wrap: break-word;\n word-break: break-word;\n -webkit-line-clamp: var(--maxLines, 3);\n -webkit-box-orient: vertical;\n margin: 0;\n }\n\n .review-title {\n font-size: 1.4rem;\n line-height: 2rem;\n max-height: 6rem;\n }\n\n .review-title > a[href] {\n color: inherit;\n text-decoration: none;\n }\n\n .review-title > a[href]:hover {\n text-decoration: underline;\n }\n\n .review-body {\n font-size: 1rem;\n line-height: 1.4rem;\n max-height: 4.2rem;\n }\n\n .star-rating svg {\n width: 10px;\n height: 10px;\n }\n\n .unfilled-star {\n fill: #ccc;\n }\n\n .list {\n margin: 0;\n padding-left: 5px;\n }\n `,\n ];\n }\n}\n"]}
@@ -14,6 +14,7 @@ import type { TileHoverPane } from './hover/tile-hover-pane';
14
14
  import { BaseTileComponent } from './base-tile-component';
15
15
  import { LayoutType } from './models';
16
16
  import { HoverPaneProperties, HoverPaneProviderInterface } from './hover/hover-pane-controller';
17
+ import type { TilePreviewOptions } from './preview/tile-preview-media';
17
18
  export declare class TileDispatcher extends BaseTileComponent implements SharedResizeObserverResizeHandlerInterface, HoverPaneProviderInterface {
18
19
  tileDisplayMode?: TileDisplayMode;
19
20
  isManageView: boolean;
@@ -24,8 +25,11 @@ export declare class TileDispatcher extends BaseTileComponent implements SharedR
24
25
  layoutType: LayoutType;
25
26
  /** Whether this tile should include a hover pane at all (for applicable tile modes) */
26
27
  enableHoverPane: boolean;
27
- /** Title for the manage checkbox. Defaults to a localized "Remove this item from the list". */
28
- manageCheckTitle?: string;
28
+ /** Whether hovering, focusing or long-pressing this tile starts a live preview */
29
+ enableTilePreview: boolean;
30
+ tilePreviewOptions: TilePreviewOptions;
31
+ private previewController;
32
+ manageCheckTitle: string;
29
33
  private hoverPaneController?;
30
34
  private container;
31
35
  private hoverPane?;
@@ -46,6 +50,8 @@ export declare class TileDispatcher extends BaseTileComponent implements SharedR
46
50
  * (e.g., whether mouse listeners should be attached, etc.)
47
51
  */
48
52
  private get shouldPrepareHoverPane();
53
+ /** Only plain item tiles preview: not collections, accounts, searches or gated items. */
54
+ private get shouldPreview();
49
55
  private get isHoverEnabled();
50
56
  /**
51
57
  * Whether the info button should be shown on this tile.