import { useState } from "react"; import { ChevronDown, FileText } from "lucide-react"; import { cn } from "../lib/cn.ts"; /** * User message content with attached files folded away. * * Text/OCR attachments travel inlined in the message as: * [attached text file: foo.txt] * ```text * * ``` * Rendering that raw blows the bubble off-screen, so each block renders as * a collapsed attachment row (header + expand chevron, no i18n needed) with * the body capped to a scrollable pane when expanded. */ const ATTACH_RE = /^(\[.*?\])\n```text\n([\s\S]*?)\n```/gm; function AttachmentBlock({ header, body, tone }: { header: string; body: string; tone: "accent" | "plain" }) { const [open, setOpen] = useState(false); const label = header.startsWith("[") && header.endsWith("]") ? header.slice(1, -1) : header; return ( {open && (
          {body}
        
)}
); } export function UserMessageContent({ content, tone = "accent" }: { content: string; tone?: "accent" | "plain" }) { const parts: React.ReactNode[] = []; let last = 0; let key = 0; ATTACH_RE.lastIndex = 0; let m: RegExpExecArray | null; while ((m = ATTACH_RE.exec(content)) !== null) { if (m.index > last) parts.push({content.slice(last, m.index)}); parts.push(); last = m.index + m[0].length; } if (last < content.length) parts.push({content.slice(last)}); if (parts.length === 0) return <>{content}; return <>{parts}; }