@lobehub/chat 0.57.0 → 0.58.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.
Files changed (38) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/package.json +1 -1
  3. package/src/components/SafeSpacing/index.tsx +27 -0
  4. package/src/const/layoutTokens.ts +2 -0
  5. package/src/features/AvatarWithUpload/index.tsx +4 -3
  6. package/src/features/MobileTabBar/index.tsx +60 -0
  7. package/src/features/SideBar/TopActions.tsx +1 -1
  8. package/src/layout/AppMobileLayout.tsx +76 -0
  9. package/src/locales/default/common.ts +3 -1
  10. package/src/pages/chat/SessionList/Header.tsx +26 -2
  11. package/src/pages/chat/SessionList/index.tsx +10 -1
  12. package/src/pages/chat/[id]/index.page.tsx +19 -7
  13. package/src/pages/chat/[id]/mobile.tsx +31 -0
  14. package/src/pages/chat/[id]/setting/Header.tsx +25 -2
  15. package/src/pages/chat/[id]/setting/index.page.tsx +33 -16
  16. package/src/pages/chat/[id]/setting/mobile.tsx +11 -0
  17. package/src/pages/chat/features/Conversation/index.tsx +5 -5
  18. package/src/pages/chat/features/Header/Mobile.tsx +47 -0
  19. package/src/pages/chat/features/Header/PC.tsx +101 -0
  20. package/src/pages/chat/features/Header/index.tsx +7 -93
  21. package/src/pages/chat/features/Sidebar/Header.tsx +6 -4
  22. package/src/pages/chat/features/Sidebar/Mobile.tsx +36 -0
  23. package/src/pages/chat/features/Sidebar/SystemRole.tsx +2 -2
  24. package/src/pages/chat/features/Sidebar/index.tsx +33 -15
  25. package/src/pages/chat/index.page.tsx +14 -8
  26. package/src/pages/chat/layout.tsx +12 -8
  27. package/src/pages/chat/mobile.tsx +25 -0
  28. package/src/pages/settings/index.page.tsx +40 -8
  29. package/src/pages/settings/layout.tsx +5 -27
  30. package/src/pages/settings/mobile.tsx +20 -0
  31. package/src/pages/welcome/Banner/Hero.tsx +3 -5
  32. package/src/pages/welcome/Banner/index.tsx +5 -5
  33. package/src/pages/welcome/index.page.tsx +13 -4
  34. package/src/pages/welcome/mobile.tsx +20 -0
  35. package/src/pages/welcome/style.ts +2 -2
  36. package/src/store/global/initialState.ts +2 -0
  37. package/src/store/global/slices/common.ts +7 -0
  38. package/src/components/HeaderSpacing/index.tsx +0 -9
