mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
add mobile post menu
This commit is contained in:
@@ -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();
|
||||
@@ -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>
|
||||
@@ -1756,7 +1784,96 @@ 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))) ? (
|
||||
<>
|
||||
<li onClick={() => handleMobileOptionClick(thread.cid)}>
|
||||
<a style={{color: 'inherit', textDecoration: 'none'}}
|
||||
href={`https://lens.google.com/uploadbyurl?url=${commentMediaInfo.url}`}
|
||||
target="_blank" rel="noreferrer"
|
||||
>Search image on Google</a>
|
||||
</li>
|
||||
<li onClick={() => handleMobileOptionClick(thread.cid)}>
|
||||
<a style={{color: 'inherit', textDecoration: 'none'}}
|
||||
href={`https://yandex.com/images/search?url=${commentMediaInfo.url}`}
|
||||
target="_blank" rel="noreferrer"
|
||||
>Search image on Yandex</a>
|
||||
</li>
|
||||
<li onClick={() => handleMobileOptionClick(thread.cid)}>
|
||||
<a style={{color: 'inherit', textDecoration: 'none'}}
|
||||
href={`https://saucenao.com/search.php?url=${commentMediaInfo.url}`}
|
||||
target="_blank" rel="noreferrer"
|
||||
>Search image on SauceNAO</a>
|
||||
</li>
|
||||
</>
|
||||
) : null
|
||||
}
|
||||
</ul>
|
||||
</PostMenuMobile>, document.body
|
||||
)}
|
||||
<span key={`mob-nbm-${index}`} className="name-block-mobile">
|
||||
{thread.author.displayName
|
||||
? thread.author.displayName.length > 20
|
||||
@@ -1993,7 +2110,96 @@ 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 thread</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))) ? (
|
||||
<>
|
||||
<li onClick={() => handleMobileOptionClick(reply.cid)}>
|
||||
<a style={{color: 'inherit', textDecoration: 'none'}}
|
||||
href={`https://lens.google.com/uploadbyurl?url=${replyMediaInfo.url}`}
|
||||
target="_blank" rel="noreferrer"
|
||||
>Search image on Google</a>
|
||||
</li>
|
||||
<li onClick={() => handleMobileOptionClick(reply.cid)}>
|
||||
<a style={{color: 'inherit', textDecoration: 'none'}}
|
||||
href={`https://yandex.com/images/search?img_url=${replyMediaInfo.url}&rpt=imageview`}
|
||||
target="_blank" rel="noreferrer"
|
||||
>Search image on Yandex</a>
|
||||
</li>
|
||||
<li onClick={() => handleMobileOptionClick(reply.cid)}>
|
||||
<a style={{color: 'inherit', textDecoration: 'none'}}
|
||||
href={`https://saucenao.com/search.php?url=${replyMediaInfo.url}`}
|
||||
target="_blank" rel="noreferrer"
|
||||
>Search image on SauceNAO</a>
|
||||
</li>
|
||||
</>
|
||||
) : null
|
||||
}
|
||||
</ul>
|
||||
</PostMenuMobile>, document.body
|
||||
)}
|
||||
<span key={`mob-nb-${index}`} className="name-block-mobile">
|
||||
{reply.author.displayName
|
||||
? reply.author.displayName.length > 20
|
||||
|
||||
Reference in New Issue
Block a user