diff --git a/apps/readest-app/src/components/UserAvatar.tsx b/apps/readest-app/src/components/UserAvatar.tsx index 9ec19e27..622b1060 100644 --- a/apps/readest-app/src/components/UserAvatar.tsx +++ b/apps/readest-app/src/components/UserAvatar.tsx @@ -1,5 +1,6 @@ import clsx from 'clsx'; import Image from 'next/image'; +import { useEffect, useState } from 'react'; import { IconType } from 'react-icons'; interface UserAvatarProps { @@ -17,6 +18,41 @@ const UserAvatar: React.FC = ({ borderClassName, DefaultIcon, }) => { + const [cachedImageUrl, setCachedImageUrl] = useState(null); + + useEffect(() => { + if (!url) return; + + const storageKey = `avatar_${btoa(url).replace(/[^a-zA-Z0-9]/g, '')}`; + const cached = localStorage.getItem(storageKey); + if (cached) { + setCachedImageUrl(cached); + return; + } + + const cacheImage = async () => { + try { + const response = await fetch(url, { referrerPolicy: 'no-referrer' }); + const blob = await response.blob(); + const reader = new FileReader(); + reader.onloadend = () => { + const base64data = reader.result as string; + try { + localStorage.setItem(storageKey, base64data); + setCachedImageUrl(base64data); + } catch (e) { + console.warn('Failed to cache avatar in localStorage:', e); + } + }; + reader.readAsDataURL(blob); + } catch (error) { + console.error('Failed to cache avatar:', error); + } + }; + + cacheImage(); + }, [url]); + return (
= ({ {url ? (