veza/apps/web/src/components/ui/avatar.tsx

98 lines
2.7 KiB
TypeScript
Raw Normal View History

import * as React from "react"
import * as AvatarPrimitive from "@radix-ui/react-avatar"
import { cn } from "@/lib/utils"
// Primitives
const Avatar = React.forwardRef<
React.ElementRef<typeof AvatarPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Root>
>(({ className, ...props }, ref) => (
<AvatarPrimitive.Root
ref={ref}
className={cn(
"relative flex h-10 w-10 shrink-0 overflow-hidden rounded-full",
className
)}
{...props}
/>
))
Avatar.displayName = AvatarPrimitive.Root.displayName
const AvatarImage = React.forwardRef<
React.ElementRef<typeof AvatarPrimitive.Image>,
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Image>
>(({ className, ...props }, ref) => (
<AvatarPrimitive.Image
ref={ref}
className={cn("aspect-square h-full w-full object-cover", className)}
{...props}
/>
))
AvatarImage.displayName = AvatarPrimitive.Image.displayName
const AvatarFallback = React.forwardRef<
React.ElementRef<typeof AvatarPrimitive.Fallback>,
React.ComponentPropsWithoutRef<typeof AvatarPrimitive.Fallback>
>(({ className, ...props }, ref) => (
<AvatarPrimitive.Fallback
ref={ref}
className={cn(
"flex h-full w-full items-center justify-center rounded-full bg-muted",
className
)}
{...props}
/>
))
AvatarFallback.displayName = AvatarPrimitive.Fallback.displayName
// Smart Component (renamed to UserAvatar)
export interface UserAvatarProps {
src?: string | null;
alt?: string;
name?: string;
size?: 'sm' | 'md' | 'lg' | 'xl';
className?: string;
}
const sizeClasses = {
sm: 'w-8 h-8 text-xs',
md: 'w-12 h-12 text-sm',
lg: 'w-16 h-16 text-base',
xl: 'w-32 h-32 text-xl',
};
export function UserAvatar({ src, alt, name, size = 'md', className = '' }: UserAvatarProps) {
const [imageError, setImageError] = React.useState(false);
const sizeClass = sizeClasses[size];
const getInitials = (name?: string): string => {
if (!name) return '?';
const parts = name.trim().split(' ');
if (parts.length >= 2) {
return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();
}
return name.substring(0, 2).toUpperCase();
};
const initials = getInitials(name || alt);
return (
<Avatar className={cn(sizeClass, className)}>
{src && !imageError ? (
<AvatarImage
src={src}
alt={alt || name || 'Avatar'}
onLoadingStatusChange={(status) => {
if (status === 'error') setImageError(true);
}}
/>
) : null}
<AvatarFallback className="bg-gray-200 text-gray-600 font-medium">
{initials}
</AvatarFallback>
</Avatar>
);
}
export { Avatar, AvatarImage, AvatarFallback };