149 lines
5.1 KiB
TypeScript
149 lines
5.1 KiB
TypeScript
import { NavigationContainer } from '@react-navigation/native';
|
|
import { createNativeStackNavigator } from '@react-navigation/native-stack';
|
|
import { FontAwesomeIcon } from '@fortawesome/react-native-fontawesome';
|
|
import { faBars } from '@fortawesome/free-solid-svg-icons/faBars';
|
|
import { Image, Modal, Pressable, StyleSheet, Text, View } from 'react-native';
|
|
import { SafeAreaProvider, SafeAreaView } from 'react-native-safe-area-context';
|
|
import { StatusBar } from 'expo-status-bar';
|
|
import { useState } from 'react';
|
|
import { EventListScreen } from '../screens/EventListScreen';
|
|
import { EventDetailScreen } from '../screens/EventDetailScreen';
|
|
import { AddEventScreen } from '../screens/AddEventScreen';
|
|
import { SettingsScreen } from '../screens/SettingsScreen';
|
|
import { CalendarImportScreen } from '../screens/CalendarImportScreen';
|
|
import type { RootStack } from '../types/navigation';
|
|
import navLogo from '../../assets/nav-logo.png';
|
|
|
|
// ── Root Stack ──
|
|
|
|
const Root = createNativeStackNavigator<RootStack>();
|
|
const byPrefixAndName = { fas: { bars: faBars } };
|
|
|
|
type HeaderMenuProps = {
|
|
navigation: {
|
|
navigate: (screen: 'CalendarImport' | 'Settings') => void;
|
|
};
|
|
};
|
|
|
|
function HeaderMenu({ navigation }: HeaderMenuProps) {
|
|
const [isOpen, setIsOpen] = useState(false);
|
|
|
|
const navigateTo = (screen: 'CalendarImport' | 'Settings') => {
|
|
setIsOpen(false);
|
|
navigation.navigate(screen);
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<Pressable
|
|
accessibilityLabel="Open menu"
|
|
accessibilityRole="button"
|
|
hitSlop={12}
|
|
onPress={() => setIsOpen(true)}
|
|
style={({ pressed }) => [styles.menuButton, pressed && styles.menuButtonPressed]}
|
|
>
|
|
<FontAwesomeIcon icon={byPrefixAndName.fas['bars']} color="#F4F1EA" size={22} />
|
|
</Pressable>
|
|
|
|
<Modal animationType="fade" transparent visible={isOpen} onRequestClose={() => setIsOpen(false)}>
|
|
<Pressable style={styles.menuOverlay} onPress={() => setIsOpen(false)}>
|
|
<View style={styles.menuPanel}>
|
|
<Pressable
|
|
accessibilityRole="menuitem"
|
|
onPress={() => navigateTo('CalendarImport')}
|
|
style={({ pressed }) => [styles.menuItem, pressed && styles.menuItemPressed]}
|
|
>
|
|
<Text style={styles.menuItemText}>Calendar</Text>
|
|
</Pressable>
|
|
<Pressable
|
|
accessibilityRole="menuitem"
|
|
onPress={() => navigateTo('Settings')}
|
|
style={({ pressed }) => [styles.menuItem, pressed && styles.menuItemPressed]}
|
|
>
|
|
<Text style={styles.menuItemText}>Settings</Text>
|
|
</Pressable>
|
|
</View>
|
|
</Pressable>
|
|
</Modal>
|
|
</>
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Root native stack navigator for the app.
|
|
* Wraps all screens in SafeAreaProvider/SafeAreaView with a dark header bar.
|
|
*/
|
|
export default function AppNavigator() {
|
|
return (
|
|
<SafeAreaProvider>
|
|
<SafeAreaView style={{ flex: 1, backgroundColor: '#090816' }}>
|
|
<StatusBar style="light" />
|
|
<NavigationContainer>
|
|
<Root.Navigator
|
|
initialRouteName="EventList"
|
|
screenOptions={({ navigation }) => ({
|
|
headerStyle: { backgroundColor: '#17112A' },
|
|
headerTintColor: '#F4F1EA',
|
|
headerRight: () => <HeaderMenu navigation={navigation} />,
|
|
headerTitle: () => (
|
|
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 8 }}>
|
|
<Image source={navLogo} style={{ width: 28, height: 28, borderRadius: 6 }} resizeMode="contain" />
|
|
<Text style={{ color: '#F4F1EA', fontSize: 18, fontWeight: '600' }}>Time</Text>
|
|
<Text style={{ color: '#ea1579', fontSize: 18, fontWeight: '600' }}>To </Text>
|
|
<Text style={{ color: '#F4F1EA', fontSize: 18, fontWeight: '600' }}>Leave</Text>
|
|
|
|
</View>
|
|
),
|
|
})}
|
|
>
|
|
<Root.Screen name="EventList" component={EventListScreen} />
|
|
<Root.Screen name="AddEvent" component={AddEventScreen} />
|
|
<Root.Screen name="EventDetail" component={EventDetailScreen} />
|
|
<Root.Screen name="Settings" component={SettingsScreen} />
|
|
<Root.Screen name="CalendarImport" component={CalendarImportScreen} />
|
|
</Root.Navigator>
|
|
</NavigationContainer>
|
|
</SafeAreaView>
|
|
</SafeAreaProvider>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
menuButton: {
|
|
alignItems: 'center',
|
|
height: 40,
|
|
justifyContent: 'center',
|
|
width: 40,
|
|
},
|
|
menuButtonPressed: {
|
|
opacity: 0.65,
|
|
},
|
|
menuOverlay: {
|
|
alignItems: 'flex-end',
|
|
backgroundColor: 'rgba(9, 8, 22, 0.45)',
|
|
flex: 1,
|
|
paddingRight: 12,
|
|
paddingTop: 72,
|
|
},
|
|
menuPanel: {
|
|
backgroundColor: '#17112A',
|
|
borderColor: '#3B3157',
|
|
borderRadius: 8,
|
|
borderWidth: 1,
|
|
minWidth: 168,
|
|
overflow: 'hidden',
|
|
},
|
|
menuItem: {
|
|
paddingHorizontal: 18,
|
|
paddingVertical: 14,
|
|
},
|
|
menuItemPressed: {
|
|
backgroundColor: '#2A2140',
|
|
},
|
|
menuItemText: {
|
|
color: '#F4F1EA',
|
|
fontSize: 16,
|
|
fontWeight: '600',
|
|
},
|
|
});
|