@lobehub/chat 0.158.0 → 0.158.2
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 +50 -0
- package/locales/ar/common.json +1 -0
- package/locales/ar/metadata.json +18 -0
- package/locales/ar/plugin.json +5 -6
- package/locales/ar/tool.json +2 -1
- package/locales/bg-BG/common.json +1 -0
- package/locales/bg-BG/metadata.json +18 -0
- package/locales/bg-BG/plugin.json +5 -6
- package/locales/bg-BG/tool.json +2 -1
- package/locales/de-DE/common.json +1 -0
- package/locales/de-DE/metadata.json +18 -0
- package/locales/de-DE/plugin.json +5 -6
- package/locales/de-DE/tool.json +2 -1
- package/locales/en-US/common.json +2 -1
- package/locales/en-US/metadata.json +18 -0
- package/locales/en-US/plugin.json +5 -6
- package/locales/en-US/tool.json +2 -1
- package/locales/es-ES/common.json +1 -0
- package/locales/es-ES/metadata.json +18 -0
- package/locales/es-ES/plugin.json +5 -6
- package/locales/es-ES/tool.json +2 -1
- package/locales/fr-FR/common.json +1 -0
- package/locales/fr-FR/metadata.json +18 -0
- package/locales/fr-FR/plugin.json +5 -6
- package/locales/fr-FR/tool.json +2 -1
- package/locales/it-IT/common.json +1 -0
- package/locales/it-IT/metadata.json +18 -0
- package/locales/it-IT/plugin.json +5 -6
- package/locales/it-IT/tool.json +2 -1
- package/locales/ja-JP/common.json +1 -0
- package/locales/ja-JP/metadata.json +18 -0
- package/locales/ja-JP/plugin.json +5 -6
- package/locales/ja-JP/tool.json +2 -1
- package/locales/ko-KR/common.json +1 -0
- package/locales/ko-KR/metadata.json +18 -0
- package/locales/ko-KR/plugin.json +5 -6
- package/locales/ko-KR/tool.json +2 -1
- package/locales/nl-NL/common.json +1 -0
- package/locales/nl-NL/metadata.json +18 -0
- package/locales/nl-NL/plugin.json +63 -64
- package/locales/nl-NL/tool.json +2 -1
- package/locales/pl-PL/common.json +1 -0
- package/locales/pl-PL/metadata.json +18 -0
- package/locales/pl-PL/plugin.json +98 -99
- package/locales/pl-PL/tool.json +2 -1
- package/locales/pt-BR/common.json +1 -0
- package/locales/pt-BR/metadata.json +18 -0
- package/locales/pt-BR/plugin.json +5 -6
- package/locales/pt-BR/tool.json +2 -1
- package/locales/ru-RU/common.json +1 -0
- package/locales/ru-RU/metadata.json +18 -0
- package/locales/ru-RU/plugin.json +5 -6
- package/locales/ru-RU/tool.json +2 -1
- package/locales/tr-TR/common.json +1 -0
- package/locales/tr-TR/metadata.json +18 -0
- package/locales/tr-TR/plugin.json +5 -6
- package/locales/tr-TR/tool.json +2 -1
- package/locales/vi-VN/common.json +1 -0
- package/locales/vi-VN/metadata.json +18 -0
- package/locales/vi-VN/plugin.json +5 -6
- package/locales/vi-VN/tool.json +2 -1
- package/locales/zh-CN/common.json +1 -0
- package/locales/zh-CN/metadata.json +18 -0
- package/locales/zh-CN/plugin.json +5 -6
- package/locales/zh-CN/tool.json +2 -1
- package/locales/zh-TW/common.json +1 -0
- package/locales/zh-TW/metadata.json +18 -0
- package/locales/zh-TW/plugin.json +5 -6
- package/locales/zh-TW/tool.json +2 -1
- package/package.json +2 -1
- package/public/manifest.json +76 -16
- package/public/og/cover.png +0 -0
- package/public/screenshots/shot-1.desktop.png +0 -0
- package/public/screenshots/shot-1.mobile.png +0 -0
- package/public/screenshots/shot-2.desktop.png +0 -0
- package/public/screenshots/shot-2.mobile.png +0 -0
- package/public/screenshots/shot-3.desktop.png +0 -0
- package/public/screenshots/shot-3.mobile.png +0 -0
- package/public/screenshots/shot-4.desktop.png +0 -0
- package/public/screenshots/shot-4.mobile.png +0 -0
- package/public/screenshots/shot-5.desktop.png +0 -0
- package/public/screenshots/shot-5.mobile.png +0 -0
- package/src/app/(auth)/login/[[...login]]/page.tsx +14 -7
- package/src/app/(auth)/signup/[[...signup]]/page.tsx +14 -7
- package/src/app/(main)/(mobile)/me/(home)/features/useCategory.tsx +16 -1
- package/src/app/(main)/(mobile)/me/(home)/page.tsx +10 -0
- package/src/app/(main)/(mobile)/me/data/page.tsx +10 -0
- package/src/app/(main)/(mobile)/me/profile/page.tsx +11 -0
- package/src/app/(main)/(mobile)/me/settings/page.tsx +11 -0
- package/src/app/(main)/chat/(workspace)/features/TelemetryNotification.tsx +1 -1
- package/src/app/(main)/chat/(workspace)/page.tsx +21 -1
- package/src/app/(main)/market/page.tsx +17 -8
- package/src/app/(main)/profile/[[...slugs]]/page.tsx +7 -4
- package/src/app/(main)/settings/about/page.tsx +5 -2
- package/src/app/(main)/settings/agent/page.tsx +5 -3
- package/src/app/(main)/settings/common/page.tsx +5 -3
- package/src/app/(main)/settings/llm/page.tsx +5 -2
- package/src/app/(main)/settings/sync/page.tsx +5 -3
- package/src/app/(main)/settings/tts/page.tsx +5 -3
- package/src/app/(main)/welcome/page.tsx +19 -6
- package/src/app/layout.tsx +1 -1
- package/src/app/metadata.ts +44 -54
- package/src/app/page.tsx +4 -4
- package/src/components/StructuredData/index.tsx +12 -0
- package/src/features/User/UserPanel/useMenu.tsx +16 -0
- package/src/hooks/usePWAInstall.ts +18 -0
- package/src/locales/default/common.ts +2 -1
- package/src/locales/default/index.ts +2 -0
- package/src/locales/default/metadata.ts +20 -0
- package/src/server/ld.ts +218 -0
- package/src/server/metadata.ts +96 -0
- package/src/server/translation.ts +11 -1
- package/src/utils/genOG.ts +20 -0
- package/public/screenshots/screenshot-1.png +0 -0
- package/public/screenshots/screenshot-2.png +0 -0
- package/public/screenshots/screenshot-3.png +0 -0
- package/public/screenshots/screenshot-4.png +0 -0
- package/src/app/(auth)/login/[[...login]]/PageTitle.tsx +0 -13
- package/src/app/(auth)/signup/[[...signup]]/PageTitle.tsx +0 -13
- /package/public/icons/{maskable-icon-192x192.png → icon-192x192.maskable.png} +0 -0
- /package/public/icons/{maskable-icon-512x512.png → icon-512x512.maskable.png} +0 -0
|
@@ -2,11 +2,21 @@ import { redirect } from 'next/navigation';
|
|
|
2
2
|
import { Center } from 'react-layout-kit';
|
|
3
3
|
|
|
4
4
|
import BrandWatermark from '@/components/BrandWatermark';
|
|
5
|
+
import { metadataModule } from '@/server/metadata';
|
|
6
|
+
import { translation } from '@/server/translation';
|
|
5
7
|
import { isMobileDevice } from '@/utils/responsive';
|
|
6
8
|
|
|
7
9
|
import Category from './features/Category';
|
|
8
10
|
import UserBanner from './features/UserBanner';
|
|
9
11
|
|
|
12
|
+
export const generateMetadata = async () => {
|
|
13
|
+
const { t } = await translation('common');
|
|
14
|
+
return metadataModule.generate({
|
|
15
|
+
title: t('tab.me'),
|
|
16
|
+
url: '/me',
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
|
|
10
20
|
const Page = () => {
|
|
11
21
|
const mobile = isMobileDevice();
|
|
12
22
|
|
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
import { redirect } from 'next/navigation';
|
|
2
2
|
|
|
3
|
+
import { metadataModule } from '@/server/metadata';
|
|
4
|
+
import { translation } from '@/server/translation';
|
|
3
5
|
import { isMobileDevice } from '@/utils/responsive';
|
|
4
6
|
|
|
5
7
|
import Category from './features/Category';
|
|
6
8
|
|
|
9
|
+
export const generateMetadata = async () => {
|
|
10
|
+
const { t } = await translation('common');
|
|
11
|
+
return metadataModule.generate({
|
|
12
|
+
title: t('userPanel.data'),
|
|
13
|
+
url: '/me/data',
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
|
|
7
17
|
const Page = () => {
|
|
8
18
|
const mobile = isMobileDevice();
|
|
9
19
|
|
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
import { redirect } from 'next/navigation';
|
|
2
2
|
|
|
3
|
+
import { metadataModule } from '@/server/metadata';
|
|
4
|
+
import { translation } from '@/server/translation';
|
|
3
5
|
import { isMobileDevice } from '@/utils/responsive';
|
|
4
6
|
|
|
5
7
|
import Category from './features/Category';
|
|
6
8
|
|
|
9
|
+
export const generateMetadata = async () => {
|
|
10
|
+
const { t } = await translation('clerk');
|
|
11
|
+
return metadataModule.generate({
|
|
12
|
+
description: t('userProfile.navbar.title'),
|
|
13
|
+
title: t('userProfile.navbar.description'),
|
|
14
|
+
url: '/me/profile',
|
|
15
|
+
});
|
|
16
|
+
};
|
|
17
|
+
|
|
7
18
|
const Page = () => {
|
|
8
19
|
const mobile = isMobileDevice();
|
|
9
20
|
|
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
import { redirect } from 'next/navigation';
|
|
2
2
|
|
|
3
|
+
import { metadataModule } from '@/server/metadata';
|
|
4
|
+
import { translation } from '@/server/translation';
|
|
3
5
|
import { isMobileDevice } from '@/utils/responsive';
|
|
4
6
|
|
|
5
7
|
import Category from './features/Category';
|
|
6
8
|
|
|
9
|
+
export const generateMetadata = async () => {
|
|
10
|
+
const { t } = await translation('setting');
|
|
11
|
+
return metadataModule.generate({
|
|
12
|
+
description: t('header.desc'),
|
|
13
|
+
title: t('header.title'),
|
|
14
|
+
url: '/me/settings',
|
|
15
|
+
});
|
|
16
|
+
};
|
|
17
|
+
|
|
7
18
|
const Page = () => {
|
|
8
19
|
const mobile = isMobileDevice();
|
|
9
20
|
|
|
@@ -1,13 +1,33 @@
|
|
|
1
|
+
import StructuredData from '@/components/StructuredData';
|
|
2
|
+
import { ldModule } from '@/server/ld';
|
|
3
|
+
import { metadataModule } from '@/server/metadata';
|
|
4
|
+
import { translation } from '@/server/translation';
|
|
1
5
|
import { isMobileDevice } from '@/utils/responsive';
|
|
2
6
|
|
|
3
7
|
import PageTitle from '../features/PageTitle';
|
|
4
8
|
import TelemetryNotification from './features/TelemetryNotification';
|
|
5
9
|
|
|
6
|
-
const
|
|
10
|
+
export const generateMetadata = async () => {
|
|
11
|
+
const { t } = await translation('metadata');
|
|
12
|
+
return metadataModule.generate({
|
|
13
|
+
description: t('chat.description'),
|
|
14
|
+
title: t('chat.title'),
|
|
15
|
+
url: '/chat',
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const Page = async () => {
|
|
7
20
|
const mobile = isMobileDevice();
|
|
21
|
+
const { t } = await translation('metadata');
|
|
22
|
+
const ld = ldModule.generate({
|
|
23
|
+
description: t('chat.description'),
|
|
24
|
+
title: t('chat.title'),
|
|
25
|
+
url: '/chat',
|
|
26
|
+
});
|
|
8
27
|
|
|
9
28
|
return (
|
|
10
29
|
<>
|
|
30
|
+
<StructuredData ld={ld} />
|
|
11
31
|
<PageTitle />
|
|
12
32
|
<TelemetryNotification mobile={mobile} />
|
|
13
33
|
</>
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { Flexbox } from 'react-layout-kit';
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import StructuredData from '@/components/StructuredData';
|
|
4
|
+
import { ldModule } from '@/server/ld';
|
|
5
|
+
import { metadataModule } from '@/server/metadata';
|
|
4
6
|
import { translation } from '@/server/translation';
|
|
5
7
|
import { isMobileDevice } from '@/utils/responsive';
|
|
6
8
|
|
|
@@ -9,18 +11,25 @@ import AgentSearchBar from './features/AgentSearchBar';
|
|
|
9
11
|
import TagList from './features/TagList';
|
|
10
12
|
|
|
11
13
|
export const generateMetadata = async () => {
|
|
12
|
-
const { t } = await translation('
|
|
13
|
-
return {
|
|
14
|
-
|
|
15
|
-
title: t('
|
|
16
|
-
|
|
14
|
+
const { t } = await translation('metadata');
|
|
15
|
+
return metadataModule.generate({
|
|
16
|
+
description: t('market.description'),
|
|
17
|
+
title: t('market.title'),
|
|
18
|
+
url: '/market',
|
|
19
|
+
});
|
|
17
20
|
};
|
|
18
21
|
|
|
19
|
-
const Page = () => {
|
|
22
|
+
const Page = async () => {
|
|
20
23
|
const mobile = isMobileDevice();
|
|
21
|
-
|
|
24
|
+
const { t } = await translation('metadata');
|
|
25
|
+
const ld = ldModule.generate({
|
|
26
|
+
description: t('market.description'),
|
|
27
|
+
title: t('market.title'),
|
|
28
|
+
url: '/market',
|
|
29
|
+
});
|
|
22
30
|
return (
|
|
23
31
|
<>
|
|
32
|
+
<StructuredData ld={ld} />
|
|
24
33
|
<AgentSearchBar mobile={mobile} />
|
|
25
34
|
<Flexbox gap={mobile ? 16 : 24}>
|
|
26
35
|
<TagList />
|
|
@@ -1,13 +1,16 @@
|
|
|
1
|
+
import { metadataModule } from '@/server/metadata';
|
|
1
2
|
import { translation } from '@/server/translation';
|
|
2
3
|
import { isMobileDevice } from '@/utils/responsive';
|
|
3
4
|
|
|
4
5
|
import Client from './Client';
|
|
5
6
|
|
|
6
7
|
export const generateMetadata = async () => {
|
|
7
|
-
const { t } = await translation('
|
|
8
|
-
return {
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
const { t } = await translation('clerk');
|
|
9
|
+
return metadataModule.generate({
|
|
10
|
+
description: t('userProfile.navbar.title'),
|
|
11
|
+
title: t('userProfile.navbar.description'),
|
|
12
|
+
url: '/profile',
|
|
13
|
+
});
|
|
11
14
|
};
|
|
12
15
|
|
|
13
16
|
const Page = () => {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { metadataModule } from '@/server/metadata';
|
|
1
2
|
import { translation } from '@/server/translation';
|
|
2
3
|
import { isMobileDevice } from '@/utils/responsive';
|
|
3
4
|
|
|
@@ -5,9 +6,11 @@ import Page from './index';
|
|
|
5
6
|
|
|
6
7
|
export const generateMetadata = async () => {
|
|
7
8
|
const { t } = await translation('setting');
|
|
8
|
-
return {
|
|
9
|
+
return metadataModule.generate({
|
|
10
|
+
description: t('header.desc'),
|
|
9
11
|
title: t('tab.about'),
|
|
10
|
-
|
|
12
|
+
url: '/settings/about',
|
|
13
|
+
});
|
|
11
14
|
};
|
|
12
15
|
|
|
13
16
|
export default () => {
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import { metadataModule } from '@/server/metadata';
|
|
1
2
|
import { translation } from '@/server/translation';
|
|
2
3
|
|
|
3
4
|
export const generateMetadata = async () => {
|
|
4
5
|
const { t } = await translation('setting');
|
|
5
|
-
return {
|
|
6
|
+
return metadataModule.generate({
|
|
7
|
+
description: t('header.desc'),
|
|
6
8
|
title: t('tab.agent'),
|
|
7
|
-
|
|
9
|
+
url: '/settings/agent',
|
|
10
|
+
});
|
|
8
11
|
};
|
|
9
|
-
|
|
10
12
|
export { default } from './index';
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import { metadataModule } from '@/server/metadata';
|
|
1
2
|
import { translation } from '@/server/translation';
|
|
2
3
|
|
|
3
4
|
export const generateMetadata = async () => {
|
|
4
5
|
const { t } = await translation('setting');
|
|
5
|
-
return {
|
|
6
|
+
return metadataModule.generate({
|
|
7
|
+
description: t('header.desc'),
|
|
6
8
|
title: t('tab.common'),
|
|
7
|
-
|
|
9
|
+
url: '/settings/common',
|
|
10
|
+
});
|
|
8
11
|
};
|
|
9
|
-
|
|
10
12
|
export { default } from './index';
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { notFound } from 'next/navigation';
|
|
2
2
|
|
|
3
3
|
import { serverFeatureFlags } from '@/config/server/featureFlags';
|
|
4
|
+
import { metadataModule } from '@/server/metadata';
|
|
4
5
|
import { translation } from '@/server/translation';
|
|
5
6
|
|
|
6
7
|
import Page from './index';
|
|
7
8
|
|
|
8
9
|
export const generateMetadata = async () => {
|
|
9
10
|
const { t } = await translation('setting');
|
|
10
|
-
return {
|
|
11
|
+
return metadataModule.generate({
|
|
12
|
+
description: t('header.desc'),
|
|
11
13
|
title: t('tab.llm'),
|
|
12
|
-
|
|
14
|
+
url: '/settings/llm',
|
|
15
|
+
});
|
|
13
16
|
};
|
|
14
17
|
|
|
15
18
|
export default () => {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { notFound } from 'next/navigation';
|
|
2
2
|
|
|
3
3
|
import { serverFeatureFlags } from '@/config/server/featureFlags';
|
|
4
|
+
import { metadataModule } from '@/server/metadata';
|
|
4
5
|
import { translation } from '@/server/translation';
|
|
5
6
|
import { gerServerDeviceInfo, isMobileDevice } from '@/utils/responsive';
|
|
6
7
|
|
|
@@ -8,11 +9,12 @@ import Page from './index';
|
|
|
8
9
|
|
|
9
10
|
export const generateMetadata = async () => {
|
|
10
11
|
const { t } = await translation('setting');
|
|
11
|
-
return {
|
|
12
|
+
return metadataModule.generate({
|
|
13
|
+
description: t('header.desc'),
|
|
12
14
|
title: t('tab.sync'),
|
|
13
|
-
|
|
15
|
+
url: '/settings/sync',
|
|
16
|
+
});
|
|
14
17
|
};
|
|
15
|
-
|
|
16
18
|
export default () => {
|
|
17
19
|
const enableWebrtc = serverFeatureFlags().enableWebrtc;
|
|
18
20
|
if (!enableWebrtc) return notFound();
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import { metadataModule } from '@/server/metadata';
|
|
1
2
|
import { translation } from '@/server/translation';
|
|
2
3
|
|
|
3
4
|
export const generateMetadata = async () => {
|
|
4
5
|
const { t } = await translation('setting');
|
|
5
|
-
return {
|
|
6
|
+
return metadataModule.generate({
|
|
7
|
+
description: t('header.desc'),
|
|
6
8
|
title: t('tab.tts'),
|
|
7
|
-
|
|
9
|
+
url: '/settings/tts',
|
|
10
|
+
});
|
|
8
11
|
};
|
|
9
|
-
|
|
10
12
|
export { default } from './index';
|
|
@@ -1,21 +1,34 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import {
|
|
1
|
+
import StructuredData from '@/components/StructuredData';
|
|
2
|
+
import { ldModule } from '@/server/ld';
|
|
3
|
+
import { metadataModule } from '@/server/metadata';
|
|
4
|
+
import { translation } from '@/server/translation';
|
|
4
5
|
import { isMobileDevice } from '@/utils/responsive';
|
|
5
6
|
|
|
6
7
|
import Actions from './features/Actions';
|
|
7
8
|
import Hero from './features/Hero';
|
|
8
9
|
import Logo from './features/Logo';
|
|
9
10
|
|
|
10
|
-
export const
|
|
11
|
-
|
|
11
|
+
export const generateMetadata = async () => {
|
|
12
|
+
const { t } = await translation('metadata');
|
|
13
|
+
return metadataModule.generate({
|
|
14
|
+
description: t('welcome.description'),
|
|
15
|
+
title: t('welcome.title'),
|
|
16
|
+
url: '/welcome',
|
|
17
|
+
});
|
|
12
18
|
};
|
|
13
19
|
|
|
14
|
-
const Page = () => {
|
|
20
|
+
const Page = async () => {
|
|
15
21
|
const mobile = isMobileDevice();
|
|
22
|
+
const { t } = await translation('metadata');
|
|
23
|
+
const ld = ldModule.generate({
|
|
24
|
+
description: t('welcome.description'),
|
|
25
|
+
title: t('welcome.title'),
|
|
26
|
+
url: '/welcome',
|
|
27
|
+
});
|
|
16
28
|
|
|
17
29
|
return (
|
|
18
30
|
<>
|
|
31
|
+
<StructuredData ld={ld} />
|
|
19
32
|
<Logo mobile={mobile} />
|
|
20
33
|
<Hero />
|
|
21
34
|
<Actions mobile={mobile} />
|
package/src/app/layout.tsx
CHANGED
|
@@ -39,7 +39,7 @@ const RootLayout = async ({ children, modal }: RootLayoutProps) => {
|
|
|
39
39
|
|
|
40
40
|
export default RootLayout;
|
|
41
41
|
|
|
42
|
-
export {
|
|
42
|
+
export { generateMetadata } from './metadata';
|
|
43
43
|
|
|
44
44
|
export const generateViewport = async (): ResolvingViewport => {
|
|
45
45
|
const isMobile = isMobileDevice();
|
package/src/app/metadata.ts
CHANGED
|
@@ -3,11 +3,9 @@ import { Metadata } from 'next';
|
|
|
3
3
|
import { getClientConfig } from '@/config/client';
|
|
4
4
|
import { getServerConfig } from '@/config/server';
|
|
5
5
|
import { OFFICIAL_URL } from '@/const/url';
|
|
6
|
-
|
|
7
|
-
import pkg from '../../package.json';
|
|
6
|
+
import { translation } from '@/server/translation';
|
|
8
7
|
|
|
9
8
|
const title = 'LobeChat';
|
|
10
|
-
const { description, homepage } = pkg;
|
|
11
9
|
|
|
12
10
|
const { SITE_URL = OFFICIAL_URL } = getServerConfig();
|
|
13
11
|
const { BASE_PATH } = getClientConfig();
|
|
@@ -15,55 +13,47 @@ const { BASE_PATH } = getClientConfig();
|
|
|
15
13
|
// if there is a base path, then we don't need the manifest
|
|
16
14
|
const noManifest = !!BASE_PATH;
|
|
17
15
|
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
title:
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
images: [
|
|
62
|
-
'https://registry.npmmirror.com/@lobehub/assets-favicons/latest/files/assets/og-960x540.png',
|
|
63
|
-
],
|
|
64
|
-
site: '@lobehub',
|
|
65
|
-
title,
|
|
66
|
-
},
|
|
16
|
+
export const generateMetadata = async (): Promise<Metadata> => {
|
|
17
|
+
const { t } = await translation('metadata');
|
|
18
|
+
return {
|
|
19
|
+
appleWebApp: {
|
|
20
|
+
statusBarStyle: 'black-translucent',
|
|
21
|
+
title,
|
|
22
|
+
},
|
|
23
|
+
description: t('chat.description'),
|
|
24
|
+
icons: {
|
|
25
|
+
apple: '/icons/apple-touch-icon.png',
|
|
26
|
+
icon: '/favicon.ico',
|
|
27
|
+
shortcut: '/favicon-32x32.ico',
|
|
28
|
+
},
|
|
29
|
+
manifest: noManifest ? undefined : '/manifest.json',
|
|
30
|
+
metadataBase: new URL(SITE_URL),
|
|
31
|
+
openGraph: {
|
|
32
|
+
description: t('chat.description'),
|
|
33
|
+
images: [
|
|
34
|
+
{
|
|
35
|
+
alt: t('chat.title'),
|
|
36
|
+
height: 640,
|
|
37
|
+
url: '/og/cover.png',
|
|
38
|
+
width: 1200,
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
locale: 'en-US',
|
|
42
|
+
siteName: title,
|
|
43
|
+
title: title,
|
|
44
|
+
type: 'website',
|
|
45
|
+
url: OFFICIAL_URL,
|
|
46
|
+
},
|
|
47
|
+
title: {
|
|
48
|
+
default: t('chat.title'),
|
|
49
|
+
template: '%s · LobeChat',
|
|
50
|
+
},
|
|
51
|
+
twitter: {
|
|
52
|
+
card: 'summary_large_image',
|
|
53
|
+
description: t('chat.description'),
|
|
54
|
+
images: ['/og/cover.png'],
|
|
55
|
+
site: '@lobehub',
|
|
56
|
+
title: t('chat.title'),
|
|
57
|
+
},
|
|
58
|
+
};
|
|
67
59
|
};
|
|
68
|
-
|
|
69
|
-
export default metadata;
|
package/src/app/page.tsx
CHANGED
|
@@ -5,6 +5,10 @@ import { getCanonicalUrl } from '@/const/url';
|
|
|
5
5
|
import Client from './(loading)/Client';
|
|
6
6
|
import Redirect from './(loading)/Redirect';
|
|
7
7
|
|
|
8
|
+
export const metadata: Metadata = {
|
|
9
|
+
alternates: { canonical: getCanonicalUrl('/') },
|
|
10
|
+
};
|
|
11
|
+
|
|
8
12
|
const Page = () => {
|
|
9
13
|
return (
|
|
10
14
|
<>
|
|
@@ -17,7 +21,3 @@ const Page = () => {
|
|
|
17
21
|
Page.displayName = 'Loading';
|
|
18
22
|
|
|
19
23
|
export default Page;
|
|
20
|
-
|
|
21
|
-
export const metadata: Metadata = {
|
|
22
|
-
alternates: { canonical: getCanonicalUrl('/') },
|
|
23
|
-
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { FC } from 'react';
|
|
2
|
+
|
|
3
|
+
const StructuredData: FC<{ ld: any }> = ({ ld }) => {
|
|
4
|
+
return (
|
|
5
|
+
<script
|
|
6
|
+
dangerouslySetInnerHTML={{ __html: JSON.stringify(ld) }}
|
|
7
|
+
id="structured-data"
|
|
8
|
+
type="application/ld+json"
|
|
9
|
+
/>
|
|
10
|
+
);
|
|
11
|
+
};
|
|
12
|
+
export default StructuredData;
|
|
@@ -3,6 +3,7 @@ import { Badge } from 'antd';
|
|
|
3
3
|
import {
|
|
4
4
|
Book,
|
|
5
5
|
CircleUserRound,
|
|
6
|
+
Download,
|
|
6
7
|
Feather,
|
|
7
8
|
HardDriveDownload,
|
|
8
9
|
HardDriveUpload,
|
|
@@ -22,6 +23,7 @@ import type { MenuProps } from '@/components/Menu';
|
|
|
22
23
|
import { DISCORD, DOCUMENTS, EMAIL_SUPPORT, GITHUB_ISSUES } from '@/const/url';
|
|
23
24
|
import DataImporter from '@/features/DataImporter';
|
|
24
25
|
import { useOpenSettings } from '@/hooks/useInterceptingRoutes';
|
|
26
|
+
import { usePWAInstall } from '@/hooks/usePWAInstall';
|
|
25
27
|
import { useQueryRoute } from '@/hooks/useQueryRoute';
|
|
26
28
|
import { configService } from '@/services/config';
|
|
27
29
|
import { SettingsTabs } from '@/store/global/initialState';
|
|
@@ -54,6 +56,7 @@ const NewVersionBadge = memo(
|
|
|
54
56
|
|
|
55
57
|
export const useMenu = () => {
|
|
56
58
|
const router = useQueryRoute();
|
|
59
|
+
const { canInstall, install } = usePWAInstall();
|
|
57
60
|
const hasNewVersion = useNewVersion();
|
|
58
61
|
const openSettings = useOpenSettings();
|
|
59
62
|
const { t } = useTranslation(['common', 'setting', 'auth']);
|
|
@@ -96,6 +99,18 @@ export const useMenu = () => {
|
|
|
96
99
|
},
|
|
97
100
|
];
|
|
98
101
|
|
|
102
|
+
const pwa: MenuProps['items'] = [
|
|
103
|
+
{
|
|
104
|
+
icon: <Icon icon={Download} />,
|
|
105
|
+
key: 'pwa',
|
|
106
|
+
label: t('installPWA'),
|
|
107
|
+
onClick: () => install(),
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
type: 'divider',
|
|
111
|
+
},
|
|
112
|
+
];
|
|
113
|
+
|
|
99
114
|
const data: MenuProps['items'] = [
|
|
100
115
|
{
|
|
101
116
|
icon: <Icon icon={HardDriveUpload} />,
|
|
@@ -192,6 +207,7 @@ export const useMenu = () => {
|
|
|
192
207
|
},
|
|
193
208
|
...(isLoginWithClerk ? profile : []),
|
|
194
209
|
...(isLogin ? settings : []),
|
|
210
|
+
...(canInstall ? pwa : []),
|
|
195
211
|
...(isLogin ? data : []),
|
|
196
212
|
...helps,
|
|
197
213
|
].filter(Boolean) as MenuProps['items'];
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { pwaInstallHandler } from 'pwa-install-handler';
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
|
|
4
|
+
export const usePWAInstall = () => {
|
|
5
|
+
const [canInstall, setCanInstall] = useState(false);
|
|
6
|
+
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
pwaInstallHandler.addListener(setCanInstall);
|
|
9
|
+
return () => {
|
|
10
|
+
pwaInstallHandler.removeListener(setCanInstall);
|
|
11
|
+
};
|
|
12
|
+
}, []);
|
|
13
|
+
|
|
14
|
+
return {
|
|
15
|
+
canInstall,
|
|
16
|
+
install: pwaInstallHandler.install,
|
|
17
|
+
};
|
|
18
|
+
};
|
|
@@ -59,6 +59,7 @@ export default {
|
|
|
59
59
|
},
|
|
60
60
|
title: '导入数据',
|
|
61
61
|
},
|
|
62
|
+
installPWA: '安装浏览器应用 (PWA)',
|
|
62
63
|
lang: {
|
|
63
64
|
'ar': '阿拉伯语',
|
|
64
65
|
'bg-BG': '保加利亚语',
|
|
@@ -138,13 +139,13 @@ export default {
|
|
|
138
139
|
title: '同步状态',
|
|
139
140
|
unconnected: { tip: '信令服务器连接失败,将无法建立点对点通信频道,请检查网络后重试' },
|
|
140
141
|
},
|
|
142
|
+
|
|
141
143
|
tab: {
|
|
142
144
|
chat: '会话',
|
|
143
145
|
market: '发现',
|
|
144
146
|
me: '我',
|
|
145
147
|
setting: '设置',
|
|
146
148
|
},
|
|
147
|
-
|
|
148
149
|
telemetry: {
|
|
149
150
|
allow: '允许',
|
|
150
151
|
deny: '拒绝',
|
|
@@ -6,6 +6,7 @@ import common from './common';
|
|
|
6
6
|
import components from './components';
|
|
7
7
|
import error from './error';
|
|
8
8
|
import market from './market';
|
|
9
|
+
import metadata from './metadata';
|
|
9
10
|
import migration from './migration';
|
|
10
11
|
import modelProvider from './modelProvider';
|
|
11
12
|
import plugin from './plugin';
|
|
@@ -20,6 +21,7 @@ const resources = {
|
|
|
20
21
|
components,
|
|
21
22
|
error,
|
|
22
23
|
market,
|
|
24
|
+
metadata,
|
|
23
25
|
migration,
|
|
24
26
|
modelProvider,
|
|
25
27
|
plugin,
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
chat: {
|
|
3
|
+
description: 'LobeChat 带给你最好的 ChatGPT, OLLaMA, Gemini, Claude WebUI 使用体验',
|
|
4
|
+
title: 'LobeChat:个人 LLM 效能工具,给自己一个更聪明的大脑',
|
|
5
|
+
},
|
|
6
|
+
market: {
|
|
7
|
+
description:
|
|
8
|
+
'内容创作、文案、问答、图像生成、视频生成、语音生成、智能 Agent、自动化工作流,定制你专属的 AI / GPTs / OLLaMA 智能助手',
|
|
9
|
+
title: '助手市场',
|
|
10
|
+
},
|
|
11
|
+
plugins: {
|
|
12
|
+
description:
|
|
13
|
+
'搜素、图表生成、学术、图像生成、视频生成、语音生成、自动化工作流,定制 ChatGPT / OLLaMA 专属的 ToolCall 插件能力',
|
|
14
|
+
title: '插件市场',
|
|
15
|
+
},
|
|
16
|
+
welcome: {
|
|
17
|
+
description: 'LobeChat 带给你最好的 ChatGPT, OLLaMA, Gemini, Claude WebUI 使用体验',
|
|
18
|
+
title: '欢迎使用 LobeChat:个人 LLM 效能工具,给自己一个更聪明的大脑',
|
|
19
|
+
},
|
|
20
|
+
};
|