mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-16 16:30:15 +01:00
feat: Enhance image loading and error handling in URLIcon and LazyAgentAvatar components
This commit is contained in:
parent
087ffa972e
commit
96ea589881
2 changed files with 68 additions and 9 deletions
|
|
@ -1,5 +1,6 @@
|
|||
import React, { memo, useState } from 'react';
|
||||
import React, { memo, useState, useEffect } from 'react';
|
||||
import { AlertCircle } from 'lucide-react';
|
||||
import { Skeleton } from '@librechat/client';
|
||||
import { icons } from '~/hooks/Endpoint/Icons';
|
||||
|
||||
export const URLIcon = memo(
|
||||
|
|
@ -19,9 +20,34 @@ export const URLIcon = memo(
|
|||
endpoint?: string;
|
||||
}) => {
|
||||
const [imageError, setImageError] = useState(false);
|
||||
const [isLoaded, setIsLoaded] = useState(() => {
|
||||
// Check if image is already cached
|
||||
if (typeof window !== 'undefined' && iconURL) {
|
||||
const img = new Image();
|
||||
img.src = iconURL;
|
||||
return img.complete && img.naturalWidth > 0;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
// When URL changes, check if new image is cached
|
||||
if (iconURL) {
|
||||
const img = new Image();
|
||||
img.src = iconURL;
|
||||
if (img.complete && img.naturalWidth > 0) {
|
||||
setIsLoaded(true);
|
||||
setImageError(false);
|
||||
} else {
|
||||
setIsLoaded(false);
|
||||
setImageError(false);
|
||||
}
|
||||
}
|
||||
}, [iconURL]);
|
||||
|
||||
const handleImageError = () => {
|
||||
setImageError(true);
|
||||
setIsLoaded(false);
|
||||
};
|
||||
|
||||
const DefaultIcon: React.ElementType =
|
||||
|
|
@ -46,18 +72,29 @@ export const URLIcon = memo(
|
|||
}
|
||||
|
||||
return (
|
||||
<div className={className} style={containerStyle}>
|
||||
<div className={`${className} relative`} style={containerStyle}>
|
||||
<img
|
||||
src={iconURL}
|
||||
alt={altName ?? 'Icon'}
|
||||
style={imageStyle}
|
||||
style={{
|
||||
...imageStyle,
|
||||
opacity: isLoaded ? 1 : 0,
|
||||
transition: 'opacity 0.2s ease-in-out',
|
||||
}}
|
||||
className="object-cover"
|
||||
onLoad={() => setIsLoaded(true)}
|
||||
onError={handleImageError}
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
width={Number(containerStyle.width) || 20}
|
||||
height={Number(containerStyle.height) || 20}
|
||||
/>
|
||||
{!isLoaded && !imageError && (
|
||||
<Skeleton
|
||||
className="absolute inset-0 rounded-full"
|
||||
style={{ width: containerStyle.width, height: containerStyle.height }}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -32,10 +32,28 @@ const LazyAgentAvatar = ({
|
|||
alt: string;
|
||||
imgClass: string;
|
||||
}) => {
|
||||
const [isLoaded, setIsLoaded] = useState(false);
|
||||
const [isLoaded, setIsLoaded] = useState(() => {
|
||||
// Check if image is already cached by creating a test image
|
||||
if (typeof window !== 'undefined') {
|
||||
const img = new Image();
|
||||
img.src = url;
|
||||
return img.complete && img.naturalWidth > 0;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
const [hasError, setHasError] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setIsLoaded(false);
|
||||
// When URL changes, check if new image is cached
|
||||
const img = new Image();
|
||||
img.src = url;
|
||||
if (img.complete && img.naturalWidth > 0) {
|
||||
setIsLoaded(true);
|
||||
setHasError(false);
|
||||
} else {
|
||||
setIsLoaded(false);
|
||||
setHasError(false);
|
||||
}
|
||||
}, [url]);
|
||||
|
||||
return (
|
||||
|
|
@ -44,15 +62,19 @@ const LazyAgentAvatar = ({
|
|||
src={url}
|
||||
alt={alt}
|
||||
className={imgClass}
|
||||
loading="lazy"
|
||||
onLoad={() => setIsLoaded(true)}
|
||||
onError={() => setIsLoaded(false)}
|
||||
onError={() => {
|
||||
setIsLoaded(false);
|
||||
setHasError(true);
|
||||
}}
|
||||
style={{
|
||||
opacity: isLoaded ? 1 : 0,
|
||||
transition: 'opacity 0.2s ease-in-out',
|
||||
}}
|
||||
/>
|
||||
{!isLoaded && <Skeleton className="absolute inset-0 rounded-full" aria-hidden="true" />}
|
||||
{!isLoaded && !hasError && (
|
||||
<Skeleton className="absolute inset-0 rounded-full" aria-hidden="true" />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue