import type { I18n } from "vue-i18n" import { StorageValue } from "../types/store" type ColorTheme = "dark" | "light" | "auto" class ColorMode { protected mode = new StorageValue("colormode") readonly modes = ["dark", "light", "auto"] private readonly prefersDark = window.matchMedia( "(prefers-color-scheme: dark)" ) async load() { if (!(await this.get)) await this.mode.set("auto") this.change(await this.get) } change(mode: ColorTheme) { if (mode === "auto") { this.autoCheck() this.prefersDark.addEventListener("change", this.autoCheck) } else { this.prefersDark.onchange = null if (mode === "dark") { document.body.classList.add("dark") } else { document.body.classList.remove("dark") } } } autoCheck(query?: MediaQueryListEvent) { document.body.classList.toggle( "dark", query ? query.matches : this.prefersDark.matches ) } get get(): Promise { return this.mode.value } set state(mode: ColorTheme) { this.mode.set(mode) this.change(mode) } } class Language { constructor(i18n: I18n) { this.i18n = i18n } readonly i18n: I18n private readonly lang = new StorageValue("language") async load(): Promise { await this.set(await this.get()) } async get(): Promise { return (await this.lang.get()) || "en" } async set(lang: string): Promise { await this.lang.set(lang) this.i18n.global.locale = lang } } export class Visuals { constructor(i18n: I18n) { this.lang = new Language(i18n) this.modules = [this.colormode.load(), this.lang.load()] } /** * Color Theme Mode Wrapper * * **Usage**: * ```ts * import { useVisuals } from "vvic-utils/visuals" * const theme = useVisuals().colormode * ``` */ public readonly colormode = new ColorMode() /** * Capacitor.js Interface Wrapper for Internationalization * * **Usage**: * ```ts * import { useVisuals } from "vvic-utils/visuals" * useVisuals().lang * ``` */ readonly lang: Language private readonly modules: Promise[] public async load() { await Promise.all(this.modules) } } export default Visuals