| 610 | } |
| 611 | |
| 612 | function ExpandableText({ |
| 613 | text, |
| 614 | limit = 220, |
| 615 | className, |
| 616 | }: { |
| 617 | text: string; |
| 618 | limit?: number; |
| 619 | className?: string; |
| 620 | }) { |
| 621 | const [expanded, setExpanded] = useState(false); |
| 622 | const shouldTruncate = text.length > limit; |
| 623 | const displayText = expanded || !shouldTruncate ? text : `${text.slice(0, limit)}…`; |
| 624 | return ( |
| 625 | <div className="space-y-1"> |
| 626 | <p className={cn('whitespace-pre-wrap leading-relaxed', className)}>{displayText}</p> |
| 627 | {shouldTruncate && ( |
| 628 | <button |
| 629 | type="button" |
| 630 | onClick={() => setExpanded((prev) => !prev)} |
| 631 | className="text-[11px] font-semibold text-primary hover:underline" |
| 632 | > |
| 633 | {expanded ? 'Show less' : 'Show more'} |
| 634 | </button> |
| 635 | )} |
| 636 | </div> |
| 637 | ); |
| 638 | } |
| 639 | |
| 640 | function summarizeUnknown(value: unknown): string { |
| 641 | if (typeof value === 'string') { |