@lobehub/chat 0.120.2 → 0.120.4
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/README.md +47 -22
- package/README.zh-CN.md +53 -26
- package/docs/Deployment/Upstream-Sync.md +8 -2
- package/docs/Deployment/Upstream-Sync.zh-CN.md +9 -3
- package/docs/Development/Add-New-Locale.md +9 -1
- package/docs/Development/Add-New-Locale.zh-CN.md +9 -1
- package/docs/Development/Contributing-Guidelines.md +83 -0
- package/docs/Development/Contributing-Guidelines.zh-CN.md +13 -0
- package/docs/Development/Internationalization-Implementation.md +125 -0
- package/docs/Development/Internationalization-Implementation.zh-CN.md +9 -1
- package/docs/Development/State-Management/State-Management-Intro.md +224 -0
- package/docs/Development/State-Management/{index.zh-CN.md → State-Management-Intro.zh-CN.md} +25 -28
- package/docs/Home.md +9 -6
- package/docs/_Sidebar.md +10 -7
- package/locales/ar/common.json +1 -0
- package/locales/ar/setting.json +1 -3
- package/locales/de-DE/common.json +1 -0
- package/locales/de-DE/setting.json +1 -3
- package/locales/en-US/common.json +1 -0
- package/locales/en-US/setting.json +1 -3
- package/locales/es-ES/common.json +1 -0
- package/locales/es-ES/setting.json +1 -3
- package/locales/fr-FR/common.json +1 -0
- package/locales/fr-FR/setting.json +1 -3
- package/locales/it-IT/common.json +1 -0
- package/locales/it-IT/setting.json +1 -3
- package/locales/ja-JP/common.json +1 -0
- package/locales/ja-JP/setting.json +1 -3
- package/locales/ko-KR/common.json +1 -0
- package/locales/ko-KR/setting.json +1 -3
- package/locales/nl-NL/common.json +1 -0
- package/locales/nl-NL/setting.json +1 -3
- package/locales/pl-PL/common.json +1 -0
- package/locales/pl-PL/setting.json +1 -3
- package/locales/pt-BR/common.json +1 -0
- package/locales/pt-BR/setting.json +1 -3
- package/locales/ru-RU/common.json +1 -0
- package/locales/ru-RU/setting.json +1 -3
- package/locales/tr-TR/common.json +1 -0
- package/locales/tr-TR/setting.json +1 -3
- package/locales/vi-VN/common.json +1 -0
- package/locales/vi-VN/setting.json +1 -3
- package/locales/zh-CN/common.json +1 -0
- package/locales/zh-CN/setting.json +1 -3
- package/locales/zh-TW/common.json +1 -0
- package/locales/zh-TW/setting.json +1 -3
- package/next.config.mjs +2 -2
- package/package.json +8 -7
- package/scripts/docsWorkflow/const.ts +1 -1
- package/scripts/docsWorkflow/index.ts +9 -3
- package/scripts/readmeWorkflow/syncAgentIndex.ts +2 -2
- package/scripts/readmeWorkflow/syncPluginIndex.ts +2 -2
- package/src/app/chat/(desktop)/features/ChatHeader.tsx +6 -6
- package/src/app/chat/{features → (desktop)/features/SideBar}/SystemRole/index.tsx +8 -5
- package/src/app/chat/(desktop)/features/{SideBar.tsx → SideBar/index.tsx} +2 -3
- package/src/app/chat/(mobile)/index.tsx +17 -4
- package/src/app/chat/(mobile)/mobile/page.tsx +30 -2
- package/src/app/chat/components/SessionHydration/index.tsx +44 -0
- package/src/app/chat/features/SessionListContent/DefaultMode.tsx +6 -1
- package/src/app/chat/features/SessionListContent/List/Item/Actions.tsx +0 -2
- package/src/app/chat/features/SessionListContent/List/index.tsx +7 -3
- package/src/app/chat/features/TopicListContent/Header.tsx +1 -1
- package/src/app/chat/page.tsx +7 -3
- package/src/app/home/Redirect.tsx +2 -2
- package/src/app/metadata.ts +6 -0
- package/src/app/settings/common/Common.tsx +5 -6
- package/src/app/welcome/features/Banner/index.tsx +6 -7
- package/src/components/StoreHydration/ChatHydration/index.tsx +33 -0
- package/src/config/server.ts +4 -0
- package/src/const/locale.ts +2 -2
- package/src/const/url.ts +1 -1
- package/src/database/models/__tests__/message.test.ts +3 -2
- package/src/database/models/message.ts +13 -9
- package/src/database/schemas/message.ts +1 -1
- package/src/features/ChatInput/ActionBar/Clear.tsx +0 -2
- package/src/features/ChatInput/useChatInput.ts +2 -6
- package/src/features/Conversation/hooks/useInitConversation.ts +0 -2
- package/src/features/Conversation/index.tsx +7 -2
- package/src/features/PluginDetailModal/index.tsx +0 -2
- package/src/features/PluginDevModal/index.tsx +0 -1
- package/src/features/SideBar/TopActions.tsx +5 -5
- package/src/layout/GlobalLayout/Locale.tsx +37 -10
- package/src/layout/GlobalLayout/StoreHydration.tsx +12 -11
- package/src/layout/GlobalLayout/index.tsx +1 -1
- package/src/locales/default/setting.ts +0 -2
- package/src/locales/resources.ts +9 -7
- package/src/store/chat/slices/message/action.ts +1 -1
- package/src/store/chat/store.ts +2 -34
- package/src/store/global/slices/common/action.ts +6 -0
- package/src/store/global/slices/common/initialState.ts +5 -0
- package/src/store/session/index.ts +0 -1
- package/src/store/session/initialState.ts +6 -2
- package/src/store/session/slices/agent/selectors.ts +3 -1
- package/src/store/session/slices/session/action.ts +13 -17
- package/src/store/session/slices/session/selectors/list.ts +7 -0
- package/src/store/session/store.ts +5 -46
- package/src/app/chat/(mobile)/layout.mobile.tsx +0 -17
- package/src/app/chat/(mobile)/mobile/index.tsx +0 -30
- package/src/app/chat/(mobile)/mobile/layout.mobile.tsx +0 -11
- package/src/store/session/hooks/index.ts +0 -4
- package/src/store/session/hooks/useEffectAfterHydrated.ts +0 -27
- package/src/store/session/hooks/useOnFinishHydrationSession.ts +0 -19
- package/src/store/session/hooks/useSessionChatInit.ts +0 -12
- package/src/store/session/hooks/useSessionHydrated.ts +0 -13
- /package/docs/Development/{index.md → Intro.md} +0 -0
- /package/docs/Development/{index.zh-CN.md → Intro.zh-CN.md} +0 -0
- /package/src/app/chat/{features → (desktop)/features/SideBar}/SystemRole/style.ts +0 -0
- /package/src/app/chat/{features → components}/SidebarHeader/index.tsx +0 -0
package/next.config.mjs
CHANGED
|
@@ -21,11 +21,11 @@ const nextConfig = {
|
|
|
21
21
|
compress: isProd,
|
|
22
22
|
experimental: {
|
|
23
23
|
optimizePackageImports: [
|
|
24
|
-
'modern-screenshot',
|
|
25
24
|
'emoji-mart',
|
|
26
25
|
'@emoji-mart/react',
|
|
27
26
|
'@emoji-mart/data',
|
|
28
27
|
'@icons-pack/react-simple-icons',
|
|
28
|
+
'@lobehub/ui',
|
|
29
29
|
'gpt-tokenizer',
|
|
30
30
|
'chroma-js',
|
|
31
31
|
],
|
|
@@ -46,7 +46,7 @@ const nextConfig = {
|
|
|
46
46
|
|
|
47
47
|
reactStrictMode: true,
|
|
48
48
|
|
|
49
|
-
transpilePackages: ['antd-style'
|
|
49
|
+
transpilePackages: ['antd-style'],
|
|
50
50
|
|
|
51
51
|
webpack(config) {
|
|
52
52
|
config.experiments = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/chat",
|
|
3
|
-
"version": "0.120.
|
|
3
|
+
"version": "0.120.4",
|
|
4
4
|
"description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"framework",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"dev": "next dev -p 3010",
|
|
33
33
|
"docs": "lobe-i18n md && npm run workflow:docs",
|
|
34
34
|
"i18n": "npm run workflow:i18n && lobe-i18n",
|
|
35
|
-
"i18n
|
|
35
|
+
"i18n:docs": "lobe-i18n md && npm run workflow:docs",
|
|
36
36
|
"lint": "npm run lint:ts && npm run lint:style && npm run type-check && npm run lint:circular",
|
|
37
37
|
"lint:circular": "dpdm src/**/*.ts --warning false --tree false --exit-code circular:1 -T true",
|
|
38
38
|
"lint:md": "remark . --quiet --frail --output",
|
|
@@ -51,9 +51,9 @@
|
|
|
51
51
|
"test:coverage-local": "vitest run --coverage",
|
|
52
52
|
"test:update": "vitest -u",
|
|
53
53
|
"type-check": "tsc --noEmit",
|
|
54
|
-
"workflow:docs": "
|
|
55
|
-
"workflow:i18n": "
|
|
56
|
-
"workflow:readme": "
|
|
54
|
+
"workflow:docs": "tsx scripts/docsWorkflow/index.ts",
|
|
55
|
+
"workflow:i18n": "tsx scripts/i18nWorkflow/index.ts",
|
|
56
|
+
"workflow:readme": "tsx scripts/readmeWorkflow/index.ts"
|
|
57
57
|
},
|
|
58
58
|
"lint-staged": {
|
|
59
59
|
"*.md": [
|
|
@@ -105,6 +105,7 @@
|
|
|
105
105
|
"modern-screenshot": "^4",
|
|
106
106
|
"nanoid": "^5",
|
|
107
107
|
"next": "^14.0.2",
|
|
108
|
+
"nuqs": "^1.15.4",
|
|
108
109
|
"openai": "^4.17.3",
|
|
109
110
|
"polished": "^4",
|
|
110
111
|
"posthog-js": "^1",
|
|
@@ -135,7 +136,7 @@
|
|
|
135
136
|
"yaml": "^2",
|
|
136
137
|
"zod": "^3",
|
|
137
138
|
"zustand": "^4.4",
|
|
138
|
-
"zustand-utils": "^1"
|
|
139
|
+
"zustand-utils": "^1.3.2"
|
|
139
140
|
},
|
|
140
141
|
"devDependencies": {
|
|
141
142
|
"@commitlint/cli": "^18",
|
|
@@ -179,7 +180,7 @@
|
|
|
179
180
|
"remark-parse": "^10",
|
|
180
181
|
"semantic-release": "^21",
|
|
181
182
|
"stylelint": "^15",
|
|
182
|
-
"
|
|
183
|
+
"tsx": "^4",
|
|
183
184
|
"typescript": "^5",
|
|
184
185
|
"unified": "^11",
|
|
185
186
|
"unist-util-visit": "^5",
|
|
@@ -6,7 +6,7 @@ export const ROOT = resolve(__dirname, '../..');
|
|
|
6
6
|
export const DOCS_DIR = resolve(ROOT, 'docs');
|
|
7
7
|
export const HOME_PATH = resolve(DOCS_DIR, 'Home.md');
|
|
8
8
|
export const SIDEBAR_PATH = resolve(DOCS_DIR, '_Sidebar.md');
|
|
9
|
-
export const docsFiles = globSync(resolve(DOCS_DIR, '**/*.md'), {
|
|
9
|
+
export const docsFiles = globSync(resolve(DOCS_DIR, '**/*.md').replaceAll('\\', '/'), {
|
|
10
10
|
ignore: ['Home.md', '_Sidebar.md', '_Footer.md'],
|
|
11
11
|
nodir: true,
|
|
12
12
|
}).filter((file) => !file.includes('.zh-CN.md'));
|
|
@@ -20,9 +20,15 @@ const run = async () => {
|
|
|
20
20
|
const links = {
|
|
21
21
|
cn: urlJoin(
|
|
22
22
|
WIKI_URL,
|
|
23
|
-
relative(DOCS_DIR, paths.cn)
|
|
23
|
+
relative(DOCS_DIR, paths.cn)
|
|
24
|
+
.replaceAll('\\', '/')
|
|
25
|
+
.split('/')[1]
|
|
26
|
+
.replace('.zh-CN.md', '.zh-CN'),
|
|
27
|
+
),
|
|
28
|
+
en: urlJoin(
|
|
29
|
+
WIKI_URL,
|
|
30
|
+
relative(DOCS_DIR, paths.en).replaceAll('\\', '/').split('/')[1].replace('.md', ''),
|
|
24
31
|
),
|
|
25
|
-
en: urlJoin(WIKI_URL, relative(DOCS_DIR, paths.en).split('/')[1].replace('.md', '')),
|
|
26
32
|
};
|
|
27
33
|
const titles = {
|
|
28
34
|
cn: await getTitle(paths.cn),
|
|
@@ -59,7 +65,7 @@ const run = async () => {
|
|
|
59
65
|
child.links.cn,
|
|
60
66
|
)}\n`;
|
|
61
67
|
sidebarContent += `- ${genMdLink(child.titles.en, child.links.en)} | ${genMdLink(
|
|
62
|
-
|
|
68
|
+
child.titles.cn,
|
|
63
69
|
child.links.cn,
|
|
64
70
|
)}\n`;
|
|
65
71
|
});
|
|
@@ -10,7 +10,7 @@ const genAgentTable = (data: DataItem[], lang: string) => {
|
|
|
10
10
|
const content = data.slice(0, 4).map((item) => [
|
|
11
11
|
[
|
|
12
12
|
genLink(
|
|
13
|
-
item.meta.title,
|
|
13
|
+
item.meta.title.replaceAll('|', ','),
|
|
14
14
|
qs.stringifyUrl({
|
|
15
15
|
query: { agent: item.identifier },
|
|
16
16
|
url: MARKET_URL,
|
|
@@ -18,7 +18,7 @@ const genAgentTable = (data: DataItem[], lang: string) => {
|
|
|
18
18
|
),
|
|
19
19
|
`<sup>By **${genLink(item.author, item.homepage)}** on **${(item as any).createAt}**</sup>`,
|
|
20
20
|
].join('<br/>'),
|
|
21
|
-
[item.meta.description, genTags(item.meta.tags)].join('<br/>'),
|
|
21
|
+
[item.meta.description.replaceAll('|', ','), genTags(item.meta.tags)].join('<br/>'),
|
|
22
22
|
]);
|
|
23
23
|
return markdownTable([
|
|
24
24
|
isCN ? ['最近新增', '助手说明'] : ['Recent Submits', 'Description'],
|
|
@@ -10,10 +10,10 @@ const genPluginTable = (data: DataItem[], lang: string) => {
|
|
|
10
10
|
.slice(0, 4)
|
|
11
11
|
.map((item) => [
|
|
12
12
|
[
|
|
13
|
-
genLink(item.meta.title, PLGUIN_URL),
|
|
13
|
+
genLink(item.meta.title.replaceAll('|', ','), PLGUIN_URL),
|
|
14
14
|
`<sup>By **${item.author}** on **${item.createdAt}**</sup>`,
|
|
15
15
|
].join('<br/>'),
|
|
16
|
-
[item.meta.description, genTags(item.meta.tags)].join('<br/>'),
|
|
16
|
+
[item.meta.description.replaceAll('|', ','), genTags(item.meta.tags)].join('<br/>'),
|
|
17
17
|
]);
|
|
18
18
|
return markdownTable([
|
|
19
19
|
isCN ? ['最近新增', '插件描述'] : ['Recent Submits', 'Description'],
|
|
@@ -9,7 +9,7 @@ import { Flexbox } from 'react-layout-kit';
|
|
|
9
9
|
|
|
10
10
|
import { DESKTOP_HEADER_ICON_SIZE } from '@/const/layoutTokens';
|
|
11
11
|
import { useGlobalStore } from '@/store/global';
|
|
12
|
-
import {
|
|
12
|
+
import { useSessionStore } from '@/store/session';
|
|
13
13
|
import { agentSelectors, sessionSelectors } from '@/store/session/selectors';
|
|
14
14
|
import { pathString } from '@/utils/url';
|
|
15
15
|
|
|
@@ -19,11 +19,12 @@ import ShareButton from '../../features/ChatHeader/ShareButton';
|
|
|
19
19
|
|
|
20
20
|
const Left = memo(() => {
|
|
21
21
|
const { t } = useTranslation('chat');
|
|
22
|
-
|
|
22
|
+
|
|
23
23
|
const router = useRouter();
|
|
24
24
|
|
|
25
|
-
const [isInbox, title, description, avatar, backgroundColor, model, plugins] =
|
|
26
|
-
(s) => [
|
|
25
|
+
const [init, isInbox, title, description, avatar, backgroundColor, model, plugins] =
|
|
26
|
+
useSessionStore((s) => [
|
|
27
|
+
sessionSelectors.isSomeSessionActive(s),
|
|
27
28
|
sessionSelectors.isInboxSession(s),
|
|
28
29
|
agentSelectors.currentAgentTitle(s),
|
|
29
30
|
agentSelectors.currentAgentDescription(s),
|
|
@@ -31,8 +32,7 @@ const Left = memo(() => {
|
|
|
31
32
|
agentSelectors.currentAgentBackgroundColor(s),
|
|
32
33
|
agentSelectors.currentAgentModel(s),
|
|
33
34
|
agentSelectors.currentAgentPlugins(s),
|
|
34
|
-
]
|
|
35
|
-
);
|
|
35
|
+
]);
|
|
36
36
|
|
|
37
37
|
const displayTitle = isInbox ? t('inbox.title') : title;
|
|
38
38
|
const displayDesc = isInbox ? t('inbox.desc') : description;
|
|
@@ -9,33 +9,36 @@ import useMergeState from 'use-merge-value';
|
|
|
9
9
|
|
|
10
10
|
import AgentInfo from '@/features/AgentInfo';
|
|
11
11
|
import { useGlobalStore } from '@/store/global';
|
|
12
|
-
import {
|
|
13
|
-
import { agentSelectors } from '@/store/session/selectors';
|
|
12
|
+
import { useSessionStore } from '@/store/session';
|
|
13
|
+
import { agentSelectors, sessionSelectors } from '@/store/session/selectors';
|
|
14
14
|
import { pathString } from '@/utils/url';
|
|
15
15
|
|
|
16
|
-
import SidebarHeader from '
|
|
16
|
+
import SidebarHeader from '../../../../components/SidebarHeader';
|
|
17
17
|
import { useStyles } from './style';
|
|
18
18
|
|
|
19
19
|
const SystemRole = memo(() => {
|
|
20
20
|
const router = useRouter();
|
|
21
21
|
const [editing, setEditing] = useState(false);
|
|
22
22
|
const { styles } = useStyles();
|
|
23
|
-
|
|
23
|
+
|
|
24
|
+
const [init, systemRole, meta, updateAgentConfig] = useSessionStore((s) => [
|
|
25
|
+
sessionSelectors.isSomeSessionActive(s),
|
|
24
26
|
agentSelectors.currentAgentSystemRole(s),
|
|
25
27
|
agentSelectors.currentAgentMeta(s),
|
|
26
28
|
s.updateAgentConfig,
|
|
27
29
|
]);
|
|
30
|
+
|
|
28
31
|
const [showSystemRole, toggleSystemRole] = useGlobalStore((s) => [
|
|
29
32
|
s.preference.showSystemRole,
|
|
30
33
|
s.toggleSystemRole,
|
|
31
34
|
]);
|
|
35
|
+
|
|
32
36
|
const [open, setOpen] = useMergeState(false, {
|
|
33
37
|
defaultValue: showSystemRole,
|
|
34
38
|
onChange: toggleSystemRole,
|
|
35
39
|
value: showSystemRole,
|
|
36
40
|
});
|
|
37
41
|
|
|
38
|
-
const init = useSessionChatInit();
|
|
39
42
|
const { t } = useTranslation('common');
|
|
40
43
|
|
|
41
44
|
const handleOpenWithEdit = () => {
|
|
@@ -3,15 +3,14 @@ import { createStyles } from 'antd-style';
|
|
|
3
3
|
import dynamic from 'next/dynamic';
|
|
4
4
|
import { memo } from 'react';
|
|
5
5
|
|
|
6
|
+
import TopicListContent from '@/app/chat/features/TopicListContent';
|
|
6
7
|
import SafeSpacing from '@/components/SafeSpacing';
|
|
7
8
|
import { CHAT_SIDEBAR_WIDTH } from '@/const/layoutTokens';
|
|
8
9
|
import { useGlobalStore } from '@/store/global';
|
|
9
10
|
import { useSessionStore } from '@/store/session';
|
|
10
11
|
import { sessionSelectors } from '@/store/session/selectors';
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const SystemRole = dynamic(() => import('../../features/SystemRole'));
|
|
13
|
+
const SystemRole = dynamic(() => import('./SystemRole'));
|
|
15
14
|
|
|
16
15
|
const useStyles = createStyles(({ css, token }) => ({
|
|
17
16
|
content: css`
|
|
@@ -1,17 +1,30 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { useRouter } from 'next/navigation';
|
|
4
|
+
import { memo, useEffect } from 'react';
|
|
5
|
+
|
|
6
|
+
import AppLayoutMobile from '@/layout/AppLayout.mobile';
|
|
7
|
+
import { useSwitchSideBarOnInit } from '@/store/global';
|
|
8
|
+
import { SidebarTabKey } from '@/store/global/slices/common/initialState';
|
|
4
9
|
|
|
5
10
|
import PageTitle from '../features/PageTitle';
|
|
11
|
+
import SessionHeader from './features/SessionHeader';
|
|
6
12
|
import SessionList from './features/SessionList';
|
|
7
|
-
import Layout from './layout.mobile';
|
|
8
13
|
|
|
9
14
|
const ChatMobilePage = memo(() => {
|
|
15
|
+
useSwitchSideBarOnInit(SidebarTabKey.Chat);
|
|
16
|
+
|
|
17
|
+
const router = useRouter();
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
router.prefetch('/chat/mobile');
|
|
20
|
+
router.prefetch('/settings');
|
|
21
|
+
}, []);
|
|
22
|
+
|
|
10
23
|
return (
|
|
11
|
-
<
|
|
24
|
+
<AppLayoutMobile navBar={<SessionHeader />} showTabBar>
|
|
12
25
|
<PageTitle />
|
|
13
26
|
<SessionList />
|
|
14
|
-
</
|
|
27
|
+
</AppLayoutMobile>
|
|
15
28
|
);
|
|
16
29
|
});
|
|
17
30
|
|
|
@@ -1,3 +1,31 @@
|
|
|
1
|
-
|
|
1
|
+
'use client';
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
import dynamic from 'next/dynamic';
|
|
4
|
+
import { memo } from 'react';
|
|
5
|
+
import { Flexbox } from 'react-layout-kit';
|
|
6
|
+
|
|
7
|
+
import ChatHeader from '@/app/chat/(mobile)/features/ChatHeader';
|
|
8
|
+
import Conversation from '@/features/Conversation';
|
|
9
|
+
import AppLayoutMobile from '@/layout/AppLayout.mobile';
|
|
10
|
+
import { useSessionStore } from '@/store/session';
|
|
11
|
+
|
|
12
|
+
import ChatInput from '../features/ChatInput';
|
|
13
|
+
|
|
14
|
+
const TopicList = dynamic(() => import('../features/TopicList'));
|
|
15
|
+
|
|
16
|
+
const Chat = memo(() => {
|
|
17
|
+
// due to mobile side don't have sessionList, so we need to fetch sessions here
|
|
18
|
+
// refs: https://github.com/lobehub/lobe-chat/pull/541
|
|
19
|
+
const useFetchSessions = useSessionStore((s) => s.useFetchSessions);
|
|
20
|
+
useFetchSessions();
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<AppLayoutMobile navBar={<ChatHeader />}>
|
|
24
|
+
<Flexbox height={'calc(100% - 44px)'} horizontal>
|
|
25
|
+
<Conversation chatInput={<ChatInput />} mobile />
|
|
26
|
+
<TopicList />
|
|
27
|
+
</Flexbox>
|
|
28
|
+
</AppLayoutMobile>
|
|
29
|
+
);
|
|
30
|
+
});
|
|
31
|
+
export default Chat;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useResponsive } from 'antd-style';
|
|
4
|
+
import { useRouter } from 'next/navigation';
|
|
5
|
+
import { useQueryState } from 'nuqs';
|
|
6
|
+
import { parseAsString } from 'nuqs/parsers';
|
|
7
|
+
import { memo, useEffect } from 'react';
|
|
8
|
+
import { createStoreUpdater } from 'zustand-utils';
|
|
9
|
+
|
|
10
|
+
import { useSessionStore } from '@/store/session';
|
|
11
|
+
|
|
12
|
+
// sync outside state to useSessionStore
|
|
13
|
+
const SessionHydration = memo(() => {
|
|
14
|
+
const useStoreUpdater = createStoreUpdater(useSessionStore);
|
|
15
|
+
|
|
16
|
+
const { mobile } = useResponsive();
|
|
17
|
+
useStoreUpdater('isMobile', mobile);
|
|
18
|
+
|
|
19
|
+
const router = useRouter();
|
|
20
|
+
// TODO: 后续可以把 router 从 useSessionStore 移除
|
|
21
|
+
useStoreUpdater('router', router);
|
|
22
|
+
|
|
23
|
+
// two-way bindings the url and session store
|
|
24
|
+
const [session, setSession] = useQueryState(
|
|
25
|
+
'session',
|
|
26
|
+
parseAsString.withDefault('inbox').withOptions({ history: 'replace', throttleMs: 500 }),
|
|
27
|
+
);
|
|
28
|
+
useStoreUpdater('activeId', session);
|
|
29
|
+
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
const unsubscribe = useSessionStore.subscribe(
|
|
32
|
+
(s) => s.activeId,
|
|
33
|
+
(state) => setSession(state),
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
return () => {
|
|
37
|
+
unsubscribe();
|
|
38
|
+
};
|
|
39
|
+
}, []);
|
|
40
|
+
|
|
41
|
+
return null;
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
export default SessionHydration;
|
|
@@ -16,13 +16,18 @@ const SessionListContent = memo(() => {
|
|
|
16
16
|
const { t } = useTranslation('chat');
|
|
17
17
|
const unpinnedSessionList = useSessionStore(sessionSelectors.unpinnedSessionList, isEqual);
|
|
18
18
|
const pinnedList = useSessionStore(sessionSelectors.pinnedSessionList, isEqual);
|
|
19
|
-
const hasPinnedSessionList = useSessionStore(
|
|
19
|
+
const [hasPinnedSessionList, useFetchSessions] = useSessionStore((s) => [
|
|
20
|
+
sessionSelectors.hasPinnedSessionList(s),
|
|
21
|
+
s.useFetchSessions,
|
|
22
|
+
]);
|
|
20
23
|
|
|
21
24
|
const [sessionGroupKeys, updatePreference] = useGlobalStore((s) => [
|
|
22
25
|
preferenceSelectors.sessionGroupKeys(s),
|
|
23
26
|
s.updatePreference,
|
|
24
27
|
]);
|
|
25
28
|
|
|
29
|
+
useFetchSessions();
|
|
30
|
+
|
|
26
31
|
const items = [
|
|
27
32
|
hasPinnedSessionList && {
|
|
28
33
|
children: <SessionList dataSource={pinnedList} />,
|