feat: support optimize images
This commit is contained in:
@@ -1,38 +1,45 @@
|
||||
import { type ComponentProps, useMemo, useState } from "react";
|
||||
import { useInject } from "@/infra/di/inject";
|
||||
import { DOCUMENT } from "@/infra/platform/injection";
|
||||
import { type ComponentProps, useMemo } from "react";
|
||||
|
||||
const URL_PARSE_REGEX = /^([^?#]*)(\?[^#]*)?(#.*)?$/;
|
||||
|
||||
function parseURL(url: string) {
|
||||
const match = url.match(URL_PARSE_REGEX);
|
||||
|
||||
if (!match) {
|
||||
return { other: url, search: "", hash: "" };
|
||||
}
|
||||
|
||||
return {
|
||||
other: match[1] || "",
|
||||
search: match[2] || "",
|
||||
hash: match[3] || "",
|
||||
};
|
||||
}
|
||||
|
||||
export type ImgProps = Omit<ComponentProps<"img">, "alt"> &
|
||||
Required<Pick<ComponentProps<"img">, "alt">> & {
|
||||
optimize?: boolean;
|
||||
optimize?: "accept";
|
||||
};
|
||||
|
||||
const LEGACY_IMAGE_REGEX = /\.(jpg|jpeg|png|gif|svg)$/;
|
||||
export const Img = ({
|
||||
src: propsSrc,
|
||||
optimize = "accept",
|
||||
...props
|
||||
}: ImgProps) => {
|
||||
const document = useInject(DOCUMENT);
|
||||
const src = useMemo(() => {
|
||||
const baseURI = document?.baseURI;
|
||||
if (!propsSrc || !baseURI) {
|
||||
return propsSrc;
|
||||
}
|
||||
const { other, search, hash } = parseURL(propsSrc);
|
||||
const searchParams = new URLSearchParams(search);
|
||||
searchParams.set("optimize", optimize);
|
||||
return `${other}?${searchParams.toString()}${hash}`;
|
||||
}, [propsSrc, optimize, document?.baseURI]);
|
||||
|
||||
export const Img = (props: ImgProps) => {
|
||||
const src = props.src;
|
||||
|
||||
const isLegacy = useMemo(() => src?.match(LEGACY_IMAGE_REGEX), [src]);
|
||||
const [isError, setIsError] = useState(false);
|
||||
|
||||
if (!src) {
|
||||
// biome-ignore lint/nursery/noImgElement: <explanation>
|
||||
return <img {...props} alt={props.alt} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<picture {...props}>
|
||||
{isLegacy && !isError && (
|
||||
<>
|
||||
<source
|
||||
srcSet={src.replace(LEGACY_IMAGE_REGEX, ".webp")}
|
||||
type="image/webp"
|
||||
/>
|
||||
<source
|
||||
srcSet={src.replace(LEGACY_IMAGE_REGEX, ".avif")}
|
||||
type="image/avif"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<img {...props} alt={props.alt} onError={() => setIsError(true)} />
|
||||
</picture>
|
||||
);
|
||||
// biome-ignore lint/nursery/noImgElement: <explanation>
|
||||
return <img {...props} alt={props.alt} src={src} />;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user