@lobehub/chat 0.84.0-beta.2 → 0.84.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 (171) hide show
  1. package/.github/workflows/lighthouse-badger-advanced.yml +92 -0
  2. package/.github/workflows/release.yml +0 -3
  3. package/.github/workflows/sync.yml +9 -2
  4. package/.releaserc.js +1 -14
  5. package/CHANGELOG.md +23 -11
  6. package/README.md +21 -0
  7. package/README.zh-CN.md +21 -0
  8. package/docs/Home.md +1 -0
  9. package/docs/Lighthouse.md +65 -0
  10. package/docs/Lighthouse.zh-CN.md +65 -0
  11. package/docs/_Sidebar.md +1 -0
  12. package/locales/en_US/common.json +5 -0
  13. package/locales/ru_RU/common.json +5 -0
  14. package/locales/zh_CN/common.json +5 -0
  15. package/locales/zh_TW/common.json +5 -0
  16. package/next.config.mjs +0 -3
  17. package/package.json +4 -4
  18. package/src/app/chat/(desktop)/features/{ChatHeader/Desktop.tsx → ChatHeader.tsx} +2 -2
  19. package/src/app/chat/(desktop)/features/{ChatInput/Desktop.tsx → ChatInput.tsx} +5 -7
  20. package/src/app/chat/(desktop)/features/{SessionHeader/Desktop.tsx → SessionHeader.tsx} +1 -1
  21. package/src/app/chat/(desktop)/features/{SessionList/Desktop.tsx → SessionList.tsx} +5 -4
  22. package/src/app/chat/(desktop)/features/{SideBar/Desktop.tsx → SideBar.tsx} +5 -4
  23. package/src/app/chat/(desktop)/index.tsx +14 -8
  24. package/src/app/chat/(desktop)/{layout/Desktop.tsx → layout.desktop.tsx} +7 -8
  25. package/src/app/chat/(desktop)/layout.responsive.tsx +12 -0
  26. package/src/app/chat/(mobile)/features/ChatHeader.tsx +54 -1
  27. package/src/app/chat/(mobile)/features/ChatInput.tsx +28 -8
  28. package/src/app/chat/(mobile)/features/SessionList.tsx +13 -8
  29. package/src/app/chat/{components/Inspector/Mobile.tsx → (mobile)/features/TopicList.tsx} +6 -4
  30. package/src/app/chat/(mobile)/index.tsx +3 -5
  31. package/src/app/chat/(mobile)/layout.mobile.tsx +17 -0
  32. package/src/app/chat/(mobile)/mobile/index.tsx +19 -0
  33. package/src/app/chat/(mobile)/mobile/layout.mobile.tsx +11 -0
  34. package/src/app/chat/(mobile)/mobile/page.tsx +2 -20
  35. package/src/app/chat/{components → features}/ChatHeader/ShareButton/Preview.tsx +25 -9
  36. package/src/app/chat/{components → features}/ChatHeader/ShareButton/style.ts +7 -7
  37. package/src/app/chat/{components/ChatInput → features/ChatInputContent}/index.tsx +3 -1
  38. package/src/app/chat/{components/SessionList → features/SessionListContent}/Inbox/index.tsx +7 -5
  39. package/src/app/chat/{components/SessionList → features/SessionListContent}/index.tsx +3 -1
  40. package/src/app/chat/{components/Inspector → features/TopicListContent}/index.tsx +3 -1
  41. package/src/app/chat/page.tsx +3 -1
  42. package/src/app/chat/settings/(desktop)/index.tsx +14 -0
  43. package/src/app/chat/settings/(desktop)/layout.desktop.tsx +10 -15
  44. package/src/app/chat/settings/(desktop)/layout.responsive.tsx +12 -0
  45. package/src/app/chat/settings/(mobile)/index.tsx +14 -0
  46. package/src/app/chat/settings/(mobile)/layout.mobile.tsx +4 -8
  47. package/src/app/chat/settings/features/EditPage.tsx +38 -0
  48. package/src/app/chat/settings/page.tsx +9 -33
  49. package/src/app/market/(desktop)/{AgentDetail/Desktop.tsx → features/AgentDetail.tsx} +5 -3
  50. package/src/app/market/(desktop)/index.tsx +12 -0
  51. package/src/app/market/(desktop)/{layout/Desktop.tsx → layout.desktop.tsx} +5 -5
  52. package/src/app/market/(desktop)/layout.responsive.tsx +16 -0
  53. package/src/app/market/{components/AgentDetail/Mobile.tsx → (mobile)/features/AgentDetail.tsx} +6 -4
  54. package/src/app/market/(mobile)/index.tsx +12 -0
  55. package/src/app/market/(mobile)/layout.mobile.tsx +5 -5
  56. package/src/app/market/{components/AgentDetail → features/AgentDetailContent}/AgentInfo/Header.tsx +1 -0
  57. package/src/app/market/{components/AgentDetail → features/AgentDetailContent}/index.tsx +3 -1
  58. package/src/app/market/features/TagList/index.tsx +2 -1
  59. package/src/app/market/page.tsx +8 -5
  60. package/src/app/settings/{features/Header/Desktop.tsx → (desktop)/features/Header.tsx} +2 -2
  61. package/src/app/settings/(desktop)/index.tsx +17 -0
  62. package/src/app/settings/{layout.desktop/Desktop.tsx → (desktop)/layout.desktop.tsx} +10 -9
  63. package/src/app/settings/(desktop)/layout.responsive.tsx +14 -0
  64. package/src/app/settings/{mobile → (mobile)/features}/ExtraList.tsx +1 -1
  65. package/src/app/settings/(mobile)/features/Header/Home.tsx +8 -0
  66. package/src/app/settings/{features/Header/Mobile.tsx → (mobile)/features/Header/index.tsx} +1 -0
  67. package/src/app/settings/(mobile)/index.tsx +3 -0
  68. package/src/app/settings/(mobile)/layout.mobile.tsx +19 -0
  69. package/src/app/settings/{mobile → (mobile)/mobile}/index.tsx +9 -9
  70. package/src/app/settings/(mobile)/mobile/layout.mobile.tsx +14 -0
  71. package/src/app/settings/agent/Agent.tsx +30 -0
  72. package/src/app/settings/agent/index.tsx +23 -0
  73. package/src/app/settings/agent/layout.tsx +1 -0
  74. package/src/app/settings/agent/page.tsx +2 -31
  75. package/src/app/settings/common/index.tsx +23 -0
  76. package/src/app/settings/common/layout.tsx +1 -0
  77. package/src/app/settings/common/page.tsx +2 -14
  78. package/src/app/settings/features/SideBar/index.tsx +2 -0
  79. package/src/app/settings/features/UpgradeAlert.tsx +32 -0
  80. package/src/app/settings/layout.server.tsx +12 -0
  81. package/src/app/settings/llm/index.tsx +23 -0
  82. package/src/app/settings/llm/layout.tsx +1 -0
  83. package/src/app/settings/llm/page.tsx +2 -14
  84. package/src/app/settings/page.tsx +14 -1
  85. package/src/app/welcome/(desktop)/features/Showcase.tsx +23 -0
  86. package/src/app/welcome/(desktop)/index.tsx +19 -0
  87. package/src/app/welcome/{DesktopLayout/Desktop.tsx → (desktop)/layout.desktop.tsx} +4 -4
  88. package/src/app/welcome/(desktop)/layout.responsive.tsx +14 -0
  89. package/src/app/welcome/(mobile)/features/Header.tsx +6 -0
  90. package/src/app/welcome/(mobile)/features/Showcase.tsx +16 -0
  91. package/src/app/welcome/(mobile)/index.tsx +10 -0
  92. package/src/app/welcome/(mobile)/layout.mobile.tsx +20 -0
  93. package/src/app/welcome/features/Banner/Hero.tsx +2 -3
  94. package/src/app/welcome/features/Banner/index.tsx +34 -31
  95. package/src/app/welcome/features/Banner/style.ts +10 -1
  96. package/src/app/welcome/page.tsx +9 -7
  97. package/src/components/ResponsiveIndex.tsx +17 -0
  98. package/src/const/version.ts +6 -0
  99. package/src/features/MobileTabBar/index.tsx +1 -1
  100. package/src/features/SideBar/BottomActions.tsx +98 -79
  101. package/src/layout/{AppLayout.tsx → AppLayout.desktop.tsx} +2 -2
  102. package/src/layout/{AppMobileLayout.tsx → AppLayout.mobile.tsx} +2 -2
  103. package/src/layout/GlobalLayout/StoreHydration.tsx +15 -1
  104. package/src/layout/ResponsiveLayout.client.tsx +18 -0
  105. package/src/{components/ResponsiveLayout.tsx → layout/ResponsiveLayout.server.tsx} +4 -3
  106. package/src/locales/default/common.ts +5 -0
  107. package/src/services/latestVersion.ts +11 -1
  108. package/src/store/global/initialState.ts +11 -9
  109. package/src/store/global/slices/common.ts +12 -0
  110. package/src/store/session/slices/session/initialState.ts +2 -2
  111. package/.dockerignore +0 -10
  112. package/Dockerfile +0 -47
  113. package/src/app/chat/(desktop)/features/ChatHeader/index.tsx +0 -14
  114. package/src/app/chat/(desktop)/features/ChatInput/index.tsx +0 -22
  115. package/src/app/chat/(desktop)/features/SessionHeader/index.tsx +0 -14
  116. package/src/app/chat/(desktop)/features/SessionList/index.tsx +0 -20
  117. package/src/app/chat/(desktop)/features/SideBar/index.tsx +0 -20
  118. package/src/app/chat/(desktop)/layout/index.tsx +0 -25
  119. package/src/app/chat/(mobile)/features/Topics.tsx +0 -12
  120. package/src/app/chat/(mobile)/layout.tsx +0 -15
  121. package/src/app/chat/components/ChatHeader/Mobile.tsx +0 -54
  122. package/src/app/chat/components/ChatInput/Mobile.tsx +0 -35
  123. package/src/app/chat/components/SessionList/Mobile.tsx +0 -16
  124. package/src/app/chat/layout.tsx +0 -15
  125. package/src/app/chat/settings/layout.tsx +0 -14
  126. package/src/app/market/(desktop)/AgentDetail/index.tsx +0 -16
  127. package/src/app/market/(desktop)/Header/index.tsx +0 -13
  128. package/src/app/market/(desktop)/layout/index.tsx +0 -17
  129. package/src/app/market/(mobile)/AgentDetail.tsx +0 -12
  130. package/src/app/market/layout.tsx +0 -13
  131. package/src/app/settings/features/Header/index.tsx +0 -14
  132. package/src/app/settings/layout.desktop/index.tsx +0 -32
  133. package/src/app/settings/layout.mobile.tsx +0 -16
  134. package/src/app/settings/layout.tsx +0 -15
  135. package/src/app/settings/mobile/page.tsx +0 -7
  136. package/src/app/welcome/DesktopLayout/index.tsx +0 -15
  137. package/src/app/welcome/MobileLayout.tsx +0 -23
  138. package/src/app/welcome/layout.tsx +0 -22
  139. /package/src/app/chat/{components → features}/ChatHeader/PluginTag/PluginStatus.tsx +0 -0
  140. /package/src/app/chat/{components → features}/ChatHeader/PluginTag/index.tsx +0 -0
  141. /package/src/app/chat/{components → features}/ChatHeader/ShareButton/Inner.tsx +0 -0
  142. /package/src/app/chat/{components → features}/ChatHeader/ShareButton/index.tsx +0 -0
  143. /package/src/app/chat/{components/ChatInput → features/ChatInputContent}/ActionBar/ActionLeft.tsx +0 -0
  144. /package/src/app/chat/{components/ChatInput → features/ChatInputContent}/ActionBar/ActionRight.tsx +0 -0
  145. /package/src/app/chat/{components/ChatInput → features/ChatInputContent}/ActionBar/Token.tsx +0 -0
  146. /package/src/app/chat/{components/ChatInput → features/ChatInputContent}/Footer/SaveTopic.tsx +0 -0
  147. /package/src/app/chat/{components/ChatInput → features/ChatInputContent}/Footer/index.tsx +0 -0
  148. /package/src/app/chat/features/{PageTitle.tsx → PageTitle/index.tsx} +0 -0
  149. /package/src/app/chat/{components/SessionList → features/SessionListContent}/CollapseGroup/index.tsx +0 -0
  150. /package/src/app/chat/{components/SessionList → features/SessionListContent}/List/AddButton.tsx +0 -0
  151. /package/src/app/chat/{components/SessionList → features/SessionListContent}/List/Item/Actions.tsx +0 -0
  152. /package/src/app/chat/{components/SessionList → features/SessionListContent}/List/Item/index.tsx +0 -0
  153. /package/src/app/chat/{components/SessionList → features/SessionListContent}/List/SkeletonList.tsx +0 -0
  154. /package/src/app/chat/{components/SessionList → features/SessionListContent}/List/index.tsx +0 -0
  155. /package/src/app/chat/{components/Inspector → features/TopicListContent}/SystemRole/Header.tsx +0 -0
  156. /package/src/app/chat/{components/Inspector → features/TopicListContent}/SystemRole/index.tsx +0 -0
  157. /package/src/app/chat/{components/Inspector → features/TopicListContent}/SystemRole/style.ts +0 -0
  158. /package/src/app/chat/{components/Inspector → features/TopicListContent}/Topic/DefaultContent.tsx +0 -0
  159. /package/src/app/chat/{components/Inspector → features/TopicListContent}/Topic/SkeletonList.tsx +0 -0
  160. /package/src/app/chat/{components/Inspector → features/TopicListContent}/Topic/TopicContent.tsx +0 -0
  161. /package/src/app/chat/{components/Inspector → features/TopicListContent}/Topic/TopicItem.tsx +0 -0
  162. /package/src/app/chat/{components/Inspector → features/TopicListContent}/Topic/index.tsx +0 -0
  163. /package/src/app/chat/{components/Inspector → features/TopicListContent}/TopicSearchBar/index.tsx +0 -0
  164. /package/src/app/market/(desktop)/{Header/Desktop.tsx → features/Header.tsx} +0 -0
  165. /package/src/app/market/(mobile)/{Header.tsx → features/Header.tsx} +0 -0
  166. /package/src/app/market/{components/AgentDetail → features/AgentDetailContent}/AgentInfo/Comment.tsx +0 -0
  167. /package/src/app/market/{components/AgentDetail → features/AgentDetailContent}/AgentInfo/Loading.tsx +0 -0
  168. /package/src/app/market/{components/AgentDetail → features/AgentDetailContent}/AgentInfo/TokenTag.tsx +0 -0
  169. /package/src/app/market/{components/AgentDetail → features/AgentDetailContent}/AgentInfo/index.tsx +0 -0
  170. /package/src/app/market/{components/AgentDetail → features/AgentDetailContent}/AgentInfo/style.ts +0 -0
  171. /package/src/app/welcome/{features/Footer/index.tsx → (desktop)/features/Footer.tsx} +0 -0
