web-map/src/services/theme.service.ts

59 lines
1.6 KiB
TypeScript

import { theme, type TokenType as AntdTheme } from 'ant-design-vue';
import { mapKeys, mapValues } from 'lodash-es';
import { ref, watch } from 'vue';
const THEME_MAP = (() => {
let temp = import.meta.glob('asset/themes/*.json', { eager: true, import: 'default' });
temp = mapKeys(temp, (_, k) => k.match(/^.*[\\|\\/](.+?)\.[^\\.]+$/)?.[1]);
temp = mapValues(temp, (v) => v);
return <Record<string, object>>temp;
})();
enum Theme {
Light = 'light',
Dark = 'dark',
}
export const THEMES = Object.freeze<[string, Theme][]>(Object.entries(Theme));
const THEME_STORAGE_KEY = '__APP__DARK__MODE__';
class ThemeService {
#theme = ref<Theme>(<Theme>localStorage.getItem(THEME_STORAGE_KEY) || Theme.Dark);
public get theme(): Theme {
return this.#theme.value;
}
public set theme(v: Theme) {
this.#theme.value = v;
localStorage.setItem(THEME_STORAGE_KEY, v);
}
public get ant(): AntdTheme {
switch (this.#theme.value) {
case Theme.Dark:
return { algorithm: theme.darkAlgorithm };
case Theme.Light:
return { algorithm: theme.defaultAlgorithm };
default:
return {};
}
}
public get editor(): object {
return THEME_MAP[`editor-${this.#theme.value}`] ?? {};
}
public get empty(): string {
const { href } = new URL(`../assets/images/empty-${this.#theme.value}.png`, import.meta.url);
return href;
}
constructor() {
watch(this.#theme, (v) => this.#load(v), { immediate: true });
}
#load(theme: Theme): void {
document.documentElement.setAttribute('theme', theme);
}
}
export default new ThemeService();