fix: add kbd tags to lesson messages and reorder task/description

- Replace single quotes with <kbd> tags in validation messages
- German and English lessons updated for consistent formatting
- Move task instruction before description in UI (index.html)
This commit is contained in:
2025-12-30 18:08:11 +01:00
parent 1267ce15ae
commit 38541c7a78
19 changed files with 263 additions and 158 deletions

View File

@@ -354,7 +354,7 @@
{ {
"type": "regex", "type": "regex",
"value": "^p#special\\s*{", "value": "^p#special\\s*{",
"message": "Use <kbd>p#special</kbd> to target paragraphs with ID 'special'", "message": "Use <kbd>p#special</kbd> to target paragraphs with ID <kbd>special</kbd>",
"options": { "options": {
"caseSensitive": true "caseSensitive": true
} }

View File

@@ -21,7 +21,7 @@
{ {
"type": "regex", "type": "regex",
"value": "^\\s*p\\s*$", "value": "^\\s*p\\s*$",
"message": "Use the 'p' selector to target all paragraph elements", "message": "Use the <kbd>p</kbd> selector to target all paragraph elements",
"options": { "options": {
"caseSensitive": false "caseSensitive": false
} }
@@ -44,7 +44,7 @@
{ {
"type": "regex", "type": "regex",
"value": "^\\s*h2\\s*$", "value": "^\\s*h2\\s*$",
"message": "Use the 'h2' element selector to target all level 2 headings", "message": "Use the <kbd>h2</kbd> element selector to target all level 2 headings",
"options": { "options": {
"caseSensitive": false "caseSensitive": false
} }
@@ -67,7 +67,7 @@
{ {
"type": "contains", "type": "contains",
"value": ".important-text", "value": ".important-text",
"message": "Use the '.important-text' class selector", "message": "Use the <kbd>.important-text</kbd> class selector",
"options": { "options": {
"caseSensitive": true "caseSensitive": true
} }
@@ -90,7 +90,7 @@
{ {
"type": "contains", "type": "contains",
"value": "#header-title", "value": "#header-title",
"message": "Use the '#header-title' ID selector", "message": "Use the <kbd>#header-title</kbd> ID selector",
"options": { "options": {
"caseSensitive": true "caseSensitive": true
} }
@@ -113,7 +113,7 @@
{ {
"type": "contains", "type": "contains",
"value": ":hover", "value": ":hover",
"message": "Add the ':hover' pseudo-class after the button selector", "message": "Add the <kbd>:hover</kbd> pseudo-class after the button selector",
"options": { "options": {
"caseSensitive": true "caseSensitive": true
} }
@@ -136,7 +136,7 @@
{ {
"type": "contains", "type": "contains",
"value": "padding", "value": "padding",
"message": "Use the 'padding' property to add space around the content", "message": "Use the <kbd>padding</kbd> property to add space around the content",
"options": { "options": {
"caseSensitive": false "caseSensitive": false
} }
@@ -147,7 +147,7 @@
"property": "padding", "property": "padding",
"expected": "20px" "expected": "20px"
}, },
"message": "Set the padding value to '20px'", "message": "Set the padding value to <kbd>20px</kbd>",
"options": { "options": {
"exact": true "exact": true
} }
@@ -170,7 +170,7 @@
{ {
"type": "contains", "type": "contains",
"value": "margin-bottom", "value": "margin-bottom",
"message": "Use the 'margin-bottom' property to add space after the title", "message": "Use the <kbd>margin-bottom</kbd> property to add space after the title",
"options": { "options": {
"caseSensitive": false "caseSensitive": false
} }
@@ -181,7 +181,7 @@
"property": "margin-bottom", "property": "margin-bottom",
"expected": "30px" "expected": "30px"
}, },
"message": "Set the margin-bottom value to '30px'", "message": "Set the margin-bottom value to <kbd>30px</kbd>",
"options": { "options": {
"exact": true "exact": true
} }
@@ -204,7 +204,7 @@
{ {
"type": "contains", "type": "contains",
"value": "border", "value": "border",
"message": "Use the 'border' property to add a border around the card", "message": "Use the <kbd>border</kbd> property to add a border around the card",
"options": { "options": {
"caseSensitive": false "caseSensitive": false
} }
@@ -212,7 +212,7 @@
{ {
"type": "regex", "type": "regex",
"value": "border:\\s*2px\\s+solid\\s+blue", "value": "border:\\s*2px\\s+solid\\s+blue",
"message": "Set the border to '2px solid blue'", "message": "Set the border to <kbd>2px solid blue</kbd>",
"options": { "options": {
"caseSensitive": false "caseSensitive": false
} }
@@ -235,7 +235,7 @@
{ {
"type": "contains", "type": "contains",
"value": "justify-content", "value": "justify-content",
"message": "Use 'justify-content' property for horizontal centering", "message": "Use <kbd>justify-content</kbd> property for horizontal centering",
"options": { "options": {
"caseSensitive": false "caseSensitive": false
} }
@@ -246,7 +246,7 @@
"property": "justify-content", "property": "justify-content",
"expected": "center" "expected": "center"
}, },
"message": "Set 'justify-content' to 'center'", "message": "Set <kbd>justify-content</kbd> to <kbd>center</kbd>",
"options": { "options": {
"exact": true "exact": true
} }
@@ -254,7 +254,7 @@
{ {
"type": "contains", "type": "contains",
"value": "align-items", "value": "align-items",
"message": "Use 'align-items' property for vertical centering", "message": "Use <kbd>align-items</kbd> property for vertical centering",
"options": { "options": {
"caseSensitive": false "caseSensitive": false
} }
@@ -265,7 +265,7 @@
"property": "align-items", "property": "align-items",
"expected": "center" "expected": "center"
}, },
"message": "Set 'align-items' to 'center'", "message": "Set <kbd>align-items</kbd> to <kbd>center</kbd>",
"options": { "options": {
"exact": true "exact": true
} }
@@ -288,7 +288,7 @@
{ {
"type": "contains", "type": "contains",
"value": "background", "value": "background",
"message": "Use the 'background' or 'background-color' property", "message": "Use the <kbd>background</kbd> or <kbd>background-color</kbd> property",
"options": { "options": {
"caseSensitive": false "caseSensitive": false
} }
@@ -296,7 +296,7 @@
{ {
"type": "regex", "type": "regex",
"value": "background(-color)?:\\s*orange", "value": "background(-color)?:\\s*orange",
"message": "Set the background/background-color to 'orange'", "message": "Set the background/background-color to <kbd>orange</kbd>",
"options": { "options": {
"caseSensitive": false "caseSensitive": false
} }
@@ -319,7 +319,7 @@
{ {
"type": "contains", "type": "contains",
"value": "font-family", "value": "font-family",
"message": "Use the 'font-family' property", "message": "Use the <kbd>font-family</kbd> property",
"options": { "options": {
"caseSensitive": false "caseSensitive": false
} }
@@ -327,7 +327,7 @@
{ {
"type": "regex", "type": "regex",
"value": "font-family:\\s*Courier,\\s*monospace", "value": "font-family:\\s*Courier,\\s*monospace",
"message": "Set the font-family to 'Courier, monospace'", "message": "Set the font-family to <kbd>Courier, monospace</kbd>",
"options": { "options": {
"caseSensitive": false "caseSensitive": false
} }
@@ -350,7 +350,7 @@
{ {
"type": "contains", "type": "contains",
"value": "width", "value": "width",
"message": "Use the 'width' property", "message": "Use the <kbd>width</kbd> property",
"options": { "options": {
"caseSensitive": false "caseSensitive": false
} }
@@ -361,7 +361,7 @@
"property": "width", "property": "width",
"expected": "80%" "expected": "80%"
}, },
"message": "Set the width to '80%'", "message": "Set the width to <kbd>80%</kbd>",
"options": { "options": {
"exact": true "exact": true
} }
@@ -369,7 +369,7 @@
{ {
"type": "contains", "type": "contains",
"value": "font-size", "value": "font-size",
"message": "Use the 'font-size' property", "message": "Use the <kbd>font-size</kbd> property",
"options": { "options": {
"caseSensitive": false "caseSensitive": false
} }
@@ -380,7 +380,7 @@
"property": "font-size", "property": "font-size",
"expected": "18px" "expected": "18px"
}, },
"message": "Set the font-size to '18px'", "message": "Set the font-size to <kbd>18px</kbd>",
"options": { "options": {
"exact": true "exact": true
} }
@@ -426,7 +426,7 @@
{ {
"type": "contains", "type": "contains",
"value": "display", "value": "display",
"message": "Use the 'display' property", "message": "Use the <kbd>display</kbd> property",
"options": { "options": {
"caseSensitive": false "caseSensitive": false
} }
@@ -437,7 +437,7 @@
"property": "display", "property": "display",
"expected": "block" "expected": "block"
}, },
"message": "Set the display value to 'block'", "message": "Set the display value to <kbd>block</kbd>",
"options": { "options": {
"exact": true "exact": true
} }

View File

@@ -18,12 +18,12 @@
"codeSuffix": "", "codeSuffix": "",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "validations": [
{ "type": "contains", "value": "p {", "message": "Use the element selector 'p'", "options": { "caseSensitive": false } }, { "type": "contains", "value": "p {", "message": "Use the element selector <kbd>p</kbd>", "options": { "caseSensitive": false } },
{ "type": "contains", "value": "color", "message": "Include the 'color' property", "options": { "caseSensitive": false } }, { "type": "contains", "value": "color", "message": "Include the <kbd>color</kbd> property", "options": { "caseSensitive": false } },
{ {
"type": "property_value", "type": "property_value",
"value": { "property": "color", "expected": "darkgray" }, "value": { "property": "color", "expected": "darkgray" },
"message": "Set color to 'darkgray'", "message": "Set color to <kbd>darkgray</kbd>",
"options": { "exact": false } "options": { "exact": false }
} }
] ]
@@ -41,11 +41,16 @@
"codeSuffix": "", "codeSuffix": "",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "validations": [
{ "type": "contains", "value": ".title", "message": "Use the '.title' class selector", "options": { "caseSensitive": false } }, {
"type": "contains",
"value": ".title",
"message": "Use the <kbd>.title</kbd> class selector",
"options": { "caseSensitive": false }
},
{ {
"type": "property_value", "type": "property_value",
"value": { "property": "color", "expected": "blueviolet" }, "value": { "property": "color", "expected": "blueviolet" },
"message": "Set color to 'blueviolet'", "message": "Set color to <kbd>blueviolet</kbd>",
"options": { "exact": false } "options": { "exact": false }
} }
] ]
@@ -66,13 +71,13 @@
{ {
"type": "contains", "type": "contains",
"value": "#description", "value": "#description",
"message": "Use the '#description' ID selector", "message": "Use the <kbd>#description</kbd> ID selector",
"options": { "caseSensitive": false } "options": { "caseSensitive": false }
}, },
{ {
"type": "property_value", "type": "property_value",
"value": { "property": "color", "expected": "orangered" }, "value": { "property": "color", "expected": "orangered" },
"message": "Set color to 'orangered'", "message": "Set color to <kbd>orangered</kbd>",
"options": { "exact": false } "options": { "exact": false }
} }
] ]
@@ -90,11 +95,16 @@
"codeSuffix": "", "codeSuffix": "",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "validations": [
{ "type": "contains", "value": "div.note", "message": "Use the 'div.note' combined selector", "options": { "caseSensitive": false } }, {
"type": "contains",
"value": "div.note",
"message": "Use the <kbd>div.note</kbd> combined selector",
"options": { "caseSensitive": false }
},
{ {
"type": "property_value", "type": "property_value",
"value": { "property": "background-color", "expected": "yellow" }, "value": { "property": "background-color", "expected": "yellow" },
"message": "Set background-color to 'yellow'", "message": "Set background-color to <kbd>yellow</kbd>",
"options": { "exact": false } "options": { "exact": false }
} }
] ]

View File

@@ -18,17 +18,17 @@
"codeSuffix": "}", "codeSuffix": "}",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "validations": [
{ "type": "contains", "value": ".colorbox", "message": "Select '.colorbox'", "options": { "caseSensitive": false } }, { "type": "contains", "value": ".colorbox", "message": "Select <kbd>.colorbox</kbd>", "options": { "caseSensitive": false } },
{ {
"type": "contains", "type": "contains",
"value": "background-color", "value": "background-color",
"message": "Use 'background-color' property", "message": "Use <kbd>background-color</kbd> property",
"options": { "caseSensitive": false } "options": { "caseSensitive": false }
}, },
{ {
"type": "property_value", "type": "property_value",
"value": { "property": "background-color", "expected": "#e0f7fa" }, "value": { "property": "background-color", "expected": "#e0f7fa" },
"message": "Set background-color to '#e0f7fa'", "message": "Set background-color to <kbd>#e0f7fa</kbd>",
"options": { "exact": true } "options": { "exact": true }
} }
] ]
@@ -46,12 +46,12 @@
"codeSuffix": "}", "codeSuffix": "}",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "validations": [
{ "type": "contains", "value": ".colorbox", "message": "Select '.colorbox'", "options": { "caseSensitive": false } }, { "type": "contains", "value": ".colorbox", "message": "Select <kbd>.colorbox</kbd>", "options": { "caseSensitive": false } },
{ "type": "contains", "value": "color", "message": "Use the 'color' property", "options": { "caseSensitive": false } }, { "type": "contains", "value": "color", "message": "Use the <kbd>color</kbd> property", "options": { "caseSensitive": false } },
{ {
"type": "property_value", "type": "property_value",
"value": { "property": "color", "expected": "#01579b" }, "value": { "property": "color", "expected": "#01579b" },
"message": "Set color to '#01579b'", "message": "Set color to <kbd>#01579b</kbd>",
"options": { "exact": true } "options": { "exact": true }
} }
] ]
@@ -69,17 +69,17 @@
"codeSuffix": "}", "codeSuffix": "}",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "validations": [
{ "type": "contains", "value": ".gradient-box", "message": "Select '.gradient-box'", "options": { "caseSensitive": false } }, { "type": "contains", "value": ".gradient-box", "message": "Select <kbd>.gradient-box</kbd>", "options": { "caseSensitive": false } },
{ {
"type": "contains", "type": "contains",
"value": "background-image", "value": "background-image",
"message": "Use 'background-image' property", "message": "Use <kbd>background-image</kbd> property",
"options": { "caseSensitive": false } "options": { "caseSensitive": false }
}, },
{ {
"type": "regex", "type": "regex",
"value": "linear-gradient\\(.*#ff9a9e.*,.*#fad0c4.*\\)", "value": "linear-gradient\\(.*#ff9a9e.*,.*#fad0c4.*\\)",
"message": "Use linear-gradient from #ff9a9e to #fad0c4", "message": "Use <kbd>linear-gradient</kbd> from <kbd>#ff9a9e</kbd> to <kbd>#fad0c4</kbd>",
"options": { "caseSensitive": false } "options": { "caseSensitive": false }
} }
] ]
@@ -100,19 +100,19 @@
{ {
"type": "contains", "type": "contains",
"value": "background-image", "value": "background-image",
"message": "Use 'background-image' property", "message": "Use <kbd>background-image</kbd> property",
"options": { "caseSensitive": false } "options": { "caseSensitive": false }
}, },
{ {
"type": "contains", "type": "contains",
"value": "background-position: center", "value": "background-position: center",
"message": "Center the background image", "message": "Center the background image with <kbd>background-position: center</kbd>",
"options": { "caseSensitive": false } "options": { "caseSensitive": false }
}, },
{ {
"type": "contains", "type": "contains",
"value": "background-repeat: no-repeat", "value": "background-repeat: no-repeat",
"message": "Prevent image tiling", "message": "Prevent image tiling with <kbd>background-repeat: no-repeat</kbd>",
"options": { "caseSensitive": false } "options": { "caseSensitive": false }
} }
] ]

View File

@@ -18,11 +18,16 @@
"codeSuffix": "}", "codeSuffix": "}",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "validations": [
{ "type": "contains", "value": "font-family", "message": "Use the 'font-family' property", "options": { "caseSensitive": false } }, {
"type": "contains",
"value": "font-family",
"message": "Use the <kbd>font-family</kbd> property",
"options": { "caseSensitive": false }
},
{ {
"type": "regex", "type": "regex",
"value": "Georgia, serif", "value": "Georgia, serif",
"message": "Include 'Georgia, serif' in the font stack", "message": "Include <kbd>Georgia, serif</kbd> in the font stack",
"options": { "caseSensitive": false } "options": { "caseSensitive": false }
} }
] ]
@@ -40,10 +45,23 @@
"codeSuffix": "}", "codeSuffix": "}",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "validations": [
{ "type": "contains", "value": "font-size", "message": "Use 'font-size' property", "options": { "caseSensitive": false } }, { "type": "contains", "value": "font-size", "message": "Use <kbd>font-size</kbd> 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",
{ "type": "property_value", "value": { "property": "line-height", "expected": "1.5" }, "message": "Set line-height to '1.5'" } "value": { "property": "font-size", "expected": "1.5rem" },
"message": "Set font-size to <kbd>1.5rem</kbd>"
},
{
"type": "contains",
"value": "line-height",
"message": "Use <kbd>line-height</kbd> property",
"options": { "caseSensitive": false }
},
{
"type": "property_value",
"value": { "property": "line-height", "expected": "1.5" },
"message": "Set line-height to <kbd>1.5</kbd>"
}
] ]
}, },
{ {
@@ -59,10 +77,23 @@
"codeSuffix": "}", "codeSuffix": "}",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "validations": [
{ "type": "contains", "value": "font-style", "message": "Use 'font-style' property", "options": { "caseSensitive": false } }, { "type": "contains", "value": "font-style", "message": "Use <kbd>font-style</kbd> 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",
{ "type": "property_value", "value": { "property": "font-weight", "expected": "bold" }, "message": "Set font-weight to 'bold'" } "value": { "property": "font-style", "expected": "italic" },
"message": "Set font-style to <kbd>italic</kbd>"
},
{
"type": "contains",
"value": "font-weight",
"message": "Use <kbd>font-weight</kbd> property",
"options": { "caseSensitive": false }
},
{
"type": "property_value",
"value": { "property": "font-weight", "expected": "bold" },
"message": "Set font-weight to <kbd>bold</kbd>"
}
] ]
}, },
{ {
@@ -81,10 +112,15 @@
{ {
"type": "contains", "type": "contains",
"value": "text-decoration", "value": "text-decoration",
"message": "Use 'text-decoration' property", "message": "Use <kbd>text-decoration</kbd> property",
"options": { "caseSensitive": false } "options": { "caseSensitive": false }
}, },
{ "type": "contains", "value": "text-shadow", "message": "Use 'text-shadow' property", "options": { "caseSensitive": false } } {
"type": "contains",
"value": "text-shadow",
"message": "Use <kbd>text-shadow</kbd> property",
"options": { "caseSensitive": false }
}
] ]
} }
] ]

View File

@@ -18,9 +18,14 @@
"codeSuffix": "}", "codeSuffix": "}",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "validations": [
{ "type": "contains", "value": "display", "message": "Use 'display: flex'", "options": { "caseSensitive": false } }, { "type": "contains", "value": "display", "message": "Use <kbd>display: flex</kbd>", "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": "justify-content",
"message": "Use <kbd>justify-content: center</kbd>",
"options": { "caseSensitive": false }
},
{ "type": "contains", "value": "align-items", "message": "Use <kbd>align-items: center</kbd>", "options": { "caseSensitive": false } }
] ]
}, },
{ {
@@ -36,11 +41,16 @@
"codeSuffix": "}\n.item { }", "codeSuffix": "}\n.item { }",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "validations": [
{ "type": "contains", "value": "flex-wrap: wrap", "message": "Use 'flex-wrap: wrap'", "options": { "caseSensitive": false } }, {
"type": "contains",
"value": "flex-wrap: wrap",
"message": "Use <kbd>flex-wrap: wrap</kbd>",
"options": { "caseSensitive": false }
},
{ {
"type": "regex", "type": "regex",
"value": ".item.*flex:\\s*1\\s+1\\s+100px", "value": ".item.*flex:\\s*1\\s+1\\s+100px",
"message": "Set flex: 1 1 100px on items", "message": "Set <kbd>flex: 1 1 100px</kbd> on items",
"options": { "caseSensitive": false } "options": { "caseSensitive": false }
} }
] ]
@@ -58,20 +68,20 @@
"codeSuffix": "}", "codeSuffix": "}",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "validations": [
{ "type": "contains", "value": "display: grid", "message": "Use 'display: grid'", "options": { "caseSensitive": false } }, { "type": "contains", "value": "display: grid", "message": "Use <kbd>display: grid</kbd>", "options": { "caseSensitive": false } },
{ {
"type": "contains", "type": "contains",
"value": "grid-template-columns", "value": "grid-template-columns",
"message": "Define 'grid-template-columns'", "message": "Define <kbd>grid-template-columns</kbd>",
"options": { "caseSensitive": false } "options": { "caseSensitive": false }
}, },
{ {
"type": "regex", "type": "regex",
"value": "grid-template-columns:\\s*repeat\\(3,\\s*1fr\\)\\s*", "value": "grid-template-columns:\\s*repeat\\(3,\\s*1fr\\)\\s*",
"message": "Create three equal columns", "message": "Create three equal columns with <kbd>repeat(3, 1fr)</kbd>",
"options": { "caseSensitive": false } "options": { "caseSensitive": false }
}, },
{ "type": "contains", "value": "gap", "message": "Use 'gap' property", "options": { "caseSensitive": false } } { "type": "contains", "value": "gap", "message": "Use <kbd>gap</kbd> property", "options": { "caseSensitive": false } }
] ]
}, },
{ {
@@ -87,11 +97,16 @@
"codeSuffix": "}", "codeSuffix": "}",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "validations": [
{ "type": "contains", "value": "grid-column", "message": "Use 'grid-column' property", "options": { "caseSensitive": false } }, {
"type": "contains",
"value": "grid-column",
"message": "Use <kbd>grid-column</kbd> property",
"options": { "caseSensitive": false }
},
{ {
"type": "property_value", "type": "property_value",
"value": { "property": "grid-column", "expected": "1 / span 2" }, "value": { "property": "grid-column", "expected": "1 / span 2" },
"message": "Span across 2 columns", "message": "Span across 2 columns with <kbd>grid-column: 1 / span 2</kbd>",
"options": { "caseSensitive": false } "options": { "caseSensitive": false }
} }
] ]

View File

@@ -20,7 +20,7 @@
{ {
"type": "contains_class", "type": "contains_class",
"value": "bg-blue-500", "value": "bg-blue-500",
"message": "Add the 'bg-blue-500' class for a blue background." "message": "Add the <kbd>bg-blue-500</kbd> class for a blue background."
} }
] ]
}, },

