Legacy Letter Generator
Introduction & Recipients
Start your letter by addressing your loved ones. Who is this letter for? Set the tone and explain why you're writing it.
Life Lessons & Values
Share the most important lessons life has taught you. What values do you hold dear and wish to pass on?
Cherished Memories
Recall specific memories that bring you joy. Sharing stories makes your letter deeply personal and meaningful.
Hopes & Wishes for Their Future
What are your dreams for your loved ones' futures? Offer them your blessings, encouragement, and support.
Closing Remarks & Final Thoughts
End your letter with final expressions of love, forgiveness, or gratitude. This is your chance for a heartfelt goodbye.
Review & Download Your Letter
Read through your completed letter below. If you need to make changes, simply click on the previous tabs. When you're ready, click the button to download a PDF copy.
Your compiled letter will appear here once you navigate to this tab.
${closing.replace(/\n/g, '
')}
Your letter is empty. Go back to the previous tabs to add your thoughts.
'; } else { reviewPanel.innerHTML = fullLetterHTML; } }; // Event Listeners for tab buttons tabButtons.forEach(btn => { btn.addEventListener('click', () => { const tab = parseInt(btn.dataset.tab, 10); showTab(tab); }); }); // Event Listeners for navigation buttons prevBtn.addEventListener('click', () => showTab(currentTab - 1)); nextBtn.addEventListener('click', () => showTab(currentTab + 1)); // PDF Download functionality - NEW & IMPROVED METHOD // This version builds the PDF directly with jsPDF for better formatting, page breaks, and smaller file size. downloadPdfBtn.addEventListener('click', () => { const { jsPDF } = window.jspdf; // Prepare button for loading state const btnText = getElem('pdf-btn-text'); const btnSpinner = getElem('pdf-btn-spinner'); if (btnText) btnText.classList.add('hidden'); if (btnSpinner) btnSpinner.classList.remove('hidden'); downloadPdfBtn.disabled = true; try { // --- PDF Configuration --- const pdf = new jsPDF({ orientation: 'portrait', unit: 'pt', format: 'a4' }); const pageHeight = pdf.internal.pageSize.getHeight(); const pageWidth = pdf.internal.pageSize.getWidth(); const margin = 50; const maxLineWidth = pageWidth - margin * 2; let y = margin; // Start Y position // --- Helper Function to add sections and handle page breaks --- const addSection = (title, text, isFirstSection = false) => { if (!text || text.trim() === '') return; // Skip empty sections const titleHeight = 25; const spaceAfterTitle = 15; // Check if there's enough space for the title if (y + titleHeight > pageHeight - margin) { pdf.addPage(); y = margin; } // Add section title pdf.setFontSize(isFirstSection ? 12 : 16); pdf.setFont('helvetica', 'bold'); pdf.text(title, margin, y); y += isFirstSection ? 0 : titleHeight; // Add section text pdf.setFontSize(11); pdf.setFont('helvetica', 'normal'); // The splitTextToSize function is key for word wrapping const lines = pdf.splitTextToSize(text, maxLineWidth); lines.forEach(line => { const lineHeight = 14; // Approximate height for a line of size 11 text // Check if the next line fits on the current page if (y + lineHeight > pageHeight - margin) { pdf.addPage(); y = margin; // Reset Y to top margin on new page } pdf.text(line, margin, y); y += lineHeight; // Move cursor down for next line }); y += 25; // Add space after the section }; // --- Header for the first page --- pdf.setFontSize(26); pdf.setFont('helvetica', 'bold'); pdf.text('My Legacy Letter', pageWidth / 2, y, { align: 'center' }); y += 40; // --- Get Content --- const introduction = getElem('introduction-text')?.value; const lessons = getElem('lessons-text')?.value; const memories = getElem('memories-text')?.value; const hopes = getElem('hopes-text')?.value; const closing = getElem('closing-text')?.value; // --- Build PDF Document --- addSection('', introduction, true); // The introduction doesn't need a title addSection('Life Lessons & Values', lessons); addSection('Cherished Memories', memories); addSection('Hopes & Wishes for the Future', hopes); addSection('Closing Remarks', closing); // --- Footer with Page Numbers --- const pageCount = pdf.internal.getNumberOfPages(); for (let i = 1; i <= pageCount; i++) { pdf.setPage(i); pdf.setFontSize(9); pdf.setFont('helvetica', 'italic'); pdf.text(`Page ${i} of ${pageCount}`, pageWidth / 2, pageHeight - 20, { align: 'center' }); } // --- Save PDF --- pdf.save('legacy-letter.pdf'); } catch (error) { console.error("Failed to generate PDF:", error); // Use a more user-friendly modal in a real app instead of alert alert("An error occurred while generating the PDF. Please try again."); } finally { // Revert button to normal state if (btnText) btnText.classList.remove('hidden'); if (btnSpinner) btnSpinner.classList.add('hidden'); downloadPdfBtn.disabled = false; } }); // Initialize the first tab showTab(1); });