feat: implement UserAvatar component with dynamic color assignment and memoization
This commit is contained in:
parent
d18aee8a95
commit
1e3a1e390b
1 changed files with 82 additions and 28 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
|
import React from "react";
|
||||||
|
import { isColorDark } from "~/lib/color";
|
||||||
import { cn, getHexColorFromString, getInitials } from "~/lib/utils";
|
import { cn, getHexColorFromString, getInitials } from "~/lib/utils";
|
||||||
import type { UsersId } from "~/schemas/public/Users";
|
import type { UsersId } from "~/schemas/public/Users";
|
||||||
import { Facehash, type FacehashProps } from "./facehash/facehash";
|
|
||||||
|
|
||||||
const colorOptions = new Map<string, string>();
|
const colorOptions = new Map<string, string>();
|
||||||
|
|
||||||
|
|
@ -39,7 +40,8 @@ export const UserAvatarOld = ({
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
*/
|
*/
|
||||||
export const UserAvatar = (
|
/*
|
||||||
|
export const UserAvatar2 = (
|
||||||
props: {
|
props: {
|
||||||
userId: UsersId;
|
userId: UsersId;
|
||||||
username?: string;
|
username?: string;
|
||||||
|
|
@ -59,7 +61,17 @@ export const UserAvatar = (
|
||||||
<Facehash
|
<Facehash
|
||||||
{...rest}
|
{...rest}
|
||||||
className={cn("size-20 rounded-full", rest.className)}
|
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",
|
"#2D3436",
|
||||||
"#535C68",
|
"#535C68",
|
||||||
"#636E72",
|
"#636E72",
|
||||||
|
|
@ -84,12 +96,54 @@ export const UserAvatar = (
|
||||||
"#A29BFE",
|
"#A29BFE",
|
||||||
"#A55EEA",
|
"#A55EEA",
|
||||||
"#6D214F",
|
"#6D214F",
|
||||||
]}
|
];
|
||||||
initialsCount={2}
|
|
||||||
intensity3d="none"
|
function stringHash(str: string): number {
|
||||||
name={value}
|
let hash = 0;
|
||||||
showInitial={username !== undefined}
|
for (let i = 0; i < str.length; i++) {
|
||||||
variant="solid"
|
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>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue