diff --git a/web/src/lib/components/assets/thumbnail/__test__/thumbnail.spec.ts b/web/src/lib/components/assets/thumbnail/__test__/thumbnail.spec.ts index f8e5fe0efa..21466780e8 100644 --- a/web/src/lib/components/assets/thumbnail/__test__/thumbnail.spec.ts +++ b/web/src/lib/components/assets/thumbnail/__test__/thumbnail.spec.ts @@ -45,15 +45,4 @@ describe('Thumbnail component', () => { const tabbables = getTabbable(container!); expect(tabbables.length).toBe(0); }); - - it('shows thumbhash while image is loading', () => { - const asset = assetFactory.build({ originalPath: 'image.jpg', originalMimeType: 'image/jpeg' }); - const sut = render(Thumbnail, { - asset, - selected: true, - }); - - const thumbhash = sut.getByTestId('thumbhash'); - expect(thumbhash).not.toBeFalsy(); - }); }); diff --git a/web/src/lib/components/assets/thumbnail/thumbnail.svelte b/web/src/lib/components/assets/thumbnail/thumbnail.svelte index e4b590b8ea..8426b182b2 100644 --- a/web/src/lib/components/assets/thumbnail/thumbnail.svelte +++ b/web/src/lib/components/assets/thumbnail/thumbnail.svelte @@ -20,6 +20,7 @@ import { authManager } from '$lib/managers/auth-manager.svelte'; import type { TimelineAsset } from '$lib/managers/timeline-manager/types'; import { mobileDevice } from '$lib/stores/mobile-device.svelte'; + import { isCached } from '$lib/utils/cache'; import { moveFocus } from '$lib/utils/focus-util'; import { currentUrlReplaceAssetId } from '$lib/utils/navigation'; import { TUNABLES } from '$lib/utils/tunables'; @@ -75,6 +76,12 @@ IMAGE_THUMBNAIL: { THUMBHASH_FADE_DURATION }, } = TUNABLES; + const thumbnailURL = getAssetThumbnailUrl({ + id: asset.id, + size: AssetMediaSize.Thumbnail, + cacheKey: asset.thumbhash, + }); + let usingMobileDevice = $derived(mobileDevice.pointerCoarse); let element: HTMLElement | undefined = $state(); let mouseOver = $state(false); @@ -313,7 +320,7 @@ {/if} - {#if (!loaded || thumbError) && asset.thumbhash} - + {#if asset.thumbhash} + {#await isCached(new Request(thumbnailURL))} + + {:then cached} + {#if !cached && !loaded && !thumbError} + + {/if} + {/await} {/if} diff --git a/web/src/lib/utils/cache.ts b/web/src/lib/utils/cache.ts new file mode 100644 index 0000000000..0c2792b541 --- /dev/null +++ b/web/src/lib/utils/cache.ts @@ -0,0 +1,18 @@ +let cache: Cache | undefined; + +const getCache = async () => { + cache ||= await openCache(); + return cache; +}; + +const openCache = async () => { + const [key] = await caches.keys(); + if (key) { + return caches.open(key); + } +}; + +export const isCached = async (req: Request) => { + const cache = await getCache(); + return !!(await cache?.match(req)); +}; diff --git a/web/src/lib/utils/tunables.ts b/web/src/lib/utils/tunables.ts index 6ce64ed041..8463ffa73a 100644 --- a/web/src/lib/utils/tunables.ts +++ b/web/src/lib/utils/tunables.ts @@ -29,6 +29,6 @@ export const TUNABLES = { NAVIGATE_ON_ASSET_IN_VIEW: getBoolean(storage.getItem('ASSET_GRID.NAVIGATE_ON_ASSET_IN_VIEW'), false), }, IMAGE_THUMBNAIL: { - THUMBHASH_FADE_DURATION: getNumber(storage.getItem('THUMBHASH_FADE_DURATION'), 100), + THUMBHASH_FADE_DURATION: getNumber(storage.getItem('THUMBHASH_FADE_DURATION'), 1000), }, };