const documentation = [ { id: "01_basics", title: "01. Python Basics", description: "Fundamental syntax and data types.", icon: "fas fa-seedling", lessons: [ { title: "Print Function", file: "01_basics/01_print.py" }, { title: "Comments", file: "01_basics/02_comments.py" }, { title: "Variables", file: "01_basics/03_variables.py" }, { title: "Data Types", file: "01_basics/04_data_types.py" } ] }, { id: "02_control_flow", title: "02. Control Flow", description: "Conditional logic and selection.", icon: "fas fa-code-branch", lessons: [ { title: "If-Else", file: "02_control_flow/01_if_else.py" }, { title: "Elif", file: "02_control_flow/02_elif.py" }, { title: "Match Case", file: "02_control_flow/03_match_case.py" } ] }, { id: "03_loops", title: "03. Loops & Iterations", description: "Repetitive task automation.", icon: "fas fa-sync", lessons: [ { title: "For Loops", file: "03_loops/01_for_loop.py" }, { title: "While Loops", file: "03_loops/02_while_loop.py" }, { title: "Break & Continue", file: "03_loops/03_break_continue.py" } ] }, { id: "04_data_structures", title: "04. Data Structures", description: "Collections and data management.", icon: "fas fa-database", lessons: [ { title: "Lists", file: "04_data_structures/01_lists.py" }, { title: "Tuples", file: "04_data_structures/02_tuples.py" }, { title: "Sets", file: "04_data_structures/03_sets.py" }, { title: "Dictionaries", file: "04_data_structures/04_dictionaries.py" } ] }, { id: "05_functions", title: "05. Functions", description: "Modular and reusable blocks.", icon: "fas fa-cube", lessons: [ { title: "Function Basics", file: "05_functions/01_function_basics.py" }, { title: "Arguments", file: "05_functions/02_arguments.py" }, { title: "Return Values", file: "05_functions/03_return_values.py" }, { title: "Lambda Functions", file: "05_functions/04_lambda_functions.py" } ] }, { id: "06_modules_packages", title: "06. Modules & Packages", description: "Code organization and imports.", icon: "fas fa-box-open", lessons: [ { title: "Imports", file: "06_modules_packages/01_imports.py" }, { title: "Custom Modules", file: "06_modules_packages/02_custom_modules.py" } ] }, { id: "07_error_handling", title: "07. Error Handling", description: "Robustness and exception safety.", icon: "fas fa-exclamation-triangle", lessons: [ { title: "Try-Except", file: "07_error_handling/01_try_except.py" }, { title: "Custom Exceptions", file: "07_error_handling/02_custom_exceptions.py" } ] }, { id: "08_oop", title: "08. Object Oriented Programming", description: "Classes, objects, and inheritance.", icon: "fas fa-project-diagram", lessons: [ { title: "Classes & Objects", file: "08_oop/01_classes_objects.py" }, { title: "Init Methods", file: "08_oop/02_init_methods.py" }, { title: "Inheritance", file: "08_oop/03_inheritance.py" }, { title: "Polymorphism", file: "08_oop/04_polymorphism.py" } ] }, { id: "09_advanced_python", title: "09. Advanced Python", description: "Generators, decorators, and more.", icon: "fas fa-bolt", lessons: [ { title: "List Comprehensions", file: "09_advanced_python/01_list_comprehensions.py" }, { title: "Generators", file: "09_advanced_python/02_generators.py" }, { title: "Decorators", file: "09_advanced_python/03_decorators.py" }, { title: "Context Managers", file: "09_advanced_python/04_context_managers.py" } ] }, { id: "10_best_practices", title: "10. Best Practices", description: "Clean code and professional PEP 8.", icon: "fas fa-check-double", lessons: [ { title: "PEP 8", file: "10_best_practices/01_pep8.py" }, { title: "Type Hinting", file: "10_best_practices/02_type_hinting.py" }, { title: "Virtual Envs", file: "10_best_practices/03_virtual_envs.py" } ] } ]; let pyodideInstance = null; let editor = null; let originalCode = ""; // Initialize Monaco Editor require.config({ paths: { 'vs': 'https://cdnjs.cloudflare.com/ajax/libs/monaco-editor/0.44.0/min/vs' } }); require(['vs/editor/editor.main'], function () { editor = monaco.editor.create(document.getElementById('monaco-editor-container'), { value: "# Select a lesson to begin...", language: 'python', theme: 'vs-dark', automaticLayout: true, readOnly: true, fontSize: 14, minimap: { enabled: false }, lineNumbers: 'on', scrollBeyondLastLine: false, padding: { top: 20 } }); }); async function initPyodide() { const outputArea = document.getElementById('output-area'); try { pyodideInstance = await loadPyodide(); outputArea.textContent = ">>> Python 3.10 (Pyodide) Ready.\n"; document.getElementById('run-btn').disabled = false; } catch (err) { outputArea.textContent = "Error loading Pyodide: " + err.message; } } async function runPython(code) { const outputArea = document.getElementById('output-area'); if (!pyodideInstance) { outputArea.textContent = ">>> Error: Python environment not yet initialized. Please wait.\n"; return; } outputArea.textContent = "Running...\n"; try { pyodideInstance.setStdout({ batched: (text) => { outputArea.textContent += text + "\n"; } }); await pyodideInstance.runPythonAsync(code); outputArea.textContent += "\n[Execution Complete]"; } catch (err) { outputArea.textContent += "\nTraceback (most recent call last):\n" + err.message; } } document.addEventListener('DOMContentLoaded', () => { initPyodide(); const content = document.getElementById('documentation-content'); const toc = document.getElementById('toc'); const modal = document.getElementById('playground-modal'); const lessonTitle = document.getElementById('lesson-title'); const resetBtn = document.getElementById('reset-btn'); const editBtn = document.getElementById('edit-btn'); const runBtn = document.getElementById('run-btn'); const closeModal = document.querySelector('.close-modal'); content.innerHTML = ''; toc.innerHTML = ''; // Render Documentation documentation.forEach((module) => { const section = document.createElement('section'); section.id = module.id; section.className = 'doc-section'; section.innerHTML = `

