@lobehub/chat 0.142.3 → 0.142.5

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 (101) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/package.json +1 -1
  3. package/src/app/chat/(desktop)/features/ChatHeader/HeaderAction.tsx +2 -2
  4. package/src/app/chat/(desktop)/index.tsx +12 -23
  5. package/src/app/chat/(mobile)/features/SessionHeader.tsx +2 -0
  6. package/src/app/chat/(mobile)/index.tsx +4 -7
  7. package/src/app/chat/(mobile)/{features/ChatHeader.tsx → mobile/ChatHeader/index.tsx} +2 -2
  8. package/src/app/chat/(mobile)/mobile/page.tsx +6 -4
  9. package/src/app/chat/{(desktop)/features → _layout/Desktop}/SessionList.tsx +2 -0
  10. package/src/app/chat/{(desktop)/layout.desktop.tsx → _layout/Desktop/index.tsx} +7 -6
  11. package/src/app/chat/_layout/Mobile/index.tsx +7 -0
  12. package/src/app/chat/components/SessionHydration/index.tsx +1 -6
  13. package/src/app/chat/features/SessionListContent/Inbox/index.tsx +4 -11
  14. package/src/app/chat/features/SessionListContent/List/index.tsx +2 -14
  15. package/src/app/chat/features/{ChatHeader/ShareButton → ShareButton}/Preview.tsx +1 -1
  16. package/src/app/chat/layout.ts +8 -0
  17. package/src/app/chat/page.tsx +2 -0
  18. package/src/app/chat/settings/(desktop)/index.tsx +13 -19
  19. package/src/app/chat/settings/(mobile)/{features/Header.tsx → Header.tsx} +4 -1
  20. package/src/app/chat/settings/(mobile)/index.tsx +4 -3
  21. package/src/app/home/Redirect.tsx +0 -4
  22. package/src/app/layout.tsx +7 -12
  23. package/src/app/market/(desktop)/index.tsx +8 -16
  24. package/src/app/market/(mobile)/index.tsx +12 -7
  25. package/src/app/market/_layout/Desktop/index.tsx +59 -0
  26. package/src/app/market/_layout/Mobile/Header.tsx +20 -0
  27. package/src/app/market/_layout/Mobile/index.tsx +14 -0
  28. package/src/app/market/layout.ts +8 -0
  29. package/src/app/settings/(desktop)/index.tsx +8 -10
  30. package/src/app/settings/(mobile)/index.tsx +53 -1
  31. package/src/app/settings/{(desktop)/features → _layout/Desktop}/Header.tsx +8 -3
  32. package/src/app/settings/{(desktop)/features → _layout/Desktop}/SideBar.tsx +8 -3
  33. package/src/app/settings/_layout/Desktop/index.tsx +27 -0
  34. package/src/app/settings/{(mobile)/features/Header/index.tsx → _layout/Mobile/SubSettingHeader.tsx} +9 -8
  35. package/src/app/settings/_layout/Mobile/index.tsx +23 -0
  36. package/src/app/settings/layout.ts +8 -0
  37. package/src/app/settings/page.tsx +4 -2
  38. package/src/app/welcome/(desktop)/index.tsx +9 -17
  39. package/src/app/welcome/(mobile)/index.tsx +12 -6
  40. package/src/app/welcome/_layout/Desktop.tsx +29 -0
  41. package/src/app/welcome/_layout/Mobile.tsx +9 -0
  42. package/src/app/welcome/features/Banner/index.tsx +1 -3
  43. package/src/app/welcome/layout.ts +8 -0
  44. package/src/components/client/ClientResponsiveContent/index.tsx +32 -0
  45. package/src/components/client/ClientResponsiveLayout.tsx +32 -0
  46. package/src/components/server/ServerLayout.tsx +20 -0
  47. package/src/features/AvatarWithUpload/index.tsx +12 -9
  48. package/src/features/MobileSwitchLoading/index.tsx +2 -0
  49. package/src/hooks/useActiveSettingsKey.ts +16 -0
  50. package/src/hooks/useActiveTabKey.ts +12 -0
  51. package/src/hooks/useIsMobile.ts +2 -1
  52. package/src/hooks/useIsSubSlug.ts +12 -0
  53. package/src/layout/AuthProvider/index.tsx +16 -0
  54. package/src/layout/{AppLayout.desktop.tsx → GlobalLayout/Desktop/Client.tsx} +11 -9
  55. package/src/layout/GlobalLayout/Desktop/index.tsx +16 -0
  56. package/src/layout/{AppLayout.mobile.tsx → GlobalLayout/Mobile/Client.tsx} +2 -16
  57. package/src/layout/GlobalLayout/Mobile/index.tsx +25 -0
  58. package/src/layout/GlobalLayout/index.tsx +8 -0
  59. package/src/store/session/slices/session/action.test.ts +0 -35
  60. package/src/store/session/slices/session/action.ts +8 -21
  61. package/src/store/session/slices/session/initialState.ts +0 -7
  62. package/src/styles/mobileHeader.ts +7 -0
  63. package/src/app/chat/settings/(desktop)/layout.desktop.tsx +0 -18
  64. package/src/app/chat/settings/(mobile)/layout.mobile.tsx +0 -9
  65. package/src/app/market/(desktop)/layout.desktop.tsx +0 -65
  66. package/src/app/market/(mobile)/features/Header.tsx +0 -10
  67. package/src/app/market/(mobile)/layout.mobile.tsx +0 -25
  68. package/src/app/settings/(desktop)/layout.desktop.tsx +0 -35
  69. package/src/app/settings/(desktop)/layout.responsive.tsx +0 -21
  70. package/src/app/settings/(mobile)/features/Header/Home.tsx +0 -8
  71. package/src/app/settings/(mobile)/layout.mobile.tsx +0 -21
  72. package/src/app/settings/(mobile)/mobile/index.tsx +0 -54
  73. package/src/app/settings/(mobile)/mobile/layout.mobile.tsx +0 -14
  74. package/src/app/settings/about/layout.tsx +0 -9
  75. package/src/app/settings/agent/layout.tsx +0 -9
  76. package/src/app/settings/common/layout.tsx +0 -9
  77. package/src/app/settings/layout.server.tsx +0 -19
  78. package/src/app/settings/llm/layout.tsx +0 -9
  79. package/src/app/settings/sync/layout.tsx +0 -9
  80. package/src/app/settings/tts/layout.tsx +0 -9
  81. package/src/app/welcome/(desktop)/layout.desktop.tsx +0 -31
  82. package/src/app/welcome/(mobile)/features/Header.tsx +0 -6
  83. package/src/app/welcome/(mobile)/features/Showcase.tsx +0 -16
  84. package/src/app/welcome/(mobile)/layout.mobile.tsx +0 -20
  85. package/src/components/ResponsiveContainer/index.tsx +0 -20
  86. package/src/layout/ServerResponsiveLayout/Client.tsx +0 -23
  87. package/src/layout/ServerResponsiveLayout/index.tsx +0 -21
  88. /package/src/app/chat/(mobile)/{features → mobile/ChatHeader}/ChatHeaderTitle.tsx +0 -0
  89. /package/src/app/chat/{(desktop)/features → _layout/Desktop}/SessionHeader.tsx +0 -0
  90. /package/src/app/chat/features/{ChatHeader/SettingButton.tsx → SettingButton.tsx} +0 -0
  91. /package/src/app/chat/features/{ChatHeader/ShareButton → ShareButton}/ShareModal.tsx +0 -0
  92. /package/src/app/chat/features/{ChatHeader/ShareButton → ShareButton}/index.tsx +0 -0
  93. /package/src/app/chat/features/{ChatHeader/ShareButton → ShareButton}/style.ts +0 -0
  94. /package/src/app/chat/features/{ChatHeader/ShareButton → ShareButton}/type.ts +0 -0
  95. /package/src/app/chat/features/{ChatHeader/ShareButton → ShareButton}/useScreenshot.ts +0 -0
  96. /package/src/app/chat/settings/(desktop)/{features/Header.tsx → Header.tsx} +0 -0
  97. /package/src/app/market/{(desktop)/features → _layout/Desktop}/AgentDetail.tsx +0 -0
  98. /package/src/app/market/{(desktop)/features → _layout/Desktop}/Header.tsx +0 -0
  99. /package/src/{features → layout/GlobalLayout/Desktop}/SideBar/BottomActions.tsx +0 -0
  100. /package/src/{features → layout/GlobalLayout/Desktop}/SideBar/TopActions.tsx +0 -0
  101. /package/src/{features → layout/GlobalLayout/Desktop}/SideBar/index.tsx +0 -0
