Skip to content

Commit 482856a

Browse files
committed
Add example search
1 parent 5b70c4b commit 482856a

1 file changed

Lines changed: 138 additions & 49 deletions

File tree

apps/common-app/App.tsx

Lines changed: 138 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,15 @@ import type {
1010
import { createStackNavigator } from '@react-navigation/stack';
1111
import { Icon } from '@swmansion/icons';
1212
import { useEffect, useState } from 'react';
13-
import { Dimensions, Platform, StyleSheet, Text, View } from 'react-native';
13+
import {
14+
Dimensions,
15+
Platform,
16+
Pressable,
17+
StyleSheet,
18+
Text,
19+
TextInput,
20+
View,
21+
} from 'react-native';
1422
import {
1523
GestureHandlerRootView,
1624
Switch,
@@ -85,6 +93,20 @@ export default function App() {
8593

8694
function MainScreen({ navigation }: StackScreenProps<ParamListBase>) {
8795
const insets = useSafeAreaInsets();
96+
const [searchQuery, setSearchQuery] = useState('');
97+
98+
const normalizedSearchQuery = searchQuery.trim().toLocaleLowerCase();
99+
const sections = showLegacyVersion ? OLD_EXAMPLES : NEW_EXAMPLES;
100+
const filteredSections = normalizedSearchQuery
101+
? sections
102+
.map((section) => ({
103+
...section,
104+
data: section.data.filter(({ name }) =>
105+
name.toLocaleLowerCase().includes(normalizedSearchQuery)
106+
),
107+
}))
108+
.filter(({ data }) => data.length > 0)
109+
: sections;
88110

89111
useEffect(() => {
90112
void AsyncStorage.multiGet([
@@ -114,9 +136,19 @@ export default function App() {
114136
<View style={styles.container}>
115137
<ListWithHeader
116138
style={styles.list}
117-
sections={showLegacyVersion ? OLD_EXAMPLES : NEW_EXAMPLES}
139+
sections={filteredSections}
118140
keyExtractor={(example) => example.name}
119-
ListHeaderComponent={Settings}
141+
ListHeaderComponent={
142+
<Settings
143+
searchQuery={searchQuery}
144+
onChangeSearchQuery={setSearchQuery}
145+
/>
146+
}
147+
ListEmptyComponent={
148+
<Text style={styles.emptyText}>
149+
No examples match “{searchQuery.trim()}
150+
</Text>
151+
}
120152
contentContainerStyle={{
121153
paddingBottom: insets.bottom,
122154
paddingTop: insets.top,
@@ -137,7 +169,12 @@ export default function App() {
137169
);
138170
}
139171

140-
function Settings() {
172+
interface SettingsProps {
173+
searchQuery: string;
174+
onChangeSearchQuery: (query: string) => void;
175+
}
176+
177+
function Settings({ searchQuery, onChangeSearchQuery }: SettingsProps) {
141178
const [openLastExample, setOpenLastExample] = useState(false);
142179

143180
useEffect(() => {
@@ -157,51 +194,77 @@ export default function App() {
157194
setShowLegacyVersion(value);
158195
}
159196
return (
160-
<View style={styles.settings}>
161-
<Touchable
162-
androidRipple={{}}
163-
underlayColor={Platform.OS === 'android' ? 'transparent' : 'black'}
164-
style={styles.settingsButton}
165-
onPress={() => {
166-
updateKeepSetting(!openLastExample);
167-
}}>
168-
<View
169-
style={styles.settingsButtonContent}
170-
pointerEvents={Platform.OS === 'web' ? 'box-only' : 'auto'}>
171-
<Text style={[styles.text, styles.aligned]}>
172-
Open last example on launch
173-
</Text>
174-
<Switch
175-
style={styles.aligned}
176-
value={openLastExample}
177-
onValueChange={() => {
178-
updateKeepSetting(!openLastExample);
179-
}}
180-
/>
181-
</View>
182-
</Touchable>
183-
<Touchable
184-
androidRipple={{}}
185-
underlayColor={Platform.OS === 'android' ? 'transparent' : 'black'}
186-
style={styles.settingsButton}
187-
onPress={() => {
188-
updateVersionSetting(!showLegacyVersion);
189-
}}>
190-
<View
191-
style={styles.settingsButtonContent}
192-
pointerEvents={Platform.OS === 'web' ? 'box-only' : 'auto'}>
193-
<Text style={[styles.text, styles.aligned]}>
194-
Show legacy version examples
195-
</Text>
196-
<Switch
197-
style={styles.aligned}
198-
value={showLegacyVersion}
199-
onValueChange={() => {
200-
updateVersionSetting(!showLegacyVersion);
201-
}}
202-
/>
203-
</View>
204-
</Touchable>
197+
<View style={styles.headerControls}>
198+
<View style={styles.searchBar}>
199+
<Icon name="search" size={20} color={COLORS.NAVY} />
200+
<TextInput
201+
accessibilityLabel="Search examples"
202+
autoCapitalize="none"
203+
autoCorrect={false}
204+
clearButtonMode="while-editing"
205+
placeholder="Search examples"
206+
placeholderTextColor={COLORS.GRAY}
207+
returnKeyType="search"
208+
selectionColor={COLORS.DARK_PURPLE}
209+
style={styles.searchInput}
210+
value={searchQuery}
211+
onChangeText={onChangeSearchQuery}
212+
/>
213+
{searchQuery.length > 0 && Platform.OS !== 'ios' && (
214+
<Pressable
215+
accessibilityLabel="Clear search"
216+
hitSlop={8}
217+
onPress={() => onChangeSearchQuery('')}>
218+
<Icon name="cross-circle" size={20} color={COLORS.GRAY} />
219+
</Pressable>
220+
)}
221+
</View>
222+
<View style={styles.settings}>
223+
<Touchable
224+
androidRipple={{}}
225+
underlayColor={Platform.OS === 'android' ? 'transparent' : 'black'}
226+
style={styles.settingsButton}
227+
onPress={() => {
228+
updateKeepSetting(!openLastExample);
229+
}}>
230+
<View
231+
style={styles.settingsButtonContent}
232+
pointerEvents={Platform.OS === 'web' ? 'box-only' : 'auto'}>
233+
<Text style={[styles.text, styles.aligned]}>
234+
Open last example on launch
235+
</Text>
236+
<Switch
237+
style={styles.aligned}
238+
value={openLastExample}
239+
onValueChange={() => {
240+
updateKeepSetting(!openLastExample);
241+
}}
242+
/>
243+
</View>
244+
</Touchable>
245+
<Touchable
246+
androidRipple={{}}
247+
underlayColor={Platform.OS === 'android' ? 'transparent' : 'black'}
248+
style={styles.settingsButton}
249+
onPress={() => {
250+
updateVersionSetting(!showLegacyVersion);
251+
}}>
252+
<View
253+
style={styles.settingsButtonContent}
254+
pointerEvents={Platform.OS === 'web' ? 'box-only' : 'auto'}>
255+
<Text style={[styles.text, styles.aligned]}>
256+
Show legacy version examples
257+
</Text>
258+
<Switch
259+
style={styles.aligned}
260+
value={showLegacyVersion}
261+
onValueChange={() => {
262+
updateVersionSetting(!showLegacyVersion);
263+
}}
264+
/>
265+
</View>
266+
</Touchable>
267+
</View>
205268
</View>
206269
);
207270
}
@@ -264,6 +327,12 @@ const styles = StyleSheet.create({
264327
separator: {
265328
height: 2,
266329
},
330+
emptyText: {
331+
paddingHorizontal: 24,
332+
paddingVertical: 32,
333+
color: COLORS.GRAY,
334+
textAlign: 'center',
335+
},
267336
button: {
268337
flex: 1,
269338
height: 48,
@@ -306,6 +375,26 @@ const styles = StyleSheet.create({
306375
settings: {
307376
flexDirection: 'row',
308377
gap: 24,
378+
},
379+
headerControls: {
380+
gap: 16,
309381
margin: 24,
310382
},
383+
searchBar: {
384+
minHeight: 44,
385+
paddingHorizontal: 14,
386+
flexDirection: 'row',
387+
alignItems: 'center',
388+
gap: 10,
389+
borderRadius: 12,
390+
borderWidth: 1,
391+
borderColor: COLORS.headerSeparator,
392+
backgroundColor: '#fff',
393+
},
394+
searchInput: {
395+
flex: 1,
396+
paddingVertical: Platform.OS === 'web' ? 10 : 8,
397+
color: COLORS.NAVY,
398+
fontSize: 16,
399+
},
311400
});

0 commit comments

Comments
 (0)