Folklore Tale Type Index Card Creator
Basic Tale Information
Aarne-Thompson-Uther (ATU) Index
The specific number for the entire tale type (e.g., ATU 510A).
List the most critical motifs (e.g., F823.2, D1055, R221).
Synopsis and Analysis
A short summary of the narrative, focusing on key events.
Any unique cultural details, historical parallels, or variants (e.g., Ash-Girl, Rhodopis).
Review the final Index Card format.
Click "Refresh Preview" to generate the card.
${escapeHTML(data.plotSynopsis)}
CULTURAL NOTES
${escapeHTML(data.culturalContext)}
`; }; const downloadTxt = () => { const data = getReportData(); let content = `FOLKLORE INDEX CARD: ${data.title.toUpperCase()}\n`; content += "========================================\n\n"; content += "IDENTIFICATION\n"; content += `Tale Title: ${data.title}\n`; content += `Collected By: ${data.collectedBy}\n`; content += `Origin Region: ${data.originCountry}\n`; content += `Narrative Group: ${data.narrativeGroup}\n\n`; content += "CLASSIFICATION (ATU/MOTIF)\n"; content += `ATU Number: ${data.atuNumber}\n`; content += `Tale Type Summary: ${data.taleTypeSummary}\n`; content += `Key Motifs: ${data.commonMotifs}\n\n`; content += "SYNOPSIS\n"; content += `${data.plotSynopsis}\n\n`; content += "CULTURAL NOTES\n"; content += `${data.culturalContext}\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, '_')}_index_card.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', 'a5'); // A5 for card size feel const data = getReportData(); const margin = 10; const pageWidth = doc.internal.pageSize.getWidth(); const usableWidth = pageWidth - margin * 2; let yPos = 15; const addWrappedText = (text, size, style, color = [52, 73, 94], indent = 0) => { doc.setFontSize(size); doc.setFont('times', style); doc.setTextColor(color[0], color[1], color[2]); const splitText = doc.splitTextToSize(text, usableWidth - indent); if (yPos + (splitText.length * 5) > 140) { doc.addPage('a5'); yPos = 15; } doc.text(splitText, margin + indent, yPos); yPos += (splitText.length * 5) + 3; }; const addSectionHeader = (title) => { yPos += 5; doc.setFontSize(11); doc.setFont('times', 'bold'); doc.setTextColor(44, 62, 80); doc.text(title.toUpperCase(), margin, yPos); doc.setDrawColor(224, 224, 224); doc.line(margin, yPos + 1, pageWidth - margin, yPos + 1); yPos += 6; }; // --- Build PDF Document --- // 1. Title Block doc.setFontSize(18); doc.setFont('times', 'bold'); doc.setTextColor(156, 79, 26); doc.text(data.title.toUpperCase(), pageWidth / 2, yPos, { align: 'center' }); yPos += 10; // Metadata Row doc.setFontSize(9); doc.setFont('times', 'normal'); doc.setTextColor(108, 117, 125); doc.text(`COLLECTED BY: ${data.collectedBy}`, margin, yPos); doc.text(`REGION: ${data.originCountry} | GROUP: ${data.narrativeGroup}`, pageWidth - margin, yPos, { align: 'right' }); yPos += 5; doc.setDrawColor(224, 224, 224); doc.line(margin, yPos, pageWidth - margin, yPos); yPos += 5; // 2. Classification addSectionHeader("CLASSIFICATION DATA"); addWrappedText(`ATU Index Number: ${data.atuNumber}`, 10, 'bold', [52, 73, 94], 5); addWrappedText(`Tale Type Summary: ${data.taleTypeSummary}`, 10, 'normal', [52, 73, 94], 5); addWrappedText(`Key Motifs: ${data.commonMotifs}`, 10, 'normal', [52, 73, 94], 5); yPos += 5; // 3. Synopsis addSectionHeader("SYNOPSIS"); addWrappedText(data.plotSynopsis, 10, 'normal', [52, 73, 94], 5); yPos += 5; // 4. Cultural Context addSectionHeader("CULTURAL NOTES"); addWrappedText(data.culturalContext, 10, 'normal', [52, 73, 94], 5); doc.save('folklore_index_card.pdf'); }; // --- Event Listeners --- // Global Navigation tabButtons.forEach((btn, index) => { btn.addEventListener('click', () => showTab(index + 1)); }); nextBtn.addEventListener('click', () => showTab(currentTab + 1)); prevBtn.addEventListener('click', () => showTab(currentTab - 1)); // Tab 4 Actions refreshBtn.addEventListener('click', generatePreview); downloadPdfBtn.addEventListener('click', downloadPDF); downloadTxtBtn.addEventListener('click', downloadTxt); // --- Initialization --- showTab(1); // Set initial state });