|
'use client'; |
|
|
|
import * as AvatarPrimitive from '@radix-ui/react-avatar'; |
|
import * as React from 'react'; |
|
|
|
import { cn } from '@/lib/utils'; |
|
|
|
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', 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; |
|
|
|
export { Avatar, AvatarFallback, AvatarImage }; |
|
|
|
type AvatarProps = React.ComponentProps<typeof Avatar>; |
|
|
|
interface AvatarGroupProps extends React.ComponentProps<'div'> { |
|
children: React.ReactElement<AvatarProps>[]; |
|
max?: number; |
|
} |
|
|
|
export const AvatarGroup = ({ |
|
children, |
|
max, |
|
className, |
|
...props |
|
}: AvatarGroupProps) => { |
|
const totalAvatars = React.Children.count(children); |
|
const displayedAvatars = React.Children.toArray(children) |
|
.slice(0, max) |
|
.reverse(); |
|
const remainingAvatars = max ? Math.max(totalAvatars - max, 1) : 0; |
|
|
|
return ( |
|
<div |
|
className={cn('flex items-center flex-row-reverse', className)} |
|
{...props} |
|
> |
|
{remainingAvatars > 0 && ( |
|
<Avatar className="-ml-2 hover:z-10 relative ring-2 ring-background"> |
|
<AvatarFallback className="bg-muted-foreground text-white"> |
|
+{remainingAvatars} |
|
</AvatarFallback> |
|
</Avatar> |
|
)} |
|
{displayedAvatars.map((avatar, index) => { |
|
if (!React.isValidElement(avatar)) return null; |
|
|
|
return ( |
|
<div key={index} className="-ml-2 hover:z-10 relative"> |
|
{React.cloneElement(avatar as React.ReactElement<AvatarProps>, { |
|
className: 'ring-2 ring-background', |
|
})} |
|
</div> |
|
); |
|
})} |
|
</div> |
|
); |
|
}; |
|
|