@@ -0,0 +1,101 @@
1
+ import { SiOpenai } from '@icons-pack/react-simple-icons';
2
+ import { ActionIcon, Avatar, ChatHeader, ChatHeaderTitle, Tag } from '@lobehub/ui';
3
+ import { Skeleton } from 'antd';
4
+ import { PanelRightClose, PanelRightOpen, Settings } from 'lucide-react';
5
+ import Router from 'next/router';
6
+ import { memo } from 'react';
7
+ import { useTranslation } from 'react-i18next';
8
+ import { Flexbox } from 'react-layout-kit';
9
+
10
+ import { INBOX_SESSION_ID } from '@/const/session';
11
+ import { useGlobalStore } from '@/store/global';
12
+ import { agentSelectors, useSessionChatInit, useSessionStore } from '@/store/session';
13
+
14
+ import PluginTag from './PluginTag';
15
+
16
+ const Header = memo<{ settings?: boolean }>(({ settings = true }) => {
17
+ const init = useSessionChatInit();
18
+
19
+ const { t } = useTranslation('common');
20
+
21
+ const [id, title, description, avatar, backgroundColor, model, plugins] = useSessionStore((s) => [
22
+ s.activeId,
23
+
24
+ agentSelectors.currentAgentTitle(s),
25
+ agentSelectors.currentAgentDescription(s),
26
+ agentSelectors.currentAgentAvatar(s),
27
+ agentSelectors.currentAgentBackgroundColor(s),
28
+ agentSelectors.currentAgentModel(s),
29
+ agentSelectors.currentAgentPlugins(s),
30
+ ]);
31
+
32
+ const isInbox = id === INBOX_SESSION_ID;
33
+ const [showAgentSettings, toggleConfig] = useGlobalStore((s) => [
34
+ s.preference.showChatSideBar,
35
+ s.toggleChatSideBar,
36
+ ]);
37
+
38
+ const displayTitle = isInbox ? t('inbox.title') : title;
39
+ const displayDesc = isInbox ? t('inbox.desc') : description;
40
+
41
+ return (
42
+ <ChatHeader
43
+ left={
44
+ !init ? (
45
+ <Flexbox horizontal>
46
+ <Skeleton
47
+ active
48
+ avatar={{ shape: 'circle', size: 'default' }}
49
+ paragraph={false}
50
+ title={{ style: { margin: 0, marginTop: 8 }, width: 200 }}
51
+ />
52
+ </Flexbox>
53
+ ) : (
54
+ <Flexbox align={'flex-start'} gap={12} horizontal>
55
+ <Avatar avatar={avatar} background={backgroundColor} size={40} title={title} />
56
+ <ChatHeaderTitle
57
+ desc={displayDesc}
58
+ tag={
59
+ <>
60
+ <Tag icon={<SiOpenai size={'1em'} />}>{model}</Tag>
61
+ {plugins?.length > 0 && <PluginTag plugins={plugins} />}
62
+ </>
63
+ }
64
+ title={displayTitle}
65
+ />
66
+ </Flexbox>
67
+ )
68
+ }
69
+ right={
70
+ <>
71
+ {/*<ActionIcon*/}
72
+ {/* icon={Share2}*/}
73
+ {/* onClick={() => {*/}
74
+ {/* // genShareUrl();*/}
75
+ {/* }}*/}
76
+ {/* size={{ fontSize: 24 }}*/}
77
+ {/* title={t('share')}*/}
78
+ {/*/>*/}
79
+ <ActionIcon
80
+ icon={showAgentSettings ? PanelRightClose : PanelRightOpen}
81
+ onClick={() => toggleConfig()}
82
+ size={{ fontSize: 24 }}
83
+ title={t('roleAndArchive')}
84
+ />
85
+ {settings && (
86
+ <ActionIcon
87
+ icon={Settings}
88
+ onClick={() => {
89
+ Router.push(`/chat/${id}/setting`);
90
+ }}
91
+ size={{ fontSize: 24 }}
92
+ title={t('header.session', { ns: 'setting' })}
93
+ />
94
+ )}
95
+ </>
96
+ }
97
+ />
98
+ );
99
+ });
100
+
101
+ export default Header;
@@ -1,101 +1,15 @@
1
- import { SiOpenai } from '@icons-pack/react-simple-icons';
2
- import { ActionIcon, Avatar, ChatHeader, ChatHeaderTitle, Tag } from '@lobehub/ui';
3
- import { Skeleton } from 'antd';
4
- import { PanelRightClose, PanelRightOpen, Settings } from 'lucide-react';
5
- import Router from 'next/router';
1
+ import { useResponsive } from 'antd-style';
6
2
  import { memo } from 'react';
7
- import { useTranslation } from 'react-i18next';
8
- import { Flexbox } from 'react-layout-kit';
9
3
 
10
- import { INBOX_SESSION_ID } from '@/const/session';
11
- import { useGlobalStore } from '@/store/global';
12
- import { agentSelectors, useSessionChatInit, useSessionStore } from '@/store/session';
4
+ import Mobile from './Mobile';
5
+ import PC from './PC';
13
6
 
