feat: add contact section and smooth lesson transitions

- Add contact section to help dialog with librete.ch, GitHub, Gitea, LinkedIn links
- Add HTML/CSS prefixes to English module titles for consistency with German
- Add CSS transitions for smooth lesson switching
- Add transitioning class to prevent content flash during lesson changes
This commit is contained in:
2025-12-30 20:48:03 +01:00
parent a359900d6e
commit 52142f1594
18 changed files with 53 additions and 14 deletions

View File

@@ -1,7 +1,7 @@
{ {
"$schema": "../schemas/code-crispies-module-schema.json", "$schema": "../schemas/code-crispies-module-schema.json",
"id": "css-basic-selectors", "id": "css-basic-selectors",
"title": "Selectors", "title": "CSS Selectors",
"description": "CSS selectors are the foundation of styling web pages, allowing you to target specific HTML elements for styling. This module introduces fundamental selector types including element type selectors, class selectors, ID selectors, and the universal selector.", "description": "CSS selectors are the foundation of styling web pages, allowing you to target specific HTML elements for styling. This module introduces fundamental selector types including element type selectors, class selectors, ID selectors, and the universal selector.",
"difficulty": "beginner", "difficulty": "beginner",
"lessons": [ "lessons": [

View File

@@ -1,7 +1,7 @@
{ {
"$schema": "../schemas/code-crispies-module-schema.json", "$schema": "../schemas/code-crispies-module-schema.json",
"id": "box-model", "id": "box-model",
"title": "Box Model", "title": "CSS Box Model",
"description": "Master the fundamental principles of space management in web design through the CSS box model. This module explores how content, padding, borders, and margins combine to create layout structures that are both visually appealing and structurally sound.", "description": "Master the fundamental principles of space management in web design through the CSS box model. This module explores how content, padding, borders, and margins combine to create layout structures that are both visually appealing and structurally sound.",
"difficulty": "beginner", "difficulty": "beginner",
"lessons": [ "lessons": [

View File

@@ -1,7 +1,7 @@
{ {
"$schema": "../schemas/code-crispies-module-schema.json", "$schema": "../schemas/code-crispies-module-schema.json",
"id": "units-variables", "id": "units-variables",
"title": "Units & Vars", "title": "CSS Units & Variables",
"description": "Understand the variety of CSS measurement units and how to define and use custom properties for maintainable styles.", "description": "Understand the variety of CSS measurement units and how to define and use custom properties for maintainable styles.",
"difficulty": "beginner", "difficulty": "beginner",
"lessons": [ "lessons": [

View File

@@ -1,7 +1,7 @@
{ {
"$schema": "../schemas/code-crispies-module-schema.json", "$schema": "../schemas/code-crispies-module-schema.json",
"id": "transitions-animations", "id": "transitions-animations",
"title": "Animations", "title": "CSS Animations",
"description": "Bring interactivity to your UI by smoothly transitioning properties and creating keyframe-driven animations.", "description": "Bring interactivity to your UI by smoothly transitioning properties and creating keyframe-driven animations.",
"difficulty": "beginner", "difficulty": "beginner",
"lessons": [ "lessons": [

View File

@@ -1,7 +1,7 @@
{ {
"$schema": "../schemas/code-crispies-module-schema.json", "$schema": "../schemas/code-crispies-module-schema.json",
"id": "responsive-design", "id": "responsive-design",
"title": "Responsive", "title": "CSS Responsive Design",
"description": "Make your layouts adapt to different screen sizes using media queries and fluid design techniques.", "description": "Make your layouts adapt to different screen sizes using media queries and fluid design techniques.",
"difficulty": "intermediate", "difficulty": "intermediate",
"lessons": [ "lessons": [

View File

@@ -1,7 +1,7 @@
{ {
"$schema": "../schemas/code-crispies-module-schema.json", "$schema": "../schemas/code-crispies-module-schema.json",
"id": "html-elements", "id": "html-elements",
"title": "HTML Elements", "title": "HTML Block & Inline",
"description": "Understanding the fundamental difference between container (block) and inline elements", "description": "Understanding the fundamental difference between container (block) and inline elements",
"mode": "html", "mode": "html",
"difficulty": "beginner", "difficulty": "beginner",

View File

@@ -1,7 +1,7 @@
{ {
"$schema": "../schemas/code-crispies-module-schema.json", "$schema": "../schemas/code-crispies-module-schema.json",
"id": "html-forms-basic", "id": "html-forms-basic",
"title": "Form Inputs", "title": "HTML Forms",
"description": "Learn to create forms with various input types", "description": "Learn to create forms with various input types",
"mode": "html", "mode": "html",
"difficulty": "beginner", "difficulty": "beginner",

View File

@@ -1,7 +1,7 @@
{ {
"$schema": "../schemas/code-crispies-module-schema.json", "$schema": "../schemas/code-crispies-module-schema.json",
"id": "html-forms-validation", "id": "html-forms-validation",
"title": "Validation", "title": "HTML Validation",
"description": "Learn HTML5 built-in form validation attributes", "description": "Learn HTML5 built-in form validation attributes",
"mode": "html", "mode": "html",
"difficulty": "intermediate", "difficulty": "intermediate",

View File

@@ -1,7 +1,7 @@
{ {
"$schema": "../schemas/code-crispies-module-schema.json", "$schema": "../schemas/code-crispies-module-schema.json",
"id": "html-details-summary", "id": "html-details-summary",
"title": "Disclosure", "title": "HTML Details & Summary",
"description": "Create expandable content sections without JavaScript", "description": "Create expandable content sections without JavaScript",
"mode": "html", "mode": "html",
"difficulty": "beginner", "difficulty": "beginner",

View File

@@ -1,7 +1,7 @@
{ {
"$schema": "../schemas/code-crispies-module-schema.json", "$schema": "../schemas/code-crispies-module-schema.json",
"id": "html-progress-meter", "id": "html-progress-meter",
"title": "Progress/Meter", "title": "HTML Progress & Meter",
"description": "Display completion status and scalar measurements natively", "description": "Display completion status and scalar measurements natively",
"mode": "html", "mode": "html",
"difficulty": "beginner", "difficulty": "beginner",

View File

@@ -1,7 +1,7 @@
{ {
"$schema": "../schemas/code-crispies-module-schema.json", "$schema": "../schemas/code-crispies-module-schema.json",
"id": "html-tables", "id": "html-tables",
"title": "Tables", "title": "HTML Tables",
"description": "Create structured data tables with headers and captions", "description": "Create structured data tables with headers and captions",
"mode": "html", "mode": "html",
"difficulty": "beginner", "difficulty": "beginner",

View File

@@ -1,7 +1,7 @@
{ {
"$schema": "../schemas/code-crispies-module-schema.json", "$schema": "../schemas/code-crispies-module-schema.json",
"id": "html-marquee", "id": "html-marquee",
"title": "Marquee", "title": "HTML Marquee",
"description": "Create scrolling text with the classic (deprecated but fun!) marquee element", "description": "Create scrolling text with the classic (deprecated but fun!) marquee element",
"mode": "html", "mode": "html",
"difficulty": "beginner", "difficulty": "beginner",

View File

@@ -1,7 +1,7 @@
{ {
"$schema": "../schemas/code-crispies-module-schema.json", "$schema": "../schemas/code-crispies-module-schema.json",
"id": "html-svg", "id": "html-svg",
"title": "SVG", "title": "HTML SVG",
"description": "Draw scalable vector graphics directly in HTML", "description": "Draw scalable vector graphics directly in HTML",
"mode": "html", "mode": "html",
"difficulty": "beginner", "difficulty": "beginner",

View File

@@ -1,7 +1,7 @@
{ {
"$schema": "../schemas/code-crispies-module-schema.json", "$schema": "../schemas/code-crispies-module-schema.json",
"id": "flexbox", "id": "flexbox",
"title": "Flexbox", "title": "CSS Flexbox",
"description": "Master the flexible box layout model for modern responsive designs", "description": "Master the flexible box layout model for modern responsive designs",
"difficulty": "intermediate", "difficulty": "intermediate",
"lessons": [ "lessons": [

View File

@@ -20,6 +20,7 @@ const elements = {
helpBtn: document.getElementById("help-btn"), helpBtn: document.getElementById("help-btn"),
// Left panel // Left panel
editorSection: document.querySelector(".editor-section"),
modulePill: document.getElementById("module-pill"), modulePill: document.getElementById("module-pill"),
moduleName: document.querySelector(".module-name"), moduleName: document.querySelector(".module-name"),
lessonTitle: document.getElementById("lesson-title"), lessonTitle: document.getElementById("lesson-title"),
@@ -313,6 +314,9 @@ function loadCurrentLesson() {
const lesson = engineState.lesson; const lesson = engineState.lesson;
const mode = lesson.mode || engineState.module?.mode || "css"; const mode = lesson.mode || engineState.module?.mode || "css";
// Add transition class for smooth content swap
elements.editorSection?.classList.add("transitioning");
// Update UI based on mode // Update UI based on mode
updateEditorForMode(mode); updateEditorForMode(mode);
@@ -388,6 +392,11 @@ function loadCurrentLesson() {
// Render the expected/solution preview // Render the expected/solution preview
lessonEngine.renderExpectedPreview(); lessonEngine.renderExpectedPreview();
// Remove transition class after content is updated
requestAnimationFrame(() => {
elements.editorSection?.classList.remove("transitioning");
});
} }
// ================= LIVE PREVIEW ================= // ================= LIVE PREVIEW =================

View File

@@ -76,6 +76,10 @@ const translations = {
emmetNested: "<kbd>form>input+button</kbd> → nested structure", emmetNested: "<kbd>form>input+button</kbd> → nested structure",
emmetContent: "<kbd>p{Hello}</kbd> → p with text content", emmetContent: "<kbd>p{Hello}</kbd> → p with text content",
// Contact
contactTitle: "Contact & Links",
contactText: "Code Crispies is developed by librete.ch",
// Reset dialog // Reset dialog
resetDialogTitle: "Reset Progress", resetDialogTitle: "Reset Progress",
resetDialogText: "Are you sure you want to reset all your progress? This cannot be undone.", resetDialogText: "Are you sure you want to reset all your progress? This cannot be undone.",
@@ -165,6 +169,10 @@ const translations = {
emmetNested: "<kbd>form>input+button</kbd> → verschachtelte Struktur", emmetNested: "<kbd>form>input+button</kbd> → verschachtelte Struktur",
emmetContent: "<kbd>p{Hallo}</kbd> → p mit Textinhalt", emmetContent: "<kbd>p{Hallo}</kbd> → p mit Textinhalt",
// Contact
contactTitle: "Kontakt & Links",
contactText: "Code Crispies wird von librete.ch entwickelt",
// Reset dialog // Reset dialog
resetDialogTitle: "Fortschritt zurücksetzen", resetDialogTitle: "Fortschritt zurücksetzen",
resetDialogText: "Bist du sicher, dass du deinen gesamten Fortschritt zurücksetzen möchtest? Dies kann nicht rückgängig gemacht werden.", resetDialogText: "Bist du sicher, dass du deinen gesamten Fortschritt zurücksetzen möchtest? Dies kann nicht rückgängig gemacht werden.",

View File

@@ -178,6 +178,15 @@
<li data-i18n-html="emmetNested"><kbd>form>input+button</kbd> → nested structure</li> <li data-i18n-html="emmetNested"><kbd>form>input+button</kbd> → nested structure</li>
<li data-i18n-html="emmetContent"><kbd>p{Hello}</kbd> → p with text content</li> <li data-i18n-html="emmetContent"><kbd>p{Hello}</kbd> → p with text content</li>
</ul> </ul>
<h4 data-i18n="contactTitle">Contact & Links</h4>
<p data-i18n="contactText">Code Crispies is developed by librete.ch</p>
<ul>
<li><a href="https://librete.ch" target="_blank">librete.ch</a></li>
<li><a href="https://github.com/nextlevelshit/code-crispies" target="_blank">GitHub</a></li>
<li><a href="https://git.librete.ch/public/code-crispies" target="_blank">Gitea</a></li>
<li><a href="https://www.linkedin.com/in/michael-werner-czechowski" target="_blank">LinkedIn</a></li>
</ul>
</div> </div>
</dialog> </dialog>

View File

@@ -228,6 +228,19 @@ code, kbd {
border-bottom: 1px solid var(--border-color); border-bottom: 1px solid var(--border-color);
} }
/* Smooth lesson transition */
#lesson-title,
.lesson-description,
.task-instruction {
transition: opacity 0.1s ease;
}
.editor-section.transitioning #lesson-title,
.editor-section.transitioning .lesson-description,
.editor-section.transitioning .task-instruction {
opacity: 0.3;
}
.module-pill { .module-pill {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;