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 94cdf368bc
commit b13c8ffea5
15 changed files with 1136 additions and 66 deletions

View File

@@ -181,13 +181,24 @@ function updateEditorForMode(mode) {
const codeInput = elements.codeInput;
const editorLabel = document.querySelector(".editor-label");
if (mode === "tailwind") {
codeInput.placeholder = "Enter Tailwind classes (e.g., bg-blue-500 text-white p-4)";
if (editorLabel) editorLabel.textContent = "Tailwind Classes:";
} else {
codeInput.placeholder = "Enter your CSS code here...";
if (editorLabel) editorLabel.textContent = "CSS Code:";
}
const modeConfig = {
html: {
placeholder: "Write your HTML here (e.g., <p>Hello World</p>)",
label: "HTML Editor"
},
tailwind: {
placeholder: "Enter Tailwind classes (e.g., bg-blue-500 text-white p-4)",
label: "Tailwind Classes"
},
css: {
placeholder: "Enter your CSS code here...",
label: "CSS Editor"
}
};
const config = modeConfig[mode] || modeConfig.css;
codeInput.placeholder = config.placeholder;
if (editorLabel) editorLabel.textContent = config.label;
}
// Configure editor layout based on display type
@@ -266,6 +277,9 @@ function loadCurrentLesson() {
// Focus on the code editor by default
elements.codeInput.focus();
// Render the expected/solution preview for comparison
lessonEngine.renderExpectedPreview();
// Track live changes and update preview when the user pauses typing
setupLivePreview();
}
@@ -379,6 +393,9 @@ function runCode() {
elements.nextBtn.classList.add("success");
elements.taskInstruction.classList.add("success-instruction");
// Show merge animation for side-by-side comparison
lessonEngine.showMatchAnimation();
// Update navigation buttons
updateNavigationButtons();
@@ -388,6 +405,9 @@ function runCode() {
// Reset any success indicators
resetSuccessIndicators();
// Hide merge animation if it was showing
lessonEngine.hideMatchAnimation();
// Show error feedback (with friendly message)
showFeedback(false, validationResult.message || "Not quite there yet! Let's try again.");
}