@lobehub/chat 0.41.1 → 0.42.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 (60) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/locales/en_US/error.json +1 -0
  3. package/locales/en_US/plugin.json +5 -0
  4. package/locales/en_US/welcome.json +14 -0
  5. package/locales/zh_CN/error.json +1 -0
  6. package/locales/zh_CN/plugin.json +5 -0
  7. package/locales/zh_CN/welcome.json +14 -0
  8. package/package.json +1 -1
  9. package/src/components/DiscordIcon/index.tsx +15 -0
  10. package/src/const/url.ts +7 -0
  11. package/src/features/AvatarWithUpload/index.tsx +1 -2
  12. package/src/features/FolderPanel/index.tsx +4 -5
  13. package/src/features/SideBar/BottomActions.tsx +7 -6
  14. package/src/features/SideBar/TopActions.tsx +1 -1
  15. package/src/features/SideBar/index.tsx +1 -2
  16. package/src/layout/AppLayout.tsx +15 -0
  17. package/src/layout/index.tsx +6 -6
  18. package/src/locales/default/common.ts +1 -0
  19. package/src/locales/default/welcome.ts +14 -0
  20. package/src/locales/resources/zh_CN.ts +2 -0
  21. package/src/pages/chat/SessionList/Header.tsx +2 -6
  22. package/src/pages/chat/SessionList/List/SessionItem.tsx +2 -2
  23. package/src/pages/chat/SessionList/List/index.tsx +2 -6
  24. package/src/pages/chat/[id]/Conversation/ChatList/Error/ApiKeyForm.tsx +1 -5
  25. package/src/pages/chat/[id]/Conversation/ChatList/Error/InvalidAccess.tsx +2 -6
  26. package/src/pages/chat/[id]/Conversation/ChatList/Error/OpenAiBizError.tsx +1 -5
  27. package/src/pages/chat/[id]/Conversation/ChatList/MessageExtra.tsx +1 -2
  28. package/src/pages/chat/[id]/Conversation/ChatList/index.tsx +7 -11
  29. package/src/pages/chat/[id]/Conversation/Input/Action.tsx +1 -2
  30. package/src/pages/chat/[id]/Conversation/Input/ActionRight.tsx +1 -2
  31. package/src/pages/chat/[id]/Conversation/Input/Token.tsx +6 -10
  32. package/src/pages/chat/[id]/Conversation/Input/index.tsx +6 -6
  33. package/src/pages/chat/[id]/Header/index.tsx +13 -17
  34. package/src/pages/chat/[id]/Sidebar/Inner.tsx +45 -28
  35. package/src/pages/chat/[id]/Sidebar/Topic/TopicContent.tsx +5 -5
  36. package/src/pages/chat/[id]/Sidebar/Topic/TopicItem.tsx +1 -2
  37. package/src/pages/chat/[id]/Sidebar/Topic/index.tsx +2 -6
  38. package/src/pages/chat/[id]/Sidebar/index.tsx +4 -5
  39. package/src/pages/chat/[id]/index.page.tsx +5 -6
  40. package/src/pages/chat/{layout.tsx → [id]/layout.tsx} +4 -12
  41. package/src/pages/chat/[id]/setting/index.page.tsx +10 -14
  42. package/src/pages/chat/index.page.tsx +1 -24
  43. package/src/pages/index.page.tsx +33 -1
  44. package/src/pages/settings/Settings/Agent.tsx +5 -5
  45. package/src/pages/settings/Settings/Common.tsx +5 -9
  46. package/src/pages/settings/ThemeSwatches/ThemeSwatchesNeutral.tsx +1 -5
  47. package/src/pages/settings/ThemeSwatches/ThemeSwatchesPrimary.tsx +1 -5
  48. package/src/pages/welcome/Banner/AgentCard.tsx +71 -0
  49. package/src/pages/welcome/Banner/AgentTemplate.tsx +43 -0
  50. package/src/pages/welcome/Banner/Hero.tsx +39 -0
  51. package/src/pages/welcome/Banner/index.tsx +56 -0
  52. package/src/pages/welcome/Footer/index.tsx +24 -0
  53. package/src/pages/welcome/index.page.tsx +28 -0
  54. package/src/pages/welcome/layout.tsx +31 -0
  55. package/src/pages/welcome/style.ts +63 -0
  56. package/src/store/session/slices/session/selectors/index.ts +2 -0
  57. package/src/store/session/slices/session/selectors/list.ts +5 -0
  58. package/src/store/session/store.ts +2 -2
  59. package/src/store/settings/hooks/useHydrated.ts +20 -0
  60. package/src/store/settings/store.ts +2 -2
