1/** 2 * Copyright (c) 650 Industries. 3 * Copyright (c) Meta Platforms, Inc. and affiliates. 4 * 5 * This source code is licensed under the MIT license found in the 6 * LICENSE file in the root directory of this source tree. 7 */ 8import React from 'react'; 9import { Image, Platform, StatusBar, StyleSheet, Text, View } from 'react-native'; 10 11import type { LogLevel } from '../Data/LogBoxLog'; 12import { useLogs } from '../Data/LogContext'; 13import { LogBoxButton } from '../UI/LogBoxButton'; 14import * as LogBoxStyle from '../UI/LogBoxStyle'; 15 16type Props = { 17 onSelectIndex: (selectedIndex: number) => void; 18 level: LogLevel; 19}; 20 21export function LogBoxInspectorHeader(props: Props) { 22 const { selectedLogIndex: selectedIndex, logs } = useLogs(); 23 const total = logs.length; 24 25 if (props.level === 'syntax') { 26 return ( 27 <View style={[styles.safeArea, styles[props.level]]}> 28 <View style={styles.header}> 29 <View style={styles.title}> 30 <Text style={styles.titleText}>Failed to compile</Text> 31 </View> 32 </View> 33 </View> 34 ); 35 } 36 37 const prevIndex = selectedIndex - 1 < 0 ? total - 1 : selectedIndex - 1; 38 const nextIndex = selectedIndex + 1 > total - 1 ? 0 : selectedIndex + 1; 39 40 const titleText = `Log ${selectedIndex + 1} of ${total}`; 41 42 return ( 43 <View style={[styles.safeArea, styles[props.level]]}> 44 <View style={styles.header}> 45 <LogBoxInspectorHeaderButton 46 disabled={total <= 1} 47 level={props.level} 48 image={require('@expo/metro-runtime/assets/chevron-left.png')} 49 onPress={() => props.onSelectIndex(prevIndex)} 50 /> 51 <View style={styles.title}> 52 <Text style={styles.titleText}>{titleText}</Text> 53 </View> 54 <LogBoxInspectorHeaderButton 55 disabled={total <= 1} 56 level={props.level} 57 image={require('@expo/metro-runtime/assets/chevron-right.png')} 58 onPress={() => props.onSelectIndex(nextIndex)} 59 /> 60 </View> 61 </View> 62 ); 63} 64 65const backgroundForLevel = (level: LogLevel) => 66 ({ 67 warn: { 68 default: 'transparent', 69 pressed: LogBoxStyle.getWarningDarkColor(), 70 }, 71 error: { 72 default: 'transparent', 73 pressed: LogBoxStyle.getErrorDarkColor(), 74 }, 75 fatal: { 76 default: 'transparent', 77 pressed: LogBoxStyle.getFatalDarkColor(), 78 }, 79 syntax: { 80 default: 'transparent', 81 pressed: LogBoxStyle.getFatalDarkColor(), 82 }, 83 static: { 84 default: 'transparent', 85 pressed: LogBoxStyle.getFatalDarkColor(), 86 }, 87 })[level]; 88 89function LogBoxInspectorHeaderButton(props: { 90 disabled: boolean; 91 image: number; 92 level: LogLevel; 93 onPress?: () => void; 94}) { 95 return ( 96 <LogBoxButton 97 backgroundColor={backgroundForLevel(props.level)} 98 onPress={props.disabled ? undefined : props.onPress} 99 style={headerStyles.button}> 100 {props.disabled ? null : ( 101 <Image 102 source={props.image} 103 tintColor={LogBoxStyle.getTextColor()} 104 style={headerStyles.buttonImage} 105 /> 106 )} 107 </LogBoxButton> 108 ); 109} 110 111const headerStyles = StyleSheet.create({ 112 button: { 113 alignItems: 'center', 114 justifyContent: 'center', 115 aspectRatio: 1, 116 marginRight: 6, 117 marginLeft: 6, 118 borderRadius: 3, 119 }, 120 buttonImage: { 121 height: 14, 122 width: 8, 123 }, 124}); 125 126const styles = StyleSheet.create({ 127 syntax: { 128 backgroundColor: LogBoxStyle.getFatalColor(), 129 }, 130 static: { 131 backgroundColor: LogBoxStyle.getFatalColor(), 132 }, 133 fatal: { 134 backgroundColor: LogBoxStyle.getFatalColor(), 135 }, 136 warn: { 137 backgroundColor: LogBoxStyle.getWarningColor(), 138 }, 139 error: { 140 backgroundColor: LogBoxStyle.getErrorColor(), 141 }, 142 header: { 143 flexDirection: 'row', 144 alignItems: 'center', 145 146 paddingHorizontal: 8, 147 height: Platform.select({ 148 default: 48, 149 ios: 44, 150 }), 151 }, 152 title: { 153 alignItems: 'center', 154 flex: 1, 155 justifyContent: 'center', 156 }, 157 titleText: { 158 color: LogBoxStyle.getTextColor(), 159 fontSize: 16, 160 fontWeight: '600', 161 includeFontPadding: false, 162 lineHeight: 20, 163 }, 164 safeArea: { 165 paddingTop: Platform.OS !== 'ios' ? StatusBar.currentHeight : 40, 166 }, 167}); 168