Family History Narrative Outline Builder

Family History Narrative Outline Builder

Narrative Metadata

The central idea or theme that unites the story (e.g., resilience, immigration, love).

Define Major Chapters (Chronological or Thematic)

Chapter List (Drag to Reorder)

Detail Scenes, Quotes, and Key Facts

Scene Details List

Review your complete narrative outline and export options.

Click "Next" or "Previous" to refresh this preview.

${escapeHTML(data.thesis)}

II. Chapter Outline

${outlineHTML || '

Please define chapters in Tab 2.

'} `; }; const downloadTxt = () => { const data = getPlanData(); let content = `FAMILY HISTORY NARRATIVE OUTLINE\n`; content += "========================================\n"; content += `Title: ${data.title}\n`; content += `Subject: ${data.subject}\n`; content += `Period: ${data.timePeriod}\n`; content += "========================================\n\n"; content += "I. NARRATIVE THESIS/THEME\n"; content += `${data.thesis}\n\n`; content += "II. CHAPTER OUTLINE\n"; data.chapters.forEach((chap, chapIndex) => { content += `\nCHAPTER ${chapIndex + 1}: ${chap.name.toUpperCase()}\n`; content += "----------------------------------------\n"; if (chap.scenes.length === 0) { content += " (No scenes defined)\n"; return; } chap.scenes.forEach((scene, sceneIndex) => { content += ` ${sceneIndex + 1}. SCENE: ${scene.text.split('\n')[0]}\n`; content += ` Source: ${scene.source}\n`; }); }); const blob = new Blob([content], { type: 'text/plain;charset=utf-8' }); const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = `${data.title.replace(/ /g, '_')}_outline.txt`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(a.href); }; const downloadPDF = () => { if (typeof window.jspdf === 'undefined' || typeof window.jspdf.jsPDF === 'undefined') { alert('Error: jsPDF library not loaded.'); return; } const { jsPDF } = window.jspdf; const doc = new jsPDF('p', 'mm', 'a4'); const data = getPlanData(); const margin = 20; const pageWidth = doc.internal.pageSize.getWidth(); const usableWidth = pageWidth - margin * 2; let yPos = 20; const addWrappedText = (text, size, style, color = [52, 73, 94], lineSpacing = 6, indent = 0) => { doc.setFontSize(size); doc.setFont(undefined, style); doc.setTextColor(color[0], color[1], color[2]); const splitText = doc.splitTextToSize(text, usableWidth - indent); if (yPos + (splitText.length * lineSpacing) > 280) { doc.addPage(); yPos = 20; } doc.text(splitText, margin + indent, yPos); yPos += (splitText.length * lineSpacing); return splitText.length; }; // 1. Title & Metadata addWrappedText(data.title.toUpperCase(), 18, 'bold', [44, 62, 80], 8, 0); yPos -= 5; addWrappedText(`Subject: ${data.subject} | Period: ${data.timePeriod}`, 10, 'normal', [108, 117, 125], 5, 0); yPos += 10; // 2. Thesis addWrappedText("I. NARRATIVE THESIS/THEME", 14, 'bold', [139, 92, 246]); yPos += 2; addWrappedText(data.thesis, 11, 'normal'); yPos += 5; // 3. Chapters and Scenes addWrappedText("II. CHAPTER OUTLINE", 14, 'bold', [139, 92, 246]); yPos += 2; data.chapters.forEach((chap, chapIndex) => { // Chapter Header yPos += 3; addWrappedText(`CHAPTER ${chapIndex + 1}: ${chap.name.toUpperCase()}`, 12, 'bold', [44, 62, 80]); yPos -= 1; if (chap.scenes.length === 0) { addWrappedText("(No scenes or key details defined for this chapter.)", 10, 'italic', [108, 117, 125], 5, 5); return; } chap.scenes.forEach((scene, sceneIndex) => { yPos += 1; const sceneText = `${sceneIndex + 1}. ${scene.text.split('\n')[0]}...`; // Scene Text (Bold) addWrappedText(sceneText, 10, 'bold', [52, 73, 94], 5, 5); yPos -= 2; // Source (Italic) addWrappedText(`Source: ${scene.source}`, 9, 'italic', [108, 117, 125], 4, 15); yPos -= 1; }); yPos += 3; // Space between chapters }); doc.save(`${data.title.replace(/ /g, '_')}_narrative_outline.pdf`); }; // --- Event Listeners --- // Tab 2 Listeners chapterInputs.addBtn.addEventListener('click', addChapter); chapterInputs.list.addEventListener('click', (e) => { if (e.target.dataset.removeId) { removeChapter(parseInt(e.target.dataset.removeId)); } }); // Tab 3 Listeners sceneInputs.addBtn.addEventListener('click', addScene); sceneInputs.list.addEventListener('click', (e) => { if (e.target.dataset.removeSceneId) { removeScene(parseInt(e.target.dataset.removeSceneId)); } }); // Tab 4 Listeners refreshBtn.addEventListener('click', generatePreview); downloadPdfBtn.addEventListener('click', downloadPDF); downloadTxtBtn.addEventListener('click', downloadTxt); // Global Navigation nextBtn.addEventListener('click', () => showTab(currentTab + 1)); prevBtn.addEventListener('click', () => showTab(currentTab - 1)); // --- Initialization --- showTab(1); // Set initial state });
Scroll to Top