Bluesky app fork with some witchin' additions 馃挮
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 135 lines 4.8 kB view raw
1import {useState} from 'react' 2import {LayoutAnimation, Pressable, View} from 'react-native' 3import {msg} from '@lingui/core/macro' 4import {useLingui} from '@lingui/react' 5import {Trans} from '@lingui/react/macro' 6 7import {useGetTimeAgo} from '#/lib/hooks/useTimeAgo' 8import { 9 type CommonNavigatorParams, 10 type NativeStackScreenProps, 11} from '#/lib/routes/types' 12import {getEntries} from '#/logger/logDump' 13import {useTickEveryMinute} from '#/state/shell' 14import {atoms as a, useTheme} from '#/alf' 15import { 16 ChevronBottom_Stroke2_Corner0_Rounded as ChevronBottomIcon, 17 ChevronTop_Stroke2_Corner0_Rounded as ChevronTopIcon, 18} from '#/components/icons/Chevron' 19import {CircleInfo_Stroke2_Corner0_Rounded as CircleInfoIcon} from '#/components/icons/CircleInfo' 20import {Warning_Stroke2_Corner0_Rounded as WarningIcon} from '#/components/icons/Warning' 21import * as Layout from '#/components/Layout' 22import {Text} from '#/components/Typography' 23 24export function LogScreen({}: NativeStackScreenProps< 25 CommonNavigatorParams, 26 'Log' 27>) { 28 const t = useTheme() 29 const {_} = useLingui() 30 const [expanded, setExpanded] = useState<string[]>([]) 31 const timeAgo = useGetTimeAgo() 32 const tick = useTickEveryMinute() 33 34 const toggler = (id: string) => () => { 35 LayoutAnimation.configureNext(LayoutAnimation.Presets.easeInEaseOut) 36 if (expanded.includes(id)) { 37 setExpanded(expanded.filter(v => v !== id)) 38 } else { 39 setExpanded([...expanded, id]) 40 } 41 } 42 43 return ( 44 <Layout.Screen> 45 <Layout.Header.Outer> 46 <Layout.Header.BackButton /> 47 <Layout.Header.Content> 48 <Layout.Header.TitleText> 49 <Trans>System log</Trans> 50 </Layout.Header.TitleText> 51 </Layout.Header.Content> 52 <Layout.Header.Slot /> 53 </Layout.Header.Outer> 54 <Layout.Content> 55 {getEntries() 56 .slice(0) 57 .map(entry => { 58 return ( 59 <View key={`entry-${entry.id}`}> 60 <Pressable 61 style={[ 62 a.flex_row, 63 a.align_center, 64 a.py_md, 65 a.px_sm, 66 a.border_b, 67 t.atoms.border_contrast_low, 68 t.atoms.bg, 69 a.gap_sm, 70 ]} 71 onPress={toggler(entry.id)} 72 accessibilityLabel={_(msg`View debug entry`)} 73 accessibilityHint={_( 74 msg`Opens additional details for a debug entry`, 75 )}> 76 {entry.level === 'warn' || entry.level === 'error' ? ( 77 <WarningIcon size="sm" fill={t.palette.negative_500} /> 78 ) : ( 79 <CircleInfoIcon size="sm" /> 80 )} 81 <View 82 style={[ 83 a.flex_1, 84 a.flex_row, 85 a.justify_start, 86 a.align_center, 87 a.gap_sm, 88 ]}> 89 {entry.context && ( 90 <Text style={[t.atoms.text_contrast_medium]}> 91 ({String(entry.context)}) 92 </Text> 93 )} 94 <Text>{String(entry.message)}</Text> 95 </View> 96 {entry.metadata && 97 Object.keys(entry.metadata).length > 0 && 98 (expanded.includes(entry.id) ? ( 99 <ChevronTopIcon 100 size="sm" 101 style={[t.atoms.text_contrast_low]} 102 /> 103 ) : ( 104 <ChevronBottomIcon 105 size="sm" 106 style={[t.atoms.text_contrast_low]} 107 /> 108 ))} 109 <Text style={[{minWidth: 40}, t.atoms.text_contrast_medium]}> 110 {timeAgo(entry.timestamp, tick)} 111 </Text> 112 </Pressable> 113 {expanded.includes(entry.id) && ( 114 <View 115 style={[ 116 t.atoms.bg_contrast_25, 117 a.rounded_xs, 118 a.p_sm, 119 a.border_b, 120 t.atoms.border_contrast_low, 121 ]}> 122 <View style={[a.px_sm, a.py_xs]}> 123 <Text style={[a.leading_snug, {fontFamily: 'monospace'}]}> 124 {JSON.stringify(entry.metadata, null, 2)} 125 </Text> 126 </View> 127 </View> 128 )} 129 </View> 130 ) 131 })} 132 </Layout.Content> 133 </Layout.Screen> 134 ) 135}