92 lines
1.9 KiB
TypeScript
92 lines
1.9 KiB
TypeScript
/**
|
|
* Avatar Component
|
|
* User avatar with status indicator
|
|
*/
|
|
|
|
import React from 'react';
|
|
|
|
export interface AvatarProps {
|
|
src?: string;
|
|
alt?: string;
|
|
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
|
status?: 'online' | 'offline' | 'busy' | 'away';
|
|
name?: string;
|
|
showStatus?: boolean;
|
|
}
|
|
|
|
export const Avatar: React.FC<AvatarProps> = ({
|
|
src,
|
|
alt,
|
|
size = 'md',
|
|
status = 'offline',
|
|
name,
|
|
showStatus = false,
|
|
}) => {
|
|
const sizeClasses = {
|
|
xs: 'w-6 h-6 text-xs',
|
|
sm: 'w-8 h-8 text-sm',
|
|
md: 'w-10 h-10 text-base',
|
|
lg: 'w-12 h-12 text-lg',
|
|
xl: 'w-16 h-16 text-2xl',
|
|
};
|
|
|
|
const statusColors = {
|
|
online: 'bg-green-500',
|
|
offline: 'bg-gray-500',
|
|
busy: 'bg-red-500',
|
|
away: 'bg-yellow-500',
|
|
};
|
|
|
|
const statusSizes = {
|
|
xs: 'w-1.5 h-1.5',
|
|
sm: 'w-2 h-2',
|
|
md: 'w-2.5 h-2.5',
|
|
lg: 'w-3 h-3',
|
|
xl: 'w-4 h-4',
|
|
};
|
|
|
|
// Generate initials from name
|
|
const getInitials = (name?: string) => {
|
|
if (!name) return '?';
|
|
return name
|
|
.split(' ')
|
|
.map(n => n[0])
|
|
.join('')
|
|
.toUpperCase()
|
|
.slice(0, 2);
|
|
};
|
|
|
|
return (
|
|
<div className="relative inline-block">
|
|
{src ? (
|
|
<img
|
|
src={src}
|
|
alt={alt || name}
|
|
className={`${sizeClasses[size]} rounded-full object-cover border-2 border-gray-700`}
|
|
/>
|
|
) : (
|
|
<div
|
|
className={`
|
|
${sizeClasses[size]} rounded-full
|
|
bg-gradient-to-br from-purple-600 to-pink-600
|
|
flex items-center justify-center
|
|
font-semibold text-white
|
|
border-2 border-gray-700
|
|
`}
|
|
>
|
|
{getInitials(name)}
|
|
</div>
|
|
)}
|
|
|
|
{showStatus && (
|
|
<span
|
|
className={`
|
|
absolute bottom-0 right-0
|
|
${statusSizes[size]} ${statusColors[status]}
|
|
rounded-full border-2 border-gray-900
|
|
`}
|
|
/>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|