14
- import PluginTag from './PluginTag';
7
+ const Header = memo<{ settings?: boolean }>((props) => {
8
+ const { mobile } = useResponsive();
15
9
 
16
- const Header = memo<{ settings?: boolean }>(({ settings = true }) => {
17
- const init = useSessionChatInit();
10
+ if (mobile) return <Mobile {...props} />;
18
11
 
19
- const { t } = useTranslation('common');
20
-
21
- const [id, title, description, avatar, backgroundColor, model, plugins] = useSessionStore((s) => [
22
- s.activeId,
23
-
24
- agentSelectors.currentAgentTitle(s),
25
- agentSelectors.currentAgentDescription(s),
26
- agentSelectors.currentAgentAvatar(s),
27
- agentSelectors.currentAgentBackgroundColor(s),
28
- agentSelectors.currentAgentModel(s),
29
- agentSelectors.currentAgentPlugins(s),
30
- ]);
31
-
32
- const isInbox = id === INBOX_SESSION_ID;
33
- const [showAgentSettings, toggleConfig] = useGlobalStore((s) => [
34
- s.preference.showChatSideBar,
35
- s.toggleChatSideBar,
36
- ]);
37
-
38
- const displayTitle = isInbox ? t('inbox.title') : title;
39
- const displayDesc = isInbox ? t('inbox.desc') : description;
40
-
41
- return (
42
- <ChatHeader
43
- left={
44
- !init ? (
45
- <Flexbox horizontal>
46
- <Skeleton
47
- active
48
- avatar={{ shape: 'circle', size: 'default' }}
49
- paragraph={false}
50
- title={{ style: { margin: 0, marginTop: 8 }, width: 200 }}
51
- />
52
- </Flexbox>
53
- ) : (
54
- <Flexbox align={'flex-start'} gap={12} horizontal>
55
- <Avatar avatar={avatar} background={backgroundColor} size={40} title={title} />
56
- <ChatHeaderTitle
57
- desc={displayDesc}
58
- tag={
59
- <>
60
- <Tag icon={<SiOpenai size={'1em'} />}>{model}</Tag>
61
- {plugins?.length > 0 && <PluginTag plugins={plugins} />}
62
- </>
63
- }
64
- title={displayTitle}
65
- />
66
- </Flexbox>
67
- )
68
- }
69
- right={
70
- <>
71
- {/*<ActionIcon*/}
72
- {/* icon={Share2}*/}
73
- {/* onClick={() => {*/}
74
- {/* // genShareUrl();*/}
75
- {/* }}*/}
76
- {/* size={{ fontSize: 24 }}*/}
77
- {/* title={t('share')}*/}
78
- {/*/>*/}
79
- <ActionIcon
80
- icon={showAgentSettings ? PanelRightClose : PanelRightOpen}
81
- onClick={() => toggleConfig()}
82
- size={{ fontSize: 24 }}
83
- title={t('roleAndArchive')}
84
- />
85
- {settings && (
86
- <ActionIcon
87
- icon={Settings}
88
- onClick={() => {
89
- Router.push(`/chat/${id}/setting`);
90
- }}
91
- size={{ fontSize: 24 }}
92
- title={t('header.session', { ns: 'setting' })}
93
- />
94
- )}
95
- </>
96
- }
97
- />
98
- );
12
+ return <PC {...props} />;
99
13
  });
100
14
 
101
15
  export default Header;
@@ -2,24 +2,26 @@ import { createStyles } from 'antd-style';
2
2
  import { type ReactNode, memo } from 'react';
3
3
  import { Flexbox } from 'react-layout-kit';
4
4
 
5
- const useStyles = createStyles(
6
- ({ css, token }) => css`
5
+ const useStyles = createStyles(({ css, token }) => ({
6
+ header: css`
7
7
  z-index: 10;
8
8
  box-shadow: 0 2px 6px ${token.colorBgLayout};
9
9
  `,
10
- );
10
+ }));
11
11
 
12
12
  interface HeaderProps {
13
13
  actions?: ReactNode;
14
+ mobile?: boolean;
14
15
  title: string;
15
16
  }
16
17
 
17
18
  const Header = memo<HeaderProps>(({ title, actions }) => {
18
19
  const { styles } = useStyles();
20
+
19
21
  return (
20
22
  <Flexbox
21
23
  align={'center'}
22
- className={styles}
24
+ className={styles.header}
23
25
  distribution={'space-between'}
24
26
  horizontal
25
27
  padding={12}
@@ -0,0 +1,36 @@
1
+ import { ActionIcon } from '@lobehub/ui';
2
+ import { Drawer } from 'antd';
3
+ import { useTheme } from 'antd-style';
4
+ import { X } from 'lucide-react';
5
+ import { PropsWithChildren, memo } from 'react';
6
+ import { useTranslation } from 'react-i18next';
7
+
8
+ import { useGlobalStore } from '@/store/global';
9
+
10
+ const Mobile = memo<PropsWithChildren>(({ children }) => {
11
+ const theme = useTheme();
12
+ const [showAgentSettings, toggleConfig] = useGlobalStore((s) => [
13
+ s.preference.mobileShowTopic,
14
+ s.toggleMobileTopic,
15
+ ]);
16
+
17
+ const { t } = useTranslation('common');
18
+
19
+ 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
+ >
31
+ {children}
32
+ </Drawer>
33
+ );
34
+ });
35
+
36
+ export default Mobile;
@@ -44,7 +44,7 @@ const useStyles = createStyles(({ css, token }) => ({
44
44
  `,
45
45
  }));
