mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
fix catalog popup positioning logic
This commit is contained in:
@@ -20,17 +20,15 @@ export const Threads = styled.div`
|
|||||||
|
|
||||||
.thread_popup {
|
.thread_popup {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
height: auto;
|
|
||||||
background-color: black;
|
background-color: black;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
margin-top: 0px;
|
margin-top: 0px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
transform:none;
|
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
padding-right: 5px;
|
padding-right: 5px;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
white-space: nowrap;
|
/* overflow-wrap: break-word; */
|
||||||
}
|
}
|
||||||
|
|
||||||
.thread_popup_content {
|
.thread_popup_content {
|
||||||
@@ -40,6 +38,7 @@ export const Threads = styled.div`
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
white-space: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
.thread_popup_lastReply {
|
.thread_popup_lastReply {
|
||||||
@@ -47,7 +46,6 @@ export const Threads = styled.div`
|
|||||||
color: #bbbfbd;
|
color: #bbbfbd;
|
||||||
display: block;
|
display: block;
|
||||||
min-width: 250px;
|
min-width: 250px;
|
||||||
text-overflow: ellipsis;
|
|
||||||
font-size: 90%;
|
font-size: 90%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -82,10 +82,14 @@ const CatalogPost = ({post}) => {
|
|||||||
const imageRef = useRef(null);
|
const imageRef = useRef(null);
|
||||||
const [isEnoughSpaceOnRight, setIsEnoughSpaceOnRight] = useState(null);
|
const [isEnoughSpaceOnRight, setIsEnoughSpaceOnRight] = useState(null);
|
||||||
const [isEnoughSpaceOnLeft,setIsEnoughSpaceOnLeft] = useState(null);
|
const [isEnoughSpaceOnLeft,setIsEnoughSpaceOnLeft] = useState(null);
|
||||||
|
const [spaceOnLeft,setSpaceOnLeft] = useState(null);
|
||||||
|
const [spaceOnRight,setSpaceOnRight] = useState(null);
|
||||||
const [isCalculationDone,setIsCalculationDone] = useState(false);
|
const [isCalculationDone,setIsCalculationDone] = useState(false);
|
||||||
const [hoverTimeoutId, setHoverTimeoutId] = useState(null);
|
const [hoverTimeoutId, setHoverTimeoutId] = useState(null);
|
||||||
|
const [isHoveringForMenu, setIsHoveringForMenu] = useState(false);
|
||||||
const textRect = textRef.current?.getBoundingClientRect();
|
const textRect = textRef.current?.getBoundingClientRect();
|
||||||
const imageRect = imageRef.current?.getBoundingClientRect();
|
const imageRect = imageRef.current?.getBoundingClientRect();
|
||||||
|
const popupRect = popupRef.current?.getBoundingClientRect();
|
||||||
const isMediaShowed = (thread.link && commentMediaInfo && (
|
const isMediaShowed = (thread.link && commentMediaInfo && (
|
||||||
commentMediaInfo.type === 'image' ||
|
commentMediaInfo.type === 'image' ||
|
||||||
commentMediaInfo.type === 'video' ||
|
commentMediaInfo.type === 'video' ||
|
||||||
@@ -95,31 +99,38 @@ const CatalogPost = ({post}) => {
|
|||||||
commentMediaInfo.thumbnail))) ? true : false;
|
commentMediaInfo.thumbnail))) ? true : false;
|
||||||
|
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
const executeLayoutEffectLogic = () => {
|
const executeLayoutEffectLogic = () => {
|
||||||
let ref;
|
let ref;
|
||||||
ref = threadRefs.current[isHoveringOnThread];
|
if (isMediaShowed) {
|
||||||
|
ref = imageRef.current;
|
||||||
if (ref && popupRef.current) {
|
} else {
|
||||||
const threadRect = ref.getBoundingClientRect();
|
ref = textRef.current;
|
||||||
const popupRect = popupRef.current.getBoundingClientRect();
|
}
|
||||||
const viewportWidth = document.documentElement.clientWidth;
|
|
||||||
const spaceOnRight = viewportWidth - (threadRect.left + threadRect.width);
|
if (ref && popupRef.current) {
|
||||||
const spaceOnLeft = threadRect.left;
|
const threadRect = ref.getBoundingClientRect();
|
||||||
const popupWidth = popupRect.width;
|
const viewportWidth = document.documentElement.clientWidth;
|
||||||
setIsEnoughSpaceOnLeft(spaceOnLeft >= popupWidth + 10);
|
const spaceRight = viewportWidth - (threadRect.left + threadRect.width);
|
||||||
setIsEnoughSpaceOnRight(spaceOnRight >= popupWidth + 10);
|
const spaceLeft = threadRect.left;
|
||||||
setIsCalculationDone(true);
|
setIsEnoughSpaceOnLeft(spaceLeft > 500);
|
||||||
|
setIsEnoughSpaceOnRight(spaceRight > 500);
|
||||||
|
setSpaceOnRight(spaceRight);
|
||||||
|
setSpaceOnLeft(spaceLeft);
|
||||||
|
setIsCalculationDone(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isHoveringOnThread) {
|
||||||
|
const timeoutId = setTimeout(executeLayoutEffectLogic, 250);
|
||||||
|
return () => {
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
setIsCalculationDone(false);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
}, [isHoveringOnThread, isMediaShowed]);
|
||||||
if (isHoveringOnThread) {
|
|
||||||
const timeoutId = setTimeout(executeLayoutEffectLogic, 250);
|
|
||||||
return () => clearTimeout(timeoutId);
|
|
||||||
}
|
|
||||||
|
|
||||||
}, [isHoveringOnThread]);
|
|
||||||
|
|
||||||
|
|
||||||
const handleMouseOnLeaveThread = () => {
|
const handleMouseOnLeaveThread = () => {
|
||||||
if (hoverTimeoutId) {
|
if (hoverTimeoutId) {
|
||||||
@@ -343,42 +354,45 @@ const CatalogPost = ({post}) => {
|
|||||||
onMouseLeave={() => {handleMouseOnLeaveThread()}}>
|
onMouseLeave={() => {handleMouseOnLeaveThread()}}>
|
||||||
{isHoveringOnThread === thread.cid ?
|
{isHoveringOnThread === thread.cid ?
|
||||||
<div ref={popupRef}
|
<div ref={popupRef}
|
||||||
|
className="thread_popup"
|
||||||
onMouseOver={() => handleMouseOnLeaveThread()}
|
onMouseOver={() => handleMouseOnLeaveThread()}
|
||||||
style={{
|
style={{
|
||||||
opacity: isCalculationDone && isEnoughSpaceOnRight !== null ? 1 : 0,
|
opacity: isCalculationDone && isEnoughSpaceOnRight !== null ? 1 : 0,
|
||||||
visibility: isCalculationDone && isEnoughSpaceOnRight !== null ? 'visible' : 'hidden',
|
visibility: isCalculationDone && isEnoughSpaceOnRight !== null ? 'visible' : 'hidden',
|
||||||
left: isCalculationDone && isEnoughSpaceOnRight !== null && isEnoughSpaceOnRight
|
left:
|
||||||
|
isCalculationDone && isEnoughSpaceOnRight !== null && popupRect.width < spaceOnRight
|
||||||
? isMediaShowed
|
? isMediaShowed
|
||||||
? `calc(50% + ${imageRect.width}px / 2 + 5px)`
|
? `calc(50% + ${imageRect.width}px / 2 + 5px)`
|
||||||
: `calc(50% + ${textRect.width}px / 2 + 5px)`
|
: `calc(50% + ${textRect.width}px / 2 + 5px)`
|
||||||
: 'auto',
|
: 'auto',
|
||||||
right: isCalculationDone && isEnoughSpaceOnRight !== null && !isEnoughSpaceOnRight
|
right:
|
||||||
? isMediaShowed
|
isCalculationDone && isEnoughSpaceOnRight !== null &&
|
||||||
? `calc(50% + ${imageRect.width}px / 2 + 5px)`
|
(popupRect.width > spaceOnRight && spaceOnLeft > spaceOnRight)
|
||||||
: `calc(50% + ${textRect.width}px / 2 + 5px)`
|
? isMediaShowed
|
||||||
|
? `calc(50% + ${imageRect.width}px / 2 + 5px)`
|
||||||
|
: `calc(50% + ${textRect.width}px / 2 + 5px)`
|
||||||
: 'auto',
|
: 'auto',
|
||||||
}}
|
}}>
|
||||||
className="thread_popup">
|
|
||||||
<p
|
<p
|
||||||
style={isEnoughSpaceOnLeft !== null && !isEnoughSpaceOnLeft
|
className="thread_popup_content"
|
||||||
&& !isEnoughSpaceOnRight
|
style={{ width: !isEnoughSpaceOnLeft && !isEnoughSpaceOnRight ? (
|
||||||
?
|
spaceOnLeft > spaceOnRight ? `${spaceOnLeft}px` :
|
||||||
{overflow:"visible",whiteSpace:"normal"}
|
spaceOnLeft < spaceOnRight ? `${spaceOnRight}px` : 'auto') : 'auto'
|
||||||
: null}
|
}}>
|
||||||
className="thread_popup_content">
|
<span className="thread_popup_title" >
|
||||||
<span className="thread_popup_title" >
|
{thread.title ? `${thread.title} ` : "Posted "}
|
||||||
{thread.title ? `${thread.title} ` : "Posted "}
|
</span>
|
||||||
</span>
|
by
|
||||||
by
|
<span className="thread_popup_author">
|
||||||
<span className="thread_popup_author">
|
{thread.author.displayName ?` ${thread.author.displayName} ` : " Anonymous "}
|
||||||
{thread.author.displayName ?` ${thread.author.displayName} ` : " Anonymous "}
|
</span>
|
||||||
</span>
|
|
||||||
{thread.timestamp ? getFormattedTime(thread.timestamp) : null}
|
{thread.timestamp ? getFormattedTime(thread.timestamp) : null}
|
||||||
</p>
|
</p>
|
||||||
<div>
|
<div>
|
||||||
{thread.replyCount > 0 ?
|
{thread.replyCount > 0 ?
|
||||||
<p className="thread_popup_lastReply">
|
<p className="thread_popup_lastReply">
|
||||||
Last reply by <span className="thread_popup_author"> Anonymous </span>
|
Last reply by
|
||||||
|
<span className="thread_popup_author"> Anonymous </span>
|
||||||
{getFormattedTime(thread.lastReplyTimestamp)}
|
{getFormattedTime(thread.lastReplyTimestamp)}
|
||||||
</p>
|
</p>
|
||||||
: null}
|
: null}
|
||||||
@@ -387,7 +401,12 @@ const CatalogPost = ({post}) => {
|
|||||||
: null }
|
: null }
|
||||||
{commentMediaInfo?.url ? (
|
{commentMediaInfo?.url ? (
|
||||||
<Link style={{all: "unset", cursor: "pointer"}} key={`link-`} to={`/p/${thread.subplebbitAddress}/c/${thread.cid}`}
|
<Link style={{all: "unset", cursor: "pointer"}} key={`link-`} to={`/p/${thread.subplebbitAddress}/c/${thread.cid}`}
|
||||||
onClick={() => setSelectedThread(thread.cid)} onMouseOver={() => {setIsHoveringOnThread(thread.cid)}}>
|
onClick={() => setSelectedThread(thread.cid)}
|
||||||
|
onMouseOver={() => {
|
||||||
|
setIsHoveringOnThread(thread.cid);
|
||||||
|
setIsHoveringForMenu(thread.cid);
|
||||||
|
}}
|
||||||
|
onMouseLeave={() => setIsHoveringForMenu(false)}>
|
||||||
{commentMediaInfo?.type === "webpage" ? (
|
{commentMediaInfo?.type === "webpage" ? (
|
||||||
thread.thumbnailUrl ? (
|
thread.thumbnailUrl ? (
|
||||||
<span className="file-thumb" style={{width: displayWidth, height: displayHeight}}>
|
<span className="file-thumb" style={{width: displayWidth, height: displayHeight}}>
|
||||||
@@ -446,7 +465,12 @@ const CatalogPost = ({post}) => {
|
|||||||
tooltipPlace="top" />
|
tooltipPlace="top" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<BoardForm selectedStyle={selectedStyle} onMouseOver={() => handleMouseOnLeaveThread()}
|
<BoardForm selectedStyle={selectedStyle}
|
||||||
|
onMouseOver={() => {
|
||||||
|
setIsHoveringForMenu(thread.cid);
|
||||||
|
handleMouseOnLeaveThread();
|
||||||
|
}}
|
||||||
|
onMouseLeave={() => setIsHoveringForMenu(false)}
|
||||||
style={{ all: "unset"}}>
|
style={{ all: "unset"}}>
|
||||||
<div key={`meta-`} className="meta" title="(R)eplies / (L)ink Replies" >
|
<div key={`meta-`} className="meta" title="(R)eplies / (L)ink Replies" >
|
||||||
R: <b key={`b-`}>{thread.replyCount}</b>
|
R: <b key={`b-`}>{thread.replyCount}</b>
|
||||||
@@ -457,7 +481,7 @@ const CatalogPost = ({post}) => {
|
|||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
<PostMenu
|
<PostMenu
|
||||||
style={{ display: isHoveringOnThread === thread.cid ? 'inline-block' : 'none',
|
style={{ display: isHoveringForMenu === thread.cid ? 'inline-block' : 'none',
|
||||||
position: 'absolute', lineHeight: '1em', marginTop: '-1px', outline: 'none',
|
position: 'absolute', lineHeight: '1em', marginTop: '-1px', outline: 'none',
|
||||||
zIndex: '999'}}
|
zIndex: '999'}}
|
||||||
key={`pmb-`}
|
key={`pmb-`}
|
||||||
@@ -599,7 +623,12 @@ const CatalogPost = ({post}) => {
|
|||||||
onClick={() => setSelectedThread(thread.cid)}>
|
onClick={() => setSelectedThread(thread.cid)}>
|
||||||
<div key={`t-`} className="teaser" style={{maxHeight: `calc(320px - ${displayHeight})`}}
|
<div key={`t-`} className="teaser" style={{maxHeight: `calc(320px - ${displayHeight})`}}
|
||||||
ref={(el) => (threadRefs.current[thread.cid] = el)}>
|
ref={(el) => (threadRefs.current[thread.cid] = el)}>
|
||||||
<span key={`teaser-width${thread.cid}`} ref={textRef} onMouseOver={() => {setIsHoveringOnThread(thread.cid)}}>
|
<span key={`teaser-width${thread.cid}`} ref={textRef}
|
||||||
|
onMouseOver={() => {
|
||||||
|
setIsHoveringOnThread(thread.cid);
|
||||||
|
setIsHoveringForMenu(thread.cid);
|
||||||
|
}}
|
||||||
|
onMouseLeave={() => setIsHoveringForMenu(false)}>
|
||||||
<b key={`b2-`}>{thread.title ? `${thread.title}` : null}</b>
|
<b key={`b2-`}>{thread.title ? `${thread.title}` : null}</b>
|
||||||
{thread.content ? `: ${thread.content}` : null}
|
{thread.content ? `: ${thread.content}` : null}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -90,11 +90,14 @@ const CatalogPost = ({post}) => {
|
|||||||
const imageRef = useRef(null);
|
const imageRef = useRef(null);
|
||||||
const [isEnoughSpaceOnRight, setIsEnoughSpaceOnRight] = useState(null);
|
const [isEnoughSpaceOnRight, setIsEnoughSpaceOnRight] = useState(null);
|
||||||
const [isEnoughSpaceOnLeft,setIsEnoughSpaceOnLeft] = useState(null);
|
const [isEnoughSpaceOnLeft,setIsEnoughSpaceOnLeft] = useState(null);
|
||||||
|
const [spaceOnLeft,setSpaceOnLeft] = useState(null);
|
||||||
|
const [spaceOnRight,setSpaceOnRight] = useState(null);
|
||||||
const [isCalculationDone,setIsCalculationDone] = useState(false);
|
const [isCalculationDone,setIsCalculationDone] = useState(false);
|
||||||
const [hoverTimeoutId, setHoverTimeoutId] = useState(null);
|
const [hoverTimeoutId, setHoverTimeoutId] = useState(null);
|
||||||
const [isHoveringForMenu, setIsHoveringForMenu] = useState(false);
|
const [isHoveringForMenu, setIsHoveringForMenu] = useState(false);
|
||||||
const textRect = textRef.current?.getBoundingClientRect();
|
const textRect = textRef.current?.getBoundingClientRect();
|
||||||
const imageRect = imageRef.current?.getBoundingClientRect();
|
const imageRect = imageRef.current?.getBoundingClientRect();
|
||||||
|
const popupRect = popupRef.current?.getBoundingClientRect();
|
||||||
const isMediaShowed = (thread.link && commentMediaInfo && (
|
const isMediaShowed = (thread.link && commentMediaInfo && (
|
||||||
commentMediaInfo.type === 'image' ||
|
commentMediaInfo.type === 'image' ||
|
||||||
commentMediaInfo.type === 'video' ||
|
commentMediaInfo.type === 'video' ||
|
||||||
@@ -106,31 +109,34 @@ const CatalogPost = ({post}) => {
|
|||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
const executeLayoutEffectLogic = () => {
|
const executeLayoutEffectLogic = () => {
|
||||||
let ref;
|
let ref;
|
||||||
if (isHoveringOnThread === 'rules' || isHoveringOnThread === 'description') {
|
if (isMediaShowed) {
|
||||||
ref = popupRef.current;
|
ref = imageRef.current;
|
||||||
} else {
|
} else {
|
||||||
ref = threadRefs.current[isHoveringOnThread];
|
ref = textRef.current;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ref && popupRef.current) {
|
if (ref && popupRef.current) {
|
||||||
const threadRect = ref.getBoundingClientRect();
|
const threadRect = ref.getBoundingClientRect();
|
||||||
const popupRect = popupRef.current.getBoundingClientRect();
|
|
||||||
const viewportWidth = document.documentElement.clientWidth;
|
const viewportWidth = document.documentElement.clientWidth;
|
||||||
const spaceOnRight = viewportWidth - (threadRect.left + threadRect.width);
|
const spaceRight = viewportWidth - (threadRect.left + threadRect.width);
|
||||||
const spaceOnLeft = threadRect.left;
|
const spaceLeft = threadRect.left;
|
||||||
const popupWidth = popupRect.width;
|
setIsEnoughSpaceOnLeft(spaceLeft > 500);
|
||||||
setIsEnoughSpaceOnLeft(spaceOnLeft >= popupWidth + 10);
|
setIsEnoughSpaceOnRight(spaceRight > 500);
|
||||||
setIsEnoughSpaceOnRight(spaceOnRight >= popupWidth + 10);
|
setSpaceOnRight(spaceRight);
|
||||||
|
setSpaceOnLeft(spaceLeft);
|
||||||
setIsCalculationDone(true);
|
setIsCalculationDone(true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isHoveringOnThread) {
|
if (isHoveringOnThread) {
|
||||||
const timeoutId = setTimeout(executeLayoutEffectLogic, 250);
|
const timeoutId = setTimeout(executeLayoutEffectLogic, 250);
|
||||||
return () => clearTimeout(timeoutId);
|
return () => {
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
setIsCalculationDone(false);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
}, [isHoveringOnThread]);
|
}, [isHoveringOnThread, isMediaShowed]);
|
||||||
|
|
||||||
|
|
||||||
const handleMouseOnLeaveThread = () => {
|
const handleMouseOnLeaveThread = () => {
|
||||||
@@ -588,30 +594,31 @@ const CatalogPost = ({post}) => {
|
|||||||
onMouseLeave={()=>{handleMouseOnLeaveThread()}}>
|
onMouseLeave={()=>{handleMouseOnLeaveThread()}}>
|
||||||
{isHoveringOnThread === thread.cid ?
|
{isHoveringOnThread === thread.cid ?
|
||||||
<div ref={popupRef}
|
<div ref={popupRef}
|
||||||
|
className="thread_popup"
|
||||||
onMouseOver={() => handleMouseOnLeaveThread()}
|
onMouseOver={() => handleMouseOnLeaveThread()}
|
||||||
style={{
|
style={{
|
||||||
opacity: isCalculationDone && isEnoughSpaceOnRight !== null ? 1 : 0,
|
opacity: isCalculationDone && isEnoughSpaceOnRight !== null ? 1 : 0,
|
||||||
visibility: isCalculationDone && isEnoughSpaceOnRight !== null ? 'visible' : 'hidden',
|
visibility: isCalculationDone && isEnoughSpaceOnRight !== null ? 'visible' : 'hidden',
|
||||||
left: isCalculationDone && isEnoughSpaceOnRight !== null && isEnoughSpaceOnRight
|
left:
|
||||||
|
isCalculationDone && isEnoughSpaceOnRight !== null && popupRect.width < spaceOnRight
|
||||||
? isMediaShowed
|
? isMediaShowed
|
||||||
? `calc(50% + ${imageRect.width}px / 2 + 5px)`
|
? `calc(50% + ${imageRect.width}px / 2 + 5px)`
|
||||||
: `calc(50% + ${textRect.width}px / 2 + 5px)`
|
: `calc(50% + ${textRect.width}px / 2 + 5px)`
|
||||||
: 'auto',
|
: 'auto',
|
||||||
right: isCalculationDone && isEnoughSpaceOnRight !== null && !isEnoughSpaceOnRight
|
right:
|
||||||
? isMediaShowed
|
isCalculationDone && isEnoughSpaceOnRight !== null &&
|
||||||
? `calc(50% + ${imageRect.width}px / 2 + 5px)`
|
(popupRect.width > spaceOnRight && spaceOnLeft > spaceOnRight)
|
||||||
: `calc(50% + ${textRect.width}px / 2 + 5px)`
|
? isMediaShowed
|
||||||
|
? `calc(50% + ${imageRect.width}px / 2 + 5px)`
|
||||||
|
: `calc(50% + ${textRect.width}px / 2 + 5px)`
|
||||||
: 'auto',
|
: 'auto',
|
||||||
}}
|
}}>
|
||||||
className="thread_popup">
|
|
||||||
<p
|
<p
|
||||||
style={isEnoughSpaceOnLeft !== null && !isEnoughSpaceOnLeft
|
className="thread_popup_content"
|
||||||
&& !isEnoughSpaceOnRight
|
style={{ width: !isEnoughSpaceOnLeft && !isEnoughSpaceOnRight ? (
|
||||||
?
|
spaceOnLeft > spaceOnRight ? `${spaceOnLeft}px` :
|
||||||
{overflow:"visible",whiteSpace:"normal"}
|
spaceOnLeft < spaceOnRight ? `${spaceOnRight}px` : 'auto') : 'auto'
|
||||||
: null
|
}}>
|
||||||
}
|
|
||||||
className="thread_popup_content">
|
|
||||||
<span className="thread_popup_title" >
|
<span className="thread_popup_title" >
|
||||||
{thread.title ? `${thread.title} ` : "Posted "}
|
{thread.title ? `${thread.title} ` : "Posted "}
|
||||||
</span>
|
</span>
|
||||||
@@ -619,12 +626,15 @@ const CatalogPost = ({post}) => {
|
|||||||
<span className="thread_popup_author">
|
<span className="thread_popup_author">
|
||||||
{thread.author.displayName ?` ${thread.author.displayName} ` : " Anonymous "}
|
{thread.author.displayName ?` ${thread.author.displayName} ` : " Anonymous "}
|
||||||
</span>
|
</span>
|
||||||
{thread.timestamp ? getFormattedTime(thread.timestamp) : null}</p>
|
{thread.timestamp ? getFormattedTime(thread.timestamp) : null}
|
||||||
|
</p>
|
||||||
<div>
|
<div>
|
||||||
{thread.replyCount > 0 ?
|
{thread.replyCount > 0 ?
|
||||||
<p className="thread_popup_lastReply">
|
<p className="thread_popup_lastReply">
|
||||||
Last reply by <span className="thread_popup_author"> Anonymous </span>
|
Last reply by
|
||||||
{getFormattedTime(thread.lastReplyTimestamp)}</p>
|
<span className="thread_popup_author"> Anonymous </span>
|
||||||
|
{getFormattedTime(thread.lastReplyTimestamp)}
|
||||||
|
</p>
|
||||||
: null}
|
: null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -82,10 +82,14 @@ const CatalogPost = ({post}) => {
|
|||||||
const imageRef = useRef(null);
|
const imageRef = useRef(null);
|
||||||
const [isEnoughSpaceOnRight, setIsEnoughSpaceOnRight] = useState(null);
|
const [isEnoughSpaceOnRight, setIsEnoughSpaceOnRight] = useState(null);
|
||||||
const [isEnoughSpaceOnLeft,setIsEnoughSpaceOnLeft] = useState(null);
|
const [isEnoughSpaceOnLeft,setIsEnoughSpaceOnLeft] = useState(null);
|
||||||
|
const [spaceOnLeft,setSpaceOnLeft] = useState(null);
|
||||||
|
const [spaceOnRight,setSpaceOnRight] = useState(null);
|
||||||
const [isCalculationDone,setIsCalculationDone] = useState(false);
|
const [isCalculationDone,setIsCalculationDone] = useState(false);
|
||||||
const [hoverTimeoutId, setHoverTimeoutId] = useState(null);
|
const [hoverTimeoutId, setHoverTimeoutId] = useState(null);
|
||||||
|
const [isHoveringForMenu, setIsHoveringForMenu] = useState(false);
|
||||||
const textRect = textRef.current?.getBoundingClientRect();
|
const textRect = textRef.current?.getBoundingClientRect();
|
||||||
const imageRect = imageRef.current?.getBoundingClientRect();
|
const imageRect = imageRef.current?.getBoundingClientRect();
|
||||||
|
const popupRect = popupRef.current?.getBoundingClientRect();
|
||||||
const isMediaShowed = (thread.link && commentMediaInfo && (
|
const isMediaShowed = (thread.link && commentMediaInfo && (
|
||||||
commentMediaInfo.type === 'image' ||
|
commentMediaInfo.type === 'image' ||
|
||||||
commentMediaInfo.type === 'video' ||
|
commentMediaInfo.type === 'video' ||
|
||||||
@@ -95,30 +99,37 @@ const CatalogPost = ({post}) => {
|
|||||||
commentMediaInfo.thumbnail))) ? true : false;
|
commentMediaInfo.thumbnail))) ? true : false;
|
||||||
|
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
const executeLayoutEffectLogic = () => {
|
const executeLayoutEffectLogic = () => {
|
||||||
let ref;
|
let ref;
|
||||||
ref = threadRefs.current[isHoveringOnThread];
|
if (isMediaShowed) {
|
||||||
|
ref = imageRef.current;
|
||||||
if (ref && popupRef.current) {
|
} else {
|
||||||
const threadRect = ref.getBoundingClientRect();
|
ref = textRef.current;
|
||||||
const popupRect = popupRef.current.getBoundingClientRect();
|
}
|
||||||
const viewportWidth = document.documentElement.clientWidth;
|
|
||||||
const spaceOnRight = viewportWidth - (threadRect.left + threadRect.width);
|
if (ref && popupRef.current) {
|
||||||
const spaceOnLeft = threadRect.left;
|
const threadRect = ref.getBoundingClientRect();
|
||||||
const popupWidth = popupRect.width;
|
const viewportWidth = document.documentElement.clientWidth;
|
||||||
setIsEnoughSpaceOnLeft(spaceOnLeft >= popupWidth + 10);
|
const spaceRight = viewportWidth - (threadRect.left + threadRect.width);
|
||||||
setIsEnoughSpaceOnRight(spaceOnRight >= popupWidth + 10);
|
const spaceLeft = threadRect.left;
|
||||||
setIsCalculationDone(true);
|
setIsEnoughSpaceOnLeft(spaceLeft > 500);
|
||||||
|
setIsEnoughSpaceOnRight(spaceRight > 500);
|
||||||
|
setSpaceOnRight(spaceRight);
|
||||||
|
setSpaceOnLeft(spaceLeft);
|
||||||
|
setIsCalculationDone(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isHoveringOnThread) {
|
||||||
|
const timeoutId = setTimeout(executeLayoutEffectLogic, 250);
|
||||||
|
return () => {
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
setIsCalculationDone(false);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
}, [isHoveringOnThread, isMediaShowed]);
|
||||||
if (isHoveringOnThread) {
|
|
||||||
const timeoutId = setTimeout(executeLayoutEffectLogic, 250);
|
|
||||||
return () => clearTimeout(timeoutId);
|
|
||||||
}
|
|
||||||
|
|
||||||
}, [isHoveringOnThread]);
|
|
||||||
|
|
||||||
|
|
||||||
const handleMouseOnLeaveThread = () => {
|
const handleMouseOnLeaveThread = () => {
|
||||||
@@ -343,43 +354,45 @@ const CatalogPost = ({post}) => {
|
|||||||
onMouseLeave={() => {handleMouseOnLeaveThread()}}>
|
onMouseLeave={() => {handleMouseOnLeaveThread()}}>
|
||||||
{isHoveringOnThread === thread.cid ?
|
{isHoveringOnThread === thread.cid ?
|
||||||
<div ref={popupRef}
|
<div ref={popupRef}
|
||||||
|
className="thread_popup"
|
||||||
onMouseOver={() => handleMouseOnLeaveThread()}
|
onMouseOver={() => handleMouseOnLeaveThread()}
|
||||||
style={{
|
style={{
|
||||||
opacity: isCalculationDone && isEnoughSpaceOnRight !== null ? 1 : 0,
|
opacity: isCalculationDone && isEnoughSpaceOnRight !== null ? 1 : 0,
|
||||||
visibility: isCalculationDone && isEnoughSpaceOnRight !== null ? 'visible' : 'hidden',
|
visibility: isCalculationDone && isEnoughSpaceOnRight !== null ? 'visible' : 'hidden',
|
||||||
left: isCalculationDone && isEnoughSpaceOnRight !== null && isEnoughSpaceOnRight
|
left:
|
||||||
|
isCalculationDone && isEnoughSpaceOnRight !== null && popupRect.width < spaceOnRight
|
||||||
? isMediaShowed
|
? isMediaShowed
|
||||||
? `calc(50% + ${imageRect.width}px / 2 + 5px)`
|
? `calc(50% + ${imageRect.width}px / 2 + 5px)`
|
||||||
: `calc(50% + ${textRect.width}px / 2 + 5px)`
|
: `calc(50% + ${textRect.width}px / 2 + 5px)`
|
||||||
: 'auto',
|
: 'auto',
|
||||||
right: isCalculationDone && isEnoughSpaceOnRight !== null && !isEnoughSpaceOnRight
|
right:
|
||||||
? isMediaShowed
|
isCalculationDone && isEnoughSpaceOnRight !== null &&
|
||||||
? `calc(50% + ${imageRect.width}px / 2 + 5px)`
|
(popupRect.width > spaceOnRight && spaceOnLeft > spaceOnRight)
|
||||||
: `calc(50% + ${textRect.width}px / 2 + 5px)`
|
? isMediaShowed
|
||||||
|
? `calc(50% + ${imageRect.width}px / 2 + 5px)`
|
||||||
|
: `calc(50% + ${textRect.width}px / 2 + 5px)`
|
||||||
: 'auto',
|
: 'auto',
|
||||||
}}
|
}}>
|
||||||
className="thread_popup">
|
|
||||||
<p
|
<p
|
||||||
style={isEnoughSpaceOnLeft !== null && !isEnoughSpaceOnLeft
|
className="thread_popup_content"
|
||||||
&& !isEnoughSpaceOnRight
|
style={{ width: !isEnoughSpaceOnLeft && !isEnoughSpaceOnRight ? (
|
||||||
?
|
spaceOnLeft > spaceOnRight ? `${spaceOnLeft}px` :
|
||||||
{overflow:"visible",whiteSpace:"normal"}
|
spaceOnLeft < spaceOnRight ? `${spaceOnRight}px` : 'auto') : 'auto'
|
||||||
: null
|
}}>
|
||||||
}
|
<span className="thread_popup_title" >
|
||||||
className="thread_popup_content">
|
{thread.title ? `${thread.title} ` : "Posted "}
|
||||||
<span className="thread_popup_title" >
|
</span>
|
||||||
{thread.title ? `${thread.title} ` : "Posted "}
|
by
|
||||||
</span>
|
<span className="thread_popup_author">
|
||||||
by
|
{thread.author.displayName ?` ${thread.author.displayName} ` : " Anonymous "}
|
||||||
<span className="thread_popup_author">
|
</span>
|
||||||
{thread.author.displayName ?` ${thread.author.displayName} ` : " Anonymous "}
|
|
||||||
</span>
|
|
||||||
{thread.timestamp ? getFormattedTime(thread.timestamp) : null}
|
{thread.timestamp ? getFormattedTime(thread.timestamp) : null}
|
||||||
</p>
|
</p>
|
||||||
<div>
|
<div>
|
||||||
{thread.replyCount > 0 ?
|
{thread.replyCount > 0 ?
|
||||||
<p className="thread_popup_lastReply">
|
<p className="thread_popup_lastReply">
|
||||||
Last reply by <span className="thread_popup_author"> Anonymous </span>
|
Last reply by
|
||||||
|
<span className="thread_popup_author"> Anonymous </span>
|
||||||
{getFormattedTime(thread.lastReplyTimestamp)}
|
{getFormattedTime(thread.lastReplyTimestamp)}
|
||||||
</p>
|
</p>
|
||||||
: null}
|
: null}
|
||||||
@@ -388,7 +401,12 @@ const CatalogPost = ({post}) => {
|
|||||||
: null }
|
: null }
|
||||||
{commentMediaInfo?.url ? (
|
{commentMediaInfo?.url ? (
|
||||||
<Link style={{all: "unset", cursor: "pointer"}} key={`link-`} to={`/p/${thread.subplebbitAddress}/c/${thread.cid}`}
|
<Link style={{all: "unset", cursor: "pointer"}} key={`link-`} to={`/p/${thread.subplebbitAddress}/c/${thread.cid}`}
|
||||||
onClick={() => setSelectedThread(thread.cid)} onMouseOver={() => {setIsHoveringOnThread(thread.cid)}}>
|
onClick={() => setSelectedThread(thread.cid)}
|
||||||
|
onMouseOver={() => {
|
||||||
|
setIsHoveringOnThread(thread.cid);
|
||||||
|
setIsHoveringForMenu(thread.cid);
|
||||||
|
}}
|
||||||
|
onMouseLeave={() => setIsHoveringForMenu(false)}>
|
||||||
{commentMediaInfo?.type === "webpage" ? (
|
{commentMediaInfo?.type === "webpage" ? (
|
||||||
thread.thumbnailUrl ? (
|
thread.thumbnailUrl ? (
|
||||||
<span className="file-thumb" style={{width: displayWidth, height: displayHeight}}>
|
<span className="file-thumb" style={{width: displayWidth, height: displayHeight}}>
|
||||||
@@ -447,7 +465,12 @@ const CatalogPost = ({post}) => {
|
|||||||
tooltipPlace="top" />
|
tooltipPlace="top" />
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<BoardForm selectedStyle={selectedStyle} onMouseOver={() => handleMouseOnLeaveThread()}
|
<BoardForm selectedStyle={selectedStyle}
|
||||||
|
onMouseOver={() => {
|
||||||
|
setIsHoveringForMenu(thread.cid);
|
||||||
|
handleMouseOnLeaveThread();
|
||||||
|
}}
|
||||||
|
onMouseLeave={() => setIsHoveringForMenu(false)}
|
||||||
style={{ all: "unset"}}>
|
style={{ all: "unset"}}>
|
||||||
<div key={`meta-`} className="meta" title="(R)eplies / (L)ink Replies" >
|
<div key={`meta-`} className="meta" title="(R)eplies / (L)ink Replies" >
|
||||||
R: <b key={`b-`}>{thread.replyCount}</b>
|
R: <b key={`b-`}>{thread.replyCount}</b>
|
||||||
@@ -458,7 +481,7 @@ const CatalogPost = ({post}) => {
|
|||||||
</>
|
</>
|
||||||
) : null}
|
) : null}
|
||||||
<PostMenu
|
<PostMenu
|
||||||
style={{ display: isHoveringOnThread === thread.cid ? 'inline-block' : 'none',
|
style={{ display: isHoveringForMenu === thread.cid ? 'inline-block' : 'none',
|
||||||
position: 'absolute', lineHeight: '1em', marginTop: '-1px', outline: 'none',
|
position: 'absolute', lineHeight: '1em', marginTop: '-1px', outline: 'none',
|
||||||
zIndex: '999'}}
|
zIndex: '999'}}
|
||||||
key={`pmb-`}
|
key={`pmb-`}
|
||||||
@@ -600,7 +623,12 @@ const CatalogPost = ({post}) => {
|
|||||||
onClick={() => setSelectedThread(thread.cid)}>
|
onClick={() => setSelectedThread(thread.cid)}>
|
||||||
<div key={`t-`} className="teaser" style={{maxHeight: `calc(320px - ${displayHeight})`}}
|
<div key={`t-`} className="teaser" style={{maxHeight: `calc(320px - ${displayHeight})`}}
|
||||||
ref={(el) => (threadRefs.current[thread.cid] = el)}>
|
ref={(el) => (threadRefs.current[thread.cid] = el)}>
|
||||||
<span key={`teaser-width${thread.cid}`} ref={textRef} onMouseOver={() => {setIsHoveringOnThread(thread.cid)}}>
|
<span key={`teaser-width${thread.cid}`} ref={textRef}
|
||||||
|
onMouseOver={() => {
|
||||||
|
setIsHoveringOnThread(thread.cid);
|
||||||
|
setIsHoveringForMenu(thread.cid);
|
||||||
|
}}
|
||||||
|
onMouseLeave={() => setIsHoveringForMenu(false)}>
|
||||||
<b key={`b2-`}>{thread.title ? `${thread.title}` : null}</b>
|
<b key={`b2-`}>{thread.title ? `${thread.title}` : null}</b>
|
||||||
{thread.content ? `: ${thread.content}` : null}
|
{thread.content ? `: ${thread.content}` : null}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user