Files
bentopdf/src/js/utils/csv-to-pdf.ts
abdullahalam123 f30a084fce feat: Add VitePress docs, EPUB to PDF tool, Phosphor icons, and licensing updates
- Set up VitePress documentation site (docs:dev, docs:build, docs:preview)
- Added Getting Started, Tools Reference, Contributing, and Commercial License pages
- Created self-hosting guides for Docker, Vercel, Netlify, Cloudflare, AWS, Hostinger, Nginx, Apache
- Updated README with documentation link, sponsors section, and docs contribution guide

- Added EPUB to PDF converter using LibreOffice WASM

- Migrated to Phosphor Icons for consistent iconography

- Added donation ribbon banner on landing page
- Removed 'Like My Work?' section (replaced by ribbon)
- Updated licensing.html with delivery model, AGPL notice, invoicing, and no-refund policy

- Added Commercial License documentation page
- Updated translations table (Chinese added, marked non-English as In Progress)

- Added sponsors.yml workflow for auto-generating sponsor avatars
2025-12-27 19:38:33 +05:30

91 lines
3.0 KiB
TypeScript

import { jsPDF } from 'jspdf';
import autoTable from 'jspdf-autotable';
import Papa from 'papaparse';
export interface CsvToPdfOptions {
onProgress?: (percent: number, message: string) => void;
}
/**
* Convert a CSV file to PDF using jsPDF and autotable
*/
export async function convertCsvToPdf(
file: File,
options?: CsvToPdfOptions
): Promise<Blob> {
const { onProgress } = options || {};
return new Promise((resolve, reject) => {
onProgress?.(10, 'Reading CSV file...');
Papa.parse(file, {
complete: (results) => {
try {
onProgress?.(50, 'Generating PDF...');
const data = results.data as string[][];
// Filter out empty rows
const filteredData = data.filter(row =>
row.some(cell => cell && cell.trim() !== '')
);
if (filteredData.length === 0) {
reject(new Error('CSV file is empty'));
return;
}
// Create PDF document
const doc = new jsPDF({
orientation: 'landscape', // Better for wide tables
unit: 'mm',
format: 'a4'
});
// Extract headers (first row) and data
const headers = filteredData[0];
const rows = filteredData.slice(1);
onProgress?.(70, 'Creating table...');
// Generate table
autoTable(doc, {
head: [headers],
body: rows,
startY: 20,
styles: {
fontSize: 9,
cellPadding: 3,
overflow: 'linebreak',
cellWidth: 'wrap',
},
headStyles: {
fillColor: [41, 128, 185], // Nice blue header
textColor: 255,
fontStyle: 'bold',
},
alternateRowStyles: {
fillColor: [245, 245, 245], // Light gray for alternate rows
},
margin: { top: 20, left: 10, right: 10 },
theme: 'striped',
});
onProgress?.(90, 'Finalizing PDF...');
// Get PDF as blob
const pdfBlob = doc.output('blob');
onProgress?.(100, 'Complete!');
resolve(pdfBlob);
} catch (error) {
reject(error);
}
},
error: (error) => {
reject(new Error(`Failed to parse CSV: ${error.message}`));
},
});
});
}