From 2198a8ccc6271ef3bc57346ee34f459e813c71cb Mon Sep 17 00:00:00 2001 From: Michael Czechowski Date: Tue, 30 Dec 2025 18:08:11 +0100 Subject: [PATCH] fix: add kbd tags to lesson messages and reorder task/description - Replace single quotes with tags in validation messages - German and English lessons updated for consistent formatting - Move task instruction before description in UI (index.html) --- lessons/00-basic-selectors.json | 2 +- lessons/00-basics.json | 50 +++++++++---------- lessons/02-selectors.json | 28 +++++++---- lessons/03-colors.json | 24 ++++----- lessons/04-typography.json | 60 ++++++++++++++++++----- lessons/07-layouts.json | 37 +++++++++----- lessons/10-tailwind-basics.json | 2 +- lessons/20-html-elements.json | 6 +-- lessons/21-html-forms-basic.json | 2 +- lessons/de/00-basic-selectors.json | 2 +- lessons/de/01-box-model.json | 16 +++--- lessons/de/05-units-variables.json | 54 ++++++++++++++------ lessons/de/06-transitions-animations.json | 42 ++++++++-------- lessons/de/08-responsive.json | 50 +++++++++++++------ lessons/de/10-tailwind-basics.json | 2 +- lessons/de/22-html-forms-validation.json | 4 +- lessons/de/flexbox.json | 14 +++--- lessons/tailwindcss.json | 24 ++++----- src/index.html | 2 +- 19 files changed, 263 insertions(+), 158 deletions(-) diff --git a/lessons/00-basic-selectors.json b/lessons/00-basic-selectors.json index 1b8229e..caa640f 100644 --- a/lessons/00-basic-selectors.json +++ b/lessons/00-basic-selectors.json @@ -354,7 +354,7 @@ { "type": "regex", "value": "^p#special\\s*{", - "message": "Use p#special to target paragraphs with ID 'special'", + "message": "Use p#special to target paragraphs with ID special", "options": { "caseSensitive": true } diff --git a/lessons/00-basics.json b/lessons/00-basics.json index 4e49649..91fdcaf 100644 --- a/lessons/00-basics.json +++ b/lessons/00-basics.json @@ -21,7 +21,7 @@ { "type": "regex", "value": "^\\s*p\\s*$", - "message": "Use the 'p' selector to target all paragraph elements", + "message": "Use the p selector to target all paragraph elements", "options": { "caseSensitive": false } @@ -44,7 +44,7 @@ { "type": "regex", "value": "^\\s*h2\\s*$", - "message": "Use the 'h2' element selector to target all level 2 headings", + "message": "Use the h2 element selector to target all level 2 headings", "options": { "caseSensitive": false } @@ -67,7 +67,7 @@ { "type": "contains", "value": ".important-text", - "message": "Use the '.important-text' class selector", + "message": "Use the .important-text class selector", "options": { "caseSensitive": true } @@ -90,7 +90,7 @@ { "type": "contains", "value": "#header-title", - "message": "Use the '#header-title' ID selector", + "message": "Use the #header-title ID selector", "options": { "caseSensitive": true } @@ -113,7 +113,7 @@ { "type": "contains", "value": ":hover", - "message": "Add the ':hover' pseudo-class after the button selector", + "message": "Add the :hover pseudo-class after the button selector", "options": { "caseSensitive": true } @@ -136,7 +136,7 @@ { "type": "contains", "value": "padding", - "message": "Use the 'padding' property to add space around the content", + "message": "Use the padding property to add space around the content", "options": { "caseSensitive": false } @@ -147,7 +147,7 @@ "property": "padding", "expected": "20px" }, - "message": "Set the padding value to '20px'", + "message": "Set the padding value to 20px", "options": { "exact": true } @@ -170,7 +170,7 @@ { "type": "contains", "value": "margin-bottom", - "message": "Use the 'margin-bottom' property to add space after the title", + "message": "Use the margin-bottom property to add space after the title", "options": { "caseSensitive": false } @@ -181,7 +181,7 @@ "property": "margin-bottom", "expected": "30px" }, - "message": "Set the margin-bottom value to '30px'", + "message": "Set the margin-bottom value to 30px", "options": { "exact": true } @@ -204,7 +204,7 @@ { "type": "contains", "value": "border", - "message": "Use the 'border' property to add a border around the card", + "message": "Use the border property to add a border around the card", "options": { "caseSensitive": false } @@ -212,7 +212,7 @@ { "type": "regex", "value": "border:\\s*2px\\s+solid\\s+blue", - "message": "Set the border to '2px solid blue'", + "message": "Set the border to 2px solid blue", "options": { "caseSensitive": false } @@ -235,7 +235,7 @@ { "type": "contains", "value": "justify-content", - "message": "Use 'justify-content' property for horizontal centering", + "message": "Use justify-content property for horizontal centering", "options": { "caseSensitive": false } @@ -246,7 +246,7 @@ "property": "justify-content", "expected": "center" }, - "message": "Set 'justify-content' to 'center'", + "message": "Set justify-content to center", "options": { "exact": true } @@ -254,7 +254,7 @@ { "type": "contains", "value": "align-items", - "message": "Use 'align-items' property for vertical centering", + "message": "Use align-items property for vertical centering", "options": { "caseSensitive": false } @@ -265,7 +265,7 @@ "property": "align-items", "expected": "center" }, - "message": "Set 'align-items' to 'center'", + "message": "Set align-items to center", "options": { "exact": true } @@ -288,7 +288,7 @@ { "type": "contains", "value": "background", - "message": "Use the 'background' or 'background-color' property", + "message": "Use the background or background-color property", "options": { "caseSensitive": false } @@ -296,7 +296,7 @@ { "type": "regex", "value": "background(-color)?:\\s*orange", - "message": "Set the background/background-color to 'orange'", + "message": "Set the background/background-color to orange", "options": { "caseSensitive": false } @@ -319,7 +319,7 @@ { "type": "contains", "value": "font-family", - "message": "Use the 'font-family' property", + "message": "Use the font-family property", "options": { "caseSensitive": false } @@ -327,7 +327,7 @@ { "type": "regex", "value": "font-family:\\s*Courier,\\s*monospace", - "message": "Set the font-family to 'Courier, monospace'", + "message": "Set the font-family to Courier, monospace", "options": { "caseSensitive": false } @@ -350,7 +350,7 @@ { "type": "contains", "value": "width", - "message": "Use the 'width' property", + "message": "Use the width property", "options": { "caseSensitive": false } @@ -361,7 +361,7 @@ "property": "width", "expected": "80%" }, - "message": "Set the width to '80%'", + "message": "Set the width to 80%", "options": { "exact": true } @@ -369,7 +369,7 @@ { "type": "contains", "value": "font-size", - "message": "Use the 'font-size' property", + "message": "Use the font-size property", "options": { "caseSensitive": false } @@ -380,7 +380,7 @@ "property": "font-size", "expected": "18px" }, - "message": "Set the font-size to '18px'", + "message": "Set the font-size to 18px", "options": { "exact": true } @@ -426,7 +426,7 @@ { "type": "contains", "value": "display", - "message": "Use the 'display' property", + "message": "Use the display property", "options": { "caseSensitive": false } @@ -437,7 +437,7 @@ "property": "display", "expected": "block" }, - "message": "Set the display value to 'block'", + "message": "Set the display value to block", "options": { "exact": true } diff --git a/lessons/02-selectors.json b/lessons/02-selectors.json index 0cefd14..28aac6e 100644 --- a/lessons/02-selectors.json +++ b/lessons/02-selectors.json @@ -18,12 +18,12 @@ "codeSuffix": "", "previewContainer": "preview-area", "validations": [ - { "type": "contains", "value": "p {", "message": "Use the element selector 'p'", "options": { "caseSensitive": false } }, - { "type": "contains", "value": "color", "message": "Include the 'color' property", "options": { "caseSensitive": false } }, + { "type": "contains", "value": "p {", "message": "Use the element selector p", "options": { "caseSensitive": false } }, + { "type": "contains", "value": "color", "message": "Include the color property", "options": { "caseSensitive": false } }, { "type": "property_value", "value": { "property": "color", "expected": "darkgray" }, - "message": "Set color to 'darkgray'", + "message": "Set color to darkgray", "options": { "exact": false } } ] @@ -41,11 +41,16 @@ "codeSuffix": "", "previewContainer": "preview-area", "validations": [ - { "type": "contains", "value": ".title", "message": "Use the '.title' class selector", "options": { "caseSensitive": false } }, + { + "type": "contains", + "value": ".title", + "message": "Use the .title class selector", + "options": { "caseSensitive": false } + }, { "type": "property_value", "value": { "property": "color", "expected": "blueviolet" }, - "message": "Set color to 'blueviolet'", + "message": "Set color to blueviolet", "options": { "exact": false } } ] @@ -66,13 +71,13 @@ { "type": "contains", "value": "#description", - "message": "Use the '#description' ID selector", + "message": "Use the #description ID selector", "options": { "caseSensitive": false } }, { "type": "property_value", "value": { "property": "color", "expected": "orangered" }, - "message": "Set color to 'orangered'", + "message": "Set color to orangered", "options": { "exact": false } } ] @@ -90,11 +95,16 @@ "codeSuffix": "", "previewContainer": "preview-area", "validations": [ - { "type": "contains", "value": "div.note", "message": "Use the 'div.note' combined selector", "options": { "caseSensitive": false } }, + { + "type": "contains", + "value": "div.note", + "message": "Use the div.note combined selector", + "options": { "caseSensitive": false } + }, { "type": "property_value", "value": { "property": "background-color", "expected": "yellow" }, - "message": "Set background-color to 'yellow'", + "message": "Set background-color to yellow", "options": { "exact": false } } ] diff --git a/lessons/03-colors.json b/lessons/03-colors.json index 7607599..419c222 100644 --- a/lessons/03-colors.json +++ b/lessons/03-colors.json @@ -18,17 +18,17 @@ "codeSuffix": "}", "previewContainer": "preview-area", "validations": [ - { "type": "contains", "value": ".colorbox", "message": "Select '.colorbox'", "options": { "caseSensitive": false } }, + { "type": "contains", "value": ".colorbox", "message": "Select .colorbox", "options": { "caseSensitive": false } }, { "type": "contains", "value": "background-color", - "message": "Use 'background-color' property", + "message": "Use background-color property", "options": { "caseSensitive": false } }, { "type": "property_value", "value": { "property": "background-color", "expected": "#e0f7fa" }, - "message": "Set background-color to '#e0f7fa'", + "message": "Set background-color to #e0f7fa", "options": { "exact": true } } ] @@ -46,12 +46,12 @@ "codeSuffix": "}", "previewContainer": "preview-area", "validations": [ - { "type": "contains", "value": ".colorbox", "message": "Select '.colorbox'", "options": { "caseSensitive": false } }, - { "type": "contains", "value": "color", "message": "Use the 'color' property", "options": { "caseSensitive": false } }, + { "type": "contains", "value": ".colorbox", "message": "Select .colorbox", "options": { "caseSensitive": false } }, + { "type": "contains", "value": "color", "message": "Use the color property", "options": { "caseSensitive": false } }, { "type": "property_value", "value": { "property": "color", "expected": "#01579b" }, - "message": "Set color to '#01579b'", + "message": "Set color to #01579b", "options": { "exact": true } } ] @@ -69,17 +69,17 @@ "codeSuffix": "}", "previewContainer": "preview-area", "validations": [ - { "type": "contains", "value": ".gradient-box", "message": "Select '.gradient-box'", "options": { "caseSensitive": false } }, + { "type": "contains", "value": ".gradient-box", "message": "Select .gradient-box", "options": { "caseSensitive": false } }, { "type": "contains", "value": "background-image", - "message": "Use 'background-image' property", + "message": "Use background-image property", "options": { "caseSensitive": false } }, { "type": "regex", "value": "linear-gradient\\(.*#ff9a9e.*,.*#fad0c4.*\\)", - "message": "Use linear-gradient from #ff9a9e to #fad0c4", + "message": "Use linear-gradient from #ff9a9e to #fad0c4", "options": { "caseSensitive": false } } ] @@ -100,19 +100,19 @@ { "type": "contains", "value": "background-image", - "message": "Use 'background-image' property", + "message": "Use background-image property", "options": { "caseSensitive": false } }, { "type": "contains", "value": "background-position: center", - "message": "Center the background image", + "message": "Center the background image with background-position: center", "options": { "caseSensitive": false } }, { "type": "contains", "value": "background-repeat: no-repeat", - "message": "Prevent image tiling", + "message": "Prevent image tiling with background-repeat: no-repeat", "options": { "caseSensitive": false } } ] diff --git a/lessons/04-typography.json b/lessons/04-typography.json index 0205fbe..5221b82 100644 --- a/lessons/04-typography.json +++ b/lessons/04-typography.json @@ -18,11 +18,16 @@ "codeSuffix": "}", "previewContainer": "preview-area", "validations": [ - { "type": "contains", "value": "font-family", "message": "Use the 'font-family' property", "options": { "caseSensitive": false } }, + { + "type": "contains", + "value": "font-family", + "message": "Use the font-family property", + "options": { "caseSensitive": false } + }, { "type": "regex", "value": "Georgia, serif", - "message": "Include 'Georgia, serif' in the font stack", + "message": "Include Georgia, serif in the font stack", "options": { "caseSensitive": false } } ] @@ -40,10 +45,23 @@ "codeSuffix": "}", "previewContainer": "preview-area", "validations": [ - { "type": "contains", "value": "font-size", "message": "Use 'font-size' property", "options": { "caseSensitive": false } }, - { "type": "property_value", "value": { "property": "font-size", "expected": "1.5rem" }, "message": "Set font-size to '1.5rem'" }, - { "type": "contains", "value": "line-height", "message": "Use 'line-height' property", "options": { "caseSensitive": false } }, - { "type": "property_value", "value": { "property": "line-height", "expected": "1.5" }, "message": "Set line-height to '1.5'" } + { "type": "contains", "value": "font-size", "message": "Use font-size property", "options": { "caseSensitive": false } }, + { + "type": "property_value", + "value": { "property": "font-size", "expected": "1.5rem" }, + "message": "Set font-size to 1.5rem" + }, + { + "type": "contains", + "value": "line-height", + "message": "Use line-height property", + "options": { "caseSensitive": false } + }, + { + "type": "property_value", + "value": { "property": "line-height", "expected": "1.5" }, + "message": "Set line-height to 1.5" + } ] }, { @@ -59,10 +77,23 @@ "codeSuffix": "}", "previewContainer": "preview-area", "validations": [ - { "type": "contains", "value": "font-style", "message": "Use 'font-style' property", "options": { "caseSensitive": false } }, - { "type": "property_value", "value": { "property": "font-style", "expected": "italic" }, "message": "Set font-style to 'italic'" }, - { "type": "contains", "value": "font-weight", "message": "Use 'font-weight' property", "options": { "caseSensitive": false } }, - { "type": "property_value", "value": { "property": "font-weight", "expected": "bold" }, "message": "Set font-weight to 'bold'" } + { "type": "contains", "value": "font-style", "message": "Use font-style property", "options": { "caseSensitive": false } }, + { + "type": "property_value", + "value": { "property": "font-style", "expected": "italic" }, + "message": "Set font-style to italic" + }, + { + "type": "contains", + "value": "font-weight", + "message": "Use font-weight property", + "options": { "caseSensitive": false } + }, + { + "type": "property_value", + "value": { "property": "font-weight", "expected": "bold" }, + "message": "Set font-weight to bold" + } ] }, { @@ -81,10 +112,15 @@ { "type": "contains", "value": "text-decoration", - "message": "Use 'text-decoration' property", + "message": "Use text-decoration property", "options": { "caseSensitive": false } }, - { "type": "contains", "value": "text-shadow", "message": "Use 'text-shadow' property", "options": { "caseSensitive": false } } + { + "type": "contains", + "value": "text-shadow", + "message": "Use text-shadow property", + "options": { "caseSensitive": false } + } ] } ] diff --git a/lessons/07-layouts.json b/lessons/07-layouts.json index 0c0f8af..6873966 100644 --- a/lessons/07-layouts.json +++ b/lessons/07-layouts.json @@ -18,9 +18,14 @@ "codeSuffix": "}", "previewContainer": "preview-area", "validations": [ - { "type": "contains", "value": "display", "message": "Use 'display: flex'", "options": { "caseSensitive": false } }, - { "type": "contains", "value": "justify-content", "message": "Use 'justify-content: center'", "options": { "caseSensitive": false } }, - { "type": "contains", "value": "align-items", "message": "Use 'align-items: center'", "options": { "caseSensitive": false } } + { "type": "contains", "value": "display", "message": "Use display: flex", "options": { "caseSensitive": false } }, + { + "type": "contains", + "value": "justify-content", + "message": "Use justify-content: center", + "options": { "caseSensitive": false } + }, + { "type": "contains", "value": "align-items", "message": "Use align-items: center", "options": { "caseSensitive": false } } ] }, { @@ -36,11 +41,16 @@ "codeSuffix": "}\n.item { }", "previewContainer": "preview-area", "validations": [ - { "type": "contains", "value": "flex-wrap: wrap", "message": "Use 'flex-wrap: wrap'", "options": { "caseSensitive": false } }, + { + "type": "contains", + "value": "flex-wrap: wrap", + "message": "Use flex-wrap: wrap", + "options": { "caseSensitive": false } + }, { "type": "regex", "value": ".item.*flex:\\s*1\\s+1\\s+100px", - "message": "Set flex: 1 1 100px on items", + "message": "Set flex: 1 1 100px on items", "options": { "caseSensitive": false } } ] @@ -58,20 +68,20 @@ "codeSuffix": "}", "previewContainer": "preview-area", "validations": [ - { "type": "contains", "value": "display: grid", "message": "Use 'display: grid'", "options": { "caseSensitive": false } }, + { "type": "contains", "value": "display: grid", "message": "Use display: grid", "options": { "caseSensitive": false } }, { "type": "contains", "value": "grid-template-columns", - "message": "Define 'grid-template-columns'", + "message": "Define grid-template-columns", "options": { "caseSensitive": false } }, { "type": "regex", "value": "grid-template-columns:\\s*repeat\\(3,\\s*1fr\\)\\s*", - "message": "Create three equal columns", + "message": "Create three equal columns with repeat(3, 1fr)", "options": { "caseSensitive": false } }, - { "type": "contains", "value": "gap", "message": "Use 'gap' property", "options": { "caseSensitive": false } } + { "type": "contains", "value": "gap", "message": "Use gap property", "options": { "caseSensitive": false } } ] }, { @@ -87,11 +97,16 @@ "codeSuffix": "}", "previewContainer": "preview-area", "validations": [ - { "type": "contains", "value": "grid-column", "message": "Use 'grid-column' property", "options": { "caseSensitive": false } }, + { + "type": "contains", + "value": "grid-column", + "message": "Use grid-column property", + "options": { "caseSensitive": false } + }, { "type": "property_value", "value": { "property": "grid-column", "expected": "1 / span 2" }, - "message": "Span across 2 columns", + "message": "Span across 2 columns with grid-column: 1 / span 2", "options": { "caseSensitive": false } } ] diff --git a/lessons/10-tailwind-basics.json b/lessons/10-tailwind-basics.json index 58ddd19..c7f5f85 100644 --- a/lessons/10-tailwind-basics.json +++ b/lessons/10-tailwind-basics.json @@ -20,7 +20,7 @@ { "type": "contains_class", "value": "bg-blue-500", - "message": "Add the 'bg-blue-500' class for a blue background." + "message": "Add the bg-blue-500 class for a blue background." } ] }, diff --git a/lessons/20-html-elements.json b/lessons/20-html-elements.json index 7410d07..dd19bdf 100644 --- a/lessons/20-html-elements.json +++ b/lessons/20-html-elements.json @@ -26,7 +26,7 @@ { "type": "parent_child", "value": { "parent": "p", "child": "strong" }, - "message": "Wrap the word 'important' with <strong> tags" + "message": "Wrap the word important with <strong> tags" } ] }, @@ -84,12 +84,12 @@ { "type": "element_exists", "value": "span", - "message": "Add a <span> around the word 'highlighted'" + "message": "Add a <span> around the word highlighted" }, { "type": "element_text", "value": { "selector": "span", "text": "highlighted" }, - "message": "The <span> should contain the word 'highlighted'" + "message": "The <span> should contain the word highlighted" } ] } diff --git a/lessons/21-html-forms-basic.json b/lessons/21-html-forms-basic.json index e199d60..e68dde6 100644 --- a/lessons/21-html-forms-basic.json +++ b/lessons/21-html-forms-basic.json @@ -94,7 +94,7 @@ { "type": "element_text", "value": { "selector": "button", "text": "Sign In" }, - "message": "The button should say 'Sign In'" + "message": "The button should say Sign In" } ] } diff --git a/lessons/de/00-basic-selectors.json b/lessons/de/00-basic-selectors.json index 096be6f..1138238 100644 --- a/lessons/de/00-basic-selectors.json +++ b/lessons/de/00-basic-selectors.json @@ -354,7 +354,7 @@ { "type": "regex", "value": "^p#special\\s*{", - "message": "Verwende p#special, um Absätze mit ID 'special' anzuvisieren", + "message": "Verwende p#special, um Absätze mit ID special anzuvisieren", "options": { "caseSensitive": true } diff --git a/lessons/de/01-box-model.json b/lessons/de/01-box-model.json index 66e307f..67c8b89 100644 --- a/lessons/de/01-box-model.json +++ b/lessons/de/01-box-model.json @@ -21,7 +21,7 @@ { "type": "property_value", "value": { "property": "padding", "expected": "1rem" }, - "message": "Setze padding auf '1rem'" + "message": "Setze padding: 1rem" } ] }, @@ -41,7 +41,7 @@ { "type": "regex", "value": "border:\\s*2px\\s+solid\\s+darkslategray", - "message": "Setze border auf '2px solid darkslategray'", + "message": "Setze border: 2px solid darkslategray", "options": { "caseSensitive": false } } ] @@ -62,7 +62,7 @@ { "type": "property_value", "value": { "property": "margin", "expected": "1rem" }, - "message": "Setze margin auf '1rem'" + "message": "Setze margin: 1rem" } ] }, @@ -82,7 +82,7 @@ { "type": "property_value", "value": { "property": "box-sizing", "expected": "border-box" }, - "message": "Setze box-sizing auf 'border-box'" + "message": "Setze box-sizing: border-box" } ] }, @@ -102,7 +102,7 @@ { "type": "property_value", "value": { "property": "margin-bottom", "expected": "2rem" }, - "message": "Setze margin-bottom auf '2rem'" + "message": "Setze margin-bottom: 2rem" } ] }, @@ -122,7 +122,7 @@ { "type": "regex", "value": "margin:\\s*1rem\\s+2rem", - "message": "Setze margin auf '1rem 2rem'", + "message": "Setze margin: 1rem 2rem", "options": { "caseSensitive": false } } ] @@ -143,7 +143,7 @@ { "type": "property_value", "value": { "property": "padding", "expected": "1.5rem" }, - "message": "Setze padding auf '1.5rem'" + "message": "Setze padding: 1.5rem" } ] }, @@ -163,7 +163,7 @@ { "type": "regex", "value": "border-bottom:\\s*4px\\s+solid\\s+dodgerblue", - "message": "Setze border-bottom auf '4px solid dodgerblue'", + "message": "Setze border-bottom: 4px solid dodgerblue", "options": { "caseSensitive": false } } ] diff --git a/lessons/de/05-units-variables.json b/lessons/de/05-units-variables.json index 488a03d..927f0b5 100644 --- a/lessons/de/05-units-variables.json +++ b/lessons/de/05-units-variables.json @@ -9,7 +9,7 @@ "id": "units-1", "title": "Absolute vs. Relative Einheiten", "description": "Lerne den Unterschied zwischen px, rem, em, % und vw/vh für flexible, responsive Layouts.", - "task": "Setze die Breite von '.unit-box' auf 80% und max-width auf 37.5rem.", + "task": "Setze die Breite von .unit-box auf 80% und max-width auf 37.5rem.", "previewHTML": "
Ändere meine Größe!
", "previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .unit-box { background: #f5f5f5; padding: 1rem; }", "sandboxCSS": "", @@ -18,17 +18,31 @@ "codeSuffix": "}", "previewContainer": "preview-area", "validations": [ - { "type": "contains", "value": "width", "message": "Verwende die 'width' Eigenschaft", "options": { "caseSensitive": false } }, - { "type": "property_value", "value": { "property": "width", "expected": "80%" }, "message": "Setze width auf '80%'" }, - { "type": "contains", "value": "max-width", "message": "Verwende die 'max-width' Eigenschaft", "options": { "caseSensitive": false } }, - { "type": "property_value", "value": { "property": "max-width", "expected": "37.5rem" }, "message": "Setze max-width auf '37.5rem'" } + { + "type": "contains", + "value": "width", + "message": "Verwende die width Eigenschaft", + "options": { "caseSensitive": false } + }, + { "type": "property_value", "value": { "property": "width", "expected": "80%" }, "message": "Setze width auf 80%" }, + { + "type": "contains", + "value": "max-width", + "message": "Verwende die max-width Eigenschaft", + "options": { "caseSensitive": false } + }, + { + "type": "property_value", + "value": { "property": "max-width", "expected": "37.5rem" }, + "message": "Setze max-width auf 37.5rem" + } ] }, { "id": "units-2", "title": "CSS Custom Properties", "description": "Definiere und verwende Variablen (--custom properties) wieder, um deine Theme-Werte zu zentralisieren.", - "task": "Erstelle eine --main-color Variable in :root mit #6200ee und wende sie als Rahmenfarbe auf '.var-box' an.", + "task": "Erstelle eine --main-color Variable in :root mit #6200ee und wende sie als Rahmenfarbe auf .var-box an.", "previewHTML": "
Variablen-Box
", "previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .var-box { padding: 1rem; border: 0.125rem solid #ddd; }", "sandboxCSS": "", @@ -37,8 +51,18 @@ "codeSuffix": "}\n.var-box { }", "previewContainer": "preview-area", "validations": [ - { "type": "contains", "value": "--main-color", "message": "Definiere '--main-color' in :root", "options": { "caseSensitive": false } }, - { "type": "contains", "value": "var(--main-color)", "message": "Verwende var(--main-color)", "options": { "caseSensitive": false } }, + { + "type": "contains", + "value": "--main-color", + "message": "Definiere --main-color in :root", + "options": { "caseSensitive": false } + }, + { + "type": "contains", + "value": "var(--main-color)", + "message": "Verwende var(--main-color)", + "options": { "caseSensitive": false } + }, { "type": "property_value", "value": { "property": "border", "expected": "var(--main-color)" }, @@ -51,7 +75,7 @@ "id": "units-3", "title": "Einheiten-Berechnungen (calc)", "description": "Verwende die calc() Funktion, um verschiedene Einheiten in einem Ausdruck zu kombinieren.", - "task": "Setze die Breite von '.calc-box' auf calc(100% - 2rem) und min-height auf calc(10vh + 1rem).", + "task": "Setze die Breite von .calc-box auf calc(100% - 2rem) und min-height auf calc(10vh + 1rem).", "previewHTML": "
Calc Demo
", "previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .calc-box { background: #e8f5e9; padding: 1rem; }", "sandboxCSS": "", @@ -60,7 +84,7 @@ "codeSuffix": "}", "previewContainer": "preview-area", "validations": [ - { "type": "contains", "value": "calc", "message": "Verwende die 'calc()' Funktion", "options": { "caseSensitive": false } }, + { "type": "contains", "value": "calc", "message": "Verwende die calc() Funktion", "options": { "caseSensitive": false } }, { "type": "regex", "value": "width:\\s*calc\\(100% - 2rem\\)", @@ -79,7 +103,7 @@ "id": "units-4", "title": "Viewport & Responsive Einheiten", "description": "Steuere Layouts relativ zur Viewport-Größe mit vw, vh und vmin/vmax Einheiten.", - "task": "Gib '.viewport-box' eine Breite von 50vw und Höhe von 20vh.", + "task": "Gib .viewport-box eine Breite von 50vw und Höhe von 20vh.", "previewHTML": "
Viewport-Box
", "previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .viewport-box { background: #ffe0b2; }", "sandboxCSS": "", @@ -88,10 +112,10 @@ "codeSuffix": "}", "previewContainer": "preview-area", "validations": [ - { "type": "contains", "value": "vw", "message": "Verwende 'vw' Einheit", "options": { "caseSensitive": false } }, - { "type": "contains", "value": "vh", "message": "Verwende 'vh' Einheit", "options": { "caseSensitive": false } }, - { "type": "property_value", "value": { "property": "width", "expected": "50vw" }, "message": "Setze width auf '50vw'" }, - { "type": "property_value", "value": { "property": "height", "expected": "20vh" }, "message": "Setze height auf '20vh'" } + { "type": "contains", "value": "vw", "message": "Verwende vw Einheit", "options": { "caseSensitive": false } }, + { "type": "contains", "value": "vh", "message": "Verwende vh Einheit", "options": { "caseSensitive": false } }, + { "type": "property_value", "value": { "property": "width", "expected": "50vw" }, "message": "Setze width auf 50vw" }, + { "type": "property_value", "value": { "property": "height", "expected": "20vh" }, "message": "Setze height auf 20vh" } ] } ] diff --git a/lessons/de/06-transitions-animations.json b/lessons/de/06-transitions-animations.json index b613e6a..3e6e2b6 100644 --- a/lessons/de/06-transitions-animations.json +++ b/lessons/de/06-transitions-animations.json @@ -9,7 +9,7 @@ "id": "transitions-1", "title": "Einfache Transitions", "description": "Lerne, wie du transition auf Eigenschaften anwendest für sanfte Änderungen bei Zustandswechseln.", - "task": "Füge eine Hover-Transition auf einen Button hinzu, sodass seine Hintergrundfarbe über 0.3s überblendet.", + "task": "Füge transition: background-color 0.3s zu .btn hinzu, damit die Farbe beim Hover sanft überblendet.", "previewHTML": "", "previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .btn { background: #6200ee; color: white; padding: 0.5rem 1rem; border: none; } .btn:hover { background: #3700b3; }", "sandboxCSS": "", @@ -18,11 +18,11 @@ "codeSuffix": "}", "previewContainer": "preview-area", "validations": [ - { "type": "contains", "value": "transition", "message": "Verwende die 'transition' Eigenschaft", "options": { "caseSensitive": false } }, + { "type": "contains", "value": "transition", "message": "Verwende die transition Eigenschaft", "options": { "caseSensitive": false } }, { "type": "regex", "value": "transition:\\s*background-color\\s*0\\.3s", - "message": "Transition background-color über 0.3s", + "message": "Setze transition: background-color 0.3s", "options": { "caseSensitive": false } } ] @@ -30,8 +30,8 @@ { "id": "transitions-2", "title": "Transition Timing-Funktionen", - "description": "Erkunde Easing-Funktionen wie ease, linear, ease-in, ease-out, um das Animationstempo zu steuern.", - "task": "Ändere den Button, um 'ease-in-out' Timing für seine Transition zu verwenden.", + "description": "Erkunde Easing-Funktionen wie ease, linear, ease-in, ease-out, um das Animationstempo zu steuern.", + "task": "Setze transition-timing-function auf ease-in-out bei .btn.", "previewHTML": "", "previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .btn { background: #6200ee; color: white; padding: 0.5rem 1rem; border: none; transition: background-color 0.3s; } .btn:hover { background: #03dac6; }", "sandboxCSS": "", @@ -43,13 +43,13 @@ { "type": "contains", "value": "transition-timing-function", - "message": "Verwende 'transition-timing-function'", + "message": "Verwende transition-timing-function", "options": { "caseSensitive": false } }, { "type": "property_value", "value": { "property": "transition-timing-function", "expected": "ease-in-out" }, - "message": "Setze Timing auf 'ease-in-out'" + "message": "Setze transition-timing-function: ease-in-out" } ] }, @@ -57,7 +57,7 @@ "id": "transitions-3", "title": "Keyframe-Animationen Grundlagen", "description": "Erstelle benannte Animationen mit @keyframes und wende sie mit der animation Kurzschreibweise an.", - "task": "Definiere ein Keyframe namens 'bounce', das ein Element bei 50% um 20px nach oben bewegt, und wende es auf '.ball' über 1s infinite an.", + "task": "Definiere bei 50% ein transform: translateY(-20px) und wende animation: bounce 1s infinite auf .ball an.", "previewHTML": "
", "previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .ball { width: 50px; height: 50px; background: #ff0266; border-radius: 50%; margin: 2rem auto; }", "sandboxCSS": "", @@ -66,18 +66,18 @@ "codeSuffix": "}\n.ball { }", "previewContainer": "preview-area", "validations": [ - { "type": "contains", "value": "@keyframes bounce", "message": "Definiere '@keyframes bounce'", "options": { "caseSensitive": false } }, + { "type": "contains", "value": "@keyframes bounce", "message": "Definiere @keyframes bounce", "options": { "caseSensitive": false } }, { "type": "regex", "value": "50%.*transform: translateY\\(-20px\\)", - "message": "Bei 50%, bewege um 20px nach oben", + "message": "Bei 50%, setze transform: translateY(-20px)", "options": { "caseSensitive": false } }, - { "type": "contains", "value": "animation", "message": "Verwende 'animation' Eigenschaft auf .ball", "options": { "caseSensitive": false } }, + { "type": "contains", "value": "animation", "message": "Verwende animation Eigenschaft auf .ball", "options": { "caseSensitive": false } }, { "type": "regex", "value": "animation:.*bounce.*1s.*infinite", - "message": "Wende 'bounce 1s infinite' an", + "message": "Wende animation: bounce 1s infinite an", "options": { "caseSensitive": false } } ] @@ -85,8 +85,8 @@ { "id": "transitions-4", "title": "Animations-Eigenschaften im Detail", - "description": "Verfeinere Animationen mit delay, iteration-count, direction und fill-mode.", - "task": "Animiere '.box' mit einem 'fade' Keyframe über 2s, Verzögerung 1s, zweimalige Ausführung und bleibe danach sichtbar.", + "description": "Verfeinere Animationen mit animation-delay, animation-iteration-count, animation-direction und animation-fill-mode.", + "task": "Wende die fade Animation auf .box an mit animation-name: fade, animation-duration: 2s, animation-delay: 1s, animation-iteration-count: 2 und animation-fill-mode: forwards.", "previewHTML": "
Fade Demo
", "previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .box { width: 100px; height: 100px; background: #4caf50; margin: 2rem auto; }", "sandboxCSS": "", @@ -98,32 +98,32 @@ { "type": "contains", "value": "animation-delay", - "message": "Verwende 'animation-delay' Eigenschaft", + "message": "Verwende animation-delay", "options": { "caseSensitive": false } }, { "type": "contains", "value": "animation-iteration-count", - "message": "Verwende 'animation-iteration-count' Eigenschaft", + "message": "Verwende animation-iteration-count", "options": { "caseSensitive": false } }, { "type": "contains", "value": "animation-fill-mode", - "message": "Verwende 'animation-fill-mode' Eigenschaft", + "message": "Verwende animation-fill-mode", "options": { "caseSensitive": false } }, - { "type": "property_value", "value": { "property": "animation-duration", "expected": "2s" }, "message": "Duration sollte 2s sein" }, - { "type": "property_value", "value": { "property": "animation-delay", "expected": "1s" }, "message": "Delay sollte 1s sein" }, + { "type": "property_value", "value": { "property": "animation-duration", "expected": "2s" }, "message": "Setze animation-duration: 2s" }, + { "type": "property_value", "value": { "property": "animation-delay", "expected": "1s" }, "message": "Setze animation-delay: 1s" }, { "type": "property_value", "value": { "property": "animation-iteration-count", "expected": "2" }, - "message": "Iteration-count sollte 2 sein" + "message": "Setze animation-iteration-count: 2" }, { "type": "property_value", "value": { "property": "animation-fill-mode", "expected": "forwards" }, - "message": "Fill-mode sollte forwards sein" + "message": "Setze animation-fill-mode: forwards" } ] } diff --git a/lessons/de/08-responsive.json b/lessons/de/08-responsive.json index ff579a2..5588049 100644 --- a/lessons/de/08-responsive.json +++ b/lessons/de/08-responsive.json @@ -9,7 +9,7 @@ "id": "responsive-1", "title": "Einführung in Media Queries", "description": "Verstehe die Syntax und Anwendungsfälle für CSS Media Queries, um Stile bedingt basierend auf Viewport-Eigenschaften anzuwenden.", - "task": "Schreibe eine Media Query, die gilt, wenn der Viewport maximal 600px breit ist, und ändere den Hintergrund von '.responsive-box' auf lightcoral.", + "task": "Schreibe eine Media Query, die gilt, wenn der Viewport maximal 600px breit ist, und ändere den Hintergrund von .responsive-box auf lightcoral.", "previewHTML": "
Ändere die Fenstergröße
", "previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .responsive-box { padding: 1rem; background: lightblue; }", "sandboxCSS": "", @@ -27,14 +27,19 @@ { "type": "contains", "value": ".responsive-box", - "message": "Adressiere '.responsive-box' innerhalb der Media Query", + "message": "Adressiere .responsive-box innerhalb der Media Query", + "options": { "caseSensitive": false } + }, + { + "type": "contains", + "value": "background", + "message": "Ändere die background Eigenschaft", "options": { "caseSensitive": false } }, - { "type": "contains", "value": "background", "message": "Ändere die 'background' Eigenschaft", "options": { "caseSensitive": false } }, { "type": "property_value", "value": { "property": "background", "expected": "lightcoral" }, - "message": "Setze background auf 'lightcoral'", + "message": "Setze background auf lightcoral", "options": { "exact": false } } ] @@ -43,7 +48,7 @@ "id": "responsive-2", "title": "Flüssige Typografie", "description": "Verwende relative Einheiten wie vw, damit Schriftgrößen mit der Viewport-Breite skalieren.", - "task": "Setze die font-size von '.fluid-text' auf 5vw, damit sie sich mit dem Viewport ändert.", + "task": "Setze die font-size von .fluid-text auf 5vw, damit sie sich mit dem Viewport ändert.", "previewHTML": "

Flüssige Typografie

", "previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; }", "sandboxCSS": "", @@ -52,16 +57,26 @@ "codeSuffix": "}", "previewContainer": "preview-area", "validations": [ - { "type": "contains", "value": "font-size", "message": "Verwende die 'font-size' Eigenschaft", "options": { "caseSensitive": false } }, - { "type": "contains", "value": "vw", "message": "Verwende 'vw' Einheit für flüssige Größe", "options": { "caseSensitive": false } }, - { "type": "property_value", "value": { "property": "font-size", "expected": "5vw" }, "message": "Setze font-size auf '5vw'" } + { + "type": "contains", + "value": "font-size", + "message": "Verwende die font-size Eigenschaft", + "options": { "caseSensitive": false } + }, + { + "type": "contains", + "value": "vw", + "message": "Verwende vw Einheit für flüssige Größe", + "options": { "caseSensitive": false } + }, + { "type": "property_value", "value": { "property": "font-size", "expected": "5vw" }, "message": "Setze font-size auf 5vw" } ] }, { "id": "responsive-3", "title": "Flexible Raster", "description": "Kombiniere CSS Grid mit auto-fit oder auto-fill für responsive Spaltenlayouts.", - "task": "Definiere '.grid-responsive' mit grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); und einem gap von 1rem.", + "task": "Definiere .grid-responsive mit grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)) und einem gap von 1rem.", "previewHTML": "
1
2
3
4
", "previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .grid-responsive > div { background: #d1c4e9; padding: 1rem; }", "sandboxCSS": "", @@ -73,23 +88,23 @@ { "type": "contains", "value": "grid-template-columns", - "message": "Definiere 'grid-template-columns'", + "message": "Definiere grid-template-columns", "options": { "caseSensitive": false } }, { "type": "regex", "value": "repeat\\(auto-fit,\\s*minmax\\(200px,\\s*1fr\\)\\)", - "message": "Verwende repeat(auto-fit, minmax(200px, 1fr))", + "message": "Verwende repeat(auto-fit, minmax(200px, 1fr))", "options": { "caseSensitive": false } }, - { "type": "contains", "value": "gap", "message": "Verwende die 'gap' Eigenschaft", "options": { "caseSensitive": false } } + { "type": "contains", "value": "gap", "message": "Verwende die gap Eigenschaft", "options": { "caseSensitive": false } } ] }, { "id": "responsive-4", "title": "Mobile-First Media Queries", "description": "Verfolge einen Mobile-First-Ansatz: Schreibe Basis-Stile für kleine Bildschirme und erweitere für größere Viewports.", - "task": "Schreibe eine Media Query für min-width 768px, die die Breite von '.sidebar' auf 250px setzt.", + "task": "Schreibe eine Media Query für min-width 768px, die die Breite von .sidebar auf 250px setzt.", "previewHTML": "", "previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .sidebar { background: #c8e6c9; padding: 1rem; }", "sandboxCSS": "", @@ -104,11 +119,16 @@ "message": "Verwende eine Media Query für min-width: 768px", "options": { "caseSensitive": false } }, - { "type": "contains", "value": ".sidebar", "message": "Adressiere '.sidebar' in der Media Query", "options": { "caseSensitive": false } }, + { + "type": "contains", + "value": ".sidebar", + "message": "Adressiere .sidebar in der Media Query", + "options": { "caseSensitive": false } + }, { "type": "property_value", "value": { "property": "width", "expected": "250px" }, - "message": "Setze width auf '250px'", + "message": "Setze width auf 250px", "options": { "exact": false } } ] diff --git a/lessons/de/10-tailwind-basics.json b/lessons/de/10-tailwind-basics.json index 237b6d0..ebee021 100644 --- a/lessons/de/10-tailwind-basics.json +++ b/lessons/de/10-tailwind-basics.json @@ -20,7 +20,7 @@ { "type": "contains_class", "value": "bg-blue-500", - "message": "Füge die 'bg-blue-500'-Klasse für einen blauen Hintergrund hinzu." + "message": "Füge die bg-blue-500-Klasse für einen blauen Hintergrund hinzu." } ] }, diff --git a/lessons/de/22-html-forms-validation.json b/lessons/de/22-html-forms-validation.json index 34c6a34..4d49b12 100644 --- a/lessons/de/22-html-forms-validation.json +++ b/lessons/de/22-html-forms-validation.json @@ -79,7 +79,7 @@ { "type": "attribute_value", "value": { "selector": "#email", "attr": "type", "value": "email" }, - "message": "Setze den Eingabetyp für E-Mail auf 'email'" + "message": "Setze den Eingabetyp für E-Mail auf email" }, { "type": "attribute_value", @@ -89,7 +89,7 @@ { "type": "attribute_value", "value": { "selector": "#password", "attr": "type", "value": "password" }, - "message": "Setze den Eingabetyp für Passwort auf 'password'" + "message": "Setze den Eingabetyp für Passwort auf password" }, { "type": "attribute_value", diff --git a/lessons/de/flexbox.json b/lessons/de/flexbox.json index c00f308..83ec27f 100644 --- a/lessons/de/flexbox.json +++ b/lessons/de/flexbox.json @@ -21,7 +21,7 @@ { "type": "property_value", "value": { "property": "display", "expected": "flex" }, - "message": "Setze display auf 'flex'" + "message": "Setze display auf flex" } ] }, @@ -41,12 +41,12 @@ { "type": "property_value", "value": { "property": "flex-direction", "expected": "column" }, - "message": "Setze flex-direction auf 'column'" + "message": "Setze flex-direction auf column" }, { "type": "property_value", "value": { "property": "flex-wrap", "expected": "wrap" }, - "message": "Setze flex-wrap auf 'wrap'" + "message": "Setze flex-wrap auf wrap" } ] }, @@ -66,7 +66,7 @@ { "type": "property_value", "value": { "property": "justify-content", "expected": "space-between" }, - "message": "Setze justify-content auf 'space-between'" + "message": "Setze justify-content auf space-between" } ] }, @@ -86,7 +86,7 @@ { "type": "property_value", "value": { "property": "align-items", "expected": "center" }, - "message": "Setze align-items auf 'center'" + "message": "Setze align-items auf center" } ] }, @@ -106,7 +106,7 @@ { "type": "property_value", "value": { "property": "flex", "expected": "2" }, - "message": "Setze flex auf '2'" + "message": "Setze flex auf 2" } ] }, @@ -126,7 +126,7 @@ { "type": "property_value", "value": { "property": "align-self", "expected": "flex-start" }, - "message": "Setze align-self auf 'flex-start'" + "message": "Setze align-self auf flex-start" } ] } diff --git a/lessons/tailwindcss.json b/lessons/tailwindcss.json index e15ea10..781b7f9 100644 --- a/lessons/tailwindcss.json +++ b/lessons/tailwindcss.json @@ -21,12 +21,12 @@ { "type": "contains", "value": "font-bold", - "message": "Add 'font-bold' to the heading" + "message": "Add font-bold to the heading" }, { "type": "contains", "value": "text-gray-600", - "message": "Add 'text-gray-600' to the paragraph" + "message": "Add text-gray-600 to the paragraph" } ] }, @@ -46,12 +46,12 @@ { "type": "contains", "value": "bg-red-400", - "message": "Use 'bg-red-400' to set the background color" + "message": "Use bg-red-400 to set the background color" }, { "type": "contains", "value": "text-white", - "message": "Use 'text-white' for the text color" + "message": "Use text-white for the text color" } ] }, @@ -71,12 +71,12 @@ { "type": "contains", "value": "m-2", - "message": "Add 'm-2' to add spacing between the buttons" + "message": "Add m-2 to add spacing between the buttons" }, { "type": "contains", "value": "p-2", - "message": "Add 'p-2' for internal button padding" + "message": "Add p-2 for internal button padding" } ] }, @@ -96,7 +96,7 @@ { "type": "contains", "value": "hover:bg-green-500", - "message": "Add 'hover:bg-green-500' to change background color on hover" + "message": "Add hover:bg-green-500 to change background color on hover" } ] }, @@ -116,27 +116,27 @@ { "type": "contains", "value": "bg-white", - "message": "Use 'bg-white' for background color" + "message": "Use bg-white for background color" }, { "type": "contains", "value": "shadow", - "message": "Use 'shadow' to add a shadow" + "message": "Use shadow to add a shadow" }, { "type": "contains", "value": "rounded", - "message": "Use 'rounded' to add rounded corners" + "message": "Use rounded to add rounded corners" }, { "type": "contains", "value": "p-4", - "message": "Use 'p-4' for padding" + "message": "Use p-4 for padding" }, { "type": "contains", "value": "text-center", - "message": "Use 'text-center' to center the text" + "message": "Use text-center to center the text" } ] } diff --git a/src/index.html b/src/index.html index 801e724..1c36172 100644 --- a/src/index.html +++ b/src/index.html @@ -32,10 +32,10 @@
Loading...

Loading...

+
Please select a lesson to begin.
-