refactor: move language picker to sidebar as dropdown
- Remove language button from header - Add language select dropdown in sidebar settings - Add translations for "Language" label in all languages - Remove unused .lang-switch CSS
This commit is contained in:
14
src/app.js
14
src/app.js
@@ -2,7 +2,7 @@ import { LessonEngine } from "./impl/LessonEngine.js";
|
|||||||
import { CodeEditor } from "./impl/CodeEditor.js";
|
import { CodeEditor } from "./impl/CodeEditor.js";
|
||||||
import { renderLesson, renderModuleList, renderLevelIndicator, updateActiveLessonInSidebar } from "./helpers/renderer.js";
|
import { renderLesson, renderModuleList, renderLevelIndicator, updateActiveLessonInSidebar } from "./helpers/renderer.js";
|
||||||
import { loadModules } from "./config/lessons.js";
|
import { loadModules } from "./config/lessons.js";
|
||||||
import { initI18n, t, getLanguage, setLanguage, getNextLanguage, applyTranslations } from "./i18n.js";
|
import { initI18n, t, getLanguage, setLanguage, applyTranslations } from "./i18n.js";
|
||||||
|
|
||||||
// Simplified state - LessonEngine now manages lesson state and progress
|
// Simplified state - LessonEngine now manages lesson state and progress
|
||||||
const state = {
|
const state = {
|
||||||
@@ -17,7 +17,7 @@ const elements = {
|
|||||||
// Header
|
// Header
|
||||||
menuBtn: document.getElementById("menu-btn"),
|
menuBtn: document.getElementById("menu-btn"),
|
||||||
logoLink: document.getElementById("logo-link"),
|
logoLink: document.getElementById("logo-link"),
|
||||||
langBtn: document.getElementById("lang-btn"),
|
langSelect: document.getElementById("lang-select"),
|
||||||
helpBtn: document.getElementById("help-btn"),
|
helpBtn: document.getElementById("help-btn"),
|
||||||
|
|
||||||
// Left panel
|
// Left panel
|
||||||
@@ -117,10 +117,7 @@ function toggleExpectedResult() {
|
|||||||
|
|
||||||
// ================= LANGUAGE TOGGLE =================
|
// ================= LANGUAGE TOGGLE =================
|
||||||
|
|
||||||
function toggleLanguage() {
|
function changeLanguage(newLang) {
|
||||||
const currentLang = getLanguage();
|
|
||||||
const newLang = getNextLanguage(currentLang);
|
|
||||||
|
|
||||||
// Add transition class before any updates
|
// Add transition class before any updates
|
||||||
elements.editorSection?.classList.add("transitioning");
|
elements.editorSection?.classList.add("transitioning");
|
||||||
|
|
||||||
@@ -730,8 +727,9 @@ function init() {
|
|||||||
loadCurrentLesson();
|
loadCurrentLesson();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Language toggle
|
// Language select
|
||||||
elements.langBtn.addEventListener("click", toggleLanguage);
|
elements.langSelect.value = getLanguage();
|
||||||
|
elements.langSelect.addEventListener("change", (e) => changeLanguage(e.target.value));
|
||||||
|
|
||||||
// Expected result toggle
|
// Expected result toggle
|
||||||
elements.showExpectedBtn.addEventListener("click", toggleExpectedResult);
|
elements.showExpectedBtn.addEventListener("click", toggleExpectedResult);
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ const translations = {
|
|||||||
// Sidebar
|
// Sidebar
|
||||||
menu: "Menu",
|
menu: "Menu",
|
||||||
closeMenu: "Close menu",
|
closeMenu: "Close menu",
|
||||||
|
language: "Language",
|
||||||
progress: "Progress",
|
progress: "Progress",
|
||||||
progressText: "{percent}% Complete ({completed}/{total})",
|
progressText: "{percent}% Complete ({completed}/{total})",
|
||||||
lessons: "Lessons",
|
lessons: "Lessons",
|
||||||
@@ -135,6 +136,7 @@ const translations = {
|
|||||||
// Sidebar
|
// Sidebar
|
||||||
menu: "Menü",
|
menu: "Menü",
|
||||||
closeMenu: "Menü schließen",
|
closeMenu: "Menü schließen",
|
||||||
|
language: "Sprache",
|
||||||
progress: "Fortschritt",
|
progress: "Fortschritt",
|
||||||
progressText: "{percent}% abgeschlossen ({completed}/{total})",
|
progressText: "{percent}% abgeschlossen ({completed}/{total})",
|
||||||
lessons: "Lektionen",
|
lessons: "Lektionen",
|
||||||
@@ -235,6 +237,7 @@ const translations = {
|
|||||||
// Sidebar
|
// Sidebar
|
||||||
menu: "Menu",
|
menu: "Menu",
|
||||||
closeMenu: "Zamknij menu",
|
closeMenu: "Zamknij menu",
|
||||||
|
language: "Język",
|
||||||
progress: "Postęp",
|
progress: "Postęp",
|
||||||
progressText: "{percent}% ukończone ({completed}/{total})",
|
progressText: "{percent}% ukończone ({completed}/{total})",
|
||||||
lessons: "Lekcje",
|
lessons: "Lekcje",
|
||||||
@@ -335,6 +338,7 @@ const translations = {
|
|||||||
// Sidebar
|
// Sidebar
|
||||||
menu: "Menú",
|
menu: "Menú",
|
||||||
closeMenu: "Cerrar menú",
|
closeMenu: "Cerrar menú",
|
||||||
|
language: "Idioma",
|
||||||
progress: "Progreso",
|
progress: "Progreso",
|
||||||
progressText: "{percent}% completado ({completed}/{total})",
|
progressText: "{percent}% completado ({completed}/{total})",
|
||||||
lessons: "Lecciones",
|
lessons: "Lecciones",
|
||||||
@@ -435,6 +439,7 @@ const translations = {
|
|||||||
// Sidebar
|
// Sidebar
|
||||||
menu: "القائمة",
|
menu: "القائمة",
|
||||||
closeMenu: "إغلاق القائمة",
|
closeMenu: "إغلاق القائمة",
|
||||||
|
language: "اللغة",
|
||||||
progress: "التقدم",
|
progress: "التقدم",
|
||||||
progressText: "{percent}% مكتمل ({completed}/{total})",
|
progressText: "{percent}% مكتمل ({completed}/{total})",
|
||||||
lessons: "الدروس",
|
lessons: "الدروس",
|
||||||
@@ -535,6 +540,7 @@ const translations = {
|
|||||||
// Sidebar
|
// Sidebar
|
||||||
menu: "Меню",
|
menu: "Меню",
|
||||||
closeMenu: "Закрити меню",
|
closeMenu: "Закрити меню",
|
||||||
|
language: "Мова",
|
||||||
progress: "Прогрес",
|
progress: "Прогрес",
|
||||||
progressText: "{percent}% завершено ({completed}/{total})",
|
progressText: "{percent}% завершено ({completed}/{total})",
|
||||||
lessons: "Уроки",
|
lessons: "Уроки",
|
||||||
|
|||||||
@@ -20,7 +20,6 @@
|
|||||||
<h1><span class="code-text">CODE</span><span>CRISPIES</span></h1>
|
<h1><span class="code-text">CODE</span><span>CRISPIES</span></h1>
|
||||||
</a>
|
</a>
|
||||||
<div class="header-actions">
|
<div class="header-actions">
|
||||||
<button id="lang-btn" class="lang-switch" data-i18n-aria-label="langSwitchLabel" data-i18n="langSwitch" aria-label="Sprache wechseln: Deutsch">DE</button>
|
|
||||||
<button id="help-btn" class="help-toggle" data-i18n-aria-label="help" aria-label="Help">?</button>
|
<button id="help-btn" class="help-toggle" data-i18n-aria-label="help" aria-label="Help">?</button>
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
@@ -109,6 +108,17 @@
|
|||||||
|
|
||||||
<div class="sidebar-section">
|
<div class="sidebar-section">
|
||||||
<h4 data-i18n="settings">Settings</h4>
|
<h4 data-i18n="settings">Settings</h4>
|
||||||
|
<label class="setting-row">
|
||||||
|
<span class="setting-label" data-i18n="language">Language</span>
|
||||||
|
<select id="lang-select" class="lang-select">
|
||||||
|
<option value="en">English</option>
|
||||||
|
<option value="de">Deutsch</option>
|
||||||
|
<option value="pl">Polski</option>
|
||||||
|
<option value="es">Español</option>
|
||||||
|
<option value="ar">العربية</option>
|
||||||
|
<option value="uk">Українська</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
<label class="toggle-switch">
|
<label class="toggle-switch">
|
||||||
<input type="checkbox" id="disable-feedback-toggle" checked />
|
<input type="checkbox" id="disable-feedback-toggle" checked />
|
||||||
<span class="toggle-slider"></span>
|
<span class="toggle-slider"></span>
|
||||||
|
|||||||
57
src/main.css
57
src/main.css
@@ -220,28 +220,6 @@ code, kbd {
|
|||||||
gap: var(--spacing-sm);
|
gap: var(--spacing-sm);
|
||||||
}
|
}
|
||||||
|
|
||||||
.lang-switch {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
width: 28px;
|
|
||||||
height: 28px;
|
|
||||||
border-radius: 50%;
|
|
||||||
border: 2px solid var(--border-color);
|
|
||||||
background: none;
|
|
||||||
font-size: 0.7rem;
|
|
||||||
font-weight: 700;
|
|
||||||
text-decoration: none;
|
|
||||||
color: var(--light-text);
|
|
||||||
transition: all 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.lang-switch:hover {
|
|
||||||
border-color: var(--primary-color);
|
|
||||||
color: var(--primary-color);
|
|
||||||
background: var(--primary-bg-light);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ================= GAME LAYOUT ================= */
|
/* ================= GAME LAYOUT ================= */
|
||||||
.game-layout {
|
.game-layout {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -991,6 +969,41 @@ button.lesson-list-item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ================= TOGGLE SWITCH ================= */
|
/* ================= TOGGLE SWITCH ================= */
|
||||||
|
/* Setting row (for label + control) */
|
||||||
|
.setting-row {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: var(--spacing-sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
.setting-label {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: var(--text-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Language select */
|
||||||
|
.lang-select {
|
||||||
|
padding: 6px 10px;
|
||||||
|
border: 1px solid var(--border-color);
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
background: var(--panel-bg);
|
||||||
|
color: var(--text-color);
|
||||||
|
font-size: 0.85rem;
|
||||||
|
cursor: pointer;
|
||||||
|
min-width: 120px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.lang-select:hover {
|
||||||
|
border-color: var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.lang-select:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: var(--primary-color);
|
||||||
|
box-shadow: 0 0 0 2px rgba(99, 102, 241, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
.toggle-switch {
|
.toggle-switch {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
Reference in New Issue
Block a user