improve tab structure

This commit is contained in:
Ada
2026-01-28 17:24:15 -08:00
parent 146320052e
commit da4a7de0ad
3 changed files with 737 additions and 61 deletions

View File

@@ -7,7 +7,7 @@ import { colors, borderRadius, typography } from '../theme/colors';
// Screens
import FlowScreen from '../screens/FlowScreen';
import SentinelScreen from '../screens/SentinelScreen';
import HeritageScreen from '../screens/HeritageScreen';
// import HeritageScreen from '../screens/HeritageScreen'; // Heritage functionality moved to Me and Sentinel
import MeScreen from '../screens/MeScreen';
const Tab = createBottomTabNavigator();
@@ -104,6 +104,7 @@ export default function TabNavigator() {
tabBarStyle: styles.tabBarDark,
}}
/>
{/* Heritage tab commented out - functionality moved to Me (Fleet Legacy) and Sentinel (Shadow Vault)
<Tab.Screen
name="Heritage"
component={HeritageScreen}
@@ -118,6 +119,7 @@ export default function TabNavigator() {
),
}}
/>
*/}
<Tab.Screen
name="Me"
component={MeScreen}

View File

@@ -9,11 +9,67 @@ import {
SafeAreaView,
Linking,
Alert,
TextInput,
} 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 { useAuth } from '../context/AuthContext';
import { Heir, HeirStatus, PaymentStrategy } from '../types';
import HeritageScreen from './HeritageScreen';
// Mock heirs data
const initialHeirs: Heir[] = [
{
id: '1',
name: 'John Smith',
email: 'john.smith@email.com',
phone: '+1 415 555 0132',
status: 'confirmed',
releaseLevel: 3,
releaseOrder: 1,
paymentStrategy: 'prepaid',
},
{
id: '2',
name: 'Jane Doe',
email: 'jane.doe@email.com',
phone: '+1 212 555 0184',
status: 'confirmed',
releaseLevel: 2,
releaseOrder: 2,
paymentStrategy: 'pay_on_access',
},
{
id: '3',
name: 'Alice Johnson',
email: 'alice.j@email.com',
phone: '+1 646 555 0149',
status: 'invited',
releaseLevel: 1,
releaseOrder: 3,
paymentStrategy: 'pay_on_access',
},
];
// Release level descriptions
const releaseLevelConfig: Record<number, { label: string; description: string; icon: string }> = {
1: {
label: 'Journal Summaries',
description: 'Captain\'s log excerpts and emotional records',
icon: 'book-open',
},
2: {
label: 'Treasure Map',
description: 'Asset inventory and metadata',
icon: 'map',
},
3: {
label: 'Full Inheritance',
description: 'Complete encrypted treasure chest',
icon: 'key',
},
};
// Sentinel Protocol Status
const protocolStatus = {
@@ -161,6 +217,19 @@ export default function MeScreen() {
const [showSanctumModal, setShowSanctumModal] = useState(false);
const [showCaptainFull, setShowCaptainFull] = useState(false);
const [showTriggerModal, setShowTriggerModal] = useState(false);
const [showHeritageModal, setShowHeritageModal] = useState(false);
const [showThemeModal, setShowThemeModal] = useState(false);
const [isDarkMode, setIsDarkMode] = useState(false);
// Heritage / Fleet Legacy states
const [heirs, setHeirs] = useState<Heir[]>(initialHeirs);
const [showAddHeirModal, setShowAddHeirModal] = useState(false);
const [showHeirDetailModal, setShowHeirDetailModal] = useState(false);
const [selectedHeir, setSelectedHeir] = useState<Heir | null>(null);
const [newHeirName, setNewHeirName] = useState('');
const [newHeirEmail, setNewHeirEmail] = useState('');
const [newHeirLevel, setNewHeirLevel] = useState(1);
const [newHeirPayment, setNewHeirPayment] = useState<PaymentStrategy>('pay_on_access');
const [tideLevel, setTideLevel] = useState<'low' | 'high' | 'red'>('low');
const [tideChannels, setTideChannels] = useState({
push: true,
@@ -186,6 +255,44 @@ export default function MeScreen() {
Linking.openURL(url).catch(() => { });
};
// Heritage / Fleet Legacy functions
const handleAddHeir = () => {
if (!newHeirName.trim() || !newHeirEmail.trim()) return;
const newHeir: Heir = {
id: Date.now().toString(),
name: newHeirName,
email: newHeirEmail,
status: 'invited',
releaseLevel: newHeirLevel,
releaseOrder: heirs.length + 1,
paymentStrategy: newHeirPayment,
};
setHeirs([...heirs, newHeir]);
resetAddHeirForm();
setShowAddHeirModal(false);
};
const resetAddHeirForm = () => {
setNewHeirName('');
setNewHeirEmail('');
setNewHeirLevel(1);
setNewHeirPayment('pay_on_access');
};
const handleHeirPress = (heir: Heir) => {
setSelectedHeir(heir);
setShowHeirDetailModal(true);
};
const getHeirStatusBadge = (status: HeirStatus) => {
if (status === 'confirmed') {
return { text: 'Aboard', color: '#6BBF8A', icon: 'checkmark-circle' };
}
return { text: 'Invited', color: colors.nautical.gold, icon: 'time-outline' };
};
const handleAbandonIsland = () => {
Alert.alert(
'Sign Out',
@@ -213,14 +320,6 @@ export default function MeScreen() {
showsVerticalScrollIndicator={false}
contentContainerStyle={styles.scrollContent}
>
{/* Header with Settings */}
<View style={styles.headerRow}>
<View style={styles.headerSpacer} />
<TouchableOpacity style={styles.settingsButton}>
<Ionicons name="moon-outline" size={20} color={colors.me.primary} />
</TouchableOpacity>
</View>
{/* Profile Card */}
<TouchableOpacity
style={styles.profileCard}
@@ -311,15 +410,23 @@ export default function MeScreen() {
))}
</View>
{/* Abandon Island Button (Logout for now) */}
<TouchableOpacity
style={styles.abandonButton}
onPress={handleAbandonIsland}
activeOpacity={0.8}
>
<Feather name="log-out" size={18} color={colors.nautical.coral} />
<Text style={styles.abandonButtonText}>SIGN OUT</Text>
</TouchableOpacity>
{/* Fleet Legacy - Single Entry Point */}
<Text style={styles.sectionTitle}>FLEET LEGACY</Text>
<View style={styles.menuCard}>
<TouchableOpacity
style={styles.menuItem}
onPress={() => setShowHeritageModal(true)}
>
<View style={[styles.menuIconContainer, { backgroundColor: `${colors.nautical.teal}20` }]}>
<MaterialCommunityIcons name="compass-outline" size={22} color={colors.nautical.teal} />
</View>
<View style={styles.menuContent}>
<Text style={styles.menuTitle}>Manage Heirs</Text>
<Text style={styles.menuSubtitle}>{heirs.length} trustees configured</Text>
</View>
<Feather name="chevron-right" size={18} color={colors.me.textSecondary} />
</TouchableOpacity>
</View>
{/* Settings Menu */}
<Text style={styles.sectionTitle}>SETTINGS</Text>
@@ -335,6 +442,9 @@ export default function MeScreen() {
if (item.id === 'trigger') {
setShowTriggerModal(true);
}
if (item.id === 'visual') {
setShowThemeModal(true);
}
}}
>
<View style={[styles.menuIconContainer, { backgroundColor: `${item.color}15` }]}>
@@ -349,44 +459,83 @@ export default function MeScreen() {
))}
</View>
{/* About Section */}
{/* About Section - Vertical List */}
<Text style={styles.sectionTitle}>ABOUT</Text>
<View style={styles.aboutGrid}>
{protocolExplainers.slice(0, 2).map((item) => (
<View style={styles.menuCard}>
{protocolExplainers.map((item, index) => (
<TouchableOpacity
key={item.id}
style={styles.aboutCard}
style={[
styles.menuItem,
index < protocolExplainers.length - 1 && styles.menuItemBorder
]}
onPress={() => setSelectedExplainer(item)}
>
<MaterialCommunityIcons name={item.icon as any} size={24} color={colors.me.primary} />
<Text style={styles.aboutTitle}>{item.title}</Text>
<Feather name="arrow-up-right" size={14} color={colors.me.textSecondary} />
<View style={[styles.menuIconContainer, { backgroundColor: `${colors.me.primary}15` }]}>
<MaterialCommunityIcons name={item.icon as any} size={20} color={colors.me.primary} />
</View>
<View style={styles.menuContent}>
<Text style={styles.menuTitle}>{item.title}</Text>
</View>
<Feather name="chevron-right" size={18} color={colors.me.textSecondary} />
</TouchableOpacity>
))}
<TouchableOpacity
style={[styles.menuItem, styles.menuItemBorder]}
onPress={() => handleOpenLink('https://github.com/sentinel')}
>
<View style={[styles.menuIconContainer, { backgroundColor: `${colors.nautical.navy}15` }]}>
<Ionicons name="logo-github" size={20} color={colors.nautical.navy} />
</View>
<View style={styles.menuContent}>
<Text style={styles.menuTitle}>GitHub</Text>
<Text style={styles.menuSubtitle}>View source code</Text>
</View>
<Feather name="external-link" size={16} color={colors.me.textSecondary} />
</TouchableOpacity>
<TouchableOpacity
style={[styles.menuItem, styles.menuItemBorder]}
onPress={() => handleOpenLink('https://sentinel.app/privacy')}
>
<View style={[styles.menuIconContainer, { backgroundColor: `${colors.nautical.sage}15` }]}>
<Ionicons name="shield-checkmark-outline" size={20} color={colors.nautical.sage} />
</View>
<View style={styles.menuContent}>
<Text style={styles.menuTitle}>Privacy Policy</Text>
</View>
<Feather name="external-link" size={16} color={colors.me.textSecondary} />
</TouchableOpacity>
<TouchableOpacity
style={styles.menuItem}
onPress={() => handleOpenLink('https://sentinel.app/terms')}
>
<View style={[styles.menuIconContainer, { backgroundColor: `${colors.nautical.sage}15` }]}>
<Ionicons name="document-text-outline" size={20} color={colors.nautical.sage} />
</View>
<View style={styles.menuContent}>
<Text style={styles.menuTitle}>Terms of Service</Text>
</View>
<Feather name="external-link" size={16} color={colors.me.textSecondary} />
</TouchableOpacity>
</View>
{/* Sign Out Button */}
<TouchableOpacity
style={styles.abandonButton}
onPress={handleAbandonIsland}
activeOpacity={0.8}
>
<Feather name="log-out" size={18} color={colors.nautical.coral} />
<Text style={styles.abandonButtonText}>SIGN OUT</Text>
</TouchableOpacity>
{/* Footer */}
<View style={styles.footer}>
<Text style={styles.footerVersion}>A E T E R N A N A U T I C A V 2 . 0</Text>
{/* <Text style={styles.footerVersion}>A E T E R N A N A U T I C A V 2 . 0</Text> */}
<Text style={styles.footerTagline}>
The sea claims what is forgotten, but the Sanctuary keeps what is loved.
</Text>
</View>
{/* Footer Links */}
<View style={styles.footerLinks}>
<TouchableOpacity onPress={() => handleOpenLink('https://github.com/sentinel')}>
<Text style={styles.footerLink}>GitHub</Text>
</TouchableOpacity>
<Text style={styles.footerDot}>·</Text>
<TouchableOpacity onPress={() => handleOpenLink('https://sentinel.app/privacy')}>
<Text style={styles.footerLink}>Privacy</Text>
</TouchableOpacity>
<Text style={styles.footerDot}>·</Text>
<TouchableOpacity onPress={() => handleOpenLink('https://sentinel.app/terms')}>
<Text style={styles.footerLink}>Terms</Text>
</TouchableOpacity>
</View>
</ScrollView>
</SafeAreaView>
</LinearGradient>
@@ -427,6 +576,114 @@ export default function MeScreen() {
</View>
</Modal>
{/* Heritage Modal - Full HeritageScreen */}
<Modal
visible={showHeritageModal}
animationType="slide"
onRequestClose={() => setShowHeritageModal(false)}
>
<View style={styles.heritageModalContainer}>
<HeritageScreen />
<TouchableOpacity
style={styles.heritageCloseButton}
onPress={() => setShowHeritageModal(false)}
activeOpacity={0.85}
>
<Ionicons name="close" size={20} color={colors.nautical.cream} />
</TouchableOpacity>
</View>
</Modal>
{/* Theme Settings Modal */}
<Modal
visible={showThemeModal}
animationType="fade"
transparent
onRequestClose={() => setShowThemeModal(false)}
>
<View style={styles.spiritOverlay}>
<View style={styles.spiritModal}>
<View style={styles.spiritHeader}>
<View style={styles.spiritIcon}>
<MaterialCommunityIcons name="palette-outline" size={24} color={colors.me.primary} />
</View>
<Text style={styles.spiritTitle}>Visual Preferences</Text>
</View>
<ScrollView style={styles.spiritScroll} showsVerticalScrollIndicator={false}>
<View style={styles.sanctumSection}>
<Text style={styles.tideLabel}>APPEARANCE</Text>
<TouchableOpacity
style={styles.sanctumToggleRow}
onPress={() => setIsDarkMode(!isDarkMode)}
activeOpacity={0.85}
>
<View style={{ flexDirection: 'row', alignItems: 'center', gap: spacing.sm }}>
<Ionicons
name={isDarkMode ? 'moon' : 'sunny'}
size={18}
color={colors.me.primary}
/>
<Text style={styles.sanctumText}>Dark Mode</Text>
</View>
<View style={[styles.sanctumToggle, isDarkMode && styles.sanctumToggleOn]}>
<Text style={styles.sanctumToggleText}>{isDarkMode ? 'ON' : 'OFF'}</Text>
</View>
</TouchableOpacity>
</View>
<View style={styles.sanctumSection}>
<Text style={styles.tideLabel}>CARD STYLE</Text>
<View style={styles.tideRow}>
{['Minimal', 'Standard', 'Rich'].map((style) => (
<TouchableOpacity
key={style}
style={[styles.tideButton, style === 'Standard' && styles.tideButtonActive]}
>
<Text style={[styles.tideButtonText, style === 'Standard' && styles.tideButtonTextActive]}>
{style}
</Text>
</TouchableOpacity>
))}
</View>
</View>
<View style={styles.sanctumSection}>
<Text style={styles.tideLabel}>FONT SIZE</Text>
<View style={styles.tideRow}>
{['Small', 'Medium', 'Large'].map((size) => (
<TouchableOpacity
key={size}
style={[styles.tideButton, size === 'Medium' && styles.tideButtonActive]}
>
<Text style={[styles.tideButtonText, size === 'Medium' && styles.tideButtonTextActive]}>
{size}
</Text>
</TouchableOpacity>
))}
</View>
</View>
</ScrollView>
<View style={styles.tideModalButtons}>
<TouchableOpacity
style={styles.confirmPulseButton}
activeOpacity={0.85}
onPress={() => setShowThemeModal(false)}
>
<Ionicons name="checkmark-circle" size={18} color={colors.nautical.teal} />
<Text style={styles.confirmPulseText}>Save</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.confirmPulseButton}
activeOpacity={0.85}
onPress={() => setShowThemeModal(false)}
>
<Ionicons name="close-circle" size={18} color={colors.nautical.teal} />
<Text style={styles.confirmPulseText}>Close</Text>
</TouchableOpacity>
</View>
</View>
</View>
</Modal>
{/* Spirit Keys Modal */}
<Modal
@@ -858,6 +1115,170 @@ export default function MeScreen() {
</View>
</Modal>
{/* Add Heir Modal */}
<Modal
visible={showAddHeirModal}
animationType="slide"
transparent
onRequestClose={() => setShowAddHeirModal(false)}
>
<View style={styles.modalOverlay}>
<View style={styles.modalContent}>
<View style={styles.modalHandle} />
<View style={styles.modalHeader}>
<View style={styles.modalIconContainer}>
<FontAwesome5 name="ship" size={20} color={colors.me.primary} />
</View>
<Text style={styles.modalTitle}>Add to Fleet</Text>
</View>
<Text style={styles.inputLabel}>NAME *</Text>
<TextInput
style={styles.heirInput}
placeholder="Trustee name"
placeholderTextColor={colors.me.textSecondary}
value={newHeirName}
onChangeText={setNewHeirName}
/>
<Text style={styles.inputLabel}>EMAIL *</Text>
<TextInput
style={styles.heirInput}
placeholder="For invitations and notifications"
placeholderTextColor={colors.me.textSecondary}
value={newHeirEmail}
onChangeText={setNewHeirEmail}
keyboardType="email-address"
autoCapitalize="none"
/>
<Text style={styles.inputLabel}>INHERITANCE TIER</Text>
<View style={styles.tideRow}>
{[1, 2, 3].map((level) => (
<TouchableOpacity
key={level}
style={[styles.tideButton, newHeirLevel === level && styles.tideButtonActive]}
onPress={() => setNewHeirLevel(level)}
>
<Text style={[styles.tideButtonText, newHeirLevel === level && styles.tideButtonTextActive]}>
Tier {level}
</Text>
</TouchableOpacity>
))}
</View>
<Text style={styles.inputLabel}>PAYMENT STRATEGY</Text>
<View style={styles.tideRow}>
<TouchableOpacity
style={[styles.tideButton, newHeirPayment === 'prepaid' && styles.tideButtonActive]}
onPress={() => setNewHeirPayment('prepaid')}
>
<Text style={[styles.tideButtonText, newHeirPayment === 'prepaid' && styles.tideButtonTextActive]}>
Prepaid
</Text>
</TouchableOpacity>
<TouchableOpacity
style={[styles.tideButton, newHeirPayment === 'pay_on_access' && styles.tideButtonActive]}
onPress={() => setNewHeirPayment('pay_on_access')}
>
<Text style={[styles.tideButtonText, newHeirPayment === 'pay_on_access' && styles.tideButtonTextActive]}>
Pay on Access
</Text>
</TouchableOpacity>
</View>
<View style={styles.tideModalButtons}>
<TouchableOpacity
style={styles.confirmPulseButton}
onPress={() => {
setShowAddHeirModal(false);
resetAddHeirForm();
}}
>
<Text style={styles.confirmPulseText}>Cancel</Text>
</TouchableOpacity>
<TouchableOpacity
style={[styles.confirmPulseButton, { backgroundColor: colors.nautical.teal }]}
onPress={handleAddHeir}
>
<Feather name="send" size={16} color="#fff" />
<Text style={[styles.confirmPulseText, { color: '#fff' }]}>Send Invitation</Text>
</TouchableOpacity>
</View>
</View>
</View>
</Modal>
{/* Heir Detail Modal */}
<Modal
visible={showHeirDetailModal}
animationType="fade"
transparent
onRequestClose={() => setShowHeirDetailModal(false)}
>
<View style={styles.spiritOverlay}>
<View style={styles.spiritModal}>
{selectedHeir && (
<>
<View style={styles.heirDetailHeader}>
<View style={styles.heirDetailAvatar}>
<FontAwesome5 name="ship" size={28} color={colors.me.primary} />
</View>
<Text style={styles.heirDetailName}>{selectedHeir.name}</Text>
<View style={[
styles.heirStatusBadge,
{ backgroundColor: `${getHeirStatusBadge(selectedHeir.status).color}15` }
]}>
<Ionicons
name={getHeirStatusBadge(selectedHeir.status).icon as any}
size={12}
color={getHeirStatusBadge(selectedHeir.status).color}
/>
<Text style={[styles.heirStatusText, { color: getHeirStatusBadge(selectedHeir.status).color }]}>
{getHeirStatusBadge(selectedHeir.status).text}
</Text>
</View>
</View>
<View style={styles.heirDetailRows}>
<View style={styles.heirDetailRow}>
<Feather name="mail" size={16} color={colors.me.textSecondary} />
<Text style={styles.heirDetailLabel}>Email</Text>
<Text style={styles.heirDetailValue}>{selectedHeir.email}</Text>
</View>
<View style={styles.heirDetailRow}>
<Feather name="hash" size={16} color={colors.me.textSecondary} />
<Text style={styles.heirDetailLabel}>Order</Text>
<Text style={styles.heirDetailValue}>#{selectedHeir.releaseOrder}</Text>
</View>
<View style={styles.heirDetailRow}>
<Feather name="layers" size={16} color={colors.me.textSecondary} />
<Text style={styles.heirDetailLabel}>Tier</Text>
<Text style={styles.heirDetailValue}>
{selectedHeir.releaseLevel} · {releaseLevelConfig[selectedHeir.releaseLevel].label}
</Text>
</View>
<View style={styles.heirDetailRow}>
<FontAwesome5 name="coins" size={14} color={colors.me.textSecondary} />
<Text style={styles.heirDetailLabel}>Payment</Text>
<Text style={styles.heirDetailValue}>
{selectedHeir.paymentStrategy === 'prepaid' ? 'Prepaid' : 'Pay on Access'}
</Text>
</View>
</View>
<TouchableOpacity
style={styles.closeButton}
onPress={() => setShowHeirDetailModal(false)}
>
<Text style={styles.closeButtonText}>Close</Text>
</TouchableOpacity>
</>
)}
</View>
</View>
</Modal>
{/* Trigger Logic Modal */}
<Modal
visible={showTriggerModal}
@@ -1010,28 +1431,9 @@ const styles = StyleSheet.create({
},
scrollContent: {
paddingHorizontal: spacing.base,
paddingTop: spacing.md,
paddingBottom: 100,
},
// Header
headerRow: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
paddingTop: spacing.sm,
paddingBottom: spacing.md,
},
headerSpacer: {
width: 40,
},
settingsButton: {
width: 40,
height: 40,
borderRadius: 20,
backgroundColor: colors.me.cardBackground,
justifyContent: 'center',
alignItems: 'center',
...shadows.soft,
},
// Profile Card
profileCard: {
backgroundColor: colors.me.cardBackground,
@@ -1760,4 +2162,175 @@ const styles = StyleSheet.create({
color: colors.me.primary,
fontWeight: '600',
},
// Fleet Legacy styles
fleetLegalNotice: {
flexDirection: 'row',
backgroundColor: colors.me.cardBackground,
borderRadius: borderRadius.xl,
padding: spacing.base,
marginBottom: spacing.md,
borderLeftWidth: 4,
borderLeftColor: colors.nautical.teal,
...shadows.soft,
},
fleetLegalIcon: {
marginRight: spacing.md,
},
fleetLegalContent: {
flex: 1,
},
fleetLegalTitle: {
fontSize: typography.fontSize.base,
fontWeight: '600',
color: colors.me.text,
marginBottom: spacing.xs,
},
fleetLegalText: {
fontSize: typography.fontSize.sm,
color: colors.me.textSecondary,
lineHeight: typography.fontSize.sm * 1.5,
},
fleetHeader: {
flexDirection: 'row',
alignItems: 'center',
gap: spacing.sm,
padding: spacing.base,
borderBottomWidth: 1,
borderBottomColor: colors.me.cardBorder,
},
fleetHeaderTitle: {
flex: 1,
fontSize: typography.fontSize.xs,
fontWeight: '700',
color: colors.me.textSecondary,
letterSpacing: typography.letterSpacing.widest,
},
fleetCountBadge: {
backgroundColor: colors.nautical.lightMint,
paddingHorizontal: spacing.sm,
paddingVertical: 4,
borderRadius: borderRadius.full,
},
fleetCountText: {
fontSize: typography.fontSize.xs,
fontWeight: '600',
color: colors.nautical.teal,
},
heirAvatar: {
width: 44,
height: 44,
borderRadius: 22,
backgroundColor: colors.nautical.lightMint,
justifyContent: 'center',
alignItems: 'center',
marginRight: spacing.md,
},
heirNameRow: {
flexDirection: 'row',
alignItems: 'center',
gap: spacing.sm,
},
heirStatusBadge: {
flexDirection: 'row',
alignItems: 'center',
gap: 4,
paddingHorizontal: spacing.sm,
paddingVertical: 2,
borderRadius: borderRadius.full,
},
heirStatusText: {
fontSize: typography.fontSize.xs,
fontWeight: '600',
},
addTrusteeButton: {
borderRadius: borderRadius.lg,
overflow: 'hidden',
marginBottom: spacing.md,
...shadows.soft,
},
addTrusteeGradient: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
paddingVertical: spacing.md,
gap: spacing.sm,
},
addTrusteeText: {
fontSize: typography.fontSize.base,
fontWeight: '700',
color: '#fff',
},
inputLabel: {
fontSize: typography.fontSize.xs,
color: colors.me.textSecondary,
marginBottom: spacing.xs,
marginTop: spacing.md,
fontWeight: '600',
letterSpacing: typography.letterSpacing.wide,
},
heirInput: {
backgroundColor: colors.nautical.paleAqua,
borderRadius: borderRadius.lg,
padding: spacing.base,
fontSize: typography.fontSize.base,
color: colors.me.text,
borderWidth: 1,
borderColor: colors.me.cardBorder,
},
heirDetailHeader: {
alignItems: 'center',
marginBottom: spacing.lg,
paddingBottom: spacing.md,
borderBottomWidth: 1,
borderBottomColor: colors.me.cardBorder,
},
heirDetailAvatar: {
width: 72,
height: 72,
borderRadius: 36,
backgroundColor: colors.nautical.lightMint,
justifyContent: 'center',
alignItems: 'center',
marginBottom: spacing.md,
},
heirDetailName: {
fontSize: typography.fontSize.lg,
fontWeight: '600',
color: colors.me.text,
marginBottom: spacing.sm,
},
heirDetailRows: {
gap: spacing.md,
},
heirDetailRow: {
flexDirection: 'row',
alignItems: 'center',
gap: spacing.sm,
},
heirDetailLabel: {
flex: 1,
fontSize: typography.fontSize.base,
color: colors.me.textSecondary,
},
heirDetailValue: {
fontSize: typography.fontSize.base,
color: colors.me.text,
fontWeight: '600',
},
// Heritage Modal
heritageModalContainer: {
flex: 1,
},
heritageCloseButton: {
position: 'absolute',
top: spacing.xl + spacing.lg,
right: spacing.lg,
width: 36,
height: 36,
borderRadius: 18,
backgroundColor: 'rgba(26, 58, 74, 0.65)',
alignItems: 'center',
justifyContent: 'center',
zIndex: 10,
},
});

View File

@@ -7,11 +7,13 @@ import {
TouchableOpacity,
SafeAreaView,
Animated,
Modal,
} 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 { SystemStatus, KillSwitchLog } from '../types';
import VaultScreen from './VaultScreen';
// Status configuration with nautical theme
const statusConfig: Record<SystemStatus, {
@@ -76,6 +78,7 @@ export default function SentinelScreen() {
const [pulseAnim] = useState(new Animated.Value(1));
const [glowAnim] = useState(new Animated.Value(0.5));
const [rotateAnim] = useState(new Animated.Value(0));
const [showVault, setShowVault] = useState(false);
useEffect(() => {
// Pulse animation
@@ -270,6 +273,26 @@ export default function SentinelScreen() {
</View>
</View>
{/* Shadow Vault Access */}
<View style={styles.vaultAccessCard}>
<View style={styles.vaultAccessIcon}>
<MaterialCommunityIcons name="treasure-chest" size={22} color={colors.nautical.teal} />
</View>
<View style={styles.vaultAccessContent}>
<Text style={styles.vaultAccessTitle}>Shadow Vault</Text>
<Text style={styles.vaultAccessText}>
Access sealed assets from the Lighthouse.
</Text>
</View>
<TouchableOpacity
style={styles.vaultAccessButton}
onPress={() => setShowVault(true)}
activeOpacity={0.8}
>
<Text style={styles.vaultAccessButtonText}>Open</Text>
</TouchableOpacity>
</View>
{/* Heartbeat Button */}
<TouchableOpacity
style={styles.heartbeatButton}
@@ -313,6 +336,24 @@ export default function SentinelScreen() {
</ScrollView>
</SafeAreaView>
</LinearGradient>
{/* Vault Modal */}
<Modal
visible={showVault}
animationType="slide"
onRequestClose={() => setShowVault(false)}
>
<View style={styles.vaultModalContainer}>
<VaultScreen />
<TouchableOpacity
style={styles.vaultCloseButton}
onPress={() => setShowVault(false)}
activeOpacity={0.85}
>
<Ionicons name="close" size={20} color={colors.nautical.cream} />
</TouchableOpacity>
</View>
</Modal>
</View>
);
}
@@ -513,4 +554,64 @@ const styles = StyleSheet.create({
color: colors.sentinel.textSecondary,
fontFamily: typography.fontFamily.mono,
},
// Shadow Vault Access Card
vaultAccessCard: {
flexDirection: 'row',
alignItems: 'center',
backgroundColor: colors.sentinel.cardBackground,
borderRadius: borderRadius.xl,
padding: spacing.base,
marginBottom: spacing.lg,
borderWidth: 1,
borderColor: colors.sentinel.cardBorder,
},
vaultAccessIcon: {
width: 44,
height: 44,
borderRadius: 22,
backgroundColor: `${colors.nautical.teal}20`,
alignItems: 'center',
justifyContent: 'center',
marginRight: spacing.md,
},
vaultAccessContent: {
flex: 1,
},
vaultAccessTitle: {
fontSize: typography.fontSize.base,
fontWeight: '600',
color: colors.sentinel.text,
marginBottom: 2,
},
vaultAccessText: {
fontSize: typography.fontSize.sm,
color: colors.sentinel.textSecondary,
},
vaultAccessButton: {
backgroundColor: colors.nautical.teal,
paddingHorizontal: spacing.md,
paddingVertical: spacing.sm,
borderRadius: borderRadius.full,
},
vaultAccessButtonText: {
color: colors.nautical.cream,
fontWeight: '700',
fontSize: typography.fontSize.sm,
},
// Vault Modal
vaultModalContainer: {
flex: 1,
backgroundColor: colors.vault.background,
},
vaultCloseButton: {
position: 'absolute',
top: spacing.xl + spacing.lg,
right: spacing.lg,
width: 36,
height: 36,
borderRadius: 18,
backgroundColor: 'rgba(26, 58, 74, 0.65)',
alignItems: 'center',
justifyContent: 'center',
},
});