Bluesky app fork with some witchin' additions 馃挮
at readme-update 203 lines 5.5 kB view raw
1import React from 'react' 2import {View} from 'react-native' 3import {Image} from 'expo-image' 4import {AppBskyGraphStarterpack, AtUri} from '@atproto/api' 5import {msg, Plural, Trans} from '@lingui/macro' 6import {useLingui} from '@lingui/react' 7import {useQueryClient} from '@tanstack/react-query' 8 9import {sanitizeHandle} from '#/lib/strings/handles' 10import {getStarterPackOgCard} from '#/lib/strings/starter-pack' 11import {precacheResolvedUri} from '#/state/queries/resolve-uri' 12import {precacheStarterPack} from '#/state/queries/starter-packs' 13import {useSession} from '#/state/session' 14import {atoms as a, useTheme} from '#/alf' 15import {StarterPack as StarterPackIcon} from '#/components/icons/StarterPack' 16import { 17 Link as BaseLink, 18 type LinkProps as BaseLinkProps, 19} from '#/components/Link' 20import {Text} from '#/components/Typography' 21import * as bsky from '#/types/bsky' 22 23export function Default({ 24 starterPack, 25}: { 26 starterPack?: bsky.starterPack.AnyStarterPackView 27}) { 28 if (!starterPack) return null 29 return ( 30 <Link starterPack={starterPack}> 31 <Card starterPack={starterPack} /> 32 </Link> 33 ) 34} 35 36export function Notification({ 37 starterPack, 38}: { 39 starterPack?: bsky.starterPack.AnyStarterPackView 40}) { 41 if (!starterPack) return null 42 return ( 43 <Link starterPack={starterPack}> 44 <Card starterPack={starterPack} noIcon={true} noDescription={true} /> 45 </Link> 46 ) 47} 48 49export function Card({ 50 starterPack, 51 noIcon, 52 noDescription, 53}: { 54 starterPack: bsky.starterPack.AnyStarterPackView 55 noIcon?: boolean 56 noDescription?: boolean 57}) { 58 const {record, creator, joinedAllTimeCount} = starterPack 59 60 const {_} = useLingui() 61 const t = useTheme() 62 const {currentAccount} = useSession() 63 64 if ( 65 !bsky.dangerousIsType<AppBskyGraphStarterpack.Record>( 66 record, 67 AppBskyGraphStarterpack.isRecord, 68 ) 69 ) { 70 return null 71 } 72 73 return ( 74 <View style={[a.w_full, a.gap_md]}> 75 <View style={[a.flex_row, a.gap_sm, a.w_full]}> 76 {!noIcon ? <StarterPackIcon width={40} gradient="sky" /> : null} 77 <View style={[a.flex_1]}> 78 <Text 79 emoji 80 style={[a.text_md, a.font_semi_bold, a.leading_snug]} 81 numberOfLines={2}> 82 {record.name} 83 </Text> 84 <Text 85 emoji 86 style={[a.leading_snug, t.atoms.text_contrast_medium]} 87 numberOfLines={1}> 88 {creator?.did === currentAccount?.did 89 ? _(msg`Starter pack by you`) 90 : _(msg`Starter pack by ${sanitizeHandle(creator.handle, '@')}`)} 91 </Text> 92 </View> 93 </View> 94 {!noDescription && record.description ? ( 95 <Text emoji numberOfLines={3} style={[a.leading_snug]}> 96 {record.description} 97 </Text> 98 ) : null} 99 {!!joinedAllTimeCount && joinedAllTimeCount >= 50 && ( 100 <Text style={[a.font_semi_bold, t.atoms.text_contrast_medium]}> 101 <Trans comment="Number of users (always at least 50) who have joined Bluesky using a specific starter pack"> 102 <Plural value={joinedAllTimeCount} other="# users have" /> joined! 103 </Trans> 104 </Text> 105 )} 106 </View> 107 ) 108} 109 110export function useStarterPackLink({ 111 view, 112}: { 113 view: bsky.starterPack.AnyStarterPackView 114}) { 115 const {_} = useLingui() 116 const qc = useQueryClient() 117 const {rkey, handleOrDid} = React.useMemo(() => { 118 const rkey = new AtUri(view.uri).rkey 119 const {creator} = view 120 return {rkey, handleOrDid: creator.handle || creator.did} 121 }, [view]) 122 const precache = () => { 123 precacheResolvedUri(qc, view.creator.handle, view.creator.did) 124 precacheStarterPack(qc, view) 125 } 126 127 return { 128 to: `/starter-pack/${handleOrDid}/${rkey}`, 129 label: AppBskyGraphStarterpack.isRecord(view.record) 130 ? _(msg`Navigate to ${view.record.name}`) 131 : _(msg`Navigate to starter pack`), 132 precache, 133 } 134} 135 136export function Link({ 137 starterPack, 138 children, 139}: { 140 starterPack: bsky.starterPack.AnyStarterPackView 141 onPress?: () => void 142 children: BaseLinkProps['children'] 143}) { 144 const {_} = useLingui() 145 const queryClient = useQueryClient() 146 const {record} = starterPack 147 const {rkey, handleOrDid} = React.useMemo(() => { 148 const rkey = new AtUri(starterPack.uri).rkey 149 const {creator} = starterPack 150 return {rkey, handleOrDid: creator.handle || creator.did} 151 }, [starterPack]) 152 153 if (!AppBskyGraphStarterpack.isRecord(record)) { 154 return null 155 } 156 157 return ( 158 <BaseLink 159 to={`/starter-pack/${handleOrDid}/${rkey}`} 160 label={_(msg`Navigate to ${record.name}`)} 161 onPress={() => { 162 precacheResolvedUri( 163 queryClient, 164 starterPack.creator.handle, 165 starterPack.creator.did, 166 ) 167 precacheStarterPack(queryClient, starterPack) 168 }} 169 style={[a.flex_col, a.align_start]}> 170 {children} 171 </BaseLink> 172 ) 173} 174 175export function Embed({ 176 starterPack, 177}: { 178 starterPack: bsky.starterPack.AnyStarterPackView 179}) { 180 const t = useTheme() 181 const imageUri = getStarterPackOgCard(starterPack) 182 183 return ( 184 <View 185 style={[ 186 a.border, 187 a.rounded_sm, 188 a.overflow_hidden, 189 t.atoms.border_contrast_low, 190 ]}> 191 <Link starterPack={starterPack}> 192 <Image 193 source={imageUri} 194 style={[a.w_full, a.aspect_card]} 195 accessibilityIgnoresInvertColors={true} 196 /> 197 <View style={[a.px_sm, a.py_md]}> 198 <Card starterPack={starterPack} /> 199 </View> 200 </Link> 201 </View> 202 ) 203}