46
46
 
47
- const SystemRole = memo(() => {
47
+ const SystemRole = memo<{ mobile?: boolean }>(() => {
48
48
  const [openModal, setOpenModal] = useState(false);
49
49
 
50
50
  const { styles } = useStyles();
@@ -62,7 +62,7 @@ const SystemRole = memo(() => {
62
62
  <ActionIcon
63
63
  icon={Edit}
64
64
  onClick={() => setOpenModal(true)}
65
- size="small"
65
+ size={'small'}
66
66
  title={t('edit')}
67
67
  />
68
68
  }
@@ -5,20 +5,25 @@ import { memo } from 'react';
5
5
  import { useTranslation } from 'react-i18next';
6
6
  import { Flexbox } from 'react-layout-kit';
7
7
 
8
- import HeaderSpacing from '@/components/HeaderSpacing';
8
+ import SafeSpacing from '@/components/SafeSpacing';
9
9
  import { CHAT_SIDEBAR_WIDTH } from '@/const/layoutTokens';
10
10
  import { useGlobalStore } from '@/store/global';
11
11
 
12
+ import Mobile from './Mobile';
12
13
  import SystemRole from './SystemRole';
13
14
  import { Topic } from './Topic';
14
15
 
15
- const useStyles = createStyles(({ cx, css, token, stylish }) => ({
16
+ const useStyles = createStyles(({ cx, css, token, stylish }, mobile: boolean) => ({
16
17
  content: css`
17
18
  display: flex;
18
19
  flex-direction: column;
19
20
  `,
20
21
  drawer: cx(
21
- stylish.blurStrong,
22
+ mobile
23
+ ? css`
24
+ background: ${token.colorBgLayout} !important;
25
+ `
26
+ : stylish.blurStrong,
22
27
  css`
23
28
  background: ${rgba(token.colorBgLayout, 0.4)};
24
29
  `,
@@ -29,10 +34,11 @@ const useStyles = createStyles(({ cx, css, token, stylish }) => ({
29
34
  }));
30
35
 
31
36
  interface SideBarProps {
37
+ mobile?: boolean;
32
38
  systemRole?: boolean;
33
39
  }
34
- const SideBar = memo<SideBarProps>(({ systemRole = true }) => {
35
- const { styles } = useStyles();
40
+ const SideBar = memo<SideBarProps>(({ systemRole = true, mobile }) => {
41
+ const { styles } = useStyles(mobile);
36
42
  const [showAgentSettings, toggleConfig] = useGlobalStore((s) => [
37
43
  s.preference.showChatSideBar,
38
44
  s.toggleChatSideBar,
@@ -40,6 +46,23 @@ const SideBar = memo<SideBarProps>(({ systemRole = true }) => {
40
46
 
41
47
  const { t } = useTranslation('common');
42
48
 
49
+ const topic = (
50
+ <Flexbox height={'100%'} style={{ overflow: 'hidden' }}>
51
+ <Flexbox padding={16}>
52
+ <SearchBar
53
+ placeholder={t('topic.searchPlaceholder')}
54
+ spotlight={!mobile}
55
+ type={mobile ? 'block' : 'ghost'}
56
+ />
57
+ </Flexbox>
58
+ <Flexbox gap={16} paddingInline={16} style={{ overflowY: 'auto', position: 'relative' }}>
59
+ <Topic />
60
+ </Flexbox>
61
+ </Flexbox>
62
+ );
63
+
64
+ if (mobile) return <Mobile>{topic}</Mobile>;
65
+
43
66
  return (
44
67
  <DraggablePanel
45
68
  className={styles.drawer}
@@ -48,22 +71,17 @@ const SideBar = memo<SideBarProps>(({ systemRole = true }) => {
48
71
  }}
49
72
  expand={showAgentSettings}
50
73
  minWidth={CHAT_SIDEBAR_WIDTH}
74
+ mode={'fixed'}
51
75
  onExpandChange={toggleConfig}
52
76
  placement={'right'}
53
77
  >
54
78
  <DraggablePanelContainer
55
79
  style={{ flex: 'none', height: '100%', minWidth: CHAT_SIDEBAR_WIDTH }}
56
80
  >
57
- <HeaderSpacing />
58
- {systemRole && <SystemRole />}
59
- <Flexbox height={'100%'} style={{ overflow: 'hidden' }}>
60
- <Flexbox padding={16}>
61
- <SearchBar placeholder={t('topic.searchPlaceholder')} spotlight type={'ghost'} />
62
- </Flexbox>
63
- <Flexbox gap={16} paddingInline={16} style={{ overflowY: 'auto', position: 'relative' }}>
64
- <Topic />
65
- </Flexbox>
66
- </Flexbox>
81
+ <SafeSpacing />
82
+ {systemRole && <SystemRole mobile={mobile} />}
83
+
84
+ {topic}
67
85
  </DraggablePanelContainer>
68
86
  </DraggablePanel>
69
87
  );
@@ -1,3 +1,4 @@
1
+ import { useResponsive } from 'antd-style';
1
2
  import Head from 'next/head';
2
3
  import { memo } from 'react';
3
4
  import { useTranslation } from 'react-i18next';
@@ -11,10 +12,11 @@ import Conversation from './features/Conversation';
11
12
  import Header from './features/Header';
12
13
  import SideBar from './features/Sidebar';
13
14
  import Layout from './layout';
15
+ import Mobile from './mobile';
14
16
 
15
17
  const Chat = memo(() => {
16
18
  const { t } = useTranslation('common');
17
-
19
+ const { mobile } = useResponsive();
18
20
  const pageTitle = genSiteHeadTitle(t('inbox.title'));
19
21
 
20
22
  useOnFinishHydrationSession(() => {
@@ -26,13 +28,17 @@ const Chat = memo(() => {
26
28
  <Head>
27
29
  <title>{pageTitle}</title>
28
30
  </Head>
29
- <Layout>
30
- <Header settings={false} />
31
- <Flexbox flex={1} height={'calc(100vh - 64px)'} horizontal>
32
- <Conversation />
33
- <SideBar systemRole={false} />
34
- </Flexbox>
35
- </Layout>
31
+ {mobile ? (
32
+ <Mobile />
33
+ ) : (
34
+ <Layout>
35
+ <Header settings={false} />
36
+ <Flexbox flex={1} height={'calc(100vh - 64px)'} horizontal>
37
+ <Conversation />
38
+ <SideBar systemRole={false} />
39
+ </Flexbox>
40
+ </Layout>
41
+ )}
36
42
  </>
37
43
  );
38
44
  });
@@ -1,3 +1,4 @@
1
+ import { useResponsive } from 'antd-style';
1
2
  import { PropsWithChildren, memo } from 'react';
2
3
  import { Flexbox } from 'react-layout-kit';
3
4
 
@@ -7,19 +8,22 @@ import { useSwitchSideBarOnInit } from '@/store/global';
7
8
  import { Sessions } from './SessionList';
8
9
 
9
10
  const ChatLayout = memo<PropsWithChildren>(({ children }) => {
11
+ const { mobile } = useResponsive();
10
12
  useSwitchSideBarOnInit('chat');
11
13
 
12
14
  return (
13
15
  <AppLayout>
14
16
  <Sessions />
15
- <Flexbox
16
- flex={1}
17
- height={'100vh'}
18
- id={'lobe-conversion-container'}
19
- style={{ position: 'relative' }}
20
- >
21
- {children}
22
- </Flexbox>
17
+ {!mobile && (
18
+ <Flexbox
19
+ flex={1}
20
+ height={'100vh'}
21
+ id={'lobe-conversion-container'}
22
+ style={{ position: 'relative' }}
23
+ >
24
+ {children}
25
+ </Flexbox>
26
+ )}
23
27
  </AppLayout>
24
28
  );
25
29
  });
@@ -0,0 +1,25 @@
1
+ import { useTheme } from 'antd-style';
2
+ import { memo } from 'react';
3
+
4
+ import AppMobileLayout from '@/layout/AppMobileLayout';
5
+ import Header from '@/pages/chat/SessionList/Header';
6
+ import { useSwitchSideBarOnInit } from '@/store/global';
7
+
8
+ import { Sessions } from './SessionList';
9
+
10
+ const ChatMobileLayout = memo(() => {
11
+ useSwitchSideBarOnInit('chat');
12
+ const theme = useTheme();
13
+
14
+ return (
15
+ <AppMobileLayout
16
+ navBar={<Header mobile={'navbar'} />}
17
+ showTabBar
18
+ style={{ background: theme.colorBgContainer }}
19
+ >
20
+ <Sessions mobile />
21
+ </AppMobileLayout>
22
+ );
23
+ });
24
+
25
+ export default ChatMobileLayout;
@@ -1,21 +1,53 @@
1
+ import { useResponsive } from 'antd-style';
2
+ import Head from 'next/head';
1
3
  import { memo } from 'react';
4
+ import { useTranslation } from 'react-i18next';
2
5
  import { Flexbox } from 'react-layout-kit';
3
6
 
4
- import HeaderSpacing from '@/components/HeaderSpacing';
7
+ import SafeSpacing from '@/components/SafeSpacing';
8
+ import { createI18nNext } from '@/locales/create';
9
+ import { useOnFinishHydrationGlobal, useSwitchSideBarOnInit } from '@/store/global';
10
+ import { genSiteHeadTitle } from '@/utils/genSiteHeadTitle';
5
11
 
6
12
  import Header from './Header';
7
13
  import Settings from './Settings';
8
14
  import SettingLayout from './layout';
15
+ import Mobile from './mobile';
16
+
17
+ const initI18n = createI18nNext({ namespace: 'setting' });
9
18
 
10
19
  const Setting = memo(() => {
20
+ const { mobile } = useResponsive();
21
+ const { t } = useTranslation('setting');
22
+ const pageTitle = genSiteHeadTitle(t('header.global'));
23
+
24
+ useSwitchSideBarOnInit('settings');
25
+
26
+ useOnFinishHydrationGlobal(() => {
27
+ initI18n.then(() => {});
28
+ });
29
+
11
30
  return (
12
- <SettingLayout>
13
- <Header />
14
- <Flexbox align={'center'} flex={1} padding={24} style={{ overflow: 'auto' }}>
15
- <HeaderSpacing />
16
- <Settings />
17
- </Flexbox>
18
- </SettingLayout>
31
+ <>
32
+ <Head>
33
+ <title>{pageTitle}</title>
34
+ </Head>
35
+ {mobile ? (
36
+ <Mobile>
37
+ <Flexbox align={'center'} padding={16} style={{ overflow: 'auto' }}>
38
+ <Settings />
39
+ </Flexbox>
40
+ </Mobile>
41
+ ) : (
42
+ <SettingLayout>
43
+ <Header />
44
+ <Flexbox align={'center'} flex={1} padding={24} style={{ overflow: 'auto' }}>
45
+ <SafeSpacing />
46
+ <Settings />
47
+ </Flexbox>
48
+ </SettingLayout>
49
+ )}
50
+ </>
19
51
  );
20
52
  });
21
53
 
@@ -1,37 +1,15 @@
1
- import Head from 'next/head';
2
1
  import { ReactNode, memo } from 'react';
3
- import { useTranslation } from 'react-i18next';
4
2
  import { Flexbox } from 'react-layout-kit';
5
3
 
6
- import SideBar from '@/features/SideBar';
7
- import { createI18nNext } from '@/locales/create';
8
- import { useOnFinishHydrationGlobal, useSwitchSideBarOnInit } from '@/store/global';
9
- import { genSiteHeadTitle } from '@/utils/genSiteHeadTitle';
10
-
11
- const initI18n = createI18nNext({ namespace: 'setting' });
4
+ import AppLayout from '@/layout/AppLayout';
12
5
 
13
6
  const SettingLayout = memo<{ children: ReactNode }>(({ children }) => {
14
- const { t } = useTranslation('setting');
15
- const pageTitle = genSiteHeadTitle(t('header.global'));
16
-
17
- useSwitchSideBarOnInit('settings');
18
-
19
- useOnFinishHydrationGlobal(() => {
20
- initI18n.then(() => {});
21
- });
22
-
23
7
  return (
24
- <>
25
- <Head>
26
- <title>{pageTitle}</title>
27
- </Head>
28
- <Flexbox horizontal width={'100%'}>
29
- <SideBar />
30
- <Flexbox flex={1} height={'100vh'} style={{ position: 'relative' }}>
31
- {children}
32
- </Flexbox>
8
+ <AppLayout>
9
+ <Flexbox flex={1} height={'100vh'} style={{ position: 'relative' }}>
10
+ {children}
33
11
  </Flexbox>
34
- </>
12
+ </AppLayout>
35
13
  );
36
14
  });
37
15
 
@@ -0,0 +1,20 @@
1
+ import { MobileNavBar, MobileNavBarTitle } from '@lobehub/ui';
2
+ import { ReactNode, memo } from 'react';
3
+ import { useTranslation } from 'react-i18next';
4
+
5
+ import AppMobileLayout from '@/layout/AppMobileLayout';
6
+
7
+ const SettingLayout = memo<{ children: ReactNode }>(({ children }) => {
8
+ const { t } = useTranslation('setting');
9
+
10
+ return (
11
+ <AppMobileLayout
12
+ navBar={<MobileNavBar center={<MobileNavBarTitle title={t('header.global')} />} />}
13
+ showTabBar
14
+ >
15
+ {children}
16
+ </AppMobileLayout>
17
+ );
18
+ });
19
+
20
+ export default SettingLayout;
@@ -21,12 +21,10 @@ const Hero = memo<{ width: number }>(({ width }) => {
21
21
 
22
22
  return (
23
23
  <>
24
- <LogoThree
25
- size={size.logo}
26
- style={{ marginBottom: -size.logo / 40, marginTop: -size.logo / 5 }}
27
- />
24
+ <LogoThree size={size.logo} style={{ marginTop: -size.logo / 5 }} />
28
25
  <div className={styles.title} style={{ fontSize: size.title }}>
29
- LobeChat{mobile ? <br /> : ' '}
26
+ <span style={mobile ? { fontSize: '1.2em' } : {}}>LobeChat</span>
27
+ {mobile ? <br /> : ' '}
30
28
  {t('slogan.title')}
31
29
  </div>
32
30
  <div className={styles.desc} style={{ fontSize: size.desc }}>
@@ -13,7 +13,7 @@ import { useImportConfig } from '@/hooks/useImportConfig';
13
13
  import { useStyles } from '../style';
14
14
  import Hero from './Hero';
15
15
 
16
- const Banner = memo(() => {
16
+ const Banner = memo<{ mobile?: boolean }>(() => {
17
17
  const { importConfig } = useImportConfig();
18
18
  const ref = useRef(null);
19
19
  const domSize = useSize(ref);
@@ -28,12 +28,15 @@ const Banner = memo(() => {
28
28
  }, []);
29
29
 
30
30
  return (
31
- <Flexbox height={'80vh'} style={{ marginTop: '10vh' }}>
31
+ <Flexbox height={'80vh'} style={{ paddingTop: '10vh' }}>
32
32
  <GridShowcase>
33
33
  <div className={styles.container} ref={ref}>
34
34
  <Hero width={width} />
35
35
  </div>
36
36
  <Flexbox gap={16} horizontal style={{ marginTop: 16 }}>
37
+ <Upload maxCount={1} onChange={handleImport} showUploadList={false}>
38
+ <Button size={'large'}>{t('button.import')}</Button>
39
+ </Upload>
37
40
  <Link href={'/chat'}>
38
41
  <Button size={'large'} type={'primary'}>
39
42
  <Flexbox align={'center'} gap={4} horizontal>
@@ -42,9 +45,6 @@ const Banner = memo(() => {
42
45
  </Flexbox>
43
46
  </Button>
44
47
  </Link>
45
- <Upload maxCount={1} onChange={handleImport} showUploadList={false}>
46
- <Button size={'large'}>{t('button.import')}</Button>
47
- </Upload>
48
48
  </Flexbox>
49
49
  </GridShowcase>
50
50
  {/*TODO:暂时隐藏,待模板完成后再补回*/}