Веб-UI: темы, навигация API, статистика и доработки API

- Шапка: логотип Kubernetes, ссылка на главную, выпадающее меню API (Swagger/ReDoc/Health), переключатель светлой/тёмной темы (localStorage).
- Светлая тема в синей гамме; выравнивание кнопки темы в ряду с пилюлями.
- Дашборд: единая карточка ошибки health/stats, подсказка Docker/Podman, поле container_cli в GET /stats, total_workers_from_meta всегда число (0 без meta).
- Правки кластеров, job_store, compose, документация и частичные шаблоны.
This commit is contained in:
Sergey Antropoff
2026-04-04 07:58:19 +03:00
parent aa8003061e
commit 6f3daa33ec
20 changed files with 1885 additions and 451 deletions
+59
View File
@@ -0,0 +1,59 @@
/**
* Переключение светлой/тёмной темы: 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");
}
function init() {
var btn = document.getElementById("theme-toggle");
if (btn) btn.addEventListener("click", toggleTheme);
syncToggleButton();
}
/* defer: скрипт в <head> выполняется после разбора документа — кнопка уже есть. */
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init);
} else {
init();
}
})();