frontend first version
This commit is contained in:
748
src/screens/VaultScreen.tsx
Normal file
748
src/screens/VaultScreen.tsx
Normal file
@@ -0,0 +1,748 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
ScrollView,
|
||||
TouchableOpacity,
|
||||
Modal,
|
||||
TextInput,
|
||||
SafeAreaView,
|
||||
Animated,
|
||||
} from 'react-native';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import { Ionicons, Feather, MaterialCommunityIcons, FontAwesome5 } from '@expo/vector-icons';
|
||||
import { colors, typography, spacing, borderRadius, shadows } from '../theme/colors';
|
||||
import { VaultAsset, VaultAssetType } from '../types';
|
||||
import BiometricModal from '../components/common/BiometricModal';
|
||||
|
||||
// Asset type configuration with nautical theme
|
||||
const assetTypeConfig: Record<VaultAssetType, { icon: string; iconType: 'ionicons' | 'feather' | 'material' | 'fontawesome5'; label: string }> = {
|
||||
game_account: { icon: 'gamepad', iconType: 'fontawesome5', label: 'Digital Account' },
|
||||
private_key: { icon: 'key', iconType: 'fontawesome5', label: 'Secret Key' },
|
||||
document: { icon: 'scroll', iconType: 'fontawesome5', label: 'Document' },
|
||||
photo: { icon: 'image', iconType: 'ionicons', label: 'Sealed Photo' },
|
||||
will: { icon: 'file-signature', iconType: 'fontawesome5', label: 'Testament' },
|
||||
custom: { icon: 'gem', iconType: 'fontawesome5', label: 'Treasure' },
|
||||
};
|
||||
|
||||
// Mock data
|
||||
const initialAssets: VaultAsset[] = [
|
||||
{
|
||||
id: '1',
|
||||
type: 'private_key',
|
||||
label: 'ETH Main Wallet Key',
|
||||
createdAt: new Date('2024-01-10'),
|
||||
updatedAt: new Date('2024-01-10'),
|
||||
isEncrypted: true,
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: 'game_account',
|
||||
label: 'Steam Account Credentials',
|
||||
createdAt: new Date('2024-01-08'),
|
||||
updatedAt: new Date('2024-01-08'),
|
||||
isEncrypted: true,
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
type: 'document',
|
||||
label: 'Insurance Policy Scan',
|
||||
createdAt: new Date('2024-01-05'),
|
||||
updatedAt: new Date('2024-01-05'),
|
||||
isEncrypted: true,
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
type: 'will',
|
||||
label: 'Testament Draft v2',
|
||||
createdAt: new Date('2024-01-02'),
|
||||
updatedAt: new Date('2024-01-15'),
|
||||
isEncrypted: true,
|
||||
},
|
||||
];
|
||||
|
||||
const renderAssetTypeIcon = (config: typeof assetTypeConfig[VaultAssetType], size: number, color: string) => {
|
||||
switch (config.iconType) {
|
||||
case 'ionicons':
|
||||
return <Ionicons name={config.icon as any} size={size} color={color} />;
|
||||
case 'feather':
|
||||
return <Feather name={config.icon as any} size={size} color={color} />;
|
||||
case 'material':
|
||||
return <MaterialCommunityIcons name={config.icon as any} size={size} color={color} />;
|
||||
case 'fontawesome5':
|
||||
return <FontAwesome5 name={config.icon as any} size={size} color={color} />;
|
||||
}
|
||||
};
|
||||
|
||||
export default function VaultScreen() {
|
||||
const [isUnlocked, setIsUnlocked] = useState(false);
|
||||
const [showBiometric, setShowBiometric] = useState(false);
|
||||
const [assets, setAssets] = useState<VaultAsset[]>(initialAssets);
|
||||
const [showAddModal, setShowAddModal] = useState(false);
|
||||
const [selectedType, setSelectedType] = useState<VaultAssetType>('custom');
|
||||
const [newLabel, setNewLabel] = useState('');
|
||||
const [showUploadSuccess, setShowUploadSuccess] = useState(false);
|
||||
const [fadeAnim] = useState(new Animated.Value(0));
|
||||
const [pulseAnim] = useState(new Animated.Value(1));
|
||||
|
||||
useEffect(() => {
|
||||
if (!isUnlocked) {
|
||||
const timer = setTimeout(() => {
|
||||
setShowBiometric(true);
|
||||
}, 500);
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (isUnlocked) {
|
||||
Animated.timing(fadeAnim, {
|
||||
toValue: 1,
|
||||
duration: 600,
|
||||
useNativeDriver: true,
|
||||
}).start();
|
||||
}
|
||||
}, [isUnlocked]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!isUnlocked) {
|
||||
Animated.loop(
|
||||
Animated.sequence([
|
||||
Animated.timing(pulseAnim, {
|
||||
toValue: 1.05,
|
||||
duration: 1500,
|
||||
useNativeDriver: true,
|
||||
}),
|
||||
Animated.timing(pulseAnim, {
|
||||
toValue: 1,
|
||||
duration: 1500,
|
||||
useNativeDriver: true,
|
||||
}),
|
||||
])
|
||||
).start();
|
||||
}
|
||||
}, [isUnlocked]);
|
||||
|
||||
const handleUnlock = () => {
|
||||
setShowBiometric(false);
|
||||
setIsUnlocked(true);
|
||||
};
|
||||
|
||||
const handleAddAsset = () => {
|
||||
if (!newLabel.trim()) return;
|
||||
|
||||
const newAsset: VaultAsset = {
|
||||
id: Date.now().toString(),
|
||||
type: selectedType,
|
||||
label: newLabel,
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
isEncrypted: true,
|
||||
};
|
||||
|
||||
setAssets([newAsset, ...assets]);
|
||||
setNewLabel('');
|
||||
setSelectedType('custom');
|
||||
setShowAddModal(false);
|
||||
|
||||
setShowUploadSuccess(true);
|
||||
setTimeout(() => setShowUploadSuccess(false), 2500);
|
||||
};
|
||||
|
||||
const formatDate = (date: Date) => {
|
||||
return date.toLocaleDateString('en-US', {
|
||||
year: 'numeric',
|
||||
month: 'short',
|
||||
day: 'numeric',
|
||||
});
|
||||
};
|
||||
|
||||
// Lock screen
|
||||
if (!isUnlocked) {
|
||||
return (
|
||||
<View style={styles.lockContainer}>
|
||||
<LinearGradient
|
||||
colors={[colors.vault.backgroundGradientStart, colors.vault.backgroundGradientEnd]}
|
||||
style={styles.lockGradient}
|
||||
>
|
||||
<SafeAreaView style={styles.lockSafeArea}>
|
||||
<View style={styles.lockContent}>
|
||||
<Animated.View style={[styles.lockIconContainer, { transform: [{ scale: pulseAnim }] }]}>
|
||||
<LinearGradient
|
||||
colors={[colors.nautical.teal, colors.nautical.deepTeal]}
|
||||
style={styles.lockIconGradient}
|
||||
>
|
||||
<MaterialCommunityIcons name="treasure-chest" size={64} color={colors.vault.primary} />
|
||||
</LinearGradient>
|
||||
</Animated.View>
|
||||
|
||||
<Text style={styles.lockTitle}>THE DEEP VAULT</Text>
|
||||
<Text style={styles.lockSubtitle}>Where treasures rest in silence</Text>
|
||||
|
||||
<View style={styles.waveContainer}>
|
||||
<MaterialCommunityIcons name="waves" size={48} color={colors.vault.secondary} style={{ opacity: 0.3 }} />
|
||||
</View>
|
||||
|
||||
<TouchableOpacity
|
||||
style={styles.unlockButton}
|
||||
onPress={() => setShowBiometric(true)}
|
||||
activeOpacity={0.8}
|
||||
>
|
||||
<LinearGradient
|
||||
colors={[colors.vault.primary, colors.vault.secondary]}
|
||||
style={styles.unlockButtonGradient}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 0 }}
|
||||
>
|
||||
<Ionicons name="finger-print" size={20} color={colors.vault.background} />
|
||||
<Text style={styles.unlockButtonText}>Captain's Verification</Text>
|
||||
</LinearGradient>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</SafeAreaView>
|
||||
</LinearGradient>
|
||||
|
||||
<BiometricModal
|
||||
visible={showBiometric}
|
||||
onSuccess={handleUnlock}
|
||||
onCancel={() => setShowBiometric(false)}
|
||||
title="Enter the Vault"
|
||||
message="Verify your identity to access your treasures"
|
||||
isDark
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<LinearGradient
|
||||
colors={[colors.vault.backgroundGradientStart, colors.vault.backgroundGradientEnd]}
|
||||
style={styles.gradient}
|
||||
>
|
||||
<SafeAreaView style={styles.safeArea}>
|
||||
<Animated.View style={[styles.content, { opacity: fadeAnim }]}>
|
||||
{/* Header */}
|
||||
<View style={styles.header}>
|
||||
<View style={styles.headerTop}>
|
||||
<View style={styles.headerTitleRow}>
|
||||
<MaterialCommunityIcons name="treasure-chest" size={26} color={colors.vault.primary} />
|
||||
<Text style={styles.title}>THE VAULT</Text>
|
||||
</View>
|
||||
<View style={styles.securityBadge}>
|
||||
<Ionicons name="shield-checkmark" size={14} color={colors.vault.success} />
|
||||
<Text style={styles.securityText}>SEALED</Text>
|
||||
</View>
|
||||
</View>
|
||||
<Text style={styles.subtitle}>
|
||||
{assets.length} treasures · Encrypted at rest
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{/* Asset List */}
|
||||
<ScrollView
|
||||
style={styles.assetList}
|
||||
showsVerticalScrollIndicator={false}
|
||||
contentContainerStyle={styles.assetListContent}
|
||||
>
|
||||
{assets.map((asset) => {
|
||||
const config = assetTypeConfig[asset.type];
|
||||
return (
|
||||
<TouchableOpacity
|
||||
key={asset.id}
|
||||
style={styles.assetCard}
|
||||
activeOpacity={0.7}
|
||||
>
|
||||
<View style={styles.assetIconContainer}>
|
||||
{renderAssetTypeIcon(config, 22, colors.vault.primary)}
|
||||
</View>
|
||||
<View style={styles.assetInfo}>
|
||||
<Text style={styles.assetType}>{config.label}</Text>
|
||||
<Text style={styles.assetLabel}>{asset.label}</Text>
|
||||
<View style={styles.assetMetaRow}>
|
||||
<Feather name="clock" size={10} color={colors.vault.textSecondary} />
|
||||
<Text style={styles.assetMeta}>Sealed {formatDate(asset.createdAt)}</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.encryptedBadge}>
|
||||
<MaterialCommunityIcons name="lock" size={16} color="#fff" />
|
||||
</View>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
})}
|
||||
<View style={{ height: 100 }} />
|
||||
</ScrollView>
|
||||
|
||||
{/* Add Button */}
|
||||
<TouchableOpacity
|
||||
style={styles.addButton}
|
||||
onPress={() => setShowAddModal(true)}
|
||||
activeOpacity={0.9}
|
||||
>
|
||||
<LinearGradient
|
||||
colors={[colors.vault.primary, colors.vault.secondary]}
|
||||
style={styles.addButtonGradient}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 0 }}
|
||||
>
|
||||
<FontAwesome5 name="plus" size={16} color={colors.vault.background} />
|
||||
<Text style={styles.addButtonText}>Add Treasure</Text>
|
||||
</LinearGradient>
|
||||
</TouchableOpacity>
|
||||
|
||||
{/* Upload Success Toast */}
|
||||
{showUploadSuccess && (
|
||||
<Animated.View style={styles.successToast}>
|
||||
<Ionicons name="checkmark-circle" size={20} color="#fff" />
|
||||
<Text style={styles.successText}>Treasure sealed successfully</Text>
|
||||
</Animated.View>
|
||||
)}
|
||||
</Animated.View>
|
||||
</SafeAreaView>
|
||||
</LinearGradient>
|
||||
|
||||
{/* Add Modal */}
|
||||
<Modal
|
||||
visible={showAddModal}
|
||||
animationType="slide"
|
||||
transparent
|
||||
onRequestClose={() => setShowAddModal(false)}
|
||||
>
|
||||
<View style={styles.modalOverlay}>
|
||||
<View style={styles.modalContent}>
|
||||
<View style={styles.modalHandle} />
|
||||
<View style={styles.modalHeader}>
|
||||
<FontAwesome5 name="gem" size={22} color={colors.nautical.teal} />
|
||||
<Text style={styles.modalTitle}>Add New Treasure</Text>
|
||||
</View>
|
||||
|
||||
<Text style={styles.modalLabel}>TREASURE TYPE</Text>
|
||||
<ScrollView
|
||||
horizontal
|
||||
showsHorizontalScrollIndicator={false}
|
||||
style={styles.typeScroll}
|
||||
contentContainerStyle={styles.typeScrollContent}
|
||||
>
|
||||
{(Object.keys(assetTypeConfig) as VaultAssetType[]).map((type) => {
|
||||
const config = assetTypeConfig[type];
|
||||
const isSelected = selectedType === type;
|
||||
return (
|
||||
<TouchableOpacity
|
||||
key={type}
|
||||
style={[styles.typeButton, isSelected && styles.typeButtonActive]}
|
||||
onPress={() => setSelectedType(type)}
|
||||
>
|
||||
<View style={[styles.typeIconContainer, isSelected && styles.typeIconContainerActive]}>
|
||||
{renderAssetTypeIcon(config, 22, isSelected ? colors.nautical.teal : colors.nautical.sage)}
|
||||
</View>
|
||||
<Text style={[styles.typeButtonLabel, isSelected && styles.typeButtonLabelActive]}>
|
||||
{config.label}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
);
|
||||
})}
|
||||
</ScrollView>
|
||||
|
||||
<Text style={styles.modalLabel}>TREASURE NAME</Text>
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="e.g., Main wallet mnemonic"
|
||||
placeholderTextColor={colors.nautical.sage}
|
||||
value={newLabel}
|
||||
onChangeText={setNewLabel}
|
||||
/>
|
||||
|
||||
<View style={styles.encryptionNote}>
|
||||
<MaterialCommunityIcons name="anchor" size={16} color={colors.nautical.teal} />
|
||||
<Text style={styles.encryptionNoteText}>
|
||||
Your treasure will be encrypted and sealed. Original data will be securely destroyed.
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
<View style={styles.modalButtons}>
|
||||
<TouchableOpacity
|
||||
style={styles.cancelButton}
|
||||
onPress={() => {
|
||||
setShowAddModal(false);
|
||||
setNewLabel('');
|
||||
}}
|
||||
>
|
||||
<Text style={styles.cancelButtonText}>Cancel</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={styles.confirmButton}
|
||||
onPress={handleAddAsset}
|
||||
>
|
||||
<LinearGradient
|
||||
colors={[colors.nautical.teal, colors.nautical.seafoam]}
|
||||
style={styles.confirmButtonGradient}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 0 }}
|
||||
>
|
||||
<MaterialCommunityIcons name="lock" size={18} color="#fff" />
|
||||
<Text style={styles.confirmButtonText}>Seal Treasure</Text>
|
||||
</LinearGradient>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
gradient: {
|
||||
flex: 1,
|
||||
},
|
||||
safeArea: {
|
||||
flex: 1,
|
||||
},
|
||||
content: {
|
||||
flex: 1,
|
||||
},
|
||||
lockContainer: {
|
||||
flex: 1,
|
||||
},
|
||||
lockGradient: {
|
||||
flex: 1,
|
||||
},
|
||||
lockSafeArea: {
|
||||
flex: 1,
|
||||
},
|
||||
lockContent: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: spacing.xl,
|
||||
},
|
||||
lockIconContainer: {
|
||||
marginBottom: spacing.lg,
|
||||
},
|
||||
lockIconGradient: {
|
||||
width: 130,
|
||||
height: 130,
|
||||
borderRadius: 65,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
...shadows.glow,
|
||||
},
|
||||
lockTitle: {
|
||||
fontSize: typography.fontSize.xxl,
|
||||
fontWeight: '700',
|
||||
color: colors.vault.text,
|
||||
letterSpacing: typography.letterSpacing.widest,
|
||||
marginBottom: spacing.sm,
|
||||
fontFamily: typography.fontFamily.serif,
|
||||
},
|
||||
lockSubtitle: {
|
||||
fontSize: typography.fontSize.base,
|
||||
color: colors.vault.textSecondary,
|
||||
marginBottom: spacing.xl,
|
||||
textAlign: 'center',
|
||||
fontStyle: 'italic',
|
||||
},
|
||||
waveContainer: {
|
||||
marginBottom: spacing.xl,
|
||||
},
|
||||
unlockButton: {
|
||||
borderRadius: borderRadius.lg,
|
||||
overflow: 'hidden',
|
||||
},
|
||||
unlockButtonGradient: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
paddingVertical: spacing.md,
|
||||
paddingHorizontal: spacing.xl,
|
||||
gap: spacing.sm,
|
||||
},
|
||||
unlockButtonText: {
|
||||
fontSize: typography.fontSize.base,
|
||||
color: colors.vault.background,
|
||||
fontWeight: '600',
|
||||
},
|
||||
header: {
|
||||
paddingHorizontal: spacing.lg,
|
||||
paddingTop: spacing.lg,
|
||||
paddingBottom: spacing.md,
|
||||
},
|
||||
headerTop: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: spacing.xs,
|
||||
},
|
||||
headerTitleRow: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: spacing.sm,
|
||||
},
|
||||
title: {
|
||||
fontSize: typography.fontSize.xl,
|
||||
fontWeight: '700',
|
||||
color: colors.vault.text,
|
||||
letterSpacing: typography.letterSpacing.wider,
|
||||
fontFamily: typography.fontFamily.serif,
|
||||
},
|
||||
securityBadge: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: `${colors.vault.success}20`,
|
||||
paddingHorizontal: spacing.sm,
|
||||
paddingVertical: spacing.xs,
|
||||
borderRadius: borderRadius.full,
|
||||
gap: spacing.xs,
|
||||
},
|
||||
securityText: {
|
||||
fontSize: typography.fontSize.xs,
|
||||
color: colors.vault.success,
|
||||
fontWeight: '700',
|
||||
letterSpacing: 1,
|
||||
},
|
||||
subtitle: {
|
||||
fontSize: typography.fontSize.sm,
|
||||
color: colors.vault.textSecondary,
|
||||
},
|
||||
assetList: {
|
||||
flex: 1,
|
||||
},
|
||||
assetListContent: {
|
||||
padding: spacing.lg,
|
||||
paddingTop: spacing.sm,
|
||||
},
|
||||
assetCard: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: colors.vault.cardBackground,
|
||||
borderRadius: borderRadius.xl,
|
||||
padding: spacing.base,
|
||||
marginBottom: spacing.md,
|
||||
borderWidth: 1,
|
||||
borderColor: colors.vault.cardBorder,
|
||||
},
|
||||
assetIconContainer: {
|
||||
width: 52,
|
||||
height: 52,
|
||||
borderRadius: 26,
|
||||
backgroundColor: `${colors.vault.primary}15`,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginRight: spacing.base,
|
||||
},
|
||||
assetInfo: {
|
||||
flex: 1,
|
||||
},
|
||||
assetType: {
|
||||
fontSize: typography.fontSize.xs,
|
||||
color: colors.vault.textSecondary,
|
||||
textTransform: 'uppercase',
|
||||
letterSpacing: 1,
|
||||
marginBottom: 2,
|
||||
fontWeight: '600',
|
||||
},
|
||||
assetLabel: {
|
||||
fontSize: typography.fontSize.base,
|
||||
color: colors.vault.text,
|
||||
fontWeight: '600',
|
||||
marginBottom: 4,
|
||||
},
|
||||
assetMetaRow: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: spacing.xs,
|
||||
},
|
||||
assetMeta: {
|
||||
fontSize: typography.fontSize.xs,
|
||||
color: colors.vault.textSecondary,
|
||||
},
|
||||
encryptedBadge: {
|
||||
width: 36,
|
||||
height: 36,
|
||||
borderRadius: 18,
|
||||
backgroundColor: colors.vault.success,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
addButton: {
|
||||
position: 'absolute',
|
||||
bottom: 100,
|
||||
left: spacing.lg,
|
||||
right: spacing.lg,
|
||||
borderRadius: borderRadius.lg,
|
||||
overflow: 'hidden',
|
||||
},
|
||||
addButtonGradient: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
paddingVertical: spacing.md,
|
||||
gap: spacing.sm,
|
||||
},
|
||||
addButtonText: {
|
||||
fontSize: typography.fontSize.base,
|
||||
color: colors.vault.background,
|
||||
fontWeight: '700',
|
||||
},
|
||||
successToast: {
|
||||
position: 'absolute',
|
||||
bottom: 170,
|
||||
left: spacing.lg,
|
||||
right: spacing.lg,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: colors.vault.success,
|
||||
paddingVertical: spacing.md,
|
||||
borderRadius: borderRadius.lg,
|
||||
gap: spacing.sm,
|
||||
},
|
||||
successText: {
|
||||
fontSize: typography.fontSize.base,
|
||||
color: '#fff',
|
||||
fontWeight: '600',
|
||||
},
|
||||
modalOverlay: {
|
||||
flex: 1,
|
||||
backgroundColor: 'rgba(26, 58, 74, 0.8)',
|
||||
justifyContent: 'flex-end',
|
||||
},
|
||||
modalContent: {
|
||||
backgroundColor: colors.nautical.cream,
|
||||
borderTopLeftRadius: borderRadius.xxl,
|
||||
borderTopRightRadius: borderRadius.xxl,
|
||||
padding: spacing.lg,
|
||||
paddingBottom: spacing.xxl,
|
||||
},
|
||||
modalHandle: {
|
||||
width: 40,
|
||||
height: 4,
|
||||
backgroundColor: colors.nautical.lightMint,
|
||||
borderRadius: 2,
|
||||
alignSelf: 'center',
|
||||
marginBottom: spacing.lg,
|
||||
},
|
||||
modalHeader: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: spacing.sm,
|
||||
marginBottom: spacing.lg,
|
||||
},
|
||||
modalTitle: {
|
||||
fontSize: typography.fontSize.lg,
|
||||
fontWeight: '600',
|
||||
color: colors.nautical.navy,
|
||||
},
|
||||
modalLabel: {
|
||||
fontSize: typography.fontSize.xs,
|
||||
color: colors.nautical.sage,
|
||||
marginBottom: spacing.sm,
|
||||
letterSpacing: typography.letterSpacing.wider,
|
||||
fontWeight: '600',
|
||||
},
|
||||
typeScroll: {
|
||||
marginBottom: spacing.lg,
|
||||
},
|
||||
typeScrollContent: {
|
||||
gap: spacing.sm,
|
||||
},
|
||||
typeButton: {
|
||||
alignItems: 'center',
|
||||
paddingVertical: spacing.sm,
|
||||
paddingHorizontal: spacing.base,
|
||||
borderRadius: borderRadius.lg,
|
||||
backgroundColor: colors.nautical.paleAqua,
|
||||
borderWidth: 2,
|
||||
borderColor: 'transparent',
|
||||
minWidth: 100,
|
||||
},
|
||||
typeButtonActive: {
|
||||
borderColor: colors.nautical.teal,
|
||||
backgroundColor: colors.nautical.lightMint,
|
||||
},
|
||||
typeIconContainer: {
|
||||
width: 44,
|
||||
height: 44,
|
||||
borderRadius: 22,
|
||||
backgroundColor: colors.nautical.cream,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginBottom: spacing.xs,
|
||||
},
|
||||
typeIconContainerActive: {
|
||||
backgroundColor: `${colors.nautical.teal}15`,
|
||||
},
|
||||
typeButtonLabel: {
|
||||
fontSize: typography.fontSize.xs,
|
||||
color: colors.nautical.sage,
|
||||
textAlign: 'center',
|
||||
fontWeight: '500',
|
||||
},
|
||||
typeButtonLabelActive: {
|
||||
color: colors.nautical.teal,
|
||||
fontWeight: '600',
|
||||
},
|
||||
input: {
|
||||
backgroundColor: colors.nautical.paleAqua,
|
||||
borderRadius: borderRadius.lg,
|
||||
padding: spacing.base,
|
||||
fontSize: typography.fontSize.base,
|
||||
color: colors.nautical.navy,
|
||||
marginBottom: spacing.md,
|
||||
borderWidth: 1,
|
||||
borderColor: colors.nautical.lightMint,
|
||||
},
|
||||
encryptionNote: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
backgroundColor: colors.nautical.lightMint,
|
||||
borderRadius: borderRadius.lg,
|
||||
padding: spacing.md,
|
||||
marginBottom: spacing.lg,
|
||||
gap: spacing.sm,
|
||||
},
|
||||
encryptionNoteText: {
|
||||
flex: 1,
|
||||
fontSize: typography.fontSize.sm,
|
||||
color: colors.nautical.teal,
|
||||
lineHeight: typography.fontSize.sm * 1.4,
|
||||
},
|
||||
modalButtons: {
|
||||
flexDirection: 'row',
|
||||
gap: spacing.md,
|
||||
},
|
||||
cancelButton: {
|
||||
flex: 1,
|
||||
paddingVertical: spacing.md,
|
||||
borderRadius: borderRadius.lg,
|
||||
backgroundColor: colors.nautical.paleAqua,
|
||||
alignItems: 'center',
|
||||
borderWidth: 1,
|
||||
borderColor: colors.nautical.lightMint,
|
||||
},
|
||||
cancelButtonText: {
|
||||
fontSize: typography.fontSize.base,
|
||||
color: colors.nautical.sage,
|
||||
fontWeight: '600',
|
||||
},
|
||||
confirmButton: {
|
||||
flex: 1,
|
||||
borderRadius: borderRadius.lg,
|
||||
overflow: 'hidden',
|
||||
},
|
||||
confirmButtonGradient: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
paddingVertical: spacing.md,
|
||||
gap: spacing.sm,
|
||||
},
|
||||
confirmButtonText: {
|
||||
fontSize: typography.fontSize.base,
|
||||
color: '#fff',
|
||||
fontWeight: '600',
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user