create-croissant 0.1.47 → 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 (47) 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/apps/mobile/.vscode/extensions.json +0 -1
  7. package/template/apps/mobile/.vscode/settings.json +0 -7
  8. package/template/apps/mobile/README.md +0 -50
  9. package/template/apps/mobile/app/(tabs)/_layout.tsx +0 -43
  10. package/template/apps/mobile/app/(tabs)/account.tsx +0 -147
  11. package/template/apps/mobile/app/(tabs)/explore.tsx +0 -345
  12. package/template/apps/mobile/app/(tabs)/index.tsx +0 -112
  13. package/template/apps/mobile/app/_layout.tsx +0 -43
  14. package/template/apps/mobile/app/index.tsx +0 -129
  15. package/template/apps/mobile/app/login.tsx +0 -135
  16. package/template/apps/mobile/app/signup.tsx +0 -144
  17. package/template/apps/mobile/app.json +0 -56
  18. package/template/apps/mobile/assets/images/android-icon-background.png +0 -0
  19. package/template/apps/mobile/assets/images/android-icon-foreground.png +0 -0
  20. package/template/apps/mobile/assets/images/android-icon-monochrome.png +0 -0
  21. package/template/apps/mobile/assets/images/favicon.png +0 -0
  22. package/template/apps/mobile/assets/images/icon.png +0 -0
  23. package/template/apps/mobile/assets/images/partial-react-logo.png +0 -0
  24. package/template/apps/mobile/assets/images/react-logo.png +0 -0
  25. package/template/apps/mobile/assets/images/react-logo@2x.png +0 -0
  26. package/template/apps/mobile/assets/images/react-logo@3x.png +0 -0
  27. package/template/apps/mobile/assets/images/splash-icon.png +0 -0
  28. package/template/apps/mobile/components/external-link.tsx +0 -25
  29. package/template/apps/mobile/components/haptic-tab.tsx +0 -18
  30. package/template/apps/mobile/components/hello-wave.tsx +0 -20
  31. package/template/apps/mobile/components/parallax-scroll-view.tsx +0 -81
  32. package/template/apps/mobile/components/themed-text.tsx +0 -60
  33. package/template/apps/mobile/components/themed-view.tsx +0 -14
  34. package/template/apps/mobile/components/ui/button.tsx +0 -86
  35. package/template/apps/mobile/components/ui/collapsible.tsx +0 -46
  36. package/template/apps/mobile/components/ui/icon-symbol.ios.tsx +0 -32
  37. package/template/apps/mobile/components/ui/icon-symbol.tsx +0 -41
  38. package/template/apps/mobile/components/ui/input.tsx +0 -56
  39. package/template/apps/mobile/constants/theme.ts +0 -53
  40. package/template/apps/mobile/hooks/use-color-scheme.ts +0 -1
  41. package/template/apps/mobile/hooks/use-color-scheme.web.ts +0 -21
  42. package/template/apps/mobile/hooks/use-theme-color.ts +0 -21
  43. package/template/apps/mobile/lib/auth-client.ts +0 -14
  44. package/template/apps/mobile/lib/orpc.ts +0 -28
  45. package/template/apps/mobile/package.json +0 -57
  46. package/template/apps/mobile/scripts/reset-project.js +0 -112
  47. package/template/apps/mobile/tsconfig.json +0 -13
