Merge pull request #238 from plebbit/development

Development
This commit is contained in:
plebeius.eth
2023-09-15 11:04:45 +02:00
committed by GitHub
12 changed files with 1649 additions and 107 deletions
+1 -1
View File
@@ -8,7 +8,7 @@ const BoardAvatar = ({ address }) => {
useEffect(() => {
if (subplebbit.suggested?.avatarUrl) {
setAvatarUrl(subplebbit.suggested.avatarUrl);
setAvatarUrl(subplebbit.suggested?.avatarUrl);
}
}, [subplebbit.suggested?.avatarUrl, subplebbit]);
@@ -90,6 +90,41 @@ export const GlobalStyle = createGlobalStyle`
max-width: 100% !important;
max-height: 100% !important;
}
.instagram-embed {
width: 100vw !important;
height: 45vh !important;
}
.streamable-embed,
.bitchute-embed,
.odysee-embed,
.youtube-embed,
.rumble-embed,
.twitch-embed {
width: 100vw !important;
height: 30vh !important;
}
.spotify-embed {
width: 100vw !important;
height: 40vh !important;
}
.tiktok-embed {
width: 100vw !important;
height: 70vh !important;
}
.twitter-embed {
width: 100vw !important;
height: 65vh !important;
}
.reddit-embed {
width: 100vw !important;
height: 55vh !important;
}
}
.post-menu-catalog {
@@ -4091,4 +4091,133 @@ export const PostMenu = styled.div`
cursor: pointer;
transition: transform 0.1s;
transform: ${props => props.rotated ? 'rotate(90deg)' : 'none'};
`;
export const PostMenuMobile = styled.div`
font-size: 16px;
line-height: 2.5em;
width: 216px;
ul {
border-right-width: 2px !important;
list-style: none;
padding: 0;
margin: 0;
white-space: nowrap;
}
li {
cursor: pointer;
position: relative;
padding: 2px 4px;
vertical-align: middle;
}
${({ selectedStyle }) => {
switch (selectedStyle) {
case 'Yotsuba':
return `
ul {
border: 1px solid #d9bfb7;
}
li {
background-color: #f0e0d6;
border-bottom: 1px solid #d9bfb7;
:hover {
background-color: #ffe;
color: #d00;
}
}
`;
case 'Yotsuba-B':
return `
ul {
border: 1px solid #b7c5d9;
}
li {
background-color: #d6daf0;
border-bottom: 1px solid #b7c5d9;
:hover {
background-color: #eef2ff;
color: #d00;
}
}
`;
case 'Futaba':
return `
ul {
border: 1px solid #d9bfb7;
}
li {
background-color: #f0e0d6;
border-bottom: 1px solid #d9bfb7;
:hover {
background-color: #ffe;
color: #d00;
}
}
`;
case 'Burichan':
return `
ul {
border: 1px solid #b7c5d9;
}
li {
background-color: #d6daf0;
border-bottom: 1px solid #b7c5d9;
:hover {
background-color: #eef2ff;
color: #d00;
}
}
`;
case 'Tomorrow':
return `
ul {
border: 1px solid #282a2e;
}
li {
background-color: #1d1f21;
border-bottom: 1px solid #282a2e;
:hover {
background-color: #1b1c1e;
}
}
`;
case 'Photon':
return `
ul {
border: 1px solid #ccc;
}
li {
background-color: #ddd;
border-bottom: 1px solid #ccc;
:hover {
background-color: #eee;
}
}
`;
default:
return '';
}}
}
`;
@@ -2495,6 +2495,10 @@ export const BoardForm = styled.div`
color: #117743;
font-weight: 700;
}
.capcode {
color: purple !important;
}
.subject-mobile {
color: #cc1105;
@@ -2612,6 +2616,10 @@ export const BoardForm = styled.div`
color: #117743;
font-weight: 700;
}
.capcode {
color: purple !important;
}
.subject-mobile {
color: #0f0c5d;
@@ -2725,6 +2733,10 @@ export const BoardForm = styled.div`
color: #117743;
font-weight: 700;
}
.capcode {
color: purple !important;
}
.subject-mobile {
color: #cc1105;
@@ -2841,6 +2853,10 @@ export const BoardForm = styled.div`
color: #117743;
font-weight: 700;
}
.capcode {
color: purple !important;
}
.subject-mobile {
color: #0f0c5d;
@@ -2954,6 +2970,10 @@ export const BoardForm = styled.div`
font-weight: 700;
}
.capcode {
color: #81a2be !important;
}
.poster-address-mobile {
color: #707070;
}
@@ -3075,6 +3095,10 @@ export const BoardForm = styled.div`
color: #004a99;
font-weight: 700;
}
.capcode {
color: #f60 !important;
}
.subject-mobile {
color: #111;
+222 -10
View File
@@ -8,7 +8,7 @@ import { Virtuoso } from 'react-virtuoso';
import { useAccount, useAccountComments, useFeed, usePublishCommentEdit, useSubplebbits } from '@plebbit/plebbit-react-hooks';
import { flattenCommentsPages } from '@plebbit/plebbit-react-hooks/dist/lib/utils'
import { debounce } from 'lodash';
import { Container, NavBar, Header, Break, TopBar, BoardForm, PostMenu } from '../styled/views/Board.styled';
import { Container, NavBar, Header, Break, TopBar, BoardForm, PostMenu, PostMenuMobile } from '../styled/views/Board.styled';
import { Footer } from '../styled/views/Thread.styled';
import { PostMenuCatalog } from '../styled/views/Catalog.styled';
import { AlertModal } from '../styled/modals/AlertModal.styled';
@@ -85,8 +85,11 @@ const All = () => {
const [, setNewSuccessMessage] = useSuccess();
const threadMenuRefs = useRef({});
const threadMenuRefsMobile = useRef({});
const replyMenuRefs = useRef({});
const replyMenuRefsMobile = useRef({});
const postMenuCatalogRef = useRef(null);
const postMenuMobileRef = useRef(null);
const backlinkRefs = useRef({});
const quoteRefs = useRef({});
const postRefs = useRef({});
@@ -105,8 +108,10 @@ const All = () => {
const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false);
const [commentCid, setCommentCid] = useState(null);
const [menuPosition, setMenuPosition] = useState({top: 0, left: 0});
const [mobileMenuPosition, setMobileMenuPosition] = useState({top: 0, left: 0});
const [triggerPublishCommentEdit, setTriggerPublishCommentEdit] = useState(false);
const [openMenuCid, setOpenMenuCid] = useState(null);
const [openMobileMenuCid, setOpenMobileMenuCid] = useState(null);
const [outOfViewCid, setOutOfViewCid] = useState(null);
const [outOfViewPosition, setOutOfViewPosition] = useState({top: 0, left: 0});
const [postOnHoverHeight, setPostOnHoverHeight] = useState(0);
@@ -196,12 +201,22 @@ const All = () => {
setOpenMenuCid(null);
};
const handleMobileOptionClick = () => {
setOpenMobileMenuCid(null);
};
const handleOutsideClick = useCallback((e) => {
if (openMenuCid !== null && !postMenuCatalogRef.current.contains(e.target)) {
setOpenMenuCid(null);
}
}, [openMenuCid, postMenuCatalogRef]);
const handleMobileOutsideClick = useCallback((e) => {
if (openMobileMenuCid !== null && !postMenuMobileRef.current.contains(e.target)) {
setOpenMobileMenuCid(null);
}
}, [openMobileMenuCid, postMenuMobileRef]);
useEffect(() => {
@@ -217,6 +232,19 @@ const All = () => {
}, [openMenuCid, handleOutsideClick]);
useEffect(() => {
if (openMobileMenuCid !== null) {
document.addEventListener('click', handleMobileOutsideClick);
} else {
document.removeEventListener('click', handleMobileOutsideClick);
}
return () => {
document.removeEventListener('click', handleMobileOutsideClick);
};
}, [openMobileMenuCid, handleMobileOutsideClick]);
useEffect(() => {
if (postOnHoverRef.current) {
const rect = postOnHoverRef.current.getBoundingClientRect();
@@ -722,10 +750,10 @@ const All = () => {
commentMediaInfo?.url.length > 30 ?
commentMediaInfo?.url.slice(0, 30) + "(...)" :
commentMediaInfo?.url
}</a>&nbsp;{commentMediaInfo?.type === "iframe" ? null : `(${commentMediaInfo?.type})`}
}</a>{commentMediaInfo?.type === "iframe" ? null : `(${commentMediaInfo?.type})`}
{((isThreadThumbnailClicked[index] && (commentMediaInfo.type === 'iframe' || commentMediaInfo.type === 'video')) || (commentMediaInfo.type === 'iframe' && !commentMediaInfo.thumbnail)) && (
<span>
[
 [
<span className='reply-link'
style={{textDecoration: 'underline', cursor: 'pointer'}}
onClick={() => {handleThumbnailClick(index, 'thread')}}>
@@ -1263,8 +1291,8 @@ const All = () => {
<ul className="post-menu-catalog">
<li onClick={() => {
handleOptionClick(reply.cid);
handleShareClick(thread.subplebbitAddress, thread.cid);
}}>Share thread</li>
handleShareClick(thread.subplebbitAddress, reply.cid);
}}>Share post</li>
<VerifiedAuthor commentCid={reply.cid}>{({ authorAddress }) => (
<>
{authorAddress === account?.author.address ||
@@ -1321,7 +1349,7 @@ const All = () => {
</li>
<li onClick={() => handleOptionClick(reply.cid)}>
<a
href={`https://yandex.com/images/search?url=${replyMediaInfo.url}`}
href={`https://yandex.com/images/search?img_url=${replyMediaInfo.url}&rpt=imageview`}
target="_blank" rel="noreferrer"
>Yandex</a>
</li>
@@ -1429,10 +1457,10 @@ const All = () => {
replyMediaInfo?.url.length > 30 ?
replyMediaInfo?.url.slice(0, 30) + "(...)" :
replyMediaInfo?.url
}</a>&nbsp;{replyMediaInfo?.type === "iframe" ? null : `(${replyMediaInfo?.type})`}
}</a>{replyMediaInfo?.type === "iframe" ? null : `(${replyMediaInfo?.type})`}
{ ((isReplyThumbnailClicked[index] && (replyMediaInfo.type === 'iframe' || replyMediaInfo.type === 'video')) || (replyMediaInfo.type === 'iframe' && !replyMediaInfo.thumbnail)) && (
<span>
[
 [
<span className='reply-link'
style={{textDecoration: 'underline', cursor: 'pointer'}}
onClick={() => {handleThumbnailClick(index, 'reply')}}>
@@ -1748,7 +1776,99 @@ const All = () => {
<div key={`mob-c-${index}`} className="op-container">
<div key={`mob-po-${index}`} className="post op op-mobile">
<div key={`mob-pi-${index}`} className="post-info-mobile">
<button key={`mob-pb-${index}`} className="post-menu-button-mobile" style={{ all: 'unset', cursor: 'pointer' }}>...</button>
<button key={`mob-pb-${index}`} className="post-menu-button-mobile"
ref={el => {
threadMenuRefsMobile.current[thread.cid] = el;
}}
onClick={(event) => {
event.stopPropagation();
const rect = threadMenuRefsMobile.current[thread.cid].getBoundingClientRect();
setMobileMenuPosition({top: rect.top + window.scrollY, left: rect.left});
setOpenMobileMenuCid(prevCid => (prevCid === thread.cid ? null : thread.cid));
}}
style={{ all: 'unset', cursor: 'pointer' }}
>...</button>
{createPortal(
<PostMenuMobile selectedStyle={selectedStyle}
ref={el => {postMenuMobileRef.current = el}}
onClick={(event) => event.stopPropagation()}
style={{position: "absolute",
display: openMobileMenuCid === thread.cid ? "block" : "none",
top: mobileMenuPosition.top + 20,
left: mobileMenuPosition.left}}>
<ul className={`post-menu-mobile-thread-${thread.cid}`}>
<li onClick={() => {
handleMobileOptionClick(thread.cid);
handleShareClick(selectedAddress, thread.cid)
}}>Share thread</li>
<VerifiedAuthor commentCid={thread.cid}>{({ authorAddress }) => (
<>
{authorAddress === account?.author.address ||
authorAddress === account?.signer.address ? (
<>
<li onClick={() => handleAuthorEditClick(thread)}>Edit post</li>
<li onClick={() => handleAuthorDeleteClick(thread)}>Delete post</li>
</>
) : null}
{isModerator ? (
<>
{authorAddress === account?.author.address ||
authorAddress === account?.signer.address ? (
null
) : (
<li onClick={() => {
setModeratingCommentCid(thread.cid)
setIsModerationOpen(true);
handleMobileOptionClick(thread.cid);
setDeletePost(true);
}}>
Delete post
</li>
)}
<li
onClick={() => {
setModeratingCommentCid(thread.cid)
setIsModerationOpen(true);
handleMobileOptionClick(thread.cid);
}}>
Mod tools
</li>
</>
) : null}
</>
)}</VerifiedAuthor>
{(commentMediaInfo && (
commentMediaInfo.type === 'image' ||
(commentMediaInfo.type === 'webpage' &&
commentMediaInfo.thumbnail))) ? (
<>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://lens.google.com/uploadbyurl?url=${commentMediaInfo.url}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleMobileOptionClick(thread.cid)}>
Search image on Google
</li>
</a>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://yandex.com/images/search?url=${commentMediaInfo.url}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleMobileOptionClick(thread.cid)}>
Search image on Yandex
</li>
</a>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://saucenao.com/search.php?url=${commentMediaInfo.url}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleMobileOptionClick(thread.cid)}>
Search image on SauceNAO
</li>
</a>
</>
) : null
}
</ul>
</PostMenuMobile>, document.body
)}
<span key={`mob-nbm-${index}`} className="name-block-mobile">
{thread.author.displayName
? thread.author.displayName.length > 20
@@ -1985,7 +2105,99 @@ const All = () => {
<div key={`mob-rc-${index}`} className="reply-container">
<div key={`mob-pr-${index}`} className="post-reply post-reply-mobile">
<div key={`mob-pi-${index}`} className="post-info-mobile">
<button key={`pmbm-${index}`} className="post-menu-button-mobile" title="Post menu" style={{ all: 'unset', cursor: 'pointer' }}>...</button>
<button key={`mob-pb-${index}`} className="post-menu-button-mobile"
ref={el => {
replyMenuRefsMobile.current[reply.cid] = el;
}}
onClick={(event) => {
event.stopPropagation();
const rect = replyMenuRefsMobile.current[reply.cid].getBoundingClientRect();
setMobileMenuPosition({top: rect.top + window.scrollY, left: rect.left});
setOpenMobileMenuCid(prevCid => (prevCid === reply.cid ? null : reply.cid));
}}
style={{ all: 'unset', cursor: 'pointer' }}
>...</button>
{createPortal(
<PostMenuMobile selectedStyle={selectedStyle}
ref={el => {postMenuMobileRef.current = el}}
onClick={(event) => event.stopPropagation()}
style={{position: "absolute",
display: openMobileMenuCid === reply.cid ? "block" : "none",
top: mobileMenuPosition.top + 20,
left: mobileMenuPosition.left}}>
<ul className={`post-menu-mobile-thread-${reply.cid}`}>
<li onClick={() => {
handleMobileOptionClick(reply.cid);
handleShareClick(selectedAddress, reply.cid)
}}>Share post</li>
<VerifiedAuthor commentCid={reply.cid}>{({ authorAddress }) => (
<>
{authorAddress === account?.author.address ||
authorAddress === account?.signer.address ? (
<>
<li onClick={() => handleAuthorEditClick(reply)}>Edit post</li>
<li onClick={() => handleAuthorDeleteClick(reply)}>Delete post</li>
</>
) : null}
{isModerator ? (
<>
{authorAddress === account?.author.address ||
authorAddress === account?.signer.address ? (
null
) : (
<li onClick={() => {
setModeratingCommentCid(reply.cid)
setIsModerationOpen(true);
handleMobileOptionClick(reply.cid);
setDeletePost(true);
}}>
Delete post
</li>
)}
<li
onClick={() => {
setModeratingCommentCid(reply.cid)
setIsModerationOpen(true);
handleMobileOptionClick(reply.cid);
}}>
Mod tools
</li>
</>
) : null}
</>
)}</VerifiedAuthor>
{(replyMediaInfo && (
replyMediaInfo.type === 'image' ||
(replyMediaInfo.type === 'webpage' &&
replyMediaInfo.thumbnail))) ? (
<>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://lens.google.com/uploadbyurl?url=${replyMediaInfo.url}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleMobileOptionClick(reply.cid)}>
Search image on Google
</li>
</a>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://yandex.com/images/search?url=${replyMediaInfo.url}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleMobileOptionClick(reply.cid)}>
Search image on Yandex
</li>
</a>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://saucenao.com/search.php?url=${replyMediaInfo.url}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleMobileOptionClick(reply.cid)}>
Search image on SauceNAO
</li>
</a>
</>
) : null
}
</ul>
</PostMenuMobile>, document.body
)}
<span key={`mob-nb-${index}`} className="name-block-mobile">
{reply.author.displayName
? reply.author.displayName.length > 20
+489 -28
View File
@@ -8,7 +8,7 @@ import { Virtuoso } from 'react-virtuoso';
import { useAccount, useAccountComments, useFeed, usePublishComment, usePublishCommentEdit, useSubplebbit, useSubscribe } from '@plebbit/plebbit-react-hooks';
import { flattenCommentsPages } from '@plebbit/plebbit-react-hooks/dist/lib/utils'
import { debounce } from 'lodash';
import { Container, NavBar, Header, Break, PostFormLink, PostFormTable, PostForm, TopBar, BoardForm, PostMenu } from '../styled/views/Board.styled';
import { Container, NavBar, Header, Break, PostFormLink, PostFormTable, PostForm, TopBar, BoardForm, PostMenu, PostMenuMobile } from '../styled/views/Board.styled';
import { Footer } from '../styled/views/Thread.styled';
import { AlertModal } from '../styled/modals/AlertModal.styled';
import { PostMenuCatalog } from '../styled/views/Catalog.styled';
@@ -105,8 +105,11 @@ const Board = () => {
const commentRef = useRef();
const linkRef = useRef();
const threadMenuRefs = useRef({});
const threadMenuRefsMobile = useRef({});
const replyMenuRefs = useRef({});
const replyMenuRefsMobile = useRef({});
const postMenuCatalogRef = useRef(null);
const postMenuMobileRef = useRef(null);
const backlinkRefs = useRef({});
const quoteRefs = useRef({});
const postRefs = useRef({});
@@ -136,7 +139,9 @@ const Board = () => {
const [isModerator, setIsModerator] = useState(false);
const [commentCid, setCommentCid] = useState(null);
const [menuPosition, setMenuPosition] = useState({top: 0, left: 0});
const [mobileMenuPosition, setMobileMenuPosition] = useState({top: 0, left: 0});
const [openMenuCid, setOpenMenuCid] = useState(null);
const [openMobileMenuCid, setOpenMobileMenuCid] = useState(null);
const [outOfViewCid, setOutOfViewCid] = useState(null);
const [outOfViewPosition, setOutOfViewPosition] = useState({top: 0, left: 0});
const [postOnHoverHeight, setPostOnHoverHeight] = useState(0);
@@ -210,12 +215,22 @@ const Board = () => {
setOpenMenuCid(null);
};
const handleMobileOptionClick = () => {
setOpenMobileMenuCid(null);
};
const handleOutsideClick = useCallback((e) => {
if (openMenuCid !== null && !postMenuCatalogRef.current.contains(e.target)) {
setOpenMenuCid(null);
}
}, [openMenuCid, postMenuCatalogRef]);
const handleMobileOutsideClick = useCallback((e) => {
if (openMobileMenuCid !== null && !postMenuMobileRef.current.contains(e.target)) {
setOpenMobileMenuCid(null);
}
}, [openMobileMenuCid, postMenuMobileRef]);
useEffect(() => {
@@ -231,6 +246,19 @@ const Board = () => {
}, [openMenuCid, handleOutsideClick]);
useEffect(() => {
if (openMobileMenuCid !== null) {
document.addEventListener('click', handleMobileOutsideClick);
} else {
document.removeEventListener('click', handleMobileOutsideClick);
}
return () => {
document.removeEventListener('click', handleMobileOutsideClick);
};
}, [openMobileMenuCid, handleMobileOutsideClick]);
useEffect(() => {
if (postOnHoverRef.current) {
const rect = postOnHoverRef.current.getBoundingClientRect();
@@ -1002,17 +1030,37 @@ const Board = () => {
style={{ display: openMenuCid === "rules" ? 'block' : 'none' }}
>
<ul className="post-menu-catalog">
<li onClick={() => {
handleOptionClick("rules");
handleShareClick(selectedAddress, "rules");
}}>
Share board
</li>
{/* {isModerator ? (
<>
change rules
</>
) : null} */}
<li
onMouseOver={() => {setIsClientRedirectMenuOpen(true)}}
onMouseLeave={() => {setIsClientRedirectMenuOpen(false)}}>
View on »
<ul className="dropdown-menu post-menu-catalog"
style={{display: isClientRedirectMenuOpen ? 'block': 'none'}}>
<li onClick={() => handleOptionClick("rules")}>
<a
href={`https://plebbitapp.eth.limo/#/p/${selectedAddress}`}
target="_blank" rel="noreferrer"
>Plebbit</a>
</li>
{/* <li onClick={() => handleOptionClick("rules")}>
<a
href={`https://seedit.eth.limo/#/p/${selectedAddress}`}
target="_blank" rel="noreferrer"
>Seedit</a>
</li> */}
<li onClick={() => handleOptionClick("rules")}>
<a
href={`https://plebones.netlify.app/#/p/${selectedAddress}`}
target="_blank" rel="noreferrer"
>Plebones</a>
</li>
</ul>
</li>
</ul>
</div>
</PostMenuCatalog>, document.body
@@ -1038,7 +1086,42 @@ const Board = () => {
<div className="post op op-mobile">
<div className="post-info-mobile">
<button className="post-menu-button-mobile"
ref={el => {
threadMenuRefsMobile.current["rules"] = el;
}}
onClick={(event) => {
event.stopPropagation();
const rect = threadMenuRefsMobile.current["rules"].getBoundingClientRect();
setMobileMenuPosition({top: rect.top + window.scrollY, left: rect.left});
setOpenMobileMenuCid(prevCid => (prevCid === "rules" ? null : "rules"));
}}
style={{ all: 'unset', cursor: 'pointer' }}>...</button>
{createPortal(
<PostMenuMobile selectedStyle={selectedStyle}
ref={el => {postMenuMobileRef.current = el}}
onClick={(event) => event.stopPropagation()}
style={{position: "absolute",
display: openMobileMenuCid === "rules" ? "block" : "none",
top: mobileMenuPosition.top + 20,
left: mobileMenuPosition.left}}>
<ul className={`post-menu-mobile-thread-${"rules"}`}>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://plebbitapp.eth.limo/#/p/${selectedAddress}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleOptionClick("rules")}>
View on plebbit
</li>
</a>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://plebones.netlify.app/#/p/${selectedAddress}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleOptionClick("rules")}>
View on plebones
</li>
</a>
</ul>
</PostMenuMobile>, document.body
)}
<span className="name-block-mobile">
<span className="name-mobile capcode"
style={{cursor: 'pointer'}}
@@ -1138,15 +1221,37 @@ const Board = () => {
style={{ display: openMenuCid === "rules" ? 'block' : 'none' }}
>
<ul className="post-menu-catalog">
<li onClick={() => {
handleOptionClick("rules");
handleShareClick(selectedAddress, "rules");
}}>Share board</li>
{/* {isModerator ? (
<>
change rules
</>
) : null} */}
<li
onMouseOver={() => {setIsClientRedirectMenuOpen(true)}}
onMouseLeave={() => {setIsClientRedirectMenuOpen(false)}}>
View on »
<ul className="dropdown-menu post-menu-catalog"
style={{display: isClientRedirectMenuOpen ? 'block': 'none'}}>
<li onClick={() => handleOptionClick("rules")}>
<a
href={`https://plebbitapp.eth.limo/#/p/${selectedAddress}`}
target="_blank" rel="noreferrer"
>Plebbit</a>
</li>
{/* <li onClick={() => handleOptionClick("rules")}>
<a
href={`https://seedit.eth.limo/#/p/${selectedAddress}`}
target="_blank" rel="noreferrer"
>Seedit</a>
</li> */}
<li onClick={() => handleOptionClick("rules")}>
<a
href={`https://plebones.netlify.app/#/p/${selectedAddress}`}
target="_blank" rel="noreferrer"
>Plebones</a>
</li>
</ul>
</li>
</ul>
</div>
</PostMenuCatalog>, document.body
@@ -1171,8 +1276,43 @@ const Board = () => {
<div className="op-container">
<div className="post op op-mobile">
<div className="post-info-mobile">
<button className="post-menu-button-mobile"
<button className="post-menu-button-mobile"
ref={el => {
threadMenuRefsMobile.current["rules"] = el;
}}
onClick={(event) => {
event.stopPropagation();
const rect = threadMenuRefsMobile.current["rules"].getBoundingClientRect();
setMobileMenuPosition({top: rect.top + window.scrollY, left: rect.left});
setOpenMobileMenuCid(prevCid => (prevCid === "rules" ? null : "rules"));
}}
style={{ all: 'unset', cursor: 'pointer' }}>...</button>
{createPortal(
<PostMenuMobile selectedStyle={selectedStyle}
ref={el => {postMenuMobileRef.current = el}}
onClick={(event) => event.stopPropagation()}
style={{position: "absolute",
display: openMobileMenuCid === "rules" ? "block" : "none",
top: mobileMenuPosition.top + 20,
left: mobileMenuPosition.left}}>
<ul className={`post-menu-mobile-thread-${"rules"}`}>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://plebbitapp.eth.limo/#/p/${selectedAddress}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleOptionClick("rules")}>
View on plebbit
</li>
</a>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://plebones.netlify.app/#/p/${selectedAddress}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleOptionClick("rules")}>
View on plebones
</li>
</a>
</ul>
</PostMenuMobile>, document.body
)}
<span className="name-block-mobile">
<span className="name-mobile capcode"
style={{cursor: 'pointer'}}
@@ -1294,15 +1434,65 @@ const Board = () => {
style={{ display: openMenuCid === subplebbit.pubsubTopic ? 'block' : 'none' }}
>
<ul className="post-menu-catalog">
<li onClick={() => {
handleOptionClick("description");
handleShareClick(selectedAddress, "description");
}}>Share board</li>
{/* {isModerator ? (
<>
change description
</>
) : null} */}
{subplebbit.suggested?.avatarUrl ? (
<li
onMouseOver={() => {setIsImageSearchOpen(true)}}
onMouseLeave={() => {setIsImageSearchOpen(false)}}>
Image search »
<ul className="dropdown-menu post-menu-catalog"
style={{display: isImageSearchOpen ? 'block': 'none'}}>
<li onClick={() => handleOptionClick("description")}>
<a
href={`https://lens.google.com/uploadbyurl?url=${subplebbit.suggested?.avatarUrl}`}
target="_blank" rel="noreferrer"
>Google</a>
</li>
<li onClick={() => handleOptionClick("description")}>
<a
href={`https://yandex.com/images/search?url=${subplebbit.suggested?.avatarUrl}`}
target="_blank" rel="noreferrer"
>Yandex</a>
</li>
<li onClick={() => handleOptionClick("description")}>
<a
href={`https://saucenao.com/search.php?url=${subplebbit.suggested?.avatarUrl}`}
target="_blank" rel="noreferrer"
>SauceNAO</a>
</li>
</ul>
</li>
) : null}
<li
onMouseOver={() => {setIsClientRedirectMenuOpen(true)}}
onMouseLeave={() => {setIsClientRedirectMenuOpen(false)}}>
View on »
<ul className="dropdown-menu post-menu-catalog"
style={{display: isClientRedirectMenuOpen ? 'block': 'none'}}>
<li onClick={() => handleOptionClick("description")}>
<a
href={`https://plebbitapp.eth.limo/#/p/${selectedAddress}`}
target="_blank" rel="noreferrer"
>Plebbit</a>
</li>
{/* <li onClick={() => handleOptionClick("description")}>
<a
href={`https://seedit.eth.limo/#/p/${selectedAddress}`}
target="_blank" rel="noreferrer"
>Seedit</a>
</li> */}
<li onClick={() => handleOptionClick("description")}>
<a
href={`https://plebones.netlify.app/#/p/${selectedAddress}`}
target="_blank" rel="noreferrer"
>Plebones</a>
</li>
</ul>
</li>
</ul>
</div>
</PostMenuCatalog>, document.body
@@ -1325,8 +1515,67 @@ const Board = () => {
<div className="op-container">
<div className="post op op-mobile">
<div className="post-info-mobile">
<button className="post-menu-button-mobile"
style={{ all: 'unset', cursor: 'pointer' }}>...</button>
<button key={`mob-pb-`} className="post-menu-button-mobile"
ref={el => {
threadMenuRefsMobile.current["description"] = el;
}}
onClick={(event) => {
event.stopPropagation();
const rect = threadMenuRefsMobile.current["description"].getBoundingClientRect();
setMobileMenuPosition({top: rect.top + window.scrollY, left: rect.left});
setOpenMobileMenuCid(prevCid => (prevCid === "description" ? null : "description"));
}}
style={{ all: 'unset', cursor: 'pointer' }}
>...</button>
{createPortal(
<PostMenuMobile selectedStyle={selectedStyle}
ref={el => {postMenuMobileRef.current = el}}
onClick={(event) => event.stopPropagation()}
style={{position: "absolute",
display: openMobileMenuCid === "description" ? "block" : "none",
top: mobileMenuPosition.top + 20,
left: mobileMenuPosition.left}}>
<ul className={`post-menu-mobile-thread-description`}>
{subplebbit.suggested?.avatarUrl ? (
<>
<a style={{ color: 'inherit', textDecoration: 'none' }}
href={`https://lens.google.com/uploadbyurl?url=${subplebbit.suggested?.avatarUrl}`}
target="_blank" rel="noreferrer"
onClick={() => handleMobileOptionClick("description")}>
<li>Search image on Google</li>
</a>
<a style={{ color: 'inherit', textDecoration: 'none' }}
href={`https://yandex.com/images/search?url=${subplebbit.suggested?.avatarUrl}`}
target="_blank" rel="noreferrer"
onClick={() => handleMobileOptionClick("description")}>
<li>Search image on Yandex</li>
</a>
<a style={{ color: 'inherit', textDecoration: 'none' }}
href={`https://saucenao.com/search.php?url=${subplebbit.suggested?.avatarUrl}`}
target="_blank" rel="noreferrer"
onClick={() => handleMobileOptionClick("description")}>
<li>Search image on SauceNAO</li>
</a>
</>
) : null
}
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://plebbitapp.eth.limo/#/p/${selectedAddress}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleOptionClick("description")}>
View on plebbit
</li>
</a>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://plebones.netlify.app/#/p/${selectedAddress}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleOptionClick("description")}>
View on plebones
</li>
</a>
</ul>
</PostMenuMobile>, document.body
)}
<span className="name-block-mobile">
<span className="name-mobile capcode"
style={{cursor: 'pointer'}}
@@ -1356,7 +1605,7 @@ const Board = () => {
<div className="file-mobile">
<div className="img-container">
<span className="file-thumb-mobile">
<img src={subplebbit.suggested.avatarUrl} alt="board avatar"
<img src={subplebbit.suggested?.avatarUrl} alt="board avatar"
onClick={handleImageClick}
style={{cursor: "pointer"}} />
<div className="file-info-mobile">image</div>
@@ -1415,10 +1664,10 @@ const Board = () => {
commentMediaInfo?.url.length > 30 ?
commentMediaInfo?.url.slice(0, 30) + "(...)" :
commentMediaInfo?.url
}</a>&nbsp;{commentMediaInfo?.type === "iframe" ? null : `(${commentMediaInfo?.type})`}
}</a>{commentMediaInfo?.type === "iframe" ? null : `(${commentMediaInfo?.type})`}
{((isThreadThumbnailClicked[index] && (commentMediaInfo.type === 'iframe' || commentMediaInfo.type === 'video')) || (commentMediaInfo.type === 'iframe' && !commentMediaInfo.thumbnail)) && (
<span>
[
 [
<span className='reply-link'
style={{textDecoration: 'underline', cursor: 'pointer'}}
onClick={() => {handleThumbnailClick(index, 'thread')}}>
@@ -1955,8 +2204,8 @@ const Board = () => {
<ul className="post-menu-catalog">
<li onClick={() => {
handleOptionClick(reply.cid);
handleShareClick(selectedAddress, thread.cid);
}}>Share thread</li>
handleShareClick(selectedAddress, reply.cid);
}}>Share post</li>
<VerifiedAuthor commentCid={reply.cid}>{({ authorAddress }) => (
<>
{authorAddress === account?.author.address ||
@@ -2011,7 +2260,7 @@ const Board = () => {
</li>
<li onClick={() => handleOptionClick(reply.cid)}>
<a
href={`https://yandex.com/images/search?url=${replyMediaInfo.url}`}
href={`https://yandex.com/images/search?img_url=${replyMediaInfo.url}&rpt=imageview`}
target="_blank" rel="noreferrer"
>Yandex</a>
</li>
@@ -2119,10 +2368,10 @@ const Board = () => {
replyMediaInfo?.url.length > 30 ?
replyMediaInfo?.url.slice(0, 30) + "(...)" :
replyMediaInfo?.url
}</a>&nbsp;{replyMediaInfo?.type === "iframe" ? null : `(${replyMediaInfo?.type})`}
}</a>{replyMediaInfo?.type === "iframe" ? null : `(${replyMediaInfo?.type})`}
{ ((isReplyThumbnailClicked[index] && (replyMediaInfo.type === 'iframe' || replyMediaInfo.type === 'video')) || (replyMediaInfo.type === 'iframe' && !replyMediaInfo.thumbnail)) && (
<span>
[
 [
<span className='reply-link'
style={{textDecoration: 'underline', cursor: 'pointer'}}
onClick={() => {handleThumbnailClick(index, 'reply')}}>
@@ -2439,7 +2688,113 @@ const Board = () => {
<div key={`mob-c-${index}`} className="op-container">
<div key={`mob-po-${index}`} className="post op op-mobile">
<div key={`mob-pi-${index}`} className="post-info-mobile">
<button key={`mob-pb-${index}`} className="post-menu-button-mobile" style={{ all: 'unset', cursor: 'pointer' }}>...</button>
<button key={`mob-pb-${index}`} className="post-menu-button-mobile"
ref={el => {
threadMenuRefsMobile.current[thread.cid] = el;
}}
onClick={(event) => {
event.stopPropagation();
const rect = threadMenuRefsMobile.current[thread.cid].getBoundingClientRect();
setMobileMenuPosition({top: rect.top + window.scrollY, left: rect.left});
setOpenMobileMenuCid(prevCid => (prevCid === thread.cid ? null : thread.cid));
}}
style={{ all: 'unset', cursor: 'pointer' }}
>...</button>
{createPortal(
<PostMenuMobile selectedStyle={selectedStyle}
ref={el => {postMenuMobileRef.current = el}}
onClick={(event) => event.stopPropagation()}
style={{position: "absolute",
display: openMobileMenuCid === thread.cid ? "block" : "none",
top: mobileMenuPosition.top + 20,
left: mobileMenuPosition.left}}>
<ul className={`post-menu-mobile-thread-${thread.cid}`}>
<li onClick={() => {
handleMobileOptionClick(thread.cid);
handleShareClick(selectedAddress, thread.cid)
}}>Share thread</li>
<VerifiedAuthor commentCid={thread.cid}>{({ authorAddress }) => (
<>
{authorAddress === account?.author.address ||
authorAddress === account?.signer.address ? (
<>
<li onClick={() => handleAuthorEditClick(thread)}>Edit post</li>
<li onClick={() => handleAuthorDeleteClick(thread)}>Delete post</li>
</>
) : null}
{isModerator ? (
<>
{authorAddress === account?.author.address ||
authorAddress === account?.signer.address ? (
null
) : (
<li onClick={() => {
setModeratingCommentCid(thread.cid)
setIsModerationOpen(true);
handleMobileOptionClick(thread.cid);
setDeletePost(true);
}}>
Delete post
</li>
)}
<li
onClick={() => {
setModeratingCommentCid(thread.cid)
setIsModerationOpen(true);
handleMobileOptionClick(thread.cid);
}}>
Mod tools
</li>
</>
) : null}
</>
)}</VerifiedAuthor>
{(commentMediaInfo && (
commentMediaInfo.type === 'image' ||
(commentMediaInfo.type === 'webpage' &&
commentMediaInfo.thumbnail))) ? (
<>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://lens.google.com/uploadbyurl?url=${commentMediaInfo.url}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleMobileOptionClick(thread.cid)}>
Search image on Google
</li>
</a>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://yandex.com/images/search?url=${commentMediaInfo.url}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleMobileOptionClick(thread.cid)}>
Search image on Yandex
</li>
</a>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://saucenao.com/search.php?url=${commentMediaInfo.url}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleMobileOptionClick(thread.cid)}>
Search image on SauceNAO
</li>
</a>
</>
) : null
}
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://plebbitapp.eth.limo/#/p/${selectedAddress}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleOptionClick(thread.cid)}>
View on plebbit
</li>
</a>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://plebones.netlify.app/#/p/${selectedAddress}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleOptionClick(thread.cid)}>
View on plebones
</li>
</a>
</ul>
</PostMenuMobile>, document.body
)}
<span key={`mob-nbm-${index}`} className="name-block-mobile">
{thread.author.displayName
? thread.author.displayName.length > 20
@@ -2677,7 +3032,113 @@ const Board = () => {
<div key={`mob-rc-${index}`} className="reply-container">
<div key={`mob-pr-${index}`} className="post-reply post-reply-mobile">
<div key={`mob-pi-${index}`} className="post-info-mobile">
<button key={`pmbm-${index}`} className="post-menu-button-mobile" title="Post menu" style={{ all: 'unset', cursor: 'pointer' }}>...</button>
<button key={`mob-pb-${index}`} className="post-menu-button-mobile"
ref={el => {
replyMenuRefsMobile.current[reply.cid] = el;
}}
onClick={(event) => {
event.stopPropagation();
const rect = replyMenuRefsMobile.current[reply.cid].getBoundingClientRect();
setMobileMenuPosition({top: rect.top + window.scrollY, left: rect.left});
setOpenMobileMenuCid(prevCid => (prevCid === reply.cid ? null : reply.cid));
}}
style={{ all: 'unset', cursor: 'pointer' }}
>...</button>
{createPortal(
<PostMenuMobile selectedStyle={selectedStyle}
ref={el => {postMenuMobileRef.current = el}}
onClick={(event) => event.stopPropagation()}
style={{position: "absolute",
display: openMobileMenuCid === reply.cid ? "block" : "none",
top: mobileMenuPosition.top + 20,
left: mobileMenuPosition.left}}>
<ul className={`post-menu-mobile-thread-${reply.cid}`}>
<li onClick={() => {
handleMobileOptionClick(reply.cid);
handleShareClick(selectedAddress, reply.cid)
}}>Share post</li>
<VerifiedAuthor commentCid={reply.cid}>{({ authorAddress }) => (
<>
{authorAddress === account?.author.address ||
authorAddress === account?.signer.address ? (
<>
<li onClick={() => handleAuthorEditClick(reply)}>Edit post</li>
<li onClick={() => handleAuthorDeleteClick(reply)}>Delete post</li>
</>
) : null}
{isModerator ? (
<>
{authorAddress === account?.author.address ||
authorAddress === account?.signer.address ? (
null
) : (
<li onClick={() => {
setModeratingCommentCid(reply.cid)
setIsModerationOpen(true);
handleMobileOptionClick(reply.cid);
setDeletePost(true);
}}>
Delete post
</li>
)}
<li
onClick={() => {
setModeratingCommentCid(reply.cid)
setIsModerationOpen(true);
handleMobileOptionClick(reply.cid);
}}>
Mod tools
</li>
</>
) : null}
</>
)}</VerifiedAuthor>
{(replyMediaInfo && (
replyMediaInfo.type === 'image' ||
(replyMediaInfo.type === 'webpage' &&
replyMediaInfo.thumbnail))) ? (
<>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://lens.google.com/uploadbyurl?url=${replyMediaInfo.url}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleMobileOptionClick(reply.cid)}>
Search image on Google
</li>
</a>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://yandex.com/images/search?url=${replyMediaInfo.url}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleMobileOptionClick(reply.cid)}>
Search image on Yandex
</li>
</a>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://saucenao.com/search.php?url=${replyMediaInfo.url}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleMobileOptionClick(reply.cid)}>
Search image on SauceNAO
</li>
</a>
</>
) : null
}
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://plebbitapp.eth.limo/#/p/${selectedAddress}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleOptionClick(reply.cid)}>
View on plebbit
</li>
</a>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://plebones.netlify.app/#/p/${selectedAddress}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleOptionClick(reply.cid)}>
View on plebones
</li>
</a>
</ul>
</PostMenuMobile>, document.body
)}
<span key={`mob-nb-${index}`} className="name-block-mobile">
{reply.author.displayName
? reply.author.displayName.length > 20
+19 -17
View File
@@ -24,7 +24,6 @@ import VerifiedAuthor from '../VerifiedAuthor';
import countLinks from '../../utils/countLinks';
import getCommentMediaInfo from '../../utils/getCommentMediaInfo';
import getFormattedTime from '../../utils/getFormattedTime';
import handleShareClick from '../../utils/handleShareClick';
import handleStyleChange from '../../utils/handleStyleChange';
import useAnonModeRef from '../../hooks/useAnonModeRef';
import useClickForm from '../../hooks/useClickForm';
@@ -433,10 +432,10 @@ const CatalogPost = ({post}) => {
style={{ display: openMenuCid === "rules" ? 'block' : 'none' }}
>
<ul className="post-menu-catalog">
<li onClick={() => {
handleOptionClick("rules");
handleShareClick(selectedAddress, "rules");
}}>Share board</li>
<a target="_blank" rel="noreferrer"
style={{color: 'inherit', textDecoration: 'none'}}
href={`https://pleb.bz/p/${selectedAddress}/?redirect=plebchan.eth.limo`}>
</a>
{/* {isModerator ? (
<>
change rules
@@ -512,7 +511,7 @@ const CatalogPost = ({post}) => {
setPopupPosition({top: rect.top + window.scrollY, left: rect.left});
}}
onMouseLeave={() => setIsHoveringForMenu(false)}
src={subplebbit.suggested.avatarUrl} alt="board avatar" />
src={subplebbit.suggested?.avatarUrl} alt="board avatar" />
) : null}
</Link>
{subplebbit.suggested?.avatarUrl ? (
@@ -577,10 +576,10 @@ const CatalogPost = ({post}) => {
style={{ display: openMenuCid === "description" ? 'block' : 'none' }}
>
<ul className="post-menu-catalog">
<li onClick={() => {
handleOptionClick("description");
handleShareClick(selectedAddress, "description");
}}>Share board</li>
<a target="_blank" rel="noreferrer"
style={{color: 'inherit', textDecoration: 'none'}}
href={`https://pleb.bz/p/${selectedAddress}/?redirect=plebchan.eth.limo`}>
</a>
{/* {isModerator ? (
<>
change description
@@ -595,19 +594,19 @@ const CatalogPost = ({post}) => {
style={{display: isImageSearchOpen ? 'block': 'none'}}>
<li onClick={() => handleOptionClick("description")}>
<a
href={`https://lens.google.com/uploadbyurl?url=${subplebbit.suggested.avatarUrl}`}
href={`https://lens.google.com/uploadbyurl?url=${subplebbit.suggested?.avatarUrl}`}
target="_blank" rel="noreferrer"
>Google</a>
</li>
<li onClick={() => handleOptionClick("description")}>
<a
href={`https://yandex.com/images/search?url=${subplebbit.suggested.avatarUrl}`}
href={`https://yandex.com/images/search?url=${subplebbit.suggested?.avatarUrl}`}
target="_blank" rel="noreferrer"
>Yandex</a>
</li>
<li onClick={() => handleOptionClick("description")}>
<a
href={`https://saucenao.com/search.php?url=${subplebbit.suggested.avatarUrl}`}
href={`https://saucenao.com/search.php?url=${subplebbit.suggested?.avatarUrl}`}
target="_blank" rel="noreferrer"
>SauceNAO</a>
</li>
@@ -818,10 +817,13 @@ const CatalogPost = ({post}) => {
style={{ display: openMenuCid === thread.cid ? 'block' : 'none' }}
>
<ul className="post-menu-catalog">
<li onClick={() => {
handleOptionClick(thread.cid);
handleShareClick(selectedAddress, thread.cid);
}}>Share thread</li>
<a target="_blank" rel="noreferrer"
style={{color: 'inherit', textDecoration: 'none'}}
href={`https://pleb.bz/p/${selectedAddress}/c/${thread.cid}?redirect=plebchan.eth.limo`}>
<li onClick={() => {
handleOptionClick(thread.cid);
}}>Share thread</li>
</a>
<VerifiedAuthor commentCid={thread.cid}>{({ authorAddress }) => (
<>
{authorAddress === account?.author.address ||
+149 -12
View File
@@ -5,7 +5,7 @@ import { Link, useNavigate, useParams } from 'react-router-dom';
import { Tooltip } from 'react-tooltip';
import { useSubplebbit } from '@plebbit/plebbit-react-hooks';
import { debounce } from 'lodash';
import { Container, NavBar, Header, Break, PostMenu, PostForm } from '../styled/views/Board.styled';
import { Container, NavBar, Header, Break, PostMenu, PostForm, PostMenuMobile } from '../styled/views/Board.styled';
import { TopBar, BoardForm, Footer, ReplyFormLink} from '../styled/views/Thread.styled';
import { PostMenuCatalog } from '../styled/views/Catalog.styled';
import BoardStats from '../BoardStats';
@@ -17,7 +17,6 @@ import OfflineIndicator from '../OfflineIndicator';
import SettingsModal from '../modals/SettingsModal';
import getDate from '../../utils/getDate';
import handleImageClick from '../../utils/handleImageClick';
import handleShareClick from '../../utils/handleShareClick';
import handleStyleChange from '../../utils/handleStyleChange';
import useGeneralStore from '../../hooks/stores/useGeneralStore';
import packageJson from '../../../package.json';
@@ -37,15 +36,20 @@ const Description = () => {
const navigate = useNavigate();
const threadMenuRefs = useRef({});
const postMenuRef = useRef(null);
const threadMenuRefsMobile = useRef({});
const postMenuMobileRef = useRef(null);
const postMenuCatalogRef = useRef(null);
const [isAdminListOpen, setIsAdminListOpen] = useState(false);
const [prevScrollPos, setPrevScrollPos] = useState(0);
const [visible, setVisible] = useState(true);
const [menuPosition, setMenuPosition] = useState({top: 0, left: 0});
const [mobileMenuPosition, setMobileMenuPosition] = useState({top: 0, left: 0});
const [openMenuCid, setOpenMenuCid] = useState(null);
const [openMobileMenuCid, setOpenMobileMenuCid] = useState(null);
const [isCreateBoardOpen, setIsCreateBoardOpen] = useState(false);
const [isImageSearchOpen, setIsImageSearchOpen] = useState(false);
const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false);
const { subplebbitAddress } = useParams();
const subplebbit = useSubplebbit({subplebbitAddress: selectedAddress});
@@ -55,12 +59,23 @@ const Description = () => {
setOpenMenuCid(null);
};
const handleMobileOptionClick = () => {
setOpenMobileMenuCid(null);
};
const handleOutsideClick = useCallback((e) => {
if (openMenuCid !== null && !postMenuRef.current.contains(e.target) && !postMenuCatalogRef.current.contains(e.target)) {
if (openMenuCid !== null && !postMenuCatalogRef.current.contains(e.target)) {
setOpenMenuCid(null);
}
}, [openMenuCid, postMenuRef, postMenuCatalogRef]);
}, [openMenuCid, postMenuCatalogRef]);
const handleMobileOutsideClick = useCallback((e) => {
if (openMobileMenuCid !== null && !postMenuMobileRef.current.contains(e.target)) {
setOpenMobileMenuCid(null);
}
}, [openMobileMenuCid, postMenuMobileRef]);
useEffect(() => {
if (openMenuCid !== null) {
@@ -74,6 +89,19 @@ const Description = () => {
};
}, [openMenuCid, handleOutsideClick]);
useEffect(() => {
if (openMobileMenuCid !== null) {
document.addEventListener('click', handleMobileOutsideClick);
} else {
document.removeEventListener('click', handleMobileOutsideClick);
}
return () => {
document.removeEventListener('click', handleMobileOutsideClick);
};
}, [openMobileMenuCid, handleMobileOutsideClick]);
useEffect(() => {
window.scrollTo(0, 0);
@@ -367,15 +395,65 @@ const Description = () => {
style={{ display: openMenuCid === subplebbit.pubsubTopic ? 'block' : 'none' }}
>
<ul className="post-menu-catalog">
<li onClick={() => {
handleOptionClick("description");
handleShareClick(selectedAddress, "description");
}}>Share board</li>
{/* {isModerator ? (
<>
change description
</>
) : null} */}
{subplebbit.suggested?.avatarUrl ? (
<li
onMouseOver={() => {setIsImageSearchOpen(true)}}
onMouseLeave={() => {setIsImageSearchOpen(false)}}>
Image search »
<ul className="dropdown-menu post-menu-catalog"
style={{display: isImageSearchOpen ? 'block': 'none'}}>
<li onClick={() => handleOptionClick("description")}>
<a
href={`https://lens.google.com/uploadbyurl?url=${subplebbit.suggested?.avatarUrl}`}
target="_blank" rel="noreferrer"
>Google</a>
</li>
<li onClick={() => handleOptionClick("description")}>
<a
href={`https://yandex.com/images/search?url=${subplebbit.suggested?.avatarUrl}`}
target="_blank" rel="noreferrer"
>Yandex</a>
</li>
<li onClick={() => handleOptionClick("description")}>
<a
href={`https://saucenao.com/search.php?url=${subplebbit.suggested?.avatarUrl}`}
target="_blank" rel="noreferrer"
>SauceNAO</a>
</li>
</ul>
</li>
) : null}
<li
onMouseOver={() => {setIsClientRedirectMenuOpen(true)}}
onMouseLeave={() => {setIsClientRedirectMenuOpen(false)}}>
View on »
<ul className="dropdown-menu post-menu-catalog"
style={{display: isClientRedirectMenuOpen ? 'block': 'none'}}>
<li onClick={() => handleOptionClick("description")}>
<a
href={`https://plebbitapp.eth.limo/#/p/${selectedAddress}`}
target="_blank" rel="noreferrer"
>Plebbit</a>
</li>
{/* <li onClick={() => handleOptionClick("description")}>
<a
href={`https://seedit.eth.limo/#/p/${selectedAddress}`}
target="_blank" rel="noreferrer"
>Seedit</a>
</li> */}
<li onClick={() => handleOptionClick("description")}>
<a
href={`https://plebones.netlify.app/#/p/${selectedAddress}`}
target="_blank" rel="noreferrer"
>Plebones</a>
</li>
</ul>
</li>
</ul>
</div>
</PostMenuCatalog>, document.body
@@ -395,8 +473,67 @@ const Description = () => {
<div className="op-container">
<div className="post op op-mobile">
<div className="post-info-mobile">
<button className="post-menu-button-mobile"
style={{ all: 'unset', cursor: 'pointer' }}>...</button>
<button key={`mob-pb-`} className="post-menu-button-mobile"
ref={el => {
threadMenuRefsMobile.current["description"] = el;
}}
onClick={(event) => {
event.stopPropagation();
const rect = threadMenuRefsMobile.current["description"].getBoundingClientRect();
setMobileMenuPosition({top: rect.top + window.scrollY, left: rect.left});
setOpenMobileMenuCid(prevCid => (prevCid === "description" ? null : "description"));
}}
style={{ all: 'unset', cursor: 'pointer' }}
>...</button>
{createPortal(
<PostMenuMobile selectedStyle={selectedStyle}
ref={el => {postMenuMobileRef.current = el}}
onClick={(event) => event.stopPropagation()}
style={{position: "absolute",
display: openMobileMenuCid === "description" ? "block" : "none",
top: mobileMenuPosition.top + 20,
left: mobileMenuPosition.left}}>
<ul className={`post-menu-mobile-thread-description`}>
{subplebbit.suggested?.avatarUrl ? (
<>
<li onClick={() => handleMobileOptionClick("description")}>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://lens.google.com/uploadbyurl?url=${subplebbit.suggested?.avatarUrl}`}
target="_blank" rel="noreferrer"
>Search image on Google</a>
</li>
<li onClick={() => handleMobileOptionClick("description")}>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://yandex.com/images/search?url=${subplebbit.suggested?.avatarUrl}`}
target="_blank" rel="noreferrer"
>Search image on Yandex</a>
</li>
<li onClick={() => handleMobileOptionClick("description")}>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://saucenao.com/search.php?url=${subplebbit.suggested?.avatarUrl}`}
target="_blank" rel="noreferrer"
>Search image on SauceNAO</a>
</li>
</>
) : null
}
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://plebbitapp.eth.limo/#/p/${selectedAddress}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleMobileOptionClick("description")}>
View on plebbit
</li>
</a>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://plebones.netlify.app/#/p/${selectedAddress}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleMobileOptionClick("description")}>
View on plebones
</li>
</a>
</ul>
</PostMenuMobile>, document.body
)}
<span className="name-block-mobile">
<span className="name-mobile capcode"
style={{cursor: 'pointer'}}
@@ -421,7 +558,7 @@ const Description = () => {
<div className="file-mobile">
<div className="img-container">
<span className="file-thumb-mobile">
<img src={subplebbit.suggested.avatarUrl} alt="board avatar"
<img src={subplebbit.suggested?.avatarUrl} alt="board avatar"
onClick={handleImageClick}
style={{cursor: "pointer"}} />
<div className="file-info-mobile">image</div>
+96 -12
View File
@@ -5,7 +5,7 @@ import { Link, useNavigate, useParams } from 'react-router-dom';
import { Tooltip } from 'react-tooltip';
import { useSubplebbit } from '@plebbit/plebbit-react-hooks';
import { debounce } from 'lodash';
import { Container, NavBar, Header, Break, PostMenu, PostForm } from '../styled/views/Board.styled';
import { Container, NavBar, Header, Break, PostMenu, PostForm, PostMenuMobile } from '../styled/views/Board.styled';
import { TopBar, BoardForm, Footer, ReplyFormLink} from '../styled/views/Thread.styled';
import { PostMenuCatalog } from '../styled/views/Catalog.styled';
import BoardStats from '../BoardStats';
@@ -15,7 +15,6 @@ import AdminListModal from '../modals/AdminListModal';
import OfflineIndicator from '../OfflineIndicator';
import SettingsModal from '../modals/SettingsModal';
import getDate from '../../utils/getDate';
import handleShareClick from '../../utils/handleShareClick';
import handleStyleChange from '../../utils/handleStyleChange';
import useGeneralStore from '../../hooks/stores/useGeneralStore';
import packageJson from '../../../package.json';
@@ -42,15 +41,19 @@ const Rules = () => {
const navigate = useNavigate();
const threadMenuRefs = useRef({});
const postMenuRef = useRef(null);
const threadMenuRefsMobile = useRef({});
const postMenuMobileRef = useRef(null);
const postMenuCatalogRef = useRef(null);
const [isAdminListOpen, setIsAdminListOpen] = useState(false);
const [prevScrollPos, setPrevScrollPos] = useState(0);
const [visible, setVisible] = useState(true);
const [menuPosition, setMenuPosition] = useState({top: 0, left: 0});
const [mobileMenuPosition, setMobileMenuPosition] = useState({top: 0, left: 0});
const [openMenuCid, setOpenMenuCid] = useState(null);
const [openMobileMenuCid, setOpenMobileMenuCid] = useState(null);
const [isCreateBoardOpen, setIsCreateBoardOpen] = useState(false);
const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false);
const { subplebbitAddress } = useParams();
const subplebbit = useSubplebbit({subplebbitAddress: selectedAddress});
@@ -60,12 +63,23 @@ const Rules = () => {
setOpenMenuCid(null);
};
const handleMobileOptionClick = () => {
setOpenMobileMenuCid(null);
};
const handleOutsideClick = useCallback((e) => {
if (openMenuCid !== null && !postMenuRef.current.contains(e.target) && !postMenuCatalogRef.current.contains(e.target)) {
if (openMenuCid !== null && !postMenuCatalogRef.current.contains(e.target)) {
setOpenMenuCid(null);
}
}, [openMenuCid, postMenuRef, postMenuCatalogRef]);
}, [openMenuCid, postMenuCatalogRef]);
const handleMobileOutsideClick = useCallback((e) => {
if (openMobileMenuCid !== null && !postMenuMobileRef.current.contains(e.target)) {
setOpenMobileMenuCid(null);
}
}, [openMobileMenuCid, postMenuMobileRef]);
useEffect(() => {
if (openMenuCid !== null) {
@@ -79,13 +93,25 @@ const Rules = () => {
};
}, [openMenuCid, handleOutsideClick]);
useEffect(() => {
if (openMobileMenuCid !== null) {
document.addEventListener('click', handleMobileOutsideClick);
} else {
document.removeEventListener('click', handleMobileOutsideClick);
}
return () => {
document.removeEventListener('click', handleMobileOutsideClick);
};
}, [openMobileMenuCid, handleMobileOutsideClick]);
useEffect(() => {
window.scrollTo(0, 0);
}, []);
useEffect(() => {
const selectedSubplebbit = defaultSubplebbits.find((subplebbit) => subplebbit.address === subplebbitAddress);
if (subplebbitAddress) {
@@ -349,15 +375,37 @@ const Rules = () => {
style={{ display: openMenuCid === "rules" ? 'block' : 'none' }}
>
<ul className="post-menu-catalog">
<li onClick={() => {
handleOptionClick("rules");
handleShareClick(selectedAddress, "rules");
}}>Share board</li>
{/* {isModerator ? (
<>
change rules
</>
) : null} */}
<li
onMouseOver={() => {setIsClientRedirectMenuOpen(true)}}
onMouseLeave={() => {setIsClientRedirectMenuOpen(false)}}>
View on »
<ul className="dropdown-menu post-menu-catalog"
style={{display: isClientRedirectMenuOpen ? 'block': 'none'}}>
<li onClick={() => handleOptionClick("rules")}>
<a
href={`https://plebbitapp.eth.limo/#/p/${selectedAddress}`}
target="_blank" rel="noreferrer"
>Plebbit</a>
</li>
{/* <li onClick={() => handleOptionClick("rules")}>
<a
href={`https://seedit.eth.limo/#/p/${selectedAddress}`}
target="_blank" rel="noreferrer"
>Seedit</a>
</li> */}
<li onClick={() => handleOptionClick("rules")}>
<a
href={`https://plebones.netlify.app/#/p/${selectedAddress}`}
target="_blank" rel="noreferrer"
>Plebones</a>
</li>
</ul>
</li>
</ul>
</div>
</PostMenuCatalog>, document.body
@@ -391,8 +439,44 @@ const Rules = () => {
<div className="op-container">
<div className="post op op-mobile">
<div className="post-info-mobile">
<button className="post-menu-button-mobile"
style={{ all: 'unset', cursor: 'pointer' }}>...</button>
<button key={`mob-pb-`} className="post-menu-button-mobile"
ref={el => {
threadMenuRefsMobile.current["rules"] = el;
}}
onClick={(event) => {
event.stopPropagation();
const rect = threadMenuRefsMobile.current["rules"].getBoundingClientRect();
setMobileMenuPosition({top: rect.top + window.scrollY, left: rect.left});
setOpenMobileMenuCid(prevCid => (prevCid === "rules" ? null : "rules"));
}}
style={{ all: 'unset', cursor: 'pointer' }}
>...</button>
{createPortal(
<PostMenuMobile selectedStyle={selectedStyle}
ref={el => {postMenuMobileRef.current = el}}
onClick={(event) => event.stopPropagation()}
style={{position: "absolute",
display: openMobileMenuCid === "rules" ? "block" : "none",
top: mobileMenuPosition.top + 20,
left: mobileMenuPosition.left}}>
<ul className={`post-menu-mobile-thread-description`}>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://plebbitapp.eth.limo/#/p/${selectedAddress}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleMobileOptionClick("rules")}>
View on plebbit
</li>
</a>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://plebones.netlify.app/#/p/${selectedAddress}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleMobileOptionClick("rules")}>
View on plebones
</li>
</a>
</ul>
</PostMenuMobile>, document.body
)}
<span className="name-block-mobile">
<span className="name-mobile capcode"
style={{cursor: 'pointer'}}
+223 -11
View File
@@ -9,7 +9,7 @@ import { useAccount, useAccountComments, useFeed, usePublishCommentEdit, useSubp
import { flattenCommentsPages } from '@plebbit/plebbit-react-hooks/dist/lib/utils'
import { debounce } from 'lodash';
import useGeneralStore from '../../hooks/stores/useGeneralStore';
import { Container, NavBar, Header, Break, TopBar, BoardForm, PostMenu } from '../styled/views/Board.styled';
import { Container, NavBar, Header, Break, TopBar, BoardForm, PostMenu, PostMenuMobile } from '../styled/views/Board.styled';
import { Footer } from '../styled/views/Thread.styled';
import { AlertModal } from '../styled/modals/AlertModal.styled';
import { PostMenuCatalog } from '../styled/views/Catalog.styled';
@@ -85,8 +85,11 @@ const Subscriptions = () => {
const [, setNewSuccessMessage] = useSuccess();
const threadMenuRefs = useRef({});
const threadMenuRefsMobile = useRef({});
const replyMenuRefs = useRef({});
const replyMenuRefsMobile = useRef({});
const postMenuCatalogRef = useRef(null);
const postMenuMobileRef = useRef(null);
const backlinkRefs = useRef({});
const quoteRefs = useRef({});
const postRefs = useRef({});
@@ -105,8 +108,10 @@ const Subscriptions = () => {
const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false);
const [commentCid, setCommentCid] = useState(null);
const [menuPosition, setMenuPosition] = useState({top: 0, left: 0});
const [mobileMenuPosition, setMobileMenuPosition] = useState({top: 0, left: 0});
const [triggerPublishCommentEdit, setTriggerPublishCommentEdit] = useState(false);
const [openMenuCid, setOpenMenuCid] = useState(null);
const [openMobileMenuCid, setOpenMobileMenuCid] = useState(null);
const [outOfViewCid, setOutOfViewCid] = useState(null);
const [outOfViewPosition, setOutOfViewPosition] = useState({top: 0, left: 0});
const [postOnHoverHeight, setPostOnHoverHeight] = useState(0);
@@ -196,12 +201,22 @@ const Subscriptions = () => {
setOpenMenuCid(null);
};
const handleMobileOptionClick = () => {
setOpenMobileMenuCid(null);
};
const handleOutsideClick = useCallback((e) => {
if (openMenuCid !== null && !postMenuCatalogRef.current.contains(e.target)) {
setOpenMenuCid(null);
}
}, [openMenuCid, postMenuCatalogRef]);
const handleMobileOutsideClick = useCallback((e) => {
if (openMobileMenuCid !== null && !postMenuMobileRef.current.contains(e.target)) {
setOpenMobileMenuCid(null);
}
}, [openMobileMenuCid, postMenuMobileRef]);
useEffect(() => {
@@ -217,6 +232,19 @@ const Subscriptions = () => {
}, [openMenuCid, handleOutsideClick]);
useEffect(() => {
if (openMobileMenuCid !== null) {
document.addEventListener('click', handleMobileOutsideClick);
} else {
document.removeEventListener('click', handleMobileOutsideClick);
}
return () => {
document.removeEventListener('click', handleMobileOutsideClick);
};
}, [openMobileMenuCid, handleMobileOutsideClick]);
useEffect(() => {
if (postOnHoverRef.current) {
const rect = postOnHoverRef.current.getBoundingClientRect();
@@ -730,10 +758,10 @@ const Subscriptions = () => {
commentMediaInfo?.url.length > 30 ?
commentMediaInfo?.url.slice(0, 30) + "(...)" :
commentMediaInfo?.url
}</a>&nbsp;{commentMediaInfo?.type === "iframe" ? null : `(${commentMediaInfo?.type})`}
}</a>{commentMediaInfo?.type === "iframe" ? null : `(${commentMediaInfo?.type})`}
{((isThreadThumbnailClicked[index] && (commentMediaInfo.type === 'iframe' || commentMediaInfo.type === 'video')) || (commentMediaInfo.type === 'iframe' && !commentMediaInfo.thumbnail)) && (
<span>
[
 [
<span className='reply-link'
style={{textDecoration: 'underline', cursor: 'pointer'}}
onClick={() => {handleThumbnailClick(index, 'thread')}}>
@@ -1271,8 +1299,8 @@ const Subscriptions = () => {
<ul className="post-menu-catalog">
<li onClick={() => {
handleOptionClick(reply.cid);
handleShareClick(thread.subplebbitAddress, thread.cid);
}}>Share thread</li>
handleShareClick(thread.subplebbitAddress, reply.cid);
}}>Share post</li>
<VerifiedAuthor commentCid={reply.cid}>{({ authorAddress }) => (
<>
{authorAddress === account?.author.address ||
@@ -1329,7 +1357,7 @@ const Subscriptions = () => {
</li>
<li onClick={() => handleOptionClick(reply.cid)}>
<a
href={`https://yandex.com/images/search?url=${replyMediaInfo.url}`}
href={`https://yandex.com/images/search?img_url=${replyMediaInfo.url}&rpt=imageview`}
target="_blank" rel="noreferrer"
>Yandex</a>
</li>
@@ -1437,10 +1465,10 @@ const Subscriptions = () => {
replyMediaInfo?.url.length > 30 ?
replyMediaInfo?.url.slice(0, 30) + "(...)" :
replyMediaInfo?.url
}</a>&nbsp;{replyMediaInfo?.type === "iframe" ? null : `(${replyMediaInfo?.type})`}
}</a>{replyMediaInfo?.type === "iframe" ? null : `(${replyMediaInfo?.type})`}
{ ((isReplyThumbnailClicked[index] && (replyMediaInfo.type === 'iframe' || replyMediaInfo.type === 'video')) || (replyMediaInfo.type === 'iframe' && !replyMediaInfo.thumbnail)) && (
<span>
[
 [
<span className='reply-link'
style={{textDecoration: 'underline', cursor: 'pointer'}}
onClick={() => {handleThumbnailClick(index, 'reply')}}>
@@ -1756,7 +1784,99 @@ const Subscriptions = () => {
<div key={`mob-c-${index}`} className="op-container">
<div key={`mob-po-${index}`} className="post op op-mobile">
<div key={`mob-pi-${index}`} className="post-info-mobile">
<button key={`mob-pb-${index}`} className="post-menu-button-mobile" style={{ all: 'unset', cursor: 'pointer' }}>...</button>
<button key={`mob-pb-${index}`} className="post-menu-button-mobile"
ref={el => {
threadMenuRefsMobile.current[thread.cid] = el;
}}
onClick={(event) => {
event.stopPropagation();
const rect = threadMenuRefsMobile.current[thread.cid].getBoundingClientRect();
setMobileMenuPosition({top: rect.top + window.scrollY, left: rect.left});
setOpenMobileMenuCid(prevCid => (prevCid === thread.cid ? null : thread.cid));
}}
style={{ all: 'unset', cursor: 'pointer' }}
>...</button>
{createPortal(
<PostMenuMobile selectedStyle={selectedStyle}
ref={el => {postMenuMobileRef.current = el}}
onClick={(event) => event.stopPropagation()}
style={{position: "absolute",
display: openMobileMenuCid === thread.cid ? "block" : "none",
top: mobileMenuPosition.top + 20,
left: mobileMenuPosition.left}}>
<ul className={`post-menu-mobile-thread-${thread.cid}`}>
<li onClick={() => {
handleMobileOptionClick(thread.cid);
handleShareClick(selectedAddress, thread.cid)
}}>Share thread</li>
<VerifiedAuthor commentCid={thread.cid}>{({ authorAddress }) => (
<>
{authorAddress === account?.author.address ||
authorAddress === account?.signer.address ? (
<>
<li onClick={() => handleAuthorEditClick(thread)}>Edit post</li>
<li onClick={() => handleAuthorDeleteClick(thread)}>Delete post</li>
</>
) : null}
{isModerator ? (
<>
{authorAddress === account?.author.address ||
authorAddress === account?.signer.address ? (
null
) : (
<li onClick={() => {
setModeratingCommentCid(thread.cid)
setIsModerationOpen(true);
handleMobileOptionClick(thread.cid);
setDeletePost(true);
}}>
Delete post
</li>
)}
<li
onClick={() => {
setModeratingCommentCid(thread.cid)
setIsModerationOpen(true);
handleMobileOptionClick(thread.cid);
}}>
Mod tools
</li>
</>
) : null}
</>
)}</VerifiedAuthor>
{(commentMediaInfo && (
commentMediaInfo.type === 'image' ||
(commentMediaInfo.type === 'webpage' &&
commentMediaInfo.thumbnail))) ? (
<>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://lens.google.com/uploadbyurl?url=${commentMediaInfo.url}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleMobileOptionClick(thread.cid)}>
Search image on Google
</li>
</a>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://yandex.com/images/search?url=${commentMediaInfo.url}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleMobileOptionClick(thread.cid)}>
Search image on Yandex
</li>
</a>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://saucenao.com/search.php?url=${commentMediaInfo.url}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleMobileOptionClick(thread.cid)}>
Search image on SauceNAO
</li>
</a>
</>
) : null
}
</ul>
</PostMenuMobile>, document.body
)}
<span key={`mob-nbm-${index}`} className="name-block-mobile">
{thread.author.displayName
? thread.author.displayName.length > 20
@@ -1993,7 +2113,99 @@ const Subscriptions = () => {
<div key={`mob-rc-${index}`} className="reply-container">
<div key={`mob-pr-${index}`} className="post-reply post-reply-mobile">
<div key={`mob-pi-${index}`} className="post-info-mobile">
<button key={`pmbm-${index}`} className="post-menu-button-mobile" title="Post menu" style={{ all: 'unset', cursor: 'pointer' }}>...</button>
<button key={`mob-pb-${index}`} className="post-menu-button-mobile"
ref={el => {
replyMenuRefsMobile.current[reply.cid] = el;
}}
onClick={(event) => {
event.stopPropagation();
const rect = replyMenuRefsMobile.current[reply.cid].getBoundingClientRect();
setMobileMenuPosition({top: rect.top + window.scrollY, left: rect.left});
setOpenMobileMenuCid(prevCid => (prevCid === reply.cid ? null : reply.cid));
}}
style={{ all: 'unset', cursor: 'pointer' }}
>...</button>
{createPortal(
<PostMenuMobile selectedStyle={selectedStyle}
ref={el => {postMenuMobileRef.current = el}}
onClick={(event) => event.stopPropagation()}
style={{position: "absolute",
display: openMobileMenuCid === reply.cid ? "block" : "none",
top: mobileMenuPosition.top + 20,
left: mobileMenuPosition.left}}>
<ul className={`post-menu-mobile-thread-${reply.cid}`}>
<li onClick={() => {
handleMobileOptionClick(reply.cid);
handleShareClick(selectedAddress, reply.cid)
}}>Share post</li>
<VerifiedAuthor commentCid={reply.cid}>{({ authorAddress }) => (
<>
{authorAddress === account?.author.address ||
authorAddress === account?.signer.address ? (
<>
<li onClick={() => handleAuthorEditClick(reply)}>Edit post</li>
<li onClick={() => handleAuthorDeleteClick(reply)}>Delete post</li>
</>
) : null}
{isModerator ? (
<>
{authorAddress === account?.author.address ||
authorAddress === account?.signer.address ? (
null
) : (
<li onClick={() => {
setModeratingCommentCid(reply.cid)
setIsModerationOpen(true);
handleMobileOptionClick(reply.cid);
setDeletePost(true);
}}>
Delete post
</li>
)}
<li
onClick={() => {
setModeratingCommentCid(reply.cid)
setIsModerationOpen(true);
handleMobileOptionClick(reply.cid);
}}>
Mod tools
</li>
</>
) : null}
</>
)}</VerifiedAuthor>
{(replyMediaInfo && (
replyMediaInfo.type === 'image' ||
(replyMediaInfo.type === 'webpage' &&
replyMediaInfo.thumbnail))) ? (
<>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://lens.google.com/uploadbyurl?url=${replyMediaInfo.url}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleMobileOptionClick(reply.cid)}>
Search image on Google
</li>
</a>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://yandex.com/images/search?url=${replyMediaInfo.url}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleMobileOptionClick(reply.cid)}>
Search image on Yandex
</li>
</a>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://saucenao.com/search.php?url=${replyMediaInfo.url}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleMobileOptionClick(reply.cid)}>
Search image on SauceNAO
</li>
</a>
</>
) : null
}
</ul>
</PostMenuMobile>, document.body
)}
<span key={`mob-nb-${index}`} className="name-block-mobile">
{reply.author.displayName
? reply.author.displayName.length > 20
+251 -10
View File
@@ -7,7 +7,7 @@ import { Tooltip } from 'react-tooltip';
import { useAccount, useAccountComments, useComment, usePublishComment, usePublishCommentEdit, useSubplebbit } from '@plebbit/plebbit-react-hooks';
import { flattenCommentsPages } from '@plebbit/plebbit-react-hooks/dist/lib/utils'
import { debounce } from 'lodash';
import { Container, NavBar, Header, Break, PostForm, PostFormTable, PostMenu } from '../styled/views/Board.styled';
import { Container, NavBar, Header, Break, PostForm, PostFormTable, PostMenu, PostMenuMobile } from '../styled/views/Board.styled';
import { ReplyFormLink, TopBar, BottomBar, BoardForm, Footer } from '../styled/views/Thread.styled';
import { AlertModal } from '../styled/modals/AlertModal.styled';
import { PostMenuCatalog } from '../styled/views/Catalog.styled';
@@ -91,8 +91,11 @@ const Thread = () => {
const commentRef = useRef();
const linkRef = useRef();
const threadMenuRefs = useRef({});
const threadMenuRefsMobile = useRef({});
const replyMenuRefs = useRef({});
const replyMenuRefsMobile = useRef({});
const postMenuRef = useRef(null);
const postMenuMobileRef = useRef(null);
const postMenuCatalogRef = useRef(null);
const backlinkRefs = useRef({});
const quoteRefs = useRef({});
@@ -114,7 +117,9 @@ const Thread = () => {
const [isModerator, setIsModerator] = useState(false);
const [commentCid, setCommentCid] = useState(null);
const [menuPosition, setMenuPosition] = useState({top: 0, left: 0});
const [mobileMenuPosition, setMobileMenuPosition] = useState({top: 0, left: 0});
const [openMenuCid, setOpenMenuCid] = useState(null);
const [openMobileMenuCid, setOpenMobileMenuCid] = useState(null);
const [outOfViewCid, setOutOfViewCid] = useState(null);
const [outOfViewPosition, setOutOfViewPosition] = useState({top: 0, left: 0});
const [postOnHoverHeight, setPostOnHoverHeight] = useState(0);
@@ -189,12 +194,22 @@ const Thread = () => {
setOpenMenuCid(null);
};
const handleMobileOptionClick = () => {
setOpenMobileMenuCid(null);
};
const handleOutsideClick = useCallback((e) => {
if (openMenuCid !== null && !postMenuRef.current.contains(e.target) && !postMenuCatalogRef.current.contains(e.target)) {
setOpenMenuCid(null);
}
}, [openMenuCid, postMenuRef, postMenuCatalogRef]);
const handleMobileOutsideClick = useCallback((e) => {
if (openMobileMenuCid !== null && !postMenuMobileRef.current.contains(e.target)) {
setOpenMobileMenuCid(null);
}
}, [openMobileMenuCid, postMenuMobileRef]);
useEffect(() => {
if (openMenuCid !== null) {
document.addEventListener('click', handleOutsideClick);
@@ -208,6 +223,20 @@ const Thread = () => {
}, [openMenuCid, handleOutsideClick]);
useEffect(() => {
if (openMobileMenuCid !== null) {
document.addEventListener('click', handleMobileOutsideClick);
} else {
document.removeEventListener('click', handleMobileOutsideClick);
}
return () => {
document.removeEventListener('click', handleMobileOutsideClick);
};
}, [openMobileMenuCid, handleMobileOutsideClick]);
useEffect(() => {
if (postOnHoverRef.current) {
const rect = postOnHoverRef.current.getBoundingClientRect();
@@ -871,10 +900,10 @@ const Thread = () => {
commentMediaInfo?.url.length > 30 ?
commentMediaInfo?.url.slice(0, 30) + "(...)" :
commentMediaInfo?.url
}</a>&nbsp;{commentMediaInfo?.type === "iframe" ? null : `(${commentMediaInfo?.type})`}
}</a>{commentMediaInfo?.type === "iframe" ? null : `(${commentMediaInfo?.type})`}
{((isThreadThumbnailClicked[index] && (commentMediaInfo.type === 'iframe' || commentMediaInfo.type === 'video')) || (commentMediaInfo.type === 'iframe' && !commentMediaInfo.thumbnail)) && (
<span>
[
 [
<span className='reply-link'
style={{textDecoration: 'underline', cursor: 'pointer'}}
onClick={() => {handleThumbnailClick(index, 'thread')}}>
@@ -1367,8 +1396,8 @@ const Thread = () => {
<ul className="post-menu-catalog">
<li onClick={() => {
handleOptionClick(reply.cid);
handleShareClick(selectedAddress, comment.cid);
}}>Share thread</li>
handleShareClick(selectedAddress, reply.cid);
}}>Share post</li>
<VerifiedAuthor commentCid={reply.cid}>{({ authorAddress }) => (
<>
{authorAddress === account?.author.address ||
@@ -1423,7 +1452,7 @@ const Thread = () => {
</li>
<li onClick={() => handleOptionClick(reply.cid)}>
<a
href={`https://yandex.com/images/search?url=${replyMediaInfo.url}`}
href={`https://yandex.com/images/search?img_url=${replyMediaInfo.url}&rpt=imageview`}
target="_blank" rel="noreferrer"
>Yandex</a>
</li>
@@ -1531,10 +1560,10 @@ const Thread = () => {
replyMediaInfo?.url.length > 30 ?
replyMediaInfo?.url.slice(0, 30) + "(...)" :
replyMediaInfo?.url
}</a>&nbsp;{replyMediaInfo?.type === "iframe" ? null : `(${replyMediaInfo?.type})`}
}</a>{replyMediaInfo?.type === "iframe" ? null : `(${replyMediaInfo?.type})`}
{ ((isReplyThumbnailClicked[index] && (replyMediaInfo.type === 'iframe' || replyMediaInfo.type === 'video')) || (replyMediaInfo.type === 'iframe' && !replyMediaInfo.thumbnail)) && (
<span>
[
 [
<span className='reply-link'
style={{textDecoration: 'underline', cursor: 'pointer'}}
onClick={() => {handleThumbnailClick(index, 'reply')}}>
@@ -1737,7 +1766,113 @@ const Thread = () => {
<div className="op-container" key="op-container">
<div key={`mob-po-${comment.cid}`} className="post op op-mobile">
<div key={`mob-pi-${comment.cid}`} className="post-info-mobile">
<button style={{ all: 'unset', cursor: 'pointer' }} key={`mob-pb-${comment.cid}`} className="post-menu-button-mobile">...</button>
<button key={`mob-pb-${index}`} className="post-menu-button-mobile"
ref={el => {
threadMenuRefsMobile.current[comment.cid] = el;
}}
onClick={(event) => {
event.stopPropagation();
const rect = threadMenuRefsMobile.current[comment.cid].getBoundingClientRect();
setMobileMenuPosition({top: rect.top + window.scrollY, left: rect.left});
setOpenMobileMenuCid(prevCid => (prevCid === comment.cid ? null : comment.cid));
}}
style={{ all: 'unset', cursor: 'pointer' }}
>...</button>
{createPortal(
<PostMenuMobile selectedStyle={selectedStyle}
ref={el => {postMenuMobileRef.current = el}}
onClick={(event) => event.stopPropagation()}
style={{position: "absolute",
display: openMobileMenuCid === comment.cid ? "block" : "none",
top: mobileMenuPosition.top + 20,
left: mobileMenuPosition.left}}>
<ul className={`post-menu-mobile-thread-${comment.cid}`}>
<li onClick={() => {
handleMobileOptionClick(comment.cid);
handleShareClick(selectedAddress, comment.cid)
}}>Share thread</li>
<VerifiedAuthor commentCid={comment.cid}>{({ authorAddress }) => (
<>
{authorAddress === account?.author.address ||
authorAddress === account?.signer.address ? (
<>
<li onClick={() => handleAuthorEditClick(comment)}>Edit post</li>
<li onClick={() => handleAuthorDeleteClick(comment)}>Delete post</li>
</>
) : null}
{isModerator ? (
<>
{authorAddress === account?.author.address ||
authorAddress === account?.signer.address ? (
null
) : (
<li onClick={() => {
setModeratingCommentCid(comment.cid)
setIsModerationOpen(true);
handleMobileOptionClick(comment.cid);
setDeletePost(true);
}}>
Delete post
</li>
)}
<li
onClick={() => {
setModeratingCommentCid(comment.cid)
setIsModerationOpen(true);
handleMobileOptionClick(comment.cid);
}}>
Mod tools
</li>
</>
) : null}
</>
)}</VerifiedAuthor>
{(commentMediaInfo && (
commentMediaInfo.type === 'image' ||
(commentMediaInfo.type === 'webpage' &&
commentMediaInfo.thumbnail))) ? (
<>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://lens.google.com/uploadbyurl?url=${commentMediaInfo.url}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleMobileOptionClick(comment.cid)}>
Search image on Google
</li>
</a>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://yandex.com/images/search?url=${commentMediaInfo.url}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleMobileOptionClick(comment.cid)}>
Search image on Yandex
</li>
</a>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://saucenao.com/search.php?url=${commentMediaInfo.url}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleMobileOptionClick(comment.cid)}>
Search image on SauceNAO
</li>
</a>
</>
) : null
}
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://plebbitapp.eth.limo/#/p/${selectedAddress}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleOptionClick(comment.cid)}>
View on plebbit
</li>
</a>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://plebones.netlify.app/#/p/${selectedAddress}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleOptionClick(comment.cid)}>
View on plebones
</li>
</a>
</ul>
</PostMenuMobile>, document.body
)}
<span className="name-block-mobile">
{comment?.author?.displayName
? comment?.author?.displayName.length > 15
@@ -1940,7 +2075,113 @@ const Thread = () => {
<div key={`mob-rc-${index}`} className="reply-container">
<div key={`mob-pr-${index}`} className="post-reply post-reply-mobile">
<div key={`mob-pi-${index}`} className="post-info-mobile">
<button className="post-menu-button-mobile" title="Post menu" style={{ all: 'unset', cursor: 'pointer' }}>...</button>
<button key={`mob-pb-${index}`} className="post-menu-button-mobile"
ref={el => {
replyMenuRefsMobile.current[reply.cid] = el;
}}
onClick={(event) => {
event.stopPropagation();
const rect = replyMenuRefsMobile.current[reply.cid].getBoundingClientRect();
setMobileMenuPosition({top: rect.top + window.scrollY, left: rect.left});
setOpenMobileMenuCid(prevCid => (prevCid === reply.cid ? null : reply.cid));
}}
style={{ all: 'unset', cursor: 'pointer' }}
>...</button>
{createPortal(
<PostMenuMobile selectedStyle={selectedStyle}
ref={el => {postMenuMobileRef.current = el}}
onClick={(event) => event.stopPropagation()}
style={{position: "absolute",
display: openMobileMenuCid === reply.cid ? "block" : "none",
top: mobileMenuPosition.top + 20,
left: mobileMenuPosition.left}}>
<ul className={`post-menu-mobile-thread-${reply.cid}`}>
<li onClick={() => {
handleMobileOptionClick(reply.cid);
handleShareClick(selectedAddress, reply.cid)
}}>Share post</li>
<VerifiedAuthor commentCid={reply.cid}>{({ authorAddress }) => (
<>
{authorAddress === account?.author.address ||
authorAddress === account?.signer.address ? (
<>
<li onClick={() => handleAuthorEditClick(reply)}>Edit post</li>
<li onClick={() => handleAuthorDeleteClick(reply)}>Delete post</li>
</>
) : null}
{isModerator ? (
<>
{authorAddress === account?.author.address ||
authorAddress === account?.signer.address ? (
null
) : (
<li onClick={() => {
setModeratingCommentCid(reply.cid)
setIsModerationOpen(true);
handleMobileOptionClick(reply.cid);
setDeletePost(true);
}}>
Delete post
</li>
)}
<li
onClick={() => {
setModeratingCommentCid(reply.cid)
setIsModerationOpen(true);
handleMobileOptionClick(reply.cid);
}}>
Mod tools
</li>
</>
) : null}
</>
)}</VerifiedAuthor>
{(replyMediaInfo && (
replyMediaInfo.type === 'image' ||
(replyMediaInfo.type === 'webpage' &&
replyMediaInfo.thumbnail))) ? (
<>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://lens.google.com/uploadbyurl?url=${replyMediaInfo.url}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleMobileOptionClick(reply.cid)}>
Search image on Google
</li>
</a>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://yandex.com/images/search?url=${replyMediaInfo.url}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleMobileOptionClick(reply.cid)}>
Search image on Yandex
</li>
</a>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://saucenao.com/search.php?url=${replyMediaInfo.url}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleMobileOptionClick(reply.cid)}>
Search image on SauceNAO
</li>
</a>
</>
) : null
}
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://plebbitapp.eth.limo/#/p/${selectedAddress}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleOptionClick(reply.cid)}>
View on plebbit
</li>
</a>
<a style={{color: 'inherit', textDecoration: 'none'}}
href={`https://plebones.netlify.app/#/p/${selectedAddress}`}
target="_blank" rel="noreferrer">
<li onClick={() => handleOptionClick(reply.cid)}>
View on plebones
</li>
</a>
</ul>
</PostMenuMobile>, document.body
)}
<span key={`mob-nb-${index}`} className="name-block-mobile">
{reply.author?.displayName
? reply.author?.displayName.length > 12
+11 -6
View File
@@ -1,14 +1,19 @@
function handleShareClick(selectedAddress, cid) {
const plebBzBaseURL = "https://pleb.bz/p/";
let shareLink;
let shareLink = `${plebBzBaseURL}${selectedAddress}/`;
if (cid === "rules" || cid === "description") {
shareLink = `https://plebchan.eth.limo/#/p/${selectedAddress}`;
} else {
const plebBzBaseURL = "https://pleb.bz/p/";
shareLink = `${plebBzBaseURL}${selectedAddress}/`;
if (cid !== "rules" && cid !== "description") {
shareLink += `c/${cid}`;
}
if (cid !== "rules" && cid !== "description") {
shareLink += `c/${cid}`;
shareLink += `?redirect=plebchan.eth.limo`;
}
shareLink += `?redirect=plebchan.eth.limo`;
if (navigator.clipboard) {
navigator.clipboard.writeText(shareLink).then(() => {
console.log("Link copied to clipboard!");