Files
jungwoo choi 919afe56f2 feat: SAPIENS Mobile App - Initial commit
React Native mobile application for SAPIENS news platform.
Consolidated all previous history into single commit.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-23 14:30:25 +09:00

127 lines
2.9 KiB
TypeScript

import { useState, useEffect } from 'react';
import { View, Text, TextInput, TouchableOpacity, StyleSheet, Animated, Dimensions } from 'react-native';
import { Ionicons } from '@expo/vector-icons';
const { width } = Dimensions.get('window');
interface SearchModalProps {
visible: boolean;
onClose: () => void;
}
export default function SearchModal({ visible, onClose }: SearchModalProps) {
const [searchText, setSearchText] = useState('');
const [slideAnim] = useState(new Animated.Value(width));
useEffect(() => {
if (visible) {
Animated.spring(slideAnim, {
toValue: 0,
useNativeDriver: true,
tension: 65,
friction: 11,
}).start();
} else {
Animated.timing(slideAnim, {
toValue: width,
duration: 250,
useNativeDriver: true,
}).start();
}
}, [visible]);
if (!visible) return null;
const handleClose = () => {
Animated.timing(slideAnim, {
toValue: width,
duration: 250,
useNativeDriver: true,
}).start(() => {
onClose();
});
};
return (
<Animated.View
style={[
styles.container,
{
transform: [{ translateX: slideAnim }],
},
]}
>
<View style={styles.searchBar}>
<Ionicons name="search-outline" size={20} color="#666" style={styles.searchIcon} />
<TextInput
style={styles.searchInput}
placeholder="Search outlets, articles..."
value={searchText}
onChangeText={setSearchText}
autoFocus
returnKeyType="search"
/>
<TouchableOpacity onPress={handleClose} style={styles.closeButton}>
<Ionicons name="close" size={24} color="#666" />
</TouchableOpacity>
</View>
<View style={styles.content}>
{searchText === '' ? (
<View style={styles.emptyState}>
<Ionicons name="search-outline" size={64} color="#ccc" />
<Text style={styles.emptyText}>Search for outlets or articles</Text>
</View>
) : (
<View style={styles.emptyState}>
<Text style={styles.emptyText}>No results found for "{searchText}"</Text>
</View>
)}
</View>
</Animated.View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
searchBar: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 16,
paddingVertical: 12,
borderBottomWidth: 1,
borderBottomColor: '#e0e0e0',
backgroundColor: '#fff',
},
searchIcon: {
marginRight: 8,
},
searchInput: {
flex: 1,
fontSize: 16,
color: '#000',
padding: 8,
},
closeButton: {
padding: 4,
},
content: {
flex: 1,
padding: 16,
},
emptyState: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
emptyText: {
fontSize: 16,
color: '#999',
marginTop: 16,
textAlign: 'center',
},
});