Onboarding flow

This commit is contained in:
2026-07-06 22:25:52 +02:00
parent 99cd885833
commit 6b57a2acfc
37 changed files with 1503 additions and 507 deletions

View File

@@ -2,13 +2,13 @@ import React, { useEffect } from 'react';
import {
Image,
ImageBackground,
SafeAreaView,
StyleSheet,
Text,
TouchableOpacity,
View,
useWindowDimensions,
} from 'react-native';
import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';
import { Ionicons } from '@expo/vector-icons';
import { router } from 'expo-router';
import { useApp } from '../context/AppContext';
@@ -61,6 +61,7 @@ export default function OnboardingScreen() {
const compact = height < 700;
const posthog = useSafeAnalytics();
const copy = getWelcomeCopy(language);
const insets = useSafeAreaInsets();
useEffect(() => {
posthog.capture('onboarding_welcome_viewed');
@@ -68,14 +69,13 @@ export default function OnboardingScreen() {
return (
<View style={styles.container}>
<ImageBackground
source={require('../assets/welcome_botanical_hero.png')}
style={[styles.hero, { height: compact ? '48%' : '55%' }]}
imageStyle={styles.heroImageContent}
<Image
source={require('../assets/welcome_hero_vertical.png')}
style={[{ position: 'absolute', top: 0, left: 0, right: 0, width: '100%' }, { height: compact ? '65%' : '70%' }]}
resizeMode="cover"
>
<View style={styles.heroShadeTop} />
<SafeAreaView style={styles.heroSafe}>
/>
<View style={[{ width: '100%' }, { height: compact ? '48%' : '52%' }]}>
<View style={[styles.heroSafe, { paddingTop: Math.max(insets.top, 16) }]}>
<View style={styles.heroTopRow}>
<View style={styles.brandRow}>
<Image
@@ -104,12 +104,13 @@ export default function OnboardingScreen() {
</View>
</View>
</View>
</SafeAreaView>
</ImageBackground>
</View>
</View>
<View style={styles.sheet}>
<View style={styles.sheetHandle} />
<View style={styles.sheetContent}>
<View style={styles.topSpacer} />
<Text style={[styles.headline, compact && styles.headlineCompact]}>{copy.headline}</Text>
<Text style={styles.subline}>{copy.subline}</Text>
@@ -131,7 +132,7 @@ export default function OnboardingScreen() {
</TouchableOpacity>
<TouchableOpacity onPress={() => router.push('/scanner')} style={styles.demoLink}>
<Ionicons name="scan-outline" size={16} color="#4b7c31" />
<Ionicons name="scan-outline" size={18} color="#a6d66f" />
<Text style={styles.demoText}>{copy.demoScan}</Text>
</TouchableOpacity>
@@ -164,14 +165,14 @@ const styles = StyleSheet.create({
heroSafe: {
flex: 1,
justifyContent: 'space-between',
paddingHorizontal: 20,
paddingTop: 8,
paddingBottom: 24,
paddingHorizontal: 24,
paddingBottom: 32,
},
heroTopRow: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
width: '100%',
},
brandRow: {
flexDirection: 'row',
@@ -190,18 +191,18 @@ const styles = StyleSheet.create({
fontWeight: '900',
},
brandAccent: {
color: '#a6d66f',
color: '#8ba885',
},
ratingPill: {
flexDirection: 'row',
alignItems: 'center',
gap: 5,
backgroundColor: 'rgba(255,255,255,0.18)',
gap: 6,
backgroundColor: 'rgba(0, 0, 0, 0.55)',
borderWidth: 1,
borderColor: 'rgba(255,255,255,0.3)',
borderColor: 'rgba(255,255,255,0.25)',
borderRadius: 999,
paddingHorizontal: 12,
paddingVertical: 6,
paddingHorizontal: 14,
paddingVertical: 8,
},
ratingText: {
color: '#ffffff',
@@ -209,20 +210,23 @@ const styles = StyleSheet.create({
fontWeight: '700',
},
testimonialCard: {
backgroundColor: 'rgba(255,255,255,0.97)',
backgroundColor: 'rgba(16, 26, 18, 0.75)',
borderRadius: 16,
padding: 16,
borderWidth: 1,
borderColor: 'rgba(255, 255, 255, 0.08)',
shadowColor: '#000',
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.18,
shadowOpacity: 0.25,
shadowRadius: 14,
elevation: 4,
marginBottom: 8,
},
testimonialCardCompact: {
padding: 12,
},
testimonialText: {
color: '#191d16',
color: '#ffffff',
fontSize: 14.5,
lineHeight: 20,
fontStyle: 'italic',
@@ -234,7 +238,7 @@ const styles = StyleSheet.create({
justifyContent: 'space-between',
},
testimonialAuthor: {
color: '#42493c',
color: '#a6d66f',
fontSize: 13,
fontWeight: '700',
},
@@ -244,17 +248,19 @@ const styles = StyleSheet.create({
},
sheet: {
flex: 1,
backgroundColor: '#fbfaf3',
backgroundColor: '#0c160d',
borderTopLeftRadius: 28,
borderTopRightRadius: 28,
marginTop: -20,
borderWidth: 1,
borderColor: 'rgba(255, 255, 255, 0.05)',
},
sheetHandle: {
alignSelf: 'center',
width: 44,
height: 5,
borderRadius: 3,
backgroundColor: 'rgba(16,28,18,0.15)',
backgroundColor: 'rgba(255,255,255,0.2)',
marginTop: 12,
marginBottom: 8,
},
@@ -264,8 +270,11 @@ const styles = StyleSheet.create({
paddingTop: 8,
paddingBottom: 12,
},
topSpacer: {
height: 12,
},
headline: {
color: '#101c12',
color: '#ffffff',
fontSize: 28,
lineHeight: 34,
fontWeight: '900',
@@ -277,15 +286,14 @@ const styles = StyleSheet.create({
lineHeight: 29,
},
subline: {
color: '#5f625d',
color: '#dae6d6',
fontSize: 16,
lineHeight: 22,
fontWeight: '500',
textAlign: 'center',
},
spacer: {
flex: 1,
minHeight: 12,
height: 18,
},
cta: {
height: 60,
@@ -305,7 +313,7 @@ const styles = StyleSheet.create({
paddingVertical: 10,
},
loginText: {
color: '#437824',
color: '#a6d66f',
fontSize: 15,
fontWeight: '800',
},
@@ -313,17 +321,22 @@ const styles = StyleSheet.create({
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
gap: 7,
paddingVertical: 6,
marginBottom: 8,
gap: 8,
height: 52,
borderRadius: 14,
borderWidth: 1.5,
borderColor: '#a6d66f',
backgroundColor: 'rgba(166, 214, 111, 0.05)',
marginVertical: 8,
marginBottom: 12,
},
demoText: {
color: '#4b7c31',
fontSize: 13.5,
color: '#a6d66f',
fontSize: 15,
fontWeight: '700',
},
legal: {
color: '#6b6d68',
color: '#8d9382',
fontSize: 11,
lineHeight: 14,
fontWeight: '500',