{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "profile-description",
  "type": "registry:block",
  "title": "Profile Description",
  "description": "A component for displaying a user's profile description.",
  "files": [
    {
      "path": "src/components/deso/profile-description.tsx",
      "content": "'use client';\n\nimport React, { useState } from 'react';\nimport { useProfile } from '@/hooks/useProfile';\nimport { cn } from '@/lib/utils/deso';\nimport { Button } from '@/components/ui/button';\n\nexport interface ProfileDescriptionProps {\n  publicKey: string;\n  className?: string;\n  lineClamp?: number;\n  showMoreText?: string;\n  showLessText?: string;\n  formatted?: boolean;\n}\n\n/**\n * Formats a description string by converting URLs and @mentions to links and preserving line breaks.\n */\nfunction formatDescription(text: string): React.ReactNode[] {\n  // Convert URLs to links\n  const urlRegex = /(https?:\\/\\/[^\\s]+)/g;\n  // Convert @mentions to links (assume /u/username route)\n  const mentionRegex = /(^|\\s)(@[a-zA-Z0-9_]+)/g;\n\n  // Split by newlines to preserve line breaks\n  return text.split(/\\n/).map((line, i) => {\n    // URLs\n    let formatted = line.replace(urlRegex, (url) => `<a href=\"${url}\" target=\"_blank\" rel=\"noopener noreferrer\">${url}</a>`);\n    // Mentions\n    formatted = formatted.replace(mentionRegex, (match, space, handle) => `${space}<a href=\"/u/${handle.slice(1)}\" class=\"text-primary underline\">${handle}</a>`);\n    return <span key={i} dangerouslySetInnerHTML={{ __html: formatted }} />;\n  });\n}\n\nexport const ProfileDescription = ({\n  publicKey,\n  className,\n  lineClamp,\n  showMoreText = 'Show more',\n  showLessText = 'Show less',\n  formatted = true,\n}: ProfileDescriptionProps) => {\n  const { profile, loading, error } = useProfile(publicKey);\n  const [isExpanded, setIsExpanded] = useState(false);\n\n  const description = profile?.description || '';\n\n  // Only apply truncation logic if lineClamp is provided.\n  const shouldTruncate =\n    !!lineClamp && description.length > lineClamp * 50;\n\n  if (loading) {\n    return (\n      <div className=\"animate-pulse bg-gray-200 dark:bg-gray-800 h-24 rounded\"></div>\n    );\n  }\n\n  if (error || !description) {\n    return null;\n  }\n\n  const isCurrentlyClamped = shouldTruncate && !isExpanded;\n\n  const style =\n    isCurrentlyClamped && lineClamp\n      ? {\n          display: '-webkit-box',\n          WebkitBoxOrient: 'vertical' as const,\n          WebkitLineClamp: lineClamp,\n          overflow: 'hidden',\n          textOverflow: 'ellipsis',\n        }\n      : {};\n\n  return (\n    <div className={cn('relative', className)}>\n      <div style={style}>\n        {formatted\n          ? (isCurrentlyClamped\n              ? formatDescription(description)\n                  .slice(0, lineClamp ? lineClamp : undefined)\n                  .map((el, i, arr) => [el, i < arr.length - 1 ? <br key={`br-${i}`} /> : null])\n              : formatDescription(description).map((el, i, arr) => [el, i < arr.length - 1 ? <br key={`br-${i}`} /> : null])\n            )\n          : description}\n      </div>\n      {shouldTruncate && (\n        <Button\n          variant=\"link\"\n          className=\"p-0 h-auto text-sm underline mt-4 text-muted-foreground\"\n          onClick={() => setIsExpanded(!isExpanded)}\n        >\n          {isExpanded ? showLessText : showMoreText}\n        </Button>\n      )}\n    </div>\n  );\n}; ",
      "type": "registry:component",
      "target": "src/components/deso-ui/profile-description.tsx"
    }
  ]
}