create-croissant 0.1.46 → 0.1.48

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 (51) hide show
  1. package/package.json +1 -1
  2. package/template/apps/platform/src/routes/api/auth/$.ts +1 -1
  3. package/template/apps/platform/src/routes/api/rpc.$.ts +2 -2
  4. package/template/package.json +2 -7
  5. package/template/tsconfig.json +1 -2
  6. package/template/.github/dependabot.yml +0 -15
  7. package/template/.github/workflows/ci.yml +0 -143
  8. package/template/.github/workflows/dependabot-automerge.yml +0 -23
  9. package/template/.husky/pre-push +0 -11
  10. package/template/apps/mobile/.vscode/extensions.json +0 -1
  11. package/template/apps/mobile/.vscode/settings.json +0 -7
  12. package/template/apps/mobile/README.md +0 -50
  13. package/template/apps/mobile/app/(tabs)/_layout.tsx +0 -43
  14. package/template/apps/mobile/app/(tabs)/account.tsx +0 -147
  15. package/template/apps/mobile/app/(tabs)/explore.tsx +0 -345
  16. package/template/apps/mobile/app/(tabs)/index.tsx +0 -112
  17. package/template/apps/mobile/app/_layout.tsx +0 -43
  18. package/template/apps/mobile/app/index.tsx +0 -129
  19. package/template/apps/mobile/app/login.tsx +0 -135
  20. package/template/apps/mobile/app/signup.tsx +0 -144
  21. package/template/apps/mobile/app.json +0 -56
  22. package/template/apps/mobile/assets/images/android-icon-background.png +0 -0
  23. package/template/apps/mobile/assets/images/android-icon-foreground.png +0 -0
  24. package/template/apps/mobile/assets/images/android-icon-monochrome.png +0 -0
  25. package/template/apps/mobile/assets/images/favicon.png +0 -0
  26. package/template/apps/mobile/assets/images/icon.png +0 -0
  27. package/template/apps/mobile/assets/images/partial-react-logo.png +0 -0
  28. package/template/apps/mobile/assets/images/react-logo.png +0 -0
  29. package/template/apps/mobile/assets/images/react-logo@2x.png +0 -0
  30. package/template/apps/mobile/assets/images/react-logo@3x.png +0 -0
  31. package/template/apps/mobile/assets/images/splash-icon.png +0 -0
  32. package/template/apps/mobile/components/external-link.tsx +0 -25
  33. package/template/apps/mobile/components/haptic-tab.tsx +0 -18
  34. package/template/apps/mobile/components/hello-wave.tsx +0 -20
  35. package/template/apps/mobile/components/parallax-scroll-view.tsx +0 -81
  36. package/template/apps/mobile/components/themed-text.tsx +0 -60
  37. package/template/apps/mobile/components/themed-view.tsx +0 -14
  38. package/template/apps/mobile/components/ui/button.tsx +0 -86
  39. package/template/apps/mobile/components/ui/collapsible.tsx +0 -46
  40. package/template/apps/mobile/components/ui/icon-symbol.ios.tsx +0 -32
  41. package/template/apps/mobile/components/ui/icon-symbol.tsx +0 -41
  42. package/template/apps/mobile/components/ui/input.tsx +0 -56
  43. package/template/apps/mobile/constants/theme.ts +0 -53
  44. package/template/apps/mobile/hooks/use-color-scheme.ts +0 -1
  45. package/template/apps/mobile/hooks/use-color-scheme.web.ts +0 -21
  46. package/template/apps/mobile/hooks/use-theme-color.ts +0 -21
  47. package/template/apps/mobile/lib/auth-client.ts +0 -14
  48. package/template/apps/mobile/lib/orpc.ts +0 -28
  49. package/template/apps/mobile/package.json +0 -57
  50. package/template/apps/mobile/scripts/reset-project.js +0 -112
  51. package/template/apps/mobile/tsconfig.json +0 -13
