mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
feat: highlight reply if visible, render it as floating preview if not visible
This commit is contained in:
@@ -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} />
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
Reference in New Issue
Block a user