Scientific Presentation Planner Generator

Scientific Presentation Planner

This is your log of saved presentation plans. Click any cell (except 'Action') to edit the data.

Presentation Title Event/Conference Date Status Action

Build your presentation plan below. Add content and allocate time for each section.

Time Planned
0 min
Time Remaining
20 min

Click 'Add to Section' to append a block of text to the 'Presentation Builder' tab.

Manage the reusable text blocks for the 'Content Library' tab.

Add New Text Block

Current Library

Name Section Content Action

${prompt.content.substring(0, 60)}...

`; libraryList.appendChild(div); }); } }; // --- EVENT HANDLERS (TAB 1 - DASHBOARD) --- logBody.addEventListener('blur', (e) => { if (e.target.isContentEditable) { const id = parseInt(e.target.dataset.id, 10); const prop = e.target.dataset.prop; const newValue = e.target.textContent.trim(); const itemIndex = presentationLog.findIndex(item => item.id === id); if (itemIndex > -1 && prop) { presentationLog[itemIndex][prop] = newValue; } } }, true); // Use capture phase logBody.addEventListener('click', (e) => { if (e.target.classList.contains('spp-btn-delete')) { const id = parseInt(e.target.dataset.id, 10); // No confirm() per spec presentationLog = presentationLog.filter(item => item.id !== id); renderLogTable(); } }); // PDF for Tab 1 (Log) downloadLogPdfBtn.addEventListener('click', () => { if (typeof jspdf === 'undefined' || typeof jspdf.autoTable === 'undefined') { alert('PDF libraries not loaded. Please check your connection.'); return; } const { jsPDF } = jspdf; const doc = new jsPDF(); const head = [['Title', 'Event', 'Date', 'Status']]; const body = presentationLog.map(item => [item.name, item.event, item.date, item.status]); doc.setFontSize(18); doc.text("Saved Presentation Plans Log", 14, 22); jsPDF.autoTable.default(doc, { startY: 30, head: head, body: body, theme: 'grid' }); doc.save('presentation-plan-log.pdf'); }); // --- EVENT HANDLERS (TAB 2 - BUILDER) --- const updatePlannedTime = () => { let totalPlanned = 0; timeInputs.forEach(input => { totalPlanned += parseFloat(input.value) || 0; }); const totalAllotted = parseFloat(totalAllottedInput.value) || 0; const remaining = totalAllotted - totalPlanned; totalTimeDisplay.textContent = `${totalPlanned} min`; remainingTimeDisplay.textContent = `${remaining} min`; // Update color based on remaining time remainingTimeDisplay.classList.remove('text-green-600', 'text-yellow-600', 'text-red-600', 'text-gray-700'); if (remaining === 0) { remainingTimeDisplay.classList.add('text-green-600'); } else if (remaining < 0) { remainingTimeDisplay.classList.add('text-red-600'); } else if (remaining < totalAllotted * 0.1) { remainingTimeDisplay.classList.add('text-yellow-600'); } else { remainingTimeDisplay.classList.add('text-gray-700'); } }; document.getElementById('spp-builder-tab').addEventListener('input', (e) => { if (e.target.classList.contains('spp-time-input') || e.target.id === 'spp-total-allotted') { updatePlannedTime(); } }); saveToLogBtn.addEventListener('click', () => { const name = titleInput.value.trim(); const event = eventInput.value.trim(); if (!name) { alert('Please enter a Presentation Title to save to the log.'); return; } const newId = (presentationLog.length > 0 ? Math.max(...presentationLog.map(i => i.id)) : 0) + 1; presentationLog.push({ id: newId, name: name, event: event || 'N/A', date: new Date().toISOString().split('T')[0], status: "Draft" }); renderLogTable(); // Switch to dashboard (Spec II.B.4.o) tabs[0].click(); }); // PDF for Tab 2 (Proposal) downloadPlanPdfBtn.addEventListener('click', () => { if (typeof jspdf === 'undefined') { alert('PDF library not loaded. Please check your connection.'); return; } try { const { jsPDF } = jspdf; const doc = new jsPDF(); const margin = 15; const maxWidth = doc.internal.pageSize.width - (margin * 2); let y = 22; // Start y-position // Helper to add a section with line wrapping const addSection = (title, content, time) => { if (!content && !time) return; // Skip empty sections // Check for page break const titleHeight = 10; const contentLines = content ? doc.splitTextToSize(content, maxWidth - 25) : ['']; // Indent content const contentHeight = (contentLines.length * 5) + 8; if (y + titleHeight + contentHeight > doc.internal.pageSize.height - margin) { doc.addPage(); y = 22; } doc.setFontSize(14); doc.setFont('helvetica', 'bold'); doc.setTextColor('#007bff'); // Blue title doc.text(title, margin, y); if (time) { doc.setFontSize(11); doc.setFont('helvetica', 'italic'); doc.setTextColor('#555555'); doc.text(`(${time} min)`, doc.internal.pageSize.width - margin, y, { align: 'right' }); } y += titleHeight; if(content) { doc.setFontSize(11); doc.setFont('helvetica', 'normal'); doc.setTextColor('#333333'); doc.text(contentLines, margin + 5, y); // Indent content y += (contentLines.length * 5) + 8; // 5 is line height, 8 is padding } else { y += 8; } }; // --- Build the PDF --- doc.setFontSize(20); doc.setFont('helvetica', 'bold'); doc.setTextColor('#333333'); const title = titleInput.value || "Untitled Presentation"; const titleLines = doc.splitTextToSize(title, maxWidth); doc.text(titleLines, margin, y); y += (titleLines.length * 8) + 5; doc.setFontSize(12); doc.setFont('helvetica', 'normal'); doc.setTextColor('#555555'); const event = eventInput.value || "No Event"; doc.text(event, margin, y); y += 10; doc.setDrawColor(200, 200, 200); doc.line(margin, y, doc.internal.pageSize.width - margin, y); // Horizontal line y += 10; // Add sections const times = Array.from(timeInputs).map(input => input.value); addSection("Introduction / Background", sectionInputs.Introduction.value, times[0]); addSection("Methods / Approach", sectionInputs.Methods.value, times[1]); addSection("Results / Key Findings", sectionInputs.Results.value, times[2]); addSection("Conclusion / Future Work", sectionInputs.Conclusion.value, times[3]); addSection("Acknowledgements / Q&A", sectionInputs.Acknowledgements.value, times[4]); // Add summary y += 5; doc.line(margin, y, doc.internal.pageSize.width - margin, y); y += 10; doc.setFontSize(12); doc.setFont('helvetica', 'bold'); doc.setTextColor('#333333'); doc.text(`Total Time Planned: ${totalTimeDisplay.textContent}`, margin, y); doc.text(`Time Remaining: ${remainingTimeDisplay.textContent}`, doc.internal.pageSize.width - margin, y, { align: 'right' }); doc.save('presentation-plan.pdf'); } catch(e) { console.error('SGP Tool: Error generating plan PDF:', e); alert('An error occurred while generating the PDF.'); } }); // --- EVENT HANDLERS (TAB 3 - LIBRARY) --- filterSection.addEventListener('change', renderLibrary); libraryList.addEventListener('click', (e) => { const btn = e.target.closest('.spp-btn-add'); if (!btn) return; const id = parseInt(btn.dataset.id, 10); const prompt = promptDatabase.find(p => p.id === id); if (!prompt) return; const targetTextarea = sectionInputs[prompt.section]; if (targetTextarea) { targetTextarea.value += (targetTextarea.value ? '\n\n' : '') + prompt.content; // Switch to builder (Tab 2) tabs[1].click(); } }); // --- EVENT HANDLERS (TAB 4 - CONFIG) --- addBlockBtn.addEventListener('click', () => { const name = newNameInput.value.trim(); const section = newSectionSelect.value; const content = newContentInput.value.trim(); if (!name || !section || !content) { alert('Please fill in all fields.'); return; } const newId = (promptDatabase.length > 0 ? Math.max(...promptDatabase.map(p => p.id)) : 0) + 1; promptDatabase.push({ id: newId, name, section, content }); renderConfigTable(); configForm.reset(); }); configBody.addEventListener('click', (e) => { if (e.target.classList.contains('spp-btn-delete')) { const id = parseInt(e.target.dataset.id, 10); // No confirm() per spec promptDatabase = promptDatabase.filter(item => item.id !== id); renderConfigTable(); } }); // --- INITIALIZATION --- const init = () => { // Initial Renders renderLogTable(); renderConfigTable(); updatePlannedTime(); // Set up tabs updateNavButtons(); // Show the first tab on load if (tabs.length > 0) { sppShowTab('spp-dashboard-tab', tabs[0]); } }; init(); });
Scroll to Top