feat: update localStorage keys for user progress and last module ID, enhance editor layout with validation indicator
This commit is contained in:
49
src/app.js
49
src/app.js
@@ -43,7 +43,7 @@ const lessonEngine = new LessonEngine();
|
|||||||
|
|
||||||
// Load user progress from localStorage
|
// Load user progress from localStorage
|
||||||
function loadUserProgress() {
|
function loadUserProgress() {
|
||||||
const savedProgress = localStorage.getItem("codeCrispiesProgress");
|
const savedProgress = localStorage.getItem("codeCrispies.Progress");
|
||||||
if (savedProgress) {
|
if (savedProgress) {
|
||||||
state.userProgress = JSON.parse(savedProgress);
|
state.userProgress = JSON.parse(savedProgress);
|
||||||
}
|
}
|
||||||
@@ -51,7 +51,7 @@ function loadUserProgress() {
|
|||||||
|
|
||||||
// Save user progress to localStorage
|
// Save user progress to localStorage
|
||||||
function saveUserProgress() {
|
function saveUserProgress() {
|
||||||
localStorage.setItem("codeCrispiesProgress", JSON.stringify(state.userProgress));
|
localStorage.setItem("codeCrispies.Progress", JSON.stringify(state.userProgress));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the module list
|
// Initialize the module list
|
||||||
@@ -61,7 +61,7 @@ async function initializeModules() {
|
|||||||
renderModuleList(elements.moduleList, state.modules, selectModule);
|
renderModuleList(elements.moduleList, state.modules, selectModule);
|
||||||
|
|
||||||
// Select the first module or the last one user was on
|
// Select the first module or the last one user was on
|
||||||
const lastModuleId = localStorage.getItem("lastModuleId");
|
const lastModuleId = localStorage.getItem("codeCrispies.lastModuleId");
|
||||||
if (lastModuleId && state.modules.find((m) => m.id === lastModuleId)) {
|
if (lastModuleId && state.modules.find((m) => m.id === lastModuleId)) {
|
||||||
selectModule(lastModuleId);
|
selectModule(lastModuleId);
|
||||||
} else if (state.modules.length > 0) {
|
} else if (state.modules.length > 0) {
|
||||||
@@ -145,7 +145,7 @@ function selectModule(moduleId) {
|
|||||||
loadCurrentLesson();
|
loadCurrentLesson();
|
||||||
|
|
||||||
// Save the last selected module
|
// Save the last selected module
|
||||||
localStorage.setItem("lastModuleId", moduleId);
|
localStorage.setItem("codeCrispies.lastModuleId", moduleId);
|
||||||
|
|
||||||
// Reset any success indicators
|
// Reset any success indicators
|
||||||
resetSuccessIndicators();
|
resetSuccessIndicators();
|
||||||
@@ -161,29 +161,10 @@ function resetSuccessIndicators() {
|
|||||||
|
|
||||||
// Configure editor layout based on display type
|
// Configure editor layout based on display type
|
||||||
function configureEditorLayout(lesson) {
|
function configureEditorLayout(lesson) {
|
||||||
// Default to block display if not specified
|
// Remove validation indicator if exists
|
||||||
const displayType = lesson.editorDisplayType || "block";
|
const existingIndicator = elements.codeEditor.querySelector(".validation-success-indicator");
|
||||||
|
if (existingIndicator) {
|
||||||
// Reset classes
|
existingIndicator.remove();
|
||||||
elements.codeEditor.classList.remove("inline-editor", "block-editor");
|
|
||||||
elements.editorContent.classList.remove("inline-mode", "block-mode");
|
|
||||||
|
|
||||||
// Apply appropriate layout class
|
|
||||||
if (displayType === "inline") {
|
|
||||||
elements.codeEditor.classList.add("inline-editor");
|
|
||||||
elements.editorContent.classList.add("inline-mode");
|
|
||||||
|
|
||||||
// Add special styling for inline mode
|
|
||||||
elements.codeInput.style.display = "inline-block";
|
|
||||||
elements.codeInput.style.width = lesson.inlineInputWidth || "auto";
|
|
||||||
} else {
|
|
||||||
// Default block mode
|
|
||||||
elements.codeEditor.classList.add("block-editor");
|
|
||||||
elements.editorContent.classList.add("block-mode");
|
|
||||||
|
|
||||||
// Reset styles for block mode
|
|
||||||
elements.codeInput.style.display = "block";
|
|
||||||
elements.codeInput.style.width = "100%";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -248,10 +229,10 @@ function loadCurrentLesson() {
|
|||||||
let previewTimer = null;
|
let previewTimer = null;
|
||||||
function setupLivePreview() {
|
function setupLivePreview() {
|
||||||
// Clear previous event listener if any
|
// Clear previous event listener if any
|
||||||
elements.codeInput.removeEventListener('input', handleUserInput);
|
elements.codeInput.removeEventListener("input", handleUserInput);
|
||||||
|
|
||||||
// Add new event listener
|
// Add new event listener
|
||||||
elements.codeInput.addEventListener('input', handleUserInput);
|
elements.codeInput.addEventListener("input", handleUserInput);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle user input with debounced preview updates
|
// Handle user input with debounced preview updates
|
||||||
@@ -327,6 +308,12 @@ function runCode() {
|
|||||||
updateModuleSelectorButtonProgress();
|
updateModuleSelectorButtonProgress();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add validation indicator to editor
|
||||||
|
const validationIndicator = document.createElement("div");
|
||||||
|
validationIndicator.className = "validation-success-indicator";
|
||||||
|
validationIndicator.innerHTML = "✓";
|
||||||
|
elements.codeEditor.appendChild(validationIndicator);
|
||||||
|
|
||||||
// Show success feedback with visual indicators
|
// Show success feedback with visual indicators
|
||||||
showFeedback(true, validationResult.message || "Great job! Your code works correctly.");
|
showFeedback(true, validationResult.message || "Great job! Your code works correctly.");
|
||||||
|
|
||||||
@@ -457,8 +444,8 @@ function resetProgress() {
|
|||||||
|
|
||||||
document.getElementById("cancel-reset").addEventListener("click", closeModal);
|
document.getElementById("cancel-reset").addEventListener("click", closeModal);
|
||||||
document.getElementById("confirm-reset").addEventListener("click", () => {
|
document.getElementById("confirm-reset").addEventListener("click", () => {
|
||||||
localStorage.removeItem("codeCrispiesProgress");
|
localStorage.removeItem("codeCrispies.Progress");
|
||||||
localStorage.removeItem("lastModuleId");
|
localStorage.removeItem("codeCrispies.lastModuleId");
|
||||||
state.userProgress = {};
|
state.userProgress = {};
|
||||||
closeModal();
|
closeModal();
|
||||||
|
|
||||||
|
|||||||
@@ -16,16 +16,16 @@ import responsiveConfig from "../../lessons/08-responsive.json";
|
|||||||
|
|
||||||
// Module store
|
// Module store
|
||||||
const moduleStore = [
|
const moduleStore = [
|
||||||
basicSelectorsConfig,
|
basicSelectorsConfig
|
||||||
basicsConfig,
|
// basicsConfig,
|
||||||
boxModelConfig,
|
// boxModelConfig,
|
||||||
selectorsConfig,
|
// selectorsConfig,
|
||||||
colorsConfig,
|
// colorsConfig,
|
||||||
typographyConfig,
|
// typographyConfig,
|
||||||
unitVariablesConfig,
|
// unitVariablesConfig,
|
||||||
transitionsAnimationsConfig,
|
// transitionsAnimationsConfig,
|
||||||
layoutConfig,
|
// layoutConfig,
|
||||||
responsiveConfig
|
// responsiveConfig
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -83,15 +83,6 @@ function validateModuleConfig(config) {
|
|||||||
config.lessons.forEach((lesson, index) => {
|
config.lessons.forEach((lesson, index) => {
|
||||||
if (!lesson.title) throw new Error(`Lesson ${index} missing "title"`);
|
if (!lesson.title) throw new Error(`Lesson ${index} missing "title"`);
|
||||||
if (!lesson.previewHTML) throw new Error(`Lesson ${index} missing "previewHTML"`);
|
if (!lesson.previewHTML) throw new Error(`Lesson ${index} missing "previewHTML"`);
|
||||||
|
|
||||||
// Apply defaults for new properties if they don't exist
|
|
||||||
if (lesson.editorDisplayType === undefined) {
|
|
||||||
lesson.editorDisplayType = "block"; // Default to block display
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lesson.editorDisplayType === "inline" && lesson.inlineInputWidth === undefined) {
|
|
||||||
lesson.inlineInputWidth = "auto"; // Default width for inline input
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,36 +111,3 @@ export function addCustomModule(moduleConfig) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Convert a module to include the enhanced schema with editorDisplayType
|
|
||||||
* @param {Object} moduleConfig - The module configuration to convert
|
|
||||||
* @returns {Object} The enhanced module configuration
|
|
||||||
*/
|
|
||||||
export function enhanceModuleSchema(moduleConfig) {
|
|
||||||
if (!moduleConfig || !moduleConfig.lessons) return moduleConfig;
|
|
||||||
|
|
||||||
const enhancedModule = {...moduleConfig};
|
|
||||||
|
|
||||||
enhancedModule.lessons = moduleConfig.lessons.map(lesson => {
|
|
||||||
const enhancedLesson = {...lesson};
|
|
||||||
|
|
||||||
// Apply defaults for new properties if they don't exist
|
|
||||||
if (enhancedLesson.editorDisplayType === undefined) {
|
|
||||||
enhancedLesson.editorDisplayType = "block"; // Default to block display
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enhancedLesson.editorDisplayType === "inline" && enhancedLesson.inlineInputWidth === undefined) {
|
|
||||||
enhancedLesson.inlineInputWidth = "auto"; // Default width for inline input
|
|
||||||
}
|
|
||||||
|
|
||||||
return enhancedLesson;
|
|
||||||
});
|
|
||||||
|
|
||||||
return enhancedModule;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enhance all modules on load to ensure they have the new schema properties
|
|
||||||
moduleStore.forEach((module, index) => {
|
|
||||||
moduleStore[index] = enhanceModuleSchema(module);
|
|
||||||
});
|
|
||||||
30
src/main.css
30
src/main.css
@@ -331,17 +331,27 @@ code {
|
|||||||
color: #d4d4d4;
|
color: #d4d4d4;
|
||||||
border: none;
|
border: none;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-height: 100px;
|
min-height: 100px; /* Ensure minimum height */
|
||||||
font-family: var(--font-code);
|
font-family: var(--font-code);
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 1.5;
|
line-height: 1.5;
|
||||||
padding: var(--spacing-xs) 0;
|
padding: var(--spacing-xs) 0;
|
||||||
outline: none;
|
outline: none;
|
||||||
resize: vertical;
|
overflow: auto; /* Ensure scrolling works */
|
||||||
|
resize: none; /* Disable textarea resize */
|
||||||
caret-color: var(--primary-light);
|
caret-color: var(--primary-light);
|
||||||
transition: background-color 0.2s ease;
|
transition: background-color 0.2s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.code-input.inline-input {
|
||||||
|
display: inline-block;
|
||||||
|
min-height: 30px;
|
||||||
|
height: auto;
|
||||||
|
padding: 2px 4px;
|
||||||
|
margin: 0 4px;
|
||||||
|
border-bottom: 1px dashed #666;
|
||||||
|
}
|
||||||
|
|
||||||
/* Controls */
|
/* Controls */
|
||||||
.controls {
|
.controls {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -414,6 +424,22 @@ code {
|
|||||||
border: 1px solid var(--success-color);
|
border: 1px solid var(--success-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.validation-success-indicator {
|
||||||
|
position: absolute;
|
||||||
|
top: 1rem;
|
||||||
|
right: 7rem;
|
||||||
|
background-color: var(--success-color);
|
||||||
|
color: white;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
font-size: 12px;
|
||||||
|
z-index: 5;
|
||||||
|
}
|
||||||
|
|
||||||
/* Module selector button with progress */
|
/* Module selector button with progress */
|
||||||
#module-selector-btn {
|
#module-selector-btn {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|||||||
Reference in New Issue
Block a user