diff --git a/src/src/components/resources/presentation.astro b/src/src/components/resources/presentation.astro index 302b9f9..786bf85 100644 --- a/src/src/components/resources/presentation.astro +++ b/src/src/components/resources/presentation.astro @@ -1,3 +1,4 @@ +// src/components/resources/presentation.astro @@ -12,6 +13,7 @@ let slides = Array.from(document.querySelectorAll(".presentation-slide")); let slide = 0; + let step = 0; // Current step within the slide let presenter = false; const presentationId = window.location.href; @@ -20,7 +22,6 @@ if (slide === slides.length - 1) { return slide; } - return slide + 1; }; @@ -28,7 +29,6 @@ if (slide === 0) { return slide; } - return slide - 1; }; @@ -38,9 +38,182 @@ const transitionClasses = [nextClass, currClass, prevClass]; - const keyHandlers: Record number> = { - ArrowRight: nextSlide, - ArrowLeft: prevSlide, + // Animation classes for step-through content + const animationClasses = { + 'fade-in': 'animate-fade-in-step', + 'slide-in-left': 'animate-slide-in-left-step', + 'slide-in-right': 'animate-slide-in-right-step', + 'slide-in-up': 'animate-slide-in-up-step', + 'slide-in-down': 'animate-slide-in-down-step', + 'type-in': 'animate-type-in-step', + 'scale-in': 'animate-scale-in-step', + 'bounce-in': 'animate-bounce-in-step' + }; + + const getCurrentSlideSteps = () => { + const currentSlide = slides[slide]; + return Array.from(currentSlide.querySelectorAll('[step]')) + .sort((a, b) => { + const stepA = parseInt((a as HTMLElement).getAttribute('step') || '0'); + const stepB = parseInt((b as HTMLElement).getAttribute('step') || '0'); + return stepA - stepB; + }); + }; + + const getMaxSteps = () => { + const steps = getCurrentSlideSteps(); + if (steps.length === 0) return 0; + const lastStep = steps[steps.length - 1] as HTMLElement; + return parseInt(lastStep.getAttribute('step') || '0'); + }; + + const showStepsUpTo = (targetStep: number, isReverse: boolean = false) => { + const steps = getCurrentSlideSteps(); + + steps.forEach((stepElement) => { + const element = stepElement as HTMLElement; + const elementStep = parseInt(element.getAttribute('step') || '0'); + const animationType = element.getAttribute('animation') || 'fade-in'; + + // Remove all animation classes first + Object.values(animationClasses).forEach(cls => { + element.classList.remove(cls); + element.classList.remove(cls.replace('-step', '-reverse-step')); + }); + element.classList.remove('step-hidden', 'step-visible'); + + if (elementStep <= targetStep) { + // Show this step with animation + element.classList.add('step-visible'); + if (elementStep === targetStep) { + // Apply animation only to the current step + const baseAnimationClass = animationClasses[animationType as keyof typeof animationClasses] || animationClasses['fade-in']; + const animationClass = isReverse ? baseAnimationClass.replace('-step', '-reverse-step') : baseAnimationClass; + + // Special handling for type-in animation + if (animationType === 'type-in') { + if (isReverse) { + startTypeAnimation(element, false); + } else { + startTypeAnimation(element, true); + } + } else { + element.classList.add(animationClass); + } + } + } else { + // Hide this step + element.classList.add('step-hidden'); + } + }); + }; + + const startTypeAnimation = (element: HTMLElement, isForward: boolean) => { + const text = element.textContent || ''; + const duration = isForward ? 1500 : 1000; // ms + const steps = Math.max(text.length, 1); + const stepDuration = duration / steps; + + if (isForward) { + // Type in: reveal characters one by one + element.textContent = ''; + element.style.opacity = '1'; + + let currentIndex = 0; + const typeInterval = setInterval(() => { + if (currentIndex < text.length) { + element.textContent = text.substring(0, currentIndex + 1); + currentIndex++; + } else { + clearInterval(typeInterval); + } + }, stepDuration); + + // Store interval reference for cleanup + (element as any)._typeInterval = typeInterval; + } else { + // Type out: hide characters one by one from the end + let currentLength = text.length; + const typeInterval = setInterval(() => { + if (currentLength > 0) { + element.textContent = text.substring(0, currentLength - 1); + currentLength--; + } else { + clearInterval(typeInterval); + element.style.opacity = '0'; + } + }, stepDuration); + + // Store interval reference for cleanup + (element as any)._typeInterval = typeInterval; + } + }; + + const resetSlideSteps = () => { + const steps = getCurrentSlideSteps(); + steps.forEach((stepElement) => { + const element = stepElement as HTMLElement; + + // Clear any running type animations + if ((element as any)._typeInterval) { + clearInterval((element as any)._typeInterval); + (element as any)._typeInterval = null; + } + + Object.values(animationClasses).forEach(cls => { + element.classList.remove(cls); + element.classList.remove(cls.replace('-step', '-reverse-step')); + }); + element.classList.remove('step-hidden', 'step-visible'); + element.classList.add('step-hidden'); + + // Reset text content and styles for type-in elements + if (element.getAttribute('animation') === 'type-in') { + element.style.opacity = '0'; + } + }); + }; + + const nextStep = () => { + const maxSteps = getMaxSteps(); + + if (step < maxSteps) { + step++; + showStepsUpTo(step, false); + return { slide, step }; + } else { + // Move to next slide + if (slide < slides.length - 1) { + const nextSlideIndex = nextSlide(); + return { slide: nextSlideIndex, step: 0 }; + } + return { slide, step }; + } + }; + + const prevStep = () => { + if (step > 0) { + step--; + showStepsUpTo(step, true); + return { slide, step }; + } else { + // Move to previous slide + if (slide > 0) { + const prevSlideIndex = prevSlide(); + // Set to max steps of previous slide + const tempSlide = slide; + slide = prevSlideIndex; + const maxSteps = getMaxSteps(); + slide = tempSlide; + return { slide: prevSlideIndex, step: maxSteps }; + } + return { slide, step }; + } + }; + + const keyHandlers: Record { slide: number, step: number }> = { + ArrowRight: nextStep, + ArrowLeft: prevStep, }; const displaySlides = () => { @@ -49,8 +222,15 @@ if (i === slide) { slides[i].classList.add("active", currClass); + // Show steps for current slide + showStepsUpTo(step, false); } else { slides[i].classList.add("inactive"); + // Reset steps for non-current slides + const tempSlide = slide; + slide = i; + resetSlideSteps(); + slide = tempSlide; if (i > slide) { slides[i].classList.add(nextClass); @@ -61,62 +241,89 @@ } }; - let presenting = false + let presenting = false; const startPresentation = () => { button.innerHTML = "Resume presentation"; document.body.classList.add("presentation-overflow-hidden"); - presenting = true + presenting = true; + step = 0; // Reset step displaySlides(); setProgress(); - initListeners() + initListeners(); }; const endPresentation = () => { document.body.classList.remove("presentation-overflow-hidden"); - presenting = false - slides.map((s) => - s.classList.remove("active", "inactive", ...transitionClasses) - ); + presenting = false; + step = 0; + slides.map((s) => { + s.classList.remove("active", "inactive", ...transitionClasses); + // Reset all steps + const tempSlide = slide; + slides.forEach((_, i) => { + slide = i; + resetSlideSteps(); + }); + slide = tempSlide; + }); }; const setPresenter = () => { presenter = true; - document.body.classList.add("presentation-presenter") + document.body.classList.add("presentation-presenter"); }; const setProgress = () => { - const progress = ((slide+1)/slides.length)*100; - document.body.style.setProperty('--presentation-progress', `${progress}%`) - } + const maxSteps = getMaxSteps(); + const totalSteps = slides.reduce((acc, _, i) => { + const tempSlide = slide; + slide = i; + const steps = getMaxSteps(); + slide = tempSlide; + return acc + Math.max(1, steps); + }, 0); + + let currentProgress = 0; + for (let i = 0; i < slide; i++) { + const tempSlide = slide; + slide = i; + const steps = getMaxSteps(); + slide = tempSlide; + currentProgress += Math.max(1, steps); + } + currentProgress += step; + + const progress = (currentProgress / totalSteps) * 100; + document.body.style.setProperty('--presentation-progress', `${progress}%`); + }; - const transition = (nextSlide: number) => { + const transition = (nextSlide: number, nextStep: number = 0) => { if (!presenting) { - return + return; } - if (slide === nextSlide) { + if (slide === nextSlide && step === nextStep) { return; } slides.forEach((s) => s.classList.remove(...transitionClasses)); - slide = nextSlide; + step = nextStep; displaySlides(); setProgress(); }; - - let listenersInitialized = false + let listenersInitialized = false; const initListeners = () => { - if (listenersInitialized) { - return - } + if (listenersInitialized) { + return; + } - listenersInitialized= true + listenersInitialized = true; window.addEventListener("keyup", (ev) => { ev.preventDefault(); const isEscape = ev.key === "Escape"; @@ -131,19 +338,19 @@ return; } - const getSlide = keyHandlers[ev.key]; + const getNextPosition = keyHandlers[ev.key]; - if (!getSlide) { + if (!getNextPosition) { return; } - const nextSlide = getSlide(); - transition(nextSlide); + const { slide: nextSlideIndex, step: nextStepIndex } = getNextPosition(); + transition(nextSlideIndex, nextStepIndex); }); let touchstartX = 0; let touchendX = 0; - const handleGesure = () => { + const handleGesture = () => { const magnitude = Math.abs(touchstartX - touchendX); if (magnitude < 40) { @@ -152,10 +359,12 @@ } if (touchendX < touchstartX) { - transition(nextSlide()); + const { slide: nextSlideIndex, step: nextStepIndex } = nextStep(); + transition(nextSlideIndex, nextStepIndex); } if (touchendX > touchstartX) { - transition(prevSlide()); + const { slide: prevSlideIndex, step: prevStepIndex } = prevStep(); + transition(prevSlideIndex, prevStepIndex); } }; @@ -171,11 +380,11 @@ "touchend", (event) => { touchendX = event.changedTouches[0].screenX; - handleGesure(); + handleGesture(); }, false ); - } + }; // If there is no presentation on the page then we don't initialize if (slides.length) { @@ -189,6 +398,259 @@ display: none; } + /* Step animation styles */ + .step-hidden { + opacity: 0; + visibility: hidden; + } + + .step-visible { + opacity: 1; + visibility: visible; + } + + /* Animation keyframes */ + @keyframes fadeInStep { + from { + opacity: 0; + } + to { + opacity: 1; + } + } + + @keyframes fadeOutStep { + from { + opacity: 1; + } + to { + opacity: 0; + } + } + + @keyframes slideInLeftStep { + from { + opacity: 0; + transform: translateX(-30px); + } + to { + opacity: 1; + transform: translateX(0); + } + } + + @keyframes slideOutLeftStep { + from { + opacity: 1; + transform: translateX(0); + } + to { + opacity: 0; + transform: translateX(-30px); + } + } + + @keyframes slideInRightStep { + from { + opacity: 0; + transform: translateX(30px); + } + to { + opacity: 1; + transform: translateX(0); + } + } + + @keyframes slideOutRightStep { + from { + opacity: 1; + transform: translateX(0); + } + to { + opacity: 0; + transform: translateX(30px); + } + } + + @keyframes slideInUpStep { + from { + opacity: 0; + transform: translateY(30px); + } + to { + opacity: 1; + transform: translateY(0); + } + } + + @keyframes slideOutUpStep { + from { + opacity: 1; + transform: translateY(0); + } + to { + opacity: 0; + transform: translateY(30px); + } + } + + @keyframes slideInDownStep { + from { + opacity: 0; + transform: translateY(-30px); + } + to { + opacity: 1; + transform: translateY(0); + } + } + + @keyframes slideOutDownStep { + from { + opacity: 1; + transform: translateY(0); + } + to { + opacity: 0; + transform: translateY(-30px); + } + } + + @keyframes scaleInStep { + from { + opacity: 0; + transform: scale(0.8); + } + to { + opacity: 1; + transform: scale(1); + } + } + + @keyframes scaleOutStep { + from { + opacity: 1; + transform: scale(1); + } + to { + opacity: 0; + transform: scale(0.8); + } + } + + @keyframes bounceInStep { + 0% { + opacity: 0; + transform: scale(0.3); + } + 50% { + opacity: 1; + transform: scale(1.05); + } + 70% { + transform: scale(0.9); + } + 100% { + opacity: 1; + transform: scale(1); + } + } + + @keyframes bounceOutStep { + 0% { + opacity: 1; + transform: scale(1); + } + 30% { + transform: scale(1.05); + } + 50% { + opacity: 1; + transform: scale(0.9); + } + 100% { + opacity: 0; + transform: scale(0.3); + } + } + + @keyframes typeInStep { + /* This is now unused - keeping for backward compatibility */ + from { opacity: 1; } + to { opacity: 1; } + } + + @keyframes typeOutStep { + /* This is now unused - keeping for backward compatibility */ + from { opacity: 1; } + to { opacity: 1; } + } + + /* Animation classes */ + .animate-fade-in-step { + animation: fadeInStep 0.6s ease-out forwards; + } + + .animate-fade-in-reverse-step { + animation: fadeOutStep 0.6s ease-out forwards; + } + + .animate-slide-in-left-step { + animation: slideInLeftStep 0.6s ease-out forwards; + } + + .animate-slide-in-left-reverse-step { + animation: slideOutLeftStep 0.6s ease-out forwards; + } + + .animate-slide-in-right-step { + animation: slideInRightStep 0.6s ease-out forwards; + } + + .animate-slide-in-right-reverse-step { + animation: slideOutRightStep 0.6s ease-out forwards; + } + + .animate-slide-in-up-step { + animation: slideInUpStep 0.6s ease-out forwards; + } + + .animate-slide-in-up-reverse-step { + animation: slideOutUpStep 0.6s ease-out forwards; + } + + .animate-slide-in-down-step { + animation: slideInDownStep 0.6s ease-out forwards; + } + + .animate-slide-in-down-reverse-step { + animation: slideOutDownStep 0.6s ease-out forwards; + } + + .animate-scale-in-step { + animation: scaleInStep 0.6s ease-out forwards; + } + + .animate-scale-in-reverse-step { + animation: scaleOutStep 0.6s ease-out forwards; + } + + .animate-bounce-in-step { + animation: bounceInStep 0.8s ease-out forwards; + } + + .animate-bounce-in-reverse-step { + animation: bounceOutStep 0.8s ease-out forwards; + } + + .animate-type-in-step { + /* JavaScript-controlled animation - no CSS animation needed */ + } + + .animate-type-in-reverse-step { + /* JavaScript-controlled animation - no CSS animation needed */ + } + .presentation-overflow-hidden { overflow: hidden; visibility: hidden; diff --git a/src/src/content/resources/curriculum/python/intro-to-python.mdx b/src/src/content/resources/curriculum/python/intro-to-python.mdx index 1ef4695..641ef52 100644 --- a/src/src/content/resources/curriculum/python/intro-to-python.mdx +++ b/src/src/content/resources/curriculum/python/intro-to-python.mdx @@ -14,84 +14,99 @@ import Presentation from "@/components/resources/presentation.astro"; # Welcome to Python! 🐍 -**A beginner-friendly programming language** +
**A beginner-friendly programming language**
-- Easy to learn and read -- Powerful and versatile -- Great for beginners -- Used by major companies +
- Easy to learn and read
+
- Powerful and versatile
+
- Great for beginners
+
- Used by major companies
## What is Python? -Python is a **high-level programming language** that emphasizes: +
Python is a **high-level programming language** that emphasizes:
-- **Readability** - Code that looks like English -- **Simplicity** - Easy to learn and use -- **Versatility** - Can be used for many things +
- **Readability** - Code that looks like English
+
- **Simplicity** - Easy to learn and use
+
- **Versatility** - Can be used for many things
-### Created by Guido van Rossum in 1991 +
### Created by Guido van Rossum in 1991
-Named after "Monty Python's Flying Circus" 🎭 +
Named after "Monty Python's Flying Circus" 🎭
## Why Learn Python? +
### 🌐 Web Development Build websites and web applications +
+
### 🤖 Data Science & AI Analyze data and build machine learning models +
+
### 🎮 Game Development Create games and interactive applications +
+
### 🔧 Automation Automate repetitive tasks +
## Your First Python Program -Let's write the classic "Hello, World!" program: +
Let's write the classic "Hello, World!" program:
+
```python print("Hello, World!") ``` +
-### How to run it: -1. Open a text editor -2. Type the code above -3. Save as `hello.py` -4. Run with: `python hello.py` +
### How to run it:
+
1. Open a text editor
+
2. Type the code above
+
3. Save as `hello.py`
+
4. Run with: `python hello.py`
## Variables and Data Types -### Creating Variables +
### Creating Variables
+
```python name = "Alice" # String age = 25 # Integer height = 5.6 # Float is_student = True # Boolean ``` +
-### Python is **dynamically typed** -You don't need to declare the type! +
### Python is **dynamically typed**
+
You don't need to declare the type!
+
```python x = 42 # x is an integer x = "Hello" # Now x is a string ``` +
## Working with Strings -### String Operations +
### String Operations
+
```python # Creating strings greeting = "Hello" @@ -100,47 +115,72 @@ name = "World" # Concatenation message = greeting + ", " + name + "!" print(message) # Output: Hello, World! +``` +
+
+```python # String methods text = "python programming" print(text.upper()) # PYTHON PROGRAMMING print(text.capitalize()) # Python programming print(text.replace("python", "Python")) # Python programming ``` +
## Numbers and Math -### Basic Math Operations +
### Basic Math Operations
+
```python # Arithmetic operators a = 10 b = 3 +``` +
+
+```python print(a + b) # Addition: 13 print(a - b) # Subtraction: 7 print(a * b) # Multiplication: 30 print(a / b) # Division: 3.333... +``` +
+ +
+```python print(a // b) # Floor division: 3 print(a % b) # Modulo (remainder): 1 print(a ** b) # Exponentiation: 1000 ``` +
## Lists - Storing Multiple Values -### Creating and Using Lists +
### Creating and Using Lists
+
```python # Creating a list fruits = ["apple", "banana", "orange"] numbers = [1, 2, 3, 4, 5] +``` +
+
+```python # Accessing items (indexing starts at 0) print(fruits[0]) # apple print(fruits[-1]) # orange (last item) +``` +
+
+```python # Adding items fruits.append("grape") fruits.insert(1, "strawberry") @@ -149,12 +189,14 @@ fruits.insert(1, "strawberry") print(len(fruits)) # Length of list print("apple" in fruits) # Check if item exists ``` +
## Control Flow - Making Decisions -### If Statements +
### If Statements
+
```python age = 18 @@ -164,65 +206,89 @@ elif age >= 16: print("You can drive!") else: print("You're still young!") +``` +
+
+```python # Comparison operators # == (equal), != (not equal) # > (greater), < (less) # >= (greater or equal), <= (less or equal) ``` +
## Loops - Repeating Actions -### For Loops +
### For Loops
+
```python # Loop through a list fruits = ["apple", "banana", "orange"] for fruit in fruits: print(f"I like {fruit}") +``` +
+
+```python # Loop through numbers for i in range(5): print(f"Count: {i}") # 0, 1, 2, 3, 4 ``` +
-### While Loops +
### While Loops
+
```python count = 0 while count < 3: print(f"Count is {count}") count += 1 # Same as count = count + 1 ``` +
## Functions - Organizing Your Code -### Creating Functions +
### Creating Functions
+
```python def greet(name): """This function greets someone""" return f"Hello, {name}!" +``` +
+
+```python def add_numbers(a, b): """Add two numbers and return the result""" result = a + b return result +``` +
-# Using functions +
### Using functions
+
+```python message = greet("Alice") print(message) # Hello, Alice! sum_result = add_numbers(5, 3) print(sum_result) # 8 ``` +
## Practice Exercise -### Build a Simple Calculator +
### Build a Simple Calculator
+
```python def calculator(): print("Simple Calculator") @@ -231,7 +297,11 @@ def calculator(): num1 = float(input("Enter first number: ")) operation = input("Enter operation (+, -, *, /): ") num2 = float(input("Enter second number: ")) - +``` +
+ +
+```python if operation == "+": result = num1 + num2 elif operation == "-": @@ -247,24 +317,29 @@ def calculator(): return "Error: Invalid operation!" return f"Result: {result}" +``` +
+
+```python # Run the calculator print(calculator()) ``` +
## 🎉 Congratulations! -You've learned the basics of Python programming! +
You've learned the basics of Python programming!
-### What's Next? -- Practice with small projects -- Learn about modules and packages -- Explore Python libraries -- Build something cool! +
### What's Next?
+
- Practice with small projects
+
- Learn about modules and packages
+
- Explore Python libraries
+
- Build something cool!
-**Ready to code? Let's build something amazing! 🚀** +
**Ready to code? Let's build something amazing! 🚀**
## Course Materials @@ -291,4 +366,4 @@ By the end of this presentation, you'll be able to: - Create and use functions - Build a simple calculator program -The presentation automatically starts when you visit this page. Use arrow keys to navigate between slides, or escape to exit presentati +The presentation automatically starts when you visit this page. Use arrow keys to navigate between slides and steps, or escape to exit presentation mode.