fix: preview image fallback

Signed-off-by: Innei <i@innei.in>
This commit is contained in:
Innei 2024-09-06 22:05:14 +08:00
parent 4b48202ea7
commit 7410ca229a
No known key found for this signature in database
GPG Key ID: 0F62D33977F021F7
3 changed files with 47 additions and 13 deletions

View File

@ -86,6 +86,7 @@ const MediaImpl: FC<MediaProps> = ({
{
url: src,
type,
fallbackUrl: imgSrc,
},
],
0,
@ -206,7 +207,10 @@ const MediaImpl: FC<MediaProps> = ({
return <FallbackMedia {...props} />
}
return (
<span className={cn("block overflow-hidden rounded", className)} style={style}>
<span
className={cn("block overflow-hidden rounded", className)}
style={style}
>
{InnerContent}
</span>
)

View File

@ -1,14 +1,14 @@
import { useCallback } from "react"
import type { MediaModel } from "src/hono"
import { useModalStack } from "../modal/stacked/hooks"
import { NoopChildren } from "../modal/stacked/utils"
import type { PreviewMediaProps } from "./preview-media"
import { PreviewMediaContent } from "./preview-media"
export const usePreviewMedia = () => {
const { present } = useModalStack()
return useCallback(
(media: MediaModel[], initialIndex = 0) => {
(media: PreviewMediaProps[], initialIndex = 0) => {
present({
content: () => (
<div className="relative size-full">

View File

@ -74,8 +74,12 @@ const Wrapper: Component<{
</div>
)
}
export interface PreviewMediaProps extends MediaModel {
fallbackUrl?: string
}
export const PreviewMediaContent: FC<{
media: MediaModel[]
media: PreviewMediaProps[]
initialIndex?: number
}> = ({ media, initialIndex = 0 }) => {
const [currentMedia, setCurrentMedia] = useState(media[initialIndex])
@ -143,6 +147,7 @@ export const PreviewMediaContent: FC<{
/>
) : (
<FallbackableImage
fallbackUrl={media[0].fallbackUrl}
className="size-full object-contain"
alt="cover"
src={src}
@ -241,6 +246,7 @@ export const PreviewMediaContent: FC<{
/>
) : (
<FallbackableImage
fallbackUrl={med.fallbackUrl}
onContextMenu={(e) => handleContextMenu(med.url, e)}
className="size-full object-contain"
alt="cover"
@ -258,23 +264,47 @@ export const PreviewMediaContent: FC<{
const FallbackableImage: FC<
Omit<React.ImgHTMLAttributes<HTMLImageElement>, "src"> & {
src: string
fallbackUrl?: string
}
> = ({ src, onError, ...props }) => {
> = ({ src, onError, fallbackUrl, ...props }) => {
const [currentSrc, setCurrentSrc] = useState(() => replaceImgUrlIfNeed(src))
const [isAllError, setIsAllError] = useState(false)
const [currentState, setCurrentState] = useState<
"proxy" | "origin" | "fallback"
>(() => (currentSrc === src ? "origin" : "proxy"))
const handleError = useCallback(
(e) => {
if (currentSrc !== src) {
setCurrentSrc(src)
} else {
onError?.(e as any)
setIsAllError(true)
() => {
switch (currentState) {
case "proxy": {
if (currentSrc !== src) {
setCurrentSrc(src)
setCurrentState("origin")
} else {
if (fallbackUrl) {
setCurrentSrc(fallbackUrl)
setCurrentState("fallback")
}
}
break
}
case "origin": {
if (fallbackUrl) {
setCurrentSrc(fallbackUrl)
setCurrentState("fallback")
}
break
}
case "fallback": {
setIsAllError(true)
}
}
},
[currentSrc, onError, src],
[currentSrc, currentState, fallbackUrl, src],
)
return (
<Fragment>
{!isAllError && <img src={currentSrc} onError={handleError} {...props} />}