57 lines
1.4 KiB
TypeScript
57 lines
1.4 KiB
TypeScript
import { cn } from '@/utils/cn'
|
|
import { colorFromString, initials } from '@/utils/misc'
|
|
|
|
export function Avatar({
|
|
name,
|
|
src,
|
|
size = 'md',
|
|
className,
|
|
online,
|
|
}: {
|
|
name: string
|
|
src?: string
|
|
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'
|
|
className?: string
|
|
online?: boolean
|
|
}) {
|
|
const sizes = {
|
|
xs: 'h-6 w-6 text-[10px]',
|
|
sm: 'h-8 w-8 text-xs',
|
|
md: 'h-10 w-10 text-sm',
|
|
lg: 'h-12 w-12 text-base',
|
|
xl: 'h-16 w-16 text-lg',
|
|
}
|
|
return (
|
|
<span className={cn('relative inline-flex shrink-0', className)}>
|
|
<span
|
|
className={cn(
|
|
'flex items-center justify-center rounded-full font-medium',
|
|
sizes[size],
|
|
colorFromString(name || '?'),
|
|
)}
|
|
>
|
|
{src ? (
|
|
<img
|
|
src={src}
|
|
alt={name}
|
|
className="h-full w-full rounded-full object-cover"
|
|
onError={(event) => {
|
|
event.currentTarget.style.display = 'none'
|
|
event.currentTarget.nextElementSibling?.classList.remove('hidden')
|
|
}}
|
|
/>
|
|
) : null}
|
|
<span className={cn(src && 'hidden')}>{initials(name)}</span>
|
|
</span>
|
|
{online !== undefined && (
|
|
<span
|
|
className={cn(
|
|
'absolute bottom-0 right-0 h-2.5 w-2.5 rounded-full border-2 border-card',
|
|
online ? 'bg-emerald-500' : 'bg-gray-300',
|
|
)}
|
|
/>
|
|
)}
|
|
</span>
|
|
)
|
|
}
|