diff --git a/src/components/styled/views/Catalog.styled.jsx b/src/components/styled/views/Catalog.styled.jsx index 7c07c68a..90e0ddad 100644 --- a/src/components/styled/views/Catalog.styled.jsx +++ b/src/components/styled/views/Catalog.styled.jsx @@ -12,57 +12,11 @@ export const Threads = styled.div` max-height: 320px; vertical-align: top; display: inline-block; - word-wrap: break-word; margin-top: 5px; margin-bottom: 20px; padding: 5px 0 3px; } - .thread_popup { - display: inline-block; - background-color: black; - position: absolute; - margin-top: 0px; - text-align: left; - z-index: 10; - padding-left: 5px; - padding-right: 5px; - border-radius: 3px; - /* overflow-wrap: break-word; */ - } - - .thread_popup_content { - max-width: 500px; - margin: 5px 3px 2px 3px !important; - color: #dedede; - display: inline-block; - overflow: hidden; - font-size: 13px; - white-space: normal; - } - - .thread_popup_lastReply { - margin: 0px 4px 5px 4px !important; - color: #bbbfbd; - display: block; - min-width: 250px; - font-size: 90%; - } - - .thread_popup_title { - color:#a89baa - } - - .thread_popup_author { - color:#519860; - font-weight: bold - } - - .thread_popup_authorAdmin { - color: purple; - font-weight: 700; - } - video, audio, img { max-width: 150px; max-height: 150px; @@ -137,82 +91,162 @@ export const Threads = styled.div` display: block; padding: 0 15px; overflow: hidden; + word-wrap: break-word; } + + ${({ selectedStyle }) => { + switch (selectedStyle) { + case 'Yotsuba': + return ``; + + case 'Yotsuba-B': + return ``; + + case 'Futaba': + return ``; + + case 'Burichan': + return ``; + + case 'Tomorrow': + return ` + .file-thumb { + background-color: rgba(255, 255, 255, 0.01) !important; + }`; + + case 'Photon': + return ``; + + default: + return ''; + } + }} +`; + +export const PostPreview = styled.div` + .post-preview { + position: absolute; + background-color: #000; + border-radius: 3px; + padding: 5px 8px 4px; + z-index: 100000; + word-wrap: break-word; + white-space: normal; + max-width: 500px; + width: fit-content; + color: #bbbfbd; + font-size: 10pt; + text-align: left; + } + + .post-author { + font-weight: 700; + } + + .post-last { + margin-top: 3px; + color: #bbbfbd; + font-size: 90%; + } + + .post-authorAdmin { + color: purple; + font-weight: 700; + } + + ${({ selectedStyle }) => { switch (selectedStyle) { case 'Yotsuba': return ` - .thread_popup_title{ + .post-subject{ color:#cc1105; font-weight:700; }; - .thread_popup_author{ + + .post-author{ color:#00a550;font-weight:bold }`; - case 'Yotsuba-B': - return ` - .thread_popup_title{ - color:#dedede; - font-weight:700; - }; - .thread_popup_author{ - color:#00a550;font-weight:bold - }`; - case 'Futaba': - return ` - .thread_popup{ - font-family: arial,helvetica,sans-serif; - } - .thread_popup_title{ - color:#cc1105; - font-weight:700; - }; - .thread_popup_author{ - color:#00a550;font-weight:700; - }`; - case 'Burichan': - return ` - .thread_popup{ - font-family: arial,helvetica,sans-serif; - } - .thread_popup_title{ - color:#dedede; - font-weight:700; - }; - .thread_popup_author{ - color:#00a550;font-weight:700; - }`; - case 'Tomorrow': - return ` - .thread_popup{ - font-family: arial,helvetica,sans-serif; - } - .file-thumb { - background-color: rgba(255, 255, 255, 0.01) !important; - } - .thread_popup_title{ - color:#b294bb; - font-weight:700; - }; - .thread_popup_author{ - color:#00a550;font-weight:700; - }`; - case 'Photon': - return ` - .thread_popup{ - font-family: arial,helvetica,sans-serif; - } - .thread_popup_title{ - color:#dedede; - font-weight:700; - }; - .thread_popup_author{ - color:#dedede;font-weight:700; - }`; + + case 'Yotsuba-B': + return ` + .post-subject{ + color:#dedede; + font-weight:700; + }; + + .post-author{ + color:#00a550;font-weight:bold + }`; + + case 'Futaba': + return ` + .post-preview{ + font-family: arial,helvetica,sans-serif; + } + + .post-subject{ + color:#cc1105; + font-weight:700; + }; + + .post-author{ + color:#00a550;font-weight:700; + }`; + + case 'Burichan': + return ` + .post-preview{ + font-family: arial,helvetica,sans-serif; + } + + .post-subject{ + color:#dedede; + font-weight:700; + }; + + .post-author{ + color:#00a550;font-weight:700; + }`; + + case 'Tomorrow': + return ` + .post-preview{ + font-family: arial,helvetica,sans-serif; + } + + .file-thumb { + background-color: rgba(255, 255, 255, 0.01) !important; + } + + .post-subject{ + color:#b294bb; + font-weight:700; + }; + + .post-author{ + color:#00a550;font-weight:700; + }`; + + case 'Photon': + return ` + .post-preview{ + font-family: arial,helvetica,sans-serif; + } + + .post-subject{ + color:#dedede; + font-weight:700; + }; + + .post-author{ + color:#dedede;font-weight:700; + }`; default: return ''; - }}} + } + }} `; export const PostMenuCatalog = styled.div` @@ -250,7 +284,7 @@ export const PostMenuCatalog = styled.div` ${({ selectedStyle }) => { switch (selectedStyle) { case 'Yotsuba': - return `.thread_popup_title{ + return `.post-subject{ color:red; }`; diff --git a/src/components/views/AllCatalog.jsx b/src/components/views/AllCatalog.jsx index dec549a0..4ab042a6 100755 --- a/src/components/views/AllCatalog.jsx +++ b/src/components/views/AllCatalog.jsx @@ -8,7 +8,7 @@ import { Virtuoso } from 'react-virtuoso'; import { useAccount, useFeed, usePublishCommentEdit, useSubplebbit, useSubplebbits } from '@plebbit/plebbit-react-hooks'; import { debounce } from 'lodash'; import { Container, NavBar, Header, Break, PostMenu, BoardForm } from '../styled/views/Board.styled'; -import { Threads, PostMenuCatalog } from '../styled/views/Catalog.styled'; +import { Threads, PostPreview, PostMenuCatalog } from '../styled/views/Catalog.styled'; import { TopBar, Footer } from '../styled/views/Thread.styled'; import { AlertModal } from '../styled/modals/AlertModal.styled'; import CatalogLoader from '../CatalogLoader'; @@ -61,6 +61,7 @@ const CatalogPost = ({post}) => { const fallbackImgUrl = "assets/filedeleted-res.gif"; const [isHoveringOnThread, setIsHoveringOnThread] = useState(false); const [menuPosition, setMenuPosition] = useState({top: 0, left: 0}); + const [popupPosition, setPopupPosition] = useState({top: 0, left: 0}); const [openMenuCid, setOpenMenuCid] = useState(null); const [triggerPublishCommentEdit, setTriggerPublishCommentEdit] = useState(false); const [isImageSearchOpen, setIsImageSearchOpen] = useState(false); @@ -74,16 +75,13 @@ const CatalogPost = ({post}) => { const account = useAccount(); const subplebbit = useSubplebbit({subplebbitAddress: thread.subplebbitAddress}); const threadMenuRefs = useRef({}); + const threadRefs = useRef({}); const postMenuRef = useRef(null); const postMenuCatalogRef = useRef(null); const popupRef = useRef(null); - const threadRefs = useRef([]); const textRef = useRef(null); 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 [spaceOnRight, setSpaceOnRight] = useState(null); const [isCalculationDone,setIsCalculationDone] = useState(false); const [hoverTimeoutId, setHoverTimeoutId] = useState(null); const [isHoveringForMenu, setIsHoveringForMenu] = useState(false); @@ -99,6 +97,9 @@ const CatalogPost = ({post}) => { commentMediaInfo.thumbnail))) ? true : false; + const { left: textLeft, right: textRight } = textRef.current?.getBoundingClientRect() || {}; + const { left: imageLeft, right: imageRight } = imageRef.current?.getBoundingClientRect() || {}; + useLayoutEffect(() => { const executeLayoutEffectLogic = () => { let ref; @@ -107,20 +108,27 @@ const CatalogPost = ({post}) => { } else { ref = textRef.current; } - + if (ref && popupRef.current) { - const threadRect = ref.getBoundingClientRect(); + const rect = ref.getBoundingClientRect(); const viewportWidth = document.documentElement.clientWidth; - const spaceRight = viewportWidth - (threadRect.left + threadRect.width); - const spaceLeft = threadRect.left; - setIsEnoughSpaceOnLeft(spaceLeft > 500); - setIsEnoughSpaceOnRight(spaceRight > 500); + const spaceRight = viewportWidth - (rect.left + rect.width); + const spaceLeft = rect.left; + const popupWidth = popupRef.current.getBoundingClientRect().width; + + if (spaceRight < 200 && spaceLeft > spaceRight) { + popupRef.current.style.maxWidth = `calc(100vw - ${isMediaShowed ? imageLeft : textLeft}px)`; + } else if (spaceRight < 200 && spaceLeft < spaceRight) { + popupRef.current.style.maxWidth = `calc(100vw - ${isMediaShowed ? imageRight : textRight}px)`; + } else { + popupRef.current.style.maxWidth = `${popupWidth}px`; + } + setSpaceOnRight(spaceRight); - setSpaceOnLeft(spaceLeft); setIsCalculationDone(true); } }; - + if (isHoveringOnThread) { const timeoutId = setTimeout(executeLayoutEffectLogic, 250); return () => { @@ -128,8 +136,8 @@ const CatalogPost = ({post}) => { setIsCalculationDone(false); }; } - - }, [isHoveringOnThread, isMediaShowed]); + + }, [isHoveringOnThread, isMediaShowed, textLeft, textRight, imageLeft, imageRight]); const handleMouseOnLeaveThread = () => { @@ -139,7 +147,6 @@ const CatalogPost = ({post}) => { setIsHoveringOnThread("") } else if (isHoveringOnThread !== "") { setIsHoveringOnThread(""); - setIsEnoughSpaceOnRight(null); setIsCalculationDone(false); } }; @@ -350,291 +357,289 @@ const CatalogPost = ({post}) => { return ( -
{handleMouseOnLeaveThread()}}> + <> {isHoveringOnThread === thread.cid ? -
handleMouseOnLeaveThread()} - style={{ - opacity: isCalculationDone && isEnoughSpaceOnRight !== null ? 1 : 0, - visibility: isCalculationDone && isEnoughSpaceOnRight !== null ? 'visible' : 'hidden', - left: - isCalculationDone && isEnoughSpaceOnRight !== null && popupRect.width < spaceOnRight - ? isMediaShowed - ? `calc(50% + ${imageRect.width}px / 2 + 5px)` - : `calc(50% + ${textRect.width}px / 2 + 5px)` - : 'auto', - 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', - }}> -

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 - {getFormattedTime(thread.lastReplyTimestamp)} -

- : null} -
-
- : null } - {commentMediaInfo?.url ? ( - setSelectedThread(thread.cid)} - onMouseOver={() => { - setIsHoveringOnThread(thread.cid); - setIsHoveringForMenu(thread.cid); + createPortal( + +
handleMouseOnLeaveThread()} + style={{ + visibility: isCalculationDone ? 'visible' : 'hidden', + left: + isCalculationDone && spaceOnRight > 250 + ? isMediaShowed ? imageRect.right + 5 : textRect.right + 5 : + isCalculationDone && spaceOnRight < 250 + ? isMediaShowed ? imageRect.left - popupRect.width - 5 : textRect.left - popupRect.width - 5 + : 'auto', + top: popupPosition.top + 5, + }}> + + {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 + {getFormattedTime(thread.lastReplyTimestamp)} +
+ : null} +
+
, document.body + ) + : null } +
{ + threadRefs.current[thread.cid] = el; }} - onMouseLeave={() => setIsHoveringForMenu(false)}> - {commentMediaInfo?.type === "webpage" ? ( - thread.thumbnailUrl ? ( + onMouseLeave={() => {handleMouseOnLeaveThread()}}> + {commentMediaInfo?.url ? ( + setSelectedThread(thread.cid)} + onMouseOver={() => { + setIsHoveringOnThread(thread.cid); + setIsHoveringForMenu(thread.cid); + const rect = threadRefs.current[thread.cid].getBoundingClientRect(); + setPopupPosition({top: rect.top + window.scrollY, left: rect.left}); + }} + onMouseLeave={() => setIsHoveringForMenu(false)}> + {commentMediaInfo?.type === "webpage" ? ( + thread.thumbnailUrl ? ( + + {commentMediaInfo.type} { + e.target.src = fallbackImgUrl + e.target.onerror = null; + }} /> + + ) : null + ) : null} + {commentMediaInfo?.type === "iframe" && (thread.thumbnailUrl || commentMediaInfo.thumbnail) ? ( {commentMediaInfo.type} { e.target.src = fallbackImgUrl }} /> + + ) : null} + {commentMediaInfo?.type === "image" ? ( + + {commentMediaInfo.type} { e.target.src = fallbackImgUrl - e.target.onerror = null; - }} /> + e.target.onerror = null;}} /> - ) : null - ) : null} - {commentMediaInfo?.type === "iframe" && (thread.thumbnailUrl || commentMediaInfo.thumbnail) ? ( - - {commentMediaInfo.type} { e.target.src = fallbackImgUrl }} /> - - ) : null} - {commentMediaInfo?.type === "image" ? ( - - {commentMediaInfo.type} { - e.target.src = fallbackImgUrl - e.target.onerror = null;}} /> - - ) : null} - {commentMediaInfo?.type === "video" ? ( - - - ) : null} - {commentMediaInfo?.type === "audio" ? ( -
+ ); }; diff --git a/src/components/views/Catalog.jsx b/src/components/views/Catalog.jsx index da1faa87..2287866b 100755 --- a/src/components/views/Catalog.jsx +++ b/src/components/views/Catalog.jsx @@ -8,7 +8,7 @@ import { Virtuoso } from 'react-virtuoso'; import { useAccount, useFeed, usePublishComment, usePublishCommentEdit, useSubplebbit, useSubscribe } from '@plebbit/plebbit-react-hooks'; import { debounce } from 'lodash'; import { Container, NavBar, Header, Break, PostForm, PostFormLink, PostFormTable, PostMenu, BoardForm } from '../styled/views/Board.styled'; -import { Threads, PostMenuCatalog } from '../styled/views/Catalog.styled'; +import { Threads, PostPreview, PostMenuCatalog } from '../styled/views/Catalog.styled'; import { TopBar, Footer } from '../styled/views/Thread.styled'; import { AlertModal } from '../styled/modals/AlertModal.styled'; import EditModal from '../modals/EditModal'; @@ -67,6 +67,7 @@ const CatalogPost = ({post}) => { const fallbackImgUrl = "assets/filedeleted-res.gif"; const [isHoveringOnThread, setIsHoveringOnThread] = useState(false); const [menuPosition, setMenuPosition] = useState({top: 0, left: 0}); + const [popupPosition, setPopupPosition] = useState({top: 0, left: 0}); const [openMenuCid, setOpenMenuCid] = useState(null); const [triggerPublishCommentEdit, setTriggerPublishCommentEdit] = useState(false); const [isImageSearchOpen, setIsImageSearchOpen] = useState(false); @@ -74,7 +75,10 @@ const CatalogPost = ({post}) => { const [commentCid, setCommentCid] = useState(null); const threadMenuRefs = useRef({}); + const threadRefs = useRef({}); const postMenuRef = useRef(null); + const popupRef = useRef(null); + const imageRef = useRef(null); const postMenuCatalogRef = useRef(null); const textRef = useRef(null); const { subplebbitAddress } = useParams(); @@ -85,13 +89,7 @@ const CatalogPost = ({post}) => { const subplebbit = useSubplebbit({subplebbitAddress: selectedAddress}); const account = useAccount(); - const popupRef = useRef(null); - const threadRefs = useRef([]); - 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 [spaceOnRight, setSpaceOnRight] = useState(null); const [isCalculationDone,setIsCalculationDone] = useState(false); const [hoverTimeoutId, setHoverTimeoutId] = useState(null); const [isHoveringForMenu, setIsHoveringForMenu] = useState(false); @@ -106,6 +104,9 @@ const CatalogPost = ({post}) => { (commentMediaInfo.type === 'iframe' && commentMediaInfo.thumbnail))) ? true : false; + const { left: textLeft, right: textRight } = textRef.current?.getBoundingClientRect() || {}; + const { left: imageLeft, right: imageRight } = imageRef.current?.getBoundingClientRect() || {}; + useLayoutEffect(() => { const executeLayoutEffectLogic = () => { let ref; @@ -114,20 +115,27 @@ const CatalogPost = ({post}) => { } else { ref = textRef.current; } - + if (ref && popupRef.current) { - const threadRect = ref.getBoundingClientRect(); + const rect = ref.getBoundingClientRect(); const viewportWidth = document.documentElement.clientWidth; - const spaceRight = viewportWidth - (threadRect.left + threadRect.width); - const spaceLeft = threadRect.left; - setIsEnoughSpaceOnLeft(spaceLeft > 500); - setIsEnoughSpaceOnRight(spaceRight > 500); + const spaceRight = viewportWidth - (rect.left + rect.width); + const spaceLeft = rect.left; + const popupWidth = popupRef.current.getBoundingClientRect().width; + + if (spaceRight < 200 && spaceLeft > spaceRight) { + popupRef.current.style.maxWidth = `calc(100vw - ${isMediaShowed ? imageLeft : textLeft}px)`; + } else if (spaceRight < 200 && spaceLeft < spaceRight) { + popupRef.current.style.maxWidth = `calc(100vw - ${isMediaShowed ? imageRight : textRight}px)`; + } else { + popupRef.current.style.maxWidth = `${popupWidth}px`; + } + setSpaceOnRight(spaceRight); - setSpaceOnLeft(spaceLeft); setIsCalculationDone(true); } }; - + if (isHoveringOnThread) { const timeoutId = setTimeout(executeLayoutEffectLogic, 250); return () => { @@ -135,8 +143,9 @@ const CatalogPost = ({post}) => { setIsCalculationDone(false); }; } - - }, [isHoveringOnThread, isMediaShowed]); + + }, [isHoveringOnThread, isMediaShowed, textLeft, textRight, imageLeft, imageRight]); + const handleMouseOnLeaveThread = () => { @@ -146,7 +155,6 @@ const CatalogPost = ({post}) => { setIsHoveringOnThread("") } else if (isHoveringOnThread !== "") { setIsHoveringOnThread(""); - setIsEnoughSpaceOnRight(null); setIsCalculationDone(false); } }; @@ -590,304 +598,302 @@ const CatalogPost = ({post}) => { ) } else { return ( -
{handleMouseOnLeaveThread()}}> + <> {isHoveringOnThread === thread.cid ? -
handleMouseOnLeaveThread()} - style={{ - opacity: isCalculationDone && isEnoughSpaceOnRight !== null ? 1 : 0, - visibility: isCalculationDone && isEnoughSpaceOnRight !== null ? 'visible' : 'hidden', - left: - isCalculationDone && isEnoughSpaceOnRight !== null && popupRect.width < spaceOnRight - ? isMediaShowed - ? `calc(50% + ${imageRect.width}px / 2 + 5px)` - : `calc(50% + ${textRect.width}px / 2 + 5px)` - : 'auto', - 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', - }}> -

spaceOnRight ? `${spaceOnLeft}px` : - spaceOnLeft < spaceOnRight ? `${spaceOnRight}px` : 'auto') : 'auto' + createPortal( + +

handleMouseOnLeaveThread()} + style={{ + visibility: isCalculationDone ? 'visible' : 'hidden', + left: + isCalculationDone && spaceOnRight > 250 + ? isMediaShowed ? imageRect.right + 5 : textRect.right + 5 : + isCalculationDone && spaceOnRight < 250 + ? isMediaShowed ? imageRect.left - popupRect.width - 5 : textRect.left - popupRect.width - 5 + : 'auto', + top: popupPosition.top + 5, }}> - - {thread.title ? `${thread.title} ` : "Posted "} - - by - - {thread.author.displayName ?` ${thread.author.displayName} ` : " Anonymous "} - - {thread.timestamp ? getFormattedTime(thread.timestamp) : null} -

-
+ + {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 - {getFormattedTime(thread.lastReplyTimestamp)} -

+ Anonymous + {getFormattedTime(thread.lastReplyTimestamp)} +
: null}
-
+ , document.body + ) : null } - {commentMediaInfo?.url ? ( - setSelectedThread(thread.cid)} - onMouseOver={() => { - setIsHoveringOnThread(thread.cid); - setIsHoveringForMenu(thread.cid); - }} - onMouseLeave={() => setIsHoveringForMenu(false)}> - {commentMediaInfo?.type === "webpage" ? ( - thread.thumbnailUrl ? ( +
{ + threadRefs.current[thread.cid] = el; + }} + onMouseLeave={()=>{handleMouseOnLeaveThread()}}> + {commentMediaInfo?.url ? ( + setSelectedThread(thread.cid)} + onMouseOver={() => { + setIsHoveringOnThread(thread.cid); + setIsHoveringForMenu(thread.cid); + const rect = threadRefs.current[thread.cid].getBoundingClientRect(); + setPopupPosition({top: rect.top + window.scrollY, left: rect.left}); + }} + onMouseLeave={() => setIsHoveringForMenu(false)}> + {commentMediaInfo?.type === "webpage" ? ( + thread.thumbnailUrl ? ( + + {commentMediaInfo.type} { + e.target.src = fallbackImgUrl + e.target.onerror = null; + }} /> + + ) : null + ) : null} + {commentMediaInfo?.type === "iframe" && (thread.thumbnailUrl || commentMediaInfo.thumbnail) ? ( {commentMediaInfo.type} { e.target.src = fallbackImgUrl }} /> + + ) : null} + {commentMediaInfo?.type === "image" ? ( + + {commentMediaInfo.type} { e.target.src = fallbackImgUrl - e.target.onerror = null; - }} /> + e.target.onerror = null;}} /> - ) : null - ) : null} - {commentMediaInfo?.type === "iframe" && (thread.thumbnailUrl || commentMediaInfo.thumbnail) ? ( - - {commentMediaInfo.type} { e.target.src = fallbackImgUrl }} /> - - ) : null} - {commentMediaInfo?.type === "image" ? ( - - {commentMediaInfo.type} { - e.target.src = fallbackImgUrl - e.target.onerror = null;}} /> - - ) : null} - {commentMediaInfo?.type === "video" ? ( - - + ) : null} + {commentMediaInfo?.type === "audio" ? ( +
+ ) } }; diff --git a/src/components/views/SubscriptionsCatalog.jsx b/src/components/views/SubscriptionsCatalog.jsx index 7e6333c8..d345c94f 100755 --- a/src/components/views/SubscriptionsCatalog.jsx +++ b/src/components/views/SubscriptionsCatalog.jsx @@ -8,7 +8,7 @@ import { Virtuoso } from 'react-virtuoso'; import { useAccount, useFeed, usePublishCommentEdit, useSubplebbit, useSubplebbits } from '@plebbit/plebbit-react-hooks'; import { debounce } from 'lodash'; import { Container, NavBar, Header, Break, PostMenu, BoardForm } from '../styled/views/Board.styled'; -import { Threads, PostMenuCatalog } from '../styled/views/Catalog.styled'; +import { Threads, PostPreview, PostMenuCatalog } from '../styled/views/Catalog.styled'; import { TopBar, Footer } from '../styled/views/Thread.styled'; import { AlertModal } from '../styled/modals/AlertModal.styled'; import CatalogLoader from '../CatalogLoader'; @@ -61,6 +61,7 @@ const CatalogPost = ({post}) => { const fallbackImgUrl = "assets/filedeleted-res.gif"; const [isHoveringOnThread, setIsHoveringOnThread] = useState(false); const [menuPosition, setMenuPosition] = useState({top: 0, left: 0}); + const [popupPosition, setPopupPosition] = useState({top: 0, left: 0}); const [openMenuCid, setOpenMenuCid] = useState(null); const [triggerPublishCommentEdit, setTriggerPublishCommentEdit] = useState(false); const [isImageSearchOpen, setIsImageSearchOpen] = useState(false); @@ -74,16 +75,13 @@ const CatalogPost = ({post}) => { const account = useAccount(); const subplebbit = useSubplebbit({subplebbitAddress: thread.subplebbitAddress}); const threadMenuRefs = useRef({}); + const threadRefs = useRef({}); const postMenuRef = useRef(null); const postMenuCatalogRef = useRef(null); const popupRef = useRef(null); - const threadRefs = useRef([]); const textRef = useRef(null); 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 [spaceOnRight, setSpaceOnRight] = useState(null); const [isCalculationDone,setIsCalculationDone] = useState(false); const [hoverTimeoutId, setHoverTimeoutId] = useState(null); const [isHoveringForMenu, setIsHoveringForMenu] = useState(false); @@ -99,6 +97,9 @@ const CatalogPost = ({post}) => { commentMediaInfo.thumbnail))) ? true : false; + const { left: textLeft, right: textRight } = textRef.current?.getBoundingClientRect() || {}; + const { left: imageLeft, right: imageRight } = imageRef.current?.getBoundingClientRect() || {}; + useLayoutEffect(() => { const executeLayoutEffectLogic = () => { let ref; @@ -107,20 +108,27 @@ const CatalogPost = ({post}) => { } else { ref = textRef.current; } - + if (ref && popupRef.current) { - const threadRect = ref.getBoundingClientRect(); + const rect = ref.getBoundingClientRect(); const viewportWidth = document.documentElement.clientWidth; - const spaceRight = viewportWidth - (threadRect.left + threadRect.width); - const spaceLeft = threadRect.left; - setIsEnoughSpaceOnLeft(spaceLeft > 500); - setIsEnoughSpaceOnRight(spaceRight > 500); + const spaceRight = viewportWidth - (rect.left + rect.width); + const spaceLeft = rect.left; + const popupWidth = popupRef.current.getBoundingClientRect().width; + + if (spaceRight < 200 && spaceLeft > spaceRight) { + popupRef.current.style.maxWidth = `calc(100vw - ${isMediaShowed ? imageLeft : textLeft}px)`; + } else if (spaceRight < 200 && spaceLeft < spaceRight) { + popupRef.current.style.maxWidth = `calc(100vw - ${isMediaShowed ? imageRight : textRight}px)`; + } else { + popupRef.current.style.maxWidth = `${popupWidth}px`; + } + setSpaceOnRight(spaceRight); - setSpaceOnLeft(spaceLeft); setIsCalculationDone(true); } }; - + if (isHoveringOnThread) { const timeoutId = setTimeout(executeLayoutEffectLogic, 250); return () => { @@ -128,8 +136,8 @@ const CatalogPost = ({post}) => { setIsCalculationDone(false); }; } - - }, [isHoveringOnThread, isMediaShowed]); + + }, [isHoveringOnThread, isMediaShowed, textLeft, textRight, imageLeft, imageRight]); const handleMouseOnLeaveThread = () => { @@ -139,7 +147,6 @@ const CatalogPost = ({post}) => { setIsHoveringOnThread("") } else if (isHoveringOnThread !== "") { setIsHoveringOnThread(""); - setIsEnoughSpaceOnRight(null); setIsCalculationDone(false); } }; @@ -350,291 +357,289 @@ const CatalogPost = ({post}) => { return ( -
{handleMouseOnLeaveThread()}}> + <> {isHoveringOnThread === thread.cid ? -
handleMouseOnLeaveThread()} - style={{ - opacity: isCalculationDone && isEnoughSpaceOnRight !== null ? 1 : 0, - visibility: isCalculationDone && isEnoughSpaceOnRight !== null ? 'visible' : 'hidden', - left: - isCalculationDone && isEnoughSpaceOnRight !== null && popupRect.width < spaceOnRight - ? isMediaShowed - ? `calc(50% + ${imageRect.width}px / 2 + 5px)` - : `calc(50% + ${textRect.width}px / 2 + 5px)` - : 'auto', - 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', - }}> -

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 - {getFormattedTime(thread.lastReplyTimestamp)} -

- : null} -
-
- : null } - {commentMediaInfo?.url ? ( - setSelectedThread(thread.cid)} - onMouseOver={() => { - setIsHoveringOnThread(thread.cid); - setIsHoveringForMenu(thread.cid); + createPortal( + +
handleMouseOnLeaveThread()} + style={{ + visibility: isCalculationDone ? 'visible' : 'hidden', + left: + isCalculationDone && spaceOnRight > 250 + ? isMediaShowed ? imageRect.right + 5 : textRect.right + 5 : + isCalculationDone && spaceOnRight < 250 + ? isMediaShowed ? imageRect.left - popupRect.width - 5 : textRect.left - popupRect.width - 5 + : 'auto', + top: popupPosition.top + 5, + }}> + + {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 + {getFormattedTime(thread.lastReplyTimestamp)} +
+ : null} +
+
, document.body + ) + : null } +
{ + threadRefs.current[thread.cid] = el; }} - onMouseLeave={() => setIsHoveringForMenu(false)}> - {commentMediaInfo?.type === "webpage" ? ( - thread.thumbnailUrl ? ( + onMouseLeave={() => {handleMouseOnLeaveThread()}}> + {commentMediaInfo?.url ? ( + setSelectedThread(thread.cid)} + onMouseOver={() => { + setIsHoveringOnThread(thread.cid); + setIsHoveringForMenu(thread.cid); + const rect = threadRefs.current[thread.cid].getBoundingClientRect(); + setPopupPosition({top: rect.top + window.scrollY, left: rect.left}); + }} + onMouseLeave={() => setIsHoveringForMenu(false)}> + {commentMediaInfo?.type === "webpage" ? ( + thread.thumbnailUrl ? ( + + {commentMediaInfo.type} { + e.target.src = fallbackImgUrl + e.target.onerror = null; + }} /> + + ) : null + ) : null} + {commentMediaInfo?.type === "iframe" && (thread.thumbnailUrl || commentMediaInfo.thumbnail) ? ( {commentMediaInfo.type} { e.target.src = fallbackImgUrl }} /> + + ) : null} + {commentMediaInfo?.type === "image" ? ( + + {commentMediaInfo.type} { e.target.src = fallbackImgUrl - e.target.onerror = null; - }} /> + e.target.onerror = null;}} /> - ) : null - ) : null} - {commentMediaInfo?.type === "iframe" && (thread.thumbnailUrl || commentMediaInfo.thumbnail) ? ( - - {commentMediaInfo.type} { e.target.src = fallbackImgUrl }} /> - - ) : null} - {commentMediaInfo?.type === "image" ? ( - - {commentMediaInfo.type} { - e.target.src = fallbackImgUrl - e.target.onerror = null;}} /> - - ) : null} - {commentMediaInfo?.type === "video" ? ( - - - ) : null} - {commentMediaInfo?.type === "audio" ? ( -
+ ); };