76 lines
2.2 KiB
TypeScript
76 lines
2.2 KiB
TypeScript
import { defineStore } from "pinia";
|
|
import { ref } from "vue";
|
|
|
|
export type DialogName = "profile" | "membership" | "password" | "search" | null;
|
|
export type Theme = "light" | "dark";
|
|
export type Confirmation = { title: string; message: string; confirmLabel: string };
|
|
|
|
const THEME_KEY = "xiaobai-theme";
|
|
|
|
export function preferredTheme(): Theme {
|
|
const stored = localStorage.getItem(THEME_KEY);
|
|
if (stored === "light" || stored === "dark") return stored;
|
|
return matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
}
|
|
|
|
export function applyTheme(theme: Theme): void {
|
|
document.documentElement.dataset.theme = theme;
|
|
document.documentElement.style.colorScheme = theme;
|
|
}
|
|
|
|
export const useUiStore = defineStore("ui", () => {
|
|
const theme = ref<Theme>(preferredTheme());
|
|
const dialog = ref<DialogName>(null);
|
|
const confirmation = ref<Confirmation | null>(null);
|
|
const toast = ref("");
|
|
let toastTimer: ReturnType<typeof setTimeout> | undefined;
|
|
let confirmationResolve: ((value: boolean) => void) | undefined;
|
|
|
|
function setTheme(next: Theme): void {
|
|
theme.value = next;
|
|
localStorage.setItem(THEME_KEY, next);
|
|
applyTheme(next);
|
|
}
|
|
|
|
function toggleTheme(): void {
|
|
setTheme(theme.value === "light" ? "dark" : "light");
|
|
}
|
|
|
|
function openDialog(name: Exclude<DialogName, null>): void {
|
|
resolveConfirmation(false);
|
|
dialog.value = name;
|
|
}
|
|
|
|
function closeDialog(): void {
|
|
dialog.value = null;
|
|
}
|
|
|
|
function askConfirmation(value: Confirmation): Promise<boolean> {
|
|
resolveConfirmation(false);
|
|
dialog.value = null;
|
|
confirmation.value = value;
|
|
return new Promise((resolve) => {
|
|
confirmationResolve = resolve;
|
|
});
|
|
}
|
|
|
|
function resolveConfirmation(value: boolean): void {
|
|
confirmation.value = null;
|
|
confirmationResolve?.(value);
|
|
confirmationResolve = undefined;
|
|
}
|
|
|
|
function showToast(message: string): void {
|
|
toast.value = message;
|
|
if (toastTimer) clearTimeout(toastTimer);
|
|
toastTimer = setTimeout(() => {
|
|
toast.value = "";
|
|
}, 2200);
|
|
}
|
|
|
|
return {
|
|
theme, dialog, confirmation, toast, setTheme, toggleTheme, openDialog, closeDialog,
|
|
askConfirmation, resolveConfirmation, showToast,
|
|
};
|
|
});
|