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:
@@ -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": [
|
||||||
|
|||||||
@@ -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": [
|
||||||
|
|||||||
@@ -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": [
|
||||||
|
|||||||
@@ -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": [
|
||||||
|
|||||||
@@ -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": [
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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",
|
||||||
|
|||||||
@@ -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": [
|
||||||
|
|||||||
@@ -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 =================
|
||||||
|
|||||||
@@ -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.",
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|
||||||
|
|||||||
13
src/main.css
13
src/main.css
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user