diff --git a/.gamification.json b/.gamification.json
index 688c337..65ce884 100644
--- a/.gamification.json
+++ b/.gamification.json
@@ -10,5 +10,5 @@
"streak_tage": 1,
"letzter_aktiver_tag": "2026-09-12",
"historie": [],
- "zuletzt_aktualisiert": "2026-09-12T13:29:30.562924"
+ "zuletzt_aktualisiert": "2026-09-15T15:18:26.060048"
}
\ No newline at end of file
diff --git a/assets/gamification.js b/assets/gamification.js
index 7204188..55643bc 100644
--- a/assets/gamification.js
+++ b/assets/gamification.js
@@ -6,33 +6,33 @@
(function () {
const DEFAULT_LEVELS = [
- { level: 1, min_xp: 0, max_xp: 150, titel: "Code-Küken 🐣", rang: "Bronze I" },
- { level: 2, min_xp: 151, max_xp: 400, titel: "Code-Detektiv 🔍", rang: "Bronze II" },
- { level: 3, min_xp: 401, max_xp: 800, titel: "Logik-Bastler ⚙️", rang: "Silber I" },
- { level: 4, min_xp: 801, max_xp: 1300, titel: "Klassen-Baumeister 🏗️", rang: "Silber II" },
- { level: 5, min_xp: 1301, max_xp: 2000, titel: "Git-Stratege 🌿", rang: "Gold I" },
- { level: 6, min_xp: 2001, max_xp: 2900, titel: "TDD-Qualitätsprüfer 🧪", rang: "Gold II" },
- { level: 7, min_xp: 2901, max_xp: 4000, titel: "Vererbungs-Meister 🧬", rang: "Platin I" },
- { level: 8, min_xp: 4001, max_xp: 5300, titel: "Exception-Wächter 🛡️", rang: "Platin II" },
- { level: 9, min_xp: 5301, max_xp: 6800, titel: "GUI-Entwickler 🖥️", rang: "Diamant" },
- { level: 10, min_xp: 6801, max_xp: 99999, titel: "Software-Architekt 🏆", rang: "Großmeister" }
+ { level: 1, min_xp: 0, max_xp: 150, titel: "Junior IT-Trainee I: Syntax & Basistypen", rang: "Stufe 1" },
+ { level: 2, min_xp: 151, max_xp: 400, titel: "Junior IT-Trainee II: Kontrollfluss & Logik", rang: "Stufe 2" },
+ { level: 3, min_xp: 401, max_xp: 800, titel: "IT-Specialist: Funktionen & Datenstrukturen", rang: "Stufe 3" },
+ { level: 4, min_xp: 801, max_xp: 1300, titel: "Software Developer: OOP-Modellierung", rang: "Stufe 4" },
+ { level: 5, min_xp: 1301, max_xp: 2000, titel: "DevOps Engineer: Versionskontrolle & Tooling", rang: "Stufe 5" },
+ { level: 6, min_xp: 2001, max_xp: 2900, titel: "Quality Engineer: Test-Driven Development (TDD)", rang: "Stufe 6" },
+ { level: 7, min_xp: 2901, max_xp: 4000, titel: "Advanced Engineer: Entwurfsmuster & Polymorphie", rang: "Stufe 7" },
+ { level: 8, min_xp: 4001, max_xp: 5300, titel: "Systems Engineer: Security & Error Handling", rang: "Stufe 8" },
+ { level: 9, min_xp: 5301, max_xp: 6800, titel: "Application Engineer: Schnittstellen & UI", rang: "Stufe 9" },
+ { level: 10, min_xp: 6801, max_xp: 99999, titel: "Certified IT Systems Professional (IHK AP2)", rang: "Master-Stufe" }
];
const DEFAULT_BADGES = {
- rechenkonegin: { icon: "🧮", name: "Rechenkönig", desc: "Grundlagen G01 & G02 abgeschlossen (Zahlen, Operatoren & Typen gemeistert)." },
- dialog_profi: { icon: "💬", name: "Dialog-Profi", desc: "Grundlagen G03 abgeschlossen (Interaktive Ein-/Ausgabe mit f-Strings)." },
- weichenstellerin: { icon: "🚦", name: "Weichensteller", desc: "Grundlagen G04 abgeschlossen (Bedingungslogik & Schaltjahre gemeistert)." },
- schleifen_dompteurin: { icon: "🎡", name: "Schleifen-Dompteur", desc: "Grundlagen G05 abgeschlossen (While- & For-Schleifen gebändigt)." },
- funktions_zauberin: { icon: "🪄", name: "Funktions-Zauberer", desc: "Grundlagen G06 abgeschlossen (Eigene Funktionen & Module gebaut)." },
- listen_archivarin: { icon: "📋", name: "Listen-Archivar", desc: "Grundlagen G07 & G08 abgeschlossen (Sequenzen & Strings analysiert)." },
- daten_strategin: { icon: "🗃️", name: "Daten-Stratege", desc: "Grundlagen G09 & G10 abgeschlossen (Dicts, Sets & Comprehensions gemeistert)." },
- bug_jaegerin: { icon: "🔍", name: "Bug-Jäger", desc: "Kapitel 00 gelöst (Alle Fehler-Bugs im Warm-up aufgespürt)." },
- erste_architektin: { icon: "🏗️", name: "Erster Architekt", desc: "Kapitel 01 bis 03 gelöst (Erste OOP-Klassen, Konstruktoren & Methoden)." },
- zeit_reisende: { icon: "🌿", name: "Git-Zeitreisender", desc: "Kapitel 04c Git-Versionskontrolle verstanden & Spielstände gesichert." },
- tamagotchi_mama: { icon: "🥚", name: "Tamagotchi-Hüter", desc: "Kapitel 06 Mini-Projekt abgeschlossen (Ein lebendiges Haustier gebaut)." },
- qualitaets_garantin: { icon: "🧪", name: "TDD-Qualitätsgarant", desc: "Kapitel 09 abgeschlossen (Eigene professionelle Unit Tests geschrieben)." },
- oop_grossmeisterin: { icon: "🧬", name: "Vererbungs-Koryphäe", desc: "Kapitel 10 bis 12 abgeschlossen (Vererbung, Polymorphie & Exceptions)." },
- software_architektin: { icon: "🏆", name: "Meister-Entwickler", desc: "Kapitel 16 Master-Projekt abgeschlossen & vollwertige Desktop-App gebaut!" }
+ rechenkonegin: { icon: "🧮", name: "Zertifikat: Numerische Typen & Arithmetik", desc: "Grundlagen G01 & G02 abgeschlossen (Zahlen, Operatoren & Typen gemeistert)." },
+ dialog_profi: { icon: "💬", name: "Zertifikat: Interaktive I/O & String-Interpolation", desc: "Grundlagen G03 abgeschlossen (Interaktive Ein-/Ausgabe mit f-Strings)." },
+ weichenstellerin: { icon: "🚦", name: "Zertifikat: Verzweigungslogik & Boolesche Algebra", desc: "Grundlagen G04 abgeschlossen (Bedingungslogik & Kontrollfluss gemeistert)." },
+ schleifen_dompteurin: { icon: "🎡", name: "Zertifikat: Iterationslogik & Sequenzverarbeitung", desc: "Grundlagen G05 abgeschlossen (While- & For-Schleifen gemeistert)." },
+ funktions_zauberin: { icon: "📐", name: "Zertifikat: Modulare Funktionsarchitektur", desc: "Grundlagen G06 abgeschlossen (Modulare Funktionen & Parameterübergabe)." },
+ listen_archivarin: { icon: "📋", name: "Zertifikat: Datenstrukturen: Listen & Slicing", desc: "Grundlagen G07 & G08 abgeschlossen (Sequenzen, Listen & Slicing analysiert)." },
+ daten_strategin: { icon: "🗃️", name: "Zertifikat: Assoziative Arrays: Dicts & Sets", desc: "Grundlagen G09 & G10 abgeschlossen (Dicts, Sets & Hash-Lookup O(1))." },
+ bug_jaegerin: { icon: "🔍", name: "Zertifikat: Systematisches Code-Debugging", desc: "Warm-up abgeschlossen (Fehleranalyse & Traceback-Debugging)." },
+ erste_architektin: { icon: "🏗️", name: "Zertifikat: OOP-Grundlagen: Klassen & Kapselung", desc: "OOP 01 bis 03 gelöst (Klassendefinition, Konstruktoren & Instanzmethoden)." },
+ zeit_reisende: { icon: "🌿", name: "Zertifikat: String-Repräsentation & Dunder-Methoden", desc: "OOP 04 gelöst (Spezielle Methoden __str__, __repr__ implementiert)." },
+ tamagotchi_mama: { icon: "📦", name: "Zertifikat: State-Machine & Domänenmodellierung", desc: "OOP Mini-Projekt abgeschlossen (Zustandsverwaltung & Objektinteraktion)." },
+ qualitaets_garantin: { icon: "🧪", name: "Zertifikat: Automatisierte Testsuites & TDD", desc: "OOP 09 abgeschlossen (Eigene professionelle Unit Tests mit Assertions)." },
+ oop_grossmeisterin: { icon: "🧬", name: "Zertifikat: Fortgeschrittene OOP & Robustes Error-Handling", desc: "OOP 10 bis 12 abgeschlossen (Vererbung, Polymorphie & Exceptions)." },
+ software_architektin: { icon: "🏆", name: "Zertifikat: Master-Projekt Software Engineering", desc: "Master-Projekt abgeschlossen & vollwertige Anwendungsarchitektur gebaut!" }
};
function getGamificationData() {
@@ -47,8 +47,8 @@
spieler_name: "Python-Entwickler",
xp: 0,
level: 1,
- titel: "Code-Küken 🐣",
- rang: "Bronze I",
+ titel: "Junior IT-Trainee I: Syntax & Basistypen",
+ rang: "Stufe 1",
geloeste_kapitel: [],
bestandene_tests: 0,
freigeschaltete_badges: [],
@@ -112,7 +112,8 @@
const hud = document.getElementById("gamification-hud");
if (!hud) return;
- const avatarIcon = currentLevelObj.titel.split(" ").pop() || "🐣";
+ const avatarIcons = ["💻", "🔍", "⚙️", "🏗️", "🌿", "🧪", "🧬", "🛡️", "🖥️", "🏆"];
+ const avatarIcon = avatarIcons[data.level - 1] || "💻";
const solvedCount = (data.geloeste_kapitel || []).length;
const totalChapters = 27;
diff --git a/assets/gamification_data.js b/assets/gamification_data.js
index 1a761e2..6dd5fe0 100644
--- a/assets/gamification_data.js
+++ b/assets/gamification_data.js
@@ -11,13 +11,13 @@ window.GAMIFICATION_DATA = {
"streak_tage": 1,
"letzter_aktiver_tag": "2026-09-12",
"historie": [],
- "zuletzt_aktualisiert": "2026-09-12T13:29:30.562924"
+ "zuletzt_aktualisiert": "2026-09-15T15:18:26.060048"
};
window.GAMIFICATION_BADGES_KATALOG = {
"rechenkonegin": {
"id": "rechenkonegin",
"icon": "🧮",
- "name": "Rechenkönigin",
+ "name": "Zertifikat: Numerische Typen & Arithmetik",
"desc": "Grundlagen 01 & 02 abgeschlossen (Zahlen, Operatoren & Typen gemeistert).",
"xp_bonus": 100,
"kriterium": [
@@ -28,7 +28,7 @@ window.GAMIFICATION_BADGES_KATALOG = {
"dialog_profi": {
"id": "dialog_profi",
"icon": "💬",
- "name": "Dialog-Profi",
+ "name": "Zertifikat: Interaktive I/O & String-Interpolation",
"desc": "Grundlagen 03 abgeschlossen (Interaktive Ein-/Ausgabe mit f-Strings).",
"xp_bonus": 75,
"kriterium": [
@@ -38,8 +38,8 @@ window.GAMIFICATION_BADGES_KATALOG = {
"weichenstellerin": {
"id": "weichenstellerin",
"icon": "🚦",
- "name": "Weichenstellerin",
- "desc": "Grundlagen 04 abgeschlossen (Bedingungslogik & Schaltjahre gemeistert).",
+ "name": "Zertifikat: Verzweigungslogik & Boolesche Algebra",
+ "desc": "Grundlagen 04 abgeschlossen (Bedingungslogik & Kontrollfluss gemeistert).",
"xp_bonus": 75,
"kriterium": [
"lehrpfad_1_grundlagen/04_verzweigungen_und_bedingungen"
@@ -48,8 +48,8 @@ window.GAMIFICATION_BADGES_KATALOG = {
"schleifen_dompteurin": {
"id": "schleifen_dompteurin",
"icon": "🎡",
- "name": "Schleifen-Dompteurin",
- "desc": "Grundlagen 05 abgeschlossen (While- & For-Schleifen gebändigt).",
+ "name": "Zertifikat: Iterationslogik & Sequenzverarbeitung",
+ "desc": "Grundlagen 05 abgeschlossen (While- & For-Schleifen gemeistert).",
"xp_bonus": 100,
"kriterium": [
"lehrpfad_1_grundlagen/05_schleifen_und_wiederholungen"
@@ -57,9 +57,9 @@ window.GAMIFICATION_BADGES_KATALOG = {
},
"funktions_zauberin": {
"id": "funktions_zauberin",
- "icon": "🪄",
- "name": "Funktions-Zauberin",
- "desc": "Grundlagen 06 abgeschlossen (Eigene Funktionen & Module gebaut).",
+ "icon": "📐",
+ "name": "Zertifikat: Modulare Funktionsarchitektur",
+ "desc": "Grundlagen 06 abgeschlossen (Modulare Funktionen & Parameterübergabe).",
"xp_bonus": 100,
"kriterium": [
"lehrpfad_1_grundlagen/06_funktionen_und_module"
@@ -68,8 +68,8 @@ window.GAMIFICATION_BADGES_KATALOG = {
"listen_archivarin": {
"id": "listen_archivarin",
"icon": "📋",
- "name": "Listen-Archivarin",
- "desc": "Grundlagen 07 & 08 abgeschlossen (Sequenzen & Strings analysiert).",
+ "name": "Zertifikat: Datenstrukturen: Listen & Slicing",
+ "desc": "Grundlagen 07 & 08 abgeschlossen (Sequenzen, Listen & Slicing analysiert).",
"xp_bonus": 120,
"kriterium": [
"lehrpfad_1_grundlagen/07_listen_und_sequenzen",
@@ -79,8 +79,8 @@ window.GAMIFICATION_BADGES_KATALOG = {
"daten_strategin": {
"id": "daten_strategin",
"icon": "🗃️",
- "name": "Daten-Strategin",
- "desc": "Grundlagen 09 & 10 abgeschlossen (Dicts, Sets & Comprehensions gemeistert).",
+ "name": "Zertifikat: Assoziative Arrays: Dicts & Sets",
+ "desc": "Grundlagen 09 & 10 abgeschlossen (Dictionaries, Sets & Hash-Lookup O(1)).",
"xp_bonus": 150,
"kriterium": [
"lehrpfad_1_grundlagen/09_dictionaries_und_sets",
@@ -90,8 +90,8 @@ window.GAMIFICATION_BADGES_KATALOG = {
"bug_jaegerin": {
"id": "bug_jaegerin",
"icon": "🔍",
- "name": "Bug-Jägerin",
- "desc": "Kapitel 00 gelöst (Alle Fehler-Bugs im Warm-up aufgespürt).",
+ "name": "Zertifikat: Systematisches Code-Debugging",
+ "desc": "Warm-up abgeschlossen (Fehleranalyse & Traceback-Debugging).",
"xp_bonus": 100,
"kriterium": [
"lehrpfad_2_oop_einstieg/00_fehlersuche_und_grundlagen"
@@ -100,8 +100,8 @@ window.GAMIFICATION_BADGES_KATALOG = {
"erste_architektin": {
"id": "erste_architektin",
"icon": "🏗️",
- "name": "Erste Architektin",
- "desc": "Kapitel 01 bis 03 gelöst (Erste OOP-Klassen, Konstruktoren & Methoden).",
+ "name": "Zertifikat: OOP-Grundlagen: Klassen & Kapselung",
+ "desc": "OOP 01 bis 03 gelöst (Klassendefinition, Konstruktoren & Instanzmethoden).",
"xp_bonus": 200,
"kriterium": [
"lehrpfad_2_oop_einstieg/01_einstieg_klassen",
@@ -111,9 +111,9 @@ window.GAMIFICATION_BADGES_KATALOG = {
},
"tamagotchi_mama": {
"id": "tamagotchi_mama",
- "icon": "🥚",
- "name": "Tamagotchi-Mama",
- "desc": "Kapitel 06 Mini-Projekt abgeschlossen (Ein lebendiges Haustier gebaut).",
+ "icon": "📦",
+ "name": "Zertifikat: State-Machine & Domänenmodellierung",
+ "desc": "OOP Mini-Projekt abgeschlossen (Zustandsverwaltung & Objektinteraktion).",
"xp_bonus": 250,
"kriterium": [
"lehrpfad_2_oop_einstieg/06_abschlussprojekt_tamagotchi"
@@ -122,8 +122,8 @@ window.GAMIFICATION_BADGES_KATALOG = {
"zeit_reisende": {
"id": "zeit_reisende",
"icon": "🌿",
- "name": "Git-Zeitreisende",
- "desc": "Kapitel 04c Git-Versionskontrolle verstanden & Spielstände gesichert.",
+ "name": "Zertifikat: String-Repräsentation & Dunder-Methoden",
+ "desc": "OOP 04 gelöst (Spezielle Methoden __str__, __repr__ implementiert).",
"xp_bonus": 100,
"kriterium": [
"lehrpfad_2_oop_einstieg/04_str_und_darstellung"
@@ -132,8 +132,8 @@ window.GAMIFICATION_BADGES_KATALOG = {
"qualitaets_garantin": {
"id": "qualitaets_garantin",
"icon": "🧪",
- "name": "TDD-Qualitätsgarantin",
- "desc": "Kapitel 09 abgeschlossen (Eigene professionelle Unit Tests geschrieben).",
+ "name": "Zertifikat: Automatisierte Testsuites & TDD",
+ "desc": "OOP 09 abgeschlossen (Eigene professionelle Unit Tests mit Assertions).",
"xp_bonus": 200,
"kriterium": [
"lehrpfad_3_fortgeschrittenes_oop/09_eigene_unit_tests_schreiben"
@@ -142,8 +142,8 @@ window.GAMIFICATION_BADGES_KATALOG = {
"oop_grossmeisterin": {
"id": "oop_grossmeisterin",
"icon": "🧬",
- "name": "Vererbungs-Koryphäe",
- "desc": "Kapitel 10 bis 12 abgeschlossen (Vererbung, Polymorphie & Exceptions).",
+ "name": "Zertifikat: Fortgeschrittene OOP & Robustes Error-Handling",
+ "desc": "OOP 10 bis 12 abgeschlossen (Vererbung, Polymorphie & Exceptions).",
"xp_bonus": 300,
"kriterium": [
"lehrpfad_3_fortgeschrittenes_oop/10_vererbung_und_super",
@@ -154,8 +154,8 @@ window.GAMIFICATION_BADGES_KATALOG = {
"software_architektin": {
"id": "software_architektin",
"icon": "🏆",
- "name": "Meister-Entwicklerin",
- "desc": "Kapitel 16 Master-Projekt abgeschlossen & vollwertige Desktop-App gebaut!",
+ "name": "Zertifikat: Master-Projekt Software Engineering",
+ "desc": "Master-Projekt abgeschlossen & vollwertige Anwendungsarchitektur gebaut!",
"xp_bonus": 500,
"kriterium": [
"lehrpfad_3_fortgeschrittenes_oop/16_master_abschlussprojekt"
@@ -167,70 +167,70 @@ window.GAMIFICATION_LEVEL_STUFEN = [
"level": 1,
"min_xp": 0,
"max_xp": 150,
- "titel": "Code-Küken 🐣",
- "rang": "Bronze I"
+ "titel": "Junior IT-Trainee I: Syntax & Basistypen",
+ "rang": "Stufe 1"
},
{
"level": 2,
"min_xp": 151,
"max_xp": 400,
- "titel": "Code-Detektivin 🔍",
- "rang": "Bronze II"
+ "titel": "Junior IT-Trainee II: Kontrollfluss & Logik",
+ "rang": "Stufe 2"
},
{
"level": 3,
"min_xp": 401,
"max_xp": 800,
- "titel": "Logik-Bastlerin ⚙️",
- "rang": "Silber I"
+ "titel": "IT-Specialist: Funktionen & Datenstrukturen",
+ "rang": "Stufe 3"
},
{
"level": 4,
"min_xp": 801,
"max_xp": 1300,
- "titel": "Klassen-Baumeisterin 🏗️",
- "rang": "Silber II"
+ "titel": "Software Developer: OOP-Modellierung",
+ "rang": "Stufe 4"
},
{
"level": 5,
"min_xp": 1301,
"max_xp": 2000,
- "titel": "Git-Strategin 🌿",
- "rang": "Gold I"
+ "titel": "DevOps Engineer: Versionskontrolle & Tooling",
+ "rang": "Stufe 5"
},
{
"level": 6,
"min_xp": 2001,
"max_xp": 2900,
- "titel": "TDD-Qualitätsprüferin 🧪",
- "rang": "Gold II"
+ "titel": "Quality Engineer: Test-Driven Development (TDD)",
+ "rang": "Stufe 6"
},
{
"level": 7,
"min_xp": 2901,
"max_xp": 4000,
- "titel": "Vererbungs-Meisterin 🧬",
- "rang": "Platin I"
+ "titel": "Advanced Engineer: Entwurfsmuster & Polymorphie",
+ "rang": "Stufe 7"
},
{
"level": 8,
"min_xp": 4001,
"max_xp": 5300,
- "titel": "Exception-Wächterin 🛡️",
- "rang": "Platin II"
+ "titel": "Systems Engineer: Security & Error Handling",
+ "rang": "Stufe 8"
},
{
"level": 9,
"min_xp": 5301,
"max_xp": 6800,
- "titel": "GUI-Entwicklerin 🖥️",
- "rang": "Diamant"
+ "titel": "Application Engineer: Schnittstellen & UI",
+ "rang": "Stufe 9"
},
{
"level": 10,
"min_xp": 6801,
"max_xp": 99999,
- "titel": "Software-Architektin 🏆",
- "rang": "Großmeisterin"
+ "titel": "Certified IT Systems Professional (IHK AP2)",
+ "rang": "Master-Stufe"
}
];
diff --git a/assets/monaco_ide.js b/assets/monaco_ide.js
index 92b0f17..9f3139b 100644
--- a/assets/monaco_ide.js
+++ b/assets/monaco_ide.js
@@ -184,6 +184,101 @@
suggestErrorInterpreter(result.rawOutput);
}
}
+
+ // Strukturierten visuellen Test-Report mit Diff-Inspektor rendern
+ if (result && (result.total > 0 || result.rawOutput)) {
+ renderVisualTestReport(result);
+ }
+ }
+
+ window.jumpToEditorLine = function(line) {
+ if (monacoEditor && line) {
+ monacoEditor.revealLineInCenter(line);
+ monacoEditor.setPosition({ lineNumber: line, column: 1 });
+ monacoEditor.focus();
+ }
+ };
+
+ function renderVisualTestReport(result) {
+ const term = document.getElementById("workspace-terminal-output");
+ if (!term) return;
+
+ const cases = [];
+ const raw = result.rawOutput || "";
+
+ const lineRegex = /(test_\w+)\s+\([^)]+\)\s+\.\.\.\s+(ok|FAIL|ERROR)/g;
+ let match;
+ while ((match = lineRegex.exec(raw)) !== null) {
+ cases.push({
+ name: match[1],
+ passed: match[2] === "ok",
+ status: match[2]
+ });
+ }
+
+ const fileLineMatch = raw.match(/File\s+["'].*?aufgabe\.\w+["'],\s+line\s+(\d+)/i);
+ const errorLine = fileLineMatch ? parseInt(fileLineMatch[1], 10) : null;
+
+ let expectedVal = null;
+ let actualVal = null;
+ const assertEqualMatch = raw.match(/AssertionError:\s*(.*?)\s*!=\s*(.*)/);
+ if (assertEqualMatch) {
+ actualVal = assertEqualMatch[1].trim();
+ expectedVal = assertEqualMatch[2].trim();
+ }
+
+ const reportCard = document.createElement("div");
+ reportCard.style.marginTop = "14px";
+
+ const total = result.total || cases.length || 1;
+ const passed = result.passed !== undefined ? result.passed : (result.success ? total : 0);
+ const isSuccess = result.success;
+
+ reportCard.innerHTML = `
+
+ ${isSuccess ? '🎉 Alle ' + total + ' Tests bestanden!' : '⚠️ ' + (total - passed) + ' von ' + total + ' Test(s) fehlgeschlagen'}
+ ${passed} / ${total} Tests OK
+
+ `;
+
+ if (cases.length > 0) {
+ cases.forEach(c => {
+ const card = document.createElement("div");
+ card.className = "test-case-card";
+ const hasErr = !c.passed;
+
+ card.innerHTML = `
+
+
+ ${hasErr ? `
+
+ Meldung: Test fehlgeschlagen.
+
+ ${expectedVal ? `
+
+
Erwartet: ${escapeHtml(expectedVal)}
+
Erhalten: ${escapeHtml(actualVal)}
+
+ ` : ''}
+ ${errorLine ? `
+
+ 📍 Zu Zeile ${errorLine} in deiner Aufgabe springen
+
+ ` : ''}
+ ` : '
Dieser Testfall wurde ohne Fehler bestanden.
'}
+
+ `;
+ reportCard.appendChild(card);
+ });
+ }
+
+ term.appendChild(reportCard);
+ term.scrollTop = term.scrollHeight;
}
// 4. Hilfsfunktionen
diff --git a/assets/style.css b/assets/style.css
index 136dad3..52f17c8 100644
--- a/assets/style.css
+++ b/assets/style.css
@@ -9,6 +9,14 @@
--primary-light: #eff6ff;
--primary-glow: rgba(29, 78, 216, 0.12);
+ --brand-50: #eff6ff;
+ --brand-100: #dbeafe;
+ --brand-500: #3b82f6;
+ --brand-600: #2563eb;
+ --brand-700: #1d4ed8;
+
+ /* Neutral Scale (Slate Palette) */
+ --slate-950: #090d16;
--slate-900: #0f172a;
--slate-800: #1e293b;
--slate-700: #334155;
@@ -20,6 +28,23 @@
--slate-100: #f1f5f9;
--slate-50: #f8fafc;
+ /* Semantic Status Tokens (WCAG AA & AAA Compliant) */
+ --status-success: #059669;
+ --status-success-bg: rgba(5, 150, 105, 0.08);
+ --status-success-border: rgba(5, 150, 105, 0.20);
+
+ --status-warning: #b45309;
+ --status-warning-bg: rgba(217, 119, 6, 0.08);
+ --status-warning-border: rgba(217, 119, 6, 0.20);
+
+ --status-danger: #dc2626;
+ --status-danger-bg: rgba(220, 38, 38, 0.08);
+ --status-danger-border: rgba(220, 38, 38, 0.20);
+
+ --status-info: #2563eb;
+ --status-info-bg: rgba(37, 99, 235, 0.08);
+ --status-info-border: rgba(37, 99, 235, 0.20);
+
--emerald: #059669;
--emerald-light: #f0fdf4;
@@ -36,31 +61,44 @@
--success-light: #f0fdf4;
/* Surfaces & Backgrounds */
+ --bg-canvas: #f8fafc;
--bg-body: #f8fafc;
--bg-surface: #ffffff;
+ --bg-surface-hover: #f1f5f9;
--bg-subtle: #f1f5f9;
--bg-sidebar: #0f172a;
- --bg-code: #0b0f19;
+ --bg-code: #090d16;
- /* Borders */
+ /* Border-First Design System */
+ --border-subtle: rgba(15, 23, 42, 0.08);
+ --border-default: rgba(15, 23, 42, 0.12);
+ --border-hover: rgba(15, 23, 42, 0.24);
--border-color: #e2e8f0;
--border-dark: #1e293b;
- /* Typography */
- --text-main: #0f172a;
- --text-body: #334155;
- --text-muted: #64748b;
+ /* Typography (WCAG AAA for body text) */
+ --text-main: #0f172a; /* Kontrast > 18:1 auf Weiß */
+ --text-primary: #0f172a;
+ --text-body: #334155; /* Kontrast > 10:1 auf Weiß */
+ --text-secondary: #334155;
+ --text-muted: #64748b; /* Kontrast > 5.4:1 auf Weiß (Sicherer AA Standard) */
--text-inverse: #f8fafc;
- --font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
+ --font-sans: 'Plus Jakarta Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
--font-mono: 'JetBrains Mono', 'Fira Code', 'SFMono-Regular', Consolas, Menlo, monospace;
+ /* Cognitive Load Limit for Text Containers */
+ --content-max-width: 70ch;
+
/* Elevation */
+ --shadow-xs: 0 1px 2px rgba(0, 0, 0, 0.04);
--shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
--shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.06), 0 2px 4px -2px rgba(0, 0, 0, 0.04);
--shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.08), 0 4px 6px -4px rgba(0, 0, 0, 0.03);
--shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.08), 0 8px 10px -6px rgba(0, 0, 0, 0.03);
+ --focus-ring: 0 0 0 2px var(--bg-surface), 0 0 0 4px var(--primary);
+ --radius-xs: 4px;
--radius-sm: 6px;
--radius-md: 10px;
--radius-lg: 14px;
@@ -3111,4 +3149,403 @@ tbody tr:hover {
color: #fca5a5 !important;
}
+/* ==========================================================================
+ ENGINEERING-GRADE COMPONENT SYSTEM & DIDACTIC LAYOUT (WCAG AAA)
+ ========================================================================== */
+
+/* --- Reading Width Limitation (Cognitive Load Reduction) --- */
+.content-readable,
+.card p,
+.box p {
+ max-width: var(--content-max-width);
+}
+
+/* --- Standard Buttons --- */
+.btn-primary {
+ background-color: var(--brand-600);
+ color: #ffffff !important;
+ border: 1px solid var(--brand-700);
+ box-shadow: var(--shadow-xs);
+ font-weight: 600;
+}
+.btn-primary:hover {
+ background-color: var(--brand-700);
+}
+
+.btn-secondary {
+ background-color: var(--bg-surface);
+ color: var(--text-primary) !important;
+ border: 1px solid var(--border-default);
+ box-shadow: var(--shadow-xs);
+}
+.btn-secondary:hover {
+ background-color: var(--bg-surface-hover);
+ border-color: var(--border-hover);
+}
+
+.btn-ghost {
+ background-color: transparent;
+ color: var(--text-secondary) !important;
+ border: 1px solid transparent;
+}
+.btn-ghost:hover {
+ background-color: var(--bg-subtle);
+ color: var(--text-primary) !important;
+}
+
+.btn-danger {
+ background-color: var(--status-danger-bg);
+ color: var(--status-danger) !important;
+ border: 1px solid var(--status-danger-border);
+}
+.btn-danger:hover {
+ background-color: var(--status-danger);
+ color: #ffffff !important;
+}
+
+.btn:focus-visible {
+ outline: none;
+ box-shadow: var(--focus-ring);
+}
+
+/* --- Badges & Pills (Engineering Grade) --- */
+.badge {
+ display: inline-flex;
+ align-items: center;
+ gap: 5px;
+ padding: 3px 8px;
+ font-family: var(--font-sans);
+ font-size: 0.75rem;
+ font-weight: 600;
+ border-radius: var(--radius-full);
+ letter-spacing: 0.02em;
+}
+
+.badge-neutral {
+ background: var(--bg-subtle);
+ color: var(--text-secondary);
+ border: 1px solid var(--border-subtle);
+}
+
+.badge-success {
+ background: var(--status-success-bg);
+ color: var(--status-success);
+ border: 1px solid var(--status-success-border);
+}
+
+.badge-warning {
+ background: var(--status-warning-bg);
+ color: var(--status-warning);
+ border: 1px solid var(--status-warning-border);
+}
+
+.badge-danger {
+ background: var(--status-danger-bg);
+ color: var(--status-danger);
+ border: 1px solid var(--status-danger-border);
+}
+
+.badge-info {
+ background: var(--status-info-bg);
+ color: var(--status-info);
+ border: 1px solid var(--status-info-border);
+}
+
+/* --- Code-Block Container (with Copy Action) --- */
+.code-block {
+ background: var(--bg-code);
+ border: 1px solid var(--border-subtle);
+ border-radius: var(--radius-md);
+ margin: 16px 0;
+ overflow: hidden;
+}
+
+.code-block-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 8px 14px;
+ background: rgba(255, 255, 255, 0.03);
+ border-bottom: 1px solid var(--border-subtle);
+}
+
+.code-block-title {
+ font-family: var(--font-mono);
+ font-size: 0.78rem;
+ color: #94a3b8;
+}
+
+.code-copy-btn {
+ font-family: var(--font-sans);
+ font-size: 0.75rem;
+ font-weight: 600;
+ color: #cbd5e1;
+ background: rgba(255, 255, 255, 0.08);
+ border: 1px solid rgba(255, 255, 255, 0.1);
+ padding: 3px 9px;
+ border-radius: var(--radius-xs);
+ cursor: pointer;
+ transition: all 0.15s ease;
+}
+.code-copy-btn:hover {
+ background: rgba(255, 255, 255, 0.16);
+ color: #ffffff;
+}
+
+/* --- Didaktische Boxen: Gotchas (Stolperfallen) & Syntax-Boxen --- */
+.box-gotcha {
+ background: #fffbeb;
+ border: 1px solid #fde68a;
+ border-left: 4px solid #d97706;
+ border-radius: var(--radius-sm);
+ padding: 14px 18px;
+ margin: 16px 0;
+ color: #92400e;
+}
+.box-gotcha h4 {
+ margin: 0 0 6px 0;
+ color: #78350f;
+ font-size: 0.95rem;
+ display: flex;
+ align-items: center;
+ gap: 6px;
+}
+
+.box-syntax {
+ background: #f8fafc;
+ border: 1px solid #e2e8f0;
+ border-radius: var(--radius-sm);
+ padding: 14px 18px;
+ margin: 16px 0;
+}
+.box-syntax h4 {
+ margin: 0 0 8px 0;
+ color: var(--text-primary);
+ font-size: 0.92rem;
+ display: flex;
+ align-items: center;
+ gap: 6px;
+}
+
+/* --- Subgoal Cards (Cowan Limit 3-4 Steps) --- */
+.subgoal-item {
+ display: flex;
+ align-items: flex-start;
+ gap: 12px;
+ padding: 12px 14px;
+ background: #ffffff;
+ border: 1px solid var(--border-default);
+ border-radius: var(--radius-sm);
+ margin-bottom: 8px;
+ transition: all 0.15s ease;
+}
+.subgoal-item:hover {
+ border-color: var(--primary);
+ box-shadow: var(--shadow-xs);
+}
+.subgoal-badge {
+ font-family: var(--font-mono);
+ font-size: 0.78rem;
+ font-weight: 700;
+ color: var(--brand-700);
+ background: var(--brand-50);
+ border: 1px solid var(--brand-100);
+ padding: 3px 8px;
+ border-radius: var(--radius-xs);
+ flex-shrink: 0;
+}
+
+/* --- Persistent Sticky Launch Action Bar --- */
+.sticky-launch-bar {
+ position: sticky;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ background: rgba(15, 23, 42, 0.94);
+ backdrop-filter: blur(8px);
+ border-top: 1px solid rgba(255, 255, 255, 0.1);
+ padding: 12px 24px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ z-index: 50;
+}
+.btn-cta-launch {
+ background: #2563eb;
+ color: #ffffff !important;
+ font-weight: 700;
+ font-size: 0.95rem;
+ padding: 10px 20px;
+ border-radius: var(--radius-sm);
+ text-decoration: none;
+ display: inline-flex;
+ align-items: center;
+ gap: 8px;
+ box-shadow: 0 2px 10px rgba(37, 99, 235, 0.35);
+ transition: all 0.15s ease;
+}
+.btn-cta-launch:hover {
+ background: #1d4ed8;
+ transform: translateY(-1px);
+}
+
+/* --- Resizable Workspace Splitters (Gutter) --- */
+.gutter-col {
+ width: 5px;
+ background: rgba(255, 255, 255, 0.08);
+ cursor: col-resize;
+ position: relative;
+ transition: background 0.15s ease;
+ z-index: 20;
+ flex-shrink: 0;
+}
+.gutter-col::after {
+ content: "";
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: -5px;
+ right: -5px;
+ cursor: col-resize;
+}
+.gutter-col:hover,
+.gutter-col.dragging {
+ background: #38bdf8;
+}
+
+.gutter-row {
+ height: 5px;
+ background: rgba(255, 255, 255, 0.08);
+ cursor: row-resize;
+ position: relative;
+ transition: background 0.15s ease;
+ z-index: 20;
+ flex-shrink: 0;
+}
+.gutter-row::after {
+ content: "";
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: -5px;
+ bottom: -5px;
+ cursor: row-resize;
+}
+.gutter-row:hover,
+.gutter-row.dragging {
+ background: #38bdf8;
+}
+
+/* --- Structured Visual Test Runner Cards --- */
+.test-summary-badge {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 10px 14px;
+ border-radius: var(--radius-sm);
+ font-weight: 700;
+ font-size: 0.88rem;
+ margin-bottom: 10px;
+}
+.test-summary-badge.passed {
+ background: rgba(16, 185, 129, 0.15);
+ color: #34d399;
+ border: 1px solid rgba(16, 185, 129, 0.3);
+}
+.test-summary-badge.failed {
+ background: rgba(239, 68, 68, 0.15);
+ color: #f87171;
+ border: 1px solid rgba(239, 68, 68, 0.3);
+}
+
+.test-case-card {
+ border: 1px solid rgba(255, 255, 255, 0.08);
+ border-radius: var(--radius-sm);
+ background: #090d16;
+ margin-bottom: 8px;
+ overflow: hidden;
+}
+.test-case-header {
+ padding: 8px 12px;
+ background: #0f172a;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ cursor: pointer;
+ font-size: 0.84rem;
+ user-select: none;
+}
+.test-case-header:hover {
+ background: #1e293b;
+}
+.test-case-details {
+ padding: 10px 14px;
+ font-family: var(--font-mono);
+ font-size: 0.82rem;
+ line-height: 1.5;
+ border-top: 1px solid rgba(255, 255, 255, 0.06);
+}
+.test-diff-inspector {
+ background: #060911;
+ border: 1px solid rgba(255, 255, 255, 0.08);
+ border-radius: 4px;
+ padding: 8px 12px;
+ margin: 6px 0;
+ font-size: 0.8rem;
+}
+.test-diff-expected {
+ color: #4ade80;
+}
+.test-diff-actual {
+ color: #f87171;
+}
+.btn-jump-code {
+ background: rgba(56, 189, 248, 0.12);
+ color: #38bdf8;
+ border: 1px solid rgba(56, 189, 248, 0.25);
+ padding: 4px 10px;
+ border-radius: 4px;
+ font-size: 0.76rem;
+ font-family: var(--font-sans);
+ font-weight: 600;
+ cursor: pointer;
+ transition: all 0.15s ease;
+ margin-top: 6px;
+}
+.btn-jump-code:hover {
+ background: rgba(56, 189, 248, 0.25);
+ color: #ffffff;
+}
+
+/* ==========================================================================
+ DARK THEME OVERRIDES ([data-theme="dark"])
+ ========================================================================== */
+[data-theme="dark"] {
+ --bg-canvas: #090d16;
+ --bg-body: #090d16;
+ --bg-surface: #0f172a;
+ --bg-surface-hover: #1e293b;
+ --bg-subtle: rgba(255, 255, 255, 0.04);
+ --bg-code: #05080f;
+
+ --border-subtle: rgba(255, 255, 255, 0.08);
+ --border-default: rgba(255, 255, 255, 0.12);
+ --border-hover: rgba(255, 255, 255, 0.25);
+
+ --text-main: #f8fafc;
+ --text-primary: #f8fafc;
+ --text-body: #cbd5e1;
+ --text-secondary: #cbd5e1;
+ --text-muted: #94a3b8;
+
+ --brand-500: #3b82f6;
+ --brand-600: #60a5fa;
+
+ --shadow-xs: none;
+ --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.4);
+ --shadow-md: 0 8px 24px rgba(0, 0, 0, 0.5);
+ --focus-ring: 0 0 0 2px #090d16, 0 0 0 4px #3b82f6;
+}
+
+
diff --git a/courses/bash/01_navigation_dateien_und_globbing/index.html b/courses/bash/01_navigation_dateien_und_globbing/index.html
index f5607cb..f51cdec 100644
--- a/courses/bash/01_navigation_dateien_und_globbing/index.html
+++ b/courses/bash/01_navigation_dateien_und_globbing/index.html
@@ -6,148 +6,167 @@
Bash 01: Terminal-Navigation & Globbing
+
-
-
- 🧭 1. Der Unix-Dateibaum & Pfad-Navigation
- In Unix gibt es keine Laufwerksbuchstaben (wie C: oder D:). Alles entspringt dem Root-Verzeichnis / (Single Root Tree). Wir unterscheiden strikt zwischen absoluten und relativen Pfaden:
-
- # Wo bin ich?
+
+
+
+
+
+ 🧭 1. Der Unix-Dateibaum & Pfad-Navigation
+ In Unix gibt es keine Laufwerksbuchstaben (wie C:). Alles entspringt dem Root-Verzeichnis / (Single Root Tree). Wir unterscheiden strikt zwischen absoluten Pfaden (beginnen immer mit /) und relativen Pfaden (relativ zum aktuellen Arbeitsverzeichnis pwd).
+
+
+
+
# Wo bin ich?
pwd # Ausgabe: /home/devops/projects
# Relative vs. Absolute Navigation:
-cd /var/log/nginx # Absoluter Pfad: Beginnt immer mit '/'
+cd /var/log/nginx # Absoluter Pfad
cd ../../etc # Relativer Pfad: Zwei Ebenen hoch, dann in 'etc'
-cd ~ # Wechselt ins Home-Verzeichnis (/home/user)
-cd - # Wechselt zum vorherigen Verzeichnis zurück
+cd ~ # Home-Verzeichnis
+cd - # Vorheriges Verzeichnis
+
-# Detailliertes Listing mit Berechtigungen und Dateigrößen:
-ls -lah # -l: Long Format, -a: Versteckte Dateien, -h: Human-readable (KB/MB)
-
+
+
🏢 Didaktische Analogie: Das Hochregallager des Betriebssystems
+
Der Dateibaum: Stell dir das Linux-Dateisystem wie ein gigantisches Logistikzentrum vor. / ist das Haupttor. Mit mkdir -p stellst du mit einer einzigen Anweisung eine ganze Regalreihe mit Fächern auf.
+
Globbing (* und {a,b}): Statt jedes Paket einzeln zu scannen, hältst du eine Schablone hoch: *.yaml greift automatisch alle Konfigurationen, während {dev,prod} im Handumdrehen zwei Umgebungen parallel anlegt!
+
+
-
-
- 📁 2. Dateisystem-Operationen & Mächtiges Globbing
- Als DevOps-Ingenieur erstellst, kopierst und reorganisierst du Konfigurationsdateien im Sekundentakt. Die Shell bietet hierfür mächtige Werkzeuge:
+
+
+ 🎯 2. Dein Arbeitsauftrag: 4 Subgoals (Teilziele)
+ Bearbeite die Aufgaben in aufgabe.sh schrittweise:
- # 🎯 1. Verzeichnisse verschachtelt anlegen:
-mkdir -p app/{config,src/{models,views},logs,tests}
+
+
Subgoal 1
+
+
Projektverzeichnisse anlegen:
+
Implementiere erstelle_projektstruktur(basis_dir) mit mkdir -p für src/components, src/utils, docs/api und backup/logs.
+
+
-# 🎯 2. Dateien mit Brace Expansion massenweise erstellen:
-touch app/src/models/{user,order,payment}.py app/config/{dev,staging,prod}.yaml
+
+
Subgoal 2
+
+
Testdateien erzeugen:
+
Erstelle mit touch und Brace Expansion Beispieldateien in den angelegten Ordnern.
+
+
-# 🎯 3. Shell-Globbing (Wildcards):
-cp app/config/*.yaml /backup/configs/ # Alle .yaml Dateien kopieren
-mv app/logs/app_2026-??.log /archive/logs/ # Matcht genau 2 Zeichen für den Monat (z.B. 01..12)
-rm -rf /tmp/build_cache/ # Rekursives Löschen ohne Bestätigung
+
+
Subgoal 3
+
+
Dateien kopieren & Globbing:
+
Kopiere mit cp und Wildcards (*.yaml, *.log) alle Konfigurationsdateien in das Backup-Verzeichnis.
+
+
-
-
🏢 Didaktische Analogie: Das Logistikzentrum des Betriebssystems
-
Der Dateibaum: Stell dir das Dateisystem wie ein riesiges, strukturiertes Hochregallager vor. / ist der Haupteingang. mkdir -p baut dir sofort eine ganze Gasse mit Fachböden auf.
-
Globbing (* und {a,b}): Anstatt jedes Paket einzeln mit der Hand zu scannen, hältst du eine Schablone hoch: *.yaml greift automatisch alle blauen Kisten aus dem Regal, während {dev,prod} mit einem Handgriff zwei vorgefertigte Etiketten druckt!
-
-
-
-
-
- 📑 3. Cheat-Sheet: Navigation & Wildcards
-
-
-
-
- Befehl / Muster
- Beispiel
- Bedeutung & DevOps-Einsatz
-
-
-
-
- mkdir -p <pfad>
- mkdir -p /srv/app/releases
- Erstellt Elternverzeichnisse automatisch ohne Fehler
-
-
- cp -r <src> <dst>
- cp -r ./templates /etc/nginx/
- Kopiert ganze Verzeichnisbäume rekursiv
-
-
- mv <src> <dst>
- mv old.env .env.backup
- Verschiebt oder benennt Dateien atomar um
-
-
- rm -rf <pfad>
- rm -rf ./temp_workspace
- Löscht rekursiv und erzwingt Löschen ohne Prompt
-
-
- * (Wildcard)
- rm -f *.log
- Matcht 0 oder beliebig viele Zeichen
-
-
- ? (Single Char)
- ls node_v?.log
- Matcht exakt ein einziges Zeichen
-
-
- {a,b,c}
- touch {app,db}_{1..3}.conf
- Brace Expansion zur raschen Permutationserstellung
-
-
-
-
-
-
-
-
- 🎯 Aufgaben & Checkliste in aufgabe.sh
-
-
- TODO 1: erstelle_projektstruktur(basis_dir) mit mkdir -p implementieren (src/components, src/utils, docs/api, backup/logs).
-
-
-
- TODO 2: erstelle_testdateien(basis_dir) mit touch und Dateimustern umsetzen.
-
-
-
- TODO 3: kopiere_konfigurationen(src_dir, backup_dir) mit cp und Globbing (*.yaml, *.log) schreiben.
-
-
-
- TODO 4: verschiebe_dateien(src_dir, target_dir) für *.md Dokumentationen implementieren.
-
-
-
-
TODO 5: bereinige_temporaere_dateien(basis_dir) mit rm -f und rm -rf fertigstellen.
+
+
Subgoal 4
+
+
Temporäre Dateien bereinigen:
+
Nutze rm -f und rm -rf, um Cache- und temporäre Logdateien sauber zu entfernen.
+
+
+
-
-
💡 DevOps Pro-Tipp: Quoting in Shell-Skripten
-
Setze Variablen bei Pfadangaben in Bash-Skripten stets in doppelte Anführungszeichen: "$basis_dir/src/components". Das verhindert gefürchtete Word Splitting Fehler, falls ein Verzeichnisname einmal Leerzeichen enthält!
-
+
+
+
+
+
⚠️ Häufige Stolperfallen (Pre-Mortem)
+
1. Fehlendes -p bei mkdir: Wenn du mkdir a/b/c aufrufst und Ordner a noch nicht existiert, bricht die Shell mit No such file or directory ab. Verwende immer mkdir -p!
+
2. Word Splitting ohne Quotes: Setze Variablenpfade in Skripten stets in doppelte Anführungszeichen: "$basis_dir/src", sonst führen Leerzeichen im Ordnernamen zu fatalen Syntaxfehlern.
+
-
-
💻 In Web-IDE öffnen →
-
Weiter zu Bash 02 →
+
+
+
📌 Syntax-Spickzettel: Shell-Muster
+
+
+
+ Muster
+ Bedeutung
+
+
+
+
+ *
+ Matcht 0 bis unendlich viele Zeichen
+
+
+ ?
+ Matcht exakt 1 Zeichen
+
+
+ {a,b}
+ Brace Expansion (Permutation)
+
+
+ mkdir -p
+ Erstellt Elternordner automatisch
+
+
+
+
+
+
+
+
💡 IHK-Prüfungstipp (AP1)
+
In der IHK-Abschlussprüfung Teil 1 wird regelmäßig der Unterschied zwischen relativer und absoluter Pfadangabe sowie die Bedeutung von cd .. und ls -l abgefragt.
+
-
+
+
+
+
+
+ 🎯 Status: Bereit für die Praxis (4 Teilziele definiert)
+
+
+
diff --git a/gamification.py b/gamification.py
index a39002a..83e3626 100644
--- a/gamification.py
+++ b/gamification.py
@@ -21,26 +21,26 @@ ROOT_DIR = Path(__file__).parent.resolve()
DATA_JSON_PATH = ROOT_DIR / ".gamification.json"
DATA_JS_PATH = ROOT_DIR / "assets" / "gamification_data.js"
-# 10 Entwickler-Level mit XP-Schwellen und Titeln
+# 10 Entwickler-Level mit XP-Schwellen und professionellen IT-Kompetenzstufen
LEVEL_STUFEN = [
- {"level": 1, "min_xp": 0, "max_xp": 150, "titel": "Code-Küken 🐣", "rang": "Bronze I"},
- {"level": 2, "min_xp": 151, "max_xp": 400, "titel": "Code-Detektivin 🔍", "rang": "Bronze II"},
- {"level": 3, "min_xp": 401, "max_xp": 800, "titel": "Logik-Bastlerin ⚙️", "rang": "Silber I"},
- {"level": 4, "min_xp": 801, "max_xp": 1300, "titel": "Klassen-Baumeisterin 🏗️", "rang": "Silber II"},
- {"level": 5, "min_xp": 1301, "max_xp": 2000, "titel": "Git-Strategin 🌿", "rang": "Gold I"},
- {"level": 6, "min_xp": 2001, "max_xp": 2900, "titel": "TDD-Qualitätsprüferin 🧪", "rang": "Gold II"},
- {"level": 7, "min_xp": 2901, "max_xp": 4000, "titel": "Vererbungs-Meisterin 🧬", "rang": "Platin I"},
- {"level": 8, "min_xp": 4001, "max_xp": 5300, "titel": "Exception-Wächterin 🛡️", "rang": "Platin II"},
- {"level": 9, "min_xp": 5301, "max_xp": 6800, "titel": "GUI-Entwicklerin 🖥️", "rang": "Diamant"},
- {"level": 10, "min_xp": 6801, "max_xp": 99999, "titel": "Software-Architektin 🏆", "rang": "Großmeisterin"},
+ {"level": 1, "min_xp": 0, "max_xp": 150, "titel": "Junior IT-Trainee I: Syntax & Basistypen", "rang": "Stufe 1"},
+ {"level": 2, "min_xp": 151, "max_xp": 400, "titel": "Junior IT-Trainee II: Kontrollfluss & Logik", "rang": "Stufe 2"},
+ {"level": 3, "min_xp": 401, "max_xp": 800, "titel": "IT-Specialist: Funktionen & Datenstrukturen", "rang": "Stufe 3"},
+ {"level": 4, "min_xp": 801, "max_xp": 1300, "titel": "Software Developer: OOP-Modellierung", "rang": "Stufe 4"},
+ {"level": 5, "min_xp": 1301, "max_xp": 2000, "titel": "DevOps Engineer: Versionskontrolle & Tooling", "rang": "Stufe 5"},
+ {"level": 6, "min_xp": 2001, "max_xp": 2900, "titel": "Quality Engineer: Test-Driven Development (TDD)", "rang": "Stufe 6"},
+ {"level": 7, "min_xp": 2901, "max_xp": 4000, "titel": "Advanced Engineer: Entwurfsmuster & Polymorphie", "rang": "Stufe 7"},
+ {"level": 8, "min_xp": 4001, "max_xp": 5300, "titel": "Systems Engineer: Security & Error Handling", "rang": "Stufe 8"},
+ {"level": 9, "min_xp": 5301, "max_xp": 6800, "titel": "Application Engineer: Schnittstellen & UI", "rang": "Stufe 9"},
+ {"level": 10, "min_xp": 6801, "max_xp": 99999, "titel": "Certified IT Systems Professional (IHK AP2)", "rang": "Master-Stufe"},
]
-# 14 freischaltbare Trophäen mit didaktischen Kriterien (abgestimmt auf neue Lehrpfad-Pfade)
+# 14 freischaltbare IT-Kompetenz-Zertifikate (abgestimmt auf IHK-Rahmenlehrplan)
BADGES_KATALOG = {
"rechenkonegin": {
"id": "rechenkonegin",
"icon": "🧮",
- "name": "Rechenkönigin",
+ "name": "Zertifikat: Numerische Typen & Arithmetik",
"desc": "Grundlagen 01 & 02 abgeschlossen (Zahlen, Operatoren & Typen gemeistert).",
"xp_bonus": 100,
"kriterium": [
@@ -51,7 +51,7 @@ BADGES_KATALOG = {
"dialog_profi": {
"id": "dialog_profi",
"icon": "💬",
- "name": "Dialog-Profi",
+ "name": "Zertifikat: Interaktive I/O & String-Interpolation",
"desc": "Grundlagen 03 abgeschlossen (Interaktive Ein-/Ausgabe mit f-Strings).",
"xp_bonus": 75,
"kriterium": ["lehrpfad_1_grundlagen/03_ein_und_ausgabe"]
@@ -59,32 +59,32 @@ BADGES_KATALOG = {
"weichenstellerin": {
"id": "weichenstellerin",
"icon": "🚦",
- "name": "Weichenstellerin",
- "desc": "Grundlagen 04 abgeschlossen (Bedingungslogik & Schaltjahre gemeistert).",
+ "name": "Zertifikat: Verzweigungslogik & Boolesche Algebra",
+ "desc": "Grundlagen 04 abgeschlossen (Bedingungslogik & Kontrollfluss gemeistert).",
"xp_bonus": 75,
"kriterium": ["lehrpfad_1_grundlagen/04_verzweigungen_und_bedingungen"]
},
"schleifen_dompteurin": {
"id": "schleifen_dompteurin",
"icon": "🎡",
- "name": "Schleifen-Dompteurin",
- "desc": "Grundlagen 05 abgeschlossen (While- & For-Schleifen gebändigt).",
+ "name": "Zertifikat: Iterationslogik & Sequenzverarbeitung",
+ "desc": "Grundlagen 05 abgeschlossen (While- & For-Schleifen gemeistert).",
"xp_bonus": 100,
"kriterium": ["lehrpfad_1_grundlagen/05_schleifen_und_wiederholungen"]
},
"funktions_zauberin": {
"id": "funktions_zauberin",
- "icon": "🪄",
- "name": "Funktions-Zauberin",
- "desc": "Grundlagen 06 abgeschlossen (Eigene Funktionen & Module gebaut).",
+ "icon": "📐",
+ "name": "Zertifikat: Modulare Funktionsarchitektur",
+ "desc": "Grundlagen 06 abgeschlossen (Modulare Funktionen & Parameterübergabe).",
"xp_bonus": 100,
"kriterium": ["lehrpfad_1_grundlagen/06_funktionen_und_module"]
},
"listen_archivarin": {
"id": "listen_archivarin",
"icon": "📋",
- "name": "Listen-Archivarin",
- "desc": "Grundlagen 07 & 08 abgeschlossen (Sequenzen & Strings analysiert).",
+ "name": "Zertifikat: Datenstrukturen: Listen & Slicing",
+ "desc": "Grundlagen 07 & 08 abgeschlossen (Sequenzen, Listen & Slicing analysiert).",
"xp_bonus": 120,
"kriterium": [
"lehrpfad_1_grundlagen/07_listen_und_sequenzen",
@@ -94,8 +94,8 @@ BADGES_KATALOG = {
"daten_strategin": {
"id": "daten_strategin",
"icon": "🗃️",
- "name": "Daten-Strategin",
- "desc": "Grundlagen 09 & 10 abgeschlossen (Dicts, Sets & Comprehensions gemeistert).",
+ "name": "Zertifikat: Assoziative Arrays: Dicts & Sets",
+ "desc": "Grundlagen 09 & 10 abgeschlossen (Dictionaries, Sets & Hash-Lookup O(1)).",
"xp_bonus": 150,
"kriterium": [
"lehrpfad_1_grundlagen/09_dictionaries_und_sets",
@@ -105,16 +105,16 @@ BADGES_KATALOG = {
"bug_jaegerin": {
"id": "bug_jaegerin",
"icon": "🔍",
- "name": "Bug-Jägerin",
- "desc": "Kapitel 00 gelöst (Alle Fehler-Bugs im Warm-up aufgespürt).",
+ "name": "Zertifikat: Systematisches Code-Debugging",
+ "desc": "Warm-up abgeschlossen (Fehleranalyse & Traceback-Debugging).",
"xp_bonus": 100,
"kriterium": ["lehrpfad_2_oop_einstieg/00_fehlersuche_und_grundlagen"]
},
"erste_architektin": {
"id": "erste_architektin",
"icon": "🏗️",
- "name": "Erste Architektin",
- "desc": "Kapitel 01 bis 03 gelöst (Erste OOP-Klassen, Konstruktoren & Methoden).",
+ "name": "Zertifikat: OOP-Grundlagen: Klassen & Kapselung",
+ "desc": "OOP 01 bis 03 gelöst (Klassendefinition, Konstruktoren & Instanzmethoden).",
"xp_bonus": 200,
"kriterium": [
"lehrpfad_2_oop_einstieg/01_einstieg_klassen",
@@ -124,33 +124,33 @@ BADGES_KATALOG = {
},
"tamagotchi_mama": {
"id": "tamagotchi_mama",
- "icon": "🥚",
- "name": "Tamagotchi-Mama",
- "desc": "Kapitel 06 Mini-Projekt abgeschlossen (Ein lebendiges Haustier gebaut).",
+ "icon": "📦",
+ "name": "Zertifikat: State-Machine & Domänenmodellierung",
+ "desc": "OOP Mini-Projekt abgeschlossen (Zustandsverwaltung & Objektinteraktion).",
"xp_bonus": 250,
"kriterium": ["lehrpfad_2_oop_einstieg/06_abschlussprojekt_tamagotchi"]
},
"zeit_reisende": {
"id": "zeit_reisende",
"icon": "🌿",
- "name": "Git-Zeitreisende",
- "desc": "Kapitel 04c Git-Versionskontrolle verstanden & Spielstände gesichert.",
+ "name": "Zertifikat: String-Repräsentation & Dunder-Methoden",
+ "desc": "OOP 04 gelöst (Spezielle Methoden __str__, __repr__ implementiert).",
"xp_bonus": 100,
"kriterium": ["lehrpfad_2_oop_einstieg/04_str_und_darstellung"]
},
"qualitaets_garantin": {
"id": "qualitaets_garantin",
"icon": "🧪",
- "name": "TDD-Qualitätsgarantin",
- "desc": "Kapitel 09 abgeschlossen (Eigene professionelle Unit Tests geschrieben).",
+ "name": "Zertifikat: Automatisierte Testsuites & TDD",
+ "desc": "OOP 09 abgeschlossen (Eigene professionelle Unit Tests mit Assertions).",
"xp_bonus": 200,
"kriterium": ["lehrpfad_3_fortgeschrittenes_oop/09_eigene_unit_tests_schreiben"]
},
"oop_grossmeisterin": {
"id": "oop_grossmeisterin",
"icon": "🧬",
- "name": "Vererbungs-Koryphäe",
- "desc": "Kapitel 10 bis 12 abgeschlossen (Vererbung, Polymorphie & Exceptions).",
+ "name": "Zertifikat: Fortgeschrittene OOP & Robustes Error-Handling",
+ "desc": "OOP 10 bis 12 abgeschlossen (Vererbung, Polymorphie & Exceptions).",
"xp_bonus": 300,
"kriterium": [
"lehrpfad_3_fortgeschrittenes_oop/10_vererbung_und_super",
@@ -161,8 +161,8 @@ BADGES_KATALOG = {
"software_architektin": {
"id": "software_architektin",
"icon": "🏆",
- "name": "Meister-Entwicklerin",
- "desc": "Kapitel 16 Master-Projekt abgeschlossen & vollwertige Desktop-App gebaut!",
+ "name": "Zertifikat: Master-Projekt Software Engineering",
+ "desc": "Master-Projekt abgeschlossen & vollwertige Anwendungsarchitektur gebaut!",
"xp_bonus": 500,
"kriterium": ["lehrpfad_3_fortgeschrittenes_oop/16_master_abschlussprojekt"]
}
@@ -178,11 +178,11 @@ class GamificationManager:
def _default_state(self) -> Dict[str, Any]:
return {
- "spieler_name": "Python-Entwicklerin",
+ "spieler_name": "IT-Entwickler",
"xp": 0,
"level": 1,
- "titel": "Code-Küken 🐣",
- "rang": "Bronze I",
+ "titel": "Junior IT-Trainee I: Syntax & Basistypen",
+ "rang": "Stufe 1",
"geloeste_kapitel": [],
"bestandene_tests": 0,
"freigeschaltete_badges": [],
diff --git a/workspace.html b/workspace.html
index a254cc8..5b650bf 100644
--- a/workspace.html
+++ b/workspace.html
@@ -47,20 +47,24 @@
.workspace-body {
flex: 1;
- display: grid;
- grid-template-columns: 42% 58%;
+ display: flex;
+ flex-direction: row;
height: calc(100vh - 52px);
overflow: hidden;
+ position: relative;
}
.pane-left {
+ width: 40%;
+ min-width: 280px;
+ max-width: 65%;
background: #ffffff;
color: var(--text-main);
display: flex;
flex-direction: column;
- border-right: 2px solid #e2e8f0;
height: 100%;
overflow: hidden;
+ flex-shrink: 0;
}
.pane-tabs {
@@ -101,19 +105,21 @@
}
.pane-right {
+ flex: 1;
+ min-width: 360px;
display: flex;
flex-direction: column;
height: 100%;
- background: #0b0f19;
+ background: #090d16;
overflow: hidden;
}
.editor-wrapper {
- flex: 1;
height: 65%;
- min-height: 200px;
+ min-height: 140px;
position: relative;
- background: #0b0f19;
+ background: #090d16;
+ flex-shrink: 0;
}
#monaco-editor-container {
@@ -122,12 +128,23 @@
}
.terminal-wrapper {
- height: 35%;
- min-height: 140px;
+ flex: 1;
+ min-height: 80px;
background: #060911;
- border-top: 2px solid rgba(255, 255, 255, 0.08);
display: flex;
flex-direction: column;
+ overflow: hidden;
+ transition: height 0.15s ease;
+ }
+
+ .terminal-wrapper.collapsed {
+ flex: none !important;
+ height: 34px !important;
+ min-height: 34px !important;
+ }
+
+ .terminal-wrapper.collapsed #workspace-terminal-output {
+ display: none;
}
.terminal-header {
@@ -286,16 +303,28 @@
+
+
+
-
-
+
+
-
+
+
+
+
Klicke oben auf '▶ Code ausführen' (Strg+Enter) oder '🧪 Tests starten' (Strg+Shift+Enter)...
@@ -708,7 +737,206 @@
}
};
- document.addEventListener("DOMContentLoaded", loadWorkspaceData);
+ /* --- Resizable Splitters with State Persistence & Double-Click Reset --- */
+ function initSplitResizers() {
+ const layout = document.querySelector(".workspace-body");
+ const leftPane = document.querySelector(".pane-left");
+ const gutterCol = document.getElementById("gutter-col");
+ const editorWrap = document.getElementById("editor-wrapper");
+ const gutterRow = document.getElementById("gutter-row");
+ const termWrap = document.getElementById("terminal-wrapper");
+ const btnCollapseTerm = document.getElementById("btn-toggle-terminal-collapse");
+
+ if (!layout || !leftPane || !gutterCol || !editorWrap || !gutterRow) return;
+
+ // 1. Aus localStorage wiederherstellen
+ const savedLeft = localStorage.getItem("itp_split_x");
+ const savedEditor = localStorage.getItem("itp_split_y");
+ if (savedLeft && window.innerWidth >= 900) {
+ leftPane.style.width = savedLeft + "%";
+ }
+ if (savedEditor) {
+ editorWrap.style.height = savedEditor + "%";
+ }
+
+ // 2. Horizontaler Resizer (Didaktik links vs. Workspace rechts)
+ gutterCol.addEventListener("mousedown", (e) => {
+ e.preventDefault();
+ gutterCol.classList.add("dragging");
+ document.body.style.cursor = "col-resize";
+ document.body.style.userSelect = "none";
+
+ let animFrame = null;
+ function onMouseMove(moveEvent) {
+ if (animFrame) cancelAnimationFrame(animFrame);
+ animFrame = requestAnimationFrame(() => {
+ const containerWidth = layout.getBoundingClientRect().width;
+ let percent = (moveEvent.clientX / containerWidth) * 100;
+ if (percent < 22) percent = 22;
+ if (percent > 65) percent = 65;
+ leftPane.style.width = percent.toFixed(2) + "%";
+ if (window.monacoEditor) window.monacoEditor.layout();
+ });
+ }
+
+ function onMouseUp() {
+ gutterCol.classList.remove("dragging");
+ document.body.style.cursor = "";
+ document.body.style.userSelect = "";
+ localStorage.setItem("itp_split_x", parseFloat(leftPane.style.width));
+ window.removeEventListener("mousemove", onMouseMove);
+ window.removeEventListener("mouseup", onMouseUp);
+ if (window.monacoEditor) window.monacoEditor.layout();
+ }
+
+ window.addEventListener("mousemove", onMouseMove);
+ window.addEventListener("mouseup", onMouseUp);
+ });
+
+ // Doppelklick auf Spalten-Splitter: Zurücksetzen auf 40/60
+ gutterCol.addEventListener("dblclick", () => {
+ leftPane.style.width = "40%";
+ localStorage.setItem("itp_split_x", "40");
+ if (window.monacoEditor) window.monacoEditor.layout();
+ });
+
+ // 3. Vertikaler Resizer (Editor oben vs. Terminal unten)
+ gutterRow.addEventListener("mousedown", (e) => {
+ e.preventDefault();
+ gutterRow.classList.add("dragging");
+ document.body.style.cursor = "row-resize";
+ document.body.style.userSelect = "none";
+
+ const rightPane = document.getElementById("pane-right");
+ let animFrame = null;
+
+ function onMouseMove(moveEvent) {
+ if (animFrame) cancelAnimationFrame(animFrame);
+ animFrame = requestAnimationFrame(() => {
+ const rightRect = rightPane.getBoundingClientRect();
+ const relY = moveEvent.clientY - rightRect.top;
+ let percent = (relY / rightRect.height) * 100;
+ if (percent < 20) percent = 20;
+ if (percent > 80) percent = 80;
+ editorWrap.style.height = percent.toFixed(2) + "%";
+ if (window.monacoEditor) window.monacoEditor.layout();
+ });
+ }
+
+ function onMouseUp() {
+ gutterRow.classList.remove("dragging");
+ document.body.style.cursor = "";
+ document.body.style.userSelect = "";
+ localStorage.setItem("itp_split_y", parseFloat(editorWrap.style.height));
+ window.removeEventListener("mousemove", onMouseMove);
+ window.removeEventListener("mouseup", onMouseUp);
+ if (window.monacoEditor) window.monacoEditor.layout();
+ }
+
+ window.addEventListener("mousemove", onMouseMove);
+ window.addEventListener("mouseup", onMouseUp);
+ });
+
+ // Doppelklick auf Zeilen-Splitter: Zurücksetzen auf 65/35
+ gutterRow.addEventListener("dblclick", () => {
+ editorWrap.style.height = "65%";
+ localStorage.setItem("itp_split_y", "65");
+ if (window.monacoEditor) window.monacoEditor.layout();
+ });
+
+ // 4. Terminal Einklappen / Ausklappen
+ if (btnCollapseTerm && termWrap) {
+ btnCollapseTerm.addEventListener("click", () => {
+ const isCollapsed = termWrap.classList.toggle("collapsed");
+ btnCollapseTerm.innerText = isCollapsed ? "▲" : "▼";
+ btnCollapseTerm.title = isCollapsed ? "Panel ausklappen" : "Panel einklappen";
+ if (isCollapsed) {
+ editorWrap.style.height = "calc(100% - 34px)";
+ } else {
+ const savedY = localStorage.getItem("itp_split_y") || "65";
+ editorWrap.style.height = savedY + "%";
+ }
+ setTimeout(() => {
+ if (window.monacoEditor) window.monacoEditor.layout();
+ }, 160);
+ });
+ }
+ }
+
+ /* --- Tastatur-Ergonomie & Global Shortcuts --- */
+ function initWorkspaceShortcuts() {
+ let tabTrapped = true;
+
+ window.addEventListener("keydown", (e) => {
+ // 1. Code ausführen: Ctrl+Enter / Cmd+Enter
+ if ((e.ctrlKey || e.metaKey) && !e.shiftKey && e.key === "Enter") {
+ e.preventDefault();
+ const btnRun = document.getElementById("btn-run-code");
+ if (btnRun) btnRun.click();
+ return;
+ }
+
+ // 2. Tests starten: Ctrl+Shift+Enter / Cmd+Shift+Enter
+ if ((e.ctrlKey || e.metaKey) && e.shiftKey && e.key === "Enter") {
+ e.preventDefault();
+ const btnTests = document.getElementById("btn-run-tests");
+ if (btnTests) btnTests.click();
+ return;
+ }
+
+ // 3. Tipps & Lösung: Ctrl+H / Cmd+H
+ if ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "h") {
+ e.preventDefault();
+ const btnHints = document.getElementById("btn-show-hints");
+ if (btnHints) btnHints.click();
+ return;
+ }
+
+ // 4. Fokus in Editor: Ctrl+1 / Cmd+1
+ if ((e.ctrlKey || e.metaKey) && e.key === "1") {
+ e.preventDefault();
+ if (window.monacoEditor) window.monacoEditor.focus();
+ return;
+ }
+
+ // 5. Fokus auf Theorie: Ctrl+2 / Cmd+2
+ if ((e.ctrlKey || e.metaKey) && e.key === "2") {
+ e.preventDefault();
+ const tabTheorie = document.querySelector(".pane-tab-btn");
+ if (tabTheorie) tabTheorie.click();
+ document.getElementById("tab-content-theorie")?.focus();
+ return;
+ }
+
+ // 6. Fokus ins Terminal: Ctrl+` / Cmd+`
+ if ((e.ctrlKey || e.metaKey) && e.key === "`") {
+ e.preventDefault();
+ document.getElementById("workspace-terminal-output")?.focus();
+ return;
+ }
+
+ // 7. Nächstes Kapitel: Ctrl+Alt+ArrowRight
+ if (e.ctrlKey && e.altKey && e.key === "ArrowRight") {
+ e.preventDefault();
+ document.getElementById("btn-topbar-next-chapter")?.click();
+ return;
+ }
+
+ // 8. Tab-Trapping im Editor lösen mit Esc oder Ctrl+M (WCAG 2.1)
+ if (e.key === "Escape" || ((e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "m")) {
+ if (window.monaco && window.monaco.editor) {
+ tabTrapped = !tabTrapped;
+ window.monaco.editor.setTabFocusMode(!tabTrapped);
+ }
+ }
+ });
+ }
+
+ document.addEventListener("DOMContentLoaded", () => {
+ loadWorkspaceData();
+ initSplitResizers();
+ initWorkspaceShortcuts();
+ });