Unifi-Voucher-Tool/assets/global.js
Friederich Loheide 2fe7e9522d
Some checks are pending
CI / PHP Lint (push) Waiting to run
CI / PHP Lint-1 (push) Waiting to run
CI / Unit Tests & Static Analysis (push) Waiting to run
CI / PHP Lint (pull_request) Waiting to run
CI / PHP Lint-1 (pull_request) Waiting to run
CI / Unit Tests & Static Analysis (pull_request) Waiting to run
Theme-Auswahl aus dem Seitenkopf nicht mehr überschreiben
global.js hat beim Laden erneut ein Theme gesetzt und dabei die
Entscheidung des Inline-Schnipsels im <head> verworfen – sichtbar als
kurzes Umspringen und daran, dass erzwungene Themes ignoriert wurden.
Jetzt gilt: ausdrückliche Auswahl > bereits gesetztes Attribut > System.

Updater-Seite übernimmt ebenfalls die Markenfarben, Screenshots neu.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-23 06:53:57 +00:00

136 lines
4.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* === DARK MODE ===
Reihenfolge: ausdrueckliche Auswahl des Nutzers > Systemeinstellung. */
(function() {
const saved = localStorage.getItem('theme');
// Der Inline-Schnipsel im <head> hat das Theme bereits gesetzt diese
// Entscheidung wird hier nicht überschrieben.
const current = document.documentElement.getAttribute('data-theme');
const system = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
document.documentElement.setAttribute('data-theme', saved || current || system);
// Solange nichts ausgewaehlt wurde, folgt die Oberflaeche dem System.
if (!saved && window.matchMedia) {
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
if (localStorage.getItem('theme')) return;
document.documentElement.setAttribute('data-theme', e.matches ? 'dark' : 'light');
if (typeof updateDarkModeBtn === 'function') updateDarkModeBtn();
});
}
})();
function toggleDarkMode() {
const html = document.documentElement;
const current = html.getAttribute('data-theme') || 'light';
const next = current === 'dark' ? 'light' : 'dark';
html.setAttribute('data-theme', next);
localStorage.setItem('theme', next);
updateDarkModeBtn();
}
function updateDarkModeBtn() {
const btn = document.getElementById('darkModeBtn');
if (!btn) return;
const isDark = document.documentElement.getAttribute('data-theme') === 'dark';
const icon = btn.querySelector('i');
if (icon) {
icon.className = isDark ? 'fas fa-sun' : 'fas fa-moon';
} else {
btn.textContent = isDark ? '☀' : '☾';
}
btn.title = isDark ? 'Light Mode' : 'Dark Mode';
}
document.addEventListener('DOMContentLoaded', updateDarkModeBtn);
/* === TOAST NOTIFICATIONS === */
(function() {
let container = null;
function getContainer() {
if (!container) {
container = document.getElementById('toast-container');
if (!container) {
container = document.createElement('div');
container.id = 'toast-container';
document.body.appendChild(container);
}
}
return container;
}
const icons = {
success: '✓',
error: '✕',
info: 'i',
warning: '!'
};
window.showToast = function(type, title, message, duration) {
duration = duration || 4000;
const c = getContainer();
const el = document.createElement('div');
el.className = 'toast ' + type;
el.innerHTML = `
<span class="toast-icon">${icons[type] || ''}</span>
<div class="toast-body">
<div class="toast-title">${title}</div>
${message ? `<div class="toast-msg">${message}</div>` : ''}
</div>
<button class="toast-close" onclick="this.parentElement.remove()">×</button>
`;
c.appendChild(el);
requestAnimationFrame(() => {
requestAnimationFrame(() => el.classList.add('show'));
});
setTimeout(() => {
el.classList.remove('show');
setTimeout(() => el.remove(), 350);
}, duration);
return el;
};
})();
/* === MOBILE SIDEBAR === */
function toggleMobileSidebar() {
const sidebar = document.querySelector('.sidebar');
const overlay = document.querySelector('.sidebar-overlay');
if (!sidebar) return;
sidebar.classList.toggle('mobile-open');
if (overlay) overlay.classList.toggle('active');
}
function closeMobileSidebar() {
const sidebar = document.querySelector('.sidebar');
const overlay = document.querySelector('.sidebar-overlay');
if (sidebar) sidebar.classList.remove('mobile-open');
if (overlay) overlay.classList.remove('active');
}
document.addEventListener('DOMContentLoaded', function() {
const overlay = document.querySelector('.sidebar-overlay');
if (overlay) overlay.addEventListener('click', closeMobileSidebar);
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') closeMobileSidebar();
});
});
/* === LANGUAGE SWITCHER === */
function switchLanguage(lang) {
fetch('?set_lang=' + lang, { method: 'GET' }).then(() => location.reload());
}
/* === CLIPBOARD === */
function copyToClipboard(text, successMsg) {
navigator.clipboard.writeText(text).then(() => {
showToast('success', successMsg || 'Kopiert!', '');
}).catch(() => {
const ta = document.createElement('textarea');
ta.value = text;
document.body.appendChild(ta);
ta.select();
document.execCommand('copy');
document.body.removeChild(ta);
showToast('success', successMsg || 'Kopiert!', '');
});
}