@lobehub/chat 0.79.0 → 0.79.1
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.
- package/CHANGELOG.md +25 -0
- package/package.json +1 -1
- package/src/app/StyleRegistry.tsx +23 -0
- package/src/app/chat/mobile/page.page.tsx +7 -0
- package/src/app/chat/page.page.tsx +7 -0
- package/src/app/chat/settings/page.page.tsx +7 -0
- package/src/app/layout.page.tsx +45 -0
- package/src/app/market/page.page.tsx +7 -0
- package/src/app/page.page.tsx +7 -0
- package/src/app/settings/page.page.tsx +7 -0
- package/src/app/welcome/page.page.tsx +7 -0
- package/src/components/AppTheme/index.tsx +61 -0
- package/src/const/settings.ts +0 -2
- package/src/const/theme.ts +5 -0
- package/src/features/MobileTabBar/index.tsx +4 -3
- package/src/features/SideBar/BottomActions.tsx +3 -2
- package/src/features/SideBar/TopActions.tsx +6 -4
- package/src/layout/{index.tsx → GlobalLayout/index.tsx} +24 -32
- package/src/pages/chat/features/Header/Desktop.tsx +3 -2
- package/src/pages/chat/features/Header/Mobile.tsx +4 -3
- package/src/pages/chat/features/SessionList/Header/Mobile.tsx +3 -2
- package/src/pages/chat/{index.page.tsx → index.tsx} +2 -0
- package/src/pages/chat/mobile/{index.page.tsx → index.tsx} +2 -0
- package/src/pages/chat/setting/features/Header/Desktop.tsx +3 -2
- package/src/pages/chat/setting/features/Header/Mobile.tsx +3 -2
- package/src/pages/chat/setting/{index.page.tsx → index.tsx} +2 -0
- package/src/pages/{index.page.tsx → home/index.tsx} +11 -5
- package/src/pages/market/features/Header/Mobile.tsx +4 -2
- package/src/pages/market/{index.page.tsx → index.tsx} +2 -0
- package/src/pages/settings/features/Header/Mobile.tsx +3 -2
- package/src/pages/settings/{index.page.tsx → index.tsx} +2 -0
- package/src/pages/welcome/{index.page.tsx → index.tsx} +2 -0
- package/src/store/session/hooks/useOnFinishHydrationSession.ts +5 -2
- package/src/store/session/slices/session/action.ts +4 -5
- package/src/store/session/slices/session/initialState.ts +2 -0
- package/src/types/settings.ts +2 -2
- package/src/utils/cookie.ts +4 -0
- package/tsconfig.json +8 -2
- package/src/pages/_app.page.tsx +0 -11
- package/src/pages/_document.page.tsx +0 -46
- /package/src/layout/{style.ts → GlobalLayout/style.ts} +0 -0
- /package/src/pages/{index → home}/Loading.tsx +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
### [Version 0.79.1](https://github.com/lobehub/lobe-chat/compare/v0.79.0...v0.79.1)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2023-09-25**</sup>
|
|
8
|
+
|
|
9
|
+
#### ♻ Code Refactoring
|
|
10
|
+
|
|
11
|
+
- **migration**: Next.js app router.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### Code refactoring
|
|
19
|
+
|
|
20
|
+
- **migration**: Next.js app router, closes [#220](https://github.com/lobehub/lobe-chat/issues/220) ([bb8085e](https://github.com/lobehub/lobe-chat/commit/bb8085e))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
5
30
|
## [Version 0.79.0](https://github.com/lobehub/lobe-chat/compare/v0.78.1...v0.79.0)
|
|
6
31
|
|
|
7
32
|
<sup>Released on **2023-09-25**</sup>
|
package/package.json
CHANGED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { StyleProvider, extractStaticStyle } from 'antd-style';
|
|
4
|
+
import { useServerInsertedHTML } from 'next/navigation';
|
|
5
|
+
import { PropsWithChildren, useRef } from 'react';
|
|
6
|
+
|
|
7
|
+
const StyleRegistry = ({ children }: PropsWithChildren) => {
|
|
8
|
+
const isInsert = useRef(false);
|
|
9
|
+
|
|
10
|
+
useServerInsertedHTML(() => {
|
|
11
|
+
// avoid duplicate css insert
|
|
12
|
+
// refs: https://github.com/vercel/next.js/discussions/49354#discussioncomment-6279917
|
|
13
|
+
if (isInsert.current) return;
|
|
14
|
+
|
|
15
|
+
isInsert.current = true;
|
|
16
|
+
|
|
17
|
+
return extractStaticStyle().map((item) => item.style);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
return <StyleProvider cache={extractStaticStyle.cache}>{children}</StyleProvider>;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export default StyleRegistry;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Analytics } from '@vercel/analytics/react';
|
|
2
|
+
import { Metadata } from 'next';
|
|
3
|
+
import { cookies } from 'next/headers';
|
|
4
|
+
import { PropsWithChildren } from 'react';
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
LOBE_THEME_APPEARANCE,
|
|
8
|
+
LOBE_THEME_NEUTRAL_COLOR,
|
|
9
|
+
LOBE_THEME_PRIMARY_COLOR,
|
|
10
|
+
} from '@/const/theme';
|
|
11
|
+
import Layout from '@/layout/GlobalLayout';
|
|
12
|
+
|
|
13
|
+
import StyleRegistry from './StyleRegistry';
|
|
14
|
+
|
|
15
|
+
export const metadata: Metadata = {
|
|
16
|
+
manifest: '/manifest.json',
|
|
17
|
+
title: 'LobeChat',
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const RootLayout = ({ children }: PropsWithChildren) => {
|
|
21
|
+
// get default theme config to use with ssr
|
|
22
|
+
const cookieStore = cookies();
|
|
23
|
+
const appearance = cookieStore.get(LOBE_THEME_APPEARANCE);
|
|
24
|
+
const neutralColor = cookieStore.get(LOBE_THEME_NEUTRAL_COLOR);
|
|
25
|
+
const primaryColor = cookieStore.get(LOBE_THEME_PRIMARY_COLOR);
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<html lang="en">
|
|
29
|
+
<body>
|
|
30
|
+
<StyleRegistry>
|
|
31
|
+
<Layout
|
|
32
|
+
defaultAppearance={appearance?.value}
|
|
33
|
+
defaultNeutralColor={neutralColor?.value as any}
|
|
34
|
+
defaultPrimaryColor={primaryColor?.value as any}
|
|
35
|
+
>
|
|
36
|
+
{children}
|
|
37
|
+
</Layout>
|
|
38
|
+
</StyleRegistry>
|
|
39
|
+
<Analytics />
|
|
40
|
+
</body>
|
|
41
|
+
</html>
|
|
42
|
+
);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export default RootLayout;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { NeutralColors, PrimaryColors, ThemeProvider } from '@lobehub/ui';
|
|
2
|
+
import { ThemeAppearance } from 'antd-style';
|
|
3
|
+
import { ReactNode, memo, useEffect } from 'react';
|
|
4
|
+
|
|
5
|
+
import {
|
|
6
|
+
LOBE_THEME_APPEARANCE,
|
|
7
|
+
LOBE_THEME_NEUTRAL_COLOR,
|
|
8
|
+
LOBE_THEME_PRIMARY_COLOR,
|
|
9
|
+
} from '@/const/theme';
|
|
10
|
+
import { useGlobalStore } from '@/store/global';
|
|
11
|
+
import { GlobalStyle } from '@/styles';
|
|
12
|
+
import { setCookie } from '@/utils/cookie';
|
|
13
|
+
|
|
14
|
+
export interface AppThemeProps {
|
|
15
|
+
children?: ReactNode;
|
|
16
|
+
defaultAppearance?: ThemeAppearance;
|
|
17
|
+
defaultNeutralColor?: NeutralColors;
|
|
18
|
+
defaultPrimaryColor?: PrimaryColors;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const AppTheme = memo<AppThemeProps>(
|
|
22
|
+
({ children, defaultAppearance, defaultPrimaryColor, defaultNeutralColor }) => {
|
|
23
|
+
console.log('server:appearance', defaultAppearance);
|
|
24
|
+
console.log('server:primaryColor', defaultPrimaryColor);
|
|
25
|
+
console.log('server:neutralColor', defaultNeutralColor);
|
|
26
|
+
const themeMode = useGlobalStore((s) => s.settings.themeMode);
|
|
27
|
+
|
|
28
|
+
const [primaryColor, neutralColor] = useGlobalStore((s) => [
|
|
29
|
+
s.settings.primaryColor,
|
|
30
|
+
s.settings.neutralColor,
|
|
31
|
+
]);
|
|
32
|
+
|
|
33
|
+
useEffect(() => {
|
|
34
|
+
console.log(primaryColor);
|
|
35
|
+
setCookie(LOBE_THEME_PRIMARY_COLOR, primaryColor);
|
|
36
|
+
}, [primaryColor]);
|
|
37
|
+
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
setCookie(LOBE_THEME_NEUTRAL_COLOR, neutralColor);
|
|
40
|
+
}, [neutralColor]);
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<ThemeProvider
|
|
44
|
+
customTheme={{
|
|
45
|
+
neutralColor: neutralColor ?? defaultNeutralColor,
|
|
46
|
+
primaryColor: primaryColor ?? defaultPrimaryColor,
|
|
47
|
+
}}
|
|
48
|
+
defaultAppearance={defaultAppearance}
|
|
49
|
+
onAppearanceChange={(appearance) => {
|
|
50
|
+
setCookie(LOBE_THEME_APPEARANCE, appearance);
|
|
51
|
+
}}
|
|
52
|
+
themeMode={themeMode}
|
|
53
|
+
>
|
|
54
|
+
<GlobalStyle />
|
|
55
|
+
{children}
|
|
56
|
+
</ThemeProvider>
|
|
57
|
+
);
|
|
58
|
+
},
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
export default AppTheme;
|
package/src/const/settings.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Icon, MobileTabBar, type MobileTabBarProps } from '@lobehub/ui';
|
|
2
2
|
import { createStyles } from 'antd-style';
|
|
3
3
|
import { Bot, MessageSquare } from 'lucide-react';
|
|
4
|
-
import
|
|
4
|
+
import { useRouter } from 'next/navigation';
|
|
5
5
|
import { rgba } from 'polished';
|
|
6
6
|
import { memo, useMemo } from 'react';
|
|
7
7
|
import { useTranslation } from 'react-i18next';
|
|
@@ -20,6 +20,7 @@ export default memo<{ className?: string }>(({ className }) => {
|
|
|
20
20
|
const [tab, setTab] = useGlobalStore((s) => [s.sidebarKey, s.switchSideBar]);
|
|
21
21
|
const { t } = useTranslation('common');
|
|
22
22
|
const { styles } = useStyles();
|
|
23
|
+
const router = useRouter();
|
|
23
24
|
const items: MobileTabBarProps['items'] = useMemo(
|
|
24
25
|
() => [
|
|
25
26
|
{
|
|
@@ -28,7 +29,7 @@ export default memo<{ className?: string }>(({ className }) => {
|
|
|
28
29
|
),
|
|
29
30
|
key: 'chat',
|
|
30
31
|
onClick: () => {
|
|
31
|
-
|
|
32
|
+
router.push('/chat');
|
|
32
33
|
},
|
|
33
34
|
title: t('tab.chat'),
|
|
34
35
|
},
|
|
@@ -36,7 +37,7 @@ export default memo<{ className?: string }>(({ className }) => {
|
|
|
36
37
|
icon: (active) => <Icon className={active ? styles.active : undefined} icon={Bot} />,
|
|
37
38
|
key: 'market',
|
|
38
39
|
onClick: () => {
|
|
39
|
-
|
|
40
|
+
router.push('/market', { hash: '' });
|
|
40
41
|
},
|
|
41
42
|
title: t('tab.market'),
|
|
42
43
|
},
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
Settings,
|
|
11
11
|
Settings2,
|
|
12
12
|
} from 'lucide-react';
|
|
13
|
-
import
|
|
13
|
+
import { useRouter } from 'next/navigation';
|
|
14
14
|
import { memo, useMemo } from 'react';
|
|
15
15
|
import { useTranslation } from 'react-i18next';
|
|
16
16
|
|
|
@@ -25,6 +25,7 @@ export interface BottomActionProps {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
const BottomActions = memo<BottomActionProps>(({ tab, setTab }) => {
|
|
28
|
+
const router = useRouter();
|
|
28
29
|
const { t } = useTranslation('common');
|
|
29
30
|
|
|
30
31
|
const { exportSessions, exportSettings, exportAll, exportAgents } = useExportConfig();
|
|
@@ -101,7 +102,7 @@ const BottomActions = memo<BottomActionProps>(({ tab, setTab }) => {
|
|
|
101
102
|
label: t('setting'),
|
|
102
103
|
onClick: () => {
|
|
103
104
|
setTab('settings');
|
|
104
|
-
|
|
105
|
+
router.push('/settings');
|
|
105
106
|
},
|
|
106
107
|
},
|
|
107
108
|
],
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ActionIcon } from '@lobehub/ui';
|
|
2
2
|
import { Bot, MessageSquare } from 'lucide-react';
|
|
3
|
-
import
|
|
3
|
+
import { usePathname, useRouter } from 'next/navigation';
|
|
4
4
|
import { memo } from 'react';
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
|
|
@@ -13,6 +13,8 @@ export interface TopActionProps {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
const TopActions = memo<TopActionProps>(({ tab, setTab }) => {
|
|
16
|
+
const pathname = usePathname();
|
|
17
|
+
const router = useRouter();
|
|
16
18
|
const { t } = useTranslation('common');
|
|
17
19
|
const switchBackToChat = useSessionStore((s) => s.switchBackToChat);
|
|
18
20
|
return (
|
|
@@ -22,7 +24,7 @@ const TopActions = memo<TopActionProps>(({ tab, setTab }) => {
|
|
|
22
24
|
icon={MessageSquare}
|
|
23
25
|
onClick={() => {
|
|
24
26
|
// 如果已经在 chat 路径下了,那么就不用再跳转了
|
|
25
|
-
if (
|
|
27
|
+
if (pathname?.startsWith('/chat')) return;
|
|
26
28
|
switchBackToChat();
|
|
27
29
|
setTab('chat');
|
|
28
30
|
}}
|
|
@@ -34,8 +36,8 @@ const TopActions = memo<TopActionProps>(({ tab, setTab }) => {
|
|
|
34
36
|
active={tab === 'market'}
|
|
35
37
|
icon={Bot}
|
|
36
38
|
onClick={() => {
|
|
37
|
-
if (
|
|
38
|
-
|
|
39
|
+
if (pathname?.startsWith('/market')) return;
|
|
40
|
+
router.push('/market');
|
|
39
41
|
setTab('market');
|
|
40
42
|
}}
|
|
41
43
|
placement={'right'}
|
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
2
3
|
import { App, ConfigProvider } from 'antd';
|
|
3
|
-
import { useThemeMode } from 'antd-style';
|
|
4
4
|
import 'antd/dist/reset.css';
|
|
5
5
|
import Zh_CN from 'antd/locale/zh_CN';
|
|
6
6
|
import { changeLanguage } from 'i18next';
|
|
7
|
-
import {
|
|
7
|
+
import { useRouter } from 'next/navigation';
|
|
8
|
+
import { PropsWithChildren, memo, useEffect } from 'react';
|
|
8
9
|
|
|
10
|
+
import AppTheme, { AppThemeProps } from '@/components/AppTheme';
|
|
9
11
|
import { createI18nNext } from '@/locales/create';
|
|
10
12
|
import { useGlobalStore, useOnFinishHydrationGlobal } from '@/store/global';
|
|
11
13
|
import { usePluginStore } from '@/store/plugin';
|
|
12
14
|
import { useOnFinishHydrationSession, useSessionStore } from '@/store/session';
|
|
13
|
-
import { GlobalStyle } from '@/styles';
|
|
14
15
|
|
|
15
16
|
import { useStyles } from './style';
|
|
16
17
|
|
|
@@ -19,14 +20,26 @@ const i18n = createI18nNext();
|
|
|
19
20
|
const Layout = memo<PropsWithChildren>(({ children }) => {
|
|
20
21
|
const { styles } = useStyles();
|
|
21
22
|
|
|
23
|
+
const router = useRouter();
|
|
24
|
+
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
// refs: https://github.com/pmndrs/zustand/blob/main/docs/integrations/persisting-store-data.md#hashydrated
|
|
27
|
+
useSessionStore.persist.rehydrate();
|
|
28
|
+
useGlobalStore.persist.rehydrate();
|
|
29
|
+
usePluginStore.persist.rehydrate();
|
|
30
|
+
}, []);
|
|
31
|
+
|
|
22
32
|
useOnFinishHydrationGlobal((state) => {
|
|
23
33
|
i18n.then(() => {
|
|
24
34
|
changeLanguage(state.settings.language);
|
|
25
35
|
});
|
|
26
36
|
});
|
|
27
37
|
|
|
28
|
-
useOnFinishHydrationSession((s) => {
|
|
38
|
+
useOnFinishHydrationSession((s, store) => {
|
|
29
39
|
usePluginStore.getState().checkLocalEnabledPlugins(s.sessions);
|
|
40
|
+
|
|
41
|
+
// add router instance to store
|
|
42
|
+
store.setState({ router });
|
|
30
43
|
});
|
|
31
44
|
|
|
32
45
|
return (
|
|
@@ -36,31 +49,10 @@ const Layout = memo<PropsWithChildren>(({ children }) => {
|
|
|
36
49
|
);
|
|
37
50
|
});
|
|
38
51
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
usePluginStore.persist.rehydrate();
|
|
45
|
-
}, []);
|
|
46
|
-
|
|
47
|
-
const themeMode = useGlobalStore((s) => s.settings.themeMode);
|
|
48
|
-
const [primaryColor, neutralColor] = useGlobalStore((s) => [
|
|
49
|
-
s.settings.primaryColor,
|
|
50
|
-
s.settings.neutralColor,
|
|
51
|
-
]);
|
|
52
|
-
const { browserPrefers } = useThemeMode();
|
|
53
|
-
const isDarkMode = themeMode === 'auto' ? browserPrefers === 'dark' : themeMode === 'dark';
|
|
52
|
+
const ThemeWrapper = ({ children, ...theme }: AppThemeProps) => (
|
|
53
|
+
<AppTheme {...theme}>
|
|
54
|
+
<Layout>{children}</Layout>
|
|
55
|
+
</AppTheme>
|
|
56
|
+
);
|
|
54
57
|
|
|
55
|
-
|
|
56
|
-
() => lobeCustomTheme({ isDarkMode, neutralColor, primaryColor }),
|
|
57
|
-
[primaryColor, neutralColor, isDarkMode],
|
|
58
|
-
);
|
|
59
|
-
|
|
60
|
-
return (
|
|
61
|
-
<ThemeProvider customToken={genCustomToken || {}} themeMode={themeMode}>
|
|
62
|
-
<GlobalStyle />
|
|
63
|
-
<Layout>{children}</Layout>
|
|
64
|
-
</ThemeProvider>
|
|
65
|
-
);
|
|
66
|
-
});
|
|
58
|
+
export default ThemeWrapper;
|
|
@@ -2,7 +2,7 @@ import { SiOpenai } from '@icons-pack/react-simple-icons';
|
|
|
2
2
|
import { ActionIcon, Avatar, ChatHeader, ChatHeaderTitle, Tag } from '@lobehub/ui';
|
|
3
3
|
import { Skeleton } from 'antd';
|
|
4
4
|
import { PanelRightClose, PanelRightOpen, Settings } from 'lucide-react';
|
|
5
|
-
import
|
|
5
|
+
import { useRouter } from 'next/navigation';
|
|
6
6
|
import { memo } from 'react';
|
|
7
7
|
import { useTranslation } from 'react-i18next';
|
|
8
8
|
import { Flexbox } from 'react-layout-kit';
|
|
@@ -16,6 +16,7 @@ import ShareButton from './ShareButton';
|
|
|
16
16
|
|
|
17
17
|
const Header = memo(() => {
|
|
18
18
|
const init = useSessionChatInit();
|
|
19
|
+
const router = useRouter();
|
|
19
20
|
|
|
20
21
|
const { t } = useTranslation('common');
|
|
21
22
|
|
|
@@ -80,7 +81,7 @@ const Header = memo(() => {
|
|
|
80
81
|
<ActionIcon
|
|
81
82
|
icon={Settings}
|
|
82
83
|
onClick={() => {
|
|
83
|
-
|
|
84
|
+
router.push('/chat/settings', { hash: location.hash });
|
|
84
85
|
}}
|
|
85
86
|
size={{ fontSize: 24 }}
|
|
86
87
|
title={t('header.session', { ns: 'setting' })}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ActionIcon, MobileNavBar, MobileNavBarTitle } from '@lobehub/ui';
|
|
2
2
|
import { LayoutList, Settings } from 'lucide-react';
|
|
3
|
-
import
|
|
3
|
+
import { useRouter } from 'next/navigation';
|
|
4
4
|
import { memo } from 'react';
|
|
5
5
|
import { useTranslation } from 'react-i18next';
|
|
6
6
|
|
|
@@ -10,6 +10,7 @@ import { agentSelectors, sessionSelectors } from '@/store/session/selectors';
|
|
|
10
10
|
|
|
11
11
|
const MobileHeader = memo(() => {
|
|
12
12
|
const { t } = useTranslation('common');
|
|
13
|
+
const router = useRouter();
|
|
13
14
|
|
|
14
15
|
const [isInbox, title, model] = useSessionStore((s) => [
|
|
15
16
|
sessionSelectors.isInboxSession(s),
|
|
@@ -24,7 +25,7 @@ const MobileHeader = memo(() => {
|
|
|
24
25
|
return (
|
|
25
26
|
<MobileNavBar
|
|
26
27
|
center={<MobileNavBarTitle desc={model} title={displayTitle} />}
|
|
27
|
-
onBackClick={() =>
|
|
28
|
+
onBackClick={() => router.push('/chat', { hash: null })}
|
|
28
29
|
right={
|
|
29
30
|
<>
|
|
30
31
|
<ActionIcon icon={LayoutList} onClick={() => toggleConfig()} />
|
|
@@ -32,7 +33,7 @@ const MobileHeader = memo(() => {
|
|
|
32
33
|
<ActionIcon
|
|
33
34
|
icon={Settings}
|
|
34
35
|
onClick={() => {
|
|
35
|
-
|
|
36
|
+
router.push('/chat/settings', { hash: location.hash });
|
|
36
37
|
}}
|
|
37
38
|
/>
|
|
38
39
|
)}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ActionIcon, Logo, MobileNavBar } from '@lobehub/ui';
|
|
2
2
|
import { createStyles } from 'antd-style';
|
|
3
3
|
import { MessageSquarePlus, Settings2 } from 'lucide-react';
|
|
4
|
-
import
|
|
4
|
+
import { useRouter } from 'next/navigation';
|
|
5
5
|
import { memo } from 'react';
|
|
6
6
|
|
|
7
7
|
import AvatarWithUpload from '@/features/AvatarWithUpload';
|
|
@@ -19,6 +19,7 @@ export const useStyles = createStyles(({ css, token }) => ({
|
|
|
19
19
|
|
|
20
20
|
const Header = memo(() => {
|
|
21
21
|
const [createSession] = useSessionStore((s) => [s.createSession]);
|
|
22
|
+
const router = useRouter();
|
|
22
23
|
|
|
23
24
|
return (
|
|
24
25
|
<MobileNavBar
|
|
@@ -30,7 +31,7 @@ const Header = memo(() => {
|
|
|
30
31
|
<ActionIcon
|
|
31
32
|
icon={Settings2}
|
|
32
33
|
onClick={() => {
|
|
33
|
-
|
|
34
|
+
router.push('/settings');
|
|
34
35
|
}}
|
|
35
36
|
/>
|
|
36
37
|
</>
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { ChatHeader, ChatHeaderTitle } from '@lobehub/ui';
|
|
2
|
-
import
|
|
2
|
+
import { useRouter } from 'next/navigation';
|
|
3
3
|
import { ReactNode, memo } from 'react';
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
5
|
|
|
6
6
|
const Header = memo<{ children: ReactNode }>(({ children }) => {
|
|
7
7
|
const { t } = useTranslation('setting');
|
|
8
|
+
const router = useRouter();
|
|
8
9
|
|
|
9
10
|
return (
|
|
10
11
|
<ChatHeader
|
|
11
12
|
left={<ChatHeaderTitle title={t('header.session')} />}
|
|
12
|
-
onBackClick={() =>
|
|
13
|
+
onBackClick={() => router.push('/chat', { hash: location.hash })}
|
|
13
14
|
right={children}
|
|
14
15
|
showBackButton
|
|
15
16
|
/>
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { MobileNavBar, MobileNavBarTitle } from '@lobehub/ui';
|
|
2
|
-
import
|
|
2
|
+
import { useRouter } from 'next/navigation';
|
|
3
3
|
import { type ReactNode, memo } from 'react';
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
5
|
|
|
6
6
|
const Header = memo<{ children: ReactNode }>(({ children }) => {
|
|
7
7
|
const { t } = useTranslation('setting');
|
|
8
|
+
const router = useRouter();
|
|
8
9
|
|
|
9
10
|
return (
|
|
10
11
|
<MobileNavBar
|
|
11
12
|
center={<MobileNavBarTitle title={t('header.session')} />}
|
|
12
|
-
onBackClick={() =>
|
|
13
|
+
onBackClick={() => router.push('/chat/mobile', { hash: location.hash })}
|
|
13
14
|
right={children}
|
|
14
15
|
showBackButton
|
|
15
16
|
/>
|
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
'use client';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { memo } from 'react';
|
|
4
|
+
|
|
5
|
+
import Loading from '@/pages/home/Loading';
|
|
6
|
+
import {
|
|
7
|
+
useEffectAfterSessionHydrated,
|
|
8
|
+
useSessionHydrated,
|
|
9
|
+
useSessionStore,
|
|
10
|
+
} from '@/store/session';
|
|
4
11
|
import { sessionSelectors } from '@/store/session/selectors';
|
|
5
12
|
|
|
6
|
-
import
|
|
7
|
-
import Welcome from './welcome/index.page';
|
|
13
|
+
import Welcome from '../welcome';
|
|
8
14
|
|
|
9
15
|
const Home = memo(() => {
|
|
10
16
|
const hydrated = useSessionHydrated();
|
|
@@ -13,7 +19,7 @@ const Home = memo(() => {
|
|
|
13
19
|
s.switchSession,
|
|
14
20
|
]);
|
|
15
21
|
|
|
16
|
-
|
|
22
|
+
useEffectAfterSessionHydrated(() => {
|
|
17
23
|
if (hasSession) switchSession();
|
|
18
24
|
}, [hasSession]);
|
|
19
25
|
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { ActionIcon, Logo, MobileNavBar } from '@lobehub/ui';
|
|
2
2
|
import { Settings2 } from 'lucide-react';
|
|
3
|
-
import
|
|
3
|
+
import { useRouter } from 'next/navigation';
|
|
4
4
|
import { memo } from 'react';
|
|
5
5
|
|
|
6
6
|
import AvatarWithUpload from '@/features/AvatarWithUpload';
|
|
7
7
|
|
|
8
8
|
const Header = memo(() => {
|
|
9
|
+
const router = useRouter();
|
|
10
|
+
|
|
9
11
|
return (
|
|
10
12
|
<MobileNavBar
|
|
11
13
|
center={<Logo type={'text'} />}
|
|
@@ -14,7 +16,7 @@ const Header = memo(() => {
|
|
|
14
16
|
<ActionIcon
|
|
15
17
|
icon={Settings2}
|
|
16
18
|
onClick={() => {
|
|
17
|
-
|
|
19
|
+
router.push('/settings');
|
|
18
20
|
}}
|
|
19
21
|
/>
|
|
20
22
|
}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
import { MobileNavBar, MobileNavBarTitle } from '@lobehub/ui';
|
|
2
|
-
import
|
|
2
|
+
import { useRouter } from 'next/navigation';
|
|
3
3
|
import { memo } from 'react';
|
|
4
4
|
import { useTranslation } from 'react-i18next';
|
|
5
5
|
|
|
6
6
|
const Header = memo(() => {
|
|
7
7
|
const { t } = useTranslation('setting');
|
|
8
|
+
const router = useRouter();
|
|
8
9
|
|
|
9
10
|
return (
|
|
10
11
|
<MobileNavBar
|
|
11
12
|
center={<MobileNavBarTitle title={t('header.global')} />}
|
|
12
|
-
onBackClick={() =>
|
|
13
|
+
onBackClick={() => router.push('/chat')}
|
|
13
14
|
showBackButton
|
|
14
15
|
/>
|
|
15
16
|
);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useEffect } from 'react';
|
|
2
|
+
import { StoreApi, UseBoundStore } from 'zustand';
|
|
2
3
|
|
|
3
4
|
import { SessionStore, useSessionStore } from '../store';
|
|
4
5
|
|
|
@@ -6,11 +7,13 @@ import { SessionStore, useSessionStore } from '../store';
|
|
|
6
7
|
* 当 Session 水合完毕后才会执行的 useEffect
|
|
7
8
|
* @param fn
|
|
8
9
|
*/
|
|
9
|
-
export const useOnFinishHydrationSession = (
|
|
10
|
+
export const useOnFinishHydrationSession = (
|
|
11
|
+
fn: (state: SessionStore, store: UseBoundStore<StoreApi<SessionStore>>) => void,
|
|
12
|
+
) => {
|
|
10
13
|
useEffect(() => {
|
|
11
14
|
// 只有当水合完毕后再开始做操作
|
|
12
15
|
useSessionStore.persist.onFinishHydration(() => {
|
|
13
|
-
fn(useSessionStore.getState());
|
|
16
|
+
fn(useSessionStore.getState(), useSessionStore);
|
|
14
17
|
});
|
|
15
18
|
}, []);
|
|
16
19
|
};
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { produce } from 'immer';
|
|
2
2
|
import { merge } from 'lodash-es';
|
|
3
|
-
import Router from 'next/router';
|
|
4
3
|
import { DeepPartial } from 'utility-types';
|
|
5
4
|
import { StateCreator } from 'zustand/vanilla';
|
|
6
5
|
|
|
@@ -154,22 +153,22 @@ export const createSessionSlice: StateCreator<
|
|
|
154
153
|
},
|
|
155
154
|
|
|
156
155
|
switchBackToChat: () => {
|
|
157
|
-
const { activeId } = get();
|
|
156
|
+
const { activeId, router } = get();
|
|
158
157
|
|
|
159
158
|
const id = activeId || INBOX_SESSION_ID;
|
|
160
159
|
|
|
161
160
|
get().activeSession(id);
|
|
162
161
|
|
|
163
|
-
|
|
162
|
+
router?.push(SESSION_CHAT_URL(id, get().isMobile));
|
|
164
163
|
},
|
|
165
164
|
switchSession: (sessionId = INBOX_SESSION_ID) => {
|
|
166
|
-
const { isMobile } = get();
|
|
165
|
+
const { isMobile, router } = get();
|
|
167
166
|
// mobile also should switch session due to chat mobile route is different
|
|
168
167
|
// fix https://github.com/lobehub/lobe-chat/issues/163
|
|
169
168
|
if (!isMobile && get().activeId === sessionId) return;
|
|
170
169
|
|
|
171
170
|
get().activeSession(sessionId);
|
|
172
171
|
|
|
173
|
-
|
|
172
|
+
router?.push(SESSION_CHAT_URL(sessionId, isMobile));
|
|
174
173
|
},
|
|
175
174
|
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { merge } from 'lodash-es';
|
|
2
|
+
import { AppRouterInstance } from 'next/dist/shared/lib/app-router-context';
|
|
2
3
|
|
|
3
4
|
import { DEFAULT_AGENT_META, DEFAULT_INBOX_AVATAR } from '@/const/meta';
|
|
4
5
|
import { LobeAgentConfig, LobeAgentSession, LobeSessionType } from '@/types/session';
|
|
@@ -14,6 +15,7 @@ export interface SessionState {
|
|
|
14
15
|
// 默认会话
|
|
15
16
|
inbox: LobeAgentSession;
|
|
16
17
|
isMobile?: boolean;
|
|
18
|
+
router?: AppRouterInstance;
|
|
17
19
|
searchKeywords: string;
|
|
18
20
|
sessions: Record<string, LobeAgentSession>;
|
|
19
21
|
topicSearchKeywords: string;
|
package/src/types/settings.ts
CHANGED
|
@@ -37,9 +37,9 @@ export interface GlobalBaseSettings {
|
|
|
37
37
|
*/
|
|
38
38
|
historyCount?: number;
|
|
39
39
|
language: Locales;
|
|
40
|
-
neutralColor
|
|
40
|
+
neutralColor?: NeutralColors;
|
|
41
41
|
password: string;
|
|
42
|
-
primaryColor
|
|
42
|
+
primaryColor?: PrimaryColors;
|
|
43
43
|
themeMode: ThemeMode;
|
|
44
44
|
}
|
|
45
45
|
|
package/tsconfig.json
CHANGED
|
@@ -19,7 +19,12 @@
|
|
|
19
19
|
"types": ["vitest/globals"],
|
|
20
20
|
"paths": {
|
|
21
21
|
"@/*": ["./src/*"]
|
|
22
|
-
}
|
|
22
|
+
},
|
|
23
|
+
"plugins": [
|
|
24
|
+
{
|
|
25
|
+
"name": "next"
|
|
26
|
+
}
|
|
27
|
+
]
|
|
23
28
|
},
|
|
24
29
|
"exclude": ["node_modules"],
|
|
25
30
|
"include": [
|
|
@@ -29,7 +34,8 @@
|
|
|
29
34
|
"tests",
|
|
30
35
|
"**/*.ts",
|
|
31
36
|
"**/*.d.ts",
|
|
32
|
-
"**/*.tsx"
|
|
37
|
+
"**/*.tsx",
|
|
38
|
+
".next/types/**/*.ts"
|
|
33
39
|
],
|
|
34
40
|
"ts-node": {
|
|
35
41
|
"compilerOptions": {
|
package/src/pages/_app.page.tsx
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { Analytics } from '@vercel/analytics/react';
|
|
2
|
-
import type { AppProps } from 'next/app';
|
|
3
|
-
|
|
4
|
-
import Layout from '@/layout';
|
|
5
|
-
|
|
6
|
-
export default ({ Component, pageProps }: AppProps) => (
|
|
7
|
-
<Layout>
|
|
8
|
-
<Component {...pageProps} />
|
|
9
|
-
<Analytics />
|
|
10
|
-
</Layout>
|
|
11
|
-
);
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { Meta } from '@lobehub/ui';
|
|
2
|
-
import { StyleProvider, extractStaticStyle } from 'antd-style';
|
|
3
|
-
import Document, { DocumentContext, Head, Html, Main, NextScript } from 'next/document';
|
|
4
|
-
|
|
5
|
-
class MyDocument extends Document {
|
|
6
|
-
static async getInitialProps(ctx: DocumentContext) {
|
|
7
|
-
const page = await ctx.renderPage({
|
|
8
|
-
enhanceApp: (App) => (props) => (
|
|
9
|
-
<StyleProvider cache={extractStaticStyle.cache}>
|
|
10
|
-
<App {...props} />
|
|
11
|
-
</StyleProvider>
|
|
12
|
-
),
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
const styles = extractStaticStyle(page.html).map((item) => item.style);
|
|
16
|
-
|
|
17
|
-
const initialProps = await Document.getInitialProps(ctx);
|
|
18
|
-
|
|
19
|
-
return {
|
|
20
|
-
...initialProps,
|
|
21
|
-
styles: (
|
|
22
|
-
<>
|
|
23
|
-
{initialProps.styles}
|
|
24
|
-
{styles}
|
|
25
|
-
</>
|
|
26
|
-
),
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
render() {
|
|
31
|
-
return (
|
|
32
|
-
<Html>
|
|
33
|
-
<Head>
|
|
34
|
-
<Meta title={'LobeChat'} />
|
|
35
|
-
<link href="/manifest.json" rel="manifest" />
|
|
36
|
-
</Head>
|
|
37
|
-
<body>
|
|
38
|
-
<Main />
|
|
39
|
-
<NextScript />
|
|
40
|
-
</body>
|
|
41
|
-
</Html>
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export default MyDocument;
|
|
File without changes
|
|
File without changes
|