create-croissant 0.1.47 → 0.1.49

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 (37) hide show
  1. package/package.json +1 -1
  2. package/template/apps/mobile/README.md +3 -3
  3. package/template/apps/mobile/app/(tabs)/_layout.tsx +17 -25
  4. package/template/apps/mobile/app/(tabs)/explore.tsx +104 -337
  5. package/template/apps/mobile/app/(tabs)/index.tsx +85 -99
  6. package/template/apps/mobile/app/_layout.tsx +13 -32
  7. package/template/apps/mobile/app/modal.tsx +29 -0
  8. package/template/apps/mobile/app.json +6 -14
  9. package/template/apps/mobile/components/external-link.tsx +5 -5
  10. package/template/apps/mobile/components/haptic-tab.tsx +4 -4
  11. package/template/apps/mobile/components/hello-wave.tsx +4 -5
  12. package/template/apps/mobile/components/parallax-scroll-view.tsx +13 -15
  13. package/template/apps/mobile/components/themed-text.tsx +14 -14
  14. package/template/apps/mobile/components/themed-view.tsx +3 -3
  15. package/template/apps/mobile/components/ui/collapsible.tsx +13 -14
  16. package/template/apps/mobile/components/ui/icon-symbol.ios.tsx +4 -4
  17. package/template/apps/mobile/components/ui/icon-symbol.tsx +9 -9
  18. package/template/apps/mobile/constants/theme.ts +19 -19
  19. package/template/apps/mobile/hooks/use-color-scheme.ts +1 -1
  20. package/template/apps/mobile/hooks/use-color-scheme.web.ts +3 -3
  21. package/template/apps/mobile/hooks/use-theme-color.ts +4 -4
  22. package/template/apps/mobile/package.json +26 -38
  23. package/template/apps/mobile/scripts/reset-project.js +2 -2
  24. package/template/apps/mobile/tsconfig.json +9 -2
  25. package/template/apps/platform/src/routes/api/auth/$.ts +1 -1
  26. package/template/apps/platform/src/routes/api/rpc.$.ts +2 -2
  27. package/template/package.json +12 -14
  28. package/template/pnpm-workspace.yaml +8 -0
  29. package/template/tsconfig.json +1 -2
  30. package/template/apps/mobile/app/(tabs)/account.tsx +0 -147
  31. package/template/apps/mobile/app/index.tsx +0 -129
  32. package/template/apps/mobile/app/login.tsx +0 -135
  33. package/template/apps/mobile/app/signup.tsx +0 -144
  34. package/template/apps/mobile/components/ui/button.tsx +0 -86
  35. package/template/apps/mobile/components/ui/input.tsx +0 -56
  36. package/template/apps/mobile/lib/auth-client.ts +0 -14
  37. package/template/apps/mobile/lib/orpc.ts +0 -28
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-croissant",
3
- "version": "0.1.47",
3
+ "version": "0.1.49",
4
4
  "description": "Scaffold a new project using the Croissant Stack",
