@lobehub/chat 0.83.5 โ†’ 0.83.7

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 CHANGED
@@ -2,6 +2,66 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 0.83.7](https://github.com/lobehub/lobe-chat/compare/v0.83.6...v0.83.7)
6
+
7
+ <sup>Released on **2023-10-07**</sup>
8
+
9
+ #### ๐Ÿ› Bug Fixes
10
+
11
+ - **misc**: Fix shuffle, use search url with agent item.
12
+
13
+ #### ๐Ÿ’„ Styles
14
+
15
+ - **misc**: Better tag style, improve loading state.
16
+
17
+ <br/>
18
+
19
+ <details>
20
+ <summary><kbd>Improvements and Fixes</kbd></summary>
21
+
22
+ #### What's fixed
23
+
24
+ - **misc**: Fix shuffle ([d4b9dc3](https://github.com/lobehub/lobe-chat/commit/d4b9dc3))
25
+ - **misc**: Use search url with agent item ([98df623](https://github.com/lobehub/lobe-chat/commit/98df623))
26
+
27
+ #### Styles
28
+
29
+ - **misc**: Better tag style ([38e42ea](https://github.com/lobehub/lobe-chat/commit/38e42ea))
30
+ - **misc**: Improve loading state ([f00c868](https://github.com/lobehub/lobe-chat/commit/f00c868))
31
+
32
+ </details>
33
+
34
+ <div align="right">
35
+
36
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
37
+
38
+ </div>
39
+
40
+ ### [Version 0.83.6](https://github.com/lobehub/lobe-chat/compare/v0.83.5...v0.83.6)
41
+
42
+ <sup>Released on **2023-10-06**</sup>
43
+
44
+ #### ๐Ÿ’„ Styles
45
+
46
+ - **misc**: Update modal style.
47
+
48
+ <br/>
49
+
50
+ <details>
51
+ <summary><kbd>Improvements and Fixes</kbd></summary>
52
+
53
+ #### Styles
54
+
55
+ - **misc**: Update modal style ([2ab1475](https://github.com/lobehub/lobe-chat/commit/2ab1475))
56
+
57
+ </details>
58
+
59
+ <div align="right">
60
+
61
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
62
+
63
+ </div>
64
+
5
65
  ### [Version 0.83.5](https://github.com/lobehub/lobe-chat/compare/v0.83.4...v0.83.5)
6
66
 
7
67
  <sup>Released on **2023-10-06**</sup>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "0.83.5",
3
+ "version": "0.83.7",
4
4
  "description": "An open-source, extensible (Function Calling), high-performance chatbot framework. It supports one-click free deployment of your private ChatGPT/LLM web application",
5
5
  "keywords": [
6
6
  "chatbot",
@@ -9,16 +9,14 @@ import ChatHeader from './features/ChatHeader';
9
9
  import ChatInput from './features/ChatInput';
10
10
  import SideBar from './features/SideBar';
11
11
 
12
- const DesktopPage = memo(() => {
13
- return (
14
- <>
15
- <PageTitle />
16
- <ChatHeader />
17
- <Flexbox flex={1} height={'calc(100vh - 64px)'} horizontal>
18
- <Conversation chatInput={<ChatInput />} />
19
- <SideBar />
20
- </Flexbox>
21
- </>
22
- );
23
- });
12
+ const DesktopPage = memo(() => (
13
+ <>
14
+ <PageTitle />
15
+ <ChatHeader />
16
+ <Flexbox flex={1} height={'calc(100vh - 64px)'} horizontal>
17
+ <Conversation chatInput={<ChatInput />} />
18
+ <SideBar />
19
+ </Flexbox>
20
+ </>
21
+ ));
24
22
  export default DesktopPage;
@@ -1,14 +1,15 @@
1
1
  import { PropsWithChildren } from 'react';
2
2
 
3
+ import ResponsiveLayout from '@/components/ResponsiveLayout';
3
4
  import { isMobileDevice } from '@/utils/responsive';
4
5
 
5
6
  import Desktop from './(desktop)/layout';
6
7
  import Mobile from './(mobile)/layout';
7
8
 
8
- const Layout = ({ children }: PropsWithChildren) => {
9
- const mobile = isMobileDevice();
10
-
11
- return mobile ? <Mobile>{children}</Mobile> : <Desktop>{children}</Desktop>;
12
- };
9
+ const Layout = ({ children }: PropsWithChildren) => (
10
+ <ResponsiveLayout Desktop={Desktop} Mobile={Mobile} isMobile={isMobileDevice}>
11
+ {children}
12
+ </ResponsiveLayout>
13
+ );
13
14
 
14
15
  export default Layout;
@@ -1,11 +1,11 @@
1
1
  import { SpotlightCard } from '@lobehub/ui';
2
2
  import { useResponsive } from 'antd-style';
3
- import { shuffle } from 'lodash-es';
4
3
  import { memo, useMemo } from 'react';
5
4
  import { useTranslation } from 'react-i18next';
6
5
  import { Flexbox } from 'react-layout-kit';
7
6
 
8
7
  import { agentMarketSelectors, useMarketStore } from '@/store/market';
8
+ import { AgentsMarketIndexItem } from '@/types/market';
9
9
 
10
10
  import TagList from '../TagList';
11
11
  import AgentCardItem from './AgentCardItem';
@@ -14,23 +14,30 @@ import { useStyles } from './style';
14
14
 
15
15
  const gridRender = (item: any) => <AgentCardItem {...item} />;
16
16
 
17
- const AgentCard = memo(() => {
18
- const { mobile } = useResponsive();
19
- const agentList = useMarketStore(agentMarketSelectors.getAgentList);
17
+ export interface AgentCardProps {
18
+ defaultAgents?: AgentsMarketIndexItem[];
19
+ }
20
+
21
+ const AgentCard = memo<AgentCardProps>(({ defaultAgents }) => {
20
22
  const { t } = useTranslation('market');
23
+ const { mobile } = useResponsive();
24
+ const { styles } = useStyles();
25
+
21
26
  const [useFetchAgentList, keywords] = useMarketStore((s) => [
22
27
  s.useFetchAgentList,
23
28
  s.searchKeywords,
24
29
  ]);
25
- const { styles } = useStyles();
26
- const { isLoading } = useFetchAgentList();
30
+ useFetchAgentList();
31
+
32
+ const clientAgentList = useMarketStore(agentMarketSelectors.getAgentList);
33
+ const agentList = clientAgentList.length === 0 && defaultAgents ? defaultAgents : clientAgentList;
27
34
 
28
35
  const agentListData = useMemo(() => {
29
36
  if (!keywords) return agentList;
30
37
  return agentList.filter(({ meta }) => JSON.stringify(meta).toLowerCase().includes(keywords));
31
38
  }, [agentList, keywords]);
32
39
 
33
- if (isLoading || !agentList) return <Loading />;
40
+ if (agentList.length === 0) return <Loading />;
34
41
 
35
42
  return (
36
43
  <Flexbox gap={mobile ? 16 : 24}>
@@ -42,11 +49,7 @@ const AgentCard = memo(() => {
42
49
  <div className={styles.subTitle}>{t('title.recentSubmits')}</div>
43
50
  <SpotlightCard items={agentListData.slice(0, 3)} renderItem={gridRender} />
44
51
  <div className={styles.subTitle}>{t('title.allAgents')}</div>
45
- <SpotlightCard
46
- items={shuffle(agentListData.slice(3))}
47
- renderItem={gridRender}
48
- spotlight={false}
49
- />
52
+ <SpotlightCard items={agentListData.slice(3)} renderItem={gridRender} spotlight={false} />
50
53
  </>
51
54
  )}
52
55
  </Flexbox>
@@ -16,7 +16,7 @@ const TagList = memo(() => {
16
16
  <Button
17
17
  key={item}
18
18
  onClick={() => useMarketStore.setState({ searchKeywords: item })}
19
- size={'small'}
19
+ shape={'round'}
20
20
  type={keywords === item ? 'primary' : 'default'}
21
21
  >
22
22
  {startCase(item)}
@@ -1,39 +1,29 @@
1
1
  'use client';
2
2
 
3
- import { useResponsive } from 'antd-style';
4
- import Head from 'next/head';
5
3
  import { memo, useEffect } from 'react';
6
4
  import { useTranslation } from 'react-i18next';
7
5
 
6
+ import PageTitle from '@/components/PageTitle';
8
7
  import { useMarketStore } from '@/store/market';
9
8
  import { genSiteHeadTitle } from '@/utils/genSiteHeadTitle';
10
9
 
11
- import AgentCard from './features/AgentCard';
10
+ import AgentCard, { AgentCardProps } from './features/AgentCard';
12
11
  import AgentSearchBar from './features/AgentSearchBar';
13
- import DesktopLayout from './layout.desktop';
14
- import MobileLayout from './layout.mobile';
15
12
 
16
- const Market = memo(() => {
13
+ const Market = memo<AgentCardProps>(({ defaultAgents }) => {
17
14
  const { t } = useTranslation('common');
18
15
  const pageTitle = genSiteHeadTitle(t('tab.market'));
19
- const { mobile } = useResponsive();
20
16
 
21
17
  useEffect(() => {
22
18
  // refs: https://github.com/pmndrs/zustand/blob/main/docs/integrations/persisting-store-data.md#hashydrated
23
19
  useMarketStore.persist.rehydrate();
24
20
  }, []);
25
21
 
26
- const RenderLayout = mobile ? MobileLayout : DesktopLayout;
27
-
28
22
  return (
29
23
  <>
30
- <Head>
31
- <title>{pageTitle}</title>
32
- </Head>
33
- <RenderLayout>
34
- <AgentSearchBar />
35
- <AgentCard />
36
- </RenderLayout>
24
+ <PageTitle title={pageTitle} />
25
+ <AgentSearchBar />
26
+ <AgentCard defaultAgents={defaultAgents} />
37
27
  </>
38
28
  );
39
29
  });
@@ -8,9 +8,9 @@ import { MAX_WIDTH } from '@/const/layoutTokens';
8
8
  import { useSwitchSideBarOnInit } from '@/store/global';
9
9
  import { SidebarTabKey } from '@/store/global/initialState';
10
10
 
11
- import AppLayout from '../../layout/AppLayout';
12
- import Header from './features/Header';
13
- import SideBar from './features/SideBar';
11
+ import AppLayout from '../../../layout/AppLayout';
12
+ import Header from '../features/Header';
13
+ import SideBar from '../features/SideBar';
14
14
 
15
15
  const useStyles = createStyles(({ css }) => ({
16
16
  background: css`
@@ -0,0 +1,17 @@
1
+ 'use client';
2
+
3
+ import { PropsWithChildren } from 'react';
4
+
5
+ import ResponsiveLayout from '@/components/ResponsiveLayout';
6
+ import { useIsMobile } from '@/hooks/useIsMobile';
7
+
8
+ import Mobile from '../layout.mobile';
9
+ import Desktop from './Desktop';
10
+
11
+ const Market = ({ children }: PropsWithChildren) => (
12
+ <ResponsiveLayout Desktop={Desktop} Mobile={Mobile} isMobile={useIsMobile}>
13
+ {children}
14
+ </ResponsiveLayout>
15
+ );
16
+
17
+ export default Market;
@@ -1,4 +1,6 @@
1
- import { ReactNode, memo } from 'react';
1
+ 'use client';
2
+
3
+ import { PropsWithChildren } from 'react';
2
4
  import { Flexbox } from 'react-layout-kit';
3
5
 
4
6
  import AppMobileLayout from '@/layout/AppMobileLayout';
@@ -8,7 +10,7 @@ import { SidebarTabKey } from '@/store/global/initialState';
8
10
  import Header from './features/Header';
9
11
  import SideBar from './features/SideBar';
10
12
 
11
- const MarketLayout = memo<{ children: ReactNode }>(({ children }) => {
13
+ const MarketLayout = ({ children }: PropsWithChildren) => {
12
14
  useSwitchSideBarOnInit(SidebarTabKey.Market);
13
15
 
14
16
  return (
@@ -19,6 +21,6 @@ const MarketLayout = memo<{ children: ReactNode }>(({ children }) => {
19
21
  <SideBar />
20
22
  </AppMobileLayout>
21
23
  );
22
- });
24
+ };
23
25
 
24
26
  export default MarketLayout;
@@ -0,0 +1,13 @@
1
+ import { PropsWithChildren } from 'react';
2
+
3
+ import ResponsiveLayout from '@/components/ResponsiveLayout';
4
+ import { isMobileDevice } from '@/utils/responsive';
5
+
6
+ import Desktop from './layout.desktop';
7
+ import Mobile from './layout.mobile';
8
+
9
+ export default ({ children }: PropsWithChildren) => (
10
+ <ResponsiveLayout Desktop={Desktop} Mobile={Mobile} isMobile={isMobileDevice}>
11
+ {children}
12
+ </ResponsiveLayout>
13
+ );
@@ -1,7 +1,29 @@
1
- import Page from './index';
1
+ import { cookies } from 'next/headers';
2
2
 
3
- const Index = () => {
4
- return <Page />;
3
+ import { LOBE_LOCALE_COOKIE } from '@/const/locale';
4
+ import { getAgentIndexJSON } from '@/const/url';
5
+ import { Locales } from '@/locales/resources';
6
+ import { LobeChatAgentsMarketIndex } from '@/types/market';
7
+
8
+ import Market from './index';
9
+
10
+ const getAgentList = async (): Promise<LobeChatAgentsMarketIndex> => {
11
+ const cookieStore = cookies();
12
+ const lang = cookieStore.get(LOBE_LOCALE_COOKIE);
13
+
14
+ try {
15
+ const res = await fetch(getAgentIndexJSON(lang?.value as Locales));
16
+
17
+ return res.json();
18
+ } catch {
19
+ return { agents: [], schemaVersion: 1 };
20
+ }
21
+ };
22
+
23
+ const Page = async () => {
24
+ const data = await getAgentList();
25
+
26
+ return <Market defaultAgents={data.agents} />;
5
27
  };
6
28
 
7
- export default Index;
29
+ export default Page;
@@ -1,4 +1,4 @@
1
- import { ReactNode, memo } from 'react';
1
+ import { PropsWithChildren } from 'react';
2
2
  import { Center, Flexbox } from 'react-layout-kit';
3
3
 
4
4
  import SafeSpacing from '@/components/SafeSpacing';
@@ -7,7 +7,7 @@ import AppLayout from '@/layout/AppLayout';
7
7
  import Header from '../features/Header';
8
8
  import SideBar from '../features/SideBar';
9
9
 
10
- const SettingLayout = memo<{ children: ReactNode }>(({ children }) => {
10
+ const SettingLayout = ({ children }: PropsWithChildren) => {
11
11
  return (
12
12
  <AppLayout>
13
13
  <SideBar />
@@ -22,6 +22,6 @@ const SettingLayout = memo<{ children: ReactNode }>(({ children }) => {
22
22
  </Flexbox>
23
23
  </AppLayout>
24
24
  );
25
- });
25
+ };
26
26
 
27
27
  export default SettingLayout;
@@ -1,10 +1,11 @@
1
1
  'use client';
2
2
 
3
- import { useResponsive } from 'antd-style';
4
- import { ReactNode, memo } from 'react';
3
+ import { PropsWithChildren } from 'react';
5
4
  import { useTranslation } from 'react-i18next';
6
5
 
7
6
  import PageTitle from '@/components/PageTitle';
7
+ import ResponsiveLayout from '@/components/ResponsiveLayout';
8
+ import { useIsMobile } from '@/hooks/useIsMobile';
8
9
  import { useSwitchSideBarOnInit } from '@/store/global';
9
10
  import { SidebarTabKey } from '@/store/global/initialState';
10
11
  import { genSiteHeadTitle } from '@/utils/genSiteHeadTitle';
@@ -12,21 +13,20 @@ import { genSiteHeadTitle } from '@/utils/genSiteHeadTitle';
12
13
  import MobileLayout from '../layout.mobile';
13
14
  import DesktopLayout from './Desktop';
14
15
 
15
- const Setting = memo<{ children: ReactNode }>(({ children }) => {
16
- const { mobile } = useResponsive();
16
+ const Setting = ({ children }: PropsWithChildren) => {
17
17
  const { t } = useTranslation('setting');
18
18
  const pageTitle = genSiteHeadTitle(t('header.global'));
19
19
 
20
- const RenderLayout = mobile ? MobileLayout : DesktopLayout;
21
-
22
20
  useSwitchSideBarOnInit(SidebarTabKey.Setting);
23
21
 
24
22
  return (
25
23
  <>
26
24
  <PageTitle title={pageTitle} />
27
- <RenderLayout>{children}</RenderLayout>
25
+ <ResponsiveLayout Desktop={DesktopLayout} Mobile={MobileLayout} isMobile={useIsMobile}>
26
+ {children}
27
+ </ResponsiveLayout>
28
28
  </>
29
29
  );
30
- });
30
+ };
31
31
 
32
32
  export default Setting;
@@ -1,18 +1,16 @@
1
1
  'use client';
2
2
 
3
- import { ReactNode, memo } from 'react';
3
+ import { PropsWithChildren } from 'react';
4
4
  import { Flexbox } from 'react-layout-kit';
5
5
 
6
6
  import AppMobileLayout from '@/layout/AppMobileLayout';
7
7
 
8
8
  import Header from './features/Header';
9
9
 
10
- const SettingLayout = memo<{ children: ReactNode }>(({ children }) => {
11
- return (
12
- <AppMobileLayout navBar={<Header />}>
13
- <Flexbox style={{ overflow: 'auto' }}>{children}</Flexbox>
14
- </AppMobileLayout>
15
- );
16
- });
10
+ const SettingLayout = ({ children }: PropsWithChildren) => (
11
+ <AppMobileLayout navBar={<Header />}>
12
+ <Flexbox style={{ overflow: 'auto' }}>{children}</Flexbox>
13
+ </AppMobileLayout>
14
+ );
17
15
 
18
16
  export default SettingLayout;
@@ -1,14 +1,15 @@
1
1
  import { PropsWithChildren } from 'react';
2
2
 
3
+ import ResponsiveLayout from '@/components/ResponsiveLayout';
3
4
  import { isMobileDevice } from '@/utils/responsive';
4
5
 
5
6
  import Desktop from './layout.desktop';
6
7
  import Mobile from './layout.mobile';
7
8
 
8
- const Layout = ({ children }: PropsWithChildren) => {
9
- const mobile = isMobileDevice();
10
-
11
- return mobile ? <Mobile>{children}</Mobile> : <Desktop>{children}</Desktop>;
12
- };
9
+ const Layout = ({ children }: PropsWithChildren) => (
10
+ <ResponsiveLayout Desktop={Desktop} Mobile={Mobile} isMobile={isMobileDevice}>
11
+ {children}
12
+ </ResponsiveLayout>
13
+ );
13
14
 
14
15
  export default Layout;
@@ -0,0 +1,15 @@
1
+ import { PropsWithChildren, ReactNode } from 'react';
2
+
3
+ interface ServerResponsiveLayoutProps {
4
+ Desktop: (props: PropsWithChildren) => ReactNode;
5
+ Mobile: (props: PropsWithChildren) => ReactNode;
6
+ children: ReactNode;
7
+ isMobile: () => boolean;
8
+ }
9
+ const ResponsiveLayout = ({ children, Desktop, Mobile, isMobile }: ServerResponsiveLayoutProps) => {
10
+ const mobile = isMobile();
11
+
12
+ return mobile ? <Mobile>{children}</Mobile> : <Desktop>{children}</Desktop>;
13
+ };
14
+
15
+ export default ResponsiveLayout;
@@ -1,5 +1,5 @@
1
1
  import { Avatar, Form } from '@lobehub/ui';
2
- import { Form as AForm, FormInstance, Switch, Tag } from 'antd';
2
+ import { Form as AForm, Card, FormInstance, Switch, Tag } from 'antd';
3
3
  import { memo } from 'react';
4
4
  import { useTranslation } from 'react-i18next';
5
5
  import { Flexbox } from 'react-layout-kit';
@@ -28,16 +28,9 @@ const PluginPreview = memo<{ form: FormInstance }>(({ form }) => {
28
28
  };
29
29
 
30
30
  return (
31
- <Form
32
- colon={false}
33
- items={[
34
- {
35
- children: [items],
36
- title: t('dev.preview.card'),
37
- },
38
- ]}
39
- style={{ marginBottom: 0 }}
40
- />
31
+ <Card size={'small'} title={t('dev.preview.card')}>
32
+ <Form.Item {...items} colon={false} style={{ marginBottom: 0 }} />
33
+ </Card>
41
34
  );
42
35
  });
43
36
 
@@ -0,0 +1,7 @@
1
+ import { useResponsive } from 'antd-style';
2
+
3
+ export const useIsMobile = (): boolean => {
4
+ const { mobile } = useResponsive();
5
+
6
+ return !!mobile;
7
+ };
@@ -1,5 +1,6 @@
1
1
  import { getAgentIndexJSON, getAgentJSON } from '@/const/url';
2
2
  import { settingsSelectors, useGlobalStore } from '@/store/global';
3
+ import { LobeChatAgentsMarketIndex } from '@/types/market';
3
4
 
4
5
  /**
5
6
  * ่ฏทๆฑ‚ๅŠฉๆ‰‹ๅˆ—่กจ
@@ -9,7 +10,9 @@ export const getAgentList = async () => {
9
10
  getAgentIndexJSON(settingsSelectors.currentLanguage(useGlobalStore.getState())),
10
11
  );
11
12
 
12
- return res.json();
13
+ const data: LobeChatAgentsMarketIndex = await res.json();
14
+
15
+ return data;
13
16
  };
14
17
 
15
18
  /**
@@ -0,0 +1 @@
1
+ fetch('https://registry.npmmirror.com/@lobehub/chat');
@@ -24,7 +24,7 @@ const persistOptions: PersistOptions<Store> = {
24
24
  selectors: ['agentMap'],
25
25
  },
26
26
  url: {
27
- mode: 'hash',
27
+ mode: 'search',
28
28
  selectors: [
29
29
  // map state key to storage key
30
30
  { currentIdentifier: 'agent' },
@@ -15,7 +15,11 @@ const createUrlSearch = (mode: 'search' | 'hash' = 'hash'): UrlSearchHelper => {
15
15
 
16
16
  return {
17
17
  getUrlSearch: () => location.search.slice(1),
18
- setUrlSearch: (params: URLSearchParams) => (location.search = params.toString()),
18
+ setUrlSearch: (params: URLSearchParams) => {
19
+ if (params.size === 0) return;
20
+
21
+ history.replaceState({}, '', '?' + params.toString());
22
+ },
19
23
  };
20
24
  };
21
25