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:
Eric Bailey 2024-04-12 17:01:32 -05:00 committed by GitHub
parent f91aa37c6b
commit 1f61109cfa
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
17 changed files with 576 additions and 146 deletions

View file

@ -0,0 +1,60 @@
import React from 'react'
import {AppBskyActorDefs} from '@atproto/api'
import {msg} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {LogEvents} from '#/lib/statsig/statsig'
import {logger} from '#/logger'
import {Shadow} from '#/state/cache/types'
import {useProfileFollowMutationQueue} from '#/state/queries/profile'
import {useRequireAuth} from '#/state/session'
import * as Toast from '#/view/com/util/Toast'
export function useFollowMethods({
profile,
logContext,
}: {
profile: Shadow<AppBskyActorDefs.ProfileViewBasic>
logContext: LogEvents['profile:follow']['logContext'] &
LogEvents['profile:unfollow']['logContext']
}) {
const {_} = useLingui()
const requireAuth = useRequireAuth()
const [queueFollow, queueUnfollow] = useProfileFollowMutationQueue(
profile,
logContext,
)
const follow = React.useCallback(() => {
requireAuth(async () => {
try {
await queueFollow()
} catch (e: any) {
logger.error(`useFollowMethods: failed to follow`, {message: String(e)})
if (e?.name !== 'AbortError') {
Toast.show(_(msg`An issue occurred, please try again.`))
}
}
})
}, [_, queueFollow, requireAuth])
const unfollow = React.useCallback(() => {
requireAuth(async () => {
try {
await queueUnfollow()
} catch (e: any) {
logger.error(`useFollowMethods: failed to unfollow`, {
message: String(e),
})
if (e?.name !== 'AbortError') {
Toast.show(_(msg`An issue occurred, please try again.`))
}
}
})
}, [_, queueUnfollow, requireAuth])
return {
follow,
unfollow,
}
}

View file

@ -0,0 +1,33 @@
import React from 'react'
import {RichText as RichTextAPI} from '@atproto/api'
import {getAgent} from '#/state/session'
export function useRichText(text: string): [RichTextAPI, boolean] {
const [prevText, setPrevText] = React.useState(text)
const [rawRT, setRawRT] = React.useState(() => new RichTextAPI({text}))
const [resolvedRT, setResolvedRT] = React.useState<RichTextAPI | null>(null)
if (text !== prevText) {
setPrevText(text)
setRawRT(new RichTextAPI({text}))
setResolvedRT(null)
// This will queue an immediate re-render
}
React.useEffect(() => {
let ignore = false
async function resolveRTFacets() {
// new each time
const resolvedRT = new RichTextAPI({text})
await resolvedRT.detectFacets(getAgent())
if (!ignore) {
setResolvedRT(resolvedRT)
}
}
resolveRTFacets()
return () => {
ignore = true
}
}, [text])
const isResolving = resolvedRT === null
return [resolvedRT ?? rawRT, isResolving]
}