@lobehub/chat 1.70.3 → 1.70.5
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 +50 -0
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/changelog/v1.json +18 -0
- package/docs/self-hosting/advanced/model-list.mdx +3 -3
- package/docs/self-hosting/advanced/model-list.zh-CN.mdx +3 -3
- package/docs/self-hosting/environment-variables/model-provider.mdx +17 -3
- package/docs/self-hosting/environment-variables/model-provider.zh-CN.mdx +16 -2
- package/package.json +1 -1
- package/packages/web-crawler/src/crawImpl/naive.ts +11 -3
- package/packages/web-crawler/src/urlRules.ts +6 -0
- package/src/app/[variants]/(main)/(mobile)/me/(home)/features/Header.tsx +2 -2
- package/src/app/[variants]/(main)/settings/common/features/Theme/index.tsx +5 -3
- package/src/components/Branding/ProductLogo/Custom.tsx +4 -0
- package/src/config/modelProviders/openrouter.ts +7 -0
- package/src/const/settings/common.ts +0 -1
- package/src/database/schemas/user.ts +3 -3
- package/src/database/server/models/__tests__/plugin.test.ts +8 -8
- package/src/database/server/models/plugin.ts +20 -20
- package/src/features/User/UserPanel/ThemeButton.tsx +4 -4
- package/src/layout/GlobalProvider/AppTheme.tsx +5 -9
- package/src/libs/agent-runtime/openrouter/index.test.ts +10 -1
- package/src/services/plugin/client.test.ts +21 -21
- package/src/services/user/_deprecated.test.ts +1 -1
- package/src/services/user/client.test.ts +1 -1
- package/src/store/aiInfra/slices/aiProvider/__tests__/selectors.test.ts +249 -0
- package/src/store/global/action.test.ts +15 -0
- package/src/store/global/actions/__tests__/general.test.ts +221 -0
- package/src/store/global/actions/general.ts +10 -1
- package/src/store/global/initialState.ts +6 -0
- package/src/store/global/selectors/systemStatus.test.ts +209 -0
- package/src/store/global/selectors/systemStatus.ts +22 -21
- package/src/store/user/slices/settings/action.test.ts +1 -19
- package/src/store/user/slices/settings/action.ts +0 -5
- package/src/store/user/slices/settings/selectors/general.test.ts +5 -15
- package/src/store/user/slices/settings/selectors/general.ts +0 -6
- package/src/types/user/settings/general.ts +0 -2
@@ -1,3 +1,4 @@
|
|
1
|
+
import type { ThemeMode } from 'antd-style';
|
1
2
|
import { AppRouterInstance } from 'next/dist/shared/lib/app-router-context.shared-runtime';
|
2
3
|
|
3
4
|
import { DatabaseLoadingState } from '@/types/clientDB';
|
@@ -61,6 +62,10 @@ export interface SystemStatus {
|
|
61
62
|
showFilePanel?: boolean;
|
62
63
|
showSessionPanel?: boolean;
|
63
64
|
showSystemRole?: boolean;
|
65
|
+
/**
|
66
|
+
* theme mode
|
67
|
+
*/
|
68
|
+
themeMode?: ThemeMode;
|
64
69
|
threadInputHeight: number;
|
65
70
|
zenMode?: boolean;
|
66
71
|
}
|
@@ -96,6 +101,7 @@ export const INITIAL_STATUS = {
|
|
96
101
|
showFilePanel: true,
|
97
102
|
showSessionPanel: true,
|
98
103
|
showSystemRole: false,
|
104
|
+
themeMode: 'auto',
|
99
105
|
threadInputHeight: 200,
|
100
106
|
zenMode: false,
|
101
107
|
} satisfies SystemStatus;
|
@@ -0,0 +1,209 @@
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
2
|
+
|
3
|
+
import { DatabaseLoadingState } from '@/types/clientDB';
|
4
|
+
import { merge } from '@/utils/merge';
|
5
|
+
|
6
|
+
import { GlobalState, INITIAL_STATUS, initialState } from '../initialState';
|
7
|
+
import { systemStatusSelectors } from './systemStatus';
|
8
|
+
|
9
|
+
// Mock version constants
|
10
|
+
vi.mock('@/const/version', () => ({
|
11
|
+
isServerMode: false,
|
12
|
+
isUsePgliteDB: true,
|
13
|
+
}));
|
14
|
+
|
15
|
+
describe('systemStatusSelectors', () => {
|
16
|
+
describe('sessionGroupKeys', () => {
|
17
|
+
it('should return expandSessionGroupKeys from status', () => {
|
18
|
+
const s: GlobalState = merge(initialState, {
|
19
|
+
status: {
|
20
|
+
expandSessionGroupKeys: ['group1', 'group2'],
|
21
|
+
},
|
22
|
+
});
|
23
|
+
expect(systemStatusSelectors.sessionGroupKeys(s)).toEqual(['group1', 'group2']);
|
24
|
+
});
|
25
|
+
|
26
|
+
it('should return initial value if not set', () => {
|
27
|
+
const s: GlobalState = merge(initialState, {
|
28
|
+
status: {
|
29
|
+
expandSessionGroupKeys: undefined,
|
30
|
+
},
|
31
|
+
});
|
32
|
+
expect(systemStatusSelectors.sessionGroupKeys(s)).toEqual(
|
33
|
+
INITIAL_STATUS.expandSessionGroupKeys,
|
34
|
+
);
|
35
|
+
});
|
36
|
+
});
|
37
|
+
|
38
|
+
describe('basic selectors', () => {
|
39
|
+
const s: GlobalState = merge(initialState, {
|
40
|
+
status: {
|
41
|
+
showSystemRole: true,
|
42
|
+
mobileShowTopic: true,
|
43
|
+
mobileShowPortal: true,
|
44
|
+
showChatSideBar: true,
|
45
|
+
showSessionPanel: true,
|
46
|
+
showFilePanel: true,
|
47
|
+
hidePWAInstaller: true,
|
48
|
+
isShowCredit: true,
|
49
|
+
zenMode: false,
|
50
|
+
sessionsWidth: 300,
|
51
|
+
portalWidth: 500,
|
52
|
+
filePanelWidth: 400,
|
53
|
+
inputHeight: 150,
|
54
|
+
threadInputHeight: 100,
|
55
|
+
},
|
56
|
+
});
|
57
|
+
|
58
|
+
it('should return correct values for basic selectors', () => {
|
59
|
+
expect(systemStatusSelectors.showSystemRole(s)).toBe(true);
|
60
|
+
expect(systemStatusSelectors.mobileShowTopic(s)).toBe(true);
|
61
|
+
expect(systemStatusSelectors.mobileShowPortal(s)).toBe(true);
|
62
|
+
expect(systemStatusSelectors.showChatSideBar(s)).toBe(true);
|
63
|
+
expect(systemStatusSelectors.showSessionPanel(s)).toBe(true);
|
64
|
+
expect(systemStatusSelectors.showFilePanel(s)).toBe(true);
|
65
|
+
expect(systemStatusSelectors.hidePWAInstaller(s)).toBe(true);
|
66
|
+
expect(systemStatusSelectors.isShowCredit(s)).toBe(true);
|
67
|
+
expect(systemStatusSelectors.showChatHeader(s)).toBe(true);
|
68
|
+
expect(systemStatusSelectors.inZenMode(s)).toBe(false);
|
69
|
+
expect(systemStatusSelectors.sessionWidth(s)).toBe(300);
|
70
|
+
expect(systemStatusSelectors.portalWidth(s)).toBe(500);
|
71
|
+
expect(systemStatusSelectors.filePanelWidth(s)).toBe(400);
|
72
|
+
expect(systemStatusSelectors.inputHeight(s)).toBe(150);
|
73
|
+
expect(systemStatusSelectors.threadInputHeight(s)).toBe(100);
|
74
|
+
});
|
75
|
+
|
76
|
+
it('should handle zen mode effects', () => {
|
77
|
+
const zenState = merge(s, {
|
78
|
+
status: { zenMode: true },
|
79
|
+
});
|
80
|
+
expect(systemStatusSelectors.showChatSideBar(zenState)).toBe(false);
|
81
|
+
expect(systemStatusSelectors.showSessionPanel(zenState)).toBe(false);
|
82
|
+
expect(systemStatusSelectors.showChatHeader(zenState)).toBe(false);
|
83
|
+
});
|
84
|
+
|
85
|
+
it('should return default portal width if not set', () => {
|
86
|
+
const noPortalWidth = merge(initialState, {
|
87
|
+
status: { portalWidth: undefined },
|
88
|
+
});
|
89
|
+
expect(systemStatusSelectors.portalWidth(noPortalWidth)).toBe(400);
|
90
|
+
});
|
91
|
+
});
|
92
|
+
|
93
|
+
describe('theme mode', () => {
|
94
|
+
it('should return the correct theme', () => {
|
95
|
+
const s: GlobalState = merge(initialState, {
|
96
|
+
status: {
|
97
|
+
themeMode: 'light',
|
98
|
+
},
|
99
|
+
});
|
100
|
+
expect(systemStatusSelectors.themeMode(s)).toBe('light');
|
101
|
+
});
|
102
|
+
|
103
|
+
it('should return auto if not set', () => {
|
104
|
+
const s: GlobalState = merge(initialState, {
|
105
|
+
status: {
|
106
|
+
themeMode: undefined,
|
107
|
+
},
|
108
|
+
});
|
109
|
+
expect(systemStatusSelectors.themeMode(s)).toBe('auto');
|
110
|
+
});
|
111
|
+
});
|
112
|
+
|
113
|
+
describe('pglite status selectors', () => {
|
114
|
+
describe('isPgliteNotEnabled', () => {
|
115
|
+
it('should return true when conditions are met', () => {
|
116
|
+
const s: GlobalState = {
|
117
|
+
...initialState,
|
118
|
+
isStatusInit: true,
|
119
|
+
status: {
|
120
|
+
...initialState.status,
|
121
|
+
isEnablePglite: false,
|
122
|
+
},
|
123
|
+
};
|
124
|
+
expect(systemStatusSelectors.isPgliteNotEnabled(s)).toBe(true);
|
125
|
+
});
|
126
|
+
|
127
|
+
it('should return false when isStatusInit is false', () => {
|
128
|
+
const s: GlobalState = {
|
129
|
+
...initialState,
|
130
|
+
isStatusInit: false,
|
131
|
+
status: {
|
132
|
+
...initialState.status,
|
133
|
+
isEnablePglite: false,
|
134
|
+
},
|
135
|
+
};
|
136
|
+
expect(systemStatusSelectors.isPgliteNotEnabled(s)).toBe(false);
|
137
|
+
});
|
138
|
+
});
|
139
|
+
|
140
|
+
describe('isPgliteNotInited', () => {
|
141
|
+
it('should return true when pglite is enabled but not ready', () => {
|
142
|
+
const s: GlobalState = {
|
143
|
+
...initialState,
|
144
|
+
isStatusInit: true,
|
145
|
+
status: {
|
146
|
+
...initialState.status,
|
147
|
+
isEnablePglite: true,
|
148
|
+
},
|
149
|
+
initClientDBStage: DatabaseLoadingState.Initializing,
|
150
|
+
};
|
151
|
+
expect(systemStatusSelectors.isPgliteNotInited(s)).toBe(true);
|
152
|
+
});
|
153
|
+
|
154
|
+
it('should return false when pglite is ready', () => {
|
155
|
+
const s: GlobalState = {
|
156
|
+
...initialState,
|
157
|
+
isStatusInit: true,
|
158
|
+
status: {
|
159
|
+
...initialState.status,
|
160
|
+
isEnablePglite: true,
|
161
|
+
},
|
162
|
+
initClientDBStage: DatabaseLoadingState.Ready,
|
163
|
+
};
|
164
|
+
expect(systemStatusSelectors.isPgliteNotInited(s)).toBe(false);
|
165
|
+
});
|
166
|
+
|
167
|
+
it('should return false when pglite is not enabled', () => {
|
168
|
+
const s: GlobalState = {
|
169
|
+
...initialState,
|
170
|
+
isStatusInit: true,
|
171
|
+
status: {
|
172
|
+
...initialState.status,
|
173
|
+
isEnablePglite: false,
|
174
|
+
},
|
175
|
+
initClientDBStage: DatabaseLoadingState.Initializing,
|
176
|
+
};
|
177
|
+
expect(systemStatusSelectors.isPgliteNotInited(s)).toBe(false);
|
178
|
+
});
|
179
|
+
});
|
180
|
+
|
181
|
+
describe('isPgliteInited', () => {
|
182
|
+
it('should return true when pglite is enabled and ready', () => {
|
183
|
+
const s: GlobalState = {
|
184
|
+
...initialState,
|
185
|
+
isStatusInit: true,
|
186
|
+
status: {
|
187
|
+
...initialState.status,
|
188
|
+
isEnablePglite: true,
|
189
|
+
},
|
190
|
+
initClientDBStage: DatabaseLoadingState.Ready,
|
191
|
+
};
|
192
|
+
expect(systemStatusSelectors.isPgliteInited(s)).toBe(true);
|
193
|
+
});
|
194
|
+
|
195
|
+
it('should return false when not ready', () => {
|
196
|
+
const s: GlobalState = {
|
197
|
+
...initialState,
|
198
|
+
isStatusInit: true,
|
199
|
+
status: {
|
200
|
+
...initialState.status,
|
201
|
+
isEnablePglite: true,
|
202
|
+
},
|
203
|
+
initClientDBStage: DatabaseLoadingState.Initializing,
|
204
|
+
};
|
205
|
+
expect(systemStatusSelectors.isPgliteInited(s)).toBe(false);
|
206
|
+
});
|
207
|
+
});
|
208
|
+
});
|
209
|
+
});
|
@@ -1,38 +1,38 @@
|
|
1
1
|
import { isServerMode, isUsePgliteDB } from '@/const/version';
|
2
|
-
import { GlobalStore } from '@/store/global';
|
3
2
|
import { DatabaseLoadingState } from '@/types/clientDB';
|
4
3
|
|
5
4
|
import { GlobalState, INITIAL_STATUS } from '../initialState';
|
6
5
|
|
7
6
|
export const systemStatus = (s: GlobalState) => s.status;
|
8
7
|
|
9
|
-
const sessionGroupKeys = (s:
|
8
|
+
const sessionGroupKeys = (s: GlobalState): string[] =>
|
10
9
|
s.status.expandSessionGroupKeys || INITIAL_STATUS.expandSessionGroupKeys;
|
11
10
|
|
12
|
-
const showSystemRole = (s:
|
13
|
-
const mobileShowTopic = (s:
|
14
|
-
const mobileShowPortal = (s:
|
15
|
-
const showChatSideBar = (s:
|
16
|
-
const showSessionPanel = (s:
|
17
|
-
const showFilePanel = (s:
|
18
|
-
const hidePWAInstaller = (s:
|
19
|
-
const isShowCredit = (s:
|
11
|
+
const showSystemRole = (s: GlobalState) => s.status.showSystemRole;
|
12
|
+
const mobileShowTopic = (s: GlobalState) => s.status.mobileShowTopic;
|
13
|
+
const mobileShowPortal = (s: GlobalState) => s.status.mobileShowPortal;
|
14
|
+
const showChatSideBar = (s: GlobalState) => !s.status.zenMode && s.status.showChatSideBar;
|
15
|
+
const showSessionPanel = (s: GlobalState) => !s.status.zenMode && s.status.showSessionPanel;
|
16
|
+
const showFilePanel = (s: GlobalState) => s.status.showFilePanel;
|
17
|
+
const hidePWAInstaller = (s: GlobalState) => s.status.hidePWAInstaller;
|
18
|
+
const isShowCredit = (s: GlobalState) => s.status.isShowCredit;
|
19
|
+
const themeMode = (s: GlobalState) => s.status.themeMode || 'auto';
|
20
20
|
|
21
|
-
const showChatHeader = (s:
|
22
|
-
const inZenMode = (s:
|
23
|
-
const sessionWidth = (s:
|
24
|
-
const portalWidth = (s:
|
25
|
-
const filePanelWidth = (s:
|
26
|
-
const inputHeight = (s:
|
27
|
-
const threadInputHeight = (s:
|
21
|
+
const showChatHeader = (s: GlobalState) => !s.status.zenMode;
|
22
|
+
const inZenMode = (s: GlobalState) => s.status.zenMode;
|
23
|
+
const sessionWidth = (s: GlobalState) => s.status.sessionsWidth;
|
24
|
+
const portalWidth = (s: GlobalState) => s.status.portalWidth || 400;
|
25
|
+
const filePanelWidth = (s: GlobalState) => s.status.filePanelWidth;
|
26
|
+
const inputHeight = (s: GlobalState) => s.status.inputHeight;
|
27
|
+
const threadInputHeight = (s: GlobalState) => s.status.threadInputHeight;
|
28
28
|
|
29
|
-
const isPgliteNotEnabled = (s:
|
29
|
+
const isPgliteNotEnabled = (s: GlobalState) =>
|
30
30
|
isUsePgliteDB && !isServerMode && s.isStatusInit && !s.status.isEnablePglite;
|
31
31
|
|
32
32
|
/**
|
33
33
|
* 当且仅当 client db 模式,且 pglite 未初始化完成时返回 true
|
34
34
|
*/
|
35
|
-
const isPgliteNotInited = (s:
|
35
|
+
const isPgliteNotInited = (s: GlobalState) =>
|
36
36
|
isUsePgliteDB &&
|
37
37
|
s.isStatusInit &&
|
38
38
|
s.status.isEnablePglite &&
|
@@ -41,14 +41,14 @@ const isPgliteNotInited = (s: GlobalStore) =>
|
|
41
41
|
/**
|
42
42
|
* 当且仅当 client db 模式,且 pglite 初始化完成时返回 true
|
43
43
|
*/
|
44
|
-
const isPgliteInited = (s:
|
44
|
+
const isPgliteInited = (s: GlobalState): boolean =>
|
45
45
|
(s.isStatusInit &&
|
46
46
|
s.status.isEnablePglite &&
|
47
47
|
s.initClientDBStage === DatabaseLoadingState.Ready) ||
|
48
48
|
false;
|
49
49
|
|
50
50
|
// 这个变量控制 clientdb 是否完成初始化,正常来说,只有 pgliteDB 模式下,才会存在变化,其他时候都是 true
|
51
|
-
const isDBInited = (s:
|
51
|
+
const isDBInited = (s: GlobalState): boolean => (isUsePgliteDB ? isPgliteInited(s) : true);
|
52
52
|
|
53
53
|
export const systemStatusSelectors = {
|
54
54
|
filePanelWidth,
|
@@ -71,5 +71,6 @@ export const systemStatusSelectors = {
|
|
71
71
|
showSessionPanel,
|
72
72
|
showSystemRole,
|
73
73
|
systemStatus,
|
74
|
+
themeMode,
|
74
75
|
threadInputHeight,
|
75
76
|
};
|
@@ -70,7 +70,7 @@ describe('SettingsAction', () => {
|
|
70
70
|
describe('setSettings', () => {
|
71
71
|
it('should set partial settings', async () => {
|
72
72
|
const { result } = renderHook(() => useUserStore());
|
73
|
-
const partialSettings: DeepPartial<UserSettings> = { general: {
|
73
|
+
const partialSettings: DeepPartial<UserSettings> = { general: { fontSize: 12 } };
|
74
74
|
|
75
75
|
// Perform the action
|
76
76
|
await act(async () => {
|
@@ -85,24 +85,6 @@ describe('SettingsAction', () => {
|
|
85
85
|
});
|
86
86
|
});
|
87
87
|
|
88
|
-
describe('switchThemeMode', () => {
|
89
|
-
it('should switch theme mode', async () => {
|
90
|
-
const { result } = renderHook(() => useUserStore());
|
91
|
-
const themeMode = 'light';
|
92
|
-
|
93
|
-
// Perform the action
|
94
|
-
await act(async () => {
|
95
|
-
await result.current.switchThemeMode(themeMode);
|
96
|
-
});
|
97
|
-
|
98
|
-
// Assert that updateUserSettings was called with the correct theme mode
|
99
|
-
expect(userService.updateUserSettings).toHaveBeenCalledWith(
|
100
|
-
{ general: { themeMode } },
|
101
|
-
expect.any(AbortSignal),
|
102
|
-
);
|
103
|
-
});
|
104
|
-
});
|
105
|
-
|
106
88
|
describe('updateDefaultAgent', () => {
|
107
89
|
it('should update default agent settings', async () => {
|
108
90
|
const { result } = renderHook(() => useUserStore());
|
@@ -1,4 +1,3 @@
|
|
1
|
-
import { ThemeMode } from 'antd-style';
|
2
1
|
import isEqual from 'fast-deep-equal';
|
3
2
|
import { DeepPartial } from 'utility-types';
|
4
3
|
import type { StateCreator } from 'zustand/vanilla';
|
@@ -24,7 +23,6 @@ export interface UserSettingsAction {
|
|
24
23
|
internal_createSignal: () => AbortController;
|
25
24
|
resetSettings: () => Promise<void>;
|
26
25
|
setSettings: (settings: DeepPartial<UserSettings>) => Promise<void>;
|
27
|
-
switchThemeMode: (themeMode: ThemeMode) => Promise<void>;
|
28
26
|
updateDefaultAgent: (agent: DeepPartial<LobeAgentSettings>) => Promise<void>;
|
29
27
|
updateGeneralConfig: (settings: Partial<UserGeneralConfig>) => Promise<void>;
|
30
28
|
updateKeyVaults: (settings: Partial<UserKeyVaults>) => Promise<void>;
|
@@ -92,9 +90,6 @@ export const createSettingsSlice: StateCreator<
|
|
92
90
|
await userService.updateUserSettings(diffs, abortController.signal);
|
93
91
|
await get().refreshUserState();
|
94
92
|
},
|
95
|
-
switchThemeMode: async (themeMode) => {
|
96
|
-
await get().updateGeneralConfig({ themeMode });
|
97
|
-
},
|
98
93
|
updateDefaultAgent: async (defaultAgent) => {
|
99
94
|
await get().setSettings({ defaultAgent });
|
100
95
|
},
|
@@ -5,27 +5,17 @@ import { merge } from '@/utils/merge';
|
|
5
5
|
import { userGeneralSettingsSelectors } from './general';
|
6
6
|
|
7
7
|
describe('settingsSelectors', () => {
|
8
|
-
describe('
|
9
|
-
it('should return the
|
8
|
+
describe('fontSize', () => {
|
9
|
+
it('should return the fontSize', () => {
|
10
10
|
const s: UserState = merge(initialState, {
|
11
11
|
settings: {
|
12
|
-
general: {
|
12
|
+
general: { fontSize: 12 },
|
13
13
|
},
|
14
14
|
});
|
15
15
|
|
16
|
-
const result = userGeneralSettingsSelectors.
|
16
|
+
const result = userGeneralSettingsSelectors.fontSize(s as UserStore);
|
17
17
|
|
18
|
-
expect(result).toBe(
|
19
|
-
});
|
20
|
-
it('should return the auto if not set the themeMode', () => {
|
21
|
-
const s: UserState = merge(initialState, {
|
22
|
-
settings: {
|
23
|
-
general: { themeMode: undefined },
|
24
|
-
},
|
25
|
-
});
|
26
|
-
const result = userGeneralSettingsSelectors.currentThemeMode(s as UserStore);
|
27
|
-
|
28
|
-
expect(result).toBe('auto');
|
18
|
+
expect(result).toBe(12);
|
29
19
|
});
|
30
20
|
});
|
31
21
|
});
|
@@ -3,18 +3,12 @@ import { currentSettings } from './settings';
|
|
3
3
|
|
4
4
|
const generalConfig = (s: UserStore) => currentSettings(s).general || {};
|
5
5
|
|
6
|
-
const currentThemeMode = (s: UserStore) => {
|
7
|
-
const themeMode = generalConfig(s).themeMode;
|
8
|
-
return themeMode || 'auto';
|
9
|
-
};
|
10
|
-
|
11
6
|
const neutralColor = (s: UserStore) => generalConfig(s).neutralColor;
|
12
7
|
const primaryColor = (s: UserStore) => generalConfig(s).primaryColor;
|
13
8
|
const fontSize = (s: UserStore) => generalConfig(s).fontSize;
|
14
9
|
|
15
10
|
export const userGeneralSettingsSelectors = {
|
16
11
|
config: generalConfig,
|
17
|
-
currentThemeMode,
|
18
12
|
fontSize,
|
19
13
|
neutralColor,
|
20
14
|
primaryColor,
|
@@ -1,9 +1,7 @@
|
|
1
1
|
import type { NeutralColors, PrimaryColors } from '@lobehub/ui';
|
2
|
-
import type { ThemeMode } from 'antd-style';
|
3
2
|
|
4
3
|
export interface UserGeneralConfig {
|
5
4
|
fontSize: number;
|
6
5
|
neutralColor?: NeutralColors;
|
7
6
|
primaryColor?: PrimaryColors;
|
8
|
-
themeMode: ThemeMode;
|
9
7
|
}
|