mirror of
https://github.com/lukevella/rallly.git
synced 2025-05-20 20:36:19 +02:00
First public commit
This commit is contained in:
commit
e05cd62e53
228 changed files with 17717 additions and 0 deletions
109
components/poll/user-avatar.tsx
Normal file
109
components/poll/user-avatar.tsx
Normal file
|
@ -0,0 +1,109 @@
|
|||
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;
|
Loading…
Add table
Add a link
Reference in a new issue