@lobehub/chat 1.39.3 → 1.40.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 (172) hide show
  1. package/.env.example +19 -8
  2. package/.eslintignore +1 -1
  3. package/CHANGELOG.md +33 -0
  4. package/changelog/v1.json +12 -0
  5. package/docs/.cdn.cache.json +25 -0
  6. package/docs/changelog/2023-09-09-plugin-system.mdx +1 -1
  7. package/docs/changelog/2023-09-09-plugin-system.zh-CN.mdx +1 -1
  8. package/docs/changelog/2024-09-20-artifacts.mdx +1 -1
  9. package/docs/changelog/2024-09-20-artifacts.zh-CN.mdx +1 -1
  10. package/docs/changelog/2024-10-27-pin-assistant.mdx +2 -2
  11. package/docs/changelog/2024-10-27-pin-assistant.zh-CN.mdx +2 -2
  12. package/docs/changelog/2024-11-06-share-text-json.mdx +2 -2
  13. package/docs/changelog/2024-11-06-share-text-json.zh-CN.mdx +2 -2
  14. package/docs/changelog/index.json +16 -16
  15. package/locales/ar/changelog.json +18 -0
  16. package/locales/ar/common.json +1 -0
  17. package/locales/ar/metadata.json +4 -0
  18. package/locales/bg-BG/changelog.json +18 -0
  19. package/locales/bg-BG/common.json +1 -0
  20. package/locales/bg-BG/metadata.json +4 -0
  21. package/locales/de-DE/changelog.json +18 -0
  22. package/locales/de-DE/common.json +1 -0
  23. package/locales/de-DE/metadata.json +4 -0
  24. package/locales/en-US/changelog.json +18 -0
  25. package/locales/en-US/common.json +1 -0
  26. package/locales/en-US/metadata.json +4 -0
  27. package/locales/es-ES/changelog.json +18 -0
  28. package/locales/es-ES/common.json +1 -0
  29. package/locales/es-ES/metadata.json +4 -0
  30. package/locales/fa-IR/changelog.json +18 -0
  31. package/locales/fa-IR/common.json +1 -0
  32. package/locales/fa-IR/metadata.json +4 -0
  33. package/locales/fr-FR/changelog.json +18 -0
  34. package/locales/fr-FR/common.json +1 -0
  35. package/locales/fr-FR/metadata.json +4 -0
  36. package/locales/it-IT/changelog.json +18 -0
  37. package/locales/it-IT/common.json +1 -0
  38. package/locales/it-IT/metadata.json +4 -0
  39. package/locales/ja-JP/changelog.json +18 -0
  40. package/locales/ja-JP/common.json +1 -0
  41. package/locales/ja-JP/metadata.json +4 -0
  42. package/locales/ko-KR/changelog.json +18 -0
  43. package/locales/ko-KR/common.json +1 -0
  44. package/locales/ko-KR/metadata.json +4 -0
  45. package/locales/nl-NL/changelog.json +18 -0
  46. package/locales/nl-NL/common.json +1 -0
  47. package/locales/nl-NL/metadata.json +4 -0
  48. package/locales/pl-PL/changelog.json +18 -0
  49. package/locales/pl-PL/common.json +1 -0
  50. package/locales/pl-PL/metadata.json +4 -0
  51. package/locales/pt-BR/changelog.json +18 -0
  52. package/locales/pt-BR/common.json +1 -0
  53. package/locales/pt-BR/metadata.json +4 -0
  54. package/locales/ru-RU/changelog.json +18 -0
  55. package/locales/ru-RU/common.json +1 -0
  56. package/locales/ru-RU/metadata.json +4 -0
  57. package/locales/tr-TR/changelog.json +18 -0
  58. package/locales/tr-TR/common.json +1 -0
  59. package/locales/tr-TR/metadata.json +4 -0
  60. package/locales/vi-VN/changelog.json +18 -0
  61. package/locales/vi-VN/common.json +1 -0
  62. package/locales/vi-VN/metadata.json +4 -0
  63. package/locales/zh-CN/changelog.json +18 -0
  64. package/locales/zh-CN/common.json +1 -0
  65. package/locales/zh-CN/metadata.json +4 -0
  66. package/locales/zh-TW/changelog.json +18 -0
  67. package/locales/zh-TW/common.json +1 -0
  68. package/locales/zh-TW/metadata.json +4 -0
  69. package/package.json +6 -1
  70. package/scripts/cdnWorkflow/index.ts +217 -0
  71. package/scripts/cdnWorkflow/optimized.ts +21 -0
  72. package/scripts/cdnWorkflow/s3/index.ts +120 -0
  73. package/scripts/cdnWorkflow/s3/types.ts +25 -0
  74. package/scripts/cdnWorkflow/s3/utils.ts +106 -0
  75. package/scripts/cdnWorkflow/uploader.ts +73 -0
  76. package/scripts/cdnWorkflow/utils.ts +93 -0
  77. package/src/app/(main)/(mobile)/me/(home)/__tests__/useCategory.test.tsx +25 -12
  78. package/src/app/(main)/(mobile)/me/(home)/features/useCategory.tsx +19 -9
  79. package/src/app/(main)/_layout/Desktop.tsx +4 -1
  80. package/src/app/(main)/_layout/Mobile.tsx +2 -1
  81. package/src/app/(main)/changelog/_layout/Desktop.tsx +25 -0
  82. package/src/app/(main)/changelog/_layout/Mobile/Header.tsx +33 -0
  83. package/src/app/(main)/changelog/_layout/Mobile/index.tsx +21 -0
  84. package/src/app/(main)/changelog/error.tsx +5 -0
  85. package/src/app/(main)/changelog/features/GridLayout.tsx +22 -0
  86. package/src/app/(main)/changelog/features/Hero.tsx +40 -0
  87. package/src/app/(main)/changelog/features/Post.tsx +56 -0
  88. package/src/app/(main)/changelog/features/PublishedTime.tsx +50 -0
  89. package/src/app/(main)/changelog/features/VersionTag.tsx +27 -0
  90. package/src/app/(main)/changelog/layout.tsx +10 -0
  91. package/src/app/(main)/changelog/loading.tsx +3 -0
  92. package/src/app/(main)/changelog/modal/page.tsx +23 -0
  93. package/src/app/(main)/changelog/not-found.tsx +3 -0
  94. package/src/app/(main)/changelog/page.tsx +73 -0
  95. package/src/app/(main)/chat/(workspace)/page.tsx +9 -2
  96. package/src/app/(main)/settings/about/features/Version.tsx +2 -2
  97. package/src/app/@modal/(.)changelog/modal/features/Cover.tsx +48 -0
  98. package/src/app/@modal/(.)changelog/modal/features/Hero.tsx +29 -0
  99. package/src/app/@modal/(.)changelog/modal/features/Pagination.tsx +54 -0
  100. package/src/app/@modal/(.)changelog/modal/features/Post.tsx +57 -0
  101. package/src/app/@modal/(.)changelog/modal/features/PublishedTime.tsx +50 -0
  102. package/src/app/@modal/(.)changelog/modal/features/ReadDetail.tsx +94 -0
  103. package/src/app/@modal/(.)changelog/modal/features/UpdateChangelogStatus.tsx +21 -0
  104. package/src/app/@modal/(.)changelog/modal/features/VersionTag.tsx +27 -0
  105. package/src/app/@modal/(.)changelog/modal/layout.tsx +39 -0
  106. package/src/app/@modal/(.)changelog/modal/loading.tsx +10 -0
  107. package/src/app/@modal/(.)changelog/modal/page.tsx +37 -0
  108. package/src/app/@modal/(.)settings/modal/layout.tsx +19 -16
  109. package/src/app/@modal/_layout/ModalLayout.tsx +63 -0
  110. package/src/app/@modal/chat/(.)settings/modal/layout.tsx +20 -17
  111. package/src/app/@modal/layout.tsx +5 -69
  112. package/src/components/mdx/Image.tsx +50 -0
  113. package/src/components/mdx/index.tsx +2 -0
  114. package/src/const/url.ts +1 -0
  115. package/src/features/ChangelogModal/index.tsx +22 -0
  116. package/src/features/User/UserPanel/useMenu.tsx +50 -46
  117. package/src/features/User/__tests__/useMenu.test.tsx +7 -6
  118. package/src/hooks/useInterceptingRoutes.ts +1 -6
  119. package/src/hooks/useShare.tsx +1 -0
  120. package/src/locales/default/changelog.ts +18 -0
  121. package/src/locales/default/common.ts +1 -0
  122. package/src/locales/default/index.ts +2 -0
  123. package/src/locales/default/metadata.ts +4 -0
  124. package/src/server/metadata.ts +5 -3
  125. package/src/server/routers/edge/appStatus.ts +3 -0
  126. package/src/server/routers/edge/index.ts +2 -0
  127. package/src/server/routers/lambda/agent.ts +1 -1
  128. package/src/server/services/changelog/index.test.ts +310 -0
  129. package/src/server/services/changelog/index.ts +196 -0
  130. package/src/server/services/discover/index.test.ts +0 -1
  131. package/src/server/sitemap.ts +4 -1
  132. package/src/services/__tests__/chat.test.ts +1 -1
  133. package/src/services/__tests__/global.test.ts +5 -2
  134. package/src/services/_auth.ts +1 -1
  135. package/src/services/agent.ts +25 -21
  136. package/src/services/chat.ts +2 -2
  137. package/src/services/file/ClientS3/index.ts +6 -6
  138. package/src/services/file/client.ts +14 -15
  139. package/src/services/file/server.ts +20 -25
  140. package/src/services/global.ts +2 -2
  141. package/src/services/import/client.ts +6 -5
  142. package/src/services/import/server.ts +6 -5
  143. package/src/services/import/type.ts +7 -0
  144. package/src/services/knowledgeBase.ts +19 -19
  145. package/src/services/message/_deprecated.ts +5 -0
  146. package/src/services/message/client.ts +52 -48
  147. package/src/services/message/server.ts +50 -53
  148. package/src/services/message/type.ts +2 -2
  149. package/src/services/plugin/client.ts +16 -22
  150. package/src/services/plugin/server.ts +15 -19
  151. package/src/services/rag.ts +18 -18
  152. package/src/services/ragEval.ts +29 -26
  153. package/src/services/session/_deprecated.ts +2 -2
  154. package/src/services/session/client.ts +55 -81
  155. package/src/services/session/server.ts +50 -74
  156. package/src/services/session/type.ts +4 -6
  157. package/src/services/share.ts +4 -4
  158. package/src/services/textToImage.ts +5 -2
  159. package/src/services/thread/client.ts +9 -15
  160. package/src/services/thread/server.ts +10 -15
  161. package/src/services/topic/client.ts +25 -25
  162. package/src/services/topic/server.ts +25 -42
  163. package/src/services/trace.ts +4 -4
  164. package/src/services/user/client.ts +13 -17
  165. package/src/services/user/server.ts +9 -13
  166. package/src/services/user/type.ts +1 -1
  167. package/src/store/chat/slices/message/reducer.ts +3 -2
  168. package/src/store/global/action.ts +27 -22
  169. package/src/store/global/initialState.ts +1 -0
  170. package/src/types/changelog.ts +6 -0
  171. package/src/types/message/index.ts +10 -8
  172. 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.title', { appName: BRANDING_NAME }),
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.title', { appName: BRANDING_NAME }),
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, RELEASES_URL } from '@/const/url';
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={RELEASES_URL} style={{ flex: 1 }} target={'_blank'}>
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,10 @@
1
+ import { Skeleton } from 'antd';
2
+ import { Flexbox } from 'react-layout-kit';
3
+
4
+ export default () => {
5
+ return (
6
+ <Flexbox paddingBlock={12} paddingInline={24}>
7
+ <Skeleton active paragraph={{ rows: 5 }} title={false} />
8
+ </Flexbox>
9
+ );
10
+ };
@@ -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
- <SettingModalLayout
26
- activeTitle={
27
- <>
28
- {t(`tab.${activeKey}`)}
29
- {activeKey === SettingsTabs.Sync && <Tag color={'gold'}>{t('tab.experiment')}</Tag>}
30
- </>
31
- }
32
- category={
33
- <>
34
- <CategoryContent modal />
35
- <UpgradeAlert />
36
- </>
37
- }
38
- >
39
- {children}
40
- </SettingModalLayout>
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;