Profile card hover preview (#3508)
* feat: initial user card hover * feat: flesh it out some more * fix: initialize middlewares once * chore: remove floating-ui react-native * chore: clean up * Update moderation apis, fix lint * Refactor profile hover card to alf * Clean up * Debounce, fix positioning when loading * Fix going away * Close on all link presses * Tweak styles * Disable on mobile web * cleanup some of the changes pt. 1 * cleanup some of the changes pt. 2 * cleanup some of the changes pt. 3 * cleanup some of the changes pt. 4 * Re-revert files * Fix handle presentation * Don't follow yourself, silly * Collapsed notifications group * ProfileCard * Tree view replies * Suggested follows * Fix hover-back-on-card edge case * Moar --------- Co-authored-by: Mary <git@mary.my.id> Co-authored-by: Hailey <me@haileyok.com>
This commit is contained in:
parent
f91aa37c6b
commit
1f61109cfa
17 changed files with 576 additions and 146 deletions
|
@ -1,18 +1,19 @@
|
|||
import React, {memo} from 'react'
|
||||
import {StyleProp, StyleSheet, TextStyle, View, ViewStyle} from 'react-native'
|
||||
import {Text} from './text/Text'
|
||||
import {TextLinkOnWebOnly} from './Link'
|
||||
import {niceDate} from 'lib/strings/time'
|
||||
import {AppBskyActorDefs, ModerationDecision, ModerationUI} from '@atproto/api'
|
||||
|
||||
import {usePrefetchProfileQuery} from '#/state/queries/profile'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {TypographyVariant} from 'lib/ThemeContext'
|
||||
import {UserAvatar} from './UserAvatar'
|
||||
import {makeProfileLink} from 'lib/routes/links'
|
||||
import {sanitizeDisplayName} from 'lib/strings/display-names'
|
||||
import {sanitizeHandle} from 'lib/strings/handles'
|
||||
import {niceDate} from 'lib/strings/time'
|
||||
import {TypographyVariant} from 'lib/ThemeContext'
|
||||
import {isAndroid, isWeb} from 'platform/detection'
|
||||
import {TextLinkOnWebOnly} from './Link'
|
||||
import {Text} from './text/Text'
|
||||
import {TimeElapsed} from './TimeElapsed'
|
||||
import {makeProfileLink} from 'lib/routes/links'
|
||||
import {AppBskyActorDefs, ModerationDecision, ModerationUI} from '@atproto/api'
|
||||
import {usePrefetchProfileQuery} from '#/state/queries/profile'
|
||||
import {PreviewableUserAvatar} from './UserAvatar'
|
||||
|
||||
interface PostMetaOpts {
|
||||
author: AppBskyActorDefs.ProfileViewBasic
|
||||
|
@ -38,9 +39,11 @@ let PostMeta = (opts: PostMetaOpts): React.ReactNode => {
|
|||
<View style={[styles.container, opts.style]}>
|
||||
{opts.showAvatar && (
|
||||
<View style={styles.avatar}>
|
||||
<UserAvatar
|
||||
avatar={opts.author.avatar}
|
||||
<PreviewableUserAvatar
|
||||
size={opts.avatarSize || 16}
|
||||
did={opts.author.did}
|
||||
handle={opts.author.handle}
|
||||
avatar={opts.author.avatar}
|
||||
moderation={opts.avatarModeration}
|
||||
type={opts.author.associated?.labeler ? 'labeler' : 'user'}
|
||||
/>
|
||||
|
|
|
@ -1,30 +1,32 @@
|
|||
import React, {memo, useMemo} from 'react'
|
||||
import {Image, StyleSheet, TouchableOpacity, View} from 'react-native'
|
||||
import Svg, {Circle, Rect, Path} from 'react-native-svg'
|
||||
import {Image as RNImage} from 'react-native-image-crop-picker'
|
||||
import {useLingui} from '@lingui/react'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||
import Svg, {Circle, Path, Rect} from 'react-native-svg'
|
||||
import {ModerationUI} from '@atproto/api'
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
|
||||
import {msg, Trans} from '@lingui/macro'
|
||||
import {useLingui} from '@lingui/react'
|
||||
|
||||
import {HighPriorityImage} from 'view/com/util/images/Image'
|
||||
import {openCamera, openCropper, openPicker} from '../../../lib/media/picker'
|
||||
import {
|
||||
usePhotoLibraryPermission,
|
||||
useCameraPermission,
|
||||
} from 'lib/hooks/usePermissions'
|
||||
import {colors} from 'lib/styles'
|
||||
import {usePalette} from 'lib/hooks/usePalette'
|
||||
import {isWeb, isAndroid, isNative} from 'platform/detection'
|
||||
import {UserPreviewLink} from './UserPreviewLink'
|
||||
import * as Menu from '#/components/Menu'
|
||||
import {
|
||||
Camera_Stroke2_Corner0_Rounded as Camera,
|
||||
useCameraPermission,
|
||||
usePhotoLibraryPermission,
|
||||
} from 'lib/hooks/usePermissions'
|
||||
import {makeProfileLink} from 'lib/routes/links'
|
||||
import {colors} from 'lib/styles'
|
||||
import {isAndroid, isNative, isWeb} from 'platform/detection'
|
||||
import {HighPriorityImage} from 'view/com/util/images/Image'
|
||||
import {tokens, useTheme} from '#/alf'
|
||||
import {
|
||||
Camera_Filled_Stroke2_Corner0_Rounded as CameraFilled,
|
||||
Camera_Stroke2_Corner0_Rounded as Camera,
|
||||
} from '#/components/icons/Camera'
|
||||
import {StreamingLive_Stroke2_Corner0_Rounded as Library} from '#/components/icons/StreamingLive'
|
||||
import {Trash_Stroke2_Corner0_Rounded as Trash} from '#/components/icons/Trash'
|
||||
import {useTheme, tokens} from '#/alf'
|
||||
import {Link} from '#/components/Link'
|
||||
import * as Menu from '#/components/Menu'
|
||||
import {ProfileHoverCard} from '#/components/ProfileHoverCard'
|
||||
import {openCamera, openCropper, openPicker} from '../../../lib/media/picker'
|
||||
|
||||
export type UserAvatarType = 'user' | 'algo' | 'list' | 'labeler'
|
||||
|
||||
|
@ -372,10 +374,18 @@ export {EditableUserAvatar}
|
|||
let PreviewableUserAvatar = (
|
||||
props: PreviewableUserAvatarProps,
|
||||
): React.ReactNode => {
|
||||
const {_} = useLingui()
|
||||
return (
|
||||
<UserPreviewLink did={props.did} handle={props.handle}>
|
||||
<UserAvatar {...props} />
|
||||
</UserPreviewLink>
|
||||
<ProfileHoverCard did={props.did}>
|
||||
<Link
|
||||
label={_(msg`See profile`)}
|
||||
to={makeProfileLink({
|
||||
did: props.did,
|
||||
handle: props.handle,
|
||||
})}>
|
||||
<UserAvatar {...props} />
|
||||
</Link>
|
||||
</ProfileHoverCard>
|
||||
)
|
||||
}
|
||||
PreviewableUserAvatar = memo(PreviewableUserAvatar)
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
import React from 'react'
|
||||
import {StyleProp, ViewStyle} from 'react-native'
|
||||
import {Link} from './Link'
|
||||
import {isWeb} from 'platform/detection'
|
||||
import {makeProfileLink} from 'lib/routes/links'
|
||||
import {usePrefetchProfileQuery} from '#/state/queries/profile'
|
||||
|
||||
interface UserPreviewLinkProps {
|
||||
did: string
|
||||
handle: string
|
||||
style?: StyleProp<ViewStyle>
|
||||
}
|
||||
export function UserPreviewLink(
|
||||
props: React.PropsWithChildren<UserPreviewLinkProps>,
|
||||
) {
|
||||
const prefetchProfileQuery = usePrefetchProfileQuery()
|
||||
return (
|
||||
<Link
|
||||
onPointerEnter={() => {
|
||||
if (isWeb) {
|
||||
prefetchProfileQuery(props.did)
|
||||
}
|
||||
}}
|
||||
href={makeProfileLink(props)}
|
||||
title={props.handle}
|
||||
asAnchor
|
||||
style={props.style}>
|
||||
{props.children}
|
||||
</Link>
|
||||
)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue