feat: highlight reply if visible, render it as floating preview if not visible

This commit is contained in:
Tom (plebeius.eth)
2024-06-07 15:26:46 +02:00
parent 81972c9c85
commit fc21d876ff
4 changed files with 87 additions and 8 deletions
@@ -287,7 +287,7 @@ const PostDesktop = ({ openReplyModal, post, roles, showAllReplies, showReplies
<div key={index} className={styles.replyContainer} ref={(el) => (replyRefs.current[index] = el)}> <div key={index} className={styles.replyContainer} ref={(el) => (replyRefs.current[index] = el)}>
<div className={styles.replyDesktop}> <div className={styles.replyDesktop}>
<div className={styles.sideArrows}>{'>>'}</div> <div className={styles.sideArrows}>{'>>'}</div>
<div className={`${styles.reply} ${isRouteLinkToReply && styles.highlight}`}> <div className={`${styles.reply} ${isRouteLinkToReply && styles.highlight}`} id={reply?.cid}>
<PostInfo openReplyModal={openReplyModal} post={reply} roles={roles} /> <PostInfo openReplyModal={openReplyModal} post={reply} roles={roles} />
{reply.link && isValidURL(reply.link) && <PostMedia post={reply} />} {reply.link && isValidURL(reply.link) && <PostMedia post={reply} />}
{reply.content && <PostMessage post={reply} />} {reply.content && <PostMessage post={reply} />}
@@ -232,7 +232,7 @@ const PostMobile = ({ openReplyModal, post, roles, showAllReplies, showReplies =
<div key={index} className={styles.replyContainer} ref={(el) => (replyRefs.current[index] = el)}> <div key={index} className={styles.replyContainer} ref={(el) => (replyRefs.current[index] = el)}>
<div className={styles.replyMobile}> <div className={styles.replyMobile}>
<div className={styles.reply}> <div className={styles.reply}>
<div className={`${styles.replyContainer} ${isRouteLinkToReply && styles.highlight}`}> <div className={`${styles.replyContainer} ${isRouteLinkToReply && styles.highlight}`} id={reply?.cid}>
<PostInfoAndMedia openReplyModal={openReplyModal} post={reply} roles={roles} /> <PostInfoAndMedia openReplyModal={openReplyModal} post={reply} roles={roles} />
{reply.content && <PostMessageMobile post={reply} />} {reply.content && <PostMessageMobile post={reply} />}
<ReplyBacklinks post={reply} /> <ReplyBacklinks post={reply} />
@@ -15,8 +15,32 @@ interface ReplyQuotePreviewProps {
quotelinkReply?: Comment; quotelinkReply?: Comment;
} }
const handleQuoteHover = (cid: string, onElementOutOfView: () => void) => {
const targetElement = document.getElementById(cid);
if (!targetElement) return;
const isInViewport = (element: HTMLElement) => {
const bounding = element.getBoundingClientRect();
return (
bounding.top >= 0 &&
bounding.left >= 0 &&
bounding.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
bounding.right <= (window.innerWidth || document.documentElement.clientWidth)
);
};
if (isInViewport(targetElement)) {
targetElement.classList.add('highlight');
} else {
targetElement.classList.remove('highlight');
onElementOutOfView();
}
};
const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, isQuotelinkReply }: ReplyQuotePreviewProps) => { const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, isQuotelinkReply }: ReplyQuotePreviewProps) => {
const [hoveredCid, setHoveredCid] = useState<string | null>(null); const [hoveredCid, setHoveredCid] = useState<string | null>(null);
const [outOfViewCid, setOutOfViewCid] = useState<string | null>(null);
const placementRef = useRef<Placement>('right'); const placementRef = useRef<Placement>('right');
const availableWidthRef = useRef<number>(0); const availableWidthRef = useRef<number>(0);
@@ -56,18 +80,37 @@ const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, i
}; };
}, [update]); }, [update]);
const handleMouseOver = (cid: string | undefined) => {
if (!cid) return;
handleQuoteHover(cid, () => setOutOfViewCid(cid));
setHoveredCid(cid);
};
const handleMouseLeave = (cid: string | null) => {
if (cid) {
const targetElement = document.getElementById(cid);
if (targetElement) {
targetElement.classList.remove('highlight');
}
}
setHoveredCid(null);
setOutOfViewCid(null);
};
const replyBacklink = ( const replyBacklink = (
<> <>
<Link <Link
className={styles.backlink} className={styles.backlink}
to={`/p/${backlinkReply?.subplebbitAddress}/c/${backlinkReply?.cid}`} to={`/p/${backlinkReply?.subplebbitAddress}/c/${backlinkReply?.cid}`}
ref={refs.setReference} ref={refs.setReference}
onMouseOver={() => setHoveredCid(backlinkReply?.cid)} onMouseOver={() => handleMouseOver(backlinkReply?.cid)}
onMouseLeave={() => setHoveredCid(null)} onMouseLeave={() => handleMouseLeave(backlinkReply?.cid)}
> >
c/{backlinkReply?.shortCid} c/{backlinkReply?.shortCid}
</Link> </Link>
{hoveredCid === backlinkReply?.cid && {hoveredCid === backlinkReply?.cid &&
outOfViewCid === backlinkReply?.cid &&
createPortal( createPortal(
<div className={styles.replyQuotePreview} ref={refs.setFloating} style={floatingStyles}> <div className={styles.replyQuotePreview} ref={refs.setFloating} style={floatingStyles}>
<Post post={backlinkReply} showReplies={false} /> <Post post={backlinkReply} showReplies={false} />
@@ -83,13 +126,14 @@ const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, i
to={`/p/${quotelinkReply?.subplebbitAddress}/c/${quotelinkReply?.cid}`} to={`/p/${quotelinkReply?.subplebbitAddress}/c/${quotelinkReply?.cid}`}
ref={refs.setReference} ref={refs.setReference}
className={styles.quoteLink} className={styles.quoteLink}
onMouseOver={() => setHoveredCid(quotelinkReply?.cid)} onMouseOver={() => handleMouseOver(quotelinkReply?.cid)}
onMouseLeave={() => setHoveredCid(null)} onMouseLeave={() => handleMouseLeave(quotelinkReply?.cid)}
> >
{`c/${quotelinkReply?.cid && Plebbit.getShortCid(quotelinkReply.cid)}`} {`c/${quotelinkReply?.cid && Plebbit.getShortCid(quotelinkReply.cid)}`}
</Link> </Link>
<br /> <br />
{hoveredCid === quotelinkReply?.cid && {hoveredCid === quotelinkReply?.cid &&
outOfViewCid === quotelinkReply?.cid &&
createPortal( createPortal(
<div className={styles.replyQuotePreview} ref={refs.setFloating} style={floatingStyles}> <div className={styles.replyQuotePreview} ref={refs.setFloating} style={floatingStyles}>
<Post post={quotelinkReply} showReplies={false} /> <Post post={quotelinkReply} showReplies={false} />
@@ -104,6 +148,7 @@ const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, i
const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, isQuotelinkReply }: ReplyQuotePreviewProps) => { const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, isQuotelinkReply }: ReplyQuotePreviewProps) => {
const [hoveredCid, setHoveredCid] = useState<string | null>(null); const [hoveredCid, setHoveredCid] = useState<string | null>(null);
const [outOfViewCid, setOutOfViewCid] = useState<string | null>(null);
const { refs, floatingStyles, update } = useFloating({ const { refs, floatingStyles, update } = useFloating({
placement: 'bottom', placement: 'bottom',
@@ -118,15 +163,39 @@ const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, is
}; };
}, [update]); }, [update]);
const handleMouseOver = (cid: string | undefined) => {
if (!cid) return;
handleQuoteHover(cid, () => setOutOfViewCid(cid));
setHoveredCid(cid);
};
const handleMouseLeave = (cid: string | null) => {
if (cid) {
const targetElement = document.getElementById(cid);
if (targetElement) {
targetElement.classList.remove('highlight');
}
}
setHoveredCid(null);
setOutOfViewCid(null);
};
const replyBacklink = ( const replyBacklink = (
<> <>
<span className={styles.backlink} ref={refs.setReference} onMouseOver={() => setHoveredCid(backlinkReply?.cid)} onMouseLeave={() => setHoveredCid(null)}> <span
className={styles.backlink}
ref={refs.setReference}
onMouseOver={() => handleMouseOver(backlinkReply?.cid)}
onMouseLeave={() => handleMouseLeave(backlinkReply?.cid)}
>
c/{backlinkReply?.shortCid}{' '} c/{backlinkReply?.shortCid}{' '}
</span> </span>
<Link to={`/p/${backlinkReply?.subplebbitAddress}/c/${backlinkReply?.cid}`} className={styles.backlinkHash}> <Link to={`/p/${backlinkReply?.subplebbitAddress}/c/${backlinkReply?.cid}`} className={styles.backlinkHash}>
# #
</Link> </Link>
{hoveredCid === backlinkReply?.cid && {hoveredCid === backlinkReply?.cid &&
outOfViewCid === backlinkReply?.cid &&
createPortal( createPortal(
<div className={styles.replyQuotePreview} ref={refs.setFloating} style={floatingStyles}> <div className={styles.replyQuotePreview} ref={refs.setFloating} style={floatingStyles}>
<Post post={backlinkReply} showReplies={false} /> <Post post={backlinkReply} showReplies={false} />
@@ -138,7 +207,12 @@ const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, is
const replyQuotelink = ( const replyQuotelink = (
<> <>
<span ref={refs.setReference} className={styles.quoteLink} onMouseOver={() => setHoveredCid(quotelinkReply?.cid)} onMouseLeave={() => setHoveredCid(null)}> <span
ref={refs.setReference}
className={styles.quoteLink}
onMouseOver={() => handleMouseOver(quotelinkReply?.cid)}
onMouseLeave={() => handleMouseLeave(quotelinkReply?.cid)}
>
c/{quotelinkReply?.shortCid}{' '} c/{quotelinkReply?.shortCid}{' '}
</span> </span>
<Link className={styles.quoteLink} to={`/p/${quotelinkReply?.subplebbitAddress}/c/${quotelinkReply?.cid}`}> <Link className={styles.quoteLink} to={`/p/${quotelinkReply?.subplebbitAddress}/c/${quotelinkReply?.cid}`}>
@@ -146,6 +220,7 @@ const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, is
</Link> </Link>
<br /> <br />
{hoveredCid === quotelinkReply?.cid && {hoveredCid === quotelinkReply?.cid &&
outOfViewCid === quotelinkReply?.cid &&
createPortal( createPortal(
<div className={styles.replyQuotePreview} ref={refs.setFloating} style={floatingStyles}> <div className={styles.replyQuotePreview} ref={refs.setFloating} style={floatingStyles}>
<Post post={quotelinkReply} showReplies={false} /> <Post post={quotelinkReply} showReplies={false} />
+4
View File
@@ -26,6 +26,10 @@ hr {
color: var(--post-greentext-color); color: var(--post-greentext-color);
} }
.highlight {
background: var(--reply-highlight-background-color) !important;
}
@media (max-width: 640px) { @media (max-width: 640px) {
.button { .button {
font-size: var(--button-font-size-mobile); font-size: var(--button-font-size-mobile);