close profilecard on mouse leave
Some checks failed
continuous-integration/drone/pr Build is failing
Some checks failed
continuous-integration/drone/pr Build is failing
This commit is contained in:
parent
561ee94ab0
commit
a92fc267c3
@ -15,7 +15,6 @@
|
|||||||
"@snort/system-wasm": "workspace:*",
|
"@snort/system-wasm": "workspace:*",
|
||||||
"@snort/system-web": "workspace:*",
|
"@snort/system-web": "workspace:*",
|
||||||
"@szhsin/react-menu": "^3.3.1",
|
"@szhsin/react-menu": "^3.3.1",
|
||||||
"@uidotdev/usehooks": "^2.3.1",
|
|
||||||
"@void-cat/api": "^1.0.10",
|
"@void-cat/api": "^1.0.10",
|
||||||
"classnames": "^2.3.2",
|
"classnames": "^2.3.2",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
|
@ -1,25 +1,35 @@
|
|||||||
import { NostrLink, NostrPrefix } from "@snort/system";
|
import { NostrLink, NostrPrefix } from "@snort/system";
|
||||||
import { useUserProfile } from "@snort/system-react";
|
import { useUserProfile } from "@snort/system-react";
|
||||||
import { useHover } from "@uidotdev/usehooks";
|
|
||||||
|
|
||||||
import DisplayName from "@/Element/User/DisplayName";
|
import DisplayName from "@/Element/User/DisplayName";
|
||||||
import { ProfileCard } from "@/Element/User/ProfileCard";
|
import { ProfileCard } from "@/Element/User/ProfileCard";
|
||||||
import { ProfileLink } from "@/Element/User/ProfileLink";
|
import { ProfileLink } from "@/Element/User/ProfileLink";
|
||||||
|
import { useCallback, useRef, useState } from "react";
|
||||||
|
|
||||||
export default function Mention({ link }: { link: NostrLink }) {
|
export default function Mention({ link }: { link: NostrLink }) {
|
||||||
const [ref, hovering] = useHover<HTMLAnchorElement>();
|
|
||||||
const profile = useUserProfile(link.id);
|
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;
|
if (link.type !== NostrPrefix.Profile && link.type !== NostrPrefix.PublicKey) return;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<span className="highlight" onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>
|
||||||
<ProfileLink pubkey={link.id} link={link} user={profile} onClick={e => e.stopPropagation()}>
|
<ProfileLink pubkey={link.id} link={link} user={profile} onClick={e => e.stopPropagation()}>
|
||||||
<span ref={ref}>
|
@<DisplayName user={profile} pubkey={link.id} />
|
||||||
@<DisplayName user={profile} pubkey={link.id} />
|
|
||||||
</span>
|
|
||||||
</ProfileLink>
|
</ProfileLink>
|
||||||
<ProfileCard pubkey={link.id} user={profile} show={hovering} ref={ref} />
|
{isHovering && <ProfileCard pubkey={link.id} user={profile} show={true} />}
|
||||||
</>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -10,28 +10,15 @@ import Text from "@/Element/Text";
|
|||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import useLogin from "../../Hooks/useLogin";
|
import useLogin from "../../Hooks/useLogin";
|
||||||
|
|
||||||
interface RectElement {
|
|
||||||
getBoundingClientRect(): {
|
|
||||||
left: number;
|
|
||||||
right: number;
|
|
||||||
top: number;
|
|
||||||
bottom: number;
|
|
||||||
width: number;
|
|
||||||
height: number;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function ProfileCard({
|
export function ProfileCard({
|
||||||
pubkey,
|
pubkey,
|
||||||
user,
|
user,
|
||||||
show,
|
show,
|
||||||
ref,
|
|
||||||
delay,
|
delay,
|
||||||
}: {
|
}: {
|
||||||
pubkey: string;
|
pubkey: string;
|
||||||
user?: UserMetadata;
|
user?: UserMetadata;
|
||||||
show: boolean;
|
show: boolean;
|
||||||
ref: React.RefObject<Element | RectElement>;
|
|
||||||
delay?: number;
|
delay?: number;
|
||||||
}) {
|
}) {
|
||||||
const [showProfileMenu, setShowProfileMenu] = useState(false);
|
const [showProfileMenu, setShowProfileMenu] = useState(false);
|
||||||
@ -56,7 +43,6 @@ export function ProfileCard({
|
|||||||
return (
|
return (
|
||||||
<ControlledMenu
|
<ControlledMenu
|
||||||
state={showProfileMenu ? "open" : "closed"}
|
state={showProfileMenu ? "open" : "closed"}
|
||||||
anchorRef={ref}
|
|
||||||
menuClassName="profile-card"
|
menuClassName="profile-card"
|
||||||
onClose={() => setShowProfileMenu(false)}
|
onClose={() => setShowProfileMenu(false)}
|
||||||
align="end">
|
align="end">
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import "./ProfileImage.css";
|
import "./ProfileImage.css";
|
||||||
|
|
||||||
import React, { ReactNode } from "react";
|
import React, { ReactNode, useCallback, useRef, useState } from "react";
|
||||||
import { HexKey, socialGraphInstance, UserMetadata } from "@snort/system";
|
import { HexKey, socialGraphInstance, UserMetadata } from "@snort/system";
|
||||||
import { useUserProfile } from "@snort/system-react";
|
import { useUserProfile } from "@snort/system-react";
|
||||||
import { useHover } from "@uidotdev/usehooks";
|
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
|
|
||||||
import Avatar from "@/Element/User/Avatar";
|
import Avatar from "@/Element/User/Avatar";
|
||||||
@ -51,7 +50,19 @@ export default function ProfileImage({
|
|||||||
const user = useUserProfile(profile ? "" : pubkey) ?? profile;
|
const user = useUserProfile(profile ? "" : pubkey) ?? profile;
|
||||||
const nip05 = defaultNip ? defaultNip : user?.nip05;
|
const nip05 = defaultNip ? defaultNip : user?.nip05;
|
||||||
const followDistance = socialGraphInstance.getFollowDistance(pubkey);
|
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) {
|
function handleClick(e: React.MouseEvent) {
|
||||||
if (link === "") {
|
if (link === "") {
|
||||||
@ -69,7 +80,7 @@ export default function ProfileImage({
|
|||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="avatar-wrapper" ref={ref}>
|
<div className="avatar-wrapper" onMouseEnter={handleMouseEnter}>
|
||||||
<Avatar
|
<Avatar
|
||||||
pubkey={pubkey}
|
pubkey={pubkey}
|
||||||
user={user}
|
user={user}
|
||||||
@ -103,8 +114,12 @@ export default function ProfileImage({
|
|||||||
}
|
}
|
||||||
|
|
||||||
function profileCard() {
|
function profileCard() {
|
||||||
if ((showProfileCard ?? true) && user) {
|
if ((showProfileCard ?? true) && user && isHovering) {
|
||||||
return <ProfileCard pubkey={pubkey} user={user} show={hovering} ref={ref} />;
|
return (
|
||||||
|
<div className="absolute shadow-lg z-10">
|
||||||
|
<ProfileCard pubkey={pubkey} user={user} show={true} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -120,7 +135,7 @@ export default function ProfileImage({
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<>
|
<div className="relative" onMouseLeave={handleMouseLeave}>
|
||||||
<ProfileLink
|
<ProfileLink
|
||||||
pubkey={pubkey}
|
pubkey={pubkey}
|
||||||
className={classNames("pfp", className)}
|
className={classNames("pfp", className)}
|
||||||
@ -130,7 +145,7 @@ export default function ProfileImage({
|
|||||||
{inner()}
|
{inner()}
|
||||||
</ProfileLink>
|
</ProfileLink>
|
||||||
{profileCard()}
|
{profileCard()}
|
||||||
</>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user