Skip to content

Commit 57888e6

Browse files
authored
Merge pull request #51 from dribble-njr/feat/common-comps
Feat/common comps
2 parents acdcf3d + 00f253f commit 57888e6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+3650
-910
lines changed

.github/workflows/pr-preview.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ jobs:
6060
nodemailer_auth_pass=${{ secrets.NODEMAILER_AUTH_PASS }}
6161
jwt_secret=agshddgfsd
6262
REDIS_PASSWORD=${{ secrets.REDIS_PASSWORD }}
63-
REDIS_URL=redis-13502.c261.us-east-1-4.ec2.redns.redis-cloud.com
63+
REDIS_URL=${{ secrets.REDIS_URL }}
64+
REDIS_PORT=${{ secrets.REDIS_PORT }}
6465
EOL
6566
6667
cd ../..

apps/mobile/app/(app)/(new)/dish.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { FieldInput, ParallaxScrollView, Modal } from '@/components/common';
1+
import { ParallaxScrollView, Modal } from '@/components/common';
2+
import { FieldInput } from '@/components/form';
23
import { useThemeColor } from '@/hooks/useThemeColor';
34
import { CreateDishDTO } from '@/types';
45
import { Formik } from 'formik';

apps/mobile/app/(app)/(tabs)/index.tsx

Lines changed: 76 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
1-
import { TouchableOpacity, StyleSheet } from 'react-native';
1+
import { StyleSheet } from 'react-native';
22
import { useEffect, useState } from 'react';
33
import { ParallaxScrollView, Surface, Text } from '@/components/common';
4-
import { Card, IconButton, Searchbar } from 'react-native-paper';
4+
import { Card, Icon, IconButton, TouchableRipple } from 'react-native-paper';
55
import { useTranslation } from 'react-i18next';
66
import { getGreeting } from '@/utils';
77
import { CategoryVO, DishVO } from '@/types';
88
import { CategoryService } from '@/service';
99
import { useThemeColor } from '@/hooks/useThemeColor';
1010
import Animated from 'react-native-reanimated';
11+
import { router } from 'expo-router';
1112

