This commit is contained in:
Abin Toppo
2025-09-29 16:32:39 +05:30
parent a624af60b7
commit 7a9ce601cb
12 changed files with 773 additions and 617 deletions
+177
View File
@@ -0,0 +1,177 @@
// src/components/CustomAlert.tsx
import React from "react";
import {
Modal,
View,
Text,
TouchableOpacity,
StyleSheet,
Platform,
} from "react-native";
import { BlurView } from "@react-native-community/blur";
import Ionicons from '@react-native-vector-icons/ionicons';
import colors from "./colors"; // Import centralized colors
interface AlertButton {
text: string;
onPress: () => void;
style?: "cancel" | "destructive" | "default";
}
interface CustomAlertProps {
visible: boolean;
title: string;
message: string;
buttons: AlertButton[];
alertType?: 'error' | 'success' | 'info';
}
const CustomAlert: React.FC<CustomAlertProps> = ({
visible,
title,
message,
buttons,
alertType = 'info',
}) => {
const getIcon = () => {
switch (alertType) {
case 'error':
return { name: "close-circle", color: colors.error };
case 'success':
return { name: "checkmark-circle", color: colors.success };
default:
return { name: "information-circle", color: colors.primary };
}
};
const icon = getIcon();
return (
<Modal
animationType="fade"
transparent={true}
visible={visible}
onRequestClose={() => {
const closeButton = buttons.find(b => b.style === 'cancel') || buttons[0];
closeButton?.onPress();
}}
>
<View style={styles.centeredView}>
{Platform.OS === 'ios' ? (
<BlurView style={styles.absolute} blurType="light" blurAmount={5} />
) : (
<View style={[styles.absolute, { backgroundColor: colors.androidBackdrop }]} />
)}
<View style={styles.alertBox}>
<View style={styles.iconContainer}>
<Ionicons name={icon.name} size={48} color={icon.color} />
</View>
<Text style={styles.alertTitle}>{title}</Text>
<Text style={styles.alertMessage}>{message}</Text>
<View style={styles.buttonContainer}>
{buttons.map((button, index) => (
<TouchableOpacity
key={index}
style={[
styles.button,
button.style === 'destructive' ? styles.destructiveButton : styles.defaultButton,
]}
onPress={button.onPress}
>
<Text style={[
styles.buttonText,
button.style === 'destructive' ? styles.destructiveButtonText : styles.defaultButtonText
]}>
{button.text}
</Text>
</TouchableOpacity>
))}
</View>
</View>
</View>
</Modal>
);
};
const styles = StyleSheet.create({
centeredView: {
flex: 1,
justifyContent: "center",
alignItems: "center",
},
absolute: {
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0,
},
alertBox: {
backgroundColor: colors.alertBackground,
borderRadius: 24,
padding: 24,
alignItems: "center",
margin: 24,
borderWidth: 1,
borderColor: 'rgba(255, 255, 255, 0.5)',
shadowColor: colors.black,
shadowOffset: { width: 0, height: 10 },
shadowOpacity: 0.1,
shadowRadius: 30,
elevation: 20,
width: '90%',
maxWidth: 400,
},
iconContainer: {
marginBottom: 16,
},
alertTitle: {
fontSize: 22,
fontWeight: "bold",
color: colors.textDark,
marginBottom: 8,
textAlign: "center",
},
alertMessage: {
fontSize: 16,
color: colors.textLight,
textAlign: "center",
marginBottom: 24,
lineHeight: 22,
},
buttonContainer: {
flexDirection: "row",
justifyContent: 'flex-end',
width: "100%",
gap: 12,
},
button: {
paddingVertical: 14,
paddingHorizontal: 24,
borderRadius: 16,
justifyContent: 'center',
alignItems: 'center',
},
defaultButton: {
backgroundColor: colors.primary,
},
destructiveButton: {
backgroundColor: colors.error,
},
buttonText: {
fontSize: 16,
fontWeight: "700",
},
defaultButtonText: {
color: colors.white,
},
destructiveButtonText: {
color: colors.white,
},
});
export default CustomAlert;
+20 -15
View File
@@ -1,22 +1,27 @@
// colors.ts
const colors = {
pastelPink: "#decbfcff", // darker pink
pastelBlue: "#D7E9F7", // darker blue
pastelGreen: "#DFF6DD", // darker green
pastelOrange: "#FFF4D2", // darker orange
// src/components/colors.ts
// darker accent colors
Home: "#995dfaff", // Rose red for contrast
Profile: "#2D9CDB", // Deep sky blue
Group: "#27AE60", // Green for freshness
Settings: "#F39C12", // Amber for warmth
const colors = {
// Pastel palette
pastelPink: "#decbfc",
pastelBlue: "#D7E9F7",
pastelGreen: "#DFF6DD",
pastelOrange: "#FFF4D2",
// common text + UI colors
textDark: "#212121",
textLight: "#555555",
// Primary and status colors
primary: "#711ff7",
error: "#EF4444",
success: "#22C55E",
// Common UI colors
textDark: "#1F2937",
textLight: "#6B7280",
white: "#FFFFFF",
black: "#000000",
primary: "#711ff7ff",
inputBorder: "#E5E7EB",
// Special background colors with transparency
alertBackground: "rgba(255, 255, 255, 0.8)",
androidBackdrop: "rgba(0, 0, 0, 0.4)",
};
export default colors;
+54 -99
View File
@@ -5,10 +5,12 @@ import {
StyleSheet,
TouchableWithoutFeedback,
Animated,
ViewStyle,
} from "react-native";
import LinearGradient from "react-native-linear-gradient";
import { Ionicons, IoniconsIconName } from "@react-native-vector-icons/ionicons";
import colors from "../colors";
import Ionicons from "react-native-vector-icons/Ionicons";
import { IoniconsIconName } from "react-native-vector-icons/Ionicons";
import colors from "../colors"; // Assuming your pastel colors are defined here
type CardProps = {
title: string;
@@ -16,7 +18,8 @@ type CardProps = {
iconName?: IoniconsIconName;
onPress?: () => void;
backOne?: string;
backTwo?: string
backTwo?: string;
style?: ViewStyle;
};
const AnimatedCard: React.FC<CardProps> = ({
@@ -24,33 +27,27 @@ const AnimatedCard: React.FC<CardProps> = ({
subtitle,
iconName = "ellipse",
onPress,
backOne = '#4facfe',
backTwo = '#00f2fe'
backOne = colors.pastelPink, // Defaulting to pastelPink
backTwo = colors.primary,
style,
}) => {
const scale = useRef(new Animated.Value(1)).current;
const handlePressIn = () => {
Animated.spring(scale, {
toValue: 0.96,
useNativeDriver: true,
friction: 4,
}).start();
Animated.spring(scale, { toValue: 0.96, useNativeDriver: true, friction: 4 }).start();
};
const handlePressOut = () => {
Animated.spring(scale, {
toValue: 1,
useNativeDriver: true,
friction: 4,
}).start(() => onPress && onPress());
Animated.spring(scale, { toValue: 1, useNativeDriver: true, friction: 4 }).start(() => {
if (onPress) {
onPress();
}
});
};
return (
<TouchableWithoutFeedback
onPressIn={handlePressIn}
onPressOut={handlePressOut}
>
<Animated.View style={[styles.card, { transform: [{ scale }] }]}>
<TouchableWithoutFeedback onPressIn={handlePressIn} onPressOut={handlePressOut}>
<Animated.View style={[styles.card, style, { transform: [{ scale }] }]}>
<LinearGradient
colors={[backOne, backTwo]}
start={{ x: 0, y: 0 }}
@@ -59,21 +56,11 @@ const AnimatedCard: React.FC<CardProps> = ({
>
{/* Decorative Graphics */}
<View style={styles.graphicCircleLarge} />
<View style={styles.graphicCircleMedium} />
<View style={styles.graphicCircleSmall} />
<View style={styles.graphicTriangleTop} />
<View style={styles.graphicTriangleBottom} />
{/* Content */}
<View style={styles.content}>
{iconName && (
<Ionicons
name={iconName}
size={32}
color="#fff"
style={styles.icon}
/>
)}
{iconName && <Ionicons name={iconName} size={38} color="#fff" style={styles.icon} />}
<View style={styles.textContainer}>
<Text style={styles.title}>{title}</Text>
{subtitle && <Text style={styles.subtitle}>{subtitle}</Text>}
@@ -87,102 +74,70 @@ const AnimatedCard: React.FC<CardProps> = ({
const styles = StyleSheet.create({
card: {
// marginHorizontal: 16,
marginVertical: 10,
borderRadius: 20,
borderRadius: 24,
overflow: "hidden",
shadowColor: "#000",
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.25,
shadowRadius: 8,
elevation: 8,
shadowOffset: { width: 0, height: 5 },
shadowOpacity: 0.15,
shadowRadius: 12,
elevation: 5,
backgroundColor: colors.white,
},
gradient: {
minHeight: 120,
minHeight: 150, // Increased height for better spacing
position: "relative",
flex: 1,
justifyContent: "center",
alignItems: "center",
},
// Graphics
graphicCircleLarge: {
position: "absolute",
top: -20,
right: -20,
width: 80,
height: 80,
borderRadius: 40,
backgroundColor: "rgba(124, 80, 80, 0.42)",
},
graphicCircleMedium: {
position: "absolute",
bottom: 30,
left: -15,
width: 60,
height: 60,
borderRadius: 30,
backgroundColor: "rgba(122, 41, 41, 0.39)",
top: -30,
right: -40,
width: 100,
height: 100,
borderRadius: 50,
backgroundColor: "rgba(255, 255, 255, 0.1)",
},
graphicCircleSmall: {
position: "absolute",
bottom: -10,
right: 40,
width: 40,
height: 40,
borderRadius: 20,
backgroundColor: "rgba(207, 110, 80, 0.25)",
},
graphicTriangleTop: {
position: "absolute",
top: 0,
left: 0,
width: 0,
height: 0,
borderStyle: "solid",
borderRightWidth: 60,
borderTopWidth: 60,
borderRightColor: "transparent",
borderTopColor: "rgba(143, 62, 62, 0.31)",
},
graphicTriangleBottom: {
position: "absolute",
bottom: 0,
right: 0,
width: 0,
height: 0,
borderStyle: "solid",
borderLeftWidth: 40,
borderBottomWidth: 40,
borderLeftColor: "transparent",
borderBottomColor: "rgba(172, 51, 51, 0.27)",
bottom: -20,
left: -25,
width: 70,
height: 70,
borderRadius: 35,
backgroundColor: "rgba(255, 255, 255, 0.08)",
},
content: {
flexDirection: "row", // stack vertically
alignItems: "center", // center horizontally
justifyContent: "center", // center vertically
padding: 20,
position: "relative",
zIndex: 1,
alignSelf: "center",
flex:1
}
,
flex: 1,
justifyContent: "center",
alignItems: "center",
},
icon: {
marginRight: 12,
marginBottom: 12,
},
textContainer: {
// alignItems: "center", // centers title and subtitle
alignItems: 'center',
},
title: {
fontSize: 18,
fontWeight: "700",
fontWeight: "bold",
color: "#fff",
marginBottom: 4,
textTransform:'uppercase'
// textAlign: "center",
textTransform: 'uppercase',
letterSpacing: 1,
textAlign: 'center',
},
subtitle: {
fontSize: 14,
color: colors.primary,
fontSize: 13,
color: colors.white,
opacity: 0.9,
fontWeight: "500",
textAlign: "center",
marginTop: 4,
},
});
+6 -5
View File
@@ -15,10 +15,12 @@ type CustomInputProps = TextInputProps & {
label?: string;
icon?: IoniconsIconName;
error?:string
value?: string | number;
};
const CustomInput: React.FC<CustomInputProps> = ({
label,
value,
icon,
style,
error,
@@ -28,7 +30,7 @@ const CustomInput: React.FC<CustomInputProps> = ({
<View style={styles.inputContainer}>
{label ? <Text style={styles.inputLabel}>{label}</Text> : null}
<View style={styles.inputWrapper}>
{icon && <Ionicons name={icon} size={20} color={colors.textDark} style={styles.inputIcon} />}
{icon && <Ionicons name={icon} size={20} color={colors.pastelBlue} style={styles.inputIcon} />}
<TextInput
style={[styles.input, icon && { paddingLeft: 36 }, style]}
placeholderTextColor={colors.textLight}
@@ -83,7 +85,7 @@ const CustomButton: React.FC<CustomButtonProps> = ({
// --- Styles ---
const styles = StyleSheet.create({
inputContainer: { marginBottom: 12 },
inputContainer: { marginBottom: 12,elevation:5 },
inputLabel: { fontSize: 14, fontWeight: "500", color: colors.textDark, marginBottom: 6 },
inputWrapper: {
flexDirection: "row",
@@ -97,9 +99,7 @@ const styles = StyleSheet.create({
},
input: {
flex: 1,
borderWidth: 1,
borderColor: colors.textLight,
borderRadius: 10,
borderRadius: 15,
padding: 12,
paddingLeft: 12,
backgroundColor: colors.white,
@@ -107,6 +107,7 @@ const styles = StyleSheet.create({
fontSize: 15,
},
button: {
elevation:5,
paddingVertical: 12,
borderRadius: 12,
alignItems: "center",