From fc21d876ff253a0dd14a5ba37683bfa854bc4230 Mon Sep 17 00:00:00 2001 From: "Tom (plebeius.eth)" Date: Fri, 7 Jun 2024 15:26:46 +0200 Subject: [PATCH] feat: highlight reply if visible, render it as floating preview if not visible --- .../post/post-desktop/post-desktop.tsx | 2 +- .../post/post-mobile/post-mobile.tsx | 2 +- .../reply-quote-preview.tsx | 87 +++++++++++++++++-- src/index.css | 4 + 4 files changed, 87 insertions(+), 8 deletions(-) diff --git a/src/components/post/post-desktop/post-desktop.tsx b/src/components/post/post-desktop/post-desktop.tsx index 99919d6c..2d8b8d8c 100644 --- a/src/components/post/post-desktop/post-desktop.tsx +++ b/src/components/post/post-desktop/post-desktop.tsx @@ -287,7 +287,7 @@ const PostDesktop = ({ openReplyModal, post, roles, showAllReplies, showReplies
(replyRefs.current[index] = el)}>
{'>>'}
-
+
{reply.link && isValidURL(reply.link) && } {reply.content && } diff --git a/src/components/post/post-mobile/post-mobile.tsx b/src/components/post/post-mobile/post-mobile.tsx index b35f4b4b..75be17c9 100644 --- a/src/components/post/post-mobile/post-mobile.tsx +++ b/src/components/post/post-mobile/post-mobile.tsx @@ -232,7 +232,7 @@ const PostMobile = ({ openReplyModal, post, roles, showAllReplies, showReplies =
(replyRefs.current[index] = el)}>
-
+
{reply.content && } diff --git a/src/components/post/reply-quote-preview/reply-quote-preview.tsx b/src/components/post/reply-quote-preview/reply-quote-preview.tsx index c01fa8b0..a054fe15 100644 --- a/src/components/post/reply-quote-preview/reply-quote-preview.tsx +++ b/src/components/post/reply-quote-preview/reply-quote-preview.tsx @@ -15,8 +15,32 @@ interface ReplyQuotePreviewProps { 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 [hoveredCid, setHoveredCid] = useState(null); + const [outOfViewCid, setOutOfViewCid] = useState(null); const placementRef = useRef('right'); const availableWidthRef = useRef(0); @@ -56,18 +80,37 @@ const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, i }; }, [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 = ( <> setHoveredCid(backlinkReply?.cid)} - onMouseLeave={() => setHoveredCid(null)} + onMouseOver={() => handleMouseOver(backlinkReply?.cid)} + onMouseLeave={() => handleMouseLeave(backlinkReply?.cid)} > c/{backlinkReply?.shortCid} {hoveredCid === backlinkReply?.cid && + outOfViewCid === backlinkReply?.cid && createPortal(
@@ -83,13 +126,14 @@ const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, i to={`/p/${quotelinkReply?.subplebbitAddress}/c/${quotelinkReply?.cid}`} ref={refs.setReference} className={styles.quoteLink} - onMouseOver={() => setHoveredCid(quotelinkReply?.cid)} - onMouseLeave={() => setHoveredCid(null)} + onMouseOver={() => handleMouseOver(quotelinkReply?.cid)} + onMouseLeave={() => handleMouseLeave(quotelinkReply?.cid)} > {`c/${quotelinkReply?.cid && Plebbit.getShortCid(quotelinkReply.cid)}`}
{hoveredCid === quotelinkReply?.cid && + outOfViewCid === quotelinkReply?.cid && createPortal(
@@ -104,6 +148,7 @@ const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, i const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, isQuotelinkReply }: ReplyQuotePreviewProps) => { const [hoveredCid, setHoveredCid] = useState(null); + const [outOfViewCid, setOutOfViewCid] = useState(null); const { refs, floatingStyles, update } = useFloating({ placement: 'bottom', @@ -118,15 +163,39 @@ const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, is }; }, [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 = ( <> - setHoveredCid(backlinkReply?.cid)} onMouseLeave={() => setHoveredCid(null)}> + handleMouseOver(backlinkReply?.cid)} + onMouseLeave={() => handleMouseLeave(backlinkReply?.cid)} + > c/{backlinkReply?.shortCid}{' '} # {hoveredCid === backlinkReply?.cid && + outOfViewCid === backlinkReply?.cid && createPortal(
@@ -138,7 +207,12 @@ const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, is const replyQuotelink = ( <> - setHoveredCid(quotelinkReply?.cid)} onMouseLeave={() => setHoveredCid(null)}> + handleMouseOver(quotelinkReply?.cid)} + onMouseLeave={() => handleMouseLeave(quotelinkReply?.cid)} + > c/{quotelinkReply?.shortCid}{' '} @@ -146,6 +220,7 @@ const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, is
{hoveredCid === quotelinkReply?.cid && + outOfViewCid === quotelinkReply?.cid && createPortal(
diff --git a/src/index.css b/src/index.css index 938cfbd0..c8b6c706 100644 --- a/src/index.css +++ b/src/index.css @@ -26,6 +26,10 @@ hr { color: var(--post-greentext-color); } +.highlight { + background: var(--reply-highlight-background-color) !important; +} + @media (max-width: 640px) { .button { font-size: var(--button-font-size-mobile);