124 lines
3.8 KiB
TypeScript
124 lines
3.8 KiB
TypeScript
import { Tabs } from 'expo-router';
|
|
import React from 'react';
|
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
import { View, StyleSheet, TouchableOpacity } from 'react-native';
|
|
import { TabBarIcon } from '@/components/TabBarIcon';
|
|
import { useSettings } from '@/theme';
|
|
import { setLastVisitedTab } from '@/utils/tabHistory';
|
|
|
|
export default function TabLayout() {
|
|
const { theme } = useSettings();
|
|
const insets = useSafeAreaInsets();
|
|
|
|
return (
|
|
<Tabs
|
|
screenOptions={{
|
|
tabBarActiveTintColor: theme.accent,
|
|
tabBarInactiveTintColor: theme.textSecondary,
|
|
tabBarStyle: {
|
|
backgroundColor: theme.tabBarBg,
|
|
borderTopWidth: 0,
|
|
height: 84 + insets.bottom,
|
|
paddingBottom: insets.bottom,
|
|
paddingTop: 12,
|
|
paddingHorizontal: 16,
|
|
elevation: 0,
|
|
shadowColor: '#000',
|
|
shadowOffset: { width: 0, height: -4 },
|
|
shadowOpacity: 0.12,
|
|
shadowRadius: 20,
|
|
},
|
|
tabBarItemStyle: {
|
|
paddingVertical: 0,
|
|
},
|
|
tabBarLabelStyle: {
|
|
fontSize: 11,
|
|
fontWeight: '700',
|
|
marginTop: 4,
|
|
},
|
|
headerShown: false,
|
|
sceneStyle: { backgroundColor: theme.background },
|
|
}}
|
|
tabBar={(props) => {
|
|
return (
|
|
<View
|
|
style={[
|
|
styles.tabBarContainer,
|
|
{
|
|
backgroundColor: theme.tabBarBg,
|
|
paddingBottom: Math.max(props.insets.bottom, 8),
|
|
shadowColor: '#000',
|
|
shadowOffset: { width: 0, height: -4 },
|
|
shadowOpacity: 0.12,
|
|
shadowRadius: 20,
|
|
elevation: 8,
|
|
},
|
|
]}
|
|
>
|
|
{props.navigation.getState().routes.map((route) => {
|
|
const focused = props.navigation.getState().index === props.navigation.getState().routes.indexOf(route);
|
|
return (
|
|
<TouchableOpacity
|
|
key={route.name}
|
|
style={[
|
|
styles.tabItem,
|
|
focused && styles.tabItemActive,
|
|
{ backgroundColor: focused ? theme.accentSoft : 'transparent' },
|
|
]}
|
|
onPress={() => props.navigation.navigate(route.name as never)}
|
|
accessibilityRole="button"
|
|
accessibilityLabel={route.name === 'index' ? 'ToDo' : route.name.charAt(0).toUpperCase() + route.name.slice(1)}
|
|
accessibilityState={{ selected: focused }}
|
|
>
|
|
<TabBarIcon
|
|
name={route.name === 'index' ? 'checklist' : route.name === 'calendar' ? 'calendar' : route.name === 'stats' ? 'stats' : 'gear'}
|
|
focused={focused}
|
|
color={focused ? theme.accent : theme.textSecondary}
|
|
size={24}
|
|
/>
|
|
</TouchableOpacity>
|
|
);
|
|
})}
|
|
</View>
|
|
);
|
|
}}
|
|
screenListeners={({ route }) => ({
|
|
focus: () => {
|
|
if (route.name !== 'settings') {
|
|
setLastVisitedTab(route.name);
|
|
}
|
|
},
|
|
})}
|
|
>
|
|
<Tabs.Screen name="index" />
|
|
<Tabs.Screen name="calendar" />
|
|
<Tabs.Screen name="stats" />
|
|
<Tabs.Screen name="settings" />
|
|
</Tabs>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
tabBarContainer: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
justifyContent: 'space-around',
|
|
paddingTop: 10,
|
|
paddingHorizontal: 16,
|
|
},
|
|
tabItem: {
|
|
flex: 1,
|
|
alignItems: 'center',
|
|
paddingVertical: 8,
|
|
paddingHorizontal: 8,
|
|
borderRadius: 16,
|
|
minWidth: 70,
|
|
},
|
|
tabItemActive: {
|
|
shadowColor: '#000',
|
|
shadowOffset: { width: 0, height: 2 },
|
|
shadowOpacity: 0.1,
|
|
shadowRadius: 8,
|
|
elevation: 4,
|
|
},
|
|
}); |