@teardown/cli 2.0.64 → 2.0.66
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.
- package/package.json +2 -2
- package/src/templates/generator.ts +66 -41
- package/templates/{src/index.tsx → index.tsx} +4 -2
- package/templates/ios/AppName/AppDelegate.swift +2 -0
- package/templates/package.json +5 -5
- package/templates/src/navigation/hooks.ts +46 -0
- package/templates/src/navigation/index.ts +1 -0
- package/templates/src/routes/(tabs)/home.tsx +7 -7
- package/templates/src/routes/(tabs)/profile.tsx +21 -58
- package/templates/src/routes/settings.tsx +24 -34
- package/templates/index.ts +0 -11
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@teardown/cli",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.66",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
},
|
|
72
72
|
"devDependencies": {
|
|
73
73
|
"@biomejs/biome": "2.3.11",
|
|
74
|
-
"@teardown/tsconfig": "2.0.
|
|
74
|
+
"@teardown/tsconfig": "2.0.66",
|
|
75
75
|
"@types/bun": "1.3.5",
|
|
76
76
|
"@types/ejs": "^3.1.5",
|
|
77
77
|
"typescript": "5.9.3"
|
|
@@ -144,7 +144,7 @@ export class TemplateGenerator {
|
|
|
144
144
|
* Check if src folder exists
|
|
145
145
|
*/
|
|
146
146
|
async srcFolderExists(): Promise<boolean> {
|
|
147
|
-
const srcPath = join(this.options.projectRoot, "src"
|
|
147
|
+
const srcPath = join(this.options.projectRoot, "src");
|
|
148
148
|
try {
|
|
149
149
|
await stat(srcPath);
|
|
150
150
|
return true;
|
|
@@ -180,62 +180,87 @@ export class TemplateGenerator {
|
|
|
180
180
|
"tsconfig.json",
|
|
181
181
|
"babel.config.js",
|
|
182
182
|
"metro.config.js",
|
|
183
|
-
"index.
|
|
183
|
+
"index.tsx",
|
|
184
184
|
"react-native.config.js",
|
|
185
185
|
"Gemfile",
|
|
186
186
|
];
|
|
187
187
|
|
|
188
188
|
for (const file of configFiles) {
|
|
189
|
-
const
|
|
190
|
-
|
|
189
|
+
const fileResult = await this.processConfigFile(file);
|
|
190
|
+
if (fileResult.created) {
|
|
191
|
+
result.filesCreated.push(fileResult.path);
|
|
192
|
+
} else if (fileResult.skipped) {
|
|
193
|
+
result.filesSkipped.push(fileResult.path);
|
|
194
|
+
} else if (fileResult.error) {
|
|
195
|
+
result.errors.push(fileResult.error);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
191
198
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
await stat(templatePath);
|
|
196
|
-
} catch {
|
|
197
|
-
// Template doesn't exist, skip
|
|
198
|
-
continue;
|
|
199
|
-
}
|
|
199
|
+
if (result.errors.length > 0) {
|
|
200
|
+
result.success = false;
|
|
201
|
+
}
|
|
200
202
|
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
try {
|
|
204
|
-
await stat(outputPath);
|
|
205
|
-
result.filesSkipped.push(outputPath);
|
|
206
|
-
this.logger?.debug(`${file} already exists, skipping`);
|
|
207
|
-
continue;
|
|
208
|
-
} catch {
|
|
209
|
-
// File doesn't exist, continue
|
|
210
|
-
}
|
|
211
|
-
}
|
|
203
|
+
return result;
|
|
204
|
+
}
|
|
212
205
|
|
|
213
|
-
|
|
214
|
-
|
|
206
|
+
/**
|
|
207
|
+
* Process a single config file from template
|
|
208
|
+
*/
|
|
209
|
+
private async processConfigFile(
|
|
210
|
+
file: string
|
|
211
|
+
): Promise<{ path: string; created?: boolean; skipped?: boolean; error?: string }> {
|
|
212
|
+
const templatePath = join(getTemplatesPath(), file);
|
|
213
|
+
const outputPath = join(this.options.projectRoot, file);
|
|
214
|
+
|
|
215
|
+
// Check if template file exists
|
|
216
|
+
if (!(await this.fileExists(templatePath))) {
|
|
217
|
+
return { path: outputPath };
|
|
218
|
+
}
|
|
215
219
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
}
|
|
220
|
+
// Check if output file already exists
|
|
221
|
+
if (!this.options.force && (await this.fileExists(outputPath))) {
|
|
222
|
+
this.logger?.debug(`${file} already exists, skipping`);
|
|
223
|
+
return { path: outputPath, skipped: true };
|
|
224
|
+
}
|
|
222
225
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
+
try {
|
|
227
|
+
const content = await readFile(templatePath, "utf-8");
|
|
228
|
+
const processedContent = this.processEjsContent(content, templatePath);
|
|
226
229
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
} catch (error) {
|
|
230
|
-
result.errors.push(`Failed to generate ${file}: ${error instanceof Error ? error.message : String(error)}`);
|
|
230
|
+
if (!this.options.dryRun) {
|
|
231
|
+
await writeFile(outputPath, processedContent, "utf-8");
|
|
231
232
|
}
|
|
233
|
+
|
|
234
|
+
this.logger?.debug(`Created: ${outputPath}`);
|
|
235
|
+
return { path: outputPath, created: true };
|
|
236
|
+
} catch (error) {
|
|
237
|
+
return {
|
|
238
|
+
path: outputPath,
|
|
239
|
+
error: `Failed to generate ${file}: ${error instanceof Error ? error.message : String(error)}`,
|
|
240
|
+
};
|
|
232
241
|
}
|
|
242
|
+
}
|
|
233
243
|
|
|
234
|
-
|
|
235
|
-
|
|
244
|
+
/**
|
|
245
|
+
* Check if a file exists
|
|
246
|
+
*/
|
|
247
|
+
private async fileExists(filePath: string): Promise<boolean> {
|
|
248
|
+
try {
|
|
249
|
+
await stat(filePath);
|
|
250
|
+
return true;
|
|
251
|
+
} catch {
|
|
252
|
+
return false;
|
|
236
253
|
}
|
|
254
|
+
}
|
|
237
255
|
|
|
238
|
-
|
|
256
|
+
/**
|
|
257
|
+
* Process EJS content if it contains EJS tags
|
|
258
|
+
*/
|
|
259
|
+
private processEjsContent(content: string, templatePath: string): string {
|
|
260
|
+
if (content.includes("<%=") || content.includes("<%")) {
|
|
261
|
+
return ejs.render(content, this.options.variables, { filename: templatePath });
|
|
262
|
+
}
|
|
263
|
+
return content;
|
|
239
264
|
}
|
|
240
265
|
|
|
241
266
|
/**
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
|
|
8
8
|
import { DevClientProvider } from "@teardown/dev-client";
|
|
9
9
|
import { AppRegistry } from "react-native";
|
|
10
|
-
import { devClientConfig } from "
|
|
11
|
-
import { App } from "./app";
|
|
10
|
+
import { devClientConfig } from "./dev-client.config";
|
|
11
|
+
import { App } from "./src/app";
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Root component with development client wrapper
|
|
@@ -20,3 +20,5 @@ export function Root() {
|
|
|
20
20
|
</DevClientProvider>
|
|
21
21
|
);
|
|
22
22
|
}
|
|
23
|
+
|
|
24
|
+
AppRegistry.registerComponent("<%= appName %>", () => Root);
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import UIKit
|
|
2
2
|
import React
|
|
3
3
|
import React_RCTAppDelegate
|
|
4
|
+
import ReactAppDependencyProvider
|
|
4
5
|
|
|
5
6
|
@main
|
|
6
7
|
class AppDelegate: RCTAppDelegate {
|
|
7
8
|
override func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
|
|
8
9
|
self.moduleName = "<%= appName %>"
|
|
10
|
+
self.dependencyProvider = RCTAppDependencyProvider()
|
|
9
11
|
self.initialProps = [:]
|
|
10
12
|
|
|
11
13
|
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
|
package/templates/package.json
CHANGED
|
@@ -41,10 +41,10 @@
|
|
|
41
41
|
"@react-native-community/cli": "20.0.0",
|
|
42
42
|
"@react-native-community/cli-platform-android": "20.0.0",
|
|
43
43
|
"@react-native-community/cli-platform-ios": "20.0.0",
|
|
44
|
-
"@react-native/babel-preset": "0.
|
|
45
|
-
"@react-native/eslint-config": "0.
|
|
46
|
-
"@react-native/metro-config": "0.
|
|
47
|
-
"@react-native/typescript-config": "0.
|
|
44
|
+
"@react-native/babel-preset": "0.83.1",
|
|
45
|
+
"@react-native/eslint-config": "0.83.1",
|
|
46
|
+
"@react-native/metro-config": "0.83.1",
|
|
47
|
+
"@react-native/typescript-config": "0.83.1",
|
|
48
48
|
"@teardown/cli": "<%= cliVersion %>",
|
|
49
49
|
"@teardown/metro-config": "<%= cliVersion %>",
|
|
50
50
|
"@teardown/navigation-metro": "<%= cliVersion %>",
|
|
@@ -60,4 +60,4 @@
|
|
|
60
60
|
"engines": {
|
|
61
61
|
"node": ">=18"
|
|
62
62
|
}
|
|
63
|
-
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Navigation Hooks
|
|
3
|
+
*
|
|
4
|
+
* Properly initialized typed navigation hooks for use in screens.
|
|
5
|
+
* These wrap the @teardown/navigation factories with React Navigation's hooks.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { useNavigation, useRoute } from "@react-navigation/native";
|
|
9
|
+
import { createUseTypedNavigation, createUseTypedParams, createUseTypedRoute } from "@teardown/navigation/hooks";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Type-safe navigation hook.
|
|
13
|
+
* Use this to navigate between screens with full TypeScript support.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```tsx
|
|
17
|
+
* const navigation = useTypedNavigation();
|
|
18
|
+
* navigation.navigate("/settings");
|
|
19
|
+
* navigation.navigate("/(tabs)/home");
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export const useTypedNavigation = createUseTypedNavigation(useNavigation);
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Type-safe route params hook.
|
|
26
|
+
* Use this to access route parameters with full TypeScript support.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```tsx
|
|
30
|
+
* const params = useTypedParams<"/users/:userId">();
|
|
31
|
+
* console.log(params.userId);
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export const useTypedParams = createUseTypedParams(useRoute);
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Type-safe route hook.
|
|
38
|
+
* Use this to access the current route with full TypeScript support.
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```tsx
|
|
42
|
+
* const route = useTypedRoute<"/users/:userId">();
|
|
43
|
+
* console.log(route.name, route.params.userId);
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export const useTypedRoute = createUseTypedRoute(useRoute);
|
|
@@ -4,20 +4,20 @@
|
|
|
4
4
|
* The main landing screen of the app.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import React from "react";
|
|
8
|
-
import { View, ScrollView, Pressable } from "react-native";
|
|
9
7
|
import { defineScreen } from "@teardown/navigation/primitives";
|
|
10
|
-
import
|
|
8
|
+
import type React from "react";
|
|
9
|
+
import { Pressable, ScrollView, View } from "react-native";
|
|
11
10
|
import {
|
|
12
|
-
|
|
11
|
+
Badge,
|
|
13
12
|
Button,
|
|
14
13
|
Card,
|
|
14
|
+
CardContent,
|
|
15
|
+
CardDescription,
|
|
15
16
|
CardHeader,
|
|
16
17
|
CardTitle,
|
|
17
|
-
|
|
18
|
-
CardContent,
|
|
19
|
-
Badge,
|
|
18
|
+
Text,
|
|
20
19
|
} from "@/components/ui";
|
|
20
|
+
import { useTypedNavigation } from "@/navigation";
|
|
21
21
|
|
|
22
22
|
function HomeScreen(): React.JSX.Element {
|
|
23
23
|
const navigation = useTypedNavigation();
|
|
@@ -4,19 +4,11 @@
|
|
|
4
4
|
* User profile and account management screen.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import React from "react";
|
|
8
|
-
import { View, ScrollView, Pressable } from "react-native";
|
|
9
7
|
import { defineScreen } from "@teardown/navigation/primitives";
|
|
10
|
-
import
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
Avatar,
|
|
15
|
-
Card,
|
|
16
|
-
CardContent,
|
|
17
|
-
Badge,
|
|
18
|
-
Separator,
|
|
19
|
-
} from "@/components/ui";
|
|
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";
|
|
20
12
|
|
|
21
13
|
function ProfileScreen(): React.JSX.Element {
|
|
22
14
|
const navigation = useTypedNavigation();
|
|
@@ -49,52 +41,32 @@ function ProfileScreen(): React.JSX.Element {
|
|
|
49
41
|
|
|
50
42
|
{/* Account Section */}
|
|
51
43
|
<View className="gap-2">
|
|
52
|
-
<Text variant="label" className="px-1">
|
|
44
|
+
<Text variant="label" className="px-1">
|
|
45
|
+
ACCOUNT
|
|
46
|
+
</Text>
|
|
53
47
|
<Card>
|
|
54
48
|
<CardContent className="p-0">
|
|
55
|
-
<MenuItem
|
|
56
|
-
icon="⚙️"
|
|
57
|
-
title="Settings"
|
|
58
|
-
onPress={() => navigation.navigate("/settings")}
|
|
59
|
-
/>
|
|
49
|
+
<MenuItem icon="⚙️" title="Settings" onPress={() => navigation.navigate("/settings")} />
|
|
60
50
|
<Separator />
|
|
61
|
-
<MenuItem
|
|
62
|
-
icon="🔒"
|
|
63
|
-
title="Privacy"
|
|
64
|
-
onPress={() => {}}
|
|
65
|
-
/>
|
|
51
|
+
<MenuItem icon="🔒" title="Privacy" onPress={() => {}} />
|
|
66
52
|
<Separator />
|
|
67
|
-
<MenuItem
|
|
68
|
-
icon="🔔"
|
|
69
|
-
title="Notifications"
|
|
70
|
-
onPress={() => {}}
|
|
71
|
-
/>
|
|
53
|
+
<MenuItem icon="🔔" title="Notifications" onPress={() => {}} />
|
|
72
54
|
</CardContent>
|
|
73
55
|
</Card>
|
|
74
56
|
</View>
|
|
75
57
|
|
|
76
58
|
{/* Support Section */}
|
|
77
59
|
<View className="gap-2">
|
|
78
|
-
<Text variant="label" className="px-1">
|
|
60
|
+
<Text variant="label" className="px-1">
|
|
61
|
+
SUPPORT
|
|
62
|
+
</Text>
|
|
79
63
|
<Card>
|
|
80
64
|
<CardContent className="p-0">
|
|
81
|
-
<MenuItem
|
|
82
|
-
icon="❓"
|
|
83
|
-
title="Help Center"
|
|
84
|
-
onPress={() => {}}
|
|
85
|
-
/>
|
|
65
|
+
<MenuItem icon="❓" title="Help Center" onPress={() => {}} />
|
|
86
66
|
<Separator />
|
|
87
|
-
<MenuItem
|
|
88
|
-
icon="💬"
|
|
89
|
-
title="Contact Us"
|
|
90
|
-
onPress={() => {}}
|
|
91
|
-
/>
|
|
67
|
+
<MenuItem icon="💬" title="Contact Us" onPress={() => {}} />
|
|
92
68
|
<Separator />
|
|
93
|
-
<MenuItem
|
|
94
|
-
icon="📝"
|
|
95
|
-
title="Send Feedback"
|
|
96
|
-
onPress={() => {}}
|
|
97
|
-
/>
|
|
69
|
+
<MenuItem icon="📝" title="Send Feedback" onPress={() => {}} />
|
|
98
70
|
</CardContent>
|
|
99
71
|
</Card>
|
|
100
72
|
</View>
|
|
@@ -121,22 +93,13 @@ function StatItem({ label, value }: { label: string; value: string }): React.JSX
|
|
|
121
93
|
);
|
|
122
94
|
}
|
|
123
95
|
|
|
124
|
-
function MenuItem({
|
|
125
|
-
icon,
|
|
126
|
-
title,
|
|
127
|
-
onPress,
|
|
128
|
-
}: {
|
|
129
|
-
icon: string;
|
|
130
|
-
title: string;
|
|
131
|
-
onPress: () => void;
|
|
132
|
-
}): React.JSX.Element {
|
|
96
|
+
function MenuItem({ icon, title, onPress }: { icon: string; title: string; onPress: () => void }): React.JSX.Element {
|
|
133
97
|
return (
|
|
134
|
-
<Pressable
|
|
135
|
-
className="flex-row items-center px-4 py-3 active:bg-muted/50"
|
|
136
|
-
onPress={onPress}
|
|
137
|
-
>
|
|
98
|
+
<Pressable className="flex-row items-center px-4 py-3 active:bg-muted/50" onPress={onPress}>
|
|
138
99
|
<Text className="text-xl mr-3">{icon}</Text>
|
|
139
|
-
<Text variant="large" className="flex-1">
|
|
100
|
+
<Text variant="large" className="flex-1">
|
|
101
|
+
{title}
|
|
102
|
+
</Text>
|
|
140
103
|
<Text className="text-muted-foreground">›</Text>
|
|
141
104
|
</Pressable>
|
|
142
105
|
);
|
|
@@ -5,19 +5,11 @@
|
|
|
5
5
|
* This is a stack screen outside of the tab navigator.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import React from "react";
|
|
9
|
-
import { View, ScrollView, Switch, Pressable } from "react-native";
|
|
10
8
|
import { defineScreen } from "@teardown/navigation/primitives";
|
|
11
|
-
import
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
Card,
|
|
16
|
-
CardHeader,
|
|
17
|
-
CardTitle,
|
|
18
|
-
CardContent,
|
|
19
|
-
Separator,
|
|
20
|
-
} from "@/components/ui";
|
|
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";
|
|
21
13
|
|
|
22
14
|
function SettingsScreen(): React.JSX.Element {
|
|
23
15
|
const navigation = useTypedNavigation();
|
|
@@ -30,7 +22,9 @@ function SettingsScreen(): React.JSX.Element {
|
|
|
30
22
|
<ScrollView className="flex-1 bg-background" contentContainerClassName="p-6 gap-6">
|
|
31
23
|
{/* Preferences Section */}
|
|
32
24
|
<View className="gap-2">
|
|
33
|
-
<Text variant="label" className="px-1">
|
|
25
|
+
<Text variant="label" className="px-1">
|
|
26
|
+
PREFERENCES
|
|
27
|
+
</Text>
|
|
34
28
|
<Card>
|
|
35
29
|
<CardContent className="p-0">
|
|
36
30
|
<SettingRow
|
|
@@ -70,7 +64,9 @@ function SettingsScreen(): React.JSX.Element {
|
|
|
70
64
|
|
|
71
65
|
{/* Storage Section */}
|
|
72
66
|
<View className="gap-2">
|
|
73
|
-
<Text variant="label" className="px-1">
|
|
67
|
+
<Text variant="label" className="px-1">
|
|
68
|
+
STORAGE
|
|
69
|
+
</Text>
|
|
74
70
|
<Card>
|
|
75
71
|
<CardContent className="gap-4 py-4">
|
|
76
72
|
<View className="flex-row justify-between">
|
|
@@ -86,7 +82,9 @@ function SettingsScreen(): React.JSX.Element {
|
|
|
86
82
|
|
|
87
83
|
{/* About Section */}
|
|
88
84
|
<View className="gap-2">
|
|
89
|
-
<Text variant="label" className="px-1">
|
|
85
|
+
<Text variant="label" className="px-1">
|
|
86
|
+
ABOUT
|
|
87
|
+
</Text>
|
|
90
88
|
<Card>
|
|
91
89
|
<CardContent className="p-0">
|
|
92
90
|
<InfoRow icon="📱" title="Version" value="1.0.0" />
|
|
@@ -100,7 +98,9 @@ function SettingsScreen(): React.JSX.Element {
|
|
|
100
98
|
|
|
101
99
|
{/* Legal Section */}
|
|
102
100
|
<View className="gap-2">
|
|
103
|
-
<Text variant="label" className="px-1">
|
|
101
|
+
<Text variant="label" className="px-1">
|
|
102
|
+
LEGAL
|
|
103
|
+
</Text>
|
|
104
104
|
<Card>
|
|
105
105
|
<CardContent className="p-0">
|
|
106
106
|
<LinkRow icon="📄" title="Terms of Service" />
|
|
@@ -150,35 +150,25 @@ function SettingRow({
|
|
|
150
150
|
);
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
-
function InfoRow({
|
|
154
|
-
icon,
|
|
155
|
-
title,
|
|
156
|
-
value,
|
|
157
|
-
}: {
|
|
158
|
-
icon: string;
|
|
159
|
-
title: string;
|
|
160
|
-
value: string;
|
|
161
|
-
}): React.JSX.Element {
|
|
153
|
+
function InfoRow({ icon, title, value }: { icon: string; title: string; value: string }): React.JSX.Element {
|
|
162
154
|
return (
|
|
163
155
|
<View className="flex-row items-center px-4 py-3">
|
|
164
156
|
<Text className="text-xl mr-3">{icon}</Text>
|
|
165
|
-
<Text variant="large" className="flex-1">
|
|
157
|
+
<Text variant="large" className="flex-1">
|
|
158
|
+
{title}
|
|
159
|
+
</Text>
|
|
166
160
|
<Text variant="muted">{value}</Text>
|
|
167
161
|
</View>
|
|
168
162
|
);
|
|
169
163
|
}
|
|
170
164
|
|
|
171
|
-
function LinkRow({
|
|
172
|
-
icon,
|
|
173
|
-
title,
|
|
174
|
-
}: {
|
|
175
|
-
icon: string;
|
|
176
|
-
title: string;
|
|
177
|
-
}): React.JSX.Element {
|
|
165
|
+
function LinkRow({ icon, title }: { icon: string; title: string }): React.JSX.Element {
|
|
178
166
|
return (
|
|
179
167
|
<Pressable className="flex-row items-center px-4 py-3 active:bg-muted/50">
|
|
180
168
|
<Text className="text-xl mr-3">{icon}</Text>
|
|
181
|
-
<Text variant="large" className="flex-1">
|
|
169
|
+
<Text variant="large" className="flex-1">
|
|
170
|
+
{title}
|
|
171
|
+
</Text>
|
|
182
172
|
<Text className="text-muted-foreground">›</Text>
|
|
183
173
|
</Pressable>
|
|
184
174
|
);
|
package/templates/index.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* App Entry Point
|
|
3
|
-
*
|
|
4
|
-
* This file registers the root component with React Native's AppRegistry.
|
|
5
|
-
* The app is wrapped with DevClientProvider for development tools.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { AppRegistry } from "react-native";
|
|
9
|
-
import { Root } from "./src";
|
|
10
|
-
|
|
11
|
-
AppRegistry.registerComponent("<%= appName %>", () => Root);
|