feat: implement UserAvatar component with dynamic color assignment and memoization

This commit is contained in:
Marco Pedone 2026-03-13 16:11:35 +01:00
parent d18aee8a95
commit 1e3a1e390b

View file

@ -1,6 +1,7 @@
import React from "react";
import { isColorDark } from "~/lib/color";
import { cn, getHexColorFromString, getInitials } from "~/lib/utils";
import type { UsersId } from "~/schemas/public/Users";
import { Facehash, type FacehashProps } from "./facehash/facehash";
const colorOptions = new Map<string, string>();
@ -39,7 +40,8 @@ export const UserAvatarOld = ({
);
};
*/
export const UserAvatar = (
/*
export const UserAvatar2 = (
props: {
userId: UsersId;
username?: string;
@ -59,7 +61,17 @@ export const UserAvatar = (
<Facehash
{...rest}
className={cn("size-20 rounded-full", rest.className)}
colors={[
colors={user_colors}
initialsCount={2}
intensity3d="none"
name={value}
showInitial={username !== undefined}
variant="solid"
/>
);
};
*/
const user_colors = [
"#2D3436",
"#535C68",
"#636E72",
@ -84,12 +96,54 @@ export const UserAvatar = (
"#A29BFE",
"#A55EEA",
"#6D214F",
]}
initialsCount={2}
intensity3d="none"
name={value}
showInitial={username !== undefined}
variant="solid"
/>
];
function stringHash(str: string): number {
let hash = 0;
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i);
hash = (hash << 5) - hash + char;
hash &= hash; // Convert to 32bit integer
}
return Math.abs(hash);
}
export const UserAvatar = (
props: {
userId: UsersId;
username?: string;
} & React.HTMLAttributes<HTMLDivElement>,
) => {
const { userId, username, className, ...rest } = props;
const value = `${username && getInitials(username)}${userId}`;
const colorIndex = React.useMemo(() => {
const hash = stringHash(value);
const colorsLength = user_colors.length ?? 1;
const _colorIndex = hash % colorsLength;
return _colorIndex;
}, [value]);
const userColor = user_colors[colorIndex];
return (
<div
{...rest}
className={cn(
"@container flex size-20 items-center justify-center rounded-full",
className,
)}
style={{
backgroundColor: userColor,
color: userColor
? isColorDark(userColor, 180)
? "#FFFFFF"
: "#oklch(0.24 0 0)"
: "#oklch(0.24 0 0)",
}}
>
<span className="text-[40cqw] tracking-wide">
{username && getInitials(username)}
</span>
</div>
);
};