View File

@@ -26,7 +26,7 @@
{ {
"type": "parent_child", "type": "parent_child",
"value": { "parent": "p", "child": "strong" }, "value": { "parent": "p", "child": "strong" },
"message": "Wrap the word 'important' with <kbd>&lt;strong&gt;</kbd> tags" "message": "Wrap the word <kbd>important</kbd> with <kbd>&lt;strong&gt;</kbd> tags"
} }
] ]
}, },
@@ -84,12 +84,12 @@
{ {
"type": "element_exists", "type": "element_exists",
"value": "span", "value": "span",
"message": "Add a <kbd>&lt;span&gt;</kbd> around the word 'highlighted'" "message": "Add a <kbd>&lt;span&gt;</kbd> around the word <kbd>highlighted</kbd>"
}, },
{ {
"type": "element_text", "type": "element_text",
"value": { "selector": "span", "text": "highlighted" }, "value": { "selector": "span", "text": "highlighted" },
"message": "The <kbd>&lt;span&gt;</kbd> should contain the word 'highlighted'" "message": "The <kbd>&lt;span&gt;</kbd> should contain the word <kbd>highlighted</kbd>"
} }
] ]
} }

View File

@@ -94,7 +94,7 @@
{ {
"type": "element_text", "type": "element_text",
"value": { "selector": "button", "text": "Sign In" }, "value": { "selector": "button", "text": "Sign In" },
"message": "The button should say 'Sign In'" "message": "The button should say <kbd>Sign In</kbd>"
} }
] ]
} }

