Skip to content

Commit 384f2a9

Browse files
committed
Add CardCarousel component and enhance onboarding screen animations
1 parent 2bd8e18 commit 384f2a9

File tree

3 files changed

+223
-79
lines changed

3 files changed

+223
-79
lines changed

assets/images/avatar.jpg

771 KB
Loading

src/components/card-carousel.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { View } from "react-native"
2+
3+
4+
export const CardCarousel = () => {
5+
return (
6+
<View>
7+
8+
</View>
9+
)
10+
}

src/screens/onboarding-screen.tsx

Lines changed: 213 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { LinearGradient } from 'expo-linear-gradient';
22
import React from 'react';
3-
import { Dimensions, Image, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
4-
import Animated, { FadeInDown, FadeInUp } from 'react-native-reanimated';
3+
import { Dimensions, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
4+
import Animated, { FadeInDown } from 'react-native-reanimated';
55
import { useSafeAreaInsets } from 'react-native-safe-area-context';
6+
import { CardCarousel } from '../components/card-carousel';
67

78
const { width } = Dimensions.get('window');
89
const CARD_WIDTH = width * 0.35;
@@ -15,6 +16,123 @@ export const OnboardingScreen = () => {
1516
const text2 = "friends"
1617
const text3 = "want"
1718

19+
const coordinates1 = [
20+
[
21+
{
22+
x: -80,
23+
y: 40
24+
},
25+
{
26+
x: -60,
27+
y: 200
28+
},
29+
{
30+
x: 100,
31+
y: 220
32+
},
33+
],
34+
[
35+
{
36+
x: -120,
37+
y: -40
38+
},
39+
{
40+
x: 140,
41+
y: 140
42+
},
43+
{
44+
x: 170,
45+
y: 170
46+
},
47+
{
48+
x: 190,
49+
y: 190
50+
}
51+
],
52+
[
53+
{
54+
x: 120,
55+
y: 160
56+
},
57+
{
58+
x: 160,
59+
y: 220
60+
},
61+
{
62+
x: -80,
63+
y: 180
64+
},
65+
{
66+
x: 150,
67+
y: 240
68+
},]
69+
70+
]
71+
const coordinates2 = [
72+
{
73+
x: -80,
74+
y: 40
75+
},
76+
{
77+
x: -60,
78+
y: 200
79+
},
80+
{
81+
x: 100,
82+
y: 220
83+
},
84+
{
85+
x: -120,
86+
y: -40
87+
},
88+
{
89+
x: 140,
90+
y: 140
91+
},
92+
{
93+
x: 170,
94+
y: 170
95+
},
96+
{
97+
x: 190,
98+
y: 190
99+
},
100+
]
101+
const coordinates3 = [
102+
{
103+
x: 120,
104+
y: 160
105+
},
106+
{
107+
x: 160,
108+
y: 220
109+
},
110+
{
111+
x: -80,
112+
y: 180
113+
},
114+
{
115+
x: 150,
116+
y: 240
117+
},
118+
]
119+
const coordinates4 = [
120+
{
121+
x: -60,
122+
y: 120
123+
},
124+
{
125+
x: 100,
126+
y: 140
127+
},
128+
{
129+
x: 200,
130+
y: 140
131+
},
132+
]
133+
134+
135+
18136
const avatars = [
19137
require('@/assets/images/avatar.jpg'),
20138
require('@/assets/images/avatar.jpg'),
@@ -25,20 +143,35 @@ export const OnboardingScreen = () => {
25143
<LinearGradient
26144
colors={['#e0d4f2ff', '#FFFFFF', '#E8F5E9']}
27145
locations={[0, 0.55, 1]}
28-
style={[styles.container, { paddingBottom: bottom + 20, paddingTop: top + 20 }]}
146+
style={[styles.container, { paddingBottom: bottom + 8, paddingTop: top + 20 }]}
29147
>
30-
<Animated.View entering={FadeInDown.delay(100).springify()}>
148+
<Animated.View entering={FadeInDown.duration(800).springify()}>
31149
<Text style={styles.headerTitle}>GIFTER</Text>
32150
</Animated.View>
33151

34-
<View style={styles.contentContainer}>
35-
<Animated.View style={[styles.rowCenter, {columnGap: 4}]}>
152+
<Animated.View style={[styles.contentContainer, {
153+
animationName: {
154+
from: { opacity: 0 },
155+
to: { opacity: 1 },
156+
},
157+
animationDuration: '800ms',
158+
animationTimingFunction: "ease-in-out",
159+
}]}>
160+
<Animated.View style={[styles.rowCenter, { columnGap: 4 }]}>
36161
{text1.split(" ").map((word, index) => (
37-
<View key={index} style={{flexDirection: 'row', alignItems: 'center'}}>
162+
<View key={index} style={{ flexDirection: 'row', alignItems: 'center' }}>
38163
{word.split("").map((char, charIndex) => (
39164
<Animated.Text
40165
key={charIndex}
41-
style={styles.title}
166+
style={[styles.title, {
167+
animationName: {
168+
from: { transform: [{ translateY: coordinates1[index][charIndex].y }, { translateX: coordinates1[index][charIndex].x }, { scale: 3 }] },
169+
to: { transform: [{ translateY: 0 }, { translateX: 0 }, { scale: 1 }] },
170+
},
171+
animationDuration: '800ms',
172+
animationTimingFunction: "ease-in-out",
173+
animationFillMode: 'forwards',
174+
}]}
42175
>
43176
{char}
44177
</Animated.Text>
@@ -47,15 +180,25 @@ export const OnboardingScreen = () => {
47180
))}
48181
</Animated.View>
49182
<Animated.View
50-
style={{
51-
flexDirection: "row",
52-
alignItems: 'center',
53-
}}
183+
style={styles.rowCenter}
54184
>
55-
<Animated.Text style={styles.title}>
56-
{text2}
57-
</Animated.Text>
58-
<Animated.View style={{flexDirection: 'row', alignItems: "center", marginHorizontal: 2}}>
185+
{text2.split("").map((char, charIndex) => (
186+
<Animated.Text
187+
key={charIndex}
188+
style={[styles.title, {
189+
animationName: {
190+
from: { transform: [{ translateY: coordinates2[charIndex].y }, { translateX: coordinates2[charIndex].x }, { scale: 3 }] },
191+
to: { transform: [{ translateY: 0 }, { translateX: 0 }, { scale: 1 }] },
192+
},
193+
animationDuration: '800ms',
194+
animationTimingFunction: "ease-in-out",
195+
animationFillMode: 'forwards',
196+
}]}
197+
>
198+
{char}
199+
</Animated.Text>
200+
))}
201+
<Animated.View style={{ flexDirection: 'row', alignItems: "center", marginHorizontal: 2 }}>
59202
{avatars.map((avatar, index) => (
60203
<Animated.Image
61204
key={index}
@@ -67,82 +210,73 @@ export const OnboardingScreen = () => {
67210
marginLeft: index === 0 ? 0 : -10,
68211
borderWidth: 1,
69212
borderColor: '#fff',
213+
animationName: {
214+
from: { transform: [{ translateY: coordinates4[index].y }, { translateX: coordinates4[index].x }, { scale: 3 }] },
215+
to: { transform: [{ translateY: 0 }, { translateX: 0 }, { scale: 1 }] },
216+
},
217+
animationDuration: '800ms',
218+
animationTimingFunction: "ease-in-out",
219+
animationFillMode: 'forwards',
220+
70221
}}
71222
resizeMode="cover"
72223
/>
73224
))}
74225
</Animated.View>
75-
<Animated.Text style={styles.title}>
76-
{text3}
77-
</Animated.Text>
226+
{text3.split("").map((char, charIndex) => (
227+
<Animated.Text
228+
key={charIndex}
229+
style={[styles.title, {
230+
animationName: {
231+
from: { transform: [{ translateY: coordinates3[charIndex].y }, { translateX: coordinates3[charIndex].x }, { scale: 3 }] },
232+
to: { transform: [{ translateY: 0 }, { translateX: 0 }, { scale: 1 }] },
233+
},
234+
animationDuration: '800ms',
235+
animationTimingFunction: "ease-in-out",
236+
animationFillMode: 'forwards',
237+
}]}
238+
>
239+
{char}
240+
</Animated.Text>
241+
))}
78242
</Animated.View>
79243
<Animated.View>
80-
<Text style={styles.subtitle}>
244+
<Animated.Text style={[styles.subtitle, {
245+
animationName: {
246+
from: { transform: [{ translateY: 200 }, { translateX: 0 }, { scale: 2 }] },
247+
to: { transform: [{ translateY: 0 }, { translateX: 0 }, { scale: 1 }] },
248+
},
249+
animationDuration: '800ms',
250+
animationTimingFunction: "ease-in-out",
251+
}]}>
81252
Your friends' wish lists are waiting{'\n'}— sneak a look and spread the joy!
82-
</Text>
253+
</Animated.Text>
83254
</Animated.View>
84255

85256
{/* Cards Carousel */}
86-
<Animated.View
87-
style={styles.carouselContainer}
88-
entering={FadeInUp.delay(400).springify()}
89-
>
90-
{/* Left Card (Partial) */}
91-
<View style={[styles.card, styles.cardLeft, { transform: [{ scale: 0.85 }] }]}>
92-
<Image
93-
source={require('@/assets/images/avatar.jpg')}
94-
style={styles.cardImage}
95-
resizeMode="cover"
96-
/>
97-
</View>
98-
99-
{/* Center Card */}
100-
<View style={[styles.card, styles.cardCenter]}>
101-
<Image
102-
source={require('@/assets/images/avatar.jpg')}
103-
style={styles.cardImage}
104-
resizeMode="cover"
105-
/>
106-
</View>
107-
108-
{/* Right Card */}
109-
<View style={[styles.card, styles.cardRight, { transform: [{ scale: 0.9 }] }]}>
110-
<View style={styles.giftCardContent}>
111-
<Text style={styles.giftCardTitle}>Gift your{'\n'}Friends</Text>
112-
<View style={styles.giftCardImages}>
113-
<Image
114-
source={require('@/assets/images/avatar.jpg')}
115-
style={styles.smallAvatar}
116-
resizeMode="cover"
117-
/>
118-
</View>
119-
</View>
120-
</View>
121-
122-
{/* Rightmost Card (Partial) */}
123-
<View style={[styles.card, styles.cardRightmost, { transform: [{ scale: 0.85 }] }]}>
124-
<View
125-
style={styles.createCardContent}>
126-
<Text style={styles.createCardTitle}>Create{'\n'}your list</Text>
127-
</View>
128-
</View>
129-
</Animated.View>
130-
</View>
257+
<CardCarousel />
258+
</Animated.View>
131259

132260
{/* Bottom Buttons */}
133261
<Animated.View
134-
style={styles.buttonContainer}
135-
entering={FadeInUp.delay(600).springify()}
262+
style={[styles.buttonContainer, {
263+
animationName: {
264+
from: { transform: [{ translateY: 100 }, { translateX: 0 }, { scale: 1 }] },
265+
to: { transform: [{ translateY: 0 }, { translateX: 0 }, { scale: 1 }] },
266+
},
267+
animationDuration: '600ms',
268+
animationTimingFunction: "ease-in-out",
269+
}]}
136270
>
137-
<TouchableOpacity style={styles.buttonSecondary}>
138-
<Text style={styles.buttonSecondaryText}>Find Friends</Text>
139-
</TouchableOpacity>
271+
<TouchableOpacity style={styles.buttonSecondary}>
272+
<Text style={styles.buttonSecondaryText}>Find Friends</Text>
273+
</TouchableOpacity>
140274

141-
<TouchableOpacity style={styles.buttonPrimary}>
142-
<Text style={styles.buttonPrimaryText}>Create an account</Text>
143-
</TouchableOpacity>
144-
</Animated.View>
145-
</LinearGradient>
275+
<TouchableOpacity style={styles.buttonPrimary}>
276+
<Text style={styles.buttonPrimaryText}>Create an account</Text>
277+
</TouchableOpacity>
278+
</Animated.View>
279+
</LinearGradient >
146280
);
147281
};
148282

@@ -151,7 +285,6 @@ const styles = StyleSheet.create({
151285
flex: 1,
152286
},
153287
rowCenter: {
154-
justifyContent: 'center',
155288
alignItems: 'center',
156289
flexDirection: 'row',
157290
},
@@ -175,7 +308,7 @@ const styles = StyleSheet.create({
175308
},
176309
title: {
177310
fontFamily: 'Piepia W01 Regular',
178-
fontSize: 32,
311+
fontSize: 28,
179312
color: '#002434',
180313
textAlign: 'center',
181314
lineHeight: 36,
@@ -184,10 +317,11 @@ const styles = StyleSheet.create({
184317
fontSize: 32,
185318
},
186319
subtitle: {
187-
fontSize: 15,
320+
fontSize: 14,
188321
color: '#002434',
189322
textAlign: 'center',
190323
fontWeight: '500',
324+
marginTop: 12,
191325
},
192326
carouselContainer: {
193327
flexDirection: 'row',

0 commit comments

Comments
 (0)