refactor(projects): 恢复pinia默认写法

This commit is contained in:
Soybean
2022-01-16 20:13:11 +08:00
parent 28b5d22401
commit b2a4ddf5e3
34 changed files with 1242 additions and 965 deletions

View File

@ -63,27 +63,14 @@ type ThemeVars = Exclude<GlobalThemeOverrides['common'], undefined>;
type ThemeVarsKeys = keyof ThemeVars;
/** 添加css vars至html */
export function addThemeCssVarsToHtml(themeVars: ThemeVars, action: 'add' | 'update' = 'add') {
export function addThemeCssVarsToHtml(themeVars: ThemeVars) {
const keys = Object.keys(themeVars) as ThemeVarsKeys[];
const style: string[] = [];
keys.forEach(key => {
style.push(`--${kebabCase(key)}: ${themeVars[key]}`);
});
const styleStr = style.join(';');
if (action === 'add') {
document.documentElement.style.cssText = styleStr;
} else {
document.documentElement.style.cssText += styleStr;
}
}
/**
* 根据主题颜色更新css vars
* @param primaryColor
*/
export function updateThemeCssVarsByPrimary(primaryColor: string) {
const themeColor = getThemeColors([['primary', primaryColor]]);
addThemeCssVarsToHtml(themeColor, 'update');
document.documentElement.style.cssText = styleStr;
}
/** windicss 暗黑模式 */

View File

@ -1,266 +0,0 @@
import { watch, onUnmounted } from 'vue';
import type { Ref, ComputedRef } from 'vue';
import { useOsTheme } from 'naive-ui';
import { useElementSize } from '@vueuse/core';
import { objectAssign } from '@/utils';
import type { ThemeSetting, ThemeLayoutMode, ThemeTabMode, ThemeAnimateMode } from '@/interface';
import { handleWindicssDarkMode, updateThemeCssVarsByPrimary } from './helpers';
export interface LayoutFunc {
/** 设置布局最小宽度 */
setLayoutMinWidth(minWidth: number): void;
/** 设置布局模式 */
setLayoutMode(mode: ThemeLayoutMode): void;
}
export function useLayoutFunc(layout: ThemeSetting['layout']): LayoutFunc {
function setLayout(data: Partial<ThemeSetting['layout']>) {
objectAssign(layout, data);
}
function setLayoutMinWidth(minWidth: number) {
setLayout({ minWidth });
}
function setLayoutMode(mode: ThemeLayoutMode) {
setLayout({ mode });
}
return {
setLayoutMinWidth,
setLayoutMode
};
}
export interface HeaderFunc {
/** 设置头部高度 */
setHeaderHeight(height: number): void;
/** 设置头部面包屑可见 */
setHeaderCrumbVisible(visible: boolean): void;
/** 设置头部面包屑图标可见 */
setHeaderCrumbIconVisible(visible: boolean): void;
}
export function useHeaderFunc(header: ThemeSetting['header']): HeaderFunc {
function setHeader(data: Partial<ThemeSetting['header']>) {
objectAssign(header, data);
}
function setHeaderHeight(height: number) {
setHeader({ height });
}
function setHeaderCrumbVisible(visible: boolean) {
setHeader({ crumb: { ...header.crumb, visible } });
}
function setHeaderCrumbIconVisible(visible: boolean) {
setHeader({ crumb: { ...header.crumb, showIcon: visible } });
}
return {
setHeaderHeight,
setHeaderCrumbVisible,
setHeaderCrumbIconVisible
};
}
export interface TabFunc {
/** 设置多页签可见 */
setTabVisible(visible: boolean): void;
/** 设置多页签高度 */
setTabHeight(height: number): void;
/** 设置多页签风格 */
setTabMode(mode: ThemeTabMode): void;
/** 设置多页签缓存 */
setTabIsCache(isCache: boolean): void;
}
export function useTabFunc(tab: ThemeSetting['tab']): TabFunc {
function setTab(data: Partial<ThemeSetting['tab']>) {
objectAssign(tab, data);
}
function setTabVisible(visible: boolean) {
setTab({ visible });
}
function setTabHeight(height: number) {
setTab({ height });
}
function setTabMode(mode: ThemeTabMode) {
setTab({ mode });
}
function setTabIsCache(isCache: boolean) {
setTab({ isCache });
}
return {
setTabVisible,
setTabHeight,
setTabMode,
setTabIsCache
};
}
export interface SiderFunc {
/** 侧边栏宽度 */
setSiderWidth(width: number): void;
/** 侧边栏折叠时的宽度 */
setSiderCollapsedWidth(width: number): void;
/** vertical-mix模式下侧边栏宽度 */
setMixSiderWidth(width: number): void;
/** vertical-mix模式下侧边栏折叠时的宽度 */
setMixSiderCollapsedWidth(width: number): void;
/** vertical-mix模式下侧边栏展示子菜单的宽度 */
setMixSiderChildMenuWidth(width: number): void;
}
export function useSiderFunc(sider: ThemeSetting['sider']): SiderFunc {
function setSider(data: Partial<ThemeSetting['sider']>) {
objectAssign(sider, data);
}
function setSiderWidth(width: number) {
setSider({ width });
}
function setSiderCollapsedWidth(width: number) {
setSider({ collapsedWidth: width });
}
function setMixSiderWidth(width: number) {
setSider({ mixWidth: width });
}
function setMixSiderCollapsedWidth(width: number) {
setSider({ mixCollapsedWidth: width });
}
function setMixSiderChildMenuWidth(width: number) {
setSider({ mixChildMenuWidth: width });
}
return {
setSiderWidth,
setSiderCollapsedWidth,
setMixSiderWidth,
setMixSiderCollapsedWidth,
setMixSiderChildMenuWidth
};
}
export interface FooterFunc {
/** 设置底部是否固定 */
setFooterIsFixed(isFixed: boolean): void;
/** 设置底部高度 */
setFooterHeight(height: number): void;
}
export function useFooterFunc(footer: ThemeSetting['footer']): FooterFunc {
function setFooter(data: Partial<ThemeSetting['footer']>) {
objectAssign(footer, data);
}
function setFooterIsFixed(isFixed: boolean) {
setFooter({ fixed: isFixed });
}
function setFooterHeight(height: number) {
setFooter({ height });
}
return {
setFooterIsFixed,
setFooterHeight
};
}
export interface PageFunc {
/** 设置切换页面时是否过渡动画 */
setPageIsAnimate(animate: boolean): void;
/** 设置页面过渡动画类型 */
setPageAnimateMode(mode: ThemeAnimateMode): void;
}
export function usePageFunc(page: ThemeSetting['page']): PageFunc {
function setPage(data: Partial<ThemeSetting['page']>) {
objectAssign(page, data);
}
function setPageIsAnimate(animate: boolean) {
setPage({ animate });
}
function setPageAnimateMode(mode: ThemeAnimateMode) {
setPage({ animateMode: mode });
}
return {
setPageIsAnimate,
setPageAnimateMode
};
}
/**
* 操作系统主题模式变化的回调函数
* @param isDark - 暗黑模式
*/
type OsThemeCallback = (isDark: boolean) => void;
/** 监听操作系统主题模式 */
export function osThemeWatcher(callback: OsThemeCallback) {
/** 操作系统暗黑主题 */
const osTheme = useOsTheme();
const stopHandle = watch(
osTheme,
newValue => {
const isDark = newValue === 'dark';
callback(isDark);
},
{ immediate: true }
);
onUnmounted(() => {
stopHandle();
});
}
/** 应用windicss的暗黑模式 */
export function setupWindicssDarkMode(darkMode: Ref<boolean>) {
const { addDarkClass, removeDarkClass } = handleWindicssDarkMode();
const stopHandle = watch(
() => darkMode.value,
newValue => {
if (newValue) {
addDarkClass();
} else {
removeDarkClass();
}
},
{ immediate: true }
);
onUnmounted(() => {
stopHandle();
});
}
/**
* 禁用横向滚动
* @description 页面切换时,过渡动画会产生水平方向的滚动条, 小于最小宽度时,不禁止
*/
export function setupHiddenScroll(minWidthOfLayout: ComputedRef<number>) {
const { width } = useElementSize(document.documentElement);
const stopHandle = watch(width, newValue => {
if (newValue < minWidthOfLayout.value) {
document.documentElement.style.overflowX = 'auto';
} else {
document.documentElement.style.overflowX = 'hidden';
}
});
onUnmounted(() => {
stopHandle();
});
}
/**
* 监听主题颜色的变化
* @param themeColor
*/
export function themeColorWatcher(themeColor: Ref<string>) {
const stopHandle = watch(themeColor, newValue => {
updateThemeCssVarsByPrimary(newValue);
});
onUnmounted(() => {
stopHandle();
});
}

View File

@ -1,229 +1,140 @@
import { ref, reactive, computed } from 'vue';
import type { Ref, ComputedRef } from 'vue';
import { defineStore } from 'pinia';
import { darkTheme } from 'naive-ui';
import type { GlobalThemeOverrides, GlobalTheme } from 'naive-ui';
import { cloneDeep } from 'lodash-es';
import { themeSetting } from '@/settings';
import { useBoolean } from '@/hooks';
import { getColorPalette } from '@/utils';
import type { ThemeSetting, ThemeHorizontalMenuPosition } from '@/interface';
import type {
ThemeSetting,
ThemeLayoutMode,
ThemeTabMode,
ThemeHorizontalMenuPosition,
ThemeAnimateMode
} from '@/interface';
import { getNaiveThemeOverrides, addThemeCssVarsToHtml } from './helpers';
import {
useLayoutFunc,
useHeaderFunc,
useTabFunc,
useSiderFunc,
useFooterFunc,
usePageFunc,
osThemeWatcher,
setupWindicssDarkMode,
setupHiddenScroll,
themeColorWatcher
} from './hooks';
import type { LayoutFunc, HeaderFunc, TabFunc, SiderFunc, FooterFunc, PageFunc } from './hooks';
type BuiltInGlobalTheme = Omit<Required<GlobalTheme>, 'InternalSelectMenu' | 'InternalSelection'>;
type ThemeState = ThemeSetting;
interface ThemeStore extends LayoutFunc, HeaderFunc, TabFunc, SiderFunc, FooterFunc, PageFunc {
/** 暗黑模式 */
darkMode: Ref<boolean>;
/** 设置暗黑模式 */
setDarkMode(dark: boolean): void;
/** 切换/关闭 暗黑模式 */
toggleDarkMode(): void;
/** 布局样式 */
layout: ThemeSetting['layout'];
/** 主题颜色 */
themeColor: Ref<string>;
/** 设置系统主题颜色 */
setThemeColor(color: string): void;
/** 主题颜色列表 */
themeColorList: string[];
/** 其他颜色 */
otherColor: ComputedRef<ThemeSetting['otherColor']>;
/** 固定头部和多页签 */
fixedHeaderAndTab: Ref<boolean>;
/** 设置固定头部和多页签 */
setIsFixedHeaderAndTab(isFixed: boolean): void;
/** 重载按钮可见 */
reloadVisible: Ref<boolean>;
/** 设置 显示/隐藏 重载按钮 */
setReloadVisible(visible: boolean): void;
/** 头部 */
header: ThemeSetting['header'];
/** 多页签 */
tab: ThemeSetting['tab'];
/** 侧边栏 */
sider: ThemeSetting['sider'];
/** 菜单 */
menu: ThemeSetting['menu'];
/** 设置水平模式的菜单的位置 */
setHorizontalMenuPosition(posiiton: ThemeHorizontalMenuPosition): void;
/** 底部 */
footer: ThemeSetting['footer'];
/** 页面 */
page: ThemeSetting['page'];
/** naiveUI的主题配置 */
naiveThemeOverrides: ComputedRef<GlobalThemeOverrides>;
/** naive-ui暗黑主题 */
naiveTheme: ComputedRef<BuiltInGlobalTheme | undefined>;
/** 重置状态 */
resetThemeStore(): void;
}
export const useThemeStore = defineStore('theme-store', () => {
// 暗黑模式
const { bool: darkMode, setBool: setDarkMode, toggle: toggleDarkMode } = useBoolean();
// 布局
const layout = reactive<ThemeSetting['layout']>({
...themeSetting.layout
});
const { setLayoutMinWidth, setLayoutMode } = useLayoutFunc(layout);
// 主题色
const themeColor = ref(themeSetting.themeColor);
/** 设置系统主题颜色 */
function setThemeColor(color: string) {
themeColor.value = color;
}
const { themeColorList } = themeSetting;
const otherColor = computed<ThemeSetting['otherColor']>(() => ({
...themeSetting.otherColor,
info: getColorPalette(themeColor.value, 7)
}));
// 固定头部和多页签
const { bool: fixedHeaderAndTab, setBool: setIsFixedHeaderAndTab } = useBoolean(themeSetting.fixedHeaderAndTab);
// 重载按钮
const { bool: reloadVisible, setBool: setReloadVisible } = useBoolean(themeSetting.showReload);
// 头部
const header = reactive<ThemeSetting['header']>({
height: themeSetting.header.height,
crumb: { ...themeSetting.header.crumb }
});
const { setHeaderHeight, setHeaderCrumbVisible, setHeaderCrumbIconVisible } = useHeaderFunc(header);
// 多页签
const tab = reactive<ThemeSetting['tab']>({
...themeSetting.tab
});
const { setTabVisible, setTabHeight, setTabMode, setTabIsCache } = useTabFunc(tab);
// 侧边栏
const sider = reactive<ThemeSetting['sider']>({
...themeSetting.sider
});
const {
setSiderWidth,
setSiderCollapsedWidth,
setMixSiderWidth,
setMixSiderCollapsedWidth,
setMixSiderChildMenuWidth
} = useSiderFunc(sider);
// 菜单
const menu = reactive<ThemeSetting['menu']>({
...themeSetting.menu
});
function setHorizontalMenuPosition(posiiton: ThemeHorizontalMenuPosition) {
menu.horizontalPosition = posiiton;
}
// 底部
const footer = reactive<ThemeSetting['footer']>({
...themeSetting.footer
});
const { setFooterIsFixed, setFooterHeight } = useFooterFunc(footer);
// 页面
const page = reactive<ThemeSetting['page']>({
...themeSetting.page
});
const { setPageIsAnimate, setPageAnimateMode } = usePageFunc(page);
// naive主题
const naiveThemeOverrides = computed<GlobalThemeOverrides>(() =>
getNaiveThemeOverrides({ primary: themeColor.value, ...otherColor.value })
);
const naiveTheme = computed(() => (darkMode.value ? darkTheme : undefined));
/** 重置theme状态 */
function resetThemeStore() {
setDarkMode(false);
}
/** 初始化css vars, 并添加至html */
function initThemeCssVars() {
const updatedThemeVars = { ...naiveThemeOverrides.value.common };
addThemeCssVarsToHtml(updatedThemeVars);
}
/** 系统主题适应操作系统 */
function handleAdaptOsTheme() {
osThemeWatcher(isDark => {
if (isDark) {
setDarkMode(true);
} else {
setDarkMode(false);
export const useThemeStore = defineStore('theme-store', {
state: (): ThemeState => cloneDeep(themeSetting),
getters: {
/** naiveUI的主题配置 */
naiveThemeOverrides(state) {
const overrides = getNaiveThemeOverrides({ primary: state.themeColor, ...state.otherColor });
addThemeCssVarsToHtml(overrides.common!);
return overrides;
},
/** naive-ui暗黑主题 */
naiveTheme(state) {
return state.darkMode ? darkTheme : undefined;
}
},
actions: {
/** 重置theme状态 */
resetThemeStore() {
this.$reset();
},
/** 设置暗黑模式 */
setDarkMode(darkMode: boolean) {
this.darkMode = darkMode;
},
/** 切换/关闭 暗黑模式 */
toggleDarkMode() {
this.darkMode = !this.darkMode;
},
/** 设置布局最小宽度 */
setLayoutMinWidth(minWidth: number) {
this.layout.minWidth = minWidth;
},
/** 设置布局模式 */
setLayoutMode(mode: ThemeLayoutMode) {
this.layout.mode = mode;
},
/** 设置系统主题颜色 */
setThemeColor(themeColor: string) {
this.themeColor = themeColor;
},
/** 设置固定头部和多页签 */
setIsFixedHeaderAndTab(isFixed: boolean) {
this.fixedHeaderAndTab = isFixed;
},
/** 设置重载按钮可见状态 */
setReloadVisible(visible: boolean) {
this.showReload = visible;
},
/** 设置头部高度 */
setHeaderHeight(height: number | null) {
if (height) {
this.header.height = height;
}
});
},
/** 设置头部面包屑可见 */
setHeaderCrumbVisible(visible: boolean) {
this.header.crumb.visible = visible;
},
/** 设置头部面包屑图标可见 */
setHeaderCrumbIconVisible(visible: boolean) {
this.header.crumb.showIcon = visible;
},
/** 设置多页签可见 */
setTabVisible(visible: boolean) {
this.tab.visible = visible;
},
/** 设置多页签高度 */
setTabHeight(height: number | null) {
if (height) {
this.tab.height = height;
}
},
/** 设置多页签风格 */
setTabMode(mode: ThemeTabMode) {
this.tab.mode = mode;
},
/** 设置多页签缓存 */
setTabIsCache(isCache: boolean) {
this.tab.isCache = isCache;
},
/** 侧边栏宽度 */
setSiderWidth(width: number | null) {
if (width) {
this.sider.width = width;
}
},
/** 侧边栏折叠时的宽度 */
setSiderCollapsedWidth(width: number) {
this.sider.collapsedWidth = width;
},
/** vertical-mix模式下侧边栏宽度 */
setMixSiderWidth(width: number | null) {
if (width) {
this.sider.mixWidth = width;
}
},
/** vertical-mix模式下侧边栏折叠时的宽度 */
setMixSiderCollapsedWidth(width: number) {
this.sider.mixCollapsedWidth = width;
},
/** vertical-mix模式下侧边栏展示子菜单的宽度 */
setMixSiderChildMenuWidth(width: number) {
this.sider.mixChildMenuWidth = width;
},
/** 设置水平模式的菜单的位置 */
setHorizontalMenuPosition(posiiton: ThemeHorizontalMenuPosition) {
this.menu.horizontalPosition = posiiton;
},
/** 设置底部是否固定 */
setFooterIsFixed(isFixed: boolean) {
this.footer.fixed = isFixed;
},
/** 设置底部高度 */
setFooterHeight(height: number) {
this.footer.height = height;
},
/** 设置切换页面时是否过渡动画 */
setPageIsAnimate(animate: boolean) {
this.page.animate = animate;
},
/** 设置页面过渡动画类型 */
setPageAnimateMode(mode: ThemeAnimateMode) {
this.page.animateMode = mode;
}
}
function init() {
initThemeCssVars();
handleAdaptOsTheme();
setupWindicssDarkMode(darkMode);
setupHiddenScroll(computed(() => layout.minWidth));
themeColorWatcher(themeColor);
}
init();
const themeStore: ThemeStore = {
darkMode,
setDarkMode,
toggleDarkMode,
layout,
setLayoutMinWidth,
setLayoutMode,
themeColor,
setThemeColor,
themeColorList,
otherColor,
fixedHeaderAndTab,
setIsFixedHeaderAndTab,
reloadVisible,
setReloadVisible,
header,
setHeaderHeight,
setHeaderCrumbVisible,
setHeaderCrumbIconVisible,
tab,
setTabVisible,
setTabHeight,
setTabMode,
setTabIsCache,
sider,
setSiderWidth,
setSiderCollapsedWidth,
setMixSiderWidth,
setMixSiderCollapsedWidth,
setMixSiderChildMenuWidth,
menu,
setHorizontalMenuPosition,
footer,
setFooterIsFixed,
setFooterHeight,
page,
setPageIsAnimate,
setPageAnimateMode,
naiveThemeOverrides,
naiveTheme,
resetThemeStore
};
return themeStore;
});