From 0a03d51e63a38ee509475474448a087cc85be45a Mon Sep 17 00:00:00 2001 From: Michael Czechowski Date: Fri, 16 Jan 2026 04:32:55 +0100 Subject: [PATCH] feat: complete section color coding with logo, hints, editor themes, and footers - Add section-specific CodeMirror syntax highlighting (purple selectors for CSS) - Logo now uses section colors (CSS purple as default, changes per section) - Add section color coding for hints - Add full footer to section and reference pages - Fix nav highlight updates for sidebar and prev/next navigation - Change welcome module mode to CSS for purple theme on first lesson - Rebrand "Code Crispies" to "CODE CRISPIES" across all translations - Fix scroll to top on section page navigation - Change HTML section color to raspberry (#c75b7a) --- lessons/00-welcome.json | 2 +- lessons/ar/00-welcome.json | 2 +- lessons/de/00-welcome.json | 2 +- lessons/es/00-welcome.json | 2 +- lessons/pl/00-welcome.json | 2 +- lessons/uk/00-welcome.json | 2 +- src/app.js | 59 +++++++++++---- src/config/sections.js | 2 +- src/i18n.js | 86 +++++++++++----------- src/impl/CodeEditor.js | 56 +++++++++++++-- src/index.html | 87 +++++++++++++++++++---- src/main.css | 142 ++++++++++++++++++++++++++----------- 12 files changed, 321 insertions(+), 123 deletions(-) diff --git a/lessons/00-welcome.json b/lessons/00-welcome.json index 25bc4dc..9a27845 100644 --- a/lessons/00-welcome.json +++ b/lessons/00-welcome.json @@ -3,7 +3,7 @@ "id": "welcome", "title": "Welcome", "description": "Get started with Code Crispies", - "mode": "html", + "mode": "css", "difficulty": "beginner", "excludeFromProgress": true, "lessons": [ diff --git a/lessons/ar/00-welcome.json b/lessons/ar/00-welcome.json index 637cb8f..6b96b24 100644 --- a/lessons/ar/00-welcome.json +++ b/lessons/ar/00-welcome.json @@ -3,7 +3,7 @@ "id": "welcome", "title": "مرحباً", "description": "ابدأ مع Code Crispies", - "mode": "html", + "mode": "css", "difficulty": "beginner", "excludeFromProgress": true, "lessons": [ diff --git a/lessons/de/00-welcome.json b/lessons/de/00-welcome.json index 282c8ba..8e61132 100644 --- a/lessons/de/00-welcome.json +++ b/lessons/de/00-welcome.json @@ -3,7 +3,7 @@ "id": "welcome", "title": "Willkommen", "description": "Erste Schritte mit Code Crispies", - "mode": "html", + "mode": "css", "difficulty": "beginner", "excludeFromProgress": true, "lessons": [ diff --git a/lessons/es/00-welcome.json b/lessons/es/00-welcome.json index 5684142..055f16d 100644 --- a/lessons/es/00-welcome.json +++ b/lessons/es/00-welcome.json @@ -3,7 +3,7 @@ "id": "welcome", "title": "Bienvenido", "description": "Comienza con Code Crispies", - "mode": "html", + "mode": "css", "difficulty": "beginner", "excludeFromProgress": true, "lessons": [ diff --git a/lessons/pl/00-welcome.json b/lessons/pl/00-welcome.json index 590738a..b0214c2 100644 --- a/lessons/pl/00-welcome.json +++ b/lessons/pl/00-welcome.json @@ -3,7 +3,7 @@ "id": "welcome", "title": "Witaj", "description": "Rozpocznij przygodę z Code Crispies", - "mode": "html", + "mode": "css", "difficulty": "beginner", "excludeFromProgress": true, "lessons": [ diff --git a/lessons/uk/00-welcome.json b/lessons/uk/00-welcome.json index f2d9fe9..7b8988a 100644 --- a/lessons/uk/00-welcome.json +++ b/lessons/uk/00-welcome.json @@ -3,7 +3,7 @@ "id": "welcome", "title": "Ласкаво просимо", "description": "Почніть з Code Crispies", - "mode": "html", + "mode": "css", "difficulty": "beginner", "excludeFromProgress": true, "lessons": [ diff --git a/src/app.js b/src/app.js index 289541d..cde104f 100644 --- a/src/app.js +++ b/src/app.js @@ -156,6 +156,8 @@ const elements = { closeSidebar: document.getElementById("close-sidebar"), moduleList: document.getElementById("module-list"), footerLessonLinks: document.getElementById("footer-lesson-links"), + refFooterLessonLinks: document.getElementById("ref-footer-lesson-links"), + sectionFooterLessonLinks: document.getElementById("section-footer-lesson-links"), progressFill: document.getElementById("progress-fill"), progressText: document.getElementById("progress-text"), resetBtn: document.getElementById("reset-btn"), @@ -456,6 +458,13 @@ function selectLesson(moduleId, lessonIndex) { loadCurrentLesson(); + // Update section color coding (after loadCurrentLesson to ensure content is loaded first) + const newState = lessonEngine.getCurrentState(); + updateSectionColor(getModuleSection(newState.module)); + + // Update nav highlight + updateNavHighlight({ type: RouteType.LESSON, moduleId, lessonIndex }); + // Close sidebar after selection on mobile if (window.innerWidth <= 768) { closeSidebar(); @@ -694,11 +703,15 @@ function nextLesson() { // Update URL updateHash(newState.module.id, newState.lessonIndex); - if (newState.module.id !== prevModuleId) { + const moduleChanged = newState.module.id !== prevModuleId; + if (moduleChanged) { updateModuleHighlight(newState.module.id); - updateSectionColor(getModuleSection(newState.module)); } loadCurrentLesson(); + if (moduleChanged) { + updateSectionColor(getModuleSection(newState.module)); + updateNavHighlight({ type: RouteType.LESSON, moduleId: newState.module.id, lessonIndex: newState.lessonIndex }); + } } } @@ -711,11 +724,15 @@ function prevLesson() { // Update URL updateHash(newState.module.id, newState.lessonIndex); - if (newState.module.id !== prevModuleId) { + const moduleChanged = newState.module.id !== prevModuleId; + if (moduleChanged) { updateModuleHighlight(newState.module.id); - updateSectionColor(getModuleSection(newState.module)); } loadCurrentLesson(); + if (moduleChanged) { + updateSectionColor(getModuleSection(newState.module)); + updateNavHighlight({ type: RouteType.LESSON, moduleId: newState.module.id, lessonIndex: newState.lessonIndex }); + } } } @@ -1852,7 +1869,7 @@ function stripHtml(html) { * Update page meta tags based on current route for SEO */ function updatePageMeta(route) { - const defaultTitle = "Code Crispies - Learn HTML & CSS Interactively | Free Coding Practice"; + const defaultTitle = "CODE CRISPIES - Learn HTML & CSS Interactively | Free Coding Practice"; const defaultDesc = "Master HTML, CSS, and Tailwind through hands-on coding exercises. Free, open-source learning platform with instant feedback. No account required."; @@ -1872,7 +1889,7 @@ function updatePageMeta(route) { case RouteType.SECTION: { const sectionNames = { css: "CSS", html: "HTML", tailwind: "Tailwind CSS" }; const sectionName = sectionNames[route.sectionId] || route.sectionId; - title = `${sectionName} Lessons - Code Crispies | Learn ${sectionName}`; + title = `${sectionName} Lessons - CODE CRISPIES | Learn ${sectionName}`; description = `Learn ${sectionName} through interactive coding exercises. Hands-on practice with instant feedback.`; break; } @@ -1881,7 +1898,7 @@ function updatePageMeta(route) { const module = lessonEngine.modules.find((m) => m.id === route.moduleId); const lesson = module?.lessons[route.lessonIndex]; if (module && lesson) { - title = `${lesson.title} - ${module.title} | Code Crispies`; + title = `${lesson.title} - ${module.title} | CODE CRISPIES`; const lessonDesc = stripHtml(lesson.description || lesson.task); description = lessonDesc.length > 155 ? lessonDesc.slice(0, 152) + "..." : lessonDesc || defaultDesc; } @@ -1897,7 +1914,7 @@ function updatePageMeta(route) { html: "HTML Elements" }; const refName = refNames[route.refId] || "Reference"; - title = `${refName} Reference - Code Crispies`; + title = `${refName} Reference - CODE CRISPIES`; description = `Quick reference guide for ${refName}. Syntax, examples, and common patterns for web development.`; break; } @@ -1913,13 +1930,13 @@ function updatePageMeta(route) { // Update Open Graph tags const ogTitle = document.querySelector('meta[property="og:title"]'); const ogDesc = document.querySelector('meta[property="og:description"]'); - if (ogTitle) ogTitle.setAttribute("content", title.replace(" | Code Crispies", "").replace(" - Code Crispies", "")); + if (ogTitle) ogTitle.setAttribute("content", title.replace(" | CODE CRISPIES", "").replace(" - CODE CRISPIES", "")); if (ogDesc) ogDesc.setAttribute("content", description); // Update Twitter tags const twitterTitle = document.querySelector('meta[name="twitter:title"]'); const twitterDesc = document.querySelector('meta[name="twitter:description"]'); - if (twitterTitle) twitterTitle.setAttribute("content", title.replace(" | Code Crispies", "").replace(" - Code Crispies", "")); + if (twitterTitle) twitterTitle.setAttribute("content", title.replace(" | CODE CRISPIES", "").replace(" - CODE CRISPIES", "")); if (twitterDesc) twitterDesc.setAttribute("content", description); } @@ -1994,6 +2011,11 @@ function updateSectionColor(sectionId) { } else { document.body.removeAttribute("data-section"); } + + // Update code editor theme for section + if (codeEditor) { + codeEditor.setSection(sectionId); + } } /** @@ -2018,8 +2040,6 @@ function showLandingPage() { * 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: [] }; @@ -2042,7 +2062,16 @@ function renderFooterLessonLinks() { html += ""; }); - elements.footerLessonLinks.innerHTML = html; + // Update all footer lesson links + if (elements.footerLessonLinks) { + elements.footerLessonLinks.innerHTML = html; + } + if (elements.refFooterLessonLinks) { + elements.refFooterLessonLinks.innerHTML = html; + } + if (elements.sectionFooterLessonLinks) { + elements.sectionFooterLessonLinks.innerHTML = html; + } } /** @@ -2077,7 +2106,6 @@ function updateLandingProgress() { function showSectionPage(sectionId) { hideAllPages(); elements.sectionPage?.classList.remove("hidden"); - window.scrollTo(0, 0); // Update section color updateSectionColor(sectionId); @@ -2120,6 +2148,9 @@ function showSectionPage(sectionId) { const percent = total > 0 ? Math.round((completed / total) * 100) : 0; if (elements.sectionProgressFill) elements.sectionProgressFill.style.width = `${percent}%`; if (elements.sectionProgressText) elements.sectionProgressText.textContent = `${completed} of ${total} lessons complete`; + + // Scroll to top after content is rendered + requestAnimationFrame(() => window.scrollTo(0, 0)); } /** diff --git a/src/config/sections.js b/src/config/sections.js index 7698808..71c42fd 100644 --- a/src/config/sections.js +++ b/src/config/sections.js @@ -15,7 +15,7 @@ export const sections = { id: "html", title: "HTML", description: "Semantic markup and native elements", - color: "#d4637b", + color: "#c75b7a", order: 2 }, tailwind: { diff --git a/src/i18n.js b/src/i18n.js index fa8b123..2c544dc 100644 --- a/src/i18n.js +++ b/src/i18n.js @@ -1,11 +1,11 @@ /** - * Internationalization module for Code Crispies + * Internationalization module for CODE CRISPIES */ const translations = { en: { // Page - pageTitle: "Code Crispies - Learn HTML & CSS Interactively", + pageTitle: "CODE CRISPIES - Learn HTML & CSS Interactively", skipLink: "Skip to main content", // Header @@ -48,9 +48,9 @@ const translations = { // Help dialog helpTitle: "Help", - aboutTitle: "About Code Crispies", + aboutTitle: "About CODE CRISPIES", aboutText: - "Code Crispies is a free, open-source platform for learning web development through hands-on exercises. No account required - just start coding!", + "CODE CRISPIES is a free, open-source platform for learning web development through hands-on exercises. No account required - just start coding!", learningModesTitle: "Learning Modes", modeCss: "CSS - Write CSS rules to style elements", modeTailwind: "Tailwind - Apply utility classes directly in HTML", @@ -85,7 +85,7 @@ const translations = { // Contact contactTitle: "Contact & Links", - contactText: 'Code Crispies is developed by LibreTECH', + contactText: 'CODE CRISPIES is developed by LibreTECH', // Reset dialog resetDialogTitle: "Reset Progress", @@ -121,7 +121,7 @@ const translations = { landingHeroHighlight: "By Writing Real Code", landingHeroSubtitle: "Master HTML, CSS, and Tailwind through hands-on exercises with instant feedback. Free and open source.", landingCtaStart: "Start Learning NOW", - landingWhyTitle: "Why Code Crispies Works", + landingWhyTitle: "Why CODE CRISPIES Works", landingBenefit1Title: "Learn by Doing", landingBenefit1Text: "Write real code from lesson one. No videos to watch—just you, an editor, and instant feedback on every keystroke.", landingBenefit2Title: "Practice at Your Pace", @@ -145,17 +145,17 @@ const translations = { footerPlayground: "Playground", footerAbout: "About", footerSupport: "Support", - footerSupportText: "Help keep Code Crispies free and open source.", + footerSupportText: "Help keep CODE CRISPIES free and open source.", footerLicense: "Released into the public domain.", // Help Dialog Support supportTitle: "Support the Project", - supportText: "Help keep Code Crispies free and open source." + supportText: "Help keep CODE CRISPIES free and open source." }, de: { // Page - pageTitle: "Code Crispies - HTML & CSS interaktiv lernen", + pageTitle: "CODE CRISPIES - HTML & CSS interaktiv lernen", skipLink: "Zum Hauptinhalt springen", // Header @@ -198,9 +198,9 @@ const translations = { // Help dialog helpTitle: "Hilfe", - aboutTitle: "Über Code Crispies", + aboutTitle: "Über CODE CRISPIES", aboutText: - "Code Crispies ist eine kostenlose Open-Source-Plattform zum Erlernen von Webentwicklung durch praktische Übungen. Kein Konto erforderlich - einfach loslegen!", + "CODE CRISPIES ist eine kostenlose Open-Source-Plattform zum Erlernen von Webentwicklung durch praktische Übungen. Kein Konto erforderlich - einfach loslegen!", learningModesTitle: "Lernmodi", modeCss: "CSS - Schreibe CSS-Regeln zum Stylen von Elementen", modeTailwind: "Tailwind - Wende Utility-Klassen direkt im HTML an", @@ -236,7 +236,7 @@ const translations = { // Contact contactTitle: "Kontakt & Links", - contactText: 'Code Crispies wird von LibreTECH entwickelt', + contactText: 'CODE CRISPIES wird von LibreTECH entwickelt', // Reset dialog resetDialogTitle: "Fortschritt zurücksetzen", @@ -272,7 +272,7 @@ const translations = { landingHeroHighlight: "Selbstständig lernen", landingHeroSubtitle: "Meistere HTML, CSS und Tailwind durch praktische Übungen mit sofortigem Feedback. Kostenlos und Open Source.", landingCtaStart: "Jetzt starten", - landingWhyTitle: "Warum Code Crispies funktioniert", + landingWhyTitle: "Warum CODE CRISPIES funktioniert", landingBenefit1Title: "Lernen durch Praxis", landingBenefit1Text: "Schreibe echten Code ab der ersten Lektion. Keine Videos – nur du, ein Editor und sofortiges Feedback bei jedem Tastendruck.", @@ -298,18 +298,18 @@ const translations = { footerPlayground: "Playground", footerAbout: "Über uns", footerSupport: "Unterstützen", - footerSupportText: "Hilf mit, Code Crispies kostenlos und Open Source zu halten.", + footerSupportText: "Hilf mit, CODE CRISPIES kostenlos und Open Source zu halten.", footerLicense: "Gemeinfrei (Public Domain).", // Help Dialog Support supportTitle: "Projekt unterstützen", - supportText: "Hilf mit, Code Crispies kostenlos und Open Source zu halten." + supportText: "Hilf mit, CODE CRISPIES kostenlos und Open Source zu halten." }, // Polish pl: { // Page - pageTitle: "Code Crispies - Nauka HTML i CSS interaktywnie", + pageTitle: "CODE CRISPIES - Nauka HTML i CSS interaktywnie", skipLink: "Przejdź do głównej treści", // Header @@ -352,9 +352,9 @@ const translations = { // Help dialog helpTitle: "Pomoc", - aboutTitle: "O Code Crispies", + aboutTitle: "O CODE CRISPIES", aboutText: - "Code Crispies to darmowa platforma open-source do nauki tworzenia stron internetowych poprzez praktyczne ćwiczenia. Nie wymaga konta - po prostu zacznij kodować!", + "CODE CRISPIES to darmowa platforma open-source do nauki tworzenia stron internetowych poprzez praktyczne ćwiczenia. Nie wymaga konta - po prostu zacznij kodować!", learningModesTitle: "Tryby nauki", modeCss: "CSS - Pisz reguły CSS do stylizowania elementów", modeTailwind: "Tailwind - Stosuj klasy utility bezpośrednio w HTML", @@ -389,7 +389,7 @@ const translations = { // Contact contactTitle: "Kontakt i linki", - contactText: 'Code Crispies jest rozwijany przez LibreTECH', + contactText: 'CODE CRISPIES jest rozwijany przez LibreTECH', // Reset dialog resetDialogTitle: "Resetuj postęp", @@ -425,7 +425,7 @@ const translations = { landingHeroHighlight: "Pisząc prawdziwy kod", landingHeroSubtitle: "Opanuj HTML, CSS i Tailwind poprzez praktyczne ćwiczenia z natychmiastową informacją zwrotną. Darmowe i open source.", landingCtaStart: "Zacznij TERAZ", - landingWhyTitle: "Dlaczego Code Crispies działa", + landingWhyTitle: "Dlaczego CODE CRISPIES działa", landingBenefit1Title: "Ucz się przez praktykę", landingBenefit1Text: "Pisz prawdziwy kod od pierwszej lekcji. Żadnych filmów – tylko ty, edytor i natychmiastowa informacja zwrotna przy każdym naciśnięciu klawisza.", @@ -451,18 +451,18 @@ const translations = { footerPlayground: "Plac zabaw", footerAbout: "O nas", footerSupport: "Wsparcie", - footerSupportText: "Pomóż utrzymać Code Crispies darmowym i open source.", + footerSupportText: "Pomóż utrzymać CODE CRISPIES darmowym i open source.", footerLicense: "Udostępnione jako domena publiczna.", // Help Dialog Support supportTitle: "Wesprzyj projekt", - supportText: "Pomóż utrzymać Code Crispies darmowym i open source." + supportText: "Pomóż utrzymać CODE CRISPIES darmowym i open source." }, // Spanish es: { // Page - pageTitle: "Code Crispies - Aprende HTML y CSS de forma interactiva", + pageTitle: "CODE CRISPIES - Aprende HTML y CSS de forma interactiva", skipLink: "Saltar al contenido principal", // Header @@ -505,9 +505,9 @@ const translations = { // Help dialog helpTitle: "Ayuda", - aboutTitle: "Acerca de Code Crispies", + aboutTitle: "Acerca de CODE CRISPIES", aboutText: - "Code Crispies es una plataforma gratuita de código abierto para aprender desarrollo web a través de ejercicios prácticos. No se requiere cuenta, ¡solo empieza a programar!", + "CODE CRISPIES es una plataforma gratuita de código abierto para aprender desarrollo web a través de ejercicios prácticos. No se requiere cuenta, ¡solo empieza a programar!", learningModesTitle: "Modos de aprendizaje", modeCss: "CSS - Escribe reglas CSS para estilizar elementos", modeTailwind: "Tailwind - Aplica clases de utilidad directamente en HTML", @@ -543,7 +543,7 @@ const translations = { // Contact contactTitle: "Contacto y enlaces", - contactText: 'Code Crispies es desarrollado por LibreTECH', + contactText: 'CODE CRISPIES es desarrollado por LibreTECH', // Reset dialog resetDialogTitle: "Reiniciar progreso", @@ -580,7 +580,7 @@ const translations = { landingHeroSubtitle: "Domina HTML, CSS y Tailwind a través de ejercicios prácticos con retroalimentación instantánea. Gratis y de código abierto.", landingCtaStart: "Empieza AHORA", - landingWhyTitle: "Por qué funciona Code Crispies", + landingWhyTitle: "Por qué funciona CODE CRISPIES", landingBenefit1Title: "Aprende haciendo", landingBenefit1Text: "Escribe código real desde la primera lección. Sin videos que ver—solo tú, un editor y retroalimentación instantánea en cada tecla.", @@ -606,18 +606,18 @@ const translations = { footerPlayground: "Zona de pruebas", footerAbout: "Acerca de", footerSupport: "Apoyar", - footerSupportText: "Ayuda a mantener Code Crispies gratis y de código abierto.", + footerSupportText: "Ayuda a mantener CODE CRISPIES gratis y de código abierto.", footerLicense: "Liberado al dominio público.", // Help Dialog Support supportTitle: "Apoyar el proyecto", - supportText: "Ayuda a mantener Code Crispies gratis y de código abierto." + supportText: "Ayuda a mantener CODE CRISPIES gratis y de código abierto." }, // Arabic ar: { // Page - pageTitle: "Code Crispies - تعلم HTML و CSS بشكل تفاعلي", + pageTitle: "CODE CRISPIES - تعلم HTML و CSS بشكل تفاعلي", skipLink: "انتقل إلى المحتوى الرئيسي", // Header @@ -660,8 +660,8 @@ const translations = { // Help dialog helpTitle: "مساعدة", - aboutTitle: "عن Code Crispies", - aboutText: "Code Crispies هي منصة مجانية مفتوحة المصدر لتعلم تطوير الويب من خلال تمارين عملية. لا يلزم حساب - فقط ابدأ البرمجة!", + aboutTitle: "عن CODE CRISPIES", + aboutText: "CODE CRISPIES هي منصة مجانية مفتوحة المصدر لتعلم تطوير الويب من خلال تمارين عملية. لا يلزم حساب - فقط ابدأ البرمجة!", learningModesTitle: "أوضاع التعلم", modeCss: "CSS - اكتب قواعد CSS لتنسيق العناصر", modeTailwind: "Tailwind - طبق فئات الأدوات مباشرة في HTML", @@ -696,7 +696,7 @@ const translations = { // Contact contactTitle: "التواصل والروابط", - contactText: 'Code Crispies تم تطويره بواسطة LibreTECH', + contactText: 'CODE CRISPIES تم تطويره بواسطة LibreTECH', // Reset dialog resetDialogTitle: "إعادة تعيين التقدم", @@ -732,7 +732,7 @@ const translations = { landingHeroHighlight: "بكتابة كود حقيقي", landingHeroSubtitle: "أتقن HTML و CSS و Tailwind من خلال تمارين عملية مع ملاحظات فورية. مجاني ومفتوح المصدر.", landingCtaStart: "ابدأ الآن", - landingWhyTitle: "لماذا Code Crispies فعال", + landingWhyTitle: "لماذا CODE CRISPIES فعال", landingBenefit1Title: "تعلم بالممارسة", landingBenefit1Text: "اكتب كودًا حقيقيًا من الدرس الأول. لا فيديوهات للمشاهدة—فقط أنت ومحرر وملاحظات فورية مع كل ضغطة مفتاح.", landingBenefit2Title: "بسرعتك الخاصة", @@ -756,18 +756,18 @@ const translations = { footerPlayground: "ساحة التجربة", footerAbout: "حول", footerSupport: "الدعم", - footerSupportText: "ساعد في إبقاء Code Crispies مجانيًا ومفتوح المصدر.", + footerSupportText: "ساعد في إبقاء CODE CRISPIES مجانيًا ومفتوح المصدر.", footerLicense: "مُطلق للملكية العامة.", // Help Dialog Support supportTitle: "ادعم المشروع", - supportText: "ساعد في إبقاء Code Crispies مجانيًا ومفتوح المصدر." + supportText: "ساعد في إبقاء CODE CRISPIES مجانيًا ومفتوح المصدر." }, // Ukrainian uk: { // Page - pageTitle: "Code Crispies - Вивчай HTML та CSS інтерактивно", + pageTitle: "CODE CRISPIES - Вивчай HTML та CSS інтерактивно", skipLink: "Перейти до основного вмісту", // Header @@ -810,9 +810,9 @@ const translations = { // Help dialog helpTitle: "Допомога", - aboutTitle: "Про Code Crispies", + aboutTitle: "Про CODE CRISPIES", aboutText: - "Code Crispies — це безкоштовна платформа з відкритим кодом для вивчення веб-розробки через практичні вправи. Обліковий запис не потрібен — просто починайте кодувати!", + "CODE CRISPIES — це безкоштовна платформа з відкритим кодом для вивчення веб-розробки через практичні вправи. Обліковий запис не потрібен — просто починайте кодувати!", learningModesTitle: "Режими навчання", modeCss: "CSS - Пишіть правила CSS для стилізації елементів", modeTailwind: "Tailwind - Застосовуйте утилітарні класи безпосередньо в HTML", @@ -847,7 +847,7 @@ const translations = { // Contact contactTitle: "Контакти та посилання", - contactText: 'Code Crispies розроблено LibreTECH', + contactText: 'CODE CRISPIES розроблено LibreTECH', // Reset dialog resetDialogTitle: "Скинути прогрес", @@ -883,7 +883,7 @@ const translations = { landingHeroHighlight: "Пишучи справжній код", landingHeroSubtitle: "Опануй HTML, CSS та Tailwind через практичні вправи з миттєвим зворотним зв'язком. Безкоштовно та з відкритим кодом.", landingCtaStart: "Почни ЗАРАЗ", - landingWhyTitle: "Чому Code Crispies працює", + landingWhyTitle: "Чому CODE CRISPIES працює", landingBenefit1Title: "Вчись на практиці", landingBenefit1Text: "Пиши справжній код з першого уроку. Жодних відео—тільки ти, редактор і миттєвий зворотний зв'язок при кожному натисканні клавіші.", @@ -908,12 +908,12 @@ const translations = { footerPlayground: "Пісочниця", footerAbout: "Про нас", footerSupport: "Підтримка", - footerSupportText: "Допоможи зберегти Code Crispies безкоштовним та з відкритим кодом.", + footerSupportText: "Допоможи зберегти CODE CRISPIES безкоштовним та з відкритим кодом.", footerLicense: "Передано у суспільне надбання.", // Help Dialog Support supportTitle: "Підтримати проєкт", - supportText: "Допоможи зберегти Code Crispies безкоштовним та з відкритим кодом." + supportText: "Допоможи зберегти CODE CRISPIES безкоштовним та з відкритим кодом." } }; diff --git a/src/impl/CodeEditor.js b/src/impl/CodeEditor.js index 6680fe2..29f078e 100644 --- a/src/impl/CodeEditor.js +++ b/src/impl/CodeEditor.js @@ -60,8 +60,8 @@ const crispyTheme = EditorView.theme( { dark: true } ); -// Syntax highlighting with purple accent -const crispyHighlight = HighlightStyle.define([ +// Default syntax highlighting (blue accent) +const defaultHighlight = HighlightStyle.define([ { tag: tags.keyword, color: "#c9a6eb" }, { tag: tags.operator, color: "#cdd6f4" }, { tag: tags.variableName, color: "#89b4fa" }, @@ -83,8 +83,42 @@ const crispyHighlight = HighlightStyle.define([ { tag: tags.color, color: "#f9e2af" } ]); -// Combined theme export -export const crispyEditorTheme = [crispyTheme, syntaxHighlighting(crispyHighlight)]; +// CSS section highlighting (purple selectors) +const cssHighlight = HighlightStyle.define([ + { tag: tags.keyword, color: "#c9a6eb" }, + { tag: tags.operator, color: "#cdd6f4" }, + { tag: tags.variableName, color: "#c9a6eb" }, + { tag: tags.propertyName, color: "#89b4fa" }, + { tag: tags.attributeName, color: "#89b4fa" }, + { tag: tags.className, color: "#c9a6eb" }, + { tag: tags.tagName, color: "#c9a6eb" }, + { tag: tags.string, color: "#a6e3a1" }, + { tag: tags.number, color: "#fab387" }, + { tag: tags.bool, color: "#fab387" }, + { tag: tags.null, color: "#fab387" }, + { tag: tags.comment, color: "#6c7086", fontStyle: "italic" }, + { tag: tags.bracket, color: "#cdd6f4" }, + { tag: tags.punctuation, color: "#cdd6f4" }, + { tag: tags.definition(tags.variableName), color: "#c9a6eb" }, + { tag: tags.function(tags.variableName), color: "#89b4fa" }, + { tag: tags.atom, color: "#c9a6eb" }, + { tag: tags.unit, color: "#a6e3a1" }, + { tag: tags.color, color: "#f9e2af" } +]); + +// Get highlight style based on section +function getHighlightForSection(section) { + if (section === "css") return cssHighlight; + return defaultHighlight; +} + +// Get theme with section-specific highlighting +export function getEditorTheme(section) { + return [crispyTheme, syntaxHighlighting(getHighlightForSection(section))]; +} + +// Default combined theme export (for backwards compatibility) +export const crispyEditorTheme = [crispyTheme, syntaxHighlighting(defaultHighlight)]; // Custom overrides for editor styling const editorTheme = EditorView.theme( @@ -110,6 +144,7 @@ export class CodeEditor { this.options = options; this.view = null; this.mode = options.mode || "css"; + this.section = options.section || null; this.onChange = options.onChange || (() => {}); } @@ -126,7 +161,7 @@ export class CodeEditor { // Build extensions array const extensions = [ langExtension, - crispyEditorTheme, + getEditorTheme(this.section), editorTheme, // History for undo/redo history(), @@ -215,6 +250,17 @@ export class CodeEditor { this.init(currentValue); } + /** + * Set section for theme (css, html, tailwind) + */ + setSection(section) { + if (this.section === section) return; + + this.section = section; + const currentValue = this.getValue(); + this.init(currentValue); + } + /** * Focus the editor */ diff --git a/src/index.html b/src/index.html index fbbb4f3..bb8d741 100644 --- a/src/index.html +++ b/src/index.html @@ -6,7 +6,7 @@ - Code Crispies - Learn HTML & CSS Interactively | Free Coding Practice + CODE CRISPIES - Learn HTML & CSS Interactively | Free Coding Practice - + - + - + @@ -35,7 +35,7 @@ { "@context": "https://schema.org", "@type": "WebApplication", - "name": "Code Crispies", + "name": "CODE CRISPIES", "description": "Interactive platform for learning HTML, CSS, and Tailwind through hands-on coding exercises", "url": "https://codecrispi.es/", "applicationCategory": "EducationalApplication", @@ -100,7 +100,7 @@
-

Why Code Crispies Works

+

Why CODE CRISPIES Works

@@ -198,7 +198,7 @@
@@ -227,6 +227,38 @@
+ @@ -243,8 +275,37 @@ -