Last week, I studied the design of Vben Admin’s environment variables and permissions. Now the project is in use and still in the stage of building the page structure. In the theme, it needs to be modified, so I have a look at the implementation of this part.

  • Vben Admin in-depth understanding of plug-in, environment variable design
  • Vben Admin in-depth understanding of routing, menu, permission design

Doubt point

This part mainly analyzes the configuration related to the topic and how to define and modify the topic.

  • How is the theme switched and what is the logic?
  • How do YOU define which configurations need to change for a topic?

Subject definition

Click on Settings, you can set theme, system theme, top bar theme, menu theme to see where the configuration order is.

Configuration of the list of available colors.

// src/settings/designSetting.ts
// app theme preset color
export const APP_PRESET_COLOR_LIST: string[] = [
  / *... * /
];

// header preset color
export const HEADER_PRESET_BG_COLOR_LIST: string[] = [
  / *... * /
];

// sider preset color
export const SIDE_BAR_BG_COLOR_LIST: string[] = [
  / *... * /
];
Copy the code

The item configuration associated with the topic updates these values as the topic changes.

// src/settings/projectSetting.ts
const setting = {
  // Project theme color
  themeColor: primaryColor,
  // Site grey mode
  grayMode: false.// Color fade mode
  colorWeak: false.// Header configuration
  headerSetting: {
    / / the background color
    bgColor: '#ffffff'./ / theme
    theme: MenuThemeEnum.LIGHT,
  }
  // Menu configuration
  menuSetting: {
    / / the background color
    bgColor: '# 273352'.// Menu theme
    theme: MenuThemeEnum.DARK
  }
}
Copy the code

Theme plug-in Configuration

Take a look at the viet-plugin-theme plug-in before analyzing the implementation, since it is based on this implementation.

This plug-in does two main things: load the ant-Design-Vue dark theme configuration and replace one color value with another.

Customize the theme based on ant-Design-Vue’s official documentation – Implement the Dark theme with getThemeVariables provided in the Dark Theme and do some additional customization.

// build/generate/generateModifyVars.ts
import { getThemeVariables } from 'ant-design-vue/dist/theme';
export function generateModifyVars(dark = false) {
  const modifyVars = getThemeVariables({ dark });
  return {
    ...modifyVars
  };
}

// build/vite/plugin/theme
import { antdDarkThemePlugin } from 'vite-plugin-theme';
export function configThemePlugin() {
  const plugin = [
    antdDarkThemePlugin({
      darkModifyVars: {
        ...generateModifyVars(true)}}); ]return plugin
}
Copy the code

Another configuration is to replace one color value with another color value, which is more complicated to deal with in the source code using a simplified example. Suppose you have a style definition.

.test {
  color: #e72528;
}
Copy the code

Define the plug-in and set it to match the colors you want to change.

// build/vite/plugin/theme
import { viteThemePlugin } from 'vite-plugin-theme';
export function configThemePlugin() {
  const plugin = [
    viteThemePlugin({
      // Match the color you want to change
      colorVariables: ["#e72528"]}); ]return plugin
}
Copy the code

Then implement a function to replace the color value of the stylesheet.

import { replaceStyleVariables } from "vite-plugin-theme/es/client";
export async function changeThemeColor(color: string) {
  return await replaceStyleVariables({
    colorVariables: [color]
  });
}
Copy the code

