Light/Dark Mode Toggle

This commit is contained in:
John Haverlack 2026-02-01 12:22:58 -09:00
parent d322358115
commit e1ffcaa696
6 changed files with 114 additions and 16 deletions

View File

@ -31,6 +31,12 @@
"page": "docs",
"enabled": true
},
{
"title": "Settings",
"icon": "fa-solid fa-gear",
"page": "settings",
"enabled": true
},
{
"title": "API",
"icon": "fa-solid fa-code",

View File

@ -213,6 +213,17 @@ json-viewer .property:hover {
color: hwb(0 55% 45%);
}
/* .dash-val {
color: hwb(116 7% 35%);
} */
[data-bs-theme="light"] .dash-val {
color: hwb(116 0% 46%);
}
[data-bs-theme="dark"] .dash-val {
color: hwb(116 40% 0%); /* 40% lighter for dark backgrounds */
}
/* Dark Theme */

View File

@ -35,7 +35,7 @@ if (Array.isArray(config.host.gpu) && config.host.gpu.length > 0) {
gpu.memory?.type === 'dedicated' &&
Number.isFinite(gpu.memory.total_mb)
) {
memLabel = `(<span class="text-success">${Math.round(gpu.memory.total_mb / 1024)}</span> GB VRAM)`;
memLabel = `(<span class="dash-val">${Math.round(gpu.memory.total_mb / 1024)}</span> GB VRAM)`;
} else if (gpu.memory?.type === 'shared') {
memLabel = '(shared VRAM)';
} else {
@ -54,11 +54,11 @@ if (Array.isArray(config.host.gpu) && config.host.gpu.length > 0) {
// Hostinfo: hostname, cpu, cores, ram, os
const hostinfo = {
"hostname": '<span class="text-success">' + config.host.hostname + '</span>',
"sdl_id": '<span class="text-success" style=" font-size:0.7em">' + config.identity.sdl_id + '</span>',
"cpu cores": '<span class="text-success">' + config.host.cpu.cores_logical + '</span> <span style="font-size:0.7em">' + config.host.cpu.model + '</span>',
"hostname": '<span class="dash-val">' + config.host.hostname + '</span>',
"sdl_id": '<span class="dash-val" style=" font-size:0.7em">' + config.identity.sdl_id + '</span>',
"cpu cores": '<span class="dash-val">' + config.host.cpu.cores_logical + '</span> <span style="font-size:0.7em">' + config.host.cpu.model + '</span>',
// "cores": config.host.cpu.cores_logical,
"ram": '<span class="text-success">' + config.host.memory.total_gb + '</span> GB ',
"ram": '<span class="dash-val">' + config.host.memory.total_gb + '</span> GB ',
"gpu": gpuSummary,
"net": "",
"os": config.host.os.pretty_name
@ -70,7 +70,7 @@ for (let intf in config.host.network) {
if (intf != 'lo') {
for (let addr in config.host.network[intf]) {
if (config.host.network[intf][addr].family == 'IPv4') {
hostinfo["net"] += '<span class="text-success" style=" font-size: 0.8em">' + config.host.network[intf][addr].cidr + '</span><br> ';
hostinfo["net"] += '<span class="dash-val" style=" font-size: 0.8em">' + config.host.network[intf][addr].cidr + '</span><br> ';
}
}
}
@ -271,55 +271,56 @@ function renderModulesTable(msg) {
sdl_html += `
<tr>
<th>SDL Version</th>
<td class="text-success" style="font-size:1em">v${msg.msg.sdl.version}</td>
<td class="dash-val" style="font-size:1em">v${msg.msg.sdl.version}</td>
</tr>
`;
sdl_html += `
<tr>
<th>Uptime (d.h.m.s)</th>
<td class="text-success" style=" font-size:0.8em">${msg.msg.sdl.uptime}</td>
<td class="dash-val" style=" font-size:0.8em">${msg.msg.sdl.uptime}</td>
</tr>
`;
sdl_html += `
<tr>
<th>Cluster ID</th>
<td class="text-success" style=" font-size:1em">${msg.msg.cluster.id}</td>
<td class="dash-val" style=" font-size:1em">${msg.msg.cluster.id}</td>
</tr>
`;
sdl_html += `
<tr>
<th>Cluster Name</th>
<td class="text-success" style=" font-size:1em">${msg.msg.cluster.name}</td>
<td class="dash-val" style=" font-size:1em">${msg.msg.cluster.name}</td>
</tr>
`;
sdl_html += `
<tr>
<th>Cluster Desc</th>
<td class="text-success" style=" font-size:0.8em">${msg.msg.cluster.desc}</td>
<td class="dash-val" style=" font-size:0.8em">${msg.msg.cluster.desc}</td>
</tr>
`;
sdl_html += `
<tr>
<th><span class="fa fa-microchip" title="CPU Cores" style="font-size:1.2em"></span> CPU</th>
<td class="text-success" style=" font-size:1em"></td>
<td class="dash-val" style=" font-size:1em"></td>
</tr>
`;
sdl_html += `
<tr>
<th><span class="fa fa-memory" title="RAM" style="font-size:1.2em"></span> RAM</th>
<td class="text-success" style=" font-size:1em"></td>
<td class="dash-val" style=" font-size:1em"></td>
</tr>
`;
sdl_html += `
<tr>
<th><span class="fa fa-dice-d20" title="GPU" style="font-size:1.2em"></span> GPU</th>
<td class="text-success" style=" font-size:1em"></td>
<td class="dash-val" style=" font-size:1em"></td>
</tr>
`;
@ -339,7 +340,7 @@ function renderModulesTable(msg) {
for (const [name, info] of Object.entries(modules)) {
const ok = info.enabled === true;
const icon = ok
? '<i class="fa-solid fa-circle-check text-success"></i>'
? '<i class="fa-solid fa-circle-check dash-val"></i>'
: '<i class="fa-solid fa-circle-xmark text-danger"></i>';
html += `
@ -386,7 +387,7 @@ function startStatusAgeMonitor() {
markAllModulesDown();
} else {
ageEl.innerHTML =
`<span class="text-success">
`<span class="dash-val">
<i class="fa-solid fa-circle-check"></i>
SDL online (${Math.round(ageMs / 1000)}s ago)
</span>`;

View File

@ -0,0 +1,50 @@
console.log('Settings.js loaded');
// Get current theme from localStorage
const currentTheme = localStorage.getItem('theme') || 'dark';
console.log('Current theme:', currentTheme);
// Set the toggle to match current theme
const themeSwitch = document.getElementById('themeSwitch');
const themeLabel = document.querySelector('label[for="themeSwitch"]');
console.log('Theme switch element found:', themeSwitch);
if (themeSwitch && themeLabel) {
themeSwitch.checked = (currentTheme === 'dark');
// Update label based on current theme
updateLabel(currentTheme);
console.log('Switch checked state:', themeSwitch.checked);
// Listen for changes
themeSwitch.addEventListener('change', (e) => {
console.log('Switch toggled!', e.target.checked);
const newTheme = e.target.checked ? 'dark' : 'light';
console.log('Setting new theme:', newTheme);
setTheme(newTheme);
updateLabel(newTheme);
});
} else {
console.error('themeSwitch or themeLabel element not found!');
}
function setTheme(theme) {
console.log('setTheme called with:', theme);
document.documentElement.setAttribute('data-bs-theme', theme);
localStorage.setItem('theme', theme);
console.log('Theme set to:', theme);
console.log('HTML data-bs-theme attribute:', document.documentElement.getAttribute('data-bs-theme'));
}
function updateLabel(theme) {
const themeLabel = document.querySelector('label[for="themeSwitch"]');
if (themeLabel) {
if (theme === 'dark') {
themeLabel.innerHTML = '<i class="fas fa-moon me-2"></i>Dark Mode';
} else {
themeLabel.innerHTML = '<i class="fas fa-sun me-2"></i>Light Mode';
}
}
}

View File

@ -832,6 +832,9 @@ export async function getUTCTimestamp() {
// Load on page load
// ===============================
window.addEventListener('DOMContentLoaded', async () => {
// Apply saved theme (default to dark)
const savedTheme = localStorage.getItem('theme') || 'dark';
document.documentElement.setAttribute('data-bs-theme', savedTheme);
const config = await loadConfig();
// console.log(`DEBUG: ${JSON.stringify(config)}`)
@ -849,6 +852,7 @@ window.addEventListener('DOMContentLoaded', async () => {
loadFooter();
// Load Markdown content
const urlParams = new URLSearchParams(window.location.search);
const page = urlParams.get('page') || 'index';

View File

@ -0,0 +1,26 @@
<div class="container-fluid mt-4">
<div class="row">
<div class="col-lg-6 col-md-8">
<div class="card mt-4">
<div class="card-header">
<h5 class="mb-0">Appearance</h5>
</div>
<div class="card-body">
<div class="row align-items-center">
<div class="col-8">
<label for="themeSwitch" class="form-label mb-1">
<i class="fas fa-moon me-2"></i>Dark Mode
</label>
<p class="text-muted small mb-0">Toggle between light and dark theme</p>
</div>
<div class="col-4 text-end">
<div class="form-check form-switch d-inline-block">
<input class="form-check-input" type="checkbox" role="switch" id="themeSwitch" checked>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>