feat: enhance website icon loading logic; implement error handling and timeout management

This commit is contained in:
shuaiplus
2026-05-09 23:46:33 +08:00
parent 7afb496eb0
commit 4e62c90700
4 changed files with 99 additions and 15 deletions
+2 -2
View File
@@ -227,6 +227,7 @@ export default function AuthViews(props: AuthViewsProps) {
value={props.loginValues.email}
autoComplete="username"
placeholder={props.authPlaceholder}
autoFocus
onInput={(e) => props.onChangeLogin({ ...props.loginValues, email: (e.currentTarget as HTMLInputElement).value })}
/>
</label>
@@ -236,7 +237,6 @@ export default function AuthViews(props: AuthViewsProps) {
autoComplete="current-password"
placeholder={props.authPlaceholder}
onInput={(v) => props.onChangeLogin({ ...props.loginValues, password: v })}
autoFocus
/>
<div className="auth-support-row">
<span />
@@ -244,7 +244,7 @@ export default function AuthViews(props: AuthViewsProps) {
type="button"
className="auth-link-btn"
onClick={props.onTogglePasswordHint}
disabled={loginBusy || !props.loginValues.email.trim()}
disabled={loginBusy || props.loginHintLoading || !props.loginValues.email.trim()}
>
{props.loginHintLoading
? t('txt_loading_password_hint')
+2 -9
View File
@@ -6,8 +6,6 @@ import {
beginWebsiteIconLoad,
getWebsiteIconImageUrl,
getWebsiteIconStatus,
markWebsiteIconErrored,
markWebsiteIconLoaded,
subscribeWebsiteIconStatus,
} from '@/lib/website-icon-cache';
import { demoBrandIconUrl } from '@/lib/demo-brand-icons';
@@ -28,7 +26,6 @@ export default function WebsiteIcon(props: WebsiteIconProps) {
const [shouldLoad, setShouldLoad] = useState(() => (host ? getWebsiteIconStatus(host) === 'loaded' : true));
const [status, setStatus] = useState(() => (host ? getWebsiteIconStatus(host) : 'idle'));
const [imageUrl, setImageUrl] = useState(() => (host ? getWebsiteIconImageUrl(host) : ''));
const [isLoadOwner, setIsLoadOwner] = useState(false);
const demoIconUrl = SHOULD_LOAD_DEMO_BRAND_ICONS && host ? demoBrandIconUrl(host) : '';
useEffect(() => {
@@ -36,14 +33,12 @@ export default function WebsiteIcon(props: WebsiteIconProps) {
setShouldLoad(true);
setStatus('idle');
setImageUrl('');
setIsLoadOwner(false);
return;
}
const nextStatus = getWebsiteIconStatus(host);
setShouldLoad(nextStatus === 'loaded');
setStatus(nextStatus);
setImageUrl(getWebsiteIconImageUrl(host));
setIsLoadOwner(false);
return subscribeWebsiteIconStatus(host, (next) => {
setStatus(next);
setImageUrl(getWebsiteIconImageUrl(host));
@@ -83,7 +78,7 @@ export default function WebsiteIcon(props: WebsiteIconProps) {
if (SHOULD_LOAD_DEMO_BRAND_ICONS) return;
if (demoIconUrl) return;
if (!host || !src || !shouldLoad || status !== 'idle') return;
setIsLoadOwner(beginWebsiteIconLoad(host, src));
beginWebsiteIconLoad(host, src);
}, [demoIconUrl, host, src, shouldLoad, status]);
if (demoIconUrl) {
@@ -104,7 +99,7 @@ export default function WebsiteIcon(props: WebsiteIconProps) {
return <span className="list-icon-fallback">{props.fallback ?? <Globe size={18} />}</span>;
}
const shouldRenderIconImage = !!imageUrl && (status === 'loaded' || (status === 'loading' && isLoadOwner));
const shouldRenderIconImage = !!imageUrl && status === 'loaded';
return (
<span className="list-icon-stack" ref={nodeRef}>
@@ -116,8 +111,6 @@ export default function WebsiteIcon(props: WebsiteIconProps) {
alt=""
loading="lazy"
decoding="async"
onLoad={() => markWebsiteIconLoaded(host, imageUrl)}
onError={() => markWebsiteIconErrored(host)}
/>
)}
</span>