mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
fix catalogs popups logic and styling
This commit is contained in:
@@ -8,8 +8,7 @@ export const Threads = styled.div`
|
|||||||
|
|
||||||
.thread {
|
.thread {
|
||||||
width: 180px;
|
width: 180px;
|
||||||
position:relative;
|
position: relative;
|
||||||
position:relative;
|
|
||||||
max-height: 320px;
|
max-height: 320px;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
@@ -31,6 +30,7 @@ export const Threads = styled.div`
|
|||||||
padding-left:5px;padding-right:5px;
|
padding-left:5px;padding-right:5px;
|
||||||
border-radius:3px;
|
border-radius:3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.thread_popup_content{
|
.thread_popup_content{
|
||||||
color: #dedede;
|
color: #dedede;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
@@ -38,6 +38,7 @@ export const Threads = styled.div`
|
|||||||
white-space:nowrap;
|
white-space:nowrap;
|
||||||
font-size:13px;
|
font-size:13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.thread_popup_lastReply{
|
.thread_popup_lastReply{
|
||||||
color: #bbbfbd;
|
color: #bbbfbd;
|
||||||
display: block;
|
display: block;
|
||||||
@@ -47,34 +48,35 @@ export const Threads = styled.div`
|
|||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
font-size:90%;
|
font-size:90%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.thread_popup_title{
|
.thread_popup_title{
|
||||||
color:#a89baa
|
color:#a89baa
|
||||||
}
|
}
|
||||||
|
|
||||||
.thread_popup_author{
|
.thread_popup_author{
|
||||||
color:#519860;font-weight:bold
|
color:#519860;font-weight:bold
|
||||||
}
|
}
|
||||||
|
|
||||||
.thread_popup_authorAdmin{
|
.thread_popup_authorAdmin{
|
||||||
color:#682071;
|
color:#682071;
|
||||||
}
|
}
|
||||||
|
|
||||||
video, audio, img {
|
video, audio, img {
|
||||||
max-width: 150px;
|
max-width: 150px;
|
||||||
max-height: 150px;
|
max-height: 150px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.file-thumb {
|
.file-thumb {
|
||||||
background-color: rgba(0, 0, 0, 0.05);
|
background-color: rgba(0, 0, 0, 0.05);
|
||||||
display: inline-block;
|
display: inline-flex;
|
||||||
text-align: center;
|
justify-content: center;
|
||||||
line-height: 150px;
|
align-items: center;
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card {
|
.card {
|
||||||
display: inline-block;
|
box-shadow: 0 0 5px rgba(0, 0, 0, .25);
|
||||||
margin: auto;
|
border: 0;
|
||||||
box-shadow: 0 0 5px rgba(0, 0, 0, .25);
|
|
||||||
border: 0;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.thread-icons {
|
.thread-icons {
|
||||||
@@ -133,9 +135,9 @@ export const Threads = styled.div`
|
|||||||
.teaser {
|
.teaser {
|
||||||
display: block;
|
display: block;
|
||||||
padding: 0 15px;
|
padding: 0 15px;
|
||||||
height:200px;
|
overflow: hidden;
|
||||||
overflow:hidden;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
${({ selectedStyle }) => {
|
${({ selectedStyle }) => {
|
||||||
switch (selectedStyle) {
|
switch (selectedStyle) {
|
||||||
case 'Yotsuba':
|
case 'Yotsuba':
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
import React, { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
|
||||||
import { createPortal } from 'react-dom';
|
import { createPortal } from 'react-dom';
|
||||||
import { Helmet } from 'react-helmet-async';
|
import { Helmet } from 'react-helmet-async';
|
||||||
import { Link, useNavigate} from 'react-router-dom';
|
import { Link, useNavigate} from 'react-router-dom';
|
||||||
@@ -21,6 +21,7 @@ import OfflineIndicator from '../OfflineIndicator';
|
|||||||
import SettingsModal from '../modals/SettingsModal';
|
import SettingsModal from '../modals/SettingsModal';
|
||||||
import countLinks from '../../utils/countLinks';
|
import countLinks from '../../utils/countLinks';
|
||||||
import getCommentMediaInfo from '../../utils/getCommentMediaInfo';
|
import getCommentMediaInfo from '../../utils/getCommentMediaInfo';
|
||||||
|
import getFormattedTime from '../../utils/getFormattedTime';
|
||||||
import handleShareClick from '../../utils/handleShareClick';
|
import handleShareClick from '../../utils/handleShareClick';
|
||||||
import handleStyleChange from '../../utils/handleStyleChange';
|
import handleStyleChange from '../../utils/handleStyleChange';
|
||||||
import useError from '../../hooks/useError';
|
import useError from '../../hooks/useError';
|
||||||
@@ -75,6 +76,51 @@ const CatalogPost = ({post}) => {
|
|||||||
const threadMenuRefs = useRef({});
|
const threadMenuRefs = useRef({});
|
||||||
const postMenuRef = useRef(null);
|
const postMenuRef = useRef(null);
|
||||||
const postMenuCatalogRef = useRef(null);
|
const postMenuCatalogRef = useRef(null);
|
||||||
|
const popupRef = useRef(null);
|
||||||
|
const threadRefs = useRef([]);
|
||||||
|
const [isEnoughSpaceOnRight, setIsEnoughSpaceOnRight] = useState(null);
|
||||||
|
const [isEnoughSpaceOnLeft,setIsEnoughSpaceOnLeft] = useState(null);
|
||||||
|
const [isCalculationDone,setIsCalculationDone] = useState(false);
|
||||||
|
const [hoverTimeoutId, setHoverTimeoutId] = useState(null);
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isHoveringOnThread) {
|
||||||
|
const timeoutId = setTimeout(executeLayoutEffectLogic, 500);
|
||||||
|
return () => clearTimeout(timeoutId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}, [isHoveringOnThread]);
|
||||||
|
|
||||||
|
|
||||||
|
const handleMouseOnLeaveThread = () => {
|
||||||
|
if (hoverTimeoutId) {
|
||||||
|
clearTimeout(hoverTimeoutId);
|
||||||
|
setHoverTimeoutId(null);
|
||||||
|
setIsHoveringOnThread("")
|
||||||
|
} else if (isHoveringOnThread !== "") {
|
||||||
|
setIsHoveringOnThread("");
|
||||||
|
setIsEnoughSpaceOnRight(null);
|
||||||
|
setIsCalculationDone(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -272,16 +318,51 @@ const CatalogPost = ({post}) => {
|
|||||||
let scale = Math.min(1, 150 / Math.max(thread.linkWidth, thread.linkHeight));
|
let scale = Math.min(1, 150 / Math.max(thread.linkWidth, thread.linkHeight));
|
||||||
displayWidth = `${thread.linkWidth * scale}px`;
|
displayWidth = `${thread.linkWidth * scale}px`;
|
||||||
displayHeight = `${thread.linkHeight * scale}px`;
|
displayHeight = `${thread.linkHeight * scale}px`;
|
||||||
} else {
|
} else if (thread.link) {
|
||||||
displayWidth = '150px';
|
displayWidth = '150px';
|
||||||
displayHeight = '150px';
|
displayHeight = '150px';
|
||||||
|
} else {
|
||||||
|
displayWidth = '0px';
|
||||||
|
displayHeight = '0px';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={`thread-`} className="thread"
|
<div key={`thread-`} className="thread"
|
||||||
onMouseOver={() => {setIsHoveringOnThread(thread.cid)}}
|
onMouseOver={() => {setIsHoveringOnThread(thread.cid)}}
|
||||||
onMouseLeave={() => {setIsHoveringOnThread('')}}>
|
onMouseLeave={() => {handleMouseOnLeaveThread()}}>
|
||||||
|
{isHoveringOnThread === thread.cid ?
|
||||||
|
<div ref={popupRef}
|
||||||
|
onMouseOver={() => handleMouseOnLeaveThread()}
|
||||||
|
style={{
|
||||||
|
opacity: isCalculationDone && isEnoughSpaceOnRight !== null ? 1 : 0,
|
||||||
|
visibility: isCalculationDone && isEnoughSpaceOnRight !== null ? 'visible' : 'hidden',
|
||||||
|
left: isCalculationDone && isEnoughSpaceOnRight !== null && isEnoughSpaceOnRight ? '100%' : 'auto',
|
||||||
|
right: isCalculationDone && isEnoughSpaceOnRight !== null && !isEnoughSpaceOnRight ? '100%' : 'auto',}}
|
||||||
|
className="thread_popup">
|
||||||
|
<p
|
||||||
|
style={isEnoughSpaceOnLeft !== null && !isEnoughSpaceOnLeft
|
||||||
|
&& !isEnoughSpaceOnRight
|
||||||
|
?
|
||||||
|
{overflow:"visible",whiteSpace:"normal"}
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
className="thread_popup_content">
|
||||||
|
<span className="thread_popup_title" >
|
||||||
|
{thread.title ? `${thread.title} ` : "Posted "}
|
||||||
|
</span>
|
||||||
|
by
|
||||||
|
<span className="thread_popup_author">
|
||||||
|
{thread.author.displayName ?` ${thread.author.displayName} ` : " Anonymous "}
|
||||||
|
</span>
|
||||||
|
{thread.timestamp ? getFormattedTime(thread.timestamp) : null}</p>
|
||||||
|
<div>
|
||||||
|
{thread.replyCount > 0 ?
|
||||||
|
<p className="thread_popup_lastReply">
|
||||||
|
Last reply by <span className="thread_popup_author"> Anonymous </span>
|
||||||
|
{getFormattedTime(thread.lastReplyTimestamp)}</p>
|
||||||
|
: null}</div>
|
||||||
|
</div> : 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)}>
|
onClick={() => setSelectedThread(thread.cid)}>
|
||||||
@@ -491,7 +572,8 @@ const CatalogPost = ({post}) => {
|
|||||||
</BoardForm>
|
</BoardForm>
|
||||||
<Link style={{all: "unset", cursor: "pointer"}} key={`link2-`} to={`/p/${thread.subplebbitAddress}/c/${thread.cid}`}
|
<Link style={{all: "unset", cursor: "pointer"}} key={`link2-`} to={`/p/${thread.subplebbitAddress}/c/${thread.cid}`}
|
||||||
onClick={() => setSelectedThread(thread.cid)}>
|
onClick={() => setSelectedThread(thread.cid)}>
|
||||||
<div key={`t-`} className="teaser">
|
<div key={`t-`} className="teaser" style={{maxHeight: `calc(320px - ${displayHeight})`}}
|
||||||
|
ref={(el) => (threadRefs.current[thread.cid] = el)}>
|
||||||
<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}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+139
-121
@@ -1,4 +1,4 @@
|
|||||||
import React, { useCallback,useLayoutEffect, useEffect, useMemo, useRef, useState } from 'react';
|
import React, { useCallback, useLayoutEffect, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { createPortal } from 'react-dom';
|
import { createPortal } from 'react-dom';
|
||||||
import { Helmet } from 'react-helmet-async';
|
import { Helmet } from 'react-helmet-async';
|
||||||
import { Link, useNavigate, useParams } from 'react-router-dom';
|
import { Link, useNavigate, useParams } from 'react-router-dom';
|
||||||
@@ -23,6 +23,7 @@ import OfflineIndicator from '../OfflineIndicator';
|
|||||||
import VerifiedAuthor from '../VerifiedAuthor';
|
import VerifiedAuthor from '../VerifiedAuthor';
|
||||||
import countLinks from '../../utils/countLinks';
|
import countLinks from '../../utils/countLinks';
|
||||||
import getCommentMediaInfo from '../../utils/getCommentMediaInfo';
|
import getCommentMediaInfo from '../../utils/getCommentMediaInfo';
|
||||||
|
import getFormattedTime from '../../utils/getFormattedTime';
|
||||||
import handleShareClick from '../../utils/handleShareClick';
|
import handleShareClick from '../../utils/handleShareClick';
|
||||||
import handleStyleChange from '../../utils/handleStyleChange';
|
import handleStyleChange from '../../utils/handleStyleChange';
|
||||||
import useAnonModeRef from '../../hooks/useAnonModeRef';
|
import useAnonModeRef from '../../hooks/useAnonModeRef';
|
||||||
@@ -88,64 +89,54 @@ const CatalogPost = ({post}) => {
|
|||||||
const [isEnoughSpaceOnRight, setIsEnoughSpaceOnRight] = useState(null);
|
const [isEnoughSpaceOnRight, setIsEnoughSpaceOnRight] = useState(null);
|
||||||
const [isEnoughSpaceOnLeft,setIsEnoughSpaceOnLeft] = useState(null);
|
const [isEnoughSpaceOnLeft,setIsEnoughSpaceOnLeft] = useState(null);
|
||||||
const [isCalculationDone,setIsCalculationDone] = useState(false);
|
const [isCalculationDone,setIsCalculationDone] = useState(false);
|
||||||
|
const [hoverTimeoutId, setHoverTimeoutId] = useState(null);
|
||||||
|
const [isHoveringForMenu, setIsHoveringForMenu] = useState(false);
|
||||||
|
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
setIsEnoughSpaceOnRight(null);
|
const executeLayoutEffectLogic = () => {
|
||||||
setIsEnoughSpaceOnLeft(null);
|
let ref;
|
||||||
const calculateSpaceOnRight = () => {
|
if (isHoveringOnThread === 'rules' || isHoveringOnThread === 'description') {
|
||||||
if (thread.cid === isHoveringOnThread){
|
ref = popupRef.current;
|
||||||
if(threadRefs.current[thread.cid] && popupRef.current) {
|
} else {
|
||||||
const threadRect = threadRefs.current[thread.cid].getBoundingClientRect();
|
ref = threadRefs.current[isHoveringOnThread];
|
||||||
const popupRect = popupRef.current.getBoundingClientRect();
|
}
|
||||||
// Get the width of the viewport area inside the browser window
|
|
||||||
const viewportWidth = document.documentElement.clientWidth;
|
|
||||||
|
|
||||||
// Calculate the space on the right side (relative to the viewport)
|
if (ref && popupRef.current) {
|
||||||
const spaceOnRight = viewportWidth - (threadRect.left + threadRect.width);
|
const threadRect = ref.getBoundingClientRect();
|
||||||
const spaceOnLeft = threadRect.left;
|
const popupRect = popupRef.current.getBoundingClientRect();
|
||||||
// Define the popup width
|
const viewportWidth = document.documentElement.clientWidth;
|
||||||
const popupWidth = popupRect.width;
|
const spaceOnRight = viewportWidth - (threadRect.left + threadRect.width);
|
||||||
// Check if there is enough space for the popup on the right side
|
const spaceOnLeft = threadRect.left;
|
||||||
const EnoughSpaceOnRight = spaceOnRight >= popupWidth + 10;
|
const popupWidth = popupRect.width;
|
||||||
const EnoughSpaceOnLeft = spaceOnLeft >= popupWidth + 10;
|
setIsEnoughSpaceOnLeft(spaceOnLeft >= popupWidth + 10);
|
||||||
setIsEnoughSpaceOnLeft(EnoughSpaceOnLeft);
|
setIsEnoughSpaceOnRight(spaceOnRight >= popupWidth + 10);
|
||||||
setIsEnoughSpaceOnRight(EnoughSpaceOnRight);
|
setIsCalculationDone(true);
|
||||||
return setIsCalculationDone(true);
|
}
|
||||||
}}
|
|
||||||
};
|
};
|
||||||
if(!isCalculationDone && isHoveringOnThread){
|
|
||||||
calculateSpaceOnRight();
|
if (isHoveringOnThread) {
|
||||||
|
const timeoutId = setTimeout(executeLayoutEffectLogic, 500);
|
||||||
|
return () => clearTimeout(timeoutId);
|
||||||
}
|
}
|
||||||
|
|
||||||
}, [isHoveringOnThread]);
|
}, [isHoveringOnThread]);
|
||||||
|
|
||||||
const timeElapsedCalc = (date) => {
|
|
||||||
const currentDateTime = new Date()
|
|
||||||
const targetToDate = new Date(date * 1000 ); // unix timestamp * 1000
|
|
||||||
const monthNames = ["January", "February", "March", "April", "May", "June",
|
|
||||||
"July", "August", "September", "October", "November", "December"
|
|
||||||
];
|
|
||||||
const targetDateTime = new Date(`${monthNames[targetToDate.getMonth()]} ${targetToDate.getDate()} ${targetToDate.getFullYear()} ${targetToDate.getHours()}:${targetToDate.getMinutes()}:${targetToDate.getSeconds()}`)
|
|
||||||
const elapsedDateTime = currentDateTime - targetDateTime;
|
|
||||||
const elapsedDay = Math.floor(elapsedDateTime / (1000 * 60 * 60 * 24));
|
|
||||||
const elapsedHour = Math.floor((elapsedDateTime / (1000 * 60 * 60)) % 24);
|
|
||||||
const elapsedMinute = Math.floor((elapsedDateTime / (1000 * 60)) % 60);
|
|
||||||
|
|
||||||
if(elapsedDay > 0){
|
|
||||||
return `${elapsedDay} ${elapsedDay > 0 ? "days" : "day"}`;
|
|
||||||
}else if(elapsedHour > 0 ){
|
|
||||||
return `${elapsedHour} ${elapsedHour > 0 ? "hours" : "hour"}`;
|
|
||||||
}else if(elapsedMinute > 0){
|
|
||||||
return `${elapsedMinute} ${elapsedMinute > 0 ? "minutes" : "minute"}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleMouseOnLeaveThread = () => {
|
const handleMouseOnLeaveThread = () => {
|
||||||
setIsHoveringOnThread("");
|
setIsHoveringForMenu(false);
|
||||||
setIsEnoughSpaceOnRight(null);
|
if (hoverTimeoutId) {
|
||||||
setIsCalculationDone(false);
|
clearTimeout(hoverTimeoutId);
|
||||||
}
|
setHoverTimeoutId(null);
|
||||||
|
setIsHoveringOnThread("")
|
||||||
|
} else if (isHoveringOnThread !== "") {
|
||||||
|
setIsHoveringOnThread("");
|
||||||
|
setIsEnoughSpaceOnRight(null);
|
||||||
|
setIsCalculationDone(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
const handleOutsideClick = useCallback((e) => {
|
const handleOutsideClick = useCallback((e) => {
|
||||||
if (openMenuCid !== null && !postMenuRef.current.contains(e.target) && !postMenuCatalogRef.current.contains(e.target)) {
|
if (openMenuCid !== null && !postMenuRef.current.contains(e.target) && !postMenuCatalogRef.current.contains(e.target)) {
|
||||||
setOpenMenuCid(null);
|
setOpenMenuCid(null);
|
||||||
@@ -323,32 +314,39 @@ const CatalogPost = ({post}) => {
|
|||||||
let scale = Math.min(1, 150 / Math.max(thread.linkWidth, thread.linkHeight));
|
let scale = Math.min(1, 150 / Math.max(thread.linkWidth, thread.linkHeight));
|
||||||
displayWidth = `${thread.linkWidth * scale}px`;
|
displayWidth = `${thread.linkWidth * scale}px`;
|
||||||
displayHeight = `${thread.linkHeight * scale}px`;
|
displayHeight = `${thread.linkHeight * scale}px`;
|
||||||
} else {
|
} else if (thread.link) {
|
||||||
displayWidth = '150px';
|
displayWidth = '150px';
|
||||||
displayHeight = '150px';
|
displayHeight = '150px';
|
||||||
|
} else {
|
||||||
|
displayWidth = '0px';
|
||||||
|
displayHeight = '0px';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (post.type === 'rules') {
|
if (post.type === 'rules') {
|
||||||
return (
|
return (
|
||||||
<div className='thread'
|
<div className='thread'
|
||||||
onMouseOver={() => setIsHoveringOnThread("rules")}
|
|
||||||
onMouseLeave={()=>{handleMouseOnLeaveThread()}}>
|
onMouseLeave={()=>{handleMouseOnLeaveThread()}}>
|
||||||
{isHoveringOnThread === 'rules' ?
|
{isHoveringOnThread === 'rules' ?
|
||||||
<div style={{left:"100%"}}
|
<div style={{left:"100%"}}
|
||||||
|
onMouseOver={() => setIsHoveringOnThread("")}
|
||||||
className={"thread_popup"}>
|
className={"thread_popup"}>
|
||||||
<p className="thread_popup_content" style={{color:"white"}}>
|
<p className="thread_popup_content" style={{color:"white"}}>
|
||||||
<span className="thread_popup_title">Rules </span>
|
<span className="thread_popup_title">Rules </span>
|
||||||
by
|
by
|
||||||
<span className="thread_popup_authorAdmin"> ## Board Admins </span>
|
<span className="thread_popup_authorAdmin"> ## Board Admins </span>
|
||||||
{timeElapsedCalc(subplebbit.createdAt)}</p>
|
{getFormattedTime(subplebbit.createdAt)}</p>
|
||||||
<div>
|
|
||||||
<p className="thread_popup_content">Last reply by
|
|
||||||
<span className="thread_popup_authorAdmin"> Anonymous </span>
|
|
||||||
560 days ago</p>
|
|
||||||
</div>
|
|
||||||
</div> : null }
|
</div> : null }
|
||||||
<BoardForm selectedStyle={selectedStyle} style={{all: 'unset'}}>
|
<BoardForm selectedStyle={selectedStyle} style={{all: 'unset'}}
|
||||||
|
onMouseOver={() => {
|
||||||
|
setIsHoveringForMenu('rules');
|
||||||
|
if (!hoverTimeoutId) {
|
||||||
|
const timeoutId = setTimeout(() => {
|
||||||
|
setIsHoveringOnThread("rules");
|
||||||
|
}, 500);
|
||||||
|
setHoverTimeoutId(timeoutId);
|
||||||
|
}
|
||||||
|
}}>
|
||||||
<div className='meta' title="(R)eplies / (L)ink Replies">
|
<div className='meta' title="(R)eplies / (L)ink Replies">
|
||||||
R: <b>0</b> / L: <b>0</b>
|
R: <b>0</b> / L: <b>0</b>
|
||||||
<div className='thread-icons'
|
<div className='thread-icons'
|
||||||
@@ -361,7 +359,7 @@ const CatalogPost = ({post}) => {
|
|||||||
imageRendering: "pixelated",}} />
|
imageRendering: "pixelated",}} />
|
||||||
</div>
|
</div>
|
||||||
<PostMenu
|
<PostMenu
|
||||||
style={{ display: isHoveringOnThread === "rules" ? 'inline-block' : 'none',
|
style={{ display: isHoveringForMenu === "rules" ? 'inline-block' : 'none',
|
||||||
position: 'absolute', lineHeight: '1em', marginTop: '-1px', outline: 'none',
|
position: 'absolute', lineHeight: '1em', marginTop: '-1px', outline: 'none',
|
||||||
zIndex: '999'}}
|
zIndex: '999'}}
|
||||||
title="Post menu"
|
title="Post menu"
|
||||||
@@ -407,8 +405,17 @@ const CatalogPost = ({post}) => {
|
|||||||
</PostMenuCatalog>, document.body
|
</PostMenuCatalog>, document.body
|
||||||
)}
|
)}
|
||||||
</BoardForm>
|
</BoardForm>
|
||||||
<Link style={{all: "unset", cursor: "pointer"}} to={`/p/${selectedAddress}/rules`}>
|
<Link style={{all: "unset", cursor: "pointer"}} to={`/p/${selectedAddress}/rules`}
|
||||||
<div className="teaser">
|
onMouseOver={() => {
|
||||||
|
setIsHoveringForMenu('rules');
|
||||||
|
if (!hoverTimeoutId) {
|
||||||
|
const timeoutId = setTimeout(() => {
|
||||||
|
setIsHoveringOnThread("rules");
|
||||||
|
}, 500);
|
||||||
|
setHoverTimeoutId(timeoutId);
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
<div className="teaser" style={{maxHeight: '312px'}}>
|
||||||
<b>Rules</b>
|
<b>Rules</b>
|
||||||
{": " + subplebbit.rules?.map((rule, index) => `${index + 1}. ${rule}`).join(' ')}
|
{": " + subplebbit.rules?.map((rule, index) => `${index + 1}. ${rule}`).join(' ')}
|
||||||
</div>
|
</div>
|
||||||
@@ -419,26 +426,29 @@ const CatalogPost = ({post}) => {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className='thread'
|
<div className='thread'
|
||||||
onMouseOver={() => setIsHoveringOnThread("description")}
|
|
||||||
onMouseLeave={()=>{handleMouseOnLeaveThread()}}>
|
onMouseLeave={()=>{handleMouseOnLeaveThread()}}>
|
||||||
{/* <!-- hovering div --> */}
|
|
||||||
{isHoveringOnThread === 'description' ?
|
{isHoveringOnThread === 'description' ?
|
||||||
<div style={{left:"100%"}}
|
<div style={{left:"100%"}}
|
||||||
|
onMouseOver={() => setIsHoveringOnThread("")}
|
||||||
className={"thread_popup"}>
|
className={"thread_popup"}>
|
||||||
<p className="thread_popup_content" style={{color:"white"}}>
|
<p className="thread_popup_content" style={{color:"white"}}>
|
||||||
<span className="thread_popup_title">Welcome to {subplebbit.title || subplebbit.address} </span>
|
<span className="thread_popup_title">Welcome to {subplebbit.title || subplebbit.address} </span>
|
||||||
by
|
by
|
||||||
<span className="thread_popup_authorAdmin"> ## Board Admins </span>
|
<span className="thread_popup_authorAdmin"> ## Board Admins </span>
|
||||||
{timeElapsedCalc(subplebbit.createdAt)} ago</p>
|
{getFormattedTime(subplebbit.createdAt)}</p>
|
||||||
<div>
|
|
||||||
<p className="thread_popup_content">Last reply by
|
|
||||||
<span className="thread_popup_authorAdmin"> Anonymous </span>
|
|
||||||
560 days ago</p>
|
|
||||||
</div>
|
|
||||||
</div> : null }
|
</div> : null }
|
||||||
<Link style={{all: 'unset', cursor: 'pointer'}} to={`/p/${selectedAddress}/description`}>
|
<Link style={{all: 'unset', cursor: 'pointer'}} to={`/p/${selectedAddress}/description`}>
|
||||||
{subplebbit.suggested?.avatarUrl ? (
|
{subplebbit.suggested?.avatarUrl ? (
|
||||||
<img className='card'
|
<img className='card'
|
||||||
|
onMouseOver={() => {
|
||||||
|
setIsHoveringForMenu('description');
|
||||||
|
if (!hoverTimeoutId) {
|
||||||
|
const timeoutId = setTimeout(() => {
|
||||||
|
setIsHoveringOnThread("description");
|
||||||
|
}, 500);
|
||||||
|
setHoverTimeoutId(timeoutId);
|
||||||
|
}
|
||||||
|
}}
|
||||||
src={subplebbit.suggested.avatarUrl} alt="board avatar" />
|
src={subplebbit.suggested.avatarUrl} alt="board avatar" />
|
||||||
) : null}
|
) : null}
|
||||||
</Link>
|
</Link>
|
||||||
@@ -452,8 +462,17 @@ const CatalogPost = ({post}) => {
|
|||||||
imageRendering: "pixelated",}} />
|
imageRendering: "pixelated",}} />
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
<BoardForm selectedStyle={selectedStyle} style={{all: 'unset'}}>
|
<BoardForm selectedStyle={selectedStyle} style={{all: 'unset'}}
|
||||||
<div style={{marginTop: '5px'}} className='meta' title="(R)eplies / (L)ink Replies">
|
onMouseOver={() => {
|
||||||
|
setIsHoveringForMenu('description');
|
||||||
|
if (!hoverTimeoutId) {
|
||||||
|
const timeoutId = setTimeout(() => {
|
||||||
|
setIsHoveringOnThread("description");
|
||||||
|
}, 500);
|
||||||
|
setHoverTimeoutId(timeoutId);
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
<div className='meta' title="(R)eplies / (L)ink Replies">
|
||||||
R: <b>0</b> / L: <b>0</b>
|
R: <b>0</b> / L: <b>0</b>
|
||||||
{subplebbit.suggested?.avatarUrl ? null : (
|
{subplebbit.suggested?.avatarUrl ? null : (
|
||||||
<div className='thread-icons'
|
<div className='thread-icons'
|
||||||
@@ -467,7 +486,7 @@ const CatalogPost = ({post}) => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<PostMenu
|
<PostMenu
|
||||||
style={{ display: isHoveringOnThread === "description" ? 'inline-block' : 'none',
|
style={{ display: isHoveringForMenu === "description" ? 'inline-block' : 'none',
|
||||||
position: 'absolute', lineHeight: '1em', marginTop: '-1px', outline: 'none',
|
position: 'absolute', lineHeight: '1em', marginTop: '-1px', outline: 'none',
|
||||||
zIndex: '999'}}
|
zIndex: '999'}}
|
||||||
title="Post menu"
|
title="Post menu"
|
||||||
@@ -542,9 +561,17 @@ const CatalogPost = ({post}) => {
|
|||||||
)}
|
)}
|
||||||
</BoardForm>
|
</BoardForm>
|
||||||
<Link style={{all: "unset", cursor: "pointer"}} to={`/p/${selectedAddress}/description`}
|
<Link style={{all: "unset", cursor: "pointer"}} to={`/p/${selectedAddress}/description`}
|
||||||
onClick={() => setSelectedThread("description")}>
|
onClick={() => setSelectedThread("description")} onMouseOver={() => {
|
||||||
<div className="teaser">
|
setIsHoveringForMenu('description');
|
||||||
<b>Welcome to {subplebbit.title || subplebbit.address}</b>
|
if (!hoverTimeoutId) {
|
||||||
|
const timeoutId = setTimeout(() => {
|
||||||
|
setIsHoveringOnThread("description");
|
||||||
|
}, 500);
|
||||||
|
setHoverTimeoutId(timeoutId);
|
||||||
|
}
|
||||||
|
}}>
|
||||||
|
<div className="teaser" style={{maxHeight: '170px'}}>
|
||||||
|
<b>Welcome to {subplebbit.title || subplebbit.address}!</b>
|
||||||
{": " + subplebbit.description}
|
{": " + subplebbit.description}
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
@@ -553,38 +580,40 @@ const CatalogPost = ({post}) => {
|
|||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<div key={`thread-`} className="thread">
|
<div key={`thread-`} className="thread"
|
||||||
{isHoveringOnThread === thread.cid ?
|
onMouseLeave={()=>{handleMouseOnLeaveThread()}} onMouseOver={() => setIsHoveringOnThread(thread.cid)}>
|
||||||
<div ref={popupRef}
|
{isHoveringOnThread === thread.cid ?
|
||||||
style={{
|
<div ref={popupRef}
|
||||||
opacity: isCalculationDone && isEnoughSpaceOnRight !== null ? 1 : 0,
|
onMouseOver={() => handleMouseOnLeaveThread()}
|
||||||
left: isCalculationDone && isEnoughSpaceOnRight !== null && isEnoughSpaceOnRight ? '100%' : 'auto',
|
style={{
|
||||||
right: isCalculationDone && isEnoughSpaceOnRight !== null && !isEnoughSpaceOnRight ? '100%' : 'auto',}}
|
opacity: isCalculationDone && isEnoughSpaceOnRight !== null ? 1 : 0,
|
||||||
className="thread_popup">
|
visibility: isCalculationDone && isEnoughSpaceOnRight !== null ? 'visible' : 'hidden',
|
||||||
<p
|
left: isCalculationDone && isEnoughSpaceOnRight !== null && isEnoughSpaceOnRight ? '100%' : 'auto',
|
||||||
style={isEnoughSpaceOnLeft !== null && !isEnoughSpaceOnLeft
|
right: isCalculationDone && isEnoughSpaceOnRight !== null && !isEnoughSpaceOnRight ? '100%' : 'auto',}}
|
||||||
&& !isEnoughSpaceOnRight
|
className="thread_popup">
|
||||||
?
|
<p
|
||||||
{overflow:"visible",whiteSpace:"normal"}
|
style={isEnoughSpaceOnLeft !== null && !isEnoughSpaceOnLeft
|
||||||
: null
|
&& !isEnoughSpaceOnRight
|
||||||
}
|
?
|
||||||
className="thread_popup_content">
|
{overflow:"visible",whiteSpace:"normal"}
|
||||||
<span className="thread_popup_title" >
|
: null
|
||||||
{thread.title ? `${thread.title} ` : "Posted "}
|
}
|
||||||
</span>
|
className="thread_popup_content">
|
||||||
by
|
<span className="thread_popup_title" >
|
||||||
<span className="thread_popup_author">
|
{thread.title ? `${thread.title} ` : "Posted "}
|
||||||
{thread.author.displayName ?` ${thread.author.displayName} ` : " Anonymous "}
|
</span>
|
||||||
</span>
|
by
|
||||||
{thread.timestamp ? timeElapsedCalc(thread.timestamp) : null} ago</p>
|
<span className="thread_popup_author">
|
||||||
<div>
|
{thread.author.displayName ?` ${thread.author.displayName} ` : " Anonymous "}
|
||||||
{thread.replyCount > 0 ?
|
</span>
|
||||||
<p className="thread_popup_lastReply">
|
{thread.timestamp ? getFormattedTime(thread.timestamp) : null}</p>
|
||||||
Last reply by <span className="thread_popup_author"> Anonymous </span>
|
<div>
|
||||||
{timeElapsedCalc(thread.lastReplyTimestamp)} ago</p>
|
{thread.replyCount > 0 ?
|
||||||
: null}</div>
|
<p className="thread_popup_lastReply">
|
||||||
</div> : null }
|
Last reply by <span className="thread_popup_author"> Anonymous </span>
|
||||||
|
{getFormattedTime(thread.lastReplyTimestamp)}</p>
|
||||||
|
: null}</div>
|
||||||
|
</div> : null }
|
||||||
{commentMediaInfo?.url ? (
|
{commentMediaInfo?.url ? (
|
||||||
<Link style={{all: "unset", cursor: "pointer"}} key={`link-`} to={`/p/${selectedAddress}/c/${thread.cid}`}
|
<Link style={{all: "unset", cursor: "pointer"}} key={`link-`} to={`/p/${selectedAddress}/c/${thread.cid}`}
|
||||||
onClick={() => setSelectedThread(thread.cid)}>
|
onClick={() => setSelectedThread(thread.cid)}>
|
||||||
@@ -593,8 +622,6 @@ const CatalogPost = ({post}) => {
|
|||||||
<span className="file-thumb" style={{width: displayWidth, height: displayHeight}}>
|
<span className="file-thumb" style={{width: displayWidth, height: displayHeight}}>
|
||||||
<img className="card" key={`img-`}
|
<img className="card" key={`img-`}
|
||||||
src={commentMediaInfo.thumbnail} alt={commentMediaInfo.type}
|
src={commentMediaInfo.thumbnail} alt={commentMediaInfo.type}
|
||||||
onMouseOver={() => setIsHoveringOnThread(thread.cid)}
|
|
||||||
onMouseLeave={()=>{handleMouseOnLeaveThread()}}
|
|
||||||
onError={(e) => {
|
onError={(e) => {
|
||||||
e.target.src = fallbackImgUrl
|
e.target.src = fallbackImgUrl
|
||||||
e.target.onerror = null;
|
e.target.onerror = null;
|
||||||
@@ -606,8 +633,6 @@ const CatalogPost = ({post}) => {
|
|||||||
<span className="file-thumb" style={{width: displayWidth, height: displayHeight}}>
|
<span className="file-thumb" style={{width: displayWidth, height: displayHeight}}>
|
||||||
<img className="card" key={`img-`}
|
<img className="card" key={`img-`}
|
||||||
src={commentMediaInfo.url} alt={commentMediaInfo.type}
|
src={commentMediaInfo.url} alt={commentMediaInfo.type}
|
||||||
onMouseOver={() => setIsHoveringOnThread(thread.cid)}
|
|
||||||
onMouseLeave={()=>{handleMouseOnLeaveThread()}}
|
|
||||||
onError={(e) => {
|
onError={(e) => {
|
||||||
e.target.src = fallbackImgUrl
|
e.target.src = fallbackImgUrl
|
||||||
e.target.onerror = null;}} />
|
e.target.onerror = null;}} />
|
||||||
@@ -616,8 +641,6 @@ const CatalogPost = ({post}) => {
|
|||||||
{commentMediaInfo?.type === "video" ? (
|
{commentMediaInfo?.type === "video" ? (
|
||||||
<span className="file-thumb" style={{width: displayWidth, height: displayHeight}}>
|
<span className="file-thumb" style={{width: displayWidth, height: displayHeight}}>
|
||||||
<video className="card" key={`fti-`}
|
<video className="card" key={`fti-`}
|
||||||
onMouseOver={() => setIsHoveringOnThread(thread.cid)}
|
|
||||||
onMouseLeave={()=>{handleMouseOnLeaveThread()}}
|
|
||||||
src={commentMediaInfo.url}
|
src={commentMediaInfo.url}
|
||||||
alt={commentMediaInfo.type}
|
alt={commentMediaInfo.type}
|
||||||
onError={(e) => e.target.src = fallbackImgUrl} />
|
onError={(e) => e.target.src = fallbackImgUrl} />
|
||||||
@@ -628,8 +651,6 @@ const CatalogPost = ({post}) => {
|
|||||||
key={`fti-`}
|
key={`fti-`}
|
||||||
src={commentMediaInfo.url}
|
src={commentMediaInfo.url}
|
||||||
alt={commentMediaInfo.type}
|
alt={commentMediaInfo.type}
|
||||||
onMouseOver={() => setIsHoveringOnThread(thread.cid)}
|
|
||||||
onMouseLeave={()=>{handleMouseOnLeaveThread()}}
|
|
||||||
onError={(e) => e.target.src = fallbackImgUrl} />
|
onError={(e) => e.target.src = fallbackImgUrl} />
|
||||||
) : null}
|
) : null}
|
||||||
</Link>
|
</Link>
|
||||||
@@ -820,11 +841,8 @@ const CatalogPost = ({post}) => {
|
|||||||
</BoardForm>
|
</BoardForm>
|
||||||
<Link style={{all: "unset", cursor: "pointer"}} key={`link2-`} to={`/p/${selectedAddress}/c/${thread.cid}`}
|
<Link style={{all: "unset", cursor: "pointer"}} key={`link2-`} to={`/p/${selectedAddress}/c/${thread.cid}`}
|
||||||
onClick={() => setSelectedThread(thread.cid)}>
|
onClick={() => setSelectedThread(thread.cid)}>
|
||||||
<div key={`t-`} className="teaser">
|
<div key={`t-`} className="teaser" style={{maxHeight: `calc(320px - ${displayHeight})`}}>
|
||||||
<div style={{cursor:"text"}}
|
<div style={{cursor:"text"}}
|
||||||
onMouseOver={() => {
|
|
||||||
!thread.thumbnailUrl && setIsHoveringOnThread(thread.cid)}}
|
|
||||||
onMouseLeave={()=>{handleMouseOnLeaveThread()}}
|
|
||||||
ref={(el) => (threadRefs.current[thread.cid] = el)}>
|
ref={(el) => (threadRefs.current[thread.cid] = el)}>
|
||||||
<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}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
import React, { useCallback, useEffect, useLayoutEffect, useRef, useState } from 'react';
|
||||||
import { createPortal } from 'react-dom';
|
import { createPortal } from 'react-dom';
|
||||||
import { Helmet } from 'react-helmet-async';
|
import { Helmet } from 'react-helmet-async';
|
||||||
import { Link, useNavigate} from 'react-router-dom';
|
import { Link, useNavigate} from 'react-router-dom';
|
||||||
@@ -21,6 +21,7 @@ import OfflineIndicator from '../OfflineIndicator';
|
|||||||
import SettingsModal from '../modals/SettingsModal';
|
import SettingsModal from '../modals/SettingsModal';
|
||||||
import countLinks from '../../utils/countLinks';
|
import countLinks from '../../utils/countLinks';
|
||||||
import getCommentMediaInfo from '../../utils/getCommentMediaInfo';
|
import getCommentMediaInfo from '../../utils/getCommentMediaInfo';
|
||||||
|
import getFormattedTime from '../../utils/getFormattedTime';
|
||||||
import handleShareClick from '../../utils/handleShareClick';
|
import handleShareClick from '../../utils/handleShareClick';
|
||||||
import handleStyleChange from '../../utils/handleStyleChange';
|
import handleStyleChange from '../../utils/handleStyleChange';
|
||||||
import useError from '../../hooks/useError';
|
import useError from '../../hooks/useError';
|
||||||
@@ -75,8 +76,53 @@ const CatalogPost = ({post}) => {
|
|||||||
const threadMenuRefs = useRef({});
|
const threadMenuRefs = useRef({});
|
||||||
const postMenuRef = useRef(null);
|
const postMenuRef = useRef(null);
|
||||||
const postMenuCatalogRef = useRef(null);
|
const postMenuCatalogRef = useRef(null);
|
||||||
|
const popupRef = useRef(null);
|
||||||
|
const threadRefs = useRef([]);
|
||||||
|
const [isEnoughSpaceOnRight, setIsEnoughSpaceOnRight] = useState(null);
|
||||||
|
const [isEnoughSpaceOnLeft,setIsEnoughSpaceOnLeft] = useState(null);
|
||||||
|
const [isCalculationDone,setIsCalculationDone] = useState(false);
|
||||||
|
const [hoverTimeoutId, setHoverTimeoutId] = useState(null);
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isHoveringOnThread) {
|
||||||
|
const timeoutId = setTimeout(executeLayoutEffectLogic, 500);
|
||||||
|
return () => clearTimeout(timeoutId);
|
||||||
|
}
|
||||||
|
|
||||||
|
}, [isHoveringOnThread]);
|
||||||
|
|
||||||
|
|
||||||
|
const handleMouseOnLeaveThread = () => {
|
||||||
|
if (hoverTimeoutId) {
|
||||||
|
clearTimeout(hoverTimeoutId);
|
||||||
|
setHoverTimeoutId(null);
|
||||||
|
setIsHoveringOnThread("")
|
||||||
|
} else if (isHoveringOnThread !== "") {
|
||||||
|
setIsHoveringOnThread("");
|
||||||
|
setIsEnoughSpaceOnRight(null);
|
||||||
|
setIsCalculationDone(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (subplebbit.roles !== undefined) {
|
if (subplebbit.roles !== undefined) {
|
||||||
const role = subplebbit.roles[account?.author.address]?.role;
|
const role = subplebbit.roles[account?.author.address]?.role;
|
||||||
@@ -272,16 +318,51 @@ const CatalogPost = ({post}) => {
|
|||||||
let scale = Math.min(1, 150 / Math.max(thread.linkWidth, thread.linkHeight));
|
let scale = Math.min(1, 150 / Math.max(thread.linkWidth, thread.linkHeight));
|
||||||
displayWidth = `${thread.linkWidth * scale}px`;
|
displayWidth = `${thread.linkWidth * scale}px`;
|
||||||
displayHeight = `${thread.linkHeight * scale}px`;
|
displayHeight = `${thread.linkHeight * scale}px`;
|
||||||
} else {
|
} else if (thread.link) {
|
||||||
displayWidth = '150px';
|
displayWidth = '150px';
|
||||||
displayHeight = '150px';
|
displayHeight = '150px';
|
||||||
|
} else {
|
||||||
|
displayWidth = '0px';
|
||||||
|
displayHeight = '0px';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={`thread-`} className="thread"
|
<div key={`thread-`} className="thread"
|
||||||
onMouseOver={() => {setIsHoveringOnThread(thread.cid)}}
|
onMouseOver={() => {setIsHoveringOnThread(thread.cid)}}
|
||||||
onMouseLeave={() => {setIsHoveringOnThread('')}}>
|
onMouseLeave={() => {handleMouseOnLeaveThread()}}>
|
||||||
|
{isHoveringOnThread === thread.cid ?
|
||||||
|
<div ref={popupRef}
|
||||||
|
onMouseOver={() => handleMouseOnLeaveThread()}
|
||||||
|
style={{
|
||||||
|
opacity: isCalculationDone && isEnoughSpaceOnRight !== null ? 1 : 0,
|
||||||
|
visibility: isCalculationDone && isEnoughSpaceOnRight !== null ? 'visible' : 'hidden',
|
||||||
|
left: isCalculationDone && isEnoughSpaceOnRight !== null && isEnoughSpaceOnRight ? '100%' : 'auto',
|
||||||
|
right: isCalculationDone && isEnoughSpaceOnRight !== null && !isEnoughSpaceOnRight ? '100%' : 'auto',}}
|
||||||
|
className="thread_popup">
|
||||||
|
<p
|
||||||
|
style={isEnoughSpaceOnLeft !== null && !isEnoughSpaceOnLeft
|
||||||
|
&& !isEnoughSpaceOnRight
|
||||||
|
?
|
||||||
|
{overflow:"visible",whiteSpace:"normal"}
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
className="thread_popup_content">
|
||||||
|
<span className="thread_popup_title" >
|
||||||
|
{thread.title ? `${thread.title} ` : "Posted "}
|
||||||
|
</span>
|
||||||
|
by
|
||||||
|
<span className="thread_popup_author">
|
||||||
|
{thread.author.displayName ?` ${thread.author.displayName} ` : " Anonymous "}
|
||||||
|
</span>
|
||||||
|
{thread.timestamp ? getFormattedTime(thread.timestamp) : null}</p>
|
||||||
|
<div>
|
||||||
|
{thread.replyCount > 0 ?
|
||||||
|
<p className="thread_popup_lastReply">
|
||||||
|
Last reply by <span className="thread_popup_author"> Anonymous </span>
|
||||||
|
{getFormattedTime(thread.lastReplyTimestamp)}</p>
|
||||||
|
: null}</div>
|
||||||
|
</div> : 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)}>
|
onClick={() => setSelectedThread(thread.cid)}>
|
||||||
@@ -491,7 +572,8 @@ const CatalogPost = ({post}) => {
|
|||||||
</BoardForm>
|
</BoardForm>
|
||||||
<Link style={{all: "unset", cursor: "pointer"}} key={`link2-`} to={`/p/${thread.subplebbitAddress}/c/${thread.cid}`}
|
<Link style={{all: "unset", cursor: "pointer"}} key={`link2-`} to={`/p/${thread.subplebbitAddress}/c/${thread.cid}`}
|
||||||
onClick={() => setSelectedThread(thread.cid)}>
|
onClick={() => setSelectedThread(thread.cid)}>
|
||||||
<div key={`t-`} className="teaser">
|
<div key={`t-`} className="teaser" style={{maxHeight: `calc(320px - ${displayHeight})`}}
|
||||||
|
ref={(el) => (threadRefs.current[thread.cid] = el)}>
|
||||||
<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}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user