mirror of
https://github.com/soybeanjs/soybean-admin.git
synced 2025-09-22 19:46:38 +08:00
163 lines
4.0 KiB
TypeScript
163 lines
4.0 KiB
TypeScript
import { computed, effectScope, onScopeDispose, ref, toRefs, watch } from 'vue';
|
|
import type { Ref } from 'vue';
|
|
import { defineStore } from 'pinia';
|
|
import { useEventListener, usePreferredColorScheme } from '@vueuse/core';
|
|
import { getColorPalette } from '@sa/color-palette';
|
|
import { SetupStoreId } from '@/enum';
|
|
import { localStg } from '@/utils/storage';
|
|
import { addThemeVarsToHtml, createThemeToken, getNaiveTheme, initThemeSettings, toggleCssDarkMode } from './shared';
|
|
|
|
/** Theme store */
|
|
export const useThemeStore = defineStore(SetupStoreId.Theme, () => {
|
|
const scope = effectScope();
|
|
const osTheme = usePreferredColorScheme();
|
|
|
|
/** Theme settings */
|
|
const settings: Ref<App.Theme.ThemeSetting> = ref(initThemeSettings());
|
|
|
|
/** Dark mode */
|
|
const darkMode = computed(() => {
|
|
if (settings.value.themeScheme === 'auto') {
|
|
return osTheme.value === 'dark';
|
|
}
|
|
return settings.value.themeScheme === 'dark';
|
|
});
|
|
|
|
/** Theme colors */
|
|
const themeColors = computed(() => {
|
|
const { themeColor, otherColor, isInfoFollowPrimary } = settings.value;
|
|
const colors: App.Theme.ThemeColor = {
|
|
primary: themeColor,
|
|
...otherColor,
|
|
info: isInfoFollowPrimary ? themeColor : otherColor.info
|
|
};
|
|
return colors;
|
|
});
|
|
|
|
/** Naive theme */
|
|
const naiveTheme = computed(() => getNaiveTheme(themeColors.value));
|
|
|
|
/**
|
|
* Settings json
|
|
*
|
|
* It is for copy settings
|
|
*/
|
|
const settingsJson = computed(() => JSON.stringify(settings.value));
|
|
|
|
/** Reset store */
|
|
function resetStore() {
|
|
const themeStore = useThemeStore();
|
|
|
|
themeStore.$reset();
|
|
}
|
|
|
|
/**
|
|
* Set theme scheme
|
|
*
|
|
* @param themeScheme
|
|
*/
|
|
function setThemeScheme(themeScheme: UnionKey.ThemeScheme) {
|
|
settings.value.themeScheme = themeScheme;
|
|
}
|
|
|
|
/** Toggle theme scheme */
|
|
function toggleThemeScheme() {
|
|
const themeSchemes: UnionKey.ThemeScheme[] = ['light', 'dark', 'auto'];
|
|
|
|
const index = themeSchemes.findIndex(item => item === settings.value.themeScheme);
|
|
|
|
const nextIndex = index === themeSchemes.length - 1 ? 0 : index + 1;
|
|
|
|
const nextThemeScheme = themeSchemes[nextIndex];
|
|
|
|
setThemeScheme(nextThemeScheme);
|
|
}
|
|
|
|
/**
|
|
* Update theme colors
|
|
*
|
|
* @param key Theme color key
|
|
* @param color Theme color
|
|
*/
|
|
function updateThemeColors(key: App.Theme.ThemeColorKey, color: string) {
|
|
// get a color palette by provided color and color name, and use the suitable color
|
|
const { main } = getColorPalette(color);
|
|
|
|
if (key === 'primary') {
|
|
settings.value.themeColor = main.hex;
|
|
} else {
|
|
settings.value.otherColor[key] = main.hex;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set theme layout
|
|
*
|
|
* @param mode Theme layout mode
|
|
*/
|
|
function setThemeLayout(mode: UnionKey.ThemeLayoutMode) {
|
|
settings.value.layout.mode = mode;
|
|
}
|
|
|
|
/** Setup theme vars to html */
|
|
function setupThemeVarsToHtml() {
|
|
const { themeTokens, darkThemeTokens } = createThemeToken(themeColors.value);
|
|
addThemeVarsToHtml(themeTokens, darkThemeTokens);
|
|
}
|
|
|
|
/** Cache theme settings */
|
|
function cacheThemeSettings() {
|
|
const isProd = import.meta.env.PROD;
|
|
|
|
if (!isProd) return;
|
|
|
|
localStg.set('themeSettings', settings.value);
|
|
}
|
|
|
|
// cache theme settings when page is closed or refreshed
|
|
useEventListener(window, 'beforeunload', () => {
|
|
cacheThemeSettings();
|
|
});
|
|
|
|
// watch store
|
|
scope.run(() => {
|
|
// watch dark mode
|
|
watch(
|
|
darkMode,
|
|
val => {
|
|
toggleCssDarkMode(val);
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
|
|
// themeColors change, update css vars and storage theme color
|
|
watch(
|
|
themeColors,
|
|
val => {
|
|
setupThemeVarsToHtml();
|
|
|
|
localStg.set('themeColor', val.primary);
|
|
},
|
|
{ immediate: true }
|
|
);
|
|
});
|
|
|
|
/** On scope dispose */
|
|
onScopeDispose(() => {
|
|
scope.stop();
|
|
});
|
|
|
|
return {
|
|
...toRefs(settings.value),
|
|
darkMode,
|
|
themeColors,
|
|
naiveTheme,
|
|
settingsJson,
|
|
resetStore,
|
|
setThemeScheme,
|
|
toggleThemeScheme,
|
|
updateThemeColors,
|
|
setThemeLayout
|
|
};
|
|
});
|