feat: 首页更新

This commit is contained in:
2025-11-13 16:47:10 +08:00
parent 9ef9233797
commit 54bf84b19b
1244 changed files with 3507 additions and 951 deletions

View File

@@ -1,9 +1,15 @@
/**
* 首页 Header 组件
* 包含搜索、用户信息、消息等功能
* Header 组件 - 增强版
* 基于 xinyong-web 的 header 组件重建
* 功能包括:
* - 顶部导航栏logo、搜索、用户按钮
* - 左侧菜单(侧边栏)
* - 登录/注册弹窗
* - 钱包信息显示
* - 主题适配
*/
import React, { useState, useCallback } from 'react';
import React, { useState, useCallback, useMemo } from 'react';
import {
View,
Text,
@@ -12,154 +18,150 @@ import {
TextInput,
Image,
Dimensions,
Modal,
ScrollView,
SafeAreaView,
} from 'react-native';
import { createThemeStyles, useColorScheme, useThemeInfo } from '@/theme';
import { useColorScheme, useThemeColors } from '@/theme';
import { useIsLoggedIn, useUser } from '@/stores/userStore';
import { useLogo } from '@/stores/tenantStore';
import { Ionicons, AntDesign } from '@expo/vector-icons';
import LeftMenu from './LeftMenu';
import LoginRegisterModal from './LoginRegisterModal';
import WalletAmount from '../WalletAmount';
import { styles } from './styles';
const { width } = Dimensions.get('window');
/**
* 创建主题样式
*/
const styles = createThemeStyles((colors) => ({
container: {
backgroundColor: colors.background,
paddingHorizontal: 12,
paddingVertical: 8,
borderBottomWidth: 1,
borderBottomColor: colors.border,
},
header: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingVertical: 8,
},
logo: {
fontSize: 18,
fontWeight: '600',
color: colors.primary,
},
searchContainer: {
flex: 1,
marginHorizontal: 12,
flexDirection: 'row',
alignItems: 'center',
backgroundColor: colors.card,
borderRadius: 20,
paddingHorizontal: 12,
height: 36,
},
searchInput: {
flex: 1,
marginLeft: 8,
fontSize: 14,
color: colors.text,
},
searchPlaceholder: {
color: colors.text + '80',
},
iconButton: {
width: 36,
height: 36,
borderRadius: 18,
justifyContent: 'center',
alignItems: 'center',
marginLeft: 8,
},
badge: {
position: 'absolute',
top: -4,
right: -4,
backgroundColor: colors.primary,
borderRadius: 8,
minWidth: 16,
height: 16,
justifyContent: 'center',
alignItems: 'center',
},
badgeText: {
color: '#fff',
fontSize: 10,
fontWeight: '600',
textAlign: 'center',
},
}));
interface HeaderProps {
onSearch?: (keyword: string) => void;
onMessagePress?: () => void;
onUserPress?: () => void;
onMenuPress?: () => void;
unreadCount?: number;
}
/**
* Header 组件
* Header 组件 - 增强版
*/
export default function Header({
onSearch,
onMessagePress,
onUserPress,
onMenuPress,
unreadCount = 0,
}: HeaderProps) {
const theme = useColorScheme();
const s = styles[theme];
const { colors } = useThemeInfo();
const colorScheme = useColorScheme();
const s = styles[colorScheme];
const themeColors = useThemeColors();
const isLoggedIn = useIsLoggedIn();
const user = useUser();
const logoUrl = useLogo();
const [searchText, setSearchText] = useState('');
const [isSearching, setIsSearching] = useState(false);
const [showLeftMenu, setShowLeftMenu] = useState(false);
const [showLoginModal, setShowLoginModal] = useState(false);
const handleSearch = useCallback(() => {
if (searchText.trim()) {
onSearch?.(searchText);
setSearchText('');
}
}, [searchText, onSearch]);
const handleClearSearch = useCallback(() => {
setSearchText('');
const handleMenuPress = useCallback(() => {
setShowLeftMenu(true);
onMenuPress?.();
}, [onMenuPress]);
const handleLoginPress = useCallback(() => {
setShowLoginModal(true);
}, []);
return (
<View style={s.container}>
{/* 顶部栏 */}
<View style={s.header}>
{/* Logo */}
<Text style={s.logo}>🎮 </Text>
<>
<View style={s.container}>
{/* 左侧部分 */}
<View style={s.leftSection}>
{/* 菜单按钮 */}
<TouchableOpacity style={s.menuButton} onPress={handleMenuPress} activeOpacity={0.7}>
<AntDesign name="menu-unfold" size={22} color={themeColors.text} />
</TouchableOpacity>
{/* 搜索框 */}
<View style={s.searchContainer}>
<Text style={{ color: colors.text + '60', fontSize: 16 }}>🔍</Text>
<TextInput
style={[s.searchInput, s.searchPlaceholder]}
placeholder="搜索游戏..."
placeholderTextColor={colors.text + '60'}
value={searchText}
onChangeText={setSearchText}
onSubmitEditing={handleSearch}
returnKeyType="search"
/>
{searchText ? (
<TouchableOpacity onPress={handleClearSearch}>
<Text style={{ fontSize: 16 }}></Text>
</TouchableOpacity>
) : null}
{/* Logo */}
{logoUrl ? <Image source={{ uri: logoUrl }} style={s.logoImage} /> : null}
</View>
{/* 消息按钮 */}
<TouchableOpacity style={s.iconButton} onPress={onMessagePress} activeOpacity={0.7}>
<Text style={{ fontSize: 18 }}>💬</Text>
{unreadCount > 0 && (
<View style={s.badge}>
<Text style={s.badgeText}>{unreadCount > 99 ? '99+' : unreadCount}</Text>
{/* 搜索框 */}
{/*<View style={s.searchContainer}>*/}
{/* <Ionicons name="search" size={16} color={themeColors.text + '60'} />*/}
{/* <TextInput*/}
{/* style={s.searchInput}*/}
{/* placeholder="搜索游戏..."*/}
{/* placeholderTextColor={themeColors.text + '60'}*/}
{/* value={searchText}*/}
{/* onChangeText={setSearchText}*/}
{/* onSubmitEditing={handleSearch}*/}
{/* returnKeyType="search"*/}
{/* />*/}
{/* {searchText ? (*/}
{/* <TouchableOpacity onPress={() => setSearchText('')}>*/}
{/* <Ionicons name="close" size={16} color={themeColors.text} />*/}
{/* </TouchableOpacity>*/}
{/* ) : null}*/}
{/*</View>*/}
{/* 右侧部分 */}
<View style={s.rightSection}>
{isLoggedIn && user ? (
<>
{/* 消息按钮 */}
<TouchableOpacity style={s.iconButton} onPress={onMessagePress} activeOpacity={0.7}>
<Ionicons name="chatbubble-outline" size={20} color={themeColors.text} />
{unreadCount > 0 && (
<View style={s.badge}>
<Text style={s.badgeText}>{unreadCount > 99 ? '99+' : unreadCount}</Text>
</View>
)}
</TouchableOpacity>
{/* 用户头像 */}
<TouchableOpacity style={s.iconButton} activeOpacity={0.7}>
{user.avatar ? (
<Image
source={{ uri: user.avatar }}
style={{ width: 32, height: 32, borderRadius: 16 }}
/>
) : (
<Ionicons name="person-circle" size={24} color={themeColors.primary} />
)}
</TouchableOpacity>
</>
) : (
/* 登录/注册按钮 */
<View style={s.authButtons}>
<TouchableOpacity
style={[s.authButton, s.registerButton]}
onPress={() => setShowLoginModal(true)}
activeOpacity={0.7}
>
<Text style={s.registerButtonText}></Text>
</TouchableOpacity>
<TouchableOpacity
style={[s.authButton, s.loginButton]}
onPress={() => setShowLoginModal(true)}
activeOpacity={0.7}
>
<Text style={s.loginButtonText}></Text>
</TouchableOpacity>
</View>
)}
</TouchableOpacity>
{/* 用户按钮 */}
<TouchableOpacity style={s.iconButton} onPress={onUserPress} activeOpacity={0.7}>
<Text style={{ fontSize: 18 }}>👤</Text>
</TouchableOpacity>
</View>
</View>
</View>
{/* 左侧菜单 */}
<LeftMenu visible={showLeftMenu} onClose={() => setShowLeftMenu(false)} />
{/* 登录/注册弹窗 */}
<LoginRegisterModal visible={showLoginModal} onClose={() => setShowLoginModal(false)} />
</>
);
}