mirror of https://git.lenooby09.tech/LeNooby09/social-app.git
at verify-code 165 lines 4.1 kB view raw
1import React from 'react' 2import {View} from 'react-native' 3import { 4 AppBskyActorDefs, 5 AppBskyGraphDefs, 6 AtUri, 7 moderateUserList, 8 ModerationUI, 9} from '@atproto/api' 10import {Trans} from '@lingui/macro' 11import {useQueryClient} from '@tanstack/react-query' 12 13import {sanitizeHandle} from 'lib/strings/handles' 14import {useModerationOpts} from 'state/preferences/moderation-opts' 15import {precacheList} from 'state/queries/feed' 16import {useSession} from 'state/session' 17import {atoms as a, useTheme} from '#/alf' 18import { 19 Avatar, 20 Description, 21 Header, 22 Outer, 23 SaveButton, 24} from '#/components/FeedCard' 25import {Link as InternalLink, LinkProps} from '#/components/Link' 26import * as Hider from '#/components/moderation/Hider' 27import {Text} from '#/components/Typography' 28 29/* 30 * This component is based on `FeedCard` and is tightly coupled with that 31 * component. Please refer to `FeedCard` for more context. 32 */ 33 34export { 35 Avatar, 36 AvatarPlaceholder, 37 Description, 38 Header, 39 Outer, 40 SaveButton, 41 TitleAndBylinePlaceholder, 42} from '#/components/FeedCard' 43 44const CURATELIST = 'app.bsky.graph.defs#curatelist' 45const MODLIST = 'app.bsky.graph.defs#modlist' 46 47type Props = { 48 view: AppBskyGraphDefs.ListView 49 showPinButton?: boolean 50} 51 52export function Default(props: Props) { 53 const {view, showPinButton} = props 54 const moderationOpts = useModerationOpts() 55 const moderation = moderationOpts 56 ? moderateUserList(view, moderationOpts) 57 : undefined 58 59 return ( 60 <Link {...props}> 61 <Outer> 62 <Header> 63 <Avatar src={view.avatar} /> 64 <TitleAndByline 65 title={view.name} 66 creator={view.creator} 67 purpose={view.purpose} 68 modUi={moderation?.ui('contentView')} 69 /> 70 {showPinButton && view.purpose === CURATELIST && ( 71 <SaveButton view={view} pin /> 72 )} 73 </Header> 74 <Description description={view.description} /> 75 </Outer> 76 </Link> 77 ) 78} 79 80export function Link({ 81 view, 82 children, 83 ...props 84}: Props & Omit<LinkProps, 'to' | 'label'>) { 85 const queryClient = useQueryClient() 86 87 const href = React.useMemo(() => { 88 return createProfileListHref({list: view}) 89 }, [view]) 90 91 React.useEffect(() => { 92 precacheList(queryClient, view) 93 }, [view, queryClient]) 94 95 return ( 96 <InternalLink label={view.name} to={href} {...props}> 97 {children} 98 </InternalLink> 99 ) 100} 101 102export function TitleAndByline({ 103 title, 104 creator, 105 purpose = CURATELIST, 106 modUi, 107}: { 108 title: string 109 creator?: AppBskyActorDefs.ProfileViewBasic 110 purpose?: AppBskyGraphDefs.ListView['purpose'] 111 modUi?: ModerationUI 112}) { 113 const t = useTheme() 114 const {currentAccount} = useSession() 115 116 return ( 117 <View style={[a.flex_1]}> 118 <Hider.Outer 119 modui={modUi} 120 isContentVisibleInitialState={ 121 creator && currentAccount?.did === creator.did 122 } 123 allowOverride={creator && currentAccount?.did === creator.did}> 124 <Hider.Mask> 125 <Text 126 style={[a.text_md, a.font_bold, a.leading_snug, a.italic]} 127 numberOfLines={1}> 128 <Trans>Hidden list</Trans> 129 </Text> 130 </Hider.Mask> 131 <Hider.Content> 132 <Text 133 style={[a.text_md, a.font_bold, a.leading_snug]} 134 numberOfLines={1}> 135 {title} 136 </Text> 137 </Hider.Content> 138 </Hider.Outer> 139 140 {creator && ( 141 <Text 142 style={[a.leading_snug, t.atoms.text_contrast_medium]} 143 numberOfLines={1}> 144 {purpose === MODLIST ? ( 145 <Trans> 146 Moderation list by {sanitizeHandle(creator.handle, '@')} 147 </Trans> 148 ) : ( 149 <Trans>List by {sanitizeHandle(creator.handle, '@')}</Trans> 150 )} 151 </Text> 152 )} 153 </View> 154 ) 155} 156 157export function createProfileListHref({ 158 list, 159}: { 160 list: AppBskyGraphDefs.ListView 161}) { 162 const urip = new AtUri(list.uri) 163 const handleOrDid = list.creator.handle || list.creator.did 164 return `/profile/${handleOrDid}/lists/${urip.rkey}` 165}