1213
export default function HomeLayout() {
1314
const [selectedCategory, setSelectedCategory] = useState<number | undefined>(undefined);
14-
const [searchQuery, setSearchQuery] = useState('');
1515
const { t } = useTranslation();
1616
const colors = useThemeColor();
1717

@@ -54,7 +54,17 @@ export default function HomeLayout() {
5454
</Text>
5555
</Surface>
5656

57-
<Searchbar placeholder="Search" onChangeText={setSearchQuery} value={searchQuery} />
57+
<TouchableRipple
58+
onPress={() => router.push('/search')}
59+
rippleColor="rgba(0, 0, 0, .3)"
60+
style={styles.searchBarContainer}
61+
borderless
62+
>
63+
<Surface style={styles.searchBar} elevation={2}>
64+
<Icon source="magnify" size={24} color={colors.onSurfaceVariant} />
65+
<Text style={[styles.searchText, { color: colors.onSurfaceVariant }]}>热词</Text>
66+
</Surface>
67+
</TouchableRipple>
5868

5969
{/* Categories */}
6070
<Surface style={styles.categoryContainer}>
@@ -65,11 +75,16 @@ export default function HomeLayout() {
6575
const textColor = isSelected ? colors.onPrimary : colors.onSurfaceVariant;
6676

6777
return (
68-
<TouchableOpacity key={category.id} onPress={() => setSelectedCategory(category.id)}>
78+
<TouchableRipple
79+
borderless
80+
key={category.id}
81+
onPress={() => setSelectedCategory(category.id)}
82+
style={{ marginRight: 16, borderRadius: 25 }}
83+
>
6984
<Surface style={[styles.categoryButton, { backgroundColor }]}>
7085
<Text style={{ color: textColor }}>{category.name}</Text>
7186
</Surface>
72-
</TouchableOpacity>
87+
</TouchableRipple>
7388
);
7489
})}
7590
</Animated.ScrollView>
@@ -80,40 +95,45 @@ export default function HomeLayout() {
8095
</Surface>
8196

8297
{/* Dish Cards */}
83-
<Animated.FlatList
84-
data={dishes}
85-
numColumns={1}
86-
renderItem={({ item: dish }) => (
87-
<Surface style={styles.dishCard} elevation={2}>
88-
<Card.Cover
89-
source={{ uri: dish.image ?? 'https://picsum.photos/200/300' }}
90-
style={styles.dishImage}
91-
resizeMode="cover"
92-
testID="dish-image"
93-
/>
94-
<Card.Content style={styles.dishContent}>
95-
<Surface style={styles.dishInfo} elevation={0}>
96-
<Text variant="titleMedium" ellipsizeMode="tail" style={styles.dishName} numberOfLines={2}>
97-
{dish.name}10串鸭肠小船
98-
</Text>
99-
100-
<Text variant="bodySmall" style={[styles.dishDescription, { color: colors.secondary }]}>
101-
{dish.description}
102-
</Text>
103-
</Surface>
104-
105-
<Surface style={styles.dishPriceContainer} elevation={0}>
106-
<Text variant="titleLarge" style={styles.dishPrice}>
107-
¥{dish.price}
108-
</Text>
109-
<IconButton icon="cart-outline" size={22} onPress={() => console.log('Pressed')} />
110-
</Surface>
111-
</Card.Content>
112-
</Surface>
113-
)}
114-
keyExtractor={(item) => item.id.toString()}
115-
showsVerticalScrollIndicator={false}
116-
/>
98+
<Surface>
99+
<Animated.FlatList
100+
data={dishes}
101+
numColumns={1}
102+
renderItem={({ item: dish }) => (
103+
<Surface style={styles.dishCard} elevation={2}>
104+
<Card.Cover
105+
source={{ uri: dish.image ?? 'https://picsum.photos/200/300' }}
106+
style={styles.dishImage}
107+
resizeMode="cover"
108+
testID="dish-image"
109+
/>
110+
<Card.Content style={styles.dishContent}>
111+
<Surface style={styles.dishInfo} elevation={0}>
112+
<Text variant="titleSmall" ellipsizeMode="tail" style={styles.dishName} numberOfLines={2}>
113+
{dish.name}
114+
</Text>
115+
116+
<Text variant="labelSmall" style={[styles.dishDescription, { color: colors.secondary }]}>
117+
{dish.description}
118+
</Text>
119+
</Surface>
120+
121+
<Surface style={styles.dishPriceContainer} elevation={0}>
122+
<Text>
123+
¥{' '}
124+
<Text variant="titleLarge" style={styles.dishPrice}>
125+
{dish.price}
126+
</Text>
127+
</Text>
128+
<IconButton icon="cart-outline" size={22} onPress={() => console.log('Pressed')} />
129+
</Surface>
130+
</Card.Content>
131+
</Surface>
132+
)}
133+
keyExtractor={(item) => item.id.toString()}
134+
showsVerticalScrollIndicator={false}
135+
/>
136+
</Surface>
117137
</ParallaxScrollView>
118138
);
119139
}
@@ -126,16 +146,14 @@ const styles = StyleSheet.create({
126146
fontWeight: '600'
127147
},
128148
searchInput: {
129-
flex: 1,
130-
marginLeft: 8
149+
height: 20
131150
},
132151
categoryContainer: {
133152
flexDirection: 'row',
134153
justifyContent: 'space-between',
135154
alignItems: 'center'
136155
},
137156
categoryButton: {
138-
marginRight: 16,
139157
paddingHorizontal: 24,
140158
paddingVertical: 8,
141159
borderRadius: 25,
@@ -177,5 +195,20 @@ const styles = StyleSheet.create({
177195
},
178196
dishDescription: {
179197
marginTop: 4
198+
},
199+
searchBarContainer: {
200+
borderRadius: 32,
201+
marginVertical: 8
202+
},
203+
searchBar: {
204+
flexDirection: 'row',
205+
alignItems: 'center',
206+
paddingHorizontal: 12,
207+
paddingVertical: 8,
208+
gap: 8
209+
},
210+
searchText: {
211+
height: 18,
212+
lineHeight: 18
180213
}
181214
});

apps/mobile/app/(app)/_layout.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ export default function AppLayout() {
4343
<Stack.Screen name="(recipe)" options={{ title: '' }} />
4444
<Stack.Screen name="(new)" options={{ title: '', headerShown: false, animation: 'fade' }} />
4545
<Stack.Screen name="(profile)" options={{ title: '', headerShown: false }} />
46+
<Stack.Screen name="search" options={{ title: '', headerShown: false, animation: 'fade' }} />
4647
</Stack>
4748
);
4849
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { StackHeader } from '@/components/navigation';
2+
import { Stack } from 'expo-router';
3+
4+
export default function SearchLayout() {
5+
return (
6+
<Stack
7+
screenOptions={{
8+
header: (props) => <StackHeader navProps={props} children={undefined} />
9+
}}
10+
>
11+
<Stack.Screen
12+
name="index"
13+
options={{
14+
title: '',
15+
animation: 'slide_from_right'
16+
}}
17+
/>
18+
</Stack>
19+
);
20+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { StyleSheet } from 'react-native';
2+
import { ParallaxScrollView } from '@/components/common';
3+
import { Searchbar, SegmentedButtons } from 'react-native-paper';
4+
import { useState } from 'react';
5+
import { useTranslation } from 'react-i18next';
6+
7+
type SearchType = 'dishes' | 'recipes';
8+
9+
export default function SearchScreen() {
10+
const [searchQuery, setSearchQuery] = useState('');
11+
const [searchType, setSearchType] = useState<SearchType>('dishes');
12+
const { t } = useTranslation();
13+
14+
return (
15+
<ParallaxScrollView>
16+
<Searchbar
17+
placeholder={t('common.search')}
18+
onChangeText={setSearchQuery}
19+
value={searchQuery}
20+
autoFocus
21+
style={styles.searchBar}
22+
/>
23+
24+
<SegmentedButtons
25+
value={searchType}
26+
onValueChange={(value) => setSearchType(value as SearchType)}
27+
buttons={[
28+
{ value: 'dishes', label: t('common.dishes') },
29+
{ value: 'recipes', label: t('common.recipes') }
30+
]}
31+
style={styles.segmentedButtons}
32+
/>
33+
34+
{/* 搜索结果区域 */}
35+
{/* {searchType === 'dishes' ? (
36+
// 菜品搜索结果
37+
<DishSearchResults query={searchQuery} />
38+
) : (
39+
// 菜谱搜索结果
40+
<RecipeSearchResults query={searchQuery} />
41+
)} */}
42+
</ParallaxScrollView>
43+
);
44+
}
45+
46+
const styles = StyleSheet.create({
47+
container: {
48+
flex: 1,
49+
padding: 16
50+
},
51+
searchBar: {
52+
marginBottom: 16
53+
},
54+
segmentedButtons: {
55+
marginBottom: 16
56+
}
57+
});

apps/mobile/app/(auth)/_layout.tsx

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,67 @@
11
import { StackHeader } from '@/components/navigation';
2+
import { CaptchaType } from '@/types';
23
import { Stack } from 'expo-router';
3-
import { useTranslation } from 'react-i18next';
4+
import { createContext, useContext, useState } from 'react';
5+
6+
const AuthFlowContext = createContext<{
7+
registerType: 'admin' | 'member';
8+
setRegisterType: (type: 'admin' | 'member') => void;
9+
captchaType: CaptchaType;
10+
setCaptchaType: (type: CaptchaType) => void;
11+
email: string;
12+
setEmail: (email: string) => void;
13+
captcha: string;
14+
setCaptcha: (captcha: string) => void;
15+
}>({
16+
registerType: 'admin',
17+
setRegisterType: () => {},
18+
captchaType: CaptchaType.REGISTER,
19+
setCaptchaType: () => {},
20+
email: '',
21+
setEmail: () => {},
22+
captcha: '',
23+
setCaptcha: () => {}
24+
});
25+
26+
export function useAuthFlowContext() {
27+
const value = useContext(AuthFlowContext);
28+
if (!value) {
29+
throw new Error('useAuthFlowContext must be used within a AuthFlowContext.Provider');
30+
}
31+
return value;
32+
}
433

534
export default function AuthLayout() {
6-
const { t } = useTranslation();
35+
const [registerType, setRegisterType] = useState<'admin' | 'member'>('admin');
36+
const [captchaType, setCaptchaType] = useState<CaptchaType>(CaptchaType.REGISTER);
37+
const [email, setEmail] = useState('');
38+
const [captcha, setCaptcha] = useState('');
739

840
return (
9-
<Stack
10-
screenOptions={{
11-
animation: 'slide_from_right',
12-
header: (props) => <StackHeader navProps={props} children={undefined} />
41+
<AuthFlowContext.Provider
42+
value={{
43+
registerType,
44+
setRegisterType,
45+
captchaType,
46+
setCaptchaType,
47+
email,
48+
setEmail,
49+
captcha,
50+
setCaptcha
1351
}}
1452
>
15-
<Stack.Screen name="guide" options={{ headerShown: false }} />
16-
<Stack.Screen name="create-kitchen" options={{ title: '' }} />
17-
<Stack.Screen name="join-kitchen" options={{ title: '' }} />
18-
<Stack.Screen name="sign-in" options={{ title: t('auth.signIn.title') }} />
19-
</Stack>
53+
<Stack
54+
screenOptions={{
55+
animation: 'slide_from_right',
56+
header: (props) => <StackHeader navProps={props} children={undefined} />
57+
}}
58+
>
59+
<Stack.Screen name="guide" options={{ headerShown: false }} />
60+
<Stack.Screen name="sign-in" options={{ title: '' }} />
61+
<Stack.Screen name="sign-up" options={{ title: '' }} />
62+
<Stack.Screen name="captcha" options={{ title: '' }} />
63+
<Stack.Screen name="set-password" options={{ title: '' }} />
64+
</Stack>
65+
</AuthFlowContext.Provider>
2066
);
2167
}

0 commit comments

Comments
 (0)