eb063aec20
- Выделена страница списка кластеров, панель упрощена; nav_active и крошки ведут в раздел Кластеры; theme.js синхронизирует активную пилюлю по URL. - Доработки дашборда, аддонов, журнала, стилей и API-документации. - Поддержка Podman: docker-compose.podman.yml, скрипты сокета; Makefile и env.
109 lines
4.0 KiB
JavaScript
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();
|
|
}
|
|
})();
|