@lobehub/chat 0.82.1 → 0.82.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 (70) hide show
  1. package/CHANGELOG.md +25 -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/Header/Mobile.tsx +12 -7
  12. package/src/app/chat/features/Header/ShareButton/Inner.tsx +31 -26
  13. package/src/app/chat/features/Header/ShareButton/index.tsx +6 -1
  14. package/src/app/chat/features/SessionList/Header/Desktop.tsx +2 -4
  15. package/src/app/chat/features/SessionList/Header/Mobile.tsx +15 -14
  16. package/src/app/chat/features/Sidebar/Mobile.tsx +3 -17
  17. package/src/app/chat/layout.desktop.tsx +2 -1
  18. package/src/app/chat/layout.mobile.tsx +2 -1
  19. package/src/app/chat/settings/features/Header/index.tsx +3 -3
  20. package/src/app/chat/settings/layout.mobile.tsx +1 -8
  21. package/src/app/market/features/AgentCard/AgentCardBanner.tsx +2 -1
  22. package/src/app/market/features/Header/Mobile.tsx +2 -21
  23. package/src/app/market/features/SideBar/AgentInfo/Header.tsx +2 -1
  24. package/src/app/market/features/SideBar/AgentInfo/index.tsx +10 -2
  25. package/src/app/market/features/SideBar/Mobile.tsx +3 -17
  26. package/src/app/market/layout.desktop.tsx +2 -1
  27. package/src/app/market/layout.mobile.tsx +2 -1
  28. package/src/app/settings/agent/index.tsx +20 -0
  29. package/src/app/settings/agent/page.tsx +7 -0
  30. package/src/app/settings/{features/Settings → common}/Common.tsx +1 -1
  31. package/src/app/settings/common/index.tsx +20 -0
  32. package/src/app/settings/common/page.tsx +7 -0
  33. package/src/app/settings/features/Header/Desktop.tsx +9 -2
  34. package/src/app/settings/features/Header/Mobile.tsx +5 -2
  35. package/src/app/settings/features/SideBar/Item.tsx +39 -0
  36. package/src/app/settings/features/SideBar/List.tsx +30 -0
  37. package/src/app/settings/features/SideBar/index.tsx +38 -0
  38. package/src/app/settings/index.tsx +5 -7
  39. package/src/app/settings/layout.desktop.tsx +6 -2
  40. package/src/app/settings/layout.mobile.tsx +1 -3
  41. package/src/app/settings/{features/Settings → llm}/LLM/index.tsx +4 -2
  42. package/src/app/settings/llm/index.tsx +20 -0
  43. package/src/app/settings/llm/page.tsx +7 -0
  44. package/src/app/settings/mobile/ExtraList.tsx +61 -0
  45. package/src/app/settings/mobile/index.tsx +43 -0
  46. package/src/app/settings/mobile/page.tsx +7 -0
  47. package/src/app/settings/page.tsx +1 -7
  48. package/src/components/MobilePadding/index.tsx +32 -0
  49. package/src/const/layoutTokens.ts +1 -0
  50. package/src/features/AgentSetting/AgentMeta/index.tsx +0 -1
  51. package/src/features/AgentSetting/AgentPlugin/MarketSettingModal.tsx +29 -16
  52. package/src/features/MobileTabBar/index.tsx +15 -3
  53. package/src/features/PluginDevModal/PluginPreview.tsx +11 -4
  54. package/src/features/PluginDevModal/index.tsx +14 -10
  55. package/src/features/SideBar/BottomActions.tsx +3 -3
  56. package/src/features/SideBar/TopActions.tsx +5 -4
  57. package/src/locales/default/common.ts +1 -1
  58. package/src/locales/default/plugin.ts +2 -1
  59. package/src/store/global/hooks/useSwitchSettingsOnInit.ts +9 -0
  60. package/src/store/global/initialState.ts +13 -4
  61. package/src/store/global/store.ts +0 -4
  62. package/src/store/session/slices/chat/actions/share.ts +1 -1
  63. package/src/styles/antdOverride.ts +2 -26
  64. package/src/styles/global.ts +9 -0
  65. package/src/app/settings/features/Banner/index.tsx +0 -94
  66. package/src/app/settings/features/Settings/index.tsx +0 -53
  67. /package/src/app/settings/{features/Settings → agent}/Agent.tsx +0 -0
  68. /package/src/app/settings/{features/Settings → llm}/LLM/Checker.tsx +0 -0
  69. /package/src/app/settings/{features/Settings → llm}/LLM/ModelList.tsx +0 -0
  70. /package/src/app/settings/{features/Settings → llm}/LLM/getModelList.ts +0 -0