View File

@@ -354,7 +354,7 @@
{ {
"type": "regex", "type": "regex",
"value": "^p#special\\s*{", "value": "^p#special\\s*{",
"message": "Verwende <kbd>p#special</kbd>, um Absätze mit ID 'special' anzuvisieren", "message": "Verwende <kbd>p#special</kbd>, um Absätze mit ID <kbd>special</kbd> anzuvisieren",
"options": { "options": {
"caseSensitive": true "caseSensitive": true
} }

View File

@@ -21,7 +21,7 @@
{ {
"type": "property_value", "type": "property_value",
"value": { "property": "padding", "expected": "1rem" }, "value": { "property": "padding", "expected": "1rem" },
"message": "Setze padding auf '1rem'" "message": "Setze <kbd>padding: 1rem</kbd>"
} }
] ]
}, },
@@ -41,7 +41,7 @@
{ {
"type": "regex", "type": "regex",
"value": "border:\\s*2px\\s+solid\\s+darkslategray", "value": "border:\\s*2px\\s+solid\\s+darkslategray",
"message": "Setze border auf '2px solid darkslategray'", "message": "Setze <kbd>border: 2px solid darkslategray</kbd>",
"options": { "caseSensitive": false } "options": { "caseSensitive": false }
} }
] ]
@@ -62,7 +62,7 @@
{ {
"type": "property_value", "type": "property_value",
"value": { "property": "margin", "expected": "1rem" }, "value": { "property": "margin", "expected": "1rem" },
"message": "Setze margin auf '1rem'" "message": "Setze <kbd>margin: 1rem</kbd>"
} }
] ]
}, },
@@ -82,7 +82,7 @@
{ {
"type": "property_value", "type": "property_value",
"value": { "property": "box-sizing", "expected": "border-box" }, "value": { "property": "box-sizing", "expected": "border-box" },
"message": "Setze box-sizing auf 'border-box'" "message": "Setze <kbd>box-sizing: border-box</kbd>"
} }
] ]
}, },
@@ -102,7 +102,7 @@
{ {
"type": "property_value", "type": "property_value",
"value": { "property": "margin-bottom", "expected": "2rem" }, "value": { "property": "margin-bottom", "expected": "2rem" },
"message": "Setze margin-bottom auf '2rem'" "message": "Setze <kbd>margin-bottom: 2rem</kbd>"
} }
] ]
}, },
@@ -122,7 +122,7 @@
{ {
"type": "regex", "type": "regex",
"value": "margin:\\s*1rem\\s+2rem", "value": "margin:\\s*1rem\\s+2rem",
"message": "Setze margin auf '1rem 2rem'", "message": "Setze <kbd>margin: 1rem 2rem</kbd>",
"options": { "caseSensitive": false } "options": { "caseSensitive": false }
} }
] ]
@@ -143,7 +143,7 @@
{ {
"type": "property_value", "type": "property_value",
"value": { "property": "padding", "expected": "1.5rem" }, "value": { "property": "padding", "expected": "1.5rem" },
"message": "Setze padding auf '1.5rem'" "message": "Setze <kbd>padding: 1.5rem</kbd>"
} }
] ]
}, },
@@ -163,7 +163,7 @@
{ {
"type": "regex", "type": "regex",
"value": "border-bottom:\\s*4px\\s+solid\\s+dodgerblue", "value": "border-bottom:\\s*4px\\s+solid\\s+dodgerblue",
"message": "Setze border-bottom auf '4px solid dodgerblue'", "message": "Setze <kbd>border-bottom: 4px solid dodgerblue</kbd>",
"options": { "caseSensitive": false } "options": { "caseSensitive": false }
} }
] ]