@@ -0,0 +1,20 @@
1
+ 'use client';
2
+
3
+ import { Logo, MobileNavBar } from '@lobehub/ui';
4
+ import { memo } from 'react';
5
+
6
+ import { mobileHeaderSticky } from '@/styles/mobileHeader';
7
+
8
+ import ShareAgentButton from '../../features/ShareAgentButton';
9
+
10
+ const Header = memo(() => {
11
+ return (
12
+ <MobileNavBar
13
+ center={<Logo type={'text'} />}
14
+ right={<ShareAgentButton mobile />}
15
+ style={mobileHeaderSticky}
16
+ />
17
+ );
18
+ });
19
+
20
+ export default Header;
@@ -0,0 +1,14 @@
1
+ import { PropsWithChildren } from 'react';
2
+
3
+ import Header from './Header';
4
+
5
+ const MobileLayout = ({ children }: PropsWithChildren) => {
6
+ return (
7
+ <>
8
+ <Header />
9
+ {children}
10
+ </>
11
+ );
12
+ };
13
+
14
+ export default MobileLayout;
@@ -0,0 +1,8 @@
1
+ import ServerLayout from '@/components/server/ServerLayout';
2
+
3
+ import Desktop from './_layout/Desktop';
4
+ import Mobile from './_layout/Mobile';
5
+
6
+ const MarketLayout = ServerLayout({ Desktop, Mobile });
7
+
8
+ export default MarketLayout;
@@ -3,23 +3,21 @@
3
3
  import dynamic from 'next/dynamic';
