diff --git a/lessons/99-goodbye.json b/lessons/99-goodbye.json
index 8e0cf46..56cda1b 100644
--- a/lessons/99-goodbye.json
+++ b/lessons/99-goodbye.json
@@ -10,7 +10,7 @@
{
"id": "next-steps",
"title": "Keep Going!",
- "description": "Great progress! You're building real web development skills.
Continue learning: • MDN Web Docs - The definitive reference • CSS-Tricks - Practical techniques
Practice ideas: • Build your portfolio site • Recreate a website you like • Try the Playground to experiment freely
Contribute: Code Crispies is open source. Add lessons, fix bugs, or translate!",
+ "description": "Great progress! You're building real web development skills.
Continue learning: • MDN Web Docs - The definitive reference • CSS-Tricks - Practical techniques
Practice ideas: • Build your portfolio site • Recreate a website you like • Try the Playground to experiment freely
Contribute: Code Crispies is open source. Add lessons, fix bugs, or translate!",
"task": "Type Thank you!",
"previewHTML": "",
"previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 20px; text-align: center; font-size: 1.5rem; color: #6366f1; }",
diff --git a/public/dice.svg b/public/dice.svg
new file mode 100644
index 0000000..55cd6af
--- /dev/null
+++ b/public/dice.svg
@@ -0,0 +1,8 @@
+
diff --git a/src/app.js b/src/app.js
index 91cc3ad..cda038e 100644
--- a/src/app.js
+++ b/src/app.js
@@ -27,7 +27,8 @@ const state = {
skipResetCodeConfirmation: false
},
showExpected: false,
- animationTimeout: null
+ animationTimeout: null,
+ lastPlaygroundTemplate: null
};
// Track CodeMirror views for cleanup
@@ -579,9 +580,9 @@ function loadCurrentLesson() {
lesson
);
- // Set user code in CodeMirror
+ // Set user code in CodeMirror (clear history to prevent undo/redo across lessons)
if (codeEditor) {
- codeEditor.setValue(engineState.userCode);
+ codeEditor.setValueAndClearHistory(engineState.userCode);
}
// Update Run button text based on completion status
@@ -731,9 +732,17 @@ function resetCode() {
// Reset editor to initial code for current lesson
lessonEngine.reset();
const engineState = lessonEngine.getCurrentState();
+ const isPlayground = engineState.lesson?.mode === "playground";
track("reset_code", { module: engineState.module?.id, lesson: engineState.lessonIndex });
+
if (codeEditor && engineState.lesson) {
- codeEditor.setValue(engineState.lesson.initialCode || "");
+ // In playground mode, restore the last template if available
+ if (isPlayground && state.lastPlaygroundTemplate) {
+ codeEditor.setValue(state.lastPlaygroundTemplate.code);
+ lessonEngine.applyUserCode(state.lastPlaygroundTemplate.code, true);
+ } else {
+ codeEditor.setValue(engineState.lesson.initialCode || "");
+ }
}
// Clear hints and success indicators
clearHint();
@@ -755,6 +764,7 @@ function loadRandomTemplate() {
const template = getRandomTemplate();
if (codeEditor && template) {
track("playground_template", { template: template.name });
+ state.lastPlaygroundTemplate = template;
codeEditor.setValue(template.code);
// Apply the code to the preview
lessonEngine.applyUserCode(template.code, true);
diff --git a/src/impl/CodeEditor.js b/src/impl/CodeEditor.js
index c39f089..6680fe2 100644
--- a/src/impl/CodeEditor.js
+++ b/src/impl/CodeEditor.js
@@ -183,7 +183,7 @@ export class CodeEditor {
}
/**
- * Set editor value
+ * Set editor value (preserves history)
*/
setValue(value) {
if (!this.view) return;
@@ -197,6 +197,13 @@ export class CodeEditor {
});
}
+ /**
+ * Set editor value and clear history (for lesson switching)
+ */
+ setValueAndClearHistory(value) {
+ this.init(value);
+ }
+
/**
* Set editor mode (html or css)
*/
diff --git a/src/index.html b/src/index.html
index 8677d66..146342a 100644
--- a/src/index.html
+++ b/src/index.html
@@ -245,7 +245,7 @@
>
⟲
-
+
diff --git a/src/main.css b/src/main.css
index 83111ec..8db786f 100644
--- a/src/main.css
+++ b/src/main.css
@@ -1154,6 +1154,9 @@ button.lesson-list-item {
}
.btn-icon {
+ display: flex;
+ align-items: center;
+ justify-content: center;
padding: 4px 8px;
font-size: 1rem;
min-width: 32px;
@@ -1168,6 +1171,13 @@ button.lesson-list-item {
border-color: var(--primary-color);
}
+.btn-icon img {
+ width: 1rem;
+ height: 1rem;
+ margin: 0;
+ display: block;
+}
+
.editor-tools {
display: flex;
gap: 4px;