diff --git a/locales/ar/common.json b/locales/ar/common.json index 538cbc2bab0d..7f9a4e2d66a4 100644 --- a/locales/ar/common.json +++ b/locales/ar/common.json @@ -140,6 +140,7 @@ "tab": { "chat": "الدردشة", "market": "الاكتشاف", + "me": "أنا", "setting": "الإعدادات" }, "telemetry": { diff --git a/locales/ar/setting.json b/locales/ar/setting.json index 78748380d53f..188a5d351458 100644 --- a/locales/ar/setting.json +++ b/locales/ar/setting.json @@ -27,9 +27,12 @@ } }, "header": { + "desc": "إعدادات التفضيلات والنماذج.", "global": "إعدادات عامة", "session": "إعدادات الجلسة", - "sessionWithName": "إعدادات الجلسة · {{name}}" + "sessionDesc": "إعداد الشخصية وتفضيلات الجلسة.", + "sessionWithName": "إعدادات الجلسة · {{name}}", + "title": "إعدادات" }, "llm": { "checker": { diff --git a/locales/bg-BG/common.json b/locales/bg-BG/common.json index ec6e4bb35a78..f12aadbb9ec8 100644 --- a/locales/bg-BG/common.json +++ b/locales/bg-BG/common.json @@ -140,6 +140,7 @@ "tab": { "chat": "Чат", "market": "Открий", + "me": "аз", "setting": "Настройки" }, "telemetry": { diff --git a/locales/bg-BG/setting.json b/locales/bg-BG/setting.json index b17c6844c5b2..3326ce875b36 100644 --- a/locales/bg-BG/setting.json +++ b/locales/bg-BG/setting.json @@ -27,9 +27,12 @@ } }, "header": { + "desc": "Предпочитания и настройки на модела.", "global": "Глобални настройки", "session": "Настройки на сесията", - "sessionWithName": "Настройки на сесията · {{name}}" + "sessionDesc": "Задаване на роля и предпочитания за сесия.", + "sessionWithName": "Настройки на сесията · {{name}}", + "title": "Настройки" }, "llm": { "checker": { diff --git a/locales/de-DE/common.json b/locales/de-DE/common.json index 78f67f5418af..ec5a7aaf6487 100644 --- a/locales/de-DE/common.json +++ b/locales/de-DE/common.json @@ -140,6 +140,7 @@ "tab": { "chat": "Chat", "market": "Entdecken", + "me": "Ich", "setting": "Einstellung" }, "telemetry": { diff --git a/locales/de-DE/setting.json b/locales/de-DE/setting.json index 2d47f00ad25b..b8aba7e1764e 100644 --- a/locales/de-DE/setting.json +++ b/locales/de-DE/setting.json @@ -27,9 +27,12 @@ } }, "header": { + "desc": "Präferenzen und Modellkonfigurationen.", "global": "Global Einstellungen", "session": "Sitzungseinstellungen", - "sessionWithName": "Sitzungseinstellungen · {{name}}" + "sessionDesc": "Rollenkonfiguration und Sitzungspräferenzen.", + "sessionWithName": "Sitzungseinstellungen · {{name}}", + "title": "Einstellungen" }, "llm": { "checker": { diff --git a/locales/en-US/common.json b/locales/en-US/common.json index 0c3c4095de66..34a345727537 100644 --- a/locales/en-US/common.json +++ b/locales/en-US/common.json @@ -140,6 +140,7 @@ "tab": { "chat": "Chat", "market": "Discover", + "me": "Me", "setting": "Settings" }, "telemetry": { diff --git a/locales/en-US/setting.json b/locales/en-US/setting.json index 7e3dba5a80d5..5b6bd98f7a9e 100644 --- a/locales/en-US/setting.json +++ b/locales/en-US/setting.json @@ -27,9 +27,12 @@ } }, "header": { + "desc": "Preferences and model settings.", "global": "Global Settings", "session": "Session Settings", - "sessionWithName": "Session Settings · {{name}}" + "sessionDesc": "Role settings and session preferences.", + "sessionWithName": "Session Settings · {{name}}", + "title": "Settings" }, "llm": { "checker": { diff --git a/locales/es-ES/common.json b/locales/es-ES/common.json index 61effe171d23..8398ef7ec62e 100644 --- a/locales/es-ES/common.json +++ b/locales/es-ES/common.json @@ -140,6 +140,7 @@ "tab": { "chat": "Chat", "market": "Descubrir", + "me": "Yo", "setting": "Configuración" }, "telemetry": { diff --git a/locales/es-ES/setting.json b/locales/es-ES/setting.json index 80a91e9fd774..9c38d8ea8c97 100644 --- a/locales/es-ES/setting.json +++ b/locales/es-ES/setting.json @@ -27,9 +27,12 @@ } }, "header": { + "desc": "Preferencias y configuración del modelo.", "global": "Configuración global", "session": "Configuración de la sesión", - "sessionWithName": "Configuración de la sesión · {{name}}" + "sessionDesc": "Configuración de roles y preferencias de sesión.", + "sessionWithName": "Configuración de la sesión · {{name}}", + "title": "Configuración" }, "llm": { "checker": { diff --git a/locales/fr-FR/common.json b/locales/fr-FR/common.json index f87d5a0a8433..9f7f3b945a61 100644 --- a/locales/fr-FR/common.json +++ b/locales/fr-FR/common.json @@ -140,6 +140,7 @@ "tab": { "chat": "Conversation", "market": "Découvrir", + "me": "moi", "setting": "Paramètre" }, "telemetry": { diff --git a/locales/fr-FR/setting.json b/locales/fr-FR/setting.json index e976b8b0be17..4462a3b3a171 100644 --- a/locales/fr-FR/setting.json +++ b/locales/fr-FR/setting.json @@ -27,9 +27,12 @@ } }, "header": { + "desc": "Préférences et paramètres du modèle.", "global": "Paramètres globaux", "session": "Paramètres de session", - "sessionWithName": "Paramètres de session · {{name}}" + "sessionDesc": "Paramètres de personnage et préférences de session.", + "sessionWithName": "Paramètres de session · {{name}}", + "title": "Paramètres" }, "llm": { "checker": { diff --git a/locales/it-IT/common.json b/locales/it-IT/common.json index 50eb8570a297..80ea9747eee9 100644 --- a/locales/it-IT/common.json +++ b/locales/it-IT/common.json @@ -140,6 +140,7 @@ "tab": { "chat": "Chat", "market": "Scopri", + "me": "io", "setting": "Impostazioni" }, "telemetry": { diff --git a/locales/it-IT/setting.json b/locales/it-IT/setting.json index c9fc959ab34f..4479c0969545 100644 --- a/locales/it-IT/setting.json +++ b/locales/it-IT/setting.json @@ -27,9 +27,12 @@ } }, "header": { + "desc": "Preferenze e impostazioni del modello.", "global": "Impostazioni globali", "session": "Impostazioni della sessione", - "sessionWithName": "Impostazioni della sessione · {{name}}" + "sessionDesc": "Impostazioni del personaggio e preferenze di sessione.", + "sessionWithName": "Impostazioni della sessione · {{name}}", + "title": "Impostazioni" }, "llm": { "checker": { diff --git a/locales/ja-JP/common.json b/locales/ja-JP/common.json index 8f614f831bfc..9daf9e2e95fe 100644 --- a/locales/ja-JP/common.json +++ b/locales/ja-JP/common.json @@ -140,6 +140,7 @@ "tab": { "chat": "チャット", "market": "探す", + "me": "私", "setting": "設定" }, "telemetry": { diff --git a/locales/ja-JP/setting.json b/locales/ja-JP/setting.json index 1b93126a6bc4..bd16d9e9b62c 100644 --- a/locales/ja-JP/setting.json +++ b/locales/ja-JP/setting.json @@ -27,9 +27,12 @@ } }, "header": { + "desc": "設定優先順位和模型設置。", "global": "グローバル設定", "session": "セッション設定", - "sessionWithName": "セッション設定 · {{name}}" + "sessionDesc": "キャラクター設定とセッションの好み。", + "sessionWithName": "セッション設定 · {{name}}", + "title": "設定" }, "llm": { "checker": { diff --git a/locales/ko-KR/common.json b/locales/ko-KR/common.json index 17c0fd0754dd..739a73b49b63 100644 --- a/locales/ko-KR/common.json +++ b/locales/ko-KR/common.json @@ -140,6 +140,7 @@ "tab": { "chat": "채팅", "market": "발견", + "me": "나", "setting": "설정" }, "telemetry": { diff --git a/locales/ko-KR/setting.json b/locales/ko-KR/setting.json index 1f9074a907fa..de24e392a164 100644 --- a/locales/ko-KR/setting.json +++ b/locales/ko-KR/setting.json @@ -27,9 +27,12 @@ } }, "header": { + "desc": "설정 및 모델 설정.", "global": "전역 설정", "session": "세션 설정", - "sessionWithName": "세션 설정 · {{name}}" + "sessionDesc": "캐릭터 설정 및 세션 환경 설정.", + "sessionWithName": "세션 설정 · {{name}}", + "title": "설정" }, "llm": { "checker": { diff --git a/locales/nl-NL/common.json b/locales/nl-NL/common.json index 19e9e3a6bb28..1a9accaa7318 100644 --- a/locales/nl-NL/common.json +++ b/locales/nl-NL/common.json @@ -140,6 +140,7 @@ "tab": { "chat": "会话", "market": "发现", + "me": "我", "setting": "设置" }, "telemetry": { diff --git a/locales/nl-NL/setting.json b/locales/nl-NL/setting.json index c47a210d402f..fed1c4a904c4 100644 --- a/locales/nl-NL/setting.json +++ b/locales/nl-NL/setting.json @@ -27,9 +27,12 @@ } }, "header": { + "desc": "Voorkeuren en modelinstellingen.", "global": "Algemene instellingen", "session": "Sessie-instellingen", - "sessionWithName": "Sessie-instellingen · {{name}}" + "sessionDesc": "Rolinstellingen en sessievoorkeuren.", + "sessionWithName": "Sessie-instellingen · {{name}}", + "title": "Instellingen" }, "llm": { "checker": { diff --git a/locales/pl-PL/common.json b/locales/pl-PL/common.json index 75f52ec08b82..748960e0d369 100644 --- a/locales/pl-PL/common.json +++ b/locales/pl-PL/common.json @@ -140,6 +140,7 @@ "tab": { "chat": "Czat", "market": "Odkrywaj", + "me": "ja", "setting": "Ustawienia" }, "telemetry": { diff --git a/locales/pl-PL/setting.json b/locales/pl-PL/setting.json index 184438eb3ee4..582be486551f 100644 --- a/locales/pl-PL/setting.json +++ b/locales/pl-PL/setting.json @@ -27,9 +27,12 @@ } }, "header": { + "desc": "Preferencje i ustawienia modelu.", "global": "Ustawienia globalne", "session": "Ustawienia sesji", - "sessionWithName": "Ustawienia sesji · {{name}}" + "sessionDesc": "Ustawienia postaci i preferencje sesji.", + "sessionWithName": "Ustawienia sesji · {{name}}", + "title": "Ustawienia" }, "llm": { "checker": { diff --git a/locales/pt-BR/common.json b/locales/pt-BR/common.json index fd7c390a2314..36bc903397a4 100644 --- a/locales/pt-BR/common.json +++ b/locales/pt-BR/common.json @@ -140,6 +140,7 @@ "tab": { "chat": "Chat", "market": "Descobrir", + "me": "eu", "setting": "Configuração" }, "telemetry": { diff --git a/locales/pt-BR/setting.json b/locales/pt-BR/setting.json index 6b6ccdc9f7e3..de2142df7c51 100644 --- a/locales/pt-BR/setting.json +++ b/locales/pt-BR/setting.json @@ -27,9 +27,12 @@ } }, "header": { + "desc": "Preferências e configurações do modelo.", "global": "Configurações Globais", "session": "Configurações de Sessão", - "sessionWithName": "Configurações de Sessão · {{name}}" + "sessionDesc": "Configurações de personagem e preferências de sessão.", + "sessionWithName": "Configurações de Sessão · {{name}}", + "title": "Configurações" }, "llm": { "checker": { diff --git a/locales/ru-RU/common.json b/locales/ru-RU/common.json index 65c4e4c3cb03..1f91511d08e0 100644 --- a/locales/ru-RU/common.json +++ b/locales/ru-RU/common.json @@ -140,6 +140,7 @@ "tab": { "chat": "Чат", "market": "Обзор", + "me": "я", "setting": "Настройки" }, "telemetry": { diff --git a/locales/ru-RU/setting.json b/locales/ru-RU/setting.json index 5abe02253731..2adb09c57d63 100644 --- a/locales/ru-RU/setting.json +++ b/locales/ru-RU/setting.json @@ -27,9 +27,12 @@ } }, "header": { + "desc": "Настройки предпочтений и моделей.", "global": "Глобальные настройки", "session": "Настройки сеанса", - "sessionWithName": "Настройки сеанса · {{name}}" + "sessionDesc": "Настройки персонажа и предпочтения сессии.", + "sessionWithName": "Настройки сеанса · {{name}}", + "title": "Настройки" }, "llm": { "checker": { diff --git a/locales/tr-TR/common.json b/locales/tr-TR/common.json index fe113b5e713b..d77b7f24f654 100644 --- a/locales/tr-TR/common.json +++ b/locales/tr-TR/common.json @@ -140,6 +140,7 @@ "tab": { "chat": "Chat", "market": "Keşfet", + "me": "ben", "setting": "Ayarlar" }, "telemetry": { diff --git a/locales/tr-TR/setting.json b/locales/tr-TR/setting.json index eeff197922c4..18b2ba254645 100644 --- a/locales/tr-TR/setting.json +++ b/locales/tr-TR/setting.json @@ -27,9 +27,12 @@ } }, "header": { + "desc": "Tercihler ve model ayarları.", "global": "Genel Ayarlar", "session": "Oturum Ayarları", - "sessionWithName": "Oturum Ayarları · {{name}}" + "sessionDesc": "Karakter ayarları ve oturum tercihleri.", + "sessionWithName": "Oturum Ayarları · {{name}}", + "title": "Ayarlar" }, "llm": { "checker": { diff --git a/locales/vi-VN/common.json b/locales/vi-VN/common.json index 48190398947b..bb7998b51d74 100644 --- a/locales/vi-VN/common.json +++ b/locales/vi-VN/common.json @@ -140,6 +140,7 @@ "tab": { "chat": "Trò chuyện", "market": "Thị trường", + "me": "Tôi", "setting": "Cài đặt" }, "telemetry": { diff --git a/locales/vi-VN/setting.json b/locales/vi-VN/setting.json index 09b4f0b5e776..cdd9a17fc3be 100644 --- a/locales/vi-VN/setting.json +++ b/locales/vi-VN/setting.json @@ -27,9 +27,12 @@ } }, "header": { + "desc": "Thiết lập Ưu tiên và Mô hình.", "global": "Cài đặt toàn cầu", "session": "Cài đặt cuộc trò chuyện", - "sessionWithName": "Cài đặt cuộc trò chuyện · {{name}}" + "sessionDesc": "Thiết lập nhân vật và ưu tiên phiên hội thoại.", + "sessionWithName": "Cài đặt cuộc trò chuyện · {{name}}", + "title": "Cài đặt" }, "llm": { "checker": { diff --git a/locales/zh-CN/common.json b/locales/zh-CN/common.json index f5ff9fb2605b..a92637c653df 100644 --- a/locales/zh-CN/common.json +++ b/locales/zh-CN/common.json @@ -140,6 +140,7 @@ "tab": { "chat": "会话", "market": "发现", + "me": "我", "setting": "设置" }, "telemetry": { diff --git a/locales/zh-CN/setting.json b/locales/zh-CN/setting.json index ad0f6bd3bc6b..5a9e5dd56cbe 100644 --- a/locales/zh-CN/setting.json +++ b/locales/zh-CN/setting.json @@ -27,9 +27,12 @@ } }, "header": { + "desc": "偏好与模型设置", "global": "全局设置", "session": "会话设置", - "sessionWithName": "会话设置 · {{name}}" + "sessionDesc": "角色设定与会话偏好", + "sessionWithName": "会话设置 · {{name}}", + "title": "设置" }, "llm": { "checker": { diff --git a/locales/zh-TW/common.json b/locales/zh-TW/common.json index c259830259ef..7476d09e5b38 100644 --- a/locales/zh-TW/common.json +++ b/locales/zh-TW/common.json @@ -140,6 +140,7 @@ "tab": { "chat": "對話", "market": "發現", + "me": "我", "setting": "設定" }, "telemetry": { diff --git a/locales/zh-TW/setting.json b/locales/zh-TW/setting.json index b2c81efa3815..acad5e84b8d6 100644 --- a/locales/zh-TW/setting.json +++ b/locales/zh-TW/setting.json @@ -27,9 +27,12 @@ } }, "header": { + "desc": "偏好與模型設定", "global": "全域設定", "session": "對話設定", - "sessionWithName": "對話設定 · {{name}}" + "sessionDesc": "角色設定與會話偏好", + "sessionWithName": "對話設定 · {{name}}", + "title": "設定" }, "llm": { "checker": { diff --git a/src/app/(main)/(mobile)/me/features/AvatarBanner.tsx b/src/app/(main)/(mobile)/me/features/AvatarBanner.tsx new file mode 100644 index 000000000000..dd3b0e43e702 --- /dev/null +++ b/src/app/(main)/(mobile)/me/features/AvatarBanner.tsx @@ -0,0 +1,52 @@ +'use client'; + +import { createStyles } from 'antd-style'; +import { PropsWithChildren, memo } from 'react'; +import { Center, Flexbox } from 'react-layout-kit'; + +export const useStyles = createStyles(({ css, token }) => ({ + avatar: css` + position: absolute; + z-index: 10; + + flex: none; + + background: ${token.colorBgContainer}; + border: 6px solid ${token.colorBgContainer}; + border-radius: 50%; + `, + banner: css` + position: relative; + flex: none; + `, + bannerBox: css` + position: relative; + + overflow: hidden; + + width: 100%; + height: 180px; + + background: ${token.colorBgLayout}; + `, + bannerImg: css` + position: absolute; + scale: 5; + filter: blur(24px) saturate(2); + `, +})); + +const AvatarBanner = memo(({ children }) => { + const { styles } = useStyles(); + + return ( + + +
{children}
+
+
{children}
+
+ ); +}); + +export default AvatarBanner; diff --git a/src/app/(main)/(mobile)/me/features/Cate.tsx b/src/app/(main)/(mobile)/me/features/Cate.tsx new file mode 100644 index 000000000000..4afe0db3d891 --- /dev/null +++ b/src/app/(main)/(mobile)/me/features/Cate.tsx @@ -0,0 +1,35 @@ +'use client'; + +import { useTheme } from 'antd-style'; +import { useRouter } from 'next/navigation'; +import { memo } from 'react'; +import { Flexbox } from 'react-layout-kit'; +import urlJoin from 'url-join'; + +import { useCategory } from '@/app/(main)/settings/hooks/useCategory'; +import Cell from '@/components/Cell'; +import Divider from '@/components/Cell/Divider'; + +const SettingCate = memo(() => { + const theme = useTheme(); + const settingItems = useCategory({ mobile: true }); + const router = useRouter(); + + return ( + + {settingItems?.map(({ key, icon, label, type }: any, index) => { + if (type === 'divider') return ; + return ( + router.push(urlJoin('/settings', key))} + /> + ); + })} + + ); +}); + +export default SettingCate; diff --git a/src/app/(main)/(mobile)/me/features/ExtraCate.tsx b/src/app/(main)/(mobile)/me/features/ExtraCate.tsx new file mode 100644 index 000000000000..fda9f857772f --- /dev/null +++ b/src/app/(main)/(mobile)/me/features/ExtraCate.tsx @@ -0,0 +1,26 @@ +'use client'; + +import { useTheme } from 'antd-style'; +import { memo } from 'react'; +import { Flexbox } from 'react-layout-kit'; + +import Cell from '@/components/Cell'; +import Divider from '@/components/Cell/Divider'; + +import { useExtraCate } from './useExtraCate'; + +const ExtraCate = memo(() => { + const theme = useTheme(); + const mainItems = useExtraCate(); + + return ( + + {mainItems?.map(({ key, icon, label, type, onClick }: any, index) => { + if (type === 'divider') return ; + return ; + })} + + ); +}); + +export default ExtraCate; diff --git a/src/app/(main)/(mobile)/me/features/useExtraCate.tsx b/src/app/(main)/(mobile)/me/features/useExtraCate.tsx new file mode 100644 index 000000000000..19e6c20ed77d --- /dev/null +++ b/src/app/(main)/(mobile)/me/features/useExtraCate.tsx @@ -0,0 +1,62 @@ +import { DiscordIcon, Icon } from '@lobehub/ui'; +import { Book, Feather, HardDriveDownload, HardDriveUpload } from 'lucide-react'; +import { useTranslation } from 'react-i18next'; + +import { type MenuProps } from '@/components/Menu'; +import { DISCORD, DOCUMENTS, FEEDBACK } from '@/const/url'; +import DataImporter from '@/features/DataImporter'; +import { configService } from '@/services/config'; + +export const useExtraCate = () => { + const { t } = useTranslation(['common', 'setting']); + + const iconSize = { fontSize: 20 }; + + const exports: MenuProps['items'] = [ + { + icon: , + key: 'import', + label: {t('import')}, + }, + { + icon: , + key: 'export', + label: t('export'), + onClick: configService.exportAll, + }, + { + type: 'divider', + }, + ]; + + const helps: MenuProps['items'] = [ + { + icon: , + key: 'docs', + label: t('document'), + onClick: () => window.open(DOCUMENTS, '__blank'), + }, + { + icon: , + key: 'feedback', + label: t('feedback'), + onClick: () => window.open(FEEDBACK, '__blank'), + }, + { + icon: , + key: 'discord', + label: 'Discord', + onClick: () => window.open(DISCORD, '__blank'), + }, + ]; + + const mainItems = [ + { + type: 'divider', + }, + ...exports, + ...helps, + ].filter(Boolean) as MenuProps['items']; + + return mainItems; +}; diff --git a/src/app/(main)/(mobile)/me/layout.tsx b/src/app/(main)/(mobile)/me/layout.tsx new file mode 100644 index 000000000000..e5de18948460 --- /dev/null +++ b/src/app/(main)/(mobile)/me/layout.tsx @@ -0,0 +1,11 @@ +import { PropsWithChildren } from 'react'; + +import MobileContentLayout from '@/components/server/MobileNavLayout'; + +const Layout = ({ children }: PropsWithChildren) => { + return {children}; +}; + +Layout.displayName = 'MeLayout'; + +export default Layout; diff --git a/src/app/(main)/(mobile)/me/loading.tsx b/src/app/(main)/(mobile)/me/loading.tsx new file mode 100644 index 000000000000..b9a637a129dc --- /dev/null +++ b/src/app/(main)/(mobile)/me/loading.tsx @@ -0,0 +1,17 @@ +'use client'; + +import { Skeleton } from 'antd'; +import { Center } from 'react-layout-kit'; + +import SkeletonLoading from '@/components/SkeletonLoading'; + +export default () => { + return ( + <> +
+ +
+ + + ); +}; diff --git a/src/app/(main)/(mobile)/me/page.tsx b/src/app/(main)/(mobile)/me/page.tsx new file mode 100644 index 000000000000..7b448c4997e8 --- /dev/null +++ b/src/app/(main)/(mobile)/me/page.tsx @@ -0,0 +1,31 @@ +import { redirect } from 'next/navigation'; +import { Center } from 'react-layout-kit'; + +import BrandWatermark from '@/components/BrandWatermark'; +import Avatar from '@/features/AvatarWithUpload'; +import { isMobileDevice } from '@/utils/responsive'; + +import AvatarBanner from './features/AvatarBanner'; +import Cate from './features/Cate'; +import ExtraCate from './features/ExtraCate'; + +const Page = () => { + const mobile = isMobileDevice(); + + if (!mobile) return redirect('/chat'); + + return ( + <> + + + + + +
+ +
+ + ); +}; + +export default Page; diff --git a/src/app/(main)/@nav/_layout/Desktop/index.tsx b/src/app/(main)/@nav/_layout/Desktop/index.tsx index 1d1ef6aaf256..cdd7f9631c11 100644 --- a/src/app/(main)/@nav/_layout/Desktop/index.tsx +++ b/src/app/(main)/@nav/_layout/Desktop/index.tsx @@ -15,7 +15,7 @@ const Nav = memo(() => { } bottomActions={} - style={{ height: '100%' }} + style={{ height: '100%', zIndex: 100 }} topActions={} /> ); diff --git a/src/app/(main)/@nav/_layout/Mobile.tsx b/src/app/(main)/@nav/_layout/Mobile.tsx index c62aa07ad868..35fdfae4f35c 100644 --- a/src/app/(main)/@nav/_layout/Mobile.tsx +++ b/src/app/(main)/@nav/_layout/Mobile.tsx @@ -53,11 +53,11 @@ const Nav = memo(() => { }, { icon: (active) => , - key: SidebarTabKey.Setting, + key: SidebarTabKey.Me, onClick: () => { - router.push('/settings'); + router.push('/me'); }, - title: t('tab.setting'), + title: t('tab.me'), }, ], [t], diff --git a/src/app/(main)/chat/(mobile)/features/SessionHeader.tsx b/src/app/(main)/chat/(mobile)/features/SessionHeader.tsx index 185cc0e4cb26..50348b5075ec 100644 --- a/src/app/(main)/chat/(mobile)/features/SessionHeader.tsx +++ b/src/app/(main)/chat/(mobile)/features/SessionHeader.tsx @@ -33,7 +33,7 @@ const Header = memo(() => { -
router.push('/settings')}> +
router.push('/me')}> {avatar ? : }
diff --git a/src/app/(main)/chat/_layout/Desktop/index.tsx b/src/app/(main)/chat/_layout/Desktop/index.tsx index 1589e03853a4..4487be9c1622 100644 --- a/src/app/(main)/chat/_layout/Desktop/index.tsx +++ b/src/app/(main)/chat/_layout/Desktop/index.tsx @@ -1,13 +1,9 @@ -'use client'; - -import { PropsWithChildren, memo } from 'react'; import { Flexbox } from 'react-layout-kit'; -import ClientResponsiveLayout from '@/components/client/ClientResponsiveLayout'; - +import { LayoutProps } from '../type'; import ResponsiveSessionList from './SessionList'; -const Desktop = memo(({ children }: PropsWithChildren) => { +const Layout = ({ children }: LayoutProps) => { return ( <> @@ -21,6 +17,8 @@ const Desktop = memo(({ children }: PropsWithChildren) => { ); -}); +}; + +Layout.displayName = 'DesktopChatLayout'; -export default ClientResponsiveLayout({ Desktop, Mobile: () => import('../Mobile') }); +export default Layout; diff --git a/src/app/(main)/chat/_layout/Mobile/index.tsx b/src/app/(main)/chat/_layout/Mobile/index.tsx index f00a4314acb8..c56a8e065ee3 100644 --- a/src/app/(main)/chat/_layout/Mobile/index.tsx +++ b/src/app/(main)/chat/_layout/Mobile/index.tsx @@ -1,7 +1,9 @@ -import { PropsWithChildren } from 'react'; +import { LayoutProps } from '../type'; -const MobileLayout = ({ children }: PropsWithChildren) => { +const Layout = ({ children }: LayoutProps) => { return children; }; -export default MobileLayout; +Layout.displayName = 'MobileChatLayout'; + +export default Layout; diff --git a/src/app/(main)/chat/_layout/type.ts b/src/app/(main)/chat/_layout/type.ts new file mode 100644 index 000000000000..4d063a09f7fa --- /dev/null +++ b/src/app/(main)/chat/_layout/type.ts @@ -0,0 +1,5 @@ +import { ReactNode } from 'react'; + +export interface LayoutProps { + children: ReactNode; +} diff --git a/src/app/(main)/chat/features/SettingButton.tsx b/src/app/(main)/chat/features/SettingButton.tsx index 47a04ae21296..d7d384604142 100644 --- a/src/app/(main)/chat/features/SettingButton.tsx +++ b/src/app/(main)/chat/features/SettingButton.tsx @@ -1,20 +1,19 @@ import { ActionIcon } from '@lobehub/ui'; import { AlignJustify } from 'lucide-react'; -import { useRouter } from 'next/navigation'; import { memo } from 'react'; import { useTranslation } from 'react-i18next'; import { DESKTOP_HEADER_ICON_SIZE, MOBILE_HEADER_ICON_SIZE } from '@/const/layoutTokens'; +import { useQueryRoute } from '@/hooks/useQueryRoute'; import { useGlobalStore } from '@/store/global'; import { SidebarTabKey } from '@/store/global/initialState'; import { useSessionStore } from '@/store/session'; import { sessionSelectors } from '@/store/session/selectors'; -import { pathString } from '@/utils/url'; const SettingButton = memo<{ mobile?: boolean }>(({ mobile }) => { const isInbox = useSessionStore(sessionSelectors.isInboxSession); const { t } = useTranslation('common'); - const router = useRouter(); + const router = useQueryRoute(); return ( (({ mobile }) => { }); router.push('/settings/agent'); } else { - router.push(pathString('/chat/settings', { search: location.search })); + router.push('/chat/settings'); } }} size={mobile ? MOBILE_HEADER_ICON_SIZE : DESKTOP_HEADER_ICON_SIZE} diff --git a/src/app/(main)/chat/layout.ts b/src/app/(main)/chat/layout.ts index 04c825460fff..713c9b7b7e13 100644 --- a/src/app/(main)/chat/layout.ts +++ b/src/app/(main)/chat/layout.ts @@ -2,7 +2,10 @@ import ServerLayout from '@/components/server/ServerLayout'; import Desktop from './_layout/Desktop'; import Mobile from './_layout/Mobile'; +import { LayoutProps } from './_layout/type'; -const ChatLayout = ServerLayout({ Desktop, Mobile }); +const Layout = ServerLayout({ Desktop, Mobile }); -export default ChatLayout; +Layout.displayName = 'ChatLayout'; + +export default Layout; diff --git a/src/app/(main)/chat/settings/(desktop)/index.tsx b/src/app/(main)/chat/settings/(desktop)/index.tsx deleted file mode 100644 index eec52e1b977f..000000000000 --- a/src/app/(main)/chat/settings/(desktop)/index.tsx +++ /dev/null @@ -1,23 +0,0 @@ -'use client'; - -import { memo } from 'react'; -import { Flexbox } from 'react-layout-kit'; - -import SafeSpacing from '@/components/SafeSpacing'; -import ClientResponsiveContent from '@/components/client/ClientResponsiveContent'; -import { HEADER_HEIGHT } from '@/const/layoutTokens'; - -import EditPage from '../features/EditPage'; -import Header from './Header'; - -const Desktop = memo(() => ( - <> -
- - - - - -)); - -export default ClientResponsiveContent({ Desktop, Mobile: () => import('../(mobile)') }); diff --git a/src/app/(main)/chat/settings/(mobile)/index.tsx b/src/app/(main)/chat/settings/(mobile)/index.tsx deleted file mode 100644 index 77619e905cfc..000000000000 --- a/src/app/(main)/chat/settings/(mobile)/index.tsx +++ /dev/null @@ -1,16 +0,0 @@ -'use client'; - -import { memo } from 'react'; - -import MobileContentLayout from '@/components/server/MobileNavLayout'; - -import EditPage from '../features/EditPage'; -import Header from './Header'; - -const ChatSettings = memo(() => ( - } withNav={false}> - - -)); - -export default ChatSettings; diff --git a/src/app/(main)/chat/settings/(desktop)/Header.tsx b/src/app/(main)/chat/settings/_layout/Desktop/Header.tsx similarity index 97% rename from src/app/(main)/chat/settings/(desktop)/Header.tsx rename to src/app/(main)/chat/settings/_layout/Desktop/Header.tsx index ff2baee6a15e..b0fd25b68e0d 100644 --- a/src/app/(main)/chat/settings/(desktop)/Header.tsx +++ b/src/app/(main)/chat/settings/_layout/Desktop/Header.tsx @@ -1,3 +1,5 @@ +'use client'; + import { ChatHeader, ChatHeaderTitle } from '@lobehub/ui'; import { useRouter } from 'next/navigation'; import { memo } from 'react'; diff --git a/src/app/(main)/chat/settings/_layout/Desktop/index.tsx b/src/app/(main)/chat/settings/_layout/Desktop/index.tsx new file mode 100644 index 000000000000..02e0d7bd5602 --- /dev/null +++ b/src/app/(main)/chat/settings/_layout/Desktop/index.tsx @@ -0,0 +1,28 @@ +import { PropsWithChildren } from 'react'; +import { Flexbox } from 'react-layout-kit'; + +import SafeSpacing from '@/components/SafeSpacing'; +import { HEADER_HEIGHT } from '@/const/layoutTokens'; + +import Header from './Header'; + +const Layout = ({ children }: PropsWithChildren) => ( + <> +
+ + + + {children} + + + +); + +Layout.displayName = 'DesktopSessionSettingsLayout'; + +export default Layout; diff --git a/src/app/(main)/chat/settings/(mobile)/Header.tsx b/src/app/(main)/chat/settings/_layout/Mobile/Header.tsx similarity index 88% rename from src/app/(main)/chat/settings/(mobile)/Header.tsx rename to src/app/(main)/chat/settings/_layout/Mobile/Header.tsx index 911a7dfb3a51..455a6dfa26ad 100644 --- a/src/app/(main)/chat/settings/(mobile)/Header.tsx +++ b/src/app/(main)/chat/settings/_layout/Mobile/Header.tsx @@ -1,13 +1,14 @@ +'use client'; + import { MobileNavBar, MobileNavBarTitle } from '@lobehub/ui'; import { useRouter } from 'next/navigation'; import { memo } from 'react'; import { useTranslation } from 'react-i18next'; +import HeaderContent from '@/app/(main)/chat/settings/features/HeaderContent'; import { mobileHeaderSticky } from '@/styles/mobileHeader'; import { pathString } from '@/utils/url'; -import HeaderContent from '../features/HeaderContent'; - const Header = memo(() => { const { t } = useTranslation('setting'); const router = useRouter(); diff --git a/src/app/(main)/chat/settings/_layout/Mobile/index.tsx b/src/app/(main)/chat/settings/_layout/Mobile/index.tsx new file mode 100644 index 000000000000..47089a1b8f5f --- /dev/null +++ b/src/app/(main)/chat/settings/_layout/Mobile/index.tsx @@ -0,0 +1,15 @@ +'use client'; + +import { PropsWithChildren } from 'react'; + +import MobileContentLayout from '@/components/server/MobileNavLayout'; + +import Header from './Header'; + +const Layout = ({ children }: PropsWithChildren) => ( + }>{children} +); + +Layout.displayName = 'MobileSessionSettingsLayout'; + +export default Layout; diff --git a/src/app/(main)/chat/settings/error.tsx b/src/app/(main)/chat/settings/error.tsx new file mode 100644 index 000000000000..071491038c70 --- /dev/null +++ b/src/app/(main)/chat/settings/error.tsx @@ -0,0 +1,5 @@ +'use client'; + +import dynamic from 'next/dynamic'; + +export default dynamic(() => import('@/components/Error')); diff --git a/src/app/(main)/chat/settings/features/HeaderContent.tsx b/src/app/(main)/chat/settings/features/HeaderContent.tsx index 892aae60e62b..620ea9629190 100644 --- a/src/app/(main)/chat/settings/features/HeaderContent.tsx +++ b/src/app/(main)/chat/settings/features/HeaderContent.tsx @@ -1,5 +1,5 @@ -import { ActionIcon } from '@lobehub/ui'; -import { Dropdown, MenuProps } from 'antd'; +import { ActionIcon, Icon } from '@lobehub/ui'; +import { Button, Dropdown, MenuProps } from 'antd'; import { useResponsive } from 'antd-style'; import { HardDriveDownload } from 'lucide-react'; import { memo, useMemo } from 'react'; @@ -11,7 +11,7 @@ import { useSessionStore } from '@/store/session'; import SubmitAgentButton from './SubmitAgentButton'; -export const HeaderContent = memo<{ mobile?: boolean }>(() => { +export const HeaderContent = memo<{ mobile?: boolean; modal?: boolean }>(({ modal }) => { const { t } = useTranslation('setting'); const id = useSessionStore((s) => s.activeId); @@ -43,13 +43,19 @@ export const HeaderContent = memo<{ mobile?: boolean }>(() => { return ( <> - + - + {modal ? ( + + ) : ( + + )} ); diff --git a/src/app/(main)/chat/settings/features/SubmitAgentButton/SubmitAgentModal.tsx b/src/app/(main)/chat/settings/features/SubmitAgentButton/SubmitAgentModal.tsx index 847276c7b210..a4bb45b69f18 100644 --- a/src/app/(main)/chat/settings/features/SubmitAgentButton/SubmitAgentModal.tsx +++ b/src/app/(main)/chat/settings/features/SubmitAgentButton/SubmitAgentModal.tsx @@ -1,3 +1,5 @@ +'use client'; + import { Alert, Modal, type ModalProps } from '@lobehub/ui'; import { Button, Divider, Input } from 'antd'; import { useTheme } from 'antd-style'; diff --git a/src/app/(main)/chat/settings/features/SubmitAgentButton/index.tsx b/src/app/(main)/chat/settings/features/SubmitAgentButton/index.tsx index af82ad074275..b27e4c6034d3 100644 --- a/src/app/(main)/chat/settings/features/SubmitAgentButton/index.tsx +++ b/src/app/(main)/chat/settings/features/SubmitAgentButton/index.tsx @@ -1,4 +1,5 @@ -import { ActionIcon } from '@lobehub/ui'; +import { ActionIcon, Icon } from '@lobehub/ui'; +import { Button } from 'antd'; import { useResponsive } from 'antd-style'; import { Share2 } from 'lucide-react'; import { memo, useState } from 'react'; @@ -8,18 +9,25 @@ import { HEADER_ICON_SIZE } from '@/const/layoutTokens'; import SubmitAgentModal from './SubmitAgentModal'; -const SubmitAgentButton = memo(() => { +const SubmitAgentButton = memo<{ modal?: boolean }>(({ modal }) => { const { t } = useTranslation('setting'); const { mobile } = useResponsive(); const [isModalOpen, setIsModalOpen] = useState(false); + return ( <> - setIsModalOpen(true)} - size={HEADER_ICON_SIZE(mobile)} - title={t('submitAgentModal.tooltips')} - /> + {modal ? ( + + ) : ( + setIsModalOpen(true)} + size={HEADER_ICON_SIZE(mobile)} + title={t('submitAgentModal.tooltips')} + /> + )} setIsModalOpen(false)} open={isModalOpen} /> ); diff --git a/src/app/(main)/chat/settings/layout.tsx b/src/app/(main)/chat/settings/layout.tsx index 2686bc7dad3d..706ea1bad237 100644 --- a/src/app/(main)/chat/settings/layout.tsx +++ b/src/app/(main)/chat/settings/layout.tsx @@ -1,14 +1,21 @@ import { notFound } from 'next/navigation'; import { PropsWithChildren } from 'react'; +import ServerLayout from '@/components/server/ServerLayout'; import { serverFeatureFlags } from '@/config/server/featureFlags'; +import Desktop from './_layout/Desktop'; +import Mobile from './_layout/Mobile'; + +const SessionSettingsLayout = ServerLayout({ Desktop, Mobile }); + const Layout = ({ children }: PropsWithChildren) => { const isAgentEditable = serverFeatureFlags().isAgentEditable; - if (!isAgentEditable) return notFound(); - return children; + return {children}; }; +Layout.displayName = 'SessionSettingsLayout'; + export default Layout; diff --git a/src/app/(main)/chat/settings/loading.tsx b/src/app/(main)/chat/settings/loading.tsx new file mode 100644 index 000000000000..9ca9c13ee77b --- /dev/null +++ b/src/app/(main)/chat/settings/loading.tsx @@ -0,0 +1,3 @@ +import SkeletonLoading from '@/components/SkeletonLoading'; + +export default () => ; diff --git a/src/app/(main)/chat/settings/not-found.tsx b/src/app/(main)/chat/settings/not-found.tsx new file mode 100644 index 000000000000..02503bc7fa46 --- /dev/null +++ b/src/app/(main)/chat/settings/not-found.tsx @@ -0,0 +1,3 @@ +import dynamic from 'next/dynamic'; + +export default dynamic(() => import('@/components/404')); diff --git a/src/app/(main)/chat/settings/page.tsx b/src/app/(main)/chat/settings/page.tsx index 1c6beb1eb15e..63b66be34dc9 100644 --- a/src/app/(main)/chat/settings/page.tsx +++ b/src/app/(main)/chat/settings/page.tsx @@ -1,14 +1,7 @@ -import { isMobileDevice } from '@/utils/responsive'; - -import DesktopPage from './(desktop)'; -import MobilePage from './(mobile)'; +import EditPage from './features/EditPage'; const Page = () => { - const mobile = isMobileDevice(); - - const Page = mobile ? MobilePage : DesktopPage; - - return ; + return ; }; export default Page; diff --git a/src/app/(main)/market/@detail/default.tsx b/src/app/(main)/market/@detail/default.tsx index 70ed783766c8..35e536e49b70 100644 --- a/src/app/(main)/market/@detail/default.tsx +++ b/src/app/(main)/market/@detail/default.tsx @@ -1,19 +1,10 @@ -import ServerLayout from '@/components/server/ServerLayout'; import { isMobileDevice } from '@/utils/responsive'; -import Desktop from './_layout/Desktop'; -import Mobile from './_layout/Mobile'; import AgentDetailContent from './features/AgentDetailContent'; -const Layout = ServerLayout({ Desktop, Mobile }); - const Detail = () => { const mobile = isMobileDevice(); - return ( - - - - ); + return ; }; Detail.displayName = 'AgentDetail'; diff --git a/src/app/(main)/market/@detail/_layout/Desktop.tsx b/src/app/(main)/market/_layout/Desktop/DetailSidebar.tsx similarity index 95% rename from src/app/(main)/market/@detail/_layout/Desktop.tsx rename to src/app/(main)/market/_layout/Desktop/DetailSidebar.tsx index 8aa4632da23f..bf3846b41998 100644 --- a/src/app/(main)/market/@detail/_layout/Desktop.tsx +++ b/src/app/(main)/market/_layout/Desktop/DetailSidebar.tsx @@ -24,7 +24,7 @@ const useStyles = createStyles(({ css, token, stylish }) => ({ noScrollbar: stylish.noScrollbar, })); -const SideBar = memo(({ children }) => { +const DetailSidebar = memo(({ children }) => { const { styles } = useStyles(); const { md = true } = useResponsive(); const [tempId, setTempId] = useState(''); @@ -81,4 +81,4 @@ const SideBar = memo(({ children }) => { ); }); -export default SideBar; +export default DetailSidebar; diff --git a/src/app/(main)/market/_layout/Desktop/index.tsx b/src/app/(main)/market/_layout/Desktop/index.tsx index 81583db43364..3cf164bd755f 100644 --- a/src/app/(main)/market/_layout/Desktop/index.tsx +++ b/src/app/(main)/market/_layout/Desktop/index.tsx @@ -4,6 +4,7 @@ import SafeSpacing from '@/components/SafeSpacing'; import { MAX_WIDTH } from '@/const/layoutTokens'; import { LayoutProps } from '../type'; +import DetailSidebar from './DetailSidebar'; import Header from './Header'; import Hero from './Hero'; @@ -29,7 +30,7 @@ const Layout = ({ children, detail }: LayoutProps) => { {children} - {detail} + {detail} ); diff --git a/src/app/(main)/market/@detail/_layout/Mobile.tsx b/src/app/(main)/market/_layout/Mobile/DetailModal.tsx similarity index 87% rename from src/app/(main)/market/@detail/_layout/Mobile.tsx rename to src/app/(main)/market/_layout/Mobile/DetailModal.tsx index 18ffcbb13673..31d03ecd4f7c 100644 --- a/src/app/(main)/market/@detail/_layout/Mobile.tsx +++ b/src/app/(main)/market/_layout/Mobile/DetailModal.tsx @@ -6,7 +6,7 @@ import { useTranslation } from 'react-i18next'; import { agentMarketSelectors, useMarketStore } from '@/store/market'; -const AgentDetail = memo(({ children }) => { +const DetailModal = memo(({ children }) => { const [showAgentSidebar, deactivateAgent] = useMarketStore((s) => [ agentMarketSelectors.showSideBar(s), s.deactivateAgent, @@ -29,4 +29,4 @@ const AgentDetail = memo(({ children }) => { ); }); -export default AgentDetail; +export default DetailModal; diff --git a/src/app/(main)/market/_layout/Mobile/index.tsx b/src/app/(main)/market/_layout/Mobile/index.tsx index e2a2acaf406c..415d8776401d 100644 --- a/src/app/(main)/market/_layout/Mobile/index.tsx +++ b/src/app/(main)/market/_layout/Mobile/index.tsx @@ -1,6 +1,7 @@ import MobileContentLayout from '@/components/server/MobileNavLayout'; import { LayoutProps } from '../type'; +import DetailModal from './DetailModal'; import Header from './Header'; const Layout = ({ children, detail }: LayoutProps) => { @@ -10,10 +11,11 @@ const Layout = ({ children, detail }: LayoutProps) => { gap={16} header={
} style={{ paddingInline: 16, paddingTop: 8 }} + withNav > {children} - {detail} + {detail} ); }; diff --git a/src/app/(main)/settings/(desktop)/index.tsx b/src/app/(main)/settings/(desktop)/index.tsx deleted file mode 100644 index 8af7b2d0727a..000000000000 --- a/src/app/(main)/settings/(desktop)/index.tsx +++ /dev/null @@ -1,23 +0,0 @@ -'use client'; - -import dynamic from 'next/dynamic'; -import { FC, memo } from 'react'; - -import MobileSwitchLoading from '@/features/MobileSwitchLoading'; -import { useIsMobile } from '@/hooks/useIsMobile'; - -import Common from '../common'; -import { SettingsCommonProps } from '../common/Common'; - -const Mobile: FC = dynamic(() => import('../(mobile)'), { - loading: MobileSwitchLoading, - ssr: false, -}) as FC; - -const Desktop = memo((props) => { - const mobile = useIsMobile(); - - return mobile ? : ; -}); - -export default Desktop; diff --git a/src/app/(main)/settings/(mobile)/features/AvatarBanner.tsx b/src/app/(main)/settings/(mobile)/features/AvatarBanner.tsx deleted file mode 100644 index 8fde99537506..000000000000 --- a/src/app/(main)/settings/(mobile)/features/AvatarBanner.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { DivProps } from '@lobehub/ui'; -import { createStyles } from 'antd-style'; -import Image from 'next/image'; -import { memo } from 'react'; -import { Flexbox } from 'react-layout-kit'; - -import { DEFAULT_USER_AVATAR_URL } from '@/const/meta'; - -export const useStyles = createStyles(({ css, token }) => ({ - banner: css` - position: relative; - - overflow: hidden; - - height: 172px; - min-height: 172px; - max-height: 172px; - `, - bannerBox: css` - position: relative; - - width: 100%; - height: 100%; - - background: ${token.colorBgLayout}; - - mask-image: linear-gradient(to bottom, #fff, transparent); - `, - bannerImg: css` - position: absolute; - top: -50%; - filter: blur(100px) saturate(2); - `, -})); - -interface AgentCardBannerProps extends DivProps { - avatar: string; - size?: number; -} - -const AvatarBanner = memo( - ({ avatar, className, size = 200, children, ...props }) => { - const { styles, cx } = useStyles(); - - return ( - - - {'banner'} - - {children} - - ); - }, -); - -export default AvatarBanner; diff --git a/src/app/(main)/settings/(mobile)/features/ExtraList.tsx b/src/app/(main)/settings/(mobile)/features/ExtraList.tsx deleted file mode 100644 index 92295ef93954..000000000000 --- a/src/app/(main)/settings/(mobile)/features/ExtraList.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import { Upload } from 'antd'; -import { useResponsive } from 'antd-style'; -import { Feather, FileClock, HardDriveDownload, HardDriveUpload } from 'lucide-react'; -import { memo } from 'react'; -import { useTranslation } from 'react-i18next'; - -import { CHANGELOG, FEEDBACK } from '@/const/url'; -import { useImportConfig } from '@/hooks/useImportConfig'; -import { configService } from '@/services/config'; -import { SettingsTabs } from '@/store/global/initialState'; - -import Item from '../../features/SettingList/Item'; - -interface ExtraListProps { - activeTab?: SettingsTabs; -} -const ExtraList = memo(({ activeTab }) => { - const { t } = useTranslation('common'); - - const { importConfig } = useImportConfig(); - const { mobile } = useResponsive(); - const items = [ - { - icon: HardDriveDownload, - label: t('export'), - onClick: configService.exportAll, - value: 'export', - }, - { - icon: Feather, - label: t('feedback'), - onClick: () => window.open(FEEDBACK, '__blank'), - value: 'feedback', - }, - { - icon: FileClock, - label: t('changelog'), - onClick: () => window.open(CHANGELOG, '__blank'), - value: 'changelog', - }, - ]; - - return ( - <> - { - importConfig(file); - - return false; - }} - maxCount={1} - showUploadList={false} - > - - - {items.map(({ value, icon, label, onClick }) => ( -
- -
- ))} - - ); -}); - -export default ExtraList; diff --git a/src/app/(main)/settings/(mobile)/index.tsx b/src/app/(main)/settings/(mobile)/index.tsx deleted file mode 100644 index d06aa856bec9..000000000000 --- a/src/app/(main)/settings/(mobile)/index.tsx +++ /dev/null @@ -1,53 +0,0 @@ -'use client'; - -import { Divider } from 'antd'; -import { createStyles } from 'antd-style'; -import { memo } from 'react'; -import { Center, Flexbox } from 'react-layout-kit'; - -import { CURRENT_VERSION } from '@/const/version'; -import AvatarWithUpload from '@/features/AvatarWithUpload'; -import { useUserStore } from '@/store/user'; -import { commonSelectors } from '@/store/user/selectors'; - -import SettingList from '../features/SettingList'; -import AvatarBanner from './features/AvatarBanner'; -import ExtraList from './features/ExtraList'; - -const useStyles = createStyles(({ css, token }) => ({ - divider: css` - height: 6px; - background: ${token.colorFillTertiary}; - `, - footer: css` - font-size: 12px; - color: ${token.colorTextQuaternary}; - `, -})); - -const Setting = memo(() => { - const avatar = useUserStore(commonSelectors.userAvatar); - const { styles } = useStyles(); - - return ( - - -
- -
-
-
- -
- -
- - LobeChat v{CURRENT_VERSION} - -
-
- - ); -}); - -export default Setting; diff --git a/src/app/(main)/settings/@category/default.tsx b/src/app/(main)/settings/@category/default.tsx new file mode 100644 index 000000000000..f0a2f1a6c51e --- /dev/null +++ b/src/app/(main)/settings/@category/default.tsx @@ -0,0 +1,16 @@ +import UpgradeAlert from '@/app/(main)/settings/features/UpgradeAlert'; + +import CategoryContent from './features/CategoryContent'; + +const Category = () => { + return ( + <> + + + + ); +}; + +Category.displayName = 'SettingCategory'; + +export default Category; diff --git a/src/app/(main)/settings/@category/features/CategoryContent.tsx b/src/app/(main)/settings/@category/features/CategoryContent.tsx new file mode 100644 index 000000000000..012dce65e795 --- /dev/null +++ b/src/app/(main)/settings/@category/features/CategoryContent.tsx @@ -0,0 +1,33 @@ +'use client'; + +import { memo } from 'react'; +import urlJoin from 'url-join'; + +import Menu from '@/components/Menu'; +import { useActiveSettingsKey } from '@/hooks/useActiveSettingsKey'; +import { useQuery } from '@/hooks/useQuery'; +import { useQueryRoute } from '@/hooks/useQueryRoute'; +import { SettingsTabs } from '@/store/global/initialState'; + +import { useCategory } from '../../hooks/useCategory'; + +const CategoryContent = memo<{ modal?: boolean }>(({ modal }) => { + const activeTab = useActiveSettingsKey(); + const { tab = SettingsTabs.Common } = useQuery(); + const cateItems = useCategory(); + const router = useQueryRoute(); + + return ( + { + router.push(urlJoin('/settings', key)); + }} + selectable + selectedKeys={[modal ? tab : (activeTab as any)]} + variant={'compact'} + /> + ); +}); + +export default CategoryContent; diff --git a/src/app/(main)/settings/@category/features/UpgradeAlert.tsx b/src/app/(main)/settings/@category/features/UpgradeAlert.tsx new file mode 100644 index 000000000000..dcfadb11b974 --- /dev/null +++ b/src/app/(main)/settings/@category/features/UpgradeAlert.tsx @@ -0,0 +1,38 @@ +import { Alert } from '@lobehub/ui'; +import { Button } from 'antd'; +import Link from 'next/link'; +import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; + +import { MANUAL_UPGRADE_URL } from '@/const/url'; +import { useGlobalStore } from '@/store/global'; + +const UpgradeAlert = memo(() => { + const [hasNewVersion, latestVersion] = useGlobalStore((s) => [s.hasNewVersion, s.latestVersion]); + const { t } = useTranslation('common'); + + if (!hasNewVersion) return null; + + return ( + + + + } + closable + message={t('upgradeVersion.newVersion', { version: latestVersion })} + showIcon={false} + type={'info'} + /> + ); +}); + +export default UpgradeAlert; diff --git a/src/app/(main)/settings/_layout/Desktop/Header.tsx b/src/app/(main)/settings/_layout/Desktop/Header.tsx index f22061db376d..f73e8c07658d 100644 --- a/src/app/(main)/settings/_layout/Desktop/Header.tsx +++ b/src/app/(main)/settings/_layout/Desktop/Header.tsx @@ -1,36 +1,91 @@ 'use client'; -import { ChatHeader, ChatHeaderTitle } from '@lobehub/ui'; -import { Tag } from 'antd'; -import { memo } from 'react'; +import { ActionIcon, ChatHeader, ChatHeaderTitle } from '@lobehub/ui'; +import { Drawer, type DrawerProps, Tag } from 'antd'; +import { createStyles } from 'antd-style'; +import { Menu } from 'lucide-react'; +import { PropsWithChildren, memo, useState } from 'react'; import { useTranslation } from 'react-i18next'; import { Flexbox } from 'react-layout-kit'; +import BrandWatermark from '@/components/BrandWatermark'; import { useActiveSettingsKey } from '@/hooks/useActiveSettingsKey'; import { SettingsTabs } from '@/store/global/initialState'; -const Header = memo(() => { - const { t } = useTranslation('setting'); +const useStyles = createStyles(({ token, css }) => ({ + container: css` + position: relative; + height: 54px; + background: ${token.colorBgContainer}; + `, + title: css` + font-size: 18px; + font-weight: 700; + `, +})); - const activeKey = useActiveSettingsKey(); +const Header = memo>( + ({ children, getContainer }) => { + const [open, setOpen] = useState(false); + const { styles, theme } = useStyles(); + const { t } = useTranslation('setting'); - return ( - - - {t(`tab.${activeKey}`)} + const activeKey = useActiveSettingsKey(); - {activeKey === SettingsTabs.Sync && {t('tab.experiment')}} - - } - /> -
- } - /> - ); -}); + return ( + <> + + + setOpen(true)} + size={{ blockSize: 32, fontSize: 18 }} + /> + {t(`tab.${activeKey}`)} + {activeKey === SettingsTabs.Sync && ( + {t('tab.experiment')} + )} +
+ } + /> +
+ } + /> + setOpen(false)} + onClose={() => setOpen(false)} + open={open} + placement={'left'} + rootStyle={{ position: 'absolute' }} + style={{ + background: theme.colorBgContainer, + borderRight: `1px solid ${theme.colorSplit}`, + }} + width={260} + zIndex={10} + > + {children} + + + + ); + }, +); export default Header; diff --git a/src/app/(main)/settings/_layout/Desktop/SideBar.tsx b/src/app/(main)/settings/_layout/Desktop/SideBar.tsx index 0a59f94ea666..f570887e292b 100644 --- a/src/app/(main)/settings/_layout/Desktop/SideBar.tsx +++ b/src/app/(main)/settings/_layout/Desktop/SideBar.tsx @@ -1,47 +1,59 @@ 'use client'; -import { createStyles, useResponsive } from 'antd-style'; -import { memo } from 'react'; +import { createStyles } from 'antd-style'; import { useTranslation } from 'react-i18next'; -import { Flexbox } from 'react-layout-kit'; +import { Flexbox, FlexboxProps } from 'react-layout-kit'; -import { useActiveSettingsKey } from '@/hooks/useActiveSettingsKey'; +import BrandWatermark from '@/components/BrandWatermark'; -import SettingList from '../../features/SettingList'; -import UpgradeAlert from '../../features/UpgradeAlert'; - -const useStyles = createStyles(({ stylish, token, css }) => ({ - body: stylish.noScrollbar, +const useStyles = createStyles(({ token, css }) => ({ container: css` + padding: 24px 12px 16px; + background: ${token.colorBgContainer}; border-inline-end: 1px solid ${token.colorBorder}; `, + desc: css` + line-height: 1.4; + color: ${token.colorTextDescription}; + `, + header: css` + padding: 0 0.75rem; + `, logo: css` fill: ${token.colorText}; `, - top: css` - font-size: 20px; - font-weight: bold; + title: css` + margin: 0; + font-size: 26px; + font-weight: 600; + line-height: 1.3; `, })); -const SideBar = memo(() => { - const { styles } = useStyles(); - const activeKey = useActiveSettingsKey(); - - const { t } = useTranslation('common'); - const { mobile } = useResponsive(); +interface SidebarLayoutProps extends FlexboxProps { + desc?: string; + title?: string; +} +const SidebarLayout = ({ children, className, title, desc, ...rest }: SidebarLayoutProps) => { + const { cx, styles } = useStyles(); + const { t } = useTranslation('setting'); return ( - - - {t('setting')} - - - - + + +

{title || t('header.title')}

+

{desc || t('header.desc')}

+ {children} +
); -}); +}; -export default SideBar; +export default SidebarLayout; diff --git a/src/app/(main)/settings/_layout/Desktop/index.tsx b/src/app/(main)/settings/_layout/Desktop/index.tsx index db37d70b0540..a55bee488f88 100644 --- a/src/app/(main)/settings/_layout/Desktop/index.tsx +++ b/src/app/(main)/settings/_layout/Desktop/index.tsx @@ -1,27 +1,51 @@ 'use client'; -import { PropsWithChildren, memo } from 'react'; -import { Center, Flexbox } from 'react-layout-kit'; - -import SafeSpacing from '@/components/SafeSpacing'; -import ClientResponsiveLayout from '@/components/client/ClientResponsiveLayout'; +import { useResponsive } from 'antd-style'; +import { memo, useRef } from 'react'; +import { Flexbox } from 'react-layout-kit'; +import { LayoutProps } from '../type'; import Header from './Header'; import SideBar from './SideBar'; -const Desktop = memo(({ children }) => ( - <> - - -
- - -
+const Layout = memo(({ children, category }) => { + const ref = useRef(null); + const { md = true, mobile = false } = useResponsive(); + + return ( + + {md ? ( + {category} + ) : ( +
ref.current}>{category}
+ )} + + {children} -
+
- -)); + ); +}); + +Layout.displayName = 'DesktopSettingsLayout'; -export default ClientResponsiveLayout({ Desktop, Mobile: () => import('../Mobile') }); +export default Layout; diff --git a/src/app/(main)/settings/_layout/Mobile/SubSettingHeader.tsx b/src/app/(main)/settings/_layout/Mobile/Header.tsx similarity index 94% rename from src/app/(main)/settings/_layout/Mobile/SubSettingHeader.tsx rename to src/app/(main)/settings/_layout/Mobile/Header.tsx index 5a1463c0b0f5..4b16e892d516 100644 --- a/src/app/(main)/settings/_layout/Mobile/SubSettingHeader.tsx +++ b/src/app/(main)/settings/_layout/Mobile/Header.tsx @@ -1,3 +1,5 @@ +'use client'; + import { MobileNavBar, MobileNavBarTitle } from '@lobehub/ui'; import { Tag } from 'antd'; import { useRouter } from 'next/navigation'; @@ -28,7 +30,7 @@ const Header = memo(() => { } /> } - onBackClick={() => router.push('/settings')} + onBackClick={() => router.push('/me')} showBackButton style={mobileHeaderSticky} /> diff --git a/src/app/(main)/settings/_layout/Mobile/index.tsx b/src/app/(main)/settings/_layout/Mobile/index.tsx index c692f35db675..37480864dc41 100644 --- a/src/app/(main)/settings/_layout/Mobile/index.tsx +++ b/src/app/(main)/settings/_layout/Mobile/index.tsx @@ -1,23 +1,12 @@ -'use client'; - -import { PropsWithChildren } from 'react'; - import MobileContentLayout from '@/components/server/MobileNavLayout'; -import { useIsSubSlug } from '@/hooks/useIsSubSlug'; - -import SubSettingHeader from './SubSettingHeader'; -const MobileLayout = ({ children }: PropsWithChildren) => { - const isSubPath = useIsSubSlug(); +import { LayoutProps } from '../type'; +import Header from './Header'; - if (isSubPath) - return ( - } withNav={false}> - {children} - - ); - - return children; +const Layout = ({ children }: LayoutProps) => { + return }>{children}; }; -export default MobileLayout; +Layout.displayName = 'MobileSettingsLayout'; + +export default Layout; diff --git a/src/app/(main)/settings/_layout/type.ts b/src/app/(main)/settings/_layout/type.ts new file mode 100644 index 000000000000..05c8d56f9d7f --- /dev/null +++ b/src/app/(main)/settings/_layout/type.ts @@ -0,0 +1,6 @@ +import { ReactNode } from 'react'; + +export interface LayoutProps { + category: ReactNode; + children: ReactNode; +} diff --git a/src/app/(main)/settings/about/AboutList.tsx b/src/app/(main)/settings/about/AboutList.tsx deleted file mode 100644 index 72a4af655a45..000000000000 --- a/src/app/(main)/settings/about/AboutList.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { Feather, FileClock, Heart } from 'lucide-react'; -import { memo } from 'react'; -import { useTranslation } from 'react-i18next'; -import { Flexbox } from 'react-layout-kit'; - -import { ABOUT, CHANGELOG, FEEDBACK } from '@/const/url'; - -import Item from '../features/SettingList/Item'; -import { useStyles } from './style'; - -const AboutList = memo(() => { - const { t } = useTranslation('setting'); - const { styles } = useStyles(); - const items = [ - { - icon: Feather, - label: t('feedback', { ns: 'common' }), - onClick: () => window.open(FEEDBACK, '__blank'), - value: 'feedback', - }, - { - icon: FileClock, - label: t('changelog', { ns: 'common' }), - onClick: () => window.open(CHANGELOG, '__blank'), - value: 'changelog', - }, - { - icon: Heart, - label: t('about', { ns: 'common' }), - onClick: () => window.open(ABOUT, '__blank'), - value: 'about', - }, - ]; - - return ( -
- - - {t('about.title')} - - - {items.map(({ value, icon, label, onClick }) => ( -
- -
- ))} -
-
-
- ); -}); - -export default AboutList; diff --git a/src/app/(main)/settings/about/Analytics.tsx b/src/app/(main)/settings/about/Analytics.tsx deleted file mode 100644 index bfd54fff37aa..000000000000 --- a/src/app/(main)/settings/about/Analytics.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { Switch } from 'antd'; -import { memo } from 'react'; -import { useTranslation } from 'react-i18next'; -import { Flexbox } from 'react-layout-kit'; - -import { useUserStore } from '@/store/user'; -import { preferenceSelectors } from '@/store/user/selectors'; - -import { useStyles } from './style'; - -const Analytics = memo(() => { - const { t } = useTranslation('setting'); - const { styles } = useStyles(); - const checked = useUserStore(preferenceSelectors.userAllowTrace); - const [updatePreference] = useUserStore((s) => [s.updatePreference]); - - return ( -
- - - {t('analytics.title')} - - - { - updatePreference({ telemetry: e }); - }} - /> - - {t('analytics.telemetry.title')} - {t('analytics.telemetry.desc')} - - - -
- ); -}); - -export default Analytics; diff --git a/src/app/(main)/settings/about/features/AboutList.tsx b/src/app/(main)/settings/about/features/AboutList.tsx new file mode 100644 index 000000000000..60cf7cf2bd2e --- /dev/null +++ b/src/app/(main)/settings/about/features/AboutList.tsx @@ -0,0 +1,134 @@ +'use client'; + +import { Grid, Icon } from '@lobehub/ui'; +import { createStyles } from 'antd-style'; +import { + Book, + Feather, + FileClock, + Github, + Heart, + HeartHandshake, + Home, + Lock, + Rss, +} from 'lucide-react'; +import Link from 'next/link'; +import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Flexbox } from 'react-layout-kit'; + +import { + ABOUT, + BLOG, + CHANGELOG, + FEEDBACK, + GITHUB, + OFFICIAL_SITE, + PRIVACY_URL, + TERMS_URL, +} from '@/const/url'; + +const useStyles = createStyles(({ css, token, responsive, isDarkMode }) => ({ + card: css` + cursor: pointer; + + padding: 20px; + + background: ${isDarkMode ? token.colorFillTertiary : token.colorBgContainer}; + border: 1px solid ${token.colorFillSecondary}; + border-radius: ${token.borderRadiusLG}px; + + &:hover { + background: ${isDarkMode ? token.colorFillSecondary : token.colorBgContainer}; + border: 1px solid ${token.colorFill}; + } + + ${responsive.mobile} { + padding: 16px; + } + `, + container: css` + ${responsive.mobile} { + padding-inline: 16px; + } + `, +})); + +const AboutList = memo(() => { + const { styles } = useStyles(); + const { t } = useTranslation('common'); + + const items = [ + { + href: OFFICIAL_SITE, + icon: Home, + label: t('officialSite'), + value: 'officialSite', + }, + + { + href: FEEDBACK, + icon: Book, + label: t('document'), + value: 'feedback', + }, + { + href: BLOG, + icon: Rss, + label: t('blog'), + value: 'blog', + }, + { + href: GITHUB, + icon: Github, + label: 'GitHub', + value: 'feedback', + }, + { + href: FEEDBACK, + icon: Feather, + label: t('feedback'), + value: 'feedback', + }, + { + href: CHANGELOG, + icon: FileClock, + label: t('changelog'), + value: 'changelog', + }, + { + href: TERMS_URL, + icon: HeartHandshake, + label: t('terms'), + value: 'terms', + }, + { + href: PRIVACY_URL, + icon: Lock, + label: t('privacy'), + value: 'privacy', + }, + { + href: ABOUT, + icon: Heart, + label: t('about'), + value: 'about', + }, + ]; + + return ( + + {items.map(({ value, icon, label, href }) => ( + + + + {label} + + + ))} + + ); +}); + +export default AboutList; diff --git a/src/app/(main)/settings/about/features/Analytics.tsx b/src/app/(main)/settings/about/features/Analytics.tsx new file mode 100644 index 000000000000..331596fd92e0 --- /dev/null +++ b/src/app/(main)/settings/about/features/Analytics.tsx @@ -0,0 +1,42 @@ +'use client'; + +import { Form, type ItemGroup } from '@lobehub/ui'; +import { Switch } from 'antd'; +import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; + +import { FORM_STYLE } from '@/const/layoutTokens'; +import { useUserStore } from '@/store/user'; +import { preferenceSelectors } from '@/store/user/selectors'; + +type SettingItemGroup = ItemGroup; + +const Analytics = memo(() => { + const { t } = useTranslation('setting'); + const checked = useUserStore(preferenceSelectors.userAllowTrace); + const [updatePreference] = useUserStore((s) => [s.updatePreference]); + + const items: SettingItemGroup = { + children: [ + { + children: ( + { + updatePreference({ telemetry: e }); + }} + /> + ), + desc: t('analytics.telemetry.desc'), + label: t('analytics.telemetry.title'), + minWidth: undefined, + valuePropName: 'checked', + }, + ], + title: t('analytics.title'), + }; + + return
; +}); + +export default Analytics; diff --git a/src/app/(main)/settings/features/SettingList/Item.tsx b/src/app/(main)/settings/about/features/Item.tsx similarity index 100% rename from src/app/(main)/settings/features/SettingList/Item.tsx rename to src/app/(main)/settings/about/features/Item.tsx diff --git a/src/app/(main)/settings/about/index.tsx b/src/app/(main)/settings/about/index.tsx new file mode 100644 index 000000000000..d9a7a050f345 --- /dev/null +++ b/src/app/(main)/settings/about/index.tsx @@ -0,0 +1,46 @@ +'use client'; + +import { Logo, Tag } from '@lobehub/ui'; +import Link from 'next/link'; +import { memo } from 'react'; +import { Flexbox } from 'react-layout-kit'; + +import { OFFICIAL_SITE, RELEASES_URL } from '@/const/url'; +import { CURRENT_VERSION } from '@/const/version'; +import Follow from '@/features/Follow'; +import { useServerConfigStore } from '@/store/serverConfig'; +import { serverConfigSelectors } from '@/store/serverConfig/selectors'; + +import AboutList from './features/AboutList'; +import Analytics from './features/Analytics'; + +const COPYRIGHT = `© 2023-${new Date().getFullYear()} LobeHub, LLC`; + +const Page = memo(({ mobile }: { mobile?: boolean }) => { + const enabledTelemetryChat = useServerConfigStore(serverConfigSelectors.enabledTelemetryChat); + + return ( + + + + +

+ LobeChat +

+ + v{CURRENT_VERSION} + + + + {enabledTelemetryChat && } + + +
Empowering your AI dreams by LobeHub
+
{COPYRIGHT}
+
+ ); +}); + +Page.displayName = 'AboutSetting'; + +export default Page; diff --git a/src/app/(main)/settings/about/page.tsx b/src/app/(main)/settings/about/page.tsx index e45b6835e035..838aa41315b3 100644 --- a/src/app/(main)/settings/about/page.tsx +++ b/src/app/(main)/settings/about/page.tsx @@ -1,37 +1,17 @@ -'use client'; +import { translation } from '@/server/translation'; +import { isMobileDevice } from '@/utils/responsive'; -import { createStyles } from 'antd-style'; -import { memo } from 'react'; -import { useTranslation } from 'react-i18next'; -import { Flexbox } from 'react-layout-kit'; +import Page from './index'; -import PageTitle from '@/components/PageTitle'; -import { useServerConfigStore } from '@/store/serverConfig'; -import { serverConfigSelectors } from '@/store/serverConfig/selectors'; +export const generateMetadata = async () => { + const { t } = await translation('setting'); + return { + title: t('tab.about'), + }; +}; -import AboutList from './AboutList'; -import Analytics from './Analytics'; +export default () => { + const isMobile = isMobileDevice(); -const useStyles = createStyles(({ css }) => ({ - container: css` - width: 100%; - max-width: 1024px; - `, -})); - -export default memo(() => { - const { t } = useTranslation('setting'); - - const { styles } = useStyles(); - const enabledTelemetryChat = useServerConfigStore(serverConfigSelectors.enabledTelemetryChat); - - return ( - <> - - - - {enabledTelemetryChat && } - - - ); -}); + return ; +}; diff --git a/src/app/(main)/settings/about/style.ts b/src/app/(main)/settings/about/style.ts deleted file mode 100644 index 09709b2314e7..000000000000 --- a/src/app/(main)/settings/about/style.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { createStyles } from 'antd-style'; - -export const useStyles = createStyles(({ css, token, responsive }) => ({ - container: css` - border: 1px solid ${token.colorBorder}; - border-radius: 8px; - `, - desc: css` - color: ${token.colorTextTertiary}; - `, - title: css` - font-size: 16px; - font-weight: 600; - `, - wrapper: css` - width: 100%; - - ${responsive.mobile} { - padding: 0 12px; - } - `, -})); diff --git a/src/app/(main)/settings/agent/Agent.tsx b/src/app/(main)/settings/agent/index.tsx similarity index 80% rename from src/app/(main)/settings/agent/Agent.tsx rename to src/app/(main)/settings/agent/index.tsx index 2b8773cc13aa..e6d49917903f 100644 --- a/src/app/(main)/settings/agent/Agent.tsx +++ b/src/app/(main)/settings/agent/index.tsx @@ -1,18 +1,20 @@ +'use client'; + import isEqual from 'fast-deep-equal'; import { memo } from 'react'; import { INBOX_SESSION_ID } from '@/const/session'; -import AgentSetting from '@/features/AgentSetting'; +import AgentSettings from '@/features/AgentSetting'; import { useUserStore } from '@/store/user'; import { settingsSelectors } from '@/store/user/selectors'; -const Agent = memo(() => { +const Page = memo(() => { const config = useUserStore(settingsSelectors.defaultAgentConfig, isEqual); const meta = useUserStore(settingsSelectors.defaultAgentMeta, isEqual); const [updateAgent] = useUserStore((s) => [s.updateDefaultAgent]); return ( - { ); }); -export default Agent; +Page.displayName = 'AgentSetting'; + +export default Page; diff --git a/src/app/(main)/settings/agent/loading.tsx b/src/app/(main)/settings/agent/loading.tsx deleted file mode 100644 index c5a9da2fe6ef..000000000000 --- a/src/app/(main)/settings/agent/loading.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import { Skeleton } from 'antd'; - -export default () => ; diff --git a/src/app/(main)/settings/agent/page.tsx b/src/app/(main)/settings/agent/page.tsx index a3cccfe776c3..c47984c050b0 100644 --- a/src/app/(main)/settings/agent/page.tsx +++ b/src/app/(main)/settings/agent/page.tsx @@ -1,18 +1,10 @@ -'use client'; +import { translation } from '@/server/translation'; -import { memo } from 'react'; -import { useTranslation } from 'react-i18next'; +export const generateMetadata = async () => { + const { t } = await translation('setting'); + return { + title: t('tab.agent'), + }; +}; -import PageTitle from '@/components/PageTitle'; - -import Agent from './Agent'; - -export default memo(() => { - const { t } = useTranslation('setting'); - return ( - <> - - - - ); -}); +export { default } from './index'; diff --git a/src/app/(main)/settings/common/Common.tsx b/src/app/(main)/settings/common/features/Common.tsx similarity index 96% rename from src/app/(main)/settings/common/Common.tsx rename to src/app/(main)/settings/common/features/Common.tsx index 6809c75eed46..1010de056fa5 100644 --- a/src/app/(main)/settings/common/Common.tsx +++ b/src/app/(main)/settings/common/features/Common.tsx @@ -1,7 +1,8 @@ +'use client'; + import { Form, type ItemGroup } from '@lobehub/ui'; -import { Form as AntForm, App, Button, Input } from 'antd'; +import { App, Button, Input } from 'antd'; import isEqual from 'fast-deep-equal'; -import { AppWindow } from 'lucide-react'; import { signIn, signOut } from 'next-auth/react'; import { memo, useCallback } from 'react'; import { useTranslation } from 'react-i18next'; @@ -26,7 +27,7 @@ export interface SettingsCommonProps { const Common = memo(({ showAccessCodeConfig, showOAuthLogin }) => { const { t } = useTranslation('setting'); - const [form] = AntForm.useForm(); + const [form] = Form.useForm(); const { user, isOAuthLoggedIn } = useOAuthSession(); @@ -146,7 +147,6 @@ const Common = memo(({ showAccessCodeConfig, showOAuthLogin minWidth: undefined, }, ], - icon: AppWindow, title: t('settingSystem.title'), }; @@ -157,7 +157,9 @@ const Common = memo(({ showAccessCodeConfig, showOAuthLogin form={form} initialValues={settings} items={[system]} + itemsType={'group'} onValuesChange={setSettings} + variant={'pure'} {...FORM_STYLE} /> ); diff --git a/src/app/(main)/settings/features/ThemeSwatches/ThemeSwatchesNeutral.tsx b/src/app/(main)/settings/common/features/Theme/ThemeSwatches/ThemeSwatchesNeutral.tsx similarity index 100% rename from src/app/(main)/settings/features/ThemeSwatches/ThemeSwatchesNeutral.tsx rename to src/app/(main)/settings/common/features/Theme/ThemeSwatches/ThemeSwatchesNeutral.tsx diff --git a/src/app/(main)/settings/features/ThemeSwatches/ThemeSwatchesPrimary.tsx b/src/app/(main)/settings/common/features/Theme/ThemeSwatches/ThemeSwatchesPrimary.tsx similarity index 100% rename from src/app/(main)/settings/features/ThemeSwatches/ThemeSwatchesPrimary.tsx rename to src/app/(main)/settings/common/features/Theme/ThemeSwatches/ThemeSwatchesPrimary.tsx diff --git a/src/app/(main)/settings/features/ThemeSwatches/index.ts b/src/app/(main)/settings/common/features/Theme/ThemeSwatches/index.ts similarity index 100% rename from src/app/(main)/settings/features/ThemeSwatches/index.ts rename to src/app/(main)/settings/common/features/Theme/ThemeSwatches/index.ts diff --git a/src/app/(main)/settings/common/Theme.tsx b/src/app/(main)/settings/common/features/Theme/index.tsx similarity index 93% rename from src/app/(main)/settings/common/Theme.tsx rename to src/app/(main)/settings/common/features/Theme/index.tsx index 6cb6892fb2bf..d62d76869fc0 100644 --- a/src/app/(main)/settings/common/Theme.tsx +++ b/src/app/(main)/settings/common/features/Theme/index.tsx @@ -1,7 +1,9 @@ +'use client'; + import { Form, type ItemGroup, SelectWithImg, SliderWithInput } from '@lobehub/ui'; -import { Form as AntForm, Select } from 'antd'; +import { Select } from 'antd'; import isEqual from 'fast-deep-equal'; -import { Monitor, Moon, Palette, Sun } from 'lucide-react'; +import { Monitor, Moon, Sun } from 'lucide-react'; import { memo } from 'react'; import { useTranslation } from 'react-i18next'; @@ -14,14 +16,13 @@ import { useUserStore } from '@/store/user'; import { settingsSelectors } from '@/store/user/selectors'; import { switchLang } from '@/utils/client/switchLang'; -import { ThemeSwatchesNeutral, ThemeSwatchesPrimary } from '../features/ThemeSwatches'; +import { ThemeSwatchesNeutral, ThemeSwatchesPrimary } from './ThemeSwatches'; type SettingItemGroup = ItemGroup; const Theme = memo(() => { const { t } = useTranslation('setting'); - const [form] = AntForm.useForm(); - + const [form] = Form.useForm(); const settings = useUserStore(settingsSelectors.currentSettings, isEqual); const [setThemeMode, setSettings] = useUserStore((s) => [s.switchThemeMode, s.setSettings]); @@ -125,7 +126,6 @@ const Theme = memo(() => { minWidth: undefined, }, ], - icon: Palette, title: t('settingTheme.title'), }; @@ -134,7 +134,9 @@ const Theme = memo(() => { form={form} initialValues={settings} items={[theme]} + itemsType={'group'} onValuesChange={setSettings} + variant={'pure'} {...FORM_STYLE} /> ); diff --git a/src/app/(main)/settings/common/index.tsx b/src/app/(main)/settings/common/index.tsx index 449d2cc4daac..cf66e7e0f432 100644 --- a/src/app/(main)/settings/common/index.tsx +++ b/src/app/(main)/settings/common/index.tsx @@ -1,24 +1,19 @@ -'use client'; +import { getServerConfig } from '@/config/server'; -import { memo } from 'react'; -import { useTranslation } from 'react-i18next'; +import Common from './features/Common'; +import Theme from './features/Theme'; -import PageTitle from '@/components/PageTitle'; -import { CURRENT_VERSION } from '@/const/version'; - -import Footer from '../features/Footer'; -import Common, { SettingsCommonProps } from './Common'; -import Theme from './Theme'; - -export default memo((props) => { - const { t } = useTranslation('setting'); +const { SHOW_ACCESS_CODE_CONFIG, ENABLE_OAUTH_SSO } = getServerConfig(); +const Page = () => { return ( <> - - -
LobeChat v{CURRENT_VERSION}
+ ); -}); +}; + +Page.displayName = 'CommonSetting'; + +export default Page; diff --git a/src/app/(main)/settings/common/loading.tsx b/src/app/(main)/settings/common/loading.tsx deleted file mode 100644 index c5a9da2fe6ef..000000000000 --- a/src/app/(main)/settings/common/loading.tsx +++ /dev/null @@ -1,3 +0,0 @@ -import { Skeleton } from 'antd'; - -export default () => ; diff --git a/src/app/(main)/settings/common/page.tsx b/src/app/(main)/settings/common/page.tsx index f0145f7d1083..aee71a1c4fa4 100644 --- a/src/app/(main)/settings/common/page.tsx +++ b/src/app/(main)/settings/common/page.tsx @@ -1,9 +1,10 @@ -import { getServerConfig } from '@/config/server'; +import { translation } from '@/server/translation'; -import Index from './index'; - -export default () => { - const { SHOW_ACCESS_CODE_CONFIG, ENABLE_OAUTH_SSO } = getServerConfig(); - - return ; +export const generateMetadata = async () => { + const { t } = await translation('setting'); + return { + title: t('tab.common'), + }; }; + +export { default } from './index'; diff --git a/src/app/(main)/settings/error.tsx b/src/app/(main)/settings/error.tsx new file mode 100644 index 000000000000..071491038c70 --- /dev/null +++ b/src/app/(main)/settings/error.tsx @@ -0,0 +1,5 @@ +'use client'; + +import dynamic from 'next/dynamic'; + +export default dynamic(() => import('@/components/Error')); diff --git a/src/app/(main)/settings/features/Footer.tsx b/src/app/(main)/settings/features/Footer.tsx index bd126582e49a..4348dccf5674 100644 --- a/src/app/(main)/settings/features/Footer.tsx +++ b/src/app/(main)/settings/features/Footer.tsx @@ -1,3 +1,5 @@ +'use client'; + import { Divider } from 'antd'; import { createStyles } from 'antd-style'; import { PropsWithChildren, memo } from 'react'; diff --git a/src/app/(main)/settings/features/SettingList/index.tsx b/src/app/(main)/settings/features/SettingList/index.tsx deleted file mode 100644 index 91a1997b3830..000000000000 --- a/src/app/(main)/settings/features/SettingList/index.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { Bot, Cloudy, Info, Mic2, Settings2, Webhook } from 'lucide-react'; -import Link from 'next/link'; -import { memo } from 'react'; -import { useTranslation } from 'react-i18next'; - -import { SettingsTabs } from '@/store/global/initialState'; -import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig'; - -import Item from './Item'; - -interface TabItem { - icon: any; - label: string; - value: SettingsTabs; -} - -export interface SettingListProps { - activeTab?: SettingsTabs; - mobile?: boolean; -} - -const SettingList = memo(({ activeTab, mobile }) => { - const { t } = useTranslation('setting'); - const { enableWebrtc, showLLM } = useServerConfigStore(featureFlagsSelectors); - - const items = [ - { icon: Settings2, label: t('tab.common'), value: SettingsTabs.Common }, - enableWebrtc && { icon: Cloudy, label: t('tab.sync'), value: SettingsTabs.Sync }, - showLLM && { icon: Webhook, label: t('tab.llm'), value: SettingsTabs.LLM }, - { icon: Mic2, label: t('tab.tts'), value: SettingsTabs.TTS }, - { icon: Bot, label: t('tab.agent'), value: SettingsTabs.Agent }, - { icon: Info, label: t('tab.about'), value: SettingsTabs.About }, - ].filter(Boolean) as TabItem[]; - - return items.map(({ value, icon, label }) => ( - - - - )); -}); - -export default SettingList; diff --git a/src/app/(main)/settings/features/UpgradeAlert.tsx b/src/app/(main)/settings/features/UpgradeAlert.tsx index 1f0a25983f8c..7a708f691e89 100644 --- a/src/app/(main)/settings/features/UpgradeAlert.tsx +++ b/src/app/(main)/settings/features/UpgradeAlert.tsx @@ -1,8 +1,11 @@ +'use client'; + import { Alert } from '@lobehub/ui'; import { Button } from 'antd'; import Link from 'next/link'; import { memo } from 'react'; import { useTranslation } from 'react-i18next'; +import { Flexbox } from 'react-layout-kit'; import { MANUAL_UPGRADE_URL } from '@/const/url'; import { useGlobalStore } from '@/store/global'; @@ -11,23 +14,28 @@ const UpgradeAlert = memo(() => { const [hasNewVersion, latestVersion] = useGlobalStore((s) => [s.hasNewVersion, s.latestVersion]); const { t } = useTranslation('common'); + if (!hasNewVersion) return; + return ( - hasNewVersion && ( - - - } - closable - message={t('upgradeVersion.newVersion', { version: latestVersion })} - showIcon={false} - style={{ marginBottom: 6 }} - type={'info'} - /> - ) + + } + type={'info'} + /> ); }); diff --git a/src/app/(main)/settings/hooks/useCategory.tsx b/src/app/(main)/settings/hooks/useCategory.tsx new file mode 100644 index 000000000000..5936ca240ed5 --- /dev/null +++ b/src/app/(main)/settings/hooks/useCategory.tsx @@ -0,0 +1,54 @@ +import { Icon } from '@lobehub/ui'; +import { Bot, Cloudy, Info, Mic2, Settings2, Webhook } from 'lucide-react'; +import { useMemo } from 'react'; +import { useTranslation } from 'react-i18next'; + +import type { MenuProps } from '@/components/Menu'; +import { SettingsTabs } from '@/store/global/initialState'; +import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig'; + +interface UseCategoryOptions { + mobile?: boolean; +} + +export const useCategory = ({ mobile }: UseCategoryOptions = {}) => { + const { t } = useTranslation('setting'); + const { enableWebrtc, showLLM } = useServerConfigStore(featureFlagsSelectors); + + const iconSize = mobile ? { fontSize: 20 } : undefined; + + const cateItems: MenuProps['items'] = useMemo( + () => + [ + { + icon: , + key: SettingsTabs.Common, + label: t('tab.common'), + }, + enableWebrtc && { + icon: , + key: SettingsTabs.Sync, + label: t('tab.sync'), + }, + showLLM && { + icon: , + key: SettingsTabs.LLM, + label: t('tab.llm'), + }, + { icon: , key: SettingsTabs.TTS, label: t('tab.tts') }, + { + icon: , + key: SettingsTabs.Agent, + label: t('tab.agent'), + }, + { + icon: , + key: SettingsTabs.About, + label: t('tab.about'), + }, + ].filter(Boolean) as MenuProps['items'], + [t, enableWebrtc, showLLM], + ); + + return cateItems; +}; diff --git a/src/app/(main)/settings/hooks/useSyncSettings.ts b/src/app/(main)/settings/hooks/useSyncSettings.ts index 224f2775c950..8dac778ef41d 100644 --- a/src/app/(main)/settings/hooks/useSyncSettings.ts +++ b/src/app/(main)/settings/hooks/useSyncSettings.ts @@ -1,10 +1,10 @@ import { FormInstance } from 'antd/es/form/hooks/useForm'; -import { useEffect } from 'react'; +import { useLayoutEffect } from 'react'; import { useUserStore } from '@/store/user'; export const useSyncSettings = (form: FormInstance) => { - useEffect(() => { + useLayoutEffect(() => { // set the first time form.setFieldsValue(useUserStore.getState().settings); diff --git a/src/app/(main)/settings/layout.ts b/src/app/(main)/settings/layout.ts index d07d1a64cbf3..d311fc68e428 100644 --- a/src/app/(main)/settings/layout.ts +++ b/src/app/(main)/settings/layout.ts @@ -2,7 +2,10 @@ import ServerLayout from '@/components/server/ServerLayout'; import Desktop from './_layout/Desktop'; import Mobile from './_layout/Mobile'; +import { LayoutProps } from './_layout/type'; -const SettingsLayout = ServerLayout({ Desktop, Mobile }); +const SettingsLayout = ServerLayout({ Desktop, Mobile }); + +SettingsLayout.displayName = 'SettingsLayout'; export default SettingsLayout; diff --git a/src/app/(main)/settings/llm/Anthropic/index.tsx b/src/app/(main)/settings/llm/Anthropic/index.tsx index ff0bdc1becd6..e13fc210cce3 100644 --- a/src/app/(main)/settings/llm/Anthropic/index.tsx +++ b/src/app/(main)/settings/llm/Anthropic/index.tsx @@ -1,3 +1,5 @@ +'use client'; + import { Anthropic, Claude } from '@lobehub/icons'; import { useTheme } from 'antd-style'; import { memo } from 'react'; @@ -7,19 +9,13 @@ import { ModelProvider } from '@/libs/agent-runtime'; import ProviderConfig from '../components/ProviderConfig'; const AnthropicProvider = memo(() => { - const theme = useTheme(); - + const { isDarkMode } = useTheme(); return ( - } + title={} /> ); }); diff --git a/src/app/(main)/settings/llm/Azure/index.tsx b/src/app/(main)/settings/llm/Azure/index.tsx index 331cbb6799b6..09b05b56e37a 100644 --- a/src/app/(main)/settings/llm/Azure/index.tsx +++ b/src/app/(main)/settings/llm/Azure/index.tsx @@ -1,3 +1,5 @@ +'use client'; + import { Azure, OpenAI } from '@lobehub/icons'; import { Markdown } from '@lobehub/ui'; import { AutoComplete, Divider, Input } from 'antd'; @@ -95,7 +97,7 @@ const AzureOpenAIProvider = memo(() => { provider={providerKey} title={ - + diff --git a/src/app/(main)/settings/llm/Bedrock/index.tsx b/src/app/(main)/settings/llm/Bedrock/index.tsx index 3f98dcbf29c5..91295e143a94 100644 --- a/src/app/(main)/settings/llm/Bedrock/index.tsx +++ b/src/app/(main)/settings/llm/Bedrock/index.tsx @@ -1,3 +1,5 @@ +'use client'; + import { Aws, Bedrock } from '@lobehub/icons'; import { Divider, Input, Select } from 'antd'; import { memo } from 'react'; @@ -62,7 +64,7 @@ const BedrockProvider = memo(() => { - + } /> diff --git a/src/app/(main)/settings/llm/Google/index.tsx b/src/app/(main)/settings/llm/Google/index.tsx index e871ab5bf600..96312c0249aa 100644 --- a/src/app/(main)/settings/llm/Google/index.tsx +++ b/src/app/(main)/settings/llm/Google/index.tsx @@ -1,3 +1,5 @@ +'use client'; + import { Gemini, Google } from '@lobehub/icons'; import { Divider } from 'antd'; import { memo } from 'react'; @@ -15,9 +17,9 @@ const GoogleProvider = memo(() => { showEndpoint title={ - + - + } /> diff --git a/src/app/(main)/settings/llm/Groq/index.tsx b/src/app/(main)/settings/llm/Groq/index.tsx index 1a66c0e5ffa4..b339f04ffd93 100644 --- a/src/app/(main)/settings/llm/Groq/index.tsx +++ b/src/app/(main)/settings/llm/Groq/index.tsx @@ -1,3 +1,5 @@ +'use client'; + import { Groq } from '@lobehub/icons'; import { useTheme } from 'antd-style'; import { memo } from 'react'; @@ -13,7 +15,7 @@ const GroqProvider = memo(() => { } + title={} /> ); }); diff --git a/src/app/(main)/settings/llm/Minimax/index.tsx b/src/app/(main)/settings/llm/Minimax/index.tsx index 9cd055d2446a..1d11742cce74 100644 --- a/src/app/(main)/settings/llm/Minimax/index.tsx +++ b/src/app/(main)/settings/llm/Minimax/index.tsx @@ -1,5 +1,6 @@ +'use client'; + import { Minimax } from '@lobehub/icons'; -import { useTheme } from 'antd-style'; import { memo } from 'react'; import { ModelProvider } from '@/libs/agent-runtime'; @@ -7,18 +8,11 @@ import { ModelProvider } from '@/libs/agent-runtime'; import ProviderConfig from '../components/ProviderConfig'; const MinimaxProvider = memo(() => { - const theme = useTheme(); - return ( - } + title={} /> ); }); diff --git a/src/app/(main)/settings/llm/Mistral/index.tsx b/src/app/(main)/settings/llm/Mistral/index.tsx index f6662664343c..3a6223f999c0 100644 --- a/src/app/(main)/settings/llm/Mistral/index.tsx +++ b/src/app/(main)/settings/llm/Mistral/index.tsx @@ -1,5 +1,6 @@ +'use client'; + import { Mistral } from '@lobehub/icons'; -import { useTheme } from 'antd-style'; import { memo } from 'react'; import { ModelProvider } from '@/libs/agent-runtime'; @@ -7,18 +8,11 @@ import { ModelProvider } from '@/libs/agent-runtime'; import ProviderConfig from '../components/ProviderConfig'; const MistralProvider = memo(() => { - const theme = useTheme(); - return ( - } + title={} /> ); }); diff --git a/src/app/(main)/settings/llm/Moonshot/index.tsx b/src/app/(main)/settings/llm/Moonshot/index.tsx index 572ead8d26e2..e4cfc2c13742 100644 --- a/src/app/(main)/settings/llm/Moonshot/index.tsx +++ b/src/app/(main)/settings/llm/Moonshot/index.tsx @@ -1,3 +1,5 @@ +'use client'; + import { Moonshot } from '@lobehub/icons'; import { useTheme } from 'antd-style'; import { memo } from 'react'; @@ -16,7 +18,7 @@ const MoonshotProvider = memo(() => { title={ } /> diff --git a/src/app/(main)/settings/llm/Ollama/index.tsx b/src/app/(main)/settings/llm/Ollama/index.tsx index cb12b4e2ba89..788abf5b4abf 100644 --- a/src/app/(main)/settings/llm/Ollama/index.tsx +++ b/src/app/(main)/settings/llm/Ollama/index.tsx @@ -1,3 +1,5 @@ +'use client'; + import { Ollama } from '@lobehub/icons'; import { memo } from 'react'; import { useTranslation } from 'react-i18next'; @@ -23,7 +25,7 @@ const OllamaProvider = memo(() => { showApiKey={false} showBrowserRequest showEndpoint - title={} + title={} /> ); }); diff --git a/src/app/(main)/settings/llm/OpenAI/index.tsx b/src/app/(main)/settings/llm/OpenAI/index.tsx index 412330879b44..1928efc12e21 100644 --- a/src/app/(main)/settings/llm/OpenAI/index.tsx +++ b/src/app/(main)/settings/llm/OpenAI/index.tsx @@ -1,3 +1,5 @@ +'use client'; + import { OpenAI } from '@lobehub/icons'; import { memo } from 'react'; diff --git a/src/app/(main)/settings/llm/OpenRouter/index.tsx b/src/app/(main)/settings/llm/OpenRouter/index.tsx index d2f282debc72..f9721ef53922 100644 --- a/src/app/(main)/settings/llm/OpenRouter/index.tsx +++ b/src/app/(main)/settings/llm/OpenRouter/index.tsx @@ -1,5 +1,6 @@ +'use client'; + import { OpenRouter } from '@lobehub/icons'; -import { useTheme } from 'antd-style'; import { memo } from 'react'; import { ModelProvider } from '@/libs/agent-runtime'; @@ -7,19 +8,12 @@ import { ModelProvider } from '@/libs/agent-runtime'; import ProviderConfig from '../components/ProviderConfig'; const OpenRouterProvider = memo(() => { - const theme = useTheme(); - return ( - } + title={} /> ); }); diff --git a/src/app/(main)/settings/llm/Perplexity/index.tsx b/src/app/(main)/settings/llm/Perplexity/index.tsx index 49f8399e88e8..419d901b0483 100644 --- a/src/app/(main)/settings/llm/Perplexity/index.tsx +++ b/src/app/(main)/settings/llm/Perplexity/index.tsx @@ -1,5 +1,6 @@ +'use client'; + import { Perplexity } from '@lobehub/icons'; -import { useTheme } from 'antd-style'; import { memo } from 'react'; import { ModelProvider } from '@/libs/agent-runtime'; @@ -7,18 +8,11 @@ import { ModelProvider } from '@/libs/agent-runtime'; import ProviderConfig from '../components/ProviderConfig'; const PerplexityProvider = memo(() => { - const theme = useTheme(); - return ( - } + title={} /> ); }); diff --git a/src/app/(main)/settings/llm/TogetherAI/index.tsx b/src/app/(main)/settings/llm/TogetherAI/index.tsx index a07a27598172..44a77e3f6ee6 100644 --- a/src/app/(main)/settings/llm/TogetherAI/index.tsx +++ b/src/app/(main)/settings/llm/TogetherAI/index.tsx @@ -1,23 +1,17 @@ +'use client'; + import { Together } from '@lobehub/icons'; -import { useTheme } from 'antd-style'; import { memo } from 'react'; import ProviderConfig from '../components/ProviderConfig'; const TogetherAIProvider = memo(() => { - const theme = useTheme(); - return ( - } + title={} /> ); }); diff --git a/src/app/(main)/settings/llm/ZeroOne/index.tsx b/src/app/(main)/settings/llm/ZeroOne/index.tsx index 2c97bc1de73c..bfe825568553 100644 --- a/src/app/(main)/settings/llm/ZeroOne/index.tsx +++ b/src/app/(main)/settings/llm/ZeroOne/index.tsx @@ -1,5 +1,6 @@ +'use client'; + import { ZeroOne } from '@lobehub/icons'; -import { useTheme } from 'antd-style'; import { memo } from 'react'; import { ModelProvider } from '@/libs/agent-runtime'; @@ -7,18 +8,11 @@ import { ModelProvider } from '@/libs/agent-runtime'; import ProviderConfig from '../components/ProviderConfig'; const ZeroOneProvider = memo(() => { - const theme = useTheme(); - return ( - } + title={} /> ); }); diff --git a/src/app/(main)/settings/llm/Zhipu/index.tsx b/src/app/(main)/settings/llm/Zhipu/index.tsx index 1cadab10591e..d80afbae4091 100644 --- a/src/app/(main)/settings/llm/Zhipu/index.tsx +++ b/src/app/(main)/settings/llm/Zhipu/index.tsx @@ -1,23 +1,16 @@ +'use client'; + import { Zhipu } from '@lobehub/icons'; -import { useTheme } from 'antd-style'; -import { lighten } from 'polished'; import { memo } from 'react'; import ProviderConfig from '../components/ProviderConfig'; const ZhipuProvider = memo(() => { - const theme = useTheme(); - return ( - } + title={} /> ); }); diff --git a/src/app/(main)/settings/llm/components/Checker.tsx b/src/app/(main)/settings/llm/components/Checker.tsx index 02a7bfe0625b..599b3a7a9cc7 100644 --- a/src/app/(main)/settings/llm/components/Checker.tsx +++ b/src/app/(main)/settings/llm/components/Checker.tsx @@ -1,3 +1,5 @@ +'use client'; + import { CheckCircleFilled } from '@ant-design/icons'; import { Alert, Highlighter } from '@lobehub/ui'; import { Button } from 'antd'; diff --git a/src/app/(main)/settings/llm/components/Footer.tsx b/src/app/(main)/settings/llm/components/Footer.tsx new file mode 100644 index 000000000000..00febb8e1707 --- /dev/null +++ b/src/app/(main)/settings/llm/components/Footer.tsx @@ -0,0 +1,26 @@ +'use client'; + +import { Divider } from 'antd'; +import Link from 'next/link'; +import { memo } from 'react'; +import { Trans } from 'react-i18next'; + +import { MORE_MODEL_PROVIDER_REQUEST_URL } from '@/const/url'; + +const Footer = memo(() => { + return ( + +

+ + 更多模型正在 + + 计划接入 + + 中 ,敬请期待 ✨ + +

+
+ ); +}); + +export default Footer; diff --git a/src/app/(main)/settings/llm/components/ProviderConfig/index.tsx b/src/app/(main)/settings/llm/components/ProviderConfig/index.tsx index 3240ea27b7b3..4a1b56470476 100644 --- a/src/app/(main)/settings/llm/components/ProviderConfig/index.tsx +++ b/src/app/(main)/settings/llm/components/ProviderConfig/index.tsx @@ -1,8 +1,12 @@ +'use client'; + import { Form, type FormItemProps, type ItemGroup } from '@lobehub/ui'; -import { Form as AntForm, Input, Switch } from 'antd'; +import { Input, Switch } from 'antd'; +import { createStyles, css } from 'antd-style'; import { debounce } from 'lodash-es'; import { ReactNode, memo } from 'react'; import { useTranslation } from 'react-i18next'; +import { Flexbox } from 'react-layout-kit'; import { useSyncSettings } from '@/app/(main)/settings/hooks/useSyncSettings'; import { @@ -19,6 +23,14 @@ import { GlobalLLMProviderKey } from '@/types/settings'; import Checker from '../Checker'; import ProviderModelListSelect from '../ProviderModelList'; +const useStyles = createStyles(() => ({ + safariIconWidthFix: css` + svg { + width: unset !important; + } + `, +})); + interface ProviderConfigProps { apiKeyItems?: FormItemProps[]; canDeactivate?: boolean; @@ -52,7 +64,8 @@ const ProviderConfig = memo( }) => { const { t } = useTranslation('setting'); const { t: modelT } = useTranslation('modelProvider'); - const [form] = AntForm.useForm(); + const [form] = Form.useForm(); + const { styles } = useStyles(); const [ toggleProviderEnabled, setSettings, @@ -142,7 +155,20 @@ const ProviderConfig = memo( value={enabled} /> ) : undefined, - title, + title: ( + + {title} + + ), }; return ( diff --git a/src/app/(main)/settings/llm/index.tsx b/src/app/(main)/settings/llm/index.tsx index 4661e6c6229f..056d734e5834 100644 --- a/src/app/(main)/settings/llm/index.tsx +++ b/src/app/(main)/settings/llm/index.tsx @@ -1,13 +1,7 @@ 'use client'; -import Link from 'next/link'; -import { memo } from 'react'; -import { Trans, useTranslation } from 'react-i18next'; +import { Flexbox } from 'react-layout-kit'; -import PageTitle from '@/components/PageTitle'; -import { MORE_MODEL_PROVIDER_REQUEST_URL } from '@/const/url'; - -import Footer from '../features/Footer'; import Anthropic from './Anthropic'; import Azure from './Azure'; import Bedrock from './Bedrock'; @@ -23,13 +17,11 @@ import Perplexity from './Perplexity'; import TogetherAI from './TogetherAI'; import ZeroOne from './ZeroOne'; import Zhipu from './Zhipu'; +import Footer from './components/Footer'; -export default memo(() => { - const { t } = useTranslation('setting'); - +const Page = () => { return ( - <> - + @@ -45,15 +37,11 @@ export default memo(() => { -
- - 更多模型正在 - - 计划接入 - - 中 ,敬请期待 ✨ - -
- +