'use client'; import { useState, type ComponentProps } from 'react'; import { useTranslations } from 'next-intl'; import ReactMarkdown from 'react-markdown'; import remarkGfm from 'remark-gfm'; import { PencilSimple } from '@phosphor-icons/react'; import { sanitize } from '@/lib/sanitize'; import { cn } from '@/lib/utils'; import { Button } from '@/components/ui/button'; import { ProfileEditDialog } from '@/components/profile-edit-dialog'; import { useProfileEdit } from '@/components/profile-edit-provider'; const COLLAPSE_THRESHOLD = 300; interface AboutSectionProps { about: string; isOwnProfile?: boolean; } /** Open links in new tab with safe rel attributes. */ function MarkdownLink(props: ComponentProps<'a'>) { // eslint-disable-next-line jsx-a11y/anchor-has-content -- children are passed via spread props from react-markdown return ; } export function AboutSection({ about, isOwnProfile }: AboutSectionProps) { const t = useTranslations('profile'); const [expanded, setExpanded] = useState(false); const [editing, setEditing] = useState(false); const { profile } = useProfileEdit(); if (!about && !isOwnProfile) return null; if (!about && isOwnProfile) { return (

{t('addAbout')}

{editing && ( setEditing(false)} /> )}
); } // Strip any raw HTML from the source before markdown rendering const cleaned = sanitize(about); const isLong = cleaned.length > COLLAPSE_THRESHOLD; return (
{cleaned}
{isOwnProfile && ( )}
{isLong && ( )} {editing && ( setEditing(false)} /> )}
); }