WorkTracker/wwwroot/theme.js

160 lines
4.4 KiB
JavaScript
Raw Permalink Normal View History

window.workTrackerTheme = (() => {
const storageKey = "worktracker.themeMode";
const mediaQuery = window.matchMedia
? window.matchMedia("(prefers-color-scheme: dark)")
: null;
function normalize(mode) {
const normalized = (mode || "system").toString().toLowerCase();
return normalized === "light" || normalized === "dark" || normalized === "system"
? normalized
: "system";
}
function resolve(mode) {
if (mode === "system") {
return mediaQuery && mediaQuery.matches ? "dark" : "light";
}
return mode;
}
function apply(mode) {
const normalized = normalize(mode);
const effectiveMode = resolve(normalized);
document.documentElement.setAttribute("data-bs-theme", effectiveMode);
document.documentElement.setAttribute("data-theme-mode", normalized);
document.documentElement.style.colorScheme = effectiveMode;
localStorage.setItem(storageKey, normalized);
}
function handleSystemThemeChange() {
const currentMode = normalize(localStorage.getItem(storageKey) || document.documentElement.getAttribute("data-theme-mode"));
if (currentMode === "system") {
apply(currentMode);
}
}
if (mediaQuery) {
if (typeof mediaQuery.addEventListener === "function") {
mediaQuery.addEventListener("change", handleSystemThemeChange);
}
else if (typeof mediaQuery.addListener === "function") {
mediaQuery.addListener(handleSystemThemeChange);
}
}
return {
init() {
apply(localStorage.getItem(storageKey) || document.documentElement.getAttribute("data-theme-mode"));
},
setTheme(mode) {
apply(mode);
}
};
})();
window.workTrackerPreferences = {
getBool(key) {
try {
const value = localStorage.getItem(key);
if (value === null) {
return null;
}
if (value === "true") {
return true;
}
if (value === "false") {
return false;
}
return null;
}
catch {
return null;
}
},
setBool(key, value) {
try {
localStorage.setItem(key, value ? "true" : "false");
}
catch {
}
}
};
window.workTrackerDownloads = {
async downloadFromUrl(url) {
const response = await fetch(url, {
credentials: "same-origin"
});
if (!response.ok) {
throw new Error(`Download failed with status ${response.status}`);
}
const blob = await response.blob();
const contentDisposition = response.headers.get("content-disposition") || "";
const fileNameMatch = /filename\*=UTF-8''([^;]+)|filename="?([^";]+)"?/i.exec(contentDisposition);
const fileName = decodeURIComponent(fileNameMatch?.[1] || fileNameMatch?.[2] || "worktracker-backup.json");
const objectUrl = URL.createObjectURL(blob);
try {
const anchor = document.createElement("a");
anchor.href = objectUrl;
anchor.download = fileName;
anchor.rel = "noopener";
anchor.style.display = "none";
document.body.appendChild(anchor);
anchor.click();
anchor.remove();
}
finally {
URL.revokeObjectURL(objectUrl);
}
}
};
window.workTrackerDateInput = (() => {
const listeners = new WeakMap();
function unregisterOutsideClick(root) {
const existingListener = listeners.get(root);
if (!existingListener) {
return;
}
document.removeEventListener("pointerdown", existingListener, true);
listeners.delete(root);
}
function registerOutsideClick(root, dotNetReference) {
if (!root || !dotNetReference) {
return;
}
unregisterOutsideClick(root);
const listener = (event) => {
if (root.contains(event.target)) {
return;
}
dotNetReference.invokeMethodAsync("ClosePopupFromOutsideClickAsync");
};
listeners.set(root, listener);
document.addEventListener("pointerdown", listener, true);
}
return {
registerOutsideClick,
unregisterOutsideClick
};
})();
window.workTrackerTheme.init();