diff --git a/index.html b/index.html new file mode 100644 index 0000000..fbef72e --- /dev/null +++ b/index.html @@ -0,0 +1,127 @@ + + + + + + + Python By Example | Interactive Learning Docs + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+
+

Python Mastery v1.0.0

+ +

Complete roadmap for mastering Python, structured for clarity and professional growth. +

+
+ +
+ +
+
+
+
+
+ + + + + + + \ No newline at end of file diff --git a/script.js b/script.js new file mode 100644 index 0000000..e33d05a --- /dev/null +++ b/script.js @@ -0,0 +1,353 @@ +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'); + } + }); + }); +}); diff --git a/style.css b/style.css new file mode 100644 index 0000000..e85a5ec --- /dev/null +++ b/style.css @@ -0,0 +1,497 @@ +:root { + --bg-main: #0d1117; + --bg-side: #010409; + --border-color: #30363d; + --text-primary: #c9d1d9; + --text-secondary: #8b949e; + --accent: #58a6ff; + --accent-bg: rgba(56, 139, 253, 0.15); + --code-bg: #161b22; + --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif; + --font-mono: 'Fira Code', ui-monospace, SFMono-Regular, SF Mono, Menlo, Consolas, Liberation Mono, monospace; +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + background-color: var(--bg-main); + color: var(--text-primary); + font-family: var(--font-sans); + line-height: 1.6; + overflow-x: hidden; +} + +/* Navigation */ +.top-nav { + position: sticky; + top: 0; + background: var(--bg-side); + border-bottom: 1px solid var(--border-color); + padding: 12px 0; + z-index: 1000; +} + +.nav-container { + max-width: 1400px; + margin: 0 auto; + display: flex; + justify-content: space-between; + align-items: center; + padding: 0 40px; +} + +.logo { + font-weight: 700; + font-size: 1.25rem; + display: flex; + align-items: center; + gap: 10px; +} + +.logo span span { + color: var(--accent); +} + +.search-box { + position: relative; + width: 300px; +} + +.search-box i { + position: absolute; + left: 12px; + top: 50%; + transform: translateY(-50%); + color: var(--text-secondary); +} + +.search-box input { + width: 100%; + background: var(--code-bg); + border: 1px solid var(--border-color); + border-radius: 6px; + padding: 8px 12px 8px 36px; + color: var(--text-primary); + outline: none; + transition: 0.2s; +} + +.search-box input:focus { + border-color: var(--accent); + box-shadow: 0 0 0 3px var(--accent-bg); +} + +/* Layout */ +.app-layout { + display: flex; + max-width: 1400px; + margin: 40px auto; + padding: 0 40px; +} + +.sidebar { + width: 280px; + position: sticky; + top: 100px; + height: calc(100vh - 120px); + overflow-y: auto; + padding-right: 20px; +} + +.sidebar-header { + font-size: 0.8rem; + text-transform: uppercase; + color: var(--text-secondary); + letter-spacing: 0.05em; + font-weight: 700; + margin-bottom: 16px; +} + +.toc-nav { + display: flex; + flex-direction: column; + gap: 8px; +} + +.toc-link { + text-decoration: none; + color: var(--text-secondary); + font-size: 0.95rem; + padding: 6px 12px; + border-radius: 6px; + transition: 0.2s; +} + +.toc-link:hover, +.toc-link.active { + color: var(--text-primary); + background: var(--code-bg); +} + +.toc-link.active { + border-left: 2px solid var(--accent); + border-radius: 0 6px 6px 0; +} + +.content-area { + flex: 1; + max-width: 900px; + margin-left: 40px; +} + +/* Header & Typography */ +.readme-header { + border-bottom: 1px solid var(--border-color); + padding-bottom: 32px; + margin-bottom: 40px; +} + +.readme-header h1 { + font-size: 2.5rem; + margin-bottom: 16px; +} + +.version { + font-size: 1rem; + color: var(--text-secondary); + font-weight: 400; + background: var(--code-bg); + padding: 4px 10px; + border-radius: 40px; + margin-left: 12px; +} + +.lead { + font-size: 1.25rem; + color: var(--text-secondary); +} + +.badges { + display: flex; + gap: 12px; + margin-bottom: 24px; +} + +.badge { + padding: 4px 12px; + border-radius: 40px; + font-size: 0.75rem; + font-weight: 600; +} + +.badge-blue { + background: #053b6d; + color: #58a6ff; +} + +.badge-green { + background: #1b4721; + color: #7ee787; +} + +.badge-purple { + background: #4c2889; + color: #d2a8ff; +} + +/* Sections */ +.doc-section { + margin-bottom: 60px; + scroll-margin-top: 100px; +} + +.doc-section h2 { + font-size: 1.75rem; + border-bottom: 1px solid var(--border-color); + padding-bottom: 12px; + margin-bottom: 24px; +} + +.doc-section p { + margin-bottom: 20px; +} + +.module-card { + background: var(--code-bg); + border: 1px solid var(--border-color); + border-radius: 12px; + padding: 24px; + margin-bottom: 24px; + transition: 0.2s; +} + +.module-card:hover { + border-color: var(--accent); +} + +.module-meta { + display: flex; + justify-content: space-between; + margin-top: 20px; + color: var(--text-secondary); + font-size: 0.85rem; +} + +/* Skeleton */ +.skeleton-line { + height: 16px; + background: var(--code-bg); + border-radius: 4px; + margin-bottom: 12px; + animation: pulse 1.5s infinite; +} + +.skeleton-section { + height: 200px; + background: var(--code-bg); + border-radius: 12px; + margin-bottom: 40px; + animation: pulse 1.5s infinite; +} + +@keyframes pulse { + 0% { + opacity: 0.5; + } + + 50% { + opacity: 0.8; + } + + 100% { + opacity: 0.5; + } +} + +/* Modal & Playground */ +.modal { + display: none; + position: fixed; + z-index: 2000; + left: 0; + top: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.85); + backdrop-filter: blur(8px); + align-items: center; + justify-content: center; +} + +.modal.active { + display: flex; +} + +.modal-content { + background: var(--bg-side); + width: 90%; + max-width: 1200px; + height: 85vh; + border-radius: 16px; + border: 1px solid var(--border-color); + display: flex; + flex-direction: column; + overflow: hidden; + box-shadow: 0 30px 60px rgba(0, 0, 0, 0.5); +} + +.modal-header { + background: var(--bg-main); + padding: 16px 24px; + border-bottom: 1px solid var(--border-color); + display: flex; + justify-content: space-between; + align-items: center; +} + +.file-info { + display: flex; + align-items: center; + gap: 12px; + font-weight: 600; +} + +.file-info i { + color: var(--accent); +} + +.header-actions { + display: flex; + gap: 16px; + align-items: center; +} + +.btn-run { + background: var(--accent); + color: white; + border: none; + padding: 8px 20px; + border-radius: 6px; + font-weight: 600; + cursor: pointer; + transition: 0.2s; + display: flex; + align-items: center; + gap: 8px; +} + +.btn-run:hover { + opacity: 0.9; + transform: translateY(-1px); +} + +.btn-run:disabled { + background: var(--text-secondary); + cursor: not-allowed; +} + +.btn-ghost { + background: transparent; + border: 1px solid var(--border-color); + color: var(--text-secondary); + padding: 8px 16px; + border-radius: 6px; + font-weight: 600; + cursor: pointer; + transition: 0.2s; + display: flex; + align-items: center; + gap: 8px; +} + +.btn-ghost:hover { + color: var(--text-primary); + background: var(--code-bg); + border-color: var(--text-secondary); +} + +.btn-ghost.active { + color: var(--accent); + border-color: var(--accent); + background: var(--accent-bg); +} + +.close-modal { + background: transparent; + border: none; + color: var(--text-secondary); + font-size: 1.25rem; + cursor: pointer; +} + +/* Monaco Editor Container */ +#monaco-editor-container { + height: 100%; + width: 100%; +} + +.playground-body { + flex: 1; + display: grid; + grid-template-columns: 1fr 400px; + overflow: hidden; +} + +.editor-pane { + position: relative; + background: #1e1e1e; + overflow: hidden; + /* Monaco handles scroll */ +} + +/* Individual Lesson Hover */ +.lesson-item { + background: transparent; + transition: all 0.2s ease; +} + +.lesson-item:hover { + background: var(--accent-bg) !important; + padding-left: 16px !important; + /* Slight organic slide effect */ +} + +.editor-pane.edit-active { + outline: 2px solid var(--accent); + outline-offset: -2px; +} + +.output-pane { + background: #010409; + border-left: 1px solid var(--border-color); + display: flex; + flex-direction: column; +} + +.output-header { + background: var(--bg-main); + padding: 8px 16px; + font-size: 0.75rem; + text-transform: uppercase; + font-weight: 700; + color: var(--text-secondary); + border-bottom: 1px solid var(--border-color); +} + +#output-area { + flex: 1; + padding: 16px; + margin: 0; + font-family: var(--font-mono); + font-size: 0.9rem; + color: #a5d6ff; + overflow-y: auto; + white-space: pre-wrap; + word-break: break-all; +} + +/* Scrollbar Style */ +::-webkit-scrollbar { + width: 10px; + height: 10px; +} + +::-webkit-scrollbar-track { + background: var(--bg-side); +} + +::-webkit-scrollbar-thumb { + background: var(--border-color); + border-radius: 5px; +} + +::-webkit-scrollbar-thumb:hover { + background: var(--text-secondary); +} + +/* Footer */ +.docs-footer { + border-top: 1px solid var(--border-color); + padding: 40px 0; + margin-top: 80px; + text-align: center; +} + +@media (max-width: 992px) { + .sidebar { + display: none; + } + + .content-area { + margin-left: 0; + } + + .playground-body { + grid-template-columns: 1fr; + grid-template-rows: 1fr 250px; + } + + .output-pane { + border-left: none; + border-top: 1px solid var(--border-color); + } +} \ No newline at end of file