Screens & Navigation
Navigation Structure
CalorieBeat uses Expo Router for file-based routing, providing type-safe navigation and automatic deep linking.
Bottom Tab Navigation
The main app interface uses bottom tabs for primary navigation:
1. Home Tab
Icon: Home
Route: /(tabs)/index
Purpose: Activity feed and dashboard
2. Analytics Tab
Icon: Bar Chart
Route: /(tabs)/analytics
Purpose: Progress charts and insights
3. Add Post (Center, Elevated)
Icon: Plus (Large, Elevated)
Route: /(tabs)/add-post
Purpose: Quick capture via camera
4. Profile Tab
Icon: User
Route: /(tabs)/profile
Purpose: User profile and settings
Authentication Stack
Before entering the main app, users go through authentication:
Landing Screen
Route: /
- App introduction
- Key features showcase
- Sign Up / Login buttons
Login Screen
Route: /(auth)/login
- Google Sign-In
- Apple Sign-In
- Email / Magic Link
- Create Account link
Onboarding Flow
Routes: /(onboarding)/step-[1-11]
11-step personalized onboarding:
- Gender Selection
- Date of Birth
- Workout Frequency
- Referral Source
- Height & Weight
- Weight Goal
- Weight Loss Speed
- Timeframe
- Calorie Tracking Preference
- Dietary Preference
- Desired Weight Confirmation
Modal Stacks
Modals appear over the main interface for focused tasks:
Food Entry Modal
Route: /(tabs)/add-post/food
- AI photo analysis or manual entry
- Food selection and portions
- Save to log
Workout Entry Modal
Route: /(tabs)/add-post/workout
- AI photo analysis or manual entry
- Exercise selection
- Duration and intensity
- Save to log
Settings Modal
Route: /settings
- Theme preferences
- Notifications
- Privacy settings
- Account management
Subscription Modal
Route: /subscription
- Plan comparison
- Payment processing
- Subscription management
File-Based Routing
Routes are automatically generated from the app/ directory structure:
app/
├── index.tsx # Landing page
├── _layout.tsx # Root layout
│
├── (auth)/ # Auth stack
│ ├── _layout.tsx # Auth layout
│ ├── login.tsx # Login screen
│ └── signup.tsx # Signup screen
│
├── (onboarding)/ # Onboarding stack
│ ├── _layout.tsx # Onboarding layout
│ ├── step-1.tsx # Gender
│ ├── step-2.tsx # DOB
│ ├── step-3.tsx # Workout frequency
│ ├── step-4.tsx # Referral
│ ├── step-5.tsx # Height & Weight
│ ├── step-6.tsx # Goal weight
│ ├── step-7.tsx # Speed
│ ├── step-8.tsx # Timeframe
│ ├── step-9.tsx # Calorie tracking
│ ├── step-10.tsx # Dietary preference
│ └── step-11.tsx # Confirmation
│
└── (tabs)/ # Main app tabs
├── _layout.tsx # Tab layout
├── index.tsx # Home feed
├── analytics.tsx # Analytics
├── profile.tsx # Profile
│
└── add-post/ # Add post screens
├── _layout.tsx # Add post layout
├── index.tsx # Method selection
├── food.tsx # Food entry
└── workout.tsx # Workout entryNavigation Patterns
Push Navigation
Navigate to a new screen:
import { router } from 'expo-router';
router.push('/analytics');Replace Navigation
Replace current screen:
router.replace('/(tabs)');Go Back
Return to previous screen:
router.back();Modal Presentation
Present as modal:
router.push({
pathname: '/settings',
params: { presentation: 'modal' }
});Deep Linking
Expo Router automatically handles deep links:
caloriebeat://analytics
caloriebeat://profile/edit
caloriebeat://add-post/foodUniversal Links (iOS):
https://caloriebeat.com/analyticsApp Links (Android):
https://caloriebeat.com/profileScreen Transitions
Default Transitions
- iOS: Slide from right
- Android: Slide from bottom
Custom Animations
<Stack.Screen
name="modal"
options={{
presentation: 'modal',
animation: 'slide_from_bottom'
}}
/>Navigation Guards
Authentication Guard
Protects routes requiring authentication:
if (!user) {
router.replace('/login');
return null;
}Onboarding Guard
Redirects incomplete onboarding:
if (!profile.onboarding_complete) {
router.replace('/(onboarding)/step-1');
return null;
}Subscription Guard
Checks premium features:
if (!isPremium && requiresPremium) {
router.push('/subscription');
return null;
}Tab Bar Customization
<Tabs
screenOptions={{
tabBarActiveTintColor: colors.primary,
tabBarInactiveTintColor: colors.textSecondary,
tabBarStyle: {
backgroundColor: colors.surface,
borderTopColor: colors.border
}
}}
>
<Tabs.Screen
name="index"
options={{
title: 'Home',
tabBarIcon: ({ color }) => <Home color={color} />
}}
/>
{/* ... other tabs */}
</Tabs>Header Configuration
<Stack.Screen
name="analytics"
options={{
title: 'Analytics',
headerShown: true,
headerStyle: {
backgroundColor: colors.surface
},
headerTitleStyle: {
color: colors.text
}
}}
/>