@particle-network/ui-react 0.4.0-beta.3 → 0.4.0-beta.30
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/dist/components/ProgressWrapper/index.d.ts +1 -1
- package/dist/components/ProgressWrapper/index.js +18 -3
- package/dist/components/UXAutocomplete/index.d.ts +5 -0
- package/dist/components/UXAutocomplete/index.js +72 -0
- package/dist/components/UXButton/button-theme.js +15 -23
- package/dist/components/UXButton/use-button.js +2 -1
- package/dist/components/UXCheckbox/checkbox.extend.js +3 -3
- package/dist/components/UXDatePicker/index.js +1 -1
- package/dist/components/UXDateRangePicker/index.js +1 -1
- package/dist/components/UXDivider/divider.extend.d.ts +2 -2
- package/dist/components/UXDrawer/index.d.ts +9 -0
- package/dist/components/UXDrawer/index.js +89 -0
- package/dist/components/UXDropdown/dropdown-item.js +1 -1
- package/dist/components/UXEmpty/index.d.ts +2 -1
- package/dist/components/UXEmpty/index.js +8 -2
- package/dist/components/UXHint/index.js +1 -1
- package/dist/components/UXInput/index.d.ts +33 -33
- package/dist/components/UXInput/input.extend.d.ts +33 -33
- package/dist/components/UXModal/index.d.ts +1 -1
- package/dist/components/UXModal/index.js +7 -6
- package/dist/components/UXSelect/index.js +3 -3
- package/dist/components/UXSwitch/index.d.ts +22 -22
- package/dist/components/UXSwitch/switch.extend.d.ts +22 -22
- package/dist/components/UXTable/index.d.ts +19 -19
- package/dist/components/UXTable/table.extend.d.ts +19 -19
- package/dist/components/UXTabs/tabs.classes.js +7 -7
- package/dist/components/UXThemeSwitch/index.d.ts +0 -1
- package/dist/components/UXThemeSwitch/index.js +0 -1
- package/dist/components/UXThemeSwitch/theme-item.d.ts +1 -1
- package/dist/components/UXThemeSwitch/theme-item.js +4 -5
- package/dist/components/UXThemeSwitch/theme-switch.d.ts +3 -3
- package/dist/components/UXThemeSwitch/theme-switch.js +131 -101
- package/dist/components/UXThemeSwitch/use-color-scheme.d.ts +1 -1
- package/dist/components/UXThemeSwitch/use-color-scheme.js +3 -3
- package/dist/components/UXThemeSwitch/use-theme-color.d.ts +1 -19
- package/dist/components/UXThemeSwitch/use-theme-color.js +3 -3
- package/dist/components/UXThemeSwitch/use-theme-store.d.ts +5 -20
- package/dist/components/UXThemeSwitch/use-theme-store.js +14 -28
- package/dist/components/UXThemeSwitch/use-theme.d.ts +7 -12
- package/dist/components/UXThemeSwitch/use-theme.js +73 -80
- package/dist/components/UXToast/index.d.ts +7 -4
- package/dist/components/UXToast/index.js +21 -17
- package/dist/components/UXTooltip/tooltip.extend.d.ts +21 -21
- package/dist/components/UXTooltip/tooltip.extend.js +2 -1
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.js +2 -0
- package/dist/hooks/useI18n.d.ts +6 -2
- package/dist/hooks/useI18n.js +15 -7
- package/dist/utils/detect.js +1 -2
- package/dist/utils/variants.js +16 -16
- package/package.json +4 -5
- package/tailwind-preset.js +192 -93
- package/dist/components/UXThemeSwitch/theme-data.d.ts +0 -29
- package/dist/components/UXThemeSwitch/theme-data.js +0 -304
- package/dist/icons/index.d.ts +0 -14
- package/dist/icons/index.js +0 -120
|
@@ -1,124 +1,154 @@
|
|
|
1
1
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
-
import "react";
|
|
3
|
-
import {
|
|
2
|
+
import { useState } from "react";
|
|
3
|
+
import { cn } from "@heroui/theme";
|
|
4
4
|
import { useDisclosure } from "@heroui/use-disclosure";
|
|
5
|
-
import {
|
|
5
|
+
import { ChartColorSwitchIcon, CopyIcon } from "@particle-network/icons/web";
|
|
6
|
+
import { themeData } from "@particle-network/ui-shared";
|
|
6
7
|
import { useI18n } from "../../hooks/index.js";
|
|
7
|
-
import {
|
|
8
|
+
import { UXCopy, UXTooltip } from "../index.js";
|
|
9
|
+
import { HStack, VStack } from "../layout/index.js";
|
|
8
10
|
import { Text } from "../typography/Text.js";
|
|
9
11
|
import { UXButton } from "../UXButton/index.js";
|
|
10
12
|
import { UXDivider } from "../UXDivider/index.js";
|
|
11
13
|
import { UXInput } from "../UXInput/index.js";
|
|
14
|
+
import { UXModal } from "../UXModal/index.js";
|
|
12
15
|
import { UXSpinner } from "../UXSpinner/index.js";
|
|
13
|
-
import { themeData } from "./theme-data.js";
|
|
14
16
|
import { ThemeItem } from "./theme-item.js";
|
|
15
17
|
import { useTheme } from "./use-theme.js";
|
|
16
|
-
const
|
|
18
|
+
const FONT_EXAMPLES = [
|
|
19
|
+
{
|
|
20
|
+
title: 'Manrope',
|
|
21
|
+
url: 'https://fonts.googleapis.com/css2?family=Manrope:wght@200..800&display=swap'
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
title: 'Poppins',
|
|
25
|
+
url: 'https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap'
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
title: 'Roboto',
|
|
29
|
+
url: 'https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100..900;1,100..900&display=swap'
|
|
30
|
+
}
|
|
31
|
+
];
|
|
32
|
+
const UXThemeSwitchModal = ({ isOpen, onClose, onOpenChange, ...props })=>{
|
|
17
33
|
const i18n = useI18n();
|
|
18
|
-
const { selectedTheme,
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
if (!_isOpen) {
|
|
22
|
-
setSelectedTheme(savedTheme);
|
|
23
|
-
setSelectedFontLink(savedFontLink);
|
|
24
|
-
}
|
|
25
|
-
};
|
|
26
|
-
const handleApplyTheme = ()=>{
|
|
27
|
-
setSavedTheme(selectedTheme);
|
|
28
|
-
setSavedFontLink(selectedFontLink);
|
|
29
|
-
onClose?.();
|
|
30
|
-
};
|
|
31
|
-
const handleReset = ()=>{
|
|
32
|
-
setSelectedTheme(savedTheme);
|
|
33
|
-
setSelectedFontLink(savedFontLink);
|
|
34
|
-
};
|
|
35
|
-
return /*#__PURE__*/ jsx(Drawer, {
|
|
34
|
+
const { theme: selectedTheme, setTheme, fontUrl, setFontUrl, fontName, fontLoadStatus, clearFontUrl } = useTheme();
|
|
35
|
+
const [isFontExampleOpen, setIsFontExampleOpen] = useState(false);
|
|
36
|
+
return /*#__PURE__*/ jsx(UXModal, {
|
|
36
37
|
isOpen: isOpen,
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
title: i18n.theme.title,
|
|
39
|
+
footer: /*#__PURE__*/ jsx(UXButton, {
|
|
40
|
+
fullWidth: true,
|
|
41
|
+
size: "lg",
|
|
42
|
+
color: "primary",
|
|
43
|
+
onPress: onClose,
|
|
44
|
+
children: i18n.theme.done
|
|
45
|
+
}),
|
|
46
|
+
onOpenChange: onOpenChange,
|
|
39
47
|
...props,
|
|
40
|
-
children: /*#__PURE__*/ jsxs(
|
|
48
|
+
children: /*#__PURE__*/ jsxs(VStack, {
|
|
49
|
+
gap: "lg",
|
|
41
50
|
children: [
|
|
42
|
-
/*#__PURE__*/ jsx(
|
|
43
|
-
className: "
|
|
44
|
-
children:
|
|
51
|
+
/*#__PURE__*/ jsx("div", {
|
|
52
|
+
className: "grid grid-cols-3 gap-y-5 pt-1",
|
|
53
|
+
children: themeData.map((theme)=>/*#__PURE__*/ jsx(ThemeItem, {
|
|
54
|
+
isSelected: selectedTheme.id === theme.id,
|
|
55
|
+
onClick: ()=>setTheme(theme),
|
|
56
|
+
...theme
|
|
57
|
+
}, theme.id))
|
|
45
58
|
}),
|
|
46
|
-
/*#__PURE__*/
|
|
59
|
+
/*#__PURE__*/ jsx(UXDivider, {}),
|
|
60
|
+
/*#__PURE__*/ jsxs(VStack, {
|
|
61
|
+
gap: "md",
|
|
47
62
|
children: [
|
|
48
|
-
/*#__PURE__*/ jsx(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
className: "gap-y-5",
|
|
52
|
-
children: themeData.map((theme)=>/*#__PURE__*/ jsx(ThemeItem, {
|
|
53
|
-
isSelected: selectedTheme.id === theme.id,
|
|
54
|
-
onClick: ()=>setSelectedTheme(theme),
|
|
55
|
-
...theme
|
|
56
|
-
}, theme.id))
|
|
63
|
+
/*#__PURE__*/ jsx(Text, {
|
|
64
|
+
body1Bold: true,
|
|
65
|
+
children: i18n.theme.font.title
|
|
57
66
|
}),
|
|
58
|
-
/*#__PURE__*/ jsx(
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}),
|
|
73
|
-
isInvalid: 'error' === fontLoadStatus,
|
|
74
|
-
className: "w-full",
|
|
75
|
-
placeholder: i18n.theme.font.placeholder,
|
|
76
|
-
value: selectedFontLink,
|
|
77
|
-
description: /*#__PURE__*/ jsxs(Fragment, {
|
|
67
|
+
/*#__PURE__*/ jsx(UXInput, {
|
|
68
|
+
isClearable: true,
|
|
69
|
+
startContent: 'loading' === fontLoadStatus && /*#__PURE__*/ jsx(UXSpinner, {
|
|
70
|
+
size: 18
|
|
71
|
+
}),
|
|
72
|
+
isInvalid: 'error' === fontLoadStatus,
|
|
73
|
+
className: "w-full",
|
|
74
|
+
placeholder: i18n.theme.font.placeholder,
|
|
75
|
+
value: fontUrl,
|
|
76
|
+
description: /*#__PURE__*/ jsxs(Fragment, {
|
|
77
|
+
children: [
|
|
78
|
+
'success' === fontLoadStatus && /*#__PURE__*/ jsxs(Text, {
|
|
79
|
+
body3Bold: true,
|
|
80
|
+
color: "success",
|
|
78
81
|
children: [
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
color: "success",
|
|
82
|
-
children: [
|
|
83
|
-
i18n.theme.font.success,
|
|
84
|
-
fontName
|
|
85
|
-
]
|
|
86
|
-
}),
|
|
87
|
-
'error' === fontLoadStatus && fontLoadError && /*#__PURE__*/ jsx(Text, {
|
|
88
|
-
body3Bold: true,
|
|
89
|
-
color: "danger",
|
|
90
|
-
children: fontLoadError
|
|
91
|
-
})
|
|
82
|
+
i18n.theme.font.success,
|
|
83
|
+
fontName
|
|
92
84
|
]
|
|
93
85
|
}),
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
86
|
+
'error' === fontLoadStatus && /*#__PURE__*/ jsx(Text, {
|
|
87
|
+
body3Bold: true,
|
|
88
|
+
color: "danger",
|
|
89
|
+
children: i18n.theme.font.error
|
|
90
|
+
})
|
|
91
|
+
]
|
|
92
|
+
}),
|
|
93
|
+
onValueChange: setFontUrl,
|
|
94
|
+
onClear: clearFontUrl
|
|
97
95
|
})
|
|
98
96
|
]
|
|
99
97
|
}),
|
|
100
|
-
/*#__PURE__*/
|
|
101
|
-
|
|
102
|
-
children:
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
98
|
+
/*#__PURE__*/ jsxs(Text, {
|
|
99
|
+
color: "secondary",
|
|
100
|
+
children: [
|
|
101
|
+
i18n.theme.font.hint,
|
|
102
|
+
/*#__PURE__*/ jsx("a", {
|
|
103
|
+
href: "https://fonts.google.com/",
|
|
104
|
+
target: "_blank",
|
|
105
|
+
rel: "noopener noreferrer",
|
|
106
|
+
className: "hover:underline",
|
|
107
|
+
children: "https://fonts.google.com/"
|
|
108
|
+
})
|
|
109
|
+
]
|
|
110
|
+
}),
|
|
111
|
+
/*#__PURE__*/ jsx(UXButton, {
|
|
112
|
+
className: "self-start",
|
|
113
|
+
variant: "text",
|
|
114
|
+
color: "primary",
|
|
115
|
+
onPress: ()=>{
|
|
116
|
+
setIsFontExampleOpen((prev)=>!prev);
|
|
117
|
+
},
|
|
118
|
+
children: i18n.theme.font.example[isFontExampleOpen ? 'hide' : 'show']
|
|
119
|
+
}),
|
|
120
|
+
/*#__PURE__*/ jsx(VStack, {
|
|
121
|
+
gap: "sm",
|
|
122
|
+
className: cn(isFontExampleOpen ? 'flex' : 'hidden'),
|
|
123
|
+
children: FONT_EXAMPLES.map((example)=>/*#__PURE__*/ jsxs(HStack, {
|
|
124
|
+
gap: "lg",
|
|
125
|
+
children: [
|
|
126
|
+
/*#__PURE__*/ jsx(UXTooltip, {
|
|
127
|
+
content: example.url,
|
|
128
|
+
placement: "bottom",
|
|
129
|
+
children: /*#__PURE__*/ jsxs(Text, {
|
|
130
|
+
color: "secondary",
|
|
131
|
+
className: "flex-1 truncate cursor-pointer",
|
|
132
|
+
children: [
|
|
133
|
+
example.title,
|
|
134
|
+
": ",
|
|
135
|
+
example.url
|
|
136
|
+
]
|
|
137
|
+
})
|
|
138
|
+
}),
|
|
139
|
+
/*#__PURE__*/ jsx(UXCopy, {
|
|
140
|
+
copyText: example.url,
|
|
141
|
+
children: /*#__PURE__*/ jsx(UXButton, {
|
|
142
|
+
isIconOnly: true,
|
|
143
|
+
size: "sm",
|
|
144
|
+
variant: "light",
|
|
145
|
+
children: /*#__PURE__*/ jsx(CopyIcon, {
|
|
146
|
+
color: "secondary"
|
|
147
|
+
})
|
|
148
|
+
})
|
|
149
|
+
})
|
|
150
|
+
]
|
|
151
|
+
}, example.title))
|
|
122
152
|
})
|
|
123
153
|
]
|
|
124
154
|
})
|
|
@@ -132,13 +162,13 @@ const UXThemeSwitch = ({ children })=>{
|
|
|
132
162
|
isIconOnly: true,
|
|
133
163
|
variant: "light",
|
|
134
164
|
onPress: onOpen,
|
|
135
|
-
children: /*#__PURE__*/ jsx(
|
|
165
|
+
children: /*#__PURE__*/ jsx(ChartColorSwitchIcon, {})
|
|
136
166
|
});
|
|
137
167
|
};
|
|
138
168
|
return /*#__PURE__*/ jsxs(Fragment, {
|
|
139
169
|
children: [
|
|
140
170
|
renderChildren(),
|
|
141
|
-
/*#__PURE__*/ jsx(
|
|
171
|
+
/*#__PURE__*/ jsx(UXThemeSwitchModal, {
|
|
142
172
|
isOpen: isOpen,
|
|
143
173
|
onClose: onClose,
|
|
144
174
|
onOpenChange: onOpenChange
|
|
@@ -146,4 +176,4 @@ const UXThemeSwitch = ({ children })=>{
|
|
|
146
176
|
]
|
|
147
177
|
});
|
|
148
178
|
};
|
|
149
|
-
export { UXThemeSwitch,
|
|
179
|
+
export { UXThemeSwitch, UXThemeSwitchModal };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useTheme } from "./use-theme.js";
|
|
2
2
|
const useColorScheme = ()=>{
|
|
3
|
-
const {
|
|
4
|
-
const { colorScheme } =
|
|
3
|
+
const { theme } = useTheme();
|
|
4
|
+
const { colorScheme } = theme;
|
|
5
5
|
return {
|
|
6
6
|
colorScheme,
|
|
7
7
|
isDark: 'dark' === colorScheme,
|
|
@@ -1,19 +1 @@
|
|
|
1
|
-
export declare const useThemeColor: () =>
|
|
2
|
-
foreground: string;
|
|
3
|
-
secondary: string;
|
|
4
|
-
tertiary: string;
|
|
5
|
-
primary: string;
|
|
6
|
-
success: string;
|
|
7
|
-
danger: string;
|
|
8
|
-
alert: string;
|
|
9
|
-
warning: string;
|
|
10
|
-
gold: string;
|
|
11
|
-
background: string;
|
|
12
|
-
'background-200': string;
|
|
13
|
-
'background-300': string;
|
|
14
|
-
'background-400': string;
|
|
15
|
-
overlay: string;
|
|
16
|
-
divider: string;
|
|
17
|
-
bullish: string;
|
|
18
|
-
bearish: string;
|
|
19
|
-
};
|
|
1
|
+
export declare const useThemeColor: () => Record<import("@particle-network/ui-shared").UXColor, string>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useTheme } from "./use-theme.js";
|
|
2
2
|
const useThemeColor = ()=>{
|
|
3
|
-
const {
|
|
4
|
-
return
|
|
3
|
+
const { theme } = useTheme();
|
|
4
|
+
return theme.colorVariables;
|
|
5
5
|
};
|
|
6
6
|
export { useThemeColor };
|
|
@@ -1,22 +1,14 @@
|
|
|
1
|
-
import { type ThemeItemType } from '
|
|
1
|
+
import { type ThemeItemType } from '@particle-network/ui-shared';
|
|
2
2
|
export type FontLoadStatus = 'idle' | 'loading' | 'success' | 'error';
|
|
3
3
|
interface State {
|
|
4
|
-
/**
|
|
5
|
-
* 临时选中的 theme(用于预览)
|
|
6
|
-
*/
|
|
7
|
-
selectedTheme: ThemeItemType;
|
|
8
4
|
/**
|
|
9
5
|
* 保存的主题
|
|
10
6
|
*/
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* 临时输入的字体链接(用于预览)
|
|
14
|
-
*/
|
|
15
|
-
selectedFontLink: string;
|
|
7
|
+
theme: ThemeItemType;
|
|
16
8
|
/**
|
|
17
9
|
* 保存的字体链接
|
|
18
10
|
*/
|
|
19
|
-
|
|
11
|
+
fontUrl: string;
|
|
20
12
|
/**
|
|
21
13
|
* 应用的字体名称
|
|
22
14
|
*/
|
|
@@ -25,18 +17,11 @@ interface State {
|
|
|
25
17
|
* 字体加载状态
|
|
26
18
|
*/
|
|
27
19
|
fontLoadStatus: FontLoadStatus;
|
|
28
|
-
/**
|
|
29
|
-
* 字体加载错误信息
|
|
30
|
-
*/
|
|
31
|
-
fontLoadError: string | null;
|
|
32
20
|
}
|
|
33
21
|
interface Actions {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
setSelectedFontLink: (link: string) => void;
|
|
37
|
-
setSavedFontLink: (link: string) => void;
|
|
22
|
+
setTheme: (theme: ThemeItemType) => void;
|
|
23
|
+
setFontUrl: (fontUrl: string) => void;
|
|
38
24
|
setFontLoadStatus: (status: FontLoadStatus) => void;
|
|
39
|
-
setFontLoadError: (error: string | null) => void;
|
|
40
25
|
setFontName: (name: string) => void;
|
|
41
26
|
}
|
|
42
27
|
type ThemeStore = State & Actions;
|
|
@@ -1,44 +1,30 @@
|
|
|
1
|
+
import { themeData } from "@particle-network/ui-shared";
|
|
1
2
|
import { create } from "zustand";
|
|
2
3
|
import { createJSONStorage, persist } from "zustand/middleware";
|
|
3
|
-
import { themeData } from "./theme-data.js";
|
|
4
4
|
const useThemeStore = create()(persist((set)=>({
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
selectedFontLink: '',
|
|
8
|
-
savedFontLink: '',
|
|
5
|
+
theme: themeData["0"],
|
|
6
|
+
fontUrl: '',
|
|
9
7
|
fontName: '',
|
|
10
8
|
fontLoadStatus: 'idle',
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
selectedTheme: theme
|
|
9
|
+
setTheme: (theme)=>set({
|
|
10
|
+
theme
|
|
14
11
|
}),
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
setFontUrl: (fontUrl)=>set({
|
|
13
|
+
fontUrl
|
|
17
14
|
}),
|
|
18
|
-
|
|
19
|
-
|
|
15
|
+
setFontLoadStatus: (fontLoadStatus)=>set({
|
|
16
|
+
fontLoadStatus
|
|
20
17
|
}),
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
}),
|
|
24
|
-
setFontLoadStatus: (status)=>set({
|
|
25
|
-
fontLoadStatus: status
|
|
26
|
-
}),
|
|
27
|
-
setFontLoadError: (error)=>set({
|
|
28
|
-
fontLoadError: error
|
|
29
|
-
}),
|
|
30
|
-
setFontName: (name)=>set({
|
|
31
|
-
fontName: name
|
|
18
|
+
setFontName: (fontName)=>set({
|
|
19
|
+
fontName
|
|
32
20
|
})
|
|
33
21
|
}), {
|
|
34
|
-
name: 'ux-theme',
|
|
22
|
+
name: 'ux-theme-2',
|
|
35
23
|
storage: createJSONStorage(()=>'undefined' != typeof window ? window.localStorage : {}),
|
|
36
24
|
partialize: (state)=>({
|
|
37
|
-
|
|
38
|
-
savedTheme: state.savedTheme,
|
|
25
|
+
theme: state.theme,
|
|
39
26
|
fontName: state.fontName,
|
|
40
|
-
|
|
41
|
-
savedFontLink: state.savedFontLink
|
|
27
|
+
fontUrl: state.fontUrl
|
|
42
28
|
})
|
|
43
29
|
}));
|
|
44
30
|
export { useThemeStore };
|
|
@@ -1,18 +1,13 @@
|
|
|
1
|
-
import { type ThemeItemType } from '
|
|
2
|
-
import { type FontLoadStatus } from './use-theme-store';
|
|
1
|
+
import { type ThemeItemType } from '@particle-network/ui-shared';
|
|
3
2
|
/**
|
|
4
3
|
* UX 主题管理 Hook
|
|
5
4
|
*/
|
|
6
5
|
export declare const useTheme: () => {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
savedFontLink: string;
|
|
14
|
-
setSavedFontLink: (link: string) => void;
|
|
15
|
-
fontLoadStatus: FontLoadStatus;
|
|
16
|
-
fontLoadError: string | null;
|
|
6
|
+
theme: ThemeItemType;
|
|
7
|
+
setTheme: (theme: ThemeItemType) => void;
|
|
8
|
+
fontUrl: string;
|
|
9
|
+
setFontUrl: (link: string) => void;
|
|
10
|
+
clearFontUrl: () => void;
|
|
11
|
+
fontLoadStatus: import("./use-theme-store").FontLoadStatus;
|
|
17
12
|
fontName: string;
|
|
18
13
|
};
|
|
@@ -1,8 +1,19 @@
|
|
|
1
1
|
import { useEffect } from "react";
|
|
2
|
+
import { themeKeys } from "@particle-network/ui-shared";
|
|
2
3
|
import { useDebounceFn } from "ahooks";
|
|
3
|
-
import { themeKeys } from "./theme-data.js";
|
|
4
4
|
import { useThemeStore } from "./use-theme-store.js";
|
|
5
|
-
const DEFAULT_FONT_FAMILY = '
|
|
5
|
+
const DEFAULT_FONT_FAMILY = 'Inter,system-ui,sans-serif,"Microsoft YaHei"';
|
|
6
|
+
const PRELOAD_FONTS_URL = 'https://fonts.googleapis.com/css2?family=Geist:wght@100..900&family=IBM+Plex+Sans:ital,wght@0,100..700;1,100..700&display=swap';
|
|
7
|
+
const preloadFonts = ()=>{
|
|
8
|
+
if ('undefined' == typeof window) return;
|
|
9
|
+
const existingLink = document.getElementById('ux-preload-fonts-link');
|
|
10
|
+
if (existingLink) return;
|
|
11
|
+
const linkElement = document.createElement('link');
|
|
12
|
+
linkElement.id = 'ux-preload-fonts-link';
|
|
13
|
+
linkElement.rel = 'stylesheet';
|
|
14
|
+
linkElement.href = PRELOAD_FONTS_URL;
|
|
15
|
+
document.head.appendChild(linkElement);
|
|
16
|
+
};
|
|
6
17
|
const applyTheme = (theme)=>{
|
|
7
18
|
if ('undefined' == typeof window) return;
|
|
8
19
|
const root = document.documentElement;
|
|
@@ -11,6 +22,8 @@ const applyTheme = (theme)=>{
|
|
|
11
22
|
themeKeys.forEach((key)=>{
|
|
12
23
|
root.classList.remove(key);
|
|
13
24
|
});
|
|
25
|
+
root.classList.remove('dark');
|
|
26
|
+
root.classList.remove('light');
|
|
14
27
|
root.classList.add(theme.id);
|
|
15
28
|
};
|
|
16
29
|
const extractFontFamilyFromLink = (link)=>{
|
|
@@ -19,107 +32,87 @@ const extractFontFamilyFromLink = (link)=>{
|
|
|
19
32
|
const url = new URL(link);
|
|
20
33
|
const familyParam = url.searchParams.get('family');
|
|
21
34
|
if (!familyParam) return null;
|
|
22
|
-
const
|
|
23
|
-
return
|
|
35
|
+
const firstFamily = familyParam.split('&family=')[0].split(':')[0].replace(/\+/g, ' ');
|
|
36
|
+
return firstFamily;
|
|
24
37
|
} catch {
|
|
25
38
|
return null;
|
|
26
39
|
}
|
|
27
40
|
};
|
|
28
|
-
const
|
|
29
|
-
const { setFontLoadStatus, setFontLoadError, setFontName } = options;
|
|
41
|
+
const applyFont = (fontName)=>{
|
|
30
42
|
if ('undefined' == typeof window) return;
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
43
|
+
if (fontName) {
|
|
44
|
+
document.documentElement.style.setProperty('--ux-font-family', `"${fontName}", ${DEFAULT_FONT_FAMILY}`);
|
|
45
|
+
document.body.style.fontFamily = `"${fontName}", ${DEFAULT_FONT_FAMILY}`;
|
|
46
|
+
} else {
|
|
34
47
|
document.documentElement.style.setProperty('--ux-font-family', DEFAULT_FONT_FAMILY);
|
|
35
48
|
document.body.style.fontFamily = DEFAULT_FONT_FAMILY;
|
|
36
|
-
setFontLoadStatus('idle');
|
|
37
|
-
setFontLoadError(null);
|
|
38
|
-
setFontName('');
|
|
39
|
-
return;
|
|
40
49
|
}
|
|
41
|
-
setFontLoadStatus('loading');
|
|
42
|
-
setFontLoadError(null);
|
|
43
|
-
const linkElement = document.createElement('link');
|
|
44
|
-
linkElement.id = 'ux-google-font-link';
|
|
45
|
-
linkElement.rel = 'stylesheet';
|
|
46
|
-
linkElement.href = link;
|
|
47
|
-
linkElement.onload = ()=>{
|
|
48
|
-
setFontLoadStatus('success');
|
|
49
|
-
setFontLoadError(null);
|
|
50
|
-
const fontFamily = extractFontFamilyFromLink(link);
|
|
51
|
-
if (fontFamily) {
|
|
52
|
-
document.documentElement.style.setProperty('--ux-font-family', `"${fontFamily}", ${DEFAULT_FONT_FAMILY}`);
|
|
53
|
-
document.body.style.fontFamily = `"${fontFamily}", ${DEFAULT_FONT_FAMILY}`;
|
|
54
|
-
setFontName(fontFamily);
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
linkElement.onerror = ()=>{
|
|
58
|
-
const errorMessage = '字体加载失败,请检查链接是否正确';
|
|
59
|
-
setFontLoadStatus('error');
|
|
60
|
-
setFontLoadError(errorMessage);
|
|
61
|
-
setFontName('');
|
|
62
|
-
document.documentElement.style.setProperty('--ux-font-family', DEFAULT_FONT_FAMILY);
|
|
63
|
-
document.body.style.fontFamily = DEFAULT_FONT_FAMILY;
|
|
64
|
-
};
|
|
65
|
-
document.head.appendChild(linkElement);
|
|
66
50
|
};
|
|
67
51
|
const useTheme = ()=>{
|
|
68
|
-
const
|
|
69
|
-
const
|
|
70
|
-
const selectedFontLink = useThemeStore((state)=>state.selectedFontLink);
|
|
71
|
-
const savedFontLink = useThemeStore((state)=>state.savedFontLink);
|
|
52
|
+
const theme = useThemeStore((state)=>state.theme);
|
|
53
|
+
const fontUrl = useThemeStore((state)=>state.fontUrl);
|
|
72
54
|
const fontName = useThemeStore((state)=>state.fontName);
|
|
73
55
|
const fontLoadStatus = useThemeStore((state)=>state.fontLoadStatus);
|
|
74
|
-
const
|
|
75
|
-
const
|
|
76
|
-
const storeSetSavedTheme = useThemeStore((state)=>state.setSavedTheme);
|
|
77
|
-
const storeSetSelectedFontLink = useThemeStore((state)=>state.setSelectedFontLink);
|
|
78
|
-
const storeSetSavedFontLink = useThemeStore((state)=>state.setSavedFontLink);
|
|
56
|
+
const storeSetTheme = useThemeStore((state)=>state.setTheme);
|
|
57
|
+
const storeSetFontUrl = useThemeStore((state)=>state.setFontUrl);
|
|
79
58
|
const storeSetFontLoadStatus = useThemeStore((state)=>state.setFontLoadStatus);
|
|
80
|
-
const storeSetFontLoadError = useThemeStore((state)=>state.setFontLoadError);
|
|
81
59
|
const storeSetFontName = useThemeStore((state)=>state.setFontName);
|
|
82
|
-
const
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
60
|
+
const applyFontWithStatus = (customFontUrl, themeFontName)=>{
|
|
61
|
+
if ('undefined' == typeof window) return;
|
|
62
|
+
const url = customFontUrl?.trim();
|
|
63
|
+
if (!url) return void applyFont(themeFontName);
|
|
64
|
+
const existingLink = document.getElementById('ux-google-font-link');
|
|
65
|
+
if (existingLink) existingLink.remove();
|
|
66
|
+
storeSetFontLoadStatus('loading');
|
|
67
|
+
const linkElement = document.createElement('link');
|
|
68
|
+
linkElement.id = 'ux-google-font-link';
|
|
69
|
+
linkElement.rel = 'stylesheet';
|
|
70
|
+
linkElement.href = url;
|
|
71
|
+
linkElement.onload = ()=>{
|
|
72
|
+
storeSetFontLoadStatus('success');
|
|
73
|
+
const fontFamily = extractFontFamilyFromLink(url);
|
|
74
|
+
if (fontFamily) {
|
|
75
|
+
applyFont(fontFamily);
|
|
76
|
+
storeSetFontName(fontFamily);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
linkElement.onerror = ()=>{
|
|
80
|
+
storeSetFontLoadStatus('error');
|
|
81
|
+
storeSetFontName('');
|
|
82
|
+
applyFont(themeFontName);
|
|
83
|
+
};
|
|
84
|
+
document.head.appendChild(linkElement);
|
|
85
|
+
};
|
|
86
|
+
const { run: debouncedApplyFont } = useDebounceFn((customFontLink, themeFontName)=>applyFontWithStatus(customFontLink, themeFontName), {
|
|
87
|
+
wait: 300
|
|
88
88
|
});
|
|
89
89
|
useEffect(()=>{
|
|
90
|
-
|
|
91
|
-
debouncedLoadGoogleFont(savedFontLink);
|
|
92
|
-
}, [
|
|
93
|
-
savedTheme,
|
|
94
|
-
savedFontLink
|
|
95
|
-
]);
|
|
96
|
-
const setSelectedTheme = (theme)=>{
|
|
97
|
-
storeSetSelectedTheme(theme);
|
|
90
|
+
preloadFonts();
|
|
98
91
|
applyTheme(theme);
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
92
|
+
debouncedApplyFont(fontUrl, theme.fontName);
|
|
93
|
+
}, []);
|
|
94
|
+
const setTheme = (theme)=>{
|
|
95
|
+
storeSetTheme(theme);
|
|
102
96
|
applyTheme(theme);
|
|
97
|
+
debouncedApplyFont(fontUrl, theme.fontName);
|
|
103
98
|
};
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
99
|
+
const setFontUrl = (link)=>{
|
|
100
|
+
storeSetFontUrl(link);
|
|
101
|
+
debouncedApplyFont(link, theme.fontName);
|
|
107
102
|
};
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
103
|
+
const clearFontUrl = ()=>{
|
|
104
|
+
storeSetFontUrl('');
|
|
105
|
+
storeSetFontName('');
|
|
106
|
+
storeSetFontLoadStatus('idle');
|
|
107
|
+
debouncedApplyFont('', theme.fontName);
|
|
111
108
|
};
|
|
112
109
|
return {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
setSelectedFontLink,
|
|
119
|
-
savedFontLink,
|
|
120
|
-
setSavedFontLink,
|
|
110
|
+
theme,
|
|
111
|
+
setTheme,
|
|
112
|
+
fontUrl,
|
|
113
|
+
setFontUrl,
|
|
114
|
+
clearFontUrl,
|
|
121
115
|
fontLoadStatus,
|
|
122
|
-
fontLoadError,
|
|
123
116
|
fontName
|
|
124
117
|
};
|
|
125
118
|
};
|