fromis_9/app/src/navigation/AppNavigator.tsx

154 lines
4.4 KiB
TypeScript
Raw Normal View History

import React from 'react';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { createNativeStackNavigator } from '@react-navigation/native-stack';
import { View, Text, StyleSheet, TouchableOpacity } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
// lucide 아이콘 (모바일 웹과 동일)
import { Home, Users, Disc3, Calendar } from 'lucide-react-native';
// 스크린 import
import HomeScreen from '../screens/HomeScreen';
import MembersScreen from '../screens/MembersScreen';
import AlbumScreen from '../screens/AlbumScreen';
import AlbumDetailScreen from '../screens/AlbumDetailScreen';
import AlbumGalleryScreen from '../screens/AlbumGalleryScreen';
import ScheduleScreen from '../screens/ScheduleScreen';
import { colors } from '../constants/colors';
// 타입 정의
export type RootTabParamList = {
HomeTab: undefined;
MembersTab: undefined;
AlbumTab: undefined;
ScheduleTab: undefined;
};
export type AlbumStackParamList = {
AlbumList: undefined;
AlbumDetail: { name: string };
AlbumGallery: { name: string };
};
const Tab = createBottomTabNavigator<RootTabParamList>();
const AlbumStack = createNativeStackNavigator<AlbumStackParamList>();
// 앨범 스택 네비게이터
function AlbumStackNavigator() {
return (
<AlbumStack.Navigator
screenOptions={{
headerShown: false,
}}
>
<AlbumStack.Screen name="AlbumList" component={AlbumScreen} />
<AlbumStack.Screen name="AlbumDetail" component={AlbumDetailScreen} />
<AlbumStack.Screen name="AlbumGallery" component={AlbumGalleryScreen} />
</AlbumStack.Navigator>
);
}
// 커스텀 탭바 (모바일 웹과 동일한 스타일)
function CustomTabBar({ state, descriptors, navigation }: any) {
const insets = useSafeAreaInsets();
const tabItems = [
{ name: 'HomeTab', label: '홈', Icon: Home },
{ name: 'MembersTab', label: '멤버', Icon: Users },
{ name: 'AlbumTab', label: '앨범', Icon: Disc3 },
{ name: 'ScheduleTab', label: '일정', Icon: Calendar },
];
return (
<View style={[
styles.tabBar,
{ paddingBottom: Math.max(insets.bottom, 8) }
]}>
<View style={styles.tabBarContent}>
{state.routes.map((route: any, index: number) => {
const isFocused = state.index === index;
const item = tabItems[index];
const IconComponent = item.Icon;
const onPress = () => {
const event = navigation.emit({
type: 'tabPress',
target: route.key,
canPreventDefault: true,
});
if (!isFocused && !event.defaultPrevented) {
navigation.navigate(route.name);
}
};
return (
<TouchableOpacity
key={route.key}
onPress={onPress}
style={styles.tabItem}
activeOpacity={0.7}
>
<IconComponent
size={22}
strokeWidth={isFocused ? 2.5 : 2}
color={isFocused ? colors.primary : '#9CA3AF'}
/>
<Text style={[
styles.tabLabel,
{ color: isFocused ? colors.primary : '#9CA3AF' }
]}>
{item.label}
</Text>
</TouchableOpacity>
);
})}
</View>
</View>
);
}
// 메인 탭 네비게이터
export default function AppNavigator() {
return (
<NavigationContainer>
<Tab.Navigator
tabBar={(props) => <CustomTabBar {...props} />}
screenOptions={{
headerShown: false,
}}
>
<Tab.Screen name="HomeTab" component={HomeScreen} />
<Tab.Screen name="MembersTab" component={MembersScreen} />
<Tab.Screen name="AlbumTab" component={AlbumStackNavigator} />
<Tab.Screen name="ScheduleTab" component={ScheduleScreen} />
</Tab.Navigator>
</NavigationContainer>
);
}
const styles = StyleSheet.create({
tabBar: {
backgroundColor: '#FFFFFF',
borderTopWidth: 1,
borderTopColor: '#E5E7EB',
},
tabBarContent: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-around',
height: 56,
},
tabItem: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
gap: 4,
},
tabLabel: {
fontSize: 11,
fontWeight: '500',
},
});