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

AuthScreen.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.

AuthScreen.tsxBlame244 lines · 1 contributor
c53cf00Claude1import React, { useState, useContext } from 'react';
2import {
3 View,
4 Text,
5 TextInput,
6 TouchableOpacity,
7 StyleSheet,
8 ScrollView,
9 KeyboardAvoidingView,
10 Platform,
11 ActivityIndicator,
12 Alert,
13} from 'react-native';
14import { SafeAreaView } from 'react-native-safe-area-context';
15import { colors } from '../theme/colors';
16import { fontSizes, fontWeights } from '../theme/typography';
9d7a803Claude17import { AuthContext } from '../navigation/AuthContext';
c53cf00Claude18
19export function AuthScreen() {
20 const { login } = useContext(AuthContext);
21 const [token, setToken] = useState('');
22 const [host, setHost] = useState('https://gluecron.com');
23 const [showAdvanced, setShowAdvanced] = useState(false);
24 const [loading, setLoading] = useState(false);
25
26 async function handleLogin() {
27 const trimmed = token.trim();
28 if (!trimmed) {
29 Alert.alert('Error', 'Please enter your Personal Access Token');
30 return;
31 }
32 setLoading(true);
33 try {
34 await login(trimmed, undefined, host.trim() || 'https://gluecron.com');
35 } catch (err) {
36 Alert.alert('Login failed', err instanceof Error ? err.message : 'Invalid token');
37 } finally {
38 setLoading(false);
39 }
40 }
41
42 return (
43 <SafeAreaView style={styles.safe}>
44 <KeyboardAvoidingView behavior={Platform.OS === 'ios' ? 'padding' : undefined} style={styles.kav}>
45 <ScrollView contentContainerStyle={styles.scroll} keyboardShouldPersistTaps="handled">
46 {/* Logo */}
47 <View style={styles.logoWrap}>
48 <Text style={styles.logoIcon}>⬡</Text>
49 <Text style={styles.logoText}>
50 glue<Text style={styles.logoAccent}>cron</Text>
51 </Text>
52 <Text style={styles.tagline}>AI-native git hosting</Text>
53 </View>
54
55 {/* Card */}
56 <View style={styles.card}>
57 <Text style={styles.heading}>Sign in</Text>
58 <Text style={styles.subheading}>
59 Use a Personal Access Token from your Gluecron account settings.
60 </Text>
61
62 <View style={styles.field}>
63 <Text style={styles.label}>Personal Access Token</Text>
64 <TextInput
65 style={styles.input}
66 value={token}
67 onChangeText={setToken}
68 placeholder="glc_..."
69 placeholderTextColor={colors.textMuted}
70 secureTextEntry
71 autoCapitalize="none"
72 autoCorrect={false}
73 autoComplete="password"
74 returnKeyType="done"
75 onSubmitEditing={handleLogin}
76 />
77 </View>
78
79 <TouchableOpacity
80 style={styles.advancedToggle}
81 onPress={() => setShowAdvanced((v) => !v)}
82 activeOpacity={0.7}
83 >
84 <Text style={styles.advancedToggleText}>
85 {showAdvanced ? '− ' : '+ '}Advanced (self-hosted)
86 </Text>
87 </TouchableOpacity>
88
89 {showAdvanced && (
90 <View style={styles.field}>
91 <Text style={styles.label}>Gluecron Host URL</Text>
92 <TextInput
93 style={styles.input}
94 value={host}
95 onChangeText={setHost}
96 placeholder="https://gluecron.com"
97 placeholderTextColor={colors.textMuted}
98 autoCapitalize="none"
99 autoCorrect={false}
100 keyboardType="url"
101 />
102 </View>
103 )}
104
105 <TouchableOpacity
106 style={[styles.loginBtn, loading && styles.loginBtnDisabled]}
107 onPress={handleLogin}
108 disabled={loading}
109 activeOpacity={0.8}
110 >
111 {loading ? (
112 <ActivityIndicator color={colors.white} size="small" />
113 ) : (
114 <Text style={styles.loginBtnText}>Sign in</Text>
115 )}
116 </TouchableOpacity>
117
118 <Text style={styles.hint}>
119 Generate a token at{' '}
120 <Text style={styles.hintLink}>Settings → Tokens</Text>
121 {' '}on your Gluecron instance.
122 </Text>
123 </View>
124 </ScrollView>
125 </KeyboardAvoidingView>
126 </SafeAreaView>
127 );
128}
129
130const styles = StyleSheet.create({
131 safe: {
132 flex: 1,
133 backgroundColor: colors.bg,
134 },
135 kav: {
136 flex: 1,
137 },
138 scroll: {
139 flexGrow: 1,
140 alignItems: 'center',
141 justifyContent: 'center',
142 padding: 24,
143 },
144 logoWrap: {
145 alignItems: 'center',
146 marginBottom: 36,
147 },
148 logoIcon: {
149 fontSize: 48,
150 color: colors.accent,
151 marginBottom: 8,
152 },
153 logoText: {
154 fontSize: fontSizes.xxl,
155 fontWeight: fontWeights.bold,
156 color: colors.text,
157 letterSpacing: -0.5,
158 },
159 logoAccent: {
160 color: colors.accent,
161 },
162 tagline: {
163 color: colors.textMuted,
164 fontSize: fontSizes.sm,
165 marginTop: 4,
166 },
167 card: {
168 width: '100%',
169 maxWidth: 400,
170 backgroundColor: colors.bgSurface,
171 borderRadius: 14,
172 padding: 24,
173 borderWidth: 1,
174 borderColor: colors.border,
175 },
176 heading: {
177 color: colors.text,
178 fontSize: fontSizes.xl,
179 fontWeight: fontWeights.bold,
180 marginBottom: 6,
181 },
182 subheading: {
183 color: colors.textMuted,
184 fontSize: fontSizes.sm,
185 lineHeight: 18,
186 marginBottom: 22,
187 },
188 field: {
189 marginBottom: 16,
190 },
191 label: {
192 color: colors.textMuted,
193 fontSize: fontSizes.xs,
194 fontWeight: fontWeights.medium,
195 marginBottom: 6,
196 textTransform: 'uppercase',
197 letterSpacing: 0.5,
198 },
199 input: {
200 backgroundColor: colors.bgSecondary,
201 borderWidth: 1,
202 borderColor: colors.border,
203 borderRadius: 8,
204 paddingHorizontal: 14,
205 paddingVertical: 12,
206 color: colors.text,
207 fontSize: fontSizes.base,
208 minHeight: 44,
209 },
210 advancedToggle: {
211 marginBottom: 12,
212 },
213 advancedToggleText: {
214 color: colors.accent,
215 fontSize: fontSizes.sm,
216 },
217 loginBtn: {
218 backgroundColor: colors.accent,
219 borderRadius: 8,
220 paddingVertical: 14,
221 alignItems: 'center',
222 marginTop: 8,
223 minHeight: 48,
224 justifyContent: 'center',
225 },
226 loginBtnDisabled: {
227 opacity: 0.6,
228 },
229 loginBtnText: {
230 color: colors.white,
231 fontSize: fontSizes.base,
232 fontWeight: fontWeights.semibold,
233 },
234 hint: {
235 color: colors.textMuted,
236 fontSize: fontSizes.xs,
237 textAlign: 'center',
238 marginTop: 16,
239 lineHeight: 18,
240 },
241 hintLink: {
242 color: colors.accent,
243 },
244});