import React, { memo, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { ExternalLink } from 'lucide-react'; import type { SubsonicArtistInfo } from '../../api/subsonicTypes'; import { isRealArtistImage, sanitizeHtml } from '../../utils/componentHelpers/nowPlayingHelpers'; import CachedImage from '../CachedImage'; interface ArtistCardProps { artistName: string; artistId?: string; artistInfo: SubsonicArtistInfo | null; onNavigate: (path: string) => void; } const ArtistCard = memo(function ArtistCard({ artistName, artistId, artistInfo, onNavigate }: ArtistCardProps) { const { t } = useTranslation(); const [bioExpanded, setBioExpanded] = useState(false); const [bioOverflows, setBioOverflows] = useState(false); const bioRef = useRef(null); useEffect(() => { setBioExpanded(false); }, [artistId]); const bioHtml = useMemo(() => artistInfo?.biography ? sanitizeHtml(artistInfo.biography) : '', [artistInfo?.biography]); useLayoutEffect(() => { const el = bioRef.current; if (!el) { setBioOverflows(false); return; } setBioOverflows(el.scrollHeight - el.clientHeight > 1); }, [bioHtml]); const similar = artistInfo?.similarArtist ?? []; const rawLarge = artistInfo?.largeImageUrl; const rawMed = artistInfo?.mediumImageUrl; const heroImage = isRealArtistImage(rawLarge) ? rawLarge! : isRealArtistImage(rawMed) ? rawMed! : ''; const heroCacheKey = artistId ? `artistInfo:${artistId}:hero` : ''; if (!bioHtml && similar.length === 0 && !heroImage) return null; return (

{t('nowPlaying.aboutArtist')}

{artistId && ( )}
{heroImage && heroCacheKey && ( { (e.currentTarget as HTMLImageElement).style.display = 'none'; }} /> )}
{artistName}
{bioHtml && ( <>
{(bioOverflows || bioExpanded) && ( )} )}
{similar.length > 0 && (
{similar.slice(0, 12).map((a, idx) => ( a.id && onNavigate(`/artist/${a.id}`)} data-tooltip={t('nowPlaying.goToArtist')}> {a.name} ))}
)}
); }); export default ArtistCard;