From 823908afcaed06f1f373290733d818d7ba0d9520 Mon Sep 17 00:00:00 2001 From: Azir <2075125282@qq.com> Date: Tue, 3 Dec 2024 16:34:54 +0800 Subject: [PATCH] feat(projects): theme init supports initialization based on initial values. --- .../modules/theme-drawer/modules/page-fun.vue | 6 +- src/store/modules/theme/shared.ts | 12 ++-- src/typings/app.d.ts | 2 +- src/utils/common.ts | 69 +++++++++++++++++++ 4 files changed, 81 insertions(+), 8 deletions(-) diff --git a/src/layouts/modules/theme-drawer/modules/page-fun.vue b/src/layouts/modules/theme-drawer/modules/page-fun.vue index dbebb911..80ae6130 100644 --- a/src/layouts/modules/theme-drawer/modules/page-fun.vue +++ b/src/layouts/modules/theme-drawer/modules/page-fun.vue @@ -69,9 +69,6 @@ const isWrapperScrollMode = computed(() => themeStore.layout.scrollMode === 'wra - - - @@ -130,6 +127,9 @@ const isWrapperScrollMode = computed(() => themeStore.layout.scrollMode === 'wra placeholder="SoybeanAdmin" /> + + + diff --git a/src/store/modules/theme/shared.ts b/src/store/modules/theme/shared.ts index 448c6992..3e63639b 100644 --- a/src/store/modules/theme/shared.ts +++ b/src/store/modules/theme/shared.ts @@ -2,30 +2,34 @@ import type { GlobalThemeOverrides } from 'naive-ui'; import { addColorAlpha, getColorPalette, getPaletteColorByNumber, getRgb } from '@sa/color'; import { overrideThemeSettings, themeSettings } from '@/theme/settings'; import { themeVars } from '@/theme/vars'; -import { toggleHtmlClass } from '@/utils/common'; +import { toggleHtmlClass, updateBase } from '@/utils/common'; import { localStg } from '@/utils/storage'; const DARK_CLASS = 'dark'; /** Init theme settings */ export function initThemeSettings() { - const isProd = import.meta.env.PROD; + // const isProd = import.meta.env.PROD; + const isProd = true; // if it is development mode, the theme settings will not be cached, by update `themeSettings` in `src/theme/settings.ts` to update theme settings if (!isProd) return themeSettings; + const localSettings = localStg.get('themeSettings') || themeSettings; + // if it is production mode, the theme settings will be cached in localStorage // if want to update theme settings when publish new version, please update `overrideThemeSettings` in `src/theme/settings.ts` - const settings = localStg.get('themeSettings') || themeSettings; + const settings = updateBase(themeSettings, localSettings); const isOverride = localStg.get('overrideThemeFlag') === BUILD_TIME; - if (!isOverride) { Object.assign(settings, overrideThemeSettings); localStg.set('overrideThemeFlag', BUILD_TIME); } + localStg.set('themeSettings', settings); + return settings; } diff --git a/src/typings/app.d.ts b/src/typings/app.d.ts index 72c12314..853ec17d 100644 --- a/src/typings/app.d.ts +++ b/src/typings/app.d.ts @@ -103,7 +103,7 @@ declare namespace App { right: boolean; }; /** Watermark */ - watermark?: { + watermark: { /** Whether to show the watermark */ visible: boolean; /** Watermark text */ diff --git a/src/utils/common.ts b/src/utils/common.ts index dc9a368f..0aca7007 100644 --- a/src/utils/common.ts +++ b/src/utils/common.ts @@ -1,3 +1,4 @@ +import { isObject } from 'lodash-es'; import { $t } from '@/locales'; /** @@ -56,3 +57,71 @@ export function toggleHtmlClass(className: string) { remove }; } + +type AnyObject = { [key: string]: any }; +/** Auxiliary type: recursively make all attributes optional */ +type PartialDeep = { + [P in keyof T]?: T[P] extends AnyObject ? PartialDeep : T[P]; +}; +/** + * Deeply update base objects without adding keys that do not exist in the base. + * + * @example + * const base = { + * a: 1, + * b: { + * c: 2, + * d: 3, + * }, + * e: [1, 2, 3], + * }; + * + * const updates = { + * a: 10, + * b: { + * c: 20, + * e: 30, // Does not exist in base. b, will be ignored + * }, + * f: 40, // Does not exist in base. b, will be ignored + * e: [4, 5], // Array will be replaced + * }; + * + * const updatedBase = updateBase(base, updates); + * + * console.log(updatedBase); + * output: + * { + * a: 10, + * b: { + * c: 20, + * d: 3 + * }, + * e: [4, 5] + * } + * + * @param base - Base object + * @param updates - Update object + * @returns New object, a deep copy of the base object with updates applied + */ +export function updateBase(base: T, updates: PartialDeep): T { + // Deep copy the base object to avoid modifying the original object + const result: AnyObject = Array.isArray(base) ? [...base] : { ...base }; + + for (const key in updates) { + if (Object.hasOwn(base, key)) { + const baseValue = base[key]; + const updateValue = updates[key]; + + if (isObject(baseValue) && isObject(updateValue)) { + // Recursively update nested objects + result[key] = updateBase(baseValue, updateValue); + } else { + // Directly assign updates + result[key] = updateValue; + } + } + // If the key in updates does not exist in base, ignore it + } + + return result as T; +}