Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

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

chore: move PdsBadge to ProfileBadges

xan.lol 3b1907bd 5c2c9b2e

+156 -229
-2
src/components/AccountList.tsx
··· 17 17 import {CheckThick_Stroke2_Corner0_Rounded as CheckIcon} from '#/components/icons/Check' 18 18 import {ChevronRight_Stroke2_Corner0_Rounded as ChevronIcon} from '#/components/icons/Chevron' 19 19 import {PlusLarge_Stroke2_Corner0_Rounded as PlusIcon} from '#/components/icons/Plus' 20 - import {PdsBadge} from '#/components/PdsBadge' 21 20 import {ProfileBadges} from '#/components/ProfileBadges' 22 21 import {Text} from '#/components/Typography' 23 22 import {useActorStatus} from '#/features/liveNow' ··· 168 167 profile?.displayName || profile?.handle || account.handle, 169 168 )} 170 169 </Text> 171 - <PdsBadge did={account.did} size="sm" /> 172 170 {profile && ( 173 171 <ProfileBadges 174 172 profile={profile}
-171
src/components/PdsBadge.tsx
··· 1 - import {View} from 'react-native' 2 - import {msg} from '@lingui/core/macro' 3 - import {useLingui} from '@lingui/react' 4 - 5 - import { 6 - usePdsLabelEnabled, 7 - usePdsLabelHideBskyPds, 8 - } from '#/state/preferences/pds-label' 9 - import {usePdsFaviconQuery, usePdsLabelQuery} from '#/state/queries/pds-label' 10 - import {atoms as a, useBreakpoints} from '#/alf' 11 - import {Button} from '#/components/Button' 12 - import * as Dialog from '#/components/Dialog' 13 - import {PdsBadgeIcon, PdsDialog} from '#/components/PdsDialog' 14 - import {IS_WEB} from '#/env' 15 - 16 - export function PdsBadge({ 17 - did, 18 - handle, 19 - size, 20 - interactive = true, 21 - }: { 22 - did: string 23 - handle?: string 24 - size: 'lg' | 'md' | 'sm' 25 - interactive?: boolean 26 - }) { 27 - const enabled = usePdsLabelEnabled() 28 - const hideBskyPds = usePdsLabelHideBskyPds() 29 - const {data, isLoading} = usePdsLabelQuery(enabled ? did : undefined) 30 - const {data: faviconUrl} = usePdsFaviconQuery( 31 - data && !data.isBsky && !data.isBridged ? data.pdsUrl : undefined, 32 - ) 33 - 34 - const isBskyHandle = 35 - !!handle && (handle.endsWith('.bsky.social') || handle === 'bsky.social') 36 - 37 - if (!enabled) return null 38 - if (isLoading) return <PdsBadgeLoading size={size} isBsky={isBskyHandle} /> 39 - if (!data) return null 40 - if (hideBskyPds && data.isBsky) return null 41 - 42 - return ( 43 - <PdsBadgeInner 44 - pdsUrl={data.pdsUrl} 45 - faviconUrl={faviconUrl} 46 - isBsky={data.isBsky} 47 - isBridged={data.isBridged} 48 - size={size} 49 - interactive={interactive} 50 - /> 51 - ) 52 - } 53 - 54 - function PdsBadgeLoading({ 55 - size, 56 - isBsky = false, 57 - }: { 58 - size: 'lg' | 'md' | 'sm' 59 - isBsky?: boolean 60 - }) { 61 - const {gtPhone} = useBreakpoints() 62 - let dimensions = 12 63 - if (size === 'lg') { 64 - dimensions = gtPhone ? 20 : 18 65 - } else if (size === 'md') { 66 - dimensions = 14 67 - } 68 - return ( 69 - <View style={{width: dimensions, height: dimensions}}> 70 - <PdsBadgeIcon 71 - faviconUrl={undefined} 72 - isBsky={isBsky} 73 - isBridged={false} 74 - size={dimensions} 75 - borderRadius={Math.round(dimensions * 0.25)} 76 - /> 77 - </View> 78 - ) 79 - } 80 - 81 - function PdsBadgeInner({ 82 - pdsUrl, 83 - faviconUrl, 84 - isBsky, 85 - isBridged, 86 - size, 87 - interactive, 88 - }: { 89 - pdsUrl: string 90 - faviconUrl: string | undefined 91 - isBsky: boolean 92 - isBridged: boolean 93 - size: 'lg' | 'md' | 'sm' 94 - interactive: boolean 95 - }) { 96 - const {_} = useLingui() 97 - const {gtPhone} = useBreakpoints() 98 - const dialogControl = Dialog.useDialogControl() 99 - 100 - let dimensions = 12 101 - if (size === 'lg') { 102 - dimensions = gtPhone ? 20 : 18 103 - } else if (size === 'md') { 104 - dimensions = 14 105 - } 106 - 107 - const icon = ( 108 - <PdsBadgeIcon 109 - faviconUrl={faviconUrl} 110 - isBsky={isBsky} 111 - isBridged={isBridged} 112 - size={dimensions} 113 - borderRadius={Math.round(dimensions * 0.25)} 114 - /> 115 - ) 116 - 117 - if (!interactive) { 118 - return ( 119 - <View 120 - style={[ 121 - a.justify_center, 122 - a.align_center, 123 - {width: dimensions, height: dimensions}, 124 - ]}> 125 - {icon} 126 - </View> 127 - ) 128 - } 129 - 130 - return ( 131 - <> 132 - <Button 133 - label={_(msg`View PDS information`)} 134 - hitSlop={20} 135 - onPress={evt => { 136 - evt.preventDefault() 137 - dialogControl.open() 138 - if (IS_WEB) { 139 - ;(document.activeElement as HTMLElement | null)?.blur() 140 - } 141 - }}> 142 - {({hovered}) => ( 143 - <View style={{width: dimensions, height: dimensions}}> 144 - <View 145 - style={[ 146 - a.justify_center, 147 - a.align_center, 148 - a.transition_transform, 149 - { 150 - position: 'absolute', 151 - top: 0, 152 - left: 0, 153 - right: 0, 154 - bottom: 0, 155 - transform: [{scale: hovered ? 1.1 : 1}], 156 - }, 157 - ]}> 158 - {icon} 159 - </View> 160 - </View> 161 - )} 162 - </Button> 163 - 164 - <PdsDialog 165 - control={dialogControl} 166 - pdsUrl={pdsUrl} 167 - faviconUrl={faviconUrl} 168 - /> 169 - </> 170 - ) 171 - }
+144
src/components/ProfileBadges.tsx
··· 1 1 import {useWindowDimensions, View} from 'react-native' 2 + import {msg} from '@lingui/core/macro' 3 + import {useLingui} from '@lingui/react' 2 4 3 5 import {useProfileShadow} from '#/state/cache/profile-shadow' 6 + import { 7 + usePdsLabelEnabled, 8 + usePdsLabelHideBskyPds, 9 + } from '#/state/preferences/pds-label' 10 + import {usePdsFaviconQuery, usePdsLabelQuery} from '#/state/queries/pds-label' 4 11 import {atoms as a, useAlf, type ViewStyleProp} from '#/alf' 5 12 import {BotBadge, BotBadgeButton, isBotAccount} from '#/components/BotBadge' 13 + import {Button} from '#/components/Button' 14 + import * as Dialog from '#/components/Dialog' 15 + import {PdsBadgeIcon, PdsDialog} from '#/components/PdsDialog' 6 16 import {isPetAccount, PetBadge, PetBadgeButton} from '#/components/PetBadge' 7 17 import {useSimpleVerificationState} from '#/components/verification' 8 18 import {VerificationCheck} from '#/components/verification/VerificationCheck' 9 19 import {VerificationCheckButton} from '#/components/verification/VerificationCheckButton' 20 + import {IS_WEB} from '#/env' 10 21 import type * as bsky from '#/types/bsky' 11 22 12 23 export type Size = 'xs' | 'sm' | 'md' | 'lg' | 'xl' ··· 30 41 export function ProfileBadges({ 31 42 profile, 32 43 interactive = false, 44 + pdsInteractive = true, 33 45 size, 34 46 style, 35 47 }: ViewStyleProp & { 36 48 profile: bsky.profile.AnyProfileView 37 49 interactive?: boolean 50 + pdsInteractive?: boolean 38 51 size: Size 39 52 }) { 40 53 const shadowed = useProfileShadow(profile) 41 54 const verification = useSimpleVerificationState({profile}) 55 + const pdsLabelEnabled = usePdsLabelEnabled() 56 + const hideBskyPds = usePdsLabelHideBskyPds() 57 + const {data: pdsData, isLoading: isPdsLoading} = usePdsLabelQuery( 58 + pdsLabelEnabled ? shadowed.did : undefined, 59 + ) 60 + const {data: pdsFaviconUrl} = usePdsFaviconQuery( 61 + pdsData && !pdsData.isBsky && !pdsData.isBridged 62 + ? pdsData.pdsUrl 63 + : undefined, 64 + ) 42 65 const {fontScale: nativeScaleMultiplier} = useWindowDimensions() 43 66 const { 44 67 fonts: {scaleMultiplier: alfScaleMultiplier}, 45 68 } = useAlf() 46 69 70 + const isBskyHandle = 71 + !!shadowed.handle && 72 + (shadowed.handle.endsWith('.bsky.social') || 73 + shadowed.handle === 'bsky.social') 74 + 75 + const showPdsBadge = 76 + pdsLabelEnabled && 77 + (isPdsLoading || (!!pdsData && !(hideBskyPds && pdsData.isBsky))) 78 + 47 79 // if nothing to show, don't render the container at all 48 80 if ( 81 + !showPdsBadge && 49 82 !verification.showBadge && 50 83 !isBotAccount(shadowed) && 51 84 !isPetAccount(shadowed) ··· 67 100 isOnTheSmallSide ? a.gap_2xs : a.gap_xs, 68 101 style, 69 102 ]}> 103 + {showPdsBadge && ( 104 + <PdsInlineIcon 105 + size={size} 106 + interactive={pdsInteractive} 107 + isLoading={isPdsLoading} 108 + isBsky={pdsData?.isBsky ?? isBskyHandle} 109 + isBridged={pdsData?.isBridged ?? false} 110 + pdsUrl={pdsData?.pdsUrl} 111 + faviconUrl={pdsFaviconUrl} 112 + /> 113 + )} 70 114 {interactive ? ( 71 115 <> 72 116 <VerificationCheckButton ··· 91 135 </View> 92 136 ) 93 137 } 138 + 139 + function pdsIconDimensions(size: Size) { 140 + switch (size) { 141 + case 'md': 142 + return 14 143 + case 'lg': 144 + return 20 145 + case 'xl': 146 + return 24 147 + default: 148 + return 12 149 + } 150 + } 151 + 152 + function PdsInlineIcon({ 153 + size, 154 + interactive, 155 + isLoading, 156 + isBsky, 157 + isBridged, 158 + pdsUrl, 159 + faviconUrl, 160 + }: { 161 + size: Size 162 + interactive: boolean 163 + isLoading: boolean 164 + isBsky: boolean 165 + isBridged: boolean 166 + pdsUrl?: string 167 + faviconUrl?: string 168 + }) { 169 + const {_} = useLingui() 170 + const dialogControl = Dialog.useDialogControl() 171 + const dimensions = pdsIconDimensions(size) 172 + 173 + const icon = ( 174 + <PdsBadgeIcon 175 + faviconUrl={faviconUrl} 176 + isBsky={isBsky} 177 + isBridged={isBridged} 178 + size={dimensions} 179 + borderRadius={Math.round(dimensions * 0.25)} 180 + /> 181 + ) 182 + 183 + if (isLoading || !pdsUrl || !interactive) { 184 + return ( 185 + <View 186 + style={[ 187 + a.justify_center, 188 + a.align_center, 189 + {width: dimensions, height: dimensions}, 190 + ]}> 191 + {icon} 192 + </View> 193 + ) 194 + } 195 + 196 + return ( 197 + <> 198 + <Button 199 + label={_(msg`View PDS information`)} 200 + hitSlop={20} 201 + onPress={evt => { 202 + evt.preventDefault() 203 + dialogControl.open() 204 + if (IS_WEB) { 205 + ;(document.activeElement as HTMLElement | null)?.blur() 206 + } 207 + }}> 208 + {({hovered}) => ( 209 + <View style={{width: dimensions, height: dimensions}}> 210 + <View 211 + style={[ 212 + a.justify_center, 213 + a.align_center, 214 + a.transition_transform, 215 + { 216 + position: 'absolute', 217 + top: 0, 218 + left: 0, 219 + right: 0, 220 + bottom: 0, 221 + transform: [{scale: hovered ? 1.1 : 1}], 222 + }, 223 + ]}> 224 + {icon} 225 + </View> 226 + </View> 227 + )} 228 + </Button> 229 + 230 + <PdsDialog 231 + control={dialogControl} 232 + pdsUrl={pdsUrl} 233 + faviconUrl={faviconUrl} 234 + /> 235 + </> 236 + ) 237 + }
+1 -14
src/components/ProfileCard.tsx
··· 40 40 import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check' 41 41 import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus' 42 42 import {Link as InternalLink, type LinkProps} from '#/components/Link' 43 - import {PdsBadge} from '#/components/PdsBadge' 44 43 import * as Pills from '#/components/Pills' 45 44 import {ProfileBadges} from '#/components/ProfileBadges' 46 45 import {RichText} from '#/components/RichText' ··· 269 268 a.self_center, 270 269 {marginTop: platform({default: 0, android: -1})}, 271 270 ]}> 272 - <PdsBadge did={profile.did} size="sm" /> 271 + <ProfileBadges profile={profile} size="sm" /> 273 272 </View> 274 - <ProfileBadges 275 - profile={profile} 276 - size="md" 277 - style={[ 278 - a.pl_2xs, 279 - a.self_center, 280 - {marginTop: platform({default: 0, android: -1})}, 281 - ]} 282 - /> 283 273 <Text 284 274 emoji 285 275 style={[ ··· 325 315 numberOfLines={1}> 326 316 {name} 327 317 </Text> 328 - <View style={[a.pl_xs]}> 329 - <PdsBadge did={profile.did} size="sm" /> 330 - </View> 331 318 <ProfileBadges profile={profile} size="md" style={[a.pl_xs]} /> 332 319 </View> 333 320 )
+1 -4
src/components/ProfileHoverCard/index.web.tsx
··· 38 38 } from '#/components/KnownFollowers' 39 39 import {InlineLinkText, Link} from '#/components/Link' 40 40 import {Loader} from '#/components/Loader' 41 - import {PdsBadge} from '#/components/PdsBadge' 42 41 import * as Pills from '#/components/Pills' 43 42 import {Portal} from '#/components/Portal' 44 43 import {ProfileBadges} from '#/components/ProfileBadges' ··· 545 544 moderation.ui('displayName'), 546 545 )} 547 546 </Text> 548 - <View style={[a.pl_xs, {marginTop: -2}]}> 549 - <PdsBadge did={profile.did} size="md" interactive={false} /> 550 - </View> 551 547 <ProfileBadges 552 548 profile={profile} 553 549 size="md" 550 + pdsInteractive={false} 554 551 style={[ 555 552 a.pl_xs, 556 553 {
-4
src/components/dms/MessagesListHeader.tsx
··· 20 20 import * as Layout from '#/components/Layout' 21 21 import {Link} from '#/components/Link' 22 22 import {PostAlerts} from '#/components/moderation/PostAlerts' 23 - import {PdsBadge} from '#/components/PdsBadge' 24 23 import {ProfileBadges} from '#/components/ProfileBadges' 25 24 import {Text} from '#/components/Typography' 26 25 import {IS_WEB} from '#/env' ··· 158 157 numberOfLines={1}> 159 158 {displayName} 160 159 </Text> 161 - <View style={[a.pl_xs]}> 162 - <PdsBadge did={profile.did} size="sm" /> 163 - </View> 164 160 <ProfileBadges profile={profile} size="md" style={[a.pl_xs]} /> 165 161 </View> 166 162 {!isDeletedAccount && (
-4
src/screens/Messages/components/ChatListItem.tsx
··· 41 41 import {Link} from '#/components/Link' 42 42 import {useMenuControl} from '#/components/Menu' 43 43 import {PostAlerts} from '#/components/moderation/PostAlerts' 44 - import {PdsBadge} from '#/components/PdsBadge' 45 44 import {createPortalGroup} from '#/components/Portal' 46 45 import {ProfileBadges} from '#/components/ProfileBadges' 47 46 import {Text} from '#/components/Typography' ··· 414 413 ]}> 415 414 {displayName} 416 415 </Text> 417 - </View> 418 - <View style={[a.pl_xs, a.self_center]}> 419 - <PdsBadge did={profile.did} size="sm" /> 420 416 </View> 421 417 <ProfileBadges 422 418 profile={profile}
-2
src/screens/PostThread/components/ThreadItemAnchor.tsx
··· 48 48 import {ContentHider} from '#/components/moderation/ContentHider' 49 49 import {LabelsOnMyPost} from '#/components/moderation/LabelsOnMe' 50 50 import {PostAlerts} from '#/components/moderation/PostAlerts' 51 - import {PdsBadge} from '#/components/PdsBadge' 52 51 import {type AppModerationCause} from '#/components/Pills' 53 52 import {Embed, PostEmbedViewContext} from '#/components/Post/Embed' 54 53 import {TranslatedPost} from '#/components/Post/Translated' ··· 368 367 369 368 <View 370 369 style={[a.pl_xs, a.flex_row, a.gap_2xs, a.align_center]}> 371 - <PdsBadge did={post.author.did} size="md" /> 372 370 <ProfileBadges 373 371 profile={authorShadow} 374 372 size="md"
+2 -4
src/screens/Profile/Header/DisplayName.tsx
··· 5 5 import {sanitizeHandle} from '#/lib/strings/handles' 6 6 import {type Shadow} from '#/state/cache/types' 7 7 import {atoms as a, platform, useBreakpoints, useTheme} from '#/alf' 8 - import {PdsBadge} from '#/components/PdsBadge' 8 + import {ProfileBadges} from '#/components/ProfileBadges' 9 9 import {Text} from '#/components/Typography' 10 - import {VerificationCheckButton} from '#/components/verification/VerificationCheckButton' 11 10 12 11 export function ProfileHeaderDisplayName({ 13 12 profile, ··· 44 43 marginTop: platform({ios: 2}), 45 44 }, 46 45 ]}> 47 - <PdsBadge did={profile.did} size="lg" /> 48 - <VerificationCheckButton profile={profile} size="lg" /> 46 + <ProfileBadges profile={profile} size="lg" interactive /> 49 47 </View> 50 48 </Text> 51 49 </View>
-2
src/screens/Profile/Header/ProfileHeaderStandard.tsx
··· 50 50 shouldShowKnownFollowers, 51 51 } from '#/components/KnownFollowers' 52 52 import {Link} from '#/components/Link' 53 - import {PdsBadge} from '#/components/PdsBadge' 54 53 import {ProfileBadges} from '#/components/ProfileBadges' 55 54 import * as Prompt from '#/components/Prompt' 56 55 import {RichText} from '#/components/RichText' ··· 202 201 a.align_center, 203 202 {marginTop: platform({ios: 2})}, 204 203 ]}> 205 - <PdsBadge did={profile.did} size="lg" /> 206 204 <ProfileBadges profile={profile} size="lg" interactive /> 207 205 </View> 208 206 </Text>
+5 -5
src/view/com/composer/ComposerReplyTo.tsx
··· 16 16 import {type ComposerOptsPostRef} from '#/state/shell/composer' 17 17 import {PreviewableUserAvatar} from '#/view/com/util/UserAvatar' 18 18 import {atoms as a, useTheme, web} from '#/alf' 19 - import {PdsBadge} from '#/components/PdsBadge' 20 19 import {QuoteEmbed} from '#/components/Post/Embed' 21 20 import {ProfileBadges} from '#/components/ProfileBadges' 22 21 import {Text} from '#/components/Typography' ··· 108 107 sanitizeHandle(replyTo.author.handle), 109 108 )} 110 109 </Text> 111 - <View style={[a.pl_xs]}> 112 - <PdsBadge did={replyTo.author.did} size="sm" /> 113 - </View> 114 110 <ProfileBadges profile={replyTo.author} size="sm" style={[a.pl_xs]} /> 115 111 {replyTo.author?.pronouns && ( 116 112 <Text ··· 140 136 )} 141 137 </View> 142 138 {showFull && parsedQuoteEmbed && parsedQuoteEmbed.type === 'post' && ( 143 - <QuoteEmbed embed={parsedQuoteEmbed} showPronouns={true} linkDisabled /> 139 + <QuoteEmbed 140 + embed={parsedQuoteEmbed} 141 + showPronouns={true} 142 + linkDisabled 143 + /> 144 144 )} 145 145 </View> 146 146 </Pressable>
-4
src/view/com/composer/text-input/mobile/Autocomplete.tsx
··· 9 9 import {useActorAutocompleteQuery} from '#/state/queries/actor-autocomplete' 10 10 import {UserAvatar} from '#/view/com/util/UserAvatar' 11 11 import {atoms as a, platform, useTheme} from '#/alf' 12 - import {PdsBadge} from '#/components/PdsBadge' 13 12 import {ProfileBadges} from '#/components/ProfileBadges' 14 13 import {Text} from '#/components/Typography' 15 14 ··· 114 113 numberOfLines={1}> 115 114 {displayName} 116 115 </Text> 117 - <View style={[{marginTop: platform({android: -2})}]}> 118 - <PdsBadge did={profile.did} size="sm" /> 119 - </View> 120 116 <ProfileBadges 121 117 profile={profile} 122 118 size="sm"
-4
src/view/com/notifications/NotificationFeedItem.tsx
··· 68 68 import {VerifiedCheck} from '#/components/icons/VerifiedCheck' 69 69 import {InlineLinkText, Link} from '#/components/Link' 70 70 import * as MediaPreview from '#/components/MediaPreview' 71 - import {PdsBadge} from '#/components/PdsBadge' 72 71 import {ProfileBadges} from '#/components/ProfileBadges' 73 72 import {ProfileHoverCard} from '#/components/ProfileHoverCard' 74 73 import {Notification as StarterPackCard} from '#/components/StarterPack/StarterPackCard' ··· 1059 1058 author.profile.displayName || author.profile.handle, 1060 1059 )} 1061 1060 </Text> 1062 - <View style={[a.pl_xs, a.self_center]}> 1063 - <PdsBadge did={author.profile.did} size="sm" /> 1064 - </View> 1065 1061 <ProfileBadges 1066 1062 profile={author.profile} 1067 1063 size="md"
+3 -7
src/view/com/util/PostMeta.tsx
··· 16 16 import {unstableCacheProfileView} from '#/state/queries/profile' 17 17 import {atoms as a, platform, useTheme, web} from '#/alf' 18 18 import {WebOnlyInlineLinkText} from '#/components/Link' 19 - import {PdsBadge} from '#/components/PdsBadge' 20 19 import {ProfileBadges} from '#/components/ProfileBadges' 21 20 import {ProfileHoverCard} from '#/components/ProfileHoverCard' 22 21 import {Text} from '#/components/Typography' ··· 114 113 <ProfileBadges 115 114 profile={author} 116 115 size="sm" 117 - style={[a.pl_2xs, a.self_center]} 118 - /> 119 - <View 116 + pdsInteractive={false} 120 117 style={[ 121 118 a.pl_2xs, 122 119 a.self_center, 123 120 { 124 121 marginTop: platform({web: 1, ios: 0, android: -1}), 125 122 }, 126 - ]}> 127 - <PdsBadge did={author.did} size="sm" interactive={false} /> 128 - </View> 123 + ]} 124 + /> 129 125 <MaybeLinkText 130 126 emoji 131 127 numberOfLines={1}
-2
src/view/shell/Drawer.tsx
··· 56 56 UserCircle_Stroke2_Corner0_Rounded as UserCircle, 57 57 } from '#/components/icons/UserCircle' 58 58 import {InlineLinkText} from '#/components/Link' 59 - import {PdsBadge} from '#/components/PdsBadge' 60 59 import {ProfileBadges} from '#/components/ProfileBadges' 61 60 import {Text} from '#/components/Typography' 62 61 import {IS_WEB} from '#/env' ··· 103 102 numberOfLines={1}> 104 103 {profile?.displayName || account.handle} 105 104 </Text> 106 - <PdsBadge did={account.did} size="md" /> 107 105 {profile && <ProfileBadges profile={profile} size="lg" />} 108 106 </View> 109 107 <Text