index.tsx raw

   1  import { HoverCard, HoverCardContent, HoverCardTrigger } from '@/components/ui/hover-card'
   2  import { Skeleton } from '@/components/ui/skeleton'
   3  import { useFetchProfile } from '@/hooks'
   4  import { toProfile } from '@/lib/link'
   5  import { generateImageByPubkey } from '@/lib/pubkey'
   6  import { cn, isTouchDevice } from '@/lib/utils'
   7  import { SecondaryPageLink } from '@/PageManager'
   8  import { useMemo } from 'react'
   9  import Image from '../Image'
  10  import ProfileCard from '../ProfileCard'
  11  
  12  const UserAvatarSizeCnMap = {
  13    large: 'w-24 h-24',
  14    big: 'w-16 h-16',
  15    semiBig: 'w-12 h-12',
  16    normal: 'w-10 h-10',
  17    medium: 'w-9 h-9',
  18    small: 'w-7 h-7',
  19    xSmall: 'w-5 h-5',
  20    tiny: 'w-4 h-4'
  21  }
  22  
  23  export default function UserAvatar({
  24    userId,
  25    className,
  26    size = 'normal'
  27  }: {
  28    userId: string
  29    className?: string
  30    size?: 'large' | 'big' | 'semiBig' | 'normal' | 'medium' | 'small' | 'xSmall' | 'tiny'
  31  }) {
  32    const supportTouch = useMemo(() => isTouchDevice(), [])
  33  
  34    const trigger = (
  35      <SecondaryPageLink to={toProfile(userId)} onClick={(e) => e.stopPropagation()}>
  36        <SimpleUserAvatar userId={userId} size={size} className={className} />
  37      </SecondaryPageLink>
  38    )
  39  
  40    if (supportTouch) {
  41      return trigger
  42    }
  43  
  44    return (
  45      <HoverCard>
  46        <HoverCardTrigger>{trigger}</HoverCardTrigger>
  47        <HoverCardContent className="w-72">
  48          <ProfileCard userId={userId} />
  49        </HoverCardContent>
  50      </HoverCard>
  51    )
  52  }
  53  
  54  export function SimpleUserAvatar({
  55    userId,
  56    size = 'normal',
  57    className,
  58    onClick
  59  }: {
  60    userId: string
  61    size?: 'large' | 'big' | 'semiBig' | 'normal' | 'medium' | 'small' | 'xSmall' | 'tiny'
  62    className?: string
  63    onClick?: (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => void
  64  }) {
  65    const { profile } = useFetchProfile(userId)
  66    const defaultAvatar = useMemo(
  67      () => (profile?.pubkey ? generateImageByPubkey(profile.pubkey) : ''),
  68      [profile]
  69    )
  70  
  71    if (!profile) {
  72      return (
  73        <Skeleton className={cn('shrink-0', UserAvatarSizeCnMap[size], 'rounded-full', className)} />
  74      )
  75    }
  76    const { avatar, pubkey } = profile || {}
  77  
  78    return (
  79      <Image
  80        image={{ url: avatar ?? defaultAvatar, pubkey }}
  81        errorPlaceholder={defaultAvatar}
  82        className="object-cover object-center"
  83        classNames={{
  84          wrapper: cn('shrink-0 rounded-full bg-background', UserAvatarSizeCnMap[size], className)
  85        }}
  86        onClick={onClick}
  87      />
  88    )
  89  }
  90