5
5
  "repository": {
6
6
  "type": "git",
@@ -7,13 +7,13 @@ This is an [Expo](https://expo.dev) project created with [`create-expo-app`](htt
7
7
  1. Install dependencies
8
8
 
9
9
  ```bash
10
- pnpm install
10
+ npm install
11
11
  ```
12
12
 
13
13
  2. Start the app
14
14
 
15
15
  ```bash
16
- pnpm dlx expo start
16
+ npx expo start
17
17
  ```
18
18
 
19
19
  In the output, you'll find options to open the app in a
@@ -30,7 +30,7 @@ You can start developing by editing the files inside the **app** directory. This
30
30
  When you're ready, run:
31
31
 
32
32
  ```bash
33
- pnpm run reset-project
33
+ npm run reset-project
34
34
  ```
35
35
 
36
36
  This command will move the starter code to the **app-example** directory and create a blank **app** directory where you can start developing.
@@ -1,41 +1,33 @@
1
- import React from "react";
2
- import { Tabs } from "expo-router";
3
- import { Ionicons } from "@expo/vector-icons";
1
+ import { Tabs } from 'expo-router';
2
+ import React from 'react';
3
+
4
+ import { HapticTab } from '@/components/haptic-tab';
5
+ import { IconSymbol } from '@/components/ui/icon-symbol';
6
+ import { Colors } from '@/constants/theme';
7
+ import { useColorScheme } from '@/hooks/use-color-scheme';
4
8
 
5
9
  export default function TabLayout() {
10
+ const colorScheme = useColorScheme();
11
+
6
12
  return (
7
13
  <Tabs
8
14
  screenOptions={{
9
- tabBarActiveTintColor: "#000",
10
- tabBarInactiveTintColor: "#888",
11
- headerShown: true,
12
- }}
13
- >
15
+ tabBarActiveTintColor: Colors[colorScheme ?? 'light'].tint,
16
+ headerShown: false,
17
+ tabBarButton: HapticTab,
18
+ }}>
14
19
  <Tabs.Screen
15
20
  name="index"
16
21
  options={{
17
- title: "Dashboard",
18
- tabBarIcon: ({ color, size }) => (
19
- <Ionicons name="home" size={size} color={color} />
20
- ),
22
+ title: 'Home',
23
+ tabBarIcon: ({ color }) => <IconSymbol size={28} name="house.fill" color={color} />,
21
24
  }}
22
25
  />
23
26
  <Tabs.Screen
24
27
  name="explore"
25
28
  options={{
26
- title: "Explore",
27
- tabBarIcon: ({ color, size }) => (
28
- <Ionicons name="planet" size={size} color={color} />
29
- ),
30
- }}
31
- />
32
- <Tabs.Screen
33
- name="account"
34
- options={{
35
- title: "Account",
36
- tabBarIcon: ({ color, size }) => (
37
- <Ionicons name="person" size={size} color={color} />
38
- ),
29
+ title: 'Explore',
30
+ tabBarIcon: ({ color }) => <IconSymbol size={28} name="paperplane.fill" color={color} />,
39
31
  }}
40
32
  />
41
33
  </Tabs>
@@ -1,345 +1,112 @@
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
-
1
+ import { Image } from 'expo-image';
2
+ import { Platform, StyleSheet } from 'react-native';
3
+
4
+ import { Collapsible } from '@/components/ui/collapsible';
5
+ import { ExternalLink } from '@/components/external-link';
6
+ import ParallaxScrollView from '@/components/parallax-scroll-view';
7
+ import { ThemedText } from '@/components/themed-text';
8
+ import { ThemedView } from '@/components/themed-view';
9
+ import { IconSymbol } from '@/components/ui/icon-symbol';
10
+ import { Fonts } from '@/constants/theme';
11
+
12
+ export default function TabTwoScreen() {
127
13
  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>
14
+ <ParallaxScrollView
15
+ headerBackgroundColor={{ light: '#D0D0D0', dark: '#353636' }}
16
+ headerImage={
17
+ <IconSymbol
18
+ size={310}
19
+ color="#808080"
20
+ name="chevron.left.forwardslash.chevron.right"
21
+ style={styles.headerImage}
22
+ />
23
+ }>
24
+ <ThemedView style={styles.titleContainer}>
25
+ <ThemedText
26
+ type="title"
27
+ style={{
28
+ fontFamily: Fonts.rounded,
29
+ }}>
30
+ Explore
31
+ </ThemedText>
32
+ </ThemedView>
33
+ <ThemedText>This app includes example code to help you get started.</ThemedText>
34
+ <Collapsible title="File-based routing">
35
+ <ThemedText>
36
+ This app has two screens:{' '}
37
+ <ThemedText type="defaultSemiBold">app/(tabs)/index.tsx</ThemedText> and{' '}
38
+ <ThemedText type="defaultSemiBold">app/(tabs)/explore.tsx</ThemedText>
39
+ </ThemedText>
40
+ <ThemedText>
41
+ The layout file in <ThemedText type="defaultSemiBold">app/(tabs)/_layout.tsx</ThemedText>{' '}
42
+ sets up the tab navigator.
43
+ </ThemedText>
44
+ <ExternalLink href="https://docs.expo.dev/router/introduction">
45
+ <ThemedText type="link">Learn more</ThemedText>
46
+ </ExternalLink>
47
+ </Collapsible>
48
+ <Collapsible title="Android, iOS, and web support">
49
+ <ThemedText>
50
+ You can open this project on Android, iOS, and the web. To open the web version, press{' '}
51
+ <ThemedText type="defaultSemiBold">w</ThemedText> in the terminal running this project.
52
+ </ThemedText>
53
+ </Collapsible>
54
+ <Collapsible title="Images">
55
+ <ThemedText>
56
+ For static images, you can use the <ThemedText type="defaultSemiBold">@2x</ThemedText> and{' '}
57
+ <ThemedText type="defaultSemiBold">@3x</ThemedText> suffixes to provide files for
58
+ different screen densities
59
+ </ThemedText>
60
+ <Image
61
+ source={require('@/assets/images/react-logo.png')}
62
+ style={{ width: 100, height: 100, alignSelf: 'center' }}
63
+ />
64
+ <ExternalLink href="https://reactnative.dev/docs/images">
65
+ <ThemedText type="link">Learn more</ThemedText>
66
+ </ExternalLink>
67
+ </Collapsible>
68
+ <Collapsible title="Light and dark mode components">
69
+ <ThemedText>
70
+ This template has light and dark mode support. The{' '}
71
+ <ThemedText type="defaultSemiBold">useColorScheme()</ThemedText> hook lets you inspect
72
+ what the user&apos;s current color scheme is, and so you can adjust UI colors accordingly.
73
+ </ThemedText>
74
+ <ExternalLink href="https://docs.expo.dev/develop/user-interface/color-themes/">
75
+ <ThemedText type="link">Learn more</ThemedText>
76
+ </ExternalLink>
77
+ </Collapsible>
78
+ <Collapsible title="Animations">
79
+ <ThemedText>
80
+ This template includes an example of an animated component. The{' '}
81
+ <ThemedText type="defaultSemiBold">components/HelloWave.tsx</ThemedText> component uses
82
+ the powerful{' '}
83
+ <ThemedText type="defaultSemiBold" style={{ fontFamily: Fonts.mono }}>
84
+ react-native-reanimated
85
+ </ThemedText>{' '}
86
+ library to create a waving hand animation.
87
+ </ThemedText>
88
+ {Platform.select({
89
+ ios: (
90
+ <ThemedText>
91
+ The <ThemedText type="defaultSemiBold">components/ParallaxScrollView.tsx</ThemedText>{' '}
92
+ component provides a parallax effect for the header image.
93
+ </ThemedText>
94
+ ),
95
+ })}
96
+ </Collapsible>
97
+ </ParallaxScrollView>
250
98
  );
251
99
  }
252
100
 
253
101
  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",
102
+ headerImage: {
103
+ color: '#808080',
104
+ bottom: -90,
105
+ left: -35,
106
+ position: 'absolute',
107
+ },
108
+ titleContainer: {
109
+ flexDirection: 'row',
299
110
  gap: 8,
300
111
  },
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
112
  });