UNPKG

safeer-pdf-generator

Version:

Framework-agnostic PDF generation library with chunking, merging, S3 upload, and email delivery

167 lines (151 loc) 6.2 kB
// Custom Template Examples // Shows three approaches: inline function, customCss/customHtml, and template registry import { generatePdf, registerTemplate, consoleLogger } from 'safeer-pdf-generator'; const sampleData = [ { name: 'Alice Johnson', department: 'Engineering', salary: 95000, status: true }, { name: 'Bob Smith', department: 'Marketing', salary: 72000, status: true }, { name: 'Carol White', department: 'Sales', salary: 68000, status: false }, ]; const columns = [ { key: 'name', title: 'Employee', dataIndex: 'name' }, { key: 'department', title: 'Department', dataIndex: 'department' }, { key: 'salary', title: 'Salary', dataIndex: 'salary' }, { key: 'status', title: 'Active', dataIndex: 'status' }, ]; // ── Approach 1: Use a built-in template with customCss and customHtml ── async function withCustomCss() { const result = await generatePdf({ title: 'Employee Report (Custom Styled)', data: sampleData, columns, template: 'modern', // or 'default' or 'simple' customCss: ` .modern-table th { background: linear-gradient(135deg, #7c3aed, #2563eb) !important; color: #fff !important; } .row-even { background: #faf5ff !important; } `, customHtml: { beforeTable: ` <div style="background: #f5f3ff; border-left: 4px solid #7c3aed; padding: 12px; margin-bottom: 12px; border-radius: 4px;"> <strong>Note:</strong> This report covers all employees as of Q4 2025. </div> `, afterTable: ` <div style="margin-top: 16px; padding: 12px; background: #f8fafc; border-radius: 4px; font-size: 11px; color: #64748b;"> Generated by HR Department • Confidential </div> `, }, logging: consoleLogger, }); console.log(`✅ Custom CSS example: ${result.fileName} (${result.pageCount} pages)`); } // ── Approach 2: Pass a custom template function inline ── async function withInlineTemplate() { const result = await generatePdf({ title: 'Employee Directory', data: sampleData, columns, // Pass a function directly — full control over HTML template: (params) => { const { title, data, columns } = params; const html = ` <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>${title}</title> <style> body { font-family: Georgia, serif; margin: 0; padding: 20px; } h1 { color: #1a1a2e; border-bottom: 3px double #1a1a2e; padding-bottom: 8px; } table { width: 100%; border-collapse: collapse; margin-top: 20px; } th { background: #1a1a2e; color: #fff; padding: 12px 8px; text-align: left; } td { padding: 10px 8px; border-bottom: 1px solid #eee; } tr:nth-child(even) { background: #f9f9f9; } </style> </head> <body> <h1>${title}</h1> <p style="color: #666;">Total records: ${data.length}</p> <table> <thead> <tr>${columns.map(c => `<th>${c.title}</th>`).join('')}</tr> </thead> <tbody> ${data.map(row => ` <tr>${columns.map(c => `<td>${row[c.dataIndex] ?? '—'}</td>`).join('')}</tr> `).join('')} </tbody> </table> </body> </html> `; return { html, header: '', // Custom header for Puppeteer (or empty) footer: '', }; }, logging: consoleLogger, }); console.log(`✅ Inline template example: ${result.fileName} (${result.pageCount} pages)`); } // ── Approach 3: Register a reusable template in the global registry ── async function withRegisteredTemplate() { // Register once — available everywhere registerTemplate('branded', (params) => { const { title, data, columns, userInfo = {} } = params; const html = ` <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>${title}</title> <style> body { font-family: 'Segoe UI', sans-serif; margin: 0; padding: 24px; } .brand-bar { background: #0f172a; color: #fff; padding: 16px 24px; border-radius: 8px; margin-bottom: 20px; } .brand-bar h1 { margin: 0; font-size: 18px; } .brand-bar .subtitle { color: #94a3b8; font-size: 12px; margin-top: 4px; } table { width: 100%; border-collapse: collapse; } th { background: #f1f5f9; padding: 10px; text-align: left; font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; color: #475569; } td { padding: 10px; border-bottom: 1px solid #f1f5f9; font-size: 12px; } </style> </head> <body> <div class="brand-bar"> <h1>${title}</h1> <div class="subtitle">Prepared for ${userInfo.name || 'Management'} • ${new Date().toLocaleDateString()}</div> </div> <table> <thead><tr>${columns.map(c => `<th>${c.title}</th>`).join('')}</tr></thead> <tbody> ${data.map(row => ` <tr>${columns.map(c => `<td>${row[c.dataIndex] ?? '—'}</td>`).join('')}</tr> `).join('')} </tbody> </table> </body> </html> `; return { html, header: '', footer: '' }; }); // Now use it by name const result = await generatePdf({ title: 'Quarterly Review', data: sampleData, columns, template: 'branded', // Refers to the registered template userInfo: { name: 'Hassan', email: 'hassan@example.com' }, logging: consoleLogger, }); console.log(`✅ Registered template example: ${result.fileName} (${result.pageCount} pages)`); } // Run all examples async function main() { await withCustomCss(); await withInlineTemplate(); await withRegisteredTemplate(); } main().catch(console.error);