View File

@@ -9,7 +9,7 @@
"id": "units-1", "id": "units-1",
"title": "Absolute vs. Relative Einheiten", "title": "Absolute vs. Relative Einheiten",
"description": "Lerne den Unterschied zwischen px, rem, em, % und vw/vh für flexible, responsive Layouts.", "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 <kbd>.unit-box</kbd> auf <kbd>80%</kbd> und max-width auf <kbd>37.5rem</kbd>.",
"previewHTML": "<div class=\"unit-box\">Ändere meine Größe!</div>", "previewHTML": "<div class=\"unit-box\">Ändere meine Größe!</div>",
"previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .unit-box { background: #f5f5f5; padding: 1rem; }", "previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .unit-box { background: #f5f5f5; padding: 1rem; }",
"sandboxCSS": "", "sandboxCSS": "",
@@ -18,17 +18,31 @@
"codeSuffix": "}", "codeSuffix": "}",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "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",
{ "type": "contains", "value": "max-width", "message": "Verwende die 'max-width' Eigenschaft", "options": { "caseSensitive": false } }, "value": "width",
{ "type": "property_value", "value": { "property": "max-width", "expected": "37.5rem" }, "message": "Setze max-width auf '37.5rem'" } "message": "Verwende die <kbd>width</kbd> Eigenschaft",
"options": { "caseSensitive": false }
},
{ "type": "property_value", "value": { "property": "width", "expected": "80%" }, "message": "Setze width auf <kbd>80%</kbd>" },
{
"type": "contains",
"value": "max-width",
"message": "Verwende die <kbd>max-width</kbd> Eigenschaft",
"options": { "caseSensitive": false }
},
{
"type": "property_value",
"value": { "property": "max-width", "expected": "37.5rem" },
"message": "Setze max-width auf <kbd>37.5rem</kbd>"
}
] ]
}, },
{ {
"id": "units-2", "id": "units-2",
"title": "CSS Custom Properties", "title": "CSS Custom Properties",
"description": "Definiere und verwende Variablen (--custom properties) wieder, um deine Theme-Werte zu zentralisieren.", "description": "Definiere und verwende Variablen (--custom properties) wieder, um deine Theme-Werte zu zentralisieren.",
"task": "Erstelle eine <code>--main-color</code> Variable in :root mit #6200ee und wende sie als Rahmenfarbe auf '.var-box' an.", "task": "Erstelle eine <code>--main-color</code> Variable in :root mit <kbd>#6200ee</kbd> und wende sie als Rahmenfarbe auf <kbd>.var-box</kbd> an.",
"previewHTML": "<div class=\"var-box\">Variablen-Box</div>", "previewHTML": "<div class=\"var-box\">Variablen-Box</div>",
"previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .var-box { padding: 1rem; border: 0.125rem solid #ddd; }", "previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .var-box { padding: 1rem; border: 0.125rem solid #ddd; }",
"sandboxCSS": "", "sandboxCSS": "",
@@ -37,8 +51,18 @@
"codeSuffix": "}\n.var-box { }", "codeSuffix": "}\n.var-box { }",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "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 <kbd>--main-color</kbd> in :root",
"options": { "caseSensitive": false }
},
{
"type": "contains",
"value": "var(--main-color)",
"message": "Verwende <kbd>var(--main-color)</kbd>",
"options": { "caseSensitive": false }
},
{ {
"type": "property_value", "type": "property_value",
"value": { "property": "border", "expected": "var(--main-color)" }, "value": { "property": "border", "expected": "var(--main-color)" },
@@ -51,7 +75,7 @@
"id": "units-3", "id": "units-3",
"title": "Einheiten-Berechnungen (calc)", "title": "Einheiten-Berechnungen (calc)",
"description": "Verwende die <code>calc()</code> Funktion, um verschiedene Einheiten in einem Ausdruck zu kombinieren.", "description": "Verwende die <code>calc()</code> 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 <kbd>.calc-box</kbd> auf <kbd>calc(100% - 2rem)</kbd> und min-height auf <kbd>calc(10vh + 1rem)</kbd>.",
"previewHTML": "<div class=\"calc-box\">Calc Demo</div>", "previewHTML": "<div class=\"calc-box\">Calc Demo</div>",
"previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .calc-box { background: #e8f5e9; padding: 1rem; }", "previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .calc-box { background: #e8f5e9; padding: 1rem; }",
"sandboxCSS": "", "sandboxCSS": "",
@@ -60,7 +84,7 @@
"codeSuffix": "}", "codeSuffix": "}",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "validations": [
{ "type": "contains", "value": "calc", "message": "Verwende die 'calc()' Funktion", "options": { "caseSensitive": false } }, { "type": "contains", "value": "calc", "message": "Verwende die <kbd>calc()</kbd> Funktion", "options": { "caseSensitive": false } },
{ {
"type": "regex", "type": "regex",
"value": "width:\\s*calc\\(100% - 2rem\\)", "value": "width:\\s*calc\\(100% - 2rem\\)",
@@ -79,7 +103,7 @@
"id": "units-4", "id": "units-4",
"title": "Viewport & Responsive Einheiten", "title": "Viewport & Responsive Einheiten",
"description": "Steuere Layouts relativ zur Viewport-Größe mit vw, vh und vmin/vmax 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 <kbd>.viewport-box</kbd> eine Breite von <kbd>50vw</kbd> und Höhe von <kbd>20vh</kbd>.",
"previewHTML": "<div class=\"viewport-box\">Viewport-Box</div>", "previewHTML": "<div class=\"viewport-box\">Viewport-Box</div>",
"previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .viewport-box { background: #ffe0b2; }", "previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .viewport-box { background: #ffe0b2; }",
"sandboxCSS": "", "sandboxCSS": "",
@@ -88,10 +112,10 @@
"codeSuffix": "}", "codeSuffix": "}",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "validations": [
{ "type": "contains", "value": "vw", "message": "Verwende 'vw' Einheit", "options": { "caseSensitive": false } }, { "type": "contains", "value": "vw", "message": "Verwende <kbd>vw</kbd> Einheit", "options": { "caseSensitive": false } },
{ "type": "contains", "value": "vh", "message": "Verwende 'vh' Einheit", "options": { "caseSensitive": false } }, { "type": "contains", "value": "vh", "message": "Verwende <kbd>vh</kbd> Einheit", "options": { "caseSensitive": false } },
{ "type": "property_value", "value": { "property": "width", "expected": "50vw" }, "message": "Setze width auf '50vw'" }, { "type": "property_value", "value": { "property": "width", "expected": "50vw" }, "message": "Setze width auf <kbd>50vw</kbd>" },
{ "type": "property_value", "value": { "property": "height", "expected": "20vh" }, "message": "Setze height auf '20vh'" } { "type": "property_value", "value": { "property": "height", "expected": "20vh" }, "message": "Setze height auf <kbd>20vh</kbd>" }
] ]
} }
] ]

View File

@@ -9,7 +9,7 @@
"id": "transitions-1", "id": "transitions-1",
"title": "Einfache Transitions", "title": "Einfache Transitions",
"description": "Lerne, wie du <code>transition</code> auf Eigenschaften anwendest für sanfte Änderungen bei Zustandswechseln.", "description": "Lerne, wie du <code>transition</code> 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 <kbd>transition: background-color 0.3s</kbd> zu <kbd>.btn</kbd> hinzu, damit die Farbe beim Hover sanft überblendet.",
"previewHTML": "<button class=\"btn\">Hover mich</button>", "previewHTML": "<button class=\"btn\">Hover mich</button>",
"previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .btn { background: #6200ee; color: white; padding: 0.5rem 1rem; border: none; } .btn:hover { background: #3700b3; }", "previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .btn { background: #6200ee; color: white; padding: 0.5rem 1rem; border: none; } .btn:hover { background: #3700b3; }",
"sandboxCSS": "", "sandboxCSS": "",
@@ -18,11 +18,11 @@
"codeSuffix": "}", "codeSuffix": "}",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "validations": [
{ "type": "contains", "value": "transition", "message": "Verwende die 'transition' Eigenschaft", "options": { "caseSensitive": false } }, { "type": "contains", "value": "transition", "message": "Verwende die <kbd>transition</kbd> Eigenschaft", "options": { "caseSensitive": false } },
{ {
"type": "regex", "type": "regex",
"value": "transition:\\s*background-color\\s*0\\.3s", "value": "transition:\\s*background-color\\s*0\\.3s",
"message": "Transition background-color über 0.3s", "message": "Setze <kbd>transition: background-color 0.3s</kbd>",
"options": { "caseSensitive": false } "options": { "caseSensitive": false }
} }
] ]
@@ -30,8 +30,8 @@
{ {
"id": "transitions-2", "id": "transitions-2",
"title": "Transition Timing-Funktionen", "title": "Transition Timing-Funktionen",
"description": "Erkunde Easing-Funktionen wie ease, linear, ease-in, ease-out, um das Animationstempo zu steuern.", "description": "Erkunde Easing-Funktionen wie <kbd>ease</kbd>, <kbd>linear</kbd>, <kbd>ease-in</kbd>, <kbd>ease-out</kbd>, um das Animationstempo zu steuern.",
"task": "Ändere den Button, um 'ease-in-out' Timing für seine Transition zu verwenden.", "task": "Setze <kbd>transition-timing-function</kbd> auf <kbd>ease-in-out</kbd> bei <kbd>.btn</kbd>.",
"previewHTML": "<button class=\"btn\">Timing</button>", "previewHTML": "<button class=\"btn\">Timing</button>",
"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; }", "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": "", "sandboxCSS": "",
@@ -43,13 +43,13 @@
{ {
"type": "contains", "type": "contains",
"value": "transition-timing-function", "value": "transition-timing-function",
"message": "Verwende 'transition-timing-function'", "message": "Verwende <kbd>transition-timing-function</kbd>",
"options": { "caseSensitive": false } "options": { "caseSensitive": false }
}, },
{ {
"type": "property_value", "type": "property_value",
"value": { "property": "transition-timing-function", "expected": "ease-in-out" }, "value": { "property": "transition-timing-function", "expected": "ease-in-out" },
"message": "Setze Timing auf 'ease-in-out'" "message": "Setze <kbd>transition-timing-function: ease-in-out</kbd>"
} }
] ]
}, },
@@ -57,7 +57,7 @@
"id": "transitions-3", "id": "transitions-3",
"title": "Keyframe-Animationen Grundlagen", "title": "Keyframe-Animationen Grundlagen",
"description": "Erstelle benannte Animationen mit <code>@keyframes</code> und wende sie mit der <code>animation</code> Kurzschreibweise an.", "description": "Erstelle benannte Animationen mit <code>@keyframes</code> und wende sie mit der <code>animation</code> 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 <kbd>50%</kbd> ein <kbd>transform: translateY(-20px)</kbd> und wende <kbd>animation: bounce 1s infinite</kbd> auf <kbd>.ball</kbd> an.",
"previewHTML": "<div class=\"ball\"></div>", "previewHTML": "<div class=\"ball\"></div>",
"previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .ball { width: 50px; height: 50px; background: #ff0266; border-radius: 50%; margin: 2rem auto; }", "previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .ball { width: 50px; height: 50px; background: #ff0266; border-radius: 50%; margin: 2rem auto; }",
"sandboxCSS": "", "sandboxCSS": "",
@@ -66,18 +66,18 @@
"codeSuffix": "}\n.ball { }", "codeSuffix": "}\n.ball { }",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "validations": [
{ "type": "contains", "value": "@keyframes bounce", "message": "Definiere '@keyframes bounce'", "options": { "caseSensitive": false } }, { "type": "contains", "value": "@keyframes bounce", "message": "Definiere <kbd>@keyframes bounce</kbd>", "options": { "caseSensitive": false } },
{ {
"type": "regex", "type": "regex",
"value": "50%.*transform: translateY\\(-20px\\)", "value": "50%.*transform: translateY\\(-20px\\)",
"message": "Bei 50%, bewege um 20px nach oben", "message": "Bei <kbd>50%</kbd>, setze <kbd>transform: translateY(-20px)</kbd>",
"options": { "caseSensitive": false } "options": { "caseSensitive": false }
}, },
{ "type": "contains", "value": "animation", "message": "Verwende 'animation' Eigenschaft auf .ball", "options": { "caseSensitive": false } }, { "type": "contains", "value": "animation", "message": "Verwende <kbd>animation</kbd> Eigenschaft auf <kbd>.ball</kbd>", "options": { "caseSensitive": false } },
{ {
"type": "regex", "type": "regex",
"value": "animation:.*bounce.*1s.*infinite", "value": "animation:.*bounce.*1s.*infinite",
"message": "Wende 'bounce 1s infinite' an", "message": "Wende <kbd>animation: bounce 1s infinite</kbd> an",
"options": { "caseSensitive": false } "options": { "caseSensitive": false }
} }
] ]
@@ -85,8 +85,8 @@
{ {
"id": "transitions-4", "id": "transitions-4",
"title": "Animations-Eigenschaften im Detail", "title": "Animations-Eigenschaften im Detail",
"description": "Verfeinere Animationen mit delay, iteration-count, direction und fill-mode.", "description": "Verfeinere Animationen mit <kbd>animation-delay</kbd>, <kbd>animation-iteration-count</kbd>, <kbd>animation-direction</kbd> und <kbd>animation-fill-mode</kbd>.",
"task": "Animiere '.box' mit einem 'fade' Keyframe über 2s, Verzögerung 1s, zweimalige Ausführung und bleibe danach sichtbar.", "task": "Wende die <kbd>fade</kbd> Animation auf <kbd>.box</kbd> an mit <kbd>animation-name: fade</kbd>, <kbd>animation-duration: 2s</kbd>, <kbd>animation-delay: 1s</kbd>, <kbd>animation-iteration-count: 2</kbd> und <kbd>animation-fill-mode: forwards</kbd>.",
"previewHTML": "<div class=\"box\">Fade Demo</div>", "previewHTML": "<div class=\"box\">Fade Demo</div>",
"previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .box { width: 100px; height: 100px; background: #4caf50; margin: 2rem auto; }", "previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .box { width: 100px; height: 100px; background: #4caf50; margin: 2rem auto; }",
"sandboxCSS": "", "sandboxCSS": "",
@@ -98,32 +98,32 @@
{ {
"type": "contains", "type": "contains",
"value": "animation-delay", "value": "animation-delay",
"message": "Verwende 'animation-delay' Eigenschaft", "message": "Verwende <kbd>animation-delay</kbd>",
"options": { "caseSensitive": false } "options": { "caseSensitive": false }
}, },
{ {
"type": "contains", "type": "contains",
"value": "animation-iteration-count", "value": "animation-iteration-count",
"message": "Verwende 'animation-iteration-count' Eigenschaft", "message": "Verwende <kbd>animation-iteration-count</kbd>",
"options": { "caseSensitive": false } "options": { "caseSensitive": false }
}, },
{ {
"type": "contains", "type": "contains",
"value": "animation-fill-mode", "value": "animation-fill-mode",
"message": "Verwende 'animation-fill-mode' Eigenschaft", "message": "Verwende <kbd>animation-fill-mode</kbd>",
"options": { "caseSensitive": false } "options": { "caseSensitive": false }
}, },
{ "type": "property_value", "value": { "property": "animation-duration", "expected": "2s" }, "message": "Duration sollte 2s sein" }, { "type": "property_value", "value": { "property": "animation-duration", "expected": "2s" }, "message": "Setze <kbd>animation-duration: 2s</kbd>" },
{ "type": "property_value", "value": { "property": "animation-delay", "expected": "1s" }, "message": "Delay sollte 1s sein" }, { "type": "property_value", "value": { "property": "animation-delay", "expected": "1s" }, "message": "Setze <kbd>animation-delay: 1s</kbd>" },
{ {
"type": "property_value", "type": "property_value",
"value": { "property": "animation-iteration-count", "expected": "2" }, "value": { "property": "animation-iteration-count", "expected": "2" },
"message": "Iteration-count sollte 2 sein" "message": "Setze <kbd>animation-iteration-count: 2</kbd>"
}, },
{ {
"type": "property_value", "type": "property_value",
"value": { "property": "animation-fill-mode", "expected": "forwards" }, "value": { "property": "animation-fill-mode", "expected": "forwards" },
"message": "Fill-mode sollte forwards sein" "message": "Setze <kbd>animation-fill-mode: forwards</kbd>"
} }
] ]
} }

