// Security: SVG content rendered here is server-sanitized by DOMPurify (DIAG-05). // Pattern mirrors MarkdownBody.tsx mermaid rendering using dangerouslySetInnerHTML. import type { DiagramBundle } from "@/types/content-bundles"; import { Button } from "@/components/ui/button"; interface DiagramPreviewProps { bundle: DiagramBundle | null; className?: string; } function base64ToBlob(base64: string, mimeType: string): Blob { const byteString = atob(base64); const ab = new ArrayBuffer(byteString.length); const ia = new Uint8Array(ab); for (let i = 0; i < byteString.length; i++) { ia[i] = byteString.charCodeAt(i); } return new Blob([ab], { type: mimeType }); } function triggerDownload(blob: Blob, filename: string) { const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); } export function DiagramPreview({ bundle, className }: DiagramPreviewProps) { if (!bundle) return null; const svgHtml = atob(bundle.svgBase64); function handleDownloadSvg() { if (!bundle) return; const blob = base64ToBlob(bundle.svgBase64, "image/svg+xml"); triggerDownload(blob, "diagram.svg"); } function handleDownloadPng() { if (!bundle) return; const blob = base64ToBlob(bundle.pngBase64, "image/png"); triggerDownload(blob, "diagram.png"); } return (