feat(store): 重构应用状态管理,移除旧的 app-store 并引入 app-store-auto-imports
This commit is contained in:
@@ -4,7 +4,7 @@ const appStore = useAppStore();
|
||||
const themeLabels: Record<AppThemeMode, string> = {
|
||||
light: '浅色',
|
||||
dark: '深色',
|
||||
system: '跟随系统',
|
||||
auto: '跟随系统',
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -12,7 +12,7 @@ const themeLabels: Record<AppThemeMode, string> = {
|
||||
<NTooltip :disabled="appStore.isMobile" placement="bottom-end">
|
||||
{{ themeLabels[appStore.themeMode] }}
|
||||
<template #trigger>
|
||||
<NButton quaternary @click="appStore.cycleTheme">
|
||||
<NButton quaternary @click="appStore.cycleTheme()">
|
||||
<icon-line-md-sunny-filled-loop-to-moon-filled-loop-transition
|
||||
v-if="appStore.themeMode === 'light'"
|
||||
w-4.5
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="tsx">
|
||||
import { useAppStore } from '@/stores/app-store';
|
||||
import { useAppStore } from '@/stores/app-store-auto-imports';
|
||||
|
||||
const menuInstRef = useTemplateRef('menuInstRef');
|
||||
const { options, selectedKey } = useMetaLayoutsNMenuOptions({
|
||||
|
||||
@@ -8,4 +8,6 @@ consola.level = LogLevels.verbose;
|
||||
/* `import.meta.glob(${g}, { eager: ${isSync} })`; */
|
||||
const autoInstallModules = import.meta.glob('./plugins/!(index).ts', { eager: true });
|
||||
|
||||
setupPlugins(createApp(App), autoInstallModules).mount('#app');
|
||||
const app = setupPlugins(createApp(App), autoInstallModules);
|
||||
await new Promise((resolve) => setTimeout(resolve, 280));
|
||||
app.mount('#app');
|
||||
|
||||
42
src/stores/app-store-auto-imports.ts
Normal file
42
src/stores/app-store-auto-imports.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { useLocalStorage, useMediaQuery } from '@vueuse/core';
|
||||
import { defineStore } from 'pinia';
|
||||
import { computed } from 'vue';
|
||||
|
||||
// >>>>>
|
||||
// https://vueuse.org/core/useColorMode/#advanced-usage
|
||||
const { system, store: themeMode } = useColorMode({
|
||||
modes: { light: '', dark: 'app-dark', auto: '' },
|
||||
disableTransition: false,
|
||||
});
|
||||
const { state, next: cycleTheme } = useCycleList(['light', 'dark', 'auto'] as const, {
|
||||
initialValue: themeMode,
|
||||
});
|
||||
watchEffect(() => (themeMode.value = state.value));
|
||||
export type AppThemeMode = typeof themeMode.value;
|
||||
// <<<<<
|
||||
|
||||
export const useAppStore = defineStore('app', () => {
|
||||
// 侧边栏展开/收起状态
|
||||
const sidebarCollapsed = useLocalStorage<boolean>('app-sidebar-collapsed', false);
|
||||
const toggleSidebar = useToggle(sidebarCollapsed);
|
||||
|
||||
// 主题模式
|
||||
const actualTheme = computed(() => (themeMode.value === 'auto' ? system.value : themeMode.value));
|
||||
const isDark = computed(() => actualTheme.value === 'dark');
|
||||
|
||||
// 是否是移动端
|
||||
const isMobile = useMediaQuery('(max-width: 768px)');
|
||||
|
||||
return {
|
||||
themeMode,
|
||||
isDark,
|
||||
isMobile,
|
||||
cycleTheme,
|
||||
sidebarCollapsed,
|
||||
toggleSidebar,
|
||||
};
|
||||
});
|
||||
|
||||
if (import.meta.hot) {
|
||||
import.meta.hot.accept(acceptHMRUpdate(useAppStore, import.meta.hot));
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
import { useLocalStorage, useMediaQuery, usePreferredColorScheme } from '@vueuse/core';
|
||||
import { defineStore } from 'pinia';
|
||||
import { computed, watch } from 'vue';
|
||||
|
||||
export const APP_THEME_MODES = ['light', 'dark', 'system'] as const;
|
||||
export type AppThemeMode = (typeof APP_THEME_MODES)[number];
|
||||
|
||||
const DARK_CLASS = 'app-dark';
|
||||
|
||||
export const useAppStore = defineStore('app', () => {
|
||||
const themeMode = useLocalStorage<AppThemeMode>('app-theme-mode', 'system');
|
||||
const preferredColor = usePreferredColorScheme();
|
||||
|
||||
// 侧边栏展开/收起状态
|
||||
const sidebarCollapsed = useLocalStorage<boolean>('app-sidebar-collapsed', false);
|
||||
|
||||
// 计算实际使用的主题
|
||||
const actualTheme = computed(() =>
|
||||
themeMode.value === 'system'
|
||||
? preferredColor.value === 'dark'
|
||||
? 'dark'
|
||||
: 'light'
|
||||
: themeMode.value,
|
||||
);
|
||||
|
||||
// 是否是暗色主题
|
||||
const isDark = computed(() => actualTheme.value === 'dark');
|
||||
|
||||
// 是否是移动端
|
||||
const isMobile = useMediaQuery('(max-width: 768px)');
|
||||
|
||||
// 更新 DOM 类名
|
||||
function updateDomClass() {
|
||||
document.documentElement.classList.toggle(DARK_CLASS, isDark.value);
|
||||
}
|
||||
|
||||
// 循环切换主题
|
||||
function cycleTheme() {
|
||||
const currentIndex = APP_THEME_MODES.indexOf(themeMode.value);
|
||||
const nextIndex = (currentIndex + 1) % APP_THEME_MODES.length;
|
||||
themeMode.value = APP_THEME_MODES[nextIndex]!;
|
||||
}
|
||||
|
||||
// 切换侧边栏展开/收起
|
||||
function toggleSidebar() {
|
||||
sidebarCollapsed.value = !sidebarCollapsed.value;
|
||||
}
|
||||
|
||||
// 监听主题变化,更新 DOM
|
||||
watch(isDark, updateDomClass, { immediate: true });
|
||||
|
||||
return {
|
||||
themeMode,
|
||||
isDark,
|
||||
isMobile,
|
||||
cycleTheme,
|
||||
sidebarCollapsed,
|
||||
toggleSidebar,
|
||||
};
|
||||
});
|
||||
|
||||
if (import.meta.hot) {
|
||||
import.meta.hot.accept(acceptHMRUpdate(useAppStore, import.meta.hot));
|
||||
}
|
||||
Reference in New Issue
Block a user