expo-duooomi-app/app/searchTemplate.tsx

356 lines
11 KiB
TypeScript

import { useState, useEffect, useRef, useCallback } from 'react'
import {
View,
Text,
StyleSheet,
TextInput,
ScrollView,
Pressable,
StatusBar as RNStatusBar,
Dimensions,
} from 'react-native'
import { StatusBar } from 'expo-status-bar'
import { SafeAreaView } from 'react-native-safe-area-context'
import { useRouter, useLocalSearchParams, useFocusEffect } from 'expo-router'
import { LeftArrowIcon, CloseIcon, DeleteIcon, ChangeIcon, Close1Icon } from '@/components/icon'
import { useTags, useSearchHistory } from '@/hooks/data'
const { width: screenWidth } = Dimensions.get('window')
export default function SearchTemplateScreen() {
const router = useRouter()
const params = useLocalSearchParams()
const [searchText, setSearchText] = useState('')
const [isDeleteMode, setIsDeleteMode] = useState(false)
const inputRef = useRef<TextInput>(null)
const { load, data: tagsData } = useTags()
const { history: searchHistory, addToHistory, removeFromHistory, clearHistory } = useSearchHistory()
useEffect(() => {
if (params.q && typeof params.q === 'string') {
setSearchText(params.q)
}
}, [params.q])
useEffect(() => {
load({ limit: 12 })
}, [])
// 当页面获得焦点且需要聚焦时,自动聚焦输入框
useFocusEffect(
useCallback(() => {
if (params.focus === 'true') {
// 延迟聚焦,确保页面渲染完成
const timer = setTimeout(() => {
inputRef.current?.focus()
}, 100)
return () => clearTimeout(timer)
}
}, [params.focus])
)
return (
<SafeAreaView style={styles.container} edges={['top']}>
<StatusBar style="light" />
<RNStatusBar barStyle="light-content" />
{/* Top Bar with Search */}
<View style={styles.topBar}>
<Pressable
onPress={() => router.push('/(tabs)')}
>
<LeftArrowIcon />
</Pressable>
<View style={styles.searchInputContainer}>
<TextInput
ref={inputRef}
style={styles.searchInput}
value={searchText}
onChangeText={setSearchText}
placeholder="搜索"
placeholderTextColor="#ABABAB"
underlineColorAndroid="transparent"
selectionColor="#F5F5F5"
autoCorrect={false}
autoCapitalize="none"
/>
{searchText.length > 0 && (
<Pressable
onPress={() => setSearchText('')}
style={styles.clearButton}
>
<CloseIcon />
</Pressable>
)}
</View>
<Pressable
style={styles.searchButton}
onPress={async () => {
if (searchText.trim()) {
await addToHistory(searchText.trim())
router.push({
pathname: '/searchResults',
params: { q: searchText.trim() },
})
}
}}
>
<Text style={styles.searchButtonText}></Text>
</Pressable>
</View>
{/* 搜索历史和推荐标签 */}
<ScrollView
style={styles.scrollView}
// contentContainerStyle={styles.scrollContent}
showsVerticalScrollIndicator={false}
>
{/* 搜索历史 */}
<View style={styles.historySection}>
<View style={styles.historyHeader}>
<Text style={styles.sectionTitle}></Text>
{isDeleteMode ? (
<View style={styles.deleteActions}>
<Pressable
onPress={async () => {
await clearHistory()
setIsDeleteMode(false)
}}
>
<Text style={styles.deleteActionText}></Text>
</Pressable>
<View style={styles.deleteActionSeparator} />
<Pressable
onPress={() => setIsDeleteMode(false)}
>
<Text style={styles.deleteActionText}></Text>
</Pressable>
</View>
) : (
<Pressable
onPress={() => setIsDeleteMode(true)}
>
<DeleteIcon />
</Pressable>
)}
</View>
<View style={styles.historyTags}>
{searchHistory.map((item, index) => (
<View
key={index}
style={styles.historyTagContainer}
>
<Pressable
style={styles.historyTag}
onPress={() => {
if (!isDeleteMode) {
setSearchText(item)
}
}}
>
<Text style={styles.historyTagText}>{item}</Text>
{isDeleteMode && (
<Pressable
style={styles.historyTagDeleteButton}
onPress={async () => {
await removeFromHistory(item)
}}
>
<Close1Icon />
</Pressable>
)}
</Pressable>
</View>
))}
</View>
</View>
{/* 探索更多 */}
<View>
<View style={styles.exploreHeader}>
<Text style={styles.sectionTitle}></Text>
<Pressable
style={styles.refreshButton}
onPress={() => load({ limit: 12 })}
>
<ChangeIcon />
<Text style={styles.refreshButtonText}></Text>
</Pressable>
</View>
<View style={styles.exploreTags}>
{tagsData?.tags.map((tag) => (
<Pressable
key={tag.id}
style={styles.exploreTag}
onPress={() => setSearchText(tag.name)}
>
<Text style={styles.exploreTagText}>{tag.name}</Text>
</Pressable>
))}
</View>
</View>
</ScrollView>
</SafeAreaView>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#090A0B',
},
topBar: {
height: 44,
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 12,
marginTop:8,
marginBottom: 20,
},
scrollView: {
flex: 1,
paddingHorizontal: 12,
},
searchInputContainer: {
flex: 1,
marginLeft: 4,
marginRight: 12,
position: 'relative',
height: 40,
},
searchInput: {
flex: 1,
color: '#F5F5F5',
fontSize: 14,
height: 40,
paddingVertical: 8,
paddingLeft: 12,
paddingRight: 36,
borderRadius: 100,
backgroundColor: '#16181B',
},
clearButton: {
position: 'absolute',
right: 8,
top: 0,
bottom: 0,
justifyContent: 'center',
alignItems: 'center',
padding: 4,
},
searchButton: {
paddingHorizontal: 0,
paddingVertical: 8,
},
searchButtonText: {
color: '#F5F5F5',
fontSize: 14,
fontWeight: '400',
},
historySection: {
paddingBottom:32,
},
historyHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
},
sectionTitle: {
color: '#F5F5F5',
fontSize: 14,
fontWeight: '500',
lineHeight: 20,
},
historyTags: {
flexDirection: 'row',
flexWrap: 'wrap',
gap: 4,
marginTop: 16,
},
historyTagContainer: {
flexDirection: 'row',
alignItems: 'center',
gap: 4,
},
historyTag: {
backgroundColor: '#191B1F',
borderRadius: 100,
paddingHorizontal: 11,
paddingVertical: 6,
borderWidth: 1,
borderColor: '#191B1F',
height: 29,
justifyContent: 'center',
flexDirection: 'row',
alignItems: 'center',
gap: 4,
},
historyTagText: {
color: '#F5F5F5',
fontSize: 12,
},
historyTagDeleteButton: {
justifyContent: 'center',
alignItems: 'center',
},
deleteActions: {
flexDirection: 'row',
alignItems: 'center',
},
deleteActionText: {
color: '#ABABAB',
fontSize: 14,
fontWeight: '400',
},
deleteActionSeparator: {
width: 1,
height: 14,
backgroundColor: '#ABABAB',
marginHorizontal: 12,
},
exploreHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
marginBottom: 16,
},
refreshButton: {
flexDirection: 'row',
alignItems: 'center',
gap: 1,
paddingVertical: 4,
},
refreshButtonText: {
color: '#8A8A8A',
fontSize: 12,
fontWeight: '400',
},
refreshIcon: {
width: 18,
height: 18,
borderRadius: 9,
backgroundColor: '#1C1E22',
justifyContent: 'center',
alignItems: 'center',
},
exploreTags: {
flexDirection: 'row',
flexWrap: 'wrap',
gap: 8,
},
exploreTag: {
width: (screenWidth - 24 - 8) / 2, // 屏幕宽度 - 左右padding(12*2) - gap(8) 除以2
justifyContent: 'center',
paddingVertical: 2,
},
exploreTagText: {
color: '#F5F5F5',
fontSize: 14,
fontWeight: '400',
},
})