rallly/components/poll/user-avatar.tsx
2022-04-12 07:14:28 +01:00

109 lines
2.5 KiB
TypeScript

import clsx from "clsx";
import * as React from "react";
import { stringToValue } from "utils/string-to-value";
export interface UserAvaterProps {
name: string;
className?: string;
size?: "default" | "large";
color?: string;
}
const UserAvatarContext =
React.createContext<((name: string) => string) | null>(null);
const colors = [
"bg-fuchsia-300",
"bg-purple-400",
"bg-indigo-400",
"bg-blue-400",
"bg-sky-400",
"bg-cyan-400",
"bg-teal-300",
"bg-emerald-300",
"bg-emerald-400",
"bg-teal-400",
"bg-cyan-400",
"bg-sky-400",
"bg-blue-400",
"bg-indigo-400",
"bg-purple-400",
"bg-fuchsia-400",
"bg-pink-400",
];
const defaultColor = "bg-slate-400";
export const UserAvatarProvider: React.VoidFunctionComponent<{
children?: React.ReactNode;
names: string[];
seed: string;
}> = ({ seed, children, names }) => {
const seedValue = React.useMemo(() => stringToValue(seed), [seed]);
const colorByName = React.useMemo(() => {
const res = {
"": defaultColor,
};
for (let i = 0; i < names.length; i++) {
const lastIndex = names.length - 1;
// start from the end since the names is "most recent" first.
const name = names[lastIndex - i].trim().toLowerCase();
const color = colors[(seedValue + i) % colors.length];
res[name] = color;
}
return res;
}, [names, seedValue]);
const getColor = React.useCallback(
(name: string) => {
const cachedColor = colorByName[name.toLowerCase()];
if (cachedColor) {
return cachedColor;
}
return defaultColor;
},
[colorByName],
);
return (
<UserAvatarContext.Provider value={getColor}>
{children}
</UserAvatarContext.Provider>
);
};
const UserAvater: React.VoidFunctionComponent<UserAvaterProps> = ({
name,
className,
color: colorOverride,
size = "default",
}) => {
const trimmedName = name.trim();
const getColor = React.useContext(UserAvatarContext);
if (!getColor) {
throw new Error("Forgot to wrap UserAvatarProvider");
}
const color = colorOverride ?? getColor(trimmedName);
return (
<span
className={clsx(
"inline-block w-5 h-5 text-white rounded-full shrink-0 text-center",
color,
{
"w-5 h-5 text-xs leading-5": size === "default",
"w-10 h-10 leading-10": size === "large",
},
className,
)}
title={name}
>
{trimmedName[0]?.toUpperCase()}
</span>
);
};
export default UserAvater;