Merge branch 'bluesky-social:main' into zh
commit
ecd51bc6f9
|
@ -1,14 +1,14 @@
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {View} from 'react-native'
|
import {View} from 'react-native'
|
||||||
import {AppBskyActorDefs, moderateProfile, ModerationOpts} from '@atproto/api'
|
import {AppBskyActorDefs, moderateProfile, ModerationOpts} from '@atproto/api'
|
||||||
import {msg, plural, Trans} from '@lingui/macro'
|
import {msg, Plural, Trans} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
import {makeProfileLink} from '#/lib/routes/links'
|
import {makeProfileLink} from '#/lib/routes/links'
|
||||||
import {sanitizeDisplayName} from 'lib/strings/display-names'
|
import {sanitizeDisplayName} from 'lib/strings/display-names'
|
||||||
import {UserAvatar} from '#/view/com/util/UserAvatar'
|
import {UserAvatar} from '#/view/com/util/UserAvatar'
|
||||||
import {atoms as a, useTheme} from '#/alf'
|
import {atoms as a, useTheme} from '#/alf'
|
||||||
import {Link} from '#/components/Link'
|
import {Link, LinkProps} from '#/components/Link'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
|
||||||
const AVI_SIZE = 30
|
const AVI_SIZE = 30
|
||||||
|
@ -29,9 +29,11 @@ export function shouldShowKnownFollowers(
|
||||||
export function KnownFollowers({
|
export function KnownFollowers({
|
||||||
profile,
|
profile,
|
||||||
moderationOpts,
|
moderationOpts,
|
||||||
|
onLinkPress,
|
||||||
}: {
|
}: {
|
||||||
profile: AppBskyActorDefs.ProfileViewDetailed
|
profile: AppBskyActorDefs.ProfileViewDetailed
|
||||||
moderationOpts: ModerationOpts
|
moderationOpts: ModerationOpts
|
||||||
|
onLinkPress?: LinkProps['onPress']
|
||||||
}) {
|
}) {
|
||||||
const cache = React.useRef<Map<string, AppBskyActorDefs.KnownFollowers>>(
|
const cache = React.useRef<Map<string, AppBskyActorDefs.KnownFollowers>>(
|
||||||
new Map(),
|
new Map(),
|
||||||
|
@ -56,6 +58,7 @@ export function KnownFollowers({
|
||||||
profile={profile}
|
profile={profile}
|
||||||
cachedKnownFollowers={cachedKnownFollowers}
|
cachedKnownFollowers={cachedKnownFollowers}
|
||||||
moderationOpts={moderationOpts}
|
moderationOpts={moderationOpts}
|
||||||
|
onLinkPress={onLinkPress}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -67,10 +70,12 @@ function KnownFollowersInner({
|
||||||
profile,
|
profile,
|
||||||
moderationOpts,
|
moderationOpts,
|
||||||
cachedKnownFollowers,
|
cachedKnownFollowers,
|
||||||
|
onLinkPress,
|
||||||
}: {
|
}: {
|
||||||
profile: AppBskyActorDefs.ProfileViewDetailed
|
profile: AppBskyActorDefs.ProfileViewDetailed
|
||||||
moderationOpts: ModerationOpts
|
moderationOpts: ModerationOpts
|
||||||
cachedKnownFollowers: AppBskyActorDefs.KnownFollowers
|
cachedKnownFollowers: AppBskyActorDefs.KnownFollowers
|
||||||
|
onLinkPress?: LinkProps['onPress']
|
||||||
}) {
|
}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const {_} = useLingui()
|
const {_} = useLingui()
|
||||||
|
@ -82,15 +87,6 @@ function KnownFollowersInner({
|
||||||
t.atoms.text_contrast_medium,
|
t.atoms.text_contrast_medium,
|
||||||
]
|
]
|
||||||
|
|
||||||
// list of users, minus blocks
|
|
||||||
const returnedCount = cachedKnownFollowers.followers.length
|
|
||||||
// db count, includes blocks
|
|
||||||
const fullCount = cachedKnownFollowers.count
|
|
||||||
// knownFollowers can return up to 5 users, but will exclude blocks
|
|
||||||
// therefore, if we have less 5 users, use whichever count is lower
|
|
||||||
const count =
|
|
||||||
returnedCount < 5 ? Math.min(fullCount, returnedCount) : fullCount
|
|
||||||
|
|
||||||
const slice = cachedKnownFollowers.followers.slice(0, 3).map(f => {
|
const slice = cachedKnownFollowers.followers.slice(0, 3).map(f => {
|
||||||
const moderation = moderateProfile(f, moderationOpts)
|
const moderation = moderateProfile(f, moderationOpts)
|
||||||
return {
|
return {
|
||||||
|
@ -104,12 +100,14 @@ function KnownFollowersInner({
|
||||||
moderation,
|
moderation,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
const count = cachedKnownFollowers.count - Math.min(slice.length, 2)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
label={_(
|
label={_(
|
||||||
msg`Press to view followers of this account that you also follow`,
|
msg`Press to view followers of this account that you also follow`,
|
||||||
)}
|
)}
|
||||||
|
onPress={onLinkPress}
|
||||||
to={makeProfileLink(profile, 'known-followers')}
|
to={makeProfileLink(profile, 'known-followers')}
|
||||||
style={[
|
style={[
|
||||||
a.flex_1,
|
a.flex_1,
|
||||||
|
@ -166,31 +164,37 @@ function KnownFollowersInner({
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
numberOfLines={2}>
|
numberOfLines={2}>
|
||||||
<Trans>Followed by</Trans>{' '}
|
|
||||||
{count > 2 ? (
|
{count > 2 ? (
|
||||||
<>
|
<Trans>
|
||||||
{slice.slice(0, 2).map(({profile: prof}, i) => (
|
Followed by{' '}
|
||||||
<Text key={prof.did} style={textStyle}>
|
<Text key={slice[0].profile.did} style={textStyle}>
|
||||||
{prof.displayName}
|
{slice[0].profile.displayName}
|
||||||
{i === 0 && ', '}
|
|
||||||
</Text>
|
|
||||||
))}
|
|
||||||
{', '}
|
|
||||||
{plural(count - 2, {
|
|
||||||
one: 'and # other',
|
|
||||||
other: 'and # others',
|
|
||||||
})}
|
|
||||||
</>
|
|
||||||
) : count === 2 ? (
|
|
||||||
slice.map(({profile: prof}, i) => (
|
|
||||||
<Text key={prof.did} style={textStyle}>
|
|
||||||
{prof.displayName} {i === 0 ? _(msg`and`) + ' ' : ''}
|
|
||||||
</Text>
|
</Text>
|
||||||
))
|
,{' '}
|
||||||
|
<Text key={slice[1].profile.did} style={textStyle}>
|
||||||
|
{slice[1].profile.displayName}
|
||||||
|
</Text>
|
||||||
|
, and{' '}
|
||||||
|
<Plural value={count - 2} one="# other" other="# others" />
|
||||||
|
</Trans>
|
||||||
|
) : count === 2 ? (
|
||||||
|
<Trans>
|
||||||
|
Followed by{' '}
|
||||||
|
<Text key={slice[0].profile.did} style={textStyle}>
|
||||||
|
{slice[0].profile.displayName}
|
||||||
|
</Text>{' '}
|
||||||
|
and{' '}
|
||||||
|
<Text key={slice[1].profile.did} style={textStyle}>
|
||||||
|
{slice[1].profile.displayName}
|
||||||
|
</Text>
|
||||||
|
</Trans>
|
||||||
) : (
|
) : (
|
||||||
<Text key={slice[0].profile.did} style={textStyle}>
|
<Trans>
|
||||||
{slice[0].profile.displayName}
|
Followed by{' '}
|
||||||
</Text>
|
<Text key={slice[0].profile.did} style={textStyle}>
|
||||||
|
{slice[0].profile.displayName}
|
||||||
|
</Text>
|
||||||
|
</Trans>
|
||||||
)}
|
)}
|
||||||
</Text>
|
</Text>
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -5,6 +5,7 @@ import {flip, offset, shift, size, useFloating} from '@floating-ui/react-dom'
|
||||||
import {msg, plural} from '@lingui/macro'
|
import {msg, plural} from '@lingui/macro'
|
||||||
import {useLingui} from '@lingui/react'
|
import {useLingui} from '@lingui/react'
|
||||||
|
|
||||||
|
import {getModerationCauseKey} from '#/lib/moderation'
|
||||||
import {makeProfileLink} from '#/lib/routes/links'
|
import {makeProfileLink} from '#/lib/routes/links'
|
||||||
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
import {sanitizeDisplayName} from '#/lib/strings/display-names'
|
||||||
import {sanitizeHandle} from '#/lib/strings/handles'
|
import {sanitizeHandle} from '#/lib/strings/handles'
|
||||||
|
@ -22,11 +23,16 @@ import {useFollowMethods} from '#/components/hooks/useFollowMethods'
|
||||||
import {useRichText} from '#/components/hooks/useRichText'
|
import {useRichText} from '#/components/hooks/useRichText'
|
||||||
import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
|
import {Check_Stroke2_Corner0_Rounded as Check} from '#/components/icons/Check'
|
||||||
import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus'
|
import {PlusLarge_Stroke2_Corner0_Rounded as Plus} from '#/components/icons/Plus'
|
||||||
|
import {
|
||||||
|
KnownFollowers,
|
||||||
|
shouldShowKnownFollowers,
|
||||||
|
} from '#/components/KnownFollowers'
|
||||||
import {InlineLinkText, Link} from '#/components/Link'
|
import {InlineLinkText, Link} from '#/components/Link'
|
||||||
import {Loader} from '#/components/Loader'
|
import {Loader} from '#/components/Loader'
|
||||||
import {Portal} from '#/components/Portal'
|
import {Portal} from '#/components/Portal'
|
||||||
import {RichText} from '#/components/RichText'
|
import {RichText} from '#/components/RichText'
|
||||||
import {Text} from '#/components/Typography'
|
import {Text} from '#/components/Typography'
|
||||||
|
import {ProfileLabel} from '../moderation/ProfileHeaderAlerts'
|
||||||
import {ProfileHoverCardProps} from './types'
|
import {ProfileHoverCardProps} from './types'
|
||||||
|
|
||||||
const floatingMiddlewares = [
|
const floatingMiddlewares = [
|
||||||
|
@ -370,7 +376,10 @@ function Inner({
|
||||||
profile: profileShadow,
|
profile: profileShadow,
|
||||||
logContext: 'ProfileHoverCard',
|
logContext: 'ProfileHoverCard',
|
||||||
})
|
})
|
||||||
const blockHide = profile.viewer?.blocking || profile.viewer?.blockedBy
|
const isBlockedUser =
|
||||||
|
profile.viewer?.blocking ||
|
||||||
|
profile.viewer?.blockedBy ||
|
||||||
|
profile.viewer?.blockingByList
|
||||||
const following = formatCount(profile.followsCount || 0)
|
const following = formatCount(profile.followsCount || 0)
|
||||||
const followers = formatCount(profile.followersCount || 0)
|
const followers = formatCount(profile.followersCount || 0)
|
||||||
const pluralizedFollowers = plural(profile.followersCount || 0, {
|
const pluralizedFollowers = plural(profile.followersCount || 0, {
|
||||||
|
@ -401,29 +410,41 @@ function Inner({
|
||||||
/>
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
{!isMe && (
|
{!isMe &&
|
||||||
<Button
|
(isBlockedUser ? (
|
||||||
size="small"
|
<Link
|
||||||
color={profileShadow.viewer?.following ? 'secondary' : 'primary'}
|
to={profileURL}
|
||||||
variant="solid"
|
label={_(msg`View blocked user's profile`)}
|
||||||
label={
|
onPress={hide}
|
||||||
profileShadow.viewer?.following
|
size="small"
|
||||||
? _(msg`Following`)
|
color="secondary"
|
||||||
: _(msg`Follow`)
|
variant="solid"
|
||||||
}
|
style={[a.rounded_full]}>
|
||||||
style={[a.rounded_full]}
|
<ButtonText>{_(msg`View profile`)}</ButtonText>
|
||||||
onPress={profileShadow.viewer?.following ? unfollow : follow}>
|
</Link>
|
||||||
<ButtonIcon
|
) : (
|
||||||
position="left"
|
<Button
|
||||||
icon={profileShadow.viewer?.following ? Check : Plus}
|
size="small"
|
||||||
/>
|
color={profileShadow.viewer?.following ? 'secondary' : 'primary'}
|
||||||
<ButtonText>
|
variant="solid"
|
||||||
{profileShadow.viewer?.following
|
label={
|
||||||
? _(msg`Following`)
|
profileShadow.viewer?.following
|
||||||
: _(msg`Follow`)}
|
? _(msg`Following`)
|
||||||
</ButtonText>
|
: _(msg`Follow`)
|
||||||
</Button>
|
}
|
||||||
)}
|
style={[a.rounded_full]}
|
||||||
|
onPress={profileShadow.viewer?.following ? unfollow : follow}>
|
||||||
|
<ButtonIcon
|
||||||
|
position="left"
|
||||||
|
icon={profileShadow.viewer?.following ? Check : Plus}
|
||||||
|
/>
|
||||||
|
<ButtonText>
|
||||||
|
{profileShadow.viewer?.following
|
||||||
|
? _(msg`Following`)
|
||||||
|
: _(msg`Follow`)}
|
||||||
|
</ButtonText>
|
||||||
|
</Button>
|
||||||
|
))}
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
<Link to={profileURL} label={_(msg`View profile`)} onPress={hide}>
|
<Link to={profileURL} label={_(msg`View profile`)} onPress={hide}>
|
||||||
|
@ -439,7 +460,19 @@ function Inner({
|
||||||
</View>
|
</View>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
{!blockHide && (
|
{isBlockedUser && (
|
||||||
|
<View style={[a.flex_row, a.flex_wrap, a.gap_xs]}>
|
||||||
|
{moderation.ui('profileView').alerts.map(cause => (
|
||||||
|
<ProfileLabel
|
||||||
|
key={getModerationCauseKey(cause)}
|
||||||
|
cause={cause}
|
||||||
|
disableDetailsDialog
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!isBlockedUser && (
|
||||||
<>
|
<>
|
||||||
<View style={[a.flex_row, a.flex_wrap, a.gap_md, a.pt_xs]}>
|
<View style={[a.flex_row, a.flex_wrap, a.gap_md, a.pt_xs]}>
|
||||||
<InlineLinkText
|
<InlineLinkText
|
||||||
|
@ -473,6 +506,17 @@ function Inner({
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
) : undefined}
|
) : undefined}
|
||||||
|
|
||||||
|
{!isMe &&
|
||||||
|
shouldShowKnownFollowers(profile.viewer?.knownFollowers) && (
|
||||||
|
<View style={[a.flex_row, a.align_center, a.gap_sm, a.pt_md]}>
|
||||||
|
<KnownFollowers
|
||||||
|
profile={profile}
|
||||||
|
moderationOpts={moderationOpts}
|
||||||
|
onLinkPress={hide}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</View>
|
</View>
|
||||||
|
|
|
@ -43,7 +43,13 @@ export function ProfileHeaderAlerts({
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function ProfileLabel({cause}: {cause: ModerationCause}) {
|
export function ProfileLabel({
|
||||||
|
cause,
|
||||||
|
disableDetailsDialog,
|
||||||
|
}: {
|
||||||
|
cause: ModerationCause
|
||||||
|
disableDetailsDialog?: boolean
|
||||||
|
}) {
|
||||||
const t = useTheme()
|
const t = useTheme()
|
||||||
const control = useModerationDetailsDialogControl()
|
const control = useModerationDetailsDialogControl()
|
||||||
const desc = useModerationCauseDescription(cause)
|
const desc = useModerationCauseDescription(cause)
|
||||||
|
@ -51,6 +57,7 @@ function ProfileLabel({cause}: {cause: ModerationCause}) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
|
disabled={disableDetailsDialog}
|
||||||
label={desc.name}
|
label={desc.name}
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
control.open()
|
control.open()
|
||||||
|
@ -87,7 +94,9 @@ function ProfileLabel({cause}: {cause: ModerationCause}) {
|
||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<ModerationDetailsDialog control={control} modcause={cause} />
|
{!disableDetailsDialog && (
|
||||||
|
<ModerationDetailsDialog control={control} modcause={cause} />
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,6 +94,7 @@ export function usePrefetchProfileQuery() {
|
||||||
const prefetchProfileQuery = useCallback(
|
const prefetchProfileQuery = useCallback(
|
||||||
async (did: string) => {
|
async (did: string) => {
|
||||||
await queryClient.prefetchQuery({
|
await queryClient.prefetchQuery({
|
||||||
|
staleTime: STALE.SECONDS.THIRTY,
|
||||||
queryKey: RQKEY(did),
|
queryKey: RQKEY(did),
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
const res = await agent.getProfile({actor: did || ''})
|
const res = await agent.getProfile({actor: did || ''})
|
||||||
|
|
|
@ -150,16 +150,27 @@ export const TextInput = React.forwardRef(function TextInputImpl(
|
||||||
attributes: {
|
attributes: {
|
||||||
class: modeClass,
|
class: modeClass,
|
||||||
},
|
},
|
||||||
handlePaste: (_, event) => {
|
handlePaste: (view, event) => {
|
||||||
const items = event.clipboardData?.items
|
const clipboardData = event.clipboardData
|
||||||
|
|
||||||
if (items === undefined) {
|
if (clipboardData) {
|
||||||
return
|
if (clipboardData.types.includes('text/html')) {
|
||||||
|
// Rich-text formatting is pasted, try retrieving plain text
|
||||||
|
const text = clipboardData.getData('text/plain')
|
||||||
|
|
||||||
|
// `pasteText` will invoke this handler again, but `clipboardData` will be null.
|
||||||
|
view.pasteText(text)
|
||||||
|
|
||||||
|
// Return `true` to prevent ProseMirror's default paste behavior.
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
// Otherwise, try retrieving images from the clipboard
|
||||||
|
|
||||||
|
getImageFromUri(clipboardData.items, (uri: string) => {
|
||||||
|
textInputWebEmitter.emit('photo-pasted', uri)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getImageFromUri(items, (uri: string) => {
|
|
||||||
textInputWebEmitter.emit('photo-pasted', uri)
|
|
||||||
})
|
|
||||||
},
|
},
|
||||||
handleKeyDown: (_, event) => {
|
handleKeyDown: (_, event) => {
|
||||||
if ((event.metaKey || event.ctrlKey) && event.code === 'Enter') {
|
if ((event.metaKey || event.ctrlKey) && event.code === 'Enter') {
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {sanitizeHandle} from 'lib/strings/handles'
|
||||||
import {niceDate} from 'lib/strings/time'
|
import {niceDate} from 'lib/strings/time'
|
||||||
import {TypographyVariant} from 'lib/ThemeContext'
|
import {TypographyVariant} from 'lib/ThemeContext'
|
||||||
import {isAndroid, isWeb} from 'platform/detection'
|
import {isAndroid, isWeb} from 'platform/detection'
|
||||||
|
import {atoms as a} from '#/alf'
|
||||||
import {ProfileHoverCard} from '#/components/ProfileHoverCard'
|
import {ProfileHoverCard} from '#/components/ProfileHoverCard'
|
||||||
import {TextLinkOnWebOnly} from './Link'
|
import {TextLinkOnWebOnly} from './Link'
|
||||||
import {Text} from './text/Text'
|
import {Text} from './text/Text'
|
||||||
|
@ -39,9 +40,13 @@ let PostMeta = (opts: PostMetaOpts): React.ReactNode => {
|
||||||
const prefetchProfileQuery = usePrefetchProfileQuery()
|
const prefetchProfileQuery = usePrefetchProfileQuery()
|
||||||
|
|
||||||
const profileLink = makeProfileLink(opts.author)
|
const profileLink = makeProfileLink(opts.author)
|
||||||
const onPointerEnter = isWeb
|
const prefetchedProfile = React.useRef(false)
|
||||||
? () => prefetchProfileQuery(opts.author.did)
|
const onPointerMove = React.useCallback(() => {
|
||||||
: undefined
|
if (!prefetchedProfile.current) {
|
||||||
|
prefetchedProfile.current = true
|
||||||
|
prefetchProfileQuery(opts.author.did)
|
||||||
|
}
|
||||||
|
}, [opts.author.did, prefetchProfileQuery])
|
||||||
|
|
||||||
const queryClient = useQueryClient()
|
const queryClient = useQueryClient()
|
||||||
const onOpenAuthor = opts.onOpenAuthor
|
const onOpenAuthor = opts.onOpenAuthor
|
||||||
|
@ -66,37 +71,39 @@ let PostMeta = (opts: PostMetaOpts): React.ReactNode => {
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
<ProfileHoverCard inline did={opts.author.did}>
|
<ProfileHoverCard inline did={opts.author.did}>
|
||||||
<Text
|
<View
|
||||||
numberOfLines={1}
|
onPointerMove={isWeb ? onPointerMove : undefined}
|
||||||
style={[styles.maxWidth, pal.textLight, opts.displayNameStyle]}>
|
style={[a.flex_1]}>
|
||||||
<TextLinkOnWebOnly
|
<Text
|
||||||
type={opts.displayNameType || 'lg-bold'}
|
numberOfLines={1}
|
||||||
style={[pal.text]}
|
style={[styles.maxWidth, pal.textLight, opts.displayNameStyle]}>
|
||||||
lineHeight={1.2}
|
<TextLinkOnWebOnly
|
||||||
disableMismatchWarning
|
type={opts.displayNameType || 'lg-bold'}
|
||||||
text={
|
style={[pal.text]}
|
||||||
<>
|
lineHeight={1.2}
|
||||||
{sanitizeDisplayName(
|
disableMismatchWarning
|
||||||
displayName,
|
text={
|
||||||
opts.moderation?.ui('displayName'),
|
<>
|
||||||
)}
|
{sanitizeDisplayName(
|
||||||
</>
|
displayName,
|
||||||
}
|
opts.moderation?.ui('displayName'),
|
||||||
href={profileLink}
|
)}
|
||||||
onBeforePress={onBeforePressAuthor}
|
</>
|
||||||
onPointerEnter={onPointerEnter}
|
}
|
||||||
/>
|
href={profileLink}
|
||||||
<TextLinkOnWebOnly
|
onBeforePress={onBeforePressAuthor}
|
||||||
type="md"
|
/>
|
||||||
disableMismatchWarning
|
<TextLinkOnWebOnly
|
||||||
style={[pal.textLight, {flexShrink: 4}]}
|
type="md"
|
||||||
text={'\xa0' + sanitizeHandle(handle, '@')}
|
disableMismatchWarning
|
||||||
href={profileLink}
|
style={[pal.textLight, {flexShrink: 4}]}
|
||||||
onBeforePress={onBeforePressAuthor}
|
text={'\xa0' + sanitizeHandle(handle, '@')}
|
||||||
onPointerEnter={onPointerEnter}
|
href={profileLink}
|
||||||
anchorNoUnderline
|
onBeforePress={onBeforePressAuthor}
|
||||||
/>
|
anchorNoUnderline
|
||||||
</Text>
|
/>
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
</ProfileHoverCard>
|
</ProfileHoverCard>
|
||||||
{!isAndroid && (
|
{!isAndroid && (
|
||||||
<Text
|
<Text
|
||||||
|
|
Loading…
Reference in New Issue