You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
181 lines
4.1 KiB
181 lines
4.1 KiB
|
1 month ago
|
/**
|
||
|
|
* 首页 Header 组件
|
||
|
|
* 包含搜索、用户信息、消息等功能
|
||
|
|
*/
|
||
|
|
|
||
|
|
import React, { useState, useCallback } from 'react';
|
||
|
|
import {
|
||
|
|
View,
|
||
|
|
Text,
|
||
|
|
StyleSheet,
|
||
|
|
TouchableOpacity,
|
||
|
|
TextInput,
|
||
|
|
Image,
|
||
|
|
Dimensions,
|
||
|
|
} from 'react-native';
|
||
|
|
import { useColorScheme } from '@/hooks';
|
||
|
|
import { createThemeStyles } from '@/theme';
|
||
|
|
import Colors from '@/constants/Colors';
|
||
|
|
|
||
|
|
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 {
|
||
|
|
theme?: 'light' | 'dark';
|
||
|
|
onSearch?: (keyword: string) => void;
|
||
|
|
onMessagePress?: () => void;
|
||
|
|
onUserPress?: () => void;
|
||
|
|
unreadCount?: number;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Header 组件
|
||
|
|
*/
|
||
|
|
export default function Header({
|
||
|
|
theme = 'light',
|
||
|
|
onSearch,
|
||
|
|
onMessagePress,
|
||
|
|
onUserPress,
|
||
|
|
unreadCount = 0,
|
||
|
|
}: HeaderProps) {
|
||
|
|
const colorScheme = useColorScheme();
|
||
|
|
const actualTheme = theme === 'light' || theme === 'dark' ? theme : colorScheme;
|
||
|
|
const s = styles[actualTheme];
|
||
|
|
const colors = Colors[actualTheme];
|
||
|
|
|
||
|
|
const [searchText, setSearchText] = useState('');
|
||
|
|
const [isSearching, setIsSearching] = useState(false);
|
||
|
|
|
||
|
|
const handleSearch = useCallback(() => {
|
||
|
|
if (searchText.trim()) {
|
||
|
|
onSearch?.(searchText);
|
||
|
|
}
|
||
|
|
}, [searchText, onSearch]);
|
||
|
|
|
||
|
|
const handleClearSearch = useCallback(() => {
|
||
|
|
setSearchText('');
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
return (
|
||
|
|
<View style={s.container}>
|
||
|
|
{/* 顶部栏 */}
|
||
|
|
<View style={s.header}>
|
||
|
|
{/* Logo */}
|
||
|
|
<Text style={s.logo}>🎮 游戏大厅</Text>
|
||
|
|
|
||
|
|
{/* 搜索框 */}
|
||
|
|
<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}
|
||
|
|
</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>
|
||
|
|
)}
|
||
|
|
</TouchableOpacity>
|
||
|
|
|
||
|
|
{/* 用户按钮 */}
|
||
|
|
<TouchableOpacity
|
||
|
|
style={s.iconButton}
|
||
|
|
onPress={onUserPress}
|
||
|
|
activeOpacity={0.7}
|
||
|
|
>
|
||
|
|
<Text style={{ fontSize: 18 }}>👤</Text>
|
||
|
|
</TouchableOpacity>
|
||
|
|
</View>
|
||
|
|
</View>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|