create-better-t-stack 3.2.22 → 3.2.23-canary.2b547ed5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/README.md +2 -2
  2. package/dist/cli.js +1 -1
  3. package/dist/index.d.ts +4 -2
  4. package/dist/index.js +1 -1
  5. package/dist/{src-WIwtBCHf.js → src-ehteLbIu.js} +105 -65
  6. package/package.json +1 -1
  7. package/templates/auth/better-auth/convex/backend/convex/auth.ts.hbs +5 -5
  8. package/templates/auth/better-auth/convex/backend/convex/http.ts.hbs +1 -1
  9. package/templates/auth/better-auth/convex/native/bare/components/sign-in.tsx.hbs +127 -0
  10. package/templates/auth/better-auth/convex/native/bare/components/sign-up.tsx.hbs +138 -0
  11. package/templates/auth/better-auth/convex/native/uniwind/components/sign-in.tsx.hbs +91 -0
  12. package/templates/auth/better-auth/convex/native/uniwind/components/sign-up.tsx.hbs +102 -0
  13. package/templates/auth/better-auth/native/bare/app/(drawer)/index.tsx.hbs +186 -0
  14. package/templates/auth/better-auth/native/bare/components/sign-in.tsx.hbs +131 -0
  15. package/templates/auth/better-auth/native/bare/components/sign-up.tsx.hbs +150 -0
  16. package/templates/auth/better-auth/native/unistyles/app/(drawer)/index.tsx.hbs +9 -1
  17. package/templates/auth/better-auth/native/unistyles/components/sign-in.tsx.hbs +5 -0
  18. package/templates/auth/better-auth/native/unistyles/components/sign-up.tsx.hbs +5 -0
  19. package/templates/auth/better-auth/native/uniwind/app/(drawer)/index.tsx.hbs +123 -0
  20. package/templates/auth/better-auth/native/uniwind/components/sign-in.tsx.hbs +90 -0
  21. package/templates/auth/better-auth/native/uniwind/components/sign-up.tsx.hbs +116 -0
  22. package/templates/auth/better-auth/server/base/src/index.ts.hbs +5 -5
  23. package/templates/examples/ai/native/bare/app/(drawer)/ai.tsx.hbs +287 -0
  24. package/templates/examples/ai/native/{nativewind → bare}/polyfills.js +1 -0
  25. package/templates/examples/ai/native/{nativewind → uniwind}/app/(drawer)/ai.tsx.hbs +52 -51
  26. package/templates/examples/ai/native/uniwind/polyfills.js +26 -0
  27. package/templates/examples/todo/native/bare/app/(drawer)/todos.tsx.hbs +430 -0
  28. package/templates/examples/todo/native/uniwind/app/(drawer)/todos.tsx.hbs +295 -0
  29. package/templates/extras/bunfig.toml.hbs +3 -3
  30. package/templates/frontend/native/bare/_gitignore +18 -0
  31. package/templates/frontend/native/{nativewind → bare}/app/(drawer)/(tabs)/_layout.tsx.hbs +7 -12
  32. package/templates/frontend/native/bare/app/(drawer)/(tabs)/index.tsx.hbs +43 -0
  33. package/templates/frontend/native/bare/app/(drawer)/(tabs)/two.tsx.hbs +43 -0
  34. package/templates/frontend/native/{nativewind → bare}/app/(drawer)/_layout.tsx.hbs +24 -1
  35. package/templates/frontend/native/bare/app/(drawer)/index.tsx.hbs +234 -0
  36. package/templates/frontend/native/bare/app/+not-found.tsx.hbs +65 -0
  37. package/templates/frontend/native/bare/app/_layout.tsx.hbs +163 -0
  38. package/templates/frontend/native/bare/app/modal.tsx.hbs +34 -0
  39. package/templates/frontend/native/{nativewind → bare}/app.json.hbs +1 -0
  40. package/templates/frontend/native/bare/components/container.tsx.hbs +25 -0
  41. package/templates/frontend/native/bare/components/header-button.tsx.hbs +47 -0
  42. package/templates/frontend/native/{nativewind → bare}/components/tabbar-icon.tsx.hbs +1 -0
  43. package/templates/frontend/native/{nativewind → bare}/lib/android-navigation-bar.tsx.hbs +1 -0
  44. package/templates/frontend/native/{nativewind → bare}/lib/constants.ts.hbs +1 -0
  45. package/templates/frontend/native/bare/lib/use-color-scheme.ts.hbs +20 -0
  46. package/templates/frontend/native/bare/metro.config.js.hbs +9 -0
  47. package/templates/frontend/native/{nativewind → bare}/package.json.hbs +1 -2
  48. package/templates/frontend/native/bare/tsconfig.json.hbs +11 -0
  49. package/templates/frontend/native/{nativewind → uniwind}/_gitignore +4 -8
  50. package/templates/frontend/native/uniwind/app/(drawer)/(tabs)/_layout.tsx.hbs +46 -0
  51. package/templates/frontend/native/uniwind/app/(drawer)/(tabs)/index.tsx.hbs +15 -0
  52. package/templates/frontend/native/uniwind/app/(drawer)/(tabs)/two.tsx.hbs +15 -0
  53. package/templates/frontend/native/uniwind/app/(drawer)/_layout.tsx.hbs +83 -0
  54. package/templates/frontend/native/uniwind/app/(drawer)/index.tsx.hbs +151 -0
  55. package/templates/frontend/native/uniwind/app/+not-found.tsx.hbs +32 -0
  56. package/templates/frontend/native/uniwind/app/_layout.tsx.hbs +131 -0
  57. package/templates/frontend/native/uniwind/app/modal.tsx.hbs +53 -0
  58. package/templates/frontend/native/uniwind/app.json.hbs +19 -0
  59. package/templates/frontend/native/uniwind/components/container.tsx.hbs +33 -0
  60. package/templates/frontend/native/uniwind/components/theme-toggle.tsx.hbs +35 -0
  61. package/templates/frontend/native/uniwind/contexts/app-theme-context.tsx.hbs +62 -0
  62. package/templates/frontend/native/uniwind/global.css +5 -0
  63. package/templates/frontend/native/uniwind/metro.config.js.hbs +13 -0
  64. package/templates/frontend/native/uniwind/package.json.hbs +54 -0
  65. package/templates/frontend/native/{nativewind → uniwind}/tsconfig.json.hbs +4 -8
  66. package/templates/auth/better-auth/convex/native/nativewind/components/sign-in.tsx.hbs +0 -86
  67. package/templates/auth/better-auth/convex/native/nativewind/components/sign-up.tsx.hbs +0 -97
  68. package/templates/auth/better-auth/native/nativewind/app/(drawer)/index.tsx.hbs +0 -95
  69. package/templates/auth/better-auth/native/nativewind/components/sign-in.tsx.hbs +0 -93
  70. package/templates/auth/better-auth/native/nativewind/components/sign-up.tsx.hbs +0 -104
  71. package/templates/examples/todo/native/nativewind/app/(drawer)/todos.tsx.hbs +0 -295
  72. package/templates/frontend/native/nativewind/app/(drawer)/(tabs)/index.tsx.hbs +0 -19
  73. package/templates/frontend/native/nativewind/app/(drawer)/(tabs)/two.tsx.hbs +0 -19
  74. package/templates/frontend/native/nativewind/app/(drawer)/index.tsx.hbs +0 -178
  75. package/templates/frontend/native/nativewind/app/+not-found.tsx.hbs +0 -29
  76. package/templates/frontend/native/nativewind/app/_layout.tsx.hbs +0 -175
  77. package/templates/frontend/native/nativewind/app/modal.tsx.hbs +0 -14
  78. package/templates/frontend/native/nativewind/babel.config.js.hbs +0 -14
  79. package/templates/frontend/native/nativewind/components/container.tsx.hbs +0 -8
  80. package/templates/frontend/native/nativewind/components/header-button.tsx.hbs +0 -26
  81. package/templates/frontend/native/nativewind/global.css +0 -50
  82. package/templates/frontend/native/nativewind/lib/use-color-scheme.ts.hbs +0 -12
  83. package/templates/frontend/native/nativewind/metro.config.js.hbs +0 -12
  84. package/templates/frontend/native/nativewind/tailwind.config.js.hbs +0 -59
