"use client"; import { useEffect, useState } from "react"; type Attachment = { name?: string; filename?: string; url?: string; externalLink?: string; type?: string; size?: string | number }; function resourceUrl(attachment: Attachment, sourceBaseUrl?: string) { if (attachment.url) return attachment.url; if (attachment.externalLink) return attachment.externalLink; if (!sourceBaseUrl || !attachment.name || !attachment.filename) return null; const resourceName = attachment.name.split("/").map(encodeURIComponent).join("/"); return `${sourceBaseUrl.replace(/\/$/, "")}/file/${resourceName}/${encodeURIComponent(attachment.filename)}`; } export function Attachments({ json, sourceBaseUrl, compact = false }: { json: string; sourceBaseUrl?: string | null; compact?: boolean }) { const [activeImage, setActiveImage] = useState<{ href: string; label: string } | null>(null); useEffect(() => { const closeOnEscape = (event: KeyboardEvent) => { if (event.key === "Escape") setActiveImage(null); }; window.addEventListener("keydown", closeOnEscape); return () => window.removeEventListener("keydown", closeOnEscape); }, []); let attachments: Attachment[] = []; try { attachments = JSON.parse(json); } catch { return null; } const displayable = attachments.map((attachment) => ({ attachment, href: resourceUrl(attachment, sourceBaseUrl || undefined) })).filter((item): item is { attachment: Attachment; href: string } => Boolean(item.href)); if (!displayable.length) return null; return <>
{displayable.map(({ attachment, href }) => { const label = attachment.filename || attachment.name || "附件"; if (attachment.type?.startsWith("image/")) return ; return 📎 {label}; })}
{activeImage &&
setActiveImage(null)}> {activeImage.label} event.stopPropagation()} />
} ; }