frontend first version
This commit is contained in:
625
src/screens/FlowScreen.tsx
Normal file
625
src/screens/FlowScreen.tsx
Normal file
@@ -0,0 +1,625 @@
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
View,
|
||||
Text,
|
||||
StyleSheet,
|
||||
ScrollView,
|
||||
TouchableOpacity,
|
||||
Modal,
|
||||
TextInput,
|
||||
SafeAreaView,
|
||||
} 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 { FlowRecord } from '../types';
|
||||
import BiometricModal from '../components/common/BiometricModal';
|
||||
import VaultDoorAnimation from '../components/common/VaultDoorAnimation';
|
||||
|
||||
// Mock data
|
||||
const initialRecords: FlowRecord[] = [
|
||||
{
|
||||
id: '1',
|
||||
type: 'text',
|
||||
content: 'Beautiful sunny day today. Went to the park with family. Felt the simple joy of life.',
|
||||
createdAt: new Date('2024-01-18T10:30:00'),
|
||||
emotion: 'Calm',
|
||||
isArchived: false,
|
||||
},
|
||||
{
|
||||
id: '2',
|
||||
type: 'text',
|
||||
content: 'Completed an important project. The process was challenging, but the result is satisfying.',
|
||||
createdAt: new Date('2024-01-17T16:45:00'),
|
||||
emotion: 'Content',
|
||||
isArchived: false,
|
||||
},
|
||||
{
|
||||
id: '3',
|
||||
type: 'text',
|
||||
content: 'Archived a reflection',
|
||||
createdAt: new Date('2024-01-15T09:20:00'),
|
||||
isArchived: true,
|
||||
archivedAt: new Date('2024-01-16T14:00:00'),
|
||||
},
|
||||
{
|
||||
id: '4',
|
||||
type: 'voice',
|
||||
content: '[Voice recording 2:30]',
|
||||
createdAt: new Date('2024-01-14T20:15:00'),
|
||||
emotion: 'Grateful',
|
||||
isArchived: false,
|
||||
},
|
||||
];
|
||||
|
||||
// Emotion config
|
||||
const emotionConfig: Record<string, { color: string; icon: string }> = {
|
||||
'Calm': { color: colors.nautical.seafoam, icon: 'water' },
|
||||
'Content': { color: colors.nautical.teal, icon: 'checkmark-circle' },
|
||||
'Grateful': { color: colors.nautical.gold, icon: 'star' },
|
||||
'Nostalgic': { color: colors.nautical.sage, icon: 'time' },
|
||||
'Hopeful': { color: colors.nautical.mint, icon: 'sunny' },
|
||||
};
|
||||
|
||||
export default function FlowScreen() {
|
||||
const [records, setRecords] = useState<FlowRecord[]>(initialRecords);
|
||||
const [showAddModal, setShowAddModal] = useState(false);
|
||||
const [newContent, setNewContent] = useState('');
|
||||
const [selectedRecord, setSelectedRecord] = useState<FlowRecord | null>(null);
|
||||
const [showArchiveWarning, setShowArchiveWarning] = useState(false);
|
||||
const [showBiometric, setShowBiometric] = useState(false);
|
||||
const [showVaultAnimation, setShowVaultAnimation] = useState(false);
|
||||
const [selectedInputType, setSelectedInputType] = useState<'text' | 'voice' | 'image'>('text');
|
||||
|
||||
const today = new Date();
|
||||
const dateStr = today.toLocaleDateString('en-US', {
|
||||
weekday: 'long',
|
||||
month: 'long',
|
||||
day: 'numeric'
|
||||
});
|
||||
|
||||
const handleAddRecord = () => {
|
||||
if (!newContent.trim()) return;
|
||||
const newRecord: FlowRecord = {
|
||||
id: Date.now().toString(),
|
||||
type: selectedInputType,
|
||||
content: newContent,
|
||||
createdAt: new Date(),
|
||||
emotion: 'Calm',
|
||||
isArchived: false,
|
||||
};
|
||||
setRecords([newRecord, ...records]);
|
||||
setNewContent('');
|
||||
setShowAddModal(false);
|
||||
};
|
||||
|
||||
const handleSendToVault = (record: FlowRecord) => {
|
||||
setSelectedRecord(record);
|
||||
setShowArchiveWarning(true);
|
||||
};
|
||||
|
||||
const handleConfirmArchive = () => {
|
||||
setShowArchiveWarning(false);
|
||||
setShowBiometric(true);
|
||||
};
|
||||
|
||||
const handleBiometricSuccess = () => {
|
||||
setShowBiometric(false);
|
||||
setShowVaultAnimation(true);
|
||||
};
|
||||
|
||||
const handleVaultAnimationComplete = () => {
|
||||
setShowVaultAnimation(false);
|
||||
if (selectedRecord) {
|
||||
setRecords(
|
||||
records.map((r) =>
|
||||
r.id === selectedRecord.id
|
||||
? { ...r, content: 'Archived a reflection', isArchived: true, archivedAt: new Date() }
|
||||
: r
|
||||
)
|
||||
);
|
||||
setSelectedRecord(null);
|
||||
}
|
||||
};
|
||||
|
||||
const formatTime = (date: Date) => {
|
||||
return date.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit' });
|
||||
};
|
||||
|
||||
const formatDate = (date: Date) => {
|
||||
return date.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<LinearGradient
|
||||
colors={[colors.flow.backgroundGradientStart, colors.flow.backgroundGradientEnd]}
|
||||
style={styles.gradient}
|
||||
>
|
||||
<SafeAreaView style={styles.safeArea}>
|
||||
{/* Header */}
|
||||
<View style={styles.header}>
|
||||
<View style={styles.headerLeft}>
|
||||
<View style={styles.iconCircle}>
|
||||
<FontAwesome5 name="scroll" size={18} color={colors.flow.primary} />
|
||||
</View>
|
||||
<View>
|
||||
<Text style={styles.headerTitle}>Journal</Text>
|
||||
<Text style={styles.headerDate}>{dateStr}</Text>
|
||||
</View>
|
||||
</View>
|
||||
<View style={styles.moodBadge}>
|
||||
<MaterialCommunityIcons name="weather-sunny" size={14} color={colors.nautical.gold} />
|
||||
<Text style={styles.moodText}>Serene</Text>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Timeline */}
|
||||
<ScrollView
|
||||
style={styles.timeline}
|
||||
showsVerticalScrollIndicator={false}
|
||||
contentContainerStyle={styles.timelineContent}
|
||||
>
|
||||
{records.map((record, index) => {
|
||||
const emotionInfo = record.emotion ? emotionConfig[record.emotion] : null;
|
||||
const showDateHeader = index === 0 ||
|
||||
formatDate(record.createdAt) !== formatDate(records[index - 1].createdAt);
|
||||
|
||||
return (
|
||||
<View key={record.id}>
|
||||
{showDateHeader && (
|
||||
<View style={styles.dateHeader}>
|
||||
<View style={styles.dateLine} />
|
||||
<Text style={styles.dateHeaderText}>{formatDate(record.createdAt)}</Text>
|
||||
<View style={styles.dateLine} />
|
||||
</View>
|
||||
)}
|
||||
<View style={[styles.card, record.isArchived && styles.archivedCard]}>
|
||||
<View style={styles.cardHeader}>
|
||||
<Text style={[styles.cardTime, record.isArchived && styles.archivedText]}>
|
||||
{formatTime(record.createdAt)}
|
||||
</Text>
|
||||
<View style={styles.cardBadges}>
|
||||
{emotionInfo && !record.isArchived && (
|
||||
<View style={[styles.emotionBadge, { backgroundColor: `${emotionInfo.color}15` }]}>
|
||||
<Ionicons name={emotionInfo.icon as any} size={11} color={emotionInfo.color} />
|
||||
<Text style={[styles.emotionText, { color: emotionInfo.color }]}>{record.emotion}</Text>
|
||||
</View>
|
||||
)}
|
||||
{record.type === 'voice' && !record.isArchived && (
|
||||
<Ionicons name="mic" size={14} color={colors.flow.secondary} />
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<Text style={[styles.cardContent, record.isArchived && styles.archivedText]}>
|
||||
{record.isArchived
|
||||
? `📦 ${record.archivedAt?.toLocaleDateString('en-US')} — ${record.content}`
|
||||
: record.content
|
||||
}
|
||||
</Text>
|
||||
|
||||
{!record.isArchived && (
|
||||
<TouchableOpacity
|
||||
style={styles.vaultButton}
|
||||
onPress={() => handleSendToVault(record)}
|
||||
>
|
||||
<MaterialCommunityIcons name="treasure-chest" size={14} color={colors.flow.primary} />
|
||||
<Text style={styles.vaultButtonText}>Seal in Vault</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
})}
|
||||
<View style={{ height: 100 }} />
|
||||
</ScrollView>
|
||||
|
||||
{/* FAB */}
|
||||
<TouchableOpacity
|
||||
style={styles.fab}
|
||||
onPress={() => setShowAddModal(true)}
|
||||
activeOpacity={0.9}
|
||||
>
|
||||
<LinearGradient
|
||||
colors={[colors.nautical.teal, colors.nautical.seafoam]}
|
||||
style={styles.fabGradient}
|
||||
>
|
||||
<Feather name="feather" size={24} color="#fff" />
|
||||
</LinearGradient>
|
||||
</TouchableOpacity>
|
||||
</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} />
|
||||
<Text style={styles.modalTitle}>New Entry</Text>
|
||||
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder="What's on your mind, Captain?"
|
||||
placeholderTextColor={colors.flow.textSecondary}
|
||||
value={newContent}
|
||||
onChangeText={setNewContent}
|
||||
multiline
|
||||
textAlignVertical="top"
|
||||
/>
|
||||
|
||||
<View style={styles.inputTypeRow}>
|
||||
{[
|
||||
{ type: 'text', icon: 'type', label: 'Text' },
|
||||
{ type: 'voice', icon: 'mic', label: 'Voice' },
|
||||
{ type: 'image', icon: 'image', label: 'Photo' },
|
||||
].map((item) => (
|
||||
<TouchableOpacity
|
||||
key={item.type}
|
||||
style={[styles.inputTypeButton, selectedInputType === item.type && styles.inputTypeActive]}
|
||||
onPress={() => setSelectedInputType(item.type as any)}
|
||||
>
|
||||
<Feather name={item.icon as any} size={20} color={selectedInputType === item.type ? colors.flow.primary : colors.flow.textSecondary} />
|
||||
<Text style={[styles.inputTypeLabel, selectedInputType === item.type && styles.inputTypeLabelActive]}>{item.label}</Text>
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
</View>
|
||||
|
||||
<View style={styles.modalButtons}>
|
||||
<TouchableOpacity style={styles.cancelButton} onPress={() => { setShowAddModal(false); setNewContent(''); }}>
|
||||
<Text style={styles.cancelButtonText}>Cancel</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity style={styles.confirmButton} onPress={handleAddRecord}>
|
||||
<LinearGradient colors={[colors.nautical.teal, colors.nautical.seafoam]} style={styles.confirmButtonGradient}>
|
||||
<Feather name="check" size={18} color="#fff" />
|
||||
<Text style={styles.confirmButtonText}>Save</Text>
|
||||
</LinearGradient>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
|
||||
{/* Archive Warning */}
|
||||
<Modal visible={showArchiveWarning} animationType="fade" transparent onRequestClose={() => setShowArchiveWarning(false)}>
|
||||
<View style={styles.warningOverlay}>
|
||||
<View style={styles.warningModal}>
|
||||
<View style={styles.warningIcon}>
|
||||
<MaterialCommunityIcons name="treasure-chest" size={40} color={colors.nautical.teal} />
|
||||
</View>
|
||||
<Text style={styles.warningTitle}>Seal Entry?</Text>
|
||||
<Text style={styles.warningText}>
|
||||
This entry will be encrypted and stored in the vault. The original will be replaced with a sealed record.
|
||||
</Text>
|
||||
<View style={styles.warningButtons}>
|
||||
<TouchableOpacity style={styles.warningCancelButton} onPress={() => setShowArchiveWarning(false)}>
|
||||
<Text style={styles.warningCancelText}>Cancel</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity style={styles.warningConfirmButton} onPress={handleConfirmArchive}>
|
||||
<MaterialCommunityIcons name="lock" size={16} color="#fff" />
|
||||
<Text style={styles.warningConfirmText}>Seal</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</Modal>
|
||||
|
||||
<BiometricModal
|
||||
visible={showBiometric}
|
||||
onSuccess={handleBiometricSuccess}
|
||||
onCancel={() => { setShowBiometric(false); setSelectedRecord(null); }}
|
||||
title="Verify Identity"
|
||||
message="Authenticate to seal this entry"
|
||||
/>
|
||||
|
||||
<VaultDoorAnimation visible={showVaultAnimation} onComplete={handleVaultAnimationComplete} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: { flex: 1 },
|
||||
gradient: { flex: 1 },
|
||||
safeArea: { flex: 1 },
|
||||
header: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: spacing.base,
|
||||
paddingTop: spacing.sm,
|
||||
paddingBottom: spacing.md,
|
||||
},
|
||||
headerLeft: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: spacing.sm,
|
||||
},
|
||||
iconCircle: {
|
||||
width: 44,
|
||||
height: 44,
|
||||
borderRadius: 14,
|
||||
backgroundColor: colors.flow.cardBackground,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
...shadows.soft,
|
||||
},
|
||||
headerTitle: {
|
||||
fontSize: typography.fontSize.xl,
|
||||
fontWeight: '700',
|
||||
color: colors.flow.text,
|
||||
},
|
||||
headerDate: {
|
||||
fontSize: typography.fontSize.sm,
|
||||
color: colors.flow.textSecondary,
|
||||
},
|
||||
moodBadge: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 4,
|
||||
backgroundColor: `${colors.nautical.gold}15`,
|
||||
paddingHorizontal: spacing.sm,
|
||||
paddingVertical: 6,
|
||||
borderRadius: borderRadius.full,
|
||||
},
|
||||
moodText: {
|
||||
fontSize: typography.fontSize.sm,
|
||||
fontWeight: '600',
|
||||
color: colors.nautical.gold,
|
||||
},
|
||||
timeline: { flex: 1 },
|
||||
timelineContent: { padding: spacing.base, paddingTop: 0 },
|
||||
dateHeader: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginVertical: spacing.md,
|
||||
},
|
||||
dateLine: {
|
||||
flex: 1,
|
||||
height: 1,
|
||||
backgroundColor: colors.flow.cardBorder,
|
||||
},
|
||||
dateHeaderText: {
|
||||
fontSize: typography.fontSize.xs,
|
||||
fontWeight: '600',
|
||||
color: colors.flow.textSecondary,
|
||||
paddingHorizontal: spacing.md,
|
||||
},
|
||||
card: {
|
||||
backgroundColor: colors.flow.cardBackground,
|
||||
borderRadius: borderRadius.xl,
|
||||
padding: spacing.base,
|
||||
marginBottom: spacing.sm,
|
||||
...shadows.soft,
|
||||
},
|
||||
archivedCard: {
|
||||
backgroundColor: colors.flow.archived,
|
||||
shadowOpacity: 0,
|
||||
},
|
||||
cardHeader: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
marginBottom: spacing.sm,
|
||||
},
|
||||
cardTime: {
|
||||
fontSize: typography.fontSize.xs,
|
||||
color: colors.flow.textSecondary,
|
||||
fontWeight: '500',
|
||||
},
|
||||
archivedText: { color: colors.flow.archivedText },
|
||||
cardBadges: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: spacing.sm,
|
||||
},
|
||||
emotionBadge: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 3,
|
||||
paddingHorizontal: 8,
|
||||
paddingVertical: 3,
|
||||
borderRadius: borderRadius.full,
|
||||
},
|
||||
emotionText: {
|
||||
fontSize: 10,
|
||||
fontWeight: '600',
|
||||
},
|
||||
cardContent: {
|
||||
fontSize: typography.fontSize.base,
|
||||
color: colors.flow.text,
|
||||
lineHeight: typography.fontSize.base * 1.6,
|
||||
},
|
||||
vaultButton: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'flex-end',
|
||||
gap: 4,
|
||||
marginTop: spacing.md,
|
||||
paddingTop: spacing.sm,
|
||||
borderTopWidth: 1,
|
||||
borderTopColor: colors.flow.cardBorder,
|
||||
},
|
||||
vaultButtonText: {
|
||||
fontSize: typography.fontSize.sm,
|
||||
color: colors.flow.primary,
|
||||
fontWeight: '600',
|
||||
},
|
||||
fab: {
|
||||
position: 'absolute',
|
||||
bottom: 100,
|
||||
right: spacing.base,
|
||||
...shadows.medium,
|
||||
},
|
||||
fabGradient: {
|
||||
width: 56,
|
||||
height: 56,
|
||||
borderRadius: 18,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
modalOverlay: {
|
||||
flex: 1,
|
||||
backgroundColor: 'rgba(26, 58, 74, 0.4)',
|
||||
justifyContent: 'flex-end',
|
||||
},
|
||||
modalContent: {
|
||||
backgroundColor: colors.flow.cardBackground,
|
||||
borderTopLeftRadius: borderRadius.xxl,
|
||||
borderTopRightRadius: borderRadius.xxl,
|
||||
padding: spacing.lg,
|
||||
paddingBottom: spacing.xxl,
|
||||
},
|
||||
modalHandle: {
|
||||
width: 36,
|
||||
height: 4,
|
||||
backgroundColor: colors.flow.cardBorder,
|
||||
borderRadius: 2,
|
||||
alignSelf: 'center',
|
||||
marginBottom: spacing.md,
|
||||
},
|
||||
modalTitle: {
|
||||
fontSize: typography.fontSize.lg,
|
||||
fontWeight: '700',
|
||||
color: colors.flow.text,
|
||||
marginBottom: spacing.md,
|
||||
},
|
||||
input: {
|
||||
backgroundColor: colors.nautical.paleAqua,
|
||||
borderRadius: borderRadius.lg,
|
||||
padding: spacing.base,
|
||||
fontSize: typography.fontSize.base,
|
||||
color: colors.flow.text,
|
||||
minHeight: 100,
|
||||
marginBottom: spacing.md,
|
||||
},
|
||||
inputTypeRow: {
|
||||
flexDirection: 'row',
|
||||
gap: spacing.sm,
|
||||
marginBottom: spacing.lg,
|
||||
},
|
||||
inputTypeButton: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
paddingVertical: spacing.md,
|
||||
borderRadius: borderRadius.lg,
|
||||
backgroundColor: colors.nautical.paleAqua,
|
||||
borderWidth: 2,
|
||||
borderColor: 'transparent',
|
||||
},
|
||||
inputTypeActive: {
|
||||
borderColor: colors.flow.primary,
|
||||
backgroundColor: colors.nautical.lightMint,
|
||||
},
|
||||
inputTypeLabel: {
|
||||
fontSize: typography.fontSize.xs,
|
||||
color: colors.flow.textSecondary,
|
||||
marginTop: 4,
|
||||
fontWeight: '500',
|
||||
},
|
||||
inputTypeLabelActive: {
|
||||
color: colors.flow.primary,
|
||||
fontWeight: '600',
|
||||
},
|
||||
modalButtons: {
|
||||
flexDirection: 'row',
|
||||
gap: spacing.md,
|
||||
},
|
||||
cancelButton: {
|
||||
flex: 1,
|
||||
paddingVertical: spacing.md,
|
||||
borderRadius: borderRadius.lg,
|
||||
backgroundColor: colors.nautical.paleAqua,
|
||||
alignItems: 'center',
|
||||
},
|
||||
cancelButtonText: {
|
||||
fontSize: typography.fontSize.base,
|
||||
color: colors.flow.textSecondary,
|
||||
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',
|
||||
},
|
||||
warningOverlay: {
|
||||
flex: 1,
|
||||
backgroundColor: 'rgba(26, 58, 74, 0.6)',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
padding: spacing.lg,
|
||||
},
|
||||
warningModal: {
|
||||
backgroundColor: colors.flow.cardBackground,
|
||||
borderRadius: borderRadius.xxl,
|
||||
padding: spacing.xl,
|
||||
alignItems: 'center',
|
||||
width: '100%',
|
||||
...shadows.medium,
|
||||
},
|
||||
warningIcon: {
|
||||
width: 72,
|
||||
height: 72,
|
||||
borderRadius: 24,
|
||||
backgroundColor: colors.nautical.lightMint,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginBottom: spacing.md,
|
||||
},
|
||||
warningTitle: {
|
||||
fontSize: typography.fontSize.lg,
|
||||
fontWeight: '700',
|
||||
color: colors.flow.text,
|
||||
marginBottom: spacing.sm,
|
||||
},
|
||||
warningText: {
|
||||
fontSize: typography.fontSize.base,
|
||||
color: colors.flow.textSecondary,
|
||||
textAlign: 'center',
|
||||
lineHeight: typography.fontSize.base * 1.5,
|
||||
marginBottom: spacing.lg,
|
||||
},
|
||||
warningButtons: {
|
||||
flexDirection: 'row',
|
||||
gap: spacing.md,
|
||||
width: '100%',
|
||||
},
|
||||
warningCancelButton: {
|
||||
flex: 1,
|
||||
paddingVertical: spacing.md,
|
||||
borderRadius: borderRadius.lg,
|
||||
backgroundColor: colors.nautical.paleAqua,
|
||||
alignItems: 'center',
|
||||
},
|
||||
warningCancelText: {
|
||||
fontSize: typography.fontSize.base,
|
||||
color: colors.flow.textSecondary,
|
||||
fontWeight: '600',
|
||||
},
|
||||
warningConfirmButton: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
paddingVertical: spacing.md,
|
||||
borderRadius: borderRadius.lg,
|
||||
backgroundColor: colors.nautical.teal,
|
||||
gap: spacing.xs,
|
||||
},
|
||||
warningConfirmText: {
|
||||
fontSize: typography.fontSize.base,
|
||||
color: '#fff',
|
||||
fontWeight: '600',
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user