@teardown/cli 2.0.65 → 2.0.67

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 (40) hide show
  1. package/package.json +2 -2
  2. package/src/templates/generator.ts +66 -42
  3. package/templates/{src/index.tsx → index.tsx} +5 -2
  4. package/templates/metro.config.js +7 -35
  5. package/templates/src/components/ui/accordion.tsx +23 -21
  6. package/templates/src/components/ui/card.tsx +28 -26
  7. package/templates/src/components/ui/checkbox.tsx +12 -10
  8. package/templates/src/components/ui/dialog.tsx +30 -28
  9. package/templates/src/components/ui/divider.tsx +6 -6
  10. package/templates/src/components/ui/form-field.tsx +2 -2
  11. package/templates/src/components/ui/pressable-feedback.tsx +2 -2
  12. package/templates/src/components/ui/radio-group.tsx +37 -35
  13. package/templates/src/components/ui/scroll-shadow.tsx +4 -4
  14. package/templates/src/components/ui/select.tsx +31 -29
  15. package/templates/src/components/ui/skeleton-group.tsx +2 -2
  16. package/templates/src/components/ui/skeleton.tsx +2 -2
  17. package/templates/src/components/ui/spinner.tsx +2 -2
  18. package/templates/src/components/ui/tabs.tsx +25 -23
  19. package/templates/src/global.css +86 -70
  20. package/templates/src/navigation/navigation-provider.tsx +8 -1
  21. package/templates/src/navigation/router.tsx +12 -95
  22. package/templates/src/providers/app.provider.tsx +8 -12
  23. package/templates/src/routes/_layout.tsx +2 -4
  24. package/templates/src/routes/home.tsx +112 -0
  25. package/templates/tsconfig.json +10 -12
  26. package/templates/index.ts +0 -11
  27. package/templates/src/components/ui/index.ts +0 -100
  28. package/templates/src/routes/(tabs)/_layout.tsx +0 -42
  29. package/templates/src/routes/(tabs)/explore.tsx +0 -161
  30. package/templates/src/routes/(tabs)/home.tsx +0 -138
  31. package/templates/src/routes/(tabs)/profile.tsx +0 -114
  32. package/templates/src/routes/settings.tsx +0 -184
  33. package/templates/src/screens/auth/index.ts +0 -6
  34. package/templates/src/screens/auth/login.tsx +0 -165
  35. package/templates/src/screens/auth/register.tsx +0 -203
  36. package/templates/src/screens/home.tsx +0 -204
  37. package/templates/src/screens/index.ts +0 -17
  38. package/templates/src/screens/profile.tsx +0 -210
  39. package/templates/src/screens/settings.tsx +0 -216
  40. package/templates/src/screens/welcome.tsx +0 -101
@@ -1,138 +0,0 @@
1
- /**
2
- * Home Screen
3
- *
4
- * The main landing screen of the app.
5
- */
6
-
7
- import { defineScreen } from "@teardown/navigation/primitives";
8
- import type React from "react";
9
- import { Pressable, ScrollView, View } from "react-native";
10
- import {
11
- Badge,
12
- Button,
13
- Card,
14
- CardContent,
15
- CardDescription,
16
- CardHeader,
17
- CardTitle,
18
- Text,
19
- } from "@/components/ui";
20
- import { useTypedNavigation } from "@/navigation";
21
-
22
- function HomeScreen(): React.JSX.Element {
23
- const navigation = useTypedNavigation();
24
-
25
- return (
26
- <ScrollView className="flex-1 bg-background" contentContainerClassName="p-6 gap-6">
27
- {/* Hero Section */}
28
- <View className="items-center gap-4 py-8">
29
- <View className="h-20 w-20 items-center justify-center rounded-2xl bg-primary">
30
- <Text className="text-3xl font-bold text-primary-foreground">T</Text>
31
- </View>
32
- <View className="items-center gap-2">
33
- <Text variant="h1" className="text-center">
34
- Welcome to <%= appName %>
35
- </Text>
36
- <Text variant="lead" className="text-center">
37
- Your React Native app with type-safe navigation
38
- </Text>
39
- </View>
40
- </View>
41
-
42
- {/* Quick Actions */}
43
- <Card>
44
- <CardHeader>
45
- <CardTitle>Quick Actions</CardTitle>
46
- <CardDescription>Navigate through your app</CardDescription>
47
- </CardHeader>
48
- <CardContent className="gap-3">
49
- <Button onPress={() => navigation.navigate("/settings")} fullWidth>
50
- Open Settings
51
- </Button>
52
- <Button variant="secondary" onPress={() => navigation.navigate("/(tabs)/explore")} fullWidth>
53
- Explore Content
54
- </Button>
55
- </CardContent>
56
- </Card>
57
-
58
- {/* Features */}
59
- <View className="gap-4">
60
- <Text variant="h3">Features</Text>
61
- <FeatureCard
62
- icon="🔒"
63
- title="Type-Safe Navigation"
64
- description="Routes are fully typed with TypeScript"
65
- tags={["TypeScript", "Safe"]}
66
- />
67
- <FeatureCard
68
- icon="📁"
69
- title="File-Based Routing"
70
- description="Routes generated from file structure"
71
- tags={["Auto", "Generated"]}
72
- />
73
- <FeatureCard
74
- icon="📱"
75
- title="Tab Navigation"
76
- description="Bottom tabs with Home, Explore, Profile"
77
- tags={["Tabs", "Navigate"]}
78
- />
79
- </View>
80
-
81
- {/* Getting Started */}
82
- <Card className="bg-primary/5 border-primary/20">
83
- <CardContent className="py-4">
84
- <Text variant="large">Getting Started</Text>
85
- <Text variant="muted" className="mt-2">
86
- 1. Explore the tabs to see different screens{"\n"}
87
- 2. Open Settings to see stack navigation{"\n"}
88
- 3. Customize screens in src/routes/{"\n"}
89
- 4. Build your app!
90
- </Text>
91
- </CardContent>
92
- </Card>
93
- </ScrollView>
94
- );
95
- }
96
-
97
- function FeatureCard({
98
- icon,
99
- title,
100
- description,
101
- tags,
102
- }: {
103
- icon: string;
104
- title: string;
105
- description: string;
106
- tags: string[];
107
- }): React.JSX.Element {
108
- return (
109
- <Card>
110
- <CardHeader className="flex-row items-start gap-3 pb-2">
111
- <View className="h-10 w-10 items-center justify-center rounded-lg bg-muted">
112
- <Text className="text-xl">{icon}</Text>
113
- </View>
114
- <View className="flex-1">
115
- <CardTitle className="text-base">{title}</CardTitle>
116
- <CardDescription>{description}</CardDescription>
117
- </View>
118
- </CardHeader>
119
- <CardContent>
120
- <View className="flex-row flex-wrap gap-2">
121
- {tags.map((tag) => (
122
- <Badge key={tag} variant="secondary">
123
- {tag}
124
- </Badge>
125
- ))}
126
- </View>
127
- </CardContent>
128
- </Card>
129
- );
130
- }
131
-
132
- export default defineScreen({
133
- component: HomeScreen,
134
- options: {
135
- title: "Home",
136
- tabBarLabel: "Home",
137
- },
138
- });
@@ -1,114 +0,0 @@
1
- /**
2
- * Profile Screen
3
- *
4
- * User profile and account management screen.
5
- */
6
-
7
- import { defineScreen } from "@teardown/navigation/primitives";
8
- import type React from "react";
9
- import { Pressable, ScrollView, View } from "react-native";
10
- import { Avatar, Badge, Button, Card, CardContent, Separator, Text } from "@/components/ui";
11
- import { useTypedNavigation } from "@/navigation";
12
-
13
- function ProfileScreen(): React.JSX.Element {
14
- const navigation = useTypedNavigation();
15
-
16
- return (
17
- <ScrollView className="flex-1 bg-background" contentContainerClassName="p-6 gap-6">
18
- {/* Profile Header */}
19
- <View className="items-center gap-4 py-4">
20
- <Avatar fallback="U" size="xl" />
21
- <View className="items-center gap-1">
22
- <Text variant="h2">User</Text>
23
- <Text variant="muted">user@example.com</Text>
24
- </View>
25
- <View className="flex-row gap-2">
26
- <Badge variant="secondary">Free Plan</Badge>
27
- <Badge variant="outline">Member since 2024</Badge>
28
- </View>
29
- </View>
30
-
31
- {/* Stats */}
32
- <Card>
33
- <CardContent className="flex-row justify-around py-4">
34
- <StatItem label="Projects" value="12" />
35
- <Separator orientation="vertical" />
36
- <StatItem label="Tasks" value="48" />
37
- <Separator orientation="vertical" />
38
- <StatItem label="Completed" value="36" />
39
- </CardContent>
40
- </Card>
41
-
42
- {/* Account Section */}
43
- <View className="gap-2">
44
- <Text variant="label" className="px-1">
45
- ACCOUNT
46
- </Text>
47
- <Card>
48
- <CardContent className="p-0">
49
- <MenuItem icon="⚙️" title="Settings" onPress={() => navigation.navigate("/settings")} />
50
- <Separator />
51
- <MenuItem icon="🔒" title="Privacy" onPress={() => {}} />
52
- <Separator />
53
- <MenuItem icon="🔔" title="Notifications" onPress={() => {}} />
54
- </CardContent>
55
- </Card>
56
- </View>
57
-
58
- {/* Support Section */}
59
- <View className="gap-2">
60
- <Text variant="label" className="px-1">
61
- SUPPORT
62
- </Text>
63
- <Card>
64
- <CardContent className="p-0">
65
- <MenuItem icon="❓" title="Help Center" onPress={() => {}} />
66
- <Separator />
67
- <MenuItem icon="💬" title="Contact Us" onPress={() => {}} />
68
- <Separator />
69
- <MenuItem icon="📝" title="Send Feedback" onPress={() => {}} />
70
- </CardContent>
71
- </Card>
72
- </View>
73
-
74
- {/* Sign Out */}
75
- <Button variant="destructive" onPress={() => {}} fullWidth>
76
- Sign Out
77
- </Button>
78
-
79
- {/* App Info */}
80
- <View className="items-center pt-4">
81
- <Text variant="muted">Version 1.0.0</Text>
82
- </View>
83
- </ScrollView>
84
- );
85
- }
86
-
87
- function StatItem({ label, value }: { label: string; value: string }): React.JSX.Element {
88
- return (
89
- <View className="items-center px-4">
90
- <Text variant="h3">{value}</Text>
91
- <Text variant="muted">{label}</Text>
92
- </View>
93
- );
94
- }
95
-
96
- function MenuItem({ icon, title, onPress }: { icon: string; title: string; onPress: () => void }): React.JSX.Element {
97
- return (
98
- <Pressable className="flex-row items-center px-4 py-3 active:bg-muted/50" onPress={onPress}>
99
- <Text className="text-xl mr-3">{icon}</Text>
100
- <Text variant="large" className="flex-1">
101
- {title}
102
- </Text>
103
- <Text className="text-muted-foreground">›</Text>
104
- </Pressable>
105
- );
106
- }
107
-
108
- export default defineScreen({
109
- component: ProfileScreen,
110
- options: {
111
- title: "Profile",
112
- tabBarLabel: "Profile",
113
- },
114
- });
@@ -1,184 +0,0 @@
1
- /**
2
- * Settings Screen
3
- *
4
- * App settings and preferences screen.
5
- * This is a stack screen outside of the tab navigator.
6
- */
7
-
8
- import { defineScreen } from "@teardown/navigation/primitives";
9
- import React from "react";
10
- import { Pressable, ScrollView, Switch, View } from "react-native";
11
- import { Button, Card, CardContent, CardHeader, CardTitle, Separator, Text } from "@/components/ui";
12
- import { useTypedNavigation } from "@/navigation";
13
-
14
- function SettingsScreen(): React.JSX.Element {
15
- const navigation = useTypedNavigation();
16
- const [notifications, setNotifications] = React.useState(true);
17
- const [darkMode, setDarkMode] = React.useState(false);
18
- const [analytics, setAnalytics] = React.useState(true);
19
- const [biometrics, setBiometrics] = React.useState(false);
20
-
21
- return (
22
- <ScrollView className="flex-1 bg-background" contentContainerClassName="p-6 gap-6">
23
- {/* Preferences Section */}
24
- <View className="gap-2">
25
- <Text variant="label" className="px-1">
26
- PREFERENCES
27
- </Text>
28
- <Card>
29
- <CardContent className="p-0">
30
- <SettingRow
31
- icon="🔔"
32
- title="Push Notifications"
33
- description="Receive push notifications"
34
- value={notifications}
35
- onValueChange={setNotifications}
36
- />
37
- <Separator />
38
- <SettingRow
39
- icon="🌙"
40
- title="Dark Mode"
41
- description="Use dark color theme"
42
- value={darkMode}
43
- onValueChange={setDarkMode}
44
- />
45
- <Separator />
46
- <SettingRow
47
- icon="📊"
48
- title="Analytics"
49
- description="Help improve the app"
50
- value={analytics}
51
- onValueChange={setAnalytics}
52
- />
53
- <Separator />
54
- <SettingRow
55
- icon="🔐"
56
- title="Biometric Lock"
57
- description="Require Face ID or Touch ID"
58
- value={biometrics}
59
- onValueChange={setBiometrics}
60
- />
61
- </CardContent>
62
- </Card>
63
- </View>
64
-
65
- {/* Storage Section */}
66
- <View className="gap-2">
67
- <Text variant="label" className="px-1">
68
- STORAGE
69
- </Text>
70
- <Card>
71
- <CardContent className="gap-4 py-4">
72
- <View className="flex-row justify-between">
73
- <Text>Cache Size</Text>
74
- <Text variant="muted">24.5 MB</Text>
75
- </View>
76
- <Button variant="outline" size="sm">
77
- Clear Cache
78
- </Button>
79
- </CardContent>
80
- </Card>
81
- </View>
82
-
83
- {/* About Section */}
84
- <View className="gap-2">
85
- <Text variant="label" className="px-1">
86
- ABOUT
87
- </Text>
88
- <Card>
89
- <CardContent className="p-0">
90
- <InfoRow icon="📱" title="Version" value="1.0.0" />
91
- <Separator />
92
- <InfoRow icon="🔨" title="Build" value="1" />
93
- <Separator />
94
- <InfoRow icon="⚛️" title="React Native" value="0.76.9" />
95
- </CardContent>
96
- </Card>
97
- </View>
98
-
99
- {/* Legal Section */}
100
- <View className="gap-2">
101
- <Text variant="label" className="px-1">
102
- LEGAL
103
- </Text>
104
- <Card>
105
- <CardContent className="p-0">
106
- <LinkRow icon="📄" title="Terms of Service" />
107
- <Separator />
108
- <LinkRow icon="🔒" title="Privacy Policy" />
109
- <Separator />
110
- <LinkRow icon="📜" title="Licenses" />
111
- </CardContent>
112
- </Card>
113
- </View>
114
-
115
- {/* Back Button */}
116
- <Button variant="secondary" onPress={() => navigation.goBack()} fullWidth>
117
- Go Back
118
- </Button>
119
- </ScrollView>
120
- );
121
- }
122
-
123
- function SettingRow({
124
- icon,
125
- title,
126
- description,
127
- value,
128
- onValueChange,
129
- }: {
130
- icon: string;
131
- title: string;
132
- description: string;
133
- value: boolean;
134
- onValueChange: (value: boolean) => void;
135
- }): React.JSX.Element {
136
- return (
137
- <View className="flex-row items-center px-4 py-3">
138
- <Text className="text-xl mr-3">{icon}</Text>
139
- <View className="flex-1 mr-4">
140
- <Text variant="large">{title}</Text>
141
- <Text variant="muted">{description}</Text>
142
- </View>
143
- <Switch
144
- value={value}
145
- onValueChange={onValueChange}
146
- trackColor={{ false: "#d1d5db", true: "#bfdbfe" }}
147
- thumbColor={value ? "#3b82f6" : "#f3f4f6"}
148
- />
149
- </View>
150
- );
151
- }
152
-
153
- function InfoRow({ icon, title, value }: { icon: string; title: string; value: string }): React.JSX.Element {
154
- return (
155
- <View className="flex-row items-center px-4 py-3">
156
- <Text className="text-xl mr-3">{icon}</Text>
157
- <Text variant="large" className="flex-1">
158
- {title}
159
- </Text>
160
- <Text variant="muted">{value}</Text>
161
- </View>
162
- );
163
- }
164
-
165
- function LinkRow({ icon, title }: { icon: string; title: string }): React.JSX.Element {
166
- return (
167
- <Pressable className="flex-row items-center px-4 py-3 active:bg-muted/50">
168
- <Text className="text-xl mr-3">{icon}</Text>
169
- <Text variant="large" className="flex-1">
170
- {title}
171
- </Text>
172
- <Text className="text-muted-foreground">›</Text>
173
- </Pressable>
174
- );
175
- }
176
-
177
- export default defineScreen({
178
- component: SettingsScreen,
179
- options: {
180
- title: "Settings",
181
- headerShown: true,
182
- animation: "slide_from_right",
183
- },
184
- });
@@ -1,6 +0,0 @@
1
- /**
2
- * Auth Screens Export
3
- */
4
-
5
- export { LoginScreen } from "./login";
6
- export { RegisterScreen } from "./register";
@@ -1,165 +0,0 @@
1
- /**
2
- * Login Screen
3
- *
4
- * Email/password login with social auth options.
5
- */
6
-
7
- import React, { useState } from "react";
8
- import { View, ScrollView, Pressable, KeyboardAvoidingView, Platform } from "react-native";
9
- import {
10
- Text,
11
- Button,
12
- Input,
13
- Card,
14
- CardHeader,
15
- CardTitle,
16
- CardDescription,
17
- CardContent,
18
- CardFooter,
19
- Separator,
20
- } from "@/components/ui";
21
-
22
- interface LoginScreenProps {
23
- onLogin?: (email: string, password: string) => void;
24
- onForgotPassword?: () => void;
25
- onRegister?: () => void;
26
- onSocialLogin?: (provider: "google" | "apple" | "github") => void;
27
- loading?: boolean;
28
- }
29
-
30
- export function LoginScreen({
31
- onLogin,
32
- onForgotPassword,
33
- onRegister,
34
- onSocialLogin,
35
- loading = false,
36
- }: LoginScreenProps): React.JSX.Element {
37
- const [email, setEmail] = useState("");
38
- const [password, setPassword] = useState("");
39
- const [errors, setErrors] = useState<{ email?: string; password?: string }>({});
40
-
41
- const validate = (): boolean => {
42
- const newErrors: { email?: string; password?: string } = {};
43
-
44
- if (!email) {
45
- newErrors.email = "Email is required";
46
- } else if (!/\S+@\S+\.\S+/.test(email)) {
47
- newErrors.email = "Please enter a valid email";
48
- }
49
-
50
- if (!password) {
51
- newErrors.password = "Password is required";
52
- } else if (password.length < 6) {
53
- newErrors.password = "Password must be at least 6 characters";
54
- }
55
-
56
- setErrors(newErrors);
57
- return Object.keys(newErrors).length === 0;
58
- };
59
-
60
- const handleLogin = () => {
61
- if (validate()) {
62
- onLogin?.(email, password);
63
- }
64
- };
65
-
66
- return (
67
- <KeyboardAvoidingView
68
- behavior={Platform.OS === "ios" ? "padding" : "height"}
69
- className="flex-1 bg-background"
70
- >
71
- <ScrollView
72
- contentContainerClassName="flex-grow justify-center p-6"
73
- keyboardShouldPersistTaps="handled"
74
- >
75
- <Card className="w-full max-w-md self-center">
76
- <CardHeader className="items-center">
77
- <View className="mb-4 h-16 w-16 items-center justify-center rounded-2xl bg-primary">
78
- <Text className="text-2xl font-bold text-primary-foreground">T</Text>
79
- </View>
80
- <CardTitle>Welcome back</CardTitle>
81
- <CardDescription>Sign in to your account to continue</CardDescription>
82
- </CardHeader>
83
-
84
- <CardContent className="gap-4">
85
- {/* Social Login Buttons */}
86
- <View className="gap-3">
87
- <Button
88
- variant="outline"
89
- fullWidth
90
- onPress={() => onSocialLogin?.("google")}
91
- >
92
- <View className="flex-row items-center gap-2">
93
- <Text>🔵</Text>
94
- <Text className="font-semibold text-foreground">Continue with Google</Text>
95
- </View>
96
- </Button>
97
-
98
- <Button
99
- variant="outline"
100
- fullWidth
101
- onPress={() => onSocialLogin?.("apple")}
102
- >
103
- <View className="flex-row items-center gap-2">
104
- <Text></Text>
105
- <Text className="font-semibold text-foreground">Continue with Apple</Text>
106
- </View>
107
- </Button>
108
- </View>
109
-
110
- {/* Divider */}
111
- <View className="flex-row items-center gap-4 my-2">
112
- <Separator className="flex-1" />
113
- <Text variant="muted">or</Text>
114
- <Separator className="flex-1" />
115
- </View>
116
-
117
- {/* Email/Password Form */}
118
- <View className="gap-4">
119
- <Input
120
- label="Email"
121
- placeholder="you@example.com"
122
- value={email}
123
- onChangeText={setEmail}
124
- error={errors.email}
125
- keyboardType="email-address"
126
- autoCapitalize="none"
127
- autoComplete="email"
128
- />
129
-
130
- <View>
131
- <Input
132
- label="Password"
133
- placeholder="Enter your password"
134
- value={password}
135
- onChangeText={setPassword}
136
- error={errors.password}
137
- secureTextEntry
138
- autoComplete="password"
139
- />
140
- <Pressable onPress={onForgotPassword} className="mt-2 self-end">
141
- <Text className="text-sm text-primary">Forgot password?</Text>
142
- </Pressable>
143
- </View>
144
- </View>
145
- </CardContent>
146
-
147
- <CardFooter className="flex-col gap-4">
148
- <Button fullWidth loading={loading} onPress={handleLogin}>
149
- Sign In
150
- </Button>
151
-
152
- <View className="flex-row items-center justify-center gap-1">
153
- <Text variant="muted">Don't have an account?</Text>
154
- <Pressable onPress={onRegister}>
155
- <Text className="font-semibold text-primary">Sign up</Text>
156
- </Pressable>
157
- </View>
158
- </CardFooter>
159
- </Card>
160
- </ScrollView>
161
- </KeyboardAvoidingView>
162
- );
163
- }
164
-
165
- export default LoginScreen;