@lobehub/chat 0.82.1 → 0.82.3

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 (77) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/README.md +22 -6
  3. package/README.zh-CN.md +21 -5
  4. package/docs/Environment-Variable.md +45 -9
  5. package/locales/en_US/common.json +1 -1
  6. package/locales/ru_RU/common.json +1 -1
  7. package/locales/zh_CN/common.json +1 -1
  8. package/locales/zh_TW/common.json +1 -1
  9. package/package.json +1 -1
  10. package/public/images/screenshot_background.webp +0 -0
  11. package/src/app/chat/features/Conversation/ChatList/Error/ApiKeyForm.tsx +44 -20
  12. package/src/app/chat/features/Conversation/ChatList/Error/InvalidAccess.tsx +20 -18
  13. package/src/app/chat/features/Conversation/ChatList/Error/OpenAiBizError.tsx +1 -11
  14. package/src/app/chat/features/Conversation/ChatList/OTPInput.tsx +0 -6
  15. package/src/app/chat/features/Header/Mobile.tsx +12 -7
  16. package/src/app/chat/features/Header/ShareButton/Inner.tsx +31 -26
  17. package/src/app/chat/features/Header/ShareButton/index.tsx +6 -1
  18. package/src/app/chat/features/SessionList/Header/Desktop.tsx +2 -4
  19. package/src/app/chat/features/SessionList/Header/Mobile.tsx +15 -14
  20. package/src/app/chat/features/Sidebar/Mobile.tsx +3 -17
  21. package/src/app/chat/layout.desktop.tsx +2 -1
  22. package/src/app/chat/layout.mobile.tsx +2 -1
  23. package/src/app/chat/settings/features/Header/index.tsx +3 -3
  24. package/src/app/chat/settings/layout.mobile.tsx +1 -8
  25. package/src/app/market/features/AgentCard/AgentCardBanner.tsx +2 -1
  26. package/src/app/market/features/Header/Mobile.tsx +2 -21
  27. package/src/app/market/features/SideBar/AgentInfo/Header.tsx +2 -1
  28. package/src/app/market/features/SideBar/AgentInfo/index.tsx +10 -2
  29. package/src/app/market/features/SideBar/Mobile.tsx +3 -17
  30. package/src/app/market/layout.desktop.tsx +2 -1
  31. package/src/app/market/layout.mobile.tsx +2 -1
  32. package/src/app/settings/agent/index.tsx +20 -0
  33. package/src/app/settings/agent/page.tsx +7 -0
  34. package/src/app/settings/{features/Settings → common}/Common.tsx +1 -1
  35. package/src/app/settings/common/index.tsx +20 -0
  36. package/src/app/settings/common/page.tsx +7 -0
  37. package/src/app/settings/features/Header/Desktop.tsx +9 -2
  38. package/src/app/settings/features/Header/Mobile.tsx +5 -2
  39. package/src/app/settings/features/SideBar/Item.tsx +39 -0
  40. package/src/app/settings/features/SideBar/List.tsx +30 -0
  41. package/src/app/settings/features/SideBar/index.tsx +38 -0
  42. package/src/app/settings/index.tsx +5 -7
  43. package/src/app/settings/layout.desktop.tsx +6 -2
  44. package/src/app/settings/layout.mobile.tsx +1 -3
  45. package/src/app/settings/{features/Settings → llm}/LLM/index.tsx +4 -2
  46. package/src/app/settings/llm/index.tsx +20 -0
  47. package/src/app/settings/llm/page.tsx +7 -0
  48. package/src/app/settings/mobile/ExtraList.tsx +61 -0
  49. package/src/app/settings/mobile/index.tsx +43 -0
  50. package/src/app/settings/mobile/page.tsx +7 -0
  51. package/src/app/settings/page.tsx +1 -7
  52. package/src/components/MobilePadding/index.tsx +32 -0
  53. package/src/const/layoutTokens.ts +1 -0
  54. package/src/features/AgentSetting/AgentMeta/index.tsx +0 -1
  55. package/src/features/AgentSetting/AgentPlugin/MarketSettingModal.tsx +29 -16
  56. package/src/features/MobileTabBar/index.tsx +15 -3
  57. package/src/features/PluginDevModal/PluginPreview.tsx +11 -4
  58. package/src/features/PluginDevModal/index.tsx +14 -10
  59. package/src/features/SideBar/BottomActions.tsx +3 -3
  60. package/src/features/SideBar/TopActions.tsx +5 -4
  61. package/src/locales/default/common.ts +1 -1
  62. package/src/locales/default/error.ts +1 -0
  63. package/src/locales/default/plugin.ts +2 -1
  64. package/src/store/global/hooks/useSwitchSettingsOnInit.ts +9 -0
  65. package/src/store/global/initialState.ts +13 -4
  66. package/src/store/global/selectors.ts +7 -0
  67. package/src/store/global/slices/settings.ts +5 -1
  68. package/src/store/global/store.ts +0 -4
  69. package/src/store/session/slices/chat/actions/share.ts +1 -1
  70. package/src/styles/antdOverride.ts +2 -26
  71. package/src/styles/global.ts +9 -0
  72. package/src/app/settings/features/Banner/index.tsx +0 -94
  73. package/src/app/settings/features/Settings/index.tsx +0 -53
  74. /package/src/app/settings/{features/Settings → agent}/Agent.tsx +0 -0
  75. /package/src/app/settings/{features/Settings → llm}/LLM/Checker.tsx +0 -0
  76. /package/src/app/settings/{features/Settings → llm}/LLM/ModelList.tsx +0 -0
  77. /package/src/app/settings/{features/Settings → llm}/LLM/getModelList.ts +0 -0
