create-rn-folder-structure 1.0.2 → 1.0.4

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.
@@ -0,0 +1,659 @@
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 generateComponents(projectRoot) {
11
+ console.log("🎨 Creating Shared 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 } from "react-native";
24
+
25
+ export default function Button({ title, onPress, style = {}, textStyle = {} }) {
26
+ return (
27
+ <TouchableOpacity style={[styles.button, style]} onPress={onPress}>
28
+ <Text style={[styles.text, textStyle]}>{title}</Text>
29
+ </TouchableOpacity>
30
+ );
31
+ }
32
+
33
+ const styles = StyleSheet.create({
34
+ button: {
35
+ backgroundColor: "#1e90ff",
36
+ padding: 14,
37
+ borderRadius: 8,
38
+ alignItems: "center",
39
+ },
40
+ text: {
41
+ color: "#fff",
42
+ fontWeight: "600",
43
+ },
44
+ });
45
+ `
46
+ );
47
+
48
+ // -----------------------------------------------------
49
+ // CARD
50
+ // -----------------------------------------------------
51
+ write(
52
+ projectRoot,
53
+ `${base}/Card.tsx`,
54
+ `
55
+ import React from "react";
56
+ import { View, StyleSheet } from "react-native";
57
+
58
+ export default function Card({ children, style = {} }) {
59
+ return <View style={[styles.card, style]}>{children}</View>;
60
+ }
61
+
62
+ const styles = StyleSheet.create({
63
+ card: {
64
+ padding: 16,
65
+ borderRadius: 10,
66
+ backgroundColor: "#fff",
67
+ elevation: 4,
68
+ shadowColor: "#000",
69
+ shadowOpacity: 0.1,
70
+ shadowRadius: 6,
71
+ },
72
+ });
73
+ `
74
+ );
75
+
76
+ // -----------------------------------------------------
77
+ // RADIO BUTTON
78
+ // -----------------------------------------------------
79
+ write(
80
+ projectRoot,
81
+ `${base}/RadioButton.tsx`,
82
+ `
83
+ import React from "react";
84
+ import { TouchableOpacity, View, StyleSheet } from "react-native";
85
+
86
+ export default function RadioButton({ selected, onPress }) {
87
+ return (
88
+ <TouchableOpacity onPress={onPress} style={styles.outer}>
89
+ {selected && <View style={styles.inner} />}
90
+ </TouchableOpacity>
91
+ );
92
+ }
93
+
94
+ const styles = StyleSheet.create({
95
+ outer: {
96
+ width: 22,
97
+ height: 22,
98
+ borderRadius: 11,
99
+ borderWidth: 2,
100
+ borderColor: "#1e90ff",
101
+ justifyContent: "center",
102
+ alignItems: "center",
103
+ },
104
+ inner: {
105
+ width: 12,
106
+ height: 12,
107
+ borderRadius: 6,
108
+ backgroundColor: "#1e90ff",
109
+ },
110
+ });
111
+ `
112
+ );
113
+
114
+ // -----------------------------------------------------
115
+ // SWITCH (Simple)
116
+ // -----------------------------------------------------
117
+ write(
118
+ projectRoot,
119
+ `${base}/Switch.tsx`,
120
+ `
121
+ import React from "react";
122
+ import { Pressable, View, StyleSheet } from "react-native";
123
+
124
+ export default function Switch({ value, onToggle }) {
125
+ return (
126
+ <Pressable onPress={onToggle} style={[styles.container, value && styles.active]}>
127
+ <View style={[styles.circle, value && styles.circleActive]} />
128
+ </Pressable>
129
+ );
130
+ }
131
+
132
+ const styles = StyleSheet.create({
133
+ container: {
134
+ width: 50,
135
+ height: 28,
136
+ borderRadius: 14,
137
+ backgroundColor: "#ccc",
138
+ justifyContent: "center",
139
+ },
140
+ active: {
141
+ backgroundColor: "#1e90ff",
142
+ },
143
+ circle: {
144
+ width: 20,
145
+ height: 20,
146
+ backgroundColor: "#fff",
147
+ borderRadius: 10,
148
+ marginLeft: 4,
149
+ },
150
+ circleActive: {
151
+ marginLeft: 26,
152
+ },
153
+ });
154
+ `
155
+ );
156
+
157
+ // -----------------------------------------------------
158
+ // MODAL
159
+ // -----------------------------------------------------
160
+ write(
161
+ projectRoot,
162
+ `${base}/Modal.tsx`,
163
+ `
164
+ import React from "react";
165
+ import { Modal, View, StyleSheet } from "react-native";
166
+
167
+ export default function CustomModal({ visible, children }) {
168
+ return (
169
+ <Modal visible={visible} transparent animationType="fade">
170
+ <View style={styles.center}>
171
+ <View style={styles.box}>{children}</View>
172
+ </View>
173
+ </Modal>
174
+ );
175
+ }
176
+
177
+ const styles = StyleSheet.create({
178
+ center: {
179
+ flex: 1,
180
+ justifyContent: "center",
181
+ alignItems: "center",
182
+ backgroundColor: "rgba(0,0,0,0.4)",
183
+ },
184
+ box: {
185
+ width: "80%",
186
+ padding: 20,
187
+ backgroundColor: "#fff",
188
+ borderRadius: 10,
189
+ },
190
+ });
191
+ `
192
+ );
193
+
194
+ // -----------------------------------------------------
195
+ // LINE SEPARATOR
196
+ // -----------------------------------------------------
197
+ write(
198
+ projectRoot,
199
+ `${base}/LineSeparator.tsx`,
200
+ `
201
+ import React from "react";
202
+ import { View } from "react-native";
203
+
204
+ export default function LineSeparator() {
205
+ return <View style={{ height: 1, backgroundColor: "#ddd", marginVertical: 10 }} />;
206
+ }
207
+ `
208
+ );
209
+
210
+ // -----------------------------------------------------
211
+ // TEXT INPUT
212
+ // -----------------------------------------------------
213
+ write(
214
+ projectRoot,
215
+ `${base}/TextInput.tsx`,
216
+ `
217
+ import React from "react";
218
+ import { TextInput as RNInput, StyleSheet } from "react-native";
219
+
220
+ export default function TextInput({ style = {}, ...rest }) {
221
+ return <RNInput style={[styles.input, style]} {...rest} />;
222
+ }
223
+
224
+ const styles = StyleSheet.create({
225
+ input: {
226
+ borderWidth: 1,
227
+ borderColor: "#bbb",
228
+ padding: 12,
229
+ borderRadius: 8,
230
+ },
231
+ });
232
+ `
233
+ );
234
+
235
+ // -----------------------------------------------------
236
+ // CHECKBOX
237
+ // -----------------------------------------------------
238
+ write(
239
+ projectRoot,
240
+ `${base}/Checkbox.tsx`,
241
+ `
242
+ import React from "react";
243
+ import { TouchableOpacity, View, StyleSheet } from "react-native";
244
+
245
+ export default function Checkbox({ checked, onPress }) {
246
+ return (
247
+ <TouchableOpacity onPress={onPress} style={styles.box}>
248
+ {checked && <View style={styles.inner} />}
249
+ </TouchableOpacity>
250
+ );
251
+ }
252
+
253
+ const styles = StyleSheet.create({
254
+ box: {
255
+ width: 22,
256
+ height: 22,
257
+ borderWidth: 2,
258
+ borderColor: "#1e90ff",
259
+ borderRadius: 4,
260
+ justifyContent: "center",
261
+ alignItems: "center",
262
+ },
263
+ inner: {
264
+ width: 12,
265
+ height: 12,
266
+ backgroundColor: "#1e90ff",
267
+ },
268
+ });
269
+ `
270
+ );
271
+
272
+ // -----------------------------------------------------
273
+ // DROPDOWN (Basic)
274
+ // -----------------------------------------------------
275
+ write(
276
+ projectRoot,
277
+ `${base}/Dropdown.tsx`,
278
+ `
279
+ import React, { useState } from "react";
280
+ import { View, Text, TouchableOpacity, StyleSheet } from "react-native";
281
+
282
+ export default function Dropdown({ options = [], selected, onSelect }) {
283
+ const [open, setOpen] = useState(false);
284
+
285
+ return (
286
+ <View style={styles.container}>
287
+ <TouchableOpacity style={styles.box} onPress={() => setOpen(!open)}>
288
+ <Text>{selected || "Select option"}</Text>
289
+ </TouchableOpacity>
290
+
291
+ {open &&
292
+ options.map((opt) => (
293
+ <TouchableOpacity
294
+ key={opt}
295
+ style={styles.option}
296
+ onPress={() => {
297
+ onSelect(opt);
298
+ setOpen(false);
299
+ }}
300
+ >
301
+ <Text>{opt}</Text>
302
+ </TouchableOpacity>
303
+ ))}
304
+ </View>
305
+ );
306
+ }
307
+
308
+ const styles = StyleSheet.create({
309
+ container: {},
310
+ box: {
311
+ padding: 12,
312
+ borderWidth: 1,
313
+ borderColor: "#bbb",
314
+ borderRadius: 8,
315
+ },
316
+ option: {
317
+ padding: 12,
318
+ backgroundColor: "#eee",
319
+ borderBottomWidth: 1,
320
+ borderColor: "#ccc",
321
+ },
322
+ });
323
+ `
324
+ );
325
+
326
+ // -----------------------------------------------------
327
+ // SEARCH BAR
328
+ // -----------------------------------------------------
329
+ write(
330
+ projectRoot,
331
+ `${base}/SearchBar.tsx`,
332
+ `
333
+ import React from "react";
334
+ import { TextInput, StyleSheet } from "react-native";
335
+
336
+ export default function SearchBar({ ...props }) {
337
+ return <TextInput style={styles.input} placeholder="Search..." {...props} />;
338
+ }
339
+
340
+ const styles = StyleSheet.create({
341
+ input: {
342
+ backgroundColor: "#f0f0f0",
343
+ padding: 12,
344
+ borderRadius: 8,
345
+ },
346
+ });
347
+ `
348
+ );
349
+
350
+ // -----------------------------------------------------
351
+ // FLATLIST CARD
352
+ // -----------------------------------------------------
353
+ write(
354
+ projectRoot,
355
+ `${base}/FlatListCard.tsx`,
356
+ `
357
+ import React from "react";
358
+ import { View, Text, StyleSheet } from "react-native";
359
+
360
+ export default function FlatListCard({ title, subtitle }) {
361
+ return (
362
+ <View style={styles.card}>
363
+ <Text style={styles.title}>{title}</Text>
364
+ {subtitle && <Text style={styles.subtitle}>{subtitle}</Text>}
365
+ </View>
366
+ );
367
+ }
368
+
369
+ const styles = StyleSheet.create({
370
+ card: {
371
+ padding: 16,
372
+ borderBottomWidth: 1,
373
+ borderColor: "#ddd",
374
+ },
375
+ title: { fontSize: 16, fontWeight: "600" },
376
+ subtitle: { color: "#666", marginTop: 4 },
377
+ });
378
+ `
379
+ );
380
+
381
+ // -----------------------------------------------------
382
+ // ALERT MESSAGE
383
+ // -----------------------------------------------------
384
+ write(
385
+ projectRoot,
386
+ `${base}/AlertMessage.tsx`,
387
+ `
388
+ import React from "react";
389
+ import { View, Text, StyleSheet } from "react-native";
390
+
391
+ export default function AlertMessage({ message, type = "error" }) {
392
+ return (
393
+ <View style={[styles.alert, type === "success" && styles.success]}>
394
+ <Text style={styles.text}>{message}</Text>
395
+ </View>
396
+ );
397
+ }
398
+
399
+ const styles = StyleSheet.create({
400
+ alert: {
401
+ padding: 12,
402
+ backgroundColor: "#ffcccc",
403
+ borderLeftWidth: 4,
404
+ borderColor: "red",
405
+ marginVertical: 8,
406
+ },
407
+ success: {
408
+ backgroundColor: "#ccffcc",
409
+ borderColor: "green",
410
+ },
411
+ text: { color: "#333" },
412
+ });
413
+ `
414
+ );
415
+
416
+ // -----------------------------------------------------
417
+ // TOAST MESSAGE
418
+ // -----------------------------------------------------
419
+ write(
420
+ projectRoot,
421
+ `${base}/Toast.tsx`,
422
+ `
423
+ import React, { useEffect, useState } from "react";
424
+ import { View, Text, StyleSheet, Animated } from "react-native";
425
+
426
+ export default function Toast({ message, visible }) {
427
+ const [fade] = useState(new Animated.Value(0));
428
+
429
+ useEffect(() => {
430
+ if (visible) {
431
+ Animated.timing(fade, { toValue: 1, duration: 200, useNativeDriver: true }).start();
432
+ setTimeout(() => {
433
+ Animated.timing(fade, { toValue: 0, duration: 200, useNativeDriver: true }).start();
434
+ }, 2000);
435
+ }
436
+ }, [visible]);
437
+
438
+ if (!visible) return null;
439
+
440
+ return (
441
+ <Animated.View style={[styles.toast, { opacity: fade }]}>
442
+ <Text style={styles.text}>{message}</Text>
443
+ </Animated.View>
444
+ );
445
+ }
446
+
447
+ const styles = StyleSheet.create({
448
+ toast: {
449
+ position: "absolute",
450
+ bottom: 40,
451
+ alignSelf: "center",
452
+ backgroundColor: "#333",
453
+ padding: 12,
454
+ borderRadius: 8,
455
+ },
456
+ text: { color: "#fff" },
457
+ });
458
+ `
459
+ );
460
+
461
+ // -----------------------------------------------------
462
+ // SIMPLE LOADER
463
+ // -----------------------------------------------------
464
+ write(
465
+ projectRoot,
466
+ `${base}/Loader.tsx`,
467
+ `
468
+ import React from "react";
469
+ import { ActivityIndicator, View } from "react-native";
470
+
471
+ export default function Loader() {
472
+ return (
473
+ <View style={{ padding: 20 }}>
474
+ <ActivityIndicator size="large" />
475
+ </View>
476
+ );
477
+ }
478
+ `
479
+ );
480
+
481
+ // -----------------------------------------------------
482
+ // SHIMMER LOADER
483
+ // -----------------------------------------------------
484
+ write(
485
+ projectRoot,
486
+ `${base}/Shimmer.tsx`,
487
+ `
488
+ import React, { useRef, useEffect } from "react";
489
+ import { View, Animated, StyleSheet } from "react-native";
490
+
491
+ export default function Shimmer({ width = "100%", height = 20 }) {
492
+ const shimmer = useRef(new Animated.Value(-1)).current;
493
+
494
+ useEffect(() => {
495
+ Animated.loop(
496
+ Animated.timing(shimmer, {
497
+ toValue: 1,
498
+ duration: 1000,
499
+ useNativeDriver: true,
500
+ })
501
+ ).start();
502
+ }, []);
503
+
504
+ return (
505
+ <View style={[styles.container, { width, height }]}>
506
+ <Animated.View
507
+ style={[
508
+ styles.shimmer,
509
+ {
510
+ transform: [
511
+ {
512
+ translateX: shimmer.interpolate({
513
+ inputRange: [-1, 1],
514
+ outputRange: [-200, 200],
515
+ }),
516
+ },
517
+ ],
518
+ },
519
+ ]}
520
+ />
521
+ </View>
522
+ );
523
+ }
524
+
525
+ const styles = StyleSheet.create({
526
+ container: {
527
+ backgroundColor: "#e0e0e0",
528
+ overflow: "hidden",
529
+ borderRadius: 6,
530
+ },
531
+ shimmer: {
532
+ width: "40%",
533
+ height: "100%",
534
+ backgroundColor: "#ccc",
535
+ opacity: 0.6,
536
+ },
537
+ });
538
+ `
539
+ );
540
+
541
+ // -----------------------------------------------------
542
+ // PROGRESS BAR
543
+ // -----------------------------------------------------
544
+ write(
545
+ projectRoot,
546
+ `${base}/ProgressBar.tsx`,
547
+ `
548
+ import React from "react";
549
+ import { View, StyleSheet } from "react-native";
550
+
551
+ export default function ProgressBar({ progress = 0 }) {
552
+ return (
553
+ <View style={styles.container}>
554
+ <View style={[styles.bar, { width: \`\${progress}%\` }]} />
555
+ </View>
556
+ );
557
+ }
558
+
559
+ const styles = StyleSheet.create({
560
+ container: {
561
+ height: 10,
562
+ borderRadius: 5,
563
+ overflow: "hidden",
564
+ backgroundColor: "#ddd",
565
+ },
566
+ bar: {
567
+ height: "100%",
568
+ backgroundColor: "#1e90ff",
569
+ },
570
+ });
571
+ `
572
+ );
573
+
574
+ // -----------------------------------------------------
575
+ // FILE UPLOAD (DocumentPicker)
576
+ // -----------------------------------------------------
577
+ write(
578
+ projectRoot,
579
+ `${base}/FileUpload.tsx`,
580
+ `
581
+ import React from "react";
582
+ import { TouchableOpacity, Text } from "react-native";
583
+ import DocumentPicker from "react-native-document-picker";
584
+
585
+ export default function FileUpload({ onSelect }) {
586
+ const pick = async () => {
587
+ try {
588
+ const res = await DocumentPicker.pickSingle();
589
+ onSelect(res);
590
+ } catch {}
591
+ };
592
+
593
+ return (
594
+ <TouchableOpacity onPress={pick} style={{ padding: 12, backgroundColor: "#eee" }}>
595
+ <Text>Select File</Text>
596
+ </TouchableOpacity>
597
+ );
598
+ }
599
+ `
600
+ );
601
+
602
+ // -----------------------------------------------------
603
+ // IMAGE UPLOAD
604
+ // -----------------------------------------------------
605
+ write(
606
+ projectRoot,
607
+ `${base}/ImageUpload.tsx`,
608
+ `
609
+ import React from "react";
610
+ import { TouchableOpacity, Text } from "react-native";
611
+ import { launchImageLibrary } from "react-native-image-picker";
612
+
613
+ export default function ImageUpload({ onSelect }) {
614
+ const pick = async () => {
615
+ const result = await launchImageLibrary({ mediaType: "photo" });
616
+ if (result.assets && result.assets.length > 0) {
617
+ onSelect(result.assets[0]);
618
+ }
619
+ };
620
+
621
+ return (
622
+ <TouchableOpacity onPress={pick} style={{ padding: 12, backgroundColor: "#eee" }}>
623
+ <Text>Select Image</Text>
624
+ </TouchableOpacity>
625
+ );
626
+ }
627
+ `
628
+ );
629
+
630
+ // -----------------------------------------------------
631
+ // VIDEO UPLOAD
632
+ // -----------------------------------------------------
633
+ write(
634
+ projectRoot,
635
+ `${base}/VideoUpload.tsx`,
636
+ `
637
+ import React from "react";
638
+ import { TouchableOpacity, Text } from "react-native";
639
+ import { launchImageLibrary } from "react-native-image-picker";
640
+
641
+ export default function VideoUpload({ onSelect }) {
642
+ const pick = async () => {
643
+ const result = await launchImageLibrary({ mediaType: "video" });
644
+ if (result.assets && result.assets.length > 0) {
645
+ onSelect(result.assets[0]);
646
+ }
647
+ };
648
+
649
+ return (
650
+ <TouchableOpacity onPress={pick} style={{ padding: 12, backgroundColor: "#eee" }}>
651
+ <Text>Select Video</Text>
652
+ </TouchableOpacity>
653
+ );
654
+ }
655
+ `
656
+ );
657
+
658
+ console.log("✅ Shared UI Components Created Successfully!");
659
+ };
@@ -0,0 +1,54 @@
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 generateConstants(projectRoot) {
11
+ console.log("🔧 Creating constants...");
12
+
13
+ const base = "src/shared/constants";
14
+
15
+ write(
16
+ projectRoot,
17
+ `${base}/colors.ts`,
18
+ `
19
+ export const Colors = {
20
+ primary: "#007AFF",
21
+ secondary: "#FF9500",
22
+ danger: "#FF3B30",
23
+ success: "#34C759",
24
+ background: "#F2F2F7",
25
+ };
26
+ `
27
+ );
28
+
29
+ write(
30
+ projectRoot,
31
+ `${base}/fonts.ts`,
32
+ `
33
+ export const Fonts = {
34
+ regular: "System",
35
+ medium: "System-Medium",
36
+ bold: "System-Bold"
37
+ }
38
+ `
39
+ );
40
+
41
+ write(
42
+ projectRoot,
43
+ `${base}/sizes.ts`,
44
+ `
45
+ export const Sizes = {
46
+ padding: 16,
47
+ radius: 8,
48
+ margin: 12,
49
+ };
50
+ `
51
+ );
52
+
53
+ console.log("✅ Constants created successfully!");
54
+ };