${module.title}

${module.description}

`; content.appendChild(section); const tocLink = document.createElement('a'); tocLink.href = `#${module.id}`; tocLink.className = 'toc-link'; tocLink.textContent = module.title; toc.appendChild(tocLink); }); // Handle Lesson Clicks document.addEventListener('click', async (e) => { const item = e.target.closest('.lesson-item'); if (!item) return; const file = item.getAttribute('data-file'); const title = item.getAttribute('data-title'); lessonTitle.textContent = `${title}.py`; modal.classList.add('active'); // Monaco needs layout() called when container becomes visible to display cursor/suggestions correctly setTimeout(() => { if (editor) { editor.layout(); editor.focus(); } }, 100); // Reset edit mode editBtn.classList.remove('active'); editBtn.innerHTML = ' Edit'; if (editor) editor.updateOptions({ readOnly: true }); if (editor) editor.setValue("# Loading source code..."); try { const response = await fetch(file); if (!response.ok) throw new Error("File not found"); const code = await response.text(); originalCode = code; if (editor) { editor.setValue(code); // Force suggestions/intellisense refresh monaco.editor.setModelLanguage(editor.getModel(), 'python'); } } catch (err) { const fallback = `# Error loading file: ${file}\n# serving from github.io might require valid paths.\n\nprint("Hello from Python By Example!")\nname = "Developer"\nprint(f"Happy coding, {name}!")`; originalCode = fallback; if (editor) editor.setValue(fallback); } }); // Edit Toggle editBtn.addEventListener('click', () => { if (!editor) return; const isEditing = editBtn.classList.toggle('active'); editor.updateOptions({ readOnly: !isEditing }); if (isEditing) { editBtn.innerHTML = ' Editing...'; editor.focus(); document.getElementById('output-area').textContent = ">>> Editing mode enabled. You can now modify the code and see suggestions.\n"; } else { editBtn.innerHTML = ' Edit'; document.getElementById('output-area').textContent = ">>> Editing mode disabled.\n"; } }); // Reset Logic resetBtn.addEventListener('click', () => { if (!editor) return; editor.setValue(originalCode); editBtn.classList.remove('active'); editor.updateOptions({ readOnly: true }); editBtn.innerHTML = ' Edit'; document.getElementById('output-area').textContent = ">>> Code reset to original state.\n"; }); // Run Logic runBtn.addEventListener('click', () => { if (editor) runPython(editor.getValue()); }); // Modal Controls closeModal.addEventListener('click', () => modal.classList.remove('active')); modal.addEventListener('click', (e) => { if (e.target === modal) modal.classList.remove('active'); }); // Search Functionality (Improved) const searchInput = document.querySelector('.search-box input'); searchInput.addEventListener('input', (e) => { const query = e.target.value.toLowerCase().trim(); document.querySelectorAll('.doc-section').forEach(section => { const heading = section.querySelector('h2').textContent.toLowerCase(); const desc = section.querySelector('p').textContent.toLowerCase(); const lessonItems = section.querySelectorAll('.lesson-item'); let isSectionVisible = query === "" || heading.includes(query) || desc.includes(query); let matchingLessonsCount = 0; lessonItems.forEach(item => { const lessonText = item.textContent.toLowerCase(); const isLessonMatch = query === "" || lessonText.includes(query); // Show lesson if it matches or if the section title matches const shouldShowLesson = isSectionVisible || isLessonMatch; item.style.setProperty('display', shouldShowLesson ? 'flex' : 'none', 'important'); if (isLessonMatch) matchingLessonsCount++; }); // Show section if title matches or if any lesson inside matches section.style.display = (isSectionVisible || matchingLessonsCount > 0) ? 'block' : 'none'; }); // Sync TOC document.querySelectorAll('.toc-link').forEach(link => { const targetId = link.getAttribute('href').substring(1); const targetSection = document.getElementById(targetId); if (targetSection) { link.style.display = targetSection.style.display === 'none' ? 'none' : 'block'; } }); }); // Scroll Spy window.addEventListener('scroll', () => { let current = ''; document.querySelectorAll('.doc-section').forEach(section => { if (section.style.display !== 'none' && window.pageYOffset >= (section.offsetTop - 150)) { current = section.getAttribute('id'); } }); document.querySelectorAll('.toc-link').forEach(link => { link.classList.remove('active'); if (link.style.display !== 'none' && link.getAttribute('href').substring(1) === current) { link.classList.add('active'); } }); }); });