@@ -0,0 +1,234 @@
1
+ import { View, Text, ScrollView, TouchableOpacity, StyleSheet } from "react-native";
2
+ import { Container } from "@/components/container";
3
+ import { useColorScheme } from "@/lib/use-color-scheme";
4
+ import { NAV_THEME } from "@/lib/constants";
5
+ {{#if (eq api "orpc")}}
6
+ import { useQuery } from "@tanstack/react-query";
7
+ import { orpc } from "@/utils/orpc";
8
+ {{/if}}
9
+ {{#if (eq api "trpc")}}
10
+ import { useQuery } from "@tanstack/react-query";
11
+ import { trpc } from "@/utils/trpc";
12
+ {{/if}}
13
+ {{#if (and (eq backend "convex") (eq auth "clerk"))}}
14
+ import { Link } from "expo-router";
15
+ import { Authenticated, AuthLoading, Unauthenticated, useQuery } from "convex/react";
16
+ import { api } from "@{{ projectName }}/backend/convex/_generated/api";
17
+ import { useUser } from "@clerk/clerk-expo";
18
+ import { SignOutButton } from "@/components/sign-out-button";
19
+ {{else if (and (eq backend "convex") (eq auth "better-auth"))}}
20
+ import { useConvexAuth, useQuery } from "convex/react";
21
+ import { api } from "@{{ projectName }}/backend/convex/_generated/api";
22
+ import { authClient } from "@/lib/auth-client";
23
+ import { SignIn } from "@/components/sign-in";
24
+ import { SignUp } from "@/components/sign-up";
25
+ {{else if (eq backend "convex")}}
26
+ import { useQuery } from "convex/react";
27
+ import { api } from "@{{ projectName }}/backend/convex/_generated/api";
28
+ {{/if}}
29
+
30
+ export default function Home() {
31
+ const { colorScheme } = useColorScheme();
32
+ const theme = colorScheme === "dark" ? NAV_THEME.dark : NAV_THEME.light;
33
+ {{#if (eq api "orpc")}}
34
+ const healthCheck = useQuery(orpc.healthCheck.queryOptions());
35
+ {{/if}}
36
+ {{#if (eq api "trpc")}}
37
+ const healthCheck = useQuery(trpc.healthCheck.queryOptions());
38
+ {{/if}}
39
+ {{#if (and (eq backend "convex") (eq auth "clerk"))}}
40
+ const { user } = useUser();
41
+ const healthCheck = useQuery(api.healthCheck.get);
42
+ const privateData = useQuery(api.privateData.get);
43
+ {{else if (and (eq backend "convex") (eq auth "better-auth"))}}
44
+ const healthCheck = useQuery(api.healthCheck.get);
45
+ const { isAuthenticated } = useConvexAuth();
46
+ const user = useQuery(api.auth.getCurrentUser, isAuthenticated ? {} : "skip");
47
+ {{else if (eq backend "convex")}}
48
+ const healthCheck = useQuery(api.healthCheck.get);
49
+ {{/if}}
50
+
51
+ return (
52
+ <Container>
53
+ <ScrollView style={styles.scrollView}>
54
+ <View style={styles.content}>
55
+ <Text style={[styles.title, { color: theme.text }]}>
56
+ BETTER T STACK
57
+ </Text>
58
+
59
+ {{#unless (and (eq backend "convex") (eq auth "better-auth"))}}
60
+ <View style={[styles.card, { backgroundColor: theme.card, borderColor: theme.border }]}>
61
+ {{#if (eq backend "convex")}}
62
+ <View style={styles.statusRow}>
63
+ <View style={[styles.statusIndicator, { backgroundColor: healthCheck ? "#10b981" : "#f59e0b" }]} />
64
+ <View style={styles.statusContent}>
65
+ <Text style={[styles.statusTitle, { color: theme.text }]}>
66
+ Convex
67
+ </Text>
68
+ <Text style={[styles.statusText, { color: theme.text, opacity: 0.7 }]}>
69
+ {healthCheck === undefined
70
+ ? "Checking..."
71
+ : healthCheck === "OK"
72
+ ? "Connected to API"
73
+ : "API Disconnected"}
74
+ </Text>
75
+ </View>
76
+ </View>
77
+ {{else}}
78
+ {{#unless (eq api "none")}}
79
+ <View style={styles.statusRow}>
80
+ <View style={[styles.statusIndicator, { backgroundColor: healthCheck.data ? "#10b981" : "#f59e0b" }]} />
81
+ <View style={styles.statusContent}>
82
+ <Text style={[styles.statusTitle, { color: theme.text }]}>
83
+ {{#if (eq api "orpc")}}ORPC{{else}}TRPC{{/if}}
84
+ </Text>
85
+ <Text style={[styles.statusText, { color: theme.text, opacity: 0.7 }]}>
86
+ {healthCheck.isLoading
87
+ ? "Checking connection..."
88
+ : healthCheck.data
89
+ ? "All systems operational"
90
+ : "Service unavailable"}
91
+ </Text>
92
+ </View>
93
+ </View>
94
+ {{/unless}}
95
+ {{/if}}
96
+ </View>
97
+ {{/unless}}
98
+
99
+ {{#if (and (eq backend "convex") (eq auth "clerk"))}}
100
+ <Authenticated>
101
+ <Text style=\{{ color: theme.text }}>Hello {user?.emailAddresses[0].emailAddress}</Text>
102
+ <Text style=\{{ color: theme.text }}>Private Data: {privateData?.message}</Text>
103
+ <SignOutButton />
104
+ </Authenticated>
105
+ <Unauthenticated>
106
+ <Link href="/(auth)/sign-in">
107
+ <Text style=\{{ color: theme.primary }}>Sign in</Text>
108
+ </Link>
109
+ <Link href="/(auth)/sign-up">
110
+ <Text style=\{{ color: theme.primary }}>Sign up</Text>
111
+ </Link>
112
+ </Unauthenticated>
113
+ <AuthLoading>
114
+ <Text style=\{{ color: theme.text }}>Loading...</Text>
115
+ </AuthLoading>
116
+ {{/if}}
117
+
118
+ {{#if (and (eq backend "convex") (eq auth "better-auth"))}}
119
+ {user ? (
120
+ <View style={[styles.userCard, { backgroundColor: theme.card, borderColor: theme.border }]}>
121
+ <View style={styles.userHeader}>
122
+ <Text style={[styles.userText, { color: theme.text }]}>
123
+ Welcome, <Text style={styles.userName}>{user.name}</Text>
124
+ </Text>
125
+ </View>
126
+ <Text style={[styles.userEmail, { color: theme.text, opacity: 0.7 }]}>
127
+ {user.email}
128
+ </Text>
129
+ <TouchableOpacity style={[styles.signOutButton, { backgroundColor: theme.notification }]} onPress={()=> {
130
+ authClient.signOut();
131
+ }}
132
+ >
133
+ <Text style={styles.signOutText}>Sign Out</Text>
134
+ </TouchableOpacity>
135
+ </View>
136
+ ) : null}
137
+ <View style={[styles.statusCard, { backgroundColor: theme.card, borderColor: theme.border }]}>
138
+ <Text style={[styles.statusCardTitle, { color: theme.text }]}>
139
+ API Status
140
+ </Text>
141
+ <View style={styles.statusRow}>
142
+ <View style={[styles.statusIndicator, { backgroundColor: healthCheck ? "#10b981" : "#ef4444" }]} />
143
+ <Text style={[styles.statusText, { color: theme.text, opacity: 0.7 }]}>
144
+ {healthCheck === undefined
145
+ ? "Checking..."
146
+ : healthCheck === "OK"
147
+ ? "Connected to API"
148
+ : "API Disconnected"}
149
+ </Text>
150
+ </View>
151
+ </View>
152
+ {!user && (
153
+ <>
154
+ <SignIn />
155
+ <SignUp />
156
+ </>
157
+ )}
158
+ {{/if}}
159
+ </View>
160
+ </ScrollView>
161
+ </Container>
162
+ );
163
+ }
164
+
165
+ const styles = StyleSheet.create({
166
+ scrollView: {
167
+ flex: 1,
168
+ },
169
+ content: {
170
+ padding: 16,
171
+ },
172
+ title: {
173
+ fontSize: 24,
174
+ fontWeight: "bold",
175
+ marginBottom: 16,
176
+ },
177
+ card: {
178
+ padding: 16,
179
+ marginBottom: 16,
180
+ borderWidth: 1,
181
+ },
182
+ statusRow: {
183
+ flexDirection: "row",
184
+ alignItems: "center",
185
+ gap: 8,
186
+ },
187
+ statusIndicator: {
188
+ height: 8,
189
+ width: 8,
190
+ },
191
+ statusContent: {
192
+ flex: 1,
193
+ },
194
+ statusTitle: {
195
+ fontSize: 14,
196
+ fontWeight: "bold",
197
+ },
198
+ statusText: {
199
+ fontSize: 12,
200
+ },
201
+ userCard: {
202
+ marginBottom: 16,
203
+ padding: 16,
204
+ borderWidth: 1,
205
+ },
206
+ userHeader: {
207
+ marginBottom: 8,
208
+ },
209
+ userText: {
210
+ fontSize: 16,
211
+ },
212
+ userName: {
213
+ fontWeight: "bold",
214
+ },
215
+ userEmail: {
216
+ fontSize: 14,
217
+ marginBottom: 12,
218
+ },
219
+ signOutButton: {
220
+ padding: 12,
221
+ },
222
+ signOutText: {
223
+ color: "#ffffff",
224
+ },
225
+ statusCard: {
226
+ marginBottom: 16,
227
+ padding: 16,
228
+ borderWidth: 1,
229
+ },
230
+ statusCardTitle: {
231
+ marginBottom: 8,
232
+ fontWeight: "bold",
233
+ },
234
+ });
@@ -0,0 +1,65 @@
1
+ import { Container } from "@/components/container";
2
+ import { Link, Stack } from "expo-router";
3
+ import { Text, View, StyleSheet } from "react-native";
4
+ import { useColorScheme } from "@/lib/use-color-scheme";
5
+ import { NAV_THEME } from "@/lib/constants";
6
+
7
+ export default function NotFoundScreen() {
8
+ const { colorScheme } = useColorScheme();
9
+ const theme = colorScheme === "dark" ? NAV_THEME.dark : NAV_THEME.light;
10
+
11
+ return (
12
+ <>
13
+ <Stack.Screen options=\{{ title: "Oops!" }} />
14
+ <Container>
15
+ <View style={styles.container}>
16
+ <View style={styles.content}>
17
+ <Text style={styles.emoji}>🤔</Text>
18
+ <Text style={[styles.title, { color: theme.text }]}>
19
+ Page Not Found
20
+ </Text>
21
+ <Text style={[styles.subtitle, { color: theme.text, opacity: 0.7 }]}>
22
+ Sorry, the page you're looking for doesn't exist.
23
+ </Text>
24
+ <Link href="/" asChild>
25
+ <Text style={[styles.link, { color: theme.primary, backgroundColor: `${theme.primary}1a` }]}>
26
+ Go to Home
27
+ </Text>
28
+ </Link>
29
+ </View>
30
+ </View>
31
+ </Container>
32
+ </>
33
+ );
34
+ }
35
+
36
+ const styles = StyleSheet.create({
37
+ container: {
38
+ flex: 1,
39
+ justifyContent: "center",
40
+ alignItems: "center",
41
+ padding: 16,
42
+ },
43
+ content: {
44
+ alignItems: "center",
45
+ },
46
+ emoji: {
47
+ fontSize: 48,
48
+ marginBottom: 16,
49
+ },
50
+ title: {
51
+ fontSize: 20,
52
+ fontWeight: "bold",
53
+ marginBottom: 8,
54
+ textAlign: "center",
55
+ },
56
+ subtitle: {
57
+ fontSize: 14,
58
+ textAlign: "center",
59
+ marginBottom: 24,
60
+ },
61
+ link: {
62
+ padding: 12,
63
+ },
64
+ });
65
+
@@ -0,0 +1,163 @@
1
+ {{#if (includes examples "ai")}}
2
+ import "@/polyfills";
3
+ {{/if}}
4
+
5
+ {{#if (eq backend "convex")}}
6
+ {{#if (eq auth "better-auth")}}
7
+ import { ConvexReactClient } from "convex/react";
8
+ import { ConvexBetterAuthProvider } from "@convex-dev/better-auth/react";
9
+ import { authClient } from "@/lib/auth-client";
10
+ {{else}}
11
+ import { ConvexProvider, ConvexReactClient } from "convex/react";
12
+ {{/if}}
13
+ {{#if (eq auth "clerk")}}
14
+ import { ClerkProvider, useAuth } from "@clerk/clerk-expo";
15
+ import { ConvexProviderWithClerk } from "convex/react-clerk";
16
+ import { tokenCache } from "@clerk/clerk-expo/token-cache";
17
+ {{/if}}
18
+ {{else}}
19
+ {{#unless (eq api "none")}}
20
+ import { QueryClientProvider } from "@tanstack/react-query";
21
+ {{/unless}}
22
+ {{/if}}
23
+
24
+ import { Stack } from "expo-router";
25
+ import {
26
+ DarkTheme,
27
+ DefaultTheme,
28
+ type Theme,
29
+ ThemeProvider,
30
+ } from "@react-navigation/native";
31
+ import { StatusBar } from "expo-status-bar";
32
+ import { GestureHandlerRootView } from "react-native-gesture-handler";
33
+ {{#if (eq api "trpc")}}
34
+ import { queryClient } from "@/utils/trpc";
35
+ {{/if}}
36
+ {{#if (eq api "orpc")}}
37
+ import { queryClient } from "@/utils/orpc";
38
+ {{/if}}
39
+ import { NAV_THEME } from "@/lib/constants";
40
+ import React, { useRef } from "react";
41
+ import { useColorScheme } from "@/lib/use-color-scheme";
42
+ import { Platform, StyleSheet } from "react-native";
43
+ import { setAndroidNavigationBar } from "@/lib/android-navigation-bar";
44
+
45
+ const LIGHT_THEME: Theme = {
46
+ ...DefaultTheme,
47
+ colors: NAV_THEME.light,
48
+ };
49
+ const DARK_THEME: Theme = {
50
+ ...DarkTheme,
51
+ colors: NAV_THEME.dark,
52
+ };
53
+
54
+ export const unstable_settings = {
55
+ initialRouteName: "(drawer)",
56
+ };
57
+
58
+ {{#if (eq backend "convex")}}
59
+ const convex = new ConvexReactClient(process.env.EXPO_PUBLIC_CONVEX_URL!, {
60
+ unsavedChangesWarning: false,
61
+ });
62
+ {{/if}}
63
+
64
+ const useIsomorphicLayoutEffect =
65
+ Platform.OS === "web" && typeof window === "undefined"
66
+ ? React.useEffect
67
+ : React.useLayoutEffect;
68
+
69
+ const styles = StyleSheet.create({
70
+ container: {
71
+ flex: 1,
72
+ },
73
+ });
74
+
75
+ export default function RootLayout() {
76
+ const hasMounted = useRef(false);
77
+ const { colorScheme, isDarkColorScheme } = useColorScheme();
78
+ const [isColorSchemeLoaded, setIsColorSchemeLoaded] = React.useState(false);
79
+
80
+ useIsomorphicLayoutEffect(() => {
81
+ if (hasMounted.current) {
82
+ return;
83
+ }
84
+ setAndroidNavigationBar(colorScheme);
85
+ setIsColorSchemeLoaded(true);
86
+ hasMounted.current = true;
87
+ }, []);
88
+
89
+ if (!isColorSchemeLoaded) {
90
+ return null;
91
+ }
92
+
93
+ return (
94
+ <>
95
+ {{#if (eq backend "convex")}}
96
+ {{#if (eq auth "clerk")}}
97
+ <ClerkProvider tokenCache={tokenCache} publishableKey={process.env.EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY}>
98
+ <ConvexProviderWithClerk client={convex} useAuth={useAuth}>
99
+ <ThemeProvider value={isDarkColorScheme ? DARK_THEME : LIGHT_THEME}>
100
+ <StatusBar style={isDarkColorScheme ? "light" : "dark"} />
101
+ <GestureHandlerRootView style={styles.container}>
102
+ <Stack>
103
+ <Stack.Screen name="(drawer)" options=\{{ headerShown: false }} />
104
+ <Stack.Screen name="(auth)" options=\{{ headerShown: false }} />
105
+ <Stack.Screen name="modal" options=\{{ title: "Modal", presentation: "modal" }} />
106
+ </Stack>
107
+ </GestureHandlerRootView>
108
+ </ThemeProvider>
109
+ </ConvexProviderWithClerk>
110
+ </ClerkProvider>
111
+ {{else if (eq auth "better-auth")}}
112
+ <ConvexBetterAuthProvider client={convex} authClient={authClient}>
113
+ <ThemeProvider value={isDarkColorScheme ? DARK_THEME : LIGHT_THEME}>
114
+ <StatusBar style={isDarkColorScheme ? "light" : "dark"} />
115
+ <GestureHandlerRootView style={styles.container}>
116
+ <Stack>
117
+ <Stack.Screen name="(drawer)" options=\{{ headerShown: false }} />
118
+ <Stack.Screen name="modal" options=\{{ title: "Modal", presentation: "modal" }} />
119
+ </Stack>
120
+ </GestureHandlerRootView>
121
+ </ThemeProvider>
122
+ </ConvexBetterAuthProvider>
123
+ {{else}}
124
+ <ConvexProvider client={convex}>
125
+ <ThemeProvider value={isDarkColorScheme ? DARK_THEME : LIGHT_THEME}>
126
+ <StatusBar style={isDarkColorScheme ? "light" : "dark"} />
127
+ <GestureHandlerRootView style={styles.container}>
128
+ <Stack>
129
+ <Stack.Screen name="(drawer)" options=\{{ headerShown: false }} />
130
+ <Stack.Screen name="modal" options=\{{ title: "Modal", presentation: "modal" }} />
131
+ </Stack>
132
+ </GestureHandlerRootView>
133
+ </ThemeProvider>
134
+ </ConvexProvider>
135
+ {{/if}}
136
+ {{else}}
137
+ {{#unless (eq api "none")}}
138
+ <QueryClientProvider client={queryClient}>
139
+ <ThemeProvider value={isDarkColorScheme ? DARK_THEME : LIGHT_THEME}>
140
+ <StatusBar style={isDarkColorScheme ? "light" : "dark"} />
141
+ <GestureHandlerRootView style={styles.container}>
142
+ <Stack>
143
+ <Stack.Screen name="(drawer)" options=\{{ headerShown: false }} />
144
+ <Stack.Screen name="modal" options=\{{ title: "Modal", presentation: "modal" }} />
145
+ </Stack>
146
+ </GestureHandlerRootView>
147
+ </ThemeProvider>
148
+ </QueryClientProvider>
149
+ {{else}}
150
+ <ThemeProvider value={isDarkColorScheme ? DARK_THEME : LIGHT_THEME}>
151
+ <StatusBar style={isDarkColorScheme ? "light" : "dark"} />
152
+ <GestureHandlerRootView style={styles.container}>
153
+ <Stack>
154
+ <Stack.Screen name="(drawer)" options=\{{ headerShown: false }} />
155
+ <Stack.Screen name="modal" options=\{{ title: "Modal", presentation: "modal" }} />
156
+ </Stack>
157
+ </GestureHandlerRootView>
158
+ </ThemeProvider>
159
+ {{/unless}}
160
+ {{/if}}
161
+ </>
162
+ );
163
+ }
@@ -0,0 +1,34 @@
1
+ import { Container } from "@/components/container";
2
+ import { Text, View, StyleSheet } from "react-native";
3
+ import { useColorScheme } from "@/lib/use-color-scheme";
4
+ import { NAV_THEME } from "@/lib/constants";
5
+
6
+ export default function Modal() {
7
+ const { colorScheme } = useColorScheme();
8
+ const theme = colorScheme === "dark" ? NAV_THEME.dark : NAV_THEME.light;
9
+
10
+ return (
11
+ <Container>
12
+ <View style={styles.container}>
13
+ <View style={styles.header}>
14
+ <Text style={[styles.title, { color: theme.text }]}>Modal</Text>
15
+ </View>
16
+ </View>
17
+ </Container>
18
+ );
19
+ }
20
+
21
+ const styles = StyleSheet.create({
22
+ container: {
23
+ flex: 1,
24
+ padding: 16,
25
+ },
26
+ header: {
27
+ marginBottom: 16,
28
+ },
29
+ title: {
30
+ fontSize: 20,
31
+ fontWeight: "bold",
32
+ },
33
+ });
34
+
@@ -0,0 +1,25 @@
1
+ import React from "react";
2
+ import { SafeAreaView } from "react-native-safe-area-context";
3
+ import { useColorScheme } from "@/lib/use-color-scheme";
4
+ import { NAV_THEME } from "@/lib/constants";
5
+ import { StyleSheet } from "react-native";
6
+
7
+ export function Container({ children }: { children: React.ReactNode }) {
8
+ const { colorScheme } = useColorScheme();
9
+ const backgroundColor = colorScheme === "dark"
10
+ ? NAV_THEME.dark.background
11
+ : NAV_THEME.light.background;
12
+
13
+ return (
14
+ <SafeAreaView style={[styles.container, { backgroundColor }]}>
15
+ {children}
16
+ </SafeAreaView>
17
+ );
18
+ }
19
+
20
+ const styles = StyleSheet.create({
21
+ container: {
22
+ flex: 1,
23
+ },
24
+ });
25
+
@@ -0,0 +1,47 @@
1
+ import FontAwesome from "@expo/vector-icons/FontAwesome";
2
+ import { forwardRef } from "react";
3
+ import { Pressable, StyleSheet } from "react-native";
4
+ import { useColorScheme } from "@/lib/use-color-scheme";
5
+ import { NAV_THEME } from "@/lib/constants";
6
+
7
+ export const HeaderButton = forwardRef<
8
+ typeof Pressable,
9
+ { onPress?: () => void }
10
+ >(({ onPress }, ref) => {
11
+ const { colorScheme } = useColorScheme();
12
+ const theme = colorScheme === "dark" ? NAV_THEME.dark : NAV_THEME.light;
13
+
14
+ return (
15
+ <Pressable
16
+ ref={ref}
17
+ onPress={onPress}
18
+ style={({ pressed }) => [
19
+ styles.button,
20
+ {
21
+ backgroundColor: pressed
22
+ ? theme.secondary
23
+ : theme.card,
24
+ },
25
+ ]}
26
+ >
27
+ {({ pressed }) => (
28
+ <FontAwesome
29
+ name="info-circle"
30
+ size={20}
31
+ color={theme.text}
32
+ style=\{{
33
+ opacity: pressed ? 0.7 : 1,
34
+ }}
35
+ />
36
+ )}
37
+ </Pressable>
38
+ );
39
+ });
40
+
41
+ const styles = StyleSheet.create({
42
+ button: {
43
+ padding: 8,
44
+ marginRight: 8,
45
+ },
46
+ });
47
+
@@ -6,3 +6,4 @@ export const TabBarIcon = (props: {
6
6
  }) => {
7
7
  return <FontAwesome size={24} style=\{{ marginBottom: -3 }} {...props} />;
8
8
  };
9
+
@@ -9,3 +9,4 @@ export async function setAndroidNavigationBar(theme: "light" | "dark") {
9
9
  theme === "dark" ? NAV_THEME.dark.background : NAV_THEME.light.background,
10
10
  );
11
11
  }
12
+
@@ -16,3 +16,4 @@ export const NAV_THEME = {
16
16
  text: "hsl(210 40% 98%)",
17
17
  },
18
18
  };
19
+
@@ -0,0 +1,20 @@
1
+ import { useColorScheme as useRNColorScheme } from "react-native";
2
+
3
+ export function useColorScheme() {
4
+ const systemColorScheme = useRNColorScheme();
5
+ const colorScheme = systemColorScheme ?? "light";
6
+
7
+ return {
8
+ colorScheme: colorScheme as "light" | "dark",
9
+ isDarkColorScheme: colorScheme === "dark",
10
+ setColorScheme: () => {
11
+ // Color scheme is managed by the system in bare mode
12
+ console.warn("setColorScheme is not available in bare mode. Color scheme is managed by the system.");
13
+ },
14
+ toggleColorScheme: () => {
15
+ // Color scheme is managed by the system in bare mode
16
+ console.warn("toggleColorScheme is not available in bare mode. Color scheme is managed by the system.");
17
+ },
18
+ };
19
+ }
20
+
@@ -0,0 +1,9 @@
1
+ // Learn more https://docs.expo.io/guides/customizing-metro
2
+ const { getDefaultConfig } = require("expo/metro-config");
3
+
4
+ const config = getDefaultConfig(__dirname);
5
+
6
+ config.resolver.unstable_enablePackageExports = true;
7
+
8
+ module.exports = config;
9
+
@@ -31,7 +31,6 @@
31
31
  "expo-status-bar": "~3.0.7",
32
32
  "expo-system-ui": "~6.0.7",
33
33
  "expo-web-browser": "~15.0.6",
34
- "nativewind": "^4.1.23",
35
34
  "react": "19.1.0",
36
35
  "react-dom": "19.1.0",
37
36
  "react-native": "0.81.4",
@@ -45,8 +44,8 @@
45
44
  "devDependencies": {
46
45
  "@babel/core": "^7.26.10",
47
46
  "@types/react": "~19.1.10",
48
- "tailwindcss": "^3.4.17",
49
47
  "typescript": "~5.8.2"
50
48
  },
51
49
  "private": true
52
50
  }
51
+
@@ -0,0 +1,11 @@
1
+ {
2
+ "extends": "expo/tsconfig.base",
3
+ "compilerOptions": {
4
+ "strict": true,
5
+ "paths": {
6
+ "@/*": ["./*"]
7
+ }
8
+ },
9
+ "include": ["**/*.ts", "**/*.tsx", ".expo/types/**/*.ts", "expo-env.d.ts"]
10
+ }
11
+
@@ -9,17 +9,13 @@ npm-debug.*
9
9
  *.mobileprovision
10
10
  *.orig.*
11
11
  web-build/
12
- # expo router
13
- expo-env.d.ts
14
-
15
- .env
16
- .cache
17
-
18
- ios
19
- android
20
12
 
21
13
  # macOS
22
14
  .DS_Store
23
15
 
24
16
  # Temporary files created by Metro to check the health of the file watcher
25
17
  .metro-health-check*
18
+
19
+ # UniWind generated types
20
+ uniwind-types.d.ts
21
+