Newsletter Writing Assistant

Newsletter Writing Assistant

Craft compelling newsletters in a few simple steps.

Define Your Audience & Goal

Your generated newsletter content will appear here once you\'ve generated and refined it.

'; previewSubjectEl.textContent = subject; // Simple Markdown to HTML conversion let bodyHtml = bodyRaw .replace(/\*\*(.*?)\*\*/g, '$1') // Bold .replace(/^\* (.*?)$/gm, '
  • $1
  • ') // List items start of line .replace(/(
  • .*<\/li>)/gs, '
      $1
    ') // Wrap lists .replace(/### (.*?)\n/g, '

    $1

    \n') // Headings .replace(/\n/g, '
    '); // Newlines // Fix for multiple UL tags bodyHtml = bodyHtml.replace(/<\/ul>
      /g, ''); previewBodyEl.innerHTML = bodyHtml; }; const handleDownloadPdf = () => { // Ensure jsPDF is loaded. if (!window.jspdf) { console.error('PDF generation library (jsPDF) is not available.'); // Gracefully notify user without using alert() const downloadBtn = document.getElementById('download-pdf-btn'); if(downloadBtn) { const originalText = downloadBtn.innerHTML; downloadBtn.innerText = 'Error: PDF Library Missing'; setTimeout(() => { downloadBtn.innerHTML = originalText; lucide.createIcons(); }, 3000); } return; } const { jsPDF } = window.jspdf; const pdf = new jsPDF({ orientation: 'portrait', unit: 'pt', // Use points for better control format: 'a4' }); // --- Document constants and state --- const pageW = pdf.internal.pageSize.getWidth(); const pageH = pdf.internal.pageSize.getHeight(); const margin = 40; const maxLineWidth = pageW - margin * 2; let cursorY = margin; // --- Helper function for page breaks --- const checkPageBreak = (elementHeight) => { if (cursorY + elementHeight > pageH - margin) { pdf.addPage(); cursorY = margin; // Add headers to new pages for continuity pdf.setFont('helvetica', 'italic').setFontSize(9).setTextColor(150); pdf.text('Newsletter Content Report (continued)', margin, cursorY); cursorY += 20; pdf.setTextColor(0); } }; // --- PDF Header --- pdf.setFont('helvetica', 'bold').setFontSize(22); pdf.text('Newsletter Content Report', pageW / 2, cursorY, { align: 'center' }); cursorY += 20; pdf.setFont('helvetica', 'normal').setFontSize(10); pdf.setTextColor(100); pdf.text(`Generated on: ${new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' })}`, pageW / 2, cursorY, { align: 'center' }); cursorY += 20; pdf.setDrawColor(220, 220, 220); pdf.line(margin, cursorY, pageW - margin, cursorY); cursorY += 30; pdf.setTextColor(0); // --- PDF Content: Subject --- const subjectText = document.getElementById('generated-subject').value || 'No subject provided.'; pdf.setFont('helvetica', 'bold').setFontSize(16); checkPageBreak(20); pdf.text('Subject Line', margin, cursorY); cursorY += 20; pdf.setFont('helvetica', 'normal').setFontSize(12); const subjectLines = pdf.splitTextToSize(subjectText, maxLineWidth); checkPageBreak(subjectLines.length * 14); pdf.text(subjectLines, margin, cursorY); cursorY += subjectLines.length * 14 + 25; // Add extra space after // --- PDF Content: Body --- checkPageBreak(40); // Check space for the title pdf.setFont('helvetica', 'bold').setFontSize(16); pdf.text('Newsletter Body', margin, cursorY); cursorY += 25; const bodyRawText = document.getElementById('generated-body').value || 'No body content provided.'; const bodyLines = bodyRawText.split('\n'); bodyLines.forEach(line => { const trimmedLine = line.trim(); if (trimmedLine.startsWith('### ')) { const headingText = trimmedLine.substring(4); checkPageBreak(30); // Extra space for heading cursorY += 10; pdf.setFont('helvetica', 'bold').setFontSize(14); pdf.text(headingText, margin, cursorY); cursorY += 16; } else if (trimmedLine.startsWith('* ')) { const itemText = trimmedLine.substring(2); pdf.setFont('helvetica', 'normal').setFontSize(11); const textLines = pdf.splitTextToSize(itemText, maxLineWidth - 20); // Indented line width checkPageBreak(textLines.length * 13); pdf.text('\u2022', margin + 10, cursorY); // Bullet point pdf.text(textLines, margin + 25, cursorY); cursorY += textLines.length * 13 + 3; } else if (trimmedLine) { pdf.setFont('helvetica', 'normal').setFontSize(11); const paraLines = pdf.splitTextToSize(trimmedLine, maxLineWidth); checkPageBreak(paraLines.length * 13); pdf.text(paraLines, margin, cursorY); cursorY += paraLines.length * 13 + 10; } else { checkPageBreak(10); cursorY += 10; } }); // --- PDF Footer: Page Numbers --- const pageCount = pdf.internal.getNumberOfPages(); for(let i = 1; i <= pageCount; i++) { pdf.setPage(i); pdf.setFont('helvetica', 'italic').setFontSize(9).setTextColor(150); pdf.text(`Page ${i} of ${pageCount}`, pageW / 2, pageH - 20, { align: 'center' }); } // --- Save the PDF --- const toolName = "Newsletter"; const date = new Date().toISOString().slice(0, 10); pdf.save(`${toolName}-Report-${date}.pdf`); }; // --- Event Listeners --- if (generateBtn) { generateBtn.addEventListener('click', handleGenerateClick); } if (downloadPdfBtn) { downloadPdfBtn.addEventListener('click', handleDownloadPdf); } });
  • Scroll to Top