@lobehub/chat 0.159.4 → 0.159.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/package.json +1 -1
- package/src/app/(main)/chat/(workspace)/@topic/_layout/Desktop.tsx +17 -0
- package/src/app/(main)/chat/(workspace)/@topic/_layout/Mobile.tsx +21 -0
- package/src/app/(main)/chat/(workspace)/@topic/default.tsx +7 -1
- package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/{Topic/SkeletonList.tsx → SkeletonList.tsx} +1 -1
- package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/{Topic/TopicItem.tsx → TopicItem.tsx} +5 -0
- package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/index.tsx +95 -13
- package/src/app/(main)/chat/(workspace)/_layout/Desktop/TopicPanel.tsx +12 -15
- package/src/app/(main)/chat/(workspace)/_layout/Mobile/TopicModal.tsx +9 -1
- package/src/app/(main)/chat/_layout/Desktop/SessionPanel.tsx +16 -25
- package/src/components/SidebarHeader/index.tsx +1 -2
- package/src/components/server/MobileNavLayout.tsx +1 -0
- package/src/features/Conversation/components/InboxWelcome/AgentsSuggest.tsx +18 -22
- package/src/layout/GlobalProvider/AppTheme.tsx +13 -0
- package/src/store/user/slices/preference/initialState.ts +1 -0
- package/src/styles/global.ts +23 -0
- package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/Topic/index.tsx +0 -101
- /package/src/app/(main)/chat/(workspace)/@topic/features/{TopicListContent/Header.tsx → Header.tsx} +0 -0
- /package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/{Topic/DefaultContent.tsx → DefaultContent.tsx} +0 -0
- /package/src/app/(main)/chat/(workspace)/@topic/features/TopicListContent/{Topic/TopicContent.tsx → TopicContent.tsx} +0 -0
- /package/src/app/(main)/chat/(workspace)/@topic/features/{TopicListContent/TopicSearchBar → TopicSearchBar}/index.tsx +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
### [Version 0.159.5](https://github.com/lobehub/lobe-chat/compare/v0.159.4...v0.159.5)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2024-05-14**</sup>
|
|
8
|
+
|
|
9
|
+
#### 💄 Styles
|
|
10
|
+
|
|
11
|
+
- **misc**: Fix scroll and expand.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### Styles
|
|
19
|
+
|
|
20
|
+
- **misc**: Fix scroll and expand, closes [#2470](https://github.com/lobehub/lobe-chat/issues/2470) ([8b1202a](https://github.com/lobehub/lobe-chat/commit/8b1202a))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
5
30
|
### [Version 0.159.4](https://github.com/lobehub/lobe-chat/compare/v0.159.3...v0.159.4)
|
|
6
31
|
|
|
7
32
|
<sup>Released on **2024-05-14**</sup>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/chat",
|
|
3
|
-
"version": "0.159.
|
|
3
|
+
"version": "0.159.5",
|
|
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",
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { PropsWithChildren } from 'react';
|
|
2
|
+
import { Flexbox } from 'react-layout-kit';
|
|
3
|
+
|
|
4
|
+
import Header from '../features/Header';
|
|
5
|
+
|
|
6
|
+
const Layout = ({ children }: PropsWithChildren) => {
|
|
7
|
+
return (
|
|
8
|
+
<>
|
|
9
|
+
<Header />
|
|
10
|
+
<Flexbox height={'100%'} style={{ overflow: 'hidden', position: 'relative' }} width={'100%'}>
|
|
11
|
+
{children}
|
|
12
|
+
</Flexbox>
|
|
13
|
+
</>
|
|
14
|
+
);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default Layout;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { PropsWithChildren } from 'react';
|
|
2
|
+
import { Flexbox } from 'react-layout-kit';
|
|
3
|
+
|
|
4
|
+
import TopicSearchBar from '../features/TopicSearchBar';
|
|
5
|
+
|
|
6
|
+
const Layout = ({ children }: PropsWithChildren) => {
|
|
7
|
+
return (
|
|
8
|
+
<Flexbox gap={8} height={'100%'} padding={'8px 8px 0'} style={{ overflow: 'hidden' }}>
|
|
9
|
+
<TopicSearchBar />
|
|
10
|
+
<Flexbox
|
|
11
|
+
height={'100%'}
|
|
12
|
+
style={{ marginInline: -8, overflow: 'hidden', position: 'relative' }}
|
|
13
|
+
width={'calc(100% + 16px)'}
|
|
14
|
+
>
|
|
15
|
+
{children}
|
|
16
|
+
</Flexbox>
|
|
17
|
+
</Flexbox>
|
|
18
|
+
);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export default Layout;
|
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
import { isMobileDevice } from '@/utils/responsive';
|
|
2
2
|
|
|
3
|
+
import Desktop from './_layout/Desktop';
|
|
4
|
+
import Mobile from './_layout/Mobile';
|
|
3
5
|
import SystemRole from './features/SystemRole';
|
|
4
6
|
import TopicListContent from './features/TopicListContent';
|
|
5
7
|
|
|
6
8
|
const Topic = () => {
|
|
7
9
|
const mobile = isMobileDevice();
|
|
8
10
|
|
|
11
|
+
const Layout = mobile ? Mobile : Desktop;
|
|
12
|
+
|
|
9
13
|
return (
|
|
10
14
|
<>
|
|
11
15
|
{!mobile && <SystemRole />}
|
|
12
|
-
<
|
|
16
|
+
<Layout>
|
|
17
|
+
<TopicListContent />
|
|
18
|
+
</Layout>
|
|
13
19
|
</>
|
|
14
20
|
);
|
|
15
21
|
};
|
|
@@ -19,7 +19,12 @@ const useStyles = createStyles(({ css, token, isDarkMode }) => ({
|
|
|
19
19
|
`,
|
|
20
20
|
container: css`
|
|
21
21
|
cursor: pointer;
|
|
22
|
+
|
|
23
|
+
width: calc(100% - 16px);
|
|
24
|
+
margin-block: 2px;
|
|
25
|
+
margin-inline: 8px;
|
|
22
26
|
padding: 8px;
|
|
27
|
+
|
|
23
28
|
border-radius: ${token.borderRadius}px;
|
|
24
29
|
|
|
25
30
|
&:hover {
|
|
@@ -1,18 +1,100 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { EmptyCard } from '@lobehub/ui';
|
|
4
|
+
import { useThemeMode } from 'antd-style';
|
|
5
|
+
import isEqual from 'fast-deep-equal';
|
|
6
|
+
import React, { memo, useCallback, useRef } from 'react';
|
|
7
|
+
import { useTranslation } from 'react-i18next';
|
|
1
8
|
import { Flexbox } from 'react-layout-kit';
|
|
9
|
+
import { Virtuoso, VirtuosoHandle } from 'react-virtuoso';
|
|
10
|
+
|
|
11
|
+
import { imageUrl } from '@/const/url';
|
|
12
|
+
import { useChatStore } from '@/store/chat';
|
|
13
|
+
import { topicSelectors } from '@/store/chat/selectors';
|
|
14
|
+
import { useUserStore } from '@/store/user';
|
|
15
|
+
import { ChatTopic } from '@/types/topic';
|
|
16
|
+
|
|
17
|
+
import { Placeholder, SkeletonList } from './SkeletonList';
|
|
18
|
+
import TopicItem from './TopicItem';
|
|
19
|
+
|
|
20
|
+
const TopicListContent = memo(() => {
|
|
21
|
+
const { t } = useTranslation('chat');
|
|
22
|
+
const virtuosoRef = useRef<VirtuosoHandle>(null);
|
|
23
|
+
const { isDarkMode } = useThemeMode();
|
|
24
|
+
const [topicsInit, activeTopicId, topicLength] = useChatStore((s) => [
|
|
25
|
+
s.topicsInit,
|
|
26
|
+
s.activeTopicId,
|
|
27
|
+
topicSelectors.currentTopicLength(s),
|
|
28
|
+
]);
|
|
29
|
+
const [visible, updateGuideState] = useUserStore((s) => [
|
|
30
|
+
s.preference.guide?.topic,
|
|
31
|
+
s.updateGuideState,
|
|
32
|
+
]);
|
|
33
|
+
|
|
34
|
+
const topics = useChatStore(
|
|
35
|
+
(s) => [
|
|
36
|
+
{
|
|
37
|
+
favorite: false,
|
|
38
|
+
id: 'default',
|
|
39
|
+
title: t('topic.defaultTitle'),
|
|
40
|
+
} as ChatTopic,
|
|
41
|
+
...topicSelectors.displayTopics(s),
|
|
42
|
+
],
|
|
43
|
+
isEqual,
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
const itemContent = useCallback(
|
|
47
|
+
(index: number, { id, favorite, title }: ChatTopic) =>
|
|
48
|
+
index === 0 ? (
|
|
49
|
+
<TopicItem active={!activeTopicId} fav={favorite} title={title} />
|
|
50
|
+
) : (
|
|
51
|
+
<TopicItem active={activeTopicId === id} fav={favorite} id={id} key={id} title={title} />
|
|
52
|
+
),
|
|
53
|
+
[activeTopicId],
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
const activeIndex = topics.findIndex((topic) => topic.id === activeTopicId);
|
|
2
57
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
58
|
+
return !topicsInit ? (
|
|
59
|
+
<SkeletonList />
|
|
60
|
+
) : (
|
|
61
|
+
<>
|
|
62
|
+
{topicLength === 0 && visible && (
|
|
63
|
+
<Flexbox paddingInline={8}>
|
|
64
|
+
<EmptyCard
|
|
65
|
+
alt={t('topic.guide.desc')}
|
|
66
|
+
cover={imageUrl(`empty_topic_${isDarkMode ? 'dark' : 'light'}.webp`)}
|
|
67
|
+
desc={t('topic.guide.desc')}
|
|
68
|
+
height={120}
|
|
69
|
+
imageProps={{
|
|
70
|
+
priority: true,
|
|
71
|
+
}}
|
|
72
|
+
onVisibleChange={(visible) => {
|
|
73
|
+
updateGuideState({ topic: visible });
|
|
74
|
+
}}
|
|
75
|
+
style={{ flex: 'none', marginBottom: 12 }}
|
|
76
|
+
title={t('topic.guide.title')}
|
|
77
|
+
visible={visible}
|
|
78
|
+
width={200}
|
|
79
|
+
/>
|
|
80
|
+
</Flexbox>
|
|
81
|
+
)}
|
|
82
|
+
<Virtuoso
|
|
83
|
+
components={{ ScrollSeekPlaceholder: Placeholder }}
|
|
84
|
+
computeItemKey={(_, item) => item.id}
|
|
85
|
+
data={topics}
|
|
86
|
+
fixedItemHeight={44}
|
|
87
|
+
initialTopMostItemIndex={Math.max(activeIndex, 0)}
|
|
88
|
+
itemContent={itemContent}
|
|
89
|
+
overscan={44 * 10}
|
|
90
|
+
ref={virtuosoRef}
|
|
91
|
+
scrollSeekConfiguration={{
|
|
92
|
+
enter: (velocity) => Math.abs(velocity) > 350,
|
|
93
|
+
exit: (velocity) => Math.abs(velocity) < 10,
|
|
94
|
+
}}
|
|
95
|
+
/>
|
|
96
|
+
</>
|
|
15
97
|
);
|
|
16
|
-
};
|
|
98
|
+
});
|
|
17
99
|
|
|
18
100
|
export default TopicListContent;
|
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import { DraggablePanel, DraggablePanelContainer } from '@lobehub/ui';
|
|
4
4
|
import { createStyles, useResponsive } from 'antd-style';
|
|
5
|
-
import
|
|
5
|
+
import isEqual from 'fast-deep-equal';
|
|
6
|
+
import { PropsWithChildren, memo, useEffect, useState } from 'react';
|
|
6
7
|
|
|
7
8
|
import SafeSpacing from '@/components/SafeSpacing';
|
|
8
9
|
import { CHAT_SIDEBAR_WIDTH } from '@/const/layoutTokens';
|
|
@@ -26,27 +27,23 @@ const useStyles = createStyles(({ css, token }) => ({
|
|
|
26
27
|
const TopicPanel = memo(({ children }: PropsWithChildren) => {
|
|
27
28
|
const { styles } = useStyles();
|
|
28
29
|
const { md = true, lg = true } = useResponsive();
|
|
29
|
-
const [showAgentSettings, toggleConfig
|
|
30
|
+
const [showAgentSettings, toggleConfig] = useGlobalStore((s) => [
|
|
30
31
|
s.preference.showChatSideBar,
|
|
31
32
|
s.toggleChatSideBar,
|
|
32
33
|
s.isPreferenceInit,
|
|
33
34
|
]);
|
|
34
|
-
const [
|
|
35
|
+
const [cacheExpand, setCacheExpand] = useState<boolean>(Boolean(showAgentSettings));
|
|
35
36
|
|
|
36
|
-
const handleExpand = (
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
const handleExpand = (expand: boolean) => {
|
|
38
|
+
if (isEqual(expand, Boolean(showAgentSettings))) return;
|
|
39
|
+
toggleConfig(expand);
|
|
40
|
+
setCacheExpand(expand);
|
|
39
41
|
};
|
|
40
42
|
|
|
41
|
-
useLayoutEffect(() => {
|
|
42
|
-
if (!isPreferenceInit) return;
|
|
43
|
-
setExpand(showAgentSettings);
|
|
44
|
-
}, [isPreferenceInit, showAgentSettings]);
|
|
45
|
-
|
|
46
43
|
useEffect(() => {
|
|
47
|
-
if (lg &&
|
|
48
|
-
if (!lg)
|
|
49
|
-
}, [lg,
|
|
44
|
+
if (lg && cacheExpand) toggleConfig(true);
|
|
45
|
+
if (!lg) toggleConfig(false);
|
|
46
|
+
}, [lg, cacheExpand]);
|
|
50
47
|
|
|
51
48
|
return (
|
|
52
49
|
<DraggablePanel
|
|
@@ -54,7 +51,7 @@ const TopicPanel = memo(({ children }: PropsWithChildren) => {
|
|
|
54
51
|
classNames={{
|
|
55
52
|
content: styles.content,
|
|
56
53
|
}}
|
|
57
|
-
expand={
|
|
54
|
+
expand={showAgentSettings}
|
|
58
55
|
minWidth={CHAT_SIDEBAR_WIDTH}
|
|
59
56
|
mode={md ? 'fixed' : 'float'}
|
|
60
57
|
onExpandChange={handleExpand}
|
|
@@ -17,7 +17,15 @@ const Topics = memo(({ children }: PropsWithChildren) => {
|
|
|
17
17
|
const { t } = useTranslation('chat');
|
|
18
18
|
|
|
19
19
|
return (
|
|
20
|
-
<Modal
|
|
20
|
+
<Modal
|
|
21
|
+
allowFullscreen
|
|
22
|
+
onCancel={() => setOpen(false)}
|
|
23
|
+
open={open}
|
|
24
|
+
styles={{
|
|
25
|
+
body: { padding: 0 },
|
|
26
|
+
}}
|
|
27
|
+
title={t('topic.title')}
|
|
28
|
+
>
|
|
21
29
|
{children}
|
|
22
30
|
</Modal>
|
|
23
31
|
);
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { DraggablePanel, DraggablePanelContainer, type DraggablePanelProps } from '@lobehub/ui';
|
|
4
4
|
import { createStyles, useResponsive } from 'antd-style';
|
|
5
5
|
import isEqual from 'fast-deep-equal';
|
|
6
|
-
import { PropsWithChildren, memo, useEffect,
|
|
6
|
+
import { PropsWithChildren, memo, useEffect, useState } from 'react';
|
|
7
7
|
|
|
8
8
|
import { FOLDER_WIDTH } from '@/const/layoutTokens';
|
|
9
9
|
import { useGlobalStore } from '@/store/global';
|
|
@@ -18,25 +18,21 @@ export const useStyles = createStyles(({ css, token }) => ({
|
|
|
18
18
|
|
|
19
19
|
const SessionPanel = memo<PropsWithChildren>(({ children }) => {
|
|
20
20
|
const { md = true } = useResponsive();
|
|
21
|
+
|
|
21
22
|
const { styles } = useStyles();
|
|
22
|
-
const [sessionsWidth, sessionExpandable, updatePreference
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
],
|
|
29
|
-
);
|
|
30
|
-
const [expand, setExpand] = useState(sessionExpandable);
|
|
23
|
+
const [sessionsWidth, sessionExpandable, updatePreference] = useGlobalStore((s) => [
|
|
24
|
+
s.preference.sessionsWidth,
|
|
25
|
+
s.preference.showSessionPanel,
|
|
26
|
+
s.updatePreference,
|
|
27
|
+
]);
|
|
28
|
+
const [cacheExpand, setCacheExpand] = useState<boolean>(Boolean(sessionExpandable));
|
|
31
29
|
const [tmpWidth, setWidth] = useState(sessionsWidth);
|
|
32
30
|
if (tmpWidth !== sessionsWidth) setWidth(sessionsWidth);
|
|
33
31
|
|
|
34
|
-
const handleExpand
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
});
|
|
39
|
-
setExpand(e);
|
|
32
|
+
const handleExpand = (expand: boolean) => {
|
|
33
|
+
if (isEqual(expand, sessionExpandable)) return;
|
|
34
|
+
updatePreference({ showSessionPanel: expand });
|
|
35
|
+
setCacheExpand(expand);
|
|
40
36
|
};
|
|
41
37
|
|
|
42
38
|
const handleSizeChange: DraggablePanelProps['onSizeChange'] = (_, size) => {
|
|
@@ -47,21 +43,16 @@ const SessionPanel = memo<PropsWithChildren>(({ children }) => {
|
|
|
47
43
|
updatePreference({ sessionsWidth: nextWidth });
|
|
48
44
|
};
|
|
49
45
|
|
|
50
|
-
useLayoutEffect(() => {
|
|
51
|
-
if (!isPreferenceInit) return;
|
|
52
|
-
setExpand(sessionExpandable);
|
|
53
|
-
}, [isPreferenceInit, sessionExpandable]);
|
|
54
|
-
|
|
55
46
|
useEffect(() => {
|
|
56
|
-
if (md &&
|
|
57
|
-
if (!md)
|
|
58
|
-
}, [md,
|
|
47
|
+
if (md && cacheExpand) updatePreference({ showSessionPanel: true });
|
|
48
|
+
if (!md) updatePreference({ showSessionPanel: false });
|
|
49
|
+
}, [md, cacheExpand]);
|
|
59
50
|
|
|
60
51
|
return (
|
|
61
52
|
<DraggablePanel
|
|
62
53
|
className={styles.panel}
|
|
63
54
|
defaultSize={{ width: tmpWidth }}
|
|
64
|
-
expand={
|
|
55
|
+
expand={sessionExpandable}
|
|
65
56
|
maxWidth={400}
|
|
66
57
|
minWidth={FOLDER_WIDTH}
|
|
67
58
|
mode={md ? 'fixed' : 'float'}
|
|
@@ -2,10 +2,9 @@ import { createStyles } from 'antd-style';
|
|
|
2
2
|
import { type ReactNode, memo } from 'react';
|
|
3
3
|
import { Flexbox } from 'react-layout-kit';
|
|
4
4
|
|
|
5
|
-
const useStyles = createStyles(({ css
|
|
5
|
+
const useStyles = createStyles(({ css }) => ({
|
|
6
6
|
header: css`
|
|
7
7
|
z-index: 10;
|
|
8
|
-
box-shadow: 0 2px 6px ${token.colorBgLayout};
|
|
9
8
|
`,
|
|
10
9
|
}));
|
|
11
10
|
|
|
@@ -6,7 +6,7 @@ import { createStyles } from 'antd-style';
|
|
|
6
6
|
import isEqual from 'fast-deep-equal';
|
|
7
7
|
import { RefreshCw } from 'lucide-react';
|
|
8
8
|
import Link from 'next/link';
|
|
9
|
-
import { memo,
|
|
9
|
+
import { memo, useState } from 'react';
|
|
10
10
|
import { useTranslation } from 'react-i18next';
|
|
11
11
|
import { Flexbox } from 'react-layout-kit';
|
|
12
12
|
|
|
@@ -71,26 +71,6 @@ const AgentsSuggest = memo<{ mobile?: boolean }>(({ mobile }) => {
|
|
|
71
71
|
</Flexbox>
|
|
72
72
|
));
|
|
73
73
|
|
|
74
|
-
const cards = useMemo(
|
|
75
|
-
() =>
|
|
76
|
-
agentList.slice(sliceStart, sliceStart + agentLength).map((agent) => (
|
|
77
|
-
<Link href={`/market?agent=${agent.identifier}`} key={agent.identifier}>
|
|
78
|
-
<Flexbox className={styles.card} gap={8} horizontal>
|
|
79
|
-
<Avatar avatar={agent.meta.avatar} style={{ flex: 'none' }} />
|
|
80
|
-
<Flexbox gap={mobile ? 2 : 8} style={{ overflow: 'hidden', width: '100%' }}>
|
|
81
|
-
<Paragraph className={styles.cardTitle} ellipsis={{ rows: 1 }}>
|
|
82
|
-
{agent.meta.title}
|
|
83
|
-
</Paragraph>
|
|
84
|
-
<Paragraph className={styles.cardDesc} ellipsis={{ rows: mobile ? 1 : 2 }}>
|
|
85
|
-
{agent.meta.description}
|
|
86
|
-
</Paragraph>
|
|
87
|
-
</Flexbox>
|
|
88
|
-
</Flexbox>
|
|
89
|
-
</Link>
|
|
90
|
-
)),
|
|
91
|
-
[agentList, sliceStart],
|
|
92
|
-
);
|
|
93
|
-
|
|
94
74
|
const handleRefresh = () => {
|
|
95
75
|
if (!agentList) return;
|
|
96
76
|
setSliceStart(Math.floor((Math.random() * agentList.length) / 2));
|
|
@@ -108,7 +88,23 @@ const AgentsSuggest = memo<{ mobile?: boolean }>(({ mobile }) => {
|
|
|
108
88
|
/>
|
|
109
89
|
</Flexbox>
|
|
110
90
|
<Grid gap={8} rows={2}>
|
|
111
|
-
{isLoading
|
|
91
|
+
{isLoading
|
|
92
|
+
? loadingCards
|
|
93
|
+
: agentList.slice(sliceStart, sliceStart + agentLength).map((agent) => (
|
|
94
|
+
<Link href={`/market?agent=${agent.identifier}`} key={agent.identifier}>
|
|
95
|
+
<Flexbox className={styles.card} gap={8} horizontal>
|
|
96
|
+
<Avatar avatar={agent.meta.avatar} style={{ flex: 'none' }} />
|
|
97
|
+
<Flexbox gap={mobile ? 2 : 8} style={{ overflow: 'hidden', width: '100%' }}>
|
|
98
|
+
<Paragraph className={styles.cardTitle} ellipsis={{ rows: 1 }}>
|
|
99
|
+
{agent.meta.title}
|
|
100
|
+
</Paragraph>
|
|
101
|
+
<Paragraph className={styles.cardDesc} ellipsis={{ rows: mobile ? 1 : 2 }}>
|
|
102
|
+
{agent.meta.description}
|
|
103
|
+
</Paragraph>
|
|
104
|
+
</Flexbox>
|
|
105
|
+
</Flexbox>
|
|
106
|
+
</Link>
|
|
107
|
+
))}
|
|
112
108
|
</Grid>
|
|
113
109
|
</Flexbox>
|
|
114
110
|
);
|
|
@@ -30,12 +30,25 @@ const useStyles = createStyles(({ css, token }) => ({
|
|
|
30
30
|
height: 100%;
|
|
31
31
|
min-height: 100dvh;
|
|
32
32
|
max-height: 100dvh;
|
|
33
|
+
|
|
34
|
+
@media (min-device-width: 576px) {
|
|
35
|
+
overflow: hidden;
|
|
36
|
+
}
|
|
33
37
|
`,
|
|
34
38
|
// scrollbar-width and scrollbar-color are supported from Chrome 121
|
|
35
39
|
// https://developer.mozilla.org/en-US/docs/Web/CSS/scrollbar-color
|
|
36
40
|
scrollbar: css`
|
|
37
41
|
scrollbar-color: ${token.colorFill} transparent;
|
|
38
42
|
scrollbar-width: thin;
|
|
43
|
+
|
|
44
|
+
#lobe-mobile-scroll-container {
|
|
45
|
+
scrollbar-width: none;
|
|
46
|
+
|
|
47
|
+
::-webkit-scrollbar {
|
|
48
|
+
width: 0;
|
|
49
|
+
height: 0;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
39
52
|
`,
|
|
40
53
|
|
|
41
54
|
// so this is a polyfill for older browsers
|
package/src/styles/global.ts
CHANGED
|
@@ -16,10 +16,33 @@ export default ({ token }: { prefixCls: string; token: Theme }) => css`
|
|
|
16
16
|
max-height: 100dvh;
|
|
17
17
|
|
|
18
18
|
background: ${token.colorBgLayout};
|
|
19
|
+
|
|
20
|
+
@media (min-device-width: 576px) {
|
|
21
|
+
overflow: hidden;
|
|
22
|
+
}
|
|
19
23
|
}
|
|
20
24
|
|
|
21
25
|
* {
|
|
22
26
|
scrollbar-color: ${token.colorFill} transparent;
|
|
23
27
|
scrollbar-width: thin;
|
|
28
|
+
|
|
29
|
+
::-webkit-scrollbar {
|
|
30
|
+
width: 0.75em;
|
|
31
|
+
height: 0.75em;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
::-webkit-scrollbar-thumb {
|
|
35
|
+
border-radius: 10px;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
:hover::-webkit-scrollbar-thumb {
|
|
39
|
+
background-color: ${token.colorText};
|
|
40
|
+
background-clip: content-box;
|
|
41
|
+
border: 3px solid transparent;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
::-webkit-scrollbar-track {
|
|
45
|
+
background-color: transparent;
|
|
46
|
+
}
|
|
24
47
|
}
|
|
25
48
|
`;
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
|
|
3
|
-
import { EmptyCard } from '@lobehub/ui';
|
|
4
|
-
import { useThemeMode } from 'antd-style';
|
|
5
|
-
import isEqual from 'fast-deep-equal';
|
|
6
|
-
import React, { memo, useCallback, useRef } from 'react';
|
|
7
|
-
import { useTranslation } from 'react-i18next';
|
|
8
|
-
import { Flexbox } from 'react-layout-kit';
|
|
9
|
-
import { Virtuoso, VirtuosoHandle } from 'react-virtuoso';
|
|
10
|
-
|
|
11
|
-
import { imageUrl } from '@/const/url';
|
|
12
|
-
import { useChatStore } from '@/store/chat';
|
|
13
|
-
import { topicSelectors } from '@/store/chat/selectors';
|
|
14
|
-
import { useUserStore } from '@/store/user';
|
|
15
|
-
import { ChatTopic } from '@/types/topic';
|
|
16
|
-
|
|
17
|
-
import { Placeholder, SkeletonList } from './SkeletonList';
|
|
18
|
-
import TopicItem from './TopicItem';
|
|
19
|
-
|
|
20
|
-
export const Topic = memo<{ mobile?: boolean }>(({ mobile }) => {
|
|
21
|
-
const { t } = useTranslation('chat');
|
|
22
|
-
const virtuosoRef = useRef<VirtuosoHandle>(null);
|
|
23
|
-
const { isDarkMode } = useThemeMode();
|
|
24
|
-
const [topicsInit, activeTopicId, topicLength] = useChatStore((s) => [
|
|
25
|
-
s.topicsInit,
|
|
26
|
-
s.activeTopicId,
|
|
27
|
-
topicSelectors.currentTopicLength(s),
|
|
28
|
-
]);
|
|
29
|
-
const [visible, updateGuideState] = useUserStore((s) => [
|
|
30
|
-
s.preference.guide?.topic,
|
|
31
|
-
s.updateGuideState,
|
|
32
|
-
]);
|
|
33
|
-
|
|
34
|
-
const topics = useChatStore(
|
|
35
|
-
(s) => [
|
|
36
|
-
{
|
|
37
|
-
favorite: false,
|
|
38
|
-
id: 'default',
|
|
39
|
-
title: t('topic.defaultTitle'),
|
|
40
|
-
} as ChatTopic,
|
|
41
|
-
...topicSelectors.displayTopics(s),
|
|
42
|
-
],
|
|
43
|
-
isEqual,
|
|
44
|
-
);
|
|
45
|
-
|
|
46
|
-
const itemContent = useCallback(
|
|
47
|
-
(index: number, { id, favorite, title }: ChatTopic) =>
|
|
48
|
-
index === 0 ? (
|
|
49
|
-
<TopicItem active={!activeTopicId} fav={favorite} title={title} />
|
|
50
|
-
) : (
|
|
51
|
-
<TopicItem active={activeTopicId === id} fav={favorite} id={id} key={id} title={title} />
|
|
52
|
-
),
|
|
53
|
-
[activeTopicId],
|
|
54
|
-
);
|
|
55
|
-
|
|
56
|
-
const activeIndex = topics.findIndex((topic) => topic.id === activeTopicId);
|
|
57
|
-
|
|
58
|
-
return !topicsInit ? (
|
|
59
|
-
<SkeletonList />
|
|
60
|
-
) : (
|
|
61
|
-
<Flexbox
|
|
62
|
-
gap={2}
|
|
63
|
-
height={'100%'}
|
|
64
|
-
paddingInline={mobile ? undefined : 8}
|
|
65
|
-
style={{ marginBottom: 12 }}
|
|
66
|
-
>
|
|
67
|
-
{topicLength === 0 && (
|
|
68
|
-
<EmptyCard
|
|
69
|
-
alt={t('topic.guide.desc')}
|
|
70
|
-
cover={imageUrl(`empty_topic_${isDarkMode ? 'dark' : 'light'}.webp`)}
|
|
71
|
-
desc={t('topic.guide.desc')}
|
|
72
|
-
height={120}
|
|
73
|
-
imageProps={{
|
|
74
|
-
priority: true,
|
|
75
|
-
}}
|
|
76
|
-
onVisibleChange={(visible) => {
|
|
77
|
-
updateGuideState({ topic: visible });
|
|
78
|
-
}}
|
|
79
|
-
style={{ flex: 'none', marginBottom: 12 }}
|
|
80
|
-
title={t('topic.guide.title')}
|
|
81
|
-
visible={visible}
|
|
82
|
-
width={200}
|
|
83
|
-
/>
|
|
84
|
-
)}
|
|
85
|
-
<Virtuoso
|
|
86
|
-
components={{ ScrollSeekPlaceholder: Placeholder }}
|
|
87
|
-
computeItemKey={(_, item) => item.id}
|
|
88
|
-
data={topics}
|
|
89
|
-
fixedItemHeight={44}
|
|
90
|
-
initialTopMostItemIndex={Math.max(activeIndex, 0)}
|
|
91
|
-
itemContent={itemContent}
|
|
92
|
-
overscan={44 * 10}
|
|
93
|
-
ref={virtuosoRef}
|
|
94
|
-
scrollSeekConfiguration={{
|
|
95
|
-
enter: (velocity) => Math.abs(velocity) > 350,
|
|
96
|
-
exit: (velocity) => Math.abs(velocity) < 10,
|
|
97
|
-
}}
|
|
98
|
-
/>
|
|
99
|
-
</Flexbox>
|
|
100
|
-
);
|
|
101
|
-
});
|
/package/src/app/(main)/chat/(workspace)/@topic/features/{TopicListContent/Header.tsx → Header.tsx}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|