From 7ef7b1e17afdcc0b441e3ae437cb42f6738d5bfa Mon Sep 17 00:00:00 2001 From: "plebeius.eth" Date: Thu, 7 Sep 2023 15:50:27 +0200 Subject: [PATCH] fix catalog popup positioning logic --- .../styled/views/Catalog.styled.jsx | 6 +- src/components/views/AllCatalog.jsx | 133 +++++++++++------- src/components/views/Catalog.jsx | 70 +++++---- src/components/views/SubscriptionsCatalog.jsx | 132 ++++++++++------- 4 files changed, 203 insertions(+), 138 deletions(-) diff --git a/src/components/styled/views/Catalog.styled.jsx b/src/components/styled/views/Catalog.styled.jsx index 6afe8d10..7c07c68a 100644 --- a/src/components/styled/views/Catalog.styled.jsx +++ b/src/components/styled/views/Catalog.styled.jsx @@ -20,17 +20,15 @@ export const Threads = styled.div` .thread_popup { display: inline-block; - height: auto; background-color: black; position: absolute; margin-top: 0px; text-align: left; z-index: 10; - transform:none; padding-left: 5px; padding-right: 5px; border-radius: 3px; - white-space: nowrap; + /* overflow-wrap: break-word; */ } .thread_popup_content { @@ -40,6 +38,7 @@ export const Threads = styled.div` display: inline-block; overflow: hidden; font-size: 13px; + white-space: normal; } .thread_popup_lastReply { @@ -47,7 +46,6 @@ export const Threads = styled.div` color: #bbbfbd; display: block; min-width: 250px; - text-overflow: ellipsis; font-size: 90%; } diff --git a/src/components/views/AllCatalog.jsx b/src/components/views/AllCatalog.jsx index ff21b514..dec549a0 100755 --- a/src/components/views/AllCatalog.jsx +++ b/src/components/views/AllCatalog.jsx @@ -82,10 +82,14 @@ const CatalogPost = ({post}) => { const imageRef = useRef(null); const [isEnoughSpaceOnRight, setIsEnoughSpaceOnRight] = useState(null); const [isEnoughSpaceOnLeft,setIsEnoughSpaceOnLeft] = useState(null); + const [spaceOnLeft,setSpaceOnLeft] = useState(null); + const [spaceOnRight,setSpaceOnRight] = useState(null); const [isCalculationDone,setIsCalculationDone] = useState(false); const [hoverTimeoutId, setHoverTimeoutId] = useState(null); + const [isHoveringForMenu, setIsHoveringForMenu] = useState(false); const textRect = textRef.current?.getBoundingClientRect(); const imageRect = imageRef.current?.getBoundingClientRect(); + const popupRect = popupRef.current?.getBoundingClientRect(); const isMediaShowed = (thread.link && commentMediaInfo && ( commentMediaInfo.type === 'image' || commentMediaInfo.type === 'video' || @@ -95,31 +99,38 @@ const CatalogPost = ({post}) => { commentMediaInfo.thumbnail))) ? true : false; - useLayoutEffect(() => { - const executeLayoutEffectLogic = () => { - let ref; - ref = threadRefs.current[isHoveringOnThread]; - - if (ref && popupRef.current) { - const threadRect = ref.getBoundingClientRect(); - const popupRect = popupRef.current.getBoundingClientRect(); - const viewportWidth = document.documentElement.clientWidth; - const spaceOnRight = viewportWidth - (threadRect.left + threadRect.width); - const spaceOnLeft = threadRect.left; - const popupWidth = popupRect.width; - setIsEnoughSpaceOnLeft(spaceOnLeft >= popupWidth + 10); - setIsEnoughSpaceOnRight(spaceOnRight >= popupWidth + 10); - setIsCalculationDone(true); + useLayoutEffect(() => { + const executeLayoutEffectLogic = () => { + let ref; + if (isMediaShowed) { + ref = imageRef.current; + } else { + ref = textRef.current; + } + + if (ref && popupRef.current) { + const threadRect = ref.getBoundingClientRect(); + const viewportWidth = document.documentElement.clientWidth; + const spaceRight = viewportWidth - (threadRect.left + threadRect.width); + const spaceLeft = threadRect.left; + setIsEnoughSpaceOnLeft(spaceLeft > 500); + setIsEnoughSpaceOnRight(spaceRight > 500); + setSpaceOnRight(spaceRight); + setSpaceOnLeft(spaceLeft); + setIsCalculationDone(true); + } + }; + + if (isHoveringOnThread) { + const timeoutId = setTimeout(executeLayoutEffectLogic, 250); + return () => { + clearTimeout(timeoutId); + setIsCalculationDone(false); + }; } - }; - - if (isHoveringOnThread) { - const timeoutId = setTimeout(executeLayoutEffectLogic, 250); - return () => clearTimeout(timeoutId); - } - - }, [isHoveringOnThread]); - + + }, [isHoveringOnThread, isMediaShowed]); + const handleMouseOnLeaveThread = () => { if (hoverTimeoutId) { @@ -343,42 +354,45 @@ const CatalogPost = ({post}) => { onMouseLeave={() => {handleMouseOnLeaveThread()}}> {isHoveringOnThread === thread.cid ?
handleMouseOnLeaveThread()} style={{ opacity: isCalculationDone && isEnoughSpaceOnRight !== null ? 1 : 0, visibility: isCalculationDone && isEnoughSpaceOnRight !== null ? 'visible' : 'hidden', - left: isCalculationDone && isEnoughSpaceOnRight !== null && isEnoughSpaceOnRight + left: + isCalculationDone && isEnoughSpaceOnRight !== null && popupRect.width < spaceOnRight ? isMediaShowed - ? `calc(50% + ${imageRect.width}px / 2 + 5px)` - : `calc(50% + ${textRect.width}px / 2 + 5px)` + ? `calc(50% + ${imageRect.width}px / 2 + 5px)` + : `calc(50% + ${textRect.width}px / 2 + 5px)` : 'auto', - right: isCalculationDone && isEnoughSpaceOnRight !== null && !isEnoughSpaceOnRight - ? isMediaShowed - ? `calc(50% + ${imageRect.width}px / 2 + 5px)` - : `calc(50% + ${textRect.width}px / 2 + 5px)` + right: + isCalculationDone && isEnoughSpaceOnRight !== null && + (popupRect.width > spaceOnRight && spaceOnLeft > spaceOnRight) + ? isMediaShowed + ? `calc(50% + ${imageRect.width}px / 2 + 5px)` + : `calc(50% + ${textRect.width}px / 2 + 5px)` : 'auto', - }} - className="thread_popup"> + }}>

- - {thread.title ? `${thread.title} ` : "Posted "} - - by - - {thread.author.displayName ?` ${thread.author.displayName} ` : " Anonymous "} - + className="thread_popup_content" + style={{ width: !isEnoughSpaceOnLeft && !isEnoughSpaceOnRight ? ( + spaceOnLeft > spaceOnRight ? `${spaceOnLeft}px` : + spaceOnLeft < spaceOnRight ? `${spaceOnRight}px` : 'auto') : 'auto' + }}> + + {thread.title ? `${thread.title} ` : "Posted "} + + by + + {thread.author.displayName ?` ${thread.author.displayName} ` : " Anonymous "} + {thread.timestamp ? getFormattedTime(thread.timestamp) : null}

{thread.replyCount > 0 ? -

- Last reply by Anonymous +

+ Last reply by + Anonymous {getFormattedTime(thread.lastReplyTimestamp)}

: null} @@ -387,7 +401,12 @@ const CatalogPost = ({post}) => { : null } {commentMediaInfo?.url ? ( setSelectedThread(thread.cid)} onMouseOver={() => {setIsHoveringOnThread(thread.cid)}}> + onClick={() => setSelectedThread(thread.cid)} + onMouseOver={() => { + setIsHoveringOnThread(thread.cid); + setIsHoveringForMenu(thread.cid); + }} + onMouseLeave={() => setIsHoveringForMenu(false)}> {commentMediaInfo?.type === "webpage" ? ( thread.thumbnailUrl ? ( @@ -446,7 +465,12 @@ const CatalogPost = ({post}) => { tooltipPlace="top" /> )}
- handleMouseOnLeaveThread()} + { + setIsHoveringForMenu(thread.cid); + handleMouseOnLeaveThread(); + }} + onMouseLeave={() => setIsHoveringForMenu(false)} style={{ all: "unset"}}>
R: {thread.replyCount} @@ -457,7 +481,7 @@ const CatalogPost = ({post}) => { ) : null} { onClick={() => setSelectedThread(thread.cid)}>
(threadRefs.current[thread.cid] = el)}> - {setIsHoveringOnThread(thread.cid)}}> + { + setIsHoveringOnThread(thread.cid); + setIsHoveringForMenu(thread.cid); + }} + onMouseLeave={() => setIsHoveringForMenu(false)}> {thread.title ? `${thread.title}` : null} {thread.content ? `: ${thread.content}` : null} diff --git a/src/components/views/Catalog.jsx b/src/components/views/Catalog.jsx index 2dcf81b6..da1faa87 100755 --- a/src/components/views/Catalog.jsx +++ b/src/components/views/Catalog.jsx @@ -90,11 +90,14 @@ const CatalogPost = ({post}) => { const imageRef = useRef(null); const [isEnoughSpaceOnRight, setIsEnoughSpaceOnRight] = useState(null); const [isEnoughSpaceOnLeft,setIsEnoughSpaceOnLeft] = useState(null); + const [spaceOnLeft,setSpaceOnLeft] = useState(null); + const [spaceOnRight,setSpaceOnRight] = useState(null); const [isCalculationDone,setIsCalculationDone] = useState(false); const [hoverTimeoutId, setHoverTimeoutId] = useState(null); const [isHoveringForMenu, setIsHoveringForMenu] = useState(false); const textRect = textRef.current?.getBoundingClientRect(); const imageRect = imageRef.current?.getBoundingClientRect(); + const popupRect = popupRef.current?.getBoundingClientRect(); const isMediaShowed = (thread.link && commentMediaInfo && ( commentMediaInfo.type === 'image' || commentMediaInfo.type === 'video' || @@ -106,31 +109,34 @@ const CatalogPost = ({post}) => { useLayoutEffect(() => { const executeLayoutEffectLogic = () => { let ref; - if (isHoveringOnThread === 'rules' || isHoveringOnThread === 'description') { - ref = popupRef.current; + if (isMediaShowed) { + ref = imageRef.current; } else { - ref = threadRefs.current[isHoveringOnThread]; + ref = textRef.current; } if (ref && popupRef.current) { const threadRect = ref.getBoundingClientRect(); - const popupRect = popupRef.current.getBoundingClientRect(); const viewportWidth = document.documentElement.clientWidth; - const spaceOnRight = viewportWidth - (threadRect.left + threadRect.width); - const spaceOnLeft = threadRect.left; - const popupWidth = popupRect.width; - setIsEnoughSpaceOnLeft(spaceOnLeft >= popupWidth + 10); - setIsEnoughSpaceOnRight(spaceOnRight >= popupWidth + 10); + const spaceRight = viewportWidth - (threadRect.left + threadRect.width); + const spaceLeft = threadRect.left; + setIsEnoughSpaceOnLeft(spaceLeft > 500); + setIsEnoughSpaceOnRight(spaceRight > 500); + setSpaceOnRight(spaceRight); + setSpaceOnLeft(spaceLeft); setIsCalculationDone(true); } }; if (isHoveringOnThread) { const timeoutId = setTimeout(executeLayoutEffectLogic, 250); - return () => clearTimeout(timeoutId); + return () => { + clearTimeout(timeoutId); + setIsCalculationDone(false); + }; } - }, [isHoveringOnThread]); + }, [isHoveringOnThread, isMediaShowed]); const handleMouseOnLeaveThread = () => { @@ -588,30 +594,31 @@ const CatalogPost = ({post}) => { onMouseLeave={()=>{handleMouseOnLeaveThread()}}> {isHoveringOnThread === thread.cid ?
handleMouseOnLeaveThread()} style={{ opacity: isCalculationDone && isEnoughSpaceOnRight !== null ? 1 : 0, visibility: isCalculationDone && isEnoughSpaceOnRight !== null ? 'visible' : 'hidden', - left: isCalculationDone && isEnoughSpaceOnRight !== null && isEnoughSpaceOnRight + left: + isCalculationDone && isEnoughSpaceOnRight !== null && popupRect.width < spaceOnRight ? isMediaShowed - ? `calc(50% + ${imageRect.width}px / 2 + 5px)` - : `calc(50% + ${textRect.width}px / 2 + 5px)` + ? `calc(50% + ${imageRect.width}px / 2 + 5px)` + : `calc(50% + ${textRect.width}px / 2 + 5px)` : 'auto', - right: isCalculationDone && isEnoughSpaceOnRight !== null && !isEnoughSpaceOnRight - ? isMediaShowed - ? `calc(50% + ${imageRect.width}px / 2 + 5px)` - : `calc(50% + ${textRect.width}px / 2 + 5px)` + right: + isCalculationDone && isEnoughSpaceOnRight !== null && + (popupRect.width > spaceOnRight && spaceOnLeft > spaceOnRight) + ? isMediaShowed + ? `calc(50% + ${imageRect.width}px / 2 + 5px)` + : `calc(50% + ${textRect.width}px / 2 + 5px)` : 'auto', - }} - className="thread_popup"> + }}>

+ className="thread_popup_content" + style={{ width: !isEnoughSpaceOnLeft && !isEnoughSpaceOnRight ? ( + spaceOnLeft > spaceOnRight ? `${spaceOnLeft}px` : + spaceOnLeft < spaceOnRight ? `${spaceOnRight}px` : 'auto') : 'auto' + }}> {thread.title ? `${thread.title} ` : "Posted "} @@ -619,12 +626,15 @@ const CatalogPost = ({post}) => { {thread.author.displayName ?` ${thread.author.displayName} ` : " Anonymous "} - {thread.timestamp ? getFormattedTime(thread.timestamp) : null}

+ {thread.timestamp ? getFormattedTime(thread.timestamp) : null} +

{thread.replyCount > 0 ?

- Last reply by Anonymous - {getFormattedTime(thread.lastReplyTimestamp)}

+ Last reply by + Anonymous + {getFormattedTime(thread.lastReplyTimestamp)} +

: null}
diff --git a/src/components/views/SubscriptionsCatalog.jsx b/src/components/views/SubscriptionsCatalog.jsx index 7c63673c..7e6333c8 100755 --- a/src/components/views/SubscriptionsCatalog.jsx +++ b/src/components/views/SubscriptionsCatalog.jsx @@ -82,10 +82,14 @@ const CatalogPost = ({post}) => { const imageRef = useRef(null); const [isEnoughSpaceOnRight, setIsEnoughSpaceOnRight] = useState(null); const [isEnoughSpaceOnLeft,setIsEnoughSpaceOnLeft] = useState(null); + const [spaceOnLeft,setSpaceOnLeft] = useState(null); + const [spaceOnRight,setSpaceOnRight] = useState(null); const [isCalculationDone,setIsCalculationDone] = useState(false); const [hoverTimeoutId, setHoverTimeoutId] = useState(null); + const [isHoveringForMenu, setIsHoveringForMenu] = useState(false); const textRect = textRef.current?.getBoundingClientRect(); const imageRect = imageRef.current?.getBoundingClientRect(); + const popupRect = popupRef.current?.getBoundingClientRect(); const isMediaShowed = (thread.link && commentMediaInfo && ( commentMediaInfo.type === 'image' || commentMediaInfo.type === 'video' || @@ -95,30 +99,37 @@ const CatalogPost = ({post}) => { commentMediaInfo.thumbnail))) ? true : false; - useLayoutEffect(() => { - const executeLayoutEffectLogic = () => { - let ref; - ref = threadRefs.current[isHoveringOnThread]; - - if (ref && popupRef.current) { - const threadRect = ref.getBoundingClientRect(); - const popupRect = popupRef.current.getBoundingClientRect(); - const viewportWidth = document.documentElement.clientWidth; - const spaceOnRight = viewportWidth - (threadRect.left + threadRect.width); - const spaceOnLeft = threadRect.left; - const popupWidth = popupRect.width; - setIsEnoughSpaceOnLeft(spaceOnLeft >= popupWidth + 10); - setIsEnoughSpaceOnRight(spaceOnRight >= popupWidth + 10); - setIsCalculationDone(true); + useLayoutEffect(() => { + const executeLayoutEffectLogic = () => { + let ref; + if (isMediaShowed) { + ref = imageRef.current; + } else { + ref = textRef.current; + } + + if (ref && popupRef.current) { + const threadRect = ref.getBoundingClientRect(); + const viewportWidth = document.documentElement.clientWidth; + const spaceRight = viewportWidth - (threadRect.left + threadRect.width); + const spaceLeft = threadRect.left; + setIsEnoughSpaceOnLeft(spaceLeft > 500); + setIsEnoughSpaceOnRight(spaceRight > 500); + setSpaceOnRight(spaceRight); + setSpaceOnLeft(spaceLeft); + setIsCalculationDone(true); + } + }; + + if (isHoveringOnThread) { + const timeoutId = setTimeout(executeLayoutEffectLogic, 250); + return () => { + clearTimeout(timeoutId); + setIsCalculationDone(false); + }; } - }; - - if (isHoveringOnThread) { - const timeoutId = setTimeout(executeLayoutEffectLogic, 250); - return () => clearTimeout(timeoutId); - } - - }, [isHoveringOnThread]); + + }, [isHoveringOnThread, isMediaShowed]); const handleMouseOnLeaveThread = () => { @@ -343,43 +354,45 @@ const CatalogPost = ({post}) => { onMouseLeave={() => {handleMouseOnLeaveThread()}}> {isHoveringOnThread === thread.cid ?
handleMouseOnLeaveThread()} style={{ opacity: isCalculationDone && isEnoughSpaceOnRight !== null ? 1 : 0, visibility: isCalculationDone && isEnoughSpaceOnRight !== null ? 'visible' : 'hidden', - left: isCalculationDone && isEnoughSpaceOnRight !== null && isEnoughSpaceOnRight + left: + isCalculationDone && isEnoughSpaceOnRight !== null && popupRect.width < spaceOnRight ? isMediaShowed - ? `calc(50% + ${imageRect.width}px / 2 + 5px)` - : `calc(50% + ${textRect.width}px / 2 + 5px)` + ? `calc(50% + ${imageRect.width}px / 2 + 5px)` + : `calc(50% + ${textRect.width}px / 2 + 5px)` : 'auto', - right: isCalculationDone && isEnoughSpaceOnRight !== null && !isEnoughSpaceOnRight - ? isMediaShowed - ? `calc(50% + ${imageRect.width}px / 2 + 5px)` - : `calc(50% + ${textRect.width}px / 2 + 5px)` + right: + isCalculationDone && isEnoughSpaceOnRight !== null && + (popupRect.width > spaceOnRight && spaceOnLeft > spaceOnRight) + ? isMediaShowed + ? `calc(50% + ${imageRect.width}px / 2 + 5px)` + : `calc(50% + ${textRect.width}px / 2 + 5px)` : 'auto', - }} - className="thread_popup"> + }}>

- - {thread.title ? `${thread.title} ` : "Posted "} - - by - - {thread.author.displayName ?` ${thread.author.displayName} ` : " Anonymous "} - + className="thread_popup_content" + style={{ width: !isEnoughSpaceOnLeft && !isEnoughSpaceOnRight ? ( + spaceOnLeft > spaceOnRight ? `${spaceOnLeft}px` : + spaceOnLeft < spaceOnRight ? `${spaceOnRight}px` : 'auto') : 'auto' + }}> + + {thread.title ? `${thread.title} ` : "Posted "} + + by + + {thread.author.displayName ?` ${thread.author.displayName} ` : " Anonymous "} + {thread.timestamp ? getFormattedTime(thread.timestamp) : null}

{thread.replyCount > 0 ? -

- Last reply by Anonymous +

+ Last reply by + Anonymous {getFormattedTime(thread.lastReplyTimestamp)}

: null} @@ -388,7 +401,12 @@ const CatalogPost = ({post}) => { : null } {commentMediaInfo?.url ? ( setSelectedThread(thread.cid)} onMouseOver={() => {setIsHoveringOnThread(thread.cid)}}> + onClick={() => setSelectedThread(thread.cid)} + onMouseOver={() => { + setIsHoveringOnThread(thread.cid); + setIsHoveringForMenu(thread.cid); + }} + onMouseLeave={() => setIsHoveringForMenu(false)}> {commentMediaInfo?.type === "webpage" ? ( thread.thumbnailUrl ? ( @@ -447,7 +465,12 @@ const CatalogPost = ({post}) => { tooltipPlace="top" /> )}
- handleMouseOnLeaveThread()} + { + setIsHoveringForMenu(thread.cid); + handleMouseOnLeaveThread(); + }} + onMouseLeave={() => setIsHoveringForMenu(false)} style={{ all: "unset"}}>
R: {thread.replyCount} @@ -458,7 +481,7 @@ const CatalogPost = ({post}) => { ) : null} { onClick={() => setSelectedThread(thread.cid)}>
(threadRefs.current[thread.cid] = el)}> - {setIsHoveringOnThread(thread.cid)}}> + { + setIsHoveringOnThread(thread.cid); + setIsHoveringForMenu(thread.cid); + }} + onMouseLeave={() => setIsHoveringForMenu(false)}> {thread.title ? `${thread.title}` : null} {thread.content ? `: ${thread.content}` : null}