[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 += `- ${item}
`;
});
imagePlacements.filter(img => img.panel.toUpperCase() === panelName.toUpperCase()).forEach(img => {
outlineHTML += `- [VISUAL: ${img.description} (${img.size})]
`;
});
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();
});