feat: add landing footer with donation support, change license to Unlicense

- Add extended landing footer with module links grouped by section
- Integrate Liberapay donation widget with Umami tracking
- Add support section to help dialog and goodbye lesson
- Change license from MIT to Unlicense (public domain)
- Disable Tailwind section (not yet activated)
- Update German CTA copy
- Update all 6 language translations for license text

🤖 Generated with [Claude Code](https://claude.com/claude-code)
This commit is contained in:
2026-01-16 03:33:41 +01:00
parent 1f7f7bb027
commit 8ad0d273a3
7 changed files with 323 additions and 14 deletions

View File

@@ -155,6 +155,7 @@ const elements = {
sidebarBackdrop: document.getElementById("sidebar-backdrop"),
closeSidebar: document.getElementById("close-sidebar"),
moduleList: document.getElementById("module-list"),
footerLessonLinks: document.getElementById("footer-lesson-links"),
progressFill: document.getElementById("progress-fill"),
progressText: document.getElementById("progress-text"),
resetBtn: document.getElementById("reset-btn"),
@@ -1991,6 +1992,40 @@ function showLandingPage() {
// Update section progress on landing page
updateLandingProgress();
// Render footer lesson links
renderFooterLessonLinks();
}
/**
* Render module links in the landing page footer, grouped by section
*/
function renderFooterLessonLinks() {
if (!elements.footerLessonLinks) return;
const modules = lessonEngine.modules || [];
const sectionGroups = { css: [], html: [] };
modules.forEach((module) => {
if (module.excludeFromProgress) return;
const sectionId = getModuleSection(module);
if (sectionId && sectionGroups[sectionId]) {
sectionGroups[sectionId].push(module);
}
});
let html = "";
Object.entries(sectionGroups).forEach(([sectionId, sectionModules]) => {
if (sectionModules.length === 0) return;
const sectionName = sectionId.toUpperCase();
html += `<div class="footer-section-group"><strong><a href="#${sectionId}">${sectionName}</a></strong>`;
sectionModules.forEach((module) => {
html += `<a href="#${module.id}/0">${module.title}</a>`;
});
html += "</div>";
});
elements.footerLessonLinks.innerHTML = html;
}
/**
@@ -2387,6 +2422,8 @@ function init() {
track("landing_cta", { href: target.getAttribute("href") });
} else if (target.classList.contains("section-card")) {
track("landing_section", { section: target.dataset.section });
} else if (target.closest(".footer-support")) {
track("support_click", { location: "landing" });
}
});
}