115 lines
No EOL
3.3 KiB
JavaScript
115 lines
No EOL
3.3 KiB
JavaScript
(() => {
|
|
'use strict';
|
|
|
|
const root = document.documentElement;
|
|
const STORAGE_KEY = 'signal-admin-theme';
|
|
|
|
// ===== Theme Management =====
|
|
|
|
const themeButtons = document.querySelectorAll('.theme-button');
|
|
|
|
function setTheme(theme) {
|
|
root.setAttribute('data-theme', theme);
|
|
themeButtons.forEach((button) => {
|
|
const isActive = button.dataset.theme === theme;
|
|
button.dataset.active = isActive ? 'true' : 'false';
|
|
button.setAttribute('aria-checked', isActive ? 'true' : 'false');
|
|
});
|
|
try {
|
|
localStorage.setItem(STORAGE_KEY, theme);
|
|
} catch {
|
|
// Storage unavailable or full
|
|
}
|
|
}
|
|
|
|
function initTheme() {
|
|
let theme = 'light';
|
|
try {
|
|
const stored = localStorage.getItem(STORAGE_KEY);
|
|
if (stored === 'light' || stored === 'dark') {
|
|
theme = stored;
|
|
} else if (window.matchMedia?.('(prefers-color-scheme: dark)').matches) {
|
|
theme = 'dark';
|
|
}
|
|
} catch {
|
|
// Storage unavailable
|
|
}
|
|
setTheme(theme);
|
|
}
|
|
|
|
themeButtons.forEach((button) => {
|
|
button.addEventListener('click', () => setTheme(button.dataset.theme || 'light'));
|
|
});
|
|
|
|
// ===== User Detail Binding =====
|
|
|
|
const tableBody = document.querySelector('#user-table tbody');
|
|
const rows = tableBody ? Array.from(tableBody.querySelectorAll('tr')) : [];
|
|
const detailEmpty = document.querySelector('.detail-empty');
|
|
const detailBody = document.querySelector('.detail-body');
|
|
|
|
// Cached detail field references
|
|
const detailFields = {
|
|
name: document.getElementById('detail-name'),
|
|
email: document.getElementById('detail-email'),
|
|
role: document.getElementById('detail-role'),
|
|
status: document.getElementById('detail-status'),
|
|
sessions: document.getElementById('detail-sessions'),
|
|
};
|
|
|
|
let selectedRow = null;
|
|
|
|
function updateDetail(row) {
|
|
if (!row) return;
|
|
|
|
const cells = row.querySelectorAll('td');
|
|
if (cells.length < 6) return;
|
|
|
|
const statusEl = cells[4].querySelector('.status');
|
|
|
|
detailFields.name.textContent = cells[1].textContent.trim();
|
|
detailFields.email.textContent = cells[2].textContent.trim();
|
|
detailFields.role.textContent = cells[3].textContent.trim();
|
|
detailFields.status.textContent = statusEl?.textContent.trim() ?? '—';
|
|
detailFields.sessions.textContent = cells[5].textContent.trim();
|
|
}
|
|
|
|
function selectRow(row) {
|
|
// Deselect previous row
|
|
if (selectedRow) {
|
|
selectedRow.removeAttribute('aria-selected');
|
|
selectedRow.style.background = '';
|
|
}
|
|
|
|
selectedRow = row;
|
|
|
|
if (!row) {
|
|
detailEmpty?.setAttribute('data-state', 'empty');
|
|
detailBody?.setAttribute('data-state', 'inactive');
|
|
detailBody?.toggleAttribute('hidden', true);
|
|
return;
|
|
}
|
|
|
|
// Select new row
|
|
row.setAttribute('aria-selected', 'true');
|
|
row.style.background = 'rgba(16, 179, 187, 0.08)';
|
|
|
|
// Update detail view
|
|
updateDetail(row);
|
|
detailEmpty?.setAttribute('data-state', 'active');
|
|
detailBody?.setAttribute('data-state', 'active');
|
|
detailBody?.toggleAttribute('hidden', false);
|
|
}
|
|
|
|
// Event delegation for table rows
|
|
tableBody?.addEventListener('click', (e) => {
|
|
const row = e.target.closest('tr');
|
|
if (row) selectRow(row);
|
|
});
|
|
|
|
// Initialize: show empty state
|
|
selectRow(null);
|
|
|
|
// Initialize theme
|
|
initTheme();
|
|
})(); |