feat: add HTML lessons mode and side-by-side comparison UI

- Add HTML mode support with new validation types (element_exists,
  element_count, attribute_value, element_text, parent_child, sibling)
- Create 3 HTML lesson modules: Elements, Forms Basic, Forms Validation
- Implement side-by-side preview comparison (Your Output vs Expected)
- Add merge animation with "Perfect Match!" overlay on validation success
- Render expected output from solutionCode field in lesson JSON
- Update schema to support HTML mode and solutionCode
- Reorder modules: HTML first, then CSS, then Tailwind
- Update tests for new functionality
This commit is contained in:
2025-12-21 22:12:00 +01:00
parent 394490c003
commit 50c4d51523
15 changed files with 1136 additions and 66 deletions

View File

@@ -19,8 +19,8 @@
},
"mode": {
"type": "string",
"enum": ["css", "tailwind"],
"description": "Whether this module teaches CSS or Tailwind"
"enum": ["css", "tailwind", "html"],
"description": "Whether this module teaches CSS, Tailwind, or HTML"
},
"difficulty": {
"type": "string",
@@ -60,7 +60,7 @@
},
"mode": {
"type": "string",
"enum": ["css", "tailwind"],
"enum": ["css", "tailwind", "html"],
"description": "Override module mode for individual lessons"
},
"tailwindConfig": {
@@ -91,6 +91,10 @@
"type": "string",
"description": "Solution code for the lesson, if applicable"
},
"solutionCode": {
"type": "string",
"description": "Expected correct code used to render the expected preview for comparison"
},
"previewContainer": {
"type": "string",
"description": "ID of the container element for the preview"
@@ -105,26 +109,83 @@
"properties": {
"type": {
"type": "string",
"enum": ["contains", "contains_class", "not_contains", "regex", "property_value", "syntax", "custom"],
"enum": [
"contains",
"contains_class",
"contains_pattern",
"not_contains",
"regex",
"property_value",
"syntax",
"custom",
"element_exists",
"element_count",
"attribute_value",
"element_text",
"parent_child",
"sibling"
],
"description": "Type of validation to perform"
},
"value": {
"description": "Value to check against, format depends on validation type",
"description": "Value to check against, format depends on validation type. String for simple checks, object for complex validations.",
"oneOf": [
{
"type": "string"
},
{
"type": "boolean"
},
{
"type": "object",
"required": ["property", "expected"],
"description": "Object format for property_value, element_count, attribute_value, element_text, parent_child validations",
"properties": {
"property": {
"type": "string",
"description": "CSS property name to validate"
"description": "CSS property name (for property_value)"
},
"expected": {
"type": "string",
"description": "Expected value for the CSS property"
"description": "Expected value (for property_value)"
},
"selector": {
"type": "string",
"description": "CSS selector to target element (for HTML validations)"
},
"count": {
"type": "integer",
"description": "Expected count of elements (for element_count)"
},
"min": {
"type": "integer",
"description": "Minimum count of elements (for element_count)"
},
"attr": {
"type": "string",
"description": "Attribute name to check (for attribute_value)"
},
"value": {
"description": "Expected attribute value (for attribute_value). Use true to check existence only."
},
"text": {
"type": "string",
"description": "Expected text content (for element_text)"
},
"parent": {
"type": "string",
"description": "Parent selector (for parent_child)"
},
"child": {
"type": "string",
"description": "Child selector (for parent_child)"
},
"first": {
"type": "string",
"description": "First sibling selector (for sibling)"
},
"then": {
"type": "string",
"description": "Following sibling selector (for sibling)"
}
}
}