Skip to content

Commit 1368f1c

Browse files
committed
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)
1 parent f1496e7 commit 1368f1c

7 files changed

Lines changed: 323 additions & 14 deletions

File tree

LICENSE

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
This is free and unencumbered software released into the public domain.
2+
3+
Anyone is free to copy, modify, publish, use, compile, sell, or
4+
distribute this software, either in source code form or as a compiled
5+
binary, for any purpose, commercial or non-commercial, and by any
6+
means.
7+
8+
In jurisdictions that recognize copyright laws, the author or authors
9+
of this software dedicate any and all copyright interest in the
10+
software to the public domain. We make this dedication for the benefit
11+
of the public at large and to the detriment of our heirs and
12+
successors. We intend this dedication to be an overt act of
13+
relinquishment in perpetuity of all present and future rights to this
14+
software under copyright law.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22+
OTHER DEALINGS IN THE SOFTWARE.
23+
24+
For more information, please refer to <https://unlicense.org>

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
![Code Crispies Logo](./public/android-chrome-192x192.png)
22
# Code Crispies
33

4-
An interactive platform for learning CSS and Tailwind CSS through practical challenges.
4+
An interactive platform for learning HTML, CSS, and Tailwind CSS through practical challenges.
55

66
## 📚 Overview
77

8-
Code Crispies is a web-based learning platform designed to help users master CSS and Tailwind CSS through hands-on exercises. The application presents a series of progressive challenges organized into themed modules, allowing learners to build their skills step by step while receiving immediate feedback.
8+
Code Crispies is a web-based learning platform designed to help users master HTML, CSS, and Tailwind CSS through hands-on exercises. The application presents a series of progressive challenges organized into themed modules, allowing learners to build their skills step by step while receiving immediate feedback.
99

1010
### Key Features
1111

12-
- **Interactive Lessons**: Learn CSS and Tailwind concepts through practical, hands-on challenges
13-
- **Dual Mode Support**: Switch between CSS and Tailwind CSS learning modes
12+
- **Interactive Lessons**: Learn HTML, CSS, and Tailwind concepts through practical, hands-on challenges
13+
- **Multiple Learning Paths**: CSS fundamentals, HTML semantics, and Tailwind CSS utilities
1414
- **Progressive Difficulty**: Modules are structured to build skills gradually from basic to advanced
1515
- **Real-Time Feedback**: Get immediate validation on your code solutions with comprehensive feedback
1616
- **Progress Tracking**: Your learning progress is automatically saved in the browser
@@ -256,4 +256,4 @@ When adding new lessons:
256256

257257
## 📄 License
258258

259-
Copyright (c) 2026 Michael Czechowski. Licensed under the [./LICENSE](WTFPL).
259+
This project is released into the public domain under the [Unlicense](./LICENSE). You are free to copy, modify, publish, use, compile, sell, or distribute this software for any purpose.

