From cbc219cd07f123610b24ef7f86d25fd03250947b Mon Sep 17 00:00:00 2001 From: CanisMinor Date: Fri, 3 Jan 2025 23:17:07 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20add=20User=20Stats=20and=20?= =?UTF-8?q?Refactor=20Profile=20(#5149)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ♻️ refactor: Refactor Profile * ✅ test: Fix test * ✨ feat: Update nextAuth profile * ♻️ refactor: Refactor hook * 💄 style: Update style * ✅ test: Fix test * 💄 style: Update sats services * ♻️ refactor: Server service arrow function * ✨ feat: Add Rank * ♻️ refactor: rebase * ♻️ refactor: rebase * ✨ feat: Add heatmap * ♻️ refactor: refactor to support upload user profile in next-auth * 💄 style: Update Stats style * 📝 docs: Update i18n * Revert "♻️ refactor: refactor to support upload user profile in next-auth" This reverts commit d479ec375efef7671d7751524a014c040657a7d7. * ✨ feat: Add Welcome * 💄 style: Update stats style * 💄 style: Update stats style * ✨ feat: Add Share Modal * 🔧 chore: Update i18n * upgrade * upgrade * 💄 style: Update Share style * ✅ test: Fix test * 💄 style: Update Modal Loading * ✨ feat: Add Model Usage Rank * add test and fix some * 🐛 fix: Fix Valid Date * 🐛 fix: Fix test * ✅ test: Fix rank order * 🐛 fix: Fix mobile * 💄 style: Update BrandLoading * 💄 style: Update moible AiHeatmaps style * 💄 style: Add Inbox * 📝 docs: Add Changelog * 📝 docs: Fix typo * ✅ test: Fix test * 📝 docs: Update Changelog * fix --------- Co-authored-by: arvinxx --- docs/.cdn.cache.json | 1 + docs/changelog/2025-01-03-user-profile.mdx | 27 ++ .../2025-01-03-user-profile.zh-CN.mdx | 26 ++ docs/changelog/index.json | 5 + .../advanced/auth/next-auth/wechat.mdx | 4 +- .../advanced/auth/next-auth/wechat.zh-CN.mdx | 4 +- locales/ar/auth.json | 80 +++- locales/bg-BG/auth.json | 78 +++- locales/de-DE/auth.json | 84 +++- locales/en-US/auth.json | 84 +++- locales/es-ES/auth.json | 78 +++- locales/fa-IR/auth.json | 82 +++- locales/fr-FR/auth.json | 84 +++- locales/it-IT/auth.json | 80 +++- locales/ja-JP/auth.json | 80 +++- locales/ko-KR/auth.json | 78 +++- locales/nl-NL/auth.json | 80 +++- locales/pl-PL/auth.json | 80 +++- locales/pt-BR/auth.json | 80 +++- locales/ru-RU/auth.json | 78 +++- locales/tr-TR/auth.json | 77 +++- locales/vi-VN/auth.json | 78 +++- locales/zh-CN/auth.json | 78 +++- locales/zh-TW/auth.json | 78 +++- package.json | 5 +- .../me/(home)/__tests__/UserBanner.test.tsx | 4 + .../me/(home)/__tests__/useCategory.test.tsx | 46 --- .../me/(home)/features/UserBanner.tsx | 25 +- .../me/(home)/features/useCategory.tsx | 27 +- .../(mobile)/me/profile/features/Category.tsx | 59 ++- src/app/(main)/(mobile)/me/profile/layout.tsx | 3 - src/app/(main)/(mobile)/me/profile/page.tsx | 6 +- src/app/(main)/chat/loading.tsx | 4 +- src/app/(main)/discover/loading.tsx | 10 +- src/app/(main)/files/loading.tsx | 4 +- src/app/(main)/profile/(home)/Client.tsx | 53 +++ .../profile/(home)/[[...slugs]]/page.tsx | 38 ++ src/app/(main)/profile/@category/default.tsx | 9 + .../@category/features/CategoryContent.tsx | 38 ++ .../(main)/profile/[[...slugs]]/Client.tsx | 76 ---- .../(main)/profile/_layout/Desktop/Header.tsx | 85 ++++ .../profile/_layout/Desktop/SideBar.tsx | 42 ++ .../(main)/profile/_layout/Desktop/index.tsx | 48 +++ .../(main)/profile/_layout/Mobile/Header.tsx | 28 +- .../(main)/profile/_layout/Mobile/index.tsx | 17 +- src/app/(main)/profile/_layout/type.ts | 6 + src/app/(main)/profile/error.tsx | 5 + .../(main)/profile/features/ClerkProfile.tsx | 72 ++++ src/app/(main)/profile/hooks/useCategory.tsx | 51 +++ src/app/(main)/profile/layout.tsx | 24 +- src/app/(main)/profile/loading.tsx | 24 +- src/app/(main)/profile/not-found.tsx | 3 + src/app/(main)/profile/security/page.tsx | 34 ++ src/app/(main)/profile/stats/Client.tsx | 52 +++ .../profile/stats/features/AiHeatmaps.tsx | 130 ++++++ .../profile/stats/features/AssistantsRank.tsx | 115 ++++++ .../profile/stats/features/ModelsRank.tsx | 84 ++++ .../stats/features/ShareButton/Preview.tsx | 159 ++++++++ .../stats/features/ShareButton/ShareModal.tsx | 87 ++++ .../stats/features/ShareButton/TotalCard.tsx | 39 ++ .../stats/features/ShareButton/index.tsx | 26 ++ .../profile/stats/features/TimeLabel.tsx | 30 ++ .../profile/stats/features/TopicsRank.tsx | 103 +++++ .../stats/features/TotalAssistants.tsx | 56 +++ .../profile/stats/features/TotalMessages.tsx | 56 +++ .../profile/stats/features/TotalTopics.tsx | 53 +++ .../profile/stats/features/TotalWords.tsx | 54 +++ .../(main)/profile/stats/features/Welcome.tsx | 86 ++++ .../profile/{[[...slugs]] => stats}/page.tsx | 9 +- .../(main)/repos/[id]/evals/dataset/page.tsx | 4 +- .../repos/[id]/evals/evaluation/page.tsx | 4 +- .../@category/features/CategoryContent.tsx | 2 +- .../(main)/settings/_layout/Desktop/index.tsx | 2 +- .../(main)/settings/_layout/Mobile/Header.tsx | 2 +- .../(main)/settings/_layout/Mobile/index.tsx | 2 + .../settings/common/features/Theme/index.tsx | 19 +- src/app/(main)/settings/loading.tsx | 4 +- .../BrandTextLoading/LobeChatText/SVG.tsx | 44 -- .../BrandTextLoading/LobeChatText/index.tsx | 6 - .../BrandTextLoading/LobeChatText/style.css | 32 -- .../Loading/BrandTextLoading/index.tsx | 4 +- src/components/Statistic/index.tsx | 15 + .../StatisticCard/TitleWithPercentage.tsx | 80 ++++ .../StatisticCard/growthPercentage.tsx | 8 + src/components/StatisticCard/index.tsx | 209 ++++++++++ src/const/url.ts | 6 +- .../server/models/__tests__/message.test.ts | 381 ++++++++++++++++-- .../server/models/__tests__/session.test.ts | 187 ++++++++- .../server/models/__tests__/topic.test.ts | 136 +++++++ .../server/models/__tests__/user.test.ts | 141 ++++++- src/database/server/models/message.ts | 123 +++++- src/database/server/models/session.ts | 79 +++- src/database/server/models/topic.ts | 46 ++- src/database/server/models/user.ts | 22 + src/database/utils/genWhere.ts | 39 ++ src/features/ShareModal/ShareImage/index.tsx | 35 +- src/features/ShareModal/ShareImage/type.ts | 7 +- src/features/User/DataStatistics.tsx | 35 +- src/features/User/UserPanel/PanelContent.tsx | 28 +- src/features/User/UserPanel/useMenu.tsx | 10 +- .../User/__tests__/PanelContent.test.tsx | 4 + src/features/User/__tests__/useMenu.test.tsx | 22 +- src/hooks/useActiveSettingsKey.ts | 20 - src/hooks/useActiveTabKey.ts | 35 +- .../ShareImage => hooks}/useScreenshot.ts | 57 ++- src/locales/default/auth.ts | 76 +++- src/server/ld.test.ts | 2 +- src/server/routers/lambda/message.ts | 41 +- src/server/routers/lambda/session.ts | 20 +- src/server/routers/lambda/topic.ts | 20 +- src/server/routers/lambda/user.ts | 4 + src/services/message/_deprecated.ts | 16 + src/services/message/client.test.ts | 18 - src/services/message/client.ts | 21 +- src/services/message/server.ts | 16 +- src/services/message/type.ts | 18 +- src/services/session/_deprecated.ts | 5 + src/services/session/client.ts | 8 +- src/services/session/server.ts | 8 +- src/services/session/type.ts | 8 +- src/services/topic/_deprecated.ts | 5 + src/services/topic/client.ts | 8 +- src/services/topic/server.ts | 8 +- src/services/topic/type.ts | 9 +- src/services/user/_deprecated.ts | 4 + src/services/user/client.ts | 4 + src/services/user/server.ts | 4 + src/services/user/type.ts | 5 + src/store/global/initialState.ts | 6 + src/store/user/slices/auth/action.test.ts | 34 +- src/store/user/slices/auth/action.ts | 9 - src/store/user/slices/common/action.test.ts | 4 +- src/types/message/index.ts | 5 + src/types/session/index.ts | 8 + src/types/topic/topic.ts | 7 + src/utils/format.ts | 2 +- src/utils/time.ts | 23 ++ 137 files changed, 5049 insertions(+), 716 deletions(-) create mode 100644 docs/changelog/2025-01-03-user-profile.mdx create mode 100644 docs/changelog/2025-01-03-user-profile.zh-CN.mdx create mode 100644 src/app/(main)/profile/(home)/Client.tsx create mode 100644 src/app/(main)/profile/(home)/[[...slugs]]/page.tsx create mode 100644 src/app/(main)/profile/@category/default.tsx create mode 100644 src/app/(main)/profile/@category/features/CategoryContent.tsx delete mode 100644 src/app/(main)/profile/[[...slugs]]/Client.tsx create mode 100644 src/app/(main)/profile/_layout/Desktop/Header.tsx create mode 100644 src/app/(main)/profile/_layout/Desktop/SideBar.tsx create mode 100644 src/app/(main)/profile/_layout/Desktop/index.tsx create mode 100644 src/app/(main)/profile/_layout/type.ts create mode 100644 src/app/(main)/profile/error.tsx create mode 100644 src/app/(main)/profile/features/ClerkProfile.tsx create mode 100644 src/app/(main)/profile/hooks/useCategory.tsx create mode 100644 src/app/(main)/profile/not-found.tsx create mode 100644 src/app/(main)/profile/security/page.tsx create mode 100644 src/app/(main)/profile/stats/Client.tsx create mode 100644 src/app/(main)/profile/stats/features/AiHeatmaps.tsx create mode 100644 src/app/(main)/profile/stats/features/AssistantsRank.tsx create mode 100644 src/app/(main)/profile/stats/features/ModelsRank.tsx create mode 100644 src/app/(main)/profile/stats/features/ShareButton/Preview.tsx create mode 100644 src/app/(main)/profile/stats/features/ShareButton/ShareModal.tsx create mode 100644 src/app/(main)/profile/stats/features/ShareButton/TotalCard.tsx create mode 100644 src/app/(main)/profile/stats/features/ShareButton/index.tsx create mode 100644 src/app/(main)/profile/stats/features/TimeLabel.tsx create mode 100644 src/app/(main)/profile/stats/features/TopicsRank.tsx create mode 100644 src/app/(main)/profile/stats/features/TotalAssistants.tsx create mode 100644 src/app/(main)/profile/stats/features/TotalMessages.tsx create mode 100644 src/app/(main)/profile/stats/features/TotalTopics.tsx create mode 100644 src/app/(main)/profile/stats/features/TotalWords.tsx create mode 100644 src/app/(main)/profile/stats/features/Welcome.tsx rename src/app/(main)/profile/{[[...slugs]] => stats}/page.tsx (72%) delete mode 100644 src/components/Loading/BrandTextLoading/LobeChatText/SVG.tsx delete mode 100644 src/components/Loading/BrandTextLoading/LobeChatText/index.tsx delete mode 100644 src/components/Loading/BrandTextLoading/LobeChatText/style.css create mode 100644 src/components/Statistic/index.tsx create mode 100644 src/components/StatisticCard/TitleWithPercentage.tsx create mode 100644 src/components/StatisticCard/growthPercentage.tsx create mode 100644 src/components/StatisticCard/index.tsx create mode 100644 src/database/utils/genWhere.ts delete mode 100644 src/hooks/useActiveSettingsKey.ts rename src/{features/ShareModal/ShareImage => hooks}/useScreenshot.ts (58%) create mode 100644 src/utils/time.ts diff --git a/docs/.cdn.cache.json b/docs/.cdn.cache.json index 2708ec042a3d..92b1655b88a5 100644 --- a/docs/.cdn.cache.json +++ b/docs/.cdn.cache.json @@ -7,6 +7,7 @@ "https://github.com/user-attachments/assets/29508dda-2382-430f-bc81-fb23f02149f8": "/blog/assets/29b13dc042e3b839ad8865354afe2fac.webp", "https://github.com/user-attachments/assets/2a4116a7-15ad-43e5-b801-cc62d8da2012": "/blog/assets/37d85fdfccff9ed56e9c6827faee01c7.webp", "https://github.com/user-attachments/assets/385eaca6-daea-484a-9bea-ba7270b4753d": "/blog/assets/d6129350de510a62fe87b2d2f0fb9477.webp", + "https://github.com/user-attachments/assets/3d80e0f5-d32a-4412-85b2-e709731460a0": "/blog/assets2d409f43b58953ad5396c6beab8a0719.webp", "https://github.com/user-attachments/assets/484f28f4-017c-4ed7-948b-4a8d51f0b63a": "/blog/assets/5bbb4b421d6df63780b3c7a05f5a102d.webp", "https://github.com/user-attachments/assets/533f7a5e-8a93-4a57-a62f-8233897d72b5": "/blog/assets/9498087e85f27e692716a63cb3b58d79.webp", "https://github.com/user-attachments/assets/6069332b-8e15-4d3c-8a77-479e8bc09c23": "/blog/assets/603fefbb944bc6761ebdab5956fc0084.webp", diff --git a/docs/changelog/2025-01-03-user-profile.mdx b/docs/changelog/2025-01-03-user-profile.mdx new file mode 100644 index 000000000000..e22ac1b49010 --- /dev/null +++ b/docs/changelog/2025-01-03-user-profile.mdx @@ -0,0 +1,27 @@ +--- +title: LobeChat Supports User Data Statistics and Activity Sharing +description: >- + LobeChat now supports multi-dimensional user data statistics and activity + sharing +--- + +# User Data Statistics and Activity Sharing 💯 + +Want to know about your activity performance on LobeChat? + +Now, you can comprehensively understand your AI data through the statistics feature, and even generate personal activity sharing images to share your LobeChat activity with friends. + +## 📊 Data Statistics + +- **Statistics**: Number of Assistants / Topics / Messages / Total Word Count +- **Rankings**: +- Model Usage Rate `Top 10` +- Assistant Usage Rate `Top 10` +- Topic Content Volume `Top 10` +- **Heat Map**: Activity distribution over the past year +- **User Activity Sharing**: Generate personal activity sharing images + +## 👉 How to Use + +1. Requires `PgLite` or `Database` mode +2. Click on your profile picture to enter "Account" - "Data Statistics" page diff --git a/docs/changelog/2025-01-03-user-profile.zh-CN.mdx b/docs/changelog/2025-01-03-user-profile.zh-CN.mdx new file mode 100644 index 000000000000..171edb99bab5 --- /dev/null +++ b/docs/changelog/2025-01-03-user-profile.zh-CN.mdx @@ -0,0 +1,26 @@ +--- +title: LobeChat 支持用户数据统计与活跃度分享 +description: LobeChat 现已支持多维度用户数据统计与活跃度分享 +--- + +# 用户数据统计与活跃度分享 💯 + +想要了解自己在 LobeChat 上的活跃度表现吗? + +现在,您可以通过数据统计功能,全方位了解自己的 AI 数据,还可以生成个人活跃度分享图片,与好友分享您在 LobeChat 上的活跃度。 + +## 📊 数据统计 + +- **数据统计**: 助手数 / 话题数 / 消息数 / 累计字数 +- **排行版**: + - 模型使用率 `Top 10` + - 助手使用率 `Top 10` + - 话题内容量 `Top 10` +- **热力图**: 过去一年内的活跃度分布 +- **用户活跃度分享**: 生成个人活跃度分享图片 + +## 👉 使用方式 + +1. 需要使用 `PgLite` 或 `数据库` 模式 +2. 点击个人头像进入「账户管理」-「数据统计」页面 + diff --git a/docs/changelog/index.json b/docs/changelog/index.json index ab2662c7fa6a..194fb90ef0a9 100644 --- a/docs/changelog/index.json +++ b/docs/changelog/index.json @@ -2,6 +2,11 @@ "$schema": "https://github.com/lobehub/lobe-chat/blob/main/docs/changelog/schema.json", "cloud": [], "community": [ + { + "image": "https://github.com/user-attachments/assets/3d80e0f5-d32a-4412-85b2-e709731460a0", + "id": "2025-01-03-user-profile", + "date": "2025-01-03" + }, { "image": "https://github.com/user-attachments/assets/2048b4c2-4a56-4029-acf9-71e35ff08652", "id": "2024-11-27-forkable-chat", diff --git a/docs/self-hosting/advanced/auth/next-auth/wechat.mdx b/docs/self-hosting/advanced/auth/next-auth/wechat.mdx index 031887045679..bff736904ede 100644 --- a/docs/self-hosting/advanced/auth/next-auth/wechat.mdx +++ b/docs/self-hosting/advanced/auth/next-auth/wechat.mdx @@ -1,6 +1,8 @@ --- title: Configure Wechat Authentication Service in LobeChat -description: Learn how to configure Wechat authentication service in LobeChat, including creating a new Wechat App, setting permissions, and environment variables. +description: >- + Learn how to configure Wechat authentication service in LobeChat, including + creating a new Wechat App, setting permissions, and environment variables. tags: - Wechat Authentication - Wechat App diff --git a/docs/self-hosting/advanced/auth/next-auth/wechat.zh-CN.mdx b/docs/self-hosting/advanced/auth/next-auth/wechat.zh-CN.mdx index 82c977319e19..24e25ad136ea 100644 --- a/docs/self-hosting/advanced/auth/next-auth/wechat.zh-CN.mdx +++ b/docs/self-hosting/advanced/auth/next-auth/wechat.zh-CN.mdx @@ -2,8 +2,8 @@ title: 在 LobeChat 中配置微信身份验证服务 description: 学习如何在 LobeChat 中配置微信身份验证服务,包括创建新的微信网站应用、设置权限和环境变量。 tags: - -微信身份验证 - -微信网站应用 + - 微信身份验证 + - 微信网站应用 - 环境变量配置 - 单点登录 - LobeChat diff --git a/locales/ar/auth.json b/locales/ar/auth.json index 1ec19662fe1a..3d194cd4edf7 100644 --- a/locales/ar/auth.json +++ b/locales/ar/auth.json @@ -1,8 +1,80 @@ { + "date": { + "prevMonth": "الشهر الماضي", + "recent30Days": "آخر 30 يومًا" + }, + "header": { + "desc": "إدارة معلومات حسابك.", + "title": "الحساب" + }, + "heatmaps": { + "legend": { + "less": "غير نشط", + "more": "نشط" + }, + "months": { + "apr": "أبريل", + "aug": "أغسطس", + "dec": "ديسمبر", + "feb": "فبراير", + "jan": "يناير", + "jul": "يوليو", + "jun": "يونيو", + "mar": "مارس", + "may": "مايو", + "nov": "نوفمبر", + "oct": "أكتوبر", + "sep": "سبتمبر" + }, + "tooltip": "{{date}} أرسل {{count}} رسائل في ذلك اليوم", + "totalCount": "إجمالي {{count}} رسائل أرسلت في العام الماضي" + }, "login": "تسجيل الدخول", - "loginOrSignup": "تسجيل الدخول / التسجيل", - "profile": "الملف الشخصي", - "security": "الأمان", + "loginOrSignup": "تسجيل الدخول / الاشتراك", + "profile": { + "avatar": "الصورة الشخصية", + "email": "عنوان البريد الإلكتروني", + "username": "اسم المستخدم" + }, "signout": "تسجيل الخروج", - "signup": "التسجيل" + "signup": "الاشتراك", + "stats": { + "aiheatmaps": "مؤشر النشاط", + "assistants": "المساعدون", + "assistantsRank": { + "left": "المساعد", + "right": "المواضيع", + "title": "ترتيب استخدام المساعد" + }, + "createdAt": "تاريخ التسجيل", + "days": "أيام", + "empty": { + "desc": "يرجى تجميع المزيد من بيانات الدردشة للعرض", + "title": "لا توجد بيانات" + }, + "lastYearActivity": "النشاط في العام الماضي", + "messages": "رسائل", + "modelsRank": { + "left": "النموذج", + "right": "الرسائل", + "title": "ترتيب استخدام النموذج" + }, + "share": { + "title": "مؤشر نشاط الذكاء الاصطناعي الخاص بي" + }, + "topics": "المواضيع", + "topicsRank": { + "left": "الموضوع", + "right": "الرسائل", + "title": "ترتيب محتوى الموضوع" + }, + "updatedAt": "تاريخ التحديث", + "welcome": "{{username}}، هذا هو يومك {{days}} مع {{appName}}", + "words": "كلمات" + }, + "tab": { + "profile": "الملف الشخصي", + "security": "الأمان", + "stats": "الإحصائيات" + } } diff --git a/locales/bg-BG/auth.json b/locales/bg-BG/auth.json index 1d88bf0f709a..28f68c11fe19 100644 --- a/locales/bg-BG/auth.json +++ b/locales/bg-BG/auth.json @@ -1,8 +1,80 @@ { + "date": { + "prevMonth": "Миналия месец", + "recent30Days": "Последните 30 дни" + }, + "header": { + "desc": "Управлявайте информацията за вашия акаунт.", + "title": "Акаунт" + }, + "heatmaps": { + "legend": { + "less": "Неактивен", + "more": "Активен" + }, + "months": { + "apr": "Апр", + "aug": "Авг", + "dec": "Дек", + "feb": "Фев", + "jan": "Ян", + "jul": "Юл", + "jun": "Юн", + "mar": "Мар", + "may": "Май", + "nov": "Ное", + "oct": "Окт", + "sep": "Сеп" + }, + "tooltip": "{{date}} изпратил(а) {{count}} съобщения този ден", + "totalCount": "Общо {{count}} съобщения изпратени през последната година" + }, "login": "Вход", "loginOrSignup": "Вход / Регистрация", - "profile": "Профил", - "security": "Сигурност", + "profile": { + "avatar": "Аватар", + "email": "Имейл адрес", + "username": "Потребителско име" + }, "signout": "Изход", - "signup": "Регистрация" + "signup": "Регистрация", + "stats": { + "aiheatmaps": "Индекс на активност", + "assistants": "Асистенти", + "assistantsRank": { + "left": "Асистент", + "right": "Тематики", + "title": "Ранг на използване на асистенти" + }, + "createdAt": "Регистриран на", + "days": "дни", + "empty": { + "desc": "Моля, натрупайте повече данни от чат, за да видите", + "title": "Няма данни" + }, + "lastYearActivity": "активност през последната година", + "messages": "Съобщения", + "modelsRank": { + "left": "Модел", + "right": "Съобщения", + "title": "Ранг на използване на модели" + }, + "share": { + "title": "Моят индекс на активност с ИИ" + }, + "topics": "Тематики", + "topicsRank": { + "left": "Тематика", + "right": "Съобщения", + "title": "Ранг на съдържание на тематики" + }, + "updatedAt": "Актуализиран на", + "welcome": "{{username}}, това е вашият {{days}} ден с {{appName}}", + "words": "Думи" + }, + "tab": { + "profile": "Профил", + "security": "Сигурност", + "stats": "Статистика" + } } diff --git a/locales/de-DE/auth.json b/locales/de-DE/auth.json index 7d6a7d8c1620..425c27c70a22 100644 --- a/locales/de-DE/auth.json +++ b/locales/de-DE/auth.json @@ -1,8 +1,80 @@ { - "login": "Anmelden", - "loginOrSignup": "Anmelden / Registrieren", - "profile": "Profil", - "security": "Sicherheit", - "signout": "Abmelden", - "signup": "Registrieren" + "date": { + "prevMonth": "Letzter Monat", + "recent30Days": "Letzte 30 Tage" + }, + "header": { + "desc": "Verwalten Sie Ihre Kontoinformationen.", + "title": "Konto" + }, + "heatmaps": { + "legend": { + "less": "Inaktiv", + "more": "Aktiv" + }, + "months": { + "apr": "Apr", + "aug": "Aug", + "dec": "Dez", + "feb": "Feb", + "jan": "Jan", + "jul": "Jul", + "jun": "Jun", + "mar": "Mär", + "may": "Mai", + "nov": "Nov", + "oct": "Okt", + "sep": "Sep" + }, + "tooltip": "{{date}} hat {{count}} Nachrichten an diesem Tag gesendet", + "totalCount": "Insgesamt wurden {{count}} Nachrichten im letzten Jahr gesendet" + }, + "login": "Einloggen", + "loginOrSignup": "Einloggen / Registrieren", + "profile": { + "avatar": "Avatar", + "email": "E-Mail-Adresse", + "username": "Benutzername" + }, + "signout": "Ausloggen", + "signup": "Registrieren", + "stats": { + "aiheatmaps": "Aktivitätsindex", + "assistants": "Assistenten", + "assistantsRank": { + "left": "Assistent", + "right": "Themen", + "title": "Rang der Assistentennutzung" + }, + "createdAt": "Registriert am", + "days": "Tage", + "empty": { + "desc": "Bitte sammeln Sie mehr Chatdaten, um sie anzuzeigen", + "title": "Keine Daten" + }, + "lastYearActivity": "Aktivität im letzten Jahr", + "messages": "Nachrichten", + "modelsRank": { + "left": "Modell", + "right": "Nachrichten", + "title": "Rang der Modellenutzung" + }, + "share": { + "title": "Mein AI Aktivitätsindex" + }, + "topics": "Themen", + "topicsRank": { + "left": "Thema", + "right": "Nachrichten", + "title": "Rang des Themeninhalts" + }, + "updatedAt": "Aktualisiert am", + "welcome": "{{username}}, dies ist Ihr {{days}} Tag mit {{appName}}", + "words": "Wörter" + }, + "tab": { + "profile": "Profil", + "security": "Sicherheit", + "stats": "Statistiken" + } } diff --git a/locales/en-US/auth.json b/locales/en-US/auth.json index 54fcd15e7150..dc14c3d13ca8 100644 --- a/locales/en-US/auth.json +++ b/locales/en-US/auth.json @@ -1,8 +1,80 @@ { - "login": "Login", - "loginOrSignup": "Login / Sign up", - "profile": "Profile", - "security": "Security", - "signout": "Sign out", - "signup": "Sign up" + "date": { + "prevMonth": "Last Month", + "recent30Days": "Last 30 Days" + }, + "header": { + "desc": "Manage your account information.", + "title": "Account" + }, + "heatmaps": { + "legend": { + "less": "Inactive", + "more": "Active" + }, + "months": { + "apr": "Apr", + "aug": "Aug", + "dec": "Dec", + "feb": "Feb", + "jan": "Jan", + "jul": "Jul", + "jun": "Jun", + "mar": "Mar", + "may": "May", + "nov": "Nov", + "oct": "Oct", + "sep": "Sep" + }, + "tooltip": "{{date}} sent {{count}} messages that day", + "totalCount": "A total of {{count}} messages sent in the past year" + }, + "login": "Log In", + "loginOrSignup": "Log In / Sign Up", + "profile": { + "avatar": "Avatar", + "email": "Email Address", + "username": "Username" + }, + "signout": "Log Out", + "signup": "Sign Up", + "stats": { + "aiheatmaps": "Activity Index", + "assistants": "Assistants", + "assistantsRank": { + "left": "Assistant", + "right": "Topics", + "title": "Assistant Usage Rank" + }, + "createdAt": "Registered at", + "days": "days", + "empty": { + "desc": "Please accumulate more chat data to view", + "title": "No Data" + }, + "lastYearActivity": "Activity in the past year", + "messages": "Messages", + "modelsRank": { + "left": "Model", + "right": "Messages", + "title": "Model Usage Rank" + }, + "share": { + "title": "My AI Activity Index" + }, + "topics": "Topics", + "topicsRank": { + "left": "Topic", + "right": "Messages", + "title": "Topic Content Rank" + }, + "updatedAt": "Updated at", + "welcome": "{{username}}, this is your {{days}} day with {{appName}}", + "words": "Total Words" + }, + "tab": { + "profile": "Profile", + "security": "Security", + "stats": "Statistics" + } } diff --git a/locales/es-ES/auth.json b/locales/es-ES/auth.json index f62b3263fc62..afe4820f1eeb 100644 --- a/locales/es-ES/auth.json +++ b/locales/es-ES/auth.json @@ -1,8 +1,80 @@ { + "date": { + "prevMonth": "Último mes", + "recent30Days": "Últimos 30 días" + }, + "header": { + "desc": "Gestiona la información de tu cuenta.", + "title": "Cuenta" + }, + "heatmaps": { + "legend": { + "less": "Inactivo", + "more": "Activo" + }, + "months": { + "apr": "Abr", + "aug": "Ago", + "dec": "Dic", + "feb": "Feb", + "jan": "Ene", + "jul": "Jul", + "jun": "Jun", + "mar": "Mar", + "may": "May", + "nov": "Nov", + "oct": "Oct", + "sep": "Sep" + }, + "tooltip": "{{date}} envió {{count}} mensajes ese día", + "totalCount": "Un total de {{count}} mensajes enviados en el último año" + }, "login": "Iniciar sesión", "loginOrSignup": "Iniciar sesión / Registrarse", - "profile": "Perfil", - "security": "Seguridad", + "profile": { + "avatar": "Avatar", + "email": "Dirección de correo electrónico", + "username": "Nombre de usuario" + }, "signout": "Cerrar sesión", - "signup": "Registrarse" + "signup": "Registrarse", + "stats": { + "aiheatmaps": "Índice de Actividad", + "assistants": "Asistentes", + "assistantsRank": { + "left": "Asistente", + "right": "Temas", + "title": "Clasificación de Uso de Asistentes" + }, + "createdAt": "Registrado en", + "days": "días", + "empty": { + "desc": "Por favor, acumula más datos de chat para ver", + "title": "Sin datos" + }, + "lastYearActivity": "actividad en el último año", + "messages": "Mensajes", + "modelsRank": { + "left": "Modelo", + "right": "Mensajes", + "title": "Clasificación de Uso de Modelos" + }, + "share": { + "title": "Mi Índice de Actividad AI" + }, + "topics": "Temas", + "topicsRank": { + "left": "Tema", + "right": "Mensajes", + "title": "Clasificación de Contenido de Temas" + }, + "updatedAt": "Actualizado en", + "welcome": "{{username}}, este es tu {{days}} día con {{appName}}", + "words": "Palabras" + }, + "tab": { + "profile": "Perfil", + "security": "Seguridad", + "stats": "Estadísticas" + } } diff --git a/locales/fa-IR/auth.json b/locales/fa-IR/auth.json index b587c60918d0..36d9ce683681 100644 --- a/locales/fa-IR/auth.json +++ b/locales/fa-IR/auth.json @@ -1,8 +1,80 @@ { + "date": { + "prevMonth": "ماه گذشته", + "recent30Days": "۳۰ روز گذشته" + }, + "header": { + "desc": "اطلاعات حساب کاربری خود را مدیریت کنید.", + "title": "حساب کاربری" + }, + "heatmaps": { + "legend": { + "less": "غیرفعال", + "more": "فعال" + }, + "months": { + "apr": "آوریل", + "aug": "اوت", + "dec": "دسامبر", + "feb": "فوریه", + "jan": "ژانویه", + "jul": "ژوئیه", + "jun": "ژوئن", + "mar": "مارس", + "may": "مه", + "nov": "نوامبر", + "oct": "اکتبر", + "sep": "سپتامبر" + }, + "tooltip": "{{date}} در آن روز {{count}} پیام ارسال کرد", + "totalCount": "در مجموع {{count}} پیام در سال گذشته ارسال شده است" + }, "login": "ورود", - "loginOrSignup": "ورود / ثبت‌نام", - "profile": "پروفایل", - "security": "امنیت", - "signout": "خروج از حساب", - "signup": "ثبت‌نام" + "loginOrSignup": "ورود / ثبت نام", + "profile": { + "avatar": "آواتار", + "email": "آدرس ایمیل", + "username": "نام کاربری" + }, + "signout": "خروج", + "signup": "ثبت نام", + "stats": { + "aiheatmaps": "شاخص فعالیت", + "assistants": "دستیاران", + "assistantsRank": { + "left": "دستیار", + "right": "موضوعات", + "title": "رتبه استفاده از دستیار" + }, + "createdAt": "تاریخ ثبت نام", + "days": "روز", + "empty": { + "desc": "لطفاً داده‌های چت بیشتری جمع‌آوری کنید تا مشاهده کنید", + "title": "داده‌ای وجود ندارد" + }, + "lastYearActivity": "فعالیت در سال گذشته", + "messages": "پیام‌ها", + "modelsRank": { + "left": "مدل", + "right": "پیام‌ها", + "title": "رتبه استفاده از مدل" + }, + "share": { + "title": "شاخص فعالیت هوش مصنوعی من" + }, + "topics": "موضوعات", + "topicsRank": { + "left": "موضوع", + "right": "پیام‌ها", + "title": "رتبه محتوای موضوع" + }, + "updatedAt": "تاریخ به‌روزرسانی", + "welcome": "{{username}}، این {{days}} روز شما با {{appName}} است", + "words": "کلمات" + }, + "tab": { + "profile": "پروفایل", + "security": "امنیت", + "stats": "آمار" + } } diff --git a/locales/fr-FR/auth.json b/locales/fr-FR/auth.json index 9f511646143e..8d46b46675b6 100644 --- a/locales/fr-FR/auth.json +++ b/locales/fr-FR/auth.json @@ -1,8 +1,80 @@ { - "login": "Connexion", - "loginOrSignup": "Connexion / Inscription", - "profile": "Profil", - "security": "Sécurité", - "signout": "Déconnexion", - "signup": "Inscription" + "date": { + "prevMonth": "Le mois dernier", + "recent30Days": "Les 30 derniers jours" + }, + "header": { + "desc": "Gérez les informations de votre compte.", + "title": "Compte" + }, + "heatmaps": { + "legend": { + "less": "Inactif", + "more": "Actif" + }, + "months": { + "apr": "Avr", + "aug": "Août", + "dec": "Déc", + "feb": "Fév", + "jan": "Jan", + "jul": "Juil", + "jun": "Juin", + "mar": "Mar", + "may": "Mai", + "nov": "Nov", + "oct": "Oct", + "sep": "Sep" + }, + "tooltip": "{{date}} a envoyé {{count}} messages ce jour-là", + "totalCount": "Un total de {{count}} messages envoyés au cours de l'année dernière" + }, + "login": "Se connecter", + "loginOrSignup": "Se connecter / S'inscrire", + "profile": { + "avatar": "Avatar", + "email": "Adresse e-mail", + "username": "Nom d'utilisateur" + }, + "signout": "Se déconnecter", + "signup": "S'inscrire", + "stats": { + "aiheatmaps": "Indice d'activité", + "assistants": "Assistants", + "assistantsRank": { + "left": "Assistant", + "right": "Sujets", + "title": "Classement d'utilisation des assistants" + }, + "createdAt": "Inscrit le", + "days": "jours", + "empty": { + "desc": "Veuillez accumuler plus de données de chat pour voir", + "title": "Aucune donnée" + }, + "lastYearActivity": "activité au cours de l'année dernière", + "messages": "Messages", + "modelsRank": { + "left": "Modèle", + "right": "Messages", + "title": "Classement d'utilisation des modèles" + }, + "share": { + "title": "Mon indice d'activité IA" + }, + "topics": "Sujets", + "topicsRank": { + "left": "Sujet", + "right": "Messages", + "title": "Classement du contenu des sujets" + }, + "updatedAt": "Mis à jour le", + "welcome": "{{username}}, c'est votre {{days}} jour avec {{appName}}", + "words": "Mots" + }, + "tab": { + "profile": "Profil", + "security": "Sécurité", + "stats": "Statistiques" + } } diff --git a/locales/it-IT/auth.json b/locales/it-IT/auth.json index da602911c861..9bdf69337646 100644 --- a/locales/it-IT/auth.json +++ b/locales/it-IT/auth.json @@ -1,8 +1,80 @@ { + "date": { + "prevMonth": "Mese Scorso", + "recent30Days": "Ultimi 30 Giorni" + }, + "header": { + "desc": "Gestisci le informazioni del tuo account.", + "title": "Account" + }, + "heatmaps": { + "legend": { + "less": "Inattivo", + "more": "Attivo" + }, + "months": { + "apr": "Apr", + "aug": "Ago", + "dec": "Dic", + "feb": "Feb", + "jan": "Gen", + "jul": "Lug", + "jun": "Giu", + "mar": "Mar", + "may": "Mag", + "nov": "Nov", + "oct": "Ott", + "sep": "Set" + }, + "tooltip": "{{date}} ha inviato {{count}} messaggi quel giorno", + "totalCount": "Un totale di {{count}} messaggi inviati nell'ultimo anno" + }, "login": "Accedi", "loginOrSignup": "Accedi / Registrati", - "profile": "Profilo", - "security": "Sicurezza", - "signout": "Esci", - "signup": "Registrati" + "profile": { + "avatar": "Avatar", + "email": "Indirizzo Email", + "username": "Nome Utente" + }, + "signout": "Disconnetti", + "signup": "Registrati", + "stats": { + "aiheatmaps": "Indice di Attività", + "assistants": "Assistenti", + "assistantsRank": { + "left": "Assistente", + "right": "Argomenti", + "title": "Classifica Utilizzo Assistente" + }, + "createdAt": "Registrato il", + "days": "giorni", + "empty": { + "desc": "Accumula più dati di chat per visualizzare", + "title": "Nessun Dato" + }, + "lastYearActivity": "attività nell'ultimo anno", + "messages": "Messaggi", + "modelsRank": { + "left": "Modello", + "right": "Messaggi", + "title": "Classifica Utilizzo Modello" + }, + "share": { + "title": "Il Mio Indice di Attività AI" + }, + "topics": "Argomenti", + "topicsRank": { + "left": "Argomento", + "right": "Messaggi", + "title": "Classifica Contenuti Argomento" + }, + "updatedAt": "Aggiornato il", + "welcome": "{{username}}, questo è il tuo {{days}} giorno con {{appName}}", + "words": "Parole" + }, + "tab": { + "profile": "Profilo", + "security": "Sicurezza", + "stats": "Statistiche" + } } diff --git a/locales/ja-JP/auth.json b/locales/ja-JP/auth.json index 0caf5566e4ea..bd3ac04b3b9a 100644 --- a/locales/ja-JP/auth.json +++ b/locales/ja-JP/auth.json @@ -1,8 +1,80 @@ { + "date": { + "prevMonth": "先月", + "recent30Days": "過去30日間" + }, + "header": { + "desc": "アカウント情報を管理します。", + "title": "アカウント" + }, + "heatmaps": { + "legend": { + "less": "非アクティブ", + "more": "アクティブ" + }, + "months": { + "apr": "4月", + "aug": "8月", + "dec": "12月", + "feb": "2月", + "jan": "1月", + "jul": "7月", + "jun": "6月", + "mar": "3月", + "may": "5月", + "nov": "11月", + "oct": "10月", + "sep": "9月" + }, + "tooltip": "{{date}} に {{count}} 件のメッセージを送信しました", + "totalCount": "過去1年間に送信されたメッセージは合計で {{count}} 件です" + }, "login": "ログイン", - "loginOrSignup": "ログイン / 登録", - "profile": "プロフィール", - "security": "セキュリティ", + "loginOrSignup": "ログイン / サインアップ", + "profile": { + "avatar": "アバター", + "email": "メールアドレス", + "username": "ユーザー名" + }, "signout": "ログアウト", - "signup": "サインアップ" + "signup": "サインアップ", + "stats": { + "aiheatmaps": "アクティビティインデックス", + "assistants": "アシスタント", + "assistantsRank": { + "left": "アシスタント", + "right": "トピック", + "title": "アシスタント使用ランク" + }, + "createdAt": "登録日", + "days": "日", + "empty": { + "desc": "チャットデータをもっと蓄積してください", + "title": "データなし" + }, + "lastYearActivity": "過去1年間のアクティビティ", + "messages": "メッセージ", + "modelsRank": { + "left": "モデル", + "right": "メッセージ", + "title": "モデル使用ランク" + }, + "share": { + "title": "私のAIアクティビティインデックス" + }, + "topics": "トピック", + "topicsRank": { + "left": "トピック", + "right": "メッセージ", + "title": "トピックコンテンツランク" + }, + "updatedAt": "更新日", + "welcome": "{{username}}さん、これはあなたの {{days}} 日目の {{appName}} です", + "words": "単語" + }, + "tab": { + "profile": "プロフィール", + "security": "セキュリティ", + "stats": "統計" + } } diff --git a/locales/ko-KR/auth.json b/locales/ko-KR/auth.json index 78e9446feae6..90b324957735 100644 --- a/locales/ko-KR/auth.json +++ b/locales/ko-KR/auth.json @@ -1,8 +1,80 @@ { + "date": { + "prevMonth": "지난 달", + "recent30Days": "최근 30일" + }, + "header": { + "desc": "계정 정보를 관리하세요.", + "title": "계정" + }, + "heatmaps": { + "legend": { + "less": "비활성", + "more": "활성" + }, + "months": { + "apr": "4월", + "aug": "8월", + "dec": "12월", + "feb": "2월", + "jan": "1월", + "jul": "7월", + "jun": "6월", + "mar": "3월", + "may": "5월", + "nov": "11월", + "oct": "10월", + "sep": "9월" + }, + "tooltip": "{{date}}에 {{count}}개의 메시지를 보냈습니다.", + "totalCount": "지난 1년 동안 총 {{count}}개의 메시지가 전송되었습니다." + }, "login": "로그인", "loginOrSignup": "로그인 / 가입", - "profile": "프로필", - "security": "보안", + "profile": { + "avatar": "아바타", + "email": "이메일 주소", + "username": "사용자 이름" + }, "signout": "로그아웃", - "signup": "가입" + "signup": "가입", + "stats": { + "aiheatmaps": "활동 지수", + "assistants": "어시스턴트", + "assistantsRank": { + "left": "어시스턴트", + "right": "주제", + "title": "어시스턴트 사용 순위" + }, + "createdAt": "등록일", + "days": "일", + "empty": { + "desc": "더 많은 채팅 데이터를 축적하여 보세요.", + "title": "데이터 없음" + }, + "lastYearActivity": "지난 1년간의 활동", + "messages": "메시지", + "modelsRank": { + "left": "모델", + "right": "메시지", + "title": "모델 사용 순위" + }, + "share": { + "title": "내 AI 활동 지수" + }, + "topics": "주제", + "topicsRank": { + "left": "주제", + "right": "메시지", + "title": "주제 내용 순위" + }, + "updatedAt": "업데이트 일", + "welcome": "{{username}}, {{appName}}와 함께한 {{days}}일입니다.", + "words": "단어" + }, + "tab": { + "profile": "프로필", + "security": "보안", + "stats": "통계" + } } diff --git a/locales/nl-NL/auth.json b/locales/nl-NL/auth.json index 94c5ab96da1d..0c678d879dd6 100644 --- a/locales/nl-NL/auth.json +++ b/locales/nl-NL/auth.json @@ -1,8 +1,80 @@ { + "date": { + "prevMonth": "Vorige maand", + "recent30Days": "Laatste 30 dagen" + }, + "header": { + "desc": "Beheer uw accountinformatie.", + "title": "Account" + }, + "heatmaps": { + "legend": { + "less": "Inactief", + "more": "Actief" + }, + "months": { + "apr": "Apr", + "aug": "Aug", + "dec": "Dec", + "feb": "Feb", + "jan": "Jan", + "jul": "Jul", + "jun": "Jun", + "mar": "Mar", + "may": "Mei", + "nov": "Nov", + "oct": "Okt", + "sep": "Sep" + }, + "tooltip": "{{date}} heeft {{count}} berichten op die dag verzonden", + "totalCount": "In totaal zijn er {{count}} berichten verzonden in het afgelopen jaar" + }, "login": "Inloggen", - "loginOrSignup": "Inloggen / Registreren", - "profile": "Profiel", - "security": "Veiligheid", + "loginOrSignup": "Inloggen / Aanmelden", + "profile": { + "avatar": "Avatar", + "email": "E-mailadres", + "username": "Gebruikersnaam" + }, "signout": "Uitloggen", - "signup": "Registreren" + "signup": "Aanmelden", + "stats": { + "aiheatmaps": "Activiteitsindex", + "assistants": "Assistenten", + "assistantsRank": { + "left": "Assistent", + "right": "Onderwerpen", + "title": "Ranglijst Assistentgebruik" + }, + "createdAt": "Geregistreerd op", + "days": "dagen", + "empty": { + "desc": "Verzamel meer chatgegevens om te bekijken", + "title": "Geen gegevens" + }, + "lastYearActivity": "activiteit in het afgelopen jaar", + "messages": "Berichten", + "modelsRank": { + "left": "Model", + "right": "Berichten", + "title": "Ranglijst Modelgebruik" + }, + "share": { + "title": "Mijn AI Activiteitsindex" + }, + "topics": "Onderwerpen", + "topicsRank": { + "left": "Onderwerp", + "right": "Berichten", + "title": "Ranglijst Onderwerpinhoud" + }, + "updatedAt": "Bijgewerkt op", + "welcome": "{{username}}, dit is uw {{days}} dag met {{appName}}", + "words": "Woorden" + }, + "tab": { + "profile": "Profiel", + "security": "Beveiliging", + "stats": "Statistieken" + } } diff --git a/locales/pl-PL/auth.json b/locales/pl-PL/auth.json index 64f2b1584a36..9bd4b95c33b1 100644 --- a/locales/pl-PL/auth.json +++ b/locales/pl-PL/auth.json @@ -1,8 +1,80 @@ { + "date": { + "prevMonth": "Poprzedni miesiąc", + "recent30Days": "Ostatnie 30 dni" + }, + "header": { + "desc": "Zarządzaj informacjami o swoim koncie.", + "title": "Konto" + }, + "heatmaps": { + "legend": { + "less": "Nieaktywny", + "more": "Aktywny" + }, + "months": { + "apr": "Kwi", + "aug": "Sie", + "dec": "Gru", + "feb": "Lut", + "jan": "Sty", + "jul": "Lip", + "jun": "Cze", + "mar": "Mar", + "may": "Maj", + "nov": "Lis", + "oct": "Paź", + "sep": "Wrz" + }, + "tooltip": "{{date}} wysłał {{count}} wiadomości tego dnia", + "totalCount": "Łącznie {{count}} wiadomości wysłanych w ciągu ostatniego roku" + }, "login": "Zaloguj się", "loginOrSignup": "Zaloguj się / Zarejestruj się", - "profile": "Profil użytkownika", - "security": "Bezpieczeństwo", - "signout": "Wyloguj", - "signup": "Zarejestruj się" + "profile": { + "avatar": "Awatar", + "email": "Adres e-mail", + "username": "Nazwa użytkownika" + }, + "signout": "Wyloguj się", + "signup": "Zarejestruj się", + "stats": { + "aiheatmaps": "Indeks Aktywności", + "assistants": "Asystenci", + "assistantsRank": { + "left": "Asystent", + "right": "Tematy", + "title": "Ranking Użycia Asystentów" + }, + "createdAt": "Zarejestrowano", + "days": "dni", + "empty": { + "desc": "Proszę zgromadzić więcej danych czatu, aby wyświetlić", + "title": "Brak danych" + }, + "lastYearActivity": "aktywność w ciągu ostatniego roku", + "messages": "Wiadomości", + "modelsRank": { + "left": "Model", + "right": "Wiadomości", + "title": "Ranking Użycia Modeli" + }, + "share": { + "title": "Mój Indeks Aktywności AI" + }, + "topics": "Tematy", + "topicsRank": { + "left": "Temat", + "right": "Wiadomości", + "title": "Ranking Treści Tematów" + }, + "updatedAt": "Zaktualizowano", + "welcome": "{{username}}, to twój {{days}} dzień z {{appName}}", + "words": "Słowa" + }, + "tab": { + "profile": "Profil", + "security": "Bezpieczeństwo", + "stats": "Statystyki" + } } diff --git a/locales/pt-BR/auth.json b/locales/pt-BR/auth.json index ef3b9cec42bd..17697ffdbc67 100644 --- a/locales/pt-BR/auth.json +++ b/locales/pt-BR/auth.json @@ -1,8 +1,80 @@ { + "date": { + "prevMonth": "Último Mês", + "recent30Days": "Últimos 30 Dias" + }, + "header": { + "desc": "Gerencie as informações da sua conta.", + "title": "Conta" + }, + "heatmaps": { + "legend": { + "less": "Inativo", + "more": "Ativo" + }, + "months": { + "apr": "Abr", + "aug": "Ago", + "dec": "Dez", + "feb": "Fev", + "jan": "Jan", + "jul": "Jul", + "jun": "Jun", + "mar": "Mar", + "may": "Mai", + "nov": "Nov", + "oct": "Out", + "sep": "Set" + }, + "tooltip": "{{date}} enviou {{count}} mensagens naquele dia", + "totalCount": "Um total de {{count}} mensagens enviadas no último ano" + }, "login": "Entrar", - "loginOrSignup": "Entrar / Registrar", - "profile": "Perfil", - "security": "Segurança", + "loginOrSignup": "Entrar / Cadastrar", + "profile": { + "avatar": "Avatar", + "email": "Endereço de E-mail", + "username": "Nome de Usuário" + }, "signout": "Sair", - "signup": "Cadastre-se" + "signup": "Cadastrar", + "stats": { + "aiheatmaps": "Índice de Atividade", + "assistants": "Assistentes", + "assistantsRank": { + "left": "Assistente", + "right": "Tópicos", + "title": "Ranking de Uso do Assistente" + }, + "createdAt": "Registrado em", + "days": "dias", + "empty": { + "desc": "Por favor, acumule mais dados de chat para visualizar", + "title": "Sem Dados" + }, + "lastYearActivity": "atividade no último ano", + "messages": "Mensagens", + "modelsRank": { + "left": "Modelo", + "right": "Mensagens", + "title": "Ranking de Uso do Modelo" + }, + "share": { + "title": "Meu Índice de Atividade de IA" + }, + "topics": "Tópicos", + "topicsRank": { + "left": "Tópico", + "right": "Mensagens", + "title": "Ranking de Conteúdo do Tópico" + }, + "updatedAt": "Atualizado em", + "welcome": "{{username}}, este é seu {{days}} dia com {{appName}}", + "words": "Palavras" + }, + "tab": { + "profile": "Perfil", + "security": "Segurança", + "stats": "Estatísticas" + } } diff --git a/locales/ru-RU/auth.json b/locales/ru-RU/auth.json index 08be60486b09..fd65a1df4c7b 100644 --- a/locales/ru-RU/auth.json +++ b/locales/ru-RU/auth.json @@ -1,8 +1,80 @@ { + "date": { + "prevMonth": "Прошлый месяц", + "recent30Days": "Последние 30 дней" + }, + "header": { + "desc": "Управляйте информацией о своей учетной записи.", + "title": "Учетная запись" + }, + "heatmaps": { + "legend": { + "less": "Неактивный", + "more": "Активный" + }, + "months": { + "apr": "Апр", + "aug": "Авг", + "dec": "Дек", + "feb": "Фев", + "jan": "Янв", + "jul": "Июл", + "jun": "Июн", + "mar": "Мар", + "may": "Май", + "nov": "Ноя", + "oct": "Окт", + "sep": "Сен" + }, + "tooltip": "{{date}} отправил {{count}} сообщений в этот день", + "totalCount": "Всего {{count}} сообщений отправлено за последний год" + }, "login": "Войти", "loginOrSignup": "Войти / Зарегистрироваться", - "profile": "Профиль", - "security": "Безопасность", + "profile": { + "avatar": "Аватар", + "email": "Электронная почта", + "username": "Имя пользователя" + }, "signout": "Выйти", - "signup": "Зарегистрироваться" + "signup": "Зарегистрироваться", + "stats": { + "aiheatmaps": "Индекс активности", + "assistants": "Ассистенты", + "assistantsRank": { + "left": "Ассистент", + "right": "Темы", + "title": "Рейтинг использования ассистентов" + }, + "createdAt": "Зарегистрирован", + "days": "дней", + "empty": { + "desc": "Пожалуйста, накопите больше данных чата для просмотра", + "title": "Нет данных" + }, + "lastYearActivity": "активность за последний год", + "messages": "Сообщения", + "modelsRank": { + "left": "Модель", + "right": "Сообщения", + "title": "Рейтинг использования моделей" + }, + "share": { + "title": "Мой индекс активности ИИ" + }, + "topics": "Темы", + "topicsRank": { + "left": "Тема", + "right": "Сообщения", + "title": "Рейтинг содержания тем" + }, + "updatedAt": "Обновлено", + "welcome": "{{username}}, это ваш {{days}} день с {{appName}}", + "words": "Слова" + }, + "tab": { + "profile": "Профиль", + "security": "Безопасность", + "stats": "Статистика" + } } diff --git a/locales/tr-TR/auth.json b/locales/tr-TR/auth.json index ba16da2bd8b2..6b63eeadab56 100644 --- a/locales/tr-TR/auth.json +++ b/locales/tr-TR/auth.json @@ -1,8 +1,79 @@ { + "date": { + "prevMonth": "Geçen Ay", + "recent30Days": "Son 30 Gün" + }, + "header": { + "desc": "Hesap bilgilerinizi yönetin.", + "title": "Hesap" + }, + "heatmaps": { + "legend": { + "less": "Pasif", + "more": "Aktif" + }, + "months": { + "apr": "Nis", + "aug": "Ağu", + "dec": "Ara", + "feb": "Şub", + "jan": "Oca", + "jul": "Tem", + "jun": "Haz", + "mar": "Mar", + "may": "May", + "nov": "Kas", + "oct": "Eki", + "sep": "Eyl" + }, + "tooltip": "{{date}} tarihinde {{count}} mesaj gönderildi", + "totalCount": "Geçen yıl toplam {{count}} mesaj gönderildi" + }, "login": "Giriş Yap", "loginOrSignup": "Giriş Yap / Kayıt Ol", - "profile": "Profil", - "security": "Güvenlik", + "profile": { + "avatar": "Avatar", + "email": "E-posta Adresi", + "username": "Kullanıcı Adı" + }, "signout": "Çıkış Yap", - "signup": "Kaydol" + "signup": "Kayıt Ol", + "stats": { + "aiheatmaps": "Aktivite İndeksi", + "assistants": "Asistanlar", + "assistantsRank": { + "left": "Asistan", + "right": "Konu", + "title": "Asistan Kullanım Sıralaması" + }, + "createdAt": "Kayıtlı olduğu tarih", + "days": "gün", + "empty": { + "desc": "Görüntülemek için daha fazla sohbet verisi biriktirin", + "title": "Veri Yok" + }, + "lastYearActivity": "geçen yılki aktivite", + "messages": "Mesajlar", + "modelsRank": { + "left": "Model", + "right": "Mesajlar", + "title": "Model Kullanım Sıralaması" + }, + "share": { + "title": "AI Aktivite İndeksim" + }, + "topics": "Konu", + "topicsRank": { + "left": "Konu", + "right": "Mesajlar", + "title": "Konu İçerik Sıralaması" + }, + "updatedAt": "Güncellenme tarihi", + "welcome": "{{username}}, bu {{appName}} ile geçirdiğin {{days}} gün." + }, + "tab": { + "profile": "Profil", + "security": "Güvenlik", + "stats": "İstatistikler" + } } diff --git a/locales/vi-VN/auth.json b/locales/vi-VN/auth.json index 08482226bad2..f019732dbe68 100644 --- a/locales/vi-VN/auth.json +++ b/locales/vi-VN/auth.json @@ -1,8 +1,80 @@ { + "date": { + "prevMonth": "Tháng trước", + "recent30Days": "30 ngày qua" + }, + "header": { + "desc": "Quản lý thông tin tài khoản của bạn.", + "title": "Tài khoản" + }, + "heatmaps": { + "legend": { + "less": "Không hoạt động", + "more": "Hoạt động" + }, + "months": { + "apr": "Th4", + "aug": "Th8", + "dec": "Th12", + "feb": "Th2", + "jan": "Th1", + "jul": "Th7", + "jun": "Th6", + "mar": "Th3", + "may": "Th5", + "nov": "Th11", + "oct": "Th10", + "sep": "Th9" + }, + "tooltip": "{{date}} đã gửi {{count}} tin nhắn trong ngày đó", + "totalCount": "Tổng cộng {{count}} tin nhắn đã gửi trong năm qua" + }, "login": "Đăng nhập", "loginOrSignup": "Đăng nhập / Đăng ký", - "profile": "Hồ sơ cá nhân", - "security": "Bảo mật", + "profile": { + "avatar": "Ảnh đại diện", + "email": "Địa chỉ email", + "username": "Tên người dùng" + }, "signout": "Đăng xuất", - "signup": "Đăng ký" + "signup": "Đăng ký", + "stats": { + "aiheatmaps": "Chỉ số hoạt động", + "assistants": "Trợ lý", + "assistantsRank": { + "left": "Trợ lý", + "right": "Chủ đề", + "title": "Xếp hạng sử dụng trợ lý" + }, + "createdAt": "Đăng ký vào", + "days": "ngày", + "empty": { + "desc": "Vui lòng tích lũy thêm dữ liệu trò chuyện để xem", + "title": "Không có dữ liệu" + }, + "lastYearActivity": "hoạt động trong năm qua", + "messages": "Tin nhắn", + "modelsRank": { + "left": "Mô hình", + "right": "Tin nhắn", + "title": "Xếp hạng sử dụng mô hình" + }, + "share": { + "title": "Chỉ số hoạt động AI của tôi" + }, + "topics": "Chủ đề", + "topicsRank": { + "left": "Chủ đề", + "right": "Tin nhắn", + "title": "Xếp hạng nội dung chủ đề" + }, + "updatedAt": "Cập nhật vào", + "welcome": "{{username}}, đây là ngày {{days}} của bạn với {{appName}}", + "words": "Từ" + }, + "tab": { + "profile": "Hồ sơ", + "security": "Bảo mật", + "stats": "Thống kê" + } } diff --git a/locales/zh-CN/auth.json b/locales/zh-CN/auth.json index 08711d759fcc..f3ab6379f912 100644 --- a/locales/zh-CN/auth.json +++ b/locales/zh-CN/auth.json @@ -1,8 +1,80 @@ { + "date": { + "prevMonth": "上个月", + "recent30Days": "最近30天" + }, + "header": { + "desc": "管理您的账户信息。", + "title": "账户" + }, + "heatmaps": { + "legend": { + "less": "不活跃", + "more": "活跃" + }, + "months": { + "apr": "四月", + "aug": "八月", + "dec": "十二月", + "feb": "二月", + "jan": "一月", + "jul": "七月", + "jun": "六月", + "mar": "三月", + "may": "五月", + "nov": "十一月", + "oct": "十月", + "sep": "九月" + }, + "tooltip": "{{date}} 当日发送 {{count}} 条消息", + "totalCount": "过去一年共发送 {{count}} 条消息" + }, "login": "登录", "loginOrSignup": "登录 / 注册", - "profile": "个人资料", - "security": "安全", + "profile": { + "avatar": "头像", + "email": "电子邮件地址", + "username": "用户名" + }, "signout": "退出登录", - "signup": "注册" + "signup": "注册", + "stats": { + "aiheatmaps": "AI 指数", + "assistants": "助手数", + "assistantsRank": { + "left": "助手名称", + "right": "话题数", + "title": "助手使用率" + }, + "createdAt": "用户创建于", + "days": "天", + "empty": { + "desc": "请积累更多聊天数据后查看", + "title": "暂无数据" + }, + "lastYearActivity": "过去一年活跃度", + "messages": "消息数", + "modelsRank": { + "left": "模型名称", + "right": "消息数", + "title": "模型使用率" + }, + "share": { + "title": "我的 AI 活跃指数" + }, + "topics": "话题数", + "topicsRank": { + "left": "话题名称", + "right": "消息数", + "title": "话题内容量" + }, + "updatedAt": "数据更新至", + "welcome": "{{username}}, 这是你和 {{appName}} 相伴的第 {{days}} 天", + "words": "累计字数" + }, + "tab": { + "profile": "个人资料", + "security": "安全", + "stats": "数据统计" + } } diff --git a/locales/zh-TW/auth.json b/locales/zh-TW/auth.json index b9c5c6194747..27137eb6d518 100644 --- a/locales/zh-TW/auth.json +++ b/locales/zh-TW/auth.json @@ -1,8 +1,80 @@ { + "date": { + "prevMonth": "上個月", + "recent30Days": "最近30天" + }, + "header": { + "desc": "管理您的帳戶資訊。", + "title": "帳戶" + }, + "heatmaps": { + "legend": { + "less": "不活躍", + "more": "活躍" + }, + "months": { + "apr": "四月", + "aug": "八月", + "dec": "十二月", + "feb": "二月", + "jan": "一月", + "jul": "七月", + "jun": "六月", + "mar": "三月", + "may": "五月", + "nov": "十一月", + "oct": "十月", + "sep": "九月" + }, + "tooltip": "{{date}} 當日發送 {{count}} 條消息", + "totalCount": "過去一年共發送 {{count}} 條消息" + }, "login": "登入", "loginOrSignup": "登入 / 註冊", - "profile": "個人檔案", - "security": "安全", + "profile": { + "avatar": "頭像", + "email": "電子郵件地址", + "username": "用戶名" + }, "signout": "登出", - "signup": "註冊" + "signup": "註冊", + "stats": { + "aiheatmaps": "AI 指數", + "assistants": "助手數", + "assistantsRank": { + "left": "助手名稱", + "right": "話題數", + "title": "助手使用率" + }, + "createdAt": "用戶創建於", + "days": "天", + "empty": { + "desc": "請累積更多聊天數據後查看", + "title": "暫無數據" + }, + "lastYearActivity": "過去一年活躍度", + "messages": "消息數", + "modelsRank": { + "left": "模型名稱", + "right": "消息數", + "title": "模型使用率" + }, + "share": { + "title": "我的 AI 活躍指數" + }, + "topics": "話題數", + "topicsRank": { + "left": "話題名稱", + "right": "消息數", + "title": "話題內容量" + }, + "updatedAt": "數據更新至", + "welcome": "{{username}}, 這是你和 {{appName}} 相伴的第 {{days}} 天", + "words": "總字數" + }, + "tab": { + "profile": "個人資料", + "security": "安全", + "stats": "數據統計" + } } diff --git a/package.json b/package.json index 28f17683fa12..f411b5f6548b 100644 --- a/package.json +++ b/package.json @@ -125,11 +125,12 @@ "@icons-pack/react-simple-icons": "9.6.0", "@khmyznikov/pwa-install": "^0.3.9", "@langchain/community": "^0.3.0", + "@lobehub/charts": "^1.9.12", "@lobehub/chat-plugin-sdk": "^1.32.4", "@lobehub/chat-plugins-gateway": "^1.9.0", "@lobehub/icons": "^1.56.0", "@lobehub/tts": "^1.25.1", - "@lobehub/ui": "^1.155.8", + "@lobehub/ui": "^1.156.3", "@neondatabase/serverless": "^0.10.1", "@next/third-parties": "^15.0.0", "@react-spring/web": "^9.7.5", @@ -176,7 +177,7 @@ "mammoth": "^1.8.0", "modern-screenshot": "^4.4.39", "nanoid": "^5.0.7", - "next": "^15.1.2", + "next": "^15.1.3", "next-auth": "beta", "next-mdx-remote": "^4.4.1", "nextjs-toploader": "^3.7.15", diff --git a/src/app/(main)/(mobile)/me/(home)/__tests__/UserBanner.test.tsx b/src/app/(main)/(mobile)/me/(home)/__tests__/UserBanner.test.tsx index e99b7ac2df12..b3b0fc826f4a 100644 --- a/src/app/(main)/(mobile)/me/(home)/__tests__/UserBanner.test.tsx +++ b/src/app/(main)/(mobile)/me/(home)/__tests__/UserBanner.test.tsx @@ -24,6 +24,10 @@ vi.mock('@/features/User/UserLoginOrSignup/Community', () => ({ default: vi.fn(() =>
Mocked UserLoginOrSignup
), })); +vi.mock('@/const/version', () => ({ + isDeprecatedEdition: false, +})); + // 定义一个变量来存储 enableAuth 的值 let enableAuth = true; let enableClerk = false; diff --git a/src/app/(main)/(mobile)/me/(home)/__tests__/useCategory.test.tsx b/src/app/(main)/(mobile)/me/(home)/__tests__/useCategory.test.tsx index addb02536f0d..5c697ce4d9b6 100644 --- a/src/app/(main)/(mobile)/me/(home)/__tests__/useCategory.test.tsx +++ b/src/app/(main)/(mobile)/me/(home)/__tests__/useCategory.test.tsx @@ -57,26 +57,6 @@ describe('useCategory', () => { const { result } = renderHook(() => useCategory(), { wrapper }); - act(() => { - const items = result.current; - expect(items.some((item) => item.key === 'profile')).toBe(false); - expect(items.some((item) => item.key === 'setting')).toBe(true); - expect(items.some((item) => item.key === 'data')).toBe(true); - expect(items.some((item) => item.key === 'docs')).toBe(true); - expect(items.some((item) => item.key === 'feedback')).toBe(true); - expect(items.some((item) => item.key === 'changelog')).toBe(true); - }); - }); - - it('should return correct items when the user is logged in with Clerk', () => { - act(() => { - useUserStore.setState({ isSignedIn: true }); - }); - enableAuth = true; - enableClerk = true; - - const { result } = renderHook(() => useCategory(), { wrapper }); - act(() => { const items = result.current; expect(items.some((item) => item.key === 'profile')).toBe(true); @@ -88,31 +68,6 @@ describe('useCategory', () => { }); }); - it('should return correct items when the user is logged in with NextAuth', () => { - act(() => { - useUserStore.setState({ - isSignedIn: true, - enableAuth: () => true, - enabledNextAuth: true, - }); - }); - enableClerk = false; - - const { result } = renderHook(() => useCategory(), { wrapper }); - - act(() => { - const items = result.current; - // Should not render profile for NextAuth, it's Clerk only - expect(items.some((item) => item.key === 'profile')).toBe(false); - expect(items.some((item) => item.key === 'setting')).toBe(true); - expect(items.some((item) => item.key === 'data')).toBe(true); - expect(items.some((item) => item.key === 'docs')).toBe(true); - expect(items.some((item) => item.key === 'feedback')).toBe(true); - expect(items.some((item) => item.key === 'changelog')).toBe(true); - expect(items.some((item) => item.key === 'nextauthSignout')).toBe(true); - }); - }); - it('should return correct items when the user is not logged in', () => { act(() => { useUserStore.setState({ isSignedIn: false, enableAuth: () => true }); @@ -128,7 +83,6 @@ describe('useCategory', () => { expect(items.some((item) => item.key === 'docs')).toBe(true); expect(items.some((item) => item.key === 'feedback')).toBe(true); expect(items.some((item) => item.key === 'changelog')).toBe(true); - expect(items.some((item) => item.key === 'nextauthSignout')).toBe(false); }); }); diff --git a/src/app/(main)/(mobile)/me/(home)/features/UserBanner.tsx b/src/app/(main)/(mobile)/me/(home)/features/UserBanner.tsx index 842845d48eeb..b71d1358a62d 100644 --- a/src/app/(main)/(mobile)/me/(home)/features/UserBanner.tsx +++ b/src/app/(main)/(mobile)/me/(home)/features/UserBanner.tsx @@ -1,9 +1,11 @@ 'use client'; +import Link from 'next/link'; import { useRouter } from 'next/navigation'; import { memo } from 'react'; import { Flexbox } from 'react-layout-kit'; +import { isDeprecatedEdition } from '@/const/version'; import DataStatistics from '@/features/User/DataStatistics'; import UserInfo from '@/features/User/UserInfo'; import UserLoginOrSignup from '@/features/User/UserLoginOrSignup/Community'; @@ -21,21 +23,16 @@ const UserBanner = memo(() => { return ( - {!enableAuth ? ( + {!enableAuth || (enableAuth && isLoginWithAuth) ? ( <> - - - - ) : isLoginWithAuth ? ( - <> - { - // Profile page only works with Clerk - if (enabledNextAuth) return; - router.push('/me/profile'); - }} - /> - + + + + {!isDeprecatedEdition && ( + + + + )} ) : ( { const { canInstall, install } = usePWAInstall(); const { t } = useTranslation(['common', 'setting', 'auth']); const { showCloudPromotion, hideDocs } = useServerConfigStore(featureFlagsSelectors); - const [isLogin, isLoginWithAuth, isLoginWithClerk, enableAuth, signOut, isLoginWithNextAuth] = - useUserStore((s) => [ - authSelectors.isLogin(s), - authSelectors.isLoginWithAuth(s), - authSelectors.isLoginWithClerk(s), - authSelectors.enabledAuth(s), - s.logout, - authSelectors.isLoginWithNextAuth(s), - ]); + const [isLogin, isLoginWithAuth, enableAuth] = useUserStore((s) => [ + authSelectors.isLogin(s), + authSelectors.isLoginWithAuth(s), + authSelectors.enabledAuth(s), + ]); const profile: CellProps[] = [ { @@ -121,20 +116,11 @@ export const useCategory = () => { }, ].filter(Boolean) as CellProps[]; - const nextAuthSignOut: CellProps[] = [ - { - icon: LogOut, - key: 'nextauthSignout', - label: t('auth:signout'), - onClick: signOut, - }, - ]; - const mainItems = [ { type: 'divider', }, - ...(isLoginWithClerk ? profile : []), + ...(!enableAuth || (enableAuth && isLoginWithAuth) ? profile : []), ...(enableAuth ? (isLoginWithAuth ? settings : []) : settingsWithoutAuth), /* ↓ cloud slot ↓ */ @@ -142,7 +128,6 @@ export const useCategory = () => { ...(canInstall ? pwa : []), ...(isLogin && !isServerMode ? data : []), ...(!hideDocs ? helps : []), - ...(enableAuth && isLoginWithNextAuth ? nextAuthSignOut : []), ].filter(Boolean) as CellProps[]; return mainItems; diff --git a/src/app/(main)/(mobile)/me/profile/features/Category.tsx b/src/app/(main)/(mobile)/me/profile/features/Category.tsx index fe3ae5a39495..0b1fb84313d2 100644 --- a/src/app/(main)/(mobile)/me/profile/features/Category.tsx +++ b/src/app/(main)/(mobile)/me/profile/features/Category.tsx @@ -1,43 +1,60 @@ 'use client'; -import { LogOut, ShieldCheck, UserCircle } from 'lucide-react'; +import { ChartColumnBigIcon, LogOut, ShieldCheck, UserCircle } from 'lucide-react'; import { useRouter } from 'next/navigation'; import { memo } from 'react'; import { useTranslation } from 'react-i18next'; import Cell, { CellProps } from '@/components/Cell'; +import { isDeprecatedEdition } from '@/const/version'; +import { ProfileTabs } from '@/store/global/initialState'; import { useUserStore } from '@/store/user'; +import { authSelectors } from '@/store/user/slices/auth/selectors'; const Category = memo(() => { + const [isLogin, enableAuth, isLoginWithClerk, signOut] = useUserStore((s) => [ + authSelectors.isLogin(s), + authSelectors.enabledAuth(s), + authSelectors.isLoginWithClerk(s), + s.logout, + ]); const router = useRouter(); const { t } = useTranslation('auth'); - const signOut = useUserStore((s) => s.logout); const items: CellProps[] = [ { icon: UserCircle, - key: 'profile', - label: t('profile'), + key: ProfileTabs.Profile, + label: t('tab.profile'), onClick: () => router.push('/profile'), }, - { - icon: ShieldCheck, - key: 'security', - label: t('security'), - onClick: () => router.push('/profile/security'), - }, - { - type: 'divider', - }, - { - icon: LogOut, - key: 'logout', - label: t('signout', { ns: 'auth' }), - onClick: () => { - signOut(); - router.push('/login'); + enableAuth && + isLoginWithClerk && { + icon: ShieldCheck, + key: ProfileTabs.Security, + label: t('tab.security'), + onClick: () => router.push('/profile/security'), }, + !isDeprecatedEdition && { + icon: ChartColumnBigIcon, + key: ProfileTabs.Stats, + label: t('tab.stats'), + onClick: () => router.push('/profile/stats'), }, - ]; + enableAuth && + isLogin && { + type: 'divider', + }, + enableAuth && + isLogin && { + icon: LogOut, + key: 'logout', + label: t('signout', { ns: 'auth' }), + onClick: () => { + signOut(); + router.push('/login'); + }, + }, + ].filter(Boolean) as CellProps[]; return items?.map((item, index) => ); }); diff --git a/src/app/(main)/(mobile)/me/profile/layout.tsx b/src/app/(main)/(mobile)/me/profile/layout.tsx index d6da87363462..ae4b25ae65a5 100644 --- a/src/app/(main)/(mobile)/me/profile/layout.tsx +++ b/src/app/(main)/(mobile)/me/profile/layout.tsx @@ -1,13 +1,10 @@ -import { notFound } from 'next/navigation'; import { PropsWithChildren } from 'react'; import MobileContentLayout from '@/components/server/MobileNavLayout'; -import { enableClerk } from '@/const/auth'; import Header from './features/Header'; const Layout = ({ children }: PropsWithChildren) => { - if (!enableClerk) return notFound(); return }>{children}; }; diff --git a/src/app/(main)/(mobile)/me/profile/page.tsx b/src/app/(main)/(mobile)/me/profile/page.tsx index 85de6656380f..32f1f5770476 100644 --- a/src/app/(main)/(mobile)/me/profile/page.tsx +++ b/src/app/(main)/(mobile)/me/profile/page.tsx @@ -7,10 +7,10 @@ import { isMobileDevice } from '@/utils/server/responsive'; import Category from './features/Category'; export const generateMetadata = async () => { - const { t } = await translation('clerk'); + const { t } = await translation('auth'); return metadataModule.generate({ - description: t('userProfile.navbar.title'), - title: t('userProfile.navbar.description'), + description: t('header.desc'), + title: t('header.title'), url: '/me/profile', }); }; diff --git a/src/app/(main)/chat/loading.tsx b/src/app/(main)/chat/loading.tsx index 44f5102947c3..3ae0d871289d 100644 --- a/src/app/(main)/chat/loading.tsx +++ b/src/app/(main)/chat/loading.tsx @@ -1,3 +1,3 @@ -import CircleLoading from '@/components/Loading/BrandTextLoading'; +import Loading from '@/components/Loading/BrandTextLoading'; -export default () => ; +export default () => ; diff --git a/src/app/(main)/discover/loading.tsx b/src/app/(main)/discover/loading.tsx index 611cded27273..3ae0d871289d 100644 --- a/src/app/(main)/discover/loading.tsx +++ b/src/app/(main)/discover/loading.tsx @@ -1,9 +1,3 @@ -import { Center } from 'react-layout-kit'; +import Loading from '@/components/Loading/BrandTextLoading'; -import CircleLoading from '@/components/Loading/BrandTextLoading'; - -export default () => ( -
- -
-); +export default () => ; diff --git a/src/app/(main)/files/loading.tsx b/src/app/(main)/files/loading.tsx index 44f5102947c3..3ae0d871289d 100644 --- a/src/app/(main)/files/loading.tsx +++ b/src/app/(main)/files/loading.tsx @@ -1,3 +1,3 @@ -import CircleLoading from '@/components/Loading/BrandTextLoading'; +import Loading from '@/components/Loading/BrandTextLoading'; -export default () => ; +export default () => ; diff --git a/src/app/(main)/profile/(home)/Client.tsx b/src/app/(main)/profile/(home)/Client.tsx new file mode 100644 index 000000000000..13ef127c9d80 --- /dev/null +++ b/src/app/(main)/profile/(home)/Client.tsx @@ -0,0 +1,53 @@ +'use client'; + +import { Form, type ItemGroup } from '@lobehub/ui'; +import { memo } from 'react'; +import { useTranslation } from 'react-i18next'; + +import { FORM_STYLE } from '@/const/layoutTokens'; +import AvatarWithUpload from '@/features/AvatarWithUpload'; +import UserAvatar from '@/features/User/UserAvatar'; +import { useUserStore } from '@/store/user'; +import { authSelectors, userProfileSelectors } from '@/store/user/selectors'; + +type SettingItemGroup = ItemGroup; + +const Client = memo<{ mobile?: boolean }>(() => { + const [isLoginWithNextAuth] = useUserStore((s) => [authSelectors.isLoginWithNextAuth(s)]); + const [enableAuth, nickname, username, userProfile] = useUserStore((s) => [ + s.enableAuth(), + userProfileSelectors.nickName(s), + userProfileSelectors.username(s), + userProfileSelectors.userProfile(s), + ]); + + const [form] = Form.useForm(); + const { t } = useTranslation('auth'); + + const profile: SettingItemGroup = { + children: [ + { + children: enableAuth && isLoginWithNextAuth ? : , + label: t('profile.avatar'), + minWidth: undefined, + }, + { + children: nickname || username, + label: t('profile.username'), + minWidth: undefined, + }, + { + children: userProfile?.email || '--', + hidden: !isLoginWithNextAuth || !userProfile?.email, + label: t('profile.email'), + minWidth: undefined, + }, + ], + title: t('tab.profile'), + }; + return ( +
+ ); +}); + +export default Client; diff --git a/src/app/(main)/profile/(home)/[[...slugs]]/page.tsx b/src/app/(main)/profile/(home)/[[...slugs]]/page.tsx new file mode 100644 index 000000000000..e122316d5df4 --- /dev/null +++ b/src/app/(main)/profile/(home)/[[...slugs]]/page.tsx @@ -0,0 +1,38 @@ +import { Skeleton } from 'antd'; +import dynamic from 'next/dynamic'; + +import { enableClerk } from '@/const/auth'; +import { metadataModule } from '@/server/metadata'; +import { translation } from '@/server/translation'; +import { isMobileDevice } from '@/utils/server/responsive'; + +import Client from '../Client'; + +// 为了兼容 ClerkProfile, 需要使用 [[...slug]] + +const ClerkProfile = dynamic(() => import('../../features/ClerkProfile'), { + loading: () => ( +
+ +
+ ), +}); + +export const generateMetadata = async () => { + const { t } = await translation('auth'); + return metadataModule.generate({ + description: t('header.desc'), + title: t('tab.profile'), + url: '/profile', + }); +}; + +const Page = async () => { + const mobile = await isMobileDevice(); + + if (enableClerk) return ; + + return ; +}; + +export default Page; diff --git a/src/app/(main)/profile/@category/default.tsx b/src/app/(main)/profile/@category/default.tsx new file mode 100644 index 000000000000..8765afe01ffc --- /dev/null +++ b/src/app/(main)/profile/@category/default.tsx @@ -0,0 +1,9 @@ +import CategoryContent from './features/CategoryContent'; + +const Category = () => { + return ; +}; + +Category.displayName = 'SettingCategory'; + +export default Category; diff --git a/src/app/(main)/profile/@category/features/CategoryContent.tsx b/src/app/(main)/profile/@category/features/CategoryContent.tsx new file mode 100644 index 000000000000..57d5b8ca483a --- /dev/null +++ b/src/app/(main)/profile/@category/features/CategoryContent.tsx @@ -0,0 +1,38 @@ +'use client'; + +import { memo } from 'react'; +import urlJoin from 'url-join'; + +import Menu from '@/components/Menu'; +import { useActiveSettingsKey } from '@/hooks/useActiveTabKey'; +import { useQuery } from '@/hooks/useQuery'; +import { useQueryRoute } from '@/hooks/useQueryRoute'; +import { ProfileTabs, 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 ( + { + const activeKey = key === ProfileTabs.Profile ? '/' : key; + if (modal) { + router.replace('/profile/modal', { query: { tab: activeKey } }); + } else { + router.push(urlJoin('/profile', activeKey)); + } + }} + selectable + selectedKeys={[modal ? tab : (activeTab as any)]} + variant={'compact'} + /> + ); +}); + +export default CategoryContent; diff --git a/src/app/(main)/profile/[[...slugs]]/Client.tsx b/src/app/(main)/profile/[[...slugs]]/Client.tsx deleted file mode 100644 index 616b2d18ebf9..000000000000 --- a/src/app/(main)/profile/[[...slugs]]/Client.tsx +++ /dev/null @@ -1,76 +0,0 @@ -'use client'; - -import { UserProfile } from '@clerk/nextjs'; -import { ElementsConfig } from '@clerk/types'; -import { createStyles } from 'antd-style'; -import { memo } from 'react'; - -export const useStyles = createStyles( - ({ css, token, cx }, mobile: boolean) => - ({ - cardBox: css` - width: 100%; - max-width: unset; - height: 100%; - - border: unset; - border-radius: unset; - box-shadow: unset; - `, - footer: cx( - mobile && - css` - display: none; - `, - ), - navbar: css` - flex: none; - - width: 280px; - max-width: unset; - margin-inline-end: 0; - padding-block: 24px 16px; - padding-inline: 12px; - - background: ${token.colorBgContainer}; - border-inline-end: 1px solid ${token.colorSplit}; - `, - navbarMobileMenuRow: cx( - mobile && - css` - display: none; - `, - ), - pageScrollBox: css` - align-self: center; - width: 100%; - max-width: 1024px; - `, - rootBox: css` - width: 100%; - height: 100%; - `, - scrollBox: css` - background: ${token.colorBgLayout}; - border: unset; - border-radius: unset; - `, - }) as Partial<{ - // eslint-disable-next-line unused-imports/no-unused-vars - [k in keyof ElementsConfig]: any; - }>, -); - -const Client = memo<{ mobile?: boolean }>(({ mobile }) => { - const { styles } = useStyles(mobile); - - return ( - - ); -}); - -export default Client; diff --git a/src/app/(main)/profile/_layout/Desktop/Header.tsx b/src/app/(main)/profile/_layout/Desktop/Header.tsx new file mode 100644 index 000000000000..77e8ef25a1c4 --- /dev/null +++ b/src/app/(main)/profile/_layout/Desktop/Header.tsx @@ -0,0 +1,85 @@ +'use client'; + +import { ActionIcon, ChatHeader, ChatHeaderTitle } from '@lobehub/ui'; +import { Drawer, type DrawerProps } from 'antd'; +import { createStyles } from 'antd-style'; +import { Menu } from 'lucide-react'; +import { ReactNode, memo, useState } from 'react'; +import { Flexbox } from 'react-layout-kit'; + +import BrandWatermark from '@/components/BrandWatermark'; + +const useStyles = createStyles(({ token, css }) => ({ + container: css` + position: relative; + flex: none; + height: 54px; + background: ${token.colorBgContainer}; + `, + title: css` + font-size: 18px; + font-weight: 700; + line-height: 1.2; + `, +})); + +interface HeaderProps extends Pick { + children: ReactNode; + title: ReactNode; +} + +const Header = memo(({ children, getContainer, title }) => { + const [open, setOpen] = useState(false); + const { styles, theme } = useStyles(); + + return ( + <> + + setOpen(true)} + size={{ blockSize: 32, fontSize: 18 }} + /> + {title} + + } + /> + } + /> + 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)/profile/_layout/Desktop/SideBar.tsx b/src/app/(main)/profile/_layout/Desktop/SideBar.tsx new file mode 100644 index 000000000000..5e5eebf200c5 --- /dev/null +++ b/src/app/(main)/profile/_layout/Desktop/SideBar.tsx @@ -0,0 +1,42 @@ +'use client'; + +import { createStyles } from 'antd-style'; +import { useTranslation } from 'react-i18next'; +import { Flexbox, FlexboxProps } from 'react-layout-kit'; + +import BrandWatermark from '@/components/BrandWatermark'; +import PanelTitle from '@/components/PanelTitle'; + +const useStyles = createStyles(({ token, css }) => ({ + container: css` + padding-block: 0 16px; + padding-inline: 12px; + background: ${token.colorBgContainer}; + border-inline-end: 1px solid ${token.colorBorder}; + `, +})); + +interface SidebarLayoutProps extends FlexboxProps { + desc?: string; + title?: string; +} + +const SidebarLayout = ({ children, className, title, desc, ...rest }: SidebarLayoutProps) => { + const { cx, styles } = useStyles(); + const { t } = useTranslation('auth'); + return ( + + + {children} + + + ); +}; + +export default SidebarLayout; diff --git a/src/app/(main)/profile/_layout/Desktop/index.tsx b/src/app/(main)/profile/_layout/Desktop/index.tsx new file mode 100644 index 000000000000..e440dcca1087 --- /dev/null +++ b/src/app/(main)/profile/_layout/Desktop/index.tsx @@ -0,0 +1,48 @@ +'use client'; + +import { useResponsive } from 'antd-style'; +import { memo, useRef } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Flexbox } from 'react-layout-kit'; + +import InitClientDB from '@/features/InitClientDB'; +import Footer from '@/features/Setting/Footer'; +import SettingContainer from '@/features/Setting/SettingContainer'; +import { useActiveProfileKey } from '@/hooks/useActiveTabKey'; + +import { LayoutProps } from '../type'; +import Header from './Header'; +import SideBar from './SideBar'; + +const Layout = memo(({ children, category }) => { + const ref = useRef(null); + const { md = true } = useResponsive(); + const { t } = useTranslation('auth'); + const activeKey = useActiveProfileKey(); + + return ( + <> + + {md ? ( + {category} + ) : ( +
ref.current} title={<>{t(`tab.${activeKey}`)}}> + {category} +
+ )} + }>{children} +
+ + + ); +}); + +Layout.displayName = 'DesktopProfileLayout'; + +export default Layout; diff --git a/src/app/(main)/profile/_layout/Mobile/Header.tsx b/src/app/(main)/profile/_layout/Mobile/Header.tsx index ee141ba9528f..0f4380dabddb 100644 --- a/src/app/(main)/profile/_layout/Mobile/Header.tsx +++ b/src/app/(main)/profile/_layout/Mobile/Header.tsx @@ -1,22 +1,40 @@ 'use client'; import { MobileNavBar, MobileNavBarTitle } from '@lobehub/ui'; -import { usePathname, useRouter } from 'next/navigation'; +import { useRouter } from 'next/navigation'; import { memo } from 'react'; import { useTranslation } from 'react-i18next'; +import { Flexbox } from 'react-layout-kit'; +import { useActiveProfileKey } from '@/hooks/useActiveTabKey'; import { mobileHeaderSticky } from '@/styles/mobileHeader'; +import ShareButton from '../../stats/features/ShareButton'; + const Header = memo(() => { const { t } = useTranslation('auth'); const router = useRouter(); - const pathname = usePathname(); - const isSecurity = pathname.startsWith('/prifile/security'); + const activeSettingsKey = useActiveProfileKey(); + const isStats = activeSettingsKey === 'stats'; + + const handleBackClick = () => { + router.push('/me/profile'); + }; + return ( } - onBackClick={() => router.push('/me/profile')} + center={ + + {t(`tab.${activeSettingsKey}`)} + + } + /> + } + onBackClick={handleBackClick} + right={isStats ? : undefined} showBackButton style={mobileHeaderSticky} /> diff --git a/src/app/(main)/profile/_layout/Mobile/index.tsx b/src/app/(main)/profile/_layout/Mobile/index.tsx index f6f20543036c..c972d95a39fd 100644 --- a/src/app/(main)/profile/_layout/Mobile/index.tsx +++ b/src/app/(main)/profile/_layout/Mobile/index.tsx @@ -1,16 +1,23 @@ -import { PropsWithChildren } from 'react'; +import MobileContentLayout from '@/components/server/MobileNavLayout'; +import InitClientDB from '@/features/InitClientDB'; +import Footer from '@/features/Setting/Footer'; +import { LayoutProps } from '../type'; import Header from './Header'; -const Layout = ({ children }: PropsWithChildren) => { +const Layout = ({ children }: LayoutProps) => { return ( <> -
- {children} + }> + {children} +
+