@lobehub/chat 0.73.0 → 0.75.0
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/.github/workflows/contributor-help.yml +1 -1
- package/.github/workflows/sync.yml +43 -0
- package/.github/workflows/wiki-sync.yml +1 -0
- package/CHANGELOG.md +87 -0
- package/README.md +40 -6
- package/{README-zh_CN.md → README.zh-CN.md} +38 -4
- package/docs/Home.md +6 -0
- package/docs/Upstream-Sync.en-US.md +16 -0
- package/docs/Upstream-Sync.zh-CN.md +16 -0
- package/docs/_Sidebar.md +6 -0
- package/locales/en_US/market.json +12 -0
- package/locales/en_US/plugin.json +11 -2
- package/locales/en_US/setting.json +63 -2
- package/locales/ru_RU/market.json +12 -0
- package/locales/ru_RU/plugin.json +44 -49
- package/locales/ru_RU/setting.json +63 -2
- package/locales/zh_CN/common.json +1 -1
- package/locales/zh_CN/market.json +12 -0
- package/locales/zh_CN/plugin.json +19 -5
- package/locales/zh_CN/setting.json +62 -14
- package/package.json +5 -4
- package/scripts/i18nWorkflow/const.ts +19 -0
- package/scripts/i18nWorkflow/genDefaultLocale.ts +19 -0
- package/scripts/i18nWorkflow/genDiff.ts +50 -0
- package/scripts/i18nWorkflow/genResources.ts +26 -0
- package/scripts/i18nWorkflow/index.ts +15 -0
- package/scripts/i18nWorkflow/utils.ts +85 -0
- package/src/const/layoutTokens.ts +3 -1
- package/src/const/market.ts +15 -0
- package/src/const/url.ts +29 -4
- package/src/features/AgentSetting/AgentConfig/index.tsx +1 -2
- package/src/features/AgentSetting/AgentPlugin/MarketSettingModal.tsx +1 -1
- package/src/features/AgentSetting/store/initialState.ts +1 -1
- package/src/features/MobileTabBar/index.tsx +2 -2
- package/src/features/SideBar/TopActions.tsx +2 -2
- package/src/locales/default/market.ts +12 -0
- package/src/locales/resources/en_US.ts +2 -0
- package/src/locales/resources/ru_RU.ts +2 -0
- package/src/locales/resources/zh_CN.ts +2 -0
- package/src/pages/chat/features/Conversation/Input/{Action.tsx → ActionBar/ActionLeft.tsx} +2 -2
- package/src/pages/chat/features/Conversation/Input/ActionBar/ActionRight.tsx +36 -0
- package/src/pages/chat/features/Conversation/Input/Desktop.tsx +40 -0
- package/src/pages/chat/features/Conversation/Input/Footer/SaveTopic.tsx +27 -0
- package/src/pages/chat/features/Conversation/Input/Footer/index.tsx +35 -0
- package/src/pages/chat/features/Conversation/Input/Mobile.tsx +12 -0
- package/src/pages/chat/features/Conversation/Input/index.tsx +20 -38
- package/src/pages/chat/features/SessionList/Header/Desktop.tsx +6 -13
- package/src/pages/chat/features/SessionList/Header/Mobile.tsx +1 -1
- package/src/pages/chat/features/SessionList/List/AddButton.tsx +1 -1
- package/src/pages/chat/features/SessionList/List/Item/index.tsx +4 -3
- package/src/pages/chat/features/SessionList/List/index.tsx +1 -3
- package/src/pages/chat/features/SessionList/Mobile.tsx +2 -12
- package/src/pages/chat/features/SessionSearchBar/index.tsx +26 -0
- package/src/pages/chat/features/Sidebar/Topic/index.tsx +18 -6
- package/src/pages/chat/features/Sidebar/TopicSearchBar/index.tsx +24 -0
- package/src/pages/chat/features/Sidebar/index.tsx +2 -9
- package/src/pages/market/features/AgentCard/AgentCardBanner.tsx +64 -0
- package/src/pages/market/features/AgentCard/AgentCardItem.tsx +57 -0
- package/src/pages/market/features/AgentCard/Loading.tsx +13 -0
- package/src/pages/market/features/AgentCard/index.tsx +37 -0
- package/src/pages/market/features/AgentCard/style.ts +22 -0
- package/src/pages/market/features/AgentSearchBar/index.tsx +26 -0
- package/src/pages/market/features/Header/Desktop.tsx +15 -4
- package/src/pages/market/features/Header/Mobile.tsx +7 -24
- package/src/pages/market/features/SideBar/AgentInfo/Comment.tsx +16 -0
- package/src/pages/market/features/SideBar/AgentInfo/Header.tsx +68 -0
- package/src/pages/market/features/SideBar/AgentInfo/Loading.tsx +61 -0
- package/src/pages/market/features/SideBar/AgentInfo/TokenTag.tsx +25 -0
- package/src/pages/market/features/SideBar/AgentInfo/index.tsx +68 -0
- package/src/pages/market/features/SideBar/AgentInfo/style.ts +46 -0
- package/src/pages/market/features/SideBar/Desktop.tsx +70 -0
- package/src/pages/market/features/SideBar/Mobile.tsx +36 -0
- package/src/pages/market/features/SideBar/index.tsx +23 -0
- package/src/pages/market/features/TagList/index.tsx +29 -0
- package/src/pages/market/index.page.tsx +11 -2
- package/src/pages/market/layout.mobile.tsx +8 -7
- package/src/pages/market/layout.tsx +39 -1
- package/src/pages/settings/features/Header/Desktop.tsx +2 -4
- package/src/pages/settings/features/Header/Mobile.tsx +1 -1
- package/src/pages/settings/features/Settings/Common.tsx +1 -2
- package/src/pages/settings/features/Settings/index.tsx +17 -4
- package/src/services/agentMarket.ts +21 -0
- package/src/store/global/initialState.ts +1 -2
- package/src/store/market/action.ts +57 -0
- package/src/store/market/index.ts +3 -0
- package/src/store/market/initialState.ts +17 -0
- package/src/store/market/selectors.ts +36 -0
- package/src/store/market/store.ts +51 -0
- package/src/store/session/slices/session/action.ts +5 -3
- package/src/store/session/slices/session/initialState.ts +2 -0
- package/src/store/session/slices/session/reducers/session.test.ts +4 -4
- package/src/types/market.ts +19 -0
- package/src/types/meta.ts +1 -1
- package/src/utils/filter.ts +1 -1
- package/src/utils/findDuplicates.ts +22 -0
- package/scripts/genDefaultLocale.ts +0 -18
- package/scripts/genResources.ts +0 -51
- package/scripts/toc.ts +0 -7
- package/src/components/Empty/index.tsx +0 -63
- package/src/components/Empty/style.ts +0 -31
- package/src/components/SelectWithImg/index.tsx +0 -97
- package/src/components/SelectWithImg/styles.ts +0 -43
- package/src/pages/chat/features/Conversation/Input/ActionRight.tsx +0 -31
- package/src/pages/chat/features/Conversation/Input/Footer.tsx +0 -49
- /package/src/components/{ManifestPreviewer.tsx → ManifestPreviewer/index.tsx} +0 -0
- /package/src/pages/chat/features/Conversation/Input/{Token.tsx → ActionBar/Token.tsx} +0 -0
|
@@ -26,10 +26,8 @@ const SessionList = memo(() => {
|
|
|
26
26
|
<Link
|
|
27
27
|
href={SESSION_CHAT_URL(id, mobile)}
|
|
28
28
|
key={id}
|
|
29
|
-
|
|
30
|
-
onPointerDown={(e) => {
|
|
29
|
+
onClick={(e) => {
|
|
31
30
|
e.preventDefault();
|
|
32
|
-
|
|
33
31
|
if (mobile) switchSession(id);
|
|
34
32
|
else activeSession(id);
|
|
35
33
|
}}
|
|
@@ -1,22 +1,12 @@
|
|
|
1
|
-
import { SearchBar } from '@lobehub/ui';
|
|
2
1
|
import { ReactNode, memo } from 'react';
|
|
3
|
-
import { useTranslation } from 'react-i18next';
|
|
4
2
|
|
|
5
|
-
import
|
|
3
|
+
import SessionSearchBar from '../SessionSearchBar';
|
|
6
4
|
|
|
7
5
|
const Sessions = memo<{ children: ReactNode }>(({ children }) => {
|
|
8
|
-
const { t } = useTranslation('common');
|
|
9
|
-
const [keywords] = useSessionStore((s) => [s.searchKeywords, s.createSession]);
|
|
10
6
|
return (
|
|
11
7
|
<>
|
|
12
8
|
<div style={{ padding: '8px 16px' }}>
|
|
13
|
-
<
|
|
14
|
-
allowClear
|
|
15
|
-
onChange={(e) => useSessionStore.setState({ searchKeywords: e.target.value })}
|
|
16
|
-
placeholder={t('searchAgentPlaceholder')}
|
|
17
|
-
type={'block'}
|
|
18
|
-
value={keywords}
|
|
19
|
-
/>
|
|
9
|
+
<SessionSearchBar />
|
|
20
10
|
</div>
|
|
21
11
|
{children}
|
|
22
12
|
</>
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { SearchBar } from '@lobehub/ui';
|
|
2
|
+
import { useResponsive } from 'antd-style';
|
|
3
|
+
import { memo } from 'react';
|
|
4
|
+
import { useTranslation } from 'react-i18next';
|
|
5
|
+
|
|
6
|
+
import { useSessionStore } from '@/store/session';
|
|
7
|
+
|
|
8
|
+
const SessionSearchBar = memo(() => {
|
|
9
|
+
const { t } = useTranslation('common');
|
|
10
|
+
const [keywords] = useSessionStore((s) => [s.searchKeywords]);
|
|
11
|
+
const { mobile } = useResponsive();
|
|
12
|
+
return (
|
|
13
|
+
<SearchBar
|
|
14
|
+
allowClear
|
|
15
|
+
enableShortKey={!mobile}
|
|
16
|
+
onChange={(e) => useSessionStore.setState({ searchKeywords: e.target.value })}
|
|
17
|
+
placeholder={t('searchAgentPlaceholder')}
|
|
18
|
+
shortKey={'k'}
|
|
19
|
+
spotlight={!mobile}
|
|
20
|
+
type={mobile ? 'block' : 'ghost'}
|
|
21
|
+
value={keywords}
|
|
22
|
+
/>
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
export default SessionSearchBar;
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { EmptyCard } from '@lobehub/ui';
|
|
1
2
|
import { useThemeMode } from 'antd-style';
|
|
2
3
|
import isEqual from 'fast-deep-equal';
|
|
4
|
+
import { useMemo } from 'react';
|
|
3
5
|
import { useTranslation } from 'react-i18next';
|
|
4
6
|
import { Flexbox } from 'react-layout-kit';
|
|
5
7
|
|
|
6
|
-
import Empty from '@/components/Empty';
|
|
7
8
|
import { useGlobalStore } from '@/store/global';
|
|
8
9
|
import { useSessionChatInit, useSessionStore } from '@/store/session';
|
|
9
10
|
import { topicSelectors } from '@/store/session/selectors';
|
|
@@ -15,20 +16,27 @@ export const Topic = () => {
|
|
|
15
16
|
const init = useSessionChatInit();
|
|
16
17
|
const topics = useSessionStore(topicSelectors.currentTopics, isEqual);
|
|
17
18
|
const { isDarkMode } = useThemeMode();
|
|
18
|
-
const [activeTopicId] = useSessionStore((s) => [
|
|
19
|
+
const [activeTopicId, keywords] = useSessionStore((s) => [
|
|
20
|
+
s.activeTopicId,
|
|
21
|
+
s.topicSearchKeywords,
|
|
22
|
+
]);
|
|
19
23
|
const { t } = useTranslation('empty');
|
|
20
|
-
|
|
21
24
|
const [visible, updateGuideState] = useGlobalStore((s) => [
|
|
22
25
|
s.preference.guide?.topic,
|
|
23
26
|
s.updateGuideState,
|
|
24
27
|
]);
|
|
25
28
|
|
|
29
|
+
const topicsData = useMemo(() => {
|
|
30
|
+
if (!keywords) return topics;
|
|
31
|
+
return topics.filter(({ title }) => title.toLowerCase().includes(keywords.toLowerCase()));
|
|
32
|
+
}, [topics, keywords]);
|
|
33
|
+
|
|
26
34
|
return !init ? (
|
|
27
35
|
<SkeletonList />
|
|
28
36
|
) : (
|
|
29
37
|
<Flexbox gap={2} style={{ marginBottom: 12 }}>
|
|
30
38
|
{topics?.length === 0 && (
|
|
31
|
-
<
|
|
39
|
+
<EmptyCard
|
|
32
40
|
alt={t('topic.desc')}
|
|
33
41
|
cover={`/images/empty_topic_${isDarkMode ? 'dark' : 'light'}.webp`}
|
|
34
42
|
desc={t('topic.desc')}
|
|
@@ -43,9 +51,13 @@ export const Topic = () => {
|
|
|
43
51
|
/>
|
|
44
52
|
)}
|
|
45
53
|
|
|
46
|
-
<TopicItem
|
|
54
|
+
<TopicItem
|
|
55
|
+
active={!activeTopicId}
|
|
56
|
+
fav={false}
|
|
57
|
+
title={t('topic.defaultTitle', { ns: 'common' })}
|
|
58
|
+
/>
|
|
47
59
|
|
|
48
|
-
{
|
|
60
|
+
{topicsData.map(({ id, favorite, title }) => (
|
|
49
61
|
<TopicItem active={activeTopicId === id} fav={favorite} id={id} key={id} title={title} />
|
|
50
62
|
))}
|
|
51
63
|
</Flexbox>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { SearchBar } from '@lobehub/ui';
|
|
2
|
+
import { useResponsive } from 'antd-style';
|
|
3
|
+
import { memo } from 'react';
|
|
4
|
+
import { useTranslation } from 'react-i18next';
|
|
5
|
+
|
|
6
|
+
import { useSessionStore } from '@/store/session';
|
|
7
|
+
|
|
8
|
+
const TopicSearchBar = memo(() => {
|
|
9
|
+
const { t } = useTranslation('common');
|
|
10
|
+
const [keywords] = useSessionStore((s) => [s.topicSearchKeywords]);
|
|
11
|
+
const { mobile } = useResponsive();
|
|
12
|
+
return (
|
|
13
|
+
<SearchBar
|
|
14
|
+
allowClear
|
|
15
|
+
onChange={(e) => useSessionStore.setState({ topicSearchKeywords: e.target.value })}
|
|
16
|
+
placeholder={t('topic.searchPlaceholder')}
|
|
17
|
+
spotlight={!mobile}
|
|
18
|
+
type={mobile ? 'block' : 'ghost'}
|
|
19
|
+
value={keywords}
|
|
20
|
+
/>
|
|
21
|
+
);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
export default TopicSearchBar;
|
|
@@ -1,29 +1,22 @@
|
|
|
1
|
-
import { SearchBar } from '@lobehub/ui';
|
|
2
1
|
import { useResponsive } from 'antd-style';
|
|
3
2
|
import { memo } from 'react';
|
|
4
|
-
import { useTranslation } from 'react-i18next';
|
|
5
3
|
import { Flexbox } from 'react-layout-kit';
|
|
6
4
|
|
|
7
5
|
import Desktop from './Desktop';
|
|
8
6
|
import Mobile from './Mobile';
|
|
9
7
|
import { Topic } from './Topic';
|
|
8
|
+
import TopicSearchBar from './TopicSearchBar';
|
|
10
9
|
|
|
11
10
|
const SideBar = memo(() => {
|
|
12
11
|
const { mobile } = useResponsive();
|
|
13
12
|
|
|
14
13
|
const Render = mobile ? Mobile : Desktop;
|
|
15
14
|
|
|
16
|
-
const { t } = useTranslation('common');
|
|
17
|
-
|
|
18
15
|
return (
|
|
19
16
|
<Render>
|
|
20
17
|
<Flexbox height={'100%'} style={{ overflow: 'hidden' }}>
|
|
21
18
|
<Flexbox padding={16}>
|
|
22
|
-
<
|
|
23
|
-
placeholder={t('topic.searchPlaceholder')}
|
|
24
|
-
spotlight={!mobile}
|
|
25
|
-
type={mobile ? 'block' : 'ghost'}
|
|
26
|
-
/>
|
|
19
|
+
<TopicSearchBar />
|
|
27
20
|
</Flexbox>
|
|
28
21
|
<Flexbox gap={16} paddingInline={16} style={{ overflowY: 'auto', position: 'relative' }}>
|
|
29
22
|
<Topic />
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Avatar, DivProps } from '@lobehub/ui';
|
|
2
|
+
import { createStyles } from 'antd-style';
|
|
3
|
+
import { memo } from 'react';
|
|
4
|
+
import { Flexbox } from 'react-layout-kit';
|
|
5
|
+
|
|
6
|
+
import { MetaData } from '@/types/meta';
|
|
7
|
+
|
|
8
|
+
export const useStyles = createStyles(({ css, token }, maskColor: string) => ({
|
|
9
|
+
banner: css`
|
|
10
|
+
position: relative;
|
|
11
|
+
|
|
12
|
+
overflow: hidden;
|
|
13
|
+
|
|
14
|
+
height: 64px;
|
|
15
|
+
margin-bottom: -56px;
|
|
16
|
+
|
|
17
|
+
background: ${token.colorFill};
|
|
18
|
+
`,
|
|
19
|
+
bannerImg: css`
|
|
20
|
+
filter: blur(6px) saturate(1.6);
|
|
21
|
+
`,
|
|
22
|
+
bannerMask: css`
|
|
23
|
+
position: absolute;
|
|
24
|
+
bottom: 0;
|
|
25
|
+
left: 0;
|
|
26
|
+
|
|
27
|
+
width: 100%;
|
|
28
|
+
height: 100%;
|
|
29
|
+
|
|
30
|
+
background: linear-gradient(to bottom, transparent, ${maskColor || token.colorBgLayout});
|
|
31
|
+
`,
|
|
32
|
+
}));
|
|
33
|
+
|
|
34
|
+
interface AgentCardBannerProps extends DivProps {
|
|
35
|
+
mask?: boolean;
|
|
36
|
+
maskColor?: string;
|
|
37
|
+
meta: MetaData;
|
|
38
|
+
size?: number;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const AgentCardBanner = memo<AgentCardBannerProps>(
|
|
42
|
+
({ meta, className, mask, size = 8, maskColor, ...props }) => {
|
|
43
|
+
const { styles, theme, cx } = useStyles(maskColor);
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<Flexbox
|
|
47
|
+
align={'center'}
|
|
48
|
+
className={cx(styles.banner, className)}
|
|
49
|
+
justify={'center'}
|
|
50
|
+
{...props}
|
|
51
|
+
>
|
|
52
|
+
<Avatar
|
|
53
|
+
avatar={meta.avatar}
|
|
54
|
+
background={meta.backgroundColor || theme.colorBgContainer}
|
|
55
|
+
className={styles.bannerImg}
|
|
56
|
+
style={{ transform: `scale(${size})` }}
|
|
57
|
+
/>
|
|
58
|
+
{mask && <div className={styles.bannerMask} />}
|
|
59
|
+
</Flexbox>
|
|
60
|
+
);
|
|
61
|
+
},
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
export default AgentCardBanner;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Avatar, Tag } from '@lobehub/ui';
|
|
2
|
+
import { useHover } from 'ahooks';
|
|
3
|
+
import { Typography } from 'antd';
|
|
4
|
+
import { useThemeMode } from 'antd-style';
|
|
5
|
+
import { startCase } from 'lodash-es';
|
|
6
|
+
import { memo, useRef } from 'react';
|
|
7
|
+
import { Flexbox } from 'react-layout-kit';
|
|
8
|
+
|
|
9
|
+
import { useMarketStore } from '@/store/market';
|
|
10
|
+
import { AgentsMarketIndexItem } from '@/types/market';
|
|
11
|
+
|
|
12
|
+
import AgentCardBanner from './AgentCardBanner';
|
|
13
|
+
import { useStyles } from './style';
|
|
14
|
+
|
|
15
|
+
const { Paragraph } = Typography;
|
|
16
|
+
const AgentCardItem = memo<AgentsMarketIndexItem>(({ meta, identifier }) => {
|
|
17
|
+
const ref = useRef(null);
|
|
18
|
+
const isHovering = useHover(ref);
|
|
19
|
+
const onAgentCardClick = useMarketStore((s) => s.activateAgent);
|
|
20
|
+
const { avatar, title, description, tags, backgroundColor } = meta;
|
|
21
|
+
const { styles, theme } = useStyles();
|
|
22
|
+
const { isDarkMode } = useThemeMode();
|
|
23
|
+
return (
|
|
24
|
+
<Flexbox className={styles.container} onClick={() => onAgentCardClick(identifier)}>
|
|
25
|
+
<AgentCardBanner
|
|
26
|
+
mask
|
|
27
|
+
maskColor={theme.colorBgContainer}
|
|
28
|
+
meta={meta}
|
|
29
|
+
style={{ opacity: isDarkMode ? 0.9 : 0.4 }}
|
|
30
|
+
/>
|
|
31
|
+
<Flexbox className={styles.inner} gap={8} ref={ref}>
|
|
32
|
+
<Avatar
|
|
33
|
+
animation={isHovering}
|
|
34
|
+
avatar={avatar}
|
|
35
|
+
background={backgroundColor || theme.colorFillTertiary}
|
|
36
|
+
className={styles.avatar}
|
|
37
|
+
size={56}
|
|
38
|
+
/>
|
|
39
|
+
<Paragraph className={styles.title} ellipsis={{ rows: 1, tooltip: title }}>
|
|
40
|
+
{title}
|
|
41
|
+
</Paragraph>
|
|
42
|
+
<Paragraph className={styles.desc} ellipsis={{ rows: 2, tooltip: description }}>
|
|
43
|
+
{description}
|
|
44
|
+
</Paragraph>
|
|
45
|
+
<Flexbox gap={6} horizontal style={{ flexWrap: 'wrap' }}>
|
|
46
|
+
{(tags as string[]).map((tag: string, index) => (
|
|
47
|
+
<Tag key={index} style={{ margin: 0 }}>
|
|
48
|
+
{startCase(tag).trim()}
|
|
49
|
+
</Tag>
|
|
50
|
+
))}
|
|
51
|
+
</Flexbox>
|
|
52
|
+
</Flexbox>
|
|
53
|
+
</Flexbox>
|
|
54
|
+
);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
export default AgentCardItem;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Skeleton } from 'antd';
|
|
2
|
+
import { memo } from 'react';
|
|
3
|
+
import { Flexbox } from 'react-layout-kit';
|
|
4
|
+
|
|
5
|
+
const Loading = memo(() => {
|
|
6
|
+
return (
|
|
7
|
+
<Flexbox>
|
|
8
|
+
<Skeleton paragraph={{ rows: 8 }} />
|
|
9
|
+
</Flexbox>
|
|
10
|
+
);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
export default Loading;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { SpotlightCard } from '@lobehub/ui';
|
|
2
|
+
import { memo, useMemo } from 'react';
|
|
3
|
+
|
|
4
|
+
import { agentMarketSelectors, useMarketStore } from '@/store/market';
|
|
5
|
+
|
|
6
|
+
import TagList from '../TagList';
|
|
7
|
+
import AgentCardItem from './AgentCardItem';
|
|
8
|
+
import Loading from './Loading';
|
|
9
|
+
|
|
10
|
+
const gridRender = (item: any) => <AgentCardItem {...item} />;
|
|
11
|
+
|
|
12
|
+
const AgentCard = memo(() => {
|
|
13
|
+
const agentList = useMarketStore(agentMarketSelectors.getAgentList);
|
|
14
|
+
|
|
15
|
+
const [useFetchAgentList, keywords] = useMarketStore((s) => [
|
|
16
|
+
s.useFetchAgentList,
|
|
17
|
+
s.searchKeywords,
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
const { isLoading } = useFetchAgentList();
|
|
21
|
+
|
|
22
|
+
const agentListData = useMemo(() => {
|
|
23
|
+
if (!keywords) return agentList;
|
|
24
|
+
return agentList.filter(({ meta }) => JSON.stringify(meta).toLowerCase().includes(keywords));
|
|
25
|
+
}, [agentList, keywords]);
|
|
26
|
+
|
|
27
|
+
if (isLoading || !agentList) return <Loading />;
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<>
|
|
31
|
+
<TagList />
|
|
32
|
+
<SpotlightCard items={agentListData} renderItem={gridRender} />
|
|
33
|
+
</>
|
|
34
|
+
);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
export default AgentCard;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createStyles } from 'antd-style';
|
|
2
|
+
|
|
3
|
+
export const useStyles = createStyles(({ css, token }) => ({
|
|
4
|
+
avatar: css``,
|
|
5
|
+
|
|
6
|
+
container: css`
|
|
7
|
+
position: relative;
|
|
8
|
+
overflow: hidden;
|
|
9
|
+
border-radius: 11px;
|
|
10
|
+
`,
|
|
11
|
+
desc: css`
|
|
12
|
+
color: ${token.colorTextDescription};
|
|
13
|
+
`,
|
|
14
|
+
inner: css`
|
|
15
|
+
padding: 16px;
|
|
16
|
+
`,
|
|
17
|
+
title: css`
|
|
18
|
+
margin-bottom: 0 !important;
|
|
19
|
+
font-size: 16px;
|
|
20
|
+
font-weight: 600;
|
|
21
|
+
`,
|
|
22
|
+
}));
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { SearchBar } from '@lobehub/ui';
|
|
2
|
+
import { useResponsive } from 'antd-style';
|
|
3
|
+
import { memo } from 'react';
|
|
4
|
+
import { useTranslation } from 'react-i18next';
|
|
5
|
+
|
|
6
|
+
import { useMarketStore } from '@/store/market';
|
|
7
|
+
|
|
8
|
+
const AgentSearchBar = memo(() => {
|
|
9
|
+
const { t } = useTranslation('market');
|
|
10
|
+
const keywords = useMarketStore((s) => s.searchKeywords);
|
|
11
|
+
const { mobile } = useResponsive();
|
|
12
|
+
return (
|
|
13
|
+
<SearchBar
|
|
14
|
+
allowClear
|
|
15
|
+
enableShortKey={!mobile}
|
|
16
|
+
onChange={(e) => useMarketStore.setState({ searchKeywords: e.target.value })}
|
|
17
|
+
placeholder={t('search.placeholder')}
|
|
18
|
+
shortKey={'k'}
|
|
19
|
+
spotlight={!mobile}
|
|
20
|
+
type={mobile ? 'block' : 'ghost'}
|
|
21
|
+
value={keywords}
|
|
22
|
+
/>
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
export default AgentSearchBar;
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import { ChatHeader,
|
|
1
|
+
import { ChatHeader, Icon, Logo } from '@lobehub/ui';
|
|
2
|
+
import { Button } from 'antd';
|
|
2
3
|
import { createStyles } from 'antd-style';
|
|
4
|
+
import { Bot } from 'lucide-react';
|
|
3
5
|
import Link from 'next/link';
|
|
4
6
|
import { memo } from 'react';
|
|
5
7
|
import { useTranslation } from 'react-i18next';
|
|
6
8
|
|
|
9
|
+
import { AGENTS_INDEX_GITHUB } from '@/const/url';
|
|
10
|
+
|
|
7
11
|
export const useStyles = createStyles(({ css, token }) => ({
|
|
8
12
|
logo: css`
|
|
9
13
|
color: ${token.colorText};
|
|
@@ -13,16 +17,23 @@ export const useStyles = createStyles(({ css, token }) => ({
|
|
|
13
17
|
|
|
14
18
|
const Header = memo(() => {
|
|
15
19
|
const { styles } = useStyles();
|
|
16
|
-
const { t } = useTranslation('
|
|
20
|
+
const { t } = useTranslation('market');
|
|
17
21
|
|
|
18
22
|
return (
|
|
19
23
|
<ChatHeader
|
|
20
24
|
left={
|
|
21
25
|
<Link href={'/'}>
|
|
22
|
-
<Logo className={styles.logo} extra={
|
|
26
|
+
<Logo className={styles.logo} extra={'Discover'} size={36} type={'text'} />
|
|
23
27
|
</Link>
|
|
24
28
|
}
|
|
25
|
-
right={
|
|
29
|
+
right={
|
|
30
|
+
<Button
|
|
31
|
+
icon={<Icon icon={Bot} />}
|
|
32
|
+
onClick={() => window.open(AGENTS_INDEX_GITHUB, '__blank')}
|
|
33
|
+
>
|
|
34
|
+
{t('submitAgent')}
|
|
35
|
+
</Button>
|
|
36
|
+
}
|
|
26
37
|
/>
|
|
27
38
|
);
|
|
28
39
|
});
|
|
@@ -1,39 +1,22 @@
|
|
|
1
1
|
import { ActionIcon, Logo, MobileNavBar } from '@lobehub/ui';
|
|
2
|
-
import {
|
|
3
|
-
import { MessageSquarePlus, Settings2 } from 'lucide-react';
|
|
2
|
+
import { Settings2 } from 'lucide-react';
|
|
4
3
|
import Router from 'next/router';
|
|
5
4
|
import { memo } from 'react';
|
|
6
5
|
|
|
7
6
|
import AvatarWithUpload from '@/features/AvatarWithUpload';
|
|
8
|
-
import { useSessionStore } from '@/store/session';
|
|
9
|
-
|
|
10
|
-
export const useStyles = createStyles(({ css, token }) => ({
|
|
11
|
-
logo: css`
|
|
12
|
-
fill: ${token.colorText};
|
|
13
|
-
`,
|
|
14
|
-
top: css`
|
|
15
|
-
position: sticky;
|
|
16
|
-
top: 0;
|
|
17
|
-
`,
|
|
18
|
-
}));
|
|
19
7
|
|
|
20
8
|
const Header = memo(() => {
|
|
21
|
-
const [createSession] = useSessionStore((s) => [s.createSession]);
|
|
22
|
-
|
|
23
9
|
return (
|
|
24
10
|
<MobileNavBar
|
|
25
11
|
center={<Logo type={'text'} />}
|
|
26
12
|
left={<AvatarWithUpload size={28} style={{ marginLeft: 8 }} />}
|
|
27
13
|
right={
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}}
|
|
35
|
-
/>
|
|
36
|
-
</>
|
|
14
|
+
<ActionIcon
|
|
15
|
+
icon={Settings2}
|
|
16
|
+
onClick={() => {
|
|
17
|
+
Router.push({ pathname: `/settings` });
|
|
18
|
+
}}
|
|
19
|
+
/>
|
|
37
20
|
}
|
|
38
21
|
/>
|
|
39
22
|
);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Giscus } from '@lobehub/ui';
|
|
2
|
+
import { memo } from 'react';
|
|
3
|
+
|
|
4
|
+
const Comment = memo<{ identifier: string }>(({ identifier }) => (
|
|
5
|
+
<Giscus
|
|
6
|
+
category="General"
|
|
7
|
+
categoryId="DIC_kwDOKON5YM4CZNRJ"
|
|
8
|
+
id="lobehub"
|
|
9
|
+
mapping="specific"
|
|
10
|
+
repo="lobehub/lobe-chat-agents"
|
|
11
|
+
repoId="R_kgDOKON5YA"
|
|
12
|
+
term={identifier}
|
|
13
|
+
/>
|
|
14
|
+
));
|
|
15
|
+
|
|
16
|
+
export default Comment;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { Avatar, Tag } from '@lobehub/ui';
|
|
2
|
+
import { Button, Typography } from 'antd';
|
|
3
|
+
import { startCase } from 'lodash-es';
|
|
4
|
+
import { memo } from 'react';
|
|
5
|
+
import { useTranslation } from 'react-i18next';
|
|
6
|
+
import { Center } from 'react-layout-kit';
|
|
7
|
+
|
|
8
|
+
import { useGlobalStore } from '@/store/global';
|
|
9
|
+
import { agentMarketSelectors, useMarketStore } from '@/store/market';
|
|
10
|
+
import { useSessionStore } from '@/store/session';
|
|
11
|
+
|
|
12
|
+
import { useStyles } from './style';
|
|
13
|
+
|
|
14
|
+
const { Link } = Typography;
|
|
15
|
+
|
|
16
|
+
const Header = memo(() => {
|
|
17
|
+
const { t } = useTranslation('market');
|
|
18
|
+
const { styles, theme } = useStyles();
|
|
19
|
+
|
|
20
|
+
const createSession = useSessionStore((s) => s.createSession);
|
|
21
|
+
const switchSideBar = useGlobalStore((s) => s.switchSideBar);
|
|
22
|
+
const agentItem = useMarketStore(agentMarketSelectors.currentAgentItem);
|
|
23
|
+
|
|
24
|
+
const { meta, createAt, author, homepage, config } = agentItem;
|
|
25
|
+
const { avatar, title, description, tags, backgroundColor } = meta;
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<Center className={styles.container} gap={16}>
|
|
29
|
+
<Avatar
|
|
30
|
+
avatar={avatar}
|
|
31
|
+
background={backgroundColor || theme.colorFillTertiary}
|
|
32
|
+
className={styles.avatar}
|
|
33
|
+
size={100}
|
|
34
|
+
/>
|
|
35
|
+
<div className={styles.title}>{title}</div>
|
|
36
|
+
<Center gap={6} horizontal style={{ flexWrap: 'wrap' }}>
|
|
37
|
+
{(tags as string[]).map((tag: string, index) => (
|
|
38
|
+
<Tag
|
|
39
|
+
key={index}
|
|
40
|
+
onClick={() => useMarketStore.setState({ searchKeywords: tag })}
|
|
41
|
+
style={{ margin: 0 }}
|
|
42
|
+
>
|
|
43
|
+
{startCase(tag).trim()}
|
|
44
|
+
</Tag>
|
|
45
|
+
))}
|
|
46
|
+
</Center>
|
|
47
|
+
<div className={styles.desc}>{description}</div>
|
|
48
|
+
<Link className={styles.author} href={homepage} target={'_blank'}>
|
|
49
|
+
@{author}
|
|
50
|
+
</Link>
|
|
51
|
+
<Button
|
|
52
|
+
block
|
|
53
|
+
onClick={() => {
|
|
54
|
+
if (!agentItem) return;
|
|
55
|
+
|
|
56
|
+
createSession({ config, meta });
|
|
57
|
+
switchSideBar('chat');
|
|
58
|
+
}}
|
|
59
|
+
type={'primary'}
|
|
60
|
+
>
|
|
61
|
+
{t('addAgent')}
|
|
62
|
+
</Button>
|
|
63
|
+
<div className={styles.date}>{createAt}</div>
|
|
64
|
+
</Center>
|
|
65
|
+
);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
export default Header;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { Skeleton } from 'antd';
|
|
2
|
+
import { memo } from 'react';
|
|
3
|
+
import { Center, Flexbox } from 'react-layout-kit';
|
|
4
|
+
|
|
5
|
+
import { useStyles } from './style';
|
|
6
|
+
|
|
7
|
+
const Loading = memo(() => {
|
|
8
|
+
const { styles } = useStyles();
|
|
9
|
+
return (
|
|
10
|
+
<>
|
|
11
|
+
<Center className={styles.container} gap={16} style={{ paddingTop: 80 }}>
|
|
12
|
+
<Skeleton.Avatar active shape={'circle'} size={100} />
|
|
13
|
+
<Skeleton
|
|
14
|
+
active
|
|
15
|
+
className={styles.loading}
|
|
16
|
+
paragraph={{
|
|
17
|
+
rows: 3,
|
|
18
|
+
style: {
|
|
19
|
+
alignItems: 'center',
|
|
20
|
+
display: 'flex',
|
|
21
|
+
flexDirection: 'column',
|
|
22
|
+
},
|
|
23
|
+
width: ['60%', '80%', '20%'],
|
|
24
|
+
}}
|
|
25
|
+
title={{
|
|
26
|
+
style: {
|
|
27
|
+
alignSelf: 'center',
|
|
28
|
+
marginBottom: 0,
|
|
29
|
+
},
|
|
30
|
+
width: '50%',
|
|
31
|
+
}}
|
|
32
|
+
/>
|
|
33
|
+
<Skeleton.Button active block />
|
|
34
|
+
<Skeleton
|
|
35
|
+
active
|
|
36
|
+
className={styles.loading}
|
|
37
|
+
paragraph={{
|
|
38
|
+
rows: 1,
|
|
39
|
+
style: {
|
|
40
|
+
alignItems: 'center',
|
|
41
|
+
display: 'flex',
|
|
42
|
+
flexDirection: 'column',
|
|
43
|
+
marginBottom: 0,
|
|
44
|
+
},
|
|
45
|
+
width: ['20%'],
|
|
46
|
+
}}
|
|
47
|
+
title={false}
|
|
48
|
+
/>
|
|
49
|
+
</Center>
|
|
50
|
+
<Center gap={16} style={{ padding: 16 }}>
|
|
51
|
+
<Flexbox gap={16} horizontal>
|
|
52
|
+
<Skeleton.Button active size={'small'} />
|
|
53
|
+
<Skeleton.Button active size={'small'} />
|
|
54
|
+
</Flexbox>
|
|
55
|
+
<Skeleton active paragraph={{ rows: 6 }} title={false} />
|
|
56
|
+
</Center>
|
|
57
|
+
</>
|
|
58
|
+
);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
export default Loading;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { createStyles } from 'antd-style';
|
|
2
|
+
import { encode } from 'gpt-tokenizer';
|
|
3
|
+
import { memo, useMemo } from 'react';
|
|
4
|
+
|
|
5
|
+
const useStyles = createStyles(
|
|
6
|
+
({ css, token }) => css`
|
|
7
|
+
padding: 2px 5px;
|
|
8
|
+
|
|
9
|
+
font-size: 12px;
|
|
10
|
+
line-height: 1;
|
|
11
|
+
color: ${token.colorBgLayout};
|
|
12
|
+
|
|
13
|
+
background: ${token.colorText};
|
|
14
|
+
border-radius: 12px;
|
|
15
|
+
`,
|
|
16
|
+
);
|
|
17
|
+
|
|
18
|
+
const TokenTag = memo<{ systemRole: string }>(({ systemRole }) => {
|
|
19
|
+
const { styles } = useStyles();
|
|
20
|
+
const value = useMemo(() => encode(systemRole).length, [systemRole]);
|
|
21
|
+
|
|
22
|
+
return <div className={styles}>{value}</div>;
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export default TokenTag;
|