diff --git a/client/src/components/Endpoints/URLIcon.tsx b/client/src/components/Endpoints/URLIcon.tsx index ddb62aaded..0e25ab175b 100644 --- a/client/src/components/Endpoints/URLIcon.tsx +++ b/client/src/components/Endpoints/URLIcon.tsx @@ -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 ( -
+
{altName setIsLoaded(true)} onError={handleImageError} - loading="lazy" decoding="async" width={Number(containerStyle.width) || 20} height={Number(containerStyle.height) || 20} /> + {!isLoaded && !imageError && ( +
); }, diff --git a/client/src/utils/agents.tsx b/client/src/utils/agents.tsx index e83a94c1aa..5793b127bb 100644 --- a/client/src/utils/agents.tsx +++ b/client/src/utils/agents.tsx @@ -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 &&