@@ -1,345 +0,0 @@
1
- import { useState } from "react";
2
- import {
3
- Alert,
4
- FlatList,
5
- Modal,
6
- StyleSheet,
7
- Text,
8
- View,
9
- ActivityIndicator,
10
- ScrollView,
11
- } from "react-native";
12
- import { useQueryClient } from "@tanstack/react-query";
13
- import { useForm } from "@tanstack/react-form";
14
- import { z } from "zod";
15
- import { Button } from "@/components/ui/button";
16
- import { Input } from "@/components/ui/input";
17
- import { usePlanets, useCreatePlanet, useUpdatePlanet, useDeletePlanet } from "@workspace/orpc/react";
18
-
19
- const planetSchema = z.object({
20
- name: z.string().min(1, "Name is required"),
21
- description: z.string(),
22
- distance: z.string().refine((val) => !isNaN(parseFloat(val)), {
23
- message: "Must be a number",
24
- }),
25
- diameter: z.string().refine((val) => !isNaN(parseFloat(val)), {
26
- message: "Must be a number",
27
- }),
28
- });
29
-
30
- export default function ExploreScreen() {
31
- const [modalVisible, setModalVisible] = useState(false);
32
- const [editingId, setEditingId] = useState<number | null>(null);
33
-
34
- const { data: planets = [], isLoading } = usePlanets();
35
-
36
- const form = useForm({
37
- defaultValues: {
38
- name: "",
39
- description: "",
40
- distance: "0",
41
- diameter: "0",
42
- },
43
- validators: {
44
- onChange: planetSchema,
45
- },
46
- onSubmit: async ({ value }) => {
47
- const payload = {
48
- name: value.name,
49
- description: value.description || undefined,
50
- distanceFromSun: parseFloat(value.distance) || 0,
51
- diameter: parseFloat(value.diameter) || 0,
52
- hasRings: false,
53
- };
54
- console.log('connard')
55
-
56
- try {
57
- if (editingId) {
58
- await updateMutation.mutateAsync({ id: editingId, ...payload });
59
- } else {
60
- await createMutation.mutateAsync(payload);
61
- }
62
- closeModal();
63
- } catch (err) {
64
- // Error handled in mutation callbacks
65
- }
66
- },
67
- });
68
-
69
- const resetForm = () => {
70
- form.reset();
71
- setEditingId(null);
72
- };
73
-
74
- const createMutation = useCreatePlanet({
75
- onSuccess: () => {
76
- Alert.alert("Success", "Planet added successfully");
77
- },
78
- onError: (err) => {
79
- Alert.alert("Error", err.message || "Failed to add planet");
80
- },
81
- });
82
-
83
- const updateMutation = useUpdatePlanet({
84
- onSuccess: () => {
85
- Alert.alert("Success", "Planet updated successfully");
86
- },
87
- onError: (err) => {
88
- Alert.alert("Error", err.message || "Failed to update planet");
89
- },
90
- });
91
-
92
- const deleteMutation = useDeletePlanet({
93
- onSuccess: () => {
94
- Alert.alert("Success", "Planet deleted successfully");
95
- },
96
- onError: (err) => {
97
- Alert.alert("Error", err.message || "Failed to delete planet");
98
- },
99
- });
100
-
101
- const handleEdit = (planet: any) => {
102
- setEditingId(planet.id);
103
- form.setFieldValue("name", planet.name);
104
- form.setFieldValue("description", planet.description || "");
105
- form.setFieldValue("distance", planet.distanceFromSun.toString());
106
- form.setFieldValue("diameter", planet.diameter.toString());
107
- setModalVisible(true);
108
- };
109
-
110
- const handleDelete = (id: number) => {
111
- deleteMutation.mutateAsync({id})
112
- };
113
-
114
- const closeModal = () => {
115
- setModalVisible(false);
116
- resetForm();
117
- };
118
-
119
- if (isLoading) {
120
- return (
121
- <View style={styles.center}>
122
- <ActivityIndicator size="large" color="#000" />
123
- </View>
124
- );
125
- }
126
-
127
- return (
128
- <View style={styles.container}>
129
- <FlatList
130
- data={planets}
131
- keyExtractor={(item) => item.id.toString()}
132
- contentContainerStyle={styles.listContent}
133
- renderItem={({ item }) => (
134
- <View style={styles.planetCard}>
135
- <View style={styles.planetInfo}>
136
- <Text style={styles.planetName}>{item.name}</Text>
137
- <Text style={styles.planetDesc}>{item.description}</Text>
138
- <Text style={styles.planetDetails}>
139
- Distance: {item.distanceFromSun} AU • Diameter: {item.diameter} km
140
- </Text>
141
- </View>
142
- <View style={styles.actions}>
143
- <Button
144
- variant="outline"
145
- onPress={() => handleEdit(item)}
146
- style={styles.actionBtn}
147
- >
148
- Edit
149
- </Button>
150
- <Button
151
- variant="destructive"
152
- onPress={() => handleDelete(item.id)}
153
- style={styles.actionBtn}
154
- >
155
- Delete
156
- </Button>
157
- </View>
158
- </View>
159
- )}
160
- ListEmptyComponent={
161
- <Text style={styles.emptyText}>No planets found. Add one!</Text>
162
- }
163
- />
164
-
165
- <Button
166
- onPress={() => setModalVisible(true)}
167
- style={styles.fab}
168
- >
169
- Add Planet
170
- </Button>
171
-
172
- <Modal
173
- visible={modalVisible}
174
- animationType="slide"
175
- onRequestClose={closeModal}
176
- >
177
- <View style={styles.modalContainer}>
178
- <ScrollView contentContainerStyle={styles.modalContent}>
179
- <Text style={styles.modalTitle}>
180
- {editingId ? "Edit Planet" : "Add New Planet"}
181
- </Text>
182
-
183
- <form.Field name="name">
184
- {(field: any) => (
185
- <Input
186
- label="Name"
187
- value={field.state.value}
188
- onChangeText={field.handleChange}
189
- placeholder="Earth"
190
- error={field.state.meta.errors?.[0]?.toString()}
191
- />
192
- )}
193
- </form.Field>
194
-
195
- <form.Field name="description">
196
- {(field: any) => (
197
- <Input
198
- label="Description"
199
- value={field.state.value}
200
- onChangeText={field.handleChange}
201
- placeholder="The blue planet"
202
- />
203
- )}
204
- </form.Field>
205
-
206
- <form.Field name="distance">
207
- {(field: any) => (
208
- <Input
209
- label="Distance from Sun (AU)"
210
- value={field.state.value}
211
- onChangeText={field.handleChange}
212
- keyboardType="numeric"
213
- error={field.state.meta.errors?.[0]?.toString()}
214
- />
215
- )}
216
- </form.Field>
217
-
218
- <form.Field name="diameter">
219
- {(field: any) => (
220
- <Input
221
- label="Diameter (km)"
222
- value={field.state.value}
223
- onChangeText={field.handleChange}
224
- keyboardType="numeric"
225
- error={field.state.meta.errors?.[0]?.toString()}
226
- />
227
- )}
228
- </form.Field>
229
-
230
- <View style={styles.modalActions}>
231
- <Button
232
- variant="outline"
233
- onPress={closeModal}
234
- style={styles.modalBtn}
235
- >
236
- Cancel
237
- </Button>
238
- <Button
239
- onPress={form.handleSubmit}
240
- loading={createMutation.isPending || updateMutation.isPending}
241
- style={styles.modalBtn}
242
- >
243
- {editingId ? "Update" : "Create"}
244
- </Button>
245
- </View>
246
- </ScrollView>
247
- </View>
248
- </Modal>
249
- </View>
250
- );
251
- }
252
-
253
- const styles = StyleSheet.create({
254
- container: {
255
- flex: 1,
256
- backgroundColor: "#fff",
257
- },
258
- center: {
259
- flex: 1,
260
- justifyContent: "center",
261
- alignItems: "center",
262
- },
263
- listContent: {
264
- padding: 16,
265
- paddingBottom: 100,
266
- },
267
- planetCard: {
268
- padding: 16,
269
- borderRadius: 12,
270
- borderWidth: 1,
271
- borderColor: "#eee",
272
- marginBottom: 16,
273
- backgroundColor: "#fff",
274
- shadowColor: "#000",
275
- shadowOffset: { width: 0, height: 2 },
276
- shadowOpacity: 0.05,
277
- shadowRadius: 4,
278
- elevation: 2,
279
- },
280
- planetInfo: {
281
- marginBottom: 16,
282
- },
283
- planetName: {
284
- fontSize: 18,
285
- fontWeight: "bold",
286
- marginBottom: 4,
287
- },
288
- planetDesc: {
289
- fontSize: 14,
290
- color: "#666",
291
- marginBottom: 8,
292
- },
293
- planetDetails: {
294
- fontSize: 12,
295
- color: "#999",
296
- },
297
- actions: {
298
- flexDirection: "row",
299
- gap: 8,
300
- },
301
- actionBtn: {
302
- flex: 1,
303
- height: 36,
304
- },
305
- emptyText: {
306
- textAlign: "center",
307
- marginTop: 40,
308
- color: "#999",
309
- fontStyle: "italic",
310
- },
311
- fab: {
312
- position: "absolute",
313
- bottom: 24,
314
- left: 24,
315
- right: 24,
316
- height: 56,
317
- borderRadius: 28,
318
- shadowColor: "#000",
319
- shadowOffset: { width: 0, height: 4 },
320
- shadowOpacity: 0.2,
321
- shadowRadius: 8,
322
- elevation: 5,
323
- },
324
- modalContainer: {
325
- flex: 1,
326
- backgroundColor: "#fff",
327
- },
328
- modalContent: {
329
- padding: 24,
330
- paddingTop: 60,
331
- },
332
- modalTitle: {
333
- fontSize: 24,
334
- fontWeight: "bold",
335
- marginBottom: 32,
336
- },
337
- modalActions: {
338
- flexDirection: "row",
339
- gap: 12,
340
- marginTop: 32,
341
- },
342
- modalBtn: {
343
- flex: 1,
344
- },
345
- });
@@ -1,112 +0,0 @@
1
- import { useEffect } from "react";
2
- import { View, Text, StyleSheet, ScrollView, Platform } from "react-native";
3
- import { useRouter } from "expo-router";
4
- import { authClient } from "@/lib/auth-client";
5
- import { useSecretData } from "@workspace/orpc/react";
6
- import { Button } from "@/components/ui/button";
7
-
8
- export default function DashboardScreen() {
9
- const router = useRouter();
10
- const { data: session, isPending: isAuthPending } = authClient.useSession();
11
-
12
- const { data: secretData, isLoading: isLoadingSecret, error: secretError } = useSecretData({
13
- enabled: !!session,
14
- });
15
-
16
- useEffect(() => {
17
- if (!isAuthPending && !session) {
18
- router.replace("/login");
19
- }
20
- }, [session, isAuthPending, router]);
21
-
22
- const handleSignOut = async () => {
23
- await authClient.signOut();
24
- router.replace("/");
25
- };
26
-
27
- if (isAuthPending) {
28
- return (
29
- <View style={styles.center}>
30
- <Text>Loading dashboard...</Text>
31
- </View>
32
- );
33
- }
34
-
35
- return (
36
- <ScrollView style={styles.container} contentContainerStyle={styles.content}>
37
- <Text style={styles.title}>Dashboard</Text>
38
- <Text style={styles.welcome}>Welcome, {session?.user?.name}!</Text>
39
- <Text style={styles.description}>
40
- This is a protected page. Only authenticated users can see this.
41
- </Text>
42
-
43
- <View style={styles.secureBox}>
44
- <Text style={styles.secureTitle}>Secure oRPC Data:</Text>
45
- {isLoadingSecret ? (
46
- <Text style={styles.secureContent}>Loading secret data...</Text>
47
- ) : secretError ? (
48
- <Text style={[styles.secureContent, styles.errorText]}>
49
- Error: {secretError.message || "Unknown error"}
50
- </Text>
51
- ) : (
52
- <Text style={styles.secureContent}>{secretData?.secret}</Text>
53
- )}
54
- </View>
55
-
56
- <Button variant="destructive" onPress={handleSignOut} style={styles.signOutBtn}>
57
- Sign Out
58
- </Button>
59
- </ScrollView>
60
- );
61
- }
62
-
63
- const styles = StyleSheet.create({
64
- container: {
65
- flex: 1,
66
- backgroundColor: "#fff",
67
- },
68
- content: {
69
- padding: 24,
70
- },
71
- center: {
72
- flex: 1,
73
- justifyContent: "center",
74
- alignItems: "center",
75
- },
76
- title: {
77
- fontSize: 28,
78
- fontWeight: "bold",
79
- marginBottom: 8,
80
- },
81
- welcome: {
82
- fontSize: 18,
83
- marginBottom: 8,
84
- },
85
- description: {
86
- fontSize: 14,
87
- color: "#666",
88
- marginBottom: 24,
89
- },
90
- secureBox: {
91
- padding: 16,
92
- backgroundColor: "#f9f9f9",
93
- borderRadius: 8,
94
- borderWidth: 1,
95
- borderColor: "#eee",
96
- marginBottom: 24,
97
- },
98
- secureTitle: {
99
- fontWeight: "600",
100
- marginBottom: 8,
101
- },
102
- secureContent: {
103
- fontFamily: Platform.OS === "ios" ? "Courier" : "monospace",
104
- fontSize: 12,
105
- },
106
- errorText: {
107
- color: "#ef4444",
108
- },
109
- signOutBtn: {
110
- marginTop: 12,
111
- },
112
- });
@@ -1,43 +0,0 @@
1
- import { DarkTheme, DefaultTheme, ThemeProvider } from "@react-navigation/native";
2
- import { Stack } from "expo-router";
3
- import { StatusBar } from "expo-status-bar";
4
- import "react-native-reanimated";
5
- import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
6
- import { ORPCProvider } from "@workspace/orpc/react";
7
- import { orpc } from "@/lib/orpc";
8
-
9
- import { useColorScheme } from "@/hooks/use-color-scheme";
10
-
11
- const queryClient = new QueryClient({
12
- defaultOptions: {
13
- mutations: {
14
- onError: (error) => {
15
- console.error("Global Mutation Error:", error);
16
- },
17
- },
18
- },
19
- });
20
-
21
- export const unstable_settings = {
22
- anchor: "(tabs)",
23
- };
24
-
25
- export default function RootLayout() {
26
- const colorScheme = useColorScheme();
27
-
28
- return (
29
- <QueryClientProvider client={queryClient}>
30
- <ORPCProvider client={orpc}>
31
- <ThemeProvider value={colorScheme === "dark" ? DarkTheme : DefaultTheme}>
32
- <Stack>
33
- <Stack.Screen name="index" options={{ headerShown: false }} />
34
- <Stack.Screen name="(tabs)" options={{ headerShown: false }} />
35
- <Stack.Screen name="login" options={{ title: "Login" }} />
36
- <Stack.Screen name="signup" options={{ title: "Sign Up" }} />
37
- </Stack>
38
- <StatusBar style="auto" />
39
- </ThemeProvider>
40
- </ORPCProvider>
41
- </QueryClientProvider>
42
- );
43
- }
@@ -1,129 +0,0 @@
1
- import { View, Text, StyleSheet, ScrollView } from "react-native";
2
- import { useRouter } from "expo-router";
3
- import { Button } from "@/components/ui/button";
4
- import { usePlanets, useHello } from "@workspace/orpc/react";
5
-
6
- export default function LandingScreen() {
7
- const router = useRouter();
8
- const { data: helloData, isLoading: isHelloLoading } = useHello("Croissant Stack Mobile");
9
- const { data: planets = [], isLoading: isPlanetsLoading } = usePlanets();
10
-
11
- return (
12
- <ScrollView style={styles.container} contentContainerStyle={styles.content}>
13
- <View style={styles.header}>
14
- <Text style={styles.title}>Project ready!</Text>
15
- <Text style={styles.subtitle}>
16
- oRPC integration: <Text style={styles.bold}>
17
- {isHelloLoading ? "Loading..." : helloData?.message}
18
- </Text>
19
- </Text>
20
- </View>
21
-
22
- <View style={styles.section}>
23
- <Text style={styles.sectionTitle}>Planets from Database:</Text>
24
- {isPlanetsLoading ? (
25
- <Text style={styles.loading}>Loading planets...</Text>
26
- ) : planets.length === 0 ? (
27
- <Text style={styles.empty}>
28
- No planets found in the database. Run `db:push` and seed data if needed.
29
- </Text>
30
- ) : (
31
- planets.map((planet: any) => (
32
- <View key={planet.id} style={styles.planetCard}>
33
- <Text style={styles.planetName}>{planet.name}</Text>
34
- <Text style={styles.planetDesc}>{planet.description}</Text>
35
- </View>
36
- ))
37
- )}
38
- </View>
39
-
40
- <View style={styles.footer}>
41
- <Button onPress={() => router.push("/login")} style={styles.button}>
42
- Go to Login
43
- </Button>
44
- <Button
45
- onPress={() => router.push("/(tabs)")}
46
- variant="outline"
47
- style={styles.button}
48
- >
49
- Go to Dashboard
50
- </Button>
51
- <Text style={styles.footerText}>
52
- You may now add components and start building.
53
- </Text>
54
- </View>
55
- </ScrollView>
56
- );
57
- }
58
-
59
- const styles = StyleSheet.create({
60
- container: {
61
- flex: 1,
62
- backgroundColor: "#fff",
63
- },
64
- content: {
65
- padding: 24,
66
- paddingTop: 60,
67
- },
68
- header: {
69
- marginBottom: 32,
70
- },
71
- title: {
72
- fontSize: 28,
73
- fontWeight: "bold",
74
- marginBottom: 8,
75
- },
76
- subtitle: {
77
- fontSize: 16,
78
- color: "#666",
79
- },
80
- bold: {
81
- fontWeight: "bold",
82
- color: "#000",
83
- },
84
- section: {
85
- marginBottom: 32,
86
- },
87
- sectionTitle: {
88
- fontSize: 20,
89
- fontWeight: "600",
90
- marginBottom: 16,
91
- },
92
- planetCard: {
93
- padding: 16,
94
- borderRadius: 8,
95
- borderWidth: 1,
96
- borderColor: "#eee",
97
- marginBottom: 12,
98
- backgroundColor: "#fafafa",
99
- },
100
- planetName: {
101
- fontSize: 16,
102
- fontWeight: "bold",
103
- marginBottom: 4,
104
- },
105
- planetDesc: {
106
- fontSize: 14,
107
- color: "#666",
108
- },
109
- loading: {
110
- fontStyle: "italic",
111
- color: "#999",
112
- },
113
- empty: {
114
- fontStyle: "italic",
115
- color: "#999",
116
- },
117
- footer: {
118
- gap: 12,
119
- },
120
- button: {
121
- width: "100%",
122
- },
123
- footerText: {
124
- marginTop: 16,
125
- textAlign: "center",
126
- color: "#999",
127
- fontSize: 14,
128
- },
129
- });