4
4
  import { FC, memo } from 'react';
5
5
 
6
- import ResponsiveContainer from '@/components/ResponsiveContainer';
7
6
  import MobileSwitchLoading from '@/features/MobileSwitchLoading';
8
- import { SettingsTabs } from '@/store/global/initialState';
7
+ import { useIsMobile } from '@/hooks/useIsMobile';
9
8
 
10
9
  import Common from '../common';
11
10
  import { SettingsCommonProps } from '../common/Common';
12
- import DesktopLayout from './layout.desktop';
13
11
 
14
12
  const Mobile: FC = dynamic(() => import('../(mobile)'), {
15
13
  loading: MobileSwitchLoading,
16
14
  ssr: false,
17
15
  }) as FC;
18
16
 
19
- export default memo<SettingsCommonProps>((props) => (
20
- <ResponsiveContainer Mobile={Mobile}>
21
- <DesktopLayout activeTab={SettingsTabs.Common}>
22
- <Common {...props} />
23
- </DesktopLayout>
24
- </ResponsiveContainer>
25
- ));
17
+ const Desktop = memo<SettingsCommonProps>((props) => {
18
+ const mobile = useIsMobile();
19
+
20
+ return mobile ? <Mobile /> : <Common {...props} />;
21
+ });
22
+
23
+ export default Desktop;
@@ -1 +1,53 @@
1
- export { default } from './mobile';
1
+ 'use client';
2
+
3
+ import { Divider } from 'antd';
4
+ import { createStyles } from 'antd-style';
5
+ import { memo } from 'react';
6
+ import { Center, Flexbox } from 'react-layout-kit';
7
+
8
+ import { CURRENT_VERSION } from '@/const/version';
9
+ import AvatarWithUpload from '@/features/AvatarWithUpload';
10
+ import { useGlobalStore } from '@/store/global';
11
+ import { commonSelectors } from '@/store/global/selectors';
12
+
13
+ import SettingList from '../features/SettingList';
14
+ import AvatarBanner from './features/AvatarBanner';
15
+ import ExtraList from './features/ExtraList';
16
+
17
+ const useStyles = createStyles(({ css, token }) => ({
18
+ divider: css`
19
+ height: 6px;
20
+ background: ${token.colorFillTertiary};
21
+ `,
22
+ footer: css`
23
+ font-size: 12px;
24
+ color: ${token.colorTextQuaternary};
25
+ `,
26
+ }));
27
+
28
+ const Setting = memo(() => {
29
+ const avatar = useGlobalStore(commonSelectors.userAvatar);
30
+ const { styles } = useStyles();
31
+
32
+ return (
33
+ <Flexbox style={{ overflow: 'scroll' }}>
34
+ <AvatarBanner avatar={avatar}>
35
+ <Center style={{ marginTop: 32, position: 'absolute', zIndex: 2 }}>
36
+ <AvatarWithUpload size={88} />
37
+ </Center>
38
+ </AvatarBanner>
39
+ <div style={{ width: '100%' }}>
40
+ <SettingList />
41
+ <div className={styles.divider} />
42
+ <ExtraList />
43
+ <Center style={{ paddingInline: 64 }}>
44
+ <Divider>
45
+ <span className={styles.footer}>LobeChat v{CURRENT_VERSION}</span>
46
+ </Divider>
47
+ </Center>
48
+ </div>
49
+ </Flexbox>
50
+ );
51
+ });
52
+
53
+ export default Setting;
@@ -1,14 +1,19 @@
1
+ 'use client';
2
+
1
3
  import { ChatHeader, ChatHeaderTitle } from '@lobehub/ui';
