From d335df6f46b362bd9f36e4040140c27b0e6a9e71 Mon Sep 17 00:00:00 2001 From: Soybean Date: Wed, 24 Apr 2024 14:01:47 +0800 Subject: [PATCH] feat(projects): support grayscale. fixed #385 --- .../theme-drawer/modules/dark-mode.vue | 7 +++++ src/locales/langs/en-us.ts | 1 + src/locales/langs/zh-cn.ts | 1 + src/store/modules/theme/index.ts | 31 +++++++++++++++++-- src/store/modules/theme/shared.ts | 28 ++++++++++++----- src/styles/css/global.css | 4 +++ src/theme/settings.ts | 1 + src/typings/app.d.ts | 3 ++ src/utils/common.ts | 20 ++++++++++++ 9 files changed, 86 insertions(+), 10 deletions(-) diff --git a/src/layouts/modules/theme-drawer/modules/dark-mode.vue b/src/layouts/modules/theme-drawer/modules/dark-mode.vue index 2bf2b6833..f5bcebf43 100644 --- a/src/layouts/modules/theme-drawer/modules/dark-mode.vue +++ b/src/layouts/modules/theme-drawer/modules/dark-mode.vue @@ -21,6 +21,10 @@ function handleSegmentChange(value: string | number) { themeStore.setThemeScheme(value as UnionKey.ThemeScheme); } +function handleGrayscaleChange(value: boolean) { + themeStore.setGrayscale(value); +} + const showSiderInverted = computed(() => !themeStore.darkMode && themeStore.layout.mode.includes('vertical')); @@ -46,6 +50,9 @@ const showSiderInverted = computed(() => !themeStore.darkMode && themeStore.layo + + + diff --git a/src/locales/langs/en-us.ts b/src/locales/langs/en-us.ts index 447fe1020..fcd534bbc 100644 --- a/src/locales/langs/en-us.ts +++ b/src/locales/langs/en-us.ts @@ -57,6 +57,7 @@ const local: App.I18n.Schema = { dark: 'Dark', auto: 'Follow System' }, + grayscale: 'Grayscale', layoutMode: { title: 'Layout Mode', vertical: 'Vertical Menu Mode', diff --git a/src/locales/langs/zh-cn.ts b/src/locales/langs/zh-cn.ts index 61400eb46..5536fe696 100644 --- a/src/locales/langs/zh-cn.ts +++ b/src/locales/langs/zh-cn.ts @@ -57,6 +57,7 @@ const local: App.I18n.Schema = { dark: '暗黑模式', auto: '跟随系统' }, + grayscale: '灰度模式', layoutMode: { title: '布局模式', vertical: '左侧菜单模式', diff --git a/src/store/modules/theme/index.ts b/src/store/modules/theme/index.ts index 8947afce7..f45a81d8c 100644 --- a/src/store/modules/theme/index.ts +++ b/src/store/modules/theme/index.ts @@ -5,7 +5,14 @@ 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'; +import { + addThemeVarsToHtml, + createThemeToken, + getNaiveTheme, + initThemeSettings, + toggleCssDarkMode, + toggleGrayscaleMode +} from './shared'; /** Theme store */ export const useThemeStore = defineStore(SetupStoreId.Theme, () => { @@ -23,6 +30,9 @@ export const useThemeStore = defineStore(SetupStoreId.Theme, () => { return settings.value.themeScheme === 'dark'; }); + /** grayscale mode */ + const grayscaleMode = computed(() => settings.value.grayscale); + /** Theme colors */ const themeColors = computed(() => { const { themeColor, otherColor, isInfoFollowPrimary } = settings.value; @@ -60,6 +70,15 @@ export const useThemeStore = defineStore(SetupStoreId.Theme, () => { settings.value.themeScheme = themeScheme; } + /** + * Set grayscale value + * + * @param isGrayscale + */ + function setGrayscale(isGrayscale: boolean) { + settings.value.grayscale = isGrayscale; + } + /** Toggle theme scheme */ function toggleThemeScheme() { const themeSchemes: UnionKey.ThemeScheme[] = ['light', 'dark', 'auto']; @@ -130,12 +149,19 @@ export const useThemeStore = defineStore(SetupStoreId.Theme, () => { { immediate: true } ); + watch( + grayscaleMode, + val => { + toggleGrayscaleMode(val); + }, + { immediate: true } + ); + // themeColors change, update css vars and storage theme color watch( themeColors, val => { setupThemeVarsToHtml(); - localStg.set('themeColor', val.primary); }, { immediate: true } @@ -153,6 +179,7 @@ export const useThemeStore = defineStore(SetupStoreId.Theme, () => { themeColors, naiveTheme, settingsJson, + setGrayscale, resetStore, setThemeScheme, toggleThemeScheme, diff --git a/src/store/modules/theme/shared.ts b/src/store/modules/theme/shared.ts index e755f8546..2c81af935 100644 --- a/src/store/modules/theme/shared.ts +++ b/src/store/modules/theme/shared.ts @@ -3,6 +3,7 @@ import { getColorByPaletteNumber, getColorPalette } from '@sa/color-palette'; import { addColorAlpha, getRgbOfColor } from '@sa/utils'; import { overrideThemeSettings, themeSettings } from '@/theme/settings'; import { themeVars } from '@/theme/vars'; +import { toggleHtmlClass } from '@/utils/common'; import { localStg } from '@/utils/storage'; const DARK_CLASS = 'dark'; @@ -167,18 +168,29 @@ export function addThemeVarsToHtml(tokens: App.Theme.BaseToken, darkTokens: App. * @param darkMode Is dark mode */ export function toggleCssDarkMode(darkMode = false) { - function addDarkClass() { - document.documentElement.classList.add(DARK_CLASS); - } + const { add, remove } = toggleHtmlClass(DARK_CLASS); - function removeDarkClass() { - document.documentElement.classList.remove(DARK_CLASS); + if (darkMode) { + add(); + } else { + remove(); } +} - if (darkMode) { - addDarkClass(); +/** + * Toggle grayscale mode + * + * @param grayscaleMode Is grayscale mode + */ +export function toggleGrayscaleMode(grayscaleMode = false) { + const GRAYSCALE_CLASS = 'grayscale'; + + const { add, remove } = toggleHtmlClass(GRAYSCALE_CLASS); + + if (grayscaleMode) { + add(); } else { - removeDarkClass(); + remove(); } } diff --git a/src/styles/css/global.css b/src/styles/css/global.css index 3121a3151..141d4de0e 100644 --- a/src/styles/css/global.css +++ b/src/styles/css/global.css @@ -11,3 +11,7 @@ body, html { overflow-x: hidden; } + +html.grayscale { + filter: grayscale(100%); +} diff --git a/src/theme/settings.ts b/src/theme/settings.ts index bba9617b0..1a1088f3e 100644 --- a/src/theme/settings.ts +++ b/src/theme/settings.ts @@ -1,6 +1,7 @@ /** Default theme settings */ export const themeSettings: App.Theme.ThemeSetting = { themeScheme: 'light', + grayscale: false, themeColor: '#646cff', otherColor: { info: '#2080f0', diff --git a/src/typings/app.d.ts b/src/typings/app.d.ts index 13cc492ff..48baaccc9 100644 --- a/src/typings/app.d.ts +++ b/src/typings/app.d.ts @@ -20,6 +20,8 @@ declare namespace App { themeScheme: UnionKey.ThemeScheme; /** Theme color */ themeColor: string; + /** grayscale mode */ + grayscale: boolean; /** Other color */ otherColor: OtherColor; /** Whether info color is followed by the primary color */ @@ -298,6 +300,7 @@ declare namespace App { }; theme: { themeSchema: { title: string } & Record; + grayscale: string; layoutMode: { title: string } & Record; themeColor: { title: string; diff --git a/src/utils/common.ts b/src/utils/common.ts index ddb312545..dc9a368fa 100644 --- a/src/utils/common.ts +++ b/src/utils/common.ts @@ -36,3 +36,23 @@ export function translateOptions(options: CommonType.Option[]) { label: $t(option.label as App.I18n.I18nKey) })); } + +/** + * Toggle html class + * + * @param className + */ +export function toggleHtmlClass(className: string) { + function add() { + document.documentElement.classList.add(className); + } + + function remove() { + document.documentElement.classList.remove(className); + } + + return { + add, + remove + }; +}