create-ern-boilerplate 0.0.20 → 0.0.22

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 (62) hide show
  1. package/package.json +1 -1
  2. package/templates/default_draft/README.md +3 -0
  3. package/templates/default_draft/app/(admin)/draft_profile.tsx +589 -0
  4. package/templates/default_draft/app/(admin)/draft_userManagement.tsx +604 -0
  5. package/templates/default_draft/app/(auth)/_layout.tsx +25 -0
  6. package/templates/default_draft/app/(auth)/draft_login.tsx +782 -0
  7. package/templates/default_draft/app/(auth)/draft_register.tsx +547 -0
  8. package/templates/default_draft/app/(protected)/_layout.tsx +91 -0
  9. package/templates/default_draft/app/(protected)/draft_home.tsx +109 -0
  10. package/templates/default_draft/app/(protected)/draft_settings.tsx +332 -0
  11. package/templates/default_draft/app/_layout.tsx +24 -0
  12. package/templates/default_draft/app.json +58 -0
  13. package/templates/default_draft/babel.config.js +29 -0
  14. package/templates/default_draft/global.css +3 -0
  15. package/templates/default_draft/metro.config.js +6 -0
  16. package/templates/default_draft/nativewind-env.d.ts +3 -0
  17. package/templates/default_draft/package.json +54 -0
  18. package/templates/default_draft/server/db.json +78 -0
  19. package/templates/default_draft/src/assets/images/adaptive-icon.png +0 -0
  20. package/templates/default_draft/src/assets/images/favicon.png +0 -0
  21. package/templates/default_draft/src/assets/images/icon.png +0 -0
  22. package/templates/default_draft/src/assets/images/splash-icon.png +0 -0
  23. package/templates/default_draft/src/components/auth/ProtectedRoute.tsx +105 -0
  24. package/templates/default_draft/src/components/common/Button.tsx +70 -0
  25. package/templates/default_draft/src/components/common/Card.tsx +32 -0
  26. package/templates/default_draft/src/components/common/Input.tsx +75 -0
  27. package/templates/default_draft/src/components/common/Loading.tsx +41 -0
  28. package/templates/default_draft/src/components/config/ToastConfig.tsx +109 -0
  29. package/templates/default_draft/src/components/header/draft_AppHeader.tsx +160 -0
  30. package/templates/default_draft/src/components/shared/ConfirmDialog.tsx +151 -0
  31. package/templates/default_draft/src/components/shared/FormInput.tsx +67 -0
  32. package/templates/default_draft/src/components/shared/LucideIcon.tsx +18 -0
  33. package/templates/default_draft/src/components/shared/RoleSelector.tsx +63 -0
  34. package/templates/default_draft/src/components/users/EmptyState.tsx +70 -0
  35. package/templates/default_draft/src/components/users/ErrorState.tsx +64 -0
  36. package/templates/default_draft/src/components/users/FilterModal.tsx +264 -0
  37. package/templates/default_draft/src/components/users/UserCard.tsx +230 -0
  38. package/templates/default_draft/src/components/users/UserFormModal.tsx +230 -0
  39. package/templates/default_draft/src/contexts/draft_AuthContext.tsx +93 -0
  40. package/templates/default_draft/src/contexts/draft_ThemeContext.tsx +56 -0
  41. package/templates/default_draft/src/hooks/draft_useAuth.ts +12 -0
  42. package/templates/default_draft/src/hooks/draft_useTheme.ts +12 -0
  43. package/templates/default_draft/src/hooks/draft_useUsers.ts +261 -0
  44. package/templates/default_draft/src/services/draft_api.ts +97 -0
  45. package/templates/default_draft/src/services/draft_authService.ts +42 -0
  46. package/templates/default_draft/src/services/draft_productService.ts +143 -0
  47. package/templates/default_draft/src/services/draft_userService.ts +49 -0
  48. package/templates/default_draft/src/services/mockApi/draft_auth.mock.ts +89 -0
  49. package/templates/default_draft/src/services/mockApi/draft_categories.mock.ts +75 -0
  50. package/templates/default_draft/src/services/mockApi/draft_products.mock.ts +125 -0
  51. package/templates/default_draft/src/services/mockApi/draft_users.mock.ts +83 -0
  52. package/templates/default_draft/src/services/mockApi/index.ts +79 -0
  53. package/templates/default_draft/src/theme/draft_colors.ts +32 -0
  54. package/templates/default_draft/src/types/draft_api.types.ts +28 -0
  55. package/templates/default_draft/src/types/draft_auth.types.ts +38 -0
  56. package/templates/default_draft/src/types/draft_product.types.ts +49 -0
  57. package/templates/default_draft/src/types/draft_user.types.ts +40 -0
  58. package/templates/default_draft/src/utils/draft_constants.ts +47 -0
  59. package/templates/default_draft/src/utils/draft_storage.ts +73 -0
  60. package/templates/default_draft/src/utils/draft_validation.ts +54 -0
  61. package/templates/default_draft/tailwind.config.js +33 -0
  62. package/templates/default_draft/tsconfig.json +57 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-ern-boilerplate",
