@lobehub/chat 0.152.12 → 0.153.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 +50 -0
- package/README.md +8 -8
- package/README.zh-CN.md +8 -8
- package/locales/ar/common.json +2 -0
- package/locales/bg-BG/common.json +2 -0
- package/locales/de-DE/common.json +2 -0
- package/locales/en-US/common.json +2 -0
- package/locales/es-ES/common.json +2 -0
- package/locales/fr-FR/common.json +2 -0
- package/locales/it-IT/common.json +2 -0
- package/locales/ja-JP/common.json +2 -0
- package/locales/ko-KR/common.json +2 -0
- package/locales/nl-NL/common.json +2 -0
- package/locales/pl-PL/common.json +2 -0
- package/locales/pt-BR/common.json +2 -0
- package/locales/ru-RU/common.json +2 -0
- package/locales/tr-TR/common.json +2 -0
- package/locales/vi-VN/common.json +2 -0
- package/locales/zh-CN/common.json +2 -0
- package/locales/zh-TW/common.json +2 -0
- package/package.json +1 -1
- package/src/app/(main)/(mobile)/me/features/AvatarBanner.tsx +12 -40
- package/src/app/(main)/(mobile)/me/features/Header.tsx +37 -0
- package/src/app/(main)/(mobile)/me/features/style.ts +29 -0
- package/src/app/(main)/(mobile)/me/layout.tsx +7 -1
- package/src/app/(main)/(mobile)/me/loading.tsx +22 -7
- package/src/app/(main)/(mobile)/me/page.tsx +4 -5
- package/src/app/(main)/@nav/_layout/Mobile.tsx +2 -2
- package/src/app/(main)/chat/(desktop)/features/ChatHeader/Main.tsx +4 -9
- package/src/app/(main)/chat/(desktop)/features/SideBar/SystemRole/index.tsx +5 -6
- package/src/app/(main)/chat/features/SettingButton.tsx +3 -17
- package/src/app/(main)/chat/features/TopicListContent/Header.tsx +1 -1
- package/src/app/(main)/chat/settings/_layout/Desktop/Header.tsx +2 -1
- package/src/app/(main)/chat/settings/_layout/Mobile/Header.tsx +2 -1
- package/src/app/(main)/chat/settings/modal/page.tsx +23 -0
- package/src/app/(main)/market/@detail/features/{AgentDetailContent/index.tsx → AgentDetailContent.tsx} +6 -12
- package/src/app/(main)/market/@detail/features/Banner.tsx +46 -0
- package/src/app/(main)/market/@detail/features/{AgentDetailContent/Header.tsx → Header.tsx} +4 -18
- package/src/app/(main)/market/@detail/features/{AgentDetailContent/Loading.tsx → Loading.tsx} +5 -4
- package/src/app/(main)/market/@detail/features/{AgentDetailContent/style.ts → style.ts} +0 -3
- package/src/app/(main)/market/features/AgentCard/AgentCardBanner.tsx +13 -8
- package/src/app/(main)/market/loading.tsx +13 -1
- package/src/app/(main)/settings/@category/features/CategoryContent.tsx +5 -1
- package/src/app/(main)/settings/modal/page.tsx +27 -0
- package/src/app/@modal/(.)settings/modal/index.tsx +40 -0
- package/src/app/@modal/(.)settings/modal/layout.tsx +32 -0
- package/src/app/@modal/(.)settings/modal/loading.tsx +5 -0
- package/src/app/@modal/(.)settings/modal/page.tsx +19 -0
- package/src/app/@modal/_layout/SettingModalLayout.tsx +59 -0
- package/src/app/@modal/chat/(.)settings/modal/features/CategoryContent.tsx +37 -0
- package/src/app/@modal/chat/(.)settings/modal/features/useCategory.tsx +54 -0
- package/src/app/@modal/chat/(.)settings/modal/layout.tsx +55 -0
- package/src/app/@modal/chat/(.)settings/modal/loading.tsx +5 -0
- package/src/app/@modal/chat/(.)settings/modal/page.tsx +55 -0
- package/src/app/@modal/default.tsx +3 -0
- package/src/app/@modal/error.tsx +5 -0
- package/src/app/@modal/layout.tsx +30 -0
- package/src/app/@modal/loading.tsx +5 -0
- package/src/app/layout.tsx +6 -2
- package/src/components/Cell/Divider.tsx +2 -0
- package/src/components/Cell/index.tsx +5 -1
- package/src/components/server/MobileNavLayout.tsx +1 -0
- package/src/features/Conversation/Messages/index.ts +9 -12
- package/src/features/Conversation/components/InboxWelcome/AgentsSuggest.tsx +15 -6
- package/src/features/Conversation/components/InboxWelcome/QuestionSuggest.tsx +9 -4
- package/src/features/Conversation/components/InboxWelcome/index.tsx +5 -3
- package/src/features/DataImporter/index.tsx +4 -1
- package/src/features/MobileTabBar/index.tsx +3 -3
- package/src/features/User/PlanTag.tsx +45 -0
- package/src/features/User/UserInfo.tsx +26 -9
- package/src/features/User/UserPanel/useMenu.tsx +31 -16
- package/src/hooks/useInterceptingRoutes.test.ts +70 -0
- package/src/hooks/useInterceptingRoutes.ts +46 -0
- package/src/hooks/useQuery.test.ts +0 -1
- package/src/hooks/useQuery.ts +2 -1
- package/src/layout/GlobalProvider/StoreInitialization.tsx +12 -5
- package/src/locales/default/common.ts +4 -2
- package/src/store/global/initialState.ts +9 -0
- package/src/styles/mobileHeader.ts +7 -0
- package/src/features/User/UserPanel/UserInfo.tsx +0 -35
- /package/src/app/(main)/market/@detail/features/{AgentDetailContent/Comment.tsx → Comment.tsx} +0 -0
- /package/src/app/(main)/market/@detail/features/{AgentDetailContent/TokenTag.tsx → TokenTag.tsx} +0 -0
- /package/src/{app/(main)/chat/components → components}/SidebarHeader/index.tsx +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DiscordIcon, Icon } from '@lobehub/ui';
|
|
1
|
+
import { ActionIcon, DiscordIcon, Icon } from '@lobehub/ui';
|
|
2
2
|
import { Badge } from 'antd';
|
|
3
3
|
import {
|
|
4
4
|
Book,
|
|
@@ -7,22 +7,29 @@ import {
|
|
|
7
7
|
HardDriveUpload,
|
|
8
8
|
LifeBuoy,
|
|
9
9
|
Mail,
|
|
10
|
+
Maximize,
|
|
10
11
|
Settings2,
|
|
11
12
|
} from 'lucide-react';
|
|
12
13
|
import Link from 'next/link';
|
|
13
14
|
import { PropsWithChildren, useCallback } from 'react';
|
|
14
15
|
import { useTranslation } from 'react-i18next';
|
|
15
16
|
import { Flexbox } from 'react-layout-kit';
|
|
17
|
+
import urlJoin from 'url-join';
|
|
16
18
|
|
|
17
19
|
import { type MenuProps } from '@/components/Menu';
|
|
18
20
|
import { DISCORD, DOCUMENTS, EMAIL_SUPPORT, GITHUB_ISSUES } from '@/const/url';
|
|
19
21
|
import DataImporter from '@/features/DataImporter';
|
|
22
|
+
import { useOpenSettings } from '@/hooks/useInterceptingRoutes';
|
|
23
|
+
import { useQueryRoute } from '@/hooks/useQueryRoute';
|
|
20
24
|
import { configService } from '@/services/config';
|
|
25
|
+
import { SettingsTabs } from '@/store/global/initialState';
|
|
21
26
|
|
|
22
27
|
import { useNewVersion } from './useNewVersion';
|
|
23
28
|
|
|
24
29
|
export const useMenu = () => {
|
|
30
|
+
const router = useQueryRoute();
|
|
25
31
|
const hasNewVersion = useNewVersion();
|
|
32
|
+
const openSettings = useOpenSettings();
|
|
26
33
|
const { t } = useTranslation(['common', 'setting']);
|
|
27
34
|
|
|
28
35
|
const NewVersionBadge = useCallback(
|
|
@@ -38,6 +45,29 @@ export const useMenu = () => {
|
|
|
38
45
|
[t],
|
|
39
46
|
);
|
|
40
47
|
|
|
48
|
+
const settings: MenuProps['items'] = [
|
|
49
|
+
{
|
|
50
|
+
icon: <Icon icon={Settings2} />,
|
|
51
|
+
key: 'setting',
|
|
52
|
+
label: (
|
|
53
|
+
<Flexbox align={'center'} horizontal>
|
|
54
|
+
<Flexbox flex={1} horizontal onClick={openSettings}>
|
|
55
|
+
<NewVersionBadge showBadge={hasNewVersion}>{t('userPanel.setting')}</NewVersionBadge>
|
|
56
|
+
</Flexbox>
|
|
57
|
+
<ActionIcon
|
|
58
|
+
icon={Maximize}
|
|
59
|
+
onClick={() => router.push(urlJoin('/settings', SettingsTabs.Common))}
|
|
60
|
+
size={'small'}
|
|
61
|
+
title={t('fullscreen')}
|
|
62
|
+
/>
|
|
63
|
+
</Flexbox>
|
|
64
|
+
),
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
type: 'divider',
|
|
68
|
+
},
|
|
69
|
+
];
|
|
70
|
+
|
|
41
71
|
const exports: MenuProps['items'] = [
|
|
42
72
|
{
|
|
43
73
|
icon: <Icon icon={HardDriveUpload} />,
|
|
@@ -79,21 +109,6 @@ export const useMenu = () => {
|
|
|
79
109
|
},
|
|
80
110
|
];
|
|
81
111
|
|
|
82
|
-
const settings: MenuProps['items'] = [
|
|
83
|
-
{
|
|
84
|
-
icon: <Icon icon={Settings2} />,
|
|
85
|
-
key: 'setting',
|
|
86
|
-
label: (
|
|
87
|
-
<Link href={'/settings'}>
|
|
88
|
-
<NewVersionBadge showBadge={hasNewVersion}>{t('userPanel.setting')}</NewVersionBadge>
|
|
89
|
-
</Link>
|
|
90
|
-
),
|
|
91
|
-
},
|
|
92
|
-
{
|
|
93
|
-
type: 'divider',
|
|
94
|
-
},
|
|
95
|
-
];
|
|
96
|
-
|
|
97
112
|
const helps: MenuProps['items'] = [
|
|
98
113
|
{
|
|
99
114
|
icon: <Icon icon={DiscordIcon} />,
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { renderHook } from '@testing-library/react';
|
|
2
|
+
import urlJoin from 'url-join';
|
|
3
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
4
|
+
|
|
5
|
+
import { INBOX_SESSION_ID } from '@/const/session';
|
|
6
|
+
import { useIsMobile } from '@/hooks/useIsMobile';
|
|
7
|
+
import { useGlobalStore } from '@/store/global';
|
|
8
|
+
import { ChatSettingsTabs, SettingsTabs, SidebarTabKey } from '@/store/global/initialState';
|
|
9
|
+
import { useSessionStore } from '@/store/session';
|
|
10
|
+
|
|
11
|
+
import { useOpenChatSettings, useOpenSettings } from './useInterceptingRoutes';
|
|
12
|
+
|
|
13
|
+
// Mocks
|
|
14
|
+
vi.mock('next/navigation', () => ({
|
|
15
|
+
useRouter: vi.fn(() => ({
|
|
16
|
+
push: vi.fn((href) => href),
|
|
17
|
+
replace: vi.fn((href) => href),
|
|
18
|
+
})),
|
|
19
|
+
}));
|
|
20
|
+
vi.mock('@/hooks/useQuery', () => ({
|
|
21
|
+
useQuery: vi.fn(() => ({})),
|
|
22
|
+
}));
|
|
23
|
+
vi.mock('@/hooks/useIsMobile', () => ({
|
|
24
|
+
useIsMobile: vi.fn(),
|
|
25
|
+
}));
|
|
26
|
+
vi.mock('@/store/session', () => ({
|
|
27
|
+
useSessionStore: vi.fn(),
|
|
28
|
+
}));
|
|
29
|
+
vi.mock('@/store/global', () => ({
|
|
30
|
+
useGlobalStore: {
|
|
31
|
+
setState: vi.fn(),
|
|
32
|
+
},
|
|
33
|
+
}));
|
|
34
|
+
|
|
35
|
+
describe('useOpenSettings', () => {
|
|
36
|
+
it('should handle mobile route correctly', () => {
|
|
37
|
+
vi.mocked(useIsMobile).mockReturnValue(true);
|
|
38
|
+
const { result } = renderHook(() => useOpenSettings(SettingsTabs.Common));
|
|
39
|
+
expect(result.current()).toBe('/settings/common');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should handle desktop route correctly', () => {
|
|
43
|
+
vi.mocked(useIsMobile).mockReturnValue(false);
|
|
44
|
+
const { result } = renderHook(() => useOpenSettings(SettingsTabs.Agent));
|
|
45
|
+
expect(result.current()).toBe('/settings/modal?tab=agent');
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe('useOpenChatSettings', () => {
|
|
50
|
+
it('should handle inbox session id correctly', () => {
|
|
51
|
+
vi.mocked(useSessionStore).mockReturnValue(INBOX_SESSION_ID);
|
|
52
|
+
const { result } = renderHook(() => useOpenChatSettings());
|
|
53
|
+
|
|
54
|
+
expect(result.current()).toBe('/settings/modal?session=inbox&tab=agent'); // Assuming openSettings returns a function
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('should handle mobile route for chat settings', () => {
|
|
58
|
+
vi.mocked(useSessionStore).mockReturnValue('123');
|
|
59
|
+
vi.mocked(useIsMobile).mockReturnValue(true);
|
|
60
|
+
const { result } = renderHook(() => useOpenChatSettings(ChatSettingsTabs.Meta));
|
|
61
|
+
expect(result.current()).toBe('/chat/settings');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('should handle desktop route for chat settings with session and tab', () => {
|
|
65
|
+
vi.mocked(useSessionStore).mockReturnValue('456');
|
|
66
|
+
vi.mocked(useIsMobile).mockReturnValue(false);
|
|
67
|
+
const { result } = renderHook(() => useOpenChatSettings(ChatSettingsTabs.Meta));
|
|
68
|
+
expect(result.current()).toBe('/chat/settings/modal?session=456&tab=meta');
|
|
69
|
+
});
|
|
70
|
+
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import urlJoin from 'url-join';
|
|
3
|
+
|
|
4
|
+
import { INBOX_SESSION_ID } from '@/const/session';
|
|
5
|
+
import { useIsMobile } from '@/hooks/useIsMobile';
|
|
6
|
+
import { useQueryRoute } from '@/hooks/useQueryRoute';
|
|
7
|
+
import { useGlobalStore } from '@/store/global';
|
|
8
|
+
import { ChatSettingsTabs, SettingsTabs, SidebarTabKey } from '@/store/global/initialState';
|
|
9
|
+
import { useSessionStore } from '@/store/session';
|
|
10
|
+
|
|
11
|
+
export const useOpenSettings = (tab: SettingsTabs = SettingsTabs.Common) => {
|
|
12
|
+
const activeId = useSessionStore((s) => s.activeId);
|
|
13
|
+
const router = useQueryRoute();
|
|
14
|
+
const mobile = useIsMobile();
|
|
15
|
+
|
|
16
|
+
return useMemo(() => {
|
|
17
|
+
if (mobile) {
|
|
18
|
+
return () => router.push(urlJoin('/settings', tab));
|
|
19
|
+
} else {
|
|
20
|
+
// use Intercepting Routes on Desktop
|
|
21
|
+
return () => router.push('/settings/modal', { query: { session: activeId, tab } });
|
|
22
|
+
}
|
|
23
|
+
}, [mobile, tab, activeId, router]);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export const useOpenChatSettings = (tab: ChatSettingsTabs = ChatSettingsTabs.Meta) => {
|
|
27
|
+
const activeId = useSessionStore((s) => s.activeId);
|
|
28
|
+
const openSettings = useOpenSettings(SettingsTabs.Agent);
|
|
29
|
+
const router = useQueryRoute();
|
|
30
|
+
const mobile = useIsMobile();
|
|
31
|
+
|
|
32
|
+
return useMemo(() => {
|
|
33
|
+
if (activeId === INBOX_SESSION_ID) {
|
|
34
|
+
useGlobalStore.setState({
|
|
35
|
+
sidebarKey: SidebarTabKey.Setting,
|
|
36
|
+
});
|
|
37
|
+
return openSettings;
|
|
38
|
+
}
|
|
39
|
+
if (mobile) {
|
|
40
|
+
return () => router.push('/chat/settings');
|
|
41
|
+
} else {
|
|
42
|
+
// use Intercepting Routes on Desktop
|
|
43
|
+
return () => router.push('/chat/settings/modal', { query: { session: activeId, tab } });
|
|
44
|
+
}
|
|
45
|
+
}, [openSettings, mobile, activeId, router, tab]);
|
|
46
|
+
};
|
package/src/hooks/useQuery.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { useSearchParams } from 'next/navigation';
|
|
2
2
|
import qs from 'query-string';
|
|
3
|
+
import { useMemo } from 'react';
|
|
3
4
|
|
|
4
5
|
export const useQuery = () => {
|
|
5
6
|
const rawQuery = useSearchParams();
|
|
6
|
-
return qs.parse(rawQuery.toString());
|
|
7
|
+
return useMemo(() => qs.parse(rawQuery.toString()), [rawQuery]);
|
|
7
8
|
};
|
|
@@ -49,12 +49,19 @@ const StoreInitialization = memo(() => {
|
|
|
49
49
|
|
|
50
50
|
useEffect(() => {
|
|
51
51
|
router.prefetch('/chat');
|
|
52
|
-
router.prefetch('/chat/settings');
|
|
53
52
|
router.prefetch('/market');
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
53
|
+
|
|
54
|
+
if (mobile) {
|
|
55
|
+
router.prefetch('/me');
|
|
56
|
+
router.prefetch('/chat/settings');
|
|
57
|
+
router.prefetch('/settings/common');
|
|
58
|
+
router.prefetch('/settings/agent');
|
|
59
|
+
router.prefetch('/settings/sync');
|
|
60
|
+
} else {
|
|
61
|
+
router.prefetch('/chat/settings/modal');
|
|
62
|
+
router.prefetch('/settings/modal');
|
|
63
|
+
}
|
|
64
|
+
}, [router, mobile]);
|
|
58
65
|
|
|
59
66
|
return null;
|
|
60
67
|
});
|
|
@@ -28,8 +28,9 @@ export default {
|
|
|
28
28
|
},
|
|
29
29
|
feedback: '反馈与建议',
|
|
30
30
|
follow: '在 {{name}} 上关注我们',
|
|
31
|
-
|
|
31
|
+
fullscreen: '全屏模式',
|
|
32
32
|
|
|
33
|
+
historyRange: '历史范围',
|
|
33
34
|
import: '导入配置',
|
|
34
35
|
importModal: {
|
|
35
36
|
finish: {
|
|
@@ -136,6 +137,7 @@ export default {
|
|
|
136
137
|
me: '我',
|
|
137
138
|
setting: '设置',
|
|
138
139
|
},
|
|
140
|
+
|
|
139
141
|
telemetry: {
|
|
140
142
|
allow: '允许',
|
|
141
143
|
deny: '拒绝',
|
|
@@ -143,7 +145,6 @@ export default {
|
|
|
143
145
|
learnMore: '了解更多',
|
|
144
146
|
title: '帮助 LobeChat 做得更好',
|
|
145
147
|
},
|
|
146
|
-
|
|
147
148
|
temp: '临时',
|
|
148
149
|
terms: '服务条款',
|
|
149
150
|
updateAgent: '更新助理信息',
|
|
@@ -162,6 +163,7 @@ export default {
|
|
|
162
163
|
help: '帮助中心',
|
|
163
164
|
moveGuide: '设置按钮搬到这里啦',
|
|
164
165
|
plans: '订阅方案',
|
|
166
|
+
preview: '预览版',
|
|
165
167
|
profile: '账户管理',
|
|
166
168
|
setting: '应用设置',
|
|
167
169
|
usages: '用量统计',
|
|
@@ -10,6 +10,15 @@ export enum SidebarTabKey {
|
|
|
10
10
|
Setting = 'settings',
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
export enum ChatSettingsTabs {
|
|
14
|
+
Chat = 'chat',
|
|
15
|
+
Meta = 'meta',
|
|
16
|
+
Modal = 'modal',
|
|
17
|
+
Plugin = 'plugin',
|
|
18
|
+
Prompt = 'prompt',
|
|
19
|
+
TTS = 'tts',
|
|
20
|
+
}
|
|
21
|
+
|
|
13
22
|
export enum SettingsTabs {
|
|
14
23
|
About = 'about',
|
|
15
24
|
Agent = 'agent',
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import { createStyles } from 'antd-style';
|
|
2
|
-
import { memo } from 'react';
|
|
3
|
-
import { Flexbox } from 'react-layout-kit';
|
|
4
|
-
|
|
5
|
-
import UserAvatar from '@/features/User/UserAvatar';
|
|
6
|
-
|
|
7
|
-
const useStyles = createStyles(({ css, token }) => ({
|
|
8
|
-
nickname: css`
|
|
9
|
-
font-size: 16px;
|
|
10
|
-
font-weight: bold;
|
|
11
|
-
line-height: 1;
|
|
12
|
-
`,
|
|
13
|
-
username: css`
|
|
14
|
-
line-height: 1;
|
|
15
|
-
color: ${token.colorTextDescription};
|
|
16
|
-
`,
|
|
17
|
-
}));
|
|
18
|
-
|
|
19
|
-
// TODO
|
|
20
|
-
|
|
21
|
-
const UserInfo = memo<{ onClick?: () => void }>(({ onClick }) => {
|
|
22
|
-
const { styles, theme } = useStyles();
|
|
23
|
-
|
|
24
|
-
return (
|
|
25
|
-
<Flexbox align={'center'} gap={12} horizontal paddingBlock={12} paddingInline={16}>
|
|
26
|
-
<UserAvatar background={theme.colorFill} onClick={onClick} size={48} />
|
|
27
|
-
<Flexbox flex={1} gap={6}>
|
|
28
|
-
<div className={styles.nickname}>{'社区版用户'}</div>
|
|
29
|
-
<div className={styles.username}> {'Community Edition'}</div>
|
|
30
|
-
</Flexbox>
|
|
31
|
-
</Flexbox>
|
|
32
|
-
);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
export default UserInfo;
|
/package/src/app/(main)/market/@detail/features/{AgentDetailContent/Comment.tsx → Comment.tsx}
RENAMED
|
File without changes
|
/package/src/app/(main)/market/@detail/features/{AgentDetailContent/TokenTag.tsx → TokenTag.tsx}
RENAMED
|
File without changes
|
|
File without changes
|