admin/components/consumer/UserAvatar.tsx
alisaza e1eaf5eff5 feat: initial ghabilee-admin backoffice app
Extract admin dashboard from ghabilee-frontend2 into a dedicated Next.js
app for backoffice.ghabilee.ir (no SEO indexing / Clarity).
2026-09-05 13:12:59 +03:30

63 lines
1.7 KiB
TypeScript

'use client'
/**
* UserAvatar — circular or square avatar with UserFillIcon fallback.
*
* Purpose
* - Shared avatar for host cards, chat, profile, and follow lists.
* - Empty/missing `src` shows a neutral background + UserFillIcon (decorative).
*
* Agent notes
* - Pass explicit `size` in pixels; Next/Image uses `fill` inside that box.
* - Prefer this over ad-hoc Image + fallback icon pairs in consumer UI.
*/
import Image from 'next/image'
import UserFillIcon from '@/components/icons/UserFillIcon'
import { cn } from '@/lib/cn'
export type UserAvatarVariant = 'circle' | 'square'
interface UserAvatarProps {
src?: string | null
alt: string
variant: UserAvatarVariant
/** Pixel size (width and height). */
size: number
className?: string
/** Extra class on the fallback UserFillIcon. */
iconClassName?: string
}
const UserAvatar = ({ src, alt, variant, size, className, iconClassName }: UserAvatarProps) => {
const trimmed = src?.trim() || null
const radiusClass = variant === 'circle' ? 'rounded-full' : 'rounded-[12px]'
return (
<span
aria-hidden={trimmed ? undefined : true}
className={cn(
'relative inline-flex shrink-0 items-center justify-center overflow-hidden bg-secondary-45 text-secondary-10',
radiusClass,
className
)}
style={{ width: size, height: size }}
>
{trimmed ? (
<Image
fill
alt={alt}
className="object-cover"
sizes={`${size}px`}
src={trimmed}
/>
) : (
<UserFillIcon className={cn(size >= 64 ? 'size-8' : 'size-5', iconClassName)} />
)}
</span>
)
}
export default UserAvatar