Science Project Planner Generator

Science Project Planner Generator

1. Project Details
2. Panel Content Layout

Outline the key text and visual sections for each panel.

LEFT PANEL (Scientific Method Start)

CENTER PANEL (Core Results & Conclusions)

RIGHT PANEL (Execution & Data)

1. Design & Color Palette

2. Image & Graphic Placements

Description Panel Size Actions

LEFT PANEL (30%)

Content & Variables

PROJECT TITLE

Data & Results

RIGHT PANEL (30%)

Procedure & Materials

Structured Content Outline

Content structure will appear here upon generating the sheet.

[GRAPHIC: ${img.description} (${img.size})]

`; }); }; // Update the visual panels updatePanelPreview(previewPanelLeftEl, content.left, 'LEFT'); updatePanelPreview(previewPanelCenterEl, content.center, 'CENTER'); updatePanelPreview(previewPanelRightEl, content.right, 'RIGHT'); // --- 2. Structured Outline Update (Text) --- let outlineHTML = `

Project: ${meta.projectName} | Student: ${meta.studentName} | Board: ${meta.boardSize.toUpperCase()}


`; const buildSection = (title, contentArray, panelName) => { outlineHTML += `

${title} (${panelName})

    `; contentArray.forEach(item => { outlineHTML += `
  1. ${item}
  2. `; }); imagePlacements.filter(img => img.panel.toUpperCase() === panelName.toUpperCase()).forEach(img => { outlineHTML += `
  3. [VISUAL: ${img.description} (${img.size})]
  4. `; }); outlineHTML += '
'; }; // Order: Center (Top/Abstract), Left, Right buildSection('CENTER PANEL CONTENT (TITLE & CORE)', content.center, 'CENTER'); buildSection('LEFT PANEL CONTENT (RESEARCH & VARIABLES)', content.left, 'LEFT'); buildSection('RIGHT PANEL CONTENT (METHODOLOGY & DATA)', content.right, 'RIGHT'); structuredContentOutline.innerHTML = outlineHTML; // Only switch tab if the button was explicitly pressed from the builder tab if (document.activeElement === generatePlanBtn) { switchTab(2); } } const downloadPDF = () => { const meta = getMeta(); const content = getPanelContent(); const { jsPDF } = window.jspdf; const doc = new jsPDF('p', 'pt', 'a4'); let currentY = 40; const margin = 40; const pageWidth = doc.internal.pageSize.width; const maxWidth = pageWidth - (margin * 2); const checkPageBreak = (spaceNeeded) => { if (currentY + spaceNeeded > doc.internal.pageSize.height - margin) { doc.addPage(); currentY = margin; } }; const addText = (text, size = 11, style = 'normal', color = [0, 0, 0], indent = 0) => { doc.setFontSize(size); doc.setFont('Helvetica', style); doc.setTextColor(color[0], color[1], color[2]); const lines = doc.splitTextToSize(text, maxWidth - indent); checkPageBreak(lines.length * (size * 1.2)); doc.text(lines, margin + indent, currentY); currentY += (lines.length * (size * 1.2)); doc.setTextColor(0); // Reset color }; const addSectionHeader = (title) => { checkPageBreak(30); doc.setFontSize(16); doc.setFont('Helvetica', 'bold'); doc.setTextColor(33, 150, 243); /* Info color */ doc.text(title, margin, currentY); currentY += 10; doc.setLineWidth(0.5); doc.setDrawColor(200); doc.line(margin, currentY, pageWidth - margin, currentY); currentY += 15; doc.setTextColor(0); }; // --- PDF Content --- // Title Block doc.setFontSize(22); doc.setFont('Helvetica', 'bold'); doc.setTextColor(76, 175, 80); /* Primary color */ doc.text("Science Project Plan", pageWidth / 2, currentY, { align: 'center' }); currentY += 15; doc.setFontSize(12); doc.setFont('Helvetica', 'normal'); doc.setTextColor(108, 117, 125); doc.text(`Project: ${meta.projectName} | Student: ${meta.studentName}`, pageWidth / 2, currentY, { align: 'center' }); currentY += 15; doc.text(`Board Type: ${document.getElementById('board-size').value.toUpperCase()} | Target Year: ${new Date().getFullYear()}`, pageWidth / 2, currentY, { align: 'center' }); currentY += 30; doc.setTextColor(0); // --- Content Section --- addSectionHeader("1. Structured Content Outline"); const addContentList = (title, contentArray, panelName) => { checkPageBreak(15); addText(`${title} (${panelName})`, 12, 'bold', [121, 85, 72], 0); /* Secondary color for heading */ contentArray.forEach((item, index) => { addText(`${index + 1}. ${item}`, 11, 'normal', [0, 0, 0], 10); }); imagePlacements.filter(img => img.panel.toUpperCase() === panelName.toUpperCase()).forEach(img => { addText(`[VISUAL: ${img.description} (${img.size})]`, 11, 'bold', [33, 150, 243], 10); /* Info color for graphics */ }); currentY += 10; }; // Order: Center, Left, Right addContentList('CENTER PANEL (Title, Abstract, Results)', content.center, 'CENTER'); addContentList('LEFT PANEL (Introduction, Hypothesis, Variables)', content.left, 'LEFT'); addContentList('RIGHT PANEL (Procedure, Materials, Bibliography)', content.right, 'RIGHT'); // --- Design Section --- addSectionHeader("2. Design & Placement Details"); const designBody = [ ['Primary Accent Color:', meta.primaryColor], ['Secondary Color:', meta.secondaryColor], ['Heading Font:', meta.fontHeading], ['Body Font:', meta.fontBody] ]; doc.autoTable({ startY: currentY, head: [['Design Element', 'Value']], body: designBody, theme: 'grid', headStyles: { fillColor: [200, 200, 200], textColor: [0], fontStyle: 'bold' }, styles: { fontSize: 10, cellPadding: 5, font: 'Helvetica' }, columnStyles: { 0: { fontStyle: 'bold', cellWidth: 150 } } }); currentY = doc.autoTable.previous.finalY + 10; // Image/Graphic Placement List addText("Graphic & Image Placement Log", 12, 'bold', [121, 85, 72]); const imageBody = imagePlacements.map(img => [img.description, img.panel, img.size]); doc.autoTable({ startY: currentY, head: [['Description', 'Panel', 'Size']], body: imageBody, theme: 'grid', headStyles: { fillColor: [76, 175, 80], textColor: [255, 255, 255] }, styles: { fontSize: 10, cellPadding: 4, font: 'Helvetica' } }); currentY = doc.autoTable.previous.finalY + 10; doc.save('science_project_plan.pdf'); } // --- Tab Navigation --- const switchTab = (tabIndex) => { tabs.forEach((tab, index) => { tab.classList.toggle('active', index === tabIndex); contents[index].classList.toggle('active', index === tabIndex); }); currentTab = tabIndex; updateNavButtons(); if (tabIndex === 2) { // Review tab generateDisplayPlan(); } } const updateNavButtons = () => { prevBtn.disabled = currentTab === 0; nextBtn.disabled = currentTab === tabs.length - 1; } // Attach listeners to tab buttons tabs.forEach((tab, index) => { tab.addEventListener('click', () => { // Find actual index based on position in DOM const tabNode = tab.closest('.planner-tab-button'); const newIndex = Array.from(tabNode.parentNode.children).indexOf(tabNode); switchTab(newIndex); }); }); nextBtn.addEventListener('click', () => { if (currentTab < tabs.length - 1) switchTab(currentTab + 1); }); prevBtn.addEventListener('click', () => { if (currentTab > 0) switchTab(currentTab - 1); }); // --- Event Listeners --- generatePlanBtn.addEventListener('click', generateDisplayPlan); pdfDownloadBtn.addEventListener('click', downloadPDF); document.getElementById('design-meta-form').addEventListener('input', generateDisplayPlan); // Update preview on color/font change // --- Initial Setup --- renderImageTable(); updateNavButtons(); // Run preview once to set initial colors/title generateDisplayPlan(); });
Scroll to Top