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 184 lines 5.4 kB view raw
1import {useMemo, useState} from 'react' 2import {View} from 'react-native' 3import {type AppBskyActorDefs, moderateProfile} from '@atproto/api' 4import {msg} from '@lingui/core/macro' 5import {useLingui} from '@lingui/react' 6import {Trans} from '@lingui/react/macro' 7import {differenceInSeconds} from 'date-fns' 8 9import {HITSLOP_10} from '#/lib/constants' 10import {useGetTimeAgo} from '#/lib/hooks/useTimeAgo' 11import {sanitizeDisplayName} from '#/lib/strings/display-names' 12import {useModerationOpts} from '#/state/preferences/moderation-opts' 13import {useSession} from '#/state/session' 14import {atoms as a, useTheme, web} from '#/alf' 15import {Button, ButtonText} from '#/components/Button' 16import * as Dialog from '#/components/Dialog' 17import {useDialogControl} from '#/components/Dialog' 18import {Newskie} from '#/components/icons/Newskie' 19import * as StarterPackCard from '#/components/StarterPack/StarterPackCard' 20import {Text} from '#/components/Typography' 21import {IS_NATIVE} from '#/env' 22 23export function NewskieDialog({ 24 profile, 25 disabled, 26}: { 27 profile: AppBskyActorDefs.ProfileViewDetailed 28 disabled?: boolean 29}) { 30 const t = useTheme() 31 const {_} = useLingui() 32 const control = useDialogControl() 33 34 const createdAt = profile.createdAt 35 36 const [now] = useState(() => Date.now()) 37 const daysOld = useMemo(() => { 38 if (!createdAt) return Infinity 39 return differenceInSeconds(now, new Date(createdAt)) / 86400 40 }, [createdAt, now]) 41 42 if (!createdAt || daysOld > 7) return null 43 44 return ( 45 <View style={[a.pr_2xs]}> 46 <Button 47 disabled={disabled} 48 label={_( 49 msg`This user is new here. Press for more info about when they joined.`, 50 )} 51 hitSlop={HITSLOP_10} 52 onPress={control.open}> 53 {({hovered, pressed}) => ( 54 <Newskie 55 size="lg" 56 fill={t.palette.yellow} 57 style={{ 58 opacity: hovered || pressed ? 0.5 : 1, 59 }} 60 /> 61 )} 62 </Button> 63 64 <Dialog.Outer control={control} nativeOptions={{preventExpansion: true}}> 65 <Dialog.Handle /> 66 <DialogInner profile={profile} createdAt={createdAt} now={now} /> 67 </Dialog.Outer> 68 </View> 69 ) 70} 71 72function DialogInner({ 73 profile, 74 createdAt, 75 now, 76}: { 77 profile: AppBskyActorDefs.ProfileViewDetailed 78 createdAt: string 79 now: number 80}) { 81 const control = Dialog.useDialogContext() 82 const {_} = useLingui() 83 const t = useTheme() 84 const moderationOpts = useModerationOpts() 85 const {currentAccount} = useSession() 86 const timeAgo = useGetTimeAgo() 87 const isMe = profile.did === currentAccount?.did 88 89 const profileName = useMemo(() => { 90 if (!moderationOpts) return profile.displayName || profile.handle 91 const moderation = moderateProfile(profile, moderationOpts) 92 return sanitizeDisplayName( 93 profile.displayName || profile.handle, 94 moderation.ui('displayName'), 95 ) 96 }, [moderationOpts, profile]) 97 98 const getJoinMessage = () => { 99 const timeAgoString = timeAgo(createdAt, now, {format: 'long'}) 100 101 if (isMe) { 102 if (profile.joinedViaStarterPack) { 103 return _( 104 msg`You joined Bluesky using a starter pack ${timeAgoString} ago`, 105 ) 106 } else { 107 return _(msg`You joined Bluesky ${timeAgoString} ago`) 108 } 109 } else { 110 if (profile.joinedViaStarterPack) { 111 return _( 112 msg`${profileName} joined Bluesky using a starter pack ${timeAgoString} ago`, 113 ) 114 } else { 115 return _(msg`${profileName} joined Bluesky ${timeAgoString} ago`) 116 } 117 } 118 } 119 120 return ( 121 <Dialog.ScrollableInner 122 label={_(msg`New user info dialog`)} 123 style={web({maxWidth: 400})}> 124 <View style={[a.gap_md]}> 125 <View style={[a.align_center]}> 126 <View 127 style={[ 128 { 129 height: 60, 130 width: 64, 131 }, 132 ]}> 133 <Newskie 134 width={64} 135 height={64} 136 fill={t.palette.yellow} 137 style={[a.absolute, a.inset_0]} 138 /> 139 </View> 140 <Text style={[a.font_semi_bold, a.text_xl]}> 141 {isMe ? <Trans>Welcome, friend!</Trans> : <Trans>Say hello!</Trans>} 142 </Text> 143 </View> 144 <Text style={[a.text_md, a.text_center, a.leading_snug]}> 145 {getJoinMessage()} 146 </Text> 147 {profile.joinedViaStarterPack ? ( 148 <StarterPackCard.Link 149 starterPack={profile.joinedViaStarterPack} 150 onPress={() => control.close()}> 151 <View 152 style={[ 153 a.w_full, 154 a.mt_sm, 155 a.p_lg, 156 a.border, 157 a.rounded_sm, 158 t.atoms.border_contrast_low, 159 ]}> 160 <StarterPackCard.Card 161 starterPack={profile.joinedViaStarterPack} 162 /> 163 </View> 164 </StarterPackCard.Link> 165 ) : null} 166 167 {IS_NATIVE && ( 168 <Button 169 label={_(msg`Close`)} 170 color="secondary" 171 size="small" 172 style={[a.mt_sm]} 173 onPress={() => control.close()}> 174 <ButtonText> 175 <Trans>Close</Trans> 176 </ButtonText> 177 </Button> 178 )} 179 </View> 180 181 <Dialog.Close /> 182 </Dialog.ScrollableInner> 183 ) 184}