lessons/99-goodbye.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
{
1111
"id": "next-steps",
1212
"title": "Keep Going!",
13-
"description": "<strong>Great progress!</strong> You're building real web development skills.<br><br><strong>Continue learning:</strong><br>• <a href=\"https://developer.mozilla.org\" target=\"_blank\">MDN Web Docs</a> - The definitive reference<br>• <a href=\"https://css-tricks.com\" target=\"_blank\">CSS-Tricks</a> - Practical techniques<br><br><strong>Practice ideas:</strong><br>• Build your portfolio site<br>• Recreate a website you like<br>• Try the <a href=\"#playground/0\">Playground</a> to experiment freely<br><br><strong>Contribute:</strong> Code Crispies is <a href=\"https://git.librete.ch/libretech/code-crispies\" target=\"_blank\">open source</a>. Add lessons, fix bugs, or translate!",
13+
"description": "<strong>Great progress!</strong> You're building real web development skills.<br><br><strong>Continue learning:</strong><br>• <a href=\"https://developer.mozilla.org\" target=\"_blank\">MDN Web Docs</a> - The definitive reference<br>• <a href=\"https://css-tricks.com\" target=\"_blank\">CSS-Tricks</a> - Practical techniques<br><br><strong>Practice ideas:</strong><br>• Build your portfolio site<br>• Recreate a website you like<br>• Try the <a href=\"#playground/0\">Playground</a> to experiment freely<br><br><strong>Contribute:</strong> Code Crispies is <a href=\"https://git.librete.ch/libretech/code-crispies\" target=\"_blank\">open source</a>. Add lessons, fix bugs, or translate!<br><br><strong>Support:</strong> Help keep it free and open source!<br><a href=\"https://liberapay.com/libretech/donate\" target=\"_blank\" onclick=\"typeof umami !== 'undefined' && umami.track('support_click', {location: 'goodbye'})\"><img alt=\"Donate using Liberapay\" src=\"https://liberapay.com/assets/widgets/donate.svg\" style=\"margin-top: 8px;\"></a>",
1414
"task": "Type <code>Thank you!</code>",
1515
"previewHTML": "",
1616
"previewBaseCSS": "body { font-family: system-ui, sans-serif; padding: 20px; text-align: center; font-size: 1.5rem; color: #6366f1; }",

src/app.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ const elements = {
155155
sidebarBackdrop: document.getElementById("sidebar-backdrop"),
156156
closeSidebar: document.getElementById("close-sidebar"),
157157
moduleList: document.getElementById("module-list"),
158+
footerLessonLinks: document.getElementById("footer-lesson-links"),
158159
progressFill: document.getElementById("progress-fill"),
159160
progressText: document.getElementById("progress-text"),
160161
resetBtn: document.getElementById("reset-btn"),
@@ -1991,6 +1992,40 @@ function showLandingPage() {
19911992

19921993
// Update section progress on landing page
19931994
updateLandingProgress();
1995+
1996+
// Render footer lesson links
1997+
renderFooterLessonLinks();
1998+
}
1999+
2000+
/**
2001+
* Render module links in the landing page footer, grouped by section
2002+
*/
2003+
function renderFooterLessonLinks() {
2004+
if (!elements.footerLessonLinks) return;
2005+
2006+
const modules = lessonEngine.modules || [];
2007+
const sectionGroups = { css: [], html: [] };
2008+
2009+
modules.forEach((module) => {
2010+
if (module.excludeFromProgress) return;
2011+
const sectionId = getModuleSection(module);
2012+
if (sectionId && sectionGroups[sectionId]) {
2013+
sectionGroups[sectionId].push(module);
2014+
}
2015+
});
2016+
2017+
let html = "";
2018+
Object.entries(sectionGroups).forEach(([sectionId, sectionModules]) => {
2019+
if (sectionModules.length === 0) return;
2020+
const sectionName = sectionId.toUpperCase();
2021+
html += `<div class="footer-section-group"><strong><a href="#${sectionId}">${sectionName}</a></strong>`;
2022+
sectionModules.forEach((module) => {
2023+
html += `<a href="#${module.id}/0">${module.title}</a>`;
2024+
});
2025+
html += "</div>";
2026+
});
2027+
2028+
elements.footerLessonLinks.innerHTML = html;
19942029
}
19952030

19962031
/**
@@ -2387,6 +2422,8 @@ function init() {
23872422
track("landing_cta", { href: target.getAttribute("href") });
23882423
} else if (target.classList.contains("section-card")) {
23892424
track("landing_section", { section: target.dataset.section });
2425+
} else if (target.closest(".footer-support")) {
2426+
track("support_click", { location: "landing" });
23902427
}
23912428
});
23922429
}

src/i18n.js

Lines changed: 84 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,20 @@ const translations = {
134134
landingTailwindDesc: "Utility-first CSS framework",
135135
landingCtaTitle: "Start Learning Today",
136136
landingCtaSub: "Free and open source. No account required. Progress saved locally.",
137-
landingCtaButton: "Begin Your Journey"
137+
landingCtaButton: "Begin Your Journey",
138+
139+
// Footer
140+
footerModules: "Modules",
141+
footerResources: "Resources",
142+
footerPlayground: "Playground",
143+
footerAbout: "About",
144+
footerSupport: "Support",
145+
footerSupportText: "Help keep Code Crispies free and open source.",
146+
footerLicense: "Released into the public domain.",
147+
148+
// Help Dialog Support
149+
supportTitle: "Support the Project",
150+
supportText: "Help keep Code Crispies free and open source."
138151
},
139152

140153
de: {
@@ -271,7 +284,20 @@ const translations = {
271284
landingTailwindDesc: "Utility-first CSS-Framework",
272285
landingCtaTitle: "Heute noch anfangen",
273286
landingCtaSub: "Kostenlos und Open Source. Kein Konto erforderlich. Fortschritt wird lokal gespeichert.",
274-
landingCtaButton: "Starte deine Reise"
287+
landingCtaButton: "Jetzt erste Schritte machen",
288+
289+
// Footer
290+
footerModules: "Module",
291+
footerResources: "Ressourcen",
292+
footerPlayground: "Playground",
293+
footerAbout: "Über uns",
294+
footerSupport: "Unterstützen",
295+
footerSupportText: "Hilf mit, Code Crispies kostenlos und Open Source zu halten.",
296+
footerLicense: "Gemeinfrei (Public Domain).",
297+
298+
// Help Dialog Support
299+
supportTitle: "Projekt unterstützen",
300+
supportText: "Hilf mit, Code Crispies kostenlos und Open Source zu halten."
275301
},
276302

277303
// Polish
@@ -408,7 +434,20 @@ const translations = {
408434
landingTailwindDesc: "Framework CSS oparty na klasach utility",
409435
landingCtaTitle: "Zacznij naukę już dziś",
410436
landingCtaSub: "Darmowe i open source. Bez konta. Postęp zapisywany lokalnie.",
411-
landingCtaButton: "Rozpocznij swoją podróż"
437+
landingCtaButton: "Rozpocznij swoją podróż",
438+
439+
// Footer
440+
footerModules: "Moduły",
441+
footerResources: "Zasoby",
442+
footerPlayground: "Plac zabaw",
443+
footerAbout: "O nas",
444+
footerSupport: "Wsparcie",
445+
footerSupportText: "Pomóż utrzymać Code Crispies darmowym i open source.",
446+
footerLicense: "Udostępnione jako domena publiczna.",
447+
448+
// Help Dialog Support
449+
supportTitle: "Wesprzyj projekt",
450+
supportText: "Pomóż utrzymać Code Crispies darmowym i open source."
412451
},
413452

414453
// Spanish
@@ -547,7 +586,20 @@ const translations = {
547586
landingTailwindDesc: "Framework CSS basado en utilidades",
548587
landingCtaTitle: "Empieza a aprender hoy",
549588
landingCtaSub: "Gratis y de código abierto. Sin cuenta requerida. Progreso guardado localmente.",
550-
landingCtaButton: "Comienza tu viaje"
589+
landingCtaButton: "Comienza tu viaje",
590+
591+
// Footer
592+
footerModules: "Módulos",
593+
footerResources: "Recursos",
594+
footerPlayground: "Zona de pruebas",
595+
footerAbout: "Acerca de",
596+
footerSupport: "Apoyar",
597+
footerSupportText: "Ayuda a mantener Code Crispies gratis y de código abierto.",
598+
footerLicense: "Liberado al dominio público.",
599+
600+
// Help Dialog Support
601+
supportTitle: "Apoyar el proyecto",
602+
supportText: "Ayuda a mantener Code Crispies gratis y de código abierto."
551603
},
552604

553605
// Arabic
@@ -681,7 +733,20 @@ const translations = {
681733
landingTailwindDesc: "إطار CSS قائم على الأدوات",
682734
landingCtaTitle: "ابدأ التعلم اليوم",
683735
landingCtaSub: "مجاني ومفتوح المصدر. لا حاجة لحساب. يُحفظ التقدم محليًا.",
684-
landingCtaButton: "ابدأ رحلتك"
736+
landingCtaButton: "ابدأ رحلتك",
737+
738+
// Footer
739+
footerModules: "الوحدات",
740+
footerResources: "الموارد",
741+
footerPlayground: "ساحة التجربة",
742+
footerAbout: "حول",
743+
footerSupport: "الدعم",
744+
footerSupportText: "ساعد في إبقاء Code Crispies مجانيًا ومفتوح المصدر.",
745+
footerLicense: "مُطلق للملكية العامة.",
746+
747+
// Help Dialog Support
748+
supportTitle: "ادعم المشروع",
749+
supportText: "ساعد في إبقاء Code Crispies مجانيًا ومفتوح المصدر."
685750
},
686751

687752
// Ukrainian
@@ -817,7 +882,20 @@ const translations = {
817882
landingTailwindDesc: "CSS-фреймворк на основі утиліт",
818883
landingCtaTitle: "Почни вчитися сьогодні",
819884
landingCtaSub: "Безкоштовно та з відкритим кодом. Без реєстрації. Прогрес зберігається локально.",
820-
landingCtaButton: "Розпочни свою подорож"
885+
landingCtaButton: "Розпочни свою подорож",
886+
887+
// Footer
888+
footerModules: "Модулі",
889+
footerResources: "Ресурси",
890+
footerPlayground: "Пісочниця",
891+
footerAbout: "Про нас",
892+
footerSupport: "Підтримка",
893+
footerSupportText: "Допоможи зберегти Code Crispies безкоштовним та з відкритим кодом.",
894+
footerLicense: "Передано у суспільне надбання.",
895+
896+
// Help Dialog Support
897+
supportTitle: "Підтримати проєкт",
898+
supportText: "Допоможи зберегти Code Crispies безкоштовним та з відкритим кодом."
821899
}
822900
};
823901

src/index.html

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ <h1><span class="code-text">CODE</span><span class="crispies-text">CRISPIES</spa
7474
<nav class="main-nav" id="main-nav" aria-label="Main sections">
7575
<a href="#css" class="nav-link" data-section="css">CSS</a>
7676
<a href="#html" class="nav-link" data-section="html">HTML</a>
77-
<a href="#tailwind" class="nav-link" data-section="tailwind">Tailwind</a>
77+
<!-- Tailwind disabled until lessons are ready -->
78+
<!-- <a href="#tailwind" class="nav-link" data-section="tailwind">Tailwind</a> -->
7879
<a href="#reference/css" class="nav-link nav-link-ref" data-section="reference">Reference</a>
7980
</nav>
8081
<button id="help-btn" class="help-toggle" data-i18n-aria-label="help" aria-label="Help">?</button>
@@ -150,12 +151,15 @@ <h3>HTML</h3>
150151
<p data-i18n="landingHtmlDesc">Semantic markup and native elements</p>
151152
<span class="section-card-progress" id="html-progress"></span>
152153
</a>
154+
<!-- Tailwind disabled until lessons are ready -->
155+
<!--
153156
<a href="#tailwind" class="section-card" data-section="tailwind">
154157
<div class="section-card-icon" style="background: #06b6d4">TW</div>
155158
<h3>Tailwind CSS</h3>
156159
<p data-i18n="landingTailwindDesc">Utility-first CSS framework</p>
157160
<span class="section-card-progress" id="tailwind-progress"></span>
158161
</a>
162+
-->
159163
</div>
160164
</section>
161165

@@ -164,6 +168,39 @@ <h2 data-i18n="landingCtaTitle">Start Learning Today</h2>
164168
<a href="#welcome/0" class="cta-button" data-i18n="landingCtaButton">Begin Your Journey</a>
165169
<p class="cta-sub" data-i18n="landingCtaSub">Free and open source. No account required. Progress saved locally.</p>
166170
</section>
171+
172+
<footer class="landing-footer">
173+
<div class="footer-grid">
174+
<section class="footer-section footer-modules">
175+
<div id="footer-lesson-links" class="footer-links"></div>
176+
</section>
177+
<section class="footer-section">
178+
<h4 data-i18n="footerResources">Resources</h4>
179+
<ul class="footer-links">
180+
<li><a href="#reference/css">CSS Reference</a></li>
181+
<li><a href="#reference/html">HTML Reference</a></li>
182+
<li><a href="#playground/0" data-i18n="footerPlayground">Playground</a></li>
183+
</ul>
184+
</section>
185+
<section class="footer-section">
186+
<h4 data-i18n="footerAbout">About</h4>
187+
<ul class="footer-links">
188+
<li><a href="https://librete.ch" target="_blank">LibreTECH</a></li>
189+
<li><a href="https://git.librete.ch/libretech/code-crispies" target="_blank">Source Code</a></li>
190+
<li><a href="https://github.com/nextlevelshit/code-crispies" target="_blank">GitHub</a></li>
191+
</ul>
192+
</section>
193+
<section class="footer-section footer-support">
194+
<h4 data-i18n="footerSupport">Support</h4>
195+
<p data-i18n="footerSupportText">Help keep Code Crispies free and open source.</p>
196+
<script src="https://liberapay.com/libretech/widgets/button.js"></script>
197+
<noscript><a href="https://liberapay.com/libretech/donate"><img alt="Donate using Liberapay" src="https://liberapay.com/assets/widgets/donate.svg"></a></noscript>
198+
</section>
199+
</div>
200+
<div class="footer-bottom">
201+
<p>&copy; 2025 <a href="https://librete.ch">LibreTECH</a>. <span data-i18n="footerLicense">Open source under MIT License.</span></p>
202+
</div>
203+
</footer>
167204
</div>
168205
</div>
169206

@@ -356,7 +393,7 @@ <h4 data-i18n="learningModesTitle">Learning Modes</h4>
356393
<li data-i18n-html="modeHtml"><strong>HTML</strong> - Practice semantic markup and native elements</li>
357394
</ul>
358395
<p class="help-nav-links">
359-
Jump to: <a href="#css">CSS</a> | <a href="#html">HTML</a> | <a href="#tailwind">Tailwind</a> |
396+
Jump to: <a href="#css">CSS</a> | <a href="#html">HTML</a> |
360397
<a href="#reference/css">Reference</a>
361398
</p>
362399

@@ -415,6 +452,13 @@ <h4 data-i18n="contactTitle">Contact & Links</h4>
415452
<li><a href="https://github.com/nextlevelshit/code-crispies" target="_blank">GitHub</a> – Public mirror</li>
416453
<li><a href="https://www.linkedin.com/in/michael-werner-czechowski" target="_blank">LinkedIn</a> – Michael Czechowski</li>
417454
</ul>
455+
456+
<h4 data-i18n="supportTitle">Support the Project</h4>
457+
<p data-i18n="supportText">Help keep Code Crispies free and open source.</p>
458+
<div class="help-support" onclick="typeof umami !== 'undefined' && umami.track('support_click', {location: 'help'})">
459+
<script src="https://liberapay.com/libretech/widgets/button.js"></script>
460+
<noscript><a href="https://liberapay.com/libretech/donate"><img alt="Donate using Liberapay" src="https://liberapay.com/assets/widgets/donate.svg"></a></noscript>
461+
</div>
418462
</div>
419463
</dialog>
420464

0 commit comments

Comments
 (0)