feat: add new lesson modules and reach 101 total lessons

New CSS Modules:
- Gradients (3 lessons): linear-gradient, radial-gradient, direction
- Filters (4 lessons): blur, grayscale, brightness, drop-shadow
- Positioning (4 lessons): relative, absolute, offset properties
- Pseudo-elements (4 lessons): ::before, ::after, content, decorative

New HTML Module:
- Semantic HTML (3 lessons): article, section, aside

Expanded Existing Modules:
- Typography: +2 lessons (text-decoration, text-shadow)
- Tables: +2 lessons (thead/tbody/tfoot, colspan)

Total lessons: 101 (up from ~66)
- Enables full milestone system (1, 5, 10, 20, 30, 50, 75, 100)
- All modules added to all 6 language stores with EN fallback
This commit is contained in:
2026-01-16 14:17:13 +01:00
parent 45a9d7216e
commit 9cf313001b
8 changed files with 629 additions and 0 deletions

View File

@@ -0,0 +1,98 @@
{
"$schema": "../schemas/code-crispies-module-schema.json",
"id": "css-positioning",
"title": "CSS Positioning",
"description": "Control element placement with CSS positioning properties.",
"difficulty": "intermediate",
"lessons": [
{
"id": "position-1",
"title": "Relative Position",
"description": "The <kbd>position</kbd> property controls how elements are placed. <kbd>relative</kbd> keeps the element in normal flow but allows you to offset it with <kbd>top</kbd>, <kbd>right</kbd>, <kbd>bottom</kbd>, <kbd>left</kbd>.<br><br><pre>.box {\n position: relative;\n top: 10px;\n}</pre>",
"task": "Make the badge position relative so we can offset it.",
"previewHTML": "<div class=\"card\"><span class=\"badge\">NEW</span><h3>Product</h3></div>",
"previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .card { padding: 1rem; background: white; border: 2px solid #eee; border-radius: 8px; } .card h3 { margin: 0; } .badge { display: inline-block; padding: 2px 8px; background: coral; color: white; font-size: 0.7rem; font-weight: bold; border-radius: 4px; }",
"sandboxCSS": "",
"codePrefix": ".badge {\n ",
"initialCode": "",
"codeSuffix": "\n}",
"solution": "position: relative;",
"previewContainer": "preview-area",
"validations": [
{
"type": "property_value",
"value": { "property": "position", "expected": "relative" },
"message": "Set <kbd>position: relative</kbd>"
}
]
},
{
"id": "position-2",
"title": "Offset Properties",
"description": "With <kbd>position: relative</kbd>, use offset properties to nudge the element from its original position:<br><br><kbd>top</kbd> - pushes down from top<br><kbd>left</kbd> - pushes right from left<br><br>Negative values move in the opposite direction.",
"task": "Move the badge up with <kbd>top: -8px</kbd>.",
"previewHTML": "<div class=\"card\"><span class=\"badge\">NEW</span><h3>Product</h3></div>",
"previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .card { padding: 1rem; background: white; border: 2px solid #eee; border-radius: 8px; } .card h3 { margin: 0; } .badge { display: inline-block; padding: 2px 8px; background: coral; color: white; font-size: 0.7rem; font-weight: bold; border-radius: 4px; position: relative; }",
"sandboxCSS": "",
"codePrefix": ".badge {\n ",
"initialCode": "",
"codeSuffix": "\n}",
"solution": "top: -8px;",
"previewContainer": "preview-area",
"validations": [
{
"type": "property_value",
"value": { "property": "top", "expected": "-8px" },
"message": "Set <kbd>top: -8px</kbd>"
}
]
},
{
"id": "position-3",
"title": "Absolute Position",
"description": "<kbd>position: absolute</kbd> removes the element from normal flow and positions it relative to its nearest positioned ancestor (or the viewport if none exists).<br><br>Always set a parent to <kbd>position: relative</kbd> to contain absolute children.",
"task": "Position the close button absolutely.",
"previewHTML": "<div class=\"modal\"><button class=\"close\">×</button><h3>Modal</h3><p>Content here</p></div>",
"previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .modal { position: relative; padding: 2rem; background: white; border-radius: 12px; box-shadow: 0 4px 24px rgba(0,0,0,0.15); max-width: 250px; } .modal h3 { margin: 0 0 8px; } .modal p { margin: 0; color: #666; } .close { width: 32px; height: 32px; border: none; background: #f5f5f5; border-radius: 50%; font-size: 1.2rem; cursor: pointer; }",
"sandboxCSS": "",
"codePrefix": ".close {\n ",
"initialCode": "",
"codeSuffix": "\n}",
"solution": "position: absolute;",
"previewContainer": "preview-area",
"validations": [
{
"type": "property_value",
"value": { "property": "position", "expected": "absolute" },
"message": "Set <kbd>position: absolute</kbd>"
}
]
},
{
"id": "position-4",
"title": "Placing Absolute Elements",
"description": "Combine <kbd>position: absolute</kbd> with offset properties to place elements precisely.<br><br><pre>.close {\n position: absolute;\n top: 8px;\n right: 8px;\n}</pre>",
"task": "Move the close button to the top right corner with <kbd>top: 8px</kbd> and <kbd>right: 8px</kbd>.",
"previewHTML": "<div class=\"modal\"><button class=\"close\">×</button><h3>Modal</h3><p>Content here</p></div>",
"previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 1rem; } .modal { position: relative; padding: 2rem; background: white; border-radius: 12px; box-shadow: 0 4px 24px rgba(0,0,0,0.15); max-width: 250px; } .modal h3 { margin: 0 0 8px; } .modal p { margin: 0; color: #666; } .close { position: absolute; width: 32px; height: 32px; border: none; background: #f5f5f5; border-radius: 50%; font-size: 1.2rem; cursor: pointer; }",
"sandboxCSS": "",
"codePrefix": ".close {\n ",
"initialCode": "",
"codeSuffix": "\n}",
"solution": "top: 8px;\n right: 8px;",
"previewContainer": "preview-area",
"validations": [
{
"type": "property_value",
"value": { "property": "top", "expected": "8px" },
"message": "Set <kbd>top: 8px</kbd>"
},
{
"type": "property_value",
"value": { "property": "right", "expected": "8px" },
"message": "Set <kbd>right: 8px</kbd>"
}
]
}
]
}