import type { AnyProfileView } from '@atcute/bluesky';
import type { DisplayRestrictions } from '@atcute/bluesky-moderation';
import { useQueryClient } from '@tanstack/react-query';
import { assignInlineVars } from '@vanilla-extract/dynamic';
import { IS_TOUCH_DEVICE } from '#/lib/browser/platform';
import { profileTarget } from '#/lib/routes/targets';
import { unstableCacheProfileView } from '#/state/queries/unstable-profile-cache';
import { LiveStatusDialog } from '#/features/liveNow/components/LiveStatusDialog';
import { useActorStatus } from '#/features/liveNow/use-actor-status';
import * as Dialog from '#/components/Dialog';
import { ProfileHoverCard } from '#/components/ProfileHoverCard';
import { type BaseUserAvatarProps, UserAvatar } from '#/components/UserAvatar';
import * as styles from '#/components/UserAvatar.css';
import { Link } from '#/components/web/Link';
import { m } from '#/paraglide/messages';
type PreviewableUserAvatarProps = BaseUserAvatarProps & {
moderation?: DisplayRestrictions;
profile: AnyProfileView;
disableHoverCard?: boolean;
disableNavigation?: boolean;
onBeforePress?: () => void;
/** Sets the link/button's `tabindex`; pass `-1` to keep it clickable but out of the tab order. */
tabIndex?: number;
};
/** {@link UserAvatar} wrapped with a profile hover card and a link/live-status affordance. */
export function PreviewableUserAvatar({
moderation,
profile,
disableHoverCard,
disableNavigation,
onBeforePress,
live,
tabIndex,
...props
}: PreviewableUserAvatarProps) {
const queryClient = useQueryClient();
const status = useActorStatus(profile);
const liveHandle = Dialog.useDialogHandle();
const name = profile.handle;
const circular = props.type !== 'algo' && props.type !== 'list';
const radius = circular ? '50%' : props.size > 32 ? '8px' : '3px';
const avatarEl = (
<UserAvatar
avatar={profile.avatar}
moderation={moderation}
type={profile.associated?.labeler ? 'labeler' : 'user'}
live={status.isActive || live}
{...props}
/>
);
// live status on touch opens a dialog on tap (there's no hover); elsewhere the avatar links to the profile.
const isTouchLive = status.isActive && IS_TOUCH_DEVICE;
const trigger = disableNavigation ? (
avatarEl
) : isTouchLive ? (
<button
type="button"
aria-label={m['common.a11y.avatar']({ name })}
className={styles.preview}
style={assignInlineVars({ [styles.previewRadiusVar]: radius })}
tabIndex={tabIndex}
onClick={() => liveHandle.open(null)}
>
{avatarEl}
</button>
) : (
<Link
className={styles.preview}
label={m['common.a11y.avatar']({ name })}
onPress={() => {
onBeforePress?.();
unstableCacheProfileView(queryClient, profile);
}}
style={assignInlineVars({ [styles.previewRadiusVar]: radius })}
tabIndex={tabIndex}
to={profileTarget(profile.did)}
>
{avatarEl}
</Link>
);
return (
<>
{disableHoverCard ? trigger : <ProfileHoverCard actor={profile.did}>{trigger}</ProfileHoverCard>}
{!disableNavigation && isTouchLive && status.embed && (
<LiveStatusDialog embed={status.embed} handle={liveHandle} profile={profile} status={status} />
)}
</>
);
}