94 lines
3.8 KiB
JavaScript
94 lines
3.8 KiB
JavaScript
document.addEventListener('DOMContentLoaded', () => {
|
|
const root = document.documentElement;
|
|
const theme = document.querySelector('[data-theme-select]');
|
|
const stored = (() => {
|
|
try { return localStorage.getItem('labtimesheet-theme') || 'system'; }
|
|
catch (_) { return 'system'; }
|
|
})();
|
|
if (theme) {
|
|
theme.value = stored;
|
|
theme.addEventListener('change', () => {
|
|
try {
|
|
theme.value === 'system'
|
|
? localStorage.removeItem('labtimesheet-theme')
|
|
: localStorage.setItem('labtimesheet-theme', theme.value);
|
|
} catch (_) {
|
|
// Theme still applies for this page when persistence is unavailable.
|
|
}
|
|
const dark = theme.value === 'dark'
|
|
|| (theme.value === 'system' && matchMedia('(prefers-color-scheme: dark)').matches);
|
|
root.dataset.theme = dark ? 'dark' : 'light';
|
|
root.style.colorScheme = dark ? 'dark' : 'light';
|
|
});
|
|
}
|
|
|
|
let collapsed = false;
|
|
try { collapsed = localStorage.getItem('labtimesheet-sidebar') === 'collapsed'; }
|
|
catch (_) { /* Use the expanded default. */ }
|
|
const sidebarToggle = document.querySelector('[data-sidebar-toggle]');
|
|
const applySidebarState = () => {
|
|
root.dataset.sidebarCollapsed = String(collapsed);
|
|
sidebarToggle?.setAttribute('aria-expanded', String(!collapsed));
|
|
};
|
|
applySidebarState();
|
|
sidebarToggle?.addEventListener('click', () => {
|
|
collapsed = !collapsed;
|
|
applySidebarState();
|
|
try { localStorage.setItem('labtimesheet-sidebar', collapsed ? 'collapsed' : 'expanded'); }
|
|
catch (_) { /* Collapse still works for this page. */ }
|
|
});
|
|
|
|
document.querySelectorAll('[data-intern-picker]').forEach((picker) => {
|
|
const open = picker.querySelector('[data-picker-open]');
|
|
const dialog = picker.querySelector('[data-picker-dialog]');
|
|
const search = picker.querySelector('[data-picker-search]');
|
|
const summary = picker.querySelector('[data-picker-summary]');
|
|
const empty = picker.querySelector('[data-picker-empty]');
|
|
const cancel = picker.querySelector('[data-picker-cancel]');
|
|
const apply = picker.querySelector('[data-picker-apply]');
|
|
const options = [...picker.querySelectorAll('[data-picker-option]')];
|
|
let initialSelection = [];
|
|
|
|
const inputs = () => options.map((option) => option.querySelector('input'));
|
|
const updateSummary = () => {
|
|
const selected = options
|
|
.filter((option) => option.querySelector('input').checked)
|
|
.map((option) => option.querySelector('[data-picker-label]').textContent.trim());
|
|
summary.textContent = selected.length === 0
|
|
? `No Intern${inputs()[0]?.type === 'radio' ? '' : 's'} selected`
|
|
: `${selected.length} Intern${selected.length === 1 ? '' : 's'} selected: ${selected.join(', ')}`;
|
|
};
|
|
const filter = () => {
|
|
const query = search.value.trim().toLocaleLowerCase();
|
|
let visible = 0;
|
|
options.forEach((option) => {
|
|
option.hidden = !option.dataset.pickerSearch.toLocaleLowerCase().includes(query);
|
|
if (!option.hidden) visible += 1;
|
|
});
|
|
empty.hidden = visible !== 0;
|
|
};
|
|
const restore = () => {
|
|
inputs().forEach((input, index) => { input.checked = initialSelection[index]; });
|
|
updateSummary();
|
|
};
|
|
|
|
inputs().forEach((input) => input.addEventListener('change', updateSummary));
|
|
search.addEventListener('input', filter);
|
|
open.addEventListener('click', () => {
|
|
initialSelection = inputs().map((input) => input.checked);
|
|
search.value = '';
|
|
filter();
|
|
dialog.showModal();
|
|
search.focus();
|
|
});
|
|
cancel.addEventListener('click', () => {
|
|
restore();
|
|
dialog.close();
|
|
});
|
|
dialog.addEventListener('cancel', restore);
|
|
dialog.addEventListener('close', () => open.focus());
|
|
apply.addEventListener('click', () => dialog.close());
|
|
updateSummary();
|
|
});
|
|
});
|