@@ -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;
@@ -0,0 +1,38 @@
1
+ import { DraggablePanelBody, Logo } from '@lobehub/ui';
2
+ import { createStyles } from 'antd-style';
3
+ import { memo } from 'react';
4
+ import { Flexbox } from 'react-layout-kit';
5
+
6
+ import FolderPanel from '@/features/FolderPanel';
7
+
8
+ import List from './List';
9
+
10
+ const useStyles = createStyles(({ stylish, token, css }) => ({
11
+ body: stylish.noScrollbar,
12
+ logo: css`
13
+ fill: ${token.colorText};
14
+ `,
15
+ top: css`
16
+ position: sticky;
17
+ top: 0;
18
+ `,
19
+ }));
20
+
21
+ const SideBar = memo(() => {
22
+ const { styles } = useStyles();
23
+
24
+ return (
25
+ <FolderPanel>
26
+ <DraggablePanelBody className={styles.body} style={{ padding: 0 }}>
27
+ <Flexbox className={styles.top} padding={16}>
28
+ <div>
29
+ <Logo className={styles.logo} size={36} type={'text'} />
30
+ </div>
31
+ </Flexbox>
32
+ <List />
33
+ </DraggablePanelBody>
34
+ </FolderPanel>
35
+ );
36
+ });
37
+
38
+ export default SideBar;
@@ -2,33 +2,31 @@
2
2
 
3
3
  import { useResponsive } from 'antd-style';
4
4
  import Head from 'next/head';
5
- import { memo } from 'react';
5
+ import { ReactNode, memo } from 'react';
6
6
  import { useTranslation } from 'react-i18next';
7
7
 
8
8
  import { useSwitchSideBarOnInit } from '@/store/global';
9
+ import { SidebarTabKey } from '@/store/global/initialState';
9
10
  import { genSiteHeadTitle } from '@/utils/genSiteHeadTitle';
10
11
 
11
- import Settings from './features/Settings';
12
12
  import DesktopLayout from './layout.desktop';
13
13
  import MobileLayout from './layout.mobile';
14
14
 
