@lobehub/chat 1.86.1 → 1.87.0
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 +33 -0
- package/changelog/v1.json +12 -0
- package/locales/ar/setting.json +43 -31
- package/locales/bg-BG/setting.json +43 -31
- package/locales/de-DE/setting.json +43 -31
- package/locales/en-US/setting.json +43 -31
- package/locales/es-ES/setting.json +43 -31
- package/locales/fa-IR/setting.json +43 -31
- package/locales/fr-FR/setting.json +43 -31
- package/locales/it-IT/setting.json +43 -31
- package/locales/ja-JP/setting.json +43 -31
- package/locales/ko-KR/setting.json +43 -31
- package/locales/nl-NL/setting.json +43 -31
- package/locales/pl-PL/setting.json +43 -31
- package/locales/pt-BR/setting.json +43 -31
- package/locales/ru-RU/setting.json +43 -31
- package/locales/tr-TR/setting.json +43 -31
- package/locales/vi-VN/setting.json +43 -31
- package/locales/zh-CN/setting.json +43 -31
- package/locales/zh-TW/setting.json +43 -31
- package/package.json +3 -3
- package/src/app/[variants]/(main)/chat/(workspace)/@conversation/features/ChatList/WelcomeChatItem/WelcomeMessage.tsx +1 -1
- package/src/app/[variants]/(main)/settings/agent/index.tsx +8 -2
- package/src/app/[variants]/(main)/settings/common/features/Appearance/Preview.tsx +298 -0
- package/src/app/[variants]/(main)/settings/common/features/{Theme → Appearance}/ThemeSwatches/ThemeSwatchesNeutral.tsx +6 -11
- package/src/app/[variants]/(main)/settings/common/features/{Theme → Appearance}/ThemeSwatches/ThemeSwatchesPrimary.tsx +6 -10
- package/src/app/[variants]/(main)/settings/common/features/Appearance/index.tsx +67 -0
- package/src/app/[variants]/(main)/settings/common/features/ChatAppearance/ChatPreview.tsx +35 -0
- package/src/app/[variants]/(main)/settings/common/features/ChatAppearance/HighlighterPreview.tsx +55 -0
- package/src/app/[variants]/(main)/settings/common/features/ChatAppearance/MermaidPreview.tsx +51 -0
- package/src/app/[variants]/(main)/settings/common/features/ChatAppearance/index.tsx +128 -0
- package/src/app/[variants]/(main)/settings/common/features/Common.tsx +74 -42
- package/src/app/[variants]/(main)/settings/common/index.tsx +4 -2
- package/src/app/[variants]/(main)/settings/hotkey/features/{HotkeySetting.tsx → Conversation.tsx} +19 -18
- package/src/app/[variants]/(main)/settings/hotkey/features/Essential.tsx +88 -0
- package/src/app/[variants]/(main)/settings/hotkey/page.tsx +8 -2
- package/src/app/[variants]/(main)/settings/llm/components/ProviderModelList/ModelConfigModal/index.tsx +1 -1
- package/src/app/[variants]/(main)/settings/storage/Advanced.tsx +26 -0
- package/src/app/[variants]/(main)/settings/system-agent/features/createForm.tsx +37 -22
- package/src/app/[variants]/(main)/settings/tts/features/OpenAI.tsx +20 -10
- package/src/app/[variants]/(main)/settings/tts/features/STT.tsx +20 -11
- package/src/const/settings/common.ts +2 -0
- package/src/features/AgentSetting/AgentTTS/index.tsx +1 -1
- package/src/features/ChatItem/index.tsx +35 -0
- package/src/features/Conversation/components/ChatItem/index.tsx +2 -6
- package/src/features/User/UserPanel/LangButton.tsx +1 -1
- package/src/features/User/UserPanel/ThemeButton.tsx +3 -3
- package/src/libs/model-runtime/{AgentRuntime.test.ts → ModelRuntime.test.ts} +1 -1
- package/src/libs/model-runtime/{AgentRuntime.ts → ModelRuntime.ts} +3 -3
- package/src/libs/model-runtime/index.ts +1 -1
- package/src/libs/oidc-provider/config.ts +1 -1
- package/src/locales/default/setting.ts +45 -31
- package/src/store/electron/initialState.ts +1 -1
- package/src/store/electron/selectors/__tests__/desktopState.test.ts +55 -0
- package/src/store/global/selectors/systemStatus.ts +2 -0
- package/src/store/user/slices/settings/selectors/general.test.ts +29 -1
- package/src/store/user/slices/settings/selectors/general.ts +4 -0
- package/src/types/user/settings/general.ts +3 -1
- package/src/app/[variants]/(main)/settings/common/features/Theme/index.tsx +0 -146
- /package/src/app/[variants]/(main)/settings/common/features/{Theme → Appearance}/ThemeSwatches/index.ts +0 -0
@@ -0,0 +1,35 @@
|
|
1
|
+
'use client';
|
2
|
+
|
3
|
+
import { ChatItemProps, ChatItem as ChatItemRaw } from '@lobehub/ui/chat';
|
4
|
+
import isEqual from 'fast-deep-equal';
|
5
|
+
import { memo } from 'react';
|
6
|
+
|
7
|
+
import { useUserStore } from '@/store/user';
|
8
|
+
import { settingsSelectors } from '@/store/user/selectors';
|
9
|
+
|
10
|
+
const ChatItem = memo<ChatItemProps>(({ markdownProps = {}, ...rest }) => {
|
11
|
+
const { componentProps, ...restMarkdown } = markdownProps;
|
12
|
+
const { general } = useUserStore(settingsSelectors.currentSettings, isEqual);
|
13
|
+
return (
|
14
|
+
<ChatItemRaw
|
15
|
+
fontSize={general.fontSize}
|
16
|
+
markdownProps={{
|
17
|
+
...restMarkdown,
|
18
|
+
componentProps: {
|
19
|
+
...componentProps,
|
20
|
+
highlight: {
|
21
|
+
theme: general.highlighterTheme,
|
22
|
+
...componentProps?.highlight,
|
23
|
+
},
|
24
|
+
mermaid: {
|
25
|
+
theme: general.mermaidTheme,
|
26
|
+
...componentProps?.mermaid,
|
27
|
+
},
|
28
|
+
},
|
29
|
+
}}
|
30
|
+
{...rest}
|
31
|
+
/>
|
32
|
+
);
|
33
|
+
});
|
34
|
+
|
35
|
+
export default ChatItem;
|
@@ -1,19 +1,17 @@
|
|
1
1
|
'use client';
|
2
2
|
|
3
|
-
import { ChatItem } from '@lobehub/ui/chat';
|
4
3
|
import { createStyles } from 'antd-style';
|
5
4
|
import isEqual from 'fast-deep-equal';
|
6
5
|
import { MouseEventHandler, ReactNode, memo, use, useCallback, useMemo } from 'react';
|
7
6
|
import { useTranslation } from 'react-i18next';
|
8
7
|
import { Flexbox } from 'react-layout-kit';
|
9
8
|
|
9
|
+
import ChatItem from '@/features/ChatItem';
|
10
10
|
import { VirtuosoContext } from '@/features/Conversation/components/VirtualizedList/VirtuosoContext';
|
11
11
|
import { useAgentStore } from '@/store/agent';
|
12
12
|
import { agentChatConfigSelectors } from '@/store/agent/selectors';
|
13
13
|
import { useChatStore } from '@/store/chat';
|
14
14
|
import { chatSelectors } from '@/store/chat/selectors';
|
15
|
-
import { useUserStore } from '@/store/user';
|
16
|
-
import { userGeneralSettingsSelectors } from '@/store/user/selectors';
|
17
15
|
import { ChatMessage } from '@/types/message';
|
18
16
|
|
19
17
|
import ErrorMessageExtra, { useErrorContent } from '../../Error';
|
@@ -72,7 +70,6 @@ const Item = memo<ChatListItemProps>(
|
|
72
70
|
|
73
71
|
const type = useAgentStore(agentChatConfigSelectors.displayMode);
|
74
72
|
const item = useChatStore(chatSelectors.getMessageById(id), isEqual);
|
75
|
-
const fontSize = useUserStore(userGeneralSettingsSelectors.fontSize);
|
76
73
|
|
77
74
|
const [
|
78
75
|
isMessageLoading,
|
@@ -178,7 +175,7 @@ const Item = memo<ChatListItemProps>(
|
|
178
175
|
enableCustomFootnotes: item?.role === 'assistant',
|
179
176
|
rehypePlugins: item?.role === 'user' ? undefined : rehypePlugins,
|
180
177
|
remarkPlugins: item?.role === 'user' ? undefined : remarkPlugins,
|
181
|
-
|
178
|
+
showFootnotes:
|
182
179
|
item?.role === 'user'
|
183
180
|
? undefined
|
184
181
|
: item?.search?.citations &&
|
@@ -235,7 +232,6 @@ const Item = memo<ChatListItemProps>(
|
|
235
232
|
editing={editing}
|
236
233
|
error={error}
|
237
234
|
errorMessage={errorMessage}
|
238
|
-
fontSize={fontSize}
|
239
235
|
loading={isProcessing}
|
240
236
|
markdownProps={markdownProps}
|
241
237
|
message={message}
|
@@ -26,7 +26,7 @@ const LangButton = memo<{ placement?: PopoverProps['placement'] }>(({ placement
|
|
26
26
|
() => [
|
27
27
|
{
|
28
28
|
key: 'auto',
|
29
|
-
label: t('
|
29
|
+
label: t('settingCommon.lang.autoMode'),
|
30
30
|
onClick: () => handleLangChange('auto'),
|
31
31
|
},
|
32
32
|
...localeOptions.map((item) => ({
|
@@ -27,19 +27,19 @@ const ThemeButton = memo<{ placement?: PopoverProps['placement'] }>(({ placement
|
|
27
27
|
{
|
28
28
|
icon: <Icon icon={themeIcons.auto} />,
|
29
29
|
key: 'auto',
|
30
|
-
label: t('
|
30
|
+
label: t('settingCommon.themeMode.auto'),
|
31
31
|
onClick: () => switchThemeMode('auto'),
|
32
32
|
},
|
33
33
|
{
|
34
34
|
icon: <Icon icon={themeIcons.light} />,
|
35
35
|
key: 'light',
|
36
|
-
label: t('
|
36
|
+
label: t('settingCommon.themeMode.light'),
|
37
37
|
onClick: () => switchThemeMode('light'),
|
38
38
|
},
|
39
39
|
{
|
40
40
|
icon: <Icon icon={themeIcons.dark} />,
|
41
41
|
key: 'dark',
|
42
|
-
label: t('
|
42
|
+
label: t('settingCommon.themeMode.dark'),
|
43
43
|
onClick: () => switchThemeMode('dark'),
|
44
44
|
},
|
45
45
|
],
|
@@ -10,7 +10,7 @@ import { AgentRuntime, ChatStreamPayload, LobeOpenAI, ModelProvider } from '@/li
|
|
10
10
|
import { providerRuntimeMap } from '@/libs/model-runtime/runtimeMap';
|
11
11
|
import { createTraceOptions } from '@/server/modules/AgentRuntime';
|
12
12
|
|
13
|
-
import { AgentChatOptions } from './
|
13
|
+
import { AgentChatOptions } from './ModelRuntime';
|
14
14
|
|
15
15
|
const specialProviders = [
|
16
16
|
{ id: 'openai', payload: { apiKey: 'user-openai-key', baseURL: 'user-endpoint' } },
|
@@ -24,7 +24,7 @@ export interface AgentChatOptions {
|
|
24
24
|
trace?: TracePayload;
|
25
25
|
}
|
26
26
|
|
27
|
-
class
|
27
|
+
class ModelRuntime {
|
28
28
|
private _runtime: LobeRuntimeAI;
|
29
29
|
|
30
30
|
constructor(runtime: LobeRuntimeAI) {
|
@@ -110,8 +110,8 @@ class AgentRuntime {
|
|
110
110
|
const providerAI = providerRuntimeMap[provider] ?? LobeOpenAI;
|
111
111
|
const runtimeModel: LobeRuntimeAI = new providerAI(params);
|
112
112
|
|
113
|
-
return new
|
113
|
+
return new ModelRuntime(runtimeModel);
|
114
114
|
}
|
115
115
|
}
|
116
116
|
|
117
|
-
export default
|
117
|
+
export default ModelRuntime;
|
@@ -1,4 +1,3 @@
|
|
1
|
-
export { default as AgentRuntime } from './AgentRuntime';
|
2
1
|
export { LobeAnthropicAI } from './anthropic';
|
3
2
|
export { LobeAzureAI } from './azureai';
|
4
3
|
export { LobeAzureOpenAI } from './azureOpenai';
|
@@ -11,6 +10,7 @@ export { LobeGroq } from './groq';
|
|
11
10
|
export * from './helpers';
|
12
11
|
export { LobeMinimaxAI } from './minimax';
|
13
12
|
export { LobeMistralAI } from './mistral';
|
13
|
+
export { default as AgentRuntime } from './ModelRuntime';
|
14
14
|
export { LobeMoonshotAI } from './moonshot';
|
15
15
|
export { LobeOllamaAI } from './ollama';
|
16
16
|
export { LobeOpenAI } from './openai';
|
@@ -25,7 +25,7 @@ export const defaultClients: ClientMetadata[] = [
|
|
25
25
|
'com.lobehub.lobehub-desktop-dev://auth/callback',
|
26
26
|
'com.lobehub.lobehub-desktop-nightly://auth/callback',
|
27
27
|
'com.lobehub.lobehub-desktop-beta://auth/callback',
|
28
|
-
'com.lobehub.lobehub-desktop://auth/
|
28
|
+
'com.lobehub.lobehub-desktop://auth/callback',
|
29
29
|
],
|
30
30
|
|
31
31
|
// 支持授权码获取令牌和刷新令牌
|
@@ -172,6 +172,22 @@ export default {
|
|
172
172
|
},
|
173
173
|
title: '助手信息',
|
174
174
|
},
|
175
|
+
|
176
|
+
settingAppearance: {
|
177
|
+
neutralColor: {
|
178
|
+
desc: '不同色彩倾向的灰阶自定义',
|
179
|
+
title: '中性色',
|
180
|
+
},
|
181
|
+
preview: {
|
182
|
+
title: '调色盘',
|
183
|
+
},
|
184
|
+
primaryColor: {
|
185
|
+
desc: '自定义主题色',
|
186
|
+
title: '主题色',
|
187
|
+
},
|
188
|
+
title: '应用外观',
|
189
|
+
},
|
190
|
+
|
175
191
|
settingChat: {
|
176
192
|
autoCreateTopicThreshold: {
|
177
193
|
desc: '当前消息数超过设定该值后,将自动创建话题',
|
@@ -214,6 +230,35 @@ export default {
|
|
214
230
|
submit: '更新聊天偏好',
|
215
231
|
title: '聊天设置',
|
216
232
|
},
|
233
|
+
settingChatAppearance: {
|
234
|
+
fontSize: {
|
235
|
+
desc: '聊天内容的字体大小',
|
236
|
+
marks: {
|
237
|
+
normal: '标准',
|
238
|
+
},
|
239
|
+
title: '字体大小',
|
240
|
+
},
|
241
|
+
highlighterTheme: {
|
242
|
+
title: '代码高亮主题',
|
243
|
+
},
|
244
|
+
mermaidTheme: {
|
245
|
+
title: 'Mermaid 主题',
|
246
|
+
},
|
247
|
+
title: '聊天外观',
|
248
|
+
},
|
249
|
+
settingCommon: {
|
250
|
+
lang: {
|
251
|
+
autoMode: '跟随系统',
|
252
|
+
title: '语言',
|
253
|
+
},
|
254
|
+
themeMode: {
|
255
|
+
auto: '自动',
|
256
|
+
dark: '深色',
|
257
|
+
light: '浅色',
|
258
|
+
title: '主题',
|
259
|
+
},
|
260
|
+
title: '通用设置',
|
261
|
+
},
|
217
262
|
settingModel: {
|
218
263
|
enableMaxTokens: {
|
219
264
|
title: '开启单次回复限制',
|
@@ -339,37 +384,6 @@ export default {
|
|
339
384
|
title: '语音合成声源',
|
340
385
|
},
|
341
386
|
},
|
342
|
-
settingTheme: {
|
343
|
-
avatar: {
|
344
|
-
title: '头像',
|
345
|
-
},
|
346
|
-
fontSize: {
|
347
|
-
desc: '聊天内容的字体大小',
|
348
|
-
marks: {
|
349
|
-
normal: '标准',
|
350
|
-
},
|
351
|
-
title: '字体大小',
|
352
|
-
},
|
353
|
-
lang: {
|
354
|
-
autoMode: '跟随系统',
|
355
|
-
title: '语言',
|
356
|
-
},
|
357
|
-
neutralColor: {
|
358
|
-
desc: '不同色彩倾向的灰阶自定义',
|
359
|
-
title: '中性色',
|
360
|
-
},
|
361
|
-
primaryColor: {
|
362
|
-
desc: '自定义主题色',
|
363
|
-
title: '主题色',
|
364
|
-
},
|
365
|
-
themeMode: {
|
366
|
-
auto: '自动',
|
367
|
-
dark: '深色',
|
368
|
-
light: '浅色',
|
369
|
-
title: '主题',
|
370
|
-
},
|
371
|
-
title: '主题设置',
|
372
|
-
},
|
373
387
|
storage: {
|
374
388
|
actions: {
|
375
389
|
export: {
|
@@ -5,7 +5,7 @@ export type RemoteServerError = 'CONFIG_ERROR' | 'AUTH_ERROR' | 'DISCONNECT_ERRO
|
|
5
5
|
export interface ElectronState {
|
6
6
|
appState: ElectronAppState;
|
7
7
|
dataSyncConfig: DataSyncConfig;
|
8
|
-
isAppStateInit
|
8
|
+
isAppStateInit?: boolean;
|
9
9
|
isConnectingServer?: boolean;
|
10
10
|
isInitRemoteServerConfig: boolean;
|
11
11
|
isSyncActive?: boolean;
|
@@ -0,0 +1,55 @@
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
2
|
+
|
3
|
+
import { ElectronState } from '@/store/electron/initialState';
|
4
|
+
|
5
|
+
import { desktopStateSelectors } from '../desktopState';
|
6
|
+
|
7
|
+
describe('desktopStateSelectors', () => {
|
8
|
+
describe('usePath', () => {
|
9
|
+
it('should return userPath from appState', () => {
|
10
|
+
const state: ElectronState = {
|
11
|
+
isAppStateInit: false,
|
12
|
+
appState: {
|
13
|
+
userPath: {
|
14
|
+
desktop: '/test/desktop',
|
15
|
+
documents: '/test/documents',
|
16
|
+
downloads: '/test/downloads',
|
17
|
+
home: '/test/home',
|
18
|
+
music: '/test/music',
|
19
|
+
pictures: '/test/pictures',
|
20
|
+
userData: '/test/userdata',
|
21
|
+
videos: '/test/videos',
|
22
|
+
},
|
23
|
+
},
|
24
|
+
dataSyncConfig: {
|
25
|
+
storageMode: 'local',
|
26
|
+
},
|
27
|
+
isInitRemoteServerConfig: false,
|
28
|
+
};
|
29
|
+
|
30
|
+
expect(desktopStateSelectors.usePath(state)).toEqual({
|
31
|
+
desktop: '/test/desktop',
|
32
|
+
documents: '/test/documents',
|
33
|
+
downloads: '/test/downloads',
|
34
|
+
home: '/test/home',
|
35
|
+
music: '/test/music',
|
36
|
+
pictures: '/test/pictures',
|
37
|
+
userData: '/test/userdata',
|
38
|
+
videos: '/test/videos',
|
39
|
+
});
|
40
|
+
});
|
41
|
+
|
42
|
+
it('should handle undefined userPath', () => {
|
43
|
+
const state: ElectronState = {
|
44
|
+
appState: {},
|
45
|
+
isAppStateInit: false,
|
46
|
+
dataSyncConfig: {
|
47
|
+
storageMode: 'local',
|
48
|
+
},
|
49
|
+
isInitRemoteServerConfig: false,
|
50
|
+
};
|
51
|
+
|
52
|
+
expect(desktopStateSelectors.usePath(state)).toBeUndefined();
|
53
|
+
});
|
54
|
+
});
|
55
|
+
});
|
@@ -17,6 +17,7 @@ const showFilePanel = (s: GlobalState) => s.status.showFilePanel;
|
|
17
17
|
const hidePWAInstaller = (s: GlobalState) => s.status.hidePWAInstaller;
|
18
18
|
const isShowCredit = (s: GlobalState) => s.status.isShowCredit;
|
19
19
|
const themeMode = (s: GlobalState) => s.status.themeMode || 'auto';
|
20
|
+
const language = (s: GlobalState) => s.status.language || 'auto';
|
20
21
|
|
21
22
|
const showChatHeader = (s: GlobalState) => !s.status.zenMode;
|
22
23
|
const inZenMode = (s: GlobalState) => s.status.zenMode;
|
@@ -68,6 +69,7 @@ export const systemStatusSelectors = {
|
|
68
69
|
isPgliteNotEnabled,
|
69
70
|
isPgliteNotInited,
|
70
71
|
isShowCredit,
|
72
|
+
language,
|
71
73
|
mobileShowPortal,
|
72
74
|
mobileShowTopic,
|
73
75
|
portalWidth,
|
@@ -15,7 +15,11 @@ describe('settingsSelectors', () => {
|
|
15
15
|
|
16
16
|
const result = userGeneralSettingsSelectors.config(s as UserStore);
|
17
17
|
|
18
|
-
expect(result).toEqual({
|
18
|
+
expect(result).toEqual({
|
19
|
+
fontSize: 12,
|
20
|
+
highlighterTheme: 'lobe-theme',
|
21
|
+
mermaidTheme: 'lobe-theme',
|
22
|
+
});
|
19
23
|
});
|
20
24
|
});
|
21
25
|
|
@@ -108,4 +112,28 @@ describe('settingsSelectors', () => {
|
|
108
112
|
expect(result).toBe('#ffffff');
|
109
113
|
});
|
110
114
|
});
|
115
|
+
|
116
|
+
it('should return the highlighterTheme', () => {
|
117
|
+
const s: UserState = merge(initialState, {
|
118
|
+
settings: {
|
119
|
+
general: { highlighterTheme: 'lobe-theme' },
|
120
|
+
},
|
121
|
+
});
|
122
|
+
|
123
|
+
const result = userGeneralSettingsSelectors.highlighterTheme(s as UserStore);
|
124
|
+
|
125
|
+
expect(result).toBe('lobe-theme');
|
126
|
+
});
|
127
|
+
|
128
|
+
it('should return the mermaidTheme', () => {
|
129
|
+
const s: UserState = merge(initialState, {
|
130
|
+
settings: {
|
131
|
+
general: { mermaidTheme: 'lobe-theme' },
|
132
|
+
},
|
133
|
+
});
|
134
|
+
|
135
|
+
const result = userGeneralSettingsSelectors.mermaidTheme(s as UserStore);
|
136
|
+
|
137
|
+
expect(result).toBe('lobe-theme');
|
138
|
+
});
|
111
139
|
});
|
@@ -6,10 +6,14 @@ const generalConfig = (s: UserStore) => currentSettings(s).general || {};
|
|
6
6
|
const neutralColor = (s: UserStore) => generalConfig(s).neutralColor;
|
7
7
|
const primaryColor = (s: UserStore) => generalConfig(s).primaryColor;
|
8
8
|
const fontSize = (s: UserStore) => generalConfig(s).fontSize;
|
9
|
+
const highlighterTheme = (s: UserStore) => generalConfig(s).highlighterTheme;
|
10
|
+
const mermaidTheme = (s: UserStore) => generalConfig(s).mermaidTheme;
|
9
11
|
|
10
12
|
export const userGeneralSettingsSelectors = {
|
11
13
|
config: generalConfig,
|
12
14
|
fontSize,
|
15
|
+
highlighterTheme,
|
16
|
+
mermaidTheme,
|
13
17
|
neutralColor,
|
14
18
|
primaryColor,
|
15
19
|
};
|
@@ -1,7 +1,9 @@
|
|
1
|
-
import type { NeutralColors, PrimaryColors } from '@lobehub/ui';
|
1
|
+
import type { HighlighterProps, MermaidProps, NeutralColors, PrimaryColors } from '@lobehub/ui';
|
2
2
|
|
3
3
|
export interface UserGeneralConfig {
|
4
4
|
fontSize: number;
|
5
|
+
highlighterTheme?: HighlighterProps['theme'];
|
6
|
+
mermaidTheme?: MermaidProps['theme'];
|
5
7
|
neutralColor?: NeutralColors;
|
6
8
|
primaryColor?: PrimaryColors;
|
7
9
|
}
|
@@ -1,146 +0,0 @@
|
|
1
|
-
'use client';
|
2
|
-
|
3
|
-
import { Form, type FormGroupItemType, ImageSelect, SliderWithInput } from '@lobehub/ui';
|
4
|
-
import { Select } from '@lobehub/ui';
|
5
|
-
import isEqual from 'fast-deep-equal';
|
6
|
-
import { Monitor, Moon, Sun } from 'lucide-react';
|
7
|
-
import { memo } from 'react';
|
8
|
-
import { useTranslation } from 'react-i18next';
|
9
|
-
|
10
|
-
import { useSyncSettings } from '@/app/[variants]/(main)/settings/hooks/useSyncSettings';
|
11
|
-
import { FORM_STYLE } from '@/const/layoutTokens';
|
12
|
-
import { imageUrl } from '@/const/url';
|
13
|
-
import { Locales, localeOptions } from '@/locales/resources';
|
14
|
-
import { useGlobalStore } from '@/store/global';
|
15
|
-
import { systemStatusSelectors } from '@/store/global/selectors';
|
16
|
-
import { useUserStore } from '@/store/user';
|
17
|
-
import { settingsSelectors } from '@/store/user/selectors';
|
18
|
-
|
19
|
-
import { ThemeSwatchesNeutral, ThemeSwatchesPrimary } from './ThemeSwatches';
|
20
|
-
|
21
|
-
const Theme = memo(() => {
|
22
|
-
const { t } = useTranslation('setting');
|
23
|
-
|
24
|
-
const [form] = Form.useForm();
|
25
|
-
const settings = useUserStore(settingsSelectors.currentSettings, isEqual);
|
26
|
-
const themeMode = useGlobalStore(systemStatusSelectors.themeMode);
|
27
|
-
const [setSettings] = useUserStore((s) => [s.setSettings]);
|
28
|
-
const [setThemeMode] = useGlobalStore((s) => [s.switchThemeMode]);
|
29
|
-
|
30
|
-
useSyncSettings(form);
|
31
|
-
const [switchLocale] = useGlobalStore((s) => [s.switchLocale]);
|
32
|
-
|
33
|
-
const handleLangChange = (value: Locales) => {
|
34
|
-
switchLocale(value);
|
35
|
-
};
|
36
|
-
|
37
|
-
const theme: FormGroupItemType = {
|
38
|
-
children: [
|
39
|
-
{
|
40
|
-
children: (
|
41
|
-
<ImageSelect
|
42
|
-
height={60}
|
43
|
-
onChange={setThemeMode}
|
44
|
-
options={[
|
45
|
-
{
|
46
|
-
icon: Sun,
|
47
|
-
img: imageUrl('theme_light.webp'),
|
48
|
-
label: t('settingTheme.themeMode.light'),
|
49
|
-
value: 'light',
|
50
|
-
},
|
51
|
-
{
|
52
|
-
icon: Moon,
|
53
|
-
img: imageUrl('theme_dark.webp'),
|
54
|
-
label: t('settingTheme.themeMode.dark'),
|
55
|
-
value: 'dark',
|
56
|
-
},
|
57
|
-
{
|
58
|
-
icon: Monitor,
|
59
|
-
img: imageUrl('theme_auto.webp'),
|
60
|
-
label: t('settingTheme.themeMode.auto'),
|
61
|
-
value: 'auto',
|
62
|
-
},
|
63
|
-
]}
|
64
|
-
unoptimized={false}
|
65
|
-
value={themeMode}
|
66
|
-
width={100}
|
67
|
-
/>
|
68
|
-
),
|
69
|
-
label: t('settingTheme.themeMode.title'),
|
70
|
-
minWidth: undefined,
|
71
|
-
},
|
72
|
-
{
|
73
|
-
children: (
|
74
|
-
<Select
|
75
|
-
onChange={handleLangChange}
|
76
|
-
options={[{ label: t('settingTheme.lang.autoMode'), value: 'auto' }, ...localeOptions]}
|
77
|
-
/>
|
78
|
-
),
|
79
|
-
label: t('settingTheme.lang.title'),
|
80
|
-
name: ['general', 'language'],
|
81
|
-
},
|
82
|
-
{
|
83
|
-
children: (
|
84
|
-
<SliderWithInput
|
85
|
-
marks={{
|
86
|
-
12: {
|
87
|
-
label: 'A',
|
88
|
-
style: {
|
89
|
-
fontSize: 12,
|
90
|
-
marginTop: 4,
|
91
|
-
},
|
92
|
-
},
|
93
|
-
14: {
|
94
|
-
label: t('settingTheme.fontSize.marks.normal'),
|
95
|
-
style: {
|
96
|
-
fontSize: 14,
|
97
|
-
marginTop: 4,
|
98
|
-
},
|
99
|
-
},
|
100
|
-
18: {
|
101
|
-
label: 'A',
|
102
|
-
style: {
|
103
|
-
fontSize: 18,
|
104
|
-
marginTop: 4,
|
105
|
-
},
|
106
|
-
},
|
107
|
-
}}
|
108
|
-
max={18}
|
109
|
-
min={12}
|
110
|
-
step={1}
|
111
|
-
/>
|
112
|
-
),
|
113
|
-
desc: t('settingTheme.fontSize.desc'),
|
114
|
-
label: t('settingTheme.fontSize.title'),
|
115
|
-
name: ['general', 'fontSize'],
|
116
|
-
},
|
117
|
-
{
|
118
|
-
children: <ThemeSwatchesPrimary />,
|
119
|
-
desc: t('settingTheme.primaryColor.desc'),
|
120
|
-
label: t('settingTheme.primaryColor.title'),
|
121
|
-
minWidth: undefined,
|
122
|
-
},
|
123
|
-
{
|
124
|
-
children: <ThemeSwatchesNeutral />,
|
125
|
-
desc: t('settingTheme.neutralColor.desc'),
|
126
|
-
label: t('settingTheme.neutralColor.title'),
|
127
|
-
minWidth: undefined,
|
128
|
-
},
|
129
|
-
],
|
130
|
-
title: t('settingTheme.title'),
|
131
|
-
};
|
132
|
-
|
133
|
-
return (
|
134
|
-
<Form
|
135
|
-
form={form}
|
136
|
-
initialValues={settings}
|
137
|
-
items={[theme]}
|
138
|
-
itemsType={'group'}
|
139
|
-
onValuesChange={setSettings}
|
140
|
-
variant={'borderless'}
|
141
|
-
{...FORM_STYLE}
|
142
|
-
/>
|
143
|
-
);
|
144
|
-
});
|
145
|
-
|
146
|
-
export default Theme;
|
File without changes
|