2
4
  import { Tag } from 'antd';
3
5
  import { memo } from 'react';
4
6
  import { useTranslation } from 'react-i18next';
5
7
  import { Flexbox } from 'react-layout-kit';
6
8
 
9
+ import { useActiveSettingsKey } from '@/hooks/useActiveSettingsKey';
7
10
  import { SettingsTabs } from '@/store/global/initialState';
8
11
 
9
- const Header = memo(({ activeTab }: { activeTab: SettingsTabs }) => {
12
+ const Header = memo(() => {
10
13
  const { t } = useTranslation('setting');
11
14
 
15
+ const activeKey = useActiveSettingsKey();
16
+
12
17
  return (
13
18
  <ChatHeader
14
19
  left={
@@ -16,9 +21,9 @@ const Header = memo(({ activeTab }: { activeTab: SettingsTabs }) => {
16
21
  <ChatHeaderTitle
17
22
  title={
18
23
  <Flexbox align={'center'} gap={8} horizontal>
19
- {t(`tab.${activeTab}`)}
24
+ {t(`tab.${activeKey}`)}
20
25
 
21
- {activeTab === SettingsTabs.Sync && <Tag color={'gold'}>{t('tab.experiment')}</Tag>}
26
+ {activeKey === SettingsTabs.Sync && <Tag color={'gold'}>{t('tab.experiment')}</Tag>}
22
27
  </Flexbox>
23
28
  }
24
29
  />
@@ -1,9 +1,13 @@
1
+ 'use client';
2
+
1
3
  import { createStyles, useResponsive } from 'antd-style';
2
4
  import { memo } from 'react';
3
5
  import { useTranslation } from 'react-i18next';
4
6
  import { Flexbox } from 'react-layout-kit';
5
7
 
6
- import SettingList, { SettingListProps } from '../../features/SettingList';
8
+ import { useActiveSettingsKey } from '@/hooks/useActiveSettingsKey';
9
+
10
+ import SettingList from '../../features/SettingList';
7
11
  import UpgradeAlert from '../../features/UpgradeAlert';
8
12
 
9
13
  const useStyles = createStyles(({ stylish, token, css }) => ({
@@ -20,8 +24,9 @@ const useStyles = createStyles(({ stylish, token, css }) => ({
20
24
  `,
21
25
  }));
22
26
 
23
- const SideBar = memo<SettingListProps>(({ activeTab }) => {
27
+ const SideBar = memo(() => {
24
28
  const { styles } = useStyles();
29
+ const activeKey = useActiveSettingsKey();
25
30
 
26
31
  const { t } = useTranslation('common');
27
32
  const { mobile } = useResponsive();
@@ -33,7 +38,7 @@ const SideBar = memo<SettingListProps>(({ activeTab }) => {
33
38
  </Flexbox>
34
39
  <Flexbox gap={8} style={{ paddingInline: 8 }}>
35
40
  <UpgradeAlert />
36
- <SettingList activeTab={activeTab} mobile={mobile} />
41
+ <SettingList activeTab={activeKey} mobile={mobile} />
37
42
  </Flexbox>
38
43
  </Flexbox>
39
44
  );
@@ -0,0 +1,27 @@
1
+ 'use client';
2
+
3
+ import { PropsWithChildren, memo } from 'react';
4
+ import { Center, Flexbox } from 'react-layout-kit';
5
+
6
+ import SafeSpacing from '@/components/SafeSpacing';
7
+ import ClientResponsiveLayout from '@/components/client/ClientResponsiveLayout';
8
+
9
+ import Header from './Header';
10
+ import SideBar from './SideBar';
11
+
12
+ const Desktop = memo<PropsWithChildren>(({ children }) => (
13
+ <>
14
+ <SideBar />
15
+ <Flexbox flex={1} height={'100%'} style={{ position: 'relative' }}>
16
+ <Header />
17
+ <Flexbox align={'center'} flex={1} padding={24} style={{ overflowY: 'scroll' }}>
18
+ <SafeSpacing />
19
+ <Center gap={16} width={'100%'}>
20
+ {children}
21
+ </Center>
22
+ </Flexbox>
23
+ </Flexbox>
24
+ </>
25
+ ));
26
+
27
+ export default ClientResponsiveLayout({ Desktop, Mobile: () => import('../Mobile') });
@@ -5,31 +5,32 @@ import { memo } from 'react';
5
5
  import { useTranslation } from 'react-i18next';
6
6
  import { Flexbox } from 'react-layout-kit';
7
7
 
8
+ import { useActiveSettingsKey } from '@/hooks/useActiveSettingsKey';
8
9
  import { SettingsTabs } from '@/store/global/initialState';
10
+ import { mobileHeaderSticky } from '@/styles/mobileHeader';
9
11
 
10
- interface HeaderProps {
11
- activeTab: SettingsTabs;
12
- }
13
-
14
- const Header = memo<HeaderProps>(({ activeTab }) => {
12
+ const Header = memo(() => {
15
13
  const { t } = useTranslation('setting');
16
14
 
17
15
  const router = useRouter();
18
-
16
+ const activeSettingsKey = useActiveSettingsKey();
19
17
  return (
20
18
  <MobileNavBar
21
19
  center={
22
20
  <MobileNavBarTitle
23
21
  title={
24
22
  <Flexbox align={'center'} gap={4} horizontal>
25
- {t(`tab.${activeTab}`)}
26
- {activeTab === SettingsTabs.Sync && <Tag color={'gold'}>{t('tab.experiment')}</Tag>}
23
+ {t(`tab.${activeSettingsKey}`)}
24
+ {activeSettingsKey === SettingsTabs.Sync && (
25
+ <Tag color={'gold'}>{t('tab.experiment')}</Tag>
26
+ )}
27
27
  </Flexbox>
28
28
  }
29
29
  />
30
30
  }
31
31
  onBackClick={() => router.push('/settings')}
32
32
  showBackButton
33
+ style={mobileHeaderSticky}
33
34
  />
34
35
  );
35
36
  });
@@ -0,0 +1,23 @@
1
+ 'use client';
2
+
3
+ import { PropsWithChildren } from 'react';
4
+
5
+ import { useIsSubSlug } from '@/hooks/useIsSubSlug';
6
+
7
+ import SubSettingHeader from './SubSettingHeader';
8
+
9
+ const MobileLayout = ({ children }: PropsWithChildren) => {
10
+ const isSubPath = useIsSubSlug();
11
+
12
+ if (isSubPath)
13
+ return (
14
+ <>
15
+ <SubSettingHeader />
16
+ {children}
17
+ </>
18
+ );
19
+
20
+ return children;
21
+ };
22
+
23
+ export default MobileLayout;
@@ -0,0 +1,8 @@
1
+ import ServerLayout from '@/components/server/ServerLayout';
2
+
3
+ import Desktop from './_layout/Desktop';
4
+ import Mobile from './_layout/Mobile';
5
+
6
+ const SettingsLayout = ServerLayout({ Desktop, Mobile });
7
+
8
+ export default SettingsLayout;
@@ -7,11 +7,13 @@ import MobilePage from './(mobile)';
7
7
  const Page = () => {
8
8
  const mobile = isMobileDevice();
9
9
 
10
- const Page = mobile ? MobilePage : DesktopPage;
10
+ if (mobile) return <MobilePage />;
11
11
 
12
12
  const { SHOW_ACCESS_CODE_CONFIG, ENABLE_OAUTH_SSO } = getServerConfig();
13
13
 
14
- return <Page showAccessCodeConfig={SHOW_ACCESS_CODE_CONFIG} showOAuthLogin={ENABLE_OAUTH_SSO} />;
14
+ return (
15
+ <DesktopPage showAccessCodeConfig={SHOW_ACCESS_CODE_CONFIG} showOAuthLogin={ENABLE_OAUTH_SSO} />
16
+ );
15
17
  };
16
18
 
17
19
  export default Page;
@@ -1,25 +1,17 @@
1
1
  'use client';
2
2
 
3
- import dynamic from 'next/dynamic';
4
- import { FC, memo } from 'react';
3
+ import { memo } from 'react';
5
4
 
6
- import ResponsiveContainer from '@/components/ResponsiveContainer';
7
- import MobileSwitchLoading from '@/features/MobileSwitchLoading';
5
+ import ClientResponsiveContent from '@/components/client/ClientResponsiveContent';
8
6
 
9
7
  import Footer from './features/Footer';
10
8
  import Showcase from './features/Showcase';
11
- import Layout from './layout.desktop';
12
9
 
13
- const Mobile: FC = dynamic(() => import('../(mobile)'), {
14
- loading: MobileSwitchLoading,
15
- ssr: false,
16
- }) as FC;
17
-
18
- export default memo(() => (
19
- <ResponsiveContainer Mobile={Mobile}>
20
- <Layout>
21
- <Showcase />
22
- <Footer />
23
- </Layout>
24
- </ResponsiveContainer>
10
+ const Desktop = memo(() => (
11
+ <>
12
+ <Showcase />
13
+ <Footer />
14
+ </>
25
15
  ));
16
+
17
+ export default ClientResponsiveContent({ Desktop, Mobile: () => import('../(mobile)') });
@@ -1,10 +1,16 @@
1
1
  import { memo } from 'react';
2
+ import { Center, Flexbox } from 'react-layout-kit';
2
3
 
3
- import Showcase from './features/Showcase';
4
- import Layout from './layout.mobile';
4
+ import Banner from '@/app/welcome/features/Banner';
5
5
 
6
- export default memo(() => (
7
- <Layout>
8
- <Showcase />
9
- </Layout>
6
+ const Showcase = memo(() => (
7
+ <Flexbox align={'center'} justify={'center'} style={{ height: 'calc(100% - 44px)' }}>
8
+ <Center gap={16}>
9
+ <Banner mobile />
10
+ </Center>
11
+ {/*TODO:暂时隐藏,待模板完成后再补回*/}
12
+ {/*<AgentTemplate width={width} />*/}
13
+ </Flexbox>
10
14
  ));
15
+
16
+ export default Showcase;
@@ -0,0 +1,29 @@
1
+ 'use client';
2
+
3
+ import { Logo } from '@lobehub/ui';
4
+ import { PropsWithChildren, memo } from 'react';
5
+ import { Center, Flexbox } from 'react-layout-kit';
6
+
7
+ import ClientResponsiveLayout from '@/components/client/ClientResponsiveLayout';
8
+
9
+ import { useStyles } from '../features/Banner/style';
10
+
11
+ const Desktop = memo<PropsWithChildren>(({ children }) => {
12
+ const { styles } = useStyles();
13
+ return (
14
+ <Center
15
+ className={styles.layout}
16
+ flex={1}
17
+ height={'100%'}
18
+ horizontal
19
+ style={{ position: 'relative' }}
20
+ >
21
+ <Logo className={styles.logo} size={36} type={'text'} />
22
+ <Flexbox className={styles.view} flex={1}>
23
+ {children}
24
+ </Flexbox>
25
+ </Center>
26
+ );
27
+ });
28
+
29
+ export default ClientResponsiveLayout({ Desktop, Mobile: () => import('./Mobile') });
@@ -0,0 +1,9 @@
1
+ 'use client';
2
+
3
+ import { PropsWithChildren, memo } from 'react';
4
+
5
+ const MobileLayout = memo<PropsWithChildren>(({ children }) => {
6
+ return <div style={{ height: '100%', paddingInline: 16 }}>{children}</div>;
7
+ });
8
+
9
+ export default MobileLayout;
@@ -10,7 +10,6 @@ import { Flexbox } from 'react-layout-kit';
10
10
 
11
11
  import DataImporter from '@/features/DataImporter';
12
12
  import { useGlobalStore } from '@/store/global';
13
- import { useSessionStore } from '@/store/session';
14
13
 
15
14
  import Hero from './Hero';
16
15
  import { useStyles } from './style';
@@ -19,7 +18,6 @@ const Banner = memo<{ mobile?: boolean }>(({ mobile }) => {
19
18
  const { t } = useTranslation('welcome');
20
19
  const router = useRouter();
21
20
  const { styles } = useStyles();
22
- const [switchSession] = useSessionStore((s) => [s.switchSession]);
23
21
  const [switchBackToChat, isMobile] = useGlobalStore((s) => [s.switchBackToChat, s.isMobile]);
24
22
 
25
23
  return (
@@ -36,7 +34,7 @@ const Banner = memo<{ mobile?: boolean }>(({ mobile }) => {
36
34
  >
37
35
  <DataImporter
38
36
  onFinishImport={() => {
39
- switchSession();
37
+ router.push('/chat');
40
38
  }}
41
39
  >
42
40
  <Button block={mobile} size={'large'}>
@@ -0,0 +1,8 @@
1
+ import ServerLayout from '@/components/server/ServerLayout';
2
+
3
+ import Desktop from './_layout/Desktop';
4
+ import Mobile from './_layout/Mobile';
5
+
6
+ const WelcomeLayout = ServerLayout({ Desktop, Mobile });
7
+
8
+ export default WelcomeLayout;
@@ -0,0 +1,32 @@
1
+ 'use client';
2
+
3
+ import { Loader } from 'next/dist/shared/lib/dynamic';
4
+ import dynamic from 'next/dynamic';
5
+ import { FC, memo } from 'react';
6
+
7
+ import MobileSwitchLoading from '@/features/MobileSwitchLoading';
8
+ import { useIsMobile } from '@/hooks/useIsMobile';
9
+
10
+ interface ClientResponsiveContentProps {
11
+ Desktop: FC;
12
+ Mobile: Loader;
13
+ }
14
+
15
+ const ClientResponsiveContent = ({ Mobile, Desktop }: ClientResponsiveContentProps) => {
16
+ const MobileComponent = dynamic(Mobile, {
17
+ loading: MobileSwitchLoading,
18
+ ssr: false,
19
+ });
20
+
21
+ const Content = memo(() => {
22
+ const mobile = useIsMobile();
23
+
24
+ return mobile ? <MobileComponent /> : <Desktop />;
25
+ });
26
+
27
+ Content.displayName = 'ClientResponsiveContent';
28
+
29
+ return Content;
30
+ };
31
+
32
+ export default ClientResponsiveContent;
@@ -0,0 +1,32 @@
1
+ 'use client';
2
+
3
+ import { Loader } from 'next/dist/shared/lib/dynamic';
4
+ import dynamic from 'next/dynamic';
5
+ import { FC, PropsWithChildren, memo } from 'react';
6
+
7
+ import MobileSwitchLoading from '@/features/MobileSwitchLoading';
8
+ import { useIsMobile } from '@/hooks/useIsMobile';
9
+
10
+ interface ClientResponsiveLayoutProps {
11
+ Desktop: FC<PropsWithChildren>;
12
+ Mobile: Loader;
13
+ }
14
+
15
+ const ClientResponsiveLayout = ({ Desktop, Mobile }: ClientResponsiveLayoutProps) => {
16
+ const MobileComponent = dynamic(Mobile, {
17
+ loading: MobileSwitchLoading,
18
+ ssr: false,
19
+ }) as FC<PropsWithChildren>;
20
+
21
+ const Layout = memo<PropsWithChildren>(({ children }) => {
22
+ const mobile = useIsMobile();
23
+
24
+ return mobile ? <MobileComponent>{children}</MobileComponent> : <Desktop>{children}</Desktop>;
25
+ });
26
+
27
+ Layout.displayName = 'ClientLayout';
28
+
29
+ return Layout;
30
+ };
31
+
32
+ export default ClientResponsiveLayout;
@@ -0,0 +1,20 @@
1
+ import { FC, PropsWithChildren } from 'react';
2
+
3
+ import { isMobileDevice } from '@/utils/responsive';
4
+
5
+ interface ServerLayoutProps {
6
+ Desktop: FC<PropsWithChildren>;
7
+ Mobile: FC<PropsWithChildren>;
8
+ }
9
+
10
+ const ServerLayout =
11
+ ({ Desktop, Mobile }: ServerLayoutProps) =>
12
+ ({ children }: PropsWithChildren) => {
13
+ const mobile = isMobileDevice();
14
+
15
+ return mobile ? <Mobile>{children}</Mobile> : <Desktop>{children}</Desktop>;
16
+ };
17
+
18
+ ServerLayout.displayName = 'ServerLayout';
19
+
20
+ export default ServerLayout;
@@ -1,7 +1,7 @@
1
1
  import { Upload } from 'antd';
2
2
  import { createStyles } from 'antd-style';
3
3
  import Avatar from 'next/image';
4
- import { CSSProperties, memo } from 'react';
4
+ import { CSSProperties, memo, useCallback } from 'react';
5
5
 
6
6
  import { imageUrl } from '@/const/url';
7
7
  import { useGlobalStore } from '@/store/global';
@@ -43,14 +43,17 @@ const AvatarWithUpload = memo<AvatarWithUploadProps>(
43
43
  s.updateAvatar,
44
44
  ]);
45
45
 
46
- const handleUploadAvatar = createUploadImageHandler((avatar) => {
47
- const img = new Image();
48
- img.src = avatar;
49
- img.addEventListener('load', () => {
50
- const webpBase64 = imageToBase64({ img, size: compressSize });
51
- updateAvatar(webpBase64);
52
- });
53
- });
46
+ const handleUploadAvatar = useCallback(
47
+ createUploadImageHandler((avatar) => {
48
+ const img = new Image();
49
+ img.src = avatar;
50
+ img.addEventListener('load', () => {
51
+ const webpBase64 = imageToBase64({ img, size: compressSize });
52
+ updateAvatar(webpBase64);
53
+ });
54
+ }),
55
+ [],
56
+ );
54
57
 
55
58
  return (
56
59
  <div className={styles} id={id} style={{ maxHeight: size, maxWidth: size, ...style }}>
@@ -1,3 +1,5 @@
1
+ 'use client';
2
+
1
3
  import { useTranslation } from 'react-i18next';
2
4
 
3
5
  import FullscreenLoading from '@/components/FullscreenLoading';
@@ -0,0 +1,16 @@
1
+ import { usePathname } from 'next/navigation';
2
+
3
+ import { SettingsTabs } from '@/store/global/initialState';
4
+
5
+ /**
6
+ * Returns the active setting page key (common/sync/agent/...)
7
+ */
8
+ export const useActiveSettingsKey = () => {
9
+ const pathname = usePathname();
10
+
11
+ const tabs = pathname.split('/').at(-1);
12
+
13
+ if (tabs === 'settings') return SettingsTabs.Common;
14
+
15
+ return tabs as SettingsTabs;
16
+ };
@@ -0,0 +1,12 @@
1
+ import { usePathname } from 'next/navigation';
2
+
3
+ import { SidebarTabKey } from '@/store/global/initialState';
4
+
5
+ /**
6
+ * Returns the active tab key (chat/market/settings/...)
7
+ */
8
+ export const useActiveTabKey = () => {
9
+ const pathname = usePathname();
10
+
11
+ return pathname.split('/').find(Boolean)! as SidebarTabKey;
12
+ };
@@ -1,7 +1,8 @@
1
1
  import { useResponsive } from 'antd-style';
2
+ import { useMemo } from 'react';
2
3
 
3
4
  export const useIsMobile = (): boolean => {
4
5
  const { mobile } = useResponsive();
5
6
 
6
- return !!mobile;
7
+ return useMemo(() => !!mobile, [mobile]);
7
8
  };
@@ -0,0 +1,12 @@
1
+ import { usePathname } from 'next/navigation';
2
+
3
+ /**
4
+ * Returns true if the current path has a sub slug (`/chat/mobile` or `/chat/settings`)
5
+ */
6
+ export const useIsSubSlug = () => {
7
+ const pathname = usePathname();
8
+
9
+ const slugs = pathname.split('/').filter(Boolean);
10
+
11
+ return slugs.length > 1;
12
+ };
@@ -0,0 +1,16 @@
1
+ import { SessionProvider } from 'next-auth/react';
2
+ import { PropsWithChildren } from 'react';
3
+
4
+ import { getServerConfig } from '@/config/server';
5
+ import { API_ENDPOINTS } from '@/services/_url';
6
+
7
+ const { ENABLE_OAUTH_SSO = false } = getServerConfig();
8
+
9
+ const AuthProvider = ({ children }: PropsWithChildren) =>
10
+ ENABLE_OAUTH_SSO ? (
11
+ <SessionProvider basePath={API_ENDPOINTS.oauth}>{children}</SessionProvider>
12
+ ) : (
13
+ children
14
+ );
15
+
16
+ export default AuthProvider;