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
@@ -3,26 +3,26 @@
3
3
  * There are many other ways to style your app. For example, [Nativewind](https://www.nativewind.dev/), [Tamagui](https://tamagui.dev/), [unistyles](https://reactnativeunistyles.vercel.app), etc.
4
4
  */
5
5
 
6
- import { Platform } from "react-native";
6
+ import { Platform } from 'react-native';
7
7
 
8
- const tintColorLight = "#0a7ea4";
9
- const tintColorDark = "#fff";
8
+ const tintColorLight = '#0a7ea4';
9
+ const tintColorDark = '#fff';
10
10
 
11
11
  export const Colors = {
12
12
  light: {
13
- text: "#11181C",
14
- background: "#fff",
13
+ text: '#11181C',
14
+ background: '#fff',
15
15
  tint: tintColorLight,
16
- icon: "#687076",
17
- tabIconDefault: "#687076",
16
+ icon: '#687076',
17
+ tabIconDefault: '#687076',
18
18
  tabIconSelected: tintColorLight,
19
19
  },
20
20
  dark: {
21
- text: "#ECEDEE",
22
- background: "#151718",
21
+ text: '#ECEDEE',
22
+ background: '#151718',
23
23
  tint: tintColorDark,
24
- icon: "#9BA1A6",
25
- tabIconDefault: "#9BA1A6",
24
+ icon: '#9BA1A6',
25
+ tabIconDefault: '#9BA1A6',
26
26
  tabIconSelected: tintColorDark,
27
27
  },
28
28
  };
@@ -30,19 +30,19 @@ export const Colors = {
30
30
  export const Fonts = Platform.select({
31
31
  ios: {
32
32
  /** iOS `UIFontDescriptorSystemDesignDefault` */
33
- sans: "system-ui",
33
+ sans: 'system-ui',
34
34
  /** iOS `UIFontDescriptorSystemDesignSerif` */
35
- serif: "ui-serif",
35
+ serif: 'ui-serif',
36
36
  /** iOS `UIFontDescriptorSystemDesignRounded` */
37
- rounded: "ui-rounded",
37
+ rounded: 'ui-rounded',
38
38
  /** iOS `UIFontDescriptorSystemDesignMonospaced` */
39
- mono: "ui-monospace",
39
+ mono: 'ui-monospace',
40
40
  },
41
41
  default: {
42
- sans: "normal",
43
- serif: "serif",
44
- rounded: "normal",
45
- mono: "monospace",
42
+ sans: 'normal',
43
+ serif: 'serif',
44
+ rounded: 'normal',
45
+ mono: 'monospace',
46
46
  },
47
47
  web: {
48
48
  sans: "system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif",
@@ -1 +1 @@
1
- export { useColorScheme } from "react-native";
1
+ export { useColorScheme } from 'react-native';
@@ -1,5 +1,5 @@
1
- import { useEffect, useState } from "react";
2
- import { useColorScheme as useRNColorScheme } from "react-native";
1
+ import { useEffect, useState } from 'react';
2
+ import { useColorScheme as useRNColorScheme } from 'react-native';
3
3
 
4
4
  /**
5
5
  * To support static rendering, this value needs to be re-calculated on the client side for web
@@ -17,5 +17,5 @@ export function useColorScheme() {
17
17
  return colorScheme;
18
18
  }
19
19
 
20
- return "light";
20
+ return 'light';
21
21
  }
@@ -3,14 +3,14 @@
3
3
  * https://docs.expo.dev/guides/color-schemes/
4
4
  */
5
5
 
6
- import { Colors } from "@/constants/theme";
7
- import { useColorScheme } from "@/hooks/use-color-scheme";
6
+ import { Colors } from '@/constants/theme';
7
+ import { useColorScheme } from '@/hooks/use-color-scheme';
8
8
 
9
9
  export function useThemeColor(
10
10
  props: { light?: string; dark?: string },
11
- colorName: keyof typeof Colors.light & keyof typeof Colors.dark,
11
+ colorName: keyof typeof Colors.light & keyof typeof Colors.dark
12
12
  ) {
13
- const theme = useColorScheme() ?? "light";
13
+ const theme = useColorScheme() ?? 'light';
14
14
  const colorFromProps = props[theme];
15
15
 
16
16
  if (colorFromProps) {
@@ -1,57 +1,45 @@
1
1
  {
2
2
  "name": "mobile",
3
- "version": "1.0.0",
4
- "private": true,
5
3
  "main": "expo-router/entry",
4
+ "version": "1.0.0",
6
5
  "scripts": {
7
6
  "dev": "expo start",
8
7
  "start": "expo start",
9
8
  "reset-project": "node ./scripts/reset-project.js",
10
9
  "android": "expo start --android",
11
10
  "ios": "expo start --ios",
12
- "web": "expo start --web",
13
- "build": "expo export --output-dir .output"
11
+ "web": "expo start --web"
14
12
  },
15
13
  "dependencies": {
16
- "@better-auth/expo": "^1.6.9",
17
14
  "@expo/vector-icons": "^15.0.3",
18
- "@orpc/client": "^1.14.0",
19
- "@orpc/server": "^1.14.0",
20
- "@orpc/tanstack-query": "^1.14.0",
21
15
  "@react-navigation/bottom-tabs": "^7.4.0",
22
16
  "@react-navigation/elements": "^2.6.3",
23
17
  "@react-navigation/native": "^7.1.8",
24
- "@tanstack/react-form": "^1.29.1",
25
- "@tanstack/react-query": "^5.100.5",
26
- "@workspace/orpc": "workspace:*",
27
- "@workspace/ui": "workspace:*",
28
- "better-auth": "^1.6.9",
29
- "expo": "^55.0.17",
30
- "expo-constants": "~55.0.15",
31
- "expo-font": "~55.0.6",
32
- "expo-haptics": "~55.0.14",
33
- "expo-image": "~55.0.9",
34
- "expo-linking": "~55.0.14",
35
- "expo-network": "^55.0.13",
36
- "expo-router": "~55.0.13",
37
- "expo-secure-store": "^55.0.13",
38
- "expo-splash-screen": "~55.0.19",
39
- "expo-status-bar": "~55.0.5",
40
- "expo-symbols": "~55.0.7",
41
- "expo-system-ui": "~55.0.16",
42
- "expo-web-browser": "~55.0.14",
43
- "react": "19.2.5",
44
- "react-dom": "19.2.5",
45
- "react-native": "0.83.6",
46
- "react-native-gesture-handler": "~2.30.0",
47
- "react-native-reanimated": "4.2.1",
18
+ "expo": "~54.0.33",
19
+ "expo-constants": "~18.0.13",
20
+ "expo-font": "~14.0.11",
21
+ "expo-haptics": "~15.0.8",
22
+ "expo-image": "~3.0.11",
23
+ "expo-linking": "~8.0.11",
24
+ "expo-router": "~6.0.23",
25
+ "expo-splash-screen": "~31.0.13",
26
+ "expo-status-bar": "~3.0.9",
27
+ "expo-symbols": "~1.0.8",
28
+ "expo-system-ui": "~6.0.9",
29
+ "expo-web-browser": "~15.0.10",
30
+ "react": "19.1.0",
31
+ "react-dom": "19.1.0",
32
+ "react-native": "0.81.5",
33
+ "react-native-gesture-handler": "~2.28.0",
34
+ "react-native-worklets": "0.5.1",
35
+ "react-native-reanimated": "~4.1.1",
48
36
  "react-native-safe-area-context": "~5.6.0",
49
- "react-native-screens": "~4.23.0",
50
- "react-native-web": "~0.21.0",
51
- "react-native-worklets": "0.7.4"
37
+ "react-native-screens": "~4.16.0",
38
+ "react-native-web": "~0.21.0"
52
39
  },
53
40
  "devDependencies": {
54
- "babel-plugin-transform-import-meta": "^2.3.3",
55
- "metro-react-native-babel-transformer": "^0.77.0"
56
- }
41
+ "@workspace/config-typescript": "workspace:*",
42
+ "@types/react": "~19.1.0"
43
+ },
44
+ "private": true
57
45
  }
@@ -91,7 +91,7 @@ const moveDirectories = async (userInput) => {
91
91
  userInput === "y"
92
92
  ? `\n3. Delete the /${exampleDir} directory when you're done referencing it.`
93
93
  : ""
94
- }`,
94
+ }`
95
95
  );
96
96
  } catch (error) {
97
97
  console.error(`❌ Error during script execution: ${error.message}`);
@@ -108,5 +108,5 @@ rl.question(
108
108
  console.log("❌ Invalid input. Please enter 'Y' or 'N'.");
109
109
  rl.close();
110
110
  }
111
- },
111
+ }
112
112
  );
@@ -6,8 +6,15 @@
6
6
  "compilerOptions": {
7
7
  "strict": true,
8
8
  "paths": {
9
- "@/*": ["./*"]
9
+ "@/*": [
10
+ "./*"
11
+ ]
10
12
  }
11
13
  },
12
- "include": ["**/*.ts", "**/*.tsx", ".expo/types/**/*.ts", "expo-env.d.ts"]
14
+ "include": [
15
+ "**/*.ts",
16
+ "**/*.tsx",
17
+ ".expo/types/**/*.ts",
18
+ "expo-env.d.ts"
19
+ ]
13
20
  }
@@ -2,7 +2,7 @@ import { auth } from "@workspace/auth/lib/auth";
2
2
  import { createFileRoute } from "@tanstack/react-router";
3
3
 
4
4
  const CORS_HEADERS = {
5
- "Access-Control-Allow-Origin": "http://localhost:8081",
5
+ "Access-Control-Allow-Origin": "*",
6
6
  "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
7
7
  "Access-Control-Allow-Headers": "Content-Type, Authorization",
8
8
  "Access-Control-Allow-Credentials": "true",
@@ -28,7 +28,7 @@ export const Route = createFileRoute("/api/rpc/$")({
28
28
  });
29
29
 
30
30
  if (response) {
31
- response.headers.set("Access-Control-Allow-Origin", "http://localhost:8081");
31
+ response.headers.set("Access-Control-Allow-Origin", "*");
32
32
  response.headers.set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
33
33
  response.headers.set("Access-Control-Allow-Headers", "Content-Type, Authorization");
34
34
  response.headers.set("Access-Control-Allow-Credentials", "true");
@@ -40,7 +40,7 @@ export const Route = createFileRoute("/api/rpc/$")({
40
40
  return new Response(null, {
41
41
  status: 204,
42
42
  headers: {
43
- "Access-Control-Allow-Origin": "http://localhost:8081",
43
+ "Access-Control-Allow-Origin": "*",
44
44
  "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
45
45
  "Access-Control-Allow-Headers": "Content-Type, Authorization",
46
46
  "Access-Control-Allow-Credentials": "true",
@@ -13,9 +13,6 @@
13
13
  "quality": "turbo quality",
14
14
  "quality:fix": "turbo quality:fix",
15
15
  "typecheck": "turbo typecheck",
16
- "dev:mobile": "turbo run dev --filter=mobile",
17
- "dev:ios": "turbo run dev --filter=mobile -- --ios",
18
- "dev:android": "turbo run dev --filter=mobile -- --android",
19
16
  "ci": "pnpm run lint && pnpm run typecheck && pnpm run build",
20
17
  "db:up": "docker compose up -d",
21
18
  "db:down": "docker compose down",
@@ -25,14 +22,13 @@
25
22
  },
26
23
  "dependencies": {
27
24
  "react": "19.2.5",
28
- "react-dom": "19.2.5",
29
- "react-native": "0.83.6"
25
+ "react-dom": "19.2.5"
30
26
  },
31
27
  "devDependencies": {
32
28
  "@better-auth/core": "^1.6.9",
33
29
  "@types/react": "^19.2.7",
34
30
  "@types/react-dom": "^19.2.3",
35
- "husky": "^9.1.7",
31
+ "husky": "latest",
36
32
  "oxfmt": "latest",
37
33
  "oxlint": "latest",
38
34
  "portless": "^0.11.0",
@@ -42,16 +38,18 @@
42
38
  "zod": "4.3.6"
43
39
  },
44
40
  "pnpm": {
45
- "overrides": {
46
- "@noble/ciphers": "2.2.0",
47
- "drizzle-orm": "^0.45.2",
48
- "react": "19.2.5",
49
- "react-dom": "19.2.5",
50
- "react-native": "0.83.6"
51
- }
41
+ "onlyBuiltDependencies": [
42
+ "@prisma/client",
43
+ "better-sqlite3",
44
+ "electron-winstaller",
45
+ "electron",
46
+ "esbuild",
47
+ "msw",
48
+ "unrs-resolver"
49
+ ]
52
50
  },
53
51
  "engines": {
54
52
  "node": ">=20"
55
53
  },
56
- "packageManager": "pnpm@9.15.0"
54
+ "packageManager": "pnpm@11.1.0"
57
55
  }
@@ -1,3 +1,11 @@
1
1
  packages:
2
2
  - 'apps/*'
3
3
  - 'packages/*'
4
+ allowBuilds:
5
+ '@prisma/client': true
6
+ better-sqlite3: true
7
+ electron: true
8
+ electron-winstaller: true
9
+ esbuild: true
10
+ msw: true
11
+ unrs-resolver: true
@@ -5,6 +5,5 @@
5
5
  "moduleResolution": "bundler",
6
6
  "skipLibCheck": true,
7
7
  "strict": true
8
- },
9
- "extends": "expo/tsconfig.base"
8
+ }
10
9
  }
@@ -1,147 +0,0 @@
1
- import { useState, useEffect } from "react";
2
- import { View, Text, StyleSheet, ScrollView, Alert, ActivityIndicator } from "react-native";
3
- import { useRouter } from "expo-router";
4
- import { authClient } from "@/lib/auth-client";
5
- import { Button } from "@/components/ui/button";
6
- import { Input } from "@/components/ui/input";
7
-
8
- export default function AccountScreen() {
9
- const router = useRouter();
10
- const { data: session, isPending } = authClient.useSession();
11
- const [updating, setUpdating] = useState(false);
12
-
13
- // Form states
14
- const [name, setName] = useState("");
15
- const [email, setEmail] = useState("");
16
-
17
- useEffect(() => {
18
- if (!isPending && !session) {
19
- router.replace("/login");
20
- return;
21
- }
22
-
23
- if (session) {
24
- setName(session.user.name);
25
- setEmail(session.user.email);
26
- }
27
- }, [session, isPending, router]);
28
-
29
- const handleUpdateProfile = async () => {
30
- if (!name) {
31
- Alert.alert("Error", "Name is required");
32
- return;
33
- }
34
-
35
- setUpdating(true);
36
- try {
37
- const { error } = await authClient.updateUser({
38
- name,
39
- });
40
-
41
- if (error) {
42
- Alert.alert("Error", error.message || "Failed to update profile");
43
- } else {
44
- Alert.alert("Success", "Profile updated successfully");
45
- }
46
- } catch (err) {
47
- Alert.alert("Error", "An unexpected error occurred");
48
- } finally {
49
- setUpdating(false);
50
- }
51
- };
52
-
53
- if (isPending) {
54
- return (
55
- <View style={styles.center}>
56
- <ActivityIndicator size="large" color="#000" />
57
- </View>
58
- );
59
- }
60
-
61
- return (
62
- <ScrollView style={styles.container} contentContainerStyle={styles.content}>
63
- <Text style={styles.title}>Account Settings</Text>
64
-
65
- <View style={styles.section}>
66
- <Text style={styles.sectionTitle}>Profile Information</Text>
67
- <View style={styles.form}>
68
- <Input
69
- label="Name"
70
- value={name}
71
- onChangeText={setName}
72
- placeholder="Your name"
73
- />
74
- <Input
75
- label="Email"
76
- value={email}
77
- editable={false}
78
- style={styles.disabledInput}
79
- />
80
- <Button
81
- onPress={handleUpdateProfile}
82
- loading={updating}
83
- style={styles.button}
84
- >
85
- Update Profile
86
- </Button>
87
- </View>
88
- </View>
89
-
90
- <View style={styles.section}>
91
- <Text style={styles.sectionTitle}>Security</Text>
92
- <Text style={styles.infoText}>
93
- Password management and other security settings are currently available on the web platform.
94
- </Text>
95
- </View>
96
- </ScrollView>
97
- );
98
- }
99
-
100
- const styles = StyleSheet.create({
101
- container: {
102
- flex: 1,
103
- backgroundColor: "#fff",
104
- },
105
- content: {
106
- padding: 24,
107
- },
108
- center: {
109
- flex: 1,
110
- justifyContent: "center",
111
- alignItems: "center",
112
- },
113
- title: {
114
- fontSize: 28,
115
- fontWeight: "bold",
116
- marginBottom: 24,
117
- },
118
- section: {
119
- marginBottom: 32,
120
- },
121
- sectionTitle: {
122
- fontSize: 18,
123
- fontWeight: "600",
124
- marginBottom: 16,
125
- color: "#333",
126
- },
127
- form: {
128
- gap: 16,
129
- },
130
- disabledInput: {
131
- backgroundColor: "#f5f5f5",
132
- color: "#888",
133
- },
134
- button: {
135
- marginTop: 8,
136
- },
137
- infoText: {
138
- fontSize: 14,
139
- color: "#666",
140
- lineHeight: 20,
141
- backgroundColor: "#f9f9f9",
142
- padding: 16,
143
- borderRadius: 8,
144
- borderWidth: 1,
145
- borderColor: "#eee",
146
- },
147
- });
@@ -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
- });