@lobehub/lobehub 2.0.0-next.333 → 2.0.0-next.334
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 +25 -0
- package/changelog/v1.json +9 -0
- package/locales/ar/common.json +1 -0
- package/locales/bg-BG/common.json +1 -0
- package/locales/de-DE/common.json +1 -0
- package/locales/en-US/common.json +1 -0
- package/locales/es-ES/common.json +1 -0
- package/locales/fa-IR/common.json +1 -0
- package/locales/fr-FR/common.json +1 -0
- package/locales/it-IT/common.json +1 -0
- package/locales/ja-JP/common.json +1 -0
- package/locales/ko-KR/common.json +1 -0
- package/locales/nl-NL/common.json +1 -0
- package/locales/pl-PL/common.json +1 -0
- package/locales/pt-BR/common.json +1 -0
- package/locales/ru-RU/common.json +1 -0
- package/locales/tr-TR/common.json +1 -0
- package/locales/vi-VN/common.json +1 -0
- package/locales/zh-CN/common.json +1 -0
- package/locales/zh-TW/common.json +1 -0
- package/package.json +1 -1
- package/packages/const/src/url.ts +6 -0
- package/src/app/[variants]/(mobile)/me/(home)/features/useCategory.tsx +16 -9
- package/src/app/[variants]/layout.tsx +0 -4
- package/src/features/User/UserPanel/useMenu.tsx +18 -9
- package/src/hooks/usePlatform.test.ts +5 -0
- package/src/hooks/usePlatform.ts +1 -0
- package/src/locales/default/common.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,31 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
## [Version 2.0.0-next.334](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.333...v2.0.0-next.334)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2026-01-21**</sup>
|
|
8
|
+
|
|
9
|
+
#### ✨ Features
|
|
10
|
+
|
|
11
|
+
- **misc**: Add platform-aware download client menu option.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### What's improved
|
|
19
|
+
|
|
20
|
+
- **misc**: Add platform-aware download client menu option, closes [#11676](https://github.com/lobehub/lobe-chat/issues/11676) ([55abddc](https://github.com/lobehub/lobe-chat/commit/55abddc))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
5
30
|
## [Version 2.0.0-next.333](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.332...v2.0.0-next.333)
|
|
6
31
|
|
|
7
32
|
<sup>Released on **2026-01-21**</sup>
|
package/changelog/v1.json
CHANGED
package/locales/ar/common.json
CHANGED
|
@@ -179,6 +179,7 @@
|
|
|
179
179
|
"delete": "Löschen",
|
|
180
180
|
"document": "Benutzerhandbuch",
|
|
181
181
|
"download": "Herunterladen",
|
|
182
|
+
"downloadClient": "Client herunterladen",
|
|
182
183
|
"duplicate": "Duplizieren",
|
|
183
184
|
"edit": "Bearbeiten",
|
|
184
185
|
"errors.invalidFileFormat": "Ungültiges Dateiformat",
|
|
@@ -179,6 +179,7 @@
|
|
|
179
179
|
"delete": "Supprimer",
|
|
180
180
|
"document": "Manuel utilisateur",
|
|
181
181
|
"download": "Télécharger",
|
|
182
|
+
"downloadClient": "Télécharger le client",
|
|
182
183
|
"duplicate": "Dupliquer",
|
|
183
184
|
"edit": "Modifier",
|
|
184
185
|
"errors.invalidFileFormat": "Format de fichier invalide",
|
|
@@ -179,6 +179,7 @@
|
|
|
179
179
|
"delete": "Verwijderen",
|
|
180
180
|
"document": "Gebruikershandleiding",
|
|
181
181
|
"download": "Downloaden",
|
|
182
|
+
"downloadClient": "Client downloaden",
|
|
182
183
|
"duplicate": "Dupliceren",
|
|
183
184
|
"edit": "Bewerken",
|
|
184
185
|
"errors.invalidFileFormat": "Ongeldig bestandsformaat",
|
|
@@ -179,6 +179,7 @@
|
|
|
179
179
|
"delete": "Удалить",
|
|
180
180
|
"document": "Руководство пользователя",
|
|
181
181
|
"download": "Скачать",
|
|
182
|
+
"downloadClient": "Скачать клиент",
|
|
182
183
|
"duplicate": "Дублировать",
|
|
183
184
|
"edit": "Редактировать",
|
|
184
185
|
"errors.invalidFileFormat": "Недопустимый формат файла",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/lobehub",
|
|
3
|
-
"version": "2.0.0-next.
|
|
3
|
+
"version": "2.0.0-next.334",
|
|
4
4
|
"description": "LobeHub - an open-source,comprehensive AI Agent framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"framework",
|
|
@@ -63,3 +63,9 @@ export const AES_GCM_URL = 'https://datatracker.ietf.org/doc/html/draft-ietf-avt
|
|
|
63
63
|
export const BASE_PROVIDER_DOC_URL = 'https://lobehub.com/docs/usage/providers';
|
|
64
64
|
export const SITEMAP_BASE_URL = isDev ? '/sitemap.xml/' : 'sitemap';
|
|
65
65
|
export const CHANGELOG_URL = urlJoin(OFFICIAL_SITE, 'changelog/versions');
|
|
66
|
+
|
|
67
|
+
export const DOWNLOAD_URL = {
|
|
68
|
+
android: 'https://play.google.com/store/apps/details?id=com.lobehub.app',
|
|
69
|
+
default: urlJoin(OFFICIAL_SITE, '/download'),
|
|
70
|
+
ios: 'https://testflight.apple.com/join/2ZbjX4Qp',
|
|
71
|
+
} as const;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { OFFICIAL_URL } from '@lobechat/const';
|
|
1
|
+
import { LOBE_CHAT_CLOUD, UTM_SOURCE } from '@lobechat/business-const';
|
|
2
|
+
import { DOWNLOAD_URL, OFFICIAL_URL } from '@lobechat/const';
|
|
3
3
|
import {
|
|
4
4
|
Book,
|
|
5
5
|
CircleUserRound,
|
|
@@ -9,22 +9,29 @@ import {
|
|
|
9
9
|
FileClockIcon,
|
|
10
10
|
Settings2,
|
|
11
11
|
} from 'lucide-react';
|
|
12
|
+
import { useMemo } from 'react';
|
|
12
13
|
import { useTranslation } from 'react-i18next';
|
|
13
14
|
import { useNavigate } from 'react-router-dom';
|
|
14
15
|
|
|
15
16
|
import { type CellProps } from '@/components/Cell';
|
|
16
17
|
import { DOCUMENTS, FEEDBACK } from '@/const/index';
|
|
17
|
-
import {
|
|
18
|
+
import { usePlatform } from '@/hooks/usePlatform';
|
|
18
19
|
import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
|
|
19
20
|
import { useUserStore } from '@/store/user';
|
|
20
21
|
import { authSelectors } from '@/store/user/selectors';
|
|
21
22
|
|
|
22
23
|
export const useCategory = (onOpenChangelogModal: () => void) => {
|
|
23
24
|
const navigate = useNavigate();
|
|
24
|
-
const { canInstall, install } = usePWAInstall();
|
|
25
25
|
const { t } = useTranslation(['common', 'setting', 'auth']);
|
|
26
26
|
const { showCloudPromotion, hideDocs } = useServerConfigStore(featureFlagsSelectors);
|
|
27
27
|
const [isLoginWithAuth] = useUserStore((s) => [authSelectors.isLoginWithAuth(s)]);
|
|
28
|
+
const { isIOS, isAndroid } = usePlatform();
|
|
29
|
+
|
|
30
|
+
const downloadUrl = useMemo(() => {
|
|
31
|
+
if (isIOS) return DOWNLOAD_URL.ios;
|
|
32
|
+
if (isAndroid) return DOWNLOAD_URL.android;
|
|
33
|
+
return DOWNLOAD_URL.default;
|
|
34
|
+
}, [isIOS, isAndroid]);
|
|
28
35
|
|
|
29
36
|
const profile: CellProps[] = [
|
|
30
37
|
{
|
|
@@ -47,12 +54,12 @@ export const useCategory = (onOpenChangelogModal: () => void) => {
|
|
|
47
54
|
},
|
|
48
55
|
];
|
|
49
56
|
|
|
50
|
-
const
|
|
57
|
+
const downloadClient: CellProps[] = [
|
|
51
58
|
{
|
|
52
59
|
icon: Download,
|
|
53
|
-
key: '
|
|
54
|
-
label: t('
|
|
55
|
-
onClick: () =>
|
|
60
|
+
key: 'download-client',
|
|
61
|
+
label: t('downloadClient'),
|
|
62
|
+
onClick: () => window.open(downloadUrl, '__blank'),
|
|
56
63
|
},
|
|
57
64
|
{
|
|
58
65
|
type: 'divider',
|
|
@@ -96,7 +103,7 @@ export const useCategory = (onOpenChangelogModal: () => void) => {
|
|
|
96
103
|
/* ↓ cloud slot ↓ */
|
|
97
104
|
|
|
98
105
|
/* ↑ cloud slot ↑ */
|
|
99
|
-
...
|
|
106
|
+
...downloadClient,
|
|
100
107
|
...(!hideDocs ? helps : []),
|
|
101
108
|
].filter(Boolean) as CellProps[];
|
|
102
109
|
|
|
@@ -9,7 +9,6 @@ import BusinessGlobalProvider from '@/business/client/BusinessGlobalProvider';
|
|
|
9
9
|
import Analytics from '@/components/Analytics';
|
|
10
10
|
import { DEFAULT_LANG } from '@/const/locale';
|
|
11
11
|
import { isDesktop } from '@/const/version';
|
|
12
|
-
import PWAInstall from '@/features/PWAInstall';
|
|
13
12
|
import AuthProvider from '@/layout/AuthProvider';
|
|
14
13
|
import GlobalProvider from '@/layout/GlobalProvider';
|
|
15
14
|
import { type Locales } from '@/locales/resources';
|
|
@@ -40,9 +39,6 @@ const RootLayout = async ({ children, params }: RootLayoutProps) => {
|
|
|
40
39
|
variants={variants}
|
|
41
40
|
>
|
|
42
41
|
<AuthProvider>{children}</AuthProvider>
|
|
43
|
-
<Suspense fallback={null}>
|
|
44
|
-
<PWAInstall />
|
|
45
|
-
</Suspense>
|
|
46
42
|
</GlobalProvider>
|
|
47
43
|
);
|
|
48
44
|
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { LOBE_CHAT_CLOUD, UTM_SOURCE } from '@lobechat/business-const';
|
|
2
|
-
import { isDesktop } from '@lobechat/const';
|
|
2
|
+
import { DOWNLOAD_URL, isDesktop } from '@lobechat/const';
|
|
3
3
|
import { Flexbox, Hotkey, Icon, Tag } from '@lobehub/ui';
|
|
4
4
|
import { type ItemType } from 'antd/es/menu/interface';
|
|
5
5
|
import { Cloudy, Download, HardDriveDownload, LogOut, Settings2 } from 'lucide-react';
|
|
6
|
-
import { type PropsWithChildren, memo } from 'react';
|
|
6
|
+
import { type PropsWithChildren, memo, useMemo } from 'react';
|
|
7
7
|
import { useTranslation } from 'react-i18next';
|
|
8
8
|
import { Link } from 'react-router-dom';
|
|
9
9
|
|
|
@@ -12,7 +12,7 @@ import type { MenuProps } from '@/components/Menu';
|
|
|
12
12
|
import { DEFAULT_DESKTOP_HOTKEY_CONFIG } from '@/const/desktop';
|
|
13
13
|
import { OFFICIAL_URL } from '@/const/url';
|
|
14
14
|
import DataImporter from '@/features/DataImporter';
|
|
15
|
-
import {
|
|
15
|
+
import { usePlatform } from '@/hooks/usePlatform';
|
|
16
16
|
import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
|
|
17
17
|
import { useUserStore } from '@/store/user';
|
|
18
18
|
import { authSelectors } from '@/store/user/selectors';
|
|
@@ -44,7 +44,6 @@ const NewVersionBadge = memo(
|
|
|
44
44
|
);
|
|
45
45
|
|
|
46
46
|
export const useMenu = () => {
|
|
47
|
-
const { canInstall, install } = usePWAInstall();
|
|
48
47
|
const hasNewVersion = useNewVersion();
|
|
49
48
|
const { t } = useTranslation(['common', 'setting', 'auth']);
|
|
50
49
|
const { showCloudPromotion, hideDocs } = useServerConfigStore(featureFlagsSelectors);
|
|
@@ -53,6 +52,13 @@ export const useMenu = () => {
|
|
|
53
52
|
authSelectors.isLoginWithAuth(s),
|
|
54
53
|
]);
|
|
55
54
|
const businessMenuItems = useBusinessMenuItems(isLogin);
|
|
55
|
+
const { isIOS, isAndroid } = usePlatform();
|
|
56
|
+
|
|
57
|
+
const downloadUrl = useMemo(() => {
|
|
58
|
+
if (isIOS) return DOWNLOAD_URL.ios;
|
|
59
|
+
if (isAndroid) return DOWNLOAD_URL.android;
|
|
60
|
+
return DOWNLOAD_URL.default;
|
|
61
|
+
}, [isIOS, isAndroid]);
|
|
56
62
|
|
|
57
63
|
const settings: MenuProps['items'] = [
|
|
58
64
|
{
|
|
@@ -71,12 +77,15 @@ export const useMenu = () => {
|
|
|
71
77
|
},
|
|
72
78
|
];
|
|
73
79
|
|
|
74
|
-
const
|
|
80
|
+
const downloadClient: MenuProps['items'] = [
|
|
75
81
|
{
|
|
76
82
|
icon: <Icon icon={Download} />,
|
|
77
|
-
key: '
|
|
78
|
-
label:
|
|
79
|
-
|
|
83
|
+
key: 'download-client',
|
|
84
|
+
label: (
|
|
85
|
+
<a href={downloadUrl} rel="noopener noreferrer" target="_blank">
|
|
86
|
+
{t('downloadClient')}
|
|
87
|
+
</a>
|
|
88
|
+
),
|
|
80
89
|
},
|
|
81
90
|
{
|
|
82
91
|
type: 'divider',
|
|
@@ -119,7 +128,7 @@ export const useMenu = () => {
|
|
|
119
128
|
|
|
120
129
|
...(isLogin ? settings : []),
|
|
121
130
|
...businessMenuItems,
|
|
122
|
-
...(
|
|
131
|
+
...(!isDesktop ? downloadClient : []),
|
|
123
132
|
...data,
|
|
124
133
|
...(!hideDocs ? helps : []),
|
|
125
134
|
].filter(Boolean) as MenuProps['items'];
|
|
@@ -25,6 +25,7 @@ describe('usePlatform', () => {
|
|
|
25
25
|
const { result } = renderHook(() => usePlatform());
|
|
26
26
|
|
|
27
27
|
expect(result.current).toEqual({
|
|
28
|
+
isAndroid: false,
|
|
28
29
|
isApple: true,
|
|
29
30
|
isChrome: true,
|
|
30
31
|
isChromium: true,
|
|
@@ -50,6 +51,7 @@ describe('usePlatform', () => {
|
|
|
50
51
|
const { result } = renderHook(() => usePlatform());
|
|
51
52
|
|
|
52
53
|
expect(result.current).toEqual({
|
|
54
|
+
isAndroid: false,
|
|
53
55
|
isApple: true,
|
|
54
56
|
isChrome: false,
|
|
55
57
|
isChromium: false,
|
|
@@ -75,6 +77,7 @@ describe('usePlatform', () => {
|
|
|
75
77
|
const { result } = renderHook(() => usePlatform());
|
|
76
78
|
|
|
77
79
|
expect(result.current).toEqual({
|
|
80
|
+
isAndroid: false,
|
|
78
81
|
isApple: false,
|
|
79
82
|
isChrome: false,
|
|
80
83
|
isChromium: true,
|
|
@@ -100,6 +103,7 @@ describe('usePlatform', () => {
|
|
|
100
103
|
const { result } = renderHook(() => usePlatform());
|
|
101
104
|
|
|
102
105
|
expect(result.current).toEqual({
|
|
106
|
+
isAndroid: false,
|
|
103
107
|
isApple: false,
|
|
104
108
|
isChrome: false,
|
|
105
109
|
isChromium: false,
|
|
@@ -125,6 +129,7 @@ describe('usePlatform', () => {
|
|
|
125
129
|
const { result } = renderHook(() => usePlatform());
|
|
126
130
|
|
|
127
131
|
expect(result.current).toEqual({
|
|
132
|
+
isAndroid: false,
|
|
128
133
|
isApple: true,
|
|
129
134
|
isChrome: true,
|
|
130
135
|
isChromium: true,
|
package/src/hooks/usePlatform.ts
CHANGED
|
@@ -13,6 +13,7 @@ export const usePlatform = () => {
|
|
|
13
13
|
const browser = useRef(getBrowser());
|
|
14
14
|
|
|
15
15
|
const platformInfo = {
|
|
16
|
+
isAndroid: platform.current?.toLowerCase() === 'android',
|
|
16
17
|
isApple: platform.current && ['mac os', 'ios'].includes(platform.current?.toLowerCase()),
|
|
17
18
|
isArc: isArc(),
|
|
18
19
|
isChrome: browser.current?.toLowerCase() === 'chrome',
|