@lobehub/chat 0.153.0 → 0.153.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.
Files changed (46) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/locales/ar/common.json +1 -0
  3. package/locales/bg-BG/common.json +1 -0
  4. package/locales/de-DE/common.json +1 -0
  5. package/locales/en-US/common.json +1 -0
  6. package/locales/es-ES/common.json +1 -0
  7. package/locales/fr-FR/common.json +1 -0
  8. package/locales/it-IT/common.json +1 -0
  9. package/locales/ja-JP/common.json +1 -0
  10. package/locales/ko-KR/common.json +1 -0
  11. package/locales/nl-NL/common.json +1 -0
  12. package/locales/pl-PL/common.json +1 -0
  13. package/locales/pt-BR/common.json +1 -0
  14. package/locales/ru-RU/common.json +1 -0
  15. package/locales/tr-TR/common.json +1 -0
  16. package/locales/vi-VN/common.json +1 -0
  17. package/locales/zh-CN/common.json +1 -0
  18. package/locales/zh-TW/common.json +1 -0
  19. package/package.json +1 -1
  20. package/src/app/(main)/(mobile)/me/features/AvatarBanner.tsx +12 -40
  21. package/src/app/(main)/(mobile)/me/features/Header.tsx +37 -0
  22. package/src/app/(main)/(mobile)/me/features/style.ts +29 -0
  23. package/src/app/(main)/(mobile)/me/layout.tsx +7 -1
  24. package/src/app/(main)/(mobile)/me/loading.tsx +22 -7
  25. package/src/app/(main)/(mobile)/me/page.tsx +4 -5
  26. package/src/app/(main)/@nav/_layout/Mobile.tsx +2 -2
  27. package/src/app/(main)/market/@detail/features/{AgentDetailContent/index.tsx → AgentDetailContent.tsx} +6 -12
  28. package/src/app/(main)/market/@detail/features/Banner.tsx +46 -0
  29. package/src/app/(main)/market/@detail/features/{AgentDetailContent/Header.tsx → Header.tsx} +4 -18
  30. package/src/app/(main)/market/@detail/features/{AgentDetailContent/Loading.tsx → Loading.tsx} +5 -4
  31. package/src/app/(main)/market/@detail/features/{AgentDetailContent/style.ts → style.ts} +0 -3
  32. package/src/app/(main)/market/features/AgentCard/AgentCardBanner.tsx +13 -8
  33. package/src/app/(main)/market/loading.tsx +13 -1
  34. package/src/components/Cell/Divider.tsx +2 -0
  35. package/src/components/Cell/index.tsx +5 -1
  36. package/src/components/server/MobileNavLayout.tsx +1 -0
  37. package/src/features/Conversation/components/InboxWelcome/AgentsSuggest.tsx +15 -6
  38. package/src/features/Conversation/components/InboxWelcome/QuestionSuggest.tsx +9 -4
  39. package/src/features/Conversation/components/InboxWelcome/index.tsx +5 -3
  40. package/src/features/DataImporter/index.tsx +4 -1
  41. package/src/features/User/PlanTag.tsx +45 -0
  42. package/src/features/User/UserInfo.tsx +26 -9
  43. package/src/locales/default/common.ts +2 -1
  44. package/src/styles/mobileHeader.ts +7 -0
  45. /package/src/app/(main)/market/@detail/features/{AgentDetailContent/Comment.tsx → Comment.tsx} +0 -0
  46. /package/src/app/(main)/market/@detail/features/{AgentDetailContent/TokenTag.tsx → TokenTag.tsx} +0 -0
