feat: add expo mobile application source code
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
import React, { useRef } from 'react';
|
||||
import {
|
||||
View, Text, StyleSheet, Image, TouchableOpacity, Dimensions, ScrollView, Animated, Platform
|
||||
} from 'react-native';
|
||||
import { useLocalSearchParams, useRouter } from 'expo-router';
|
||||
import { useAppTheme } from '../../context/ThemeContext';
|
||||
import { Feather } from '@expo/vector-icons';
|
||||
import { BlurView } from 'expo-blur';
|
||||
import * as Haptics from 'expo-haptics';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
|
||||
const { width } = Dimensions.get('window');
|
||||
const LIME = '#C6F135';
|
||||
const IMG_H = 340;
|
||||
|
||||
export default function DetailScreen() {
|
||||
const { id, title, category, img, author } = useLocalSearchParams();
|
||||
const { colors, isDark } = useAppTheme();
|
||||
const router = useRouter();
|
||||
const scrollY = useRef(new Animated.Value(0)).current;
|
||||
|
||||
const bg = isDark ? '#111111' : '#F5F5F5';
|
||||
const cardBg = isDark ? '#1A1A1A' : '#FFFFFF';
|
||||
const border = isDark ? '#2A2A2A' : '#EEEEEE';
|
||||
const subText = isDark ? '#6B6B6B' : '#9B9B9B';
|
||||
|
||||
const imageTranslateY = scrollY.interpolate({
|
||||
inputRange: [0, IMG_H],
|
||||
outputRange: [0, -IMG_H / 3],
|
||||
extrapolate: 'clamp'
|
||||
});
|
||||
|
||||
return (
|
||||
<View style={[styles.container, { backgroundColor: bg }]}>
|
||||
<Animated.ScrollView
|
||||
showsVerticalScrollIndicator={false}
|
||||
scrollEventThrottle={16}
|
||||
onScroll={Animated.event(
|
||||
[{ nativeEvent: { contentOffset: { y: scrollY } } }],
|
||||
{ useNativeDriver: true }
|
||||
)}
|
||||
>
|
||||
{/* ── Hero image with parallax ── */}
|
||||
<View style={styles.imageContainer}>
|
||||
<Animated.View style={[StyleSheet.absoluteFill, { transform: [{ translateY: imageTranslateY }] }]}>
|
||||
<Image source={{ uri: img as string }} style={styles.heroImg} />
|
||||
</Animated.View>
|
||||
<LinearGradient
|
||||
colors={['transparent', isDark ? '#111111' : '#F5F5F5']}
|
||||
style={styles.gradient}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* ── Content card ── */}
|
||||
<View style={[styles.contentCard, { backgroundColor: cardBg, borderColor: border }]}>
|
||||
<View style={styles.badgeRow}>
|
||||
<View style={[styles.catBadge, { backgroundColor: `${LIME}25` }]}>
|
||||
<Text style={styles.catBadgeText}>{category}</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<Text style={[styles.title, { color: colors.text }]}>{title}</Text>
|
||||
|
||||
<View style={[styles.authorRow, { borderBottomColor: border }]}>
|
||||
<Image
|
||||
source={{ uri: `https://i.pravatar.cc/100?u=${author}` }}
|
||||
style={styles.authorImg}
|
||||
/>
|
||||
<View>
|
||||
<Text style={[styles.authorName, { color: colors.text }]}>{author}</Text>
|
||||
<Text style={[styles.date, { color: subText }]}>Published 2 hours ago</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<Text style={[styles.paragraph, { color: subText }]}>
|
||||
This is a deep dive into the topic of{' '}
|
||||
<Text style={{ color: colors.text, fontFamily: 'Outfit_600SemiBold' }}>{title}</Text>.
|
||||
Implementing modern technologies requires a balance between performance and aesthetics.
|
||||
In biiproject, we prioritize the user experience by using the latest React Native features.
|
||||
</Text>
|
||||
<Text style={[styles.paragraph, { color: subText }]}>
|
||||
Our modernization engine ensures that every pixel is optimized, every transition is smooth,
|
||||
and every interaction feels alive with haptic feedback and fluid motion.
|
||||
</Text>
|
||||
|
||||
<View style={[styles.highlightBox, { backgroundColor: isDark ? '#222222' : '#F5F5F5' }]}>
|
||||
<Feather name="info" size={16} color={LIME} style={{ marginRight: 10 }} />
|
||||
<Text style={[styles.highlightText, { color: subText }]}>
|
||||
This content is curated by our AI engine and updated daily.
|
||||
</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View style={{ height: 120 }} />
|
||||
</Animated.ScrollView>
|
||||
|
||||
{/* ── Floating back button ── */}
|
||||
<TouchableOpacity
|
||||
style={styles.backBtn}
|
||||
onPress={() => { Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium); router.back(); }}
|
||||
>
|
||||
<BlurView intensity={40} tint="dark" style={styles.blurBtn}>
|
||||
<Feather name="chevron-left" size={22} color="#FFFFFF" />
|
||||
</BlurView>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: { flex: 1 },
|
||||
imageContainer: { width, height: IMG_H, overflow: 'hidden' },
|
||||
heroImg: { width: '100%', height: IMG_H + 60, resizeMode: 'cover' },
|
||||
gradient: { position: 'absolute', bottom: 0, left: 0, right: 0, height: 160 },
|
||||
contentCard: { marginHorizontal: 16, marginTop: -32, borderRadius: 28, borderWidth: 1, padding: 24, shadowColor: '#000', shadowOffset: { width: 0, height: 8 }, shadowOpacity: 0.08, shadowRadius: 20, elevation: 6 },
|
||||
badgeRow: { marginBottom: 12 },
|
||||
catBadge: { alignSelf: 'flex-start', paddingHorizontal: 10, paddingVertical: 4, borderRadius: 8 },
|
||||
catBadgeText: { fontSize: 10, fontFamily: 'Outfit_800ExtraBold', textTransform: 'uppercase', letterSpacing: 0.5, color: '#5A7000' },
|
||||
title: { fontSize: 26, fontFamily: 'Outfit_800ExtraBold', lineHeight: 34, marginBottom: 20 },
|
||||
authorRow: { flexDirection: 'row', alignItems: 'center', paddingBottom: 20, marginBottom: 20, borderBottomWidth: 1 },
|
||||
authorImg: { width: 42, height: 42, borderRadius: 21, marginRight: 12 },
|
||||
authorName: { fontSize: 15, fontFamily: 'Outfit_700Bold' },
|
||||
date: { fontSize: 12, fontFamily: 'Outfit_400Regular', marginTop: 2 },
|
||||
paragraph: { fontSize: 15, fontFamily: 'Outfit_400Regular', lineHeight: 26, marginBottom: 18 },
|
||||
highlightBox: { flexDirection: 'row', alignItems: 'flex-start', borderRadius: 14, padding: 14, marginTop: 6 },
|
||||
highlightText: { flex: 1, fontSize: 13, fontFamily: 'Outfit_400Regular', lineHeight: 20 },
|
||||
backBtn: { position: 'absolute', top: Platform.OS === 'ios' ? 52 : 32, left: 20, zIndex: 100 },
|
||||
blurBtn: { width: 44, height: 44, borderRadius: 22, alignItems: 'center', justifyContent: 'center', overflow: 'hidden' },
|
||||
});
|
||||
Reference in New Issue
Block a user