feat: add undo/redo/reset editor tools with keyboard shortcuts
- Add history extension to CodeMirror for undo/redo support - Ctrl+Z for undo, Ctrl+Shift+Z for redo now work - Add toolbar buttons: ↶ Undo, ↷ Redo, ⟲ Reset - Reset button restores editor to initial lesson code - Add .btn-icon and .editor-tools CSS styles
This commit is contained in:
25
src/app.js
25
src/app.js
@@ -23,6 +23,9 @@ const elements = {
|
||||
taskInstruction: document.getElementById("task-instruction"),
|
||||
codeInput: document.getElementById("code-input"),
|
||||
runBtn: document.getElementById("run-btn"),
|
||||
undoBtn: document.getElementById("undo-btn"),
|
||||
redoBtn: document.getElementById("redo-btn"),
|
||||
resetCodeBtn: document.getElementById("reset-code-btn"),
|
||||
hintArea: document.getElementById("hint-area"),
|
||||
validationIndicators: document.querySelector(".validation-indicators-container"),
|
||||
editorContent: document.querySelector(".editor-content"),
|
||||
@@ -376,6 +379,19 @@ function prevLesson() {
|
||||
|
||||
// ================= CODE EXECUTION =================
|
||||
|
||||
function resetCode() {
|
||||
// Reset editor to initial code for current lesson
|
||||
lessonEngine.reset();
|
||||
const engineState = lessonEngine.getCurrentState();
|
||||
if (codeEditor && engineState.lesson) {
|
||||
codeEditor.setValue(engineState.lesson.initialCode || "");
|
||||
}
|
||||
// Clear hints and success indicators
|
||||
clearHint();
|
||||
resetSuccessIndicators();
|
||||
elements.validationIndicators.innerHTML = "";
|
||||
}
|
||||
|
||||
function runCode() {
|
||||
const userCode = codeEditor ? codeEditor.getValue() : "";
|
||||
|
||||
@@ -561,6 +577,15 @@ function init() {
|
||||
elements.nextBtn.addEventListener("click", nextLesson);
|
||||
elements.runBtn.addEventListener("click", runCode);
|
||||
|
||||
// Editor tools
|
||||
elements.undoBtn.addEventListener("click", () => {
|
||||
if (codeEditor) codeEditor.undo();
|
||||
});
|
||||
elements.redoBtn.addEventListener("click", () => {
|
||||
if (codeEditor) codeEditor.redo();
|
||||
});
|
||||
elements.resetCodeBtn.addEventListener("click", resetCode);
|
||||
|
||||
// Modals
|
||||
elements.helpBtn.addEventListener("click", showHelp);
|
||||
elements.modalClose.addEventListener("click", closeModal);
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
*/
|
||||
import { EditorState, Prec } from "@codemirror/state";
|
||||
import { EditorView, keymap, placeholder } from "@codemirror/view";
|
||||
import { defaultKeymap, indentMore, indentLess } from "@codemirror/commands";
|
||||
import { defaultKeymap, historyKeymap, indentMore, indentLess, undo, redo } from "@codemirror/commands";
|
||||
import { history } from "@codemirror/commands";
|
||||
import { oneDark } from "@codemirror/theme-one-dark";
|
||||
import { html } from "@codemirror/lang-html";
|
||||
import { css } from "@codemirror/lang-css";
|
||||
@@ -49,6 +50,8 @@ export class CodeEditor {
|
||||
langExtension,
|
||||
oneDark,
|
||||
editorTheme,
|
||||
// History for undo/redo
|
||||
history(),
|
||||
// Emmet abbreviation tracking
|
||||
abbreviationTracker(),
|
||||
// High priority keymap for Emmet
|
||||
@@ -58,8 +61,9 @@ export class CodeEditor {
|
||||
run: expandAbbreviation
|
||||
}
|
||||
])),
|
||||
// Standard keymaps
|
||||
// Standard keymaps including history (Ctrl+Z, Ctrl+Shift+Z)
|
||||
keymap.of([
|
||||
...historyKeymap,
|
||||
{ key: "Tab", run: indentMore },
|
||||
{ key: "Shift-Tab", run: indentLess },
|
||||
...defaultKeymap
|
||||
@@ -138,6 +142,24 @@ export class CodeEditor {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Undo last change
|
||||
*/
|
||||
undo() {
|
||||
if (this.view) {
|
||||
undo(this.view);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Redo last undone change
|
||||
*/
|
||||
redo() {
|
||||
if (this.view) {
|
||||
redo(this.view);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the editor
|
||||
*/
|
||||
|
||||
@@ -42,6 +42,11 @@
|
||||
<div class="editor-header">
|
||||
<label for="code-input" class="editor-label">CSS Editor</label>
|
||||
<div class="editor-actions">
|
||||
<div class="editor-tools">
|
||||
<button id="undo-btn" class="btn btn-icon" title="Undo (Ctrl+Z)">↶</button>
|
||||
<button id="redo-btn" class="btn btn-icon" title="Redo (Ctrl+Shift+Z)">↷</button>
|
||||
<button id="reset-code-btn" class="btn btn-icon" title="Reset to initial code">⟲</button>
|
||||
</div>
|
||||
<div class="validation-indicators-container"></div>
|
||||
<button id="run-btn" class="btn btn-run">
|
||||
<img src="./gear.svg" alt="" />Run
|
||||
|
||||
21
src/main.css
21
src/main.css
@@ -712,6 +712,27 @@ code, kbd {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.btn-icon {
|
||||
padding: 4px 8px;
|
||||
font-size: 1rem;
|
||||
min-width: 32px;
|
||||
background: transparent;
|
||||
color: var(--light-text);
|
||||
border: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
.btn-icon:hover {
|
||||
background: var(--bg-color);
|
||||
color: var(--text-color);
|
||||
border-color: var(--primary-color);
|
||||
}
|
||||
|
||||
.editor-tools {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
margin-right: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.btn-ghost {
|
||||
background: transparent;
|
||||
color: var(--light-text);
|
||||
|
||||
Reference in New Issue
Block a user