All checks were successful
Deploy with Docker Compose / deploy (push) Successful in 2m57s
71 lines
1.9 KiB
TypeScript
71 lines
1.9 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useEffect, useRef } from "react";
|
|
import { normalizeAvatarUrl } from "@/lib/avatars";
|
|
|
|
interface AvatarProps {
|
|
src: string | null | undefined;
|
|
username: string;
|
|
size?: "xs" | "sm" | "md" | "lg" | "xl" | "2xl";
|
|
className?: string;
|
|
borderClassName?: string;
|
|
fallbackText?: string;
|
|
}
|
|
|
|
const sizeClasses = {
|
|
xs: "w-6 h-6 text-[8px]",
|
|
sm: "w-8 h-8 text-[10px]",
|
|
md: "w-10 h-10 text-xs",
|
|
lg: "w-16 h-16 sm:w-20 sm:h-20 text-xl sm:text-2xl",
|
|
xl: "w-24 h-24 text-4xl",
|
|
"2xl": "w-32 h-32 text-4xl",
|
|
};
|
|
|
|
export default function Avatar({
|
|
src,
|
|
username,
|
|
size = "md",
|
|
className = "",
|
|
borderClassName = "",
|
|
fallbackText,
|
|
}: AvatarProps) {
|
|
const [avatarError, setAvatarError] = useState(false);
|
|
const prevSrcRef = useRef<string | null | undefined>(undefined);
|
|
|
|
// Reset error state when src changes
|
|
useEffect(() => {
|
|
if (src !== prevSrcRef.current) {
|
|
prevSrcRef.current = src;
|
|
// Reset error when src changes to allow retry
|
|
// eslint-disable-next-line react-hooks/set-state-in-effect
|
|
setAvatarError(false);
|
|
}
|
|
}, [src]);
|
|
|
|
const sizeClass = sizeClasses[size];
|
|
const normalizedSrc = normalizeAvatarUrl(src);
|
|
const displaySrc = normalizedSrc && !avatarError ? normalizedSrc : null;
|
|
const initial = fallbackText || username.charAt(0).toUpperCase();
|
|
|
|
return (
|
|
<div
|
|
className={`${sizeClass} rounded-full border overflow-hidden bg-black/60 flex items-center justify-center relative ${className} ${borderClassName}`}
|
|
>
|
|
{displaySrc ? (
|
|
<img
|
|
key={displaySrc}
|
|
src={displaySrc}
|
|
alt={username}
|
|
className="w-full h-full object-cover absolute inset-0"
|
|
onError={() => setAvatarError(true)}
|
|
/>
|
|
) : null}
|
|
<span
|
|
className={`text-pixel-gold font-bold ${displaySrc ? "hidden" : ""}`}
|
|
>
|
|
{initial}
|
|
</span>
|
|
</div>
|
|
);
|
|
}
|