import jsPDF from "jspdf"; import html2canvas from "html2canvas"; /** * Converts markdown content to a styled PDF document * @param {string} content - Markdown content * @param {string} filename - Name for the exported file (without extension) */ export async function exportToPdf(content, filename = "document") { // Create a temporary container to render the content const container = document.createElement("div"); container.style.cssText = ` position: absolute; left: -9999px; top: 0; width: 210mm; padding: 20mm; background: white; color: black; font-family: 'Inter', 'Segoe UI', 'Arial', sans-serif; font-size: 12pt; line-height: 1.6; `; // Process the markdown content to HTML with basic styling const htmlContent = markdownToHtml(content); container.innerHTML = htmlContent; document.body.appendChild(container); try { // Wait for any images/fonts to load await new Promise(resolve => setTimeout(resolve, 100)); // Capture the content as canvas const canvas = await html2canvas(container, { scale: 2, useCORS: true, logging: false, backgroundColor: "#ffffff" }); // Create PDF const imgWidth = 210; // A4 width in mm const pageHeight = 297; // A4 height in mm const imgHeight = (canvas.height * imgWidth) / canvas.width; let heightLeft = imgHeight; let position = 0; const pdf = new jsPDF("p", "mm", "a4"); const imgData = canvas.toDataURL("image/png"); // Add first page pdf.addImage(imgData, "PNG", 0, position, imgWidth, imgHeight); heightLeft -= pageHeight; // Add additional pages if content is longer than one page while (heightLeft > 0) { position = heightLeft - imgHeight; pdf.addPage(); pdf.addImage(imgData, "PNG", 0, position, imgWidth, imgHeight); heightLeft -= pageHeight; } // Save the PDF pdf.save(`${filename}.pdf`); } finally { // Clean up document.body.removeChild(container); } } /** * Converts markdown to styled HTML for PDF rendering * Handles common markdown syntax including LaTeX (as plain text for PDF) */ function markdownToHtml(markdown) { if (!markdown) return ""; let html = markdown; // Escape HTML entities html = html .replace(/&/g, "&") .replace(//g, ">"); // Convert LaTeX blocks to styled spans (rendered as formatted text) html = html.replace(/\$\$([^$]+)\$\$/g, '
$1');
// Code blocks
html = html.replace(/```[\w]*\n([\s\S]*?)```/g, '$1'); // Blockquotes html = html.replace(/^> (.+)$/gm, '
$1'); // Horizontal rules html = html.replace(/^---$/gm, '
');
html = html.replace(/\n/g, '
');
// Wrap in paragraph tags
html = `
${html}
`; // Clean up empty paragraphs html = html.replace(/]*>\s*<\/p>/g, ''); return ` ${html} `; }