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(preferredTheme()); const dialog = ref(null); const confirmation = ref(null); const toast = ref(""); let toastTimer: ReturnType | 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): void { resolveConfirmation(false); dialog.value = name; } function closeDialog(): void { dialog.value = null; } function askConfirmation(value: Confirmation): Promise { 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, }; });