Bluesky app fork with some witchin' additions 馃挮 witchsky.app
bluesky fork client
119
fork

Configure Feed

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

at a876aae44ea07494ebea9727350aa060b81f317b 187 lines 5.9 kB view raw
1import {useCallback} from 'react' 2import {Pressable, View} from 'react-native' 3import Animated, {useAnimatedRef} from 'react-native-reanimated' 4import {type AppBskyGraphDefs} from '@atproto/api' 5import {msg} from '@lingui/core/macro' 6import {useLingui} from '@lingui/react' 7import {Trans} from '@lingui/react/macro' 8import {useNavigation} from '@react-navigation/native' 9 10import {usePalette} from '#/lib/hooks/usePalette' 11import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries' 12import {makeProfileLink} from '#/lib/routes/links' 13import {type NavigationProp} from '#/lib/routes/types' 14import {sanitizeHandle} from '#/lib/strings/handles' 15import {emitSoftReset} from '#/state/events' 16import {useLightboxControls} from '#/state/lightbox' 17import {TextLink} from '#/view/com/util/Link' 18import {LoadingPlaceholder} from '#/view/com/util/LoadingPlaceholder' 19import {Text} from '#/view/com/util/text/Text' 20import {UserAvatar, type UserAvatarType} from '#/view/com/util/UserAvatar' 21import {StarterPack} from '#/components/icons/StarterPack' 22import * as Layout from '#/components/Layout' 23 24export function ProfileSubpageHeader({ 25 isLoading, 26 href, 27 title, 28 avatar, 29 isOwner, 30 purpose, 31 creator, 32 avatarType, 33 children, 34}: React.PropsWithChildren<{ 35 isLoading?: boolean 36 href: string 37 title: string | undefined 38 avatar: string | undefined 39 isOwner: boolean | undefined 40 purpose: AppBskyGraphDefs.ListPurpose | undefined 41 creator: 42 | { 43 did: string 44 handle: string 45 } 46 | undefined 47 avatarType: UserAvatarType | 'starter-pack' 48}>) { 49 const navigation = useNavigation<NavigationProp>() 50 const {_} = useLingui() 51 const {isMobile} = useWebMediaQueries() 52 const {openLightbox} = useLightboxControls() 53 const pal = usePalette('default') 54 const canGoBack = navigation.canGoBack() 55 const aviRef = useAnimatedRef() 56 57 const onPressAvi = useCallback(() => { 58 if ( 59 avatar // TODO && !(view.moderation.avatar.blur && view.moderation.avatar.noOverride) 60 ) { 61 openLightbox({ 62 images: [ 63 { 64 uri: avatar, 65 thumbUri: avatar, 66 thumbRect: null, 67 thumbRef: aviRef, 68 dimensions: { 69 // It's fine if it's actually smaller but we know it's 1:1. 70 height: 1000, 71 width: 1000, 72 }, 73 thumbDimensions: null, 74 type: 'rect-avi', 75 }, 76 ], 77 index: 0, 78 }) 79 } 80 }, [openLightbox, avatar, aviRef]) 81 82 return ( 83 <> 84 <Layout.Header.Outer> 85 {canGoBack ? ( 86 <Layout.Header.BackButton /> 87 ) : ( 88 <Layout.Header.MenuButton /> 89 )} 90 <Layout.Header.Content /> 91 {children} 92 </Layout.Header.Outer> 93 94 <View 95 style={{ 96 flexDirection: 'row', 97 alignItems: 'flex-start', 98 gap: 10, 99 paddingTop: 14, 100 paddingBottom: 14, 101 paddingHorizontal: isMobile ? 12 : 14, 102 }}> 103 <Animated.View ref={aviRef} collapsable={false}> 104 <Pressable 105 testID="headerAviButton" 106 onPress={onPressAvi} 107 accessibilityRole="image" 108 accessibilityLabel={_(msg`View the avatar`)} 109 accessibilityHint="" 110 style={{width: 58}}> 111 {avatarType === 'starter-pack' ? ( 112 <StarterPack width={58} gradient="sky" /> 113 ) : ( 114 <UserAvatar type={avatarType} size={58} avatar={avatar} /> 115 )} 116 </Pressable> 117 </Animated.View> 118 <View style={{flex: 1, gap: 4}}> 119 {isLoading ? ( 120 <LoadingPlaceholder 121 width={200} 122 height={32} 123 style={{marginVertical: 6}} 124 /> 125 ) : ( 126 <TextLink 127 testID="headerTitle" 128 type="title-xl" 129 href={href} 130 style={[pal.text, {fontWeight: '600'}]} 131 text={title || ''} 132 onPress={emitSoftReset} 133 numberOfLines={4} 134 /> 135 )} 136 137 {isLoading || !creator ? ( 138 <LoadingPlaceholder width={50} height={8} /> 139 ) : ( 140 <Text type="lg" style={[pal.textLight]} numberOfLines={1}> 141 {purpose === 'app.bsky.graph.defs#curatelist' ? ( 142 isOwner ? ( 143 <Trans>List by you</Trans> 144 ) : ( 145 <Trans> 146 List by{' '} 147 <TextLink 148 text={sanitizeHandle(creator.handle || '', '@')} 149 href={makeProfileLink(creator)} 150 style={pal.textLight} 151 /> 152 </Trans> 153 ) 154 ) : purpose === 'app.bsky.graph.defs#modlist' ? ( 155 isOwner ? ( 156 <Trans>Moderation list by you</Trans> 157 ) : ( 158 <Trans> 159 Moderation list by{' '} 160 <TextLink 161 text={sanitizeHandle(creator.handle || '', '@')} 162 href={makeProfileLink(creator)} 163 style={pal.textLight} 164 /> 165 </Trans> 166 ) 167 ) : purpose === 'app.bsky.graph.defs#referencelist' ? ( 168 isOwner ? ( 169 <Trans>Starter pack by you</Trans> 170 ) : ( 171 <Trans> 172 Starter pack by{' '} 173 <TextLink 174 text={sanitizeHandle(creator.handle || '', '@')} 175 href={makeProfileLink(creator)} 176 style={pal.textLight} 177 /> 178 </Trans> 179 ) 180 ) : null} 181 </Text> 182 )} 183 </View> 184 </View> 185 </> 186 ) 187}