3
- "version": "0.0.20",
3
+ "version": "0.0.22",
4
4
  "description": "Expo React Native boilerplate generator",
5
5
  "bin": {
6
6
  "create-ern-boilerplate": "./create.js",
@@ -0,0 +1,3 @@
1
+ # Expo React Native Boilerplate
2
+
3
+ A comprehensive boilerplate for building React Native applications with Expo, featuring authentication, theming, and a clean architecture.
@@ -0,0 +1,589 @@
1
+ import React, { useState, useEffect } from 'react';
2
+ import {
3
+ View,
4
+ Text,
5
+ ScrollView,
6
+ StyleSheet,
7
+ TouchableOpacity,
8
+ TextInput,
9
+ Alert,
10
+ ActivityIndicator,
11
+ Image,
12
+ } from 'react-native';
13
+ import { User, Mail, Phone, MapPin, Calendar, Edit2, Save, X } from 'lucide-react-native';
14
+ import { useTheme } from '@/hooks/draft_useTheme';
15
+ import { useAuth } from '@/hooks/draft_useAuth';
16
+ import { useUsers } from '@/hooks/draft_useUsers';
17
+ import { SafeAreaView } from 'react-native-safe-area-context';
18
+ import { AppHeader } from '@/components/header/draft_AppHeader';
19
+ import { useRouter } from 'expo-router';
20
+ import { UpdateUserInput } from '@/types/draft_user.types';
21
+
22
+ export default function ProfileScreen() {
23
+ const { colors } = useTheme();
24
+ const { user } = useAuth();
25
+ const router = useRouter();
26
+ const { users, loading, updateUser } = useUsers();
27
+
28
+ const [isEditing, setIsEditing] = useState(false);
29
+ const [saving, setSaving] = useState(false);
30
+ const [currentUser, setCurrentUser] = useState<any>(null);
31
+
32
+ // Profile data state - FIX: Separate state untuk setiap field
33
+ const [name, setName] = useState('');
34
+ const [email, setEmail] = useState('');
35
+ const [phone, setPhone] = useState('');
36
+ const [location, setLocation] = useState('');
37
+ const [about, setAbout] = useState('');
38
+ const [avatar, setAvatar] = useState('');
39
+ const [joinDate, setJoinDate] = useState('');
40
+
41
+ // Load current user data
42
+ useEffect(() => {
43
+ if (user && users.length > 0) {
44
+ const userProfile = users.find(u => u.id === user.id || u.email === user.email);
45
+ if (userProfile) {
46
+ setCurrentUser(userProfile);
47
+ setName(userProfile.name || '');
48
+ setEmail(userProfile.email || '');
49
+ setPhone(userProfile.phone || '');
50
+ setLocation(userProfile.location || '');
51
+ setAbout(userProfile.about || '');
52
+ setAvatar(userProfile.avatar || '');
53
+ setJoinDate(
54
+ new Date(userProfile.createdAt).toLocaleDateString('en-US', {
55
+ year: 'numeric',
56
+ month: 'long',
57
+ day: 'numeric'
58
+ })
59
+ );
60
+ }
61
+ }
62
+ }, [user, users]);
63
+
64
+ const handleSave = async () => {
65
+ if (!currentUser) return;
66
+
67
+ setSaving(true);
68
+ try {
69
+ const updateData: UpdateUserInput = {
70
+ id: currentUser.id,
71
+ name,
72
+ email,
73
+ phone,
74
+ location,
75
+ about,
76
+ role: currentUser.role,
77
+ status: currentUser.status,
78
+ avatar: currentUser.avatar,
79
+ };
80
+
81
+ const result = await updateUser(updateData);
82
+
83
+ if (result.success) {
84
+ setIsEditing(false);
85
+ Alert.alert('Success', 'Profile updated successfully');
86
+ }
87
+ } catch (error) {
88
+ Alert.alert('Error', 'Failed to update profile');
89
+ } finally {
90
+ setSaving(false);
91
+ }
92
+ };
93
+
94
+ const handleCancel = () => {
95
+ setIsEditing(false);
96
+ // Reset to original values
97
+ if (currentUser) {
98
+ setName(currentUser.name || '');
99
+ setEmail(currentUser.email || '');
100
+ setPhone(currentUser.phone || '');
101
+ setLocation(currentUser.location || '');
102
+ setAbout(currentUser.about || '');
103
+ }
104
+ };
105
+
106
+ const InfoCard = ({ icon: Icon, label, value, editable = false, onChangeText }: any) => (
107
+ <View style={[styles.infoCard, { backgroundColor: colors.card || colors.background }]}>
108
+ <View style={[styles.iconWrapper, { backgroundColor: `${colors.primary}15` }]}>
109
+ <Icon size={20} color={colors.primary} />
110
+ </View>
111
+ <View style={styles.infoContent}>
112
+ <Text style={[styles.infoLabel, { color: colors.textSecondary }]}>{label}</Text>
113
+ {isEditing && editable ? (
114
+ <TextInput
115
+ style={[styles.infoInput, { color: colors.text, borderColor: `${colors.primary}30` }]}
116
+ value={value}
117
+ onChangeText={onChangeText}
118
+ placeholder={label}
119
+ placeholderTextColor={colors.textSecondary}
120
+ editable={!saving}
121
+ />
122
+ ) : (
123
+ <Text style={[styles.infoValue, { color: colors.text }]}>{value || '-'}</Text>
124
+ )}
125
+ </View>
126
+ </View>
127
+ );
128
+
129
+ const StatCard = ({ title, value, color }: any) => (
130
+ <View style={[styles.statCard, { backgroundColor: colors.card || colors.background }]}>
131
+ <Text style={[styles.statValue, { color }]}>{value}</Text>
132
+ <Text style={[styles.statTitle, { color: colors.textSecondary }]}>{title}</Text>
133
+ </View>
134
+ );
135
+
136
+ if (loading && !currentUser) {
137
+ return (
138
+ <SafeAreaView style={[styles.container, { backgroundColor: colors.background }]} edges={['top']}>
139
+ <AppHeader
140
+ variant="back"
141
+ title="Profile"
142
+ subtitle="Manage your personal information"
143
+ onBackPress={() => router.back()}
144
+ colors={colors}
145
+ />
146
+ <View style={styles.loadingContainer}>
147
+ <ActivityIndicator size="large" color={colors.primary} />
148
+ <Text style={[styles.loadingText, { color: colors.textSecondary }]}>
149
+ Loading profile...
150
+ </Text>
151
+ </View>
152
+ </SafeAreaView>
153
+ );
154
+ }
155
+
156
+ if (!currentUser) {
157
+ return (
158
+ <SafeAreaView style={[styles.container, { backgroundColor: colors.background }]} edges={['top']}>
159
+ <AppHeader
160
+ variant="back"
161
+ title="Profile"
162
+ subtitle="Manage your personal information"
163
+ onBackPress={() => router.back()}
164
+ colors={colors}
165
+ />
166
+ <View style={styles.loadingContainer}>
167
+ <Text style={[styles.errorText, { color: colors.textSecondary }]}>
168
+ Profile not found
169
+ </Text>
170
+ </View>
171
+ </SafeAreaView>
172
+ );
173
+ }
174
+
175
+ return (
176
+ <SafeAreaView style={[styles.container, { backgroundColor: colors.background }]} edges={['top']}>
177
+ <AppHeader
178
+ variant="back"
179
+ title="Profile"
180
+ subtitle="Manage your personal information"
181
+ onBackPress={() => router.back()}
182
+ colors={colors}
183
+ />
184
+ <ScrollView showsVerticalScrollIndicator={false}>
185
+ {/* Header with Avatar */}
186
+ <View style={styles.header}>
187
+ <View style={[styles.avatarContainer, { backgroundColor: `${colors.primary}20` }]}>
188
+ {avatar ? (
189
+ <Image
190
+ source={{ uri: avatar }}
191
+ style={styles.avatarImage}
192
+ defaultSource={require('@/assets/images/icon.png')}
193
+ />
194
+ ) : (
195
+ <Text style={[styles.avatarText, { color: colors.primary }]}>
196
+ {name.charAt(0).toUpperCase()}
197
+ </Text>
198
+ )}
199
+ </View>
200
+
201
+ <Text style={[styles.userName, { color: colors.text }]}>{name}</Text>
202
+
203
+ <View style={styles.badgeContainer}>
204
+ <View style={[styles.roleBadge, { backgroundColor: `${colors.primary}15` }]}>
205
+ <Text style={[styles.roleText, { color: colors.primary }]}>
206
+ {currentUser.role.toUpperCase()}
207
+ </Text>
208
+ </View>
209
+
210
+ <View style={[
211
+ styles.statusBadge,
212
+ { backgroundColor: currentUser.status === 'active' ? '#10b98115' : '#ef444415' }
213
+ ]}>
214
+ <View style={[
215
+ styles.statusDot,
216
+ { backgroundColor: currentUser.status === 'active' ? '#10b981' : '#ef4444' }
217
+ ]} />
218
+ <Text style={[
219
+ styles.statusText,
220
+ { color: currentUser.status === 'active' ? '#10b981' : '#ef4444' }
221
+ ]}>
222
+ {currentUser.status === 'active' ? 'Active' : 'Inactive'}
223
+ </Text>
224
+ </View>
225
+ </View>
226
+ </View>
227
+
228
+ {/* Stats */}
229
+ <View style={styles.statsContainer}>
230
+ <StatCard title="Articles" value="127" color="#10b981" />
231
+ <StatCard title="Favorites" value="34" color="#f59e0b" />
232
+ <StatCard title="Comments" value="89" color="#3b82f6" />
233
+ </View>
234
+
235
+ {/* Edit Button */}
236
+ {!isEditing ? (
237
+ <TouchableOpacity
238
+ style={[styles.editButton, { backgroundColor: colors.primary }]}
239
+ onPress={() => setIsEditing(true)}
240
+ activeOpacity={0.7}
241
+ >
242
+ <Edit2 size={18} color="#FFFFFF" />
243
+ <Text style={styles.editButtonText}>Edit Profile</Text>
244
+ </TouchableOpacity>
245
+ ) : (
246
+ <View style={styles.editActions}>
247
+ <TouchableOpacity
248
+ style={[styles.actionButton, styles.cancelButton, {
249
+ borderColor: colors.border,
250
+ backgroundColor: colors.card || colors.background
251
+ }]}
252
+ onPress={handleCancel}
253
+ activeOpacity={0.7}
254
+ disabled={saving}
255
+ >
256
+ <X size={18} color={colors.text} />
257
+ <Text style={[styles.actionButtonText, { color: colors.text }]}>Cancel</Text>
258
+ </TouchableOpacity>
259
+ <TouchableOpacity
260
+ style={[styles.actionButton, styles.saveButton, {
261
+ backgroundColor: colors.primary,
262
+ opacity: saving ? 0.7 : 1
263
+ }]}
264
+ onPress={handleSave}
265
+ activeOpacity={0.7}
266
+ disabled={saving}
267
+ >
268
+ {saving ? (
269
+ <ActivityIndicator size="small" color="#FFFFFF" />
270
+ ) : (
271
+ <Save size={18} color="#FFFFFF" />
272
+ )}
273
+ <Text style={[styles.actionButtonText, { color: '#FFFFFF' }]}>
274
+ {saving ? 'Saving...' : 'Save Changes'}
275
+ </Text>
276
+ </TouchableOpacity>
277
+ </View>
278
+ )}
279
+
280
+ {/* Profile Information */}
281
+ <View style={styles.section}>
282
+ <Text style={[styles.sectionTitle, { color: colors.text }]}>Personal Information</Text>
283
+
284
+ <InfoCard
285
+ icon={User}
286
+ label="Full Name"
287
+ value={name}
288
+ editable
289
+ onChangeText={setName}
290
+ />
291
+ <InfoCard
292
+ icon={Mail}
293
+ label="Email Address"
294
+ value={email}
295
+ editable
296
+ onChangeText={setEmail}
297
+ />
298
+ <InfoCard
299
+ icon={Phone}
300
+ label="Phone Number"
301
+ value={phone}
302
+ editable
303
+ onChangeText={setPhone}
304
+ />
305
+ <InfoCard
306
+ icon={MapPin}
307
+ label="Location"
308
+ value={location}
309
+ editable
310
+ onChangeText={setLocation}
311
+ />
312
+ <InfoCard
313
+ icon={Calendar}
314
+ label="Member Since"
315
+ value={joinDate}
316
+ />
317
+ </View>
318
+
319
+ {/* Bio Section */}
320
+ <View style={styles.section}>
321
+ <Text style={[styles.sectionTitle, { color: colors.text }]}>About Me</Text>
322
+ <View style={[styles.bioCard, { backgroundColor: colors.card || colors.background }]}>
323
+ {isEditing ? (
324
+ <TextInput
325
+ style={[styles.bioInput, {
326
+ color: colors.text,
327
+ borderColor: `${colors.primary}30`,
328
+ backgroundColor: colors.background
329
+ }]}
330
+ value={about}
331
+ onChangeText={setAbout}
332
+ placeholder="Tell us about yourself..."
333
+ placeholderTextColor={colors.textSecondary}
334
+ multiline
335
+ numberOfLines={4}
336
+ textAlignVertical="top"
337
+ editable={!saving}
338
+ />
339
+ ) : (
340
+ <Text style={[styles.bioText, { color: colors.text }]}>
341
+ {about || 'No bio available. Add your bio by editing your profile.'}
342
+ </Text>
343
+ )}
344
+ </View>
345
+ </View>
346
+
347
+ <View style={{ height: 40 }} />
348
+ </ScrollView>
349
+ </SafeAreaView>
350
+ );
351
+ }
352
+
353
+ const styles = StyleSheet.create({
354
+ container: {
355
+ flex: 1,
356
+ },
357
+ loadingContainer: {
358
+ flex: 1,
359
+ justifyContent: 'center',
360
+ alignItems: 'center',
361
+ paddingHorizontal: 24,
362
+ },
363
+ loadingText: {
364
+ marginTop: 16,
365
+ fontSize: 15,
366
+ fontWeight: '600',
367
+ },
368
+ errorText: {
369
+ fontSize: 15,
370
+ fontWeight: '600',
371
+ },
372
+ header: {
373
+ alignItems: 'center',
374
+ paddingTop: 40,
375
+ paddingBottom: 32,
376
+ paddingHorizontal: 24,
377
+ },
378
+ avatarContainer: {
379
+ width: 120,
380
+ height: 120,
381
+ borderRadius: 60,
382
+ justifyContent: 'center',
383
+ alignItems: 'center',
384
+ marginBottom: 20,
385
+ elevation: 6,
386
+ shadowColor: '#000',
387
+ shadowOffset: { width: 0, height: 4 },
388
+ shadowOpacity: 0.15,
389
+ shadowRadius: 12,
390
+ overflow: 'hidden',
391
+ },
392
+ avatarImage: {
393
+ width: '100%',
394
+ height: '100%',
395
+ borderRadius: 60,
396
+ },
397
+ avatarText: {
398
+ fontSize: 48,
399
+ fontWeight: '800',
400
+ },
401
+ userName: {
402
+ fontSize: 28,
403
+ fontWeight: '800',
404
+ marginBottom: 12,
405
+ textAlign: 'center',
406
+ },
407
+ badgeContainer: {
408
+ flexDirection: 'row',
409
+ alignItems: 'center',
410
+ gap: 8,
411
+ },
412
+ roleBadge: {
413
+ paddingHorizontal: 16,
414
+ paddingVertical: 6,
415
+ borderRadius: 20,
416
+ },
417
+ roleText: {
418
+ fontSize: 12,
419
+ fontWeight: '700',
420
+ letterSpacing: 0.8,
421
+ },
422
+ statusBadge: {
423
+ flexDirection: 'row',
424
+ alignItems: 'center',
425
+ paddingHorizontal: 12,
426
+ paddingVertical: 6,
427
+ borderRadius: 20,
428
+ gap: 6,
429
+ },
430
+ statusDot: {
431
+ width: 6,
432
+ height: 6,
433
+ borderRadius: 3,
434
+ },
435
+ statusText: {
436
+ fontSize: 12,
437
+ fontWeight: '600',
438
+ },
439
+ statsContainer: {
440
+ flexDirection: 'row',
441
+ paddingHorizontal: 24,
442
+ marginBottom: 24,
443
+ gap: 12,
444
+ },
445
+ statCard: {
446
+ flex: 1,
447
+ padding: 20,
448
+ borderRadius: 16,
449
+ alignItems: 'center',
450
+ elevation: 2,
451
+ shadowColor: '#000',
452
+ shadowOffset: { width: 0, height: 2 },
453
+ shadowOpacity: 0.08,
454
+ shadowRadius: 8,
455
+ },
456
+ statValue: {
457
+ fontSize: 28,
458
+ fontWeight: '800',
459
+ marginBottom: 4,
460
+ },
461
+ statTitle: {
462
+ fontSize: 11,
463
+ fontWeight: '600',
464
+ textTransform: 'uppercase',
465
+ letterSpacing: 0.5,
466
+ },
467
+ editButton: {
468
+ flexDirection: 'row',
469
+ alignItems: 'center',
470
+ justifyContent: 'center',
471
+ marginHorizontal: 24,
472
+ marginBottom: 32,
473
+ paddingVertical: 16,
474
+ borderRadius: 16,
475
+ gap: 8,
476
+ elevation: 3,
477
+ shadowColor: '#000',
478
+ shadowOffset: { width: 0, height: 2 },
479
+ shadowOpacity: 0.1,
480
+ shadowRadius: 8,
481
+ },
482
+ editButtonText: {
483
+ color: '#FFFFFF',
484
+ fontSize: 16,
485
+ fontWeight: '700',
486
+ },
487
+ editActions: {
488
+ flexDirection: 'row',
489
+ paddingHorizontal: 24,
490
+ marginBottom: 32,
491
+ gap: 12,
492
+ },
493
+ actionButton: {
494
+ flex: 1,
495
+ flexDirection: 'row',
496
+ alignItems: 'center',
497
+ justifyContent: 'center',
498
+ paddingVertical: 16,
499
+ borderRadius: 16,
500
+ gap: 8,
501
+ elevation: 2,
502
+ shadowColor: '#000',
503
+ shadowOffset: { width: 0, height: 1 },
504
+ shadowOpacity: 0.08,
505
+ shadowRadius: 4,
506
+ },
507
+ cancelButton: {
508
+ borderWidth: 2,
509
+ },
510
+ saveButton: {
511
+ // backgroundColor set dynamically
512
+ },
513
+ actionButtonText: {
514
+ fontSize: 15,
515
+ fontWeight: '700',
516
+ },
517
+ section: {
518
+ paddingHorizontal: 24,
519
+ marginBottom: 32,
520
+ },
521
+ sectionTitle: {
522
+ fontSize: 20,
523
+ fontWeight: '800',
524
+ marginBottom: 16,
525
+ letterSpacing: 0.3,
526
+ },
527
+ infoCard: {
528
+ flexDirection: 'row',
529
+ alignItems: 'center',
530
+ padding: 16,
531
+ borderRadius: 16,
532
+ marginBottom: 12,
533
+ elevation: 1,
534
+ shadowColor: '#000',
535
+ shadowOffset: { width: 0, height: 1 },
536
+ shadowOpacity: 0.05,
537
+ shadowRadius: 4,
538
+ },
539
+ iconWrapper: {
540
+ width: 48,
541
+ height: 48,
542
+ borderRadius: 14,
543
+ justifyContent: 'center',
544
+ alignItems: 'center',
545
+ marginRight: 14,
546
+ },
547
+ infoContent: {
548
+ flex: 1,
549
+ },
550
+ infoLabel: {
551
+ fontSize: 12,
552
+ fontWeight: '600',
553
+ marginBottom: 6,
554
+ textTransform: 'uppercase',
555
+ letterSpacing: 0.5,
556
+ },
557
+ infoValue: {
558
+ fontSize: 16,
559
+ fontWeight: '600',
560
+ },
561
+ infoInput: {
562
+ fontSize: 16,
563
+ fontWeight: '600',
564
+ borderBottomWidth: 2,
565
+ paddingVertical: 6,
566
+ paddingHorizontal: 4,
567
+ },
568
+ bioCard: {
569
+ padding: 20,
570
+ borderRadius: 16,
571
+ elevation: 1,
572
+ shadowColor: '#000',
573
+ shadowOffset: { width: 0, height: 1 },
574
+ shadowOpacity: 0.05,
575
+ shadowRadius: 4,
576
+ },
577
+ bioText: {
578
+ fontSize: 15,
579
+ lineHeight: 24,
580
+ },
581
+ bioInput: {
582
+ fontSize: 15,
583
+ lineHeight: 24,
584
+ minHeight: 120,
585
+ borderWidth: 2,
586
+ borderRadius: 12,
587
+ padding: 16,
588
+ },
589
+ });