diff --git a/web/src/lib/components/asset-viewer/asset-viewer.svelte b/web/src/lib/components/asset-viewer/asset-viewer.svelte index eec55ec396b..91461d574d3 100644 --- a/web/src/lib/components/asset-viewer/asset-viewer.svelte +++ b/web/src/lib/components/asset-viewer/asset-viewer.svelte @@ -595,7 +595,7 @@ id="stack-slideshow" class="z-[1002] flex place-item-center place-content-center absolute bottom-0 w-full col-span-4 col-start-1 overflow-x-auto horizontal-scrollbar" > -
+
{#each stackedAssets as stackedAsset (stackedAsset.id)}
{ diff --git a/web/src/lib/components/asset-viewer/photo-viewer.svelte b/web/src/lib/components/asset-viewer/photo-viewer.svelte index 6bc67a5257e..d3a9da3633f 100644 --- a/web/src/lib/components/asset-viewer/photo-viewer.svelte +++ b/web/src/lib/components/asset-viewer/photo-viewer.svelte @@ -184,7 +184,9 @@ ]} /> {#if imageError} - +
+ +
{/if} diff --git a/web/src/lib/components/assets/broken-asset.svelte b/web/src/lib/components/assets/broken-asset.svelte index 31acb832e5d..9ba6f24f9a8 100644 --- a/web/src/lib/components/assets/broken-asset.svelte +++ b/web/src/lib/components/assets/broken-asset.svelte @@ -14,7 +14,7 @@
diff --git a/web/src/lib/components/assets/thumbnail/image-thumbnail.svelte b/web/src/lib/components/assets/thumbnail/image-thumbnail.svelte index 4f4390b23df..55357abbc03 100644 --- a/web/src/lib/components/assets/thumbnail/image-thumbnail.svelte +++ b/web/src/lib/components/assets/thumbnail/image-thumbnail.svelte @@ -21,7 +21,8 @@ border?: boolean; hiddenIconClass?: string; class?: ClassValue; - onComplete?: (() => void) | undefined; + brokenAssetClass?: ClassValue; + onComplete?: ((errored: boolean) => void) | undefined; } let { @@ -39,6 +40,7 @@ hiddenIconClass = 'text-white', onComplete = undefined, class: imageClass = '', + brokenAssetClass = '', }: Props = $props(); let { @@ -50,17 +52,17 @@ const setLoaded = () => { loaded = true; - onComplete?.(); + onComplete?.(false); }; const setErrored = () => { errored = true; - onComplete?.(); + onComplete?.(true); }; function mount(elem: HTMLImageElement) { if (elem.complete) { loaded = true; - onComplete?.(); + onComplete?.(false); } } @@ -71,6 +73,7 @@ shadow && 'shadow-lg', (circle || !heightStyle) && 'aspect-square', border && 'border-[3px] border-immich-dark-primary/80 hover:border-immich-primary', + brokenAssetClass, ] .filter(Boolean) .join(' '), diff --git a/web/src/lib/components/assets/thumbnail/thumbnail.svelte b/web/src/lib/components/assets/thumbnail/thumbnail.svelte index 4e203470e3c..c1db6971d59 100644 --- a/web/src/lib/components/assets/thumbnail/thumbnail.svelte +++ b/web/src/lib/components/assets/thumbnail/thumbnail.svelte @@ -40,6 +40,7 @@ showArchiveIcon?: boolean; showStackedIcon?: boolean; imageClass?: ClassValue; + brokenAssetClass?: ClassValue; dimmed?: boolean; onClick?: ((asset: AssetResponseDto) => void) | undefined; onSelect?: ((asset: AssetResponseDto) => void) | undefined; @@ -66,6 +67,7 @@ onMouseEvent = undefined, handleFocus = undefined, imageClass = '', + brokenAssetClass = '', dimmed = false, }: Props = $props(); @@ -77,6 +79,7 @@ let focussableElement: HTMLElement | undefined = $state(); let mouseOver = $state(false); let loaded = $state(false); + let thumbError = $state(false); $effect(() => { if (focussed && document.activeElement !== focussableElement) { @@ -153,10 +156,10 @@ style:width="{width}px" style:height="{height}px" > - {#if !loaded && asset.thumbhash} + {#if (!loaded || thumbError) && asset.thumbhash} (loaded = true)} + onComplete={(errored) => ((loaded = true), (thumbError = errored))} /> {#if asset.type === AssetTypeEnum.Video}