mirror of
https://github.com/SamyRai/turash.git
synced 2025-12-26 23:01:33 +00:00
113 lines
2.5 KiB
TypeScript
113 lines
2.5 KiB
TypeScript
import React from 'react';
|
|
import { clsx } from 'clsx';
|
|
import { User } from 'lucide-react';
|
|
|
|
export interface AvatarProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
src?: string;
|
|
alt?: string;
|
|
name?: string;
|
|
size?: 'sm' | 'md' | 'lg' | 'xl';
|
|
fallback?: React.ReactNode;
|
|
status?: 'online' | 'offline' | 'away' | 'busy';
|
|
showStatus?: boolean;
|
|
}
|
|
|
|
const sizeClasses = {
|
|
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',
|
|
};
|
|
|
|
const statusSizeClasses = {
|
|
sm: 'h-2 w-2',
|
|
md: 'h-2.5 w-2.5',
|
|
lg: 'h-3 w-3',
|
|
xl: 'h-3.5 w-3.5',
|
|
};
|
|
|
|
const statusStyles = {
|
|
online: 'bg-success',
|
|
offline: 'bg-muted-foreground',
|
|
away: 'bg-warning',
|
|
busy: 'bg-destructive',
|
|
};
|
|
|
|
/**
|
|
* Avatar component with image, fallback, and status indicator
|
|
*/
|
|
export const Avatar = React.forwardRef<HTMLDivElement, AvatarProps>(
|
|
(
|
|
{
|
|
src,
|
|
alt,
|
|
name,
|
|
size = 'md',
|
|
fallback,
|
|
status = 'offline',
|
|
showStatus = false,
|
|
className,
|
|
...props
|
|
},
|
|
ref
|
|
) => {
|
|
const [imageError, setImageError] = React.useState(false);
|
|
|
|
const getInitials = (name: string) => {
|
|
return name
|
|
.split(' ')
|
|
.map((n) => n[0])
|
|
.join('')
|
|
.toUpperCase()
|
|
.slice(0, 2);
|
|
};
|
|
|
|
const displayFallback =
|
|
fallback ||
|
|
(name ? (
|
|
<span className="font-medium">{getInitials(name)}</span>
|
|
) : (
|
|
<User className="h-1/2 w-1/2" />
|
|
));
|
|
|
|
return (
|
|
<div
|
|
ref={ref}
|
|
className={clsx('relative inline-flex items-center justify-center', className)}
|
|
{...props}
|
|
>
|
|
<div
|
|
className={clsx(
|
|
'relative flex items-center justify-center rounded-full',
|
|
'bg-muted text-muted-foreground',
|
|
'overflow-hidden',
|
|
sizeClasses[size]
|
|
)}
|
|
>
|
|
{src && !imageError ? (
|
|
<img
|
|
src={src}
|
|
alt={alt || name || 'Avatar'}
|
|
className="h-full w-full object-cover"
|
|
onError={() => setImageError(true)}
|
|
/>
|
|
) : (
|
|
displayFallback
|
|
)}
|
|
</div>
|
|
{showStatus && (
|
|
<div
|
|
className={clsx(
|
|
'absolute bottom-0 right-0 rounded-full border-2 border-background',
|
|
statusStyles[status],
|
|
statusSizeClasses[size]
|
|
)}
|
|
aria-label={`Status: ${status}`}
|
|
/>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|
|
);
|
|
Avatar.displayName = 'Avatar';
|