@lobehub/chat 1.39.3 → 1.40.1
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/.env.example +19 -8
- package/.eslintignore +1 -1
- package/CHANGELOG.md +58 -0
- package/changelog/v1.json +21 -0
- package/docs/.cdn.cache.json +25 -0
- package/docs/changelog/2023-09-09-plugin-system.mdx +1 -1
- package/docs/changelog/2023-09-09-plugin-system.zh-CN.mdx +1 -1
- package/docs/changelog/2024-09-20-artifacts.mdx +1 -1
- package/docs/changelog/2024-09-20-artifacts.zh-CN.mdx +1 -1
- package/docs/changelog/2024-10-27-pin-assistant.mdx +2 -2
- package/docs/changelog/2024-10-27-pin-assistant.zh-CN.mdx +2 -2
- package/docs/changelog/2024-11-06-share-text-json.mdx +2 -2
- package/docs/changelog/2024-11-06-share-text-json.zh-CN.mdx +2 -2
- package/docs/changelog/index.json +16 -16
- package/locales/ar/changelog.json +18 -0
- package/locales/ar/common.json +1 -0
- package/locales/ar/metadata.json +4 -0
- package/locales/bg-BG/changelog.json +18 -0
- package/locales/bg-BG/common.json +1 -0
- package/locales/bg-BG/metadata.json +4 -0
- package/locales/de-DE/changelog.json +18 -0
- package/locales/de-DE/common.json +1 -0
- package/locales/de-DE/metadata.json +4 -0
- package/locales/en-US/changelog.json +18 -0
- package/locales/en-US/common.json +1 -0
- package/locales/en-US/metadata.json +4 -0
- package/locales/es-ES/changelog.json +18 -0
- package/locales/es-ES/common.json +1 -0
- package/locales/es-ES/metadata.json +4 -0
- package/locales/fa-IR/changelog.json +18 -0
- package/locales/fa-IR/common.json +1 -0
- package/locales/fa-IR/metadata.json +4 -0
- package/locales/fr-FR/changelog.json +18 -0
- package/locales/fr-FR/common.json +1 -0
- package/locales/fr-FR/metadata.json +4 -0
- package/locales/it-IT/changelog.json +18 -0
- package/locales/it-IT/common.json +1 -0
- package/locales/it-IT/metadata.json +4 -0
- package/locales/ja-JP/changelog.json +18 -0
- package/locales/ja-JP/common.json +1 -0
- package/locales/ja-JP/metadata.json +4 -0
- package/locales/ko-KR/changelog.json +18 -0
- package/locales/ko-KR/common.json +1 -0
- package/locales/ko-KR/metadata.json +4 -0
- package/locales/nl-NL/changelog.json +18 -0
- package/locales/nl-NL/common.json +1 -0
- package/locales/nl-NL/metadata.json +4 -0
- package/locales/pl-PL/changelog.json +18 -0
- package/locales/pl-PL/common.json +1 -0
- package/locales/pl-PL/metadata.json +4 -0
- package/locales/pt-BR/changelog.json +18 -0
- package/locales/pt-BR/common.json +1 -0
- package/locales/pt-BR/metadata.json +4 -0
- package/locales/ru-RU/changelog.json +18 -0
- package/locales/ru-RU/common.json +1 -0
- package/locales/ru-RU/metadata.json +4 -0
- package/locales/tr-TR/changelog.json +18 -0
- package/locales/tr-TR/common.json +1 -0
- package/locales/tr-TR/metadata.json +4 -0
- package/locales/vi-VN/changelog.json +18 -0
- package/locales/vi-VN/common.json +1 -0
- package/locales/vi-VN/metadata.json +4 -0
- package/locales/zh-CN/changelog.json +18 -0
- package/locales/zh-CN/common.json +1 -0
- package/locales/zh-CN/metadata.json +4 -0
- package/locales/zh-TW/changelog.json +18 -0
- package/locales/zh-TW/common.json +1 -0
- package/locales/zh-TW/metadata.json +4 -0
- package/package.json +6 -1
- package/scripts/cdnWorkflow/index.ts +217 -0
- package/scripts/cdnWorkflow/optimized.ts +21 -0
- package/scripts/cdnWorkflow/s3/index.ts +120 -0
- package/scripts/cdnWorkflow/s3/types.ts +25 -0
- package/scripts/cdnWorkflow/s3/utils.ts +106 -0
- package/scripts/cdnWorkflow/uploader.ts +73 -0
- package/scripts/cdnWorkflow/utils.ts +93 -0
- package/src/app/(main)/(mobile)/me/(home)/__tests__/useCategory.test.tsx +25 -12
- package/src/app/(main)/(mobile)/me/(home)/features/useCategory.tsx +19 -9
- package/src/app/(main)/_layout/Desktop.tsx +4 -1
- package/src/app/(main)/_layout/Mobile.tsx +2 -1
- package/src/app/(main)/changelog/_layout/Desktop.tsx +25 -0
- package/src/app/(main)/changelog/_layout/Mobile/Header.tsx +33 -0
- package/src/app/(main)/changelog/_layout/Mobile/index.tsx +21 -0
- package/src/app/(main)/changelog/error.tsx +5 -0
- package/src/app/(main)/changelog/features/GridLayout.tsx +22 -0
- package/src/app/(main)/changelog/features/Hero.tsx +40 -0
- package/src/app/(main)/changelog/features/Post.tsx +56 -0
- package/src/app/(main)/changelog/features/PublishedTime.tsx +50 -0
- package/src/app/(main)/changelog/features/VersionTag.tsx +27 -0
- package/src/app/(main)/changelog/layout.tsx +10 -0
- package/src/app/(main)/changelog/loading.tsx +3 -0
- package/src/app/(main)/changelog/modal/page.tsx +23 -0
- package/src/app/(main)/changelog/not-found.tsx +3 -0
- package/src/app/(main)/changelog/page.tsx +73 -0
- package/src/app/(main)/chat/(workspace)/_layout/Desktop/HotKeys.tsx +7 -0
- package/src/app/(main)/chat/(workspace)/page.tsx +9 -2
- package/src/app/(main)/settings/about/features/Version.tsx +2 -2
- package/src/app/@modal/(.)changelog/modal/features/Cover.tsx +48 -0
- package/src/app/@modal/(.)changelog/modal/features/Hero.tsx +29 -0
- package/src/app/@modal/(.)changelog/modal/features/Pagination.tsx +54 -0
- package/src/app/@modal/(.)changelog/modal/features/Post.tsx +57 -0
- package/src/app/@modal/(.)changelog/modal/features/PublishedTime.tsx +50 -0
- package/src/app/@modal/(.)changelog/modal/features/ReadDetail.tsx +94 -0
- package/src/app/@modal/(.)changelog/modal/features/UpdateChangelogStatus.tsx +21 -0
- package/src/app/@modal/(.)changelog/modal/features/VersionTag.tsx +27 -0
- package/src/app/@modal/(.)changelog/modal/layout.tsx +39 -0
- package/src/app/@modal/(.)changelog/modal/loading.tsx +10 -0
- package/src/app/@modal/(.)changelog/modal/page.tsx +37 -0
- package/src/app/@modal/(.)settings/modal/layout.tsx +19 -16
- package/src/app/@modal/_layout/ModalLayout.tsx +63 -0
- package/src/app/@modal/chat/(.)settings/modal/layout.tsx +20 -17
- package/src/app/@modal/layout.tsx +5 -69
- package/src/components/mdx/Image.tsx +50 -0
- package/src/components/mdx/index.tsx +2 -0
- package/src/const/hotkeys.ts +1 -0
- package/src/const/url.ts +1 -0
- package/src/features/ChangelogModal/index.tsx +22 -0
- package/src/features/User/UserPanel/useMenu.tsx +50 -46
- package/src/features/User/__tests__/useMenu.test.tsx +7 -6
- package/src/hooks/useInterceptingRoutes.ts +1 -6
- package/src/hooks/useShare.tsx +1 -0
- package/src/libs/agent-runtime/openai/index.ts +2 -0
- package/src/locales/default/changelog.ts +18 -0
- package/src/locales/default/common.ts +1 -0
- package/src/locales/default/index.ts +2 -0
- package/src/locales/default/metadata.ts +4 -0
- package/src/server/metadata.ts +5 -3
- package/src/server/routers/edge/appStatus.ts +3 -0
- package/src/server/routers/edge/index.ts +2 -0
- package/src/server/routers/lambda/agent.ts +1 -1
- package/src/server/services/changelog/index.test.ts +310 -0
- package/src/server/services/changelog/index.ts +196 -0
- package/src/server/services/discover/index.test.ts +0 -1
- package/src/server/sitemap.ts +4 -1
- package/src/services/__tests__/chat.test.ts +1 -1
- package/src/services/__tests__/global.test.ts +5 -2
- package/src/services/_auth.ts +1 -1
- package/src/services/agent.ts +25 -21
- package/src/services/chat.ts +2 -2
- package/src/services/file/ClientS3/index.ts +6 -6
- package/src/services/file/client.ts +14 -15
- package/src/services/file/server.ts +20 -25
- package/src/services/global.ts +2 -2
- package/src/services/import/client.ts +6 -5
- package/src/services/import/server.ts +6 -5
- package/src/services/import/type.ts +7 -0
- package/src/services/knowledgeBase.ts +19 -19
- package/src/services/message/_deprecated.ts +5 -0
- package/src/services/message/client.ts +52 -48
- package/src/services/message/server.ts +50 -53
- package/src/services/message/type.ts +2 -2
- package/src/services/plugin/client.ts +16 -22
- package/src/services/plugin/server.ts +15 -19
- package/src/services/rag.ts +18 -18
- package/src/services/ragEval.ts +29 -26
- package/src/services/session/_deprecated.ts +2 -2
- package/src/services/session/client.ts +55 -81
- package/src/services/session/server.ts +50 -74
- package/src/services/session/type.ts +4 -6
- package/src/services/share.ts +4 -4
- package/src/services/textToImage.ts +5 -2
- package/src/services/thread/client.ts +9 -15
- package/src/services/thread/server.ts +10 -15
- package/src/services/topic/client.ts +25 -25
- package/src/services/topic/server.ts +25 -42
- package/src/services/trace.ts +4 -4
- package/src/services/user/client.ts +13 -17
- package/src/services/user/server.ts +9 -13
- package/src/services/user/type.ts +1 -1
- package/src/store/chat/slices/message/reducer.ts +3 -2
- package/src/store/global/action.ts +27 -22
- package/src/store/global/initialState.ts +1 -0
- package/src/types/changelog.ts +6 -0
- package/src/types/message/index.ts +10 -8
- package/src/app/@modal/features/InterceptingContext.tsx +0 -9
@@ -1,7 +1,10 @@
|
|
1
1
|
import StructuredData from '@/components/StructuredData';
|
2
|
+
import { serverFeatureFlags } from '@/config/featureFlags';
|
2
3
|
import { BRANDING_NAME } from '@/const/branding';
|
4
|
+
import ChangelogModal from '@/features/ChangelogModal';
|
3
5
|
import { ldModule } from '@/server/ld';
|
4
6
|
import { metadataModule } from '@/server/metadata';
|
7
|
+
import { ChangelogService } from '@/server/services/changelog';
|
5
8
|
import { translation } from '@/server/translation';
|
6
9
|
import { isMobileDevice } from '@/utils/server/responsive';
|
7
10
|
|
@@ -11,17 +14,18 @@ import TelemetryNotification from './features/TelemetryNotification';
|
|
11
14
|
export const generateMetadata = async () => {
|
12
15
|
const { t } = await translation('metadata');
|
13
16
|
return metadataModule.generate({
|
14
|
-
description: t('chat.
|
17
|
+
description: t('chat.description', { appName: BRANDING_NAME }),
|
15
18
|
title: t('chat.title', { appName: BRANDING_NAME }),
|
16
19
|
url: '/chat',
|
17
20
|
});
|
18
21
|
};
|
19
22
|
|
20
23
|
const Page = async () => {
|
24
|
+
const hideDocs = serverFeatureFlags().hideDocs;
|
21
25
|
const mobile = await isMobileDevice();
|
22
26
|
const { t } = await translation('metadata');
|
23
27
|
const ld = ldModule.generate({
|
24
|
-
description: t('chat.
|
28
|
+
description: t('chat.description', { appName: BRANDING_NAME }),
|
25
29
|
title: t('chat.title', { appName: BRANDING_NAME }),
|
26
30
|
url: '/chat',
|
27
31
|
});
|
@@ -31,6 +35,9 @@ const Page = async () => {
|
|
31
35
|
<StructuredData ld={ld} />
|
32
36
|
<PageTitle />
|
33
37
|
<TelemetryNotification mobile={mobile} />
|
38
|
+
{!hideDocs && !mobile && (
|
39
|
+
<ChangelogModal currentId={await new ChangelogService().getLatestChangelogId()} />
|
40
|
+
)}
|
34
41
|
</>
|
35
42
|
);
|
36
43
|
};
|
@@ -7,7 +7,7 @@ import { Center, Flexbox } from 'react-layout-kit';
|
|
7
7
|
|
8
8
|
import { ProductLogo } from '@/components/Branding';
|
9
9
|
import { BRANDING_NAME } from '@/const/branding';
|
10
|
-
import { MANUAL_UPGRADE_URL, OFFICIAL_SITE
|
10
|
+
import { CHANGELOG_URL, MANUAL_UPGRADE_URL, OFFICIAL_SITE } from '@/const/url';
|
11
11
|
import { CURRENT_VERSION } from '@/const/version';
|
12
12
|
import { useNewVersion } from '@/features/User/UserPanel/useNewVersion';
|
13
13
|
import { useGlobalStore } from '@/store/global';
|
@@ -62,7 +62,7 @@ const Version = memo<{ mobile?: boolean }>(({ mobile }) => {
|
|
62
62
|
</Flexbox>
|
63
63
|
</Flexbox>
|
64
64
|
<Flexbox flex={mobile ? 1 : undefined} gap={8} horizontal>
|
65
|
-
<Link href={
|
65
|
+
<Link href={CHANGELOG_URL} style={{ flex: 1 }} target={'_blank'}>
|
66
66
|
<Button block={mobile}>{t('changelog')}</Button>
|
67
67
|
</Link>
|
68
68
|
{hasNewVersion && (
|
@@ -0,0 +1,48 @@
|
|
1
|
+
'use client';
|
2
|
+
|
3
|
+
import { createStyles } from 'antd-style';
|
4
|
+
import { PropsWithChildren, memo } from 'react';
|
5
|
+
import { Flexbox } from 'react-layout-kit';
|
6
|
+
|
7
|
+
const useStyles = createStyles(
|
8
|
+
({ css, token }) => css`
|
9
|
+
position: relative;
|
10
|
+
overflow: hidden;
|
11
|
+
background: ${token.colorFillSecondary};
|
12
|
+
|
13
|
+
&::before {
|
14
|
+
content: '';
|
15
|
+
|
16
|
+
position: absolute;
|
17
|
+
z-index: 1;
|
18
|
+
inset-block-start: 0;
|
19
|
+
inset-inline-start: 0;
|
20
|
+
|
21
|
+
width: 100%;
|
22
|
+
height: 1px;
|
23
|
+
|
24
|
+
background: ${token.colorFillTertiary};
|
25
|
+
}
|
26
|
+
|
27
|
+
&::after {
|
28
|
+
content: '';
|
29
|
+
|
30
|
+
position: absolute;
|
31
|
+
z-index: 1;
|
32
|
+
inset-block-end: 0;
|
33
|
+
inset-inline-start: 0;
|
34
|
+
|
35
|
+
width: 100%;
|
36
|
+
height: 1px;
|
37
|
+
|
38
|
+
background: ${token.colorFillTertiary};
|
39
|
+
}
|
40
|
+
`,
|
41
|
+
);
|
42
|
+
|
43
|
+
const Cover = memo<PropsWithChildren>(({ children }) => {
|
44
|
+
const { styles } = useStyles();
|
45
|
+
return <Flexbox className={styles}>{children}</Flexbox>;
|
46
|
+
});
|
47
|
+
|
48
|
+
export default Cover;
|
@@ -0,0 +1,29 @@
|
|
1
|
+
'use client';
|
2
|
+
|
3
|
+
import { FluentEmoji } from '@lobehub/ui';
|
4
|
+
import { createStyles } from 'antd-style';
|
5
|
+
import { memo } from 'react';
|
6
|
+
import { useTranslation } from 'react-i18next';
|
7
|
+
import { Flexbox } from 'react-layout-kit';
|
8
|
+
|
9
|
+
const useStyles = createStyles(
|
10
|
+
({ css, token }) => css`
|
11
|
+
background: linear-gradient(to bottom, ${token.colorFillTertiary}, transparent);
|
12
|
+
`,
|
13
|
+
);
|
14
|
+
|
15
|
+
const Hero = memo(() => {
|
16
|
+
const { theme, styles } = useStyles();
|
17
|
+
const { t } = useTranslation('changelog');
|
18
|
+
return (
|
19
|
+
<Flexbox className={styles} gap={8} padding={24}>
|
20
|
+
<Flexbox align={'center'} gap={12} horizontal>
|
21
|
+
<h1 style={{ fontSize: 24, fontWeight: 'bold', margin: 0 }}>{t('welcomeBack')}</h1>
|
22
|
+
<FluentEmoji emoji={'🤯'} size={28} type={'anim'} />
|
23
|
+
</Flexbox>
|
24
|
+
<div style={{ color: theme.colorTextSecondary, fontSize: 16 }}>{t('addedWhileAway')}</div>
|
25
|
+
</Flexbox>
|
26
|
+
);
|
27
|
+
});
|
28
|
+
|
29
|
+
export default Hero;
|
@@ -0,0 +1,54 @@
|
|
1
|
+
'use client';
|
2
|
+
|
3
|
+
import { Icon } from '@lobehub/ui';
|
4
|
+
import { createStyles } from 'antd-style';
|
5
|
+
import { ChevronRightIcon } from 'lucide-react';
|
6
|
+
import Link from 'next/link';
|
7
|
+
import { memo } from 'react';
|
8
|
+
import { useTranslation } from 'react-i18next';
|
9
|
+
import { Flexbox } from 'react-layout-kit';
|
10
|
+
import urlJoin from 'url-join';
|
11
|
+
|
12
|
+
import { OFFICIAL_SITE } from '@/const/url';
|
13
|
+
|
14
|
+
const useStyles = createStyles(({ css, token }) => ({
|
15
|
+
button: css`
|
16
|
+
border: 1px solid ${token.colorBorderSecondary};
|
17
|
+
border-radius: ${token.borderRadiusLG}px;
|
18
|
+
|
19
|
+
&:hover {
|
20
|
+
background: ${token.colorFillTertiary};
|
21
|
+
}
|
22
|
+
`,
|
23
|
+
desc: css`
|
24
|
+
color: ${token.colorTextSecondary};
|
25
|
+
`,
|
26
|
+
title: css`
|
27
|
+
font-size: 16px;
|
28
|
+
font-weight: 500;
|
29
|
+
`,
|
30
|
+
}));
|
31
|
+
|
32
|
+
const Pagination = memo(() => {
|
33
|
+
const { t } = useTranslation('changelog');
|
34
|
+
const { styles } = useStyles();
|
35
|
+
return (
|
36
|
+
<Flexbox gap={16} horizontal style={{ marginTop: 24 }} width={'100%'}>
|
37
|
+
<Link
|
38
|
+
href={urlJoin(OFFICIAL_SITE, '/changelog/page/2')}
|
39
|
+
style={{ color: 'inherit', flex: 1 }}
|
40
|
+
target={'_blank'}
|
41
|
+
>
|
42
|
+
<Flexbox align={'flex-end'} className={styles.button} gap={4} padding={16}>
|
43
|
+
<Flexbox align={'center'} className={styles.desc} gap={4} horizontal>
|
44
|
+
{t('pagination.prev')}
|
45
|
+
<Icon icon={ChevronRightIcon} />
|
46
|
+
</Flexbox>
|
47
|
+
<div className={styles.title}>{t('pagination.older')}</div>
|
48
|
+
</Flexbox>
|
49
|
+
</Link>
|
50
|
+
</Flexbox>
|
51
|
+
);
|
52
|
+
});
|
53
|
+
|
54
|
+
export default Pagination;
|
@@ -0,0 +1,57 @@
|
|
1
|
+
import { Typography } from '@lobehub/ui';
|
2
|
+
import Link from 'next/link';
|
3
|
+
import { Flexbox } from 'react-layout-kit';
|
4
|
+
import urlJoin from 'url-join';
|
5
|
+
|
6
|
+
import { CustomMDX } from '@/components/mdx';
|
7
|
+
import Image from '@/components/mdx/Image';
|
8
|
+
import { OFFICIAL_SITE } from '@/const/url';
|
9
|
+
import { Locales } from '@/locales/resources';
|
10
|
+
import { ChangelogService } from '@/server/services/changelog';
|
11
|
+
import { ChangelogIndexItem } from '@/types/changelog';
|
12
|
+
|
13
|
+
import Cover from './Cover';
|
14
|
+
import PublishedTime from './PublishedTime';
|
15
|
+
import ReadDetail from './ReadDetail';
|
16
|
+
import VersionTag from './VersionTag';
|
17
|
+
|
18
|
+
const Post = async ({
|
19
|
+
id,
|
20
|
+
versionRange,
|
21
|
+
locale,
|
22
|
+
}: ChangelogIndexItem & { branch?: string; locale: Locales; mobile?: boolean }) => {
|
23
|
+
const changelogService = new ChangelogService();
|
24
|
+
const data = await changelogService.getPostById(id, { locale });
|
25
|
+
const url = urlJoin(OFFICIAL_SITE, 'changelog', id);
|
26
|
+
|
27
|
+
if (!data) return null;
|
28
|
+
|
29
|
+
return (
|
30
|
+
<Flexbox gap={8}>
|
31
|
+
<Link href={url} style={{ color: 'inherit' }} target={'_blank'}>
|
32
|
+
<Cover>
|
33
|
+
<Image alt={data.title} src={data.image} />
|
34
|
+
</Cover>
|
35
|
+
</Link>
|
36
|
+
<Flexbox gap={8} paddingInline={24}>
|
37
|
+
<Typography headerMultiple={0.2} style={{ width: '100%' }}>
|
38
|
+
<Link href={url} style={{ color: 'inherit' }} target={'_blank'}>
|
39
|
+
<h1 id={id}>{data.rawTitle || data.title}</h1>
|
40
|
+
</Link>
|
41
|
+
<CustomMDX source={data.content} />
|
42
|
+
</Typography>
|
43
|
+
<Flexbox align={'center'} gap={8} horizontal justify={'space-between'} width={'100%'}>
|
44
|
+
<VersionTag range={versionRange} />
|
45
|
+
<PublishedTime
|
46
|
+
date={data.date.toISOString()}
|
47
|
+
style={{ fontSize: 12, opacity: 0.5 }}
|
48
|
+
template={'MMMM D, YYYY'}
|
49
|
+
/>
|
50
|
+
</Flexbox>
|
51
|
+
<ReadDetail desc={data.description} postId={id} title={data.rawTitle || data.title} />
|
52
|
+
</Flexbox>
|
53
|
+
</Flexbox>
|
54
|
+
);
|
55
|
+
};
|
56
|
+
|
57
|
+
export default Post;
|
@@ -0,0 +1,50 @@
|
|
1
|
+
'use client';
|
2
|
+
|
3
|
+
import { createStyles } from 'antd-style';
|
4
|
+
import dayjs from 'dayjs';
|
5
|
+
import 'dayjs/locale/zh.js';
|
6
|
+
import { CSSProperties, FC } from 'react';
|
7
|
+
import { useTranslation } from 'react-i18next';
|
8
|
+
|
9
|
+
const useStyles = createStyles(({ css, token }) => {
|
10
|
+
return {
|
11
|
+
time: css`
|
12
|
+
margin-block: calc(var(--lobe-markdown-margin-multiple) * 1em);
|
13
|
+
|
14
|
+
font-size: 14px;
|
15
|
+
line-height: var(--lobe-markdown-line-height);
|
16
|
+
color: ${token.colorTextSecondary};
|
17
|
+
letter-spacing: 0.02em;
|
18
|
+
`,
|
19
|
+
};
|
20
|
+
});
|
21
|
+
|
22
|
+
interface PrivacyUpdatedProps {
|
23
|
+
className?: string;
|
24
|
+
date: string;
|
25
|
+
style?: CSSProperties;
|
26
|
+
template?: string;
|
27
|
+
}
|
28
|
+
const PublishedTime: FC<PrivacyUpdatedProps> = ({
|
29
|
+
date = new Date().toISOString(),
|
30
|
+
style,
|
31
|
+
className,
|
32
|
+
template = 'dddd, MMMM D YYYY',
|
33
|
+
}) => {
|
34
|
+
const { i18n } = useTranslation();
|
35
|
+
const { styles, cx } = useStyles();
|
36
|
+
const time = dayjs(date).locale(i18n.language).format(template);
|
37
|
+
|
38
|
+
return (
|
39
|
+
<time
|
40
|
+
aria-label={'published-date'}
|
41
|
+
className={cx(styles.time, className)}
|
42
|
+
dateTime={time}
|
43
|
+
style={style}
|
44
|
+
>
|
45
|
+
{time}
|
46
|
+
</time>
|
47
|
+
);
|
48
|
+
};
|
49
|
+
|
50
|
+
export default PublishedTime;
|
@@ -0,0 +1,94 @@
|
|
1
|
+
'use client';
|
2
|
+
|
3
|
+
import { ActionIcon, Icon } from '@lobehub/ui';
|
4
|
+
import { Divider } from 'antd';
|
5
|
+
import { createStyles } from 'antd-style';
|
6
|
+
import { ChevronRightIcon } from 'lucide-react';
|
7
|
+
import Link from 'next/link';
|
8
|
+
import { memo } from 'react';
|
9
|
+
import { useTranslation } from 'react-i18next';
|
10
|
+
import { Flexbox } from 'react-layout-kit';
|
11
|
+
import urlJoin from 'url-join';
|
12
|
+
|
13
|
+
import { OFFICIAL_SITE } from '@/const/url';
|
14
|
+
import { useShare } from '@/hooks/useShare';
|
15
|
+
|
16
|
+
const useStyles = createStyles(
|
17
|
+
({ css, token }) => css`
|
18
|
+
position: relative;
|
19
|
+
|
20
|
+
margin-block: 16px 32px;
|
21
|
+
padding: 16px;
|
22
|
+
|
23
|
+
background: ${token.colorFillTertiary};
|
24
|
+
border-radius: ${token.borderRadiusLG}px;
|
25
|
+
`,
|
26
|
+
);
|
27
|
+
|
28
|
+
const ReadDetail = memo<{ desc: string; postId: string; title: string }>(
|
29
|
+
({ postId, title, desc }) => {
|
30
|
+
const { t } = useTranslation('changelog');
|
31
|
+
const { styles, theme } = useStyles();
|
32
|
+
const url = urlJoin(OFFICIAL_SITE, `/changelog/${postId}`);
|
33
|
+
const { x, telegram, reddit, mastodon, whatsapp } = useShare({ desc, title, url });
|
34
|
+
|
35
|
+
return (
|
36
|
+
<Flexbox align={'center'} className={styles} gap={4} horizontal>
|
37
|
+
<Link href={x.link} style={{ color: 'inherit' }} target={'_blank'}>
|
38
|
+
<ActionIcon
|
39
|
+
fill={theme.colorTextSecondary}
|
40
|
+
icon={x.icon}
|
41
|
+
size={{ blockSize: 28, fontSize: 16 }}
|
42
|
+
/>
|
43
|
+
</Link>
|
44
|
+
<Link href={telegram.link} style={{ color: 'inherit' }} target={'_blank'}>
|
45
|
+
<ActionIcon
|
46
|
+
fill={theme.colorTextSecondary}
|
47
|
+
icon={telegram.icon}
|
48
|
+
size={{ blockSize: 28, fontSize: 16 }}
|
49
|
+
/>
|
50
|
+
</Link>
|
51
|
+
<Link href={reddit.link} style={{ color: 'inherit' }} target={'_blank'}>
|
52
|
+
<ActionIcon
|
53
|
+
fill={theme.colorTextSecondary}
|
54
|
+
icon={reddit.icon}
|
55
|
+
size={{ blockSize: 28, fontSize: 16 }}
|
56
|
+
/>
|
57
|
+
</Link>
|
58
|
+
<Link href={mastodon.link} style={{ color: 'inherit' }} target={'_blank'}>
|
59
|
+
<ActionIcon
|
60
|
+
fill={theme.colorTextSecondary}
|
61
|
+
icon={mastodon.icon}
|
62
|
+
size={{ blockSize: 28, fontSize: 16 }}
|
63
|
+
/>
|
64
|
+
</Link>
|
65
|
+
<Link href={whatsapp.link} style={{ color: 'inherit' }} target={'_blank'}>
|
66
|
+
<ActionIcon
|
67
|
+
fill={theme.colorTextSecondary}
|
68
|
+
icon={whatsapp.icon}
|
69
|
+
size={{ blockSize: 28, fontSize: 16 }}
|
70
|
+
/>
|
71
|
+
</Link>
|
72
|
+
<Divider style={{ height: '100%' }} type={'vertical'} />
|
73
|
+
<Link href={url} style={{ color: 'inherit', flex: 1 }} target={'_blank'}>
|
74
|
+
<Flexbox
|
75
|
+
align={'center'}
|
76
|
+
horizontal
|
77
|
+
justify={'space-between'}
|
78
|
+
paddingInline={4}
|
79
|
+
width={'100%'}
|
80
|
+
>
|
81
|
+
{t('readDetails')}
|
82
|
+
<Icon
|
83
|
+
color={theme.colorTextSecondary}
|
84
|
+
icon={ChevronRightIcon}
|
85
|
+
size={{ fontSize: 20 }}
|
86
|
+
/>
|
87
|
+
</Flexbox>
|
88
|
+
</Link>
|
89
|
+
</Flexbox>
|
90
|
+
);
|
91
|
+
},
|
92
|
+
);
|
93
|
+
|
94
|
+
export default ReadDetail;
|
@@ -0,0 +1,21 @@
|
|
1
|
+
'use client';
|
2
|
+
|
3
|
+
import { memo, useEffect } from 'react';
|
4
|
+
|
5
|
+
import { useGlobalStore } from '@/store/global';
|
6
|
+
|
7
|
+
const UpdateChangelogStatus = memo<{ currentId?: string }>(({ currentId }) => {
|
8
|
+
const [latestChangelogId, updateSystemStatus] = useGlobalStore((s) => [
|
9
|
+
s.status.latestChangelogId,
|
10
|
+
s.updateSystemStatus,
|
11
|
+
]);
|
12
|
+
|
13
|
+
useEffect(() => {
|
14
|
+
if (!currentId || currentId === latestChangelogId) return;
|
15
|
+
updateSystemStatus({ latestChangelogId: currentId });
|
16
|
+
}, [latestChangelogId, currentId]);
|
17
|
+
|
18
|
+
return null;
|
19
|
+
});
|
20
|
+
|
21
|
+
export default UpdateChangelogStatus;
|
@@ -0,0 +1,27 @@
|
|
1
|
+
'use client';
|
2
|
+
|
3
|
+
import { Tag } from '@lobehub/ui';
|
4
|
+
import { createStyles } from 'antd-style';
|
5
|
+
import { memo } from 'react';
|
6
|
+
|
7
|
+
const useStyles = createStyles(({ token, css }) => {
|
8
|
+
return {
|
9
|
+
tag: css`
|
10
|
+
margin: 0;
|
11
|
+
padding-block: 4px;
|
12
|
+
padding-inline: 12px;
|
13
|
+
|
14
|
+
color: ${token.colorTextSecondary};
|
15
|
+
|
16
|
+
border-radius: 16px;
|
17
|
+
`,
|
18
|
+
};
|
19
|
+
});
|
20
|
+
|
21
|
+
const VersionTag = memo<{ range: string[] }>(({ range }) => {
|
22
|
+
const { styles } = useStyles();
|
23
|
+
|
24
|
+
return <Tag className={styles.tag}>{range.map((v) => 'v' + v).join(' ~ ')}</Tag>;
|
25
|
+
});
|
26
|
+
|
27
|
+
export default VersionTag;
|
@@ -0,0 +1,39 @@
|
|
1
|
+
'use client';
|
2
|
+
|
3
|
+
import { createStyles } from 'antd-style';
|
4
|
+
import { PropsWithChildren, memo } from 'react';
|
5
|
+
import { Flexbox } from 'react-layout-kit';
|
6
|
+
|
7
|
+
import ModalLayout from '../../_layout/ModalLayout';
|
8
|
+
import Hero from './features/Hero';
|
9
|
+
import Pagination from './features/Pagination';
|
10
|
+
|
11
|
+
const useStyles = createStyles(
|
12
|
+
({ css, prefixCls, token }) => css`
|
13
|
+
.${prefixCls}-modal-close {
|
14
|
+
background: ${token.colorBgElevated} !important;
|
15
|
+
border: 1px solid ${token.colorBorderSecondary};
|
16
|
+
}
|
17
|
+
`,
|
18
|
+
);
|
19
|
+
|
20
|
+
const Layout = memo<PropsWithChildren>(({ children }) => {
|
21
|
+
const { styles } = useStyles();
|
22
|
+
|
23
|
+
return (
|
24
|
+
<ModalLayout centered className={styles} height={'min(90vh, 800px)'} width={'min(90vw, 600px)'}>
|
25
|
+
<Flexbox
|
26
|
+
style={{ overflowX: 'hidden', overflowY: 'auto', position: 'relative' }}
|
27
|
+
width={'100%'}
|
28
|
+
>
|
29
|
+
<Hero />
|
30
|
+
{children}
|
31
|
+
<Flexbox padding={24}>
|
32
|
+
<Pagination />
|
33
|
+
</Flexbox>
|
34
|
+
</Flexbox>
|
35
|
+
</ModalLayout>
|
36
|
+
);
|
37
|
+
});
|
38
|
+
|
39
|
+
export default Layout;
|
@@ -0,0 +1,37 @@
|
|
1
|
+
import { notFound } from 'next/navigation';
|
2
|
+
import { Suspense } from 'react';
|
3
|
+
|
4
|
+
import { serverFeatureFlags } from '@/config/featureFlags';
|
5
|
+
import { ChangelogService } from '@/server/services/changelog';
|
6
|
+
import { getLocale } from '@/server/translation';
|
7
|
+
import { isMobileDevice } from '@/utils/server/responsive';
|
8
|
+
|
9
|
+
import Post from './features/Post';
|
10
|
+
import UpdateChangelogStatus from './features/UpdateChangelogStatus';
|
11
|
+
import Loading from './loading';
|
12
|
+
|
13
|
+
const Page = async () => {
|
14
|
+
const hideDocs = serverFeatureFlags().hideDocs;
|
15
|
+
|
16
|
+
if (hideDocs) return notFound();
|
17
|
+
|
18
|
+
const locale = await getLocale();
|
19
|
+
const mobile = await isMobileDevice();
|
20
|
+
const changelogService = new ChangelogService();
|
21
|
+
const data = await changelogService.getChangelogIndex();
|
22
|
+
|
23
|
+
return (
|
24
|
+
<>
|
25
|
+
{data.map((item) => (
|
26
|
+
<Suspense fallback={<Loading />} key={item.id}>
|
27
|
+
<Post locale={locale} mobile={mobile} {...item} />
|
28
|
+
</Suspense>
|
29
|
+
))}
|
30
|
+
<UpdateChangelogStatus currentId={data[0]?.id} />
|
31
|
+
</>
|
32
|
+
);
|
33
|
+
};
|
34
|
+
|
35
|
+
Page.displayName = 'ChangelogModal';
|
36
|
+
|
37
|
+
export default Page;
|
@@ -8,6 +8,7 @@ import { useTranslation } from 'react-i18next';
|
|
8
8
|
import { useActiveSettingsKey } from '@/hooks/useActiveSettingsKey';
|
9
9
|
import { SettingsTabs } from '@/store/global/initialState';
|
10
10
|
|
11
|
+
import ModalLayout from '../../_layout/ModalLayout';
|
11
12
|
import SettingModalLayout from '../../_layout/SettingModalLayout';
|
12
13
|
|
13
14
|
const CategoryContent = dynamic(
|
@@ -22,22 +23,24 @@ const Layout = memo<PropsWithChildren>(({ children }) => {
|
|
22
23
|
const { t } = useTranslation('setting');
|
23
24
|
const activeKey = useActiveSettingsKey();
|
24
25
|
return (
|
25
|
-
<
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
26
|
+
<ModalLayout>
|
27
|
+
<SettingModalLayout
|
28
|
+
activeTitle={
|
29
|
+
<>
|
30
|
+
{t(`tab.${activeKey}`)}
|
31
|
+
{activeKey === SettingsTabs.Sync && <Tag color={'gold'}>{t('tab.experiment')}</Tag>}
|
32
|
+
</>
|
33
|
+
}
|
34
|
+
category={
|
35
|
+
<>
|
36
|
+
<CategoryContent modal />
|
37
|
+
<UpgradeAlert />
|
38
|
+
</>
|
39
|
+
}
|
40
|
+
>
|
41
|
+
{children}
|
42
|
+
</SettingModalLayout>
|
43
|
+
</ModalLayout>
|
41
44
|
);
|
42
45
|
});
|
43
46
|
|
@@ -0,0 +1,63 @@
|
|
1
|
+
'use client';
|
2
|
+
|
3
|
+
import { Modal, type ModalProps } from '@lobehub/ui';
|
4
|
+
import { useTheme } from 'antd-style';
|
5
|
+
import { useRouter } from 'next/navigation';
|
6
|
+
import { memo, useState } from 'react';
|
7
|
+
|
8
|
+
const ModalLayout = memo<ModalProps>(
|
9
|
+
({
|
10
|
+
children,
|
11
|
+
height = 'min(80vh,750px)',
|
12
|
+
width = 'min(80vw, 1024px)',
|
13
|
+
onCancel,
|
14
|
+
afterClose,
|
15
|
+
styles,
|
16
|
+
...rest
|
17
|
+
}) => {
|
18
|
+
const [open, setOpen] = useState(true);
|
19
|
+
const router = useRouter();
|
20
|
+
const theme = useTheme();
|
21
|
+
|
22
|
+
return (
|
23
|
+
<Modal
|
24
|
+
afterClose={() => {
|
25
|
+
afterClose?.();
|
26
|
+
router.back();
|
27
|
+
}}
|
28
|
+
enableResponsive={false}
|
29
|
+
footer={null}
|
30
|
+
height={height}
|
31
|
+
onCancel={(e) => {
|
32
|
+
onCancel?.(e);
|
33
|
+
setOpen(false);
|
34
|
+
router.back();
|
35
|
+
}}
|
36
|
+
open={open}
|
37
|
+
styles={{
|
38
|
+
...styles,
|
39
|
+
body: {
|
40
|
+
display: 'flex',
|
41
|
+
height: height,
|
42
|
+
overflow: 'hidden',
|
43
|
+
padding: 0,
|
44
|
+
position: 'relative',
|
45
|
+
...styles?.body,
|
46
|
+
},
|
47
|
+
content: {
|
48
|
+
border: 'none',
|
49
|
+
boxShadow: `0 0 0 1px ${theme.colorBorderSecondary}`,
|
50
|
+
...styles?.content,
|
51
|
+
},
|
52
|
+
}}
|
53
|
+
title={false}
|
54
|
+
width={width}
|
55
|
+
{...rest}
|
56
|
+
>
|
57
|
+
{children}
|
58
|
+
</Modal>
|
59
|
+
);
|
60
|
+
},
|
61
|
+
);
|
62
|
+
|
63
|
+
export default ModalLayout;
|