@@ -1,5 +1,5 @@
1
1
  import { ActionIcon, DiscordIcon, Icon } from '@lobehub/ui';
2
- import { Dropdown, MenuProps, Upload } from 'antd';
2
+ import { Badge, ConfigProvider, Dropdown, MenuProps, Upload } from 'antd';
3
3
  import {
4
4
  Feather,
5
5
  FileClock,
@@ -11,13 +11,14 @@ import {
11
11
  Settings2,
12
12
  } from 'lucide-react';
13
13
  import { useRouter } from 'next/navigation';
14
- import { memo, useMemo } from 'react';
14
+ import { memo } from 'react';
15
15
  import { useTranslation } from 'react-i18next';
16
+ import { Flexbox } from 'react-layout-kit';
16
17
 
17
18
  import { ABOUT, CHANGELOG, DISCORD, FEEDBACK, GITHUB } from '@/const/url';
18
19
  import { useExportConfig } from '@/hooks/useExportConfig';
19
20
  import { useImportConfig } from '@/hooks/useImportConfig';
20
- import { GlobalStore } from '@/store/global';
21
+ import { GlobalStore, useGlobalStore } from '@/store/global';
21
22
  import { SidebarTabKey } from '@/store/global/initialState';
22
23
 
23
24
  export interface BottomActionProps {
@@ -31,83 +32,91 @@ const BottomActions = memo<BottomActionProps>(({ tab, setTab }) => {
31
32
  const { exportSessions, exportSettings, exportAll, exportAgents } = useExportConfig();
32
33
  const { importConfig } = useImportConfig();
33
34
 
34
- const items: MenuProps['items'] = useMemo(
35
- () => [
36
- {
37
- icon: <Icon icon={HardDriveUpload} />,
38
- key: 'import',
39
- label: (
40
- <Upload maxCount={1} onChange={importConfig} showUploadList={false}>
41
- {t('import')}
42
- </Upload>
43
- ),
44
- },
45
- {
46
- children: [
47
- {
48
- key: 'allAgent',
49
- label: <div>{t('exportType.allAgent')}</div>,
50
- onClick: exportAgents,
51
- },
52
- {
53
- key: 'allAgentWithMessage',
54
- label: <div>{t('exportType.allAgentWithMessage')}</div>,
55
- onClick: exportSessions,
56
- },
57
- {
58
- key: 'globalSetting',
59
- label: <div>{t('exportType.globalSetting')}</div>,
60
- onClick: exportSettings,
61
- },
62
- {
63
- type: 'divider',
64
- },
65
- {
66
- key: 'all',
67
- label: <div>{t('exportType.all')}</div>,
68
- onClick: exportAll,
69
- },
70
- ],
71
- icon: <Icon icon={HardDriveDownload} />,
72
- key: 'export',
73
- label: t('export'),
74
- },
75
- {
76
- type: 'divider',
77
- },
78
- {
79
- icon: <Icon icon={Feather} />,
80
- key: 'feedback',
81
- label: t('feedback'),
82
- onClick: () => window.open(FEEDBACK, '__blank'),
83
- },
84
- {
85
- icon: <Icon icon={FileClock} />,
86
- key: 'changelog',
87
- label: t('changelog'),
88
- onClick: () => window.open(CHANGELOG, '__blank'),
89
- },
90
- {
91
- icon: <Icon icon={Heart} />,
92
- key: 'about',
93
- label: t('about'),
94
- onClick: () => window.open(ABOUT, '__blank'),
95
- },
96
- {
97
- type: 'divider',
98
- },
99
- {
100
- icon: <Icon icon={Settings} />,
101
- key: 'setting',
102
- label: t('setting'),
103
- onClick: () => {
104
- setTab(SidebarTabKey.Setting);
105
- router.push('/settings');
35
+ const [hasNewVersion, useCheckLatestVersion] = useGlobalStore((s) => [
36
+ s.hasNewVersion,
37
+ s.useCheckLatestVersion,
38
+ ]);
39
+
40
+ useCheckLatestVersion();
41
+
42
+ const items: MenuProps['items'] = [
43
+ {
44
+ icon: <Icon icon={HardDriveUpload} />,
45
+ key: 'import',
46
+ label: (
47
+ <Upload maxCount={1} onChange={importConfig} showUploadList={false}>
48
+ {t('import')}
49
+ </Upload>
50
+ ),
51
+ },
52
+ {
53
+ children: [
54
+ {
55
+ key: 'allAgent',
56
+ label: <div>{t('exportType.allAgent')}</div>,
57
+ onClick: exportAgents,
58
+ },
59
+ {
60
+ key: 'allAgentWithMessage',
61
+ label: <div>{t('exportType.allAgentWithMessage')}</div>,
62
+ onClick: exportSessions,
63
+ },
64
+ {
65
+ key: 'globalSetting',
66
+ label: <div>{t('exportType.globalSetting')}</div>,
67
+ onClick: exportSettings,
106
68
  },
69
+ {
70
+ type: 'divider',
71
+ },
72
+ {
73
+ key: 'all',
74
+ label: <div>{t('exportType.all')}</div>,
75
+ onClick: exportAll,
76
+ },
77
+ ],
78
+ icon: <Icon icon={HardDriveDownload} />,
79
+ key: 'export',
80
+ label: t('export'),
81
+ },
82
+ {
83
+ type: 'divider',
84
+ },
85
+ {
86
+ icon: <Icon icon={Feather} />,
87
+ key: 'feedback',
88
+ label: t('feedback'),
89
+ onClick: () => window.open(FEEDBACK, '__blank'),
90
+ },
91
+ {
92
+ icon: <Icon icon={FileClock} />,
93
+ key: 'changelog',
94
+ label: t('changelog'),
95
+ onClick: () => window.open(CHANGELOG, '__blank'),
96
+ },
97
+ {
98
+ icon: <Icon icon={Heart} />,
99
+ key: 'about',
100
+ label: t('about'),
101
+ onClick: () => window.open(ABOUT, '__blank'),
102
+ },
103
+ {
104
+ type: 'divider',
105
+ },
106
+ {
107
+ icon: <Icon icon={Settings} />,
108
+ key: 'setting',
109
+ label: (
110
+ <Flexbox align={'center'} distribution={'space-between'} gap={8} horizontal>
111
+ {t('setting')} {hasNewVersion && <Badge count={t('upgradeVersion.hasNew')} />}
112
+ </Flexbox>
113
+ ),
114
+ onClick: () => {
115
+ setTab(SidebarTabKey.Setting);
116
+ router.push('/settings/common');
107
117
  },
108
- ],
109
- [],
110
- );
118
+ },
119
+ ];
111
120
 
112
121
  return (
113
122
  <>
@@ -124,7 +133,17 @@ const BottomActions = memo<BottomActionProps>(({ tab, setTab }) => {
124
133
  title={'Github'}
125
134
  />
126
135
  <Dropdown arrow={false} menu={{ items }} trigger={['click']}>
127
- <ActionIcon active={tab === SidebarTabKey.Setting} icon={Settings2} />
136
+ {hasNewVersion ? (
137
+ <Flexbox>
138
+ <ConfigProvider theme={{ components: { Badge: { dotSize: 8 } } }}>
139
+ <Badge dot offset={[-4, 4]}>
140
+ <ActionIcon active={tab === SidebarTabKey.Setting} icon={Settings2} />
141
+ </Badge>
142
+ </ConfigProvider>
143
+ </Flexbox>
144
+ ) : (
145
+ <ActionIcon active={tab === SidebarTabKey.Setting} icon={Settings2} />
146
+ )}
128
147
  </Dropdown>
129
148
  </>
130
149
  );
@@ -5,7 +5,7 @@ import { Flexbox } from 'react-layout-kit';
5
5
  import SideBar from '@/features/SideBar';
6
6
  import { useIsPWA } from '@/hooks/useIsPWA';
7
7
 
8
- const AppLayout = memo<PropsWithChildren>(({ children }) => {
8
+ const AppLayoutDesktop = memo<PropsWithChildren>(({ children }) => {
9
9
  const isPWA = useIsPWA();
10
10
  const theme = useTheme();
11
11
  return (
@@ -20,4 +20,4 @@ const AppLayout = memo<PropsWithChildren>(({ children }) => {
20
20
  );
21
21
  });
22
22
 
23
- export default AppLayout;
23
+ export default AppLayoutDesktop;
@@ -43,7 +43,7 @@ interface AppMobileLayoutProps extends PropsWithChildren {
43
43
  title?: MobileNavBarTitleProps;
44
44
  }
45
45
 
46
- const AppMobileLayout = memo<AppMobileLayoutProps>(
46
+ const AppLayoutMobile = memo<AppMobileLayoutProps>(
47
47
  ({ children, showTabBar, navBar, style, className }) => {
48
48
  const { styles, cx } = useStyles();
49
49
 
@@ -67,4 +67,4 @@ const AppMobileLayout = memo<AppMobileLayoutProps>(
67
67
  },
68
68
  );
69
69
 
70
- export default AppMobileLayout;
70
+ export default AppLayoutMobile;
@@ -1,9 +1,14 @@
1
+ import { useResponsive } from 'antd-style';
1
2
  import { useRouter } from 'next/navigation';
2
3
  import { memo, useEffect } from 'react';
3
4
 
4
5
  import { useGlobalStore } from '@/store/global';
5
6
  import { usePluginStore } from '@/store/plugin';
6
- import { useOnFinishHydrationSession, useSessionStore } from '@/store/session';
7
+ import {
8
+ useEffectAfterSessionHydrated,
9
+ useOnFinishHydrationSession,
10
+ useSessionStore,
11
+ } from '@/store/session';
7
12
 
8
13
  const StoreHydration = memo(() => {
9
14
  const router = useRouter();
@@ -22,6 +27,15 @@ const StoreHydration = memo(() => {
22
27
  store.setState({ router });
23
28
  });
24
29
 
30
+ const { mobile } = useResponsive();
31
+
32
+ useEffectAfterSessionHydrated(
33
+ (store) => {
34
+ store.setState({ isMobile: mobile });
35
+ },
36
+ [mobile],
37
+ );
38
+
25
39
  return null;
26
40
  });
27
41
 
@@ -0,0 +1,18 @@
1
+ 'use client';
2
+
3
+ import { PropsWithChildren, ReactNode } from 'react';
4
+
5
+ import { useIsMobile } from '@/hooks/useIsMobile';
6
+
7
+ interface ServerResponsiveLayoutProps {
8
+ Desktop: (props: PropsWithChildren) => ReactNode;
9
+ Mobile: (props: PropsWithChildren) => ReactNode;
10
+ children?: ReactNode;
11
+ }
12
+ const ResponsiveLayout = ({ children, Desktop, Mobile }: ServerResponsiveLayoutProps) => {
13
+ const mobile = useIsMobile();
14
+
15
+ return mobile ? <Mobile>{children}</Mobile> : <Desktop>{children}</Desktop>;
16
+ };
17
+
18
+ export default ResponsiveLayout;
@@ -1,13 +1,14 @@
1
1
  import { PropsWithChildren, ReactNode } from 'react';
2
2
 
3
+ import { isMobileDevice } from '@/utils/responsive';
4
+
3
5
  interface ServerResponsiveLayoutProps {
4
6
  Desktop: (props: PropsWithChildren) => ReactNode;
5
7
  Mobile: (props: PropsWithChildren) => ReactNode;
6
8
  children?: ReactNode;
7
- isMobile: () => boolean;
8
9
  }
9
- const ResponsiveLayout = ({ children, Desktop, Mobile, isMobile }: ServerResponsiveLayoutProps) => {
10
- const mobile = isMobile();
10
+ const ResponsiveLayout = ({ children, Desktop, Mobile }: ServerResponsiveLayoutProps) => {
11
+ const mobile = isMobileDevice();
11
12
 
12
13
  return mobile ? <Mobile>{children}</Mobile> : <Desktop>{children}</Desktop>;
13
14
  };
@@ -96,5 +96,10 @@ export default {
96
96
  },
97
97
  updateAgent: '更新助理信息',
98
98
  updatePrompt: '更新提示词',
99
+ upgradeVersion: {
100
+ action: '立即升级',
101
+ hasNew: '有可用更新',
102
+ newVersion: '有新版本可用:{{version}}',
103
+ },
99
104
  warp: '换行',
100
105
  };
@@ -1 +1,11 @@
1
- fetch('https://registry.npmmirror.com/@lobehub/chat');
1
+ const VERSION_URL = 'https://registry.npmmirror.com/@lobehub/chat';
2
+
3
+ /**
4
+ * get latest version from npm
5
+ */
6
+ export const featLatestVersion = async (): Promise<string> => {
7
+ const res = await fetch(VERSION_URL);
8
+ const data = await res.json();
9
+
10
+ return data['dist-tags']?.latest;
11
+ };
@@ -18,7 +18,18 @@ export interface Guide {
18
18
  topic?: boolean;
19
19
  }
20
20
 
21
+ export interface GlobalPreference {
22
+ guide?: Guide;
23
+ inputHeight: number;
24
+ mobileShowTopic?: boolean;
25
+ sessionsWidth: number;
26
+ showChatSideBar?: boolean;
27
+ showSessionPanel?: boolean;
28
+ }
29
+
21
30
  export interface GlobalState {
31
+ hasNewVersion?: boolean;
32
+ latestVersion?: string;
22
33
  /**
23
34
  * 用户偏好的 UI 状态
24
35
  * @localStorage
@@ -33,15 +44,6 @@ export interface GlobalState {
33
44
  sidebarKey: SidebarTabKey;
34
45
  }
35
46
 
36
- export interface GlobalPreference {
37
- guide?: Guide;
38
- inputHeight: number;
39
- mobileShowTopic?: boolean;
40
- sessionsWidth: number;
41
- showChatSideBar?: boolean;
42
- showSessionPanel?: boolean;
43
- }
44
-
45
47
  export const initialState: GlobalState = {
46
48
  preference: {
47
49
  guide: {},
@@ -1,6 +1,10 @@
1
1
  import { produce } from 'immer';
2
+ import { gt } from 'semver';
3
+ import useSWR, { SWRResponse } from 'swr';
2
4
  import type { StateCreator } from 'zustand/vanilla';
3
5
 
6
+ import { CURRENT_VERSION } from '@/const/version';
7
+ import { featLatestVersion } from '@/services/latestVersion';
4
8
  import { merge } from '@/utils/merge';
5
9
  import { setNamespace } from '@/utils/storeDebug';
6
10
 
@@ -22,6 +26,7 @@ export interface CommonAction {
22
26
  toggleMobileTopic: (visible?: boolean) => void;
23
27
  updateGuideState: (guide: Partial<Guide>) => void;
24
28
  updatePreference: (preference: Partial<GlobalPreference>, action?: string) => void;
29
+ useCheckLatestVersion: () => SWRResponse<string>;
25
30
  }
26
31
 
27
32
  export const createCommonSlice: StateCreator<
@@ -59,4 +64,11 @@ export const createCommonSlice: StateCreator<
59
64
  action,
60
65
  );
61
66
  },
67
+ useCheckLatestVersion: () =>
68
+ useSWR('checkLatestVersion', featLatestVersion, {
69
+ onSuccess: (data: string) => {
70
+ if (gt(data, CURRENT_VERSION))
71
+ set({ hasNewVersion: true, latestVersion: data }, false, t('checkLatestVersion'));
72
+ },
73
+ }),
62
74
  });
@@ -33,7 +33,7 @@ export const initLobeSession: LobeAgentSession = {
33
33
 
34
34
  export const initInbox = merge({}, initLobeSession, {
35
35
  config: {
36
- systemRole: '你是一名 AI 助理',
36
+ systemRole: '',
37
37
  } as LobeAgentConfig,
38
38
  id: 'inbox',
39
39
  meta: {
@@ -42,7 +42,7 @@ export const initInbox = merge({}, initLobeSession, {
42
42
  } as Partial<LobeAgentSession>);
43
43
 
44
44
  export const initialSessionState: SessionState = {
45
- activeId: undefined,
45
+ activeId: 'inbox',
46
46
  inbox: initInbox,
47
47
  isMobile: false,
48
48
  searchKeywords: '',
package/.dockerignore DELETED
@@ -1,10 +0,0 @@
1
- Dockerfile
2
- .dockerignore
3
- node_modules
4
- npm-debug.log
5
- .next
6
- .git
7
- scripts
8
- docs
9
- .github
10
- *.md
package/Dockerfile DELETED
@@ -1,47 +0,0 @@
1
- FROM node:20-slim AS base
2
- ENV PNPM_HOME="/pnpm"
3
- ENV PATH="$PNPM_HOME:$PATH"
4
- RUN corepack enable
5
-
6
- ## Install dependencies only when needed
7
- FROM base AS builder
8
- WORKDIR /app
9
-
10
- COPY package.json ./
11
-
12
- RUN pnpm i -g bun
13
- # If you want to build docker in China
14
- #RUN npm config set registry https://registry.npmmirror.com/
15
- RUN bun i
16
-
17
- COPY . .
18
- RUN pnpm run build:docker # run build standalone for docker version
19
-
20
- ## Production image, copy all the files and run next
21
- FROM base AS runner
22
- WORKDIR /app
23
-
24
- ENV NODE_ENV production
25
-
26
- RUN addgroup --system --gid 1001 nodejs
27
- RUN adduser --system --uid 1001 nextjs
28
-
29
- COPY --from=builder /app/public ./public
30
-
31
- # Set the correct permission for prerender cache
32
- RUN mkdir .next
33
- RUN chown nextjs:nodejs .next
34
-
35
- # Automatically leverage output traces to reduce image size
36
- # https://nextjs.org/docs/advanced-features/output-file-tracing
37
- COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
38
- COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
39
-
40
- USER nextjs
41
-
42
- EXPOSE 3000
43
-
44
- # set hostname to localhost
45
- ENV HOSTNAME "0.0.0.0"
46
-
47
- CMD ["node", "server.js"]
@@ -1,14 +0,0 @@
1
- import { useResponsive } from 'antd-style';
2
- import { memo } from 'react';
3
-
4
- import Mobile from '../../../components/ChatHeader/Mobile';
5
- import Desktop from './Desktop';
6
-
7
- const Header = memo(() => {
8
- const { mobile } = useResponsive();
9
- const Render = mobile ? Mobile : Desktop;
10
-
11
- return <Render />;
12
- });
13
-
14
- export default Header;
@@ -1,22 +0,0 @@
1
- import { useResponsive } from 'antd-style';
2
- import { memo, useState } from 'react';
3
-
4
- import { ChatInputContent } from '../../../components/ChatInput';
5
- import Mobile from '../../../components/ChatInput/Mobile';
6
- import Desktop from './Desktop';
7
-
8
- const ChatInput = () => {
9
- const [expand, setExpand] = useState<boolean>(false);
10
-
11
- const { mobile } = useResponsive();
12
-
13
- const Render = mobile ? Mobile : Desktop;
14
-
15
- return (
16
- <Render expand={expand}>
17
- <ChatInputContent expand={expand} onExpandChange={setExpand} />
18
- </Render>
19
- );
20
- };
21
-
22
- export default memo(ChatInput);
@@ -1,14 +0,0 @@
1
- import { useResponsive } from 'antd-style';
2
- import { memo } from 'react';
3
-
4
- import Mobile from '../../../(mobile)/features/SessionHeader';
5
- import Desktop from './Desktop';
6
-
7
- const Header = memo(() => {
8
- const { mobile } = useResponsive();
9
- const Render = mobile ? Mobile : Desktop;
10
-
11
- return <Render />;
12
- });
13
-
14
- export default Header;
@@ -1,20 +0,0 @@
1
- import { useResponsive } from 'antd-style';
2
- import { memo } from 'react';
3
-
4
- import { SessionListContent } from '../../../components/SessionList';
5
- import Mobile from '../../../components/SessionList/Mobile';
6
- import Desktop from './Desktop';
7
-
8
- const ResponsiveSessionList = memo(() => {
9
- const { mobile } = useResponsive();
10
-
11
- const Wrapper = mobile ? Mobile : Desktop;
12
-
13
- return (
14
- <Wrapper>
15
- <SessionListContent />
16
- </Wrapper>
17
- );
18
- });
19
-
20
- export default ResponsiveSessionList;
@@ -1,20 +0,0 @@
1
- import { useResponsive } from 'antd-style';
2
- import { memo } from 'react';
3
-
4
- import { InspectorContent } from '../../../components/Inspector';
5
- import Mobile from '../../../components/Inspector/Mobile';
6
- import Desktop from './Desktop';
7
-
8
- const SideBar = memo(() => {
9
- const { mobile } = useResponsive();
10
-
11
- const Render = mobile ? Mobile : Desktop;
12
-
13
- return (
14
- <Render>
15
- <InspectorContent />
16
- </Render>
17
- );
18
- });
19
-
20
- export default SideBar;
@@ -1,25 +0,0 @@
1
- 'use client';
2
-
3
- import { useResponsive } from 'antd-style';
4
- import { PropsWithChildren, memo } from 'react';
5
-
6
- import { useEffectAfterSessionHydrated } from '@/store/session/hooks';
7
-
8
- import MobileLayout from '../../(mobile)/layout';
9
- import DesktopLayout from './Desktop';
10
-
11
- const Chat = memo<PropsWithChildren>(({ children }) => {
12
- const { mobile } = useResponsive();
13
-
14
- const RenderLayout = mobile ? MobileLayout : DesktopLayout;
15
-
16
- useEffectAfterSessionHydrated(
17
- (store) => {
18
- store.setState({ isMobile: mobile });
19
- },
20
- [mobile],
21
- );
22
-
23
- return <RenderLayout>{children}</RenderLayout>;
24
- });
25
- export default Chat;
@@ -1,12 +0,0 @@
1
- import { memo } from 'react';
2
-
3
- import { InspectorContent } from '../../components/Inspector';
4
- import Mobile from '../../components/Inspector/Mobile';
5
-
6
- const Topics = memo(() => (
7
- <Mobile>
8
- <InspectorContent />
9
- </Mobile>
10
- ));
11
-
12
- export default Topics;
@@ -1,15 +0,0 @@
1
- 'use client';
2
-
3
- import { PropsWithChildren, memo } from 'react';
4
-
5
- import { useEffectAfterSessionHydrated } from '@/store/session';
6
-
7
- const ChatMobileLayout = memo<PropsWithChildren>(({ children }) => {
8
- useEffectAfterSessionHydrated((store) => {
9
- store.setState({ isMobile: true });
10
- }, []);
11
-
12
- return children;
13
- });
14
-
15
- export default ChatMobileLayout;