This component no longer exists. It was in deso-ui’s manifest when we first indexed it and is not there now — the registry served its inventory on 2026-08-06 and this item was not on it. The install command below will fail. It is kept here because a tutorial somewhere still tells people to run it.
Profile Description
deso-ui/profile-descriptionRemovedBlock
A component for displaying a user's profile description.
Install it
npx shadcn@latest add https://ui.deso.com/r/profile-description.jsonSource
1'use client';23import React, { useState } from 'react';4import { useProfile } from '@/hooks/useProfile';5import { cn } from '@/lib/utils/deso';6import { Button } from '@/components/ui/button';78export interface ProfileDescriptionProps {9 publicKey: string;10 className?: string;11 lineClamp?: number;12 showMoreText?: string;13 showLessText?: string;14 formatted?: boolean;15}1617/**18 * Formats a description string by converting URLs and @mentions to links and preserving line breaks.19 */20function formatDescription(text: string): React.ReactNode[] {21 // Convert URLs to links22 const urlRegex = /(https?:\/\/[^\s]+)/g;23 // Convert @mentions to links (assume /u/username route)24 const mentionRegex = /(^|\s)(@[a-zA-Z0-9_]+)/g;2526 // Split by newlines to preserve line breaks27 return text.split(/\n/).map((line, i) => {28 // URLs29 let formatted = line.replace(urlRegex, (url) => `<a href="${url}" target="_blank" rel="noopener noreferrer">${url}</a>`);30 // Mentions31 formatted = formatted.replace(mentionRegex, (match, space, handle) => `${space}<a href="/u/${handle.slice(1)}" class="text-primary underline">${handle}</a>`);32 return <span key={i} dangerouslySetInnerHTML={{ __html: formatted }} />;33 });34}3536export const ProfileDescription = ({37 publicKey,38 className,39 lineClamp,40 showMoreText = 'Show more',41 showLessText = 'Show less',42 formatted = true,43}: ProfileDescriptionProps) => {44 const { profile, loading, error } = useProfile(publicKey);45 const [isExpanded, setIsExpanded] = useState(false);4647 const description = profile?.description || '';4849 // Only apply truncation logic if lineClamp is provided.50 const shouldTruncate =51 !!lineClamp && description.length > lineClamp * 50;5253 if (loading) {54 return (55 <div className="animate-pulse bg-gray-200 dark:bg-gray-800 h-24 rounded"></div>56 );57 }5859 if (error || !description) {60 return null;61 }6263 const isCurrentlyClamped = shouldTruncate && !isExpanded;6465 const style =66 isCurrentlyClamped && lineClamp67 ? {68 display: '-webkit-box',69 WebkitBoxOrient: 'vertical' as const,70 WebkitLineClamp: lineClamp,71 overflow: 'hidden',72 textOverflow: 'ellipsis',73 }74 : {};7576 return (77 <div className={cn('relative', className)}>78 <div style={style}>79 {formatted80 ? (isCurrentlyClamped81 ? formatDescription(description)82 .slice(0, lineClamp ? lineClamp : undefined)83// … truncated
