/** * PDF Export module for Atmosphere Docs. * * Uses html2pdf.js to convert the editor content into a downloadable PDF. * Always exports in light mode regardless of current theme. */ import type { PdfExportOptions } from './types.js'; /** * Build a self-contained HTML string suitable for PDF rendering. * Extracted as a pure function for testability. */ export function buildPdfHtml(editorHtml: string, title: string): string { return ` ${editorHtml} `; } /** * Derive a safe filename from a document title. */ export function pdfFilename(title: string | null | undefined): string { const clean = (title || '').trim() || 'Untitled Document'; return clean.replace(/[^a-zA-Z0-9_\- ]/g, '').replace(/\s+/g, '_'); } /** * Generate and download a PDF from editor content. * This is the DOM-coupled entry point — not unit-testable. */ export async function exportPdf({ editorHtml, title }: PdfExportOptions): Promise { const html2pdf = (await import('html2pdf.js')).default; const container = document.createElement('div'); container.innerHTML = buildPdfHtml(editorHtml, title); container.style.position = 'fixed'; container.style.left = '-9999px'; container.style.top = '0'; container.style.width = '8.5in'; container.style.background = '#fff'; container.style.color = '#1a1815'; document.body.appendChild(container); try { await html2pdf() .set({ margin: [0.5, 0.5, 0.5, 0.5], filename: `${pdfFilename(title)}.pdf`, image: { type: 'jpeg', quality: 0.95 }, html2canvas: { scale: 2, useCORS: true, backgroundColor: '#ffffff', }, jsPDF: { unit: 'in', format: 'letter', orientation: 'portrait', }, }) .from(container) .save(); } finally { document.body.removeChild(container); } }