From c1b8946875190cce61bdd4968ef1dd6fe24c19d9 Mon Sep 17 00:00:00 2001 From: SleeplessOne1917 <28871516+SleeplessOne1917@users.noreply.github.com> Date: Mon, 22 Apr 2024 15:54:04 +0000 Subject: [PATCH] Add fallback image for broken images (#2434) Co-authored-by: Dessalines --- src/assets/images/broken-image-fallback.png | Bin 0 -> 8399 bytes src/assets/symbols.svg | 7 +++- src/shared/components/common/pictrs-image.tsx | 36 +++++++++++++++--- 3 files changed, 35 insertions(+), 8 deletions(-) create mode 100644 src/assets/images/broken-image-fallback.png diff --git a/src/assets/images/broken-image-fallback.png b/src/assets/images/broken-image-fallback.png new file mode 100644 index 0000000000000000000000000000000000000000..84e828fbf71b6c024de45c64a08df31f27ccd180 GIT binary patch literal 8399 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 M2m`IEKOLU^53*)PTmS$7 literal 0 HcmV?d00001 diff --git a/src/assets/symbols.svg b/src/assets/symbols.svg index 87d63361..c9fda729 100644 --- a/src/assets/symbols.svg +++ b/src/assets/symbols.svg @@ -170,8 +170,11 @@ - - + + + + + diff --git a/src/shared/components/common/pictrs-image.tsx b/src/shared/components/common/pictrs-image.tsx index 9a5f450e..d942aba6 100644 --- a/src/shared/components/common/pictrs-image.tsx +++ b/src/shared/components/common/pictrs-image.tsx @@ -1,9 +1,10 @@ import classNames from "classnames"; -import { Component } from "inferno"; +import { Component, linkEvent } from "inferno"; import { UserService } from "../../services"; import { setIsoData } from "@utils/app"; import { IsoData } from "../../interfaces"; +import { getStaticDir } from "@utils/env"; const iconThumbnailSize = 96; const thumbnailSize = 256; @@ -20,13 +21,35 @@ interface PictrsImageProps { cardTop?: boolean; } -export class PictrsImage extends Component { +interface PictrsImageState { + src: string; +} + +function handleImgLoadError(i: PictrsImage) { + i.setState({ + src: `${getStaticDir()}/assets/images/broken-image-fallback.png`, + }); +} + +export class PictrsImage extends Component { private readonly isoData: IsoData = setIsoData(this.context); + state: PictrsImageState = { + src: this.props.src, + }; + + componentDidUpdate(prevProps: PictrsImageProps) { + if (prevProps.src !== this.props.src) { + this.setState({ src: this.props.src }); + } + } + render() { - const { src, icon, iconOverlay, banner, thumbnail, nsfw, pushup, cardTop } = + const { icon, iconOverlay, banner, thumbnail, nsfw, pushup, cardTop } = this.props; + const { src } = this.state; + const blurImage = nsfw && (UserService.Instance.myUserInfo?.local_user_view.local_user.blur_nsfw ?? @@ -58,6 +81,7 @@ export class PictrsImage extends Component { "avatar-pushup": pushup, "card-img-top": cardTop, })} + onError={linkEvent(this, handleImgLoadError)} /> ) @@ -70,14 +94,14 @@ export class PictrsImage extends Component { let url: URL | undefined; try { - url = new URL(this.props.src); + url = new URL(this.state.src); } catch { - return this.props.src; + return this.state.src; } // If there's no match, then it's not a pictrs image if (!url.pathname.includes("/pictrs/image/")) { - return this.props.src; + return this.state.src; } // Keeps original search params. Could probably do `url.search = ""` here.