uview-pro 0.3.16 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/changelog.md +82 -0
- package/components/u-action-sheet-item/u-action-sheet-item.vue +1 -1
- package/components/u-alert-tips/u-alert-tips.vue +2 -2
- package/components/u-avatar/u-avatar.vue +5 -5
- package/components/u-avatar-cropper/u-avatar-cropper.vue +5 -5
- package/components/u-avatar-cropper/weCropper.js +1 -1
- package/components/u-avatar-cropper/weCropper.ts +1 -1
- package/components/u-back-top/types.ts +1 -1
- package/components/u-back-top/u-back-top.vue +1 -1
- package/components/u-badge/u-badge.vue +1 -31
- package/components/u-button/types.ts +1 -1
- package/components/u-button/u-button.vue +45 -37
- package/components/u-calendar/types.ts +4 -4
- package/components/u-calendar/u-calendar.vue +8 -8
- package/components/u-car-keyboard/u-car-keyboard.vue +5 -5
- package/components/u-card/types.ts +2 -2
- package/components/u-card/u-card.vue +3 -3
- package/components/u-cell-group/u-cell-group.vue +1 -1
- package/components/u-cell-item/u-cell-item.vue +2 -2
- package/components/u-checkbox/u-checkbox.vue +7 -7
- package/components/u-circle-progress/types.ts +4 -3
- package/components/u-circle-progress/u-circle-progress.vue +3 -3
- package/components/u-city-select/u-city-select.vue +1 -1
- package/components/u-collapse/types.ts +2 -2
- package/components/u-collapse/u-collapse.vue +1 -1
- package/components/u-collapse-item/u-collapse-item.vue +1 -1
- package/components/u-column-notice/u-column-notice.vue +2 -2
- package/components/u-config-provider/types.ts +34 -0
- package/components/u-config-provider/u-config-provider.vue +141 -0
- package/components/u-count-down/types.ts +4 -4
- package/components/u-count-down/u-count-down.vue +4 -4
- package/components/u-count-to/types.ts +1 -1
- package/components/u-count-to/u-count-to.vue +1 -1
- package/components/u-divider/types.ts +3 -3
- package/components/u-divider/u-divider.vue +4 -4
- package/components/u-dropdown/u-dropdown.vue +3 -3
- package/components/u-empty/types.ts +2 -2
- package/components/u-empty/u-empty.vue +1 -1
- package/components/u-field/types.ts +3 -3
- package/components/u-field/u-field.vue +6 -6
- package/components/u-form-item/u-form-item.vue +1 -1
- package/components/u-full-screen/u-full-screen.vue +1 -1
- package/components/u-gap/u-gap.vue +2 -2
- package/components/u-grid-item/types.ts +1 -1
- package/components/u-grid-item/u-grid-item.vue +3 -3
- package/components/u-icon/types.ts +2 -2
- package/components/u-icon/u-icon.vue +2 -2
- package/components/u-image/types.ts +4 -2
- package/components/u-image/u-image.vue +7 -2
- package/components/u-index-anchor/u-index-anchor.vue +3 -3
- package/components/u-index-list/u-index-list.vue +1 -1
- package/components/u-input/types.ts +4 -4
- package/components/u-input/u-input.vue +7 -7
- package/components/u-keyboard/u-keyboard.vue +3 -3
- package/components/u-lazy-load/u-lazy-load.vue +1 -1
- package/components/u-line/types.ts +1 -1
- package/components/u-line/u-line.vue +1 -1
- package/components/u-line-progress/types.ts +2 -2
- package/components/u-line-progress/u-line-progress.vue +3 -3
- package/components/u-link/u-link.vue +1 -1
- package/components/u-loading/types.ts +1 -1
- package/components/u-loading/u-loading.vue +3 -3
- package/components/u-loading-popup/types.ts +1 -1
- package/components/u-loading-popup/u-loading-popup.vue +2 -2
- package/components/u-loadmore/types.ts +2 -2
- package/components/u-loadmore/u-loadmore.vue +6 -6
- package/components/u-message-input/u-message-input.vue +5 -5
- package/components/u-modal/u-modal.vue +2 -2
- package/components/u-navbar/types.ts +4 -4
- package/components/u-navbar/u-navbar.vue +27 -20
- package/components/u-no-network/u-no-network.vue +2 -2
- package/components/u-number-box/types.ts +4 -4
- package/components/u-number-box/u-number-box.vue +6 -6
- package/components/u-number-keyboard/u-number-keyboard.vue +2 -2
- package/components/u-picker/u-picker.vue +4 -4
- package/components/u-popup/types.ts +1 -1
- package/components/u-popup/u-popup.vue +6 -6
- package/components/u-radio/u-radio.vue +7 -7
- package/components/u-rate/types.ts +2 -2
- package/components/u-rate/u-rate.vue +2 -2
- package/components/u-read-more/types.ts +1 -1
- package/components/u-row-notice/u-row-notice.vue +2 -2
- package/components/u-search/types.ts +4 -4
- package/components/u-search/u-search.vue +4 -4
- package/components/u-section/types.ts +2 -2
- package/components/u-section/u-section.vue +2 -2
- package/components/u-select/u-select.vue +6 -6
- package/components/u-skeleton/types.ts +2 -2
- package/components/u-skeleton/u-skeleton.vue +2 -2
- package/components/u-slider/types.ts +1 -1
- package/components/u-slider/u-slider.vue +4 -4
- package/components/u-step/u-step.vue +4 -4
- package/components/u-steps/u-steps.vue +3 -3
- package/components/u-sticky/types.ts +1 -1
- package/components/u-sticky/u-sticky.vue +1 -1
- package/components/u-subsection/types.ts +4 -4
- package/components/u-subsection/u-subsection.vue +7 -7
- package/components/u-swipe-action/types.ts +1 -1
- package/components/u-swipe-action/u-swipe-action.vue +2 -2
- package/components/u-swiper/types.ts +1 -1
- package/components/u-swiper/u-swiper.vue +1 -1
- package/components/u-switch/types.ts +1 -1
- package/components/u-switch/u-switch.vue +5 -5
- package/components/u-tabbar/types.ts +5 -4
- package/components/u-tabbar/u-tabbar.vue +5 -5
- package/components/u-table/types.ts +3 -3
- package/components/u-table/u-table.vue +3 -3
- package/components/u-tabs/types.ts +1 -1
- package/components/u-tabs/u-tabs.vue +2 -2
- package/components/u-tabs-swiper/types.ts +1 -1
- package/components/u-tabs-swiper/u-tabs-swiper.vue +2 -2
- package/components/u-tag/u-tag.vue +12 -12
- package/components/u-text/types.ts +1 -1
- package/components/u-text/u-text.vue +1 -1
- package/components/u-textarea/types.ts +1 -1
- package/components/u-textarea/u-textarea.vue +6 -6
- package/components/u-time-line/u-time-line.vue +1 -1
- package/components/u-time-line-item/types.ts +1 -1
- package/components/u-time-line-item/u-time-line-item.vue +2 -3
- package/components/u-toast/u-toast.vue +8 -8
- package/components/u-top-tips/u-top-tips.vue +1 -1
- package/components/u-upload/types.ts +2 -2
- package/components/u-upload/u-upload.vue +1 -1
- package/index.scss +1 -0
- package/index.ts +42 -11
- package/libs/config/theme-tokens.ts +101 -0
- package/libs/css/style.theme.scss +31 -0
- package/libs/css/style.vue.scss +1 -1
- package/libs/function/clipboard.ts +6 -11
- package/libs/function/color.ts +53 -22
- package/libs/hooks/index.ts +2 -0
- package/libs/hooks/useColor.ts +61 -0
- package/libs/hooks/useTheme.ts +162 -0
- package/libs/index.ts +4 -3
- package/libs/util/config-provider.ts +580 -0
- package/libs/util/system-theme.ts +25 -0
- package/package.json +5 -5
- package/theme.scss +50 -34
- package/types/components.d.ts +1 -0
- package/types/global.d.ts +47 -2
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { Theme, ThemeColor } from '../../types/global';
|
|
2
|
+
|
|
3
|
+
const lightPalette: ThemeColor = {
|
|
4
|
+
primary: '#2979ff',
|
|
5
|
+
primaryDark: '#2b85e4',
|
|
6
|
+
primaryDisabled: '#a0cfff',
|
|
7
|
+
primaryLight: '#ecf5ff',
|
|
8
|
+
success: '#19be6b',
|
|
9
|
+
successDark: '#18b566',
|
|
10
|
+
successDisabled: '#71d5a1',
|
|
11
|
+
successLight: '#dbf1e1',
|
|
12
|
+
warning: '#ff9900',
|
|
13
|
+
warningDark: '#f29100',
|
|
14
|
+
warningDisabled: '#fcbd71',
|
|
15
|
+
warningLight: '#fdf6ec',
|
|
16
|
+
error: '#fa3534',
|
|
17
|
+
errorDark: '#dd6161',
|
|
18
|
+
errorDisabled: '#fab6b6',
|
|
19
|
+
errorLight: '#fef0f0',
|
|
20
|
+
info: '#909399',
|
|
21
|
+
infoDark: '#82848a',
|
|
22
|
+
infoDisabled: '#c8c9cc',
|
|
23
|
+
infoLight: '#f4f4f5',
|
|
24
|
+
whiteColor: '#ffffff',
|
|
25
|
+
blackColor: '#000000',
|
|
26
|
+
mainColor: '#303133',
|
|
27
|
+
contentColor: '#606266',
|
|
28
|
+
tipsColor: '#909399',
|
|
29
|
+
lightColor: '#c0c4cc',
|
|
30
|
+
borderColor: '#dcdfe6',
|
|
31
|
+
dividerColor: '#e4e7ed',
|
|
32
|
+
maskColor: 'rgba(0, 0, 0, 0.4)',
|
|
33
|
+
shadowColor: 'rgba(0, 0, 0, 0.1)',
|
|
34
|
+
bgColor: '#f3f4f6',
|
|
35
|
+
bgWhite: '#ffffff',
|
|
36
|
+
bgGrayLight: '#f5f7fa',
|
|
37
|
+
bgGrayDark: '#2f343c',
|
|
38
|
+
bgBlack: '#000000'
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
const darkPalette: ThemeColor = {
|
|
42
|
+
primary: '#8ab4ff',
|
|
43
|
+
primaryDark: '#5f8dff',
|
|
44
|
+
primaryDisabled: '#3d4f74',
|
|
45
|
+
primaryLight: '#1d273f',
|
|
46
|
+
success: '#4ade80',
|
|
47
|
+
successDark: '#1f9d57',
|
|
48
|
+
successDisabled: '#2f4d3d',
|
|
49
|
+
successLight: '#10291f',
|
|
50
|
+
warning: '#fbbf24',
|
|
51
|
+
warningDark: '#c88f00',
|
|
52
|
+
warningDisabled: '#4a3b17',
|
|
53
|
+
warningLight: '#2b1f05',
|
|
54
|
+
error: '#ff6b6b',
|
|
55
|
+
errorDark: '#d83a3a',
|
|
56
|
+
errorDisabled: '#4f2323',
|
|
57
|
+
errorLight: '#2d1414',
|
|
58
|
+
info: '#a0a7b8',
|
|
59
|
+
infoDark: '#7c8394',
|
|
60
|
+
infoDisabled: '#3b3f4c',
|
|
61
|
+
infoLight: '#1d2029',
|
|
62
|
+
whiteColor: '#f5f6f7',
|
|
63
|
+
blackColor: '#f5f6f7',
|
|
64
|
+
mainColor: '#f5f6f7',
|
|
65
|
+
contentColor: '#cfd3dc',
|
|
66
|
+
tipsColor: '#9aa1af',
|
|
67
|
+
lightColor: '#6b7082',
|
|
68
|
+
borderColor: '#3a4251',
|
|
69
|
+
dividerColor: '#3a4251',
|
|
70
|
+
maskColor: 'rgba(0, 0, 0, 0.6)',
|
|
71
|
+
shadowColor: 'rgba(0, 0, 0, 0.3)',
|
|
72
|
+
bgColor: '#111827',
|
|
73
|
+
bgWhite: '#000000',
|
|
74
|
+
bgGrayLight: '#1a1a1a',
|
|
75
|
+
bgGrayDark: '#f5f7fa',
|
|
76
|
+
bgBlack: '#ffffff'
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const lightCss: Record<string, string> = {
|
|
80
|
+
'--u-background': '#ffffff',
|
|
81
|
+
'--u-surface': '#f7f8fa',
|
|
82
|
+
'--u-text': '#303133'
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
const darkCss: Record<string, string> = {
|
|
86
|
+
'--u-background': '#0f1115',
|
|
87
|
+
'--u-surface': '#1c2233',
|
|
88
|
+
'--u-text': '#f5f6f7'
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
export const defaultThemes: Theme[] = [
|
|
92
|
+
{
|
|
93
|
+
name: 'uviewpro',
|
|
94
|
+
label: '默认蓝',
|
|
95
|
+
description: 'uView Pro 默认主题,支持亮色与暗黑模式',
|
|
96
|
+
color: lightPalette,
|
|
97
|
+
darkColor: darkPalette,
|
|
98
|
+
css: lightCss,
|
|
99
|
+
darkCss: darkCss
|
|
100
|
+
}
|
|
101
|
+
];
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
color-scheme: light;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
:root.u-theme-dark,
|
|
6
|
+
:root[data-u-theme-mode='dark'] {
|
|
7
|
+
color-scheme: dark;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
page {
|
|
11
|
+
color: $u-main-color;
|
|
12
|
+
background-color: $u-bg-color;
|
|
13
|
+
font-size: 28rpx;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
page.u-theme-dark,
|
|
17
|
+
:root.u-theme-dark page,
|
|
18
|
+
:root[data-u-theme-mode='dark'] page {
|
|
19
|
+
background-color: $u-bg-color;
|
|
20
|
+
color: $u-main-color;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.u-config-provider {
|
|
24
|
+
color: $u-main-color;
|
|
25
|
+
background-color: var(--u-bg-white, #ffffff);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.u-config-provider.u-theme-dark {
|
|
29
|
+
background-color: var(--u-bg-white, #0f1115);
|
|
30
|
+
color: $u-main-color;
|
|
31
|
+
}
|
package/libs/css/style.vue.scss
CHANGED
|
@@ -48,7 +48,6 @@ function H5Copy(text: string, config: TClipboardOptions) {
|
|
|
48
48
|
|
|
49
49
|
function UniCopy(text: string, config: TClipboardOptions) {
|
|
50
50
|
const opt = Object.assign({ data: text }, config);
|
|
51
|
-
console.log(opt);
|
|
52
51
|
uni.setClipboardData(opt);
|
|
53
52
|
}
|
|
54
53
|
|
|
@@ -56,17 +55,13 @@ type TClipboardOptions = Omit<UniNamespace.SetClipboardDataOptions, 'data'>;
|
|
|
56
55
|
|
|
57
56
|
export function clipboard(content: string, options?: TClipboardOptions) {
|
|
58
57
|
const text = String(content);
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
let config: TClipboardOptions = {
|
|
65
|
-
showToast,
|
|
66
|
-
success: copySuccessCb,
|
|
67
|
-
fail: copyFailCb,
|
|
68
|
-
complete: copyCompleteCb
|
|
58
|
+
const defaultOpt = {
|
|
59
|
+
showToast: true,
|
|
60
|
+
success: () => {},
|
|
61
|
+
fail: () => {},
|
|
62
|
+
complete: () => {}
|
|
69
63
|
};
|
|
64
|
+
const config = Object.assign(defaultOpt, options);
|
|
70
65
|
|
|
71
66
|
// #ifdef H5
|
|
72
67
|
H5Copy(text, config);
|
package/libs/function/color.ts
CHANGED
|
@@ -1,46 +1,77 @@
|
|
|
1
|
+
import { reactive } from 'vue';
|
|
1
2
|
import type { ColorType, ThemeColor } from '../../types/global';
|
|
2
3
|
|
|
3
|
-
//
|
|
4
|
-
const
|
|
4
|
+
// 默认颜色值(作为初始值)
|
|
5
|
+
const defaultColor: ThemeColor = {
|
|
5
6
|
primary: '#2979ff',
|
|
6
7
|
primaryDark: '#2b85e4',
|
|
7
8
|
primaryDisabled: '#a0cfff',
|
|
8
9
|
primaryLight: '#ecf5ff',
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
infoDisabled: '#c8c9cc',
|
|
14
|
-
infoLight: '#f4f4f5',
|
|
15
|
-
|
|
10
|
+
success: '#19be6b',
|
|
11
|
+
successDark: '#18b566',
|
|
12
|
+
successDisabled: '#71d5a1',
|
|
13
|
+
successLight: '#dbf1e1',
|
|
16
14
|
warning: '#ff9900',
|
|
17
15
|
warningDark: '#f29100',
|
|
18
16
|
warningDisabled: '#fcbd71',
|
|
19
17
|
warningLight: '#fdf6ec',
|
|
20
|
-
|
|
21
18
|
error: '#fa3534',
|
|
22
19
|
errorDark: '#dd6161',
|
|
23
20
|
errorDisabled: '#fab6b6',
|
|
24
21
|
errorLight: '#fef0f0',
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
22
|
+
info: '#909399',
|
|
23
|
+
infoDark: '#82848a',
|
|
24
|
+
infoDisabled: '#c8c9cc',
|
|
25
|
+
infoLight: '#f4f4f5',
|
|
26
|
+
whiteColor: '#ffffff',
|
|
27
|
+
blackColor: '#000000',
|
|
31
28
|
mainColor: '#303133',
|
|
32
29
|
contentColor: '#606266',
|
|
33
30
|
tipsColor: '#909399',
|
|
34
31
|
lightColor: '#c0c4cc',
|
|
35
|
-
borderColor: '#
|
|
32
|
+
borderColor: '#dcdfe6',
|
|
33
|
+
dividerColor: '#e4e7ed',
|
|
34
|
+
maskColor: 'rgba(0, 0, 0, 0.4)',
|
|
35
|
+
shadowColor: 'rgba(0, 0, 0, 0.1)',
|
|
36
|
+
bgColor: '#f3f4f6',
|
|
37
|
+
bgWhite: '#ffffff',
|
|
38
|
+
bgGrayLight: '#f5f7fa',
|
|
39
|
+
bgGrayDark: '#2f343c',
|
|
40
|
+
bgBlack: '#000000'
|
|
36
41
|
};
|
|
37
42
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
43
|
+
// 使用 reactive 包装颜色对象,使其在运行时可被响应式读取与更新
|
|
44
|
+
// 这个对象会被 configProvider 在主题切换时更新
|
|
45
|
+
export const color = reactive<ThemeColor>({ ...defaultColor });
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 获取颜色值(响应式)
|
|
49
|
+
* 优先从 configProvider 获取当前主题颜色,否则返回默认值
|
|
50
|
+
* @param name 颜色名称
|
|
51
|
+
* @returns 颜色值
|
|
52
|
+
*/
|
|
53
|
+
export function getColor(name: ColorType): string {
|
|
54
|
+
// // 优先从 configProvider 获取当前主题颜色
|
|
55
|
+
// const currentTheme = configProvider.getCurrentTheme();
|
|
56
|
+
// if (currentTheme) {
|
|
57
|
+
// const isDark = configProvider.isInDarkMode();
|
|
58
|
+
// const palette =
|
|
59
|
+
// isDark && currentTheme.darkColor && Object.keys(currentTheme.darkColor).length
|
|
60
|
+
// ? currentTheme.darkColor
|
|
61
|
+
// : currentTheme.color || {};
|
|
62
|
+
|
|
63
|
+
// if (palette[name]) {
|
|
64
|
+
// return palette[name] as string;
|
|
65
|
+
// }
|
|
66
|
+
// }
|
|
67
|
+
|
|
68
|
+
// 从响应式 color 对象获取(会被 configProvider 更新)
|
|
69
|
+
if (color[name]) {
|
|
70
|
+
return color[name] as string;
|
|
42
71
|
}
|
|
43
|
-
|
|
72
|
+
|
|
73
|
+
// 兜底返回默认值
|
|
74
|
+
return defaultColor[name] || '';
|
|
44
75
|
}
|
|
45
76
|
|
|
46
77
|
export default color;
|
package/libs/hooks/index.ts
CHANGED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 响应式颜色管理 composable
|
|
3
|
+
* 提供响应式的颜色访问,支持主题切换和暗黑模式
|
|
4
|
+
*
|
|
5
|
+
* 使用方式:
|
|
6
|
+
* const { color, getColor } = useColor()
|
|
7
|
+
* // color 是响应式的,可以直接在模板中使用
|
|
8
|
+
* // getColor('primary') 返回响应式的颜色值
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { computed, type ComputedRef } from 'vue';
|
|
12
|
+
import type { ColorType } from '../../types/global';
|
|
13
|
+
import configProvider from '../util/config-provider';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 响应式颜色 composable
|
|
17
|
+
* 返回响应式的颜色对象和获取颜色的方法
|
|
18
|
+
*/
|
|
19
|
+
export function useColor() {
|
|
20
|
+
// 从 configProvider 获取当前主题的响应式引用
|
|
21
|
+
const currentTheme = configProvider.currentThemeRef;
|
|
22
|
+
const darkModeRef = configProvider.darkModeRef;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 获取当前激活模式下的颜色对象(响应式)
|
|
26
|
+
*/
|
|
27
|
+
const color = computed(() => {
|
|
28
|
+
const theme = currentTheme.value;
|
|
29
|
+
if (!theme) return {} as Record<ColorType, string>;
|
|
30
|
+
|
|
31
|
+
const isDark = configProvider.isInDarkMode();
|
|
32
|
+
const palette =
|
|
33
|
+
isDark && theme.darkColor && Object.keys(theme.darkColor).length ? theme.darkColor : theme.color || {};
|
|
34
|
+
|
|
35
|
+
// 合并默认值,确保所有颜色都有值
|
|
36
|
+
const defaultPalette = isDark
|
|
37
|
+
? (configProvider as any).baseDarkColorTokens || {}
|
|
38
|
+
: (configProvider as any).baseColorTokens || {};
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
...defaultPalette,
|
|
42
|
+
...palette
|
|
43
|
+
} as Record<ColorType, string>;
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* 获取指定颜色(响应式)
|
|
48
|
+
* @param name 颜色名称
|
|
49
|
+
* @returns 颜色值
|
|
50
|
+
*/
|
|
51
|
+
const getColor = (name: ColorType): ComputedRef<string> => {
|
|
52
|
+
return computed(() => {
|
|
53
|
+
return color.value[name] || '';
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
color,
|
|
59
|
+
getColor
|
|
60
|
+
};
|
|
61
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 主题管理 composable
|
|
3
|
+
* 提供主题切换、持久化、CSS 变量注入、暗黑模式等功能
|
|
4
|
+
*
|
|
5
|
+
* 使用方式:
|
|
6
|
+
* const { currentTheme, themes, setTheme, getDarkMode, setDarkMode, isInDarkMode, getAvailableThemes, initTheme } = useTheme()
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { DarkMode, Theme } from '../../types/global';
|
|
10
|
+
import configProvider from '../util/config-provider';
|
|
11
|
+
import { defaultThemes } from '../config/theme-tokens';
|
|
12
|
+
|
|
13
|
+
const THEME_STORAGE_KEY = 'uview-pro-theme';
|
|
14
|
+
const DARK_MODE_STORAGE_KEY = 'uview-pro-dark-mode';
|
|
15
|
+
const themesRef = configProvider.themesRef;
|
|
16
|
+
const currentTheme = configProvider.currentThemeRef;
|
|
17
|
+
const darkModeRef = configProvider.darkModeRef;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 保存主题到 Storage
|
|
21
|
+
*/
|
|
22
|
+
function saveThemeToStorage(themeName: string) {
|
|
23
|
+
try {
|
|
24
|
+
uni.setStorageSync(THEME_STORAGE_KEY, themeName);
|
|
25
|
+
} catch (e) {
|
|
26
|
+
console.warn('[useTheme] failed to write storage', e);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* 保存暗黑模式设置到 Storage
|
|
32
|
+
*/
|
|
33
|
+
function saveDarkModeToStorage(mode: DarkMode) {
|
|
34
|
+
try {
|
|
35
|
+
uni.setStorageSync(DARK_MODE_STORAGE_KEY, mode);
|
|
36
|
+
} catch (e) {
|
|
37
|
+
console.warn('[useTheme] failed to write storage', e);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* 设置主题
|
|
43
|
+
*/
|
|
44
|
+
function setTheme(themeName: string) {
|
|
45
|
+
configProvider.setTheme(themeName);
|
|
46
|
+
currentTheme.value = configProvider.getCurrentTheme();
|
|
47
|
+
saveThemeToStorage(themeName);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* 获取当前主题
|
|
52
|
+
*/
|
|
53
|
+
function getCurrentTheme(): Theme | null {
|
|
54
|
+
return currentTheme.value || configProvider.getCurrentTheme();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* 获取所有可用主题
|
|
59
|
+
*/
|
|
60
|
+
function getAvailableThemes() {
|
|
61
|
+
return configProvider.getThemes();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* 初始化主题系统
|
|
66
|
+
* @param themes 可选的主题列表,如果未提供则尝试从 uni.$u.themes 读取
|
|
67
|
+
* @param defaultThemeName 可选的默认主题名
|
|
68
|
+
*/
|
|
69
|
+
export function initTheme(themes?: any[], defaultThemeName?: string) {
|
|
70
|
+
// 如果有传入主题列表,使用传入的
|
|
71
|
+
if (Array.isArray(themes) && themes.length > 0) {
|
|
72
|
+
configProvider.init(themes, defaultThemeName);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// 若已通过插件或其他方式完成初始化,则不再覆盖,最多按需切换默认主题
|
|
77
|
+
const existingThemes = configProvider.getThemes();
|
|
78
|
+
if (existingThemes.length > 0) {
|
|
79
|
+
if (defaultThemeName) {
|
|
80
|
+
configProvider.setTheme(defaultThemeName);
|
|
81
|
+
} else if (!configProvider.getCurrentTheme()) {
|
|
82
|
+
configProvider.setTheme(existingThemes[0].name);
|
|
83
|
+
} else {
|
|
84
|
+
// 触发一次 apply,便于初始化 CSS 变量
|
|
85
|
+
configProvider.setTheme(configProvider.getCurrentTheme()!.name);
|
|
86
|
+
}
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// 初始化 configProvider(如果运行时提供了内置主题)
|
|
91
|
+
try {
|
|
92
|
+
const builtin = (typeof uni !== 'undefined' && (uni as any).$u && (uni as any).$u.themes) || [];
|
|
93
|
+
if (Array.isArray(builtin) && builtin.length > 0) {
|
|
94
|
+
configProvider.init(builtin as Theme[], defaultThemeName);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
} catch (e) {
|
|
98
|
+
// ignore
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// 回退到内置默认主题
|
|
102
|
+
configProvider.init(defaultThemes as Theme[], defaultThemeName);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* 获取当前暗黑模式设置
|
|
107
|
+
*/
|
|
108
|
+
function getDarkMode(): DarkMode {
|
|
109
|
+
return configProvider.getDarkMode();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* 设置暗黑模式
|
|
114
|
+
* @param mode 'auto' (跟随系统) | 'light' (强制亮色) | 'dark' (强制暗黑)
|
|
115
|
+
*/
|
|
116
|
+
function setDarkMode(mode: DarkMode) {
|
|
117
|
+
configProvider.setDarkMode(mode);
|
|
118
|
+
darkModeRef.value = mode;
|
|
119
|
+
saveDarkModeToStorage(mode);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* 检查当前是否处于暗黑模式
|
|
124
|
+
*/
|
|
125
|
+
function isInDarkMode(): boolean {
|
|
126
|
+
return configProvider.isInDarkMode();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* 切换暗黑模式(在当前模式的基础上切换)
|
|
131
|
+
*/
|
|
132
|
+
function toggleDarkMode() {
|
|
133
|
+
const current = getDarkMode();
|
|
134
|
+
const nextMode = current === 'dark' ? 'light' : 'dark';
|
|
135
|
+
setDarkMode(nextMode);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* 使用主题的 composable
|
|
140
|
+
* 返回所有主题相关的响应式引用和方法
|
|
141
|
+
*/
|
|
142
|
+
export function useTheme() {
|
|
143
|
+
return {
|
|
144
|
+
// 响应式引用
|
|
145
|
+
currentTheme,
|
|
146
|
+
themes: themesRef,
|
|
147
|
+
darkMode: darkModeRef,
|
|
148
|
+
cssVars: configProvider.cssVarsRef,
|
|
149
|
+
|
|
150
|
+
// 主题相关方法
|
|
151
|
+
setTheme,
|
|
152
|
+
getCurrentTheme,
|
|
153
|
+
getAvailableThemes,
|
|
154
|
+
initTheme,
|
|
155
|
+
|
|
156
|
+
// 暗黑模式相关方法
|
|
157
|
+
getDarkMode,
|
|
158
|
+
setDarkMode,
|
|
159
|
+
isInDarkMode,
|
|
160
|
+
toggleDarkMode
|
|
161
|
+
};
|
|
162
|
+
}
|
package/libs/index.ts
CHANGED
|
@@ -248,7 +248,7 @@ export function kebabCase(word: string): string {
|
|
|
248
248
|
* 运行时设置主题颜色(就地合并到 reactive 的 $u.color)
|
|
249
249
|
* @param theme Partial<ThemeColor>
|
|
250
250
|
*/
|
|
251
|
-
function
|
|
251
|
+
function setColor(theme: Partial<ThemeColor> | undefined) {
|
|
252
252
|
if (!theme) return;
|
|
253
253
|
try {
|
|
254
254
|
const merged = deepMerge($u.color, theme);
|
|
@@ -291,7 +291,7 @@ export {
|
|
|
291
291
|
config,
|
|
292
292
|
zIndex,
|
|
293
293
|
mitt,
|
|
294
|
-
|
|
294
|
+
setColor
|
|
295
295
|
};
|
|
296
296
|
|
|
297
297
|
export const $u = {
|
|
@@ -334,7 +334,7 @@ export const $u = {
|
|
|
334
334
|
addStyle,
|
|
335
335
|
toStyle,
|
|
336
336
|
kebabCase,
|
|
337
|
-
|
|
337
|
+
setColor
|
|
338
338
|
};
|
|
339
339
|
|
|
340
340
|
// 颜色相关方法单独导出
|
|
@@ -353,3 +353,4 @@ export {
|
|
|
353
353
|
export * from './hooks';
|
|
354
354
|
|
|
355
355
|
export * from './util/logger';
|
|
356
|
+
export * from './util/config-provider';
|