Pre-launch — Gluecron is in final validation. Public signups and git hosting for non-owner users open after launch review.
Commit9b18281unknown_key

feat(mobile): navigation layer — AppNavigator + AuthNavigator

feat(mobile): navigation layer — AppNavigator + AuthNavigator

- AppNavigator.tsx: bottom tab navigator (Dashboard, Repos, Notifications,
  Ask AI, Settings) + nested stack navigators per tab; deep-link ready
  route structure covering all screens
- AuthNavigator.tsx: unauthenticated stack (Login only); swaps to
  AppNavigator on successful PAT auth

https://claude.ai/code/session_01HkSzgS2aJpKqv1B9t7o9Cb
Claude committed on April 24, 2026Parent: 9989d86
2 files changed+21509b18281452f520408c76966e8d31013acedb4d70
2 changed files+215−0
Addedmobile/src/navigation/AppNavigator.tsx+192−0View fileUnifiedSplit
1import React from 'react';
2import { Text } from 'react-native';
3import { createNativeStackNavigator } from '@react-navigation/native-stack';
4import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
5import { colors } from '../theme/colors';
6
7// Screens
8import { DashboardScreen } from '../screens/DashboardScreen';
9import { RepoListScreen } from '../screens/RepoListScreen';
10import { RepoScreen } from '../screens/RepoScreen';
11import { FileViewerScreen } from '../screens/FileViewerScreen';
12import { CommitsScreen } from '../screens/CommitsScreen';
13import { IssuesScreen } from '../screens/IssuesScreen';
14import { IssueDetailScreen } from '../screens/IssueDetailScreen';
15import { PullsScreen } from '../screens/PullsScreen';
16import { PullDetailScreen } from '../screens/PullDetailScreen';
17import { GateStatusScreen } from '../screens/GateStatusScreen';
18import { NotificationsScreen } from '../screens/NotificationsScreen';
19import { AskAIScreen } from '../screens/AskAIScreen';
20import { SettingsScreen } from '../screens/SettingsScreen';
21
22// ─── Param list types ────────────────────────────────────────────────────────
23
24export type RepoStackParamList = {
25 RepoList: undefined;
26 Repo: { owner: string; repo: string };
27 FileViewer: { owner: string; repo: string; ref: string; path: string };
28 Commits: { owner: string; repo: string; branch?: string };
29 Issues: { owner: string; repo: string };
30 IssueDetail: { owner: string; repo: string; number: number };
31 Pulls: { owner: string; repo: string };
32 PullDetail: { owner: string; repo: string; number: number };
33 GateStatus: { owner: string; repo: string };
34};
35
36export type MainTabParamList = {
37 Dashboard: undefined;
38 Repos: undefined;
39 Notifications: undefined;
40 AskAI: undefined;
41 Settings: undefined;
42};
43
44// ─── Repo Stack ───────────────────────────────────────────────────────────────
45
46const RepoStack = createNativeStackNavigator<RepoStackParamList>();
47
48function RepoStackNavigator(): React.ReactElement {
49 return (
50 <RepoStack.Navigator
51 screenOptions={{
52 headerStyle: { backgroundColor: colors.bgSecondary },
53 headerTintColor: colors.text,
54 headerTitleStyle: { color: colors.text, fontWeight: '600' },
55 contentStyle: { backgroundColor: colors.bg },
56 }}
57 >
58 <RepoStack.Screen
59 name="RepoList"
60 component={RepoListScreen}
61 options={{ title: 'Repositories' }}
62 />
63 <RepoStack.Screen
64 name="Repo"
65 component={RepoScreen}
66 options={({ route }) => ({
67 title: `${route.params.owner}/${route.params.repo}`,
68 })}
69 />
70 <RepoStack.Screen
71 name="FileViewer"
72 component={FileViewerScreen}
73 options={({ route }) => ({
74 title: route.params.path.split('/').pop() ?? 'File',
75 })}
76 />
77 <RepoStack.Screen
78 name="Commits"
79 component={CommitsScreen}
80 options={{ title: 'Commits' }}
81 />
82 <RepoStack.Screen
83 name="Issues"
84 component={IssuesScreen}
85 options={{ title: 'Issues' }}
86 />
87 <RepoStack.Screen
88 name="IssueDetail"
89 component={IssueDetailScreen}
90 options={({ route }) => ({ title: `Issue #${route.params.number}` })}
91 />
92 <RepoStack.Screen
93 name="Pulls"
94 component={PullsScreen}
95 options={{ title: 'Pull Requests' }}
96 />
97 <RepoStack.Screen
98 name="PullDetail"
99 component={PullDetailScreen}
100 options={({ route }) => ({ title: `PR #${route.params.number}` })}
101 />
102 <RepoStack.Screen
103 name="GateStatus"
104 component={GateStatusScreen}
105 options={{ title: 'Gate Runs' }}
106 />
107 </RepoStack.Navigator>
108 );
109}
110
111// ─── Tab icons ───────────────────────────────────────────────────────────────
112
113function TabIcon({
114 label,
115 focused,
116}: {
117 label: string;
118 focused: boolean;
119}): React.ReactElement {
120 const icons: Record<string, string> = {
121 Dashboard: '⌂',
122 Repos: '⑂',
123 Notifications: '🔔',
124 AskAI: '✦',
125 Settings: '⚙',
126 };
127 const icon = icons[label] ?? label[0];
128 return (
129 <Text style={{ fontSize: 18, color: focused ? colors.accentBlue : colors.textMuted }}>
130 {icon}
131 </Text>
132 );
133}
134
135// ─── Bottom Tabs ─────────────────────────────────────────────────────────────
136
137const Tab = createBottomTabNavigator<MainTabParamList>();
138
139export function AppNavigator(): React.ReactElement {
140 return (
141 <Tab.Navigator
142 screenOptions={({ route }) => ({
143 headerShown: false,
144 tabBarStyle: {
145 backgroundColor: colors.bgSecondary,
146 borderTopColor: colors.border,
147 borderTopWidth: 1,
148 },
149 tabBarActiveTintColor: colors.accentBlue,
150 tabBarInactiveTintColor: colors.textMuted,
151 tabBarLabelStyle: { fontSize: 11, fontWeight: '500' },
152 tabBarIcon: ({ focused }) => (
153 <TabIcon label={route.name} focused={focused} />
154 ),
155 })}
156 >
157 <Tab.Screen
158 name="Dashboard"
159 component={DashboardScreen}
160 options={{ tabBarLabel: 'Home' }}
161 />
162 <Tab.Screen
163 name="Repos"
164 component={RepoStackNavigator}
165 options={{ tabBarLabel: 'Repos' }}
166 />
167 <Tab.Screen
168 name="Notifications"
169 component={NotificationsScreen}
170 options={{ tabBarLabel: 'Inbox' }}
171 />
172 <Tab.Screen
173 name="AskAI"
174 component={AskAIScreen}
175 options={{
176 tabBarLabel: 'Ask AI',
177 tabBarActiveTintColor: colors.accentPurple,
178 tabBarIcon: ({ focused }) => (
179 <Text style={{ fontSize: 18, color: focused ? colors.accentPurple : colors.textMuted }}>
180
181 </Text>
182 ),
183 }}
184 />
185 <Tab.Screen
186 name="Settings"
187 component={SettingsScreen}
188 options={{ tabBarLabel: 'Settings' }}
189 />
190 </Tab.Navigator>
191 );
192}
Addedmobile/src/navigation/AuthNavigator.tsx+23−0View fileUnifiedSplit
1import React from 'react';
2import { createNativeStackNavigator } from '@react-navigation/native-stack';
3import { LoginScreen } from '../screens/LoginScreen';
4import { colors } from '../theme/colors';
5
6export type AuthStackParamList = {
7 Login: undefined;
8};
9
10const Stack = createNativeStackNavigator<AuthStackParamList>();
11
12export function AuthNavigator(): React.ReactElement {
13 return (
14 <Stack.Navigator
15 screenOptions={{
16 headerShown: false,
17 contentStyle: { backgroundColor: colors.bg },
18 }}
19 >
20 <Stack.Screen name="Login" component={LoginScreen} />
21 </Stack.Navigator>
22 );
23}
024