@@ -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
- });
@@ -1,135 +0,0 @@
1
- import { useState } from "react";
2
- import { View, StyleSheet, KeyboardAvoidingView, Platform, ScrollView, Text } 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 LoginScreen() {
9
- const router = useRouter();
10
- const [email, setEmail] = useState("");
11
- const [password, setPassword] = useState("");
12
- const [loading, setLoading] = useState(false);
13
- const [error, setError] = useState<string | null>(null);
14
-
15
- const handleLogin = async () => {
16
- if (!email || !password) {
17
- setError("Please fill in all fields");
18
- return;
19
- }
20
-
21
- setLoading(true);
22
- setError(null);
23
- try {
24
- const { error } = await authClient.signIn.email({
25
- email,
26
- password,
27
- });
28
-
29
- if (error) {
30
- setError(error.message || "Invalid credentials");
31
- } else {
32
- router.replace("/(tabs)");
33
- }
34
- } catch (err) {
35
- setError(err instanceof Error ? err.message : "An error occurred during login");
36
- } finally {
37
- setLoading(false);
38
- }
39
- };
40
-
41
- return (
42
- <KeyboardAvoidingView
43
- behavior={Platform.OS === "ios" ? "padding" : "height"}
44
- style={styles.container}
45
- >
46
- <ScrollView contentContainerStyle={styles.scrollContent}>
47
- <View style={styles.header}>
48
- <Text style={styles.title}>Welcome Back</Text>
49
- <Text style={styles.subtitle}>Sign in to your account</Text>
50
- </View>
51
-
52
- <View style={styles.form}>
53
- <Input
54
- label="Email"
55
- placeholder="email@example.com"
56
- value={email}
57
- onChangeText={setEmail}
58
- autoCapitalize="none"
59
- keyboardType="email-address"
60
- />
61
-
62
- <Input
63
- label="Password"
64
- placeholder="••••••••"
65
- value={password}
66
- onChangeText={setPassword}
67
- secureTextEntry
68
- />
69
-
70
- {error && <Text style={styles.errorText}>{error}</Text>}
71
-
72
- <Button
73
- onPress={handleLogin}
74
- loading={loading}
75
- >
76
- Sign In
77
- </Button>
78
-
79
- <View style={styles.footer}>
80
- <Text style={styles.footerText}>Don't have an account? </Text>
81
- <Text
82
- style={styles.link}
83
- onPress={() => router.push("/signup")}
84
- >
85
- Sign Up
86
- </Text>
87
- </View>
88
- </View>
89
- </ScrollView>
90
- </KeyboardAvoidingView>
91
- );
92
- }
93
-
94
- const styles = StyleSheet.create({
95
- container: {
96
- flex: 1,
97
- backgroundColor: "#fff",
98
- },
99
- scrollContent: {
100
- flexGrow: 1,
101
- padding: 24,
102
- justifyContent: "center",
103
- },
104
- header: {
105
- marginBottom: 40,
106
- },
107
- title: {
108
- fontSize: 32,
109
- fontWeight: "bold",
110
- marginBottom: 8,
111
- },
112
- subtitle: {
113
- fontSize: 16,
114
- color: "#666",
115
- },
116
- form: {
117
- gap: 20,
118
- },
119
- errorText: {
120
- color: "#ef4444",
121
- fontSize: 14,
122
- },
123
- footer: {
124
- flexDirection: "row",
125
- justifyContent: "center",
126
- marginTop: 20,
127
- },
128
- footerText: {
129
- color: "#666",
130
- },
131
- link: {
132
- color: "#000",
133
- fontWeight: "bold",
134
- },
135
- });
@@ -1,144 +0,0 @@
1
- import { useState } from "react";
2
- import { View, StyleSheet, KeyboardAvoidingView, Platform, ScrollView, Text } 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 SignupScreen() {
9
- const router = useRouter();
10
- const [name, setName] = useState("");
11
- const [email, setEmail] = useState("");
12
- const [password, setPassword] = useState("");
13
- const [loading, setLoading] = useState(false);
14
- const [error, setError] = useState<string | null>(null);
15
-
16
- const handleSignup = async () => {
17
- if (!name || !email || !password) {
18
- setError("Please fill in all fields");
19
- return;
20
- }
21
-
22
- setLoading(true);
23
- setError(null);
24
- try {
25
- const { error } = await authClient.signUp.email({
26
- email,
27
- password,
28
- name,
29
- });
30
-
31
- if (error) {
32
- setError(error.message || "An error occurred during signup");
33
- } else {
34
- router.replace("/(tabs)");
35
- }
36
- } catch (err) {
37
- setError(err instanceof Error ? err.message : "An error occurred during signup");
38
- } finally {
39
- setLoading(false);
40
- }
41
- };
42
-
43
- return (
44
- <KeyboardAvoidingView
45
- behavior={Platform.OS === "ios" ? "padding" : "height"}
46
- style={styles.container}
47
- >
48
- <ScrollView contentContainerStyle={styles.scrollContent}>
49
- <View style={styles.header}>
50
- <Text style={styles.title}>Create Account</Text>
51
- <Text style={styles.subtitle}>Join the Croissant Stack</Text>
52
- </View>
53
-
54
- <View style={styles.form}>
55
- <Input
56
- label="Name"
57
- placeholder="John Doe"
58
- value={name}
59
- onChangeText={setName}
60
- />
61
-
62
- <Input
63
- label="Email"
64
- placeholder="email@example.com"
65
- value={email}
66
- onChangeText={setEmail}
67
- autoCapitalize="none"
68
- keyboardType="email-address"
69
- />
70
-
71
- <Input
72
- label="Password"
73
- placeholder="••••••••"
74
- value={password}
75
- onChangeText={setPassword}
76
- secureTextEntry
77
- />
78
-
79
- {error && <Text style={styles.errorText}>{error}</Text>}
80
-
81
- <Button
82
- onPress={handleSignup}
83
- loading={loading}
84
- >
85
- Sign Up
86
- </Button>
87
-
88
- <View style={styles.footer}>
89
- <Text style={styles.footerText}>Already have an account? </Text>
90
- <Text
91
- style={styles.link}
92
- onPress={() => router.push("/login")}
93
- >
94
- Sign In
95
- </Text>
96
- </View>
97
- </View>
98
- </ScrollView>
99
- </KeyboardAvoidingView>
100
- );
101
- }
102
-
103
- const styles = StyleSheet.create({
104
- container: {
105
- flex: 1,
106
- backgroundColor: "#fff",
107
- },
108
- scrollContent: {
109
- flexGrow: 1,
110
- padding: 24,
111
- justifyContent: "center",
112
- },
113
- header: {
114
- marginBottom: 40,
115
- },
116
- title: {
117
- fontSize: 32,
118
- fontWeight: "bold",
119
- marginBottom: 8,
120
- },
121
- subtitle: {
122
- fontSize: 16,
123
- color: "#666",
124
- },
125
- form: {
126
- gap: 20,
127
- },
128
- errorText: {
129
- color: "#ef4444",
130
- fontSize: 14,
131
- },
132
- footer: {
133
- flexDirection: "row",
134
- justifyContent: "center",
135
- marginTop: 20,
136
- },
137
- footerText: {
138
- color: "#666",
139
- },
140
- link: {
141
- color: "#000",
142
- fontWeight: "bold",
143
- },
144
- });
@@ -1,56 +0,0 @@
1
- {
2
- "expo": {
3
- "name": "mobile",
4
- "slug": "mobile",
5
- "version": "1.0.0",
6
- "orientation": "portrait",
7
- "icon": "./assets/images/icon.png",
8
- "scheme": "mobile",
9
- "userInterfaceStyle": "automatic",
10
- "newArchEnabled": true,
11
- "ios": {
12
- "supportsTablet": true,
13
- "infoPlist": {
14
- "NSAppTransportSecurity": {
15
- "NSAllowsLocalNetworking": true
16
- }
17
- }
18
- },
19
- "android": {
20
- "adaptiveIcon": {
21
- "backgroundColor": "#E6F4FE",
22
- "foregroundImage": "./assets/images/android-icon-foreground.png",
23
- "backgroundImage": "./assets/images/android-icon-background.png",
24
- "monochromeImage": "./assets/images/android-icon-monochrome.png"
25
- },
26
- "edgeToEdgeEnabled": true,
27
- "predictiveBackGestureEnabled": false
28
- },
29
- "web": {
30
- "output": "single",
31
- "favicon": "./assets/images/favicon.png",
32
- "bundler": "metro"
33
- },
34
- "plugins": [
35
- "expo-router",
36
- [
37
- "expo-splash-screen",
38
- {
39
- "image": "./assets/images/splash-icon.png",
40
- "imageWidth": 200,
41
- "resizeMode": "contain",
42
- "backgroundColor": "#ffffff",
43
- "dark": {
44
- "backgroundColor": "#000000"
45
- }
46
- }
47
- ],
48
- "expo-font",
49
- "expo-image",
50
- "expo-web-browser"
51
- ],
52
- "experiments": {
53
- "typedRoutes": true
54
- }
55
- }
56
- }
@@ -1,25 +0,0 @@
1
- import { Href, Link } from "expo-router";
2
- import { openBrowserAsync, WebBrowserPresentationStyle } from "expo-web-browser";
3
- import { type ComponentProps } from "react";
4
-
5
- type Props = Omit<ComponentProps<typeof Link>, "href"> & { href: Href & string };
6
-
7
- export function ExternalLink({ href, ...rest }: Props) {
8
- return (
9
- <Link
10
- target="_blank"
11
- {...rest}
12
- href={href}
13
- onPress={async (event) => {
14
- if (process.env.EXPO_OS !== "web") {
15
- // Prevent the default behavior of linking to the default browser on native.
16
- event.preventDefault();
17
- // Open the link in an in-app browser.
18
- await openBrowserAsync(href, {
19
- presentationStyle: WebBrowserPresentationStyle.AUTOMATIC,
20
- });
21
- }
22
- }}
23
- />
24
- );
25
- }
@@ -1,18 +0,0 @@
1
- import { BottomTabBarButtonProps } from "@react-navigation/bottom-tabs";
2
- import { PlatformPressable } from "@react-navigation/elements";
3
- import * as Haptics from "expo-haptics";
4
-
5
- export function HapticTab(props: BottomTabBarButtonProps) {
6
- return (
7
- <PlatformPressable
8
- {...props}
9
- onPressIn={(ev) => {
10
- if (process.env.EXPO_OS === "ios") {
11
- // Add a soft haptic feedback when pressing down on the tabs.
12
- Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
13
- }
14
- props.onPressIn?.(ev);
15
- }}
16
- />
17
- );
18
- }