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