When changeThemeColor(“#1d1b1b”) is called, the result is as follows.

.test {
  color: #e72528;
}
/* One more style overrides the previous */
.test {
  color: #e72528;
}
Copy the code

Topic switching processing

When the theme switch is found to be processed by a function, so focus on how this function is processed.

// src/layouts/default/setting/SettingDrawer.tsx
function renderHeaderTheme() {
  // ...
  baseHandler(event, value);
}
function renderSiderTheme() {
  // ...
  baseHandler(event, value);
}
function renderMainTheme() {
  // ...
  baseHandler(event, value);
}
Copy the code

Call different functions on each branch for separate processing, and let’s look at the implementation of each function.

// src/layouts/default/setting/handler.ts
export function baseHandler(event: HandlerEnum, value: any) {
  const appStore = useAppStore();
  // Handle the setting type
  const config = handler(event, value);
  // Update the project configuration
  appStore.setProjectConfig(config);
}

export function handler(event: HandlerEnum, value: any) :DeepPartial<ProjectConfig> {
  const appStore = useAppStore();
  const { getThemeColor, getDarkMode } = useRootSetting();
  switch (event) {
    // Update the system color
    case HandlerEnum.CHANGE_THEME_COLOR:
      if (getThemeColor.value === value) {
        return {};
      }
      changeTheme(value);

      return { themeColor: value };

    // Update the system theme
    case HandlerEnum.CHANGE_THEME:
      if (getDarkMode.value === value) {
        return {};
      }
      updateDarkTheme(value);

      return {};

    // Update the menu theme
    case HandlerEnum.MENU_THEME:
      updateSidebarBgColor(value);
      return { menuSetting: { bgColor: value } };

    // Update the top column theme
    case HandlerEnum.HEADER_THEME:
      updateHeaderBgColor(value);
      return { headerSetting: { bgColor: value } }; }}Copy the code

The system theme

Calling changeTheme to update the system theme is done using the color value substitution stylesheet method above, as configured above.

// src/logics/theme/index.ts
export async function changeTheme(color: string) {
  const colors = generateColors({
    mixDarken,
    mixLighten,
    tinycolor,
    color
  });

  return await replaceStyleVariables({
    colorVariables: [...getThemeColors(color), ...colors]
  });
}
Copy the code

Default theme and dark theme

Call updateDarkTheme to update the dark theme and switch the dark theme by changing the DATA-theme attribute of the HTML tag.

// src/logics/theme/dark.ts
export async function updateDarkTheme(mode: string | null = "light") {
  const htmlRoot = document.getElementById("htmlRoot");
  if (mode === "dark") {
    if (import.meta.env.PROD && ! darkCssIsReady) {await loadDarkThemeCss();
    }
    htmlRoot.setAttribute("data-theme"."dark");
  } else {
    htmlRoot.setAttribute("data-theme"."light"); }}Copy the code

Use sample columns.

[data-theme="dark"] {
  /* Dark theme theme style */
}
[data-theme="light"] {
  /* Color theme theme style */
}
Copy the code

Top bar theme and menu theme

The top bar and menu styles are implemented using the CSS function var to get the style variables and update the variable values on the HTML properties.

// src/logics/theme/updateBackground.ts
export function updateHeaderBgColor(color) {
  setCssVar("--header-bg-color", color);
  // ...
}

export function updateSidebarBgColor(color) {
  setCssVar("--sider-dark-bg-color", color);
  // ...
}
Copy the code

Use sample columns.

html{-header-bg-color: # 394664;
  --sider-dark-bg-color: # 273352;
}

.ant-layout-sider-dark {
  background-color: var(--sider-dark-bg-color);
}

.vben-layout-header--dark {
  background-color: var(--header-bg-color);
}
Copy the code

Color weak mode and gray mode

There are also two theme modes that change the project color as a whole, using filters.

// src/logics/theme/updateColorWeak.ts
export function updateColorWeak(colorWeak: boolean) {
  toggleClass(colorWeak, "color-weak".document.documentElement);
}

// src/logics/theme/updateGrayMode.ts
export function updateGrayMode(gray: boolean) {
  toggleClass(gray, "gray-mode".document.documentElement);
}
Copy the code
.color-weak {
  filter: invert(80%);
}

.gray-mode {
  filter: grayscale(100%);
  filter: progid:dximagetransform.microsoft.basicimage(grayscale=1);
}
Copy the code

conclusion

No summary, the existing Vben Admin common situation has been handled when writing new components should try to use defined variables, take advantage of the existing theme rules.