- Rename app title to SUB-ALIGATOR (header, page titles, exports, README) - Add dark amber-terminal theme with a header toggle, persisted in localStorage - Add pool deletion (soft delete): allocations are kept in history and block the address space again when the same or an overlapping pool is re-added (re-enable on exact CIDR match, re-attach contained allocations) - Reject new pools that overlap an enabled pool - Move Home link into the page header, keep other links in the footer - Load app.js globally via base template, add theme.js (CSP-safe, no inline JS)
49 lines
1.3 KiB
JavaScript
49 lines
1.3 KiB
JavaScript
(function () {
|
|
var STORAGE_KEY = 'sub-aligator-theme';
|
|
|
|
function storedTheme() {
|
|
try {
|
|
return localStorage.getItem(STORAGE_KEY);
|
|
} catch (e) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
function currentTheme() {
|
|
return document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light';
|
|
}
|
|
|
|
function applyTheme(theme) {
|
|
document.documentElement.setAttribute('data-theme', theme);
|
|
}
|
|
|
|
// Apply the saved theme before the body renders to avoid a flash of the wrong theme.
|
|
applyTheme(storedTheme() === 'dark' ? 'dark' : 'light');
|
|
|
|
function updateToggle(btn) {
|
|
btn.textContent = currentTheme() === 'dark' ? '[ Light ]' : '[ Dark ]';
|
|
btn.setAttribute('aria-pressed', currentTheme() === 'dark' ? 'true' : 'false');
|
|
}
|
|
|
|
function wireToggle() {
|
|
var btn = document.getElementById('theme-toggle');
|
|
if (!btn) {
|
|
return;
|
|
}
|
|
updateToggle(btn);
|
|
btn.addEventListener('click', function () {
|
|
var next = currentTheme() === 'dark' ? 'light' : 'dark';
|
|
applyTheme(next);
|
|
try {
|
|
localStorage.setItem(STORAGE_KEY, next);
|
|
} catch (e) {}
|
|
updateToggle(btn);
|
|
});
|
|
}
|
|
|
|
if (document.readyState === 'loading') {
|
|
document.addEventListener('DOMContentLoaded', wireToggle);
|
|
} else {
|
|
wireToggle();
|
|
}
|
|
})();
|