@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.
Files changed (106) hide show
  1. package/.github/workflows/contributor-help.yml +1 -1
  2. package/.github/workflows/sync.yml +43 -0
  3. package/.github/workflows/wiki-sync.yml +1 -0
  4. package/CHANGELOG.md +87 -0
  5. package/README.md +40 -6
  6. package/{README-zh_CN.md → README.zh-CN.md} +38 -4
  7. package/docs/Home.md +6 -0
  8. package/docs/Upstream-Sync.en-US.md +16 -0
  9. package/docs/Upstream-Sync.zh-CN.md +16 -0
  10. package/docs/_Sidebar.md +6 -0
  11. package/locales/en_US/market.json +12 -0
  12. package/locales/en_US/plugin.json +11 -2
  13. package/locales/en_US/setting.json +63 -2
  14. package/locales/ru_RU/market.json +12 -0
  15. package/locales/ru_RU/plugin.json +44 -49
  16. package/locales/ru_RU/setting.json +63 -2
  17. package/locales/zh_CN/common.json +1 -1
  18. package/locales/zh_CN/market.json +12 -0
  19. package/locales/zh_CN/plugin.json +19 -5
  20. package/locales/zh_CN/setting.json +62 -14
  21. package/package.json +5 -4
  22. package/scripts/i18nWorkflow/const.ts +19 -0
  23. package/scripts/i18nWorkflow/genDefaultLocale.ts +19 -0
  24. package/scripts/i18nWorkflow/genDiff.ts +50 -0
  25. package/scripts/i18nWorkflow/genResources.ts +26 -0
  26. package/scripts/i18nWorkflow/index.ts +15 -0
  27. package/scripts/i18nWorkflow/utils.ts +85 -0
  28. package/src/const/layoutTokens.ts +3 -1
  29. package/src/const/market.ts +15 -0
  30. package/src/const/url.ts +29 -4
  31. package/src/features/AgentSetting/AgentConfig/index.tsx +1 -2
  32. package/src/features/AgentSetting/AgentPlugin/MarketSettingModal.tsx +1 -1
  33. package/src/features/AgentSetting/store/initialState.ts +1 -1
  34. package/src/features/MobileTabBar/index.tsx +2 -2
  35. package/src/features/SideBar/TopActions.tsx +2 -2
  36. package/src/locales/default/market.ts +12 -0
  37. package/src/locales/resources/en_US.ts +2 -0
  38. package/src/locales/resources/ru_RU.ts +2 -0
  39. package/src/locales/resources/zh_CN.ts +2 -0
  40. package/src/pages/chat/features/Conversation/Input/{Action.tsx → ActionBar/ActionLeft.tsx} +2 -2
  41. package/src/pages/chat/features/Conversation/Input/ActionBar/ActionRight.tsx +36 -0
  42. package/src/pages/chat/features/Conversation/Input/Desktop.tsx +40 -0
  43. package/src/pages/chat/features/Conversation/Input/Footer/SaveTopic.tsx +27 -0
  44. package/src/pages/chat/features/Conversation/Input/Footer/index.tsx +35 -0
  45. package/src/pages/chat/features/Conversation/Input/Mobile.tsx +12 -0
  46. package/src/pages/chat/features/Conversation/Input/index.tsx +20 -38
  47. package/src/pages/chat/features/SessionList/Header/Desktop.tsx +6 -13
  48. package/src/pages/chat/features/SessionList/Header/Mobile.tsx +1 -1
  49. package/src/pages/chat/features/SessionList/List/AddButton.tsx +1 -1
  50. package/src/pages/chat/features/SessionList/List/Item/index.tsx +4 -3
  51. package/src/pages/chat/features/SessionList/List/index.tsx +1 -3
  52. package/src/pages/chat/features/SessionList/Mobile.tsx +2 -12
  53. package/src/pages/chat/features/SessionSearchBar/index.tsx +26 -0
  54. package/src/pages/chat/features/Sidebar/Topic/index.tsx +18 -6
  55. package/src/pages/chat/features/Sidebar/TopicSearchBar/index.tsx +24 -0
  56. package/src/pages/chat/features/Sidebar/index.tsx +2 -9
  57. package/src/pages/market/features/AgentCard/AgentCardBanner.tsx +64 -0
  58. package/src/pages/market/features/AgentCard/AgentCardItem.tsx +57 -0
  59. package/src/pages/market/features/AgentCard/Loading.tsx +13 -0
  60. package/src/pages/market/features/AgentCard/index.tsx +37 -0
  61. package/src/pages/market/features/AgentCard/style.ts +22 -0
  62. package/src/pages/market/features/AgentSearchBar/index.tsx +26 -0
  63. package/src/pages/market/features/Header/Desktop.tsx +15 -4
  64. package/src/pages/market/features/Header/Mobile.tsx +7 -24
  65. package/src/pages/market/features/SideBar/AgentInfo/Comment.tsx +16 -0
  66. package/src/pages/market/features/SideBar/AgentInfo/Header.tsx +68 -0
  67. package/src/pages/market/features/SideBar/AgentInfo/Loading.tsx +61 -0
  68. package/src/pages/market/features/SideBar/AgentInfo/TokenTag.tsx +25 -0
  69. package/src/pages/market/features/SideBar/AgentInfo/index.tsx +68 -0
  70. package/src/pages/market/features/SideBar/AgentInfo/style.ts +46 -0
  71. package/src/pages/market/features/SideBar/Desktop.tsx +70 -0
  72. package/src/pages/market/features/SideBar/Mobile.tsx +36 -0
  73. package/src/pages/market/features/SideBar/index.tsx +23 -0
  74. package/src/pages/market/features/TagList/index.tsx +29 -0
  75. package/src/pages/market/index.page.tsx +11 -2
  76. package/src/pages/market/layout.mobile.tsx +8 -7
  77. package/src/pages/market/layout.tsx +39 -1
  78. package/src/pages/settings/features/Header/Desktop.tsx +2 -4
  79. package/src/pages/settings/features/Header/Mobile.tsx +1 -1
  80. package/src/pages/settings/features/Settings/Common.tsx +1 -2
  81. package/src/pages/settings/features/Settings/index.tsx +17 -4
  82. package/src/services/agentMarket.ts +21 -0
  83. package/src/store/global/initialState.ts +1 -2
  84. package/src/store/market/action.ts +57 -0
  85. package/src/store/market/index.ts +3 -0
  86. package/src/store/market/initialState.ts +17 -0
  87. package/src/store/market/selectors.ts +36 -0
  88. package/src/store/market/store.ts +51 -0
  89. package/src/store/session/slices/session/action.ts +5 -3
  90. package/src/store/session/slices/session/initialState.ts +2 -0
  91. package/src/store/session/slices/session/reducers/session.test.ts +4 -4
  92. package/src/types/market.ts +19 -0
  93. package/src/types/meta.ts +1 -1
  94. package/src/utils/filter.ts +1 -1
  95. package/src/utils/findDuplicates.ts +22 -0
  96. package/scripts/genDefaultLocale.ts +0 -18
  97. package/scripts/genResources.ts +0 -51
  98. package/scripts/toc.ts +0 -7
  99. package/src/components/Empty/index.tsx +0 -63
  100. package/src/components/Empty/style.ts +0 -31
  101. package/src/components/SelectWithImg/index.tsx +0 -97
  102. package/src/components/SelectWithImg/styles.ts +0 -43
  103. package/src/pages/chat/features/Conversation/Input/ActionRight.tsx +0 -31
  104. package/src/pages/chat/features/Conversation/Input/Footer.tsx +0 -49
  105. /package/src/components/{ManifestPreviewer.tsx → ManifestPreviewer/index.tsx} +0 -0
  106. /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
- // replace onClick with onPointerDown to prevent double click on mobile
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 { useSessionStore } from '@/store/session';
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
- <SearchBar
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) => [s.activeTopicId]);
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
- <Empty
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 active={!activeTopicId} fav={false} title={'默认话题'} />
54
+ <TopicItem
55
+ active={!activeTopicId}
56
+ fav={false}
57
+ title={t('topic.defaultTitle', { ns: 'common' })}
58
+ />
47
59
 
48
- {topics.map(({ id, favorite, title }) => (
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
- <SearchBar
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, Logo, SearchBar } from '@lobehub/ui';
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('common');
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={t('tab.market')} size={36} type={'text'} />
26
+ <Logo className={styles.logo} extra={'Discover'} size={36} type={'text'} />
23
27
  </Link>
24
28
  }
25
- right={<SearchBar allowClear spotlight type={'ghost'} />}
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 { createStyles } from 'antd-style';
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
- <ActionIcon icon={MessageSquarePlus} onClick={createSession} />
30
- <ActionIcon
31
- icon={Settings2}
32
- onClick={() => {
33
- Router.push({ pathname: `/settings` });
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;