feat: 首页更新
This commit is contained in:
@@ -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)} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user