View File

@@ -9,7 +9,7 @@
"id": "responsive-1", "id": "responsive-1",
"title": "Einführung in Media Queries", "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.", "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 <kbd>.responsive-box</kbd> auf <kbd>lightcoral</kbd>.",
"previewHTML": "<div class=\"responsive-box\">Ändere die Fenstergröße</div>", "previewHTML": "<div class=\"responsive-box\">Ändere die Fenstergröße</div>",
"previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .responsive-box { padding: 1rem; background: lightblue; }", "previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .responsive-box { padding: 1rem; background: lightblue; }",
"sandboxCSS": "", "sandboxCSS": "",
@@ -27,14 +27,19 @@
{ {
"type": "contains", "type": "contains",
"value": ".responsive-box", "value": ".responsive-box",
"message": "Adressiere '.responsive-box' innerhalb der Media Query", "message": "Adressiere <kbd>.responsive-box</kbd> innerhalb der Media Query",
"options": { "caseSensitive": false }
},
{
"type": "contains",
"value": "background",
"message": "Ändere die <kbd>background</kbd> Eigenschaft",
"options": { "caseSensitive": false } "options": { "caseSensitive": false }
}, },
{ "type": "contains", "value": "background", "message": "Ändere die 'background' Eigenschaft", "options": { "caseSensitive": false } },
{ {
"type": "property_value", "type": "property_value",
"value": { "property": "background", "expected": "lightcoral" }, "value": { "property": "background", "expected": "lightcoral" },
"message": "Setze background auf 'lightcoral'", "message": "Setze background auf <kbd>lightcoral</kbd>",
"options": { "exact": false } "options": { "exact": false }
} }
] ]
@@ -43,7 +48,7 @@
"id": "responsive-2", "id": "responsive-2",
"title": "Flüssige Typografie", "title": "Flüssige Typografie",
"description": "Verwende relative Einheiten wie vw, damit Schriftgrößen mit der Viewport-Breite skalieren.", "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 <kbd>.fluid-text</kbd> auf <kbd>5vw</kbd>, damit sie sich mit dem Viewport ändert.",
"previewHTML": "<p class=\"fluid-text\">Flüssige Typografie</p>", "previewHTML": "<p class=\"fluid-text\">Flüssige Typografie</p>",
"previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; }", "previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; }",
"sandboxCSS": "", "sandboxCSS": "",
@@ -52,16 +57,26 @@
"codeSuffix": "}", "codeSuffix": "}",
"previewContainer": "preview-area", "previewContainer": "preview-area",
"validations": [ "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": "contains",
{ "type": "property_value", "value": { "property": "font-size", "expected": "5vw" }, "message": "Setze font-size auf '5vw'" } "value": "font-size",
"message": "Verwende die <kbd>font-size</kbd> Eigenschaft",
"options": { "caseSensitive": false }
},
{
"type": "contains",
"value": "vw",
"message": "Verwende <kbd>vw</kbd> Einheit für flüssige Größe",
"options": { "caseSensitive": false }
},
{ "type": "property_value", "value": { "property": "font-size", "expected": "5vw" }, "message": "Setze font-size auf <kbd>5vw</kbd>" }
] ]
}, },
{ {
"id": "responsive-3", "id": "responsive-3",
"title": "Flexible Raster", "title": "Flexible Raster",
"description": "Kombiniere CSS Grid mit auto-fit oder auto-fill für responsive Spaltenlayouts.", "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 <kbd>.grid-responsive</kbd> mit <kbd>grid-template-columns: repeat(auto-fit, minmax(200px, 1fr))</kbd> und einem gap von <kbd>1rem</kbd>.",
"previewHTML": "<div class=\"grid-responsive\"><div>1</div><div>2</div><div>3</div><div>4</div></div>", "previewHTML": "<div class=\"grid-responsive\"><div>1</div><div>2</div><div>3</div><div>4</div></div>",
"previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .grid-responsive > div { background: #d1c4e9; padding: 1rem; }", "previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .grid-responsive > div { background: #d1c4e9; padding: 1rem; }",
"sandboxCSS": "", "sandboxCSS": "",
@@ -73,23 +88,23 @@
{ {
"type": "contains", "type": "contains",
"value": "grid-template-columns", "value": "grid-template-columns",
"message": "Definiere 'grid-template-columns'", "message": "Definiere <kbd>grid-template-columns</kbd>",
"options": { "caseSensitive": false } "options": { "caseSensitive": false }
}, },
{ {
"type": "regex", "type": "regex",
"value": "repeat\\(auto-fit,\\s*minmax\\(200px,\\s*1fr\\)\\)", "value": "repeat\\(auto-fit,\\s*minmax\\(200px,\\s*1fr\\)\\)",
"message": "Verwende repeat(auto-fit, minmax(200px, 1fr))", "message": "Verwende <kbd>repeat(auto-fit, minmax(200px, 1fr))</kbd>",
"options": { "caseSensitive": false } "options": { "caseSensitive": false }
}, },
{ "type": "contains", "value": "gap", "message": "Verwende die 'gap' Eigenschaft", "options": { "caseSensitive": false } } { "type": "contains", "value": "gap", "message": "Verwende die <kbd>gap</kbd> Eigenschaft", "options": { "caseSensitive": false } }
] ]
}, },
{ {
"id": "responsive-4", "id": "responsive-4",
"title": "Mobile-First Media Queries", "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.", "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 <kbd>.sidebar</kbd> auf <kbd>250px</kbd> setzt.",
"previewHTML": "<aside class=\"sidebar\">Seitenleiste</aside>", "previewHTML": "<aside class=\"sidebar\">Seitenleiste</aside>",
"previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .sidebar { background: #c8e6c9; padding: 1rem; }", "previewBaseCSS": "body { font-family: sans-serif; padding: 1rem; } .sidebar { background: #c8e6c9; padding: 1rem; }",
"sandboxCSS": "", "sandboxCSS": "",
@@ -104,11 +119,16 @@
"message": "Verwende eine Media Query für min-width: 768px", "message": "Verwende eine Media Query für min-width: 768px",
"options": { "caseSensitive": false } "options": { "caseSensitive": false }
}, },
{ "type": "contains", "value": ".sidebar", "message": "Adressiere '.sidebar' in der Media Query", "options": { "caseSensitive": false } }, {
"type": "contains",
"value": ".sidebar",
"message": "Adressiere <kbd>.sidebar</kbd> in der Media Query",
"options": { "caseSensitive": false }
},
{ {
"type": "property_value", "type": "property_value",
"value": { "property": "width", "expected": "250px" }, "value": { "property": "width", "expected": "250px" },
"message": "Setze width auf '250px'", "message": "Setze width auf <kbd>250px</kbd>",
"options": { "exact": false } "options": { "exact": false }
} }
] ]

