mirror of
				https://github.com/soybeanjs/soybean-admin.git
				synced 2025-11-04 07:43:42 +08:00 
			
		
		
		
	feat(projects): support grayscale. fixed #385
This commit is contained in:
		@@ -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'));
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
@@ -46,6 +50,9 @@ const showSiderInverted = computed(() => !themeStore.darkMode && themeStore.layo
 | 
			
		||||
        <NSwitch v-model:value="themeStore.sider.inverted" />
 | 
			
		||||
      </SettingItem>
 | 
			
		||||
    </Transition>
 | 
			
		||||
    <SettingItem :label="$t('theme.grayscale')">
 | 
			
		||||
      <NSwitch :value="themeStore.grayscale" @update:value="handleGrayscaleChange" />
 | 
			
		||||
    </SettingItem>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -57,6 +57,7 @@ const local: App.I18n.Schema = {
 | 
			
		||||
      dark: 'Dark',
 | 
			
		||||
      auto: 'Follow System'
 | 
			
		||||
    },
 | 
			
		||||
    grayscale: 'Grayscale',
 | 
			
		||||
    layoutMode: {
 | 
			
		||||
      title: 'Layout Mode',
 | 
			
		||||
      vertical: 'Vertical Menu Mode',
 | 
			
		||||
 
 | 
			
		||||
@@ -57,6 +57,7 @@ const local: App.I18n.Schema = {
 | 
			
		||||
      dark: '暗黑模式',
 | 
			
		||||
      auto: '跟随系统'
 | 
			
		||||
    },
 | 
			
		||||
    grayscale: '灰度模式',
 | 
			
		||||
    layoutMode: {
 | 
			
		||||
      title: '布局模式',
 | 
			
		||||
      vertical: '左侧菜单模式',
 | 
			
		||||
 
 | 
			
		||||
@@ -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,
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  function removeDarkClass() {
 | 
			
		||||
    document.documentElement.classList.remove(DARK_CLASS);
 | 
			
		||||
  }
 | 
			
		||||
  const { add, remove } = toggleHtmlClass(DARK_CLASS);
 | 
			
		||||
 | 
			
		||||
  if (darkMode) {
 | 
			
		||||
    addDarkClass();
 | 
			
		||||
    add();
 | 
			
		||||
  } else {
 | 
			
		||||
    removeDarkClass();
 | 
			
		||||
    remove();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 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 {
 | 
			
		||||
    remove();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -11,3 +11,7 @@ body,
 | 
			
		||||
html {
 | 
			
		||||
  overflow-x: hidden;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
html.grayscale {
 | 
			
		||||
  filter: grayscale(100%);
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,7 @@
 | 
			
		||||
/** Default theme settings */
 | 
			
		||||
export const themeSettings: App.Theme.ThemeSetting = {
 | 
			
		||||
  themeScheme: 'light',
 | 
			
		||||
  grayscale: false,
 | 
			
		||||
  themeColor: '#646cff',
 | 
			
		||||
  otherColor: {
 | 
			
		||||
    info: '#2080f0',
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										3
									
								
								src/typings/app.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								src/typings/app.d.ts
									
									
									
									
										vendored
									
									
								
							@@ -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<UnionKey.ThemeScheme, string>;
 | 
			
		||||
        grayscale: string;
 | 
			
		||||
        layoutMode: { title: string } & Record<UnionKey.ThemeLayoutMode, string>;
 | 
			
		||||
        themeColor: {
 | 
			
		||||
          title: string;
 | 
			
		||||
 
 | 
			
		||||
@@ -36,3 +36,23 @@ export function translateOptions(options: CommonType.Option<string>[]) {
 | 
			
		||||
    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
 | 
			
		||||
  };
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user