sendou.ink/app/components/Avatar.tsx
Kalle 77978c450f
Some checks are pending
E2E Tests / e2e (push) Waiting to run
Tests and checks on push / run-checks-and-tests (push) Waiting to run
Updates translation progress / update-translation-progress-issue (push) Waiting to run
New user page (#2812)
Co-authored-by: hfcRed <hfcred@gmx.net>
2026-02-16 19:26:57 +02:00

64 lines
1.4 KiB
TypeScript

import clsx from "clsx";
import * as React from "react";
import type { Tables } from "~/db/tables";
import { BLANK_IMAGE_URL, discordAvatarUrl } from "~/utils/urls";
const dimensions = {
xxxs: 16,
xxxsm: 20,
xxs: 24,
xs: 36,
sm: 44,
xsm: 62,
md: 81,
xmd: 94,
lg: 125,
} as const;
export function Avatar({
user,
url,
size = "sm",
className,
alt = "",
...rest
}: {
user?: Pick<Tables["User"], "discordId" | "discordAvatar">;
url?: string;
className?: string;
alt?: string;
size: keyof typeof dimensions;
} & React.ButtonHTMLAttributes<HTMLImageElement>) {
const [isErrored, setIsErrored] = React.useState(false);
// TODO: just show text... my profile?
// TODO: also show this if discordAvatar is stale and 404's
// biome-ignore lint/correctness/useExhaustiveDependencies: every avatar error state is unique and we want to avoid using key on every avatar
React.useEffect(() => {
setIsErrored(false);
}, [user?.discordAvatar]);
const src =
url ??
(user?.discordAvatar && !isErrored
? discordAvatarUrl({
discordAvatar: user.discordAvatar,
discordId: user.discordId,
size: size === "lg" || size === "xmd" ? "lg" : "sm",
})
: BLANK_IMAGE_URL); // avoid broken image placeholder
return (
<img
className={clsx("avatar", className)}
src={src}
alt={alt}
title={alt ? alt : undefined}
width={dimensions[size]}
height={dimensions[size]}
onError={() => setIsErrored(true)}
{...rest}
/>
);
}