Pre-launch — Gluecron is in final validation. Public signups and git hosting for non-owner users open after launch review.
CodeIssuesDiscussionsWikiPull RequestsProjectsCommitsActionsReleasesContributorsPulse● GatesSecuritySettingsDeploymentsPipelineInsightsAgents✨ Explain✨ Ask AI✨ Workspace✨ Spec✨ Tests▓ Debt Map✨ NL Search🏛 Archaeology
Blame · Line-by-line history

MainTabNavigator.tsx

Each line is annotated with the commit that last touched it. Click any SHA to jump to that commit and see the surrounding change.

MainTabNavigator.tsxBlame132 lines · 1 contributor
c53cf00Claude1import React from 'react';
2import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
3import { createNativeStackNavigator } from '@react-navigation/native-stack';
9d7a803Claude4import { Text } from 'react-native';
c53cf00Claude5import { colors } from '../theme/colors';
6import { fontSizes } from '../theme/typography';
9d7a803Claude7import { type MainStackParamList } from './types';
8
9// Re-export for convenience (navigators that don't import screens can still get the type)
10export type { MainStackParamList };
c53cf00Claude11
12import { DashboardScreen } from '../screens/DashboardScreen';
13import { RepoListScreen } from '../screens/RepoListScreen';
14import { RepoDetailScreen } from '../screens/RepoDetailScreen';
15import { FileViewerScreen } from '../screens/FileViewerScreen';
16import { IssueListScreen } from '../screens/IssueListScreen';
17import { IssueDetailScreen } from '../screens/IssueDetailScreen';
18import { PullListScreen } from '../screens/PullListScreen';
19import { PullDetailScreen } from '../screens/PullDetailScreen';
20import { NotificationsScreen } from '../screens/NotificationsScreen';
21import { SettingsScreen } from '../screens/SettingsScreen';
22
23const Stack = createNativeStackNavigator<MainStackParamList>();
24const Tab = createBottomTabNavigator();
25
26// ─── Stack navigators (one per tab root) ────────────────────────────────────
27
28function DashboardStack() {
29 return (
30 <Stack.Navigator screenOptions={stackScreenOptions}>
31 <Stack.Screen name="Dashboard" component={DashboardScreen} options={{ title: 'Dashboard' }} />
32 <Stack.Screen name="RepoDetail" component={RepoDetailScreen} options={({ route }) => ({ title: route.params.repo })} />
33 <Stack.Screen name="FileViewer" component={FileViewerScreen} options={({ route }) => ({ title: route.params.path.split('/').pop() ?? 'File' })} />
34 <Stack.Screen name="IssueList" component={IssueListScreen} options={{ title: 'Issues' }} />
35 <Stack.Screen name="IssueDetail" component={IssueDetailScreen} options={({ route }) => ({ title: `#${route.params.number}` })} />
36 <Stack.Screen name="PullList" component={PullListScreen} options={{ title: 'Pull Requests' }} />
37 <Stack.Screen name="PullDetail" component={PullDetailScreen} options={({ route }) => ({ title: `PR #${route.params.number}` })} />
38 {/* Dummy screens required by type — never actually navigated to from this stack */}
39 <Stack.Screen name="RepoList" component={RepoListScreen} options={{ title: 'Repositories' }} />
40 </Stack.Navigator>
41 );
42}
43
44function RepoStack() {
45 return (
46 <Stack.Navigator screenOptions={stackScreenOptions}>
47 <Stack.Screen name="RepoList" component={RepoListScreen} options={{ title: 'Repositories' }} />
48 <Stack.Screen name="RepoDetail" component={RepoDetailScreen} options={({ route }) => ({ title: route.params.repo })} />
49 <Stack.Screen name="FileViewer" component={FileViewerScreen} options={({ route }) => ({ title: route.params.path.split('/').pop() ?? 'File' })} />
50 <Stack.Screen name="IssueList" component={IssueListScreen} options={{ title: 'Issues' }} />
51 <Stack.Screen name="IssueDetail" component={IssueDetailScreen} options={({ route }) => ({ title: `#${route.params.number}` })} />
52 <Stack.Screen name="PullList" component={PullListScreen} options={{ title: 'Pull Requests' }} />
53 <Stack.Screen name="PullDetail" component={PullDetailScreen} options={({ route }) => ({ title: `PR #${route.params.number}` })} />
54 {/* Dummy — needed to satisfy shared type */}
55 <Stack.Screen name="Dashboard" component={DashboardScreen} options={{ title: 'Dashboard' }} />
56 </Stack.Navigator>
57 );
58}
59
60// ─── Tab navigator ───────────────────────────────────────────────────────────
61
62export function MainTabNavigator() {
63 return (
64 <Tab.Navigator
65 screenOptions={{
66 headerShown: false,
67 tabBarStyle: {
68 backgroundColor: colors.bgSecondary,
69 borderTopColor: colors.border,
70 borderTopWidth: 1,
71 height: 60,
72 paddingBottom: 8,
73 },
74 tabBarActiveTintColor: colors.accent,
75 tabBarInactiveTintColor: colors.textMuted,
76 tabBarLabelStyle: {
77 fontSize: fontSizes.xs,
78 fontWeight: '500',
79 },
80 }}
81 >
82 <Tab.Screen
83 name="DashboardTab"
84 component={DashboardStack}
85 options={{
86 title: 'Dashboard',
87 tabBarIcon: ({ color }) => <TabIcon icon="⌂" color={color} />,
88 }}
89 />
90 <Tab.Screen
91 name="ReposTab"
92 component={RepoStack}
93 options={{
94 title: 'Repos',
95 tabBarIcon: ({ color }) => <TabIcon icon="⌥" color={color} />,
96 }}
97 />
98 <Tab.Screen
99 name="NotificationsTab"
100 component={NotificationsScreen}
101 options={{
102 title: 'Notifications',
103 tabBarIcon: ({ color }) => <TabIcon icon="◉" color={color} />,
104 }}
105 />
106 <Tab.Screen
107 name="SettingsTab"
108 component={SettingsScreen}
109 options={{
110 title: 'Settings',
111 tabBarIcon: ({ color }) => <TabIcon icon="⚙" color={color} />,
112 }}
113 />
114 </Tab.Navigator>
115 );
116}
117
118// ─── Helpers ─────────────────────────────────────────────────────────────────
119
120function TabIcon({ icon, color }: { icon: string; color: string }) {
121 return (
122 <Text style={{ fontSize: 18, color, lineHeight: 22 }}>{icon}</Text>
123 );
124}
125
126const stackScreenOptions = {
127 headerStyle: { backgroundColor: colors.bgSecondary },
128 headerTintColor: colors.text,
129 headerTitleStyle: { color: colors.text, fontWeight: '600' as const },
130 headerBackTitleVisible: false,
131 contentStyle: { backgroundColor: colors.bg },
132};