{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "profile-picture",
  "type": "registry:block",
  "title": "Profile Picture",
  "description": "Displays user profile pictures with NFT support, hex decoding, and fallbacks.",
  "files": [
    {
      "path": "src/components/deso/profile-picture.tsx",
      "content": "'use client';\n\nimport React, { useState, useEffect } from 'react';\nimport { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';\nimport { Skeleton } from '@/components/ui/skeleton';\nimport { useProfile } from '@/hooks/useProfile';\nimport { cn, getUsernameInitial, getSingleProfilePictureUrl, buildProfilePictureUrl } from '@/lib/utils/deso';\nimport { Profile } from '@/lib/schemas/deso';\n\n// Size configurations\nconst sizeConfig = {\n  xxs: { avatar: 'h-4 w-4', text: 'text-xs' },\n  xs: { avatar: 'h-6 w-6', text: 'text-xs' },\n  sm: { avatar: 'h-8 w-8', text: 'text-sm' },\n  md: { avatar: 'h-10 w-10', text: 'text-base' },\n  lg: { avatar: 'h-12 w-12', text: 'text-lg' },\n  xl: { avatar: 'h-16 w-16', text: 'text-xl' },\n} as const;\n\ninterface ProfilePictureComponentProps {\n  publicKey: string;\n  profile?: Profile;\n  size?: 'xxs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl';\n  className?: string;\n  onClick?: () => void;\n  lazy?: boolean;\n  variant?: 'default' | 'nft' | 'highres';\n  shape?: 'circle' | 'rounded' | 'square';\n  border?: 'none' | 'gradient' | 'solid';\n  isLive?: boolean;\n  associatedPublicKey?: string;\n  actionIcon?: React.ReactNode;\n}\n\nexport function ProfilePicture({\n  publicKey,\n  profile: profileProp,\n  size = 'md',\n  className,\n  onClick,\n  lazy = true,\n  variant = 'default',\n  shape = 'circle',\n  border = 'none',\n  isLive = false,\n  associatedPublicKey,\n  actionIcon,\n}: ProfilePictureComponentProps) {\n  const {\n    profile: fetchedProfile,\n    loading,\n    error,\n  } = useProfile(profileProp ? '' : publicKey);\n  const profile = profileProp || fetchedProfile;\n  const profilePic = profile?.profilePic;\n  const extraData = profile?.extraData || {};\n  const sizeClasses = sizeConfig[size];\n\n  const shapeStyle =\n    variant === 'nft'\n      ? 'nft-hexagon'\n      : shape === 'square'\n      ? 'rounded-none'\n      : shape === 'rounded'\n      ? 'rounded-xl'\n      : 'rounded-full';\n\n  const initialProfilePicUrl = buildProfilePictureUrl(profilePic, extraData, variant) || getSingleProfilePictureUrl(publicKey);\n  const [imgSrc, setImgSrc] = useState<string | undefined>(initialProfilePicUrl);\n  const [triedFallback, setTriedFallback] = useState(false);\n\n  useEffect(() => {\n    setImgSrc(initialProfilePicUrl);\n    setTriedFallback(false);\n  }, [initialProfilePicUrl]);\n\n  const fallbackInitial = profile?.username\n    ? getUsernameInitial(profile.username)\n    : publicKey\n      ? publicKey[0].toUpperCase()\n      : '?';\n\n  const handleImgError = () => {\n    if (!triedFallback) {\n      setImgSrc(getSingleProfilePictureUrl(publicKey));\n      setTriedFallback(true);\n    } else {\n      setImgSrc(undefined);\n    }\n  };\n  \n  const renderAdornment = () => {\n    const adornmentContainerClasses = 'absolute -bottom-1 -right-1';\n    const adornmentSizeMap = {\n      xl: 'sm',\n      lg: 'xs',\n      md: 'xs',\n      sm: 'xxs',\n      xs: 'xxs',\n      xxs: 'xxs',\n    } as const;\n    const adornmentSize = adornmentSizeMap[size];\n\n    if (associatedPublicKey) {\n      return (\n        <div className={adornmentContainerClasses}>\n          <ProfilePicture\n            publicKey={associatedPublicKey}\n            size={adornmentSize}\n            border=\"solid\"\n          />\n        </div>\n      );\n    }\n    if (actionIcon) {\n      return <div className={adornmentContainerClasses}>{actionIcon}</div>;\n    }\n    if (isLive) {\n      const liveIndicatorSize = {\n        xl: 'w-4 h-4 border-2',\n        lg: 'w-3.5 h-3.5 border-2',\n        md: 'w-3 h-3 border-2',\n        sm: 'w-2.5 h-2.5 border-2',\n        xs: 'w-2 h-2 border',\n        xxs: 'w-1.5 h-1.5 border',\n      }[size];\n      return (\n        <div\n          className={cn(\n            'absolute bottom-0 right-0 rounded-full border-background bg-green-500',\n            liveIndicatorSize\n          )}\n        />\n      );\n    }\n    return null;\n  };\n\n  const innerContent = (\n    loading ? (\n      <Skeleton className={cn('w-full h-full', shapeStyle)} />\n    ) : (error || !imgSrc) ? (\n      <div\n        className={cn(\n          'flex items-center justify-center w-full h-full bg-gradient-to-br from-gray-400 to-gray-600',\n          shapeStyle\n        )}\n      >\n        <span className={cn('text-white font-semibold', sizeClasses.text)}>\n          {error ? '?' : fallbackInitial}\n        </span>\n      </div>\n    ) : (\n      <Avatar className={cn('w-full h-full', shapeStyle)}>\n        <AvatarImage\n          src={imgSrc}\n          alt={`${profile?.username || 'User'}'s profile picture`}\n          loading={lazy ? 'lazy' : 'eager'}\n          className={cn('object-cover', shapeStyle)}\n          onError={handleImgError}\n        />\n        <AvatarFallback className={cn('bg-gradient-to-br from-blue-500 to-purple-600', shapeStyle)}>\n          <span className={cn('text-white font-semibold', sizeClasses.text)}>\n            {fallbackInitial}\n          </span>\n        </AvatarFallback>\n      </Avatar>\n    )\n  );\n  \n  const borderGradientClass = 'bg-gradient-to-tr from-yellow-400 via-pink-500 to-purple-500';\n  const borderSolidClass = 'bg-neutral-200';\n\n  let containerClasses = cn(sizeClasses.avatar, 'relative', className);\n\n  if (border === 'gradient') {\n    containerClasses = cn('p-0.5', borderGradientClass, shapeStyle, sizeClasses.avatar, 'relative', className);\n  } else if (border === 'solid') {\n    containerClasses = cn('p-px', borderSolidClass, shapeStyle, sizeClasses.avatar, 'relative', className);\n  }\n\n  return (\n    <div className={containerClasses} onClick={onClick}>\n      {innerContent}\n      {renderAdornment()}\n    </div>\n  );\n}\n\nProfilePicture.displayName = 'ProfilePicture'; ",
      "type": "registry:component",
      "target": "src/components/deso-ui/profile-picture.tsx"
    }
  ]
}