@lobehub/chat 0.152.0 → 0.152.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (255) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +8 -8
  3. package/README.zh-CN.md +8 -8
  4. package/locales/ar/common.json +14 -0
  5. package/locales/ar/setting.json +4 -1
  6. package/locales/bg-BG/common.json +14 -0
  7. package/locales/bg-BG/setting.json +4 -1
  8. package/locales/de-DE/common.json +14 -0
  9. package/locales/de-DE/setting.json +4 -1
  10. package/locales/en-US/common.json +14 -0
  11. package/locales/en-US/setting.json +4 -1
  12. package/locales/es-ES/common.json +14 -0
  13. package/locales/es-ES/setting.json +4 -1
  14. package/locales/fr-FR/common.json +14 -0
  15. package/locales/fr-FR/setting.json +4 -1
  16. package/locales/it-IT/common.json +14 -0
  17. package/locales/it-IT/setting.json +4 -1
  18. package/locales/ja-JP/common.json +14 -0
  19. package/locales/ja-JP/setting.json +4 -1
  20. package/locales/ko-KR/common.json +14 -0
  21. package/locales/ko-KR/setting.json +4 -1
  22. package/locales/nl-NL/common.json +14 -0
  23. package/locales/nl-NL/setting.json +4 -1
  24. package/locales/pl-PL/common.json +14 -0
  25. package/locales/pl-PL/setting.json +4 -1
  26. package/locales/pt-BR/common.json +14 -0
  27. package/locales/pt-BR/setting.json +4 -1
  28. package/locales/ru-RU/common.json +14 -0
  29. package/locales/ru-RU/setting.json +4 -1
  30. package/locales/tr-TR/common.json +14 -0
  31. package/locales/tr-TR/setting.json +4 -1
  32. package/locales/vi-VN/common.json +14 -0
  33. package/locales/vi-VN/setting.json +4 -1
  34. package/locales/zh-CN/common.json +14 -0
  35. package/locales/zh-CN/setting.json +4 -1
  36. package/locales/zh-TW/common.json +14 -0
  37. package/locales/zh-TW/setting.json +4 -1
  38. package/package.json +1 -1
  39. package/src/app/(main)/(mobile)/me/features/AvatarBanner.tsx +52 -0
  40. package/src/app/(main)/(mobile)/me/features/Cate.tsx +34 -0
  41. package/src/app/(main)/(mobile)/me/features/ExtraCate.tsx +26 -0
  42. package/src/app/(main)/(mobile)/me/features/useExtraCate.tsx +68 -0
  43. package/src/app/(main)/(mobile)/me/layout.tsx +11 -0
  44. package/src/app/(main)/(mobile)/me/loading.tsx +17 -0
  45. package/src/app/(main)/(mobile)/me/page.tsx +31 -0
  46. package/src/app/(main)/@nav/_layout/Desktop/BottomActions.tsx +7 -120
  47. package/src/app/(main)/@nav/_layout/Desktop/index.tsx +7 -2
  48. package/src/app/(main)/@nav/_layout/Mobile.tsx +3 -3
  49. package/src/app/(main)/@nav/features/UserAvatar.tsx +24 -0
  50. package/src/app/(main)/@nav/features/UserPanel/LangButton.tsx +55 -0
  51. package/src/app/(main)/@nav/features/UserPanel/Popover.tsx +34 -0
  52. package/src/app/(main)/@nav/features/UserPanel/ThemeButton.tsx +70 -0
  53. package/src/app/(main)/@nav/features/UserPanel/UserInfo.tsx +35 -0
  54. package/src/app/(main)/@nav/features/UserPanel/index.tsx +69 -0
  55. package/src/app/(main)/@nav/features/UserPanel/useMenu.tsx +144 -0
  56. package/src/app/(main)/@nav/features/UserPanel/useNewVersion.tsx +12 -0
  57. package/src/app/(main)/chat/(mobile)/features/SessionHeader.tsx +1 -1
  58. package/src/app/(main)/chat/_layout/Desktop/index.tsx +6 -8
  59. package/src/app/(main)/chat/_layout/Mobile/index.tsx +5 -3
  60. package/src/app/(main)/chat/_layout/type.ts +5 -0
  61. package/src/app/(main)/chat/features/SettingButton.tsx +5 -2
  62. package/src/app/(main)/chat/layout.ts +5 -2
  63. package/src/app/(main)/chat/settings/{(desktop) → _layout/Desktop}/Header.tsx +2 -0
  64. package/src/app/(main)/chat/settings/_layout/Desktop/index.tsx +32 -0
  65. package/src/app/(main)/chat/settings/{(mobile) → _layout/Mobile}/Header.tsx +3 -2
  66. package/src/app/(main)/chat/settings/_layout/Mobile/index.tsx +15 -0
  67. package/src/app/(main)/chat/settings/error.tsx +5 -0
  68. package/src/app/(main)/chat/settings/features/HeaderContent.tsx +15 -9
  69. package/src/app/(main)/chat/settings/features/SubmitAgentButton/SubmitAgentModal.tsx +2 -0
  70. package/src/app/(main)/chat/settings/features/SubmitAgentButton/index.tsx +16 -8
  71. package/src/app/(main)/chat/settings/layout.tsx +9 -2
  72. package/src/app/(main)/chat/settings/loading.tsx +3 -0
  73. package/src/app/(main)/chat/settings/not-found.tsx +3 -0
  74. package/src/app/(main)/chat/settings/page.tsx +2 -9
  75. package/src/app/(main)/market/@detail/default.tsx +12 -0
  76. package/src/app/(main)/market/{features/AgentDetailContent/AgentInfo → @detail/features/AgentDetailContent}/Header.tsx +30 -21
  77. package/src/app/(main)/market/{features/AgentDetailContent/AgentInfo → @detail/features/AgentDetailContent}/index.tsx +10 -4
  78. package/src/app/(main)/market/{features/AgentDetailContent/AgentInfo → @detail/features/AgentDetailContent}/style.ts +7 -11
  79. package/src/app/(main)/market/@detail/loading.tsx +1 -0
  80. package/src/app/(main)/market/_layout/Desktop/{AgentDetail.tsx → DetailSidebar.tsx} +17 -12
  81. package/src/app/(main)/market/_layout/Desktop/Header.tsx +3 -6
  82. package/src/app/(main)/market/_layout/Desktop/Hero.tsx +39 -0
  83. package/src/app/(main)/market/_layout/Desktop/index.tsx +24 -44
  84. package/src/app/(main)/market/{(mobile)/features/AgentDetail.tsx → _layout/Mobile/DetailModal.tsx} +9 -7
  85. package/src/app/(main)/market/_layout/Mobile/Header.tsx +2 -2
  86. package/src/app/(main)/market/_layout/Mobile/index.tsx +17 -9
  87. package/src/app/(main)/market/_layout/type.ts +6 -0
  88. package/src/app/(main)/market/features/AgentCard/AgentCardBanner.tsx +10 -9
  89. package/src/app/(main)/market/features/AgentCard/index.tsx +133 -58
  90. package/src/app/(main)/market/features/AgentList.tsx +94 -0
  91. package/src/app/(main)/market/features/AgentSearchBar.tsx +42 -0
  92. package/src/app/(main)/market/features/ShareAgentButton/Inner.tsx +9 -7
  93. package/src/app/(main)/market/features/ShareAgentButton/index.tsx +22 -15
  94. package/src/app/(main)/market/features/TagList.tsx +65 -0
  95. package/src/app/(main)/market/layout.tsx +11 -0
  96. package/src/app/(main)/market/loading.tsx +2 -2
  97. package/src/app/(main)/market/page.tsx +22 -12
  98. package/src/app/(main)/settings/@category/default.tsx +16 -0
  99. package/src/app/(main)/settings/@category/features/CategoryContent.tsx +35 -0
  100. package/src/app/(main)/settings/@category/features/UpgradeAlert.tsx +38 -0
  101. package/src/app/(main)/settings/_layout/Desktop/Header.tsx +78 -23
  102. package/src/app/(main)/settings/_layout/Desktop/SideBar.tsx +39 -27
  103. package/src/app/(main)/settings/_layout/Desktop/index.tsx +41 -17
  104. package/src/app/(main)/settings/_layout/Mobile/{SubSettingHeader.tsx → Header.tsx} +3 -1
  105. package/src/app/(main)/settings/_layout/Mobile/index.tsx +7 -18
  106. package/src/app/(main)/settings/_layout/type.ts +6 -0
  107. package/src/app/(main)/settings/about/features/AboutList.tsx +122 -0
  108. package/src/app/(main)/settings/about/features/Analytics.tsx +42 -0
  109. package/src/app/(main)/settings/about/layout.tsx +26 -0
  110. package/src/app/(main)/settings/about/loading.tsx +5 -0
  111. package/src/app/(main)/settings/about/page.tsx +20 -25
  112. package/src/app/(main)/settings/agent/layout.tsx +35 -0
  113. package/src/app/(main)/settings/agent/loading.tsx +4 -2
  114. package/src/app/(main)/settings/agent/page.tsx +25 -12
  115. package/src/app/(main)/settings/common/{Common.tsx → features/Common.tsx} +7 -5
  116. package/src/app/(main)/settings/common/{Theme.tsx → features/Theme/index.tsx} +8 -6
  117. package/src/app/(main)/settings/common/page.tsx +21 -4
  118. package/src/app/(main)/settings/error.tsx +5 -0
  119. package/src/app/(main)/settings/features/Footer.tsx +2 -0
  120. package/src/app/(main)/settings/features/UpgradeAlert.tsx +21 -13
  121. package/src/app/(main)/settings/hooks/useCategory.tsx +54 -0
  122. package/src/app/(main)/settings/hooks/useSyncSettings.ts +2 -2
  123. package/src/app/(main)/settings/layout.ts +4 -1
  124. package/src/app/(main)/settings/llm/Anthropic/index.tsx +4 -10
  125. package/src/app/(main)/settings/llm/Azure/index.tsx +3 -1
  126. package/src/app/(main)/settings/llm/Bedrock/index.tsx +3 -1
  127. package/src/app/(main)/settings/llm/Google/index.tsx +4 -2
  128. package/src/app/(main)/settings/llm/Groq/index.tsx +3 -1
  129. package/src/app/(main)/settings/llm/Minimax/index.tsx +3 -9
  130. package/src/app/(main)/settings/llm/Mistral/index.tsx +3 -9
  131. package/src/app/(main)/settings/llm/Moonshot/index.tsx +3 -1
  132. package/src/app/(main)/settings/llm/Ollama/index.tsx +3 -1
  133. package/src/app/(main)/settings/llm/OpenAI/index.tsx +2 -0
  134. package/src/app/(main)/settings/llm/OpenRouter/index.tsx +3 -9
  135. package/src/app/(main)/settings/llm/Perplexity/index.tsx +3 -9
  136. package/src/app/(main)/settings/llm/TogetherAI/index.tsx +3 -9
  137. package/src/app/(main)/settings/llm/ZeroOne/index.tsx +3 -9
  138. package/src/app/(main)/settings/llm/Zhipu/index.tsx +3 -10
  139. package/src/app/(main)/settings/llm/components/Checker.tsx +2 -0
  140. package/src/app/(main)/settings/llm/components/Footer.tsx +26 -0
  141. package/src/app/(main)/settings/llm/components/ProviderConfig/index.tsx +16 -1
  142. package/src/app/(main)/settings/llm/page.tsx +57 -3
  143. package/src/app/(main)/settings/loading.tsx +9 -0
  144. package/src/app/(main)/settings/not-found.tsx +3 -0
  145. package/src/app/(main)/settings/page.tsx +2 -14
  146. package/src/app/(main)/settings/sync/{DeviceInfo → features/DeviceInfo}/Card.tsx +6 -5
  147. package/src/app/(main)/settings/sync/features/DeviceInfo/DeviceName.tsx +63 -0
  148. package/src/app/(main)/settings/sync/{components → features/DeviceInfo}/SystemIcon.tsx +6 -14
  149. package/src/app/(main)/settings/sync/{DeviceInfo → features/DeviceInfo}/index.tsx +22 -36
  150. package/src/app/(main)/settings/sync/{WebRTC → features/WebRTC}/ChannelNameInput.tsx +3 -3
  151. package/src/app/(main)/settings/sync/{WebRTC → features/WebRTC}/index.tsx +10 -9
  152. package/src/app/(main)/settings/sync/page.tsx +19 -11
  153. package/src/app/(main)/settings/tts/features/OpenAI.tsx +54 -0
  154. package/src/app/(main)/settings/tts/{TTS/index.tsx → features/STT.tsx} +11 -27
  155. package/src/app/(main)/settings/tts/page.tsx +17 -11
  156. package/src/app/@modal/(.)settings/about/layout.tsx +1 -0
  157. package/src/app/@modal/(.)settings/about/page.tsx +1 -0
  158. package/src/app/@modal/(.)settings/agent/layout.tsx +1 -0
  159. package/src/app/@modal/(.)settings/agent/page.tsx +1 -0
  160. package/src/app/@modal/(.)settings/common/page.tsx +1 -0
  161. package/src/app/@modal/(.)settings/layout.tsx +28 -0
  162. package/src/app/@modal/(.)settings/llm/page.tsx +1 -0
  163. package/src/app/@modal/(.)settings/loading.tsx +5 -0
  164. package/src/app/@modal/(.)settings/sync/page.tsx +1 -0
  165. package/src/app/@modal/(.)settings/tts/page.tsx +1 -0
  166. package/src/app/@modal/_layout/SettingModalLayout.tsx +59 -0
  167. package/src/app/@modal/chat/(.)settings/features/CategoryContent.tsx +36 -0
  168. package/src/app/@modal/chat/(.)settings/features/useCategory.tsx +62 -0
  169. package/src/app/@modal/chat/(.)settings/layout.tsx +55 -0
  170. package/src/app/@modal/chat/(.)settings/loading.tsx +5 -0
  171. package/src/app/@modal/chat/(.)settings/page.tsx +40 -0
  172. package/src/app/@modal/default.tsx +1 -0
  173. package/src/app/@modal/layout.tsx +30 -0
  174. package/src/app/@modal/loading.tsx +5 -0
  175. package/src/app/layout.tsx +11 -3
  176. package/src/components/BrandWatermark/index.tsx +39 -0
  177. package/src/components/Cell/Divider.tsx +19 -0
  178. package/src/components/Cell/index.tsx +38 -0
  179. package/src/components/Menu/index.tsx +97 -0
  180. package/src/components/SkeletonLoading/index.tsx +21 -0
  181. package/src/const/url.ts +1 -0
  182. package/src/features/AgentSetting/AgentChat/index.tsx +135 -0
  183. package/src/features/AgentSetting/AgentMeta/index.tsx +4 -3
  184. package/src/features/AgentSetting/AgentModal/index.tsx +95 -0
  185. package/src/features/AgentSetting/AgentPlugin/index.tsx +65 -66
  186. package/src/features/AgentSetting/AgentPrompt/index.tsx +101 -47
  187. package/src/features/AgentSetting/AgentTTS/index.tsx +4 -0
  188. package/src/features/AgentSetting/StoreUpdater.tsx +2 -0
  189. package/src/features/AgentSetting/index.tsx +6 -6
  190. package/src/features/AgentSetting/store/index.ts +2 -0
  191. package/src/features/AvatarWithUpload/index.tsx +2 -0
  192. package/src/features/ChatInput/STT/browser.tsx +1 -1
  193. package/src/features/ChatInput/STT/openai.tsx +1 -1
  194. package/src/features/Conversation/components/InboxWelcome/AgentsSuggest.tsx +2 -2
  195. package/src/hooks/useQuery.ts +7 -0
  196. package/src/hooks/useQueryRoute.ts +16 -0
  197. package/src/locales/default/common.ts +14 -0
  198. package/src/locales/default/setting.ts +3 -0
  199. package/src/locales/resources.ts +1 -0
  200. package/src/server/redirectHard.ts +9 -0
  201. package/src/server/translation.ts +20 -0
  202. package/src/services/__tests__/chat.test.ts +1 -1
  203. package/src/store/global/initialState.ts +1 -0
  204. package/src/store/market/action.ts +1 -1
  205. package/src/store/session/slices/session/action.ts +1 -1
  206. package/src/utils/difference.ts +2 -1
  207. package/src/app/(main)/@nav/_layout/Desktop/Avatar.tsx +0 -11
  208. package/src/app/(main)/chat/settings/(desktop)/index.tsx +0 -23
  209. package/src/app/(main)/chat/settings/(mobile)/index.tsx +0 -16
  210. package/src/app/(main)/market/(desktop)/index.tsx +0 -20
  211. package/src/app/(main)/market/(mobile)/features/AgentCard.tsx +0 -31
  212. package/src/app/(main)/market/(mobile)/index.tsx +0 -25
  213. package/src/app/(main)/market/components/Loading.tsx +0 -13
  214. package/src/app/(main)/market/features/AgentCard/AgentCardItem.tsx +0 -54
  215. package/src/app/(main)/market/features/AgentCard/style.ts +0 -33
  216. package/src/app/(main)/market/features/AgentDetailContent/index.tsx +0 -12
  217. package/src/app/(main)/market/features/AgentSearchBar/index.tsx +0 -40
  218. package/src/app/(main)/market/features/PageTitle/index.tsx +0 -13
  219. package/src/app/(main)/market/features/TagList/Inner.tsx +0 -28
  220. package/src/app/(main)/market/features/TagList/index.tsx +0 -23
  221. package/src/app/(main)/market/layout.ts +0 -8
  222. package/src/app/(main)/settings/(desktop)/index.tsx +0 -23
  223. package/src/app/(main)/settings/(mobile)/features/AvatarBanner.tsx +0 -68
  224. package/src/app/(main)/settings/(mobile)/features/ExtraList.tsx +0 -65
  225. package/src/app/(main)/settings/(mobile)/index.tsx +0 -53
  226. package/src/app/(main)/settings/about/AboutList.tsx +0 -53
  227. package/src/app/(main)/settings/about/Analytics.tsx +0 -40
  228. package/src/app/(main)/settings/about/style.ts +0 -22
  229. package/src/app/(main)/settings/agent/Agent.tsx +0 -29
  230. package/src/app/(main)/settings/common/index.tsx +0 -24
  231. package/src/app/(main)/settings/common/loading.tsx +0 -3
  232. package/src/app/(main)/settings/features/SettingList/index.tsx +0 -47
  233. package/src/app/(main)/settings/llm/index.tsx +0 -59
  234. package/src/app/(main)/settings/llm/layout.tsx +0 -11
  235. package/src/app/(main)/settings/llm/loading.tsx +0 -3
  236. package/src/app/(main)/settings/sync/DeviceInfo/DeviceName.tsx +0 -66
  237. package/src/app/(main)/settings/sync/PageTitle.tsx +0 -11
  238. package/src/app/(main)/settings/sync/layout.tsx +0 -12
  239. package/src/app/(main)/settings/sync/loading.tsx +0 -3
  240. package/src/app/(main)/settings/tts/loading.tsx +0 -3
  241. package/src/features/AgentSetting/AgentConfig/index.tsx +0 -202
  242. package/src/features/AgentSetting/AgentConfig/useSyncConfig.ts +0 -23
  243. /package/src/app/(main)/market/{features/AgentDetailContent/AgentInfo → @detail/features/AgentDetailContent}/Comment.tsx +0 -0
  244. /package/src/app/(main)/market/{features/AgentDetailContent/AgentInfo → @detail/features/AgentDetailContent}/Loading.tsx +0 -0
  245. /package/src/app/(main)/market/{features/AgentDetailContent/AgentInfo → @detail/features/AgentDetailContent}/TokenTag.tsx +0 -0
  246. /package/src/app/(main)/settings/{features/SettingList → about/features}/Item.tsx +0 -0
  247. /package/src/app/(main)/settings/{features → common/features/Theme}/ThemeSwatches/ThemeSwatchesNeutral.tsx +0 -0
  248. /package/src/app/(main)/settings/{features → common/features/Theme}/ThemeSwatches/ThemeSwatchesPrimary.tsx +0 -0
  249. /package/src/app/(main)/settings/{features → common/features/Theme}/ThemeSwatches/index.ts +0 -0
  250. /package/src/app/(main)/settings/sync/{Alert.tsx → features/Alert.tsx} +0 -0
  251. /package/src/app/(main)/settings/sync/{components → features/WebRTC}/SyncSwitch/index.css +0 -0
  252. /package/src/app/(main)/settings/sync/{components → features/WebRTC}/SyncSwitch/index.tsx +0 -0
  253. /package/src/app/(main)/settings/sync/{util.ts → features/WebRTC/generateRandomRoomName.ts} +0 -0
  254. /package/src/app/(main)/settings/tts/{TTS/options.ts → features/const.ts} +0 -0
  255. /package/src/features/AgentSetting/{AgentConfig → AgentModal}/ModelSelect.tsx +0 -0
