@lobehub/lobehub 2.0.0-next.163 → 2.0.0-next.164

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,33 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ## [Version 2.0.0-next.164](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.163...v2.0.0-next.164)
6
+
7
+ <sup>Released on **2025-12-08**</sup>
8
+
9
+ #### 💄 Styles
10
+
11
+ - **profile**: Add mobile responsive layout and signup improvements.
12
+ - **misc**: Update link handling in PlanTag component to use react-router-dom.
13
+
14
+ <br/>
15
+
16
+ <details>
17
+ <summary><kbd>Improvements and Fixes</kbd></summary>
18
+
19
+ #### Styles
20
+
21
+ - **profile**: Add mobile responsive layout and signup improvements, closes [#10669](https://github.com/lobehub/lobe-chat/issues/10669) ([1afd471](https://github.com/lobehub/lobe-chat/commit/1afd471))
22
+ - **misc**: Update link handling in PlanTag component to use react-router-dom, closes [#10673](https://github.com/lobehub/lobe-chat/issues/10673) ([3aceeb6](https://github.com/lobehub/lobe-chat/commit/3aceeb6))
23
+
24
+ </details>
25
+
26
+ <div align="right">
27
+
28
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
29
+
30
+ </div>
31
+
5
32
  ## [Version 2.0.0-next.163](https://github.com/lobehub/lobe-chat/compare/v2.0.0-next.162...v2.0.0-next.163)
6
33
 
7
34
  <sup>Released on **2025-12-06**</sup>
package/changelog/v1.json CHANGED
@@ -1,4 +1,13 @@
1
1
  [
2
+ {
3
+ "children": {
4
+ "improvements": [
5
+ "Update link handling in PlanTag component to use react-router-dom."
6
+ ]
7
+ },
8
+ "date": "2025-12-08",
9
+ "version": "2.0.0-next.164"
10
+ },
2
11
  {
3
12
  "children": {
4
13
  "fixes": [
@@ -54,6 +54,7 @@
54
54
  },
55
55
  "betterAuth": {
56
56
  "errors": {
57
+ "confirmPasswordRequired": "يرجى تأكيد كلمة المرور",
57
58
  "emailExists": "هذا البريد الإلكتروني مسجّل بالفعل، يرجى تسجيل الدخول مباشرة",
58
59
  "emailInvalid": "يرجى إدخال عنوان بريد إلكتروني صالح",
59
60
  "emailNotRegistered": "هذا البريد الإلكتروني غير مسجل",
@@ -65,6 +66,7 @@
65
66
  "passwordFormat": "يجب أن تحتوي كلمة المرور على أحرف وأرقام",
66
67
  "passwordMaxLength": "يجب ألا تتجاوز كلمة المرور 64 حرفًا",
67
68
  "passwordMinLength": "يجب أن تتكون كلمة المرور من 8 أحرف على الأقل",
69
+ "passwordMismatch": "كلمتا المرور غير متطابقتين",
68
70
  "passwordRequired": "يرجى إدخال كلمة المرور",
69
71
  "usernameNotRegistered": "اسم المستخدم هذا غير مسجل",
70
72
  "usernameRequired": "يرجى إدخال اسم المستخدم"
@@ -125,6 +127,7 @@
125
127
  "submit": "تسجيل الدخول"
126
128
  },
127
129
  "signup": {
130
+ "confirmPasswordPlaceholder": "يرجى تأكيد كلمة المرور",
128
131
  "emailPlaceholder": "يرجى إدخال عنوان البريد الإلكتروني",
129
132
  "error": "فشل التسجيل، يرجى المحاولة مرة أخرى",
130
133
  "firstNamePlaceholder": "الاسم الأول",
@@ -54,6 +54,7 @@
54
54
  },
55
55
  "betterAuth": {
56
56
  "errors": {
57
+ "confirmPasswordRequired": "Моля, потвърдете паролата",
57
58
  "emailExists": "Този имейл вече е регистриран. Моля, влезте директно.",
58
59
  "emailInvalid": "Моля, въведете валиден имейл адрес",
59
60
  "emailNotRegistered": "Този имейл все още не е регистриран",
@@ -65,6 +66,7 @@
65
66
  "passwordFormat": "Паролата трябва да съдържа както букви, така и цифри",
66
67
  "passwordMaxLength": "Паролата не може да надвишава 64 знака",
67
68
  "passwordMinLength": "Паролата трябва да бъде поне 8 знака",
69
+ "passwordMismatch": "Въведените пароли не съвпадат",
68
70
  "passwordRequired": "Моля, въведете парола",
69
71
  "usernameNotRegistered": "Това потребителско име не е регистрирано",
70
72
  "usernameRequired": "Моля, въведете потребителско име"
@@ -125,6 +127,7 @@
125
127
  "submit": "Вход"
126
128
  },
127
129
  "signup": {
130
+ "confirmPasswordPlaceholder": "Моля, потвърдете паролата",
128
131
  "emailPlaceholder": "Моля, въведете имейл адрес",
129
132
  "error": "Регистрацията не бе успешна, моля опитайте отново",
130
133
  "firstNamePlaceholder": "Собствено име",
@@ -54,6 +54,7 @@
54
54
  },
55
55
  "betterAuth": {
56
56
  "errors": {
57
+ "confirmPasswordRequired": "Bitte bestätigen Sie Ihr Passwort",
57
58
  "emailExists": "Diese E-Mail-Adresse ist bereits registriert. Bitte melden Sie sich direkt an.",
58
59
  "emailInvalid": "Bitte geben Sie eine gültige E-Mail-Adresse ein",
59
60
  "emailNotRegistered": "Diese E-Mail-Adresse ist noch nicht registriert",
@@ -65,6 +66,7 @@
65
66
  "passwordFormat": "Das Passwort muss Buchstaben und Zahlen enthalten",
66
67
  "passwordMaxLength": "Das Passwort darf maximal 64 Zeichen lang sein",
67
68
  "passwordMinLength": "Das Passwort muss mindestens 8 Zeichen lang sein",
69
+ "passwordMismatch": "Die beiden eingegebenen Passwörter stimmen nicht überein",
68
70
  "passwordRequired": "Bitte geben Sie ein Passwort ein",
69
71
  "usernameNotRegistered": "Dieser Benutzername ist noch nicht registriert",
70
72
  "usernameRequired": "Bitte geben Sie einen Benutzernamen ein"
@@ -125,6 +127,7 @@
125
127
  "submit": "Anmelden"
126
128
  },
127
129
  "signup": {
130
+ "confirmPasswordPlaceholder": "Bitte bestätigen Sie Ihr Passwort",
128
131
  "emailPlaceholder": "Bitte geben Sie Ihre E-Mail-Adresse ein",
129
132
  "error": "Registrierung fehlgeschlagen, bitte versuchen Sie es erneut",
130
133
  "firstNamePlaceholder": "Vorname",
@@ -54,8 +54,9 @@
54
54
  },
55
55
  "betterAuth": {
56
56
  "errors": {
57
- "emailInvalid": "Please enter a valid email address or username",
57
+ "confirmPasswordRequired": "Please confirm your password",
58
58
  "emailExists": "This email is already registered. Please sign in instead",
59
+ "emailInvalid": "Please enter a valid email address or username",
59
60
  "emailNotRegistered": "This email or username is not registered",
60
61
  "emailNotVerified": "Email not verified, please verify your email first",
61
62
  "emailRequired": "Please enter your email address or username",
@@ -65,6 +66,7 @@
65
66
  "passwordFormat": "Password must contain both letters and numbers",
66
67
  "passwordMaxLength": "Password must not exceed 64 characters",
67
68
  "passwordMinLength": "Password must be at least 8 characters",
69
+ "passwordMismatch": "The passwords do not match",
68
70
  "passwordRequired": "Please enter your password",
69
71
  "usernameNotRegistered": "This username is not registered",
70
72
  "usernameRequired": "Please enter your username"
@@ -125,6 +127,7 @@
125
127
  "submit": "Sign In"
126
128
  },
127
129
  "signup": {
130
+ "confirmPasswordPlaceholder": "Confirm your password",
128
131
  "emailPlaceholder": "Enter your email address",
129
132
  "error": "Sign up failed, please try again",
130
133
  "firstNamePlaceholder": "First Name",
@@ -54,6 +54,7 @@
54
54
  },
55
55
  "betterAuth": {
56
56
  "errors": {
57
+ "confirmPasswordRequired": "Por favor, confirma la contraseña",
57
58
  "emailExists": "Este correo electrónico ya está registrado. Por favor, inicia sesión directamente.",
58
59
  "emailInvalid": "Por favor, introduce una dirección de correo electrónico válida",
59
60
  "emailNotRegistered": "Este correo electrónico no está registrado",
@@ -65,6 +66,7 @@
65
66
  "passwordFormat": "La contraseña debe contener letras y números",
66
67
  "passwordMaxLength": "La contraseña no puede tener más de 64 caracteres",
67
68
  "passwordMinLength": "La contraseña debe tener al menos 8 caracteres",
69
+ "passwordMismatch": "Las contraseñas no coinciden",
68
70
  "passwordRequired": "Por favor, introduce tu contraseña",
69
71
  "usernameNotRegistered": "Este nombre de usuario no está registrado",
70
72
  "usernameRequired": "Por favor, introduce tu nombre de usuario"
@@ -125,6 +127,7 @@
125
127
  "submit": "Iniciar sesión"
126
128
  },
127
129
  "signup": {
130
+ "confirmPasswordPlaceholder": "Confirma tu contraseña",
128
131
  "emailPlaceholder": "Introduce tu dirección de correo electrónico",
129
132
  "error": "Error al registrarse. Inténtalo de nuevo",
130
133
  "firstNamePlaceholder": "Nombre",
@@ -54,6 +54,7 @@
54
54
  },
55
55
  "betterAuth": {
56
56
  "errors": {
57
+ "confirmPasswordRequired": "لطفاً رمز عبور را تأیید کنید",
57
58
  "emailExists": "این ایمیل قبلاً ثبت شده است، لطفاً مستقیماً وارد شوید",
58
59
  "emailInvalid": "لطفاً یک آدرس ایمیل معتبر وارد کنید",
59
60
  "emailNotRegistered": "این ایمیل هنوز ثبت نشده است",
@@ -65,6 +66,7 @@
65
66
  "passwordFormat": "رمز عبور باید شامل حروف و اعداد باشد",
66
67
  "passwordMaxLength": "رمز عبور نباید بیش از ۶۴ کاراکتر باشد",
67
68
  "passwordMinLength": "رمز عبور باید حداقل ۸ کاراکتر باشد",
69
+ "passwordMismatch": "رمزهای عبور وارد شده یکسان نیستند",
68
70
  "passwordRequired": "لطفاً رمز عبور را وارد کنید",
69
71
  "usernameNotRegistered": "این نام کاربری هنوز ثبت نشده است",
70
72
  "usernameRequired": "لطفاً نام کاربری را وارد کنید"
@@ -125,6 +127,7 @@
125
127
  "submit": "ورود"
126
128
  },
127
129
  "signup": {
130
+ "confirmPasswordPlaceholder": "لطفاً رمز عبور را تأیید کنید",
128
131
  "emailPlaceholder": "لطفاً آدرس ایمیل را وارد کنید",
129
132
  "error": "ثبت‌نام ناموفق بود، لطفاً دوباره تلاش کنید",
130
133
  "firstNamePlaceholder": "نام",
@@ -54,6 +54,7 @@
54
54
  },
55
55
  "betterAuth": {
56
56
  "errors": {
57
+ "confirmPasswordRequired": "Veuillez confirmer le mot de passe",
57
58
  "emailExists": "Cet e-mail est déjà enregistré, veuillez vous connecter directement.",
58
59
  "emailInvalid": "Veuillez saisir une adresse e-mail valide",
59
60
  "emailNotRegistered": "Cette adresse e-mail n'est pas encore enregistrée",
@@ -65,6 +66,7 @@
65
66
  "passwordFormat": "Le mot de passe doit contenir à la fois des lettres et des chiffres",
66
67
  "passwordMaxLength": "Le mot de passe ne doit pas dépasser 64 caractères",
67
68
  "passwordMinLength": "Le mot de passe doit contenir au moins 8 caractères",
69
+ "passwordMismatch": "Les mots de passe saisis ne correspondent pas",
68
70
  "passwordRequired": "Veuillez saisir un mot de passe",
69
71
  "usernameNotRegistered": "Ce nom d'utilisateur n'est pas encore enregistré",
70
72
  "usernameRequired": "Veuillez saisir un nom d'utilisateur"
@@ -125,6 +127,7 @@
125
127
  "submit": "Connexion"
126
128
  },
127
129
  "signup": {
130
+ "confirmPasswordPlaceholder": "Veuillez confirmer le mot de passe",
128
131
  "emailPlaceholder": "Veuillez saisir votre adresse e-mail",
129
132
  "error": "Échec de l'inscription, veuillez réessayer",
130
133
  "firstNamePlaceholder": "Prénom",
@@ -54,6 +54,7 @@
54
54
  },
55
55
  "betterAuth": {
56
56
  "errors": {
57
+ "confirmPasswordRequired": "Conferma la password",
57
58
  "emailExists": "Questo indirizzo email è già registrato, effettua direttamente l'accesso",
58
59
  "emailInvalid": "Inserisci un indirizzo email valido",
59
60
  "emailNotRegistered": "Questo indirizzo email non è registrato",
@@ -65,6 +66,7 @@
65
66
  "passwordFormat": "La password deve contenere lettere e numeri",
66
67
  "passwordMaxLength": "La password non può superare i 64 caratteri",
67
68
  "passwordMinLength": "La password deve contenere almeno 8 caratteri",
69
+ "passwordMismatch": "Le password inserite non corrispondono",
68
70
  "passwordRequired": "Inserisci la password",
69
71
  "usernameNotRegistered": "Questo nome utente non è ancora registrato",
70
72
  "usernameRequired": "Inserisci il nome utente"
@@ -125,6 +127,7 @@
125
127
  "submit": "Accedi"
126
128
  },
127
129
  "signup": {
130
+ "confirmPasswordPlaceholder": "Conferma la password",
128
131
  "emailPlaceholder": "Inserisci l'indirizzo email",
129
132
  "error": "Registrazione fallita, riprova",
130
133
  "firstNamePlaceholder": "Nome",
@@ -54,6 +54,7 @@
54
54
  },
55
55
  "betterAuth": {
56
56
  "errors": {
57
+ "confirmPasswordRequired": "パスワードの確認を入力してください",
57
58
  "emailExists": "このメールアドレスは既に登録されています。ログインしてください。",
58
59
  "emailInvalid": "有効なメールアドレスを入力してください",
59
60
  "emailNotRegistered": "このメールアドレスは未登録です",
@@ -65,6 +66,7 @@
65
66
  "passwordFormat": "パスワードは英字と数字を含める必要があります",
66
67
  "passwordMaxLength": "パスワードは64文字以内で入力してください",
67
68
  "passwordMinLength": "パスワードは8文字以上で入力してください",
69
+ "passwordMismatch": "入力されたパスワードが一致しません",
68
70
  "passwordRequired": "パスワードを入力してください",
69
71
  "usernameNotRegistered": "このユーザー名は未登録です",
70
72
  "usernameRequired": "ユーザー名を入力してください"
@@ -125,6 +127,7 @@
125
127
  "submit": "ログイン"
126
128
  },
127
129
  "signup": {
130
+ "confirmPasswordPlaceholder": "パスワードの確認を入力してください",
128
131
  "emailPlaceholder": "メールアドレスを入力してください",
129
132
  "error": "登録に失敗しました。もう一度お試しください",
130
133
  "firstNamePlaceholder": "名",
@@ -54,6 +54,7 @@
54
54
  },
55
55
  "betterAuth": {
56
56
  "errors": {
57
+ "confirmPasswordRequired": "비밀번호 확인이 필요합니다",
57
58
  "emailExists": "이 이메일은 이미 등록되어 있습니다. 바로 로그인해 주세요.",
58
59
  "emailInvalid": "유효한 이메일 주소를 입력하세요",
59
60
  "emailNotRegistered": "이 이메일은 아직 등록되지 않았습니다",
@@ -65,6 +66,7 @@
65
66
  "passwordFormat": "비밀번호는 영문자와 숫자를 모두 포함해야 합니다",
66
67
  "passwordMaxLength": "비밀번호는 최대 64자까지 입력할 수 있습니다",
67
68
  "passwordMinLength": "비밀번호는 최소 8자 이상이어야 합니다",
69
+ "passwordMismatch": "입력한 비밀번호가 일치하지 않습니다",
68
70
  "passwordRequired": "비밀번호를 입력하세요",
69
71
  "usernameNotRegistered": "해당 사용자 이름은 등록되어 있지 않습니다",
70
72
  "usernameRequired": "사용자 이름을 입력하세요"
@@ -125,6 +127,7 @@
125
127
  "submit": "로그인"
126
128
  },
127
129
  "signup": {
130
+ "confirmPasswordPlaceholder": "비밀번호를 다시 입력해 주세요",
128
131
  "emailPlaceholder": "이메일 주소를 입력하세요",
129
132
  "error": "회원가입에 실패했습니다. 다시 시도하세요",
130
133
  "firstNamePlaceholder": "이름",
@@ -54,6 +54,7 @@
54
54
  },
55
55
  "betterAuth": {
56
56
  "errors": {
57
+ "confirmPasswordRequired": "Bevestig alstublieft uw wachtwoord",
57
58
  "emailExists": "Dit e-mailadres is al geregistreerd. Log direct in.",
58
59
  "emailInvalid": "Voer een geldig e-mailadres in",
59
60
  "emailNotRegistered": "Dit e-mailadres is nog niet geregistreerd",
@@ -65,6 +66,7 @@
65
66
  "passwordFormat": "Het wachtwoord moet letters en cijfers bevatten",
66
67
  "passwordMaxLength": "Het wachtwoord mag maximaal 64 tekens bevatten",
67
68
  "passwordMinLength": "Het wachtwoord moet minimaal 8 tekens bevatten",
69
+ "passwordMismatch": "De ingevoerde wachtwoorden komen niet overeen",
68
70
  "passwordRequired": "Voer een wachtwoord in",
69
71
  "usernameNotRegistered": "Deze gebruikersnaam is nog niet geregistreerd",
70
72
  "usernameRequired": "Voer een gebruikersnaam in"
@@ -125,6 +127,7 @@
125
127
  "submit": "Inloggen"
126
128
  },
127
129
  "signup": {
130
+ "confirmPasswordPlaceholder": "Bevestig alstublieft uw wachtwoord",
128
131
  "emailPlaceholder": "Voer je e-mailadres in",
129
132
  "error": "Registratie mislukt, probeer het opnieuw",
130
133
  "firstNamePlaceholder": "Voornaam",
@@ -54,6 +54,7 @@
54
54
  },
55
55
  "betterAuth": {
56
56
  "errors": {
57
+ "confirmPasswordRequired": "Proszę potwierdzić hasło",
57
58
  "emailExists": "Ten adres e-mail jest już zarejestrowany, zaloguj się bezpośrednio.",
58
59
  "emailInvalid": "Wprowadź poprawny adres e-mail",
59
60
  "emailNotRegistered": "Ten adres e-mail nie jest zarejestrowany",
@@ -65,6 +66,7 @@
65
66
  "passwordFormat": "Hasło musi zawierać litery i cyfry",
66
67
  "passwordMaxLength": "Hasło nie może przekraczać 64 znaków",
67
68
  "passwordMinLength": "Hasło musi mieć co najmniej 8 znaków",
69
+ "passwordMismatch": "Wprowadzone hasła nie są takie same",
68
70
  "passwordRequired": "Wprowadź hasło",
69
71
  "usernameNotRegistered": "Nazwa użytkownika nie została zarejestrowana",
70
72
  "usernameRequired": "Wprowadź nazwę użytkownika"
@@ -125,6 +127,7 @@
125
127
  "submit": "Zaloguj się"
126
128
  },
127
129
  "signup": {
130
+ "confirmPasswordPlaceholder": "Proszę potwierdzić hasło",
128
131
  "emailPlaceholder": "Wprowadź adres e-mail",
129
132
  "error": "Rejestracja nie powiodła się, spróbuj ponownie",
130
133
  "firstNamePlaceholder": "Imię",
@@ -54,6 +54,7 @@
54
54
  },
55
55
  "betterAuth": {
56
56
  "errors": {
57
+ "confirmPasswordRequired": "Por favor, confirme a senha",
57
58
  "emailExists": "Este e-mail já está registrado. Por favor, faça login diretamente.",
58
59
  "emailInvalid": "Por favor, insira um endereço de e-mail válido",
59
60
  "emailNotRegistered": "Este e-mail ainda não está registrado",
@@ -65,6 +66,7 @@
65
66
  "passwordFormat": "A senha deve conter letras e números",
66
67
  "passwordMaxLength": "A senha não pode ter mais de 64 caracteres",
67
68
  "passwordMinLength": "A senha deve ter pelo menos 8 caracteres",
69
+ "passwordMismatch": "As senhas inseridas não coincidem",
68
70
  "passwordRequired": "Por favor, insira a senha",
69
71
  "usernameNotRegistered": "Este nome de usuário ainda não está registrado",
70
72
  "usernameRequired": "Por favor, insira o nome de usuário"
@@ -125,6 +127,7 @@
125
127
  "submit": "Entrar"
126
128
  },
127
129
  "signup": {
130
+ "confirmPasswordPlaceholder": "Por favor, confirme a senha",
128
131
  "emailPlaceholder": "Por favor, insira o endereço de e-mail",
129
132
  "error": "Falha no cadastro, tente novamente",
130
133
  "firstNamePlaceholder": "Nome",
@@ -54,6 +54,7 @@
54
54
  },
55
55
  "betterAuth": {
56
56
  "errors": {
57
+ "confirmPasswordRequired": "Пожалуйста, подтвердите пароль",
57
58
  "emailExists": "Этот адрес электронной почты уже зарегистрирован. Пожалуйста, войдите в систему.",
58
59
  "emailInvalid": "Пожалуйста, введите действительный адрес электронной почты",
59
60
  "emailNotRegistered": "Этот адрес электронной почты не зарегистрирован",
@@ -65,6 +66,7 @@
65
66
  "passwordFormat": "Пароль должен содержать как буквы, так и цифры",
66
67
  "passwordMaxLength": "Пароль не должен превышать 64 символа",
67
68
  "passwordMinLength": "Пароль должен содержать не менее 8 символов",
69
+ "passwordMismatch": "Введённые пароли не совпадают",
68
70
  "passwordRequired": "Пожалуйста, введите пароль",
69
71
  "usernameNotRegistered": "Это имя пользователя не зарегистрировано",
70
72
  "usernameRequired": "Пожалуйста, введите имя пользователя"
@@ -125,6 +127,7 @@
125
127
  "submit": "Войти"
126
128
  },
127
129
  "signup": {
130
+ "confirmPasswordPlaceholder": "Пожалуйста, подтвердите пароль",
128
131
  "emailPlaceholder": "Введите адрес электронной почты",
129
132
  "error": "Не удалось зарегистрироваться, попробуйте снова",
130
133
  "firstNamePlaceholder": "Имя",
@@ -54,6 +54,7 @@
54
54
  },
55
55
  "betterAuth": {
56
56
  "errors": {
57
+ "confirmPasswordRequired": "Lütfen şifreyi onaylayın",
57
58
  "emailExists": "Bu e-posta adresi zaten kayıtlı, lütfen doğrudan giriş yapın",
58
59
  "emailInvalid": "Lütfen geçerli bir e-posta adresi girin",
59
60
  "emailNotRegistered": "Bu e-posta henüz kayıtlı değil",
@@ -65,6 +66,7 @@
65
66
  "passwordFormat": "Şifre hem harf hem de rakam içermelidir",
66
67
  "passwordMaxLength": "Şifre en fazla 64 karakter olabilir",
67
68
  "passwordMinLength": "Şifre en az 8 karakter olmalıdır",
69
+ "passwordMismatch": "Girdiğiniz şifreler eşleşmiyor",
68
70
  "passwordRequired": "Lütfen şifrenizi girin",
69
71
  "usernameNotRegistered": "Bu kullanıcı adı henüz kayıtlı değil",
70
72
  "usernameRequired": "Lütfen kullanıcı adınızı girin"
@@ -125,6 +127,7 @@
125
127
  "submit": "Giriş Yap"
126
128
  },
127
129
  "signup": {
130
+ "confirmPasswordPlaceholder": "Lütfen şifreyi onaylayın",
128
131
  "emailPlaceholder": "Lütfen e-posta adresinizi girin",
129
132
  "error": "Kayıt başarısız oldu, lütfen tekrar deneyin",
130
133
  "firstNamePlaceholder": "Ad",
@@ -54,6 +54,7 @@
54
54
  },
55
55
  "betterAuth": {
56
56
  "errors": {
57
+ "confirmPasswordRequired": "Vui lòng xác nhận mật khẩu",
57
58
  "emailExists": "Email này đã được đăng ký, vui lòng đăng nhập trực tiếp",
58
59
  "emailInvalid": "Vui lòng nhập địa chỉ email hợp lệ",
59
60
  "emailNotRegistered": "Email này chưa được đăng ký",
@@ -65,6 +66,7 @@
65
66
  "passwordFormat": "Mật khẩu phải bao gồm cả chữ và số",
66
67
  "passwordMaxLength": "Mật khẩu không được vượt quá 64 ký tự",
67
68
  "passwordMinLength": "Mật khẩu phải có ít nhất 8 ký tự",
69
+ "passwordMismatch": "Mật khẩu nhập hai lần không khớp",
68
70
  "passwordRequired": "Vui lòng nhập mật khẩu",
69
71
  "usernameNotRegistered": "Tên người dùng này chưa được đăng ký",
70
72
  "usernameRequired": "Vui lòng nhập tên người dùng"
@@ -125,6 +127,7 @@
125
127
  "submit": "Đăng nhập"
126
128
  },
127
129
  "signup": {
130
+ "confirmPasswordPlaceholder": "Vui lòng xác nhận mật khẩu",
128
131
  "emailPlaceholder": "Vui lòng nhập địa chỉ email",
129
132
  "error": "Đăng ký thất bại, vui lòng thử lại",
130
133
  "firstNamePlaceholder": "Tên",
@@ -54,6 +54,7 @@
54
54
  },
55
55
  "betterAuth": {
56
56
  "errors": {
57
+ "confirmPasswordRequired": "请确认密码",
57
58
  "emailExists": "该邮箱已注册,请直接登录",
58
59
  "emailInvalid": "请输入有效的邮箱地址或用户名",
59
60
  "emailNotRegistered": "该邮箱或用户名尚未注册",
@@ -65,6 +66,7 @@
65
66
  "passwordFormat": "密码必须同时包含字母和数字",
66
67
  "passwordMaxLength": "密码最多不超过 64 个字符",
67
68
  "passwordMinLength": "密码至少需要 8 个字符",
69
+ "passwordMismatch": "两次输入的密码不一致",
68
70
  "passwordRequired": "请输入密码",
69
71
  "usernameNotRegistered": "该用户名尚未注册",
70
72
  "usernameRequired": "请输入用户名"
@@ -125,6 +127,7 @@
125
127
  "submit": "登录"
126
128
  },
127
129
  "signup": {
130
+ "confirmPasswordPlaceholder": "请确认密码",
128
131
  "emailPlaceholder": "请输入邮箱地址",
129
132
  "error": "注册失败,请重试",
130
133
  "firstNamePlaceholder": "名字",
@@ -54,6 +54,7 @@
54
54
  },
55
55
  "betterAuth": {
56
56
  "errors": {
57
+ "confirmPasswordRequired": "請確認密碼",
57
58
  "emailExists": "該電子郵件已註冊,請直接登入",
58
59
  "emailInvalid": "請輸入有效的電子郵件地址",
59
60
  "emailNotRegistered": "該電子郵件尚未註冊",
@@ -65,6 +66,7 @@
65
66
  "passwordFormat": "密碼必須同時包含字母與數字",
66
67
  "passwordMaxLength": "密碼長度不得超過 64 個字元",
67
68
  "passwordMinLength": "密碼長度至少需為 8 個字元",
69
+ "passwordMismatch": "兩次輸入的密碼不一致",
68
70
  "passwordRequired": "請輸入密碼",
69
71
  "usernameNotRegistered": "該使用者名稱尚未註冊",
70
72
  "usernameRequired": "請輸入使用者名稱"
@@ -125,6 +127,7 @@
125
127
  "submit": "登入"
126
128
  },
127
129
  "signup": {
130
+ "confirmPasswordPlaceholder": "請確認密碼",
128
131
  "emailPlaceholder": "請輸入電子郵件地址",
129
132
  "error": "註冊失敗,請重試",
130
133
  "firstNamePlaceholder": "名字",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/lobehub",
3
- "version": "2.0.0-next.163",
3
+ "version": "2.0.0-next.164",
4
4
  "description": "LobeHub - an open-source,comprehensive AI Agent framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
5
5
  "keywords": [
6
6
  "framework",
@@ -52,6 +52,7 @@ const useStyles = createStyles(({ css, token }) => ({
52
52
  }));
53
53
 
54
54
  interface SignUpFormValues {
55
+ confirmPassword: string;
55
56
  email: string;
56
57
  password: string;
57
58
  }
@@ -179,6 +180,28 @@ export default function BetterAuthSignUpForm() {
179
180
  />
180
181
  </Form.Item>
181
182
 
183
+ <Form.Item
184
+ dependencies={['password']}
185
+ name="confirmPassword"
186
+ rules={[
187
+ { message: t('betterAuth.errors.confirmPasswordRequired'), required: true },
188
+ ({ getFieldValue }) => ({
189
+ validator(_, value) {
190
+ if (!value || getFieldValue('password') === value) {
191
+ return Promise.resolve();
192
+ }
193
+ return Promise.reject(new Error(t('betterAuth.errors.passwordMismatch')));
194
+ },
195
+ }),
196
+ ]}
197
+ >
198
+ <Input.Password
199
+ placeholder={t('betterAuth.signup.confirmPasswordPlaceholder')}
200
+ prefix={<Lock size={16} />}
201
+ size="large"
202
+ />
203
+ </Form.Item>
204
+
182
205
  <Form.Item>
183
206
  <Button
184
207
  block
@@ -1,10 +1,10 @@
1
1
  'use client';
2
2
 
3
3
  import { memo } from 'react';
4
- import { Link, useNavigate } from 'react-router-dom';
5
4
  import { Flexbox } from 'react-layout-kit';
5
+ import { Link } from 'react-router-dom';
6
6
 
7
- import { enableAuth, enableNextAuth } from '@/const/auth';
7
+ import { enableAuth } from '@/const/auth';
8
8
  import DataStatistics from '@/features/User/DataStatistics';
9
9
  import UserInfo from '@/features/User/UserInfo';
10
10
  import UserLoginOrSignup from '@/features/User/UserLoginOrSignup/Community';
@@ -12,7 +12,6 @@ import { useUserStore } from '@/store/user';
12
12
  import { authSelectors } from '@/store/user/selectors';
13
13
 
14
14
  const UserBanner = memo(() => {
15
- const navigate = useNavigate();
16
15
  const isLoginWithAuth = useUserStore(authSelectors.isLoginWithAuth);
17
16
  const [signIn] = useUserStore((s) => [s.openLogin]);
18
17
 
@@ -30,12 +29,7 @@ const UserBanner = memo(() => {
30
29
  ) : (
31
30
  <UserLoginOrSignup
32
31
  onClick={() => {
33
- // If use NextAuth, call openLogin method directly
34
- if (enableNextAuth) {
35
- signIn();
36
- return;
37
- }
38
- navigate('/login');
32
+ signIn();
39
33
  }}
40
34
  />
41
35
  )}
@@ -31,6 +31,7 @@ interface ProfileRowProps {
31
31
  action?: ReactNode;
32
32
  children: ReactNode;
33
33
  label: string;
34
+ mobile?: boolean;
34
35
  }
35
36
 
36
37
  const rowStyle: CSSProperties = {
@@ -43,17 +44,31 @@ const labelStyle: CSSProperties = {
43
44
  width: 160,
44
45
  };
45
46
 
46
- const ProfileRow = memo<ProfileRowProps>(({ label, children, action }) => (
47
- <Flexbox align="center" gap={24} horizontal justify="space-between" style={rowStyle}>
48
- <Flexbox align="center" gap={24} horizontal style={{ flex: 1 }}>
49
- <Typography.Text style={labelStyle}>{label}</Typography.Text>
50
- <Flexbox style={{ flex: 1 }}>{children}</Flexbox>
47
+ const ProfileRow = memo<ProfileRowProps>(({ label, children, action, mobile }) => {
48
+ if (mobile) {
49
+ return (
50
+ <Flexbox gap={12} style={rowStyle}>
51
+ <Flexbox align="center" horizontal justify="space-between">
52
+ <Typography.Text strong>{label}</Typography.Text>
53
+ {action}
54
+ </Flexbox>
55
+ <Flexbox>{children}</Flexbox>
56
+ </Flexbox>
57
+ );
58
+ }
59
+
60
+ return (
61
+ <Flexbox align="center" gap={24} horizontal justify="space-between" style={rowStyle}>
62
+ <Flexbox align="center" gap={24} horizontal style={{ flex: 1 }}>
63
+ <Typography.Text style={labelStyle}>{label}</Typography.Text>
64
+ <Flexbox style={{ flex: 1 }}>{children}</Flexbox>
65
+ </Flexbox>
66
+ {action && <Flexbox>{action}</Flexbox>}
51
67
  </Flexbox>
52
- {action && <Flexbox>{action}</Flexbox>}
53
- </Flexbox>
54
- ));
68
+ );
69
+ });
55
70
 
56
- const AvatarRow = memo(() => {
71
+ const AvatarRow = memo<{ mobile?: boolean }>(({ mobile }) => {
57
72
  const { t } = useTranslation('auth');
58
73
  const isLogin = useUserStore(authSelectors.isLogin);
59
74
  const updateAvatar = useUserStore((s) => s.updateAvatar);
@@ -89,34 +104,48 @@ const AvatarRow = memo(() => {
89
104
 
90
105
  const canUpload = !enableAuth || isLogin;
91
106
 
107
+ const avatarContent = canUpload ? (
108
+ <Spin indicator={<LoadingOutlined spin />} spinning={uploading}>
109
+ <Upload beforeUpload={handleUploadAvatar} itemRender={() => void 0} maxCount={1}>
110
+ <UserAvatar clickable size={40} />
111
+ </Upload>
112
+ </Spin>
113
+ ) : (
114
+ <UserAvatar size={40} />
115
+ );
116
+
117
+ const updateAction = canUpload ? (
118
+ <Upload beforeUpload={handleUploadAvatar} itemRender={() => void 0} maxCount={1}>
119
+ <Typography.Text style={{ cursor: 'pointer', fontSize: 13 }}>
120
+ {t('profile.updateAvatar')}
121
+ </Typography.Text>
122
+ </Upload>
123
+ ) : null;
124
+
125
+ if (mobile) {
126
+ return (
127
+ <Flexbox gap={12} style={rowStyle}>
128
+ <Flexbox align="center" horizontal justify="space-between">
129
+ <Typography.Text strong>{t('profile.avatar')}</Typography.Text>
130
+ {updateAction}
131
+ </Flexbox>
132
+ <Flexbox>{avatarContent}</Flexbox>
133
+ </Flexbox>
134
+ );
135
+ }
136
+
92
137
  return (
93
138
  <Flexbox align="center" gap={24} horizontal justify="space-between" style={rowStyle}>
94
139
  <Flexbox align="center" gap={24} horizontal style={{ flex: 1 }}>
95
140
  <Typography.Text style={labelStyle}>{t('profile.avatar')}</Typography.Text>
96
- <Flexbox style={{ flex: 1 }}>
97
- {canUpload ? (
98
- <Spin indicator={<LoadingOutlined spin />} spinning={uploading}>
99
- <Upload beforeUpload={handleUploadAvatar} itemRender={() => void 0} maxCount={1}>
100
- <UserAvatar clickable size={40} />
101
- </Upload>
102
- </Spin>
103
- ) : (
104
- <UserAvatar size={40} />
105
- )}
106
- </Flexbox>
141
+ <Flexbox style={{ flex: 1 }}>{avatarContent}</Flexbox>
107
142
  </Flexbox>
108
- {canUpload && (
109
- <Upload beforeUpload={handleUploadAvatar} itemRender={() => void 0} maxCount={1}>
110
- <Typography.Text style={{ cursor: 'pointer', fontSize: 13 }}>
111
- {t('profile.updateAvatar')}
112
- </Typography.Text>
113
- </Upload>
114
- )}
143
+ {updateAction}
115
144
  </Flexbox>
116
145
  );
117
146
  });
118
147
 
119
- const FullNameRow = memo(() => {
148
+ const FullNameRow = memo<{ mobile?: boolean }>(({ mobile }) => {
120
149
  const { t } = useTranslation('auth');
121
150
  const fullName = useUserStore(userProfileSelectors.fullName);
122
151
  const updateFullName = useUserStore((s) => s.updateFullName);
@@ -152,64 +181,83 @@ const FullNameRow = memo(() => {
152
181
  }
153
182
  }, [editValue, updateFullName]);
154
183
 
184
+ const editingContent = (
185
+ <motion.div
186
+ animate={{ opacity: 1, y: 0 }}
187
+ exit={{ opacity: 0, y: -10 }}
188
+ initial={{ opacity: 0, y: -10 }}
189
+ key="editing"
190
+ transition={{ duration: 0.2 }}
191
+ >
192
+ <Flexbox gap={12}>
193
+ {!mobile && <Typography.Text strong>{t('profile.fullNameInputHint')}</Typography.Text>}
194
+ <Input
195
+ autoFocus
196
+ onChange={(e) => setEditValue(e.target.value)}
197
+ onPressEnter={handleSave}
198
+ placeholder={t('profile.fullName')}
199
+ value={editValue}
200
+ />
201
+ <Flexbox gap={8} horizontal justify="flex-end">
202
+ <Button disabled={saving} onClick={handleCancel} size="small">
203
+ {t('profile.cancel')}
204
+ </Button>
205
+ <Button loading={saving} onClick={handleSave} size="small" type="primary">
206
+ {t('profile.save')}
207
+ </Button>
208
+ </Flexbox>
209
+ </Flexbox>
210
+ </motion.div>
211
+ );
212
+
213
+ const displayContent = (
214
+ <motion.div
215
+ animate={{ opacity: 1 }}
216
+ exit={{ opacity: 0 }}
217
+ initial={{ opacity: 0 }}
218
+ key="display"
219
+ transition={{ duration: 0.2 }}
220
+ >
221
+ {mobile ? (
222
+ <Typography.Text>{fullName || '--'}</Typography.Text>
223
+ ) : (
224
+ <Flexbox align="center" horizontal justify="space-between">
225
+ <Typography.Text>{fullName || '--'}</Typography.Text>
226
+ <Typography.Text onClick={handleStartEdit} style={{ cursor: 'pointer', fontSize: 13 }}>
227
+ {t('profile.updateFullName')}
228
+ </Typography.Text>
229
+ </Flexbox>
230
+ )}
231
+ </motion.div>
232
+ );
233
+
234
+ if (mobile) {
235
+ return (
236
+ <Flexbox gap={12} style={rowStyle}>
237
+ <Flexbox align="center" horizontal justify="space-between">
238
+ <Typography.Text strong>{t('profile.fullName')}</Typography.Text>
239
+ {!isEditing && (
240
+ <Typography.Text onClick={handleStartEdit} style={{ cursor: 'pointer', fontSize: 13 }}>
241
+ {t('profile.updateFullName')}
242
+ </Typography.Text>
243
+ )}
244
+ </Flexbox>
245
+ <AnimatePresence mode="wait">{isEditing ? editingContent : displayContent}</AnimatePresence>
246
+ </Flexbox>
247
+ );
248
+ }
249
+
155
250
  return (
156
251
  <Flexbox gap={24} horizontal style={rowStyle}>
157
252
  <Typography.Text style={labelStyle}>{t('profile.fullName')}</Typography.Text>
158
253
  <Flexbox style={{ flex: 1 }}>
159
- <AnimatePresence mode="wait">
160
- {isEditing ? (
161
- <motion.div
162
- animate={{ opacity: 1, y: 0 }}
163
- exit={{ opacity: 0, y: -10 }}
164
- initial={{ opacity: 0, y: -10 }}
165
- key="editing"
166
- transition={{ duration: 0.2 }}
167
- >
168
- <Flexbox gap={12}>
169
- <Typography.Text strong>{t('profile.fullNameInputHint')}</Typography.Text>
170
- <Input
171
- autoFocus
172
- onChange={(e) => setEditValue(e.target.value)}
173
- onPressEnter={handleSave}
174
- placeholder={t('profile.fullName')}
175
- value={editValue}
176
- />
177
- <Flexbox gap={8} horizontal justify="flex-end">
178
- <Button disabled={saving} onClick={handleCancel} size="small">
179
- {t('profile.cancel')}
180
- </Button>
181
- <Button loading={saving} onClick={handleSave} size="small" type="primary">
182
- {t('profile.save')}
183
- </Button>
184
- </Flexbox>
185
- </Flexbox>
186
- </motion.div>
187
- ) : (
188
- <motion.div
189
- animate={{ opacity: 1 }}
190
- exit={{ opacity: 0 }}
191
- initial={{ opacity: 0 }}
192
- key="display"
193
- transition={{ duration: 0.2 }}
194
- >
195
- <Flexbox align="center" horizontal justify="space-between">
196
- <Typography.Text>{fullName || '--'}</Typography.Text>
197
- <Typography.Text
198
- onClick={handleStartEdit}
199
- style={{ cursor: 'pointer', fontSize: 13 }}
200
- >
201
- {t('profile.updateFullName')}
202
- </Typography.Text>
203
- </Flexbox>
204
- </motion.div>
205
- )}
206
- </AnimatePresence>
254
+ <AnimatePresence mode="wait">{isEditing ? editingContent : displayContent}</AnimatePresence>
207
255
  </Flexbox>
208
256
  </Flexbox>
209
257
  );
210
258
  });
211
259
 
212
- const UsernameRow = memo(() => {
260
+ const UsernameRow = memo<{ mobile?: boolean }>(({ mobile }) => {
213
261
  const { t } = useTranslation('auth');
214
262
  const username = useUserStore(userProfileSelectors.username);
215
263
  const updateUsername = useUserStore((s) => s.updateUsername);
@@ -281,70 +329,89 @@ const UsernameRow = memo(() => {
281
329
  setError('');
282
330
  };
283
331
 
332
+ const editingContent = (
333
+ <motion.div
334
+ animate={{ opacity: 1, y: 0 }}
335
+ exit={{ opacity: 0, y: -10 }}
336
+ initial={{ opacity: 0, y: -10 }}
337
+ key="editing"
338
+ transition={{ duration: 0.2 }}
339
+ >
340
+ <Flexbox gap={12}>
341
+ {!mobile && <Typography.Text strong>{t('profile.usernameInputHint')}</Typography.Text>}
342
+ <Input
343
+ autoFocus
344
+ onChange={handleInputChange}
345
+ onPressEnter={handleSave}
346
+ placeholder={t('profile.usernamePlaceholder')}
347
+ status={error ? 'error' : undefined}
348
+ value={editValue}
349
+ />
350
+ {error && (
351
+ <Typography.Text style={{ fontSize: 12 }} type="danger">
352
+ {error}
353
+ </Typography.Text>
354
+ )}
355
+ <Flexbox gap={8} horizontal justify="flex-end">
356
+ <Button disabled={saving} onClick={handleCancel} size="small">
357
+ {t('profile.cancel')}
358
+ </Button>
359
+ <Button loading={saving} onClick={handleSave} size="small" type="primary">
360
+ {t('profile.save')}
361
+ </Button>
362
+ </Flexbox>
363
+ </Flexbox>
364
+ </motion.div>
365
+ );
366
+
367
+ const displayContent = (
368
+ <motion.div
369
+ animate={{ opacity: 1 }}
370
+ exit={{ opacity: 0 }}
371
+ initial={{ opacity: 0 }}
372
+ key="display"
373
+ transition={{ duration: 0.2 }}
374
+ >
375
+ {mobile ? (
376
+ <Typography.Text>{username || '--'}</Typography.Text>
377
+ ) : (
378
+ <Flexbox align="center" horizontal justify="space-between">
379
+ <Typography.Text>{username || '--'}</Typography.Text>
380
+ <Typography.Text onClick={handleStartEdit} style={{ cursor: 'pointer', fontSize: 13 }}>
381
+ {t('profile.updateUsername')}
382
+ </Typography.Text>
383
+ </Flexbox>
384
+ )}
385
+ </motion.div>
386
+ );
387
+
388
+ if (mobile) {
389
+ return (
390
+ <Flexbox gap={12} style={rowStyle}>
391
+ <Flexbox align="center" horizontal justify="space-between">
392
+ <Typography.Text strong>{t('profile.username')}</Typography.Text>
393
+ {!isEditing && (
394
+ <Typography.Text onClick={handleStartEdit} style={{ cursor: 'pointer', fontSize: 13 }}>
395
+ {t('profile.updateUsername')}
396
+ </Typography.Text>
397
+ )}
398
+ </Flexbox>
399
+ <AnimatePresence mode="wait">{isEditing ? editingContent : displayContent}</AnimatePresence>
400
+ </Flexbox>
401
+ );
402
+ }
403
+
284
404
  return (
285
405
  <Flexbox gap={24} horizontal style={rowStyle}>
286
406
  <Typography.Text style={labelStyle}>{t('profile.username')}</Typography.Text>
287
407
  <Flexbox style={{ flex: 1 }}>
288
- <AnimatePresence mode="wait">
289
- {isEditing ? (
290
- <motion.div
291
- animate={{ opacity: 1, y: 0 }}
292
- exit={{ opacity: 0, y: -10 }}
293
- initial={{ opacity: 0, y: -10 }}
294
- key="editing"
295
- transition={{ duration: 0.2 }}
296
- >
297
- <Flexbox gap={12}>
298
- <Typography.Text strong>{t('profile.usernameInputHint')}</Typography.Text>
299
- <Input
300
- autoFocus
301
- onChange={handleInputChange}
302
- onPressEnter={handleSave}
303
- placeholder={t('profile.usernamePlaceholder')}
304
- status={error ? 'error' : undefined}
305
- value={editValue}
306
- />
307
- {error && (
308
- <Typography.Text style={{ fontSize: 12 }} type="danger">
309
- {error}
310
- </Typography.Text>
311
- )}
312
- <Flexbox gap={8} horizontal justify="flex-end">
313
- <Button disabled={saving} onClick={handleCancel} size="small">
314
- {t('profile.cancel')}
315
- </Button>
316
- <Button loading={saving} onClick={handleSave} size="small" type="primary">
317
- {t('profile.save')}
318
- </Button>
319
- </Flexbox>
320
- </Flexbox>
321
- </motion.div>
322
- ) : (
323
- <motion.div
324
- animate={{ opacity: 1 }}
325
- exit={{ opacity: 0 }}
326
- initial={{ opacity: 0 }}
327
- key="display"
328
- transition={{ duration: 0.2 }}
329
- >
330
- <Flexbox align="center" horizontal justify="space-between">
331
- <Typography.Text>{username || '--'}</Typography.Text>
332
- <Typography.Text
333
- onClick={handleStartEdit}
334
- style={{ cursor: 'pointer', fontSize: 13 }}
335
- >
336
- {t('profile.updateUsername')}
337
- </Typography.Text>
338
- </Flexbox>
339
- </motion.div>
340
- )}
341
- </AnimatePresence>
408
+ <AnimatePresence mode="wait">{isEditing ? editingContent : displayContent}</AnimatePresence>
342
409
  </Flexbox>
343
410
  </Flexbox>
344
411
  );
345
412
  });
346
413
 
347
- const PasswordRow = memo(() => {
414
+ const PasswordRow = memo<{ mobile?: boolean }>(({ mobile }) => {
348
415
  const { t } = useTranslation('auth');
349
416
  const userProfile = useUserStore(userProfileSelectors.userProfile);
350
417
  const hasPasswordAccount = useUserStore(authSelectors.hasPasswordAccount);
@@ -387,6 +454,7 @@ const PasswordRow = memo(() => {
387
454
  </Typography.Text>
388
455
  }
389
456
  label={t('profile.password')}
457
+ mobile={mobile}
390
458
  >
391
459
  <Typography.Text>{hasPasswordAccount ? '••••••' : '--'}</Typography.Text>
392
460
  </ProfileRow>
@@ -435,24 +503,24 @@ const Client = memo<{ mobile?: boolean }>(({ mobile }) => {
435
503
  <Divider style={{ marginBlock: 0 }} />
436
504
 
437
505
  {/* Avatar Row - Editable */}
438
- <AvatarRow />
506
+ <AvatarRow mobile={mobile} />
439
507
 
440
508
  <Divider style={{ margin: 0 }} />
441
509
 
442
510
  {/* Full Name Row - Editable */}
443
- <FullNameRow />
511
+ <FullNameRow mobile={mobile} />
444
512
 
445
513
  <Divider style={{ margin: 0 }} />
446
514
 
447
515
  {/* Username Row - Editable */}
448
- <UsernameRow />
516
+ <UsernameRow mobile={mobile} />
449
517
 
450
518
  <Divider style={{ margin: 0 }} />
451
519
 
452
520
  {/* Password Row - For Better Auth users to change or set password */}
453
521
  {isLoginWithBetterAuth && (
454
522
  <>
455
- <PasswordRow />
523
+ <PasswordRow mobile={mobile} />
456
524
  <Divider style={{ margin: 0 }} />
457
525
  </>
458
526
  )}
@@ -460,7 +528,7 @@ const Client = memo<{ mobile?: boolean }>(({ mobile }) => {
460
528
  {/* Email Row - Read Only */}
461
529
  {isLoginWithAuth && userProfile?.email && (
462
530
  <>
463
- <ProfileRow label={t('profile.email')}>
531
+ <ProfileRow label={t('profile.email')} mobile={mobile}>
464
532
  <Typography.Text>{userProfile.email}</Typography.Text>
465
533
  </ProfileRow>
466
534
  <Divider style={{ margin: 0 }} />
@@ -469,7 +537,7 @@ const Client = memo<{ mobile?: boolean }>(({ mobile }) => {
469
537
 
470
538
  {/* SSO Providers Row */}
471
539
  {isLoginWithAuth && (
472
- <ProfileRow label={t('profile.sso.providers')}>
540
+ <ProfileRow label={t('profile.sso.providers')} mobile={mobile}>
473
541
  <SSOProvidersList />
474
542
  </ProfileRow>
475
543
  )}
@@ -1,8 +1,8 @@
1
1
  import { Tag } from '@lobehub/ui';
2
2
  import { useTheme } from 'antd-style';
3
- import Link from 'next/link';
4
3
  import { memo } from 'react';
5
4
  import { useTranslation } from 'react-i18next';
5
+ import { Link } from 'react-router-dom';
6
6
  import urlJoin from 'url-join';
7
7
 
8
8
  import { OFFICIAL_URL } from '@/const/url';
@@ -37,12 +37,12 @@ const PlanTag = memo<PlanTagProps>(({ type = PlanType.Preview }) => {
37
37
 
38
38
  return (
39
39
  <Link
40
- href={urlJoin(
40
+ style={{ cursor: 'pointer' }}
41
+ target={isDesktop ? '_blank' : undefined}
42
+ to={urlJoin(
41
43
  isDesktop ? OFFICIAL_URL : '/',
42
44
  isFree ? '/subscription/plans' : '/subscription/usage',
43
45
  )}
44
- style={{ cursor: 'pointer' }}
45
- target={isDesktop ? '_blank' : undefined}
46
46
  >
47
47
  <PlanIcon plan={type} size={22} type={'tag'} />
48
48
  </Link>
@@ -54,6 +54,7 @@ export default {
54
54
  },
55
55
  betterAuth: {
56
56
  errors: {
57
+ confirmPasswordRequired: '请确认密码',
57
58
  emailExists: '该邮箱已注册,请直接登录',
58
59
  emailInvalid: '请输入有效的邮箱地址或用户名',
59
60
  emailNotRegistered: '该邮箱或用户名尚未注册',
@@ -65,6 +66,7 @@ export default {
65
66
  passwordFormat: '密码必须同时包含字母和数字',
66
67
  passwordMaxLength: '密码最多不超过 64 个字符',
67
68
  passwordMinLength: '密码至少需要 8 个字符',
69
+ passwordMismatch: '两次输入的密码不一致',
68
70
  passwordRequired: '请输入密码',
69
71
  usernameNotRegistered: '该用户名尚未注册',
70
72
  usernameRequired: '请输入用户名',
@@ -125,6 +127,7 @@ export default {
125
127
  submit: '登录',
126
128
  },
127
129
  signup: {
130
+ confirmPasswordPlaceholder: '请确认密码',
128
131
  emailPlaceholder: '请输入邮箱地址',
129
132
  error: '注册失败,请重试',
130
133
  firstNamePlaceholder: '名字',