Files
Brief-app/app/(tabs)/index.tsx
2026-07-20 15:08:07 +02:00

153 lines
5.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useRouter } from 'expo-router';
import { Pressable, ScrollView, StyleSheet, Text, View } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { DitherBackground } from '../../src/components/DitherBackground';
import { CameraIcon } from '../../src/components/Icons';
import { LetterRow } from '../../src/components/LetterRow';
import { letters } from '../../src/data/letters';
import { colors, font, glow, radius, shadow, space } from '../../src/theme';
/** Home, design option 4b: the scan card carries the dither gradient. */
export default function Home() {
const router = useRouter();
const insets = useSafeAreaInsets();
const openDeadline = letters.find((l) => l.deadlineDays !== undefined);
return (
<View style={styles.screen}>
<ScrollView
contentContainerStyle={{ paddingTop: insets.top + 24, paddingBottom: 24 }}
showsVerticalScrollIndicator={false}
>
<View style={styles.header}>
<Text style={styles.greeting}>Hallo Lena!</Text>
<Text style={styles.greetingSub}>Ein neuer Brief? Kein Stress wir helfen dir.</Text>
</View>
<Pressable
style={({ pressed }) => [styles.scanCard, pressed && styles.pressed]}
onPress={() => router.push('/scan')}
accessibilityRole="button"
accessibilityLabel="Brief scannen"
>
<DitherBackground
color1={colors.blueDeep}
color2={colors.blueHaze}
speed={1}
pixel={2.5}
style={styles.scanCardBg}
/>
<View style={styles.scanCardRow}>
<View style={styles.scanIcon}>
<CameraIcon size={28} />
</View>
<View style={styles.scanCardText}>
<Text style={styles.scanTitle}>Brief scannen</Text>
<Text style={styles.scanSub}>Foto machen, fertig!</Text>
</View>
</View>
<View style={styles.scanCta}>
<Text style={styles.scanCtaLabel}>Los geht's</Text>
</View>
</Pressable>
<View style={styles.stats}>
<View style={styles.stat}>
<Text style={[styles.statNumber, { color: colors.blueDeep }]}>
{letters.filter((l) => l.deadlineDays !== undefined).length}
</Text>
<Text style={styles.statLabel}>Frist offen</Text>
<Text style={styles.statHint}>
{openDeadline ? `noch ${openDeadline.deadlineDays} Tage` : 'alles erledigt'}
</Text>
</View>
<View style={styles.stat}>
<Text style={[styles.statNumber, { color: colors.blueSoft }]}>{letters.length}</Text>
<Text style={styles.statLabel}>Briefe erklärt</Text>
<Text style={styles.statHint}>alles im Archiv</Text>
</View>
</View>
<View style={styles.listHeader}>
<Text style={styles.listTitle}>Deine Briefe</Text>
<Pressable onPress={() => router.push('/(tabs)/archive')} hitSlop={10}>
<Text style={styles.listAll}>Alle </Text>
</Pressable>
</View>
<View style={styles.list}>
{letters.slice(0, 2).map((letter) => (
<LetterRow key={letter.id} letter={letter} />
))}
</View>
</ScrollView>
</View>
);
}
const styles = StyleSheet.create({
screen: { flex: 1, backgroundColor: colors.canvas },
pressed: { opacity: 0.9 },
header: { paddingHorizontal: space.gutter },
greeting: { fontFamily: font.serif, fontSize: 28, letterSpacing: -0.5, color: colors.ink },
greetingSub: { fontFamily: font.semibold, fontSize: 15, color: colors.slate, marginTop: 3 },
scanCard: {
marginHorizontal: space.gutter,
marginTop: 20,
borderRadius: radius['4xl'],
paddingVertical: 26,
paddingHorizontal: 24,
overflow: 'hidden',
backgroundColor: colors.blueDeep,
...shadow.blueCard,
},
scanCardBg: { borderRadius: radius['4xl'] },
scanCardRow: { flexDirection: 'row', alignItems: 'center', gap: 14 },
scanIcon: {
width: 56,
height: 56,
borderRadius: 28,
backgroundColor: 'rgba(255,255,255,0.22)',
alignItems: 'center',
justifyContent: 'center',
},
scanCardText: { flex: 1 },
scanTitle: { fontFamily: font.display, fontSize: 22, color: colors.onBlue, ...glow },
scanSub: { fontFamily: font.bold, fontSize: 14, color: colors.onBlue, marginTop: 2, ...glow },
scanCta: {
marginTop: 18,
backgroundColor: '#FFFFFF',
borderRadius: radius.lg,
paddingVertical: 14,
alignItems: 'center',
},
scanCtaLabel: { fontFamily: font.extrabold, fontSize: 16, color: colors.blueDeep },
stats: { flexDirection: 'row', gap: 10, marginHorizontal: space.gutter, marginTop: 14 },
stat: {
flex: 1,
backgroundColor: colors.surface,
borderRadius: radius['2xl'],
paddingVertical: 14,
paddingHorizontal: 16,
...shadow.card,
},
statNumber: { fontFamily: font.display, fontSize: 22 },
statLabel: { fontFamily: font.bold, fontSize: 12.5, color: colors.ink, marginTop: 2 },
statHint: { fontFamily: font.regular, fontSize: 11.5, color: colors.slate },
listHeader: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'baseline',
paddingHorizontal: space.gutter,
marginTop: 22,
},
listTitle: { fontFamily: font.display, fontSize: 17, color: colors.ink },
listAll: { fontFamily: font.extrabold, fontSize: 13, color: colors.blueDeep },
list: { gap: 9, paddingHorizontal: space.gutter, marginTop: 12 },
});