50 lines
1.4 KiB
TypeScript
50 lines
1.4 KiB
TypeScript
import { useMemo } from 'react';
|
|
|
|
interface AvatarProps {
|
|
src?: string;
|
|
name?: string;
|
|
size?: number;
|
|
className?: string;
|
|
}
|
|
|
|
export function Avatar({ src, name = '', size = 40, className = '' }: AvatarProps) {
|
|
const initials = useMemo(() => {
|
|
return name
|
|
.split(/\s+|(?=[A-Z])/)
|
|
.map(word => word[0])
|
|
.slice(0, 2)
|
|
.join('')
|
|
.toUpperCase();
|
|
}, [name]);
|
|
|
|
const backgroundColor = useMemo(() => {
|
|
let hash = 0;
|
|
for (let i = 0; i < name.length; i++) {
|
|
hash = name.charCodeAt(i) + ((hash << 5) - hash);
|
|
}
|
|
const hue = hash % 360;
|
|
return `hsl(${hue}, 70%, 50%)`;
|
|
}, [name]);
|
|
|
|
return (
|
|
<div
|
|
className={`relative rounded-full overflow-hidden ${className}`}
|
|
style={{ width: size, height: size }}
|
|
>
|
|
{src ? (
|
|
<img
|
|
src={src}
|
|
alt={name}
|
|
className="w-full h-full object-cover"
|
|
/>
|
|
) : (
|
|
<div
|
|
className="w-full h-full flex items-center justify-center text-white font-medium"
|
|
style={{ backgroundColor }}
|
|
>
|
|
<span style={{ fontSize: `${size * 0.4}px` }}>{initials}</span>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
} |