feat: add dark mode support v2
This commit is contained in:
@@ -1,3 +1,63 @@
|
||||
// ============ THEME ============
|
||||
const THEME_STORAGE_KEY = 'agentdash-theme';
|
||||
const themeToggleBtn = document.getElementById('theme-toggle');
|
||||
const systemThemeMedia = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
|
||||
function getSystemTheme() {
|
||||
return systemThemeMedia.matches ? 'dark' : 'light';
|
||||
}
|
||||
|
||||
function getSavedTheme() {
|
||||
try {
|
||||
const saved = localStorage.getItem(THEME_STORAGE_KEY);
|
||||
return saved === 'light' || saved === 'dark' ? saved : null;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function setSavedTheme(theme) {
|
||||
try {
|
||||
localStorage.setItem(THEME_STORAGE_KEY, theme);
|
||||
} catch {
|
||||
// Ignore localStorage errors (privacy mode, quota, etc.).
|
||||
}
|
||||
}
|
||||
|
||||
function updateThemeToggleLabel() {
|
||||
if (!themeToggleBtn) return;
|
||||
const isDarkTheme = document.documentElement.getAttribute('data-theme') === 'dark';
|
||||
const nextTheme = isDarkTheme ? 'light' : 'dark';
|
||||
themeToggleBtn.textContent = isDarkTheme ? 'Light Mode' : 'Dark Mode';
|
||||
themeToggleBtn.setAttribute('aria-label', `Switch to ${nextTheme} mode`);
|
||||
}
|
||||
|
||||
function applyTheme(theme, { persist = false } = {}) {
|
||||
document.documentElement.setAttribute('data-theme', theme);
|
||||
if (persist) setSavedTheme(theme);
|
||||
updateThemeToggleLabel();
|
||||
if (usageStats) renderUsageCharts();
|
||||
}
|
||||
|
||||
function initTheme() {
|
||||
const savedTheme = getSavedTheme();
|
||||
applyTheme(savedTheme || getSystemTheme());
|
||||
|
||||
if (themeToggleBtn) {
|
||||
themeToggleBtn.addEventListener('click', () => {
|
||||
const currentTheme = document.documentElement.getAttribute('data-theme') || getSystemTheme();
|
||||
const nextTheme = currentTheme === 'dark' ? 'light' : 'dark';
|
||||
applyTheme(nextTheme, { persist: true });
|
||||
});
|
||||
}
|
||||
|
||||
systemThemeMedia.addEventListener('change', (event) => {
|
||||
if (!getSavedTheme()) {
|
||||
applyTheme(event.matches ? 'dark' : 'light');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// ============ NAVIGATION ============
|
||||
const navLinks = document.querySelectorAll('.nav-link');
|
||||
const pages = document.querySelectorAll('.page');
|
||||
@@ -559,6 +619,11 @@ function renderUsageStats() {
|
||||
}
|
||||
|
||||
function renderUsageCharts() {
|
||||
const rootStyles = getComputedStyle(document.documentElement);
|
||||
const themeForeground = rootStyles.getPropertyValue('--fg').trim() || '#e0e0e0';
|
||||
const themeBorder = rootStyles.getPropertyValue('--border').trim() || '#444';
|
||||
const themePrimary = rootStyles.getPropertyValue('--primary').trim() || '#3498db';
|
||||
|
||||
// Provider chart
|
||||
const providerCtx = document.getElementById('chart-provider').getContext('2d');
|
||||
|
||||
@@ -583,7 +648,7 @@ function renderUsageCharts() {
|
||||
plugins: {
|
||||
legend: {
|
||||
position: 'bottom',
|
||||
labels: { color: '#e0e0e0' }
|
||||
labels: { color: themeForeground }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -604,7 +669,7 @@ function renderUsageCharts() {
|
||||
datasets: [{
|
||||
label: 'Requests',
|
||||
data: agentData,
|
||||
backgroundColor: '#3498db'
|
||||
backgroundColor: themePrimary
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
@@ -617,12 +682,12 @@ function renderUsageCharts() {
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
ticks: { color: '#e0e0e0' },
|
||||
grid: { color: '#444' }
|
||||
ticks: { color: themeForeground },
|
||||
grid: { color: themeBorder }
|
||||
},
|
||||
x: {
|
||||
ticks: { color: '#e0e0e0' },
|
||||
grid: { color: '#444' }
|
||||
ticks: { color: themeForeground },
|
||||
grid: { color: themeBorder }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -708,6 +773,7 @@ function escapeHtml(text) {
|
||||
|
||||
// ============ INITIALIZATION ============
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
initTheme();
|
||||
populateAgentDropdown();
|
||||
loadTasks();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user