feat: enhance module list rendering with expandable lessons and active lesson tracking
This commit is contained in:
@@ -7,40 +7,110 @@ let feedbackElement = null;
|
||||
let feedbackTimeout = null;
|
||||
|
||||
/**
|
||||
* Render the module list in the sidebar
|
||||
* Render the module list in the sidebar with expandable lessons
|
||||
* @param {HTMLElement} container - The container element for the module list
|
||||
* @param {Array} modules - The list of modules
|
||||
* @param {Function} onSelectModule - Callback when a module is selected
|
||||
* @param {Function} onSelectLesson - Callback when a lesson is selected
|
||||
*/
|
||||
export function renderModuleList(container, modules, onSelectModule) {
|
||||
export function renderModuleList(container, modules, onSelectModule, onSelectLesson) {
|
||||
// Clear the container
|
||||
container.innerHTML = "<h3>CSS Lessons</h3>";
|
||||
|
||||
// Get user progress from localStorage
|
||||
const progressData = localStorage.getItem("codeCrispies.Progress");
|
||||
let progress = {};
|
||||
if (progressData) {
|
||||
try {
|
||||
progress = JSON.parse(progressData);
|
||||
} catch (e) {
|
||||
console.error("Error parsing progress data:", e);
|
||||
}
|
||||
}
|
||||
|
||||
// Create list items for each module
|
||||
modules.forEach((module) => {
|
||||
const moduleItem = document.createElement("div");
|
||||
moduleItem.classList.add("module-list-item");
|
||||
moduleItem.dataset.moduleId = module.id;
|
||||
moduleItem.textContent = module.title;
|
||||
// Create module container
|
||||
const moduleContainer = document.createElement("div");
|
||||
moduleContainer.classList.add("module-container");
|
||||
|
||||
// Get user progress from localStorage to mark completed lessons
|
||||
const progressData = localStorage.getItem("codeCrispies.Progress");
|
||||
if (progressData) {
|
||||
try {
|
||||
const progress = JSON.parse(progressData);
|
||||
if (progress[module.id] && progress[module.id].completed.length === module.lessons.length) {
|
||||
moduleItem.classList.add("completed");
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Error parsing progress data:", e);
|
||||
}
|
||||
// Create module header item (clickable to expand/collapse)
|
||||
const moduleHeader = document.createElement("div");
|
||||
moduleHeader.classList.add("module-list-item", "module-header");
|
||||
moduleHeader.dataset.moduleId = module.id;
|
||||
|
||||
// Create module title with expand/collapse indicator
|
||||
const moduleTitle = document.createElement("span");
|
||||
moduleTitle.classList.add("module-title");
|
||||
moduleTitle.textContent = module.title;
|
||||
|
||||
// Create expand/collapse icon
|
||||
const expandIcon = document.createElement("span");
|
||||
expandIcon.classList.add("expand-icon");
|
||||
expandIcon.innerHTML = "▶"; // Right-pointing triangle
|
||||
|
||||
moduleHeader.appendChild(expandIcon);
|
||||
moduleHeader.appendChild(moduleTitle);
|
||||
|
||||
// Check if the module is completed
|
||||
if (progress[module.id] && progress[module.id].completed.length === module.lessons.length) {
|
||||
moduleHeader.classList.add("completed");
|
||||
}
|
||||
|
||||
moduleItem.addEventListener("click", () => {
|
||||
onSelectModule(module.id);
|
||||
// Lessons container (initially hidden)
|
||||
const lessonsContainer = document.createElement("div");
|
||||
lessonsContainer.classList.add("lessons-container");
|
||||
lessonsContainer.style.display = "none"; // Initially collapsed
|
||||
|
||||
// Create list items for each lesson in this module
|
||||
module.lessons.forEach((lesson, index) => {
|
||||
const lessonItem = document.createElement("div");
|
||||
lessonItem.classList.add("lesson-list-item");
|
||||
lessonItem.dataset.moduleId = module.id;
|
||||
lessonItem.dataset.lessonIndex = index;
|
||||
lessonItem.textContent = lesson.title || `Lesson ${index + 1}`;
|
||||
|
||||
// Mark lesson as completed if in progress data
|
||||
if (progress[module.id] && progress[module.id].completed.includes(index)) {
|
||||
lessonItem.classList.add("completed");
|
||||
}
|
||||
|
||||
// Mark lesson as current if it's the current lesson
|
||||
if (progress[module.id] && progress[module.id].current === index) {
|
||||
lessonItem.classList.add("current");
|
||||
}
|
||||
|
||||
// Add click event to select lesson
|
||||
lessonItem.addEventListener("click", () => {
|
||||
// Update UI to show this lesson is selected
|
||||
document.querySelectorAll(".lesson-list-item").forEach((item) => {
|
||||
item.classList.remove("active");
|
||||
});
|
||||
lessonItem.classList.add("active");
|
||||
|
||||
// Call the onSelectLesson callback
|
||||
onSelectLesson(module.id, index);
|
||||
});
|
||||
|
||||
lessonsContainer.appendChild(lessonItem);
|
||||
});
|
||||
|
||||
container.appendChild(moduleItem);
|
||||
// Toggle expand/collapse when clicking on module header
|
||||
moduleHeader.addEventListener("click", () => {
|
||||
// Toggle visibility of lessons container
|
||||
const isExpanded = lessonsContainer.style.display !== "none";
|
||||
lessonsContainer.style.display = isExpanded ? "none" : "block";
|
||||
|
||||
// Update expand/collapse icon
|
||||
expandIcon.innerHTML = isExpanded ? "▶" : "▼";
|
||||
});
|
||||
|
||||
// Add module header and lessons container to module container
|
||||
moduleContainer.appendChild(moduleHeader);
|
||||
moduleContainer.appendChild(lessonsContainer);
|
||||
|
||||
// Add the complete module container to the sidebar
|
||||
container.appendChild(moduleContainer);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -132,3 +202,41 @@ export function clearFeedback() {
|
||||
}
|
||||
feedbackElement = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the active lesson in the sidebar
|
||||
* @param {string} moduleId - The ID of the module
|
||||
* @param {number} lessonIndex - The index of the lesson
|
||||
*/
|
||||
export function updateActiveLessonInSidebar(moduleId, lessonIndex) {
|
||||
// Remove active class from all lessons
|
||||
document.querySelectorAll(".lesson-list-item").forEach((item) => {
|
||||
item.classList.remove("active");
|
||||
});
|
||||
|
||||
// Find and activate the current lesson
|
||||
const selector = `.lesson-list-item[data-module-id="${moduleId}"][data-lesson-index="${lessonIndex}"]`;
|
||||
const currentLessonItem = document.querySelector(selector);
|
||||
|
||||
if (currentLessonItem) {
|
||||
currentLessonItem.classList.add("active");
|
||||
|
||||
// Make sure parent module is expanded
|
||||
const parentLessonsContainer = currentLessonItem.parentElement;
|
||||
if (parentLessonsContainer && parentLessonsContainer.classList.contains("lessons-container")) {
|
||||
parentLessonsContainer.style.display = "block";
|
||||
|
||||
// Update expand icon
|
||||
const moduleHeader = parentLessonsContainer.previousElementSibling;
|
||||
if (moduleHeader) {
|
||||
const expandIcon = moduleHeader.querySelector(".expand-icon");
|
||||
if (expandIcon) {
|
||||
expandIcon.innerHTML = "▼"; // Down arrow when expanded
|
||||
}
|
||||
}
|
||||
|
||||
// Scroll to ensure the item is visible
|
||||
currentLessonItem.scrollIntoView({ behavior: "smooth", block: "nearest" });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user