package/CHANGELOG.md CHANGED
@@ -2,6 +2,31 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 0.153.1](https://github.com/lobehub/lobe-chat/compare/v0.153.0...v0.153.1)
6
+
7
+ <sup>Released on **2024-05-04**</sup>
8
+
9
+ #### 💄 Styles
10
+
11
+ - **misc**: Imporve mobile styles and loading skeleton.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### Styles
19
+
20
+ - **misc**: Imporve mobile styles and loading skeleton, closes [#2363](https://github.com/lobehub/lobe-chat/issues/2363) ([8ee3591](https://github.com/lobehub/lobe-chat/commit/8ee3591))
21
+
22
+ </details>
23
+
24
+ <div align="right">
25
+
26
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
27
+
28
+ </div>
29
+
5
30
  ## [Version 0.153.0](https://github.com/lobehub/lobe-chat/compare/v0.152.12...v0.153.0)
6
31
 
7
32
  <sup>Released on **2024-05-04**</sup>
@@ -169,6 +169,7 @@
169
169
  "help": "مركز المساعدة",
170
170
  "moveGuide": "تم نقل زر الإعدادات إلى هنا",
171
171
  "plans": "خطط الاشتراك",
172
+ "preview": "المعاينة",
172
173
  "profile": "إدارة الحساب",
173
174
  "setting": "إعدادات التطبيق",
174
175
  "usages": "إحصاءات الاستخدام"
@@ -169,6 +169,7 @@
169
169
  "help": "Център за помощ",
170
170
  "moveGuide": "Бутонът за настройки е преместен тук",
171
171
  "plans": "Планове за абонамент",
172
+ "preview": "Преглед",
172
173
  "profile": "Управление на профила",
173
174
  "setting": "Настройки на приложението",
174
175
  "usages": "Статистика за използване"
@@ -169,6 +169,7 @@
169
169
  "help": "Hilfezentrum",
170
170
  "moveGuide": "Die Einstellungen wurden hierher verschoben.",
171
171
  "plans": "Abonnementpläne",
172
+ "preview": "Vorschau",
172
173
  "profile": "Kontoverwaltung",
173
174
  "setting": "App-Einstellungen",
174
175
  "usages": "Nutzungsstatistiken"
@@ -169,6 +169,7 @@
169
169
  "help": "Help Center",
170
170
  "moveGuide": "The settings button has been moved here",
171
171
  "plans": "Subscription Plans",
172
+ "preview": "Preview",
172
173
  "profile": "Account Management",
173
174
  "setting": "App Settings",
174
175
  "usages": "Usage Statistics"
@@ -169,6 +169,7 @@
169
169
  "help": "Centro de ayuda",
170
170
  "moveGuide": "El botón de configuración se ha movido aquí",
171
171
  "plans": "Planes de suscripción",
172
+ "preview": "Vista previa",
172
173
  "profile": "Gestión de cuenta",
173
174
  "setting": "Configuración de la aplicación",
174
175
  "usages": "Estadísticas de uso"
@@ -169,6 +169,7 @@
169
169
  "help": "Centre d'aide",
170
170
  "moveGuide": "Le bouton de configuration a été déplacé ici",
171
171
  "plans": "Forfaits d'abonnement",
172
+ "preview": "Aperçu",
172
173
  "profile": "Gestion du compte",
173
174
  "setting": "Paramètres de l'application",
174
175
  "usages": "Statistiques d'utilisation"
@@ -169,6 +169,7 @@
169
169
  "help": "Centro assistenza",
170
170
  "moveGuide": "Il pulsante delle impostazioni è stato spostato qui",
171
171
  "plans": "Piani di abbonamento",
172
+ "preview": "Anteprima",
172
173
  "profile": "Gestione account",
173
174
  "setting": "Impostazioni app",
174
175
  "usages": "Statistiche di utilizzo"
@@ -169,6 +169,7 @@
169
169
  "help": "ヘルプセンター",
170
170
  "moveGuide": "設定ボタンがこちらに移動しました",
171
171
  "plans": "サブスクリプションプラン",
172
+ "preview": "プレビュー",
172
173
  "profile": "アカウント管理",
173
174
  "setting": "アプリ設定",
174
175
  "usages": "利用量統計"
@@ -169,6 +169,7 @@
169
169
  "help": "도움말 센터",
170
170
  "moveGuide": "설정 버튼을 여기로 이동했습니다",
171
171
  "plans": "요금제",
172
+ "preview": "미리보기",
172
173
  "profile": "계정 관리",
173
174
  "setting": "앱 설정",
174
175
  "usages": "사용량 통계"
@@ -169,6 +169,7 @@
169
169
  "help": "帮助中心",
170
170
  "moveGuide": "De instellingenknop is hierheen verplaatst",
171
171
  "plans": "订阅方案",
172
+ "preview": "Voorbeeld",
172
173
  "profile": "账户管理",
173
174
  "setting": "应用设置",
174
175
  "usages": "用量统计"
@@ -169,6 +169,7 @@
169
169
  "help": "Centrum pomocy",
170
170
  "moveGuide": "Przenieś przycisk ustawień tutaj",
171
171
  "plans": "Plan abonamentu",
172
+ "preview": "Podgląd",
172
173
  "profile": "Zarządzanie kontem",
173
174
  "setting": "Ustawienia aplikacji",
174
175
  "usages": "Statystyki użycia"
@@ -169,6 +169,7 @@
169
169
  "help": "Central de Ajuda",
170
170
  "moveGuide": "O botão de configurações foi movido para cá",
171
171
  "plans": "Planos de Assinatura",
172
+ "preview": "Versão de visualização",
172
173
  "profile": "Gerenciamento de Conta",
173
174
  "setting": "Configurações do Aplicativo",
174
175
  "usages": "Estatísticas de Uso"
@@ -169,6 +169,7 @@
169
169
  "help": "Центр помощи",
170
170
  "moveGuide": "Кнопка настроек перемещена сюда",
171
171
  "plans": "Планы подписки",
172
+ "preview": "Предпросмотр",
172
173
  "profile": "Управление аккаунтом",
173
174
  "setting": "Настройки приложения",
174
175
  "usages": "Статистика использования"
@@ -169,6 +169,7 @@
169
169
  "help": "Yardım Merkezi",
170
170
  "moveGuide": "Ayarlar düğmesini buraya taşıyın",
171
171
  "plans": "Planlar",
172
+ "preview": "Önizleme",
172
173
  "profile": "Hesap Yönetimi",
173
174
  "setting": "Uygulama Ayarları",
174
175
  "usages": "Kullanım İstatistikleri"
@@ -169,6 +169,7 @@
169
169
  "help": "Trung tâm trợ giúp",
170
170
  "moveGuide": "Đã di chuyển nút cài đặt đến đây",
171
171
  "plans": "Kế hoạch đăng ký",
172
+ "preview": "Phiên bản xem trước",
172
173
  "profile": "Quản lý tài khoản",
173
174
  "setting": "Cài đặt ứng dụng",
174
175
  "usages": "Thống kê sử dụng"
@@ -169,6 +169,7 @@
169
169
  "help": "帮助中心",
170
170
  "moveGuide": "设置按钮搬到这里啦",
171
171
  "plans": "订阅方案",
172
+ "preview": "预览版",
172
173
  "profile": "账户管理",
173
174
  "setting": "应用设置",
174
175
  "usages": "用量统计"
@@ -169,6 +169,7 @@
169
169
  "help": "幫助中心",
170
170
  "moveGuide": "設置按鈕搬到這裡啦",
171
171
  "plans": "訂閱方案",
172
+ "preview": "預覽",
172
173
  "profile": "帳戶管理",
173
174
  "setting": "應用設定",
174
175
  "usages": "用量統計"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "0.153.0",
3
+ "version": "0.153.1",
4
4
  "description": "Lobe Chat - an open-source, high-performance chatbot 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",
@@ -1,55 +1,27 @@
1
1
  'use client';
2
2
 
3
- import { createStyles } from 'antd-style';
4
3
  import { PropsWithChildren, memo } from 'react';
5
- import { Center, Flexbox } from 'react-layout-kit';
4
+ import { Flexbox } from 'react-layout-kit';
6
5
 
7
- export const AVATAR_SIZE = 80;
8
-
9
- export const useStyles = createStyles(({ css, token, isDarkMode }) => ({
10
- avatar: css`
11
- z-index: 10;
12
-
13
- flex: none;
14
-
15
- margin-top: -${AVATAR_SIZE / 2 + 6}px;
6
+ import UserAvatar from '@/features/User/UserAvatar';
7
+ import UserInfo from '@/features/User/UserInfo';
16
8
 
17
- background: ${isDarkMode ? token.colorBgLayout : token.colorBgContainer};
18
- border: 6px solid ${isDarkMode ? token.colorBgLayout : token.colorBgContainer};
19
- border-radius: 50%;
20
- `,
21
- banner: css`
22
- position: relative;
23
- flex: none;
24
- background: ${isDarkMode ? token.colorBgLayout : token.colorBgContainer};
25
- `,
26
- bannerBox: css`
27
- position: relative;
9
+ import { useStyles } from './style';
28
10
 
29
- overflow: hidden;
30
-
31
- width: 100%;
32
- height: 100px;
33
-
34
- background: ${token.colorBgLayout};
35
- `,
36
- bannerImg: css`
37
- position: absolute;
38
- scale: 5;
39
- filter: blur(24px) saturate(2);
40
- `,
41
- }));
11
+ export const AVATAR_SIZE = 80;
42
12
 
43
- const AvatarBanner = memo<PropsWithChildren>(({ children }) => {
13
+ const AvatarBanner = memo<PropsWithChildren>(() => {
44
14
  const { styles } = useStyles();
45
15
 
46
16
  return (
47
- <Flexbox align={'center'} className={styles.banner} justify={'center'} width={'100%'}>
17
+ <>
48
18
  <Flexbox align={'center'} className={styles.bannerBox} justify={'center'}>
49
- <div className={styles.bannerImg}>{children}</div>
19
+ <div className={styles.bannerImg}>
20
+ <UserAvatar shape={'square'} size={AVATAR_SIZE} />
21
+ </div>
50
22
  </Flexbox>
51
- <Center className={styles.avatar}>{children}</Center>
52
- </Flexbox>
23
+ <UserInfo className={styles.info} />
24
+ </>
53
25
  );
54
26
  });
55
27
 
@@ -0,0 +1,37 @@
1
+ 'use client';
2
+
3
+ import { ActionIcon, MobileNavBar } from '@lobehub/ui';
4
+ import { useScroll } from 'ahooks';
5
+ import { useTheme } from 'antd-style';
6
+ import { Moon, Sun } from 'lucide-react';
7
+ import { memo } from 'react';
8
+
9
+ import { MOBILE_HEADER_ICON_SIZE } from '@/const/layoutTokens';
10
+ import { useUserStore } from '@/store/user';
11
+ import { mobileHeaderFixed } from '@/styles/mobileHeader';
12
+
13
+ const Header = memo(() => {
14
+ const theme = useTheme();
15
+ const scroll = useScroll(() => document.querySelector('#lobe-mobile-scroll-container'));
16
+ const switchThemeMode = useUserStore((s) => s.switchThemeMode);
17
+ const showBackground = (scroll as any)?.top > 44;
18
+
19
+ return (
20
+ <MobileNavBar
21
+ right={
22
+ <ActionIcon
23
+ color={showBackground ? undefined : theme.colorBgLayout}
24
+ icon={theme.isDarkMode ? Moon : Sun}
25
+ onClick={() => switchThemeMode(theme.isDarkMode ? 'light' : 'dark')}
26
+ size={MOBILE_HEADER_ICON_SIZE}
27
+ />
28
+ }
29
+ style={{
30
+ ...mobileHeaderFixed,
31
+ background: showBackground ? undefined : 'transparent',
32
+ }}
33
+ />
34
+ );
35
+ });
36
+
37
+ export default Header;
@@ -0,0 +1,29 @@
1
+ import { createStyles } from 'antd-style';
2
+
3
+ export const useStyles = createStyles(({ css, token, isDarkMode }) => ({
4
+ bannerBox: css`
5
+ position: relative;
6
+
7
+ overflow: hidden;
8
+ flex: none;
9
+
10
+ width: 100%;
11
+ height: 100px;
12
+
13
+ background: ${token.colorFill};
14
+ `,
15
+ bannerImg: css`
16
+ position: absolute;
17
+ scale: 8;
18
+ filter: blur(6px) saturate(2);
19
+ `,
20
+ info: css`
21
+ position: relative;
22
+
23
+ margin-top: ${-token.borderRadiusLG}px;
24
+
25
+ background: ${isDarkMode ? token.colorBgLayout : token.colorBgContainer};
26
+ border-top-left-radius: ${token.borderRadiusLG}px;
27
+ border-top-right-radius: ${token.borderRadiusLG}px;
28
+ `,
29
+ }));
@@ -2,8 +2,14 @@ import { PropsWithChildren } from 'react';
2
2
 
3
3
  import MobileContentLayout from '@/components/server/MobileNavLayout';
4
4
 
5
+ import Header from './features/Header';
6
+
5
7
  const Layout = ({ children }: PropsWithChildren) => {
6
- return <MobileContentLayout withNav>{children}</MobileContentLayout>;
8
+ return (
9
+ <MobileContentLayout header={<Header />} withNav>
10
+ {children}
11
+ </MobileContentLayout>
12
+ );
7
13
  };
8
14
 
9
15
  Layout.displayName = 'MeLayout';
@@ -1,17 +1,32 @@
1
1
  'use client';
2
2
 
3
3
  import { Skeleton } from 'antd';
4
- import { Center } from 'react-layout-kit';
4
+ import { memo } from 'react';
5
+ import { Flexbox } from 'react-layout-kit';
5
6
 
6
7
  import SkeletonLoading from '@/components/SkeletonLoading';
7
8
 
8
- export default () => {
9
+ import { useStyles } from './features/style';
10
+
11
+ const Loading = memo(() => {
12
+ const { styles } = useStyles();
9
13
  return (
10
14
  <>
11
- <Center height={180}>
12
- <Skeleton.Avatar shape={'circle'} size={88} />
13
- </Center>
14
- <SkeletonLoading paragraph={{ rows: 8 }} title={false} />
15
+ <Flexbox align={'center'} className={styles.bannerBox} justify={'center'} />
16
+ <Flexbox
17
+ align={'center'}
18
+ className={styles.info}
19
+ gap={12}
20
+ horizontal
21
+ paddingBlock={12}
22
+ paddingInline={12}
23
+ >
24
+ <Skeleton.Avatar active shape={'circle'} size={48} />
25
+ <Skeleton active paragraph={{ rows: 1 }} title={false} />
26
+ </Flexbox>
27
+ <SkeletonLoading active paragraph={{ rows: 8 }} title={false} />
15
28
  </>
16
29
  );
17
- };
30
+ });
31
+
32
+ export default Loading;
@@ -2,10 +2,10 @@ import { redirect } from 'next/navigation';
2
2
  import { Center } from 'react-layout-kit';
3
3
 
4
4
  import BrandWatermark from '@/components/BrandWatermark';
5
- import UserAvatar from '@/features/User/UserAvatar';
5
+ import Divider from '@/components/Cell/Divider';
6
6
  import { isMobileDevice } from '@/utils/responsive';
7
7
 
8
- import AvatarBanner, { AVATAR_SIZE } from './features/AvatarBanner';
8
+ import AvatarBanner from './features/AvatarBanner';
9
9
  import Cate from './features/Cate';
10
10
  import ExtraCate from './features/ExtraCate';
11
11
 
@@ -16,9 +16,8 @@ const Page = () => {
16
16
 
17
17
  return (
18
18
  <>
19
- <AvatarBanner>
20
- <UserAvatar size={AVATAR_SIZE} />
21
- </AvatarBanner>
19
+ <AvatarBanner />
20
+ <Divider />
22
21
  <Cate />
23
22
  <ExtraCate />
24
23
  <Center padding={16}>
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { Icon, MobileTabBar, type MobileTabBarProps } from '@lobehub/ui';
4
4
  import { createStyles } from 'antd-style';
5
- import { Bot, MessageSquare, User } from 'lucide-react';
5
+ import { Compass, MessageSquare, User } from 'lucide-react';
6
6
  import { useRouter } from 'next/navigation';
7
7
  import { rgba } from 'polished';
8
8
  import { memo, useMemo } from 'react';
@@ -44,7 +44,7 @@ const Nav = memo(() => {
44
44
  title: t('tab.chat'),
45
45
  },
46
46
  {
47
- icon: (active) => <Icon className={active ? styles.active : undefined} icon={Bot} />,
47
+ icon: (active) => <Icon className={active ? styles.active : undefined} icon={Compass} />,
48
48
  key: SidebarTabKey.Market,
49
49
  onClick: () => {
50
50
  router.push('/market');
@@ -5,21 +5,20 @@ import { memo, useState } from 'react';
5
5
  import { useTranslation } from 'react-i18next';
6
6
  import { Flexbox } from 'react-layout-kit';
7
7
 
8
- import AgentCardBanner from '@/app/(main)/market/features/AgentCard/AgentCardBanner';
8
+ import Banner from '@/app/(main)/market/@detail/features/Banner';
9
9
  import { useMarketStore } from '@/store/market';
10
10
 
11
11
  import Comment from './Comment';
12
12
  import Header from './Header';
13
13
  import Loading from './Loading';
14
14
  import TokenTag from './TokenTag';
15
- import { useStyles } from './style';
16
15
 
17
16
  enum InfoTabs {
18
17
  comment = 'comment',
19
18
  prompt = 'prompt',
20
19
  }
21
20
 
22
- const AgentModalInner = memo<{ mobile?: boolean }>(({ mobile }) => {
21
+ const AgentDetailContent = memo<{ mobile?: boolean }>(({ mobile }) => {
23
22
  const [useFetchAgent, currentIdentifier] = useMarketStore((s) => [
24
23
  s.useFetchAgent,
25
24
  s.currentIdentifier,
@@ -27,7 +26,6 @@ const AgentModalInner = memo<{ mobile?: boolean }>(({ mobile }) => {
27
26
  const { t } = useTranslation('market');
28
27
  const [tab, setTab] = useState<string>(InfoTabs.prompt);
29
28
  const { data, isLoading } = useFetchAgent(currentIdentifier);
30
- const { styles } = useStyles();
31
29
 
32
30
  if (isLoading || !data?.meta) return <Loading />;
33
31
 
@@ -36,16 +34,11 @@ const AgentModalInner = memo<{ mobile?: boolean }>(({ mobile }) => {
36
34
 
37
35
  return (
38
36
  <>
39
- <AgentCardBanner
40
- avatar={meta?.avatar}
41
- size={800}
42
- style={{ height: 120, marginBottom: -60 }}
43
- />
44
- <Header mobile={mobile} />
37
+ <Banner avatar={meta.avatar} backgroundColor={meta.backgroundColor} mobile={mobile} />
38
+ <Header />
45
39
  <Flexbox align={'center'}>
46
40
  <TabsNav
47
41
  activeKey={tab}
48
- className={styles.nav}
49
42
  items={[
50
43
  {
51
44
  key: InfoTabs.prompt,
@@ -61,6 +54,7 @@ const AgentModalInner = memo<{ mobile?: boolean }>(({ mobile }) => {
61
54
  },
62
55
  ]}
63
56
  onChange={setTab}
57
+ style={{ paddingTop: 8 }}
64
58
  variant={'compact'}
65
59
  />
66
60
  </Flexbox>
@@ -76,4 +70,4 @@ const AgentModalInner = memo<{ mobile?: boolean }>(({ mobile }) => {
76
70
  );
77
71
  });
78
72
 
79
- export default AgentModalInner;
73
+ export default AgentDetailContent;
@@ -0,0 +1,46 @@
1
+ import { Avatar } from '@lobehub/ui';
2
+ import { Skeleton } from 'antd';
3
+ import { useTheme } from 'antd-style';
4
+ import { memo } from 'react';
5
+ import { Center, Flexbox } from 'react-layout-kit';
6
+
7
+ import AgentCardBanner from '../../features/AgentCard/AgentCardBanner';
8
+
9
+ const Banner = memo<{
10
+ avatar?: string;
11
+ backgroundColor?: string;
12
+ loading?: boolean;
13
+ mobile?: boolean;
14
+ }>(({ avatar, backgroundColor, mobile, loading }) => {
15
+ const theme = useTheme();
16
+
17
+ return (
18
+ <Flexbox align={'center'}>
19
+ <AgentCardBanner
20
+ avatar={loading ? undefined : avatar}
21
+ size={800}
22
+ style={{ height: 120, marginBottom: -60 }}
23
+ />
24
+ <Center
25
+ flex={'none'}
26
+ height={120}
27
+ style={{
28
+ backgroundColor:
29
+ backgroundColor || mobile ? theme.colorBgElevated : theme.colorBgContainer,
30
+ borderRadius: '50%',
31
+ overflow: 'hidden',
32
+ zIndex: 2,
33
+ }}
34
+ width={120}
35
+ >
36
+ {loading ? (
37
+ <Skeleton.Avatar active size={100} />
38
+ ) : (
39
+ <Avatar animation avatar={avatar} shape={'circle'} size={100} />
40
+ )}
41
+ </Center>
42
+ </Flexbox>
43
+ );
44
+ });
45
+
46
+ export default Banner;
@@ -1,4 +1,4 @@
1
- import { Avatar, Tag } from '@lobehub/ui';
1
+ import { Tag } from '@lobehub/ui';
2
2
  import { App, Button, Typography } from 'antd';
3
3
  import isEqual from 'fast-deep-equal';
4
4
  import { startCase } from 'lodash-es';
@@ -16,18 +16,18 @@ import { useStyles } from './style';
16
16
 
17
17
  const { Link } = Typography;
18
18
 
19
- const Header = memo<{ mobile?: boolean }>(({ mobile }) => {
19
+ const Header = memo(() => {
20
20
  const setSearchKeywords = useMarketStore((s) => s.setSearchKeywords);
21
21
  const router = useRouter();
22
22
  const { t } = useTranslation('market');
23
- const { styles, theme } = useStyles();
23
+ const { styles } = useStyles();
24
24
  const createSession = useSessionStore((s) => s.createSession);
25
25
  const agentItem = useMarketStore(agentMarketSelectors.currentAgentItem, isEqual);
26
26
 
27
27
  const { message } = App.useApp();
28
28
 
29
29
  const { meta, createAt, author, homepage, config } = agentItem;
30
- const { avatar, title, description, tags, backgroundColor } = meta;
30
+ const { title, description, tags } = meta;
31
31
 
32
32
  const isMobile = useIsMobile();
33
33
 
@@ -47,20 +47,6 @@ const Header = memo<{ mobile?: boolean }>(({ mobile }) => {
47
47
 
48
48
  return (
49
49
  <Center className={styles.container} gap={16}>
50
- <Center
51
- flex={'none'}
52
- height={120}
53
- style={{
54
- backgroundColor:
55
- backgroundColor || mobile ? theme.colorBgElevated : theme.colorBgContainer,
56
- borderRadius: '50%',
57
- overflow: 'hidden',
58
- zIndex: 2,
59
- }}
60
- width={120}
61
- >
62
- <Avatar animation avatar={avatar} size={100} />
63
- </Center>
64
50
  <h2 className={styles.title}>{title}</h2>
65
51
  <Center gap={6} horizontal style={{ flexWrap: 'wrap' }}>
66
52
  {(tags as string[]).map((tag: string, index) => (
@@ -2,25 +2,26 @@ import { Skeleton } from 'antd';
2
2
  import { memo } from 'react';
3
3
  import { Center, Flexbox } from 'react-layout-kit';
4
4
 
5
+ import Banner from './Banner';
5
6
  import { useStyles } from './style';
6
7
 
7
8
  const Loading = memo(() => {
8
9
  const { styles } = useStyles();
9
10
  return (
10
11
  <>
11
- <Center className={styles.container} gap={16} style={{ paddingTop: 80 }}>
12
- <Skeleton.Avatar active shape={'circle'} size={100} />
12
+ <Banner loading />
13
+ <Center className={styles.container} gap={16}>
13
14
  <Skeleton
14
15
  active
15
16
  className={styles.loading}
16
17
  paragraph={{
17
- rows: 3,
18
+ rows: 2,
18
19
  style: {
19
20
  alignItems: 'center',
20
21
  display: 'flex',
21
22
  flexDirection: 'column',
22
23
  },
23
- width: ['60%', '80%', '20%'],
24
+ width: ['60%', '80%'],
24
25
  }}
25
26
  title={{
26
27
  style: {
@@ -19,9 +19,6 @@ export const useStyles = createStyles(({ css, token, prefixCls }) => ({
19
19
  flex-direction: column;
20
20
  }
21
21
  `,
22
- nav: css`
23
- padding-top: 8px;
24
- `,
25
22
  time: css`
26
23
  font-size: 12px;
27
24
  color: ${token.colorTextDescription};
@@ -22,6 +22,7 @@ export const useStyles = createStyles(({ css, token }) => ({
22
22
 
23
23
  interface AgentCardBannerProps extends DivProps {
24
24
  avatar?: string;
25
+ loading?: boolean;
25
26
  mask?: boolean;
26
27
  maskColor?: string;
27
28
  size?: number;
@@ -29,22 +30,26 @@ interface AgentCardBannerProps extends DivProps {
29
30
 
30
31
  const AgentCardBanner = memo<AgentCardBannerProps>(
31
32
  ({ avatar, className, size = 600, children, ...props }) => {
32
- const { styles, cx } = useStyles();
33
+ const { styles, theme, cx } = useStyles();
33
34
 
34
35
  return (
35
36
  <Flexbox
36
37
  align={'center'}
37
38
  className={cx(styles.banner, className)}
38
39
  justify={'center'}
40
+ style={avatar ? {} : { backgroundColor: theme.colorFillTertiary }}
41
+ width={'100%'}
39
42
  {...props}
40
43
  >
41
- <Avatar
42
- alt={'banner'}
43
- avatar={avatar}
44
- className={styles.bannerImg}
45
- shape={'square'}
46
- size={size}
47
- />
44
+ {avatar && (
45
+ <Avatar
46
+ alt={'banner'}
47
+ avatar={avatar}
48
+ className={styles.bannerImg}
49
+ shape={'square'}
50
+ size={size}
51
+ />
52
+ )}
48
53
  {children}
49
54
  </Flexbox>
50
55
  );
@@ -1,3 +1,15 @@
1
+ 'use client';
2
+
1
3
  import { Skeleton } from 'antd';
4
+ import { Flexbox } from 'react-layout-kit';
2
5
 
3
- export default () => <Skeleton paragraph={{ rows: 8 }} style={{ marginBlock: 24 }} title={false} />;
6
+ export default () => (
7
+ <Flexbox gap={16}>
8
+ <Skeleton.Input active block />
9
+ <Skeleton paragraph={{ rows: 8 }} style={{ marginBlock: 24 }} title={false} />
10
+ <Skeleton.Button active />
11
+ <Skeleton paragraph={{ rows: 8 }} style={{ marginBlock: 24 }} title={false} />
12
+ <Skeleton.Button active />
13
+ <Skeleton paragraph={{ rows: 8 }} style={{ marginBlock: 24 }} title={false} />
14
+ </Flexbox>
15
+ );
@@ -5,6 +5,8 @@ import { memo } from 'react';
5
5
 
6
6
  const useStyles = createStyles(
7
7
  ({ css, token, isDarkMode }) => css`
8
+ flex: none;
9
+ width: 100%;
8
10
  height: 6px;
9
11
  background: ${isDarkMode ? token.colorBgContainer : token.colorBgLayout};
10
12
  `,
@@ -8,7 +8,11 @@ const { Item } = List;
8
8
  const useStyles = createStyles(({ css, token, isDarkMode }) => ({
9
9
  container: css`
10
10
  position: relative;
11
- padding-block: 16px !important;
11
+
12
+ gap: 12px;
13
+
14
+ padding: 16px !important;
15
+
12
16
  background: ${isDarkMode ? token.colorBgLayout : token.colorBgContainer};
13
17
  border-radius: 0;
14
18
  `,
@@ -38,6 +38,7 @@ const MobileContentLayout = ({
38
38
  {header}
39
39
  <Flexbox
40
40
  height="100%"
41
+ id={'lobe-mobile-scroll-container'}
41
42
  style={{
42
43
  overflowX: 'hidden',
43
44
  overflowY: 'auto',
@@ -14,10 +14,12 @@ import { useMarketStore } from '@/store/market';
14
14
 
15
15
  const { Paragraph } = Typography;
16
16
 
17
- const useStyles = createStyles(({ css, token }) => ({
17
+ const useStyles = createStyles(({ css, token, responsive }) => ({
18
18
  card: css`
19
19
  position: relative;
20
20
 
21
+ overflow: hidden;
22
+
21
23
  height: 100%;
22
24
  min-height: 110px;
23
25
  padding: 16px;
@@ -30,6 +32,10 @@ const useStyles = createStyles(({ css, token }) => ({
30
32
  &:hover {
31
33
  background: ${token.colorBgElevated};
32
34
  }
35
+
36
+ ${responsive.mobile} {
37
+ min-height: 72px;
38
+ }
33
39
  `,
34
40
  cardDesc: css`
35
41
  margin-block: 0 !important;
@@ -48,15 +54,18 @@ const useStyles = createStyles(({ css, token }) => ({
48
54
  `,
49
55
  }));
50
56
 
51
- const AgentsSuggest = memo(() => {
57
+ const AgentsSuggest = memo<{ mobile?: boolean }>(({ mobile }) => {
52
58
  const { t } = useTranslation('welcome');
59
+
53
60
  const [sliceStart, setSliceStart] = useState(0);
54
61
  const useFetchAgentList = useMarketStore((s) => s.useFetchAgentList);
55
62
  const { isLoading } = useFetchAgentList();
56
63
  const agentList = useMarketStore((s) => s.agentList, isEqual);
57
64
  const { styles } = useStyles();
58
65
 
59
- const loadingCards = Array.from({ length: 4 }).map((_, index) => (
66
+ const agentLength = mobile ? 3 : 4;
67
+
68
+ const loadingCards = Array.from({ length: agentLength }).map((_, index) => (
60
69
  <Flexbox className={styles.card} key={index}>
61
70
  <Skeleton active avatar paragraph={{ rows: 2 }} title={false} />
62
71
  </Flexbox>
@@ -64,15 +73,15 @@ const AgentsSuggest = memo(() => {
64
73
 
65
74
  const cards = useMemo(
66
75
  () =>
67
- agentList.slice(sliceStart, sliceStart + 4).map((agent) => (
76
+ agentList.slice(sliceStart, sliceStart + agentLength).map((agent) => (
68
77
  <Link href={`/market?agent=${agent.identifier}`} key={agent.identifier}>
69
78
  <Flexbox className={styles.card} gap={8} horizontal>
70
79
  <Avatar avatar={agent.meta.avatar} style={{ flex: 'none' }} />
71
- <Flexbox gap={8}>
80
+ <Flexbox gap={mobile ? 2 : 8} style={{ overflow: 'hidden', width: '100%' }}>
72
81
  <Paragraph className={styles.cardTitle} ellipsis={{ rows: 1 }}>
73
82
  {agent.meta.title}
74
83
  </Paragraph>
75
- <Paragraph className={styles.cardDesc} ellipsis={{ rows: 2 }}>
84
+ <Paragraph className={styles.cardDesc} ellipsis={{ rows: mobile ? 1 : 2 }}>
76
85
  {agent.meta.description}
77
86
  </Paragraph>
78
87
  </Flexbox>
@@ -13,7 +13,7 @@ import { USAGE_DOCUMENTS } from '@/const/url';
13
13
  import { useSendMessage } from '@/features/ChatInput/useSend';
14
14
  import { useChatStore } from '@/store/chat';
15
15
 
16
- const useStyles = createStyles(({ css, token }) => ({
16
+ const useStyles = createStyles(({ css, token, responsive }) => ({
17
17
  card: css`
18
18
  cursor: pointer;
19
19
 
@@ -27,6 +27,10 @@ const useStyles = createStyles(({ css, token }) => ({
27
27
  &:hover {
28
28
  background: ${token.colorBgElevated};
29
29
  }
30
+
31
+ ${responsive.mobile} {
32
+ padding: 8px 16px;
33
+ }
30
34
  `,
31
35
  icon: css`
32
36
  color: ${token.colorTextSecondary};
@@ -52,10 +56,11 @@ const qa = shuffle([
52
56
  'q13',
53
57
  'q14',
54
58
  'q15',
55
- ]).slice(0, 5);
59
+ ]);
56
60
 
57
- const QuestionSuggest = memo(() => {
61
+ const QuestionSuggest = memo<{ mobile?: boolean }>(({ mobile }) => {
58
62
  const [updateInputMessage] = useChatStore((s) => [s.updateInputMessage]);
63
+
59
64
  const { t } = useTranslation('welcome');
60
65
  const { styles } = useStyles();
61
66
  const sendMessage = useSendMessage();
@@ -73,7 +78,7 @@ const QuestionSuggest = memo(() => {
73
78
  </Link>
74
79
  </Flexbox>
75
80
  <Flexbox gap={8} horizontal wrap={'wrap'}>
76
- {qa.map((item) => {
81
+ {qa.slice(0, mobile ? 2 : 5).map((item) => {
77
82
  const text = t(`guide.qa.${item}` as any);
78
83
  return (
79
84
  <Flexbox
@@ -6,6 +6,8 @@ import { memo, useEffect, useState } from 'react';
6
6
  import { useTranslation } from 'react-i18next';
7
7
  import { Center, Flexbox } from 'react-layout-kit';
8
8
 
9
+ import { useIsMobile } from '@/hooks/useIsMobile';
10
+
9
11
  import AgentsSuggest from './AgentsSuggest';
10
12
  import QuestionSuggest from './QuestionSuggest';
11
13
 
@@ -40,7 +42,7 @@ const InboxWelcome = memo(() => {
40
42
  const { t } = useTranslation('welcome');
41
43
  const [greeting, setGreeting] = useState<'morning' | 'noon' | 'afternoon' | 'night'>();
42
44
  const { styles } = useStyles();
43
-
45
+ const mobile = useIsMobile();
44
46
  useEffect(() => {
45
47
  const now = new Date();
46
48
  const hours = now.getHours();
@@ -66,8 +68,8 @@ const InboxWelcome = memo(() => {
66
68
  <Markdown className={styles.desc} variant={'chat'}>
67
69
  {t('guide.defaultMessage')}
68
70
  </Markdown>
69
- <AgentsSuggest />
70
- <QuestionSuggest />
71
+ <AgentsSuggest mobile={mobile} />
72
+ <QuestionSuggest mobile={mobile} />
71
73
  </Flexbox>
72
74
  </Center>
73
75
  );
@@ -22,7 +22,6 @@ const useStyles = createStyles(({ css, token }) => {
22
22
  background-color: transparent;
23
23
  }
24
24
  `,
25
-
26
25
  loader: css`
27
26
  transform: translateX(-${size * 2}px);
28
27
 
@@ -125,6 +124,9 @@ const useStyles = createStyles(({ css, token }) => {
125
124
  }
126
125
  }
127
126
  `,
127
+ wrapper: css`
128
+ font-size: inherit;
129
+ `,
128
130
  };
129
131
  });
130
132
 
@@ -237,6 +239,7 @@ const DataImporter = memo<DataImporterProps>(({ children, onFinishImport }) => {
237
239
 
238
240
  return false;
239
241
  }}
242
+ className={styles.wrapper}
240
243
  maxCount={1}
241
244
  showUploadList={false}
242
245
  >
@@ -0,0 +1,45 @@
1
+ import { Tooltip } from '@lobehub/ui';
2
+ import { Tag } from 'antd';
3
+ import { useTheme } from 'antd-style';
4
+ import { CSSProperties, memo, useMemo } from 'react';
5
+ import { useTranslation } from 'react-i18next';
6
+
7
+ export enum PlanType {
8
+ Preview = 'preview',
9
+ }
10
+
11
+ export interface PlanTagProps {
12
+ type?: PlanType;
13
+ }
14
+
15
+ const PlanTag = memo<PlanTagProps>(({ type = PlanType.Preview }) => {
16
+ const { t } = useTranslation('common');
17
+ const theme = useTheme();
18
+ const tag: {
19
+ desc: string;
20
+ style: CSSProperties;
21
+ title: string;
22
+ } = useMemo(() => {
23
+ switch (type) {
24
+ case PlanType.Preview: {
25
+ return {
26
+ desc: t('userPanel.preview'),
27
+ style: {
28
+ background: theme.colorFill,
29
+ },
30
+ title: 'Preview',
31
+ };
32
+ }
33
+ }
34
+ }, []);
35
+
36
+ return (
37
+ <Tooltip title={tag.desc}>
38
+ <Tag bordered={false} style={{ ...tag.style, borderRadius: 12, cursor: 'pointer' }}>
39
+ {tag.title}
40
+ </Tag>
41
+ </Tooltip>
42
+ );
43
+ });
44
+
45
+ export default PlanTag;
@@ -3,11 +3,13 @@
3
3
  import { createStyles } from 'antd-style';
4
4
  import { memo } from 'react';
5
5
  import { useTranslation } from 'react-i18next';
6
- import { Flexbox } from 'react-layout-kit';
6
+ import { Flexbox, FlexboxProps } from 'react-layout-kit';
7
7
 
8
- import UserAvatar from './UserAvatar';
8
+ import PlanTag from '@/features/User/PlanTag';
9
9
 
10
- const DEFAULT_USERNAME = 'LobeChat Community Edition';
10
+ import UserAvatar, { type UserAvatarProps } from './UserAvatar';
11
+
12
+ const DEFAULT_USERNAME = 'LobeChat';
11
13
 
12
14
  const useStyles = createStyles(({ css, token }) => ({
13
15
  nickname: css`
@@ -21,19 +23,34 @@ const useStyles = createStyles(({ css, token }) => ({
21
23
  `,
22
24
  }));
23
25
 
24
- const UserInfo = memo<{ onClick?: () => void }>(({ onClick }) => {
26
+ export interface UserInfoProps extends FlexboxProps {
27
+ avatarProps?: Partial<UserAvatarProps>;
28
+ }
29
+
30
+ const UserInfo = memo<UserInfoProps>(({ avatarProps, ...rest }) => {
25
31
  const { t } = useTranslation('common');
26
32
  const { styles, theme } = useStyles();
27
33
 
28
34
  const DEFAULT_NICKNAME = t('userPanel.defaultNickname');
29
35
 
30
36
  return (
31
- <Flexbox align={'center'} gap={12} horizontal paddingBlock={12} paddingInline={16}>
32
- <UserAvatar background={theme.colorFill} onClick={onClick} size={48} />
33
- <Flexbox flex={1} gap={6}>
34
- <div className={styles.nickname}>{DEFAULT_NICKNAME}</div>
35
- <div className={styles.username}>{DEFAULT_USERNAME}</div>
37
+ <Flexbox
38
+ align={'center'}
39
+ gap={12}
40
+ horizontal
41
+ justify={'space-between'}
42
+ paddingBlock={12}
43
+ paddingInline={12}
44
+ {...rest}
45
+ >
46
+ <Flexbox align={'center'} gap={12} horizontal>
47
+ <UserAvatar background={theme.colorFill} size={48} {...avatarProps} />
48
+ <Flexbox flex={1} gap={6}>
49
+ <div className={styles.nickname}>{DEFAULT_NICKNAME}</div>
50
+ <div className={styles.username}>{DEFAULT_USERNAME}</div>
51
+ </Flexbox>
36
52
  </Flexbox>
53
+ <PlanTag />
37
54
  </Flexbox>
38
55
  );
39
56
  });
@@ -137,6 +137,7 @@ export default {
137
137
  me: '我',
138
138
  setting: '设置',
139
139
  },
140
+
140
141
  telemetry: {
141
142
  allow: '允许',
142
143
  deny: '拒绝',
@@ -144,7 +145,6 @@ export default {
144
145
  learnMore: '了解更多',
145
146
  title: '帮助 LobeChat 做得更好',
146
147
  },
147
-
148
148
  temp: '临时',
149
149
  terms: '服务条款',
150
150
  updateAgent: '更新助理信息',
@@ -163,6 +163,7 @@ export default {
163
163
  help: '帮助中心',
164
164
  moveGuide: '设置按钮搬到这里啦',
165
165
  plans: '订阅方案',
166
+ preview: '预览版',
166
167
  profile: '账户管理',
167
168
  setting: '应用设置',
168
169
  usages: '用量统计',
@@ -6,3 +6,10 @@ export const mobileHeaderSticky: CSSProperties = {
6
6
  width: '100%',
7
7
  zIndex: 100,
8
8
  };
9
+
10
+ export const mobileHeaderFixed: CSSProperties = {
11
+ position: 'fixed',
12
+ top: 0,
13
+ width: '100%',
14
+ zIndex: 100,
15
+ };