add tema
This commit is contained in:
49
src/app.js
49
src/app.js
@@ -15,6 +15,8 @@ const NAV_ITEMS = [
|
||||
const SESSION_TYPES = ["open_practice", "free_practice", "practice", "qualification", "heat", "final", "team_race"];
|
||||
const STORAGE_KEY = "rc_timing_control_v1";
|
||||
const DEFAULT_LANGUAGE = "sv";
|
||||
const DEFAULT_THEME = "dark";
|
||||
const AVAILABLE_THEMES = ["dark", "nord", "light"];
|
||||
|
||||
const TRANSLATIONS = {
|
||||
sv: {
|
||||
@@ -41,6 +43,10 @@ const TRANSLATIONS = {
|
||||
"nav.guide": "Guide",
|
||||
"nav.guide_sub": "Dokumentation och uppstart",
|
||||
"ui.language": "Språk",
|
||||
"ui.theme": "Tema",
|
||||
"ui.theme_dark": "Mörk",
|
||||
"ui.theme_nord": "Nord",
|
||||
"ui.theme_light": "Ljus",
|
||||
"brand.title": "JMK RB RaceController",
|
||||
"brand.subtitle": "RC Timing System",
|
||||
"ui.no_active_session": "Ingen aktiv session",
|
||||
@@ -775,6 +781,10 @@ const TRANSLATIONS = {
|
||||
"nav.guide": "Guide",
|
||||
"nav.guide_sub": "Documentation and setup",
|
||||
"ui.language": "Language",
|
||||
"ui.theme": "Theme",
|
||||
"ui.theme_dark": "Dark",
|
||||
"ui.theme_nord": "Nord",
|
||||
"ui.theme_light": "Light",
|
||||
"brand.title": "JMK RB RaceController",
|
||||
"brand.subtitle": "RC Timing System",
|
||||
"ui.no_active_session": "No Active Session",
|
||||
@@ -1554,7 +1564,9 @@ init();
|
||||
async function init() {
|
||||
document.body.classList.toggle("overlay-mode", overlayMode);
|
||||
seedDefaultData();
|
||||
applyTheme();
|
||||
await hydrateFromBackend();
|
||||
applyTheme();
|
||||
await loadAmmcConfigFromBackend();
|
||||
renderNav();
|
||||
renderView();
|
||||
@@ -1594,6 +1606,10 @@ function seedDefaultData() {
|
||||
state.settings.language = DEFAULT_LANGUAGE;
|
||||
}
|
||||
|
||||
if (!AVAILABLE_THEMES.includes(String(state.settings.theme || "").toLowerCase())) {
|
||||
state.settings.theme = DEFAULT_THEME;
|
||||
}
|
||||
|
||||
if (typeof state.settings.audioEnabled !== "boolean") {
|
||||
state.settings.audioEnabled = true;
|
||||
}
|
||||
@@ -1678,6 +1694,7 @@ function loadState() {
|
||||
wsUrl: parsed.settings?.wsUrl || "ws://127.0.0.1:9000",
|
||||
backendUrl: parsed.settings?.backendUrl || getDefaultBackendUrl(),
|
||||
language: parsed.settings?.language || DEFAULT_LANGUAGE,
|
||||
theme: AVAILABLE_THEMES.includes(String(parsed.settings?.theme || "").toLowerCase()) ? String(parsed.settings.theme).toLowerCase() : DEFAULT_THEME,
|
||||
autoReconnect: parsed.settings?.autoReconnect !== false,
|
||||
audioEnabled: parsed.settings?.audioEnabled !== false,
|
||||
passingSoundMode: parsed.settings?.passingSoundMode || "beep",
|
||||
@@ -1720,6 +1737,7 @@ function loadState() {
|
||||
wsUrl: "ws://127.0.0.1:9000",
|
||||
backendUrl: getDefaultBackendUrl(),
|
||||
language: DEFAULT_LANGUAGE,
|
||||
theme: DEFAULT_THEME,
|
||||
autoReconnect: true,
|
||||
audioEnabled: true,
|
||||
passingSoundMode: "beep",
|
||||
@@ -1761,6 +1779,14 @@ function currentLanguage() {
|
||||
return state.settings.language === "en" ? "en" : "sv";
|
||||
}
|
||||
|
||||
function currentTheme() {
|
||||
return AVAILABLE_THEMES.includes(String(state.settings.theme || "").toLowerCase()) ? String(state.settings.theme).toLowerCase() : DEFAULT_THEME;
|
||||
}
|
||||
|
||||
function applyTheme() {
|
||||
document.body.dataset.theme = currentTheme();
|
||||
}
|
||||
|
||||
function t(key, vars = {}) {
|
||||
const lang = currentLanguage();
|
||||
const dict = TRANSLATIONS[lang] || TRANSLATIONS.en;
|
||||
@@ -1769,6 +1795,23 @@ function t(key, vars = {}) {
|
||||
}
|
||||
|
||||
function setupLanguageControl() {
|
||||
const themeLabel = document.getElementById("themeLabel");
|
||||
if (themeLabel) {
|
||||
themeLabel.textContent = t("ui.theme");
|
||||
}
|
||||
const themeSelect = document.getElementById("themeSelect");
|
||||
if (themeSelect instanceof HTMLSelectElement) {
|
||||
themeSelect.value = currentTheme();
|
||||
Array.from(themeSelect.options).forEach((option) => {
|
||||
option.textContent = t(`ui.theme_${option.value}`);
|
||||
});
|
||||
themeSelect.onchange = () => {
|
||||
state.settings.theme = AVAILABLE_THEMES.includes(themeSelect.value) ? themeSelect.value : DEFAULT_THEME;
|
||||
applyTheme();
|
||||
saveState();
|
||||
};
|
||||
}
|
||||
|
||||
const label = document.getElementById("languageLabel");
|
||||
if (label) {
|
||||
label.textContent = t("ui.language");
|
||||
@@ -1966,6 +2009,7 @@ function applyPersistedState(persisted) {
|
||||
wsUrl: persisted.settings?.wsUrl || state.settings.wsUrl || "ws://127.0.0.1:9000",
|
||||
backendUrl: persisted.settings?.backendUrl || state.settings.backendUrl || getDefaultBackendUrl(),
|
||||
language: persisted.settings?.language || state.settings.language || DEFAULT_LANGUAGE,
|
||||
theme: AVAILABLE_THEMES.includes(String(persisted.settings?.theme || state.settings.theme || DEFAULT_THEME).toLowerCase()) ? String(persisted.settings?.theme || state.settings.theme || DEFAULT_THEME).toLowerCase() : DEFAULT_THEME,
|
||||
autoReconnect: persisted.settings?.autoReconnect !== false,
|
||||
audioEnabled: persisted.settings?.audioEnabled !== false,
|
||||
passingSoundMode: persisted.settings?.passingSoundMode || state.settings.passingSoundMode || "beep",
|
||||
@@ -1987,6 +2031,7 @@ function applyPersistedState(persisted) {
|
||||
? state.settings.racePresets.map((preset) => normalizeStoredRacePreset(preset)).filter((preset) => preset.name)
|
||||
: [],
|
||||
};
|
||||
applyTheme();
|
||||
}
|
||||
|
||||
function normalizeSession(session) {
|
||||
@@ -2405,6 +2450,10 @@ function renderView() {
|
||||
if (languageLabel) {
|
||||
languageLabel.textContent = t("ui.language");
|
||||
}
|
||||
const themeLabel = document.getElementById("themeLabel");
|
||||
if (themeLabel) {
|
||||
themeLabel.textContent = t("ui.theme");
|
||||
}
|
||||
|
||||
switch (currentView) {
|
||||
case "dashboard":
|
||||
|
||||
Reference in New Issue
Block a user