Files
ts3-monolith-go/internal/web/assets/app.js
T
2026-11-04 14:57:48 +01:00

126 lines
4.2 KiB
JavaScript

(function () {
'use strict';
// --- theme (dark/light), persisted per browser -------------------------
var THEME_KEY = 'ts3monolith-theme';
var root = document.documentElement;
var toggle = document.querySelector('.theme-toggle');
var graphs = document.querySelectorAll('.js-live-graph');
var openers = document.querySelectorAll('.js-graph-open');
function currentTheme() {
return root.getAttribute('data-theme') === 'light' ? 'light' : 'dark';
}
// RRD graphs are static PNGs rendered server-side in both a dark and a
// light palette (see internal/rrd/rrd.go); swap to the variant matching
// the active theme so panel graphs never clash with the page around them.
function applyGraphTheme(theme) {
var stamp = Date.now();
graphs.forEach(function (img) {
var src = theme === 'light' ? img.dataset.srcLight : img.dataset.src;
if (src) img.src = src + '?v=' + stamp;
});
openers.forEach(function (button) {
var full = theme === 'light' ? button.getAttribute('data-full-light') : button.getAttribute('data-full');
if (full) button.setAttribute('data-full-active', full);
});
}
function applyTheme(mode) {
if (mode === 'light') root.setAttribute('data-theme', 'light');
else root.removeAttribute('data-theme');
applyGraphTheme(mode === 'light' ? 'light' : 'dark');
}
try {
var saved = window.localStorage.getItem(THEME_KEY);
if (saved) applyTheme(saved);
else applyGraphTheme(currentTheme());
} catch (e) {
applyGraphTheme(currentTheme());
}
if (toggle) {
toggle.addEventListener('click', function () {
var next = currentTheme() === 'light' ? 'dark' : 'light';
applyTheme(next);
try { window.localStorage.setItem(THEME_KEY, next); } catch (e) { /* ignore */ }
});
}
// --- live stats + graph refresh -----------------------------------------
var count = document.getElementById('online-count');
var status = document.getElementById('refresh-status');
var progress = document.getElementById('route-progress');
function setBusy(busy) {
if (progress) progress.hidden = !busy;
}
function refresh() {
setBusy(true);
if (status) status.textContent = 'Odświeżanie…';
var done = Promise.resolve();
if (count) {
done = fetch('/stats/live', { cache: 'no-store' })
.then(function (response) {
if (!response.ok) throw new Error('stats');
return response.json();
})
.then(function (data) {
if (typeof data.current === 'number') count.textContent = String(data.current);
if (status) status.textContent = 'Dane aktualne';
})
.catch(function () {
if (status) status.textContent = 'Nie udało się odświeżyć';
});
}
applyGraphTheme(currentTheme());
done.then(function () { setBusy(false); });
}
if (count || graphs.length) {
window.setInterval(refresh, 60000);
}
// --- graph lightbox -------------------------------------------------------
var lightbox = document.getElementById('graph-lightbox');
var lightboxImage = document.getElementById('lightbox-image');
var openers = document.querySelectorAll('.js-graph-open');
var closeButtons = document.querySelectorAll('[data-lightbox-close]');
function openLightbox(src) {
if (!lightbox || !lightboxImage) return;
lightboxImage.src = src + (src.indexOf('?') === -1 ? '?' : '&') + 'v=' + Date.now();
lightbox.hidden = false;
lightbox.setAttribute('aria-hidden', 'false');
document.body.classList.add('lightbox-open');
}
function closeLightbox() {
if (!lightbox || !lightboxImage) return;
lightbox.hidden = true;
lightbox.setAttribute('aria-hidden', 'true');
lightboxImage.src = '';
document.body.classList.remove('lightbox-open');
}
openers.forEach(function (button) {
button.addEventListener('click', function () {
var src = button.getAttribute('data-full-active') || button.getAttribute('data-full');
if (src) openLightbox(src);
});
});
closeButtons.forEach(function (button) {
button.addEventListener('click', closeLightbox);
});
document.addEventListener('keydown', function (event) {
if (event.key === 'Escape' && lightbox && !lightbox.hidden) closeLightbox();
});
})();