Course Syllabus Generator

Course Syllabus Generator

Live Syllabus Preview

Grading Scale

Course Policies

${policies.replace(/\n/g, '
')}

`; } // --- Event Handlers --- tabContainer.addEventListener('click', (e) => { if (e.target.matches('.tab-button')) { currentTabIndex = tabs.indexOf(e.target.dataset.tab); switchTab(); } }); nextBtn.addEventListener('click', () => { if (currentTabIndex < tabs.length - 1) { currentTabIndex++; switchTab(); } }); prevBtn.addEventListener('click', () => { if (currentTabIndex > 0) { currentTabIndex--; switchTab(); } }); addWeekBtn.addEventListener('click', () => { syllabusData.schedule.push({ topic: '', assignments: '' }); renderSchedule(); }); addGradeBtn.addEventListener('click', () => { syllabusData.grading.push({ grade: '', range: '' }); renderGradingScale(); }); aiButtons.forEach(btn => btn.addEventListener('click', handleAIGeneration)); // --- Navigation --- function switchTab() { document.querySelectorAll('.tab-button').forEach(btn => btn.classList.remove('active')); document.querySelectorAll('.tab-content').forEach(content => content.classList.remove('active')); const newTabName = tabs[currentTabIndex]; document.querySelector(`.tab-button[data-tab="${newTabName}"]`).classList.add('active'); document.getElementById(`${newTabName}Content`).classList.add('active'); updateNavButtons(); } function updateNavButtons() { prevBtn.style.visibility = currentTabIndex === 0 ? 'hidden' : 'visible'; nextBtn.style.visibility = currentTabIndex === tabs.length - 1 ? 'hidden' : 'visible'; } // --- AI Generation --- async function handleAIGeneration(e) { const btn = e.currentTarget; const originalContent = btn.innerHTML; btn.innerHTML = ''; btn.disabled = true; const targetId = btn.dataset.target; const promptSourceId = btn.dataset.promptSource; const targetIndex = btn.dataset.targetIndex; const targetField = btn.dataset.targetField; let prompt = ''; if (targetId === 'courseDescription') { const title = document.getElementById(promptSourceId).value; prompt = `Generate a concise, one-paragraph course description for a university course titled "${title}".`; } else if (targetId === 'coursePolicies') { prompt = 'Generate a standard, generic course policy section for a university syllabus, including points on academic integrity, attendance, and late submissions. Format it with newlines.'; } else if (targetIndex !== undefined && targetField === 'topic') { const courseTitle = syllabusData.info.title; prompt = `For a university course titled "${courseTitle}", suggest a single, concise topic for Week ${parseInt(targetIndex)+1}.`; } try { const response = await callGemini(prompt); if (targetId) { document.getElementById(targetId).value = response; // Manually trigger input event to update state document.getElementById(targetId).dispatchEvent(new Event('input')); } else { // For dynamic weekly topics syllabusData.schedule[targetIndex][targetField] = response; renderSchedule(); updateSyllabusView(); } } catch (error) { console.error("AI Generation Error:", error); alert("Failed to generate content. Please try again."); } finally { btn.innerHTML = originalContent; btn.disabled = false; } } async function callGemini(prompt) { const apiKey = ""; // Handled by environment const apiUrl = `https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-preview-05-20:generateContent?key=${apiKey}`; const payload = { contents: [{ role: "user", parts: [{ text: prompt }] }] }; const response = await fetch(apiUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); if (!response.ok) throw new Error(`API Error: ${response.status}`); const data = await response.json(); return data.candidates[0].content.parts[0].text; } // --- PDF Generation --- function downloadPDF() { const { jsPDF } = window.jspdf; const doc = new jsPDF(); const { info, schedule, policies, grading } = syllabusData; const margin = 15; const pageWidth = doc.internal.pageSize.getWidth(); let y = 0; // Header doc.setFont('helvetica', 'bold'); doc.setFontSize(20); doc.text(info.title, pageWidth / 2, 20, { align: 'center' }); doc.setFontSize(14); doc.setFont('helvetica', 'normal'); doc.text(info.code, pageWidth / 2, 28, { align: 'center' }); y = 40; // Info doc.setFontSize(11); doc.text(`Instructor: ${info.instructor}`, margin, y); doc.text(`Email: ${info.email}`, margin, y + 6); y += 18; // Description doc.setFont('helvetica', 'bold'); doc.text('Course Description', margin, y); y += 6; doc.setFont('helvetica', 'normal'); const descLines = doc.splitTextToSize(info.description, pageWidth - margin * 2); doc.text(descLines, margin, y); y += descLines.length * 5 + 5; // Schedule doc.autoTable({ startY: y, head: [['Week', 'Topic', 'Assignments & Readings']], body: schedule.map((w, i) => [`Week ${i + 1}`, w.topic, w.assignments]), headStyles: { fillColor: [37, 99, 235] } }); y = doc.lastAutoTable.finalY + 10; // Grading and Policies const gradingBody = grading.map(g => [g.grade, g.range]); doc.autoTable({ startY: y, head: [['Grade', 'Range']], body: gradingBody, headStyles: { fillColor: [37, 99, 235] }, tableWidth: 80, margin: { left: margin } }); const policiesX = margin + 80 + 10; doc.setFont('helvetica', 'bold'); doc.text('Course Policies', policiesX, y); doc.setFont('helvetica', 'normal'); const policyLines = doc.splitTextToSize(policies, pageWidth - policiesX - margin); doc.text(policyLines, policiesX, y + 8); doc.save(`${info.code}_Syllabus.pdf`); } // --- Run on Load --- initialize(); });
Scroll to Top