From cdebe3750cf7481f1de07a36b8122ce88f3d8054 Mon Sep 17 00:00:00 2001 From: Kirk Lin Date: Wed, 19 Jul 2023 18:30:41 +0800 Subject: [PATCH] feat: add support for CSS variables in UnoCSS references --- apps/admin/src/App.vue | 6 ++ .../composables/useNaiveUIConfigProvider.ts | 1 + apps/admin/src/setting/themeSetting.ts | 1 + apps/admin/src/store/subscribe/index.ts | 9 +++ apps/admin/src/store/subscribe/theme.ts | 59 +++++++++++++++++++ packages/node/vite/src/plugins/unocss.ts | 34 +++++++++++ packages/web/utils/src/color/utils.ts | 9 +++ packages/web/utils/src/domUtils.ts | 13 ++++ 8 files changed, 132 insertions(+) create mode 100644 apps/admin/src/store/subscribe/index.ts create mode 100644 apps/admin/src/store/subscribe/theme.ts diff --git a/apps/admin/src/App.vue b/apps/admin/src/App.vue index b79d5d8..180ea23 100644 --- a/apps/admin/src/App.vue +++ b/apps/admin/src/App.vue @@ -1,7 +1,13 @@ diff --git a/apps/admin/src/composables/useNaiveUIConfigProvider.ts b/apps/admin/src/composables/useNaiveUIConfigProvider.ts index b65c2a1..f9b2be5 100644 --- a/apps/admin/src/composables/useNaiveUIConfigProvider.ts +++ b/apps/admin/src/composables/useNaiveUIConfigProvider.ts @@ -10,6 +10,7 @@ export function useNaiveUIConfigProvider() { "theme": getNaiveUIPresetTheme, "theme-overrides": getNaiveUICustomTheme, "namespace": designNamespace, + "inline-theme-disabled": true, }); return { diff --git a/apps/admin/src/setting/themeSetting.ts b/apps/admin/src/setting/themeSetting.ts index 8ce65e2..89ad983 100644 --- a/apps/admin/src/setting/themeSetting.ts +++ b/apps/admin/src/setting/themeSetting.ts @@ -26,5 +26,6 @@ export const DEFAULT_THEME_SETTING: ThemeSetting = { info: presetPrimaryColors.blue, success: presetPrimaryColors.green, warning: presetPrimaryColors.orange, + error: presetPrimaryColors.red, }, }; diff --git a/apps/admin/src/store/subscribe/index.ts b/apps/admin/src/store/subscribe/index.ts new file mode 100644 index 0000000..83dee89 --- /dev/null +++ b/apps/admin/src/store/subscribe/index.ts @@ -0,0 +1,9 @@ +import subscribeThemeStore from "./theme"; + +/** + * Subscribe to the store. + * 订阅 store。 + */ +export function subscribeStore() { + subscribeThemeStore(); +} diff --git a/apps/admin/src/store/subscribe/theme.ts b/apps/admin/src/store/subscribe/theme.ts new file mode 100644 index 0000000..a8f425b --- /dev/null +++ b/apps/admin/src/store/subscribe/theme.ts @@ -0,0 +1,59 @@ +import { colorToRgb, generateColorPalettes, setCssVariable } from "@celeris/utils"; +import { effectScope, onScopeDispose, watch } from "vue"; +import type { GlobalThemeOverrides } from "naive-ui"; +import { kebabCase } from "lodash-es"; +import { useDesignStore } from "~/store/modules/design"; + +/** + * 订阅NaiveUI自定义主题的变化 + * Subscribe to changes in the NaiveUI custom theme + */ +export default function subscribeThemeStore() { + const designStore = useDesignStore(); + const scope = effectScope(); + + scope.run(() => { + watch( + () => designStore.getNaiveUICustomTheme, + (newTheme) => { + if (newTheme?.common) { + addThemeCssVariablesToHtml(newTheme?.common); + } + }, + { immediate: true }, + ); + }); + /** + * 组件销毁时清理effect scope + * Clean up the effect scope when the component is destroyed + */ + onScopeDispose(() => { + scope.stop(); + }); +} + +type ThemeVars = Exclude; +type ThemeVarsKeys = keyof ThemeVars; + +/** + * 将主题颜色变量添加到HTML中 + * Add theme color variables to HTML + * @param {ThemeVars} themeVars - 主题变量对象 + */ +function addThemeCssVariablesToHtml(themeVars: ThemeVars) { + for (const [key, color] of Object.entries(themeVars) as [ThemeVarsKeys, string][]) { + if (color) { + const { r, g, b } = colorToRgb(color); + setCssVariable(`--${kebabCase(key)}`, `${r},${g},${b}`); + if (key === "primaryColor") { + const colorPalettes = generateColorPalettes(color); + + for (let index = 0; index < colorPalettes.length; index++) { + const palette = colorPalettes[index]; + const { r: pR, g: pG, b: pB } = colorToRgb(palette); + setCssVariable(`--${kebabCase(key)}${index + 1}`, `${pR},${pG},${pB}`); + } + } + } + } +} diff --git a/packages/node/vite/src/plugins/unocss.ts b/packages/node/vite/src/plugins/unocss.ts index 30b7c30..d2a1038 100644 --- a/packages/node/vite/src/plugins/unocss.ts +++ b/packages/node/vite/src/plugins/unocss.ts @@ -46,6 +46,40 @@ export function createUnoCSSPluginConfig(): PluginOption { "flex-x-center": "flex justify-center", "flex-y-center": "flex items-center", }, + theme: { + colors: { + primary: "rgb(var(--primary-color))", + primary_hover: "rgb(var(--primary-color-hover))", + primary_suppl: "rgb(var(--primary-color-suppl))", + primary_pressed: "rgb(var(--primary-color-pressed))", + primary_1: "rgb(var(--primary-color1))", + primary_2: "rgb(var(--primary-color2))", + primary_3: "rgb(var(--primary-color3))", + primary_4: "rgb(var(--primary-color4))", + primary_5: "rgb(var(--primary-color5))", + primary_6: "rgb(var(--primary-color6))", + primary_7: "rgb(var(--primary-color7))", + primary_8: "rgb(var(--primary-color8))", + primary_9: "rgb(var(--primary-color9))", + primary_10: "rgb(var(--primary-color10))", + info: "rgb(var(--info-color))", + info_hover: "rgb(var(--info-color-hover))", + info_suppl: "rgb(var(--info-color-suppl))", + info_pressed: "rgb(var(--info-color-pressed))", + success: "rgb(var(--success-color))", + success_hover: "rgb(var(--success-color-hover))", + success_suppl: "rgb(var(--success-color-suppl))", + success_pressed: "rgb(var(--success-color-pressed))", + warning: "rgb(var(--warning-color))", + warning_hover: "rgb(var(--warning-color-hover))", + warning_suppl: "rgb(var(--warning-color-suppl))", + warning_pressed: "rgb(var(--warning-color-pressed))", + error: "rgb(var(--error-color))", + error_hover: "rgb(var(--error-color-hover))", + error_suppl: "rgb(var(--error-color-suppl))", + error_pressed: "rgb(var(--error-color-pressed))", + }, + }, transformers: [ transformerDirectives(), transformerVariantGroup(), diff --git a/packages/web/utils/src/color/utils.ts b/packages/web/utils/src/color/utils.ts index 4729ba7..cab5235 100644 --- a/packages/web/utils/src/color/utils.ts +++ b/packages/web/utils/src/color/utils.ts @@ -1,5 +1,14 @@ import { colord } from "colord"; +import type { RgbaColor } from "colord/types"; export function isWhiteColor(color: string) { return colord(color).isEqual("#ffffff"); } + +export function isBlackColor(color: string) { + return colord(color).isEqual("#000000"); +} + +export function colorToRgb(color: string): RgbaColor { + return colord(color).toRgb(); +} diff --git a/packages/web/utils/src/domUtils.ts b/packages/web/utils/src/domUtils.ts index 99e774f..85a93cf 100644 --- a/packages/web/utils/src/domUtils.ts +++ b/packages/web/utils/src/domUtils.ts @@ -24,6 +24,19 @@ export function setCssVariable(property: string, value: string | null, element: element.style.setProperty(property, value); // Set the specified property with the specified value. } +/** + * Set CSS variables on the specified element. + * 在指定的元素上设置 CSS 变量。 + * + * @param variables - An object containing the CSS variables to set and their values. 包含要设置的 CSS 变量及其值的对象。 + * @param element - The HTML element on which to set the CSS variables. 要设置 CSS 变量的 HTML 元素。 + */ +export function setCssVariables(variables: Record, element: HTMLElement = document.documentElement) { + for (const [property, value] of Object.entries(variables)) { + element.style.setProperty(property, value); + } +} + /** * Parses a CSS string and returns an object with key-value pairs of CSS properties and their values. * 解析 CSS 字符串并返回一个包含 CSS 属性及其值的键值对对象。