Files
siftlode/frontend/src/components/ui/Avatar.tsx
T
peter 383d394e32 fix(ui): a picture that fails to load shows the card's own frame, then retries
A bare <img> sent a Referer that Google's image CDNs refuse and had no retry and no fallback, so a
Home shelf card showed the browser's broken-image mark. ui/RemoteImage gathers what Avatar, the
channel banner and the download rows had each hand-rolled: no Referer, up to three retries past the
browser's negative cache, the caller's fallback (by default the card's empty frame) instead of the
broken mark, the failure remembered by URL. Every picture now goes through it; a lint rule refuses
a bare <img>.
2026-10-14 20:51:08 +02:00

36 lines
1.0 KiB
TypeScript

import RemoteImage from "./RemoteImage";
// Avatar image with a graceful fallback: a neutral disc (optionally the name's initial) while there is
// no picture. The loading itself — no Referer for Google's avatar CDNs, the retry past the browser's
// negative cache, the failure remembered by URL so a recycled feed slot never paints one channel's
// initial over the next one's picture — is ui/RemoteImage's.
export default function Avatar({
src,
alt = "",
fallback,
className = "",
}: {
src?: string | null;
alt?: string;
fallback?: string; // a name/title; its first letter is shown when there's no image
className?: string;
}) {
const initial = fallback?.trim()?.[0]?.toUpperCase() ?? "";
return (
<RemoteImage
src={src}
alt={alt}
loading="lazy"
className={className}
fallback={
<div
className={`bg-card grid place-items-center font-semibold text-muted select-none ${className}`}
aria-hidden
>
{initial}
</div>
}
/>
);
}