15
- const Setting = memo(() => {
15
+ const Setting = memo<{ children: ReactNode }>(({ children }) => {
16
16
  const { mobile } = useResponsive();
17
17
  const { t } = useTranslation('setting');
18
18
  const pageTitle = genSiteHeadTitle(t('header.global'));
19
19
 
20
20
  const RenderLayout = mobile ? MobileLayout : DesktopLayout;
21
21
 
22
- useSwitchSideBarOnInit('settings');
22
+ useSwitchSideBarOnInit(SidebarTabKey.Setting);
23
23
 
24
24
  return (
25
25
  <>
26
26
  <Head>
27
27
  <title>{pageTitle}</title>
28
28
  </Head>
29
- <RenderLayout>
30
- <Settings />
31
- </RenderLayout>
29
+ <RenderLayout>{children}</RenderLayout>
32
30
  </>
33
31
  );
34
32
  });
@@ -1,19 +1,23 @@
1
1
  import { ReactNode, memo } from 'react';
2
- import { Flexbox } from 'react-layout-kit';
2
+ import { Center, Flexbox } from 'react-layout-kit';
3
3
 
4
4
  import SafeSpacing from '@/components/SafeSpacing';
5
5
  import AppLayout from '@/layout/AppLayout';
6
6
 
7
7
  import Header from './features/Header';
8
+ import SideBar from './features/SideBar';
8
9
 
9
10
  const SettingLayout = memo<{ children: ReactNode }>(({ children }) => {
10
11
  return (
11
12
  <AppLayout>
13
+ <SideBar />
12
14
  <Flexbox flex={1} height={'100vh'} style={{ position: 'relative' }}>
13
15
  <Header />
14
16
  <Flexbox align={'center'} flex={1} padding={24} style={{ overflow: 'auto' }}>
15
17
  <SafeSpacing />
16
- {children}
18
+ <Center gap={16} width={'100%'}>
19
+ {children}
20
+ </Center>
17
21
  </Flexbox>
18
22
  </Flexbox>
19
23
  </AppLayout>
@@ -8,9 +8,7 @@ import Header from './features/Header';
8
8
  const SettingLayout = memo<{ children: ReactNode }>(({ children }) => {
9
9
  return (
10
10
  <AppMobileLayout navBar={<Header />}>
11
- <Flexbox align={'center'} padding={16} style={{ overflow: 'auto' }}>
12
- {children}
13
- </Flexbox>
11
+ <Flexbox style={{ overflow: 'auto' }}>{children}</Flexbox>
14
12
  </AppMobileLayout>
15
13
  );
16
14
  });
@@ -1,4 +1,4 @@
1
- import { Form, Markdown } from '@lobehub/ui';
1
+ import { Form, type ItemGroup, Markdown } from '@lobehub/ui';
2
2
  import { Form as AntForm, AutoComplete, Input, Switch } from 'antd';
3
3
  import { createStyles } from 'antd-style';
4
4
  import { debounce } from 'lodash-es';
@@ -49,7 +49,7 @@ const LLM = memo(() => {
49
49
 
50
50
  const useAzure = useGlobalStore((s) => s.settings.languageModel.openAI.useAzure);
51
51
 
52
- const openAI = {
52
+ const openAI: ItemGroup = {
53
53
  children: [
54
54
  {
55
55
  children: (
@@ -94,6 +94,7 @@ const LLM = memo(() => {
94
94
  ),
95
95
  desc: t('llm.OpenAI.useAzure.desc'),
96
96
  label: t('llm.OpenAI.useAzure.title'),
97
+ minWidth: undefined,
97
98
  name: [configKey, 'openAI', 'useAzure'],
98
99
  valuePropName: 'checked',
99
100
  },
@@ -124,6 +125,7 @@ const LLM = memo(() => {
124
125
  children: <Checker checkModel={!useAzure} />,
125
126
  desc: t('llm.OpenAI.check.desc'),
126
127
  label: t('llm.OpenAI.check.title'),
128
+ minWidth: undefined,
127
129
  },
128
130
  // {
129
131
  // children: useAzure ? <Flexbox>{t('llm.OpenAI.models.notSupport')}</Flexbox> : <ModelList />,
@@ -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 LLM from './LLM';
10
+
11
+ const LLMSetting = memo(() => {
12
+ useSwitchSideBarOnInit(SettingsTabs.LLM);
13
+ return (
14
+ <Layout>
15
+ <LLM />
16
+ </Layout>
17
+ );
18
+ });
19
+
20
+ export default LLMSetting;
@@ -0,0 +1,7 @@
1
+ import Page from './index';
2
+
3
+ const Index = () => {
4
+ return <Page />;
5
+ };
6
+
7
+ export default Index;
@@ -0,0 +1,61 @@
1
+ import { Upload } from 'antd';
2
+ import { useResponsive } from 'antd-style';
3
+ import { Feather, FileClock, HardDriveDownload, HardDriveUpload, Heart } from 'lucide-react';
4
+ import { memo } from 'react';
5
+ import { useTranslation } from 'react-i18next';
6
+
7
+ import { ABOUT, CHANGELOG, FEEDBACK } from '@/const/url';
8
+ import { useExportConfig } from '@/hooks/useExportConfig';
9
+ import { useImportConfig } from '@/hooks/useImportConfig';
10
+ import { useGlobalStore } from '@/store/global';
11
+
12
+ import Item from '../features/SideBar/Item';
13
+
14
+ const ExtraList = memo(() => {
15
+ const { t } = useTranslation('common');
16
+ const { exportAll } = useExportConfig();
17
+ const { importConfig } = useImportConfig();
18
+ const tab = useGlobalStore((s) => s.settingsTab);
19
+ const { mobile } = useResponsive();
20
+ const items = [
21
+ {
22
+ icon: HardDriveDownload,
23
+ label: t('export'),
24
+ onClick: exportAll,
25
+ value: 'export',
26
+ },
27
+ {
28
+ icon: Feather,
29
+ label: t('feedback'),
30
+ onClick: () => window.open(FEEDBACK, '__blank'),
31
+ value: 'feedback',
32
+ },
33
+ {
34
+ icon: FileClock,
35
+ label: t('changelog'),
36
+ onClick: () => window.open(CHANGELOG, '__blank'),
37
+ value: 'changelog',
38
+ },
39
+ {
40
+ icon: Heart,
41
+ label: t('about'),
42
+ onClick: () => window.open(ABOUT, '__blank'),
43
+ value: 'about',
44
+ },
45
+ ];
46
+
47
+ return (
48
+ <>
49
+ <Upload maxCount={1} onChange={importConfig} showUploadList={false}>
50
+ <Item icon={HardDriveUpload} label={t('import')} style={{ width: '100vw' }} />
51
+ </Upload>
52
+ {items.map(({ value, icon, label, onClick }) => (
53
+ <div key={value} onClick={onClick}>
54
+ <Item active={mobile ? false : tab === value} icon={icon} label={label} />
55
+ </div>
56
+ ))}
57
+ </>
58
+ );
59
+ });
60
+
61
+ export default ExtraList;