diff --git a/README.md b/README.md
index 9d5d883..6ba9c91 100644
--- a/README.md
+++ b/README.md
@@ -67,3 +67,79 @@ pnpm up
pnpm lint
pnpm lint:fix
```
+
+## 主题
+
+### 主题配置
+
+```ts
+const themeSetting = {
+ themeMode: 'auto',
+ themeColor: {
+ primaryColor: '#18A058',
+ infoColor: '#2080F0',
+ successColor: '#18A058',
+ warningColor: '#F0A020',
+ errorColor: '#D03050',
+ },
+ darkThemeColor: {
+ primaryColor: '#63e2b7',
+ infoColor: '#70c0e8',
+ successColor: '#63e2b7',
+ warningColor: '#f2c97d',
+ errorColor: '#e88080',
+ },
+ layoutMode: 'vertical',
+ header: {
+ show: true,
+ height: 64,
+ inverted: false,
+ },
+ sider: {
+ show: true,
+ width: 240,
+ collapsedWidth: 64,
+ inverted: false,
+ },
+ footer: {
+ show: true,
+ height: 64,
+ inverted: false,
+ },
+ page: {
+ animate: true,
+ animateMode: 'fade-slide',
+ loadingBar: true,
+ },
+}
+
+const { setting } = useThemeSetting({ initialValue: themeSetting })
+```
+
+### 主题模式
+
+- 明亮
+- 暗黑
+- 系统
+
+```ts
+const mode = useColorMode()
+console.log(mode.value) // 'light' | 'dark' | 'auto'
+```
+
+### 全局化配置
+
+```ts
+const configProviderProps = useNaiveConfigProvider()
+```
+
+```html
+ ...
+```
+
+### 脱离上下文的 API
+
+```ts
+const { dialog } = useNaiveApi()
+dialog.warning('warning!')
+```
diff --git a/src/App.vue b/src/App.vue
index 3d7e4ba..a8002a2 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -3,9 +3,21 @@ import { cloneDeep } from 'lodash-es'
import { themeSetting } from '~/settings/theme'
const { setting } = useThemeSetting({ initialValue: cloneDeep(themeSetting) })
-const { theme, themeOverrides } = useNaiveTheme({
- themeOverrides: computed(() => ({
- common: setting.value?.themeColor,
+
+const configProviderProps = useNaiveConfigProvider({
+ themeOverrides: {
+ common: {
+ borderRadius: '8px',
+ },
+ Card: {
+ borderRadius: '12px',
+ },
+ Drawer: {
+ borderRadius: '12px',
+ },
+ },
+ lightThemeOverrides: computed(() => ({
+ common: setting.value?.lightThemeColor,
})),
darkThemeOverrides: computed(() => ({
common: setting.value?.darkThemeColor,
@@ -14,10 +26,7 @@ const { theme, themeOverrides } = useNaiveTheme({
-
+
diff --git a/src/composables/useNaiveConfigProvider.ts b/src/composables/useNaiveConfigProvider.ts
new file mode 100644
index 0000000..db45da5
--- /dev/null
+++ b/src/composables/useNaiveConfigProvider.ts
@@ -0,0 +1,156 @@
+import type { UseColorModeOptions } from '@vueuse/core'
+import { merge } from 'lodash-es'
+import type { ConfigProviderProps, GlobalThemeOverrides } from 'naive-ui'
+import { commonDark, darkTheme, dateZhCN, zhCN } from 'naive-ui'
+import type { MaybeRefOrGetter } from 'vue'
+
+export type ColorType = 'primary' | 'info' | 'success' | 'warning' | 'error'
+export type ColorScene = '' | 'Suppl' | 'Hover' | 'Pressed'
+export interface ColorAction {
+ scene: ColorScene
+ handler: (color: string) => string
+}
+
+export interface UseNaiveConfigProviderOptions {
+ /**
+ * 是否不存在 DOM 包裹
+ */
+ abstract?: ConfigProviderProps['abstract']
+ /**
+ * 屏幕响应式断点,对 n-grid 生效。这个属性不是响应式的,你需要在组件第一次挂载时就设定好
+ */
+ breakpoints?: ConfigProviderProps['breakpoints']
+ /**
+ * 内部所有组件的类的前缀,仅首次设定会生效
+ */
+ clsPrefix?: ConfigProviderProps['clsPrefix']
+ /**
+ * 对后代组件生效的日期语言对象,为 null 时会使用默认 dateEnUS,为 undefined 时会继承上级 n-config-provider
+ */
+ dateLocale?: ConfigProviderProps['dateLocale']
+ /**
+ * 是否禁用 inline css 主题变量,如果你不会频繁调整主题变量,并且需要 SSR 或者想让 devtools 看起来更干净,可以打开这个选项。注意,这个属性不是响应式的
+ */
+ inlineThemeDisabled?: ConfigProviderProps['inlineThemeDisabled']
+ /**
+ * 公式组件需要的 katex 对象
+ */
+ katex?: ConfigProviderProps['katex']
+ /**
+ * 对后代组件生效的语言对象,为 null 时会使用默认 enUS,为 undefined 时会继承上级 n-config-provider
+ */
+ locale?: ConfigProviderProps['locale']
+ /**
+ * n-config-provider 内部组件被卸载于其他位置的 DOM 的类名
+ */
+ namespace?: ConfigProviderProps['namespace']
+ /**
+ * 是否禁用默认样式,如果你禁用了它,便可以完全控制全局样式。你也可以使用 n-global-style 去挂载全局样式(推荐,样式是响应式的)
+ */
+ preflightStyleDisabled?: ConfigProviderProps['preflightStyleDisabled']
+ /**
+ * n-config-provider 被渲染成的元素
+ */
+ tag?: ConfigProviderProps['tag']
+ /**
+ * 主题模式
+ */
+ themeMode?: UseColorModeOptions['initialValue']
+ /**
+ * Naive UI 主题覆盖
+ */
+ themeOverrides?: MaybeRefOrGetter
+ /**
+ * Naive UI 明亮主题覆盖
+ */
+ lightThemeOverrides?: MaybeRefOrGetter
+ /**
+ * Naive UI 暗黑主题覆盖
+ */
+ darkThemeOverrides?: MaybeRefOrGetter
+}
+
+export interface UseNaiveConfigProviderReturn extends ConfigProviderProps {}
+
+export function useNaiveConfigProvider(options: UseNaiveConfigProviderOptions = {}): UseNaiveConfigProviderReturn {
+ const {
+ dateLocale = dateZhCN,
+ locale = zhCN,
+ themeMode,
+ themeOverrides: initialThemeOverrides = {},
+ lightThemeOverrides: initialLightThemeOverrides = {},
+ darkThemeOverrides: initialDarkThemeOverrides = {},
+ ...opts
+ } = options
+
+ const mode = useColorMode({ initialValue: themeMode })
+ const isDark = computed(() => mode.value === 'dark')
+ const theme = computed(() => isDark.value ? darkTheme : null)
+
+ const currentThemeOverrides = computed(() => {
+ const themeOverrides = isDark.value ? toValue(initialDarkThemeOverrides) : toValue(initialLightThemeOverrides)
+ return merge(themeOverrides, toValue(initialThemeOverrides))
+ })
+ const themeOverrides = computed(() => {
+ if (!currentThemeOverrides.value)
+ return {}
+
+ const commonColor = getCommonColor(currentThemeOverrides.value.common, isDark.value)
+ return {
+ ...currentThemeOverrides.value,
+ common: {
+ ...currentThemeOverrides.value.common,
+ ...commonColor,
+ },
+ }
+ })
+
+ function getGenerateColors(color: string, isDark: boolean): string[] {
+ return isDark
+ ? generateColorPalettes(color, true, commonDark.bodyColor)
+ : generateColorPalettes(color)
+ }
+
+ function getCommonColor(commonColor: GlobalThemeOverrides['common'], isDark: boolean) {
+ const result: any = {}
+ const keys = Object.keys(commonColor!) as ColorType[]
+
+ const colorActions: ColorAction[] = [
+ {
+ scene: '',
+ handler: color => color,
+ },
+ {
+ scene: 'Hover',
+ handler: color => getGenerateColors(color, isDark)[4],
+ },
+ {
+ scene: 'Suppl',
+ handler: color => getGenerateColors(color, isDark)[4],
+ },
+ {
+ scene: 'Pressed',
+ handler: color => getGenerateColors(color, isDark)[6],
+ },
+ ]
+ keys.forEach((key) => {
+ if (key.includes('Color')) {
+ colorActions.forEach((action) => {
+ const color = action.handler((commonColor as any)[key])
+ const colorKey = key + action.scene
+ result[colorKey] = color
+ })
+ }
+ })
+
+ return result
+ }
+
+ return reactive({
+ dateLocale,
+ locale,
+ theme,
+ themeOverrides,
+ ...opts,
+ })
+}
diff --git a/src/composables/useNaiveApi.ts b/src/composables/useNaiveDiscreteApi.ts
similarity index 58%
rename from src/composables/useNaiveApi.ts
rename to src/composables/useNaiveDiscreteApi.ts
index 431f8e5..9787f89 100644
--- a/src/composables/useNaiveApi.ts
+++ b/src/composables/useNaiveDiscreteApi.ts
@@ -1,7 +1,9 @@
-import type { DialogApi, LoadingBarApi, MessageApi, NotificationApi } from 'naive-ui'
+import type { ConfigProviderProps, DialogApi, LoadingBarApi, MessageApi, NotificationApi } from 'naive-ui'
import { createDiscreteApi } from 'naive-ui'
-export interface UseNaiveApiReturn {
+export interface UseNaiveDiscreteApiOptions extends ConfigProviderProps {}
+
+export interface UseNaiveDiscreteApiReturn {
/**
* Naive UI 对话框 API
*/
@@ -23,25 +25,23 @@ export interface UseNaiveApiReturn {
/**
* Naive UI 脱离上下文的 API
*/
-export function useNaiveApi(): UseNaiveApiReturn {
+export function useNaiveDiscreteApi(options: UseNaiveDiscreteApiOptions = {}): UseNaiveDiscreteApiReturn {
const { setting } = useThemeSetting()
- const { theme, themeOverrides } = useNaiveTheme({
- themeOverrides: computed(() => ({
- common: setting.value?.themeColor,
+ const configProviderProps = useNaiveConfigProvider({
+ lightThemeOverrides: computed(() => ({
+ common: setting.value?.lightThemeColor,
})),
darkThemeOverrides: computed(() => ({
common: setting.value?.darkThemeColor,
})),
+ ...options,
})
const { dialog, loadingBar, message, notification } = createDiscreteApi(
['message', 'dialog', 'notification', 'loadingBar'],
{
- configProviderProps: {
- theme: theme.value,
- themeOverrides: themeOverrides.value,
- },
+ configProviderProps,
},
)
diff --git a/src/settings/theme.ts b/src/settings/theme.ts
index a5d3054..72da0fd 100644
--- a/src/settings/theme.ts
+++ b/src/settings/theme.ts
@@ -1,6 +1,6 @@
export const themeSetting = {
themeMode: 'auto',
- themeColor: {
+ lightThemeColor: {
primaryColor: '#18A058',
infoColor: '#2080F0',
successColor: '#18A058',
@@ -24,6 +24,7 @@ export const themeSetting = {
show: true,
width: 240,
collapsedWidth: 64,
+ collapsed: false,
inverted: false,
},
footer: {