View File

@@ -20,7 +20,7 @@
{ {
"type": "contains_class", "type": "contains_class",
"value": "bg-blue-500", "value": "bg-blue-500",
"message": "Füge die 'bg-blue-500'-Klasse für einen blauen Hintergrund hinzu." "message": "Füge die <kbd>bg-blue-500</kbd>-Klasse für einen blauen Hintergrund hinzu."
} }
] ]
}, },

View File

@@ -79,7 +79,7 @@
{ {
"type": "attribute_value", "type": "attribute_value",
"value": { "selector": "#email", "attr": "type", "value": "email" }, "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 <kbd>email</kbd>"
}, },
{ {
"type": "attribute_value", "type": "attribute_value",
@@ -89,7 +89,7 @@
{ {
"type": "attribute_value", "type": "attribute_value",
"value": { "selector": "#password", "attr": "type", "value": "password" }, "value": { "selector": "#password", "attr": "type", "value": "password" },
"message": "Setze den Eingabetyp für Passwort auf 'password'" "message": "Setze den Eingabetyp für Passwort auf <kbd>password</kbd>"
}, },
{ {
"type": "attribute_value", "type": "attribute_value",

View File

@@ -21,7 +21,7 @@
{ {
"type": "property_value", "type": "property_value",
"value": { "property": "display", "expected": "flex" }, "value": { "property": "display", "expected": "flex" },
"message": "Setze display auf 'flex'" "message": "Setze display auf <kbd>flex</kbd>"
} }
] ]
}, },
@@ -41,12 +41,12 @@
{ {
"type": "property_value", "type": "property_value",
"value": { "property": "flex-direction", "expected": "column" }, "value": { "property": "flex-direction", "expected": "column" },
"message": "Setze flex-direction auf 'column'" "message": "Setze flex-direction auf <kbd>column</kbd>"
}, },
{ {
"type": "property_value", "type": "property_value",
"value": { "property": "flex-wrap", "expected": "wrap" }, "value": { "property": "flex-wrap", "expected": "wrap" },
"message": "Setze flex-wrap auf 'wrap'" "message": "Setze flex-wrap auf <kbd>wrap</kbd>"
} }
] ]
}, },
@@ -66,7 +66,7 @@
{ {
"type": "property_value", "type": "property_value",
"value": { "property": "justify-content", "expected": "space-between" }, "value": { "property": "justify-content", "expected": "space-between" },
"message": "Setze justify-content auf 'space-between'" "message": "Setze justify-content auf <kbd>space-between</kbd>"
} }
] ]
}, },
@@ -86,7 +86,7 @@
{ {
"type": "property_value", "type": "property_value",
"value": { "property": "align-items", "expected": "center" }, "value": { "property": "align-items", "expected": "center" },
"message": "Setze align-items auf 'center'" "message": "Setze align-items auf <kbd>center</kbd>"
} }
] ]
}, },
@@ -106,7 +106,7 @@
{ {
"type": "property_value", "type": "property_value",
"value": { "property": "flex", "expected": "2" }, "value": { "property": "flex", "expected": "2" },
"message": "Setze flex auf '2'" "message": "Setze flex auf <kbd>2</kbd>"
} }
] ]
}, },
@@ -126,7 +126,7 @@
{ {
"type": "property_value", "type": "property_value",
"value": { "property": "align-self", "expected": "flex-start" }, "value": { "property": "align-self", "expected": "flex-start" },
"message": "Setze align-self auf 'flex-start'" "message": "Setze align-self auf <kbd>flex-start</kbd>"
} }
] ]
} }

