create-ern-boilerplate 0.0.37 → 0.0.38

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-ern-boilerplate",
3
- "version": "0.0.37",
3
+ "version": "0.0.38",
4
4
  "description": "Expo React Native boilerplate generator",
5
5
  "bin": {
6
6
  "create-ern-boilerplate": "./create.js",
@@ -68,4 +68,5 @@ expo-env.d.ts
68
68
  # @end expo-cli
69
69
 
70
70
  # Other
71
- structure.txt
71
+ structure.txt
72
+ .claude
@@ -11,6 +11,7 @@
11
11
 
12
12
  import React, { useState, useEffect } from 'react';
13
13
  import { View, Text, FlatList, RefreshControl, ActivityIndicator } from 'react-native';
14
+ import { SafeAreaView } from 'react-native-safe-area-context';
14
15
  import { useThemeStore } from '@/store/themeStore';
15
16
  import { Card } from '@/components/common/Card';
16
17
  import { Button } from '@/components/common/Button';
@@ -123,7 +124,7 @@ export default function NewsListScreen() {
123
124
 
124
125
  // Main content
125
126
  return (
126
- <View className="flex-1" style={{ backgroundColor: isDark ? '#000' : '#F9FAFB' }}>
127
+ <SafeAreaView className="flex-1" style={{ backgroundColor: isDark ? '#000' : '#F9FAFB' }}>
127
128
  <FlatList
128
129
  data={news}
129
130
  renderItem={renderItem}
@@ -133,6 +134,6 @@ export default function NewsListScreen() {
133
134
  <RefreshControl refreshing={refreshing} onRefresh={onRefresh} tintColor="#3b82f6" />
134
135
  }
135
136
  />
136
- </View>
137
+ </SafeAreaView>
137
138
  );
138
139
  }
@@ -1,6 +1,6 @@
1
1
  // components/auth/ProtectedRoute.tsx
2
2
  import React from 'react';
3
- import { View, Text, StyleSheet, ActivityIndicator } from 'react-native';
3
+ import { View, Text, ActivityIndicator } from 'react-native';
4
4
  import { Redirect } from 'expo-router';
5
5
  import { useAuth } from '@/hooks/useAuth';
6
6
  import { useTheme } from '@/hooks/useTheme';
@@ -18,9 +18,15 @@ export function ProtectedRoute({ children, requireAdmin = false }: ProtectedRout
18
18
  // Show loading state while checking authentication
19
19
  if (isLoading) {
20
20
  return (
21
- <View style={[styles.container, { backgroundColor: colors.background }]}>
21
+ <View
22
+ className="flex-1 justify-center items-center p-6"
23
+ style={{ backgroundColor: colors.background }}
24
+ >
22
25
  <ActivityIndicator size="large" color={colors.primary} />
23
- <Text style={[styles.loadingText, { color: colors.text }]}>
26
+ <Text
27
+ className="mt-4 text-base font-semibold"
28
+ style={{ color: colors.text }}
29
+ >
24
30
  Checking authentication...
25
31
  </Text>
26
32
  </View>
@@ -35,16 +41,31 @@ export function ProtectedRoute({ children, requireAdmin = false }: ProtectedRout
35
41
  // Check admin access if required
36
42
  if (requireAdmin && user?.role !== 'admin') {
37
43
  return (
38
- <View style={[styles.container, { backgroundColor: colors.background }]}>
39
- <View style={[styles.errorContainer, { backgroundColor: `${colors.error}10` }]}>
44
+ <View
45
+ className="flex-1 justify-center items-center p-6"
46
+ style={{ backgroundColor: colors.background }}
47
+ >
48
+ <View
49
+ className="p-8 rounded-3xl items-center max-w-md"
50
+ style={{ backgroundColor: `${colors.error}10` }}
51
+ >
40
52
  <ShieldAlert size={64} color={colors.error} />
41
- <Text style={[styles.errorTitle, { color: colors.error }]}>
53
+ <Text
54
+ className="text-2xl font-extrabold mt-4 mb-2"
55
+ style={{ color: colors.error }}
56
+ >
42
57
  Access Denied
43
58
  </Text>
44
- <Text style={[styles.errorMessage, { color: colors.textSecondary }]}>
59
+ <Text
60
+ className="text-base text-center mb-2"
61
+ style={{ color: colors.textSecondary }}
62
+ >
45
63
  You don't have permission to access this page.
46
64
  </Text>
47
- <Text style={[styles.errorHint, { color: colors.textSecondary }]}>
65
+ <Text
66
+ className="text-sm text-center italic"
67
+ style={{ color: colors.textSecondary }}
68
+ >
48
69
  This page is only accessible to administrators.
49
70
  </Text>
50
71
  </View>
@@ -55,42 +76,6 @@ export function ProtectedRoute({ children, requireAdmin = false }: ProtectedRout
55
76
  return <>{children}</>;
56
77
  }
57
78
 
58
- const styles = StyleSheet.create({
59
- container: {
60
- flex: 1,
61
- justifyContent: 'center',
62
- alignItems: 'center',
63
- padding: 24,
64
- },
65
- loadingText: {
66
- marginTop: 16,
67
- fontSize: 16,
68
- fontWeight: '600',
69
- },
70
- errorContainer: {
71
- padding: 32,
72
- borderRadius: 24,
73
- alignItems: 'center',
74
- maxWidth: 400,
75
- },
76
- errorTitle: {
77
- fontSize: 24,
78
- fontWeight: '800',
79
- marginTop: 16,
80
- marginBottom: 8,
81
- },
82
- errorMessage: {
83
- fontSize: 16,
84
- textAlign: 'center',
85
- marginBottom: 8,
86
- },
87
- errorHint: {
88
- fontSize: 14,
89
- textAlign: 'center',
90
- fontStyle: 'italic',
91
- },
92
- });
93
-
94
79
  // Usage Example in Settings Screen:
95
80
  // import { ProtectedRoute } from '@/components/auth/ProtectedRoute';
96
81
  //
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  import { TouchableOpacity, Text, ActivityIndicator, TouchableOpacityProps } from 'react-native';
3
+ import { useTheme } from '@/hooks/useTheme';
3
4
 
4
5
  interface ButtonProps extends TouchableOpacityProps {
5
6
  title: string;
@@ -19,12 +20,7 @@ export function Button({
19
20
  className = '',
20
21
  ...props
21
22
  }: ButtonProps) {
22
- const variantClasses = {
23
- primary: 'bg-primary-600 active:bg-primary-700',
24
- secondary: 'bg-gray-600 active:bg-gray-700',
25
- outline: 'border-2 border-primary-600 bg-transparent active:bg-primary-50',
26
- ghost: 'bg-transparent active:bg-gray-100',
27
- };
23
+ const { colors } = useTheme();
28
24
 
29
25
  const sizeClasses = {
30
26
  sm: 'px-3 py-2',
@@ -38,30 +34,63 @@ export function Button({
38
34
  lg: 'text-lg',
39
35
  };
40
36
 
41
- const textColorClasses = {
42
- primary: 'text-white',
43
- secondary: 'text-white',
44
- outline: 'text-primary-600',
45
- ghost: 'text-primary-600',
37
+ // Get dynamic colors based on variant
38
+ const getButtonStyles = () => {
39
+ switch (variant) {
40
+ case 'primary':
41
+ return { backgroundColor: colors.primary };
42
+ case 'secondary':
43
+ return { backgroundColor: colors.textSecondary };
44
+ case 'outline':
45
+ return {
46
+ backgroundColor: 'transparent',
47
+ borderWidth: 2,
48
+ borderColor: colors.primary
49
+ };
50
+ case 'ghost':
51
+ return { backgroundColor: 'transparent' };
52
+ default:
53
+ return { backgroundColor: colors.primary };
54
+ }
55
+ };
56
+
57
+ const getTextColor = () => {
58
+ switch (variant) {
59
+ case 'primary':
60
+ case 'secondary':
61
+ return '#ffffff';
62
+ case 'outline':
63
+ case 'ghost':
64
+ return colors.primary;
65
+ default:
66
+ return '#ffffff';
67
+ }
68
+ };
69
+
70
+ const getLoaderColor = () => {
71
+ return variant === 'outline' || variant === 'ghost' ? colors.primary : '#ffffff';
46
72
  };
47
73
 
48
74
  return (
49
75
  <TouchableOpacity
50
76
  className={`
51
- ${variantClasses[variant]}
52
77
  ${sizeClasses[size]}
53
78
  ${fullWidth ? 'w-full' : ''}
54
79
  ${disabled || loading ? 'opacity-50' : ''}
55
80
  rounded-lg items-center justify-center
56
81
  ${className}
57
82
  `}
83
+ style={getButtonStyles()}
58
84
  disabled={disabled || loading}
59
85
  {...props}
60
86
  >
61
87
  {loading ? (
62
- <ActivityIndicator color={variant === 'outline' || variant === 'ghost' ? '#3b82f6' : '#ffffff'} />
88
+ <ActivityIndicator color={getLoaderColor()} />
63
89
  ) : (
64
- <Text className={`${textColorClasses[variant]} ${textSizeClasses[size]} font-semibold`}>
90
+ <Text
91
+ className={`${textSizeClasses[size]} font-semibold`}
92
+ style={{ color: getTextColor() }}
93
+ >
65
94
  {title}
66
95
  </Text>
67
96
  )}
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { View, ViewProps } from 'react-native';
3
- import { useTheme } from '@hooks/useTheme';
3
+ import { useTheme } from '@/hooks/useTheme';
4
4
 
5
5
  interface CardProps extends ViewProps {
6
6
  children: React.ReactNode;
@@ -1,6 +1,7 @@
1
1
  import React, { useState } from 'react';
2
2
  import { View, TextInput, Text, TouchableOpacity, TextInputProps } from 'react-native';
3
- import { useTheme } from '@hooks/useTheme';
3
+ import { Eye, EyeOff } from 'lucide-react-native';
4
+ import { useTheme } from '@/hooks/useTheme';
4
5
 
5
6
  interface InputProps extends TextInputProps {
6
7
  label?: string;
@@ -52,9 +53,11 @@ export function Input({
52
53
 
53
54
  {secureTextEntry && (
54
55
  <TouchableOpacity onPress={() => setShowPassword(!showPassword)} className="ml-2">
55
- <Text style={{ color: colors.textSecondary }}>
56
- {showPassword ? '🙈' : '👁️'}
57
- </Text>
56
+ {showPassword ? (
57
+ <EyeOff size={20} color={colors.textSecondary} />
58
+ ) : (
59
+ <Eye size={20} color={colors.textSecondary} />
60
+ )}
58
61
  </TouchableOpacity>
59
62
  )}
60
63
 
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { View, ActivityIndicator, Text } from 'react-native';
3
- import { useTheme } from '@hooks/useTheme';
3
+ import { useTheme } from '@/hooks/useTheme';
4
4
 
5
5
  interface LoadingProps {
6
6
  text?: string;
@@ -1,4 +1,5 @@
1
1
  import { useThemeStore } from '@/store/themeStore';
2
+ import { colors as themeColors } from '@/theme/colors';
2
3
 
3
4
  /**
4
5
  * Hook for accessing theme state and actions
@@ -8,11 +9,16 @@ export function useTheme() {
8
9
  const colorScheme = useThemeStore((state) => state.colorScheme);
9
10
  const setColorScheme = useThemeStore((state) => state.setColorScheme);
10
11
  const toggleColorScheme = useThemeStore((state) => state.toggleColorScheme);
12
+ const isDark = colorScheme === 'dark';
13
+
14
+ // Get colors based on current color scheme
15
+ const colors = isDark ? themeColors.dark : themeColors.light;
11
16
 
12
17
  return {
13
18
  colorScheme,
14
19
  setColorScheme,
15
20
  toggleColorScheme,
16
- isDark: colorScheme === 'dark',
21
+ isDark,
22
+ colors,
17
23
  };
18
24
  }