From 130b0dbdc7233254a059d073dfa1a7f7693095e3 Mon Sep 17 00:00:00 2001 From: Michael Czechowski Date: Tue, 30 Dec 2025 21:44:37 +0100 Subject: [PATCH] feat: add welcome lesson, DVD bounce animation, mobile layout reorder - Add Welcome module with intro lessons (EN/DE) - Success message now bounces like DVD screensaver (10s duration) - Mobile: nav bar at top, preview before editor - Logo: CODE with purple background pill --- lessons/00-welcome.json | 111 +++++++++++++++++++++++++++++++++++++ lessons/de/00-welcome.json | 111 +++++++++++++++++++++++++++++++++++++ src/app.js | 4 +- src/config/lessons.js | 6 ++ src/main.css | 64 +++++++++++++-------- 5 files changed, 270 insertions(+), 26 deletions(-) create mode 100644 lessons/00-welcome.json create mode 100644 lessons/de/00-welcome.json diff --git a/lessons/00-welcome.json b/lessons/00-welcome.json new file mode 100644 index 0000000..fe5aa92 --- /dev/null +++ b/lessons/00-welcome.json @@ -0,0 +1,111 @@ +{ + "$schema": "../schemas/code-crispies-module-schema.json", + "id": "welcome", + "title": "Welcome", + "description": "Learn how to use Code Crispies and get started with interactive web development lessons", + "mode": "html", + "difficulty": "beginner", + "lessons": [ + { + "id": "what-is-code-crispies", + "title": "What is Code Crispies?", + "description": "Code Crispies is a free, open-source platform for learning web development through hands-on exercises.

You'll learn:
- HTML - Semantic markup and native elements
- CSS - Styling and layout techniques
- Tailwind - Utility-first CSS framework

No account required - just start coding!", + "task": "Try it out! Type <h1>Hello World</h1> in the editor below and watch the preview update.", + "previewHTML": "", + "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 20px; text-align: center; } h1 { color: #6366f1; }", + "sandboxCSS": "", + "initialCode": "", + "solution": "

Hello World

", + "previewContainer": "preview-area", + "validations": [ + { + "type": "element_exists", + "value": "h1", + "message": "Add an <h1> heading element" + }, + { + "type": "contains", + "value": "Hello", + "message": "Add the text 'Hello' inside your heading" + } + ] + }, + { + "id": "how-lessons-work", + "title": "How Lessons Work", + "description": "Each lesson has:

1. Instructions - Read the task on the left
2. Editor - Write your code below the instructions
3. Preview - See results instantly on the right
4. Hints - Get feedback when you run your code

When all validations pass, you'll see a success message!", + "task": "Create a paragraph with the text 'I am learning!' using <p> tags.", + "previewHTML": "", + "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 20px; } p { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 20px; border-radius: 8px; text-align: center; font-size: 1.2em; }", + "sandboxCSS": "", + "initialCode": "", + "solution": "

I am learning!

", + "previewContainer": "preview-area", + "validations": [ + { + "type": "element_exists", + "value": "p", + "message": "Add a <p> paragraph element" + }, + { + "type": "contains", + "value": "learning", + "message": "Include the word 'learning' in your paragraph" + } + ] + }, + { + "id": "navigation-tips", + "title": "Navigation Tips", + "description": "Use these controls to navigate:

Menu button (top left) - Browse all lesson modules
Previous / Next buttons - Move between lessons
Show Expected - See the target result
Reset button - Start the lesson over

Keyboard shortcuts:
Ctrl+Enter - Run your code
Ctrl+Z - Undo
Ctrl+Shift+Z - Redo", + "task": "Create a button element with the text 'Click me!' using <button> tags.", + "previewHTML": "", + "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 20px; display: flex; justify-content: center; align-items: center; min-height: 80px; } button { background: #6366f1; color: white; border: none; padding: 12px 24px; border-radius: 6px; font-size: 1em; cursor: pointer; transition: transform 0.2s; } button:hover { transform: scale(1.05); }", + "sandboxCSS": "", + "initialCode": "", + "solution": "", + "previewContainer": "preview-area", + "validations": [ + { + "type": "element_exists", + "value": "button", + "message": "Add a <button> element" + }, + { + "type": "contains", + "value": "Click", + "message": "Add the text 'Click me!' inside the button" + } + ] + }, + { + "id": "ready-to-learn", + "title": "Ready to Learn!", + "description": "You're all set! Here's what to explore next:

HTML Modules - Learn semantic elements, forms, tables
CSS Modules - Master selectors, box model, flexbox
Advanced Topics - Animations, responsive design

Open the menu to browse all available modules. Your progress is saved automatically!", + "task": "Create a simple card with a heading and paragraph:
1. Add <h2> with 'Ready!'
2. Add <p> with 'Let's start learning.'", + "previewHTML": "", + "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 20px; } h2, p { background: white; margin: 0; } h2 { color: #6366f1; padding: 20px 20px 10px; border-radius: 8px 8px 0 0; border: 2px solid #e5e7eb; border-bottom: none; } p { padding: 10px 20px 20px; border-radius: 0 0 8px 8px; border: 2px solid #e5e7eb; border-top: none; color: #4b5563; }", + "sandboxCSS": "", + "initialCode": "", + "solution": "

Ready!

\n

Let's start learning.

", + "previewContainer": "preview-area", + "validations": [ + { + "type": "element_exists", + "value": "h2", + "message": "Add an <h2> heading" + }, + { + "type": "element_exists", + "value": "p", + "message": "Add a <p> paragraph" + }, + { + "type": "contains", + "value": "Ready", + "message": "Include 'Ready!' in your heading" + } + ] + } + ] +} diff --git a/lessons/de/00-welcome.json b/lessons/de/00-welcome.json new file mode 100644 index 0000000..a1a7329 --- /dev/null +++ b/lessons/de/00-welcome.json @@ -0,0 +1,111 @@ +{ + "$schema": "../../schemas/code-crispies-module-schema.json", + "id": "welcome", + "title": "Willkommen", + "description": "Lerne, wie du Code Crispies nutzt und starte mit interaktiven Webentwicklungs-Lektionen", + "mode": "html", + "difficulty": "beginner", + "lessons": [ + { + "id": "what-is-code-crispies", + "title": "Was ist Code Crispies?", + "description": "Code Crispies ist eine kostenlose Open-Source-Plattform zum Erlernen von Webentwicklung durch praktische Übungen.

Du lernst:
- HTML - Semantisches Markup und native Elemente
- CSS - Styling und Layout-Techniken
- Tailwind - Utility-First CSS Framework

Kein Konto erforderlich - einfach loslegen!", + "task": "Probiere es aus! Tippe <h1>Hallo Welt</h1> in den Editor und beobachte die Vorschau.", + "previewHTML": "", + "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 20px; text-align: center; } h1 { color: #6366f1; }", + "sandboxCSS": "", + "initialCode": "", + "solution": "

Hallo Welt

", + "previewContainer": "preview-area", + "validations": [ + { + "type": "element_exists", + "value": "h1", + "message": "Füge ein <h1> Überschrift-Element hinzu" + }, + { + "type": "contains", + "value": "Hallo", + "message": "Füge den Text 'Hallo' in deine Überschrift ein" + } + ] + }, + { + "id": "how-lessons-work", + "title": "Wie Lektionen funktionieren", + "description": "Jede Lektion hat:

1. Anweisungen - Lies die Aufgabe links
2. Editor - Schreibe deinen Code unter den Anweisungen
3. Vorschau - Sieh Ergebnisse sofort rechts
4. Hinweise - Bekomme Feedback beim Ausführen

Wenn alle Validierungen bestanden sind, siehst du eine Erfolgsmeldung!", + "task": "Erstelle einen Absatz mit dem Text 'Ich lerne!' mit <p> Tags.", + "previewHTML": "", + "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 20px; } p { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 20px; border-radius: 8px; text-align: center; font-size: 1.2em; }", + "sandboxCSS": "", + "initialCode": "", + "solution": "

Ich lerne!

", + "previewContainer": "preview-area", + "validations": [ + { + "type": "element_exists", + "value": "p", + "message": "Füge ein <p> Absatz-Element hinzu" + }, + { + "type": "contains", + "value": "lerne", + "message": "Füge das Wort 'lerne' in deinen Absatz ein" + } + ] + }, + { + "id": "navigation-tips", + "title": "Navigations-Tipps", + "description": "Nutze diese Steuerungen zur Navigation:

Menü-Button (oben links) - Alle Lektionsmodule durchsuchen
Zurück / Weiter Buttons - Zwischen Lektionen wechseln
Lösung zeigen - Das Zielergebnis anzeigen
Zurücksetzen - Lektion neu starten

Tastenkürzel:
Strg+Enter - Code ausführen
Strg+Z - Rückgängig
Strg+Umschalt+Z - Wiederholen", + "task": "Erstelle ein Button-Element mit dem Text 'Klick mich!' mit <button> Tags.", + "previewHTML": "", + "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 20px; display: flex; justify-content: center; align-items: center; min-height: 80px; } button { background: #6366f1; color: white; border: none; padding: 12px 24px; border-radius: 6px; font-size: 1em; cursor: pointer; transition: transform 0.2s; } button:hover { transform: scale(1.05); }", + "sandboxCSS": "", + "initialCode": "", + "solution": "", + "previewContainer": "preview-area", + "validations": [ + { + "type": "element_exists", + "value": "button", + "message": "Füge ein <button> Element hinzu" + }, + { + "type": "contains", + "value": "Klick", + "message": "Füge den Text 'Klick mich!' in den Button ein" + } + ] + }, + { + "id": "ready-to-learn", + "title": "Bereit zum Lernen!", + "description": "Du bist startklar! Hier ist, was du als nächstes erkunden kannst:

HTML Module - Lerne semantische Elemente, Formulare, Tabellen
CSS Module - Meistere Selektoren, Box-Model, Flexbox
Fortgeschrittene Themen - Animationen, Responsives Design

Öffne das Menü, um alle verfügbaren Module zu durchsuchen. Dein Fortschritt wird automatisch gespeichert!", + "task": "Erstelle eine einfache Karte mit Überschrift und Absatz:
1. Füge <h2> mit 'Fertig!' hinzu
2. Füge <p> mit 'Los geht's!' hinzu", + "previewHTML": "", + "previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 20px; } h2, p { background: white; margin: 0; } h2 { color: #6366f1; padding: 20px 20px 10px; border-radius: 8px 8px 0 0; border: 2px solid #e5e7eb; border-bottom: none; } p { padding: 10px 20px 20px; border-radius: 0 0 8px 8px; border: 2px solid #e5e7eb; border-top: none; color: #4b5563; }", + "sandboxCSS": "", + "initialCode": "", + "solution": "

Fertig!

\n

Los geht's!

", + "previewContainer": "preview-area", + "validations": [ + { + "type": "element_exists", + "value": "h2", + "message": "Füge eine <h2> Überschrift hinzu" + }, + { + "type": "element_exists", + "value": "p", + "message": "Füge einen <p> Absatz hinzu" + }, + { + "type": "contains", + "value": "Fertig", + "message": "Füge 'Fertig!' in deine Überschrift ein" + } + ] + } + ] +} diff --git a/src/app.js b/src/app.js index dd22fd0..00214dd 100644 --- a/src/app.js +++ b/src/app.js @@ -599,11 +599,11 @@ function runCode() { elements.nextBtn.classList.add("success"); elements.taskInstruction.classList.add("success-instruction"); - // Show match animation + // Show match animation (DVD-style bouncing) elements.previewWrapper?.classList.add("matched"); setTimeout(() => { elements.previewWrapper?.classList.remove("matched"); - }, 2500); + }, 10000); updateNavigationButtons(); updateProgressDisplay(); diff --git a/src/config/lessons.js b/src/config/lessons.js index 8d46814..f019d7e 100644 --- a/src/config/lessons.js +++ b/src/config/lessons.js @@ -4,6 +4,7 @@ */ // English lesson imports +import welcomeEN from "../../lessons/00-welcome.json"; import basicSelectorsEN from "../../lessons/00-basic-selectors.json"; import boxModelEN from "../../lessons/01-box-model.json"; import unitsVariablesEN from "../../lessons/05-units-variables.json"; @@ -20,6 +21,7 @@ import htmlSvgEN from "../../lessons/32-html-svg.json"; import flexboxEN from "../../lessons/flexbox.json"; // German lesson imports +import welcomeDE from "../../lessons/de/00-welcome.json"; import basicSelectorsDE from "../../lessons/de/00-basic-selectors.json"; import boxModelDE from "../../lessons/de/01-box-model.json"; import unitsVariablesDE from "../../lessons/de/05-units-variables.json"; @@ -37,6 +39,8 @@ import flexboxDE from "../../lessons/de/flexbox.json"; // English module store - ordered by learning path const moduleStoreEN = [ + // Welcome + welcomeEN, // HTML Grundlagen htmlElementsEN, htmlFormsBasicEN, @@ -61,6 +65,8 @@ const moduleStoreEN = [ // German module store - ordered by learning path const moduleStoreDE = [ + // Welcome + welcomeDE, // HTML Grundlagen htmlElementsDE, htmlFormsBasicDE, diff --git a/src/main.css b/src/main.css index 75e7824..2e186ee 100644 --- a/src/main.css +++ b/src/main.css @@ -589,27 +589,42 @@ code, kbd { .preview-wrapper.matched::after { content: "CRISPY! ٩(◕‿◕)۶"; position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); background: var(--success-color); color: white; padding: var(--spacing-sm) var(--spacing-lg); border-radius: var(--border-radius-lg); font-weight: bold; font-size: 1.1rem; - animation: pop-in 0.4s ease-out; + animation: dvd-bounce 8s ease-in-out infinite; z-index: 10; + white-space: nowrap; } -@keyframes pop-in { +@keyframes dvd-bounce { 0% { - transform: translate(-50%, -50%) scale(0.8); - opacity: 0; + top: 10%; + left: 10%; + transform: scale(1); + } + 25% { + top: 70%; + left: 80%; + transform: scale(1.1); + } + 50% { + top: 20%; + left: 70%; + transform: scale(0.95); + } + 75% { + top: 60%; + left: 15%; + transform: scale(1.05); } 100% { - transform: translate(-50%, -50%) scale(1); - opacity: 1; + top: 10%; + left: 10%; + transform: scale(1); } } @@ -1111,40 +1126,41 @@ input:checked + .toggle-slider::before { width: 100%; flex-shrink: 0; border-right: none; + display: contents; } - .left-panel { - min-height: 80vh; - border-bottom: 1px solid var(--border-color); - } - - .right-panel { - min-height: 50vh; + /* Mobile order: nav -> instructions -> preview -> editor */ + .game-controls { + order: 1; + padding: var(--spacing-sm); } .instructions { + order: 2; max-height: none; overflow-y: visible; } + .preview-section { + order: 3; + } + .editor-section { + order: 4; flex: 1; min-height: 50vh; } + .preview-wrapper { + margin: var(--spacing-sm); + min-height: 40vh; + } + .editor-content { flex: 1; min-height: 45vh; } - .preview-wrapper { - margin: var(--spacing-sm); - } - - .game-controls { - padding: var(--spacing-sm); - } - .module-pill { flex: 1; margin: 0 var(--spacing-sm);