feat: add landing pages and section navigation

- Add home landing page with section cards (CSS, HTML, Tailwind)
- Add section landing pages with module grid and progress tracking
- Implement extended URL routing for pages, sections, and lessons
- Create sections.js configuration for module categorization
- Exclude welcome/goodbye modules from progress stats
- Add main navigation links in header (desktop only)
- Update logo click to navigate to home landing

Routes:
- # → Home landing
- #css, #html, #tailwind → Section landing pages
- #module/index → Lesson (unchanged)

🤖 Generated with [Claude Code](https://claude.com/claude-code)
This commit is contained in:
2026-01-14 23:15:34 +01:00
parent 5083032735
commit 165ed3d73f
13 changed files with 679 additions and 42 deletions

75
src/config/sections.js Normal file
View File

@@ -0,0 +1,75 @@
/**
* Section definitions for Code Crispies
* Sections group related modules (CSS, HTML, Tailwind)
*/
export const sections = {
css: {
id: "css",
title: "CSS",
description: "Styling, layout, and animations",
color: "#264de4",
order: 1
},
html: {
id: "html",
title: "HTML",
description: "Semantic markup and native elements",
color: "#e34c26",
order: 2
},
tailwind: {
id: "tailwind",
title: "Tailwind CSS",
description: "Utility-first CSS framework",
color: "#06b6d4",
order: 3
}
};
/**
* Get section by ID
* @param {string} sectionId
* @returns {object|null}
*/
export function getSection(sectionId) {
return sections[sectionId] || null;
}
/**
* Get all sections sorted by order
* @returns {object[]}
*/
export function getSectionList() {
return Object.values(sections).sort((a, b) => a.order - b.order);
}
/**
* Infer section from module mode
* @param {object} module
* @returns {string}
*/
export function getModuleSection(module) {
// Explicit section takes precedence
if (module.section) return module.section;
// Infer from mode
const mode = module.mode || "css";
if (mode === "html") return "html";
if (mode === "tailwind") return "tailwind";
return "css";
}
/**
* Filter modules by section
* @param {object[]} modules
* @param {string} sectionId
* @returns {object[]}
*/
export function getModulesBySection(modules, sectionId) {
return modules.filter((m) => {
// Skip excluded modules (welcome, goodbye)
if (m.excludeFromProgress) return false;
return getModuleSection(m) === sectionId;
});
}