frontend first version
This commit is contained in:
238
src/components/common/BiometricModal.tsx
Normal file
238
src/components/common/BiometricModal.tsx
Normal file
@@ -0,0 +1,238 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
Modal,
|
||||
StyleSheet,
|
||||
TouchableOpacity,
|
||||
Animated,
|
||||
} from 'react-native';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import { Ionicons, MaterialCommunityIcons } from '@expo/vector-icons';
|
||||
import { colors, borderRadius, spacing, typography, shadows } from '../../theme/colors';
|
||||
|
||||
interface BiometricModalProps {
|
||||
visible: boolean;
|
||||
onSuccess: () => void;
|
||||
onCancel: () => void;
|
||||
title?: string;
|
||||
message?: string;
|
||||
isDark?: boolean;
|
||||
}
|
||||
|
||||
export default function BiometricModal({
|
||||
visible,
|
||||
onSuccess,
|
||||
onCancel,
|
||||
title = 'Captain\'s Verification',
|
||||
message = 'Verify your identity to continue',
|
||||
isDark = false,
|
||||
}: BiometricModalProps) {
|
||||
const [scanAnimation] = useState(new Animated.Value(0));
|
||||
const [pulseAnimation] = useState(new Animated.Value(1));
|
||||
const [isScanning, setIsScanning] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (visible) {
|
||||
setIsScanning(false);
|
||||
scanAnimation.setValue(0);
|
||||
|
||||
// Pulse animation
|
||||
Animated.loop(
|
||||
Animated.sequence([
|
||||
Animated.timing(pulseAnimation, {
|
||||
toValue: 1.08,
|
||||
duration: 1000,
|
||||
useNativeDriver: true,
|
||||
}),
|
||||
Animated.timing(pulseAnimation, {
|
||||
toValue: 1,
|
||||
duration: 1000,
|
||||
useNativeDriver: true,
|
||||
}),
|
||||
])
|
||||
).start();
|
||||
}
|
||||
}, [visible]);
|
||||
|
||||
const handleScan = () => {
|
||||
setIsScanning(true);
|
||||
|
||||
Animated.loop(
|
||||
Animated.sequence([
|
||||
Animated.timing(scanAnimation, {
|
||||
toValue: 1,
|
||||
duration: 800,
|
||||
useNativeDriver: true,
|
||||
}),
|
||||
Animated.timing(scanAnimation, {
|
||||
toValue: 0,
|
||||
duration: 800,
|
||||
useNativeDriver: true,
|
||||
}),
|
||||
]),
|
||||
{ iterations: 2 }
|
||||
).start(() => {
|
||||
setTimeout(() => {
|
||||
onSuccess();
|
||||
}, 300);
|
||||
});
|
||||
};
|
||||
|
||||
const backgroundColor = isDark ? colors.vault.cardBackground : colors.white;
|
||||
const textColor = isDark ? colors.vault.text : colors.nautical.navy;
|
||||
const accentColor = isDark ? colors.vault.primary : colors.nautical.teal;
|
||||
const accentGradient: [string, string] = isDark
|
||||
? [colors.vault.primary, colors.vault.secondary]
|
||||
: [colors.nautical.teal, colors.nautical.seafoam];
|
||||
|
||||
return (
|
||||
<Modal
|
||||
visible={visible}
|
||||
transparent
|
||||
animationType="fade"
|
||||
onRequestClose={onCancel}
|
||||
>
|
||||
<View style={styles.overlay}>
|
||||
<View style={[styles.container, { backgroundColor }, shadows.medium]}>
|
||||
{/* Ship wheel watermark */}
|
||||
<View style={styles.watermark}>
|
||||
<MaterialCommunityIcons
|
||||
name="ship-wheel"
|
||||
size={150}
|
||||
color={isDark ? colors.vault.primary : colors.nautical.lightMint}
|
||||
style={{ opacity: 0.15 }}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<Text style={[styles.title, { color: textColor }]}>{title}</Text>
|
||||
<Text style={[styles.message, { color: isDark ? colors.vault.textSecondary : colors.nautical.sage }]}>
|
||||
{message}
|
||||
</Text>
|
||||
|
||||
<TouchableOpacity
|
||||
style={styles.fingerprintButton}
|
||||
onPress={handleScan}
|
||||
activeOpacity={0.8}
|
||||
>
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.fingerprintOuter,
|
||||
{
|
||||
backgroundColor: `${accentColor}15`,
|
||||
transform: [{ scale: pulseAnimation }],
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.fingerprintContainer,
|
||||
{
|
||||
opacity: scanAnimation.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [1, 0.7],
|
||||
}),
|
||||
transform: [
|
||||
{
|
||||
scale: scanAnimation.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [1, 1.05],
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
]}
|
||||
>
|
||||
<LinearGradient
|
||||
colors={accentGradient}
|
||||
style={styles.fingerprintGradient}
|
||||
>
|
||||
<Ionicons
|
||||
name={isScanning ? "finger-print" : "finger-print-outline"}
|
||||
size={48}
|
||||
color="#fff"
|
||||
/>
|
||||
</LinearGradient>
|
||||
</Animated.View>
|
||||
<Text style={[styles.scanText, { color: accentColor }]}>
|
||||
{isScanning ? 'Verifying...' : 'Tap to Verify'}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity style={styles.cancelButton} onPress={onCancel}>
|
||||
<Text style={[styles.cancelText, { color: isDark ? colors.vault.textSecondary : colors.nautical.sage }]}>
|
||||
Cancel
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
overlay: {
|
||||
flex: 1,
|
||||
backgroundColor: 'rgba(26, 58, 74, 0.7)',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
padding: spacing.lg,
|
||||
},
|
||||
container: {
|
||||
width: '100%',
|
||||
borderRadius: borderRadius.xxl,
|
||||
padding: spacing.xl,
|
||||
alignItems: 'center',
|
||||
overflow: 'hidden',
|
||||
},
|
||||
watermark: {
|
||||
position: 'absolute',
|
||||
top: -30,
|
||||
right: -30,
|
||||
},
|
||||
title: {
|
||||
fontSize: typography.fontSize.lg,
|
||||
fontWeight: '600',
|
||||
marginBottom: spacing.sm,
|
||||
textAlign: 'center',
|
||||
fontFamily: typography.fontFamily.serif,
|
||||
},
|
||||
message: {
|
||||
fontSize: typography.fontSize.base,
|
||||
textAlign: 'center',
|
||||
marginBottom: spacing.xl,
|
||||
lineHeight: typography.fontSize.base * 1.5,
|
||||
},
|
||||
fingerprintButton: {
|
||||
alignItems: 'center',
|
||||
marginBottom: spacing.lg,
|
||||
},
|
||||
fingerprintOuter: {
|
||||
position: 'absolute',
|
||||
width: 150,
|
||||
height: 150,
|
||||
borderRadius: 75,
|
||||
},
|
||||
fingerprintContainer: {
|
||||
marginBottom: spacing.md,
|
||||
},
|
||||
fingerprintGradient: {
|
||||
width: 110,
|
||||
height: 110,
|
||||
borderRadius: 55,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
scanText: {
|
||||
fontSize: typography.fontSize.base,
|
||||
fontWeight: '600',
|
||||
},
|
||||
cancelButton: {
|
||||
paddingVertical: spacing.md,
|
||||
paddingHorizontal: spacing.xl,
|
||||
},
|
||||
cancelText: {
|
||||
fontSize: typography.fontSize.base,
|
||||
fontWeight: '500',
|
||||
},
|
||||
});
|
||||
169
src/components/common/Icons.tsx
Normal file
169
src/components/common/Icons.tsx
Normal file
@@ -0,0 +1,169 @@
|
||||
import React from 'react';
|
||||
import { ViewStyle, TextStyle } from 'react-native';
|
||||
import { Feather, Ionicons, MaterialCommunityIcons, FontAwesome5 } from '@expo/vector-icons';
|
||||
|
||||
interface IconProps {
|
||||
name: string;
|
||||
size?: number;
|
||||
color?: string;
|
||||
style?: ViewStyle | TextStyle;
|
||||
}
|
||||
|
||||
// Icon component with unified interface
|
||||
export const Icon: React.FC<IconProps> = ({
|
||||
name,
|
||||
size = 24,
|
||||
color = '#000',
|
||||
style
|
||||
}) => {
|
||||
// Map custom names to actual icon library icons
|
||||
switch (name) {
|
||||
// Tab icons
|
||||
case 'flow':
|
||||
return <Ionicons name="water-outline" size={size} color={color} style={style} />;
|
||||
case 'vault':
|
||||
return <MaterialCommunityIcons name="safe-square-outline" size={size} color={color} style={style} />;
|
||||
case 'sentinel':
|
||||
return <Ionicons name="shield-checkmark-outline" size={size} color={color} style={style} />;
|
||||
case 'heritage':
|
||||
return <MaterialCommunityIcons name="file-document-outline" size={size} color={color} style={style} />;
|
||||
case 'me':
|
||||
return <Feather name="user" size={size} color={color} style={style} />;
|
||||
|
||||
// Asset type icons
|
||||
case 'game':
|
||||
return <Ionicons name="game-controller-outline" size={size} color={color} style={style} />;
|
||||
case 'key':
|
||||
return <Feather name="key" size={size} color={color} style={style} />;
|
||||
case 'document':
|
||||
return <Ionicons name="document-text-outline" size={size} color={color} style={style} />;
|
||||
case 'photo':
|
||||
return <Ionicons name="image-outline" size={size} color={color} style={style} />;
|
||||
case 'will':
|
||||
return <MaterialCommunityIcons name="script-text-outline" size={size} color={color} style={style} />;
|
||||
case 'custom':
|
||||
return <Feather name="package" size={size} color={color} style={style} />;
|
||||
|
||||
// Action icons
|
||||
case 'add':
|
||||
return <Feather name="plus" size={size} color={color} style={style} />;
|
||||
case 'check':
|
||||
return <Feather name="check" size={size} color={color} style={style} />;
|
||||
case 'lock':
|
||||
return <Feather name="lock" size={size} color={color} style={style} />;
|
||||
case 'unlock':
|
||||
return <Feather name="unlock" size={size} color={color} style={style} />;
|
||||
case 'shield':
|
||||
return <Ionicons name="shield-checkmark" size={size} color={color} style={style} />;
|
||||
case 'fingerprint':
|
||||
return <Ionicons name="finger-print" size={size} color={color} style={style} />;
|
||||
case 'encrypted':
|
||||
return <MaterialCommunityIcons name="lock-check" size={size} color={color} style={style} />;
|
||||
|
||||
// Input type icons
|
||||
case 'text':
|
||||
return <MaterialCommunityIcons name="format-text" size={size} color={color} style={style} />;
|
||||
case 'voice':
|
||||
return <Ionicons name="mic-outline" size={size} color={color} style={style} />;
|
||||
case 'image':
|
||||
return <Ionicons name="camera-outline" size={size} color={color} style={style} />;
|
||||
|
||||
// Status icons
|
||||
case 'statusnormal':
|
||||
return <Ionicons name="checkmark-circle" size={size} color={color} style={style} />;
|
||||
case 'statuswarning':
|
||||
return <Ionicons name="warning" size={size} color={color} style={style} />;
|
||||
case 'statusreleasing':
|
||||
return <Ionicons name="alert-circle" size={size} color={color} style={style} />;
|
||||
|
||||
// Navigation icons
|
||||
case 'arrowRight':
|
||||
return <Feather name="arrow-right" size={size} color={color} style={style} />;
|
||||
case 'arrowUp':
|
||||
return <Feather name="arrow-up-right" size={size} color={color} style={style} />;
|
||||
case 'chevronRight':
|
||||
return <Feather name="chevron-right" size={size} color={color} style={style} />;
|
||||
case 'close':
|
||||
return <Feather name="x" size={size} color={color} style={style} />;
|
||||
|
||||
// Other icons
|
||||
case 'heartbeat':
|
||||
return <MaterialCommunityIcons name="heart-pulse" size={size} color={color} style={style} />;
|
||||
case 'warningSign':
|
||||
return <Ionicons name="warning-outline" size={size} color={color} style={style} />;
|
||||
case 'info':
|
||||
return <Feather name="info" size={size} color={color} style={style} />;
|
||||
case 'settings':
|
||||
return <Feather name="settings" size={size} color={color} style={style} />;
|
||||
case 'clock':
|
||||
return <Feather name="clock" size={size} color={color} style={style} />;
|
||||
case 'calendar':
|
||||
return <Feather name="calendar" size={size} color={color} style={style} />;
|
||||
case 'link':
|
||||
return <Feather name="external-link" size={size} color={color} style={style} />;
|
||||
case 'github':
|
||||
return <Feather name="github" size={size} color={color} style={style} />;
|
||||
case 'mail':
|
||||
return <Feather name="mail" size={size} color={color} style={style} />;
|
||||
case 'privacy':
|
||||
return <Feather name="eye-off" size={size} color={color} style={style} />;
|
||||
case 'terms':
|
||||
return <MaterialCommunityIcons name="file-sign" size={size} color={color} style={style} />;
|
||||
case 'wave':
|
||||
return <MaterialCommunityIcons name="wave" size={size} color={color} style={style} />;
|
||||
case 'palm':
|
||||
return <FontAwesome5 name="tree" size={size} color={color} style={style} />;
|
||||
case 'sun':
|
||||
return <Feather name="sun" size={size} color={color} style={style} />;
|
||||
case 'star':
|
||||
return <Feather name="star" size={size} color={color} style={style} />;
|
||||
case 'heart':
|
||||
return <Feather name="heart" size={size} color={color} style={style} />;
|
||||
case 'users':
|
||||
return <Feather name="users" size={size} color={color} style={style} />;
|
||||
case 'gift':
|
||||
return <Feather name="gift" size={size} color={color} style={style} />;
|
||||
case 'zap':
|
||||
return <Feather name="zap" size={size} color={color} style={style} />;
|
||||
|
||||
default:
|
||||
return <Feather name="circle" size={size} color={color} style={style} />;
|
||||
}
|
||||
};
|
||||
|
||||
// Predefined icon components for common use cases
|
||||
export const GameIcon = (props: Omit<IconProps, 'name'>) => (
|
||||
<Icon name="game" {...props} />
|
||||
);
|
||||
|
||||
export const KeyIcon = (props: Omit<IconProps, 'name'>) => (
|
||||
<Icon name="key" {...props} />
|
||||
);
|
||||
|
||||
export const DocumentIcon = (props: Omit<IconProps, 'name'>) => (
|
||||
<Icon name="document" {...props} />
|
||||
);
|
||||
|
||||
export const PhotoIcon = (props: Omit<IconProps, 'name'>) => (
|
||||
<Icon name="photo" {...props} />
|
||||
);
|
||||
|
||||
export const WillIcon = (props: Omit<IconProps, 'name'>) => (
|
||||
<Icon name="will" {...props} />
|
||||
);
|
||||
|
||||
export const CustomIcon = (props: Omit<IconProps, 'name'>) => (
|
||||
<Icon name="custom" {...props} />
|
||||
);
|
||||
|
||||
export const CheckIcon = (props: Omit<IconProps, 'name'>) => (
|
||||
<Icon name="check" {...props} />
|
||||
);
|
||||
|
||||
export const LockIcon = (props: Omit<IconProps, 'name'>) => (
|
||||
<Icon name="lock" {...props} />
|
||||
);
|
||||
|
||||
export const ShieldIcon = (props: Omit<IconProps, 'name'>) => (
|
||||
<Icon name="shield" {...props} />
|
||||
);
|
||||
250
src/components/common/VaultDoorAnimation.tsx
Normal file
250
src/components/common/VaultDoorAnimation.tsx
Normal file
@@ -0,0 +1,250 @@
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { View, Text, Animated, StyleSheet, Modal } from 'react-native';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import { MaterialCommunityIcons, Ionicons, FontAwesome5 } from '@expo/vector-icons';
|
||||
import { colors, typography, spacing, borderRadius } from '../../theme/colors';
|
||||
|
||||
interface VaultDoorAnimationProps {
|
||||
visible: boolean;
|
||||
onComplete: () => void;
|
||||
}
|
||||
|
||||
export default function VaultDoorAnimation({
|
||||
visible,
|
||||
onComplete,
|
||||
}: VaultDoorAnimationProps) {
|
||||
const doorLeft = useRef(new Animated.Value(0)).current;
|
||||
const doorRight = useRef(new Animated.Value(0)).current;
|
||||
const lockRotation = useRef(new Animated.Value(0)).current;
|
||||
const lockScale = useRef(new Animated.Value(1)).current;
|
||||
const fadeOut = useRef(new Animated.Value(1)).current;
|
||||
const checkScale = useRef(new Animated.Value(0)).current;
|
||||
|
||||
useEffect(() => {
|
||||
if (visible) {
|
||||
// Reset animations
|
||||
doorLeft.setValue(0);
|
||||
doorRight.setValue(0);
|
||||
lockRotation.setValue(0);
|
||||
lockScale.setValue(1);
|
||||
fadeOut.setValue(1);
|
||||
checkScale.setValue(0);
|
||||
|
||||
// Play closing animation sequence
|
||||
Animated.sequence([
|
||||
// Doors slide in
|
||||
Animated.parallel([
|
||||
Animated.timing(doorLeft, {
|
||||
toValue: 1,
|
||||
duration: 600,
|
||||
useNativeDriver: true,
|
||||
}),
|
||||
Animated.timing(doorRight, {
|
||||
toValue: 1,
|
||||
duration: 600,
|
||||
useNativeDriver: true,
|
||||
}),
|
||||
]),
|
||||
// Lock rotates and pulses
|
||||
Animated.parallel([
|
||||
Animated.timing(lockRotation, {
|
||||
toValue: 1,
|
||||
duration: 400,
|
||||
useNativeDriver: true,
|
||||
}),
|
||||
Animated.sequence([
|
||||
Animated.timing(lockScale, {
|
||||
toValue: 1.2,
|
||||
duration: 200,
|
||||
useNativeDriver: true,
|
||||
}),
|
||||
Animated.timing(lockScale, {
|
||||
toValue: 1,
|
||||
duration: 200,
|
||||
useNativeDriver: true,
|
||||
}),
|
||||
]),
|
||||
]),
|
||||
// Show checkmark
|
||||
Animated.spring(checkScale, {
|
||||
toValue: 1,
|
||||
friction: 5,
|
||||
useNativeDriver: true,
|
||||
}),
|
||||
// Pause
|
||||
Animated.delay(500),
|
||||
// Fade out
|
||||
Animated.timing(fadeOut, {
|
||||
toValue: 0,
|
||||
duration: 300,
|
||||
useNativeDriver: true,
|
||||
}),
|
||||
]).start(() => {
|
||||
onComplete();
|
||||
});
|
||||
}
|
||||
}, [visible]);
|
||||
|
||||
if (!visible) return null;
|
||||
|
||||
return (
|
||||
<Modal transparent visible={visible} animationType="fade">
|
||||
<Animated.View style={[styles.container, { opacity: fadeOut }]}>
|
||||
<View style={styles.doorContainer}>
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.door,
|
||||
styles.doorLeft,
|
||||
{
|
||||
transform: [
|
||||
{
|
||||
translateX: doorLeft.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [-200, 0],
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
]}
|
||||
>
|
||||
<LinearGradient
|
||||
colors={[colors.nautical.teal, colors.nautical.deepTeal]}
|
||||
style={styles.doorGradient}
|
||||
>
|
||||
<FontAwesome5 name="anchor" size={32} color={colors.vault.primary} style={{ opacity: 0.3 }} />
|
||||
</LinearGradient>
|
||||
</Animated.View>
|
||||
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.door,
|
||||
styles.doorRight,
|
||||
{
|
||||
transform: [
|
||||
{
|
||||
translateX: doorRight.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: [200, 0],
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
]}
|
||||
>
|
||||
<LinearGradient
|
||||
colors={[colors.nautical.deepTeal, colors.nautical.teal]}
|
||||
style={styles.doorGradient}
|
||||
>
|
||||
<FontAwesome5 name="anchor" size={32} color={colors.vault.primary} style={{ opacity: 0.3 }} />
|
||||
</LinearGradient>
|
||||
</Animated.View>
|
||||
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.lockContainer,
|
||||
{
|
||||
transform: [
|
||||
{
|
||||
rotate: lockRotation.interpolate({
|
||||
inputRange: [0, 1],
|
||||
outputRange: ['0deg', '90deg'],
|
||||
}),
|
||||
},
|
||||
{ scale: lockScale },
|
||||
],
|
||||
},
|
||||
]}
|
||||
>
|
||||
<LinearGradient
|
||||
colors={[colors.vault.primary, colors.vault.secondary]}
|
||||
style={styles.lockGradient}
|
||||
>
|
||||
<MaterialCommunityIcons name="lock" size={28} color={colors.vault.background} />
|
||||
</LinearGradient>
|
||||
</Animated.View>
|
||||
</View>
|
||||
|
||||
<Animated.View
|
||||
style={[
|
||||
styles.checkContainer,
|
||||
{
|
||||
transform: [{ scale: checkScale }],
|
||||
opacity: checkScale,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Ionicons name="checkmark-circle" size={52} color={colors.vault.success} />
|
||||
</Animated.View>
|
||||
|
||||
<Text style={styles.statusText}>Treasure Sealed</Text>
|
||||
<Text style={styles.subText}>Your legacy is now protected</Text>
|
||||
</Animated.View>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: 'rgba(26, 58, 74, 0.98)',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
doorContainer: {
|
||||
width: 200,
|
||||
height: 200,
|
||||
position: 'relative',
|
||||
overflow: 'hidden',
|
||||
borderRadius: borderRadius.xl,
|
||||
marginBottom: spacing.lg,
|
||||
},
|
||||
door: {
|
||||
position: 'absolute',
|
||||
width: 100,
|
||||
height: 200,
|
||||
},
|
||||
doorLeft: {
|
||||
left: 0,
|
||||
},
|
||||
doorRight: {
|
||||
right: 0,
|
||||
},
|
||||
doorGradient: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
borderWidth: 2,
|
||||
borderColor: colors.vault.primary,
|
||||
},
|
||||
lockContainer: {
|
||||
position: 'absolute',
|
||||
top: '50%',
|
||||
left: '50%',
|
||||
marginTop: -32,
|
||||
marginLeft: -32,
|
||||
width: 64,
|
||||
height: 64,
|
||||
zIndex: 10,
|
||||
},
|
||||
lockGradient: {
|
||||
flex: 1,
|
||||
borderRadius: 32,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
checkContainer: {
|
||||
marginBottom: spacing.md,
|
||||
},
|
||||
statusText: {
|
||||
fontSize: typography.fontSize.xl,
|
||||
color: colors.vault.primary,
|
||||
fontWeight: '600',
|
||||
marginBottom: spacing.xs,
|
||||
fontFamily: typography.fontFamily.serif,
|
||||
},
|
||||
subText: {
|
||||
fontSize: typography.fontSize.base,
|
||||
color: colors.vault.textSecondary,
|
||||
fontStyle: 'italic',
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user