Files
KindClustersDashboard/app/static/js/theme.js
T
Sergey Antropoff eb063aec20 Веб-интерфейс: страница /clusters, навигация и крошки для кластеров
- Выделена страница списка кластеров, панель упрощена; nav_active и крошки
  ведут в раздел Кластеры; theme.js синхронизирует активную пилюлю по URL.
- Доработки дашборда, аддонов, журнала, стилей и API-документации.
- Поддержка Podman: docker-compose.podman.yml, скрипты сокета; Makefile и env.
2026-04-04 13:42:21 +03:00

109 lines
4.0 KiB
JavaScript

/**
* Переключение светлой/тёмной темы: data-theme на <html>, ключ localStorage.
* Начальная тема задаётся инлайн-скриптом в base.html (без мигания).
*
* Автор: Сергей Антропов
* Сайт: https://devops.org.ru
*/
(function () {
"use strict";
var STORAGE_KEY = "kind_k8s_theme";
function getTheme() {
var t = document.documentElement.getAttribute("data-theme");
return t === "light" ? "light" : "dark";
}
function setTheme(theme) {
var next = theme === "light" ? "light" : "dark";
document.documentElement.setAttribute("data-theme", next);
try {
localStorage.setItem(STORAGE_KEY, next);
} catch (e) {
/* приватный режим и т.п. */
}
syncToggleButton();
}
function syncToggleButton() {
var btn = document.getElementById("theme-toggle");
if (!btn) return;
var dark = getTheme() === "dark";
btn.setAttribute("aria-pressed", dark ? "true" : "false");
if (dark) {
btn.setAttribute("aria-label", "Включить светлую тему");
btn.setAttribute("title", "Светлая тема");
} else {
btn.setAttribute("aria-label", "Включить тёмную тему");
btn.setAttribute("title", "Тёмная тема");
}
}
function toggleTheme() {
setTheme(getTheme() === "dark" ? "light" : "dark");
}
/**
* Нормализует pathname: убирает хвостовые слэши (кроме корня «/»).
* Нужен для сопоставления с маршрутами FastAPI без зависимости от редиректов.
*/
function normalizePathname(path) {
var p = path || "/";
if (p.length > 1 && p.charAt(p.length - 1) === "/") {
p = p.replace(/\/+$/, "");
}
return p || "/";
}
/**
* Какой пункт шапки (href пилюли) должен быть активен по текущему URL.
* Дублирует логику nav_active из шаблонов: страницы кластера и /cluster/…/edit
* относятся к разделу «Кластеры», чтобы подсветка не зависела только от SSR
* (кэш образа, устаревший контейнер и т.п.).
*/
function desiredNavHrefFromPath() {
var path = normalizePathname(window.location.pathname);
if (path === "/") return "/";
if (path === "/clusters") return "/clusters";
if (/^\/cluster\/[^/]+\/edit$/.test(path)) return "/clusters";
if (/^\/cluster\/[^/]+$/.test(path)) return "/clusters";
if (path.indexOf("/cluster-addons") === 0) return "/cluster-addons";
if (path.indexOf("/journal") === 0) return "/journal";
if (path.indexOf("/documentation") === 0) return "/documentation";
if (path.indexOf("/cluster-create") === 0) return "/clusters";
return null;
}
/** Снимает активность со всех пилюль в прокручиваемой полосе и включает одну по href. */
function syncNavPillActive() {
var want = desiredNavHrefFromPath();
if (!want) return;
var scroll = document.querySelector(".nav-links-scroll");
if (!scroll) return;
var pills = scroll.querySelectorAll("a.nav-link.nav-pill[href]");
pills.forEach(function (a) {
a.classList.remove("nav-pill--active");
});
pills.forEach(function (a) {
if (a.getAttribute("href") === want) {
a.classList.add("nav-pill--active");
}
});
}
function init() {
var btn = document.getElementById("theme-toggle");
if (btn) btn.addEventListener("click", toggleTheme);
syncToggleButton();
syncNavPillActive();
}
/* defer: скрипт в <head> выполняется после разбора документа — кнопка уже есть. */
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init);
} else {
init();
}
})();