import { FileSystemItem } from '@/lib/types/database' import { Editor } from '@tiptap/react' export interface DownloadOptions { format: 'current' | 'pdf' fileName: string content: string fileExtension?: string } /** * Downloads a file in its current format */ export function downloadCurrentFormat(file: FileSystemItem): void { if (!file.content) { console.error('No content to download') return } const blob = new Blob([file.content], { type: getContentType(file.file_extension || 'txt') }) const url = URL.createObjectURL(blob) const link = document.createElement('a') link.href = url link.download = file.name document.body.appendChild(link) link.click() document.body.removeChild(link) URL.revokeObjectURL(url) } /** * Downloads a file as PDF using TipTap editor instance * This provides the best formatting since it uses the actual rendered HTML */ export async function downloadAsPDFFromEditor( editor: Editor, fileName: string ): Promise { try { // Get the HTML content from TipTap editor const htmlContent = editor.getHTML() // Create a complete HTML document with proper styling const fullHtml = createPrintableHTML(htmlContent, fileName) // Use the browser's print API with PDF generation await generatePDFFromHTML(fullHtml, fileName) } catch (error) { console.error('Error generating PDF from editor:', error) throw new Error('Failed to generate PDF from editor') } } /** * Downloads a file as PDF (fallback method) * This is used when TipTap editor instance is not available */ export async function downloadAsPDF(file: FileSystemItem): Promise { if (!file.content) { console.error('No content to download') return } try { // Create a temporary editor instance to convert markdown to HTML const { Editor } = await import('@tiptap/core') const { default: StarterKit } = await import('@tiptap/starter-kit') const editor = new Editor({ extensions: [StarterKit], content: file.content, }) const htmlContent = editor.getHTML() const fileName = file.name.replace(/\.[^/.]+$/, '') // Create a complete HTML document const fullHtml = createPrintableHTML(htmlContent, fileName) // Generate PDF await generatePDFFromHTML(fullHtml, fileName + '.pdf') } catch (error) { console.error('Error generating PDF:', error) // Fallback to plain text download downloadCurrentFormat(file) } } /** * Create a complete HTML document optimized for PDF generation */ function createPrintableHTML(content: string, title: string): string { return ` ${escapeHtml(title)}
${content}
` } /** * Generate PDF from HTML using the browser's print API */ async function generatePDFFromHTML(html: string, fileName: string): Promise { // Create a new window for printing const printWindow = window.open('', '_blank', 'width=800,height=600') if (!printWindow) { throw new Error('Could not open print window. Please allow popups for this site.') } // Write HTML to the new window printWindow.document.write(html) printWindow.document.close() // Wait for the content to load await new Promise((resolve) => { printWindow.onload = () => { // Small delay to ensure everything is rendered setTimeout(() => { resolve() }, 100) } }) // Set the document title for the PDF printWindow.document.title = fileName // Trigger print dialog printWindow.print() // Clean up after a delay setTimeout(() => { printWindow.close() }, 1000) } /** * Alternative PDF generation using Puppeteer (for server-side) * This would be called via an API endpoint */ export async function generatePDFServerSide( content: string, fileName: string ): Promise { const response = await fetch('/api/generate-pdf', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ html: createPrintableHTML(content, fileName), fileName }) }) if (!response.ok) { throw new Error('Failed to generate PDF on server') } return response.blob() } /** * Escape HTML special characters */ function escapeHtml(text: string): string { const div = document.createElement('div') div.textContent = text return div.innerHTML } /** * Get the appropriate MIME type for a file extension */ function getContentType(extension: string): string { const ext = extension.toLowerCase() const mimeTypes: Record = { 'txt': 'text/plain', 'md': 'text/markdown', 'markdown': 'text/markdown', 'html': 'text/html', 'htm': 'text/html', 'json': 'application/json', 'js': 'text/javascript', 'ts': 'text/typescript', 'css': 'text/css', 'xml': 'text/xml', 'csv': 'text/csv' } return mimeTypes[ext] || 'text/plain' } /** * Get a user-friendly format name for display */ export function getFormatDisplayName(extension?: string): string { if (!extension) return 'Text File' const ext = extension.toLowerCase() const displayNames: Record = { 'txt': 'Text File', 'md': 'Markdown', 'markdown': 'Markdown', 'html': 'HTML', 'htm': 'HTML', 'json': 'JSON', 'js': 'JavaScript', 'ts': 'TypeScript', 'css': 'CSS', 'xml': 'XML', 'csv': 'CSV' } return displayNames[ext] || ext.toUpperCase() } /** * Get a description of supported PDF features */ export function getPDFFeatures(): string[] { return [ '✓ Perfect formatting using TipTap\'s rendered HTML', '✓ Proper page breaks and print styling', '✓ All markdown elements: headings, lists, tables, quotes', '✓ Syntax-highlighted code blocks', '✓ Clickable links with URLs shown in print', '✓ Task lists with checkboxes', '✓ Professional typography and spacing', '✓ Responsive images and media', '✓ Print-optimized styling', '✓ Browser-native PDF generation (no external dependencies)' ] }