@@ -5,6 +5,7 @@ import { memo, useMemo, useState } from 'react';
5
5
  import { useTranslation } from 'react-i18next';
6
6
  import { Flexbox } from 'react-layout-kit';
7
7
 
8
+ import MobilePadding from '@/components/MobilePadding';
8
9
  import { FORM_STYLE } from '@/const/layoutTokens';
9
10
  import { useGlobalStore } from '@/store/global';
10
11
  import { useSessionStore } from '@/store/session';
@@ -89,33 +90,37 @@ const Inner = memo(() => {
89
90
 
90
91
  return (
91
92
  <Flexbox gap={16}>
92
- <Segmented
93
- block
94
- onChange={(value) => setTab(value as Tab)}
95
- options={options}
96
- style={{ width: '100%' }}
97
- value={tab}
98
- />
99
- <Form items={[settings]} {...FORM_STYLE} />
100
- {tab === Tab.Screenshot && (
101
- <Preview
102
- imageType={imageType}
103
- withBackground={withBackground}
104
- withFooter={withFooter}
105
- withSystemRole={withSystemRole}
106
- />
107
- )}
108
- {tab === Tab.ShareGPT && (
109
- <Button
93
+ <MobilePadding bottom={0}>
94
+ <Segmented
110
95
  block
111
- loading={shareLoading}
112
- onClick={() => shareToShareGPT({ avatar, withPluginInfo, withSystemRole })}
113
- size={'large'}
114
- type={'primary'}
115
- >
116
- {t('shareModal.shareToShareGPT')}
117
- </Button>
118
- )}
96
+ onChange={(value) => setTab(value as Tab)}
97
+ options={options}
98
+ style={{ width: '100%' }}
99
+ value={tab}
100
+ />
101
+ </MobilePadding>
102
+ <Form items={[settings]} {...FORM_STYLE} />
103
+ <MobilePadding gap={16} top={0}>
104
+ {tab === Tab.Screenshot && (
105
+ <Preview
106
+ imageType={imageType}
107
+ withBackground={withBackground}
108
+ withFooter={withFooter}
109
+ withSystemRole={withSystemRole}
110
+ />
111
+ )}
112
+ {tab === Tab.ShareGPT && (
113
+ <Button
114
+ block
115
+ loading={shareLoading}
116
+ onClick={() => shareToShareGPT({ avatar, withPluginInfo, withSystemRole })}
117
+ size={'large'}
118
+ type={'primary'}
119
+ >
120
+ {t('shareModal.shareToShareGPT')}
121
+ </Button>
122
+ )}
123
+ </MobilePadding>
119
124
  </Flexbox>
120
125
  );
121
126
  });
