diff --git a/app/index.tsx b/app/index.tsx
index f412813..9e2149f 100644
--- a/app/index.tsx
+++ b/app/index.tsx
@@ -7,5 +7,5 @@ export default function Index() {
if (isAuthenticated) {
return ;
}
- return ;
+ return ;
}
diff --git a/app/welcome.tsx b/app/welcome.tsx
new file mode 100644
index 0000000..b582aae
--- /dev/null
+++ b/app/welcome.tsx
@@ -0,0 +1,5 @@
+import { WelcomeScreen } from '../src/screens/auth';
+
+export default function WelcomeRoute() {
+ return ;
+}
diff --git a/src/navigation/hrefs.ts b/src/navigation/hrefs.ts
index a169d5c..00243b2 100644
--- a/src/navigation/hrefs.ts
+++ b/src/navigation/hrefs.ts
@@ -156,6 +156,10 @@ export function hrefAuthForgot(): string {
return '/forgot-password';
}
+export function hrefAuthWelcome(): string {
+ return '/welcome';
+}
+
// ==================== Materials (学习资料) ====================
export function hrefMaterials(): string {
diff --git a/src/screens/auth/ForgotPasswordScreen.tsx b/src/screens/auth/ForgotPasswordScreen.tsx
index fe092de..3049063 100644
--- a/src/screens/auth/ForgotPasswordScreen.tsx
+++ b/src/screens/auth/ForgotPasswordScreen.tsx
@@ -1,4 +1,15 @@
-import React, { useEffect, useMemo, useState } from 'react';
+/**
+ * 忘记密码页 ForgotPasswordScreen(简洁表单样式)
+ * 胡萝卜BBS - 找回密码
+ *
+ * 设计风格:
+ * - 纯白背景,扁平化设计
+ * - 增大间距
+ * - 输入框带灰色背景填充
+ * - 橙色圆角按钮
+ */
+
+import React, { useEffect, useMemo, useState, useRef } from 'react';
import {
View,
Text,
@@ -9,123 +20,28 @@ import {
Platform,
ScrollView,
ActivityIndicator,
+ Animated,
+ StatusBar,
} from 'react-native';
import { SafeAreaView } from 'react-native-safe-area-context';
import { useRouter } from 'expo-router';
import { MaterialCommunityIcons } from '@expo/vector-icons';
-import { LinearGradient } from 'expo-linear-gradient';
-import { spacing, borderRadius, shadows, fontSizes, useAppColors, type AppColors } from '../../theme';
+import { useAppColors, type AppColors } from '../../theme';
import { authService, resolveAuthApiError } from '../../services/authService';
import { showPrompt } from '../../services/promptService';
-function createForgotPasswordStyles(colors: AppColors) {
- return StyleSheet.create({
- container: { flex: 1 },
- gradient: { flex: 1 },
- keyboardView: { flex: 1 },
- scrollContent: {
- flexGrow: 1,
- justifyContent: 'center',
- paddingHorizontal: spacing.xl,
- paddingVertical: spacing['2xl'],
- },
- formCard: {
- backgroundColor: colors.background.paper,
- borderRadius: borderRadius['2xl'],
- padding: spacing.xl,
- ...shadows.md,
- },
- title: {
- fontSize: fontSizes['2xl'],
- fontWeight: '700',
- color: colors.text.primary,
- textAlign: 'center',
- marginBottom: spacing.xs,
- },
- subtitle: {
- fontSize: fontSizes.sm,
- color: colors.text.secondary,
- textAlign: 'center',
- marginBottom: spacing.lg,
- },
- inputWrapper: {
- flexDirection: 'row',
- alignItems: 'center',
- backgroundColor: colors.background.default,
- borderRadius: borderRadius.lg,
- borderWidth: 1.5,
- borderColor: colors.divider,
- paddingHorizontal: spacing.md,
- height: 52,
- marginBottom: spacing.md,
- },
- inputIcon: {
- marginRight: spacing.sm,
- },
- input: {
- flex: 1,
- fontSize: fontSizes.md,
- color: colors.text.primary,
- },
- codeRow: {
- flexDirection: 'row',
- alignItems: 'center',
- gap: spacing.sm,
- marginBottom: spacing.md,
- },
- codeInput: {
- flex: 1,
- marginBottom: 0,
- },
- sendCodeButton: {
- height: 52,
- minWidth: 110,
- borderRadius: borderRadius.lg,
- backgroundColor: colors.primary.main,
- alignItems: 'center',
- justifyContent: 'center',
- paddingHorizontal: spacing.md,
- },
- sendCodeButtonDisabled: {
- opacity: 0.6,
- },
- sendCodeButtonText: {
- color: '#fff',
- fontSize: fontSizes.sm,
- fontWeight: '600',
- },
- submitButton: {
- height: 50,
- borderRadius: borderRadius.lg,
- backgroundColor: colors.primary.main,
- alignItems: 'center',
- justifyContent: 'center',
- marginTop: spacing.sm,
- },
- submitButtonDisabled: {
- opacity: 0.6,
- },
- submitButtonText: {
- color: '#fff',
- fontSize: fontSizes.lg,
- fontWeight: '700',
- },
- backButton: {
- alignItems: 'center',
- marginTop: spacing.md,
- },
- backButtonText: {
- color: colors.primary.main,
- fontSize: fontSizes.md,
- fontWeight: '500',
- },
- });
-}
+// 胡萝卜橙主题色
+const THEME_COLORS = {
+ primary: '#FF6B35',
+ primaryLight: '#FF8C5A',
+ primaryDark: '#E55A2B',
+};
export const ForgotPasswordScreen: React.FC = () => {
const colors = useAppColors();
const styles = useMemo(() => createForgotPasswordStyles(colors), [colors]);
const router = useRouter();
+
const [email, setEmail] = useState('');
const [verificationCode, setVerificationCode] = useState('');
const [newPassword, setNewPassword] = useState('');
@@ -136,6 +52,26 @@ export const ForgotPasswordScreen: React.FC = () => {
const [loading, setLoading] = useState(false);
const [countdown, setCountdown] = useState(0);
+ // 动画值
+ const fadeAnim = useRef(new Animated.Value(0)).current;
+ const slideAnim = useRef(new Animated.Value(20)).current;
+
+ // 启动入场动画
+ useEffect(() => {
+ Animated.parallel([
+ Animated.timing(fadeAnim, {
+ toValue: 1,
+ duration: 400,
+ useNativeDriver: true,
+ }),
+ Animated.timing(slideAnim, {
+ toValue: 0,
+ duration: 400,
+ useNativeDriver: true,
+ }),
+ ]).start();
+ }, []);
+
useEffect(() => {
if (countdown <= 0) {
return;
@@ -208,101 +144,308 @@ export const ForgotPasswordScreen: React.FC = () => {
return (
-
-
-
-
+
+
+
+
+ {/* 标题区域 */}
+
找回密码
- 请输入邮箱并完成验证码验证
+
+ 请输入邮箱并完成验证
+
-
-
-
-
-
-
-
-
+ {/* 表单区域 */}
+
+ {/* 邮箱输入框 */}
+
+ 邮箱
+
-
- 0) && styles.sendCodeButtonDisabled]}
- onPress={handleSendCode}
- disabled={sendingCode || countdown > 0}
- >
- {sendingCode ? (
-
- ) : (
- {countdown > 0 ? `${countdown}s` : '发送验证码'}
+ {email.length > 0 && validateEmail(email) && (
+
)}
-
+
-
-
-
- setShowPassword((v) => !v)}>
-
-
+ {/* 验证码 */}
+
+ 验证码
+
+
+
+
+ 0) && styles.sendCodeButtonDisabled]}
+ onPress={handleSendCode}
+ disabled={sendingCode || countdown > 0}
+ activeOpacity={0.8}
+ >
+ {sendingCode ? (
+
+ ) : (
+ {countdown > 0 ? `${countdown}s` : '获取验证码'}
+ )}
+
+
-
-
-
- setShowConfirmPassword((v) => !v)}>
-
-
+ {/* 新密码输入框 */}
+
+ 新密码
+
+
+ setShowPassword((v) => !v)}
+ style={styles.eyeButton}
+ >
+
+
+
+ {/* 确认密码输入框 */}
+
+ 确认密码
+
+
+ setShowConfirmPassword((v) => !v)}
+ style={styles.eyeButton}
+ >
+
+
+
+
+
+ {/* 重置密码按钮 */}
- {loading ? : 重置密码}
+ {loading ? (
+
+ ) : (
+ 重置密码
+ )}
- router.back()}>
+ {/* 返回登录 */}
+ router.back()}
+ activeOpacity={0.8}
+ >
+
返回登录
-
-
-
+
+
+
);
};
+function createForgotPasswordStyles(colors: AppColors) {
+ return StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: '#fff',
+ },
+ keyboardView: {
+ flex: 1,
+ },
+ scrollContent: {
+ flexGrow: 1,
+ paddingHorizontal: 28,
+ paddingTop: 50,
+ paddingBottom: 40,
+ },
+ content: {
+ flex: 1,
+ maxWidth: 400,
+ width: '100%',
+ alignSelf: 'center',
+ },
+
+ // 标题区域
+ titleSection: {
+ marginBottom: 40,
+ marginTop: 20,
+ },
+ title: {
+ fontSize: 32,
+ fontWeight: '700',
+ color: colors.text.primary,
+ lineHeight: 40,
+ },
+ underline: {
+ width: 40,
+ height: 4,
+ backgroundColor: THEME_COLORS.primary,
+ borderRadius: 2,
+ marginTop: 12,
+ marginBottom: 16,
+ },
+ subtitle: {
+ fontSize: 16,
+ color: colors.text.secondary,
+ },
+
+ // 表单区域
+ formSection: {
+ marginBottom: 24,
+ },
+
+ // 输入框
+ inputContainer: {
+ marginBottom: 20,
+ },
+ inputLabel: {
+ fontSize: 14,
+ fontWeight: '500',
+ color: colors.text.secondary,
+ marginBottom: 10,
+ },
+ inputWrapper: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ backgroundColor: '#F5F5F7',
+ borderRadius: 14,
+ paddingHorizontal: 18,
+ height: 56,
+ },
+ input: {
+ flex: 1,
+ fontSize: 16,
+ color: colors.text.primary,
+ height: 56,
+ },
+ checkIcon: {
+ marginLeft: 8,
+ },
+ eyeButton: {
+ padding: 4,
+ marginLeft: 4,
+ },
+
+ // 验证码行
+ codeRow: {
+ flexDirection: 'row',
+ gap: 12,
+ },
+ codeInputWrapper: {
+ flex: 1,
+ },
+ sendCodeButton: {
+ height: 56,
+ paddingHorizontal: 16,
+ backgroundColor: 'rgba(255, 107, 53, 0.1)',
+ borderRadius: 14,
+ alignItems: 'center',
+ justifyContent: 'center',
+ minWidth: 100,
+ },
+ sendCodeButtonDisabled: {
+ opacity: 0.5,
+ },
+ sendCodeButtonText: {
+ fontSize: 14,
+ fontWeight: '600',
+ color: THEME_COLORS.primary,
+ },
+
+ // 提交按钮
+ submitButton: {
+ height: 56,
+ borderRadius: 14,
+ backgroundColor: THEME_COLORS.primary,
+ alignItems: 'center',
+ justifyContent: 'center',
+ marginTop: 8,
+ },
+ submitButtonDisabled: {
+ opacity: 0.7,
+ },
+ submitButtonText: {
+ color: '#fff',
+ fontSize: 17,
+ fontWeight: '600',
+ },
+
+ // 返回按钮
+ backButton: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ justifyContent: 'center',
+ marginTop: 24,
+ },
+ backButtonText: {
+ color: THEME_COLORS.primary,
+ fontSize: 15,
+ fontWeight: '500',
+ },
+ });
+}
+
export default ForgotPasswordScreen;
diff --git a/src/screens/auth/LoginScreen.tsx b/src/screens/auth/LoginScreen.tsx
index 9443b65..b7c7a05 100644
--- a/src/screens/auth/LoginScreen.tsx
+++ b/src/screens/auth/LoginScreen.tsx
@@ -1,10 +1,12 @@
/**
- * 登录页 LoginScreen(响应式适配 - 分栏布局)
+ * 登录页 LoginScreen(简洁表单样式)
* 胡萝卜BBS - 用户登录
*
- * 布局规则:
- * - 屏幕宽度 < 768px:单栏布局,橙色渐变背景
- * - 屏幕宽度 >= 768px:分栏布局,左侧橙色右侧中性灰
+ * 设计风格:
+ * - 纯白背景,扁平化设计
+ * - 增大间距,避免页面太空
+ * - 输入框带灰色背景填充
+ * - 橙色圆角按钮
*/
import React, { useState, useEffect, useRef, useMemo } from 'react';
@@ -24,15 +26,18 @@ import {
import { SafeAreaView } from 'react-native-safe-area-context';
import { useRouter } from 'expo-router';
import { MaterialCommunityIcons } from '@expo/vector-icons';
-import { LinearGradient } from 'expo-linear-gradient';
-import { spacing, borderRadius, shadows, fontSizes, useAppColors, type AppColors } from '../../theme';
+import { useAppColors, type AppColors } from '../../theme';
import { useAuthStore } from '../../stores';
import * as hrefs from '../../navigation/hrefs';
-import { useResponsive, useResponsiveValue } from '../../hooks';
+import { useResponsive } from '../../hooks';
import { showPrompt } from '../../services/promptService';
-// 分栏布局断点
-const SPLIT_BREAKPOINT = 768;
+// 胡萝卜橙主题色
+const THEME_COLORS = {
+ primary: '#FF6B35',
+ primaryLight: '#FF8C5A',
+ primaryDark: '#E55A2B',
+};
export const LoginScreen: React.FC = () => {
const colors = useAppColors();
@@ -40,67 +45,29 @@ export const LoginScreen: React.FC = () => {
const router = useRouter();
const login = useAuthStore((state) => state.login);
const isAuthenticated = useAuthStore((state) => state.isAuthenticated);
- const storeError = useAuthStore((state) => state.error);
const setStoreError = useAuthStore((state) => state.setError);
- // 响应式布局
- const { isLandscape, width } = useResponsive();
-
- // 是否使用分栏布局
- const isSplitLayout = width >= SPLIT_BREAKPOINT;
+ const { isLandscape } = useResponsive();
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');
const [loading, setLoading] = useState(false);
const [showPassword, setShowPassword] = useState(false);
- const [errorMsg, setErrorMsg] = useState(null);
// 动画值
const fadeAnim = useRef(new Animated.Value(0)).current;
- const slideAnim = useRef(new Animated.Value(50)).current;
- const scaleAnim = useRef(new Animated.Value(0.9)).current;
- const inputFadeAnim = useRef(new Animated.Value(0)).current;
-
- // 响应式值 - 大屏模式单独放大Logo尺寸,更显大气
- const logoSize = useResponsiveValue({
- xs: 64, sm: 72, md: 80,
- lg: isSplitLayout ? 140 : 96, // 大屏模式Logo图标进一步放大
- xl: isSplitLayout ? 160 : 110
- });
- const logoContainerSize = useResponsiveValue({
- xs: 110, sm: 120, md: 130,
- lg: isSplitLayout ? 200 : 150, // 大屏模式Logo容器进一步放大
- xl: isSplitLayout ? 220 : 170
- });
- const appNameSize = useResponsiveValue({
- xs: 28, sm: 30, md: 32,
- lg: isSplitLayout ? 60 : 36, // 大屏模式标题文字大幅放大
- xl: isSplitLayout ? 72 : 40
- });
- const formMaxWidth = isSplitLayout ? 420 : undefined;
+ const slideAnim = useRef(new Animated.Value(20)).current;
// 启动入场动画
useEffect(() => {
- Animated.sequence([
- Animated.parallel([
- Animated.timing(fadeAnim, {
- toValue: 1,
- duration: 600,
- useNativeDriver: true,
- }),
- Animated.timing(scaleAnim, {
- toValue: 1,
- duration: 600,
- useNativeDriver: true,
- }),
- ]),
- Animated.timing(slideAnim, {
- toValue: 0,
- duration: 500,
+ Animated.parallel([
+ Animated.timing(fadeAnim, {
+ toValue: 1,
+ duration: 400,
useNativeDriver: true,
}),
- Animated.timing(inputFadeAnim, {
- toValue: 1,
+ Animated.timing(slideAnim, {
+ toValue: 0,
duration: 400,
useNativeDriver: true,
}),
@@ -124,13 +91,6 @@ export const LoginScreen: React.FC = () => {
return true;
};
- // store error 同步到本地
- useEffect(() => {
- if (storeError) {
- setErrorMsg(storeError);
- }
- }, [storeError]);
-
useEffect(() => {
if (isAuthenticated) {
router.replace(hrefs.hrefHome());
@@ -138,7 +98,6 @@ export const LoginScreen: React.FC = () => {
}, [isAuthenticated, router]);
const clearError = () => {
- setErrorMsg(null);
setStoreError(null);
};
@@ -152,11 +111,11 @@ export const LoginScreen: React.FC = () => {
const success = await login({ username, password });
if (!success) {
if (!useAuthStore.getState().error) {
- setErrorMsg('登录失败,请稍后重试');
+ showPrompt({ title: '登录失败', message: '请检查用户名和密码', type: 'error' });
}
}
} catch (error: any) {
- setErrorMsg(error.message || '登录失败,请检查用户名和密码');
+ showPrompt({ title: '登录失败', message: error.message || '请检查用户名和密码', type: 'error' });
} finally {
setLoading(false);
}
@@ -167,605 +126,257 @@ export const LoginScreen: React.FC = () => {
router.push(hrefs.hrefAuthRegister());
};
- // 渲染左侧面板(Logo和品牌信息)- 优化大屏布局
- const renderLeftPanel = () => (
-
- {/* 胡萝卜图标 - 靠上显示 */}
-
-
-
-
- {/* 品牌名称 - 优化大屏排版 */}
- 萝卜社区
- 发现有趣的内容,结识志同道合的朋友
-
- {/* 装饰元素 - 大屏模式改为水平排列 + 大幅放大 */}
-
- {isSplitLayout ? (
- // 大屏模式:水平排列 + 大幅放大图标
-
-
-
-
-
- ) : (
- // 小屏模式:保持原有横向排列
-
-
-
-
-
- )}
-
-
- );
-
- // 渲染表单内容
- const renderFormContent = () => (
-
-
- 欢迎回来
-
- {/* 用户名输入框 */}
-
-
-
- { setUsername(v); clearError(); }}
- autoCapitalize="none"
- autoCorrect={false}
- returnKeyType="next"
- />
- {username.length > 0 && (
- setUsername('')}
- style={styles.clearButton}
- >
-
-
- )}
-
-
-
- {/* 密码输入框 */}
-
-
-
- { setPassword(v); clearError(); }}
- secureTextEntry={!showPassword}
- autoCapitalize="none"
- returnKeyType="done"
- onSubmitEditing={handleLogin}
- />
- setShowPassword(!showPassword)}
- style={styles.clearButton}
- >
-
-
-
-
-
- {/* 忘记密码 */}
- router.push(hrefs.hrefAuthForgot())}
- >
- 忘记密码?
-
-
- {/* 内联错误提示 */}
- {errorMsg && (
-
-
- {errorMsg}
-
- )}
-
- {/* 登录按钮 */}
-
-
- {loading ? (
-
- ) : (
- 登 录
- )}
-
-
-
-
- {/* 底部注册提示 */}
-
- 还没有账号?
-
- 立即注册
-
-
-
- );
-
- // 渲染分栏布局
- const renderSplitLayout = () => (
-
- {/* 左侧橙色面板 */}
-
- {/* 装饰性背景元素 */}
-
-
-
-
-
- {renderLeftPanel()}
-
-
-
- {/* 右侧中性灰面板 */}
-
-
-
- {/* 核心修复:用View包裹,确保垂直+水平居中 */}
-
- {renderFormContent()}
-
-
-
-
- );
-
- // 渲染单栏布局
- const renderSingleLayout = () => (
+ return (
-
-
+
-
-
- {/* 装饰性背景元素 */}
-
-
-
- {/* 头部 */}
-
-
-
-
- 萝卜社区
- 发现有趣的内容,结识志同道合的朋友
-
+ {/* 标题区域 - 增大间距 */}
+
+ 欢迎回来
+
+ 请登录您的账号
+
- {/* 表单 */}
- {renderFormContent()}
-
-
-
+ {/* 表单区域 */}
+
+ {/* 用户名输入框 */}
+
+ 用户名
+
+ { setUsername(v); clearError(); }}
+ autoCapitalize="none"
+ autoCorrect={false}
+ returnKeyType="next"
+ />
+ {username.length > 0 && (
+
+ )}
+
+
+
+ {/* 密码输入框 */}
+
+ 密码
+
+ { setPassword(v); clearError(); }}
+ secureTextEntry={!showPassword}
+ autoCapitalize="none"
+ returnKeyType="done"
+ onSubmitEditing={handleLogin}
+ />
+ setShowPassword(!showPassword)}
+ style={styles.eyeButton}
+ >
+
+
+
+
+
+ {/* 忘记密码 */}
+ router.push(hrefs.hrefAuthForgot())}
+ >
+ 忘记密码?
+
+
+ {/* 登录按钮 */}
+
+ {loading ? (
+
+ ) : (
+ 登 录
+ )}
+
+
+
+ {/* 底部注册提示 */}
+
+ 还没有账号?
+
+ 立即注册
+
+
+
+
+
);
-
- return isSplitLayout ? renderSplitLayout() : renderSingleLayout();
};
function createLoginStyles(colors: AppColors) {
return StyleSheet.create({
- container: {
- flex: 1,
- },
- gradient: {
- flex: 1,
- },
- keyboardView: {
- flex: 1,
- },
- // 单栏布局内容
- scrollContent: {
- flexGrow: 1,
- paddingHorizontal: spacing.xl,
- paddingVertical: spacing['2xl'],
- },
- scrollContentCentered: {
- alignItems: 'center',
- justifyContent: 'center',
- flex: 1,
- },
- scrollContentLandscape: {
- paddingVertical: spacing.lg,
- },
- // 装饰性背景元素
- decorCircle1: {
- position: 'absolute',
- top: -100,
- right: -100,
- width: 300,
- height: 300,
- borderRadius: 150,
- backgroundColor: 'rgba(255,255,255,0.1)',
- },
- decorCircle2: {
- position: 'absolute',
- bottom: 100,
- left: -150,
- width: 250,
- height: 250,
- borderRadius: 125,
- backgroundColor: 'rgba(255,255,255,0.08)',
- },
- // 头部区域
- headerSection: {
- alignItems: 'center',
- marginTop: spacing['3xl'],
- marginBottom: spacing['3xl'],
- },
- headerSectionLandscape: {
- marginTop: spacing.lg,
- marginBottom: spacing.lg,
- },
- logoContainer: {
- backgroundColor: 'rgba(255,255,255,0.25)',
- alignItems: 'center',
- justifyContent: 'center',
- marginBottom: spacing.lg,
- borderWidth: 2,
- borderColor: 'rgba(255,255,255,0.4)',
- ...shadows.md,
- },
- // 大屏模式Logo容器样式 - 增加阴影和内边距,更立体
- splitLogoContainer: {
- borderWidth: 3,
- borderColor: 'rgba(255,255,255,0.5)',
- ...shadows.lg,
- },
- logoContainerTop: {
- marginTop: spacing['3xl'],
- },
- appName: {
- fontWeight: '800',
- color: '#FFFFFF',
- marginBottom: spacing.sm,
- textShadowColor: 'rgba(0,0,0,0.1)',
- textShadowOffset: { width: 0, height: 2 },
- textShadowRadius: 4,
- },
- // 大屏模式标题样式 - 大幅放大,增加间距和文字效果
- splitAppName: {
- fontSize: 72, // 大幅放大主标题
- marginBottom: spacing['2xl'],
- textShadowOffset: { width: 0, height: 4 },
- textShadowRadius: 8,
- letterSpacing: 4, // 增加字间距,更显大气
- fontWeight: '900',
- },
- subtitle: {
- fontSize: fontSizes.md,
- color: 'rgba(255,255,255,0.9)',
- textAlign: 'center',
- paddingHorizontal: spacing.xl,
- },
- // 大屏模式副标题样式 - 大幅放大
- splitSubtitle: {
- fontSize: 24, // 放大副标题
- marginBottom: spacing['6xl'], // 增加底部间距
- lineHeight: 36,
- paddingHorizontal: spacing['4xl'],
- letterSpacing: 1.5,
- fontWeight: '500',
- },
- // 表单卡片(基础样式,无阴影)
- formCard: {
- backgroundColor: colors.background.paper,
- borderRadius: borderRadius['2xl'],
- padding: spacing['2xl'],
- marginBottom: spacing.xl,
- },
- // 小屏模式:原有默认阴影
- normalFormCardShadow: {
- ...shadows.md,
- },
- // 大屏模式:专用全向阴影
- splitFormCardShadow: {
- // iOS 全向柔和阴影
- shadowColor: '#000',
- shadowOffset: { width: 0, height: 2 },
- shadowOpacity: 0.12,
- shadowRadius: 12,
- // Android 高程 + 轻微边框(模拟顶部阴影)
- elevation: 8,
- // 新增:极细微的顶部边框,强化区分度
- borderTopWidth: 1,
- borderTopColor: 'rgba(0,0,0,0.05)',
- },
- formTitle: {
- fontSize: fontSizes['2xl'],
- fontWeight: '700',
- color: colors.text.primary,
- marginBottom: spacing.xl,
- textAlign: 'center',
- },
- inputContainer: {
- marginBottom: spacing.lg,
- },
- inputWrapper: {
- flexDirection: 'row',
- alignItems: 'center',
- backgroundColor: colors.background.default,
- borderRadius: borderRadius.lg,
- borderWidth: 1.5,
- borderColor: colors.divider,
- paddingHorizontal: spacing.md,
- height: 56,
- },
- inputIcon: {
- marginRight: spacing.sm,
- },
- input: {
- flex: 1,
- fontSize: fontSizes.md,
- color: colors.text.primary,
- },
- clearButton: {
- padding: spacing.xs,
- },
- forgotPassword: {
- alignSelf: 'flex-end',
- marginBottom: spacing.md,
- },
- forgotPasswordText: {
- fontSize: fontSizes.sm,
- color: colors.primary.main,
- fontWeight: '600',
- },
- errorBox: {
- flexDirection: 'row',
- alignItems: 'flex-start',
- backgroundColor: colors.accent.light,
- borderRadius: borderRadius.md,
- paddingHorizontal: spacing.md,
- paddingVertical: spacing.sm,
- marginBottom: spacing.md,
- borderLeftWidth: 3,
- borderLeftColor: colors.accent.main,
- },
- errorText: {
- flex: 1,
- fontSize: fontSizes.sm,
- color: colors.accent.dark,
- lineHeight: 20,
- },
- loginButton: {
- borderRadius: borderRadius.lg,
- overflow: 'hidden',
- ...shadows.md,
- },
- loginButtonGradient: {
- height: 52,
- alignItems: 'center',
- justifyContent: 'center',
- },
- loginButtonDisabled: {
- opacity: 0.7,
- },
- loginButtonText: {
- fontSize: fontSizes.lg,
- fontWeight: '700',
- color: '#FFFFFF',
- },
- // 底部区域
- footerSection: {
- flexDirection: 'row',
- justifyContent: 'center',
- alignItems: 'center',
- paddingTop: spacing.xl,
- },
- footerText: {
- fontSize: fontSizes.md,
- color: colors.text.primary,
- },
- registerLink: {
- fontSize: fontSizes.md,
- color: colors.primary.main,
- fontWeight: '700',
- marginLeft: spacing.xs,
- textDecorationLine: 'underline',
- },
- // ========== 分栏布局样式 ==========
- splitContainer: {
- flex: 1,
- flexDirection: 'row',
- },
- leftPanelContainer: {
- flex: 1, // 50%
- justifyContent: 'center',
- alignItems: 'center',
- overflow: 'hidden',
- },
- leftPanelSafeArea: {
- flex: 1,
- justifyContent: 'center',
- alignItems: 'center',
- paddingHorizontal: spacing['4xl'], // 增加内边距,不贴边
- },
- leftPanel: {
- alignItems: 'center',
- paddingHorizontal: spacing['2xl'],
- },
- // 大屏模式左侧面板布局
- splitLeftPanel: {
- width: '100%',
- justifyContent: 'center',
- paddingVertical: spacing['6xl'],
- },
- leftPanelDecor: {
- position: 'absolute',
- bottom: spacing['4xl'],
- left: 0,
- right: 0,
- alignItems: 'center',
- },
- leftPanelDecorBottom: {
- marginTop: spacing['2xl'],
- },
- // 大屏模式装饰元素布局
- splitLeftPanelDecorBottom: {
- marginTop: spacing['6xl'],
- width: '100%',
- alignItems: 'center',
- },
- // 大屏模式装饰元素水平排列
- splitDecorRow: {
- flexDirection: 'row',
- alignItems: 'center',
- justifyContent: 'space-around',
- width: '100%',
- gap: spacing['2xl'], // 增加图标间距
- },
- // 大屏模式装饰图标样式
- splitDecorIcon: {
- transform: [{ scale: 1.1 }],
- opacity: 0.9,
- },
- decorRow: {
- flexDirection: 'row',
- alignItems: 'center',
- justifyContent: 'space-around',
- width: '80%',
- },
- rightPanelContainer: {
- flex: 1, // 50%
- backgroundColor: colors.background.paper,
- },
- rightPanelSafeArea: {
- flex: 1,
- // 移除左右内边距,交给子容器控制
- },
- // 分栏布局右侧内容包裹器(核心修复)
- splitRightContentWrapper: {
- flex: 1,
- justifyContent: 'center',
- alignItems: 'center',
- // 新增:左右内边距,保证表单和边缘有间距
- paddingHorizontal: spacing['2xl'],
- },
- // 表单内容包裹器(区分大屏/小屏)
- splitFormWrapper: {
- // 关键修改:设置最大宽度 + 自适应宽度,实现水平居中
- maxWidth: 420,
- width: '100%',
- },
- singleFormWrapper: {
- flexGrow: 1,
- width: '100%',
- // 移除这里的阴影,避免重复
- },
+ container: {
+ flex: 1,
+ backgroundColor: '#fff',
+ },
+ keyboardView: {
+ flex: 1,
+ },
+ scrollContent: {
+ flexGrow: 1,
+ paddingHorizontal: 28,
+ paddingTop: 60,
+ paddingBottom: 40,
+ },
+ scrollContentLandscape: {
+ paddingTop: 30,
+ },
+ content: {
+ flex: 1,
+ maxWidth: 400,
+ width: '100%',
+ alignSelf: 'center',
+ },
+
+ // 标题区域 - 增大间距
+ titleSection: {
+ marginBottom: 48,
+ marginTop: 20,
+ },
+ title: {
+ fontSize: 32,
+ fontWeight: '700',
+ color: colors.text.primary,
+ lineHeight: 40,
+ },
+ underline: {
+ width: 40,
+ height: 4,
+ backgroundColor: THEME_COLORS.primary,
+ borderRadius: 2,
+ marginTop: 12,
+ marginBottom: 16,
+ },
+ subtitle: {
+ fontSize: 16,
+ color: colors.text.secondary,
+ },
+
+ // 表单区域
+ formSection: {
+ marginBottom: 32,
+ },
+
+ // 输入框
+ inputContainer: {
+ marginBottom: 24,
+ },
+ inputLabel: {
+ fontSize: 14,
+ fontWeight: '500',
+ color: colors.text.secondary,
+ marginBottom: 10,
+ },
+ inputWrapper: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ backgroundColor: '#F5F5F7',
+ borderRadius: 14,
+ paddingHorizontal: 18,
+ height: 56,
+ },
+ input: {
+ flex: 1,
+ fontSize: 16,
+ color: colors.text.primary,
+ height: 56,
+ },
+ checkIcon: {
+ marginLeft: 8,
+ },
+ eyeButton: {
+ padding: 4,
+ marginLeft: 4,
+ },
+
+ // 忘记密码
+ forgotPassword: {
+ alignSelf: 'flex-end',
+ marginBottom: 28,
+ marginTop: -8,
+ },
+ forgotPasswordText: {
+ fontSize: 14,
+ color: THEME_COLORS.primary,
+ fontWeight: '500',
+ },
+
+ // 登录按钮
+ loginButton: {
+ height: 56,
+ borderRadius: 14,
+ backgroundColor: THEME_COLORS.primary,
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ loginButtonDisabled: {
+ opacity: 0.7,
+ },
+ loginButtonText: {
+ fontSize: 17,
+ fontWeight: '600',
+ color: '#FFFFFF',
+ },
+
+ // 底部
+ footer: {
+ flexDirection: 'row',
+ justifyContent: 'center',
+ alignItems: 'center',
+ marginTop: 40,
+ },
+ footerText: {
+ fontSize: 15,
+ color: colors.text.secondary,
+ },
+ registerLink: {
+ fontSize: 15,
+ color: THEME_COLORS.primary,
+ fontWeight: '600',
+ marginLeft: 6,
+ },
});
}
-export default LoginScreen;
\ No newline at end of file
+export default LoginScreen;
diff --git a/src/screens/auth/RegisterScreen.tsx b/src/screens/auth/RegisterScreen.tsx
index 19c0b90..bf77133 100644
--- a/src/screens/auth/RegisterScreen.tsx
+++ b/src/screens/auth/RegisterScreen.tsx
@@ -1,10 +1,12 @@
/**
- * 注册页 RegisterScreen(响应式适配 - 分栏布局)
+ * 注册页 RegisterScreen(简洁表单样式)
* 胡萝卜BBS - 用户注册
- *
- * 布局规则:
- * - 屏幕宽度 < 768px:单栏布局,橙色渐变背景
- * - 屏幕宽度 >= 768px:分栏布局,左侧橙色右侧中性灰
+ *
+ * 设计风格:
+ * - 纯白背景,扁平化设计
+ * - 增大间距,避免页面太空
+ * - 输入框带灰色背景填充
+ * - 橙色圆角按钮
*/
import React, { useState, useEffect, useRef, useMemo } from 'react';
@@ -24,16 +26,18 @@ import {
import { SafeAreaView } from 'react-native-safe-area-context';
import { useRouter } from 'expo-router';
import { MaterialCommunityIcons } from '@expo/vector-icons';
-import { LinearGradient } from 'expo-linear-gradient';
-import { spacing, borderRadius, shadows, fontSizes, useAppColors, type AppColors } from '../../theme';
+import { useAppColors, type AppColors } from '../../theme';
import { authService, resolveAuthApiError } from '../../services/authService';
import { useAuthStore } from '../../stores';
import * as hrefs from '../../navigation/hrefs';
-import { useResponsive, useResponsiveValue } from '../../hooks';
import { showPrompt } from '../../services/promptService';
-// 分栏布局断点
-const SPLIT_BREAKPOINT = 768;
+// 胡萝卜橙主题色
+const THEME_COLORS = {
+ primary: '#FF6B35',
+ primaryLight: '#FF8C5A',
+ primaryDark: '#E55A2B',
+};
export const RegisterScreen: React.FC = () => {
const colors = useAppColors();
@@ -41,12 +45,6 @@ export const RegisterScreen: React.FC = () => {
const router = useRouter();
const register = useAuthStore((state) => state.register);
const isAuthenticated = useAuthStore((state) => state.isAuthenticated);
-
- // 响应式布局
- const { isLandscape, width } = useResponsive();
-
- // 是否使用分栏布局
- const isSplitLayout = width >= SPLIT_BREAKPOINT;
useEffect(() => {
if (isAuthenticated) {
@@ -70,51 +68,19 @@ export const RegisterScreen: React.FC = () => {
// 动画值
const fadeAnim = useRef(new Animated.Value(0)).current;
- const slideAnim = useRef(new Animated.Value(50)).current;
- const scaleAnim = useRef(new Animated.Value(0.95)).current;
- const inputFadeAnim = useRef(new Animated.Value(0)).current;
-
- // 响应式值 - 大屏模式单独放大图标尺寸,更显大气
- const iconSize = useResponsiveValue({
- xs: 48, sm: 52, md: 56,
- lg: isSplitLayout ? 120 : 64, // 大屏模式图标进一步放大
- xl: isSplitLayout ? 140 : 72
- });
- const iconContainerSize = useResponsiveValue({
- xs: 80, sm: 88, md: 96,
- lg: isSplitLayout ? 180 : 108, // 大屏模式图标容器进一步放大
- xl: isSplitLayout ? 200 : 120
- });
- const titleSize = useResponsiveValue({
- xs: 24, sm: 26, md: 28,
- lg: isSplitLayout ? 60 : 30, // 大屏模式标题文字大幅放大
- xl: isSplitLayout ? 72 : 32
- });
- const formMaxWidth = isSplitLayout ? 480 : undefined;
+ const slideAnim = useRef(new Animated.Value(20)).current;
// 启动入场动画
useEffect(() => {
- Animated.sequence([
- Animated.parallel([
- Animated.timing(fadeAnim, {
- toValue: 1,
- duration: 500,
- useNativeDriver: true,
- }),
- Animated.timing(scaleAnim, {
- toValue: 1,
- duration: 500,
- useNativeDriver: true,
- }),
- ]),
- Animated.timing(slideAnim, {
- toValue: 0,
+ Animated.parallel([
+ Animated.timing(fadeAnim, {
+ toValue: 1,
duration: 400,
useNativeDriver: true,
}),
- Animated.timing(inputFadeAnim, {
- toValue: 1,
- duration: 300,
+ Animated.timing(slideAnim, {
+ toValue: 0,
+ duration: 400,
useNativeDriver: true,
}),
]).start();
@@ -164,7 +130,6 @@ export const RegisterScreen: React.FC = () => {
showPrompt({ title: '提示', message: '请输入邮箱验证码', type: 'warning' });
return false;
}
- // 手机号验证(如果填写了)
if (phone && !/^1[3-9]\d{9}$/.test(phone)) {
showPrompt({ title: '提示', message: '请输入正确的手机号', type: 'warning' });
return false;
@@ -247,838 +212,405 @@ export const RegisterScreen: React.FC = () => {
router.push(hrefs.hrefAuthLogin());
};
- // 渲染左侧面板(Logo和品牌信息)- 优化大屏布局
- const renderLeftPanel = () => (
-
- {/* 用户图标 - 靠上显示 */}
-
-
-
-
- {/* 品牌名称 - 优化大屏排版 */}
- 加入萝卜社区
- 加入萝卜社区,发现有趣的内容
-
- {/* 装饰元素 - 大屏模式改为水平排列 + 大幅放大 */}
-
- {isSplitLayout ? (
- // 大屏模式:水平排列 + 大幅放大图标
-
-
-
-
-
- ) : (
- // 小屏模式:保持原有横向排列
-
-
-
-
-
- )}
-
-
- );
-
- // 渲染表单内容
- const renderFormContent = () => (
-
-
- 注册账号
-
- {/* 用户名输入框 */}
-
-
-
-
- {username.length > 0 && (
- setUsername('')}
- style={styles.clearButton}
- >
-
-
- )}
-
-
-
- {/* 昵称输入框 */}
-
-
-
-
- {nickname.length > 0 && (
- setNickname('')}
- style={styles.clearButton}
- >
-
-
- )}
-
-
-
- {/* 邮箱输入框 */}
-
-
-
-
- {email.length > 0 && (
- setEmail('')}
- style={styles.clearButton}
- >
-
-
- )}
-
-
-
- {/* 邮箱验证码 */}
-
-
-
-
-
-
- 0) && styles.sendCodeButtonDisabled,
- ]}
- onPress={handleSendCode}
- disabled={sendingCode || countdown > 0}
- activeOpacity={0.8}
- >
-
- {sendingCode ? '发送中...' : countdown > 0 ? `${countdown}s` : '发送验证码'}
-
-
-
-
-
- {/* 手机号输入框 */}
-
-
-
-
- {phone.length > 0 && (
- setPhone('')}
- style={styles.clearButton}
- >
-
-
- )}
-
-
-
- {/* 密码输入框 */}
-
-
-
-
- setShowPassword(!showPassword)}
- style={styles.clearButton}
- >
-
-
-
-
-
- {/* 确认密码输入框 */}
-
-
-
-
- setShowConfirmPassword(!showConfirmPassword)}
- style={styles.clearButton}
- >
-
-
-
-
-
- {/* 服务条款 */}
- setAgreedToTerms(!agreedToTerms)}
- activeOpacity={0.8}
- >
-
-
-
-
- 我已阅读并同意
- 《用户协议》
- 和
- 《隐私政策》
-
-
-
- {/* 注册按钮 */}
-
-
- {loading ? (
-
- ) : (
- 注 册
- )}
-
-
-
-
- {/* 底部登录提示 */}
-
- 已有账号?
-
- 立即登录
-
-
-
- );
-
- // 渲染分栏布局
- const renderSplitLayout = () => (
-
- {/* 左侧橙色面板 */}
-
- {/* 装饰性背景元素 */}
-
-
-
-
-
- {renderLeftPanel()}
-
-
-
- {/* 右侧中性灰面板 */}
-
-
-
- {/* 核心修复:用View包裹,确保垂直+水平居中 */}
-
- {renderFormContent()}
-
-
-
-
- );
-
- // 渲染单栏布局
- const renderSingleLayout = () => (
+ return (
-
-
+
-
-
- {/* 装饰性背景元素 */}
-
-
-
- {/* 头部 */}
-
-
-
-
- 加入萝卜社区
- 加入萝卜社区,发现有趣的内容
-
+ {/* 标题区域 - 增大间距 */}
+
+ 创建新账号
+
+ 填写以下信息完成注册
+
- {/* 表单 */}
- {renderFormContent()}
-
-
-
+ {/* 表单区域 */}
+
+ {/* 用户名输入框 */}
+
+ 用户名
+
+
+ {username.length > 0 && /^[a-zA-Z0-9_]{3,20}$/.test(username) && (
+
+ )}
+
+
+
+ {/* 昵称输入框 */}
+
+ 昵称
+
+
+ {nickname.length > 0 && nickname.length >= 2 && (
+
+ )}
+
+
+
+ {/* 邮箱输入框 */}
+
+ 邮箱
+
+
+ {email.length > 0 && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email) && (
+
+ )}
+
+
+
+ {/* 邮箱验证码 */}
+
+ 验证码
+
+
+
+
+ 0) && styles.sendCodeButtonDisabled,
+ ]}
+ onPress={handleSendCode}
+ disabled={sendingCode || countdown > 0}
+ activeOpacity={0.8}
+ >
+
+ {sendingCode ? '发送中...' : countdown > 0 ? `${countdown}s` : '获取验证码'}
+
+
+
+
+
+ {/* 手机号输入框 */}
+
+ 手机号(选填)
+
+
+
+
+
+ {/* 密码输入框 */}
+
+ 密码
+
+
+ setShowPassword(!showPassword)}
+ style={styles.eyeButton}
+ >
+
+
+
+
+
+ {/* 确认密码输入框 */}
+
+ 确认密码
+
+
+ setShowConfirmPassword(!showConfirmPassword)}
+ style={styles.eyeButton}
+ >
+
+
+
+
+
+ {/* 服务条款 */}
+ setAgreedToTerms(!agreedToTerms)}
+ activeOpacity={0.8}
+ >
+
+
+ 我已阅读并同意
+ 《用户协议》
+ 和
+ 《隐私政策》
+
+
+
+ {/* 注册按钮 */}
+
+ {loading ? (
+
+ ) : (
+ 注 册
+ )}
+
+
+
+ {/* 底部登录提示 */}
+
+ 已有账号?
+
+ 立即登录
+
+
+
+
+
);
-
- return isSplitLayout ? renderSplitLayout() : renderSingleLayout();
};
function createRegisterStyles(colors: AppColors) {
return StyleSheet.create({
- container: {
- flex: 1,
- },
- gradient: {
- flex: 1,
- },
- keyboardView: {
- flex: 1,
- },
- scrollContent: {
- flexGrow: 1,
- paddingHorizontal: spacing.xl,
- paddingVertical: spacing.xl,
- },
- scrollContentLandscape: {
- paddingVertical: spacing.md,
- },
- // 装饰性背景元素
- decorCircle1: {
- position: 'absolute',
- top: -80,
- right: -80,
- width: 250,
- height: 250,
- borderRadius: 125,
- backgroundColor: 'rgba(255,255,255,0.1)',
- },
- decorCircle2: {
- position: 'absolute',
- bottom: 150,
- left: -120,
- width: 200,
- height: 200,
- borderRadius: 100,
- backgroundColor: 'rgba(255,255,255,0.08)',
- },
- // 头部区域
- headerSection: {
- alignItems: 'center',
- marginTop: spacing.xl,
- marginBottom: spacing.xl,
- },
- headerSectionLandscape: {
- marginTop: spacing.md,
- marginBottom: spacing.md,
- },
- iconContainer: {
- backgroundColor: 'rgba(255,255,255,0.25)',
- alignItems: 'center',
- justifyContent: 'center',
- marginBottom: spacing.md,
- borderWidth: 2,
- borderColor: 'rgba(255,255,255,0.4)',
- ...shadows.md,
- },
- title: {
- fontWeight: '800',
- color: '#FFFFFF',
- marginBottom: spacing.xs,
- textShadowColor: 'rgba(0,0,0,0.1)',
- textShadowOffset: { width: 0, height: 2 },
- textShadowRadius: 4,
- },
- subtitle: {
- fontSize: fontSizes.md,
- color: 'rgba(255,255,255,0.9)',
- },
- // 表单卡片
- formCard: {
- backgroundColor: colors.background.paper,
- borderRadius: borderRadius['2xl'],
- padding: spacing.xl,
- marginBottom: spacing.lg,
- ...shadows.md,
- },
- inputContainer: {
- marginBottom: spacing.md,
- },
- codeRow: {
- flexDirection: 'row',
- alignItems: 'center',
- gap: spacing.sm,
- },
- inputWrapper: {
- flexDirection: 'row',
- alignItems: 'center',
- backgroundColor: colors.background.default,
- borderRadius: borderRadius.lg,
- borderWidth: 1.5,
- borderColor: colors.divider,
- paddingHorizontal: spacing.md,
- height: 52,
- },
- inputWrapperWide: {
- height: 56,
- },
- codeInputWrapper: {
- flex: 1,
- },
- inputIcon: {
- marginRight: spacing.sm,
- },
- input: {
- flex: 1,
- fontSize: fontSizes.md,
- color: colors.text.primary,
- },
- inputWide: {
- fontSize: fontSizes.lg,
- },
- clearButton: {
- padding: spacing.xs,
- },
- sendCodeButton: {
- height: 52,
- minWidth: 110,
- paddingHorizontal: spacing.md,
- borderRadius: borderRadius.lg,
- backgroundColor: colors.primary.main,
- alignItems: 'center',
- justifyContent: 'center',
- },
- sendCodeButtonDisabled: {
- opacity: 0.6,
- },
- sendCodeButtonText: {
- color: '#fff',
- fontSize: fontSizes.sm,
- fontWeight: '600',
- },
- // 服务条款
- termsContainer: {
- flexDirection: 'row',
- alignItems: 'center',
- marginBottom: spacing.lg,
- marginTop: spacing.sm,
- },
- checkbox: {
- marginRight: spacing.sm,
- },
- checkboxChecked: {
- // 选中状态的额外样式
- },
- termsText: {
- fontSize: fontSizes.sm,
- color: colors.text.secondary,
- flex: 1,
- lineHeight: 20,
- },
- termsLink: {
- color: colors.primary.main,
- fontWeight: '500',
- },
- // 注册按钮
- registerButton: {
- borderRadius: borderRadius.lg,
- overflow: 'hidden',
- ...shadows.md,
- },
- registerButtonGradient: {
- height: 50,
- alignItems: 'center',
- justifyContent: 'center',
- },
- registerButtonGradientWide: {
- height: 54,
- },
- registerButtonDisabled: {
- opacity: 0.7,
- },
- registerButtonText: {
- fontSize: fontSizes.lg,
- fontWeight: '700',
- color: '#FFFFFF',
- },
- // 底部区域
- footerSection: {
- flexDirection: 'row',
- justifyContent: 'center',
- alignItems: 'center',
- marginTop: 'auto',
- paddingTop: spacing.md,
- paddingBottom: spacing.md,
- },
- splitFooterSection: {
- paddingTop: spacing.xl,
- },
- footerText: {
- fontSize: fontSizes.md,
- color: 'rgba(255,255,255,0.9)',
- },
- splitFooterText: {
- color: colors.text.primary,
- },
- loginLink: {
- fontSize: fontSizes.md,
- color: '#FFFFFF',
- fontWeight: '700',
- marginLeft: spacing.xs,
- textDecorationLine: 'underline',
- },
- splitLoginLink: {
- color: colors.primary.main,
- },
- // ========== 分栏布局样式 ==========
- splitContainer: {
- flex: 1,
- flexDirection: 'row',
- },
- leftPanelContainer: {
- flex: 1, // 50%
- justifyContent: 'center',
- alignItems: 'center',
- overflow: 'hidden',
- },
- leftPanelSafeArea: {
- flex: 1,
- justifyContent: 'center',
- alignItems: 'center',
- paddingHorizontal: spacing['4xl'], // 增加内边距,不贴边
- },
- leftPanel: {
- alignItems: 'center',
- paddingHorizontal: spacing['2xl'],
- },
- // 大屏模式左侧面板布局
- splitLeftPanel: {
- width: '100%',
- justifyContent: 'center',
- paddingVertical: 120,
- },
- // 大屏模式图标容器样式 - 增加阴影和内边距,更立体
- splitIconContainer: {
- borderWidth: 3,
- borderColor: 'rgba(255,255,255,0.5)',
- ...shadows.lg,
- },
- iconContainerTop: {
- marginTop: spacing['3xl'],
- },
- // 大屏模式标题样式 - 大幅放大,增加间距和文字效果
- splitTitle: {
- fontSize: 72, // 大幅放大主标题
- marginBottom: 48,
- textShadowOffset: { width: 0, height: 4 },
- textShadowRadius: 8,
- letterSpacing: 4, // 增加字间距,更显大气
- fontWeight: '900',
- },
- // 大屏模式副标题样式 - 大幅放大
- splitSubtitle: {
- fontSize: 24, // 放大副标题
- marginBottom: 120, // 增加底部间距
- lineHeight: 36,
- paddingHorizontal: spacing['4xl'],
- letterSpacing: 1.5,
- fontWeight: '500',
- },
- leftPanelDecorBottom: {
- marginTop: spacing['2xl'],
- },
- // 大屏模式装饰元素布局
- splitLeftPanelDecorBottom: {
- marginTop: 120,
- width: '100%',
- alignItems: 'center',
- },
- // 大屏模式装饰元素水平排列
- splitDecorRow: {
- flexDirection: 'row',
- alignItems: 'center',
- justifyContent: 'space-around',
- width: '100%',
- gap: spacing['2xl'], // 增加图标间距
- },
- // 大屏模式装饰图标样式
- splitDecorIcon: {
- transform: [{ scale: 1.1 }],
- opacity: 0.9,
- },
- decorRow: {
- flexDirection: 'row',
- alignItems: 'center',
- justifyContent: 'space-around',
- width: '80%',
- },
- rightPanelContainer: {
- flex: 1, // 50%
- backgroundColor: colors.background.paper,
- },
- rightPanelSafeArea: {
- flex: 1,
- // 移除左右内边距,交给子容器控制
- },
- // 分栏布局右侧内容包裹器(核心修复)
- splitRightContentWrapper: {
- flex: 1,
- justifyContent: 'center',
- alignItems: 'center',
- // 新增:左右内边距,保证表单和边缘有间距
- paddingHorizontal: spacing['2xl'],
- },
- // 表单内容包裹器(区分大屏/小屏)
- splitFormWrapper: {
- // 关键修改:设置最大宽度 + 自适应宽度,实现水平居中
- maxWidth: 480,
- width: '100%',
- },
- singleFormWrapper: {
- flexGrow: 1,
- width: '100%',
- },
- // 小屏模式:原有默认阴影
- normalFormCardShadow: {
- ...shadows.md,
- },
- // 大屏模式:专用全向阴影
- splitFormCardShadow: {
- // iOS 全向柔和阴影
- shadowColor: '#000',
- shadowOffset: { width: 0, height: 2 },
- shadowOpacity: 0.12,
- shadowRadius: 12,
- // Android 高程 + 轻微边框(模拟顶部阴影)
- elevation: 8,
- // 新增:极细微的顶部边框,强化区分度
- borderTopWidth: 1,
- borderTopColor: 'rgba(0,0,0,0.05)',
- },
- formTitle: {
- fontSize: fontSizes['2xl'],
- fontWeight: '700',
- color: colors.text.primary,
- marginBottom: spacing.xl,
- textAlign: 'center',
- },
+ container: {
+ flex: 1,
+ backgroundColor: '#fff',
+ },
+ keyboardView: {
+ flex: 1,
+ },
+ scrollContent: {
+ flexGrow: 1,
+ paddingHorizontal: 28,
+ paddingTop: 50,
+ paddingBottom: 50,
+ },
+ content: {
+ flex: 1,
+ maxWidth: 400,
+ width: '100%',
+ alignSelf: 'center',
+ },
+
+ // 标题区域 - 增大间距
+ titleSection: {
+ marginBottom: 40,
+ marginTop: 10,
+ },
+ title: {
+ fontSize: 32,
+ fontWeight: '700',
+ color: colors.text.primary,
+ lineHeight: 40,
+ },
+ underline: {
+ width: 40,
+ height: 4,
+ backgroundColor: THEME_COLORS.primary,
+ borderRadius: 2,
+ marginTop: 12,
+ marginBottom: 16,
+ },
+ subtitle: {
+ fontSize: 16,
+ color: colors.text.secondary,
+ },
+
+ // 表单区域
+ formSection: {
+ marginBottom: 24,
+ },
+
+ // 输入框
+ inputContainer: {
+ marginBottom: 20,
+ },
+ inputLabel: {
+ fontSize: 14,
+ fontWeight: '500',
+ color: colors.text.secondary,
+ marginBottom: 10,
+ },
+ inputWrapper: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ backgroundColor: '#F5F5F7',
+ borderRadius: 14,
+ paddingHorizontal: 18,
+ height: 56,
+ },
+ input: {
+ flex: 1,
+ fontSize: 16,
+ color: colors.text.primary,
+ height: 56,
+ },
+ checkIcon: {
+ marginLeft: 8,
+ },
+ eyeButton: {
+ padding: 4,
+ marginLeft: 4,
+ },
+
+ // 验证码行
+ codeRow: {
+ flexDirection: 'row',
+ gap: 12,
+ },
+ codeInputWrapper: {
+ flex: 1,
+ },
+ sendCodeButton: {
+ height: 56,
+ paddingHorizontal: 16,
+ backgroundColor: 'rgba(255, 107, 53, 0.1)',
+ borderRadius: 14,
+ alignItems: 'center',
+ justifyContent: 'center',
+ minWidth: 100,
+ },
+ sendCodeButtonDisabled: {
+ opacity: 0.5,
+ },
+ sendCodeButtonText: {
+ fontSize: 14,
+ fontWeight: '600',
+ color: THEME_COLORS.primary,
+ },
+
+ // 服务条款
+ termsContainer: {
+ flexDirection: 'row',
+ alignItems: 'center',
+ marginBottom: 28,
+ marginTop: 4,
+ },
+ termsText: {
+ fontSize: 14,
+ color: colors.text.secondary,
+ marginLeft: 10,
+ flex: 1,
+ lineHeight: 22,
+ },
+ termsLink: {
+ color: THEME_COLORS.primary,
+ fontWeight: '500',
+ },
+
+ // 注册按钮
+ registerButton: {
+ height: 56,
+ borderRadius: 14,
+ backgroundColor: THEME_COLORS.primary,
+ alignItems: 'center',
+ justifyContent: 'center',
+ },
+ registerButtonDisabled: {
+ opacity: 0.7,
+ },
+ registerButtonText: {
+ fontSize: 17,
+ fontWeight: '600',
+ color: '#FFFFFF',
+ },
+
+ // 底部
+ footer: {
+ flexDirection: 'row',
+ justifyContent: 'center',
+ alignItems: 'center',
+ marginTop: 32,
+ },
+ footerText: {
+ fontSize: 15,
+ color: colors.text.secondary,
+ },
+ loginLink: {
+ fontSize: 15,
+ color: THEME_COLORS.primary,
+ fontWeight: '600',
+ marginLeft: 6,
+ },
});
}
diff --git a/src/screens/auth/WelcomeScreen.tsx b/src/screens/auth/WelcomeScreen.tsx
new file mode 100644
index 0000000..efa0de5
--- /dev/null
+++ b/src/screens/auth/WelcomeScreen.tsx
@@ -0,0 +1,265 @@
+/**
+ * 欢迎页 WelcomeScreen
+ * 胡萝卜BBS - 用户欢迎页
+ *
+ * 亮色模式:白色主色调 + 胡萝卜橙辅色
+ * 暗色模式:深色背景 + 胡萝卜橙辅色
+ */
+
+import React, { useEffect, useRef, useMemo } from 'react';
+import {
+ View,
+ Text,
+ StyleSheet,
+ TouchableOpacity,
+ Animated,
+ StatusBar,
+ Dimensions,
+} from 'react-native';
+import { SafeAreaView } from 'react-native-safe-area-context';
+import { useRouter } from 'expo-router';
+import { useAppColors, useResolvedColorScheme, type AppColors } from '../../theme';
+import * as hrefs from '../../navigation/hrefs';
+
+const { width, height } = Dimensions.get('window');
+
+export const WelcomeScreen: React.FC = () => {
+ const router = useRouter();
+ const colors = useAppColors();
+ const resolved = useResolvedColorScheme();
+ const styles = useMemo(() => createWelcomeStyles(colors), [colors]);
+ const isDark = resolved === 'dark';
+
+ // 动画值
+ const fadeAnim = useRef(new Animated.Value(0)).current;
+ const slideUpAnim = useRef(new Animated.Value(50)).current;
+ const scaleAnim = useRef(new Animated.Value(0.9)).current;
+
+ useEffect(() => {
+ // 启动入场动画
+ Animated.parallel([
+ Animated.timing(fadeAnim, {
+ toValue: 1,
+ duration: 800,
+ useNativeDriver: true,
+ }),
+ Animated.timing(slideUpAnim, {
+ toValue: 0,
+ duration: 800,
+ useNativeDriver: true,
+ }),
+ Animated.timing(scaleAnim, {
+ toValue: 1,
+ duration: 800,
+ useNativeDriver: true,
+ }),
+ ]).start();
+ }, []);
+
+ const handleSignIn = () => {
+ router.push(hrefs.hrefAuthLogin());
+ };
+
+ const handleCreateAccount = () => {
+ router.push(hrefs.hrefAuthRegister());
+ };
+
+ return (
+
+
+
+ {/* 装饰性背景元素 */}
+
+
+
+
+
+
+ {/* 品牌区域 */}
+
+ Welcome To
+ 萝卜社区
+
+
+
+ 发现有趣的内容{'\n'}
+ 结识志同道合的朋友
+
+
+
+ {/* 按钮区域 */}
+
+
+ 登录
+
+
+
+ 创建账号
+
+
+
+
+
+ );
+};
+
+function createWelcomeStyles(colors: AppColors) {
+ return StyleSheet.create({
+ container: {
+ flex: 1,
+ backgroundColor: colors.background.default,
+ },
+ safeArea: {
+ flex: 1,
+ },
+ content: {
+ flex: 1,
+ justifyContent: 'space-between',
+ paddingHorizontal: 32,
+ paddingTop: 60,
+ paddingBottom: 40,
+ },
+
+ // 装饰性背景元素 - 使用胡萝卜橙的淡色
+ decorCircle1: {
+ position: 'absolute',
+ top: -100,
+ right: -100,
+ width: 400,
+ height: 400,
+ borderRadius: 200,
+ backgroundColor: colors.primary.main + '08', // 非常淡的胡萝卜橙
+ },
+ decorCircle2: {
+ position: 'absolute',
+ top: height * 0.3,
+ left: -80,
+ width: 200,
+ height: 200,
+ borderRadius: 100,
+ backgroundColor: colors.primary.main + '10',
+ },
+ decorCircle3: {
+ position: 'absolute',
+ bottom: -50,
+ right: -50,
+ width: 250,
+ height: 250,
+ borderRadius: 125,
+ backgroundColor: colors.primary.main + '08',
+ },
+
+ // 品牌区域
+ brandSection: {
+ alignItems: 'center',
+ },
+ badge: {
+ backgroundColor: colors.primary.main + '15',
+ paddingHorizontal: 20,
+ paddingVertical: 8,
+ borderRadius: 20,
+ marginBottom: 24,
+ },
+ badgeText: {
+ color: colors.primary.main,
+ fontSize: 14,
+ fontWeight: '600',
+ letterSpacing: 1,
+ },
+ welcomeEn: {
+ fontSize: 24,
+ fontWeight: '400',
+ color: colors.text.secondary,
+ marginBottom: 4,
+ letterSpacing: 1,
+ },
+ brandName: {
+ fontSize: 42,
+ fontWeight: '800',
+ color: colors.text.primary,
+ letterSpacing: 4,
+ marginBottom: 8,
+ },
+ brandUnderline: {
+ width: 80,
+ height: 4,
+ backgroundColor: colors.primary.main,
+ borderRadius: 2,
+ marginBottom: 24,
+ },
+ title: {
+ fontSize: 48,
+ fontWeight: '800',
+ color: colors.text.primary,
+ marginBottom: 16,
+ letterSpacing: 2,
+ },
+ subtitle: {
+ fontSize: 16,
+ color: colors.text.secondary,
+ textAlign: 'center',
+ lineHeight: 24,
+ letterSpacing: 0.5,
+ },
+
+ // 按钮区域
+ buttonSection: {
+ width: '100%',
+ gap: 16,
+ },
+ signInButton: {
+ backgroundColor: colors.primary.main,
+ borderRadius: 16,
+ height: 56,
+ alignItems: 'center',
+ justifyContent: 'center',
+ shadowColor: colors.primary.main,
+ shadowOffset: { width: 0, height: 4 },
+ shadowOpacity: 0.3,
+ shadowRadius: 8,
+ elevation: 5,
+ },
+ signInButtonText: {
+ color: colors.primary.contrast,
+ fontSize: 16,
+ fontWeight: '700',
+ letterSpacing: 1,
+ },
+ createAccountButton: {
+ backgroundColor: 'transparent',
+ borderRadius: 16,
+ height: 56,
+ alignItems: 'center',
+ justifyContent: 'center',
+ borderWidth: 2,
+ borderColor: colors.primary.main,
+ },
+ createAccountButtonText: {
+ color: colors.primary.main,
+ fontSize: 16,
+ fontWeight: '700',
+ letterSpacing: 1,
+ },
+ });
+}
+
+export default WelcomeScreen;
diff --git a/src/screens/auth/index.ts b/src/screens/auth/index.ts
index f74a9f0..620897d 100644
--- a/src/screens/auth/index.ts
+++ b/src/screens/auth/index.ts
@@ -6,3 +6,4 @@
export { LoginScreen } from './LoginScreen';
export { RegisterScreen } from './RegisterScreen';
export { ForgotPasswordScreen } from './ForgotPasswordScreen';
+export { WelcomeScreen } from './WelcomeScreen';