@@ -0,0 +1,24 @@
1
+ 'use client';
2
+
3
+ import { Avatar, type AvatarProps } from '@lobehub/ui';
4
+ import { memo } from 'react';
5
+
6
+ import { DEFAULT_USER_AVATAR_URL } from '@/const/meta';
7
+ import { useUserStore } from '@/store/user';
8
+ import { commonSelectors } from '@/store/user/selectors';
9
+
10
+ const UserAvatar = memo<AvatarProps>(({ size = 40, background, ...rest }) => {
11
+ const avatar = useUserStore(commonSelectors.userAvatar);
12
+ return (
13
+ <Avatar
14
+ avatar={avatar || DEFAULT_USER_AVATAR_URL}
15
+ background={avatar ? background : undefined}
16
+ size={size}
17
+ {...rest}
18
+ />
19
+ );
20
+ });
21
+
22
+ UserAvatar.displayName = 'UserAvatar';
23
+
24
+ export default UserAvatar;
@@ -0,0 +1,55 @@
1
+ import { ActionIcon } from '@lobehub/ui';
2
+ import { Popover } from 'antd';
3
+ import { useTheme } from 'antd-style';
4
+ import { Languages } from 'lucide-react';
5
+ import { memo, useMemo } from 'react';
6
+ import { useTranslation } from 'react-i18next';
7
+
8
+ import Menu, { type MenuProps } from '@/components/Menu';
9
+ import { localeOptions } from '@/locales/resources';
10
+ import { useUserStore } from '@/store/user';
11
+ import { settingsSelectors } from '@/store/user/selectors';
12
+ import { switchLang } from '@/utils/client/switchLang';
13
+
14
+ const LangButton = memo(() => {
15
+ const theme = useTheme();
16
+ const language = useUserStore((s) => settingsSelectors.currentSettings(s).language);
17
+
18
+ const { t } = useTranslation('setting');
19
+
20
+ const items: MenuProps['items'] = useMemo(
21
+ () => [
22
+ {
23
+ key: 'auto',
24
+ label: t('settingTheme.lang.autoMode'),
25
+ onClick: () => switchLang('auto'),
26
+ },
27
+ ...localeOptions.map((item) => ({
28
+ key: item.value,
29
+ label: item.label,
30
+ onClick: () => switchLang(item.value),
31
+ })),
32
+ ],
33
+ [t],
34
+ );
35
+
36
+ return (
37
+ <Popover
38
+ arrow={false}
39
+ content={<Menu items={items} selectable selectedKeys={[language]} />}
40
+ overlayInnerStyle={{
41
+ padding: 0,
42
+ }}
43
+ placement={'right'}
44
+ trigger={['click', 'hover']}
45
+ >
46
+ <ActionIcon
47
+ icon={Languages}
48
+ size={{ blockSize: 32, fontSize: 16 }}
49
+ style={{ border: `1px solid ${theme.colorFillSecondary}` }}
50
+ />
51
+ </Popover>
52
+ );
53
+ });
54
+
55
+ export default LangButton;
@@ -0,0 +1,34 @@
1
+ import { memo } from 'react';
2
+ import { Flexbox } from 'react-layout-kit';
3
+
4
+ import BrandWatermark from '@/components/BrandWatermark';
5
+ import Menu from '@/components/Menu';
6
+
7
+ import LangButton from './LangButton';
8
+ import ThemeButton from './ThemeButton';
9
+ import { useMenu } from './useMenu';
10
+
11
+ const PopoverContent = memo<{ closePopover: () => void }>(({ closePopover }) => {
12
+ const { mainItems } = useMenu();
13
+
14
+ return (
15
+ <Flexbox gap={2} style={{ minWidth: 300 }}>
16
+ {/*<UserInfo />*/}
17
+ <Menu items={mainItems} onClick={closePopover} />
18
+ <Flexbox
19
+ align={'center'}
20
+ horizontal
21
+ justify={'space-between'}
22
+ style={{ padding: '6px 6px 6px 16px' }}
23
+ >
24
+ <BrandWatermark />
25
+ <Flexbox align={'center'} flex={'none'} gap={6} horizontal>
26
+ <LangButton />
27
+ <ThemeButton />
28
+ </Flexbox>
29
+ </Flexbox>
30
+ </Flexbox>
31
+ );
32
+ });
33
+
34
+ export default PopoverContent;
@@ -0,0 +1,70 @@
1
+ import { ActionIcon, Icon } from '@lobehub/ui';
2
+ import { Popover } from 'antd';
3
+ import { useTheme } from 'antd-style';
4
+ import { Monitor, Moon, Sun } from 'lucide-react';
5
+ import { memo, useMemo } from 'react';
6
+ import { useTranslation } from 'react-i18next';
7
+
8
+ import Menu, { type MenuProps } from '@/components/Menu';
9
+ import { useUserStore } from '@/store/user';
10
+ import { settingsSelectors } from '@/store/user/selectors';
11
+
12
+ const themeIcons = {
13
+ auto: Monitor,
14
+ dark: Moon,
15
+ light: Sun,
16
+ };
17
+
18
+ const ThemeButton = memo(() => {
19
+ const theme = useTheme();
20
+ const [themeMode, switchThemeMode] = useUserStore((s) => [
21
+ settingsSelectors.currentSettings(s).themeMode,
22
+ s.switchThemeMode,
23
+ ]);
24
+
25
+ const { t } = useTranslation('setting');
26
+
27
+ const items: MenuProps['items'] = useMemo(
28
+ () => [
29
+ {
30
+ icon: <Icon icon={themeIcons.auto} />,
31
+ key: 'auto',
32
+ label: t('settingTheme.themeMode.auto'),
33
+ onClick: () => switchThemeMode('auto'),
34
+ },
35
+ {
36
+ icon: <Icon icon={themeIcons.light} />,
37
+ key: 'light',
38
+ label: t('settingTheme.themeMode.light'),
39
+ onClick: () => switchThemeMode('light'),
40
+ },
41
+ {
42
+ icon: <Icon icon={themeIcons.dark} />,
43
+ key: 'dark',
44
+ label: t('settingTheme.themeMode.dark'),
45
+ onClick: () => switchThemeMode('dark'),
46
+ },
47
+ ],
48
+ [t],
49
+ );
50
+
51
+ return (
52
+ <Popover
53
+ arrow={false}
54
+ content={<Menu items={items} selectable selectedKeys={[themeMode]} />}
55
+ overlayInnerStyle={{
56
+ padding: 0,
57
+ }}
58
+ placement={'right'}
59
+ trigger={['click', 'hover']}
60
+ >
61
+ <ActionIcon
62
+ icon={themeIcons[themeMode]}
63
+ size={{ blockSize: 32, fontSize: 16 }}
64
+ style={{ border: `1px solid ${theme.colorFillSecondary}` }}
65
+ />
66
+ </Popover>
67
+ );
68
+ });
69
+
70
+ export default ThemeButton;
@@ -0,0 +1,35 @@
1
+ import { createStyles } from 'antd-style';
2
+ import { memo } from 'react';
3
+ import { Flexbox } from 'react-layout-kit';
4
+
5
+ import UserAvatar from '../UserAvatar';
6
+
7
+ const useStyles = createStyles(({ css, token }) => ({
8
+ nickname: css`
9
+ font-size: 16px;
10
+ font-weight: bold;
11
+ line-height: 1;
12
+ `,
13
+ username: css`
14
+ line-height: 1;
15
+ color: ${token.colorTextDescription};
16
+ `,
17
+ }));
18
+
19
+ // TODO
20
+
21
+ const UserInfo = memo<{ onClick?: () => void }>(({ onClick }) => {
22
+ const { styles, theme } = useStyles();
23
+
24
+ return (
25
+ <Flexbox align={'center'} gap={12} horizontal paddingBlock={12} paddingInline={16}>
26
+ <UserAvatar background={theme.colorFill} onClick={onClick} size={48} />
27
+ <Flexbox flex={1} gap={6}>
28
+ <div className={styles.nickname}>{'社区版用户'}</div>
29
+ <div className={styles.username}> {'Community Edition'}</div>
30
+ </Flexbox>
31
+ </Flexbox>
32
+ );
33
+ });
34
+
35
+ export default UserInfo;
@@ -0,0 +1,69 @@
1
+ 'use client';
2
+
3
+ import { Alert } from '@lobehub/ui';
4
+ import { Badge, ConfigProvider, Popover } from 'antd';
5
+ import { createStyles } from 'antd-style';
6
+ import { PropsWithChildren, memo, useCallback, useState } from 'react';
7
+ import { useTranslation } from 'react-i18next';
8
+ import { Flexbox } from 'react-layout-kit';
9
+
10
+ import PopoverContent from './Popover';
11
+ import { useNewVersion } from './useNewVersion';
12
+
13
+ const useStyles = createStyles(({ css }) => ({
14
+ popover: css`
15
+ top: 8px !important;
16
+ left: 8px !important;
17
+ `,
18
+ }));
19
+
20
+ const UserPanel = memo<PropsWithChildren<{ bottom?: boolean }>>(({ children, bottom }) => {
21
+ const hasNewVersion = useNewVersion();
22
+ const [open, setOpen] = useState(false);
23
+ const { styles } = useStyles();
24
+ const { t } = useTranslation('common');
25
+
26
+ const AvararBadge = useCallback(
27
+ ({ children: badgeChildren, showBadge }: PropsWithChildren<{ showBadge?: boolean }>) => {
28
+ if (bottom || !showBadge) return badgeChildren;
29
+ return (
30
+ <Flexbox>
31
+ <ConfigProvider theme={{ components: { Badge: { dotSize: 8 } } }}>
32
+ <Badge dot offset={[-4, 4]}>
33
+ {badgeChildren}
34
+ </Badge>
35
+ </ConfigProvider>
36
+ </Flexbox>
37
+ );
38
+ },
39
+ [],
40
+ );
41
+
42
+ return (
43
+ <AvararBadge showBadge={hasNewVersion}>
44
+ <Popover
45
+ arrow={false}
46
+ content={
47
+ <>
48
+ {bottom && <Alert banner message={t('userPanel.warn')} type={'warning'} />}
49
+ <PopoverContent closePopover={() => setOpen(false)} />
50
+ </>
51
+ }
52
+ onOpenChange={setOpen}
53
+ open={open}
54
+ overlayInnerStyle={{
55
+ padding: 0,
56
+ }}
57
+ placement={'topRight'}
58
+ rootClassName={bottom ? undefined : styles.popover}
59
+ trigger={['click']}
60
+ >
61
+ {children}
62
+ </Popover>
63
+ </AvararBadge>
64
+ );
65
+ });
66
+
67
+ UserPanel.displayName = 'UserPanel';
68
+
69
+ export default UserPanel;
@@ -0,0 +1,144 @@
1
+ import { DiscordIcon, Icon } from '@lobehub/ui';
2
+ import { Badge } from 'antd';
3
+ import {
4
+ Book,
5
+ Feather,
6
+ HardDriveDownload,
7
+ HardDriveUpload,
8
+ LifeBuoy,
9
+ Mail,
10
+ Settings2,
11
+ } from 'lucide-react';
12
+ import { PropsWithChildren, useCallback } from 'react';
13
+ import { useTranslation } from 'react-i18next';
14
+ import { Flexbox } from 'react-layout-kit';
15
+
16
+ import { type MenuProps } from '@/components/Menu';
17
+ import { AGENTS_INDEX_GITHUB_ISSUE, DISCORD, DOCUMENTS, EMAIL_SUPPORT } from '@/const/url';
18
+ import DataImporter from '@/features/DataImporter';
19
+ import { useQueryRoute } from '@/hooks/useQueryRoute';
20
+ import { configService } from '@/services/config';
21
+
22
+ import { useNewVersion } from './useNewVersion';
23
+
24
+ export const useMenu = () => {
25
+ const router = useQueryRoute();
26
+ const hasNewVersion = useNewVersion();
27
+
28
+ const { t } = useTranslation(['common', 'setting']);
29
+
30
+ const NewVersionBadge = useCallback(
31
+ ({ children, showBadge }: PropsWithChildren & { showBadge?: boolean }) => {
32
+ if (!showBadge) return children;
33
+ return (
34
+ <Flexbox align={'center'} distribution={'space-between'} gap={8} horizontal width={'100%'}>
35
+ <span>{children}</span>
36
+ <Badge count={t('upgradeVersion.hasNew')} />
37
+ </Flexbox>
38
+ );
39
+ },
40
+ [t],
41
+ );
42
+
43
+ const exports: MenuProps['items'] = [
44
+ {
45
+ icon: <Icon icon={HardDriveUpload} />,
46
+ key: 'import',
47
+ label: <DataImporter>{t('import')}</DataImporter>,
48
+ },
49
+ {
50
+ children: [
51
+ {
52
+ key: 'allAgent',
53
+ label: <div>{t('exportType.allAgent')}</div>,
54
+ onClick: configService.exportAgents,
55
+ },
56
+ {
57
+ key: 'allAgentWithMessage',
58
+ label: <div>{t('exportType.allAgentWithMessage')}</div>,
59
+ onClick: configService.exportSessions,
60
+ },
61
+ {
62
+ key: 'globalSetting',
63
+ label: <div>{t('exportType.globalSetting')}</div>,
64
+ onClick: configService.exportSettings,
65
+ },
66
+ {
67
+ type: 'divider',
68
+ },
69
+ {
70
+ key: 'all',
71
+ label: <div>{t('exportType.all')}</div>,
72
+ onClick: configService.exportAll,
73
+ },
74
+ ],
75
+ icon: <Icon icon={HardDriveDownload} />,
76
+ key: 'export',
77
+ label: t('export'),
78
+ },
79
+ {
80
+ type: 'divider',
81
+ },
82
+ ];
83
+
84
+ const settings: MenuProps['items'] = [
85
+ {
86
+ icon: <Icon icon={Settings2} />,
87
+ key: 'setting',
88
+ label: <NewVersionBadge showBadge={hasNewVersion}>{t('userPanel.setting')}</NewVersionBadge>,
89
+ onClick: () => {
90
+ router.push('/settings/common');
91
+ },
92
+ },
93
+ {
94
+ type: 'divider',
95
+ },
96
+ ];
97
+
98
+ const helps: MenuProps['items'] = [
99
+ {
100
+ icon: <Icon icon={DiscordIcon} />,
101
+ key: 'discord',
102
+ label: t('userPanel.discord'),
103
+ onClick: () => window.open(DISCORD, '__blank'),
104
+ },
105
+ {
106
+ children: [
107
+ {
108
+ icon: <Icon icon={Book} />,
109
+ key: 'docs',
110
+ label: t('userPanel.docs'),
111
+ onClick: () => window.open(DOCUMENTS, '__blank'),
112
+ },
113
+ {
114
+ icon: <Icon icon={Feather} />,
115
+ key: 'feedback',
116
+ label: t('userPanel.feedback'),
117
+ onClick: () => window.open(AGENTS_INDEX_GITHUB_ISSUE, '__blank'),
118
+ },
119
+ {
120
+ icon: <Icon icon={Mail} />,
121
+ key: 'email',
122
+ label: t('userPanel.email'),
123
+ onClick: () => window.open(`mailto:${EMAIL_SUPPORT}`, '__blank'),
124
+ },
125
+ ],
126
+ icon: <Icon icon={LifeBuoy} />,
127
+ key: 'help',
128
+ label: t('userPanel.help'),
129
+ },
130
+ ];
131
+
132
+ const mainItems = [
133
+ ...settings,
134
+ ...exports,
135
+ ...helps,
136
+ {
137
+ type: 'divider',
138
+ },
139
+ ].filter(Boolean) as MenuProps['items'];
140
+
141
+ return {
142
+ mainItems,
143
+ };
144
+ };
@@ -0,0 +1,12 @@
1
+ import { useGlobalStore } from '@/store/global';
2
+
3
+ export const useNewVersion = () => {
4
+ const [hasNewVersion, useCheckLatestVersion] = useGlobalStore((s) => [
5
+ s.hasNewVersion,
6
+ s.useCheckLatestVersion,
7
+ ]);
8
+
9
+ useCheckLatestVersion();
10
+
11
+ return hasNewVersion;
12
+ };
@@ -33,7 +33,7 @@ const Header = memo(() => {
33
33
  <MobileNavBar
34
34
  left={
35
35
  <Flexbox align={'center'} gap={8} horizontal style={{ marginLeft: 8 }}>
36
- <div onClick={() => router.push('/settings')}>
36
+ <div onClick={() => router.push('/me')}>
37
37
  {avatar ? <Avatar avatar={avatar} size={28} /> : <Logo size={28} />}
38
38
  </div>
39
39
  <Logo type={'text'} />
@@ -1,13 +1,9 @@
1
- 'use client';
2
-
3
- import { PropsWithChildren, memo } from 'react';
4
1
  import { Flexbox } from 'react-layout-kit';
5
2
 
6
- import ClientResponsiveLayout from '@/components/client/ClientResponsiveLayout';
7
-
3
+ import { LayoutProps } from '../type';
8
4
  import ResponsiveSessionList from './SessionList';
9
5
 
10
- const Desktop = memo(({ children }: PropsWithChildren) => {
6
+ const Layout = ({ children }: LayoutProps) => {
11
7
  return (
12
8
  <>
13
9
  <ResponsiveSessionList />
@@ -21,6 +17,8 @@ const Desktop = memo(({ children }: PropsWithChildren) => {
21
17
  </Flexbox>
22
18
  </>
23
19
  );
24
- });
20
+ };
21
+
22
+ Layout.displayName = 'DesktopChatLayout';
25
23
 
26
- export default ClientResponsiveLayout({ Desktop, Mobile: () => import('../Mobile') });
24
+ export default Layout;
@@ -1,7 +1,9 @@
1
- import { PropsWithChildren } from 'react';
1
+ import { LayoutProps } from '../type';
2
2
 
3
- const MobileLayout = ({ children }: PropsWithChildren) => {
3
+ const Layout = ({ children }: LayoutProps) => {
4
4
  return children;
5
5
  };
6
6
 
7
- export default MobileLayout;
7
+ Layout.displayName = 'MobileChatLayout';
8
+
9
+ export default Layout;
@@ -0,0 +1,5 @@
1
+ import { ReactNode } from 'react';
2
+
3
+ export interface LayoutProps {
4
+ children: ReactNode;
5
+ }
@@ -5,6 +5,7 @@ import { memo } from 'react';
5
5
  import { useTranslation } from 'react-i18next';
6
6
 
7
7
  import { DESKTOP_HEADER_ICON_SIZE, MOBILE_HEADER_ICON_SIZE } from '@/const/layoutTokens';
8
+ import redirectHard from '@/server/redirectHard';
8
9
  import { useGlobalStore } from '@/store/global';
9
10
  import { SidebarTabKey } from '@/store/global/initialState';
10
11
  import { useSessionStore } from '@/store/session';
@@ -16,6 +17,8 @@ const SettingButton = memo<{ mobile?: boolean }>(({ mobile }) => {
16
17
  const { t } = useTranslation('common');
17
18
  const router = useRouter();
18
19
 
20
+ const push = mobile ? redirectHard : router.push;
21
+
19
22
  return (
20
23
  <ActionIcon
21
24
  icon={AlignJustify}
@@ -24,9 +27,9 @@ const SettingButton = memo<{ mobile?: boolean }>(({ mobile }) => {
24
27
  useGlobalStore.setState({
25
28
  sidebarKey: SidebarTabKey.Setting,
26
29
  });
27
- router.push('/settings/agent');
30
+ push('/settings/agent');
28
31
  } else {
29
- router.push(pathString('/chat/settings', { search: location.search }));
32
+ push(pathString('/chat/settings', { search: location.search }));
30
33
  }
31
34
  }}
32
35
  size={mobile ? MOBILE_HEADER_ICON_SIZE : DESKTOP_HEADER_ICON_SIZE}
@@ -2,7 +2,10 @@ import ServerLayout from '@/components/server/ServerLayout';
2
2
 
3
3
  import Desktop from './_layout/Desktop';
4
4
  import Mobile from './_layout/Mobile';
5
+ import { LayoutProps } from './_layout/type';
5
6
 
6
- const ChatLayout = ServerLayout({ Desktop, Mobile });
7
+ const Layout = ServerLayout<LayoutProps>({ Desktop, Mobile });
7
8
 
8
- export default ChatLayout;
9
+ Layout.displayName = 'ChatLayout';
10
+
11
+ export default Layout;
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import { ChatHeader, ChatHeaderTitle } from '@lobehub/ui';
2
4
  import { useRouter } from 'next/navigation';
3
5
  import { memo } from 'react';
@@ -0,0 +1,32 @@
1
+ import { PropsWithChildren } from 'react';
2
+ import { Flexbox } from 'react-layout-kit';
3
+
4
+ import SafeSpacing from '@/components/SafeSpacing';
5
+ import { HEADER_HEIGHT } from '@/const/layoutTokens';
6
+
7
+ import Header from './Header';
8
+
9
+ const Layout = ({ children }: PropsWithChildren) => (
10
+ <>
11
+ <Header />
12
+ <Flexbox
13
+ align={'center'}
14
+ height={'100%'}
15
+ style={{ overflowX: 'hidden', overflowY: 'auto' }}
16
+ width={'100%'}
17
+ >
18
+ <SafeSpacing height={HEADER_HEIGHT - 16} />
19
+ <Flexbox
20
+ gap={64}
21
+ style={{ maxWidth: 1024, padding: '1.75rem 1.5rem 1.75rem 2rem' }}
22
+ width={'100%'}
23
+ >
24
+ {children}
25
+ </Flexbox>
26
+ </Flexbox>
27
+ </>
28
+ );
29
+
30
+ Layout.displayName = 'DesktopSessionSettingsLayout';
31
+
32
+ export default Layout;
@@ -1,13 +1,14 @@
1
+ 'use client';
2
+
1
3
  import { MobileNavBar, MobileNavBarTitle } from '@lobehub/ui';
2
4
  import { useRouter } from 'next/navigation';
3
5
  import { memo } from 'react';
4
6
  import { useTranslation } from 'react-i18next';
5
7
 
8
+ import HeaderContent from '@/app/(main)/chat/settings/features/HeaderContent';
6
9
  import { mobileHeaderSticky } from '@/styles/mobileHeader';
7
10
  import { pathString } from '@/utils/url';
8
11
 
9
- import HeaderContent from '../features/HeaderContent';
10
-
11
12
  const Header = memo(() => {
12
13
  const { t } = useTranslation('setting');
13
14
  const router = useRouter();
@@ -0,0 +1,15 @@
1
+ 'use client';
2
+
3
+ import { PropsWithChildren } from 'react';
4
+
5
+ import MobileContentLayout from '@/components/server/MobileNavLayout';
6
+
7
+ import Header from './Header';
8
+
9
+ const Layout = ({ children }: PropsWithChildren) => (
10
+ <MobileContentLayout header={<Header />}>{children}</MobileContentLayout>
11
+ );
12
+
13
+ Layout.displayName = 'MobileSessionSettingsLayout';
14
+
15
+ export default Layout;
@@ -0,0 +1,5 @@
1
+ 'use client';
2
+
3
+ import dynamic from 'next/dynamic';
4
+
5
+ export default dynamic(() => import('@/components/Error'), { ssr: false });
@@ -1,5 +1,5 @@
1
- import { ActionIcon } from '@lobehub/ui';
2
- import { Dropdown, MenuProps } from 'antd';
1
+ import { ActionIcon, Icon } from '@lobehub/ui';
2
+ import { Button, Dropdown, MenuProps } from 'antd';
3
3
  import { useResponsive } from 'antd-style';
4
4
  import { HardDriveDownload } from 'lucide-react';
5
5
  import { memo, useMemo } from 'react';
@@ -11,7 +11,7 @@ import { useSessionStore } from '@/store/session';
11
11
 
12
12
  import SubmitAgentButton from './SubmitAgentButton';
13
13
 
14
- export const HeaderContent = memo<{ mobile?: boolean }>(() => {
14
+ export const HeaderContent = memo<{ mobile?: boolean; modal?: boolean }>(({ modal }) => {
15
15
  const { t } = useTranslation('setting');
16
16
  const id = useSessionStore((s) => s.activeId);
17
17
 
@@ -43,13 +43,19 @@ export const HeaderContent = memo<{ mobile?: boolean }>(() => {
43
43
 
44
44
  return (
45
45
  <>
46
- <SubmitAgentButton />
46
+ <SubmitAgentButton modal={modal} />
47
47
  <Dropdown arrow={false} menu={{ items }} trigger={['click']}>
48
- <ActionIcon
49
- icon={HardDriveDownload}
50
- size={HEADER_ICON_SIZE(mobile)}
51
- title={t('export', { ns: 'common' })}
52
- />
48
+ {modal ? (
49
+ <Button block icon={<Icon icon={HardDriveDownload} />}>
50
+ {t('export', { ns: 'common' })}
51
+ </Button>
52
+ ) : (
53
+ <ActionIcon
54
+ icon={HardDriveDownload}
55
+ size={HEADER_ICON_SIZE(mobile)}
56
+ title={t('export', { ns: 'common' })}
57
+ />
58
+ )}
53
59
  </Dropdown>
54
60
  </>
55
61
  );