@@ -1,8 +1,10 @@
1
1
  import { ActionIcon, Modal } from '@lobehub/ui';
2
+ import { useResponsive } from 'antd-style';
2
3
  import { Share2 } from 'lucide-react';
3
4
  import { memo, useState } from 'react';
4
5
  import { useTranslation } from 'react-i18next';
5
6
 
7
+ import { MOBILE_HEADER_ICON_SIZE } from '@/const/layoutTokens';
6
8
  import { useSessionStore } from '@/store/session';
7
9
 
8
10
  import Inner from './Inner';
@@ -11,6 +13,9 @@ const ShareButton = memo(() => {
11
13
  const [isModalOpen, setIsModalOpen] = useState(false);
12
14
  const { t } = useTranslation('common');
13
15
  const [shareLoading] = useSessionStore((s) => [s.shareLoading]);
16
+ const { mobile } = useResponsive();
17
+
18
+ const size = mobile ? MOBILE_HEADER_ICON_SIZE : { fontSize: 24 };
14
19
 
15
20
  return (
16
21
  <>
@@ -18,7 +23,7 @@ const ShareButton = memo(() => {
18
23
  icon={Share2}
19
24
  loading={shareLoading}
20
25
  onClick={() => setIsModalOpen(true)}
21
- size={{ fontSize: 24 }}
26
+ size={size}
22
27
  title={t('share')}
23
28
  />
24
29
  <Modal
@@ -1,7 +1,6 @@
1
1
  import { ActionIcon, Logo } from '@lobehub/ui';
2
2
  import { createStyles } from 'antd-style';
3
3
  import { MessageSquarePlus } from 'lucide-react';
4
- import Link from 'next/link';
5
4
  import { memo } from 'react';
6
5
  import { useTranslation } from 'react-i18next';
7
6
  import { Flexbox } from 'react-layout-kit';
@@ -28,9 +27,8 @@ const Header = memo(() => {
28
27
  return (
29
28
  <Flexbox className={styles.top} gap={16} padding={16}>
30
29
  <Flexbox distribution={'space-between'} horizontal>
31
- <Link href={'/'}>
32
- <Logo className={styles.logo} size={36} type={'text'} />
33
- </Link>
30
+ <Logo className={styles.logo} size={36} type={'text'} />
31
+
34
32
  <ActionIcon
35
33
  icon={MessageSquarePlus}
36
34
  onClick={() => createSession()}
@@ -1,10 +1,11 @@
1
- import { ActionIcon, Logo, MobileNavBar } from '@lobehub/ui';
1
+ import { ActionIcon, Avatar, Logo, MobileNavBar } from '@lobehub/ui';
2
2
  import { createStyles } from 'antd-style';
3
- import { MessageSquarePlus, Settings2 } from 'lucide-react';
3
+ import { MessageSquarePlus } from 'lucide-react';
4
4
  import { useRouter } from 'next/navigation';
5
5
  import { memo } from 'react';
6
6
 
7
- import AvatarWithUpload from '@/features/AvatarWithUpload';
7
+ import { MOBILE_HEADER_ICON_SIZE } from '@/const/layoutTokens';
8
+ import { useGlobalStore } from '@/store/global';
8
9
  import { useSessionStore } from '@/store/session';
9
10
 
10
11
  export const useStyles = createStyles(({ css, token }) => ({
@@ -20,21 +21,21 @@ export const useStyles = createStyles(({ css, token }) => ({
20
21
  const Header = memo(() => {
21
22
  const [createSession] = useSessionStore((s) => [s.createSession]);
22
23
  const router = useRouter();
23
-
24
+ const avatar = useGlobalStore((st) => st.settings.avatar);
24
25
  return (
25
26
  <MobileNavBar
26
27
  center={<Logo type={'text'} />}
27
- left={<AvatarWithUpload size={28} style={{ marginLeft: 8 }} />}
28
+ left={
29
+ <div onClick={() => router.push('/settings/mobile')} style={{ marginLeft: 8 }}>
30
+ {avatar ? <Avatar avatar={avatar} size={28} /> : <Logo size={28} />}
31
+ </div>
32
+ }
28
33
  right={
29
- <>
30
- <ActionIcon icon={MessageSquarePlus} onClick={() => createSession()} />
31
- <ActionIcon
32
- icon={Settings2}
33
- onClick={() => {
34
- router.push('/settings');
35
- }}
36
- />
37
- </>
34
+ <ActionIcon
35
+ icon={MessageSquarePlus}
36
+ onClick={() => createSession()}
37
+ size={MOBILE_HEADER_ICON_SIZE}
38
+ />
38
39
  }
39
40
  />
40
41
  );
@@ -1,14 +1,10 @@
1
- import { ActionIcon } from '@lobehub/ui';
2
- import { Drawer } from 'antd';
3
- import { useTheme } from 'antd-style';
4
- import { X } from 'lucide-react';
1
+ import { Modal } from '@lobehub/ui';
5
2
  import { PropsWithChildren, memo } from 'react';
6
3
  import { useTranslation } from 'react-i18next';
7
4
 
8
5
  import { useGlobalStore } from '@/store/global';
9
6
 
10
7
  const Mobile = memo<PropsWithChildren>(({ children }) => {
11
- const theme = useTheme();
12
8
  const [showAgentSettings, toggleConfig] = useGlobalStore((s) => [
13
9
  s.preference.mobileShowTopic,
14
10
  s.toggleMobileTopic,
@@ -17,19 +13,9 @@ const Mobile = memo<PropsWithChildren>(({ children }) => {
17
13
  const { t } = useTranslation('common');
18
14
 
19
15
  return (
20
- <Drawer
21
- bodyStyle={{ padding: 0 }}
22
- closeIcon={<ActionIcon icon={X} size={{ blockSize: 32, fontSize: 20 }} />}
23
- drawerStyle={{ background: theme.colorBgContainer }}
24
- headerStyle={{ padding: '8px 4px' }}
25
- height={'75vh'}
26
- onClose={() => toggleConfig(false)}
27
- open={showAgentSettings}
28
- placement={'bottom'}
29
- title={t('topic.title')}
30
- >
16
+ <Modal onCancel={() => toggleConfig(false)} open={showAgentSettings} title={t('topic.title')}>
31
17
  {children}
32
- </Drawer>
18
+ </Modal>
33
19
  );
34
20
  });
35
21
 
@@ -3,11 +3,12 @@ import { Flexbox } from 'react-layout-kit';
3
3
 
4
4
  import AppLayout from '@/layout/AppLayout';
5
5
  import { useSwitchSideBarOnInit } from '@/store/global';
6
+ import { SidebarTabKey } from '@/store/global/initialState';
6
7
 
7
8
  import { Sessions } from './features/SessionList';
8
9
 
9
10
  const ChatLayout = memo<PropsWithChildren>(({ children }) => {
10
- useSwitchSideBarOnInit('chat');
11
+ useSwitchSideBarOnInit(SidebarTabKey.Chat);
11
12
 
12
13
  return (
13
14
  <AppLayout>
@@ -2,12 +2,13 @@ import { memo } from 'react';
2
2
 
3
3
  import AppMobileLayout from '@/layout/AppMobileLayout';
4
4
  import { useSwitchSideBarOnInit } from '@/store/global';
5
+ import { SidebarTabKey } from '@/store/global/initialState';
5
6
 
6
7
  import { Sessions } from './features/SessionList';
7
8
  import Header from './features/SessionList/Header';
8
9
 
9
10
  const ChatMobileLayout = memo(() => {
10
- useSwitchSideBarOnInit('chat');
11
+ useSwitchSideBarOnInit(SidebarTabKey.Chat);
11
12
 
12
13
  return (
13
14
  <AppMobileLayout navBar={<Header />} showTabBar>
@@ -1,10 +1,11 @@
1
1
  import { ActionIcon } from '@lobehub/ui';
2
2
  import { Dropdown, MenuProps } from 'antd';
3
3
  import { useResponsive } from 'antd-style';
4
- import { HardDriveDownload, Share2 } from 'lucide-react';
4
+ import { HardDriveDownload } from 'lucide-react';
5
5
  import { memo, useMemo } from 'react';
6
6
  import { useTranslation } from 'react-i18next';
7
7
 
8
+ import { MOBILE_HEADER_ICON_SIZE } from '@/const/layoutTokens';
8
9
  import { exportSingleAgent, exportSingleSession } from '@/helpers/export';
9
10
  import { useSessionStore } from '@/store/session';
10
11
 
@@ -42,11 +43,10 @@ const Header = memo<{ mobile?: boolean }>(() => {
42
43
  [],
43
44
  );
44
45
 
45
- const size = mobile ? undefined : { fontSize: 24 };
46
+ const size = mobile ? MOBILE_HEADER_ICON_SIZE : { fontSize: 24 };
46
47
 
47
48
  return (
48
49
  <Render>
49
- <ActionIcon icon={Share2} size={size} title={t('share', { ns: 'common' })} />
50
50
  <Dropdown arrow={false} menu={{ items }} trigger={['click']}>
51
51
  <ActionIcon icon={HardDriveDownload} size={size} title={t('export', { ns: 'common' })} />
52
52
  </Dropdown>
@@ -1,18 +1,11 @@
1
1
  import { PropsWithChildren, memo } from 'react';
2
- import { Flexbox } from 'react-layout-kit';
3
2
 
4
3
  import AppMobileLayout from '@/layout/AppMobileLayout';
5
4
 
6
5
  import Header from './features/Header';
7
6
 
8
7
  const MobileLayout = memo<PropsWithChildren>(({ children }) => {
9
- return (
10
- <AppMobileLayout navBar={<Header />}>
11
- <Flexbox gap={16} padding={16}>
12
- {children}
13
- </Flexbox>
14
- </AppMobileLayout>
15
- );
8
+ return <AppMobileLayout navBar={<Header />}>{children}</AppMobileLayout>;
16
9
  });
17
10
 
18
11
  export default MobileLayout;
@@ -39,7 +39,7 @@ interface AgentCardBannerProps extends DivProps {
39
39
  }
40
40
 
41
41
  const AgentCardBanner = memo<AgentCardBannerProps>(
42
- ({ meta, className, mask, size = 8, maskColor, ...props }) => {
42
+ ({ meta, className, mask, size = 8, maskColor, children, ...props }) => {
43
43
  const { styles, theme, cx } = useStyles(maskColor);
44
44
 
45
45
  return (
@@ -56,6 +56,7 @@ const AgentCardBanner = memo<AgentCardBannerProps>(
56
56
  style={{ transform: `scale(${size})` }}
57
57
  />
58
58
  {mask && <div className={styles.bannerMask} />}
59
+ {children}
59
60
  </Flexbox>
60
61
  );
61
62
  },
@@ -1,27 +1,8 @@
1
- import { ActionIcon, Logo, MobileNavBar } from '@lobehub/ui';
2
- import { Settings2 } from 'lucide-react';
3
- import { useRouter } from 'next/navigation';
1
+ import { Logo, MobileNavBar } from '@lobehub/ui';
4
2
  import { memo } from 'react';
5
3
 
6
- import AvatarWithUpload from '@/features/AvatarWithUpload';
7
-
8
4
  const Header = memo(() => {
9
- const router = useRouter();
10
-
11
- return (
12
- <MobileNavBar
13
- center={<Logo type={'text'} />}
14
- left={<AvatarWithUpload size={28} style={{ marginLeft: 8 }} />}
15
- right={
16
- <ActionIcon
17
- icon={Settings2}
18
- onClick={() => {
19
- router.push('/settings');
20
- }}
21
- />
22
- }
23
- />
24
- );
5
+ return <MobileNavBar center={<Logo type={'text'} />} />;
25
6
  });
26
7
 
27
8
  export default Header;
@@ -6,6 +6,7 @@ import { useTranslation } from 'react-i18next';
6
6
  import { Center } from 'react-layout-kit';
7
7
 
8
8
  import { useGlobalStore } from '@/store/global';
9
+ import { SidebarTabKey } from '@/store/global/initialState';
9
10
  import { agentMarketSelectors, useMarketStore } from '@/store/market';
10
11
  import { useSessionStore } from '@/store/session';
11
12
 
@@ -54,7 +55,7 @@ const Header = memo(() => {
54
55
  if (!agentItem) return;
55
56
 
56
57
  createSession({ config, meta });
57
- switchSideBar('chat');
58
+ switchSideBar(SidebarTabKey.Chat);
58
59
  }}
59
60
  type={'primary'}
60
61
  >
@@ -1,4 +1,5 @@
1
1
  import { Markdown, TabsNav } from '@lobehub/ui';
2
+ import { useResponsive } from 'antd-style';
2
3
  import { memo, useState } from 'react';
3
4
  import { useTranslation } from 'react-i18next';
4
5
  import { Flexbox } from 'react-layout-kit';
@@ -22,7 +23,8 @@ const AgentModalInner = memo(() => {
22
23
  s.useFetchAgent,
23
24
  s.currentIdentifier,
24
25
  ]);
25
- const { styles } = useStyles();
26
+ const { styles, theme } = useStyles();
27
+ const { mobile } = useResponsive();
26
28
  const { data, isLoading } = useFetchAgent(currentIdentifier);
27
29
  const { t } = useTranslation('market');
28
30
  const [tab, setTab] = useState<string>(InfoTabs.prompt);
@@ -34,7 +36,13 @@ const AgentModalInner = memo(() => {
34
36
 
35
37
  return (
36
38
  <>
37
- <AgentCardBanner mask meta={meta} size={10} style={{ height: 120, marginBottom: -60 }} />
39
+ <AgentCardBanner
40
+ mask
41
+ maskColor={mobile ? theme.colorBgContainer : undefined}
42
+ meta={meta}
43
+ size={10}
44
+ style={{ height: 120, marginBottom: -60 }}
45
+ />
38
46
  <Header />
39
47
  <Flexbox align={'center'}>
40
48
  <TabsNav
@@ -1,14 +1,10 @@
1
- import { ActionIcon } from '@lobehub/ui';
2
- import { Drawer } from 'antd';
3
- import { useTheme } from 'antd-style';
4
- import { X } from 'lucide-react';
1
+ import { Modal } from '@lobehub/ui';
5
2
  import { PropsWithChildren, memo } from 'react';
6
3
  import { useTranslation } from 'react-i18next';
7
4
 
8
5
  import { agentMarketSelectors, useMarketStore } from '@/store/market';
9
6
 
10
7
  const Mobile = memo<PropsWithChildren>(({ children }) => {
11
- const theme = useTheme();
12
8
  const [showAgentSidebar, deactivateAgent] = useMarketStore((s) => [
13
9
  agentMarketSelectors.showSideBar(s),
14
10
  s.deactivateAgent,
@@ -17,19 +13,9 @@ const Mobile = memo<PropsWithChildren>(({ children }) => {
17
13
  const { t } = useTranslation('market');
18
14
 
19
15
  return (
20
- <Drawer
21
- bodyStyle={{ padding: 0 }}
22
- closeIcon={<ActionIcon icon={X} size={{ blockSize: 32, fontSize: 20 }} />}
23
- drawerStyle={{ background: theme.colorBgLayout }}
24
- headerStyle={{ padding: '8px 4px' }}
25
- height={'75vh'}
26
- onClose={deactivateAgent}
27
- open={showAgentSidebar}
28
- placement={'bottom'}
29
- title={t('sidebar.title')}
30
- >
16
+ <Modal onCancel={deactivateAgent} open={showAgentSidebar} title={t('sidebar.title')}>
31
17
  {children}
32
- </Drawer>
18
+ </Modal>
33
19
  );
34
20
  });
35
21
 
@@ -6,6 +6,7 @@ import { Center, Flexbox } from 'react-layout-kit';
6
6
  import SafeSpacing from '@/components/SafeSpacing';
7
7
  import { MAX_WIDTH } from '@/const/layoutTokens';
8
8
  import { useSwitchSideBarOnInit } from '@/store/global';
9
+ import { SidebarTabKey } from '@/store/global/initialState';
9
10
 
10
11
  import AppLayout from '../../layout/AppLayout';
11
12
  import Header from './features/Header';
@@ -27,7 +28,7 @@ const useStyles = createStyles(({ css }) => ({
27
28
  const MarketLayout = memo<PropsWithChildren>(({ children }) => {
28
29
  const { theme, styles } = useStyles();
29
30
 
30
- useSwitchSideBarOnInit('market');
31
+ useSwitchSideBarOnInit(SidebarTabKey.Market);
31
32
 
32
33
  return (
33
34
  <AppLayout>
@@ -3,12 +3,13 @@ import { Flexbox } from 'react-layout-kit';
3
3
 
4
4
  import AppMobileLayout from '@/layout/AppMobileLayout';
5
5
  import { useSwitchSideBarOnInit } from '@/store/global';
6
+ import { SidebarTabKey } from '@/store/global/initialState';
6
7
 
7
8
  import Header from './features/Header';
8
9
  import SideBar from './features/SideBar';
9
10
 
10
11
  const MarketLayout = memo<{ children: ReactNode }>(({ children }) => {
11
- useSwitchSideBarOnInit('market');
12
+ useSwitchSideBarOnInit(SidebarTabKey.Market);
12
13
 
13
14
  return (
14
15
  <AppMobileLayout navBar={<Header />} showTabBar>
@@ -0,0 +1,20 @@
1
+ 'use client';
2
+
3
+ import { memo } from 'react';
4
+
5
+ import { useSwitchSideBarOnInit } from '@/store/global/hooks/useSwitchSettingsOnInit';
6
+ import { SettingsTabs } from '@/store/global/initialState';
7
+
8
+ import Layout from '../index';
9
+ import Agent from './Agent';
10
+
11
+ const AgentSetting = memo(() => {
12
+ useSwitchSideBarOnInit(SettingsTabs.Agent);
13
+ return (
14
+ <Layout>
15
+ <Agent />
16
+ </Layout>
17
+ );
18
+ });
19
+
20
+ export default AgentSetting;
@@ -0,0 +1,7 @@
1
+ import Page from './index';
2
+
3
+ const Index = () => {
4
+ return <Page />;
5
+ };
6
+
7
+ export default Index;
@@ -15,7 +15,7 @@ import { useSessionStore } from '@/store/session';
15
15
  import { ConfigKeys } from '@/types/settings';
16
16
  import { switchLang } from '@/utils/switchLang';
17
17
 
18
- import { ThemeSwatchesNeutral, ThemeSwatchesPrimary } from '../ThemeSwatches';
18
+ import { ThemeSwatchesNeutral, ThemeSwatchesPrimary } from '../features/ThemeSwatches';
19
19
 
20
20
  type SettingItemGroup = ItemGroup & {
21
21
  children: {
@@ -0,0 +1,20 @@
1
+ 'use client';
2
+
3
+ import { memo } from 'react';
4
+
5
+ import { useSwitchSideBarOnInit } from '@/store/global/hooks/useSwitchSettingsOnInit';
6
+ import { SettingsTabs } from '@/store/global/initialState';
7
+
8
+ import Layout from '../index';
9
+ import Common from './Common';
10
+
11
+ const CommonSetting = memo(() => {
12
+ useSwitchSideBarOnInit(SettingsTabs.Common);
13
+ return (
14
+ <Layout>
15
+ <Common />
16
+ </Layout>
17
+ );
18
+ });
19
+
20
+ export default CommonSetting;
@@ -0,0 +1,7 @@
1
+ import Page from './index';
2
+
3
+ const Index = () => {
4
+ return <Page />;
5
+ };
6
+
7
+ export default Index;
@@ -1,13 +1,20 @@
1
- import { ChatHeader, ChatHeaderTitle, Logo } from '@lobehub/ui';
1
+ import { ChatHeader, ChatHeaderTitle } from '@lobehub/ui';
2
2
  import { memo } from 'react';
3
3
  import { useTranslation } from 'react-i18next';
4
4
 
5
+ import { useGlobalStore } from '@/store/global';
6
+
5
7
  const Index = memo(() => {
6
8
  const { t } = useTranslation('setting');
9
+ const tab = useGlobalStore((s) => s.settingsTab);
7
10
 
8
11
  return (
9
12
  <ChatHeader
10
- left={<ChatHeaderTitle title={<Logo extra={t('header.global')} type={'text'} />} />}
13
+ left={
14
+ <div style={{ paddingLeft: 8 }}>
15
+ <ChatHeaderTitle title={t(`tab.${tab}`)} />
16
+ </div>
17
+ }
11
18
  />
12
19
  );
13
20
  });
@@ -3,14 +3,17 @@ import { useRouter } from 'next/navigation';
3
3
  import { memo } from 'react';
4
4
  import { useTranslation } from 'react-i18next';
5
5
 
6
+ import { useGlobalStore } from '@/store/global';
7
+
6
8
  const Header = memo(() => {
7
9
  const { t } = useTranslation('setting');
10
+ const tab = useGlobalStore((s) => s.settingsTab);
8
11
  const router = useRouter();
9
12
 
10
13
  return (
11
14
  <MobileNavBar
12
- center={<MobileNavBarTitle title={t('header.global')} />}
13
- onBackClick={() => router.push('/chat')}
15
+ center={<MobileNavBarTitle title={t(`tab.${tab}`)} />}
16
+ onBackClick={() => router.back()}
14
17
  showBackButton
15
18
  />
16
19
  );
@@ -0,0 +1,39 @@
1
+ import { Icon, List } from '@lobehub/ui';
2
+ import { createStyles, useResponsive } from 'antd-style';
3
+ import { ChevronRight, type LucideIcon } from 'lucide-react';
4
+ import { CSSProperties, ReactNode, memo } from 'react';
5
+
6
+ const { Item } = List;
7
+
8
+ const useStyles = createStyles(({ css }) => ({
9
+ container: css`
10
+ padding-top: 20px;
11
+ padding-bottom: 20px;
12
+ `,
13
+ }));
14
+
15
+ export interface ItemProps {
16
+ active?: boolean;
17
+ className?: string;
18
+ icon: LucideIcon;
19
+ label: ReactNode;
20
+ style?: CSSProperties;
21
+ }
22
+
23
+ const SettingItem = memo<ItemProps>(({ label, icon, active = false, style, className }) => {
24
+ const { cx, styles } = useStyles();
25
+ const { mobile } = useResponsive();
26
+ return (
27
+ <Item
28
+ active={active}
29
+ avatar={<Icon icon={icon} size={{ fontSize: 16 }} />}
30
+ className={cx(styles.container, className)}
31
+ style={style}
32
+ title={label as string}
33
+ >
34
+ {mobile && <Icon icon={ChevronRight} size={{ fontSize: 16 }} />}
35
+ </Item>
36
+ );
37
+ });
38
+
39
+ export default SettingItem;
@@ -0,0 +1,30 @@
1
+ import { useResponsive } from 'antd-style';
2
+ import { Bot, Settings2, Webhook } from 'lucide-react';
3
+ import { useRouter } from 'next/navigation';
4
+ import { memo } from 'react';
5
+ import { useTranslation } from 'react-i18next';
6
+
7
+ import { useGlobalStore } from '@/store/global';
8
+ import { SettingsTabs } from '@/store/global/initialState';
9
+
10
+ import Item from './Item';
11
+
12
+ const List = memo(() => {
13
+ const { t } = useTranslation('setting');
14
+ const tab = useGlobalStore((s) => s.settingsTab);
15
+ const router = useRouter();
16
+ const { mobile } = useResponsive();
17
+ const items = [
18
+ { icon: Settings2, label: t('tab.common'), value: SettingsTabs.Common },
19
+ { icon: Webhook, label: t('tab.llm'), value: SettingsTabs.LLM },
20
+ { icon: Bot, label: t('tab.agent'), value: SettingsTabs.Agent },
21
+ ];
22
+
23
+ return items.map(({ value, icon, label }) => (
24
+ <div key={value} onClick={() => router.push(`/settings/${value}`)}>
25
+ <Item active={mobile ? false : tab === value} icon={icon} label={label} />
26
+ </div>
27
+ ));
28
+ });
29
+
30
+ export default List;