/** * TabataFit Browse Screen * React Native UI — wired to shared data */ import { View, StyleSheet, ScrollView, Pressable, Dimensions, Text as RNText } from 'react-native' import { useRouter } from 'expo-router' import { useSafeAreaInsets } from 'react-native-safe-area-context' import { LinearGradient } from 'expo-linear-gradient' import { BlurView } from 'expo-blur' import Ionicons from '@expo/vector-icons/Ionicons' import { useHaptics } from '@/src/shared/hooks' import { COLLECTIONS, PROGRAMS, getFeaturedCollection, COLLECTION_COLORS, WORKOUTS, getTrainerById, } from '@/src/shared/data' import { StyledText } from '@/src/shared/components/StyledText' import { BRAND, DARK, TEXT, GLASS, SHADOW, } from '@/src/shared/constants/colors' import { SPACING, LAYOUT } from '@/src/shared/constants/spacing' import { RADIUS } from '@/src/shared/constants/borderRadius' const { width: SCREEN_WIDTH } = Dimensions.get('window') const FONTS = { LARGE_TITLE: 34, TITLE: 28, TITLE_2: 22, HEADLINE: 17, SUBHEADLINE: 15, CAPTION_1: 12, CAPTION_2: 11, } function TextButton({ children, onPress }: { children: string; onPress?: () => void }) { return ( {children} ) } // New Releases: last 4 workouts const NEW_RELEASES = WORKOUTS.slice(-4) // ═══════════════════════════════════════════════════════════════════════════ // MAIN SCREEN // ═══════════════════════════════════════════════════════════════════════════ export default function BrowseScreen() { const insets = useSafeAreaInsets() const router = useRouter() const haptics = useHaptics() const featuredCollection = getFeaturedCollection() const handleWorkoutPress = (id: string) => { haptics.buttonTap() router.push(`/workout/${id}`) } const handleCollectionPress = (id: string) => { haptics.buttonTap() router.push(`/collection/${id}`) } return ( {/* Header */} Browse {/* Featured Collection */} {featuredCollection && ( handleCollectionPress(featuredCollection.id)}> FEATURED {featuredCollection.title} {featuredCollection.description} {featuredCollection.workoutIds.length + ' workouts'} )} {/* Collections Grid */} Collections {COLLECTIONS.map((collection) => { const color = COLLECTION_COLORS[collection.id] ?? BRAND.PRIMARY return ( handleCollectionPress(collection.id)} > {collection.icon} {collection.title} {collection.workoutIds.length + ' workouts'} ) })} {/* Programs */} Programs See All {PROGRAMS.map((program) => ( {program.level} {program.title} {program.weeks + ' weeks'} {program.workoutsPerWeek + 'x /week'} ))} {/* New Releases */} New Releases {NEW_RELEASES.map((workout) => { const trainer = getTrainerById(workout.trainerId) return ( handleWorkoutPress(workout.id)} > {trainer?.name[0] ?? 'T'} {workout.title} {(trainer?.name ?? '') + ' \u00B7 ' + workout.duration + ' min \u00B7 ' + workout.level} ) })} ) } // ═══════════════════════════════════════════════════════════════════════════ // STYLES // ═══════════════════════════════════════════════════════════════════════════ const COLLECTION_CARD_WIDTH = (SCREEN_WIDTH - LAYOUT.SCREEN_PADDING * 2 - SPACING[3]) / 2 const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: DARK.BASE, }, scrollView: { flex: 1, }, scrollContent: { paddingHorizontal: LAYOUT.SCREEN_PADDING, }, // Featured Collection featuredCard: { height: 200, borderRadius: RADIUS.GLASS_CARD, overflow: 'hidden', marginBottom: SPACING[8], marginTop: SPACING[4], ...SHADOW.lg, }, featuredBadge: { flexDirection: 'row', alignItems: 'center', backgroundColor: 'rgba(0, 0, 0, 0.3)', paddingHorizontal: SPACING[2], paddingVertical: SPACING[1], borderRadius: RADIUS.SM, alignSelf: 'flex-start', margin: SPACING[4], gap: SPACING[1], }, featuredBadgeText: { fontSize: 11, fontWeight: 'bold', color: TEXT.PRIMARY, }, featuredInfo: { position: 'absolute', bottom: SPACING[5], left: SPACING[5], right: SPACING[5], }, featuredStats: { flexDirection: 'row', gap: SPACING[4], marginTop: SPACING[3], }, featuredStat: { flexDirection: 'row', alignItems: 'center', gap: SPACING[1], }, // Section section: { marginBottom: SPACING[6], }, sectionHeader: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', marginBottom: SPACING[4], }, // Collections Grid collectionsGrid: { flexDirection: 'row', flexWrap: 'wrap', gap: SPACING[3], marginTop: SPACING[3], }, collectionCard: { width: COLLECTION_CARD_WIDTH, paddingVertical: SPACING[4], paddingHorizontal: SPACING[3], borderRadius: RADIUS.LG, overflow: 'hidden', borderWidth: 1, borderColor: 'rgba(255, 255, 255, 0.1)', gap: SPACING[1], }, collectionIconBg: { width: 44, height: 44, borderRadius: 12, alignItems: 'center', justifyContent: 'center', marginBottom: SPACING[2], }, collectionEmoji: { fontSize: 22, }, // Programs programsScroll: { gap: SPACING[3], }, programCard: { width: 200, height: 140, borderRadius: RADIUS.LG, overflow: 'hidden', padding: SPACING[4], borderWidth: 1, borderColor: 'rgba(255, 255, 255, 0.1)', }, programHeader: { flexDirection: 'row', justifyContent: 'flex-end', marginBottom: SPACING[2], }, programLevelBadge: { backgroundColor: 'rgba(255, 107, 53, 0.2)', paddingHorizontal: SPACING[2], paddingVertical: SPACING[1], borderRadius: RADIUS.SM, }, programMeta: { flexDirection: 'row', gap: SPACING[3], marginTop: SPACING[3], }, programMetaItem: { flexDirection: 'row', alignItems: 'center', gap: SPACING[1], }, // New Releases releaseRow: { flexDirection: 'row', alignItems: 'center', paddingVertical: SPACING[3], paddingHorizontal: SPACING[4], backgroundColor: DARK.SURFACE, borderRadius: RADIUS.LG, marginBottom: SPACING[2], gap: SPACING[3], }, releaseAvatar: { width: 44, height: 44, borderRadius: 22, alignItems: 'center', justifyContent: 'center', }, releaseInitial: { fontSize: 18, fontWeight: '700', color: TEXT.PRIMARY, }, releaseInfo: { flex: 1, gap: 2, }, })