View File

@@ -21,12 +21,12 @@
{ {
"type": "contains", "type": "contains",
"value": "font-bold", "value": "font-bold",
"message": "Add 'font-bold' to the heading" "message": "Add <kbd>font-bold</kbd> to the heading"
}, },
{ {
"type": "contains", "type": "contains",
"value": "text-gray-600", "value": "text-gray-600",
"message": "Add 'text-gray-600' to the paragraph" "message": "Add <kbd>text-gray-600</kbd> to the paragraph"
} }
] ]
}, },
@@ -46,12 +46,12 @@
{ {
"type": "contains", "type": "contains",
"value": "bg-red-400", "value": "bg-red-400",
"message": "Use 'bg-red-400' to set the background color" "message": "Use <kbd>bg-red-400</kbd> to set the background color"
}, },
{ {
"type": "contains", "type": "contains",
"value": "text-white", "value": "text-white",
"message": "Use 'text-white' for the text color" "message": "Use <kbd>text-white</kbd> for the text color"
} }
] ]
}, },
@@ -71,12 +71,12 @@
{ {
"type": "contains", "type": "contains",
"value": "m-2", "value": "m-2",
"message": "Add 'm-2' to add spacing between the buttons" "message": "Add <kbd>m-2</kbd> to add spacing between the buttons"
}, },
{ {
"type": "contains", "type": "contains",
"value": "p-2", "value": "p-2",
"message": "Add 'p-2' for internal button padding" "message": "Add <kbd>p-2</kbd> for internal button padding"
} }
] ]
}, },
@@ -96,7 +96,7 @@
{ {
"type": "contains", "type": "contains",
"value": "hover:bg-green-500", "value": "hover:bg-green-500",
"message": "Add 'hover:bg-green-500' to change background color on hover" "message": "Add <kbd>hover:bg-green-500</kbd> to change background color on hover"
} }
] ]
}, },
@@ -116,27 +116,27 @@
{ {
"type": "contains", "type": "contains",
"value": "bg-white", "value": "bg-white",
"message": "Use 'bg-white' for background color" "message": "Use <kbd>bg-white</kbd> for background color"
}, },
{ {
"type": "contains", "type": "contains",
"value": "shadow", "value": "shadow",
"message": "Use 'shadow' to add a shadow" "message": "Use <kbd>shadow</kbd> to add a shadow"
}, },
{ {
"type": "contains", "type": "contains",
"value": "rounded", "value": "rounded",
"message": "Use 'rounded' to add rounded corners" "message": "Use <kbd>rounded</kbd> to add rounded corners"
}, },
{ {
"type": "contains", "type": "contains",
"value": "p-4", "value": "p-4",
"message": "Use 'p-4' for padding" "message": "Use <kbd>p-4</kbd> for padding"
}, },
{ {
"type": "contains", "type": "contains",
"value": "text-center", "value": "text-center",
"message": "Use 'text-center' to center the text" "message": "Use <kbd>text-center</kbd> to center the text"
} }
] ]
} }

View File

@@ -32,10 +32,10 @@
<section class="instructions"> <section class="instructions">
<span class="module-pill" id="module-pill" data-i18n="loading">Loading...</span> <span class="module-pill" id="module-pill" data-i18n="loading">Loading...</span>
<h2 id="lesson-title" data-i18n="loading">Loading...</h2> <h2 id="lesson-title" data-i18n="loading">Loading...</h2>
<div class="task-instruction" id="task-instruction"></div>
<div class="lesson-description" id="lesson-description" data-i18n="selectLesson"> <div class="lesson-description" id="lesson-description" data-i18n="selectLesson">
Please select a lesson to begin. Please select a lesson to begin.
</div> </div>
<div class="task-instruction" id="task-instruction"></div>
</section> </section>
<section class="editor-section"> <section class="editor-section">