@@ -0,0 +1,39 @@
1
+ import { LogoThree } from '@lobehub/ui';
2
+ import { useResponsive } from 'antd-style';
3
+ import { memo, useMemo } from 'react';
4
+ import { useTranslation } from 'react-i18next';
5
+
6
+ import { genSize, useStyles } from '../style';
7
+
8
+ const Hero = memo<{ width: number }>(({ width }) => {
9
+ const size = useMemo(
10
+ () => ({
11
+ base: genSize(width / 3.5, 240),
12
+ desc: genSize(width / 50, 14),
13
+ logo: genSize(width / 3.8, 180),
14
+ title: genSize(width / 20, 32),
15
+ }),
16
+ [width],
17
+ );
18
+ const { styles } = useStyles(size.base);
19
+ const { mobile } = useResponsive();
20
+ const { t } = useTranslation('welcome');
21
+
22
+ return (
23
+ <>
24
+ <LogoThree
25
+ size={size.logo}
26
+ style={{ marginBottom: -size.logo / 40, marginTop: -size.logo / 5 }}
27
+ />
28
+ <div className={styles.title} style={{ fontSize: size.title }}>
29
+ LobeChat{mobile ? <br /> : ' '}
30
+ {t('slogan.title')}
31
+ </div>
32
+ <div className={styles.desc} style={{ fontSize: size.desc }}>
33
+ {t('slogan.desc1')}
34
+ </div>
35
+ </>
36
+ );
37
+ });
38
+
39
+ export default Hero;
@@ -0,0 +1,56 @@
1
+ import { GridShowcase, Icon } from '@lobehub/ui';
2
+ import { useSize } from 'ahooks';
3
+ import { Button, Upload } from 'antd';
4
+ import { SendHorizonal } from 'lucide-react';
5
+ import Link from 'next/link';
6
+ import Router from 'next/router';
7
+ import { memo, useCallback, useRef } from 'react';
8
+ import { useTranslation } from 'react-i18next';
9
+ import { Flexbox } from 'react-layout-kit';
10
+
11
+ import { useImportConfig } from '@/hooks/useImportConfig';
12
+
13
+ import { useStyles } from '../style';
14
+ import AgentTemplate from './AgentTemplate';
15
+ import Hero from './Hero';
16
+
17
+ const Banner = memo(() => {
18
+ const { importConfig } = useImportConfig();
19
+ const ref = useRef(null);
20
+ const domSize = useSize(ref);
21
+ const width = domSize?.width || 1024;
22
+ const { t } = useTranslation('welcome');
23
+
24
+ const { styles } = useStyles();
25
+
26
+ const handleImport = useCallback((e: any) => {
27
+ importConfig(e);
28
+ Router.push('/chat');
29
+ }, []);
30
+
31
+ return (
32
+ <>
33
+ <GridShowcase>
34
+ <div className={styles.container} ref={ref}>
35
+ <Hero width={width} />
36
+ </div>
37
+ <Flexbox gap={16} horizontal style={{ marginTop: 16 }}>
38
+ <Link href={'/chat'}>
39
+ <Button size={'large'} type={'primary'}>
40
+ <Flexbox align={'center'} gap={4} horizontal>
41
+ {t('button.start')}
42
+ <Icon icon={SendHorizonal} />
43
+ </Flexbox>
44
+ </Button>
45
+ </Link>
46
+ <Upload maxCount={1} onChange={handleImport} showUploadList={false}>
47
+ <Button size={'large'}>{t('button.import')}</Button>
48
+ </Upload>
49
+ </Flexbox>
50
+ </GridShowcase>
51
+ <AgentTemplate width={width} />
52
+ </>
53
+ );
54
+ });
55
+
56
+ export default Banner;
@@ -0,0 +1,24 @@
1
+ import { ActionIcon } from '@lobehub/ui';
2
+ import { useTheme } from 'antd-style';
3
+ import { Book, Github } from 'lucide-react';
4
+ import { memo } from 'react';
5
+ import { Flexbox } from 'react-layout-kit';
6
+
7
+ import Discord from '@/components/DiscordIcon';
8
+ import { CHANGELOG, DISCORD, GITHUB } from '@/const/url';
9
+
10
+ const Footer = memo(() => {
11
+ const theme = useTheme();
12
+ return (
13
+ <Flexbox align={'center'} horizontal justify={'space-between'} style={{ padding: 16 }}>
14
+ <span style={{ color: theme.colorTextDescription }}>©{new Date().getFullYear()} LobeHub</span>
15
+ <Flexbox horizontal>
16
+ <ActionIcon icon={Discord} onClick={() => window.open(DISCORD, '__blank')} size={'site'} />
17
+ <ActionIcon icon={Book} onClick={() => window.open(CHANGELOG, '__blank')} size={'site'} />
18
+ <ActionIcon icon={Github} onClick={() => window.open(GITHUB, '__blank')} size={'site'} />
19
+ </Flexbox>
20
+ </Flexbox>
21
+ );
22
+ });
23
+
24
+ export default Footer;
@@ -0,0 +1,28 @@
1
+ import Head from 'next/head';
2
+ import { memo } from 'react';
3
+ import { useTranslation } from 'react-i18next';
4
+
5
+ import { genSiteHeadTitle } from '@/utils/genSiteHeadTitle';
6
+
7
+ import Banner from './Banner';
8
+ import Footer from './Footer';
9
+ import Layout from './layout';
10
+
11
+ const Welcome = memo(() => {
12
+ const { t } = useTranslation('welcome');
13
+ const pageTitle = genSiteHeadTitle(t('header'));
14
+
15
+ return (
16
+ <>
17
+ <Head>
18
+ <title>{pageTitle}</title>
19
+ </Head>
20
+ <Layout>
21
+ <Banner />
22
+ <Footer />
23
+ </Layout>
24
+ </>
25
+ );
26
+ });
27
+
28
+ export default Welcome;
@@ -0,0 +1,31 @@
1
+ import { Logo } from '@lobehub/ui';
2
+ import Link from 'next/link';
3
+ import { PropsWithChildren, memo } from 'react';
4
+ import { Center, Flexbox } from 'react-layout-kit';
5
+
6
+ import AppLayout from '../../layout/AppLayout';
7
+ import { useStyles } from './style';
8
+
9
+ const WelcomeLayout = memo<PropsWithChildren>(({ children }) => {
10
+ const { styles } = useStyles();
11
+ return (
12
+ <AppLayout>
13
+ <Center
14
+ className={styles.layout}
15
+ flex={1}
16
+ height={'100vh'}
17
+ horizontal
18
+ style={{ position: 'relative' }}
19
+ >
20
+ <Link href={'/'}>
21
+ <Logo className={styles.logo} size={36} type={'text'} />
22
+ </Link>
23
+ <Flexbox className={styles.view} flex={1} style={{ maxWidth: 1024 }}>
24
+ {children}
25
+ </Flexbox>
26
+ </Center>
27
+ </AppLayout>
28
+ );
29
+ });
30
+
31
+ export default WelcomeLayout;
@@ -0,0 +1,63 @@
1
+ import { createStyles } from 'antd-style';
2
+ import { rgba } from 'polished';
3
+
4
+ export const useStyles = createStyles(({ css, token, stylish, cx }) => {
5
+ return {
6
+ container: css`
7
+ z-index: 10;
8
+
9
+ display: flex;
10
+ flex-direction: column;
11
+ align-items: center;
12
+
13
+ width: 100%;
14
+ margin-bottom: 24px;
15
+ `,
16
+ desc: css`
17
+ font-weight: 400;
18
+ color: ${rgba(token.colorText, 0.8)};
19
+ text-align: center;
20
+ `,
21
+ layout: css`
22
+ background: ${token.colorBgContainer};
23
+ `,
24
+ logo: css`
25
+ position: absolute;
26
+ top: 16px;
27
+ left: 16px;
28
+ fill: ${token.colorText};
29
+ `,
30
+ note: css`
31
+ z-index: 10;
32
+ margin-top: 16px;
33
+ color: ${token.colorTextDescription};
34
+ `,
35
+ skip: css`
36
+ color: ${token.colorTextDescription};
37
+ `,
38
+ templateContainer: css`
39
+ flex-wrap: wrap;
40
+ width: 100%;
41
+ padding: 16px;
42
+ `,
43
+ title: css`
44
+ margin-bottom: 0.2em;
45
+ font-weight: 800;
46
+ line-height: 1.2;
47
+ text-align: center;
48
+ `,
49
+ view: cx(
50
+ stylish.noScrollbar,
51
+ css`
52
+ overflow-x: hidden;
53
+ overflow-y: auto;
54
+ height: 100vh;
55
+ padding: 32px 16px;
56
+ `,
57
+ ),
58
+ };
59
+ });
60
+
61
+ export const genSize = (size: number, minSize: number) => {
62
+ return size < minSize ? minSize : size;
63
+ };
@@ -4,6 +4,7 @@ import {
4
4
  currentSessionSafe,
5
5
  getSessionById,
6
6
  getSessionMetaById,
7
+ hasSessionList,
7
8
  sessionList,
8
9
  } from './list';
9
10
 
@@ -15,5 +16,6 @@ export const sessionSelectors = {
15
16
  getExportAgent,
16
17
  getSessionById,
17
18
  getSessionMetaById,
19
+ hasSessionList,
18
20
  sessionList,
19
21
  };
@@ -36,6 +36,11 @@ export const sessionList = (s: SessionStore) => {
36
36
  });
37
37
  };
38
38
 
39
+ export const hasSessionList = (s: SessionStore) => {
40
+ const list = sessionList(s);
41
+ return list?.length > 0;
42
+ };
43
+
39
44
  export const getSessionById =
40
45
  (id: string) =>
41
46
  (s: SessionStore): LobeAgentSession => {
@@ -1,5 +1,5 @@
1
- import equal from 'fast-deep-equal';
2
1
  import { PersistOptions, devtools, persist } from 'zustand/middleware';
2
+ import { shallow } from 'zustand/shallow';
3
3
  import { createWithEqualityFn } from 'zustand/traditional';
4
4
  import { StateCreator } from 'zustand/vanilla';
5
5
 
@@ -49,5 +49,5 @@ export const useSessionStore = createWithEqualityFn<SessionStore>()(
49
49
  }),
50
50
  persistOptions,
51
51
  ),
52
- equal,
52
+ shallow,
53
53
  );
@@ -0,0 +1,20 @@
1
+ import { useEffect, useState } from 'react';
2
+
3
+ import { useSettings } from '../store';
4
+
5
+ export const useSettingsHydrated = () => {
6
+ // 根据 sessions 是否有值来判断是否已经初始化
7
+ const hasInited = !!Object.values(useSettings.getState().settings).length;
8
+
9
+ const [isInit, setInit] = useState(hasInited);
10
+
11
+ useEffect(() => {
12
+ const hasRehydrated = useSettings.persist.hasHydrated();
13
+
14
+ if (hasRehydrated && !isInit) {
15
+ setInit(true);
16
+ }
17
+ }, []);
18
+
19
+ return isInit;
20
+ };
@@ -1,5 +1,5 @@
1
- import equal from 'fast-deep-equal';
2
1
  import { PersistOptions, devtools, persist } from 'zustand/middleware';
2
+ import { shallow } from 'zustand/shallow';
3
3
  import { createWithEqualityFn } from 'zustand/traditional';
4
4
  import { StateCreator } from 'zustand/vanilla';
5
5
 
@@ -39,5 +39,5 @@ export const useSettings = createWithEqualityFn<SettingsStore>()(
39
39
  }),
40
40
  persistOptions,
41
41
  ),
42
- equal,
42
+ shallow,
43
43
  );