@lobehub/chat 0.79.0 → 0.79.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.
- package/CHANGELOG.md +50 -0
- package/package.json +1 -1
- package/public/manifest.json +7 -11
- package/src/app/StyleRegistry.tsx +24 -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 +41 -0
- package/src/app/market/page.page.tsx +7 -0
- package/src/app/metadata.ts +62 -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/public/icons/icon-192x192.png +0 -0
- package/public/icons/icon-512x512.png +0 -0
- package/public/icons/icon-72x72.png +0 -0
- package/public/icons/icon-96x96.png +0 -0
- 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,56 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
### [Version 0.79.2](https://github.com/lobehub/lobe-chat/compare/v0.79.1...v0.79.2)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2023-09-25**</sup>
|
|
8
|
+
|
|
9
|
+
#### 💄 Styles
|
|
10
|
+
|
|
11
|
+
- **meta**: Fix and add metadata.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### Styles
|
|
19
|
+
|
|
20
|
+
- **meta**: Fix and add metadata ([c872522](https://github.com/lobehub/lobe-chat/commit/c872522))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
### [Version 0.79.1](https://github.com/lobehub/lobe-chat/compare/v0.79.0...v0.79.1)
|
|
31
|
+
|
|
32
|
+
<sup>Released on **2023-09-25**</sup>
|
|
33
|
+
|
|
34
|
+
#### ♻ Code Refactoring
|
|
35
|
+
|
|
36
|
+
- **migration**: Next.js app router.
|
|
37
|
+
|
|
38
|
+
<br/>
|
|
39
|
+
|
|
40
|
+
<details>
|
|
41
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
42
|
+
|
|
43
|
+
#### Code refactoring
|
|
44
|
+
|
|
45
|
+
- **migration**: Next.js app router, closes [#220](https://github.com/lobehub/lobe-chat/issues/220) ([bb8085e](https://github.com/lobehub/lobe-chat/commit/bb8085e))
|
|
46
|
+
|
|
47
|
+
</details>
|
|
48
|
+
|
|
49
|
+
<div align="right">
|
|
50
|
+
|
|
51
|
+
[](#readme-top)
|
|
52
|
+
|
|
53
|
+
</div>
|
|
54
|
+
|
|
5
55
|
## [Version 0.79.0](https://github.com/lobehub/lobe-chat/compare/v0.78.1...v0.79.0)
|
|
6
56
|
|
|
7
57
|
<sup>Released on **2023-09-25**</sup>
|
package/package.json
CHANGED
package/public/manifest.json
CHANGED
|
@@ -1,20 +1,15 @@
|
|
|
1
1
|
{
|
|
2
|
-
"background_color": "#
|
|
2
|
+
"background_color": "#000000",
|
|
3
3
|
"display": "fullscreen",
|
|
4
4
|
"icons": [
|
|
5
5
|
{
|
|
6
|
-
"src": "
|
|
7
|
-
"sizes": "
|
|
8
|
-
"type": "image/png"
|
|
9
|
-
},
|
|
10
|
-
{
|
|
11
|
-
"src": "icons/icon-96x96.png",
|
|
12
|
-
"sizes": "96x96",
|
|
6
|
+
"src": "https://registry.npmmirror.com/@lobehub/assets-favicons/1.1.0/files/assets/android-chrome-192x192.png",
|
|
7
|
+
"sizes": "192x192",
|
|
13
8
|
"type": "image/png"
|
|
14
9
|
},
|
|
15
10
|
{
|
|
16
|
-
"src": "
|
|
17
|
-
"sizes": "
|
|
11
|
+
"src": "https://registry.npmmirror.com/@lobehub/assets-favicons/1.1.0/files/assets/android-chrome-512x512.png",
|
|
12
|
+
"sizes": "512x512",
|
|
18
13
|
"type": "image/png"
|
|
19
14
|
}
|
|
20
15
|
],
|
|
@@ -23,5 +18,6 @@
|
|
|
23
18
|
"scope": "/",
|
|
24
19
|
"short_name": "LobeChat",
|
|
25
20
|
"splash_pages": null,
|
|
26
|
-
"start_url": "/"
|
|
21
|
+
"start_url": "/",
|
|
22
|
+
"theme_color": "#000000"
|
|
27
23
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
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
|
+
// @ts-ignore
|
|
18
|
+
return extractStaticStyle().map((item) => item.style);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
return <StyleProvider cache={extractStaticStyle.cache}>{children}</StyleProvider>;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export default StyleRegistry;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Analytics } from '@vercel/analytics/react';
|
|
2
|
+
import { cookies } from 'next/headers';
|
|
3
|
+
import { PropsWithChildren } 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 Layout from '@/layout/GlobalLayout';
|
|
11
|
+
|
|
12
|
+
import StyleRegistry from './StyleRegistry';
|
|
13
|
+
|
|
14
|
+
const RootLayout = ({ children }: PropsWithChildren) => {
|
|
15
|
+
// get default theme config to use with ssr
|
|
16
|
+
const cookieStore = cookies();
|
|
17
|
+
const appearance = cookieStore.get(LOBE_THEME_APPEARANCE);
|
|
18
|
+
const neutralColor = cookieStore.get(LOBE_THEME_NEUTRAL_COLOR);
|
|
19
|
+
const primaryColor = cookieStore.get(LOBE_THEME_PRIMARY_COLOR);
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<html lang="en">
|
|
23
|
+
<body>
|
|
24
|
+
<StyleRegistry>
|
|
25
|
+
<Layout
|
|
26
|
+
defaultAppearance={appearance?.value}
|
|
27
|
+
defaultNeutralColor={neutralColor?.value as any}
|
|
28
|
+
defaultPrimaryColor={primaryColor?.value as any}
|
|
29
|
+
>
|
|
30
|
+
{children}
|
|
31
|
+
</Layout>
|
|
32
|
+
</StyleRegistry>
|
|
33
|
+
<Analytics />
|
|
34
|
+
</body>
|
|
35
|
+
</html>
|
|
36
|
+
);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export default RootLayout;
|
|
40
|
+
|
|
41
|
+
export { default as metadata } from './metadata';
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Metadata } from 'next';
|
|
2
|
+
|
|
3
|
+
import { genSiteHeadTitle } from '@/utils/genSiteHeadTitle';
|
|
4
|
+
|
|
5
|
+
import pkg from '../../package.json';
|
|
6
|
+
|
|
7
|
+
const title = genSiteHeadTitle();
|
|
8
|
+
const description = pkg.description;
|
|
9
|
+
const metadata: Metadata = {
|
|
10
|
+
appleWebApp: {
|
|
11
|
+
statusBarStyle: 'black-translucent',
|
|
12
|
+
title: title,
|
|
13
|
+
},
|
|
14
|
+
description: description,
|
|
15
|
+
icons: {
|
|
16
|
+
apple:
|
|
17
|
+
'https://registry.npmmirror.com/@lobehub/assets-favicons/1.1.0/files/assets/apple-touch-icon.png',
|
|
18
|
+
icon: 'https://registry.npmmirror.com/@lobehub/assets-favicons/1.1.0/files/assets/favicon-32x32.png',
|
|
19
|
+
other: {
|
|
20
|
+
rel: 'mask-icon',
|
|
21
|
+
url: 'https://registry.npmmirror.com/@lobehub/assets-favicons/1.1.0/files/assets/safari-pinned-tab.svg',
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
manifest: '/manifest.json',
|
|
25
|
+
openGraph: {
|
|
26
|
+
description: description,
|
|
27
|
+
images: [
|
|
28
|
+
{
|
|
29
|
+
alt: title,
|
|
30
|
+
height: 192,
|
|
31
|
+
url: 'https://registry.npmmirror.com/@lobehub/assets-favicons/1.1.0/files/assets/android-chrome-192x192.png',
|
|
32
|
+
width: 192,
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
alt: title,
|
|
36
|
+
height: 512,
|
|
37
|
+
url: 'https://registry.npmmirror.com/@lobehub/assets-favicons/1.1.0/files/assets/android-chrome-512x512.png',
|
|
38
|
+
width: 512,
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
locale: 'en_US',
|
|
42
|
+
siteName: title,
|
|
43
|
+
title: title,
|
|
44
|
+
type: 'website',
|
|
45
|
+
url: pkg.homepage,
|
|
46
|
+
},
|
|
47
|
+
themeColor: [
|
|
48
|
+
{ color: '#fff', media: '(prefers-color-scheme: light)' },
|
|
49
|
+
{ color: '#000', media: '(prefers-color-scheme: dark)' },
|
|
50
|
+
],
|
|
51
|
+
title: genSiteHeadTitle(),
|
|
52
|
+
viewport: {
|
|
53
|
+
initialScale: 1,
|
|
54
|
+
maximumScale: 1,
|
|
55
|
+
minimumScale: 1,
|
|
56
|
+
userScalable: false,
|
|
57
|
+
viewportFit: 'cover',
|
|
58
|
+
width: 'device-width',
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export default metadata;
|
|
@@ -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": {
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
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
|