close profilecard on mouse leave
continuous-integration/drone/pr Build is failing Details

This commit is contained in:
Martti Malmi 2023-11-25 22:53:50 +02:00
parent 561ee94ab0
commit a92fc267c3
4 changed files with 41 additions and 31 deletions

View File

@ -15,7 +15,6 @@
"@snort/system-wasm": "workspace:*",
"@snort/system-web": "workspace:*",
"@szhsin/react-menu": "^3.3.1",
"@uidotdev/usehooks": "^2.3.1",
"@void-cat/api": "^1.0.10",
"classnames": "^2.3.2",
"debug": "^4.3.4",

View File

@ -1,25 +1,35 @@
import { NostrLink, NostrPrefix } from "@snort/system";
import { useUserProfile } from "@snort/system-react";
import { useHover } from "@uidotdev/usehooks";
import DisplayName from "@/Element/User/DisplayName";
import { ProfileCard } from "@/Element/User/ProfileCard";
import { ProfileLink } from "@/Element/User/ProfileLink";
import { useCallback, useRef, useState } from "react";
export default function Mention({ link }: { link: NostrLink }) {
const [ref, hovering] = useHover<HTMLAnchorElement>();
const profile = useUserProfile(link.id);
const [isHovering, setIsHovering] = useState(false);
const hoverTimeoutRef = useRef<NodeJS.Timeout | null>(null);
const handleMouseEnter = useCallback(() => {
hoverTimeoutRef.current && clearTimeout(hoverTimeoutRef.current);
hoverTimeoutRef.current = setTimeout(() => setIsHovering(true), 100); // Adjust timeout as needed
}, []);
const handleMouseLeave = useCallback(() => {
hoverTimeoutRef.current && clearTimeout(hoverTimeoutRef.current);
hoverTimeoutRef.current = setTimeout(() => setIsHovering(false), 300); // Adjust timeout as needed
}, []);
if (link.type !== NostrPrefix.Profile && link.type !== NostrPrefix.PublicKey) return;
return (
<>
<span className="highlight" onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>
<ProfileLink pubkey={link.id} link={link} user={profile} onClick={e => e.stopPropagation()}>
<span ref={ref}>
@<DisplayName user={profile} pubkey={link.id} />
</span>
@<DisplayName user={profile} pubkey={link.id} />
</ProfileLink>
<ProfileCard pubkey={link.id} user={profile} show={hovering} ref={ref} />
</>
{isHovering && <ProfileCard pubkey={link.id} user={profile} show={true} />}
</span>
);
}

View File

@ -10,28 +10,15 @@ import Text from "@/Element/Text";
import { useEffect, useState } from "react";
import useLogin from "../../Hooks/useLogin";
interface RectElement {
getBoundingClientRect(): {
left: number;
right: number;
top: number;
bottom: number;
width: number;
height: number;
};
}
export function ProfileCard({
pubkey,
user,
show,
ref,
delay,
}: {
pubkey: string;
user?: UserMetadata;
show: boolean;
ref: React.RefObject<Element | RectElement>;
delay?: number;
}) {
const [showProfileMenu, setShowProfileMenu] = useState(false);
@ -56,7 +43,6 @@ export function ProfileCard({
return (
<ControlledMenu
state={showProfileMenu ? "open" : "closed"}
anchorRef={ref}
menuClassName="profile-card"
onClose={() => setShowProfileMenu(false)}
align="end">

View File

@ -1,9 +1,8 @@
import "./ProfileImage.css";
import React, { ReactNode } from "react";
import React, { ReactNode, useCallback, useRef, useState } from "react";
import { HexKey, socialGraphInstance, UserMetadata } from "@snort/system";
import { useUserProfile } from "@snort/system-react";
import { useHover } from "@uidotdev/usehooks";
import classNames from "classnames";
import Avatar from "@/Element/User/Avatar";
@ -51,7 +50,19 @@ export default function ProfileImage({
const user = useUserProfile(profile ? "" : pubkey) ?? profile;
const nip05 = defaultNip ? defaultNip : user?.nip05;
const followDistance = socialGraphInstance.getFollowDistance(pubkey);
const [ref, hovering] = useHover<HTMLDivElement>();
const [isHovering, setIsHovering] = useState(false);
const hoverTimeoutRef = useRef<NodeJS.Timeout | null>(null);
const handleMouseEnter = useCallback(() => {
hoverTimeoutRef.current && clearTimeout(hoverTimeoutRef.current);
hoverTimeoutRef.current = setTimeout(() => setIsHovering(true), 100); // Adjust timeout as needed
}, []);
const handleMouseLeave = useCallback(() => {
hoverTimeoutRef.current && clearTimeout(hoverTimeoutRef.current);
hoverTimeoutRef.current = setTimeout(() => setIsHovering(false), 300); // Adjust timeout as needed
}, []);
function handleClick(e: React.MouseEvent) {
if (link === "") {
@ -69,7 +80,7 @@ export default function ProfileImage({
}
return (
<>
<div className="avatar-wrapper" ref={ref}>
<div className="avatar-wrapper" onMouseEnter={handleMouseEnter}>
<Avatar
pubkey={pubkey}
user={user}
@ -103,8 +114,12 @@ export default function ProfileImage({
}
function profileCard() {
if ((showProfileCard ?? true) && user) {
return <ProfileCard pubkey={pubkey} user={user} show={hovering} ref={ref} />;
if ((showProfileCard ?? true) && user && isHovering) {
return (
<div className="absolute shadow-lg z-10">
<ProfileCard pubkey={pubkey} user={user} show={true} />
</div>
);
}
return null;
}
@ -120,7 +135,7 @@ export default function ProfileImage({
);
} else {
return (
<>
<div className="relative" onMouseLeave={handleMouseLeave}>
<ProfileLink
pubkey={pubkey}
className={classNames("pfp", className)}
@ -130,7 +145,7 @@ export default function ProfileImage({
{inner()}
</ProfileLink>
{profileCard()}
</>
</div>
);
}
}