create-rn-folder-structure 1.0.0 → 1.0.3

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/README.md ADDED
@@ -0,0 +1,91 @@
1
+ # 📦 create-rn-folder-structure
2
+
3
+ A lightweight CLI tool that automatically generates a **clean, scalable,
4
+ and production-ready folder structure** for React Native projects.
5
+
6
+ This tool helps you quickly bootstrap a well-organized architecture so
7
+ you can focus on writing features---not setting up directories.
8
+
9
+ ------------------------------------------------------------------------
10
+
11
+ ## 🚀 Features
12
+
13
+ - 📁 Generates a modern, opinionated React Native folder structure\
14
+ - 🔌 Auto-creates feature modules (screens, store, API)\
15
+ - 🧩 Shared components, constants, hooks, and utilities\
16
+ - 📡 Centralized API configuration\
17
+ - 💾 Async storage service helpers\
18
+ - ⚡ Fast, simple, and zero-dependency CLI
19
+
20
+ ------------------------------------------------------------------------
21
+
22
+ ## 📦 Installation
23
+
24
+ Install the package globally:
25
+
26
+ ``` sh
27
+ npm install -g create-rn-folder-structure
28
+ ```
29
+
30
+ Or use **npx** (recommended):
31
+
32
+ ``` sh
33
+ npx create-rn-folder-structure
34
+ ```
35
+
36
+ ------------------------------------------------------------------------
37
+
38
+ ## 🛠️ Usage
39
+
40
+ Run inside your React Native project:
41
+
42
+ ``` sh
43
+ npx create-rn-folder-structure
44
+ ```
45
+
46
+ ------------------------------------------------------------------------
47
+
48
+ ## 📁 Generated Folder Structure
49
+
50
+ src/
51
+ ├── app/
52
+ │ ├── navigation/
53
+ │ └── store/
54
+ ├── features/
55
+ │ ├── auth/
56
+ │ ├── profile/
57
+ │ ├── dashboard/
58
+ │ └── settings/
59
+ ├── shared/
60
+ │ ├── components/
61
+ │ ├── constants/
62
+ │ ├── custom-hooks/
63
+ │ └── utils/
64
+ ├── services/
65
+ │ ├── api/
66
+ │ └── storage/
67
+
68
+ ------------------------------------------------------------------------
69
+
70
+ ## ✨ What Gets Generated?
71
+
72
+ ✔ Feature screens\
73
+ ✔ Base API service\
74
+ ✔ Centralized store structure\
75
+ ✔ Shared UI components folder\
76
+ ✔ Custom hooks folder\
77
+ ✔ App-level constants & utilities\
78
+ ✔ Typed folder layout (if using TS)
79
+
80
+ ------------------------------------------------------------------------
81
+
82
+ ## 🤝 Contributing
83
+
84
+ Contributions are welcome!
85
+
86
+ ------------------------------------------------------------------------
87
+
88
+ ## ❤️ Author
89
+
90
+ Generated with ❤️ using **create-rn-folder-structure**
91
+ "Winner-Winner Chicken Dinner"
@@ -0,0 +1,221 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+
4
+ function write(root, filePath, content) {
5
+ const fullPath = path.join(root, filePath);
6
+ fs.mkdirSync(path.dirname(fullPath), { recursive: true });
7
+ fs.writeFileSync(fullPath, content);
8
+ }
9
+
10
+ module.exports = function generateAdvancedComponents(projectRoot) {
11
+ console.log("⚡ Creating Advanced UI Components...");
12
+
13
+ const base = "src/shared/components";
14
+
15
+ // ---------------------------------------------------------
16
+ // Toast Message
17
+ // ---------------------------------------------------------
18
+ write(
19
+ projectRoot,
20
+ `${base}/Toast.tsx`,
21
+ `
22
+ import React, { useEffect, useRef } from "react";
23
+ import { Animated, Text, StyleSheet, Dimensions } from "react-native";
24
+
25
+ interface Props {
26
+ message: string;
27
+ visible: boolean;
28
+ type?: "success" | "error" | "info";
29
+ }
30
+
31
+ const { width } = Dimensions.get("window");
32
+
33
+ export default function Toast({ message, visible, type = "info" }: Props) {
34
+ const opacity = useRef(new Animated.Value(0)).current;
35
+
36
+ useEffect(() => {
37
+ if (visible) {
38
+ Animated.timing(opacity, {
39
+ toValue: 1,
40
+ duration: 300,
41
+ useNativeDriver: true,
42
+ }).start(() => {
43
+ setTimeout(() => {
44
+ Animated.timing(opacity, {
45
+ toValue: 0,
46
+ duration: 300,
47
+ useNativeDriver: true,
48
+ }).start();
49
+ }, 1500);
50
+ });
51
+ }
52
+ }, [visible]);
53
+
54
+ return (
55
+ <Animated.View
56
+ style={[
57
+ styles.toast,
58
+ styles[type],
59
+ { opacity, transform: [{ translateY: opacity.interpolate({
60
+ inputRange: [0, 1],
61
+ outputRange: [40, 0],
62
+ }) }] },
63
+ ]}
64
+ >
65
+ <Text style={styles.text}>{message}</Text>
66
+ </Animated.View>
67
+ );
68
+ }
69
+
70
+ const styles = StyleSheet.create({
71
+ toast: {
72
+ position: "absolute",
73
+ bottom: 50,
74
+ alignSelf: "center",
75
+ width: width * 0.8,
76
+ padding: 12,
77
+ borderRadius: 6,
78
+ },
79
+ text: { color: "#fff", fontWeight: "600", textAlign: "center" },
80
+ success: { backgroundColor: "green" },
81
+ error: { backgroundColor: "red" },
82
+ info: { backgroundColor: "blue" },
83
+ });
84
+ `
85
+ );
86
+
87
+ // ---------------------------------------------------------
88
+ // Loader (simple spinner overlay)
89
+ // ---------------------------------------------------------
90
+ write(
91
+ projectRoot,
92
+ `${base}/Loader.tsx`,
93
+ `
94
+ import React from "react";
95
+ import { View, ActivityIndicator, StyleSheet } from "react-native";
96
+
97
+ export default function Loader({ visible }: { visible: boolean }) {
98
+ if (!visible) return null;
99
+
100
+ return (
101
+ <View style={styles.overlay}>
102
+ <ActivityIndicator size="large" color="#fff" />
103
+ </View>
104
+ );
105
+ }
106
+
107
+ const styles = StyleSheet.create({
108
+ overlay: {
109
+ position: "absolute",
110
+ zIndex: 1000,
111
+ top: 0,
112
+ left: 0,
113
+ right: 0,
114
+ bottom: 0,
115
+ backgroundColor: "rgba(0,0,0,0.5)",
116
+ justifyContent: "center",
117
+ alignItems: "center",
118
+ },
119
+ });
120
+ `
121
+ );
122
+
123
+ // ---------------------------------------------------------
124
+ // Skeleton / Shimmer Loader
125
+ // ---------------------------------------------------------
126
+ write(
127
+ projectRoot,
128
+ `${base}/SkeletonLoader.tsx`,
129
+ `
130
+ import React, { useEffect, useRef } from "react";
131
+ import { Animated, StyleSheet, View } from "react-native";
132
+
133
+ interface Props {
134
+ height?: number;
135
+ width?: number | string;
136
+ radius?: number;
137
+ }
138
+
139
+ export default function SkeletonLoader({
140
+ height = 20,
141
+ width = "100%",
142
+ radius = 6,
143
+ }: Props) {
144
+ const shimmer = useRef(new Animated.Value(0.3)).current;
145
+
146
+ useEffect(() => {
147
+ Animated.loop(
148
+ Animated.sequence([
149
+ Animated.timing(shimmer, {
150
+ toValue: 1,
151
+ duration: 800,
152
+ useNativeDriver: false,
153
+ }),
154
+ Animated.timing(shimmer, {
155
+ toValue: 0.3,
156
+ duration: 800,
157
+ useNativeDriver: false,
158
+ }),
159
+ ])
160
+ ).start();
161
+ }, []);
162
+
163
+ return (
164
+ <Animated.View
165
+ style={[
166
+ styles.box,
167
+ { height, width, borderRadius: radius, opacity: shimmer },
168
+ ]}
169
+ />
170
+ );
171
+ }
172
+
173
+ const styles = StyleSheet.create({
174
+ box: {
175
+ backgroundColor: "#e0e0e0",
176
+ marginVertical: 6,
177
+ },
178
+ });
179
+ `
180
+ );
181
+
182
+ // ---------------------------------------------------------
183
+ // Progress Bar
184
+ // ---------------------------------------------------------
185
+ write(
186
+ projectRoot,
187
+ `${base}/ProgressBar.tsx`,
188
+ `
189
+ import React from "react";
190
+ import { View, StyleSheet } from "react-native";
191
+
192
+ interface Props {
193
+ progress: number; // 0 to 1
194
+ }
195
+
196
+ export default function ProgressBar({ progress }: Props) {
197
+ return (
198
+ <View style={styles.container}>
199
+ <View style={[styles.bar, { width: \`\${progress * 100}%\` }]} />
200
+ </View>
201
+ );
202
+ }
203
+
204
+ const styles = StyleSheet.create({
205
+ container: {
206
+ height: 12,
207
+ backgroundColor: "#eee",
208
+ borderRadius: 6,
209
+ overflow: "hidden",
210
+ marginVertical: 6,
211
+ },
212
+ bar: {
213
+ height: "100%",
214
+ backgroundColor: "#007AFF",
215
+ },
216
+ });
217
+ `
218
+ );
219
+
220
+ console.log("✅ Advanced Components Created!");
221
+ };
@@ -0,0 +1,243 @@
1
+ const fs = require("fs");
2
+ const path = require("path");
3
+
4
+ function write(root, filePath, content) {
5
+ const fullPath = path.join(root, filePath);
6
+ fs.mkdirSync(path.dirname(fullPath), { recursive: true });
7
+ fs.writeFileSync(fullPath, content);
8
+ }
9
+
10
+ module.exports = function generateBasicComponents(projectRoot) {
11
+ console.log("🎨 Creating Basic UI Components...");
12
+
13
+ const base = "src/shared/components";
14
+
15
+ // ---------------------------------------------------------
16
+ // Button
17
+ // ---------------------------------------------------------
18
+ write(
19
+ projectRoot,
20
+ `${base}/Button.tsx`,
21
+ `
22
+ import React from "react";
23
+ import { TouchableOpacity, Text, StyleSheet, ActivityIndicator } from "react-native";
24
+
25
+ interface Props {
26
+ title: string;
27
+ onPress: () => void;
28
+ disabled?: boolean;
29
+ loading?: boolean;
30
+ }
31
+
32
+ export default function Button({ title, onPress, disabled, loading }: Props) {
33
+ return (
34
+ <TouchableOpacity
35
+ style={[styles.button, disabled && styles.disabled]}
36
+ onPress={onPress}
37
+ disabled={disabled || loading}
38
+ >
39
+ {loading ? (
40
+ <ActivityIndicator color="#fff" />
41
+ ) : (
42
+ <Text style={styles.text}>{title}</Text>
43
+ )}
44
+ </TouchableOpacity>
45
+ );
46
+ }
47
+
48
+ const styles = StyleSheet.create({
49
+ button: {
50
+ backgroundColor: "#007AFF",
51
+ paddingVertical: 12,
52
+ paddingHorizontal: 18,
53
+ borderRadius: 8,
54
+ alignItems: "center",
55
+ justifyContent: "center",
56
+ },
57
+ disabled: { opacity: 0.6 },
58
+ text: {
59
+ color: "#fff",
60
+ fontSize: 16,
61
+ fontWeight: "600",
62
+ },
63
+ });
64
+ `
65
+ );
66
+
67
+ // ---------------------------------------------------------
68
+ // Card
69
+ // ---------------------------------------------------------
70
+ write(
71
+ projectRoot,
72
+ `${base}/Card.tsx`,
73
+ `
74
+ import React from "react";
75
+ import { View, StyleSheet } from "react-native";
76
+
77
+ export default function Card({ children }: any) {
78
+ return <View style={styles.card}>{children}</View>;
79
+ }
80
+
81
+ const styles = StyleSheet.create({
82
+ card: {
83
+ backgroundColor: "#fff",
84
+ padding: 15,
85
+ borderRadius: 10,
86
+ marginVertical: 8,
87
+ shadowColor: "#000",
88
+ shadowOpacity: 0.1,
89
+ shadowOffset: { width: 0, height: 2 },
90
+ elevation: 3,
91
+ },
92
+ });
93
+ `
94
+ );
95
+
96
+ // ---------------------------------------------------------
97
+ // TextInput
98
+ // ---------------------------------------------------------
99
+ write(
100
+ projectRoot,
101
+ `${base}/TextInput.tsx`,
102
+ `
103
+ import React from "react";
104
+ import { TextInput as RNInput, StyleSheet } from "react-native";
105
+
106
+ export default function TextInput({ style, ...rest }: any) {
107
+ return <RNInput style={[styles.input, style]} {...rest} />;
108
+ }
109
+
110
+ const styles = StyleSheet.create({
111
+ input: {
112
+ borderWidth: 1,
113
+ borderColor: "#ccc",
114
+ padding: 12,
115
+ borderRadius: 8,
116
+ fontSize: 16,
117
+ marginVertical: 6,
118
+ },
119
+ });
120
+ `
121
+ );
122
+
123
+ // ---------------------------------------------------------
124
+ // LineSeparator
125
+ // ---------------------------------------------------------
126
+ write(
127
+ projectRoot,
128
+ `${base}/LineSeparator.tsx`,
129
+ `
130
+ import React from "react";
131
+ import { View, StyleSheet } from "react-native";
132
+
133
+ export default function LineSeparator() {
134
+ return <View style={styles.line} />;
135
+ }
136
+
137
+ const styles = StyleSheet.create({
138
+ line: {
139
+ height: 1,
140
+ backgroundColor: "#ddd",
141
+ marginVertical: 10,
142
+ },
143
+ });
144
+ `
145
+ );
146
+
147
+ // ---------------------------------------------------------
148
+ // Switch
149
+ // ---------------------------------------------------------
150
+ write(
151
+ projectRoot,
152
+ `${base}/Switch.tsx`,
153
+ `
154
+ import React from "react";
155
+ import { Switch as RNSwitch } from "react-native";
156
+
157
+ export default function Switch({ value, onValueChange }: any) {
158
+ return <RNSwitch value={value} onValueChange={onValueChange} />;
159
+ }
160
+ `
161
+ );
162
+
163
+ // ---------------------------------------------------------
164
+ // Radio Button
165
+ // ---------------------------------------------------------
166
+ write(
167
+ projectRoot,
168
+ `${base}/RadioButton.tsx`,
169
+ `
170
+ import React from "react";
171
+ import { TouchableOpacity, View, Text, StyleSheet } from "react-native";
172
+
173
+ interface Props {
174
+ selected: boolean;
175
+ label: string;
176
+ onPress: () => void;
177
+ }
178
+
179
+ export default function RadioButton({ selected, label, onPress }: Props) {
180
+ return (
181
+ <TouchableOpacity style={styles.row} onPress={onPress}>
182
+ <View style={[styles.circle, selected && styles.active]} />
183
+ <Text>{label}</Text>
184
+ </TouchableOpacity>
185
+ );
186
+ }
187
+
188
+ const styles = StyleSheet.create({
189
+ row: { flexDirection: "row", alignItems: "center", marginVertical: 8 },
190
+ circle: {
191
+ height: 20,
192
+ width: 20,
193
+ borderRadius: 20,
194
+ borderWidth: 2,
195
+ borderColor: "#007AFF",
196
+ marginRight: 10,
197
+ },
198
+ active: { backgroundColor: "#007AFF" },
199
+ });
200
+ `
201
+ );
202
+
203
+ // ---------------------------------------------------------
204
+ // Checkbox
205
+ // ---------------------------------------------------------
206
+ write(
207
+ projectRoot,
208
+ `${base}/Checkbox.tsx`,
209
+ `
210
+ import React from "react";
211
+ import { TouchableOpacity, View, Text, StyleSheet } from "react-native";
212
+
213
+ interface Props {
214
+ label: string;
215
+ checked: boolean;
216
+ onPress: () => void;
217
+ }
218
+
219
+ export default function Checkbox({ label, checked, onPress }: Props) {
220
+ return (
221
+ <TouchableOpacity style={styles.row} onPress={onPress}>
222
+ <View style={[styles.box, checked && styles.checked]} />
223
+ <Text>{label}</Text>
224
+ </TouchableOpacity>
225
+ );
226
+ }
227
+
228
+ const styles = StyleSheet.create({
229
+ row: { flexDirection: "row", alignItems: "center", marginVertical: 8 },
230
+ box: {
231
+ width: 22,
232
+ height: 22,
233
+ borderWidth: 2,
234
+ borderColor: "#007AFF",
235
+ marginRight: 10,
236
+ },
237
+ checked: { backgroundColor: "#007AFF" },
238
+ });
239
+ `
240
+ );
241
+
242
+ console.log("✅ Basic UI Components Created!");
243
+ };