Icon source fallbacks

This commit is contained in:
Dustin Brett 2023-11-16 21:38:03 -08:00
parent 3cdce71150
commit da94d68318
3 changed files with 67 additions and 14 deletions

View File

@ -1,7 +1,16 @@
import { forwardRef, memo, useEffect, useMemo, useState } from "react";
import styled from "styled-components";
import { ICON_CACHE, YT_ICON_CACHE } from "utils/constants";
import { cleanUpBufferUrl, imageSrc, imageSrcs } from "utils/functions";
import {
ICON_CACHE,
SUPPORTED_ICON_PIXEL_RATIOS,
YT_ICON_CACHE,
} from "utils/constants";
import {
cleanUpBufferUrl,
createFallbackSrcSet,
imageSrc,
imageSrcs,
} from "utils/functions";
export type IconProps = {
$eager?: boolean;
@ -40,8 +49,6 @@ const StyledIcon = styled.img.attrs<StyledIconProps>(
visibility: ${({ $loaded }) => ($loaded ? "visible" : "hidden")};
`;
const SUPPORTED_PIXEL_RATIOS = [3, 2, 1];
const Icon = forwardRef<
HTMLImageElement,
IconProps & React.ImgHTMLAttributes<HTMLImageElement>
@ -83,19 +90,28 @@ const Icon = forwardRef<
onError={({ target }) => {
const { currentSrc = "" } = (target as HTMLImageElement) || {};
if (currentSrc && !failedUrls.includes(currentSrc)) {
try {
const { pathname } = new URL(currentSrc);
setFailedUrls((currentFailedUrls) => [
...currentFailedUrls,
pathname,
]);
if (pathname && !failedUrls.includes(pathname)) {
setFailedUrls((currentFailedUrls) => [
...currentFailedUrls,
pathname,
]);
}
} catch {
// Ignore failure to log failed url
}
}}
onLoad={() => setLoaded(true)}
src={isStaticIcon ? src : imageSrc(src, imgSize, 1, ".png")}
srcSet={
isStaticIcon ? undefined : imageSrcs(src, imgSize, ".png", failedUrls)
isStaticIcon
? undefined
: imageSrcs(src, imgSize, ".png", failedUrls) ||
(failedUrls.length === 0
? ""
: createFallbackSrcSet(src, failedUrls))
}
{...componentProps}
{...dimensionProps}
@ -105,7 +121,7 @@ const Icon = forwardRef<
return (
<picture>
{!isStaticIcon &&
SUPPORTED_PIXEL_RATIOS.map((ratio) => {
SUPPORTED_ICON_PIXEL_RATIOS.map((ratio) => {
const srcSet = imageSrc(src, imgSize, ratio, ".webp");
const mediaRatio = ratio - 0.99;

View File

@ -302,6 +302,10 @@ export const MAX_RES_ICON_OVERRIDE: Record<string, [number, number]> = {
videos: [16, 32],
};
export const SUPPORTED_ICON_PIXEL_RATIOS = [3, 2, 1];
export const SUPPORTED_ICON_SIZES = [16, 32, 48, 96, 144];
export const MAX_ICON_SIZE = 144;
export const DEFAULT_TEXT_FILE_SAVE_PATH = `${DESKTOP_PATH}/Untitled.txt`;

View File

@ -12,13 +12,16 @@ import { basename, dirname, extname, join } from "path";
import {
DEFAULT_LOCALE,
HIGH_PRIORITY_REQUEST,
ICON_PATH,
ICON_RES_MAP,
MAX_ICON_SIZE,
MAX_RES_ICON_OVERRIDE,
ONE_TIME_PASSIVE_EVENT,
SMALLEST_JXL_FILE,
SUPPORTED_ICON_SIZES,
TASKBAR_HEIGHT,
TIMESTAMP_DATE_FORMAT,
USER_ICON_PATH,
} from "utils/constants";
export const GOOGLE_SEARCH_QUERY = "https://www.google.com/search?igu=1&q=";
@ -113,14 +116,44 @@ export const imageSrcs = (
extension: string,
failedUrls?: string[]
): string => {
return [
const srcs = [
imageSrc(imagePath, size, 1, extension),
imageSrc(imagePath, size, 2, extension),
imageSrc(imagePath, size, 3, extension),
]
.filter(
(url) => !failedUrls?.length || failedUrls?.includes(url.split(" ")[0])
.filter((url) => failedUrls?.includes(url.split(" ")[0]))
.join(", ");
return failedUrls?.includes(srcs) ? "" : srcs;
};
export const createFallbackSrcSet = (
src: string,
failedUrls: string[]
): string => {
const failedSizes = new Set(
new Set(
failedUrls.map((failedUrl) => {
const fileName = basename(src, extname(src));
return Number(
failedUrl
.replace(`${ICON_PATH}/`, "")
.replace(`${USER_ICON_PATH}/`, "")
.replace(`/${fileName}.png`, "")
.replace(`/${fileName}.webp`, "")
.split("x")[0]
);
})
)
);
const possibleSizes = SUPPORTED_ICON_SIZES.filter(
(size) => !failedSizes.has(size)
);
return possibleSizes
.map((size) => imageSrc(src, size, 1, extname(src)))
.reverse()
.join(", ");
};