@particle-network/ui-react 0.5.1-beta.2 → 0.5.1-beta.4
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/UXColorPicker/color-picker.js +13 -7
- package/dist/components/UXColorPicker/types.d.ts +11 -0
- package/dist/components/UXThemeSwitch/custom-theme-config.d.ts +2 -0
- package/dist/components/UXThemeSwitch/custom-theme-config.js +132 -0
- package/dist/components/UXThemeSwitch/theme-item.js +46 -3
- package/dist/components/UXThemeSwitch/theme-switch.js +22 -2
- package/dist/components/UXThemeSwitch/use-color-scheme.js +11 -8
- package/dist/components/UXThemeSwitch/use-theme-color.js +11 -7
- package/dist/components/UXThemeSwitch/use-theme-store.js +1 -1
- package/dist/components/UXThemeSwitch/use-theme.js +31 -3
- package/dist/hooks/useI18n.d.ts +113 -25
- package/dist/hooks/useI18n.js +64 -2
- package/dist/hooks/useLang.d.ts +5 -1
- package/dist/hooks/useLang.js +13 -1
- package/package.json +4 -3
- package/tailwind-preset.js +0 -79
|
@@ -8,10 +8,12 @@ import RefreshCcwIcon from "@particle-network/icons/web/RefreshCcwIcon";
|
|
|
8
8
|
import { HStack } from "../layout/index.js";
|
|
9
9
|
import { UXButton } from "../UXButton/index.js";
|
|
10
10
|
import { UXPopover, UXPopoverContent, UXPopoverTrigger } from "../UXPopover/index.js";
|
|
11
|
+
import { useThemeColor } from "../UXThemeSwitch/index.js";
|
|
11
12
|
import { ColorFields } from "./color-fields.js";
|
|
12
13
|
import { ColorInput } from "./color-input.js";
|
|
13
14
|
import { normalizeColor } from "./utils.js";
|
|
14
|
-
const UXColorPicker = ({ className, value, defaultValue, onChange, onChangeEnd, onValueChange, onValueChangeEnd,
|
|
15
|
+
const UXColorPicker = ({ className, isDisabled, placement = 'bottom-start', value, defaultValue, onChange, onChangeEnd, onValueChange, onValueChangeEnd, isChanged, onReset })=>{
|
|
16
|
+
const { 'bg-200': bg200 } = useThemeColor();
|
|
15
17
|
const isControlled = void 0 !== value;
|
|
16
18
|
const [pickerKey, setPickerKey] = useState(0);
|
|
17
19
|
const [isInputFocused, setIsInputFocused] = useState(false);
|
|
@@ -92,13 +94,16 @@ const UXColorPicker = ({ className, value, defaultValue, onChange, onChangeEnd,
|
|
|
92
94
|
onValueChangeEnd
|
|
93
95
|
]);
|
|
94
96
|
const hasChanged = useMemo(()=>{
|
|
97
|
+
if (void 0 !== isChanged) return isChanged;
|
|
95
98
|
const initialHex = initialColorRef.current.toString('hex');
|
|
96
99
|
const currentHex = currentColor.toString('hex');
|
|
97
100
|
return initialHex !== currentHex;
|
|
98
101
|
}, [
|
|
99
|
-
currentColor
|
|
102
|
+
currentColor,
|
|
103
|
+
isChanged
|
|
100
104
|
]);
|
|
101
105
|
const handleReset = ()=>{
|
|
106
|
+
if (onReset) return void onReset();
|
|
102
107
|
const resetColor = initialColorRef.current;
|
|
103
108
|
if (!isControlled) {
|
|
104
109
|
setInternalColor(resetColor);
|
|
@@ -130,10 +135,11 @@ const UXColorPicker = ({ className, value, defaultValue, onChange, onChangeEnd,
|
|
|
130
135
|
children: [
|
|
131
136
|
/*#__PURE__*/ jsx(UXPopoverTrigger, {
|
|
132
137
|
children: /*#__PURE__*/ jsx(UXButton, {
|
|
138
|
+
radius: "none",
|
|
133
139
|
size: "auto",
|
|
134
140
|
isDisabled: isDisabled,
|
|
135
141
|
children: /*#__PURE__*/ jsx(ColorSwatch, {
|
|
136
|
-
className:
|
|
142
|
+
className: cn('h-4 w-4 rounded-[4px]', internalColor.toString('hex') === bg200 && 'border-foreground/10 border')
|
|
137
143
|
})
|
|
138
144
|
})
|
|
139
145
|
}),
|
|
@@ -149,7 +155,7 @@ const UXColorPicker = ({ className, value, defaultValue, onChange, onChangeEnd,
|
|
|
149
155
|
className: "aspect-square w-full overflow-hidden rounded-lg",
|
|
150
156
|
onChangeEnd: handleChangeEnd,
|
|
151
157
|
children: /*#__PURE__*/ jsx(ColorThumb, {
|
|
152
|
-
className: "
|
|
158
|
+
className: "h-4 w-4 rounded-full border-2 border-white shadow-[0_2px_4px_rgba(0,0,0,0.2)]"
|
|
153
159
|
})
|
|
154
160
|
}),
|
|
155
161
|
/*#__PURE__*/ jsxs(HStack, {
|
|
@@ -177,7 +183,7 @@ const UXColorPicker = ({ className, value, defaultValue, onChange, onChangeEnd,
|
|
|
177
183
|
children: /*#__PURE__*/ jsx(SliderTrack, {
|
|
178
184
|
className: "h-3 rounded-full",
|
|
179
185
|
children: /*#__PURE__*/ jsx(ColorThumb, {
|
|
180
|
-
className: "top-[50%] z-10 h-4 w-4 rounded-full border-2 border-white"
|
|
186
|
+
className: "top-[50%] z-10 h-4 w-4 rounded-full border-2 border-white shadow-[0_2px_4px_rgba(0,0,0,0.2)]"
|
|
181
187
|
})
|
|
182
188
|
})
|
|
183
189
|
})
|
|
@@ -195,10 +201,10 @@ const UXColorPicker = ({ className, value, defaultValue, onChange, onChangeEnd,
|
|
|
195
201
|
}),
|
|
196
202
|
/*#__PURE__*/ jsx(ColorInput, {
|
|
197
203
|
isDisabled: isDisabled,
|
|
198
|
-
inputClassName: "focus:ring-0 px-0 text-left flex-1",
|
|
204
|
+
inputClassName: "focus:ring-0 px-0 text-left flex-1 relative h-7",
|
|
199
205
|
value: value,
|
|
200
206
|
defaultValue: !isControlled && pickerKey > 0 ? internalColor : defaultValue,
|
|
201
|
-
onChange:
|
|
207
|
+
onChange: handleColorFieldsChange,
|
|
202
208
|
onFocus: ()=>setIsInputFocused(true),
|
|
203
209
|
onBlur: ()=>setIsInputFocused(false)
|
|
204
210
|
}),
|
|
@@ -26,10 +26,21 @@ export interface UXColorPickerProps {
|
|
|
26
26
|
* HEX 格式颜色变化结束回调(释放时调用)
|
|
27
27
|
*/
|
|
28
28
|
onValueChangeEnd?: (color: string) => void;
|
|
29
|
+
/**
|
|
30
|
+
* 是否已改变
|
|
31
|
+
*/
|
|
32
|
+
isChanged?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* 重置回调
|
|
35
|
+
*/
|
|
36
|
+
onReset?: () => void;
|
|
29
37
|
/**
|
|
30
38
|
* 是否禁用
|
|
31
39
|
*/
|
|
32
40
|
isDisabled?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Popover 位置
|
|
43
|
+
*/
|
|
33
44
|
placement?: UXPopoverProps['placement'];
|
|
34
45
|
}
|
|
35
46
|
export interface ColorFieldsProps extends Pick<UXColorPickerProps, 'value' | 'defaultValue'> {
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo } from "react";
|
|
3
|
+
import { DEFAULT_THEME_ID, themeData } from "@particle-network/ui-shared";
|
|
4
|
+
import { produce } from "immer";
|
|
5
|
+
import { useI18n, useLang } from "../../hooks/index.js";
|
|
6
|
+
import { HStack, VStack } from "../layout/index.js";
|
|
7
|
+
import { Text } from "../typography/Text.js";
|
|
8
|
+
import { UXColorPicker } from "../UXColorPicker/index.js";
|
|
9
|
+
import { UXSelect, UXSelectItem } from "../UXSelect/index.js";
|
|
10
|
+
import { UXTab, UXTabs } from "../UXTabs/index.js";
|
|
11
|
+
import { useTheme } from "./use-theme.js";
|
|
12
|
+
const COLOR_CATEGORIES = {
|
|
13
|
+
basic: [
|
|
14
|
+
'primary',
|
|
15
|
+
'bullish',
|
|
16
|
+
'bearish'
|
|
17
|
+
],
|
|
18
|
+
background: [
|
|
19
|
+
'bg-default',
|
|
20
|
+
'bg-400',
|
|
21
|
+
'bg-300',
|
|
22
|
+
'bg-200',
|
|
23
|
+
'overlay',
|
|
24
|
+
'divider'
|
|
25
|
+
],
|
|
26
|
+
text: [
|
|
27
|
+
'foreground',
|
|
28
|
+
'secondary',
|
|
29
|
+
'tertiary'
|
|
30
|
+
],
|
|
31
|
+
signal: [
|
|
32
|
+
'success',
|
|
33
|
+
'danger',
|
|
34
|
+
'alert',
|
|
35
|
+
'gold'
|
|
36
|
+
]
|
|
37
|
+
};
|
|
38
|
+
const CustomThemeConfig = ()=>{
|
|
39
|
+
const { lang } = useLang();
|
|
40
|
+
const i18n = useI18n();
|
|
41
|
+
const { theme, setTheme } = useTheme();
|
|
42
|
+
const baseThemes = useMemo(()=>themeData.filter((t)=>'custom' !== t.id), []);
|
|
43
|
+
const baseThemeId = theme.baseThemeId || DEFAULT_THEME_ID;
|
|
44
|
+
const baseTheme = useMemo(()=>themeData.find((t)=>t.id === baseThemeId) || themeData.find((t)=>t.id === DEFAULT_THEME_ID), [
|
|
45
|
+
baseThemeId
|
|
46
|
+
]);
|
|
47
|
+
const handleBaseThemeChange = (themeId)=>{
|
|
48
|
+
const selectedBaseTheme = themeData.find((t)=>t.id === themeId);
|
|
49
|
+
if (selectedBaseTheme) setTheme({
|
|
50
|
+
...theme,
|
|
51
|
+
baseThemeId: themeId,
|
|
52
|
+
colorScheme: selectedBaseTheme.colorScheme,
|
|
53
|
+
colorVariables: selectedBaseTheme.colorVariables
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
const handleColorChange = (color, value)=>{
|
|
57
|
+
const updatedTheme = produce(theme, (draft)=>{
|
|
58
|
+
draft.colorVariables[color] = value;
|
|
59
|
+
});
|
|
60
|
+
setTheme(updatedTheme);
|
|
61
|
+
};
|
|
62
|
+
const getColorValue = (color)=>theme.colorVariables[color] || baseTheme.colorVariables[color] || '#000000';
|
|
63
|
+
const renderColorItem = (color, label)=>{
|
|
64
|
+
const value = getColorValue(color);
|
|
65
|
+
const isCustomized = void 0 !== theme.colorVariables[color] && theme.colorVariables[color] !== baseTheme.colorVariables[color];
|
|
66
|
+
return /*#__PURE__*/ jsxs(HStack, {
|
|
67
|
+
justify: "between",
|
|
68
|
+
children: [
|
|
69
|
+
/*#__PURE__*/ jsx(Text, {
|
|
70
|
+
color: "secondary",
|
|
71
|
+
children: label
|
|
72
|
+
}),
|
|
73
|
+
/*#__PURE__*/ jsx(UXColorPicker, {
|
|
74
|
+
value: value,
|
|
75
|
+
isChanged: isCustomized,
|
|
76
|
+
onValueChange: (newValue)=>handleColorChange(color, newValue),
|
|
77
|
+
onReset: ()=>handleColorChange(color, baseTheme.colorVariables[color])
|
|
78
|
+
})
|
|
79
|
+
]
|
|
80
|
+
}, color);
|
|
81
|
+
};
|
|
82
|
+
return /*#__PURE__*/ jsxs(VStack, {
|
|
83
|
+
gap: "lg",
|
|
84
|
+
children: [
|
|
85
|
+
/*#__PURE__*/ jsx(HStack, {
|
|
86
|
+
justify: "between",
|
|
87
|
+
children: /*#__PURE__*/ jsx(Text, {
|
|
88
|
+
body1Bold: true,
|
|
89
|
+
children: i18n.theme.custom.title
|
|
90
|
+
})
|
|
91
|
+
}),
|
|
92
|
+
/*#__PURE__*/ jsxs(HStack, {
|
|
93
|
+
justify: "between",
|
|
94
|
+
children: [
|
|
95
|
+
/*#__PURE__*/ jsx(Text, {
|
|
96
|
+
color: "secondary",
|
|
97
|
+
children: i18n.theme.custom.preset
|
|
98
|
+
}),
|
|
99
|
+
/*#__PURE__*/ jsx(UXSelect, {
|
|
100
|
+
className: "min-w-48",
|
|
101
|
+
selectedKeys: [
|
|
102
|
+
baseThemeId
|
|
103
|
+
],
|
|
104
|
+
onSelectionChange: (keys)=>{
|
|
105
|
+
const selectedKey = Array.from(keys)[0];
|
|
106
|
+
if (selectedKey) handleBaseThemeChange(selectedKey);
|
|
107
|
+
},
|
|
108
|
+
children: baseThemes.map((t)=>/*#__PURE__*/ jsx(UXSelectItem, {
|
|
109
|
+
children: 'zh' === lang ? t.zhName : t.enName
|
|
110
|
+
}, t.id))
|
|
111
|
+
})
|
|
112
|
+
]
|
|
113
|
+
}),
|
|
114
|
+
/*#__PURE__*/ jsx(UXTabs, {
|
|
115
|
+
fullWidth: true,
|
|
116
|
+
variant: "switch",
|
|
117
|
+
children: Object.entries(COLOR_CATEGORIES).map(([category, colors])=>/*#__PURE__*/ jsx(UXTab, {
|
|
118
|
+
title: i18n.theme.custom.categories[category],
|
|
119
|
+
children: /*#__PURE__*/ jsx(VStack, {
|
|
120
|
+
gap: "md",
|
|
121
|
+
className: "pt-md",
|
|
122
|
+
children: colors.map((color)=>{
|
|
123
|
+
const label = i18n.theme.custom.colors[color] || color;
|
|
124
|
+
return renderColorItem(color, label);
|
|
125
|
+
})
|
|
126
|
+
})
|
|
127
|
+
}, category))
|
|
128
|
+
})
|
|
129
|
+
]
|
|
130
|
+
});
|
|
131
|
+
};
|
|
132
|
+
export { CustomThemeConfig };
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import "react";
|
|
3
3
|
import { cn } from "@heroui/theme";
|
|
4
4
|
import { useLang } from "../../hooks/index.js";
|
|
5
5
|
import { VStack } from "../layout/index.js";
|
|
6
6
|
import { Text } from "../typography/Text.js";
|
|
7
7
|
const ThemeItem = ({ id, zhName, enName, isSelected, onClick })=>{
|
|
8
|
-
const lang = useLang();
|
|
8
|
+
const { lang } = useLang();
|
|
9
9
|
return /*#__PURE__*/ jsxs(VStack, {
|
|
10
10
|
gap: 2,
|
|
11
11
|
items: "center",
|
|
@@ -123,7 +123,50 @@ const ThemeItem = ({ id, zhName, enName, isSelected, onClick })=>{
|
|
|
123
123
|
fill: "currentColor",
|
|
124
124
|
className: "text-secondary"
|
|
125
125
|
}),
|
|
126
|
-
/*#__PURE__*/
|
|
126
|
+
'custom' === id ? /*#__PURE__*/ jsxs(Fragment, {
|
|
127
|
+
children: [
|
|
128
|
+
/*#__PURE__*/ jsx("g", {
|
|
129
|
+
"clip-path": "url(#paint0_angular_48986_280686_clip_path)",
|
|
130
|
+
"data-figma-skip-parse": "true",
|
|
131
|
+
children: /*#__PURE__*/ jsx("g", {
|
|
132
|
+
transform: "matrix(0 0.011 -0.011 0 39 51)",
|
|
133
|
+
children: /*#__PURE__*/ jsx("foreignObject", {
|
|
134
|
+
x: "-1043.94",
|
|
135
|
+
y: "-1043.94",
|
|
136
|
+
width: "2087.87",
|
|
137
|
+
height: "2087.87",
|
|
138
|
+
children: /*#__PURE__*/ jsx("div", {
|
|
139
|
+
style: {
|
|
140
|
+
background: 'conic-gradient(from 90deg,rgba(255, 0, 0, 1) 0deg,rgba(255, 133, 0, 1) 54deg,rgba(190, 255, 0, 1) 117deg,rgba(7, 225, 255, 1) 199.8deg,rgba(35, 0, 255, 1) 282.6deg,rgba(173, 0, 255, 1) 360deg)',
|
|
141
|
+
height: '100%',
|
|
142
|
+
width: '100%',
|
|
143
|
+
opacity: 1
|
|
144
|
+
}
|
|
145
|
+
})
|
|
146
|
+
})
|
|
147
|
+
})
|
|
148
|
+
}),
|
|
149
|
+
/*#__PURE__*/ jsx("circle", {
|
|
150
|
+
cx: "39",
|
|
151
|
+
cy: "51",
|
|
152
|
+
r: "10.7583",
|
|
153
|
+
"data-figma-gradient-fill": '{"type":"GRADIENT_ANGULAR","stops":[{"color":{"r":1.0,"g":0.0,"b":0.0,"a":1.0},"position":0.0},{"color":{"r":1.0,"g":0.52295231819152832,"b":0.0,"a":1.0},"position":0.15000000596046448},{"color":{"r":0.74555355310440063,"g":1.0,"b":0.0,"a":1.0},"position":0.32499998807907104},{"color":{"r":0.029410807415843010,"g":0.88352936506271362,"b":1.0,"a":1.0},"position":0.55500000715255737},{"color":{"r":0.14000000059604645,"g":0.0,"b":1.0,"a":1.0},"position":0.78500002622604370},{"color":{"r":0.67999994754791260,"g":0.0,"b":1.0,"a":1.0},"position":1.0}],"stopsVar":[{"color":{"r":1.0,"g":0.0,"b":0.0,"a":1.0},"position":0.0},{"color":{"r":1.0,"g":0.52295231819152832,"b":0.0,"a":1.0},"position":0.15000000596046448},{"color":{"r":0.74555355310440063,"g":1.0,"b":0.0,"a":1.0},"position":0.32499998807907104},{"color":{"r":0.029410807415843010,"g":0.88352936506271362,"b":1.0,"a":1.0},"position":0.55500000715255737},{"color":{"r":0.14000000059604645,"g":0.0,"b":1.0,"a":1.0},"position":0.78500002622604370},{"color":{"r":0.67999994754791260,"g":0.0,"b":1.0,"a":1.0},"position":1.0}],"transform":{"m00":1.3471115643134642e-15,"m01":-22.0,"m02":50.0,"m10":22.0,"m11":1.3471115643134642e-15,"m12":40.0},"opacity":1.0,"blendMode":"NORMAL","visible":true}',
|
|
154
|
+
stroke: "#8B8EA1",
|
|
155
|
+
"stroke-width": "0.483303"
|
|
156
|
+
}),
|
|
157
|
+
/*#__PURE__*/ jsx("defs", {
|
|
158
|
+
children: /*#__PURE__*/ jsx("clipPath", {
|
|
159
|
+
id: "paint0_angular_48986_280686_clip_path",
|
|
160
|
+
children: /*#__PURE__*/ jsx("circle", {
|
|
161
|
+
cx: "39",
|
|
162
|
+
cy: "51",
|
|
163
|
+
r: "10.7583",
|
|
164
|
+
"stroke-width": "0.483303"
|
|
165
|
+
})
|
|
166
|
+
})
|
|
167
|
+
})
|
|
168
|
+
]
|
|
169
|
+
}) : /*#__PURE__*/ jsx("rect", {
|
|
127
170
|
x: "27",
|
|
128
171
|
y: "39",
|
|
129
172
|
width: "22.5688",
|
|
@@ -3,7 +3,7 @@ import { useMemo, useState } from "react";
|
|
|
3
3
|
import { cn } from "@heroui/theme";
|
|
4
4
|
import { useDisclosure } from "@heroui/use-disclosure";
|
|
5
5
|
import { ChartColorSwitchIcon, CopyIcon } from "@particle-network/icons/web";
|
|
6
|
-
import { themeData } from "@particle-network/ui-shared";
|
|
6
|
+
import { DEFAULT_THEME_ID, themeData } from "@particle-network/ui-shared";
|
|
7
7
|
import { useI18n } from "../../hooks/index.js";
|
|
8
8
|
import { HStack, VStack } from "../layout/index.js";
|
|
9
9
|
import { Text } from "../typography/Text.js";
|
|
@@ -15,6 +15,7 @@ import { UXInput } from "../UXInput/index.js";
|
|
|
15
15
|
import { UXModal } from "../UXModal/index.js";
|
|
16
16
|
import { UXSpinner } from "../UXSpinner/index.js";
|
|
17
17
|
import { UXTooltip } from "../UXTooltip/index.js";
|
|
18
|
+
import { CustomThemeConfig } from "./custom-theme-config.js";
|
|
18
19
|
import { ThemeItem } from "./theme-item.js";
|
|
19
20
|
import { useTheme } from "./use-theme.js";
|
|
20
21
|
const FONT_EXAMPLES = [
|
|
@@ -39,6 +40,18 @@ const UXThemeSwitchModal = ({ as = 'modal', omitThemes = [], backdrop, isOpen, o
|
|
|
39
40
|
const themes = useMemo(()=>themeData.filter((theme)=>!omitThemes.includes(theme.id)), [
|
|
40
41
|
omitThemes
|
|
41
42
|
]);
|
|
43
|
+
const handleThemeSelect = (theme)=>{
|
|
44
|
+
if ('custom' === theme.id && 'custom' !== selectedTheme.id) {
|
|
45
|
+
const baseTheme = themeData.find((t)=>t.id === DEFAULT_THEME_ID) || themeData["0"];
|
|
46
|
+
const customTheme = {
|
|
47
|
+
...theme,
|
|
48
|
+
baseThemeId: DEFAULT_THEME_ID,
|
|
49
|
+
colorScheme: baseTheme.colorScheme,
|
|
50
|
+
colorVariables: baseTheme.colorVariables
|
|
51
|
+
};
|
|
52
|
+
setTheme(customTheme);
|
|
53
|
+
} else setTheme(theme);
|
|
54
|
+
};
|
|
42
55
|
return /*#__PURE__*/ jsx(Component, {
|
|
43
56
|
isOpen: isOpen,
|
|
44
57
|
classNames: {
|
|
@@ -61,10 +74,17 @@ const UXThemeSwitchModal = ({ as = 'modal', omitThemes = [], backdrop, isOpen, o
|
|
|
61
74
|
className: "grid grid-cols-3 gap-y-5 pt-1",
|
|
62
75
|
children: themes.map((theme)=>/*#__PURE__*/ jsx(ThemeItem, {
|
|
63
76
|
isSelected: selectedTheme.id === theme.id,
|
|
64
|
-
onClick: ()=>
|
|
77
|
+
onClick: ()=>handleThemeSelect(theme),
|
|
65
78
|
...theme
|
|
66
79
|
}, theme.id))
|
|
67
80
|
}),
|
|
81
|
+
'custom' === selectedTheme.id && /*#__PURE__*/ jsxs(Fragment, {
|
|
82
|
+
children: [
|
|
83
|
+
/*#__PURE__*/ jsx(UXDivider, {}),
|
|
84
|
+
/*#__PURE__*/ jsx(CustomThemeConfig, {}),
|
|
85
|
+
/*#__PURE__*/ jsx(UXDivider, {})
|
|
86
|
+
]
|
|
87
|
+
}),
|
|
68
88
|
/*#__PURE__*/ jsx(UXDivider, {}),
|
|
69
89
|
/*#__PURE__*/ jsxs(VStack, {
|
|
70
90
|
gap: "md",
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
import { useThemeStore } from "./use-theme-store.js";
|
|
2
3
|
const useColorScheme = ()=>{
|
|
3
|
-
const {
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
const { colorScheme } = useThemeStore((state)=>state.theme);
|
|
5
|
+
const scheme = useMemo(()=>({
|
|
6
|
+
colorScheme,
|
|
7
|
+
isDark: 'dark' === colorScheme,
|
|
8
|
+
isLight: 'light' === colorScheme
|
|
9
|
+
}), [
|
|
10
|
+
colorScheme
|
|
11
|
+
]);
|
|
12
|
+
return scheme;
|
|
10
13
|
};
|
|
11
14
|
export { useColorScheme };
|
|
@@ -1,10 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useMemo } from "react";
|
|
2
|
+
import { useThemeStore } from "./use-theme-store.js";
|
|
2
3
|
const useThemeColor = ()=>{
|
|
3
|
-
const {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
const { colorVariables } = useThemeStore((state)=>state.theme);
|
|
5
|
+
const themeColor = useMemo(()=>({
|
|
6
|
+
...colorVariables,
|
|
7
|
+
transparent: 'transparent',
|
|
8
|
+
white: '#FFFFFF'
|
|
9
|
+
}), [
|
|
10
|
+
colorVariables
|
|
11
|
+
]);
|
|
12
|
+
return themeColor;
|
|
9
13
|
};
|
|
10
14
|
export { useThemeColor };
|
|
@@ -20,7 +20,7 @@ const useThemeStore = create()(persist((set)=>({
|
|
|
20
20
|
})
|
|
21
21
|
}), {
|
|
22
22
|
name: 'ux-preferences-theme',
|
|
23
|
-
version:
|
|
23
|
+
version: 2,
|
|
24
24
|
storage: createJSONStorage(()=>'undefined' != typeof window ? window.localStorage : {}),
|
|
25
25
|
partialize: (state)=>({
|
|
26
26
|
theme: state.theme,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useEffect } from "react";
|
|
2
|
-
import { themeKeys } from "@particle-network/ui-shared";
|
|
2
|
+
import { colorToCSSVariable, hexColorToHSLValue, themeKeys } from "@particle-network/ui-shared";
|
|
3
3
|
import { useDebounceFn } from "ahooks";
|
|
4
4
|
import { useThemeStore } from "./use-theme-store.js";
|
|
5
5
|
const DEFAULT_FONT_FAMILY = 'Inter,system-ui,sans-serif,"Microsoft YaHei"';
|
|
@@ -14,13 +14,36 @@ const preloadFonts = ()=>{
|
|
|
14
14
|
linkElement.href = PRELOAD_FONTS_URL;
|
|
15
15
|
document.head.appendChild(linkElement);
|
|
16
16
|
};
|
|
17
|
+
const applyCustomThemeColors = (theme)=>{
|
|
18
|
+
if ('undefined' == typeof window) return;
|
|
19
|
+
const root = document.documentElement;
|
|
20
|
+
Object.entries(theme.colorVariables).forEach(([color, value])=>{
|
|
21
|
+
const cssVariable = colorToCSSVariable[color]?.self;
|
|
22
|
+
if (cssVariable) cssVariable.forEach((variable)=>{
|
|
23
|
+
root.style.setProperty(variable, hexColorToHSLValue(value));
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
const clearCustomThemeColors = ()=>{
|
|
28
|
+
if ('undefined' == typeof window) return;
|
|
29
|
+
const root = document.documentElement;
|
|
30
|
+
Object.values(colorToCSSVariable).forEach((cssVar)=>{
|
|
31
|
+
cssVar.self?.forEach((variable)=>{
|
|
32
|
+
root.style.removeProperty(variable);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
};
|
|
17
36
|
const applyTheme = (theme)=>{
|
|
18
37
|
if ('undefined' == typeof window) return;
|
|
19
38
|
const root = document.documentElement;
|
|
20
39
|
const isClassListCorrect = root.classList.contains(theme.id);
|
|
21
40
|
const isDataThemeCorrect = root.getAttribute('data-theme') === theme.colorScheme;
|
|
22
41
|
const isDataPrefersColorCorrect = root.getAttribute('data-prefers-color') === theme.colorScheme;
|
|
23
|
-
if (
|
|
42
|
+
if ('custom' === theme.id) {
|
|
43
|
+
clearCustomThemeColors();
|
|
44
|
+
applyCustomThemeColors(theme);
|
|
45
|
+
} else clearCustomThemeColors();
|
|
46
|
+
if (isClassListCorrect && isDataThemeCorrect && isDataPrefersColorCorrect && 'custom' !== theme.id) return;
|
|
24
47
|
if (!isDataThemeCorrect) root.setAttribute('data-theme', theme.colorScheme);
|
|
25
48
|
if (!isDataPrefersColorCorrect) root.setAttribute('data-prefers-color', theme.colorScheme);
|
|
26
49
|
root.classList.remove('dark');
|
|
@@ -29,7 +52,7 @@ const applyTheme = (theme)=>{
|
|
|
29
52
|
themeKeys.forEach((key)=>{
|
|
30
53
|
root.classList.remove(key);
|
|
31
54
|
});
|
|
32
|
-
root.classList.add(theme.id);
|
|
55
|
+
root.classList.add('custom' === theme.id ? theme.baseThemeId : theme.id);
|
|
33
56
|
}
|
|
34
57
|
};
|
|
35
58
|
const extractFontFamilyFromLink = (link)=>{
|
|
@@ -97,6 +120,11 @@ const useTheme = ()=>{
|
|
|
97
120
|
applyTheme(theme);
|
|
98
121
|
debouncedApplyFont(fontUrl, theme.fontName);
|
|
99
122
|
}, []);
|
|
123
|
+
useEffect(()=>{
|
|
124
|
+
applyTheme(theme);
|
|
125
|
+
}, [
|
|
126
|
+
theme
|
|
127
|
+
]);
|
|
100
128
|
const setTheme = (theme)=>{
|
|
101
129
|
storeSetTheme(theme);
|
|
102
130
|
applyTheme(theme);
|
package/dist/hooks/useI18n.d.ts
CHANGED
|
@@ -1,31 +1,119 @@
|
|
|
1
1
|
export declare const useI18n: () => {
|
|
2
|
-
table: {
|
|
3
|
-
emptyContent:
|
|
4
|
-
};
|
|
5
|
-
copy: {
|
|
6
|
-
copy:
|
|
7
|
-
success:
|
|
8
|
-
error:
|
|
9
|
-
address:
|
|
10
|
-
};
|
|
11
|
-
theme: {
|
|
12
|
-
title:
|
|
13
|
-
done:
|
|
14
|
-
font: {
|
|
15
|
-
title:
|
|
16
|
-
placeholder:
|
|
17
|
-
loading:
|
|
18
|
-
success:
|
|
19
|
-
error:
|
|
20
|
-
hint:
|
|
21
|
-
example: {
|
|
22
|
-
show:
|
|
23
|
-
hide:
|
|
2
|
+
readonly table: {
|
|
3
|
+
readonly emptyContent: "No data";
|
|
4
|
+
};
|
|
5
|
+
readonly copy: {
|
|
6
|
+
readonly copy: "Copy";
|
|
7
|
+
readonly success: "Copied successfully!";
|
|
8
|
+
readonly error: "Copy failed: ";
|
|
9
|
+
readonly address: "Address copied: ";
|
|
10
|
+
};
|
|
11
|
+
readonly theme: {
|
|
12
|
+
readonly title: "Theme";
|
|
13
|
+
readonly done: "Finish";
|
|
14
|
+
readonly font: {
|
|
15
|
+
readonly title: "Custom Font";
|
|
16
|
+
readonly placeholder: "Enter Google Fonts URL or custom font URL";
|
|
17
|
+
readonly loading: "Loading font...";
|
|
18
|
+
readonly success: "Font loaded: ";
|
|
19
|
+
readonly error: "Failed to load font";
|
|
20
|
+
readonly hint: "Try Google Fonts: ";
|
|
21
|
+
readonly example: {
|
|
22
|
+
readonly show: "Show example";
|
|
23
|
+
readonly hide: "Hide example";
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
readonly custom: {
|
|
27
|
+
readonly title: "Custom Theme";
|
|
28
|
+
readonly preset: "Theme Preset";
|
|
29
|
+
readonly categories: {
|
|
30
|
+
readonly basic: "Basic";
|
|
31
|
+
readonly background: "Background";
|
|
32
|
+
readonly text: "Text";
|
|
33
|
+
readonly signal: "Signal";
|
|
34
|
+
};
|
|
35
|
+
readonly colors: {
|
|
36
|
+
readonly primary: "Primary";
|
|
37
|
+
readonly bullish: "Positive";
|
|
38
|
+
readonly bearish: "Negative";
|
|
39
|
+
readonly 'bg-default': "Background";
|
|
40
|
+
readonly 'bg-200': "Background Quaternary";
|
|
41
|
+
readonly 'bg-300': "Background Tertiary";
|
|
42
|
+
readonly 'bg-400': "Background Secondary";
|
|
43
|
+
readonly overlay: "Overlay";
|
|
44
|
+
readonly default: "Default";
|
|
45
|
+
readonly foreground: "Text Primary";
|
|
46
|
+
readonly secondary: "Text Secondary";
|
|
47
|
+
readonly tertiary: "Text Tertiary";
|
|
48
|
+
readonly divider: "Divider";
|
|
49
|
+
readonly success: "Signal Green";
|
|
50
|
+
readonly danger: "Signal Red";
|
|
51
|
+
readonly alert: "Signal Orange";
|
|
52
|
+
readonly gold: "Signal Yellow";
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
readonly switch: {
|
|
57
|
+
readonly on: "On";
|
|
58
|
+
readonly off: "Off";
|
|
59
|
+
};
|
|
60
|
+
} | {
|
|
61
|
+
readonly table: {
|
|
62
|
+
readonly emptyContent: "暂无数据";
|
|
63
|
+
};
|
|
64
|
+
readonly copy: {
|
|
65
|
+
readonly copy: "复制";
|
|
66
|
+
readonly success: "复制成功!";
|
|
67
|
+
readonly error: "复制失败:";
|
|
68
|
+
readonly address: "地址已复制:";
|
|
69
|
+
};
|
|
70
|
+
readonly theme: {
|
|
71
|
+
readonly title: "主题";
|
|
72
|
+
readonly done: "完成";
|
|
73
|
+
readonly font: {
|
|
74
|
+
readonly title: "自定义字体";
|
|
75
|
+
readonly placeholder: "输入 Google Fonts 或自定义字体链接";
|
|
76
|
+
readonly loading: "正在加载字体...";
|
|
77
|
+
readonly success: "已加载字体:";
|
|
78
|
+
readonly error: "字体加载失败";
|
|
79
|
+
readonly hint: "参考 Google Fonts: ";
|
|
80
|
+
readonly example: {
|
|
81
|
+
readonly show: "显示示例";
|
|
82
|
+
readonly hide: "隐藏示例";
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
readonly custom: {
|
|
86
|
+
readonly title: "自定义主题";
|
|
87
|
+
readonly preset: "主题预设";
|
|
88
|
+
readonly categories: {
|
|
89
|
+
readonly basic: "基础";
|
|
90
|
+
readonly background: "背景";
|
|
91
|
+
readonly text: "文字";
|
|
92
|
+
readonly signal: "信号";
|
|
93
|
+
};
|
|
94
|
+
readonly colors: {
|
|
95
|
+
readonly primary: "主要色";
|
|
96
|
+
readonly bullish: "上涨色";
|
|
97
|
+
readonly bearish: "下跌色";
|
|
98
|
+
readonly 'bg-default': "一级背景色";
|
|
99
|
+
readonly 'bg-200': "四级背景色";
|
|
100
|
+
readonly 'bg-300': "三级背景色";
|
|
101
|
+
readonly 'bg-400': "二级背景色";
|
|
102
|
+
readonly overlay: "浮窗色";
|
|
103
|
+
readonly default: "默认";
|
|
104
|
+
readonly foreground: "一级文字色";
|
|
105
|
+
readonly secondary: "二级文字色";
|
|
106
|
+
readonly tertiary: "三级文字色";
|
|
107
|
+
readonly divider: "分割线";
|
|
108
|
+
readonly success: "绿色信号";
|
|
109
|
+
readonly danger: "红色信号";
|
|
110
|
+
readonly alert: "橙色信号";
|
|
111
|
+
readonly gold: "黄色信号";
|
|
24
112
|
};
|
|
25
113
|
};
|
|
26
114
|
};
|
|
27
|
-
switch: {
|
|
28
|
-
on:
|
|
29
|
-
off:
|
|
115
|
+
readonly switch: {
|
|
116
|
+
readonly on: "开";
|
|
117
|
+
readonly off: "关";
|
|
30
118
|
};
|
|
31
119
|
};
|
package/dist/hooks/useI18n.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useMemo } from "react";
|
|
1
2
|
import { useLang } from "./useLang.js";
|
|
2
3
|
const en = {
|
|
3
4
|
table: {
|
|
@@ -23,6 +24,35 @@ const en = {
|
|
|
23
24
|
show: 'Show example',
|
|
24
25
|
hide: 'Hide example'
|
|
25
26
|
}
|
|
27
|
+
},
|
|
28
|
+
custom: {
|
|
29
|
+
title: 'Custom Theme',
|
|
30
|
+
preset: 'Theme Preset',
|
|
31
|
+
categories: {
|
|
32
|
+
basic: 'Basic',
|
|
33
|
+
background: 'Background',
|
|
34
|
+
text: 'Text',
|
|
35
|
+
signal: 'Signal'
|
|
36
|
+
},
|
|
37
|
+
colors: {
|
|
38
|
+
primary: 'Primary',
|
|
39
|
+
bullish: 'Positive',
|
|
40
|
+
bearish: 'Negative',
|
|
41
|
+
'bg-default': 'Background',
|
|
42
|
+
'bg-200': 'Background Quaternary',
|
|
43
|
+
'bg-300': 'Background Tertiary',
|
|
44
|
+
'bg-400': 'Background Secondary',
|
|
45
|
+
overlay: 'Overlay',
|
|
46
|
+
default: 'Default',
|
|
47
|
+
foreground: 'Text Primary',
|
|
48
|
+
secondary: 'Text Secondary',
|
|
49
|
+
tertiary: 'Text Tertiary',
|
|
50
|
+
divider: 'Divider',
|
|
51
|
+
success: 'Signal Green',
|
|
52
|
+
danger: 'Signal Red',
|
|
53
|
+
alert: 'Signal Orange',
|
|
54
|
+
gold: 'Signal Yellow'
|
|
55
|
+
}
|
|
26
56
|
}
|
|
27
57
|
},
|
|
28
58
|
switch: {
|
|
@@ -54,6 +84,35 @@ const zh = {
|
|
|
54
84
|
show: '显示示例',
|
|
55
85
|
hide: '隐藏示例'
|
|
56
86
|
}
|
|
87
|
+
},
|
|
88
|
+
custom: {
|
|
89
|
+
title: '自定义主题',
|
|
90
|
+
preset: '主题预设',
|
|
91
|
+
categories: {
|
|
92
|
+
basic: '基础',
|
|
93
|
+
background: '背景',
|
|
94
|
+
text: '文字',
|
|
95
|
+
signal: '信号'
|
|
96
|
+
},
|
|
97
|
+
colors: {
|
|
98
|
+
primary: '主要色',
|
|
99
|
+
bullish: '上涨色',
|
|
100
|
+
bearish: '下跌色',
|
|
101
|
+
'bg-default': '一级背景色',
|
|
102
|
+
'bg-200': '四级背景色',
|
|
103
|
+
'bg-300': '三级背景色',
|
|
104
|
+
'bg-400': '二级背景色',
|
|
105
|
+
overlay: '浮窗色',
|
|
106
|
+
default: '默认',
|
|
107
|
+
foreground: '一级文字色',
|
|
108
|
+
secondary: '二级文字色',
|
|
109
|
+
tertiary: '三级文字色',
|
|
110
|
+
divider: '分割线',
|
|
111
|
+
success: '绿色信号',
|
|
112
|
+
danger: '红色信号',
|
|
113
|
+
alert: '橙色信号',
|
|
114
|
+
gold: '黄色信号'
|
|
115
|
+
}
|
|
57
116
|
}
|
|
58
117
|
},
|
|
59
118
|
switch: {
|
|
@@ -62,7 +121,10 @@ const zh = {
|
|
|
62
121
|
}
|
|
63
122
|
};
|
|
64
123
|
const useI18n = ()=>{
|
|
65
|
-
const lang = useLang();
|
|
66
|
-
|
|
124
|
+
const { lang } = useLang();
|
|
125
|
+
const i18n = useMemo(()=>'zh' === lang ? zh : en, [
|
|
126
|
+
lang
|
|
127
|
+
]);
|
|
128
|
+
return i18n;
|
|
67
129
|
};
|
|
68
130
|
export { useI18n };
|
package/dist/hooks/useLang.d.ts
CHANGED
package/dist/hooks/useLang.js
CHANGED
|
@@ -23,6 +23,18 @@ function useLang() {
|
|
|
23
23
|
observer.disconnect();
|
|
24
24
|
};
|
|
25
25
|
}, []);
|
|
26
|
-
|
|
26
|
+
const handleSetLang = (lang)=>{
|
|
27
|
+
setLang(lang);
|
|
28
|
+
document.documentElement.lang = lang;
|
|
29
|
+
};
|
|
30
|
+
const toggleLang = ()=>{
|
|
31
|
+
const newLang = 'zh' === lang ? 'en' : 'zh';
|
|
32
|
+
handleSetLang(newLang);
|
|
33
|
+
};
|
|
34
|
+
return {
|
|
35
|
+
lang,
|
|
36
|
+
setLang: handleSetLang,
|
|
37
|
+
toggleLang
|
|
38
|
+
};
|
|
27
39
|
}
|
|
28
40
|
export { useLang };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@particle-network/ui-react",
|
|
3
|
-
"version": "0.5.1-beta.
|
|
3
|
+
"version": "0.5.1-beta.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -48,10 +48,11 @@
|
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"ahooks": "^3.9.4",
|
|
50
50
|
"copy-to-clipboard": "^3.3.3",
|
|
51
|
+
"immer": "^11.1.3",
|
|
51
52
|
"react-aria-components": "^1.14.0",
|
|
52
53
|
"zustand": "^5.0.8",
|
|
53
|
-
"@particle-network/
|
|
54
|
-
"@particle-network/
|
|
54
|
+
"@particle-network/ui-shared": "0.4.1-beta.0",
|
|
55
|
+
"@particle-network/icons": "0.5.1-beta.1"
|
|
55
56
|
},
|
|
56
57
|
"scripts": {
|
|
57
58
|
"build": "rslib build",
|
package/tailwind-preset.js
CHANGED
|
@@ -1094,85 +1094,6 @@ module.exports = {
|
|
|
1094
1094
|
},
|
|
1095
1095
|
},
|
|
1096
1096
|
},
|
|
1097
|
-
'product-test': {
|
|
1098
|
-
extend: 'dark',
|
|
1099
|
-
colors: {
|
|
1100
|
-
default: {
|
|
1101
|
-
DEFAULT: '#222D33',
|
|
1102
|
-
foreground: '#F6FEFD',
|
|
1103
|
-
},
|
|
1104
|
-
secondary: {
|
|
1105
|
-
DEFAULT: '#D1D4DC',
|
|
1106
|
-
foreground: '#000000',
|
|
1107
|
-
},
|
|
1108
|
-
tertiary: {
|
|
1109
|
-
DEFAULT: '#949E9C',
|
|
1110
|
-
foreground: '#000000',
|
|
1111
|
-
},
|
|
1112
|
-
primary: {
|
|
1113
|
-
100: '#EFF5F5',
|
|
1114
|
-
200: '#CEE6E4',
|
|
1115
|
-
300: '#A8DBD6',
|
|
1116
|
-
400: '#7ED4CB',
|
|
1117
|
-
500: '#50D2C1',
|
|
1118
|
-
600: '#34B9A5',
|
|
1119
|
-
700: '#2B8C7C',
|
|
1120
|
-
800: '#206255',
|
|
1121
|
-
900: '#143831',
|
|
1122
|
-
DEFAULT: '#50D2C1',
|
|
1123
|
-
foreground: '#000000',
|
|
1124
|
-
},
|
|
1125
|
-
success: {
|
|
1126
|
-
DEFAULT: '#19AB5E',
|
|
1127
|
-
foreground: '#000000',
|
|
1128
|
-
},
|
|
1129
|
-
danger: {
|
|
1130
|
-
DEFAULT: '#E84A5A',
|
|
1131
|
-
foreground: '#000000',
|
|
1132
|
-
},
|
|
1133
|
-
alert: {
|
|
1134
|
-
DEFAULT: '#F57733',
|
|
1135
|
-
foreground: '#000000',
|
|
1136
|
-
},
|
|
1137
|
-
warning: {
|
|
1138
|
-
DEFAULT: '#FFD13F',
|
|
1139
|
-
foreground: '#000000',
|
|
1140
|
-
},
|
|
1141
|
-
gold: {
|
|
1142
|
-
DEFAULT: '#FFB800',
|
|
1143
|
-
foreground: '#000000',
|
|
1144
|
-
},
|
|
1145
|
-
overlay: {
|
|
1146
|
-
DEFAULT: '#1B2429',
|
|
1147
|
-
foreground: '#FFFFFF',
|
|
1148
|
-
},
|
|
1149
|
-
divider: {
|
|
1150
|
-
DEFAULT: '#394145',
|
|
1151
|
-
foreground: '#FFFFFF',
|
|
1152
|
-
},
|
|
1153
|
-
bullish: {
|
|
1154
|
-
DEFAULT: '#D745FF',
|
|
1155
|
-
foreground: '#000000',
|
|
1156
|
-
},
|
|
1157
|
-
bearish: {
|
|
1158
|
-
DEFAULT: '#F38300',
|
|
1159
|
-
foreground: '#000000',
|
|
1160
|
-
},
|
|
1161
|
-
background: {
|
|
1162
|
-
200: '#222D33',
|
|
1163
|
-
300: '#1B2429',
|
|
1164
|
-
400: '#0F1A1F',
|
|
1165
|
-
500: '#0A1318',
|
|
1166
|
-
DEFAULT: '#0A1318',
|
|
1167
|
-
},
|
|
1168
|
-
foreground: {
|
|
1169
|
-
100: '#949E9C',
|
|
1170
|
-
300: '#D1D4DC',
|
|
1171
|
-
500: '#F6FEFD',
|
|
1172
|
-
DEFAULT: '#F6FEFD',
|
|
1173
|
-
},
|
|
1174
|
-
},
|
|
1175
|
-
},
|
|
1176
1097
|
},
|
|
1177
1098
|
function({ addVariant, addComponents }) {
|
|
1178
1099
|
addVariant('child', '& > *');
|