diff --git a/public/apple-touch-icon.png b/public/apple-touch-icon.png
index 1aeb7743..dcb70b99 100644
Binary files a/public/apple-touch-icon.png and b/public/apple-touch-icon.png differ
diff --git a/public/assets/logo/apple-touch-icon.png b/public/assets/logo/apple-touch-icon.png
index 1aeb7743..dcb70b99 100644
Binary files a/public/assets/logo/apple-touch-icon.png and b/public/assets/logo/apple-touch-icon.png differ
diff --git a/public/assets/logo/favicon-16x16.png b/public/assets/logo/favicon-16x16.png
index 7ab5a989..00310534 100644
Binary files a/public/assets/logo/favicon-16x16.png and b/public/assets/logo/favicon-16x16.png differ
diff --git a/public/assets/logo/favicon-32x32.png b/public/assets/logo/favicon-32x32.png
index 7ab5a989..00310534 100644
Binary files a/public/assets/logo/favicon-32x32.png and b/public/assets/logo/favicon-32x32.png differ
diff --git a/public/assets/logo/favicon.ico b/public/assets/logo/favicon.ico
index 7ab5a989..5cccad7a 100644
Binary files a/public/assets/logo/favicon.ico and b/public/assets/logo/favicon.ico differ
diff --git a/public/assets/logo/logo-transparent.png b/public/assets/logo/logo-transparent.png
index 3a174855..7965b497 100644
Binary files a/public/assets/logo/logo-transparent.png and b/public/assets/logo/logo-transparent.png differ
diff --git a/public/electron-tray-icon.png b/public/electron-tray-icon.png
index 1aeb7743..dcb70b99 100644
Binary files a/public/electron-tray-icon.png and b/public/electron-tray-icon.png differ
diff --git a/public/favicon.ico b/public/favicon.ico
index 7ab5a989..5cccad7a 100644
Binary files a/public/favicon.ico and b/public/favicon.ico differ
diff --git a/public/icon.png b/public/icon.png
index 6e018400..2198013a 100644
Binary files a/public/icon.png and b/public/icon.png differ
diff --git a/public/manifest-icon-192x192.png b/public/manifest-icon-192x192.png
index 7b0fc39c..b016bc12 100644
Binary files a/public/manifest-icon-192x192.png and b/public/manifest-icon-192x192.png differ
diff --git a/public/manifest-icon-512x512.png b/public/manifest-icon-512x512.png
index 6e018400..2198013a 100644
Binary files a/public/manifest-icon-512x512.png and b/public/manifest-icon-512x512.png differ
diff --git a/src/components/modals/SettingsModal.jsx b/src/components/modals/SettingsModal.jsx
index 9b09d7e0..8e001156 100755
--- a/src/components/modals/SettingsModal.jsx
+++ b/src/components/modals/SettingsModal.jsx
@@ -145,7 +145,7 @@ const SettingsModal = ({ isOpen, closeModal }) => {
clearTimeout(checkedENSTimeoutId);
};
}, [copyStatus, checkedENS]);
-
+
const handleSavePlebbitOptions = async () => {
let gatewayUrls = gatewayRef.current.value.split('\n').filter((url) => url.trim());
@@ -165,9 +165,9 @@ const SettingsModal = ({ isOpen, closeModal }) => {
}
const invalidUrls = [
- ...gatewayUrls || defaultGatewayUrls,
- ...(ipfsClientsOptions || []),
- ...pubsubClientsOptions || defaultPubsubHttpClientsOptions,
+ ...(Array.isArray(gatewayUrls) ? gatewayUrls : (Array.isArray(defaultGatewayUrls) ? defaultGatewayUrls : [])),
+ ...(Array.isArray(ipfsClientsOptions) ? ipfsClientsOptions : []),
+ ...(Array.isArray(pubsubClientsOptions) ? pubsubClientsOptions : (Array.isArray(defaultPubsubHttpClientsOptions) ? defaultPubsubHttpClientsOptions : [])),
].filter((url) => !isValidURL(url));
if (invalidUrls.length > 0) {
@@ -244,9 +244,9 @@ const SettingsModal = ({ isOpen, closeModal }) => {
setNewErrorMessage(null);
setNewSuccessMessage(null);
- gatewayRef.current.value = defaultGatewayUrls.join('\n');
+ gatewayRef.current.value = defaultGatewayUrls ? defaultGatewayUrls.join('\n') : "";
ipfsRef.current.value = "";
- pubsubRef.current.value = defaultPubsubHttpClientsOptions.join('\n');
+ pubsubRef.current.value = defaultPubsubHttpClientsOptions ? defaultPubsubHttpClientsOptions.join('\n') : "";
dataPathRef.current.value = "";
try {
diff --git a/src/components/views/All.jsx b/src/components/views/All.jsx
index e9fc510b..47072883 100755
--- a/src/components/views/All.jsx
+++ b/src/components/views/All.jsx
@@ -97,6 +97,7 @@ const All = () => {
const [prevScrollPos, setPrevScrollPos] = useState(0);
const [visible, setVisible] = useState(true);
const [isImageSearchOpen, setIsImageSearchOpen] = useState(false);
+ const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false);
const [commentCid, setCommentCid] = useState(null);
const [menuPosition, setMenuPosition] = useState({top: 0, left: 0});
const [triggerPublishCommentEdit, setTriggerPublishCommentEdit] = useState(false);
@@ -991,6 +992,32 @@ const All = () => {
) : null
}
+
{setIsClientRedirectMenuOpen(true)}}
+ onMouseLeave={() => {setIsClientRedirectMenuOpen(false)}}>
+ View on »
+
+ - handleOptionClick(thread.cid)}>
+ Plebbit
+
+ {/* - handleOptionClick(thread.cid)}>
+ Seedit
+
*/}
+ - handleOptionClick(thread.cid)}>
+ Plebones
+
+
+
, document.body
@@ -1294,6 +1321,32 @@ const All = () => {
) : null
}
+ {setIsClientRedirectMenuOpen(true)}}
+ onMouseLeave={() => {setIsClientRedirectMenuOpen(false)}}>
+ View on »
+
+ - handleOptionClick(reply.cid)}>
+ Plebbit
+
+ {/* - handleOptionClick(reply.cid)}>
+ Seedit
+
*/}
+ - handleOptionClick(reply.cid)}>
+ Plebones
+
+
+
, document.body
diff --git a/src/components/views/AllCatalog.jsx b/src/components/views/AllCatalog.jsx
index e47ef8c9..8cace4a8 100755
--- a/src/components/views/AllCatalog.jsx
+++ b/src/components/views/AllCatalog.jsx
@@ -1,11 +1,11 @@
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import { Helmet } from 'react-helmet-async';
-import { Link, useNavigate } from 'react-router-dom';
+import { Link, useNavigate} from 'react-router-dom';
import { confirmAlert } from 'react-confirm-alert';
import { Tooltip } from 'react-tooltip';
import { Virtuoso } from 'react-virtuoso';
-import { useAccount, useFeed, usePublishCommentEdit, useSubplebbits } from '@plebbit/plebbit-react-hooks';
+import { useAccount, useFeed, usePublishCommentEdit, useSubplebbit, useSubplebbits } from '@plebbit/plebbit-react-hooks';
import { debounce } from 'lodash';
import { Container, NavBar, Header, Break, PostMenu, BoardForm } from '../styled/views/Board.styled';
import { Threads, PostMenuCatalog } from '../styled/views/Catalog.styled';
@@ -28,110 +28,139 @@ import useSuccess from '../../hooks/useSuccess';
import useWindowWidth from '../../hooks/useWindowWidth';
import useGeneralStore from '../../hooks/stores/useGeneralStore';
import packageJson from '../../../package.json'
-const { version } = packageJson
+const {version} = packageJson
let lastVirtuosoStates = {}
-const AllCatalog = () => {
+const CatalogPost = ({post}) => {
const {
- setCaptchaResponse,
- setChallengesArray,
- defaultSubplebbits,
editedComment,
+ setDeletePost,
setIsAuthorDelete,
+ captchaResponse, setCaptchaResponse,
+ setIsModerationOpen,
+ setChallengesArray,
setIsAuthorEdit,
setIsCaptchaOpen,
- isModerationOpen, setIsModerationOpen,
- isSettingsOpen, setIsSettingsOpen,
+ setIsEditModalOpen,
setModeratingCommentCid,
+ setOriginalCommentContent,
+ setPendingComment,
setResolveCaptchaPromise,
selectedAddress, setSelectedAddress,
selectedStyle,
setSelectedThread,
- setSelectedTitle,
} = useGeneralStore(state => state);
+ const thread = post;
+ const commentMediaInfo = getCommentMediaInfo(thread);
+ const linkCount = countLinks(thread);
+ const fallbackImgUrl = "assets/filedeleted-res.gif";
+ const [isHoveringOnThread, setIsHoveringOnThread] = useState(false);
+ const [menuPosition, setMenuPosition] = useState({top: 0, left: 0});
+ const [openMenuCid, setOpenMenuCid] = useState(null);
+ const [triggerPublishCommentEdit, setTriggerPublishCommentEdit] = useState(false);
+ const [isImageSearchOpen, setIsImageSearchOpen] = useState(false);
+ const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false);
+ const [commentCid, setCommentCid] = useState(null);
+ const [isModerator, setIsModerator] = useState(false);
- const threadMenuRefs = useRef({});
- const postMenuRef = useRef(null);
- const postMenuCatalogRef = useRef(null);
- const virtuosoRef = useRef();
-
- const account = useAccount();
- const navigate = useNavigate();
const [, setNewErrorMessage] = useError();
const [, setNewSuccessMessage] = useSuccess();
- const [prevScrollPos, setPrevScrollPos] = useState(0);
- const [visible, setVisible] = useState(true);
-
- const [isEditModalOpen, setIsEditModalOpen] = useState(false);
- const [originalCommentContent, setOriginalCommentContent] = useState(null);
- const [triggerPublishCommentEdit, setTriggerPublishCommentEdit] = useState(false);
- const [deletePost, setDeletePost] = useState(false);
- const [isImageSearchOpen, setIsImageSearchOpen] = useState(false);
- const [commentCid, setCommentCid] = useState(null);
- const [moderatorPermissions, setModeratorPermissions] = useState({});
- const [isCreateBoardOpen, setIsCreateBoardOpen] = useState(false);
-
- const addresses = defaultSubplebbits.map(subplebbit => subplebbit.address);
- const { feed, hasMore, loadMore } = useFeed({ subplebbitAddresses: addresses, sortType: 'active' });
- const { subplebbits } = useSubplebbits({ subplebbitAddresses: addresses, sortType: 'active' });
- const [selectedFeed, setSelectedFeed] = useState(feed.sort((a, b) => b.timestamp - a.timestamp));
-
- const stateString = useFeedStateString(subplebbits);
-
- const columnWidth = 180;
- const windowWidth = useWindowWidth();
- const columnCount = Math.floor(windowWidth / columnWidth);
- const rows = useFeedRows(selectedFeed, columnCount);
+ const account = useAccount();
+ const subplebbit = useSubplebbit({subplebbitAddress: thread.subplebbitAddress});
+ const threadMenuRefs = useRef({});
+ const postMenuRef = useRef(null);
+ const postMenuCatalogRef = useRef(null);
useEffect(() => {
- let permissions = {};
+ if (subplebbit.roles !== undefined) {
+ const role = subplebbit.roles[account?.author.address]?.role;
+
+ if (role === 'moderator' || role === 'admin' || role === 'owner') {
+ setIsModerator(true);
+ } else {
+ setIsModerator(false);
+ }
+ }
+ }, [account?.author.address, subplebbit.roles]);
- selectedFeed.forEach(thread => {
- const subplebbit = subplebbits.find(s => s && s.address === thread.subplebbitAddress);
- if (subplebbit && subplebbit.roles) {
- const role = subplebbit.roles[account?.author.address]?.role;
+ const handleOutsideClick = useCallback((e) => {
+ if (openMenuCid !== null && !postMenuRef.current.contains(e.target) && !postMenuCatalogRef.current.contains(e.target)) {
+ setOpenMenuCid(null);
+ }
+ }, [openMenuCid]);
- if (role === 'moderator' || role === 'admin' || role === 'owner') {
- permissions[thread.subplebbitAddress] = true;
- } else {
- permissions[thread.subplebbitAddress] = false;
- }
+ const handleOptionClick = () => {
+ setOpenMenuCid(null);
+ };
+
+ useEffect(() => {
+ if (openMenuCid !== null) {
+ document.addEventListener('click', handleOutsideClick);
+ } else {
+ document.removeEventListener('click', handleOutsideClick);
+ }
+
+ return () => {
+ document.removeEventListener('click', handleOutsideClick);
+ };
+ }, [openMenuCid, handleOutsideClick]);
+
+ const handleAuthorDeleteClick = (comment) => {
+ handleOptionClick(comment.cid);
+
+ confirmAlert({
+ customUI: ({ onClose }) => {
+ return (
+
+
+
Are you sure you want to delete this post?
+
+
+
+
+
+
+ );
}
});
-
- setModeratorPermissions(permissions);
- }, [account?.author.address, selectedFeed, subplebbits]);
-
-
- // mobile navbar scroll effect
- useEffect(() => {
- const debouncedHandleScroll = debounce(() => {
- const currentScrollPos = window.pageYOffset;
- setVisible(prevScrollPos > currentScrollPos || currentScrollPos < 10);
- setPrevScrollPos(currentScrollPos);
- }, 50);
-
- window.addEventListener('scroll', debouncedHandleScroll);
-
- return () => window.removeEventListener('scroll', debouncedHandleScroll);
- }, [prevScrollPos, visible]);
-
-
- const tryLoadMore = async () => {
- try { loadMore() }
- catch (e) { await new Promise(resolve => setTimeout(resolve, 1000)) }
};
+ const handleAuthorEditClick = (comment) => {
+ handleOptionClick(comment.cid);
+ setIsAuthorEdit(true);
+ setIsAuthorDelete(false);
+ setCommentCid(comment.cid);
+ setOriginalCommentContent(comment.content);
+ setIsEditModalOpen(true);
+ }
+
+
+
const onChallengeVerification = (challengeVerification) => {
if (challengeVerification.challengeSuccess === true) {
- setNewSuccessMessage('Challenge Success');
- }
+ setNewSuccessMessage('Challenge Success');
+ }
else if (challengeVerification.challengeSuccess === false) {
setNewErrorMessage(`Challenge Failed, reason: ${challengeVerification.reason}. Errors: ${challengeVerification.errors}`);
console.log('challenge failed', challengeVerification);
@@ -140,6 +169,7 @@ const AllCatalog = () => {
const onChallenge = async (challenges, comment) => {
+ setPendingComment(comment);
let challengeAnswers = [];
try {
challengeAnswers = await getChallengeAnswersFromUser(challenges)
@@ -155,19 +185,19 @@ const AllCatalog = () => {
const getChallengeAnswersFromUser = async (challenges) => {
setChallengesArray(challenges);
-
+
return new Promise((resolve, reject) => {
const imageString = challenges?.challenges[0].challenge;
const imageSource = `data:image/png;base64,${imageString}`;
const challengeImg = new Image();
challengeImg.src = imageSource;
-
+
challengeImg.onload = () => {
setIsCaptchaOpen(true);
-
+
const handleKeyDown = async (event) => {
if (event.key === 'Enter') {
- const currentCaptchaResponse = useGeneralStore.getState().captchaResponse;
+ const currentCaptchaResponse = captchaResponse;
resolve(currentCaptchaResponse);
setIsCaptchaOpen(false);
document.removeEventListener('keydown', handleKeyDown);
@@ -180,7 +210,7 @@ const AllCatalog = () => {
setResolveCaptchaPromise(resolve);
};
-
+
challengeImg.onerror = () => {
reject(setNewErrorMessage('Could not load challenges'));
};
@@ -197,8 +227,8 @@ const AllCatalog = () => {
setNewErrorMessage(error.message); console.log(error);
},
});
-
-
+
+
const { publishCommentEdit } = usePublishCommentEdit(publishCommentEditOptions);
@@ -217,7 +247,7 @@ const AllCatalog = () => {
}
}, [editedComment, setIsAuthorEdit]);
-
+
useEffect(() => {
let isActive = true;
if (publishCommentEditOptions && triggerPublishCommentEdit) {
@@ -235,6 +265,276 @@ const AllCatalog = () => {
}, [triggerPublishCommentEdit, publishCommentEdit, publishCommentEditOptions]);
+ return (
+ {setIsHoveringOnThread(thread.cid)}}
+ onMouseLeave={() => {setIsHoveringOnThread('')}}>
+ {commentMediaInfo?.url ? (
+
setSelectedThread(thread.cid)}>
+ {commentMediaInfo?.type === "webpage" ? (
+ thread.thumbnailUrl ? (
+

{
+ e.target.src = fallbackImgUrl
+ e.target.onerror = null;
+ }} />
+ ) : null
+ ) : null}
+ {commentMediaInfo?.type === "image" ? (
+

{
+ e.target.src = fallbackImgUrl
+ e.target.onerror = null;}} />
+ ) : null}
+ {commentMediaInfo?.type === "video" ? (
+
+ );
+};
+
+
+const CatalogRow = ({row}) => {
+ const posts = []
+ for (const post of row) {
+ posts.push()
+ }
+ return {posts}
+}
+
+
+const AllCatalog = () => {
+ const {
+ defaultSubplebbits,
+ isModerationOpen, setIsModerationOpen,
+ isSettingsOpen, setIsSettingsOpen,
+ originalCommentContent,
+ selectedAddress, setSelectedAddress,
+ selectedStyle,
+ setSelectedTitle,
+ } = useGeneralStore(state => state);
+
+ const virtuosoRef = useRef();
+
+ const navigate = useNavigate();
+
+ const [prevScrollPos, setPrevScrollPos] = useState(0);
+ const [visible, setVisible] = useState(true);
+
+ const [isEditModalOpen, setIsEditModalOpen] = useState(false);
+ const [deletePost, setDeletePost] = useState(false);
+ const [isCreateBoardOpen, setIsCreateBoardOpen] = useState(false);
+
+ const addresses = defaultSubplebbits.map(subplebbit => subplebbit.address);
+ const { feed, hasMore, loadMore } = useFeed({subplebbitAddresses: addresses, sortType: 'active'});
+ const {subplebbits} = useSubplebbits({subplebbitAddresses: addresses, sortType: 'active'});
+ const [selectedFeed, setSelectedFeed] = useState(feed.sort((a, b) => b.timestamp - a.timestamp));
+
+ const stateString = useFeedStateString(subplebbits);
+
+ const columnWidth = 180;
+ const windowWidth = useWindowWidth();
+ const columnCount = Math.floor(windowWidth / columnWidth);
+ const rows = useFeedRows(selectedFeed, columnCount);
+
+ // mobile navbar scroll effect
+ useEffect(() => {
+ const debouncedHandleScroll = debounce(() => {
+ const currentScrollPos = window.pageYOffset;
+ setVisible(prevScrollPos > currentScrollPos || currentScrollPos < 10);
+ setPrevScrollPos(currentScrollPos);
+ }, 50);
+
+ window.addEventListener('scroll', debouncedHandleScroll);
+
+ return () => window.removeEventListener('scroll', debouncedHandleScroll);
+ }, [prevScrollPos, visible]);
+
// mobile navbar board select functionality
const handleSelectChange = (event) => {
const selected = event.target.value;
@@ -261,284 +561,6 @@ const AllCatalog = () => {
};
- const CatalogPost = ({ post }) => {
- const thread = post;
- const commentMediaInfo = getCommentMediaInfo(thread);
- const linkCount = countLinks(thread);
- const fallbackImgUrl = "assets/filedeleted-res.gif";
- const [isHoveringOnThread, setIsHoveringOnThread] = useState(false);
- const [menuPosition, setMenuPosition] = useState({ top: 0, left: 0 });
- const [openMenuCid, setOpenMenuCid] = useState(null);
- const isModerator = moderatorPermissions[thread.subplebbitAddress];
-
- const handleOutsideClick = useCallback((e) => {
- if (openMenuCid !== null && !postMenuRef.current.contains(e.target) && !postMenuCatalogRef.current.contains(e.target)) {
- setOpenMenuCid(null);
- }
- }, [openMenuCid]);
-
- const handleOptionClick = () => {
- setOpenMenuCid(null);
- };
-
- useEffect(() => {
- if (openMenuCid !== null) {
- document.addEventListener('click', handleOutsideClick);
- } else {
- document.removeEventListener('click', handleOutsideClick);
- }
-
- return () => {
- document.removeEventListener('click', handleOutsideClick);
- };
- }, [openMenuCid, handleOutsideClick]);
-
- const handleAuthorDeleteClick = (comment) => {
- handleOptionClick(comment.cid);
-
- confirmAlert({
- customUI: ({ onClose }) => {
- return (
-
-
-
Are you sure you want to delete this post?
-
-
-
-
-
-
- );
- }
- });
- };
-
-
- const handleAuthorEditClick = (comment) => {
- handleOptionClick(comment.cid);
- setIsAuthorEdit(true);
- setIsAuthorDelete(false);
- setCommentCid(comment.cid);
- setOriginalCommentContent(comment.content);
- setIsEditModalOpen(true);
- }
-
- return (
- { setIsHoveringOnThread(thread.cid) }}
- onMouseLeave={() => { setIsHoveringOnThread('') }}>
- {commentMediaInfo?.url ? (
-
setSelectedThread(thread.cid)}>
- {commentMediaInfo?.type === "webpage" ? (
- thread.thumbnailUrl ? (
-

{
- e.target.src = fallbackImgUrl
- e.target.onerror = null;
- }} />
- ) : null
- ) : null}
- {commentMediaInfo?.type === "image" ? (
-

{
- e.target.src = fallbackImgUrl
- e.target.onerror = null;
- }} />
- ) : null}
- {commentMediaInfo?.type === "video" ? (
-
- );
- };
-
-
- const CatalogRow = ({ row }) => {
- const posts = []
- for (const post of row) {
- posts.push()
- }
- return {posts}
- }
-
useEffect(() => {
const setLastVirtuosoState = () => {
virtuosoRef.current?.getState((snapshot) => {
@@ -551,7 +573,7 @@ const AllCatalog = () => {
return () => window.removeEventListener('scroll', setLastVirtuosoState);
}, [selectedAddress]);
-
+
const lastVirtuosoState = lastVirtuosoStates["allCatalog"];
@@ -559,60 +581,60 @@ const AllCatalog = () => {
return (
<>
- p/All - Catalog - plebchan
+ p/All - Catalog - plebchan
setIsCreateBoardOpen(false)} />
+ selectedStyle={selectedStyle}
+ isOpen={isCreateBoardOpen}
+ closeModal={() => setIsCreateBoardOpen(false)} />
setIsSettingsOpen(false)} />
- { setIsModerationOpen(false); setDeletePost(false) }}
- deletePost={deletePost} />
+ selectedStyle={selectedStyle}
+ isOpen={isSettingsOpen}
+ closeModal={() => setIsSettingsOpen(false)} />
+ {setIsModerationOpen(false); setDeletePost(false)}}
+ deletePost={deletePost} />
setIsEditModalOpen(false)}
- originalCommentContent={originalCommentContent} />
+ selectedStyle={selectedStyle}
+ isOpen={isEditModalOpen}
+ closeModal={() => setIsEditModalOpen(false)}
+ originalCommentContent={originalCommentContent} />
<>
-
- [
+
+ [
window.scrollTo(0, 0)}>All
- /
+ /
window.scrollTo(0, 0)}>Subscriptions
- ] [
- {defaultSubplebbits.map((subplebbit, index) => (
-
- {index === 0 ? null : "\u00a0"}
- {
- setSelectedTitle(subplebbit.title);
- setSelectedAddress(subplebbit.address);
- }}
- >{subplebbit.title ? subplebbit.title : subplebbit.address}
- {index !== defaultSubplebbits.length - 1 ? " /" : null}
-
- ))}
- ]
-
+ ] [
+ {defaultSubplebbits.map((subplebbit, index) => (
+
+ {index === 0 ? null : "\u00a0"}
+ {
+ setSelectedTitle(subplebbit.title);
+ setSelectedAddress(subplebbit.address);
+ }}
+ >{subplebbit.title ? subplebbit.title : subplebbit.address}
+ {index !== defaultSubplebbits.length - 1 ? " /" : null}
+
+ ))}
+ ]
+
[
- {
- window.electron && window.electron.isElectron ? (
- setIsCreateBoardOpen(true)
- ) : (
- alert(
- 'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n'
- )
+ {
+ window.electron && window.electron.isElectron ? (
+ setIsCreateBoardOpen(true)
+ ) : (
+ alert(
+ 'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n'
)
- }
+ )
+ }
}>Create Board
]
[
@@ -631,20 +653,20 @@ const AllCatalog = () => {
{defaultSubplebbits.map(subplebbit => (
-
- ))}
-
- alert(
- 'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n'
+
+ ))}
+
+ alert(
+ 'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n'
)
}>Create Board
setIsSettingsOpen(true)}>Settings
- { handleStyleChange({ target: { value: "Yotsuba" } }); window.scrollTo(0, 0); }}>Home
+ {handleStyleChange({target: {value: "Yotsuba"}}); window.scrollTo(0, 0);}}>Home
@@ -666,7 +688,7 @@ const AllCatalog = () => {
Style:
-
+
diff --git a/src/components/views/Board.jsx b/src/components/views/Board.jsx
index 23e7b945..749d37d8 100755
--- a/src/components/views/Board.jsx
+++ b/src/components/views/Board.jsx
@@ -125,6 +125,7 @@ const Board = () => {
const [selectedFeed, setSelectedFeed] = useState(feed);
const [deletePost, setDeletePost] = useState(false);
const [isImageSearchOpen, setIsImageSearchOpen] = useState(false);
+ const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false);
const [isModerator, setIsModerator] = useState(false);
const [commentCid, setCommentCid] = useState(null);
const [menuPosition, setMenuPosition] = useState({top: 0, left: 0});
@@ -1651,6 +1652,32 @@ const Board = () => {
) : null
}
+ {setIsClientRedirectMenuOpen(true)}}
+ onMouseLeave={() => {setIsClientRedirectMenuOpen(false)}}>
+ View on »
+
+ - handleOptionClick(thread.cid)}>
+ Plebbit
+
+ {/* - handleOptionClick(thread.cid)}>
+ Seedit
+
*/}
+ - handleOptionClick(thread.cid)}>
+ Plebones
+
+
+
, document.body
@@ -1948,6 +1975,32 @@ const Board = () => {
) : null
}
+ {setIsClientRedirectMenuOpen(true)}}
+ onMouseLeave={() => {setIsClientRedirectMenuOpen(false)}}>
+ View on »
+
+ - handleOptionClick(reply.cid)}>
+ Plebbit
+
+ {/* - handleOptionClick(reply.cid)}>
+ Seedit
+
*/}
+ - handleOptionClick(reply.cid)}>
+ Plebones
+
+
+
, document.body
diff --git a/src/components/views/Catalog.jsx b/src/components/views/Catalog.jsx
index 3c6dd1d6..79a21001 100755
--- a/src/components/views/Catalog.jsx
+++ b/src/components/views/Catalog.jsx
@@ -35,24 +35,671 @@ const {version} = packageJson
let lastVirtuosoStates = {}
+const CatalogPost = ({post}) => {
+ const {
+ editedComment,
+ setDeletePost,
+ setIsAuthorDelete,
+ captchaResponse, setCaptchaResponse,
+ selectedAddress,
+ setIsModerationOpen,
+ setChallengesArray,
+ setIsAuthorEdit,
+ setIsCaptchaOpen,
+ setIsEditModalOpen,
+ isModerator,
+ setModeratingCommentCid,
+ setOriginalCommentContent,
+ setPendingComment,
+ setResolveCaptchaPromise,
+ selectedStyle,
+ setSelectedThread,
+ } = useGeneralStore(state => state);
+
+ const thread = post;
+ const commentMediaInfo = getCommentMediaInfo(thread);
+ const linkCount = countLinks(thread);
+ const fallbackImgUrl = "assets/filedeleted-res.gif";
+ const [isHoveringOnThread, setIsHoveringOnThread] = useState(false);
+ const [menuPosition, setMenuPosition] = useState({top: 0, left: 0});
+ const [openMenuCid, setOpenMenuCid] = useState(null);
+ const [triggerPublishCommentEdit, setTriggerPublishCommentEdit] = useState(false);
+ const [isImageSearchOpen, setIsImageSearchOpen] = useState(false);
+ const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false);
+ const [commentCid, setCommentCid] = useState(null);
+
+ const threadMenuRefs = useRef({});
+ const postMenuRef = useRef(null);
+ const postMenuCatalogRef = useRef(null);
+ const { subplebbitAddress } = useParams();
+
+ const [, setNewErrorMessage] = useError();
+ const [, setNewSuccessMessage] = useSuccess();
+
+ const subplebbit = useSubplebbit({subplebbitAddress: selectedAddress});
+
+ const account = useAccount();
+
+
+ const handleOutsideClick = useCallback((e) => {
+ if (openMenuCid !== null && !postMenuRef.current.contains(e.target) && !postMenuCatalogRef.current.contains(e.target)) {
+ setOpenMenuCid(null);
+ }
+ }, [openMenuCid]);
+
+ const handleOptionClick = () => {
+ setOpenMenuCid(null);
+ };
+
+
+ useEffect(() => {
+ if (openMenuCid !== null) {
+ document.addEventListener('click', handleOutsideClick);
+ } else {
+ document.removeEventListener('click', handleOutsideClick);
+ }
+
+ return () => {
+ document.removeEventListener('click', handleOutsideClick);
+ };
+ }, [openMenuCid, handleOutsideClick]);
+
+
+ const handleAuthorDeleteClick = (comment) => {
+ handleOptionClick(comment.cid);
+
+ confirmAlert({
+ customUI: ({ onClose }) => {
+ return (
+
+
+
Are you sure you want to delete this post?
+
+
+
+
+
+
+ );
+ }
+ });
+ };
+
+
+ const handleAuthorEditClick = (comment) => {
+ handleOptionClick(comment.cid);
+ setIsAuthorEdit(true);
+ setIsAuthorDelete(false);
+ setCommentCid(comment.cid);
+ setOriginalCommentContent(comment.content);
+ setIsEditModalOpen(true);
+ }
+
+
+ const onChallengeVerification = (challengeVerification) => {
+ if (challengeVerification.challengeSuccess === true) {
+ setNewSuccessMessage('Challenge Success');
+ }
+ else if (challengeVerification.challengeSuccess === false) {
+ setNewErrorMessage(`Challenge Failed, reason: ${challengeVerification.reason}. Errors: ${challengeVerification.errors}`);
+ console.log('challenge failed', challengeVerification);
+ }
+ };
+
+
+ const onChallenge = async (challenges, comment) => {
+ setPendingComment(comment);
+ let challengeAnswers = [];
+
+ try {
+ challengeAnswers = await getChallengeAnswersFromUser(challenges)
+ }
+ catch (error) {
+ setNewErrorMessage(error.message); console.log(error);
+ }
+ if (challengeAnswers) {
+ await comment.publishChallengeAnswers(challengeAnswers)
+ }
+ };
+
+
+ const [publishCommentEditOptions, setPublishCommentEditOptions] = useState({
+ commentCid: commentCid,
+ content: editedComment || undefined,
+ subplebbitAddress: selectedAddress || subplebbitAddress,
+ onChallenge,
+ onChallengeVerification,
+ onError: (error) => {
+ setNewErrorMessage(error.message); console.log(error);
+ },
+ });
+
+
+ const { publishCommentEdit } = usePublishCommentEdit(publishCommentEditOptions);
+
+
+ useEffect(() => {
+ setPublishCommentEditOptions((prevOptions) => ({
+ ...prevOptions,
+ commentCid: commentCid,
+ content: editedComment || undefined,
+ }));
+ }, [commentCid, editedComment]);
+
+
+ useEffect(() => {
+ if (editedComment !== '') {
+ setTriggerPublishCommentEdit(true);
+ }
+ }, [editedComment]);
+
+
+ useEffect(() => {
+ if (publishCommentEditOptions && triggerPublishCommentEdit) {
+ (async () => {
+ await publishCommentEdit();
+ setTriggerPublishCommentEdit(false);
+ })();
+ }
+ }, [publishCommentEditOptions, triggerPublishCommentEdit, publishCommentEdit]);
+
+
+ const getChallengeAnswersFromUser = async (challenges) => {
+ setChallengesArray(challenges);
+
+ return new Promise((resolve, reject) => {
+ const imageString = challenges?.challenges[0].challenge;
+ const imageSource = `data:image/png;base64,${imageString}`;
+ const challengeImg = new Image();
+ challengeImg.src = imageSource;
+
+ challengeImg.onload = () => {
+ setIsCaptchaOpen(true);
+
+ const handleKeyDown = async (event) => {
+ if (event.key === 'Enter') {
+ const currentCaptchaResponse = captchaResponse;
+ resolve(currentCaptchaResponse);
+ setIsCaptchaOpen(false);
+ document.removeEventListener('keydown', handleKeyDown);
+ event.preventDefault();
+ }
+ };
+
+ setCaptchaResponse('');
+ document.addEventListener('keydown', handleKeyDown);
+
+ setResolveCaptchaPromise(resolve);
+ };
+
+ challengeImg.onerror = () => {
+ reject(setNewErrorMessage('Could not load challenges'));
+ };
+ });
+ };
+
+
+
+ if (post.type === 'rules') {
+ return (
+ setIsHoveringOnThread('rules')}
+ onMouseLeave={() => setIsHoveringOnThread('')}>
+
+
+ R:
0 / L:
0
+
+
+
+
+
{
+ threadMenuRefs.current["rules"] = el;
+ postMenuRef.current = el;
+ }}
+ className='post-menu-button'
+ id='post-menu-button-catalog'
+ rotated={openMenuCid === "rules"}
+ onClick={(event) => {
+ event.stopPropagation();
+ const rect = threadMenuRefs.current["rules"].getBoundingClientRect();
+ setMenuPosition({top: rect.top + window.scrollY, left: rect.left});
+ setOpenMenuCid(prevCid => (prevCid === "rules" ? null : "rules"));
+ }}
+ >
+ ▶
+
+
+ {createPortal(
+ {postMenuCatalogRef.current = el}}
+ onClick={(event) => event.stopPropagation()}
+ style={{position: "absolute",
+ top: menuPosition.top + 7,
+ left: menuPosition.left}}>
+
+
+ - handleOptionClick("rules")}>Hide thread
+ {/* {isModerator ? (
+ <>
+ change rules
+ >
+ ) : null} */}
+
+
+ , document.body
+ )}
+
+
+
+ Rules
+ {": " + subplebbit.rules?.map((rule, index) => `${index + 1}. ${rule}`).join(' ')}
+
+
+
+ )
+ } else if (post.type === 'description') {
+ return (
+ <>
+ setIsHoveringOnThread('description')}
+ onMouseLeave={() => setIsHoveringOnThread('')}>
+
+ {subplebbit.suggested?.avatarUrl ? (
+

+ ) : null}
+
+ {subplebbit.suggested?.avatarUrl ? (
+
+
+
+
+ ) : null}
+
+
+ R:
0 / L:
0
+ {subplebbit.suggested?.avatarUrl ? null : (
+
+
+
+
+ )}
+
{
+ threadMenuRefs.current["description"] = el;
+ postMenuRef.current = el;
+ }}
+ className='post-menu-button'
+ id='post-menu-button-catalog'
+ rotated={openMenuCid === "description"}
+ onClick={(event) => {
+ event.stopPropagation();
+ const rect = threadMenuRefs.current["description"].getBoundingClientRect();
+ setMenuPosition({top: rect.top + window.scrollY, left: rect.left});
+ setOpenMenuCid(prevCid => (prevCid === "description" ? null : "description"));
+ }}
+ >
+ ▶
+
+
+ {createPortal(
+ {postMenuCatalogRef.current = el}}
+ onClick={(event) => event.stopPropagation()}
+ style={{position: "absolute",
+ top: menuPosition.top + 7,
+ left: menuPosition.left}}>
+
+
+ - handleOptionClick("description")}>Hide thread
+ {/* {isModerator ? (
+ <>
+ change description
+ >
+ ) : null} */}
+ {subplebbit.suggested?.avatarUrl ? (
+ - {setIsImageSearchOpen(true)}}
+ onMouseLeave={() => {setIsImageSearchOpen(false)}}>
+ Image search »
+
+ - handleOptionClick("description")}>
+ Google
+
+ - handleOptionClick("description")}>
+ Yandex
+
+ - handleOptionClick("description")}>
+ SauceNAO
+
+
+
+ ) : null}
+
+
+ , document.body
+ )}
+
+
setSelectedThread("description")}>
+
+ Welcome to {subplebbit.title || subplebbit.address}
+ {": " + subplebbit.description}
+
+
+
+ >
+ )
+ } else {
+ return (
+ {setIsHoveringOnThread(thread.cid)}}
+ onMouseLeave={() => {setIsHoveringOnThread('')}}>
+ {commentMediaInfo?.url ? (
+
setSelectedThread(thread.cid)}>
+ {commentMediaInfo?.type === "webpage" ? (
+ thread.thumbnailUrl ? (
+

{
+ e.target.src = fallbackImgUrl
+ e.target.onerror = null;
+ }} />
+ ) : null
+ ) : null}
+ {commentMediaInfo?.type === "image" ? (
+

{
+ e.target.src = fallbackImgUrl
+ e.target.onerror = null;}} />
+ ) : null}
+ {commentMediaInfo?.type === "video" ? (
+
+ )
+ }
+};
+
+
+const CatalogRow = ({row}) => {
+ const posts = []
+ for (const post of row) {
+ posts.push()
+ }
+ return {posts}
+}
+
+
const Catalog = () => {
const {
captchaResponse, setCaptchaResponse,
setChallengesArray,
defaultSubplebbits,
- editedComment,
- setIsAuthorDelete,
- setIsAuthorEdit,
setIsCaptchaOpen,
isModerationOpen, setIsModerationOpen,
+ setIsModerator,
isSettingsOpen, setIsSettingsOpen,
- setModeratingCommentCid,
+ originalCommentContent,
setPendingComment,
setPendingCommentIndex,
setResolveCaptchaPromise,
selectedAddress, setSelectedAddress,
selectedStyle,
- setSelectedThread,
selectedTitle, setSelectedTitle,
showPostForm,
showPostFormLink,
@@ -64,9 +711,6 @@ const Catalog = () => {
const subjectRef = useRef();
const commentRef = useRef();
const linkRef = useRef();
- const threadMenuRefs = useRef({});
- const postMenuRef = useRef(null);
- const postMenuCatalogRef = useRef(null);
const selectedThreadCidRef = useRef(null);
const virtuosoRef = useRef();
@@ -78,13 +722,8 @@ const Catalog = () => {
const [triggerPublishComment, setTriggerPublishComment] = useState(false);
const [prevScrollPos, setPrevScrollPos] = useState(0);
const [visible, setVisible] = useState(true);
- const [isModerator, setIsModerator] = useState(false);
const [isEditModalOpen, setIsEditModalOpen] = useState(false);
- const [originalCommentContent, setOriginalCommentContent] = useState(null);
- const [triggerPublishCommentEdit, setTriggerPublishCommentEdit] = useState(false);
const [deletePost, setDeletePost] = useState(false);
- const [isImageSearchOpen, setIsImageSearchOpen] = useState(false);
- const [commentCid, setCommentCid] = useState(null);
const [executeAnonMode, setExecuteAnonMode] = useState(false);
const [isCreateBoardOpen, setIsCreateBoardOpen] = useState(false);
@@ -97,13 +736,15 @@ const Catalog = () => {
const stateString = useStateString(subplebbit);
let feedWithDescriptionAndRules = [...feed];
+
if (subplebbit.rules) {
feedWithDescriptionAndRules.unshift({ type: 'rules', content: subplebbit.rules });
}
-
+
if (subplebbit.description) {
feedWithDescriptionAndRules.unshift({ type: 'description', content: subplebbit.description });
}
+
const columnWidth = 180;
const windowWidth = useWindowWidth();
@@ -120,7 +761,7 @@ const Catalog = () => {
setIsModerator(false);
}
}
- }, [account?.author.address, subplebbit.roles]);
+ }, [account?.author.address, subplebbit.roles, setIsModerator]);
useEffect(() => {
@@ -232,7 +873,7 @@ const Catalog = () => {
useEffect(() => {
if (index !== undefined) {
setPendingCommentIndex(index);
- navigate(`/profile/c/`);
+ navigate(`/profile/c/${index}`);
}
}, [index, navigate, setPendingCommentIndex]);
@@ -368,46 +1009,6 @@ const Catalog = () => {
};
- const [publishCommentEditOptions, setPublishCommentEditOptions] = useState({
- commentCid: commentCid,
- content: editedComment || undefined,
- subplebbitAddress: selectedAddress || subplebbitAddress,
- onChallenge,
- onChallengeVerification,
- onError: (error) => {
- setNewErrorMessage(error.message); console.log(error);
- },
- });
-
-
- const { publishCommentEdit } = usePublishCommentEdit(publishCommentEditOptions);
-
-
- useEffect(() => {
- setPublishCommentEditOptions((prevOptions) => ({
- ...prevOptions,
- commentCid: commentCid,
- content: editedComment || undefined,
- }));
- }, [commentCid, editedComment]);
-
-
- useEffect(() => {
- if (editedComment !== '') {
- setTriggerPublishCommentEdit(true);
- }
- }, [editedComment]);
-
-
- useEffect(() => {
- if (publishCommentEditOptions && triggerPublishCommentEdit) {
- (async () => {
- await publishCommentEdit();
- setTriggerPublishCommentEdit(false);
- })();
- }
- }, [publishCommentEditOptions, triggerPublishCommentEdit, publishCommentEdit]);
-
// mobile navbar board select functionality
const handleSelectChange = (event) => {
const selected = event.target.value;
@@ -439,486 +1040,6 @@ const Catalog = () => {
};
- const CatalogPost = ({post}) => {
- const thread = post;
- const commentMediaInfo = getCommentMediaInfo(thread);
- const linkCount = countLinks(thread);
- const fallbackImgUrl = "assets/filedeleted-res.gif";
- const [isHoveringOnThread, setIsHoveringOnThread] = useState(false);
- const [menuPosition, setMenuPosition] = useState({top: 0, left: 0});
- const [openMenuCid, setOpenMenuCid] = useState(null);
-
- const handleOutsideClick = useCallback((e) => {
- if (openMenuCid !== null && !postMenuRef.current.contains(e.target) && !postMenuCatalogRef.current.contains(e.target)) {
- setOpenMenuCid(null);
- }
- }, [openMenuCid]);
-
- const handleOptionClick = () => {
- setOpenMenuCid(null);
- };
-
- useEffect(() => {
- if (openMenuCid !== null) {
- document.addEventListener('click', handleOutsideClick);
- } else {
- document.removeEventListener('click', handleOutsideClick);
- }
-
- return () => {
- document.removeEventListener('click', handleOutsideClick);
- };
- }, [openMenuCid, handleOutsideClick]);
-
- const handleAuthorDeleteClick = (comment) => {
- handleOptionClick(comment.cid);
-
- confirmAlert({
- customUI: ({ onClose }) => {
- return (
-
-
-
Are you sure you want to delete this post?
-
-
-
-
-
-
- );
- }
- });
- };
-
-
- const handleAuthorEditClick = (comment) => {
- handleOptionClick(comment.cid);
- setIsAuthorEdit(true);
- setIsAuthorDelete(false);
- setCommentCid(comment.cid);
- setOriginalCommentContent(comment.content);
- setIsEditModalOpen(true);
- }
-
-
- if (post.type === 'rules') {
- return (
- setIsHoveringOnThread('rules')}
- onMouseLeave={() => setIsHoveringOnThread('')}>
-
-
- R:
0 / L:
0
-
-
-
-
-
{
- threadMenuRefs.current["rules"] = el;
- postMenuRef.current = el;
- }}
- className='post-menu-button'
- id='post-menu-button-catalog'
- rotated={openMenuCid === "rules"}
- onClick={(event) => {
- event.stopPropagation();
- const rect = threadMenuRefs.current["rules"].getBoundingClientRect();
- setMenuPosition({top: rect.top + window.scrollY, left: rect.left});
- setOpenMenuCid(prevCid => (prevCid === "rules" ? null : "rules"));
- }}
- >
- ▶
-
-
- {createPortal(
- {postMenuCatalogRef.current = el}}
- onClick={(event) => event.stopPropagation()}
- style={{position: "absolute",
- top: menuPosition.top + 7,
- left: menuPosition.left}}>
-
-
- - handleOptionClick("rules")}>Hide thread
- {/* {isModerator ? (
- <>
- change rules
- >
- ) : null} */}
-
-
- , document.body
- )}
-
-
-
- Rules
- {": " + subplebbit.rules.map((rule, index) => `${index + 1}. ${rule}`).join(' ')}
-
-
-
- )
- } else if (post.type === 'description') {
- return (
- <>
- setIsHoveringOnThread('description')}
- onMouseLeave={() => setIsHoveringOnThread('')}>
-
- {subplebbit.suggested?.avatarUrl ? (
-

- ) : null}
-
- {subplebbit.suggested?.avatarUrl ? (
-
-
-
-
- ) : null}
-
-
- R:
0 / L:
0
- {subplebbit.suggested?.avatarUrl ? null : (
-
-
-
-
- )}
-
{
- threadMenuRefs.current["description"] = el;
- postMenuRef.current = el;
- }}
- className='post-menu-button'
- id='post-menu-button-catalog'
- rotated={openMenuCid === "description"}
- onClick={(event) => {
- event.stopPropagation();
- const rect = threadMenuRefs.current["description"].getBoundingClientRect();
- setMenuPosition({top: rect.top + window.scrollY, left: rect.left});
- setOpenMenuCid(prevCid => (prevCid === "description" ? null : "description"));
- }}
- >
- ▶
-
-
- {createPortal(
- {postMenuCatalogRef.current = el}}
- onClick={(event) => event.stopPropagation()}
- style={{position: "absolute",
- top: menuPosition.top + 7,
- left: menuPosition.left}}>
-
-
- - handleOptionClick("description")}>Hide thread
- {/* {isModerator ? (
- <>
- change description
- >
- ) : null} */}
- {subplebbit.suggested?.avatarUrl ? (
- - {setIsImageSearchOpen(true)}}
- onMouseLeave={() => {setIsImageSearchOpen(false)}}>
- Image search »
-
- - handleOptionClick("description")}>
- Google
-
- - handleOptionClick("description")}>
- Yandex
-
- - handleOptionClick("description")}>
- SauceNAO
-
-
-
- ) : null}
-
-
- , document.body
- )}
-
-
setSelectedThread("description")}>
-
- Welcome to {subplebbit.title || subplebbit.address}
- {": " + subplebbit.description}
-
-
-
- >
- )
- } else {
- return (
- {setIsHoveringOnThread(thread.cid)}}
- onMouseLeave={() => {setIsHoveringOnThread('')}}>
- {commentMediaInfo?.url ? (
-
setSelectedThread(thread.cid)}>
- {commentMediaInfo?.type === "webpage" ? (
- thread.thumbnailUrl ? (
-

{
- e.target.src = fallbackImgUrl
- e.target.onerror = null;
- }} />
- ) : null
- ) : null}
- {commentMediaInfo?.type === "image" ? (
-

{
- e.target.src = fallbackImgUrl
- e.target.onerror = null;}} />
- ) : null}
- {commentMediaInfo?.type === "video" ? (
-
- )
- }
- };
-
-
- const CatalogRow = ({row}) => {
- const posts = []
- for (const post of row) {
- posts.push()
- }
- return {posts}
- }
-
useEffect(() => {
const setLastVirtuosoState = () => {
virtuosoRef.current?.getState((snapshot) => {
diff --git a/src/components/views/NotFound.jsx b/src/components/views/NotFound.jsx
index 8cad9317..cbcc290a 100644
--- a/src/components/views/NotFound.jsx
+++ b/src/components/views/NotFound.jsx
@@ -1,6 +1,5 @@
-import React, { useEffect, useRef } from 'react';
+import React, { useEffect } from 'react';
import { Helmet } from 'react-helmet-async';
-import useGeneralStore from '../../hooks/stores/useGeneralStore';
import { Link } from "react-router-dom";
import { Container, Header, Logo, Page, Boards, BoardsTitle } from '../styled/views/Home.styled';
import packageJson from '../../../package.json'
@@ -8,31 +7,28 @@ const {version} = packageJson
const NotFound = () => {
- const {
- bodyStyle, setBodyStyle,
- selectedStyle, setSelectedStyle,
- } = useGeneralStore(state => state);
-
- const prevStyle = useRef(selectedStyle);
- const prevBodyStyle = useRef(bodyStyle);
-
- // prevent dark mode
useEffect(() => {
- const currentPrevStyle = prevStyle.current;
- const currentPrevBodyStyle = prevBodyStyle.current;
-
- setBodyStyle({
+ const yotsubaBodyStyle = {
background: "#ffe url(assets/fade.png) top repeat-x",
color: "maroon",
- fontFamily: "Helvetica, Arial, sans-serif"
- });
- setSelectedStyle("Yotsuba");
+ fontFamily: "Arial, Helvetica, sans-serif"
+ };
+ const originalBodyStyles = {
+ background: document.body.style.background,
+ color: document.body.style.color,
+ fontFamily: document.body.style.fontFamily
+ };
+
+ for (const [key, value] of Object.entries(yotsubaBodyStyle)) {
+ document.body.style[key] = value;
+ }
return () => {
- setSelectedStyle(currentPrevStyle);
- setBodyStyle(currentPrevBodyStyle);
+ for (const [key, value] of Object.entries(originalBodyStyles)) {
+ document.body.style[key] = value;
+ }
};
- }, [setBodyStyle, setSelectedStyle]);
+ }, []);
return (
<>
diff --git a/src/components/views/Subscriptions.jsx b/src/components/views/Subscriptions.jsx
index 7e380338..7ce31183 100755
--- a/src/components/views/Subscriptions.jsx
+++ b/src/components/views/Subscriptions.jsx
@@ -97,6 +97,7 @@ const Subscriptions = () => {
const [prevScrollPos, setPrevScrollPos] = useState(0);
const [visible, setVisible] = useState(true);
const [isImageSearchOpen, setIsImageSearchOpen] = useState(false);
+ const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false);
const [commentCid, setCommentCid] = useState(null);
const [menuPosition, setMenuPosition] = useState({top: 0, left: 0});
const [triggerPublishCommentEdit, setTriggerPublishCommentEdit] = useState(false);
@@ -1002,6 +1003,32 @@ const Subscriptions = () => {
) : null
}
+ {setIsClientRedirectMenuOpen(true)}}
+ onMouseLeave={() => {setIsClientRedirectMenuOpen(false)}}>
+ View on »
+
+ - handleOptionClick(thread.cid)}>
+ Plebbit
+
+ {/* - handleOptionClick(thread.cid)}>
+ Seedit
+
*/}
+ - handleOptionClick(thread.cid)}>
+ Plebones
+
+
+
, document.body
@@ -1305,6 +1332,32 @@ const Subscriptions = () => {
) : null
}
+ {setIsClientRedirectMenuOpen(true)}}
+ onMouseLeave={() => {setIsClientRedirectMenuOpen(false)}}>
+ View on »
+
+ - handleOptionClick(reply.cid)}>
+ Plebbit
+
+ {/* - handleOptionClick(reply.cid)}>
+ Seedit
+
*/}
+ - handleOptionClick(reply.cid)}>
+ Plebones
+
+
+
, document.body
diff --git a/src/components/views/SubscriptionsCatalog.jsx b/src/components/views/SubscriptionsCatalog.jsx
index 0ed1316a..ca8b70dc 100755
--- a/src/components/views/SubscriptionsCatalog.jsx
+++ b/src/components/views/SubscriptionsCatalog.jsx
@@ -1,11 +1,11 @@
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import { Helmet } from 'react-helmet-async';
-import { Link, useNavigate } from 'react-router-dom';
+import { Link, useNavigate} from 'react-router-dom';
import { confirmAlert } from 'react-confirm-alert';
import { Tooltip } from 'react-tooltip';
import { Virtuoso } from 'react-virtuoso';
-import { useAccount, useFeed, usePublishCommentEdit, useSubplebbits } from '@plebbit/plebbit-react-hooks';
+import { useAccount, useFeed, usePublishCommentEdit, useSubplebbit, useSubplebbits } from '@plebbit/plebbit-react-hooks';
import { debounce } from 'lodash';
import { Container, NavBar, Header, Break, PostMenu, BoardForm } from '../styled/views/Board.styled';
import { Threads, PostMenuCatalog } from '../styled/views/Catalog.styled';
@@ -28,102 +28,139 @@ import useGeneralStore from '../../hooks/stores/useGeneralStore';
import useSuccess from '../../hooks/useSuccess';
import useWindowWidth from '../../hooks/useWindowWidth';
import packageJson from '../../../package.json';
-const { version } = packageJson
+const {version} = packageJson
let lastVirtuosoStates = {}
-const SubscriptionsCatalog = () => {
+const CatalogPost = ({post}) => {
const {
- setCaptchaResponse,
- setChallengesArray,
- defaultSubplebbits,
editedComment,
+ setDeletePost,
setIsAuthorDelete,
+ captchaResponse, setCaptchaResponse,
+ setIsModerationOpen,
+ setChallengesArray,
setIsAuthorEdit,
setIsCaptchaOpen,
- isModerationOpen, setIsModerationOpen,
- isSettingsOpen, setIsSettingsOpen,
+ setIsEditModalOpen,
setModeratingCommentCid,
+ setOriginalCommentContent,
+ setPendingComment,
setResolveCaptchaPromise,
selectedAddress, setSelectedAddress,
selectedStyle,
setSelectedThread,
- setSelectedTitle,
} = useGeneralStore(state => state);
- const threadMenuRefs = useRef({});
- const postMenuRef = useRef(null);
- const postMenuCatalogRef = useRef(null);
- const virtuosoRef = useRef();
+ const thread = post;
+ const commentMediaInfo = getCommentMediaInfo(thread);
+ const linkCount = countLinks(thread);
+ const fallbackImgUrl = "assets/filedeleted-res.gif";
+ const [isHoveringOnThread, setIsHoveringOnThread] = useState(false);
+ const [menuPosition, setMenuPosition] = useState({top: 0, left: 0});
+ const [openMenuCid, setOpenMenuCid] = useState(null);
+ const [triggerPublishCommentEdit, setTriggerPublishCommentEdit] = useState(false);
+ const [isImageSearchOpen, setIsImageSearchOpen] = useState(false);
+ const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false);
+ const [commentCid, setCommentCid] = useState(null);
+ const [isModerator, setIsModerator] = useState(false);
- const account = useAccount();
- const navigate = useNavigate();
const [, setNewErrorMessage] = useError();
const [, setNewSuccessMessage] = useSuccess();
- const [prevScrollPos, setPrevScrollPos] = useState(0);
- const [visible, setVisible] = useState(true);
-
- const [isEditModalOpen, setIsEditModalOpen] = useState(false);
- const [originalCommentContent, setOriginalCommentContent] = useState(null);
- const [triggerPublishCommentEdit, setTriggerPublishCommentEdit] = useState(false);
- const [deletePost, setDeletePost] = useState(false);
- const [isImageSearchOpen, setIsImageSearchOpen] = useState(false);
- const [commentCid, setCommentCid] = useState(null);
- const [moderatorPermissions, setModeratorPermissions] = useState({});
- const [isCreateBoardOpen, setIsCreateBoardOpen] = useState(false);
-
- const { feed, hasMore, loadMore } = useFeed({ subplebbitAddresses: account?.subscriptions, sortType: 'active' });
- const [selectedFeed, setSelectedFeed] = useState(feed.sort((a, b) => b.timestamp - a.timestamp));
- const { subplebbits } = useSubplebbits({ subplebbitAddresses: account?.subscriptions, sortType: 'active' });
-
- const stateString = useFeedStateString(subplebbits);
-
- const columnWidth = 180;
- const windowWidth = useWindowWidth();
- const columnCount = Math.floor(windowWidth / columnWidth);
- const rows = useFeedRows(feed, columnCount);
+ const account = useAccount();
+ const subplebbit = useSubplebbit({subplebbitAddress: thread.subplebbitAddress});
+ const threadMenuRefs = useRef({});
+ const postMenuRef = useRef(null);
+ const postMenuCatalogRef = useRef(null);
useEffect(() => {
- let permissions = {};
+ if (subplebbit.roles !== undefined) {
+ const role = subplebbit.roles[account?.author.address]?.role;
+
+ if (role === 'moderator' || role === 'admin' || role === 'owner') {
+ setIsModerator(true);
+ } else {
+ setIsModerator(false);
+ }
+ }
+ }, [account?.author.address, subplebbit.roles]);
- selectedFeed.forEach(thread => {
- const subplebbit = subplebbits.find(s => s && s.address === thread.subplebbitAddress);
- if (subplebbit && subplebbit.roles) {
- const role = subplebbit.roles[account?.author.address]?.role;
+ const handleOutsideClick = useCallback((e) => {
+ if (openMenuCid !== null && !postMenuRef.current.contains(e.target) && !postMenuCatalogRef.current.contains(e.target)) {
+ setOpenMenuCid(null);
+ }
+ }, [openMenuCid]);
- if (role === 'moderator' || role === 'admin' || role === 'owner') {
- permissions[thread.subplebbitAddress] = true;
- } else {
- permissions[thread.subplebbitAddress] = false;
- }
+ const handleOptionClick = () => {
+ setOpenMenuCid(null);
+ };
+
+ useEffect(() => {
+ if (openMenuCid !== null) {
+ document.addEventListener('click', handleOutsideClick);
+ } else {
+ document.removeEventListener('click', handleOutsideClick);
+ }
+
+ return () => {
+ document.removeEventListener('click', handleOutsideClick);
+ };
+ }, [openMenuCid, handleOutsideClick]);
+
+ const handleAuthorDeleteClick = (comment) => {
+ handleOptionClick(comment.cid);
+
+ confirmAlert({
+ customUI: ({ onClose }) => {
+ return (
+
+
+
Are you sure you want to delete this post?
+
+
+
+
+
+
+ );
}
});
-
- setModeratorPermissions(permissions);
- }, [account?.author.address, selectedFeed, subplebbits]);
+ };
- // mobile navbar scroll effect
- useEffect(() => {
- const debouncedHandleScroll = debounce(() => {
- const currentScrollPos = window.pageYOffset;
- setVisible(prevScrollPos > currentScrollPos || currentScrollPos < 10);
- setPrevScrollPos(currentScrollPos);
- }, 50);
+ const handleAuthorEditClick = (comment) => {
+ handleOptionClick(comment.cid);
+ setIsAuthorEdit(true);
+ setIsAuthorDelete(false);
+ setCommentCid(comment.cid);
+ setOriginalCommentContent(comment.content);
+ setIsEditModalOpen(true);
+ }
- window.addEventListener('scroll', debouncedHandleScroll);
-
- return () => window.removeEventListener('scroll', debouncedHandleScroll);
- }, [prevScrollPos, visible]);
const onChallengeVerification = (challengeVerification) => {
if (challengeVerification.challengeSuccess === true) {
- setNewSuccessMessage('Challenge Success');
- }
+ setNewSuccessMessage('Challenge Success');
+ }
else if (challengeVerification.challengeSuccess === false) {
setNewErrorMessage(`Challenge Failed, reason: ${challengeVerification.reason}. Errors: ${challengeVerification.errors}`);
console.log('challenge failed', challengeVerification);
@@ -132,6 +169,7 @@ const SubscriptionsCatalog = () => {
const onChallenge = async (challenges, comment) => {
+ setPendingComment(comment);
let challengeAnswers = [];
try {
challengeAnswers = await getChallengeAnswersFromUser(challenges)
@@ -147,19 +185,19 @@ const SubscriptionsCatalog = () => {
const getChallengeAnswersFromUser = async (challenges) => {
setChallengesArray(challenges);
-
+
return new Promise((resolve, reject) => {
const imageString = challenges?.challenges[0].challenge;
const imageSource = `data:image/png;base64,${imageString}`;
const challengeImg = new Image();
challengeImg.src = imageSource;
-
+
challengeImg.onload = () => {
setIsCaptchaOpen(true);
-
+
const handleKeyDown = async (event) => {
if (event.key === 'Enter') {
- const currentCaptchaResponse = useGeneralStore.getState().captchaResponse;
+ const currentCaptchaResponse = captchaResponse;
resolve(currentCaptchaResponse);
setIsCaptchaOpen(false);
document.removeEventListener('keydown', handleKeyDown);
@@ -172,7 +210,7 @@ const SubscriptionsCatalog = () => {
setResolveCaptchaPromise(resolve);
};
-
+
challengeImg.onerror = () => {
reject(setNewErrorMessage('Could not load challenges'));
};
@@ -189,8 +227,8 @@ const SubscriptionsCatalog = () => {
setNewErrorMessage(error.message); console.log(error);
},
});
-
-
+
+
const { publishCommentEdit } = usePublishCommentEdit(publishCommentEditOptions);
@@ -209,7 +247,7 @@ const SubscriptionsCatalog = () => {
}
}, [editedComment, setIsAuthorEdit]);
-
+
useEffect(() => {
let isActive = true;
if (publishCommentEditOptions && triggerPublishCommentEdit) {
@@ -226,6 +264,279 @@ const SubscriptionsCatalog = () => {
};
}, [triggerPublishCommentEdit, publishCommentEdit, publishCommentEditOptions]);
+
+ return (
+ {setIsHoveringOnThread(thread.cid)}}
+ onMouseLeave={() => {setIsHoveringOnThread('')}}>
+ {commentMediaInfo?.url ? (
+
setSelectedThread(thread.cid)}>
+ {commentMediaInfo?.type === "webpage" ? (
+ thread.thumbnailUrl ? (
+

{
+ e.target.src = fallbackImgUrl
+ e.target.onerror = null;
+ }} />
+ ) : null
+ ) : null}
+ {commentMediaInfo?.type === "image" ? (
+

{
+ e.target.src = fallbackImgUrl
+ e.target.onerror = null;}} />
+ ) : null}
+ {commentMediaInfo?.type === "video" ? (
+
+ );
+};
+
+
+const CatalogRow = ({row}) => {
+ const posts = []
+ for (const post of row) {
+ posts.push()
+ }
+ return {posts}
+}
+
+
+const SubscriptionsCatalog = () => {
+ const {
+ defaultSubplebbits,
+ isModerationOpen, setIsModerationOpen,
+ isSettingsOpen, setIsSettingsOpen,
+ originalCommentContent,
+ selectedAddress, setSelectedAddress,
+ selectedStyle,
+ setSelectedTitle,
+ } = useGeneralStore(state => state);
+
+ const virtuosoRef = useRef();
+
+ const account = useAccount();
+ const navigate = useNavigate();
+
+ const [prevScrollPos, setPrevScrollPos] = useState(0);
+ const [visible, setVisible] = useState(true);
+
+ const [isEditModalOpen, setIsEditModalOpen] = useState(false);
+ const [deletePost, setDeletePost] = useState(false);
+ const [isCreateBoardOpen, setIsCreateBoardOpen] = useState(false);
+
+ const { feed, hasMore, loadMore } = useFeed({subplebbitAddresses: account?.subscriptions, sortType: 'active'});
+ const [selectedFeed, setSelectedFeed] = useState(feed.sort((a, b) => b.timestamp - a.timestamp));
+ const {subplebbits} = useSubplebbits({subplebbitAddresses: account?.subscriptions, sortType: 'active'});
+
+ const stateString = useFeedStateString(subplebbits);
+
+ const columnWidth = 180;
+ const windowWidth = useWindowWidth();
+ const columnCount = Math.floor(windowWidth / columnWidth);
+ const rows = useFeedRows(selectedFeed, columnCount);
+
+
+ // mobile navbar scroll effect
+ useEffect(() => {
+ const debouncedHandleScroll = debounce(() => {
+ const currentScrollPos = window.pageYOffset;
+ setVisible(prevScrollPos > currentScrollPos || currentScrollPos < 10);
+ setPrevScrollPos(currentScrollPos);
+ }, 50);
+
+ window.addEventListener('scroll', debouncedHandleScroll);
+
+ return () => window.removeEventListener('scroll', debouncedHandleScroll);
+ }, [prevScrollPos, visible]);
+
+
// desktop navbar board select functionality
const handleClickTitle = (title, address) => {
setSelectedTitle(title);
@@ -252,284 +563,6 @@ const SubscriptionsCatalog = () => {
};
- const CatalogPost = ({ post }) => {
- const thread = post;
- const commentMediaInfo = getCommentMediaInfo(thread);
- const linkCount = countLinks(thread);
- const fallbackImgUrl = "assets/filedeleted-res.gif";
- const [isHoveringOnThread, setIsHoveringOnThread] = useState(false);
- const [menuPosition, setMenuPosition] = useState({ top: 0, left: 0 });
- const [openMenuCid, setOpenMenuCid] = useState(null);
- const isModerator = moderatorPermissions[thread.subplebbitAddress];
-
- const handleOutsideClick = useCallback((e) => {
- if (openMenuCid !== null && !postMenuRef.current.contains(e.target) && !postMenuCatalogRef.current.contains(e.target)) {
- setOpenMenuCid(null);
- }
- }, [openMenuCid]);
-
- const handleOptionClick = () => {
- setOpenMenuCid(null);
- };
-
- useEffect(() => {
- if (openMenuCid !== null) {
- document.addEventListener('click', handleOutsideClick);
- } else {
- document.removeEventListener('click', handleOutsideClick);
- }
-
- return () => {
- document.removeEventListener('click', handleOutsideClick);
- };
- }, [openMenuCid, handleOutsideClick]);
-
- const handleAuthorDeleteClick = (comment) => {
- handleOptionClick(comment.cid);
-
- confirmAlert({
- customUI: ({ onClose }) => {
- return (
-
-
-
Are you sure you want to delete this post?
-
-
-
-
-
-
- );
- }
- });
- };
-
-
- const handleAuthorEditClick = (comment) => {
- handleOptionClick(comment.cid);
- setIsAuthorEdit(true);
- setIsAuthorDelete(false);
- setCommentCid(comment.cid);
- setOriginalCommentContent(comment.content);
- setIsEditModalOpen(true);
- }
-
- return (
- { setIsHoveringOnThread(thread.cid) }}
- onMouseLeave={() => { setIsHoveringOnThread('') }}>
- {commentMediaInfo?.url ? (
-
setSelectedThread(thread.cid)}>
- {commentMediaInfo?.type === "webpage" ? (
- thread.thumbnailUrl ? (
-

{
- e.target.src = fallbackImgUrl
- e.target.onerror = null;
- }} />
- ) : null
- ) : null}
- {commentMediaInfo?.type === "image" ? (
-

{
- e.target.src = fallbackImgUrl
- e.target.onerror = null;
- }} />
- ) : null}
- {commentMediaInfo?.type === "video" ? (
-
- );
- };
-
-
- const CatalogRow = ({ row }) => {
- const posts = []
- for (const post of row) {
- posts.push()
- }
- return {posts}
- }
-
useEffect(() => {
const setLastVirtuosoState = () => {
virtuosoRef.current?.getState((snapshot) => {
@@ -542,7 +575,7 @@ const SubscriptionsCatalog = () => {
return () => window.removeEventListener('scroll', setLastVirtuosoState);
}, [selectedAddress]);
-
+
const lastVirtuosoState = lastVirtuosoStates["subscriptionsCatalog"];
@@ -550,60 +583,60 @@ const SubscriptionsCatalog = () => {
return (
<>
- Subscriptions - Catalog - plebchan
+ Subscriptions - Catalog - plebchan
setIsCreateBoardOpen(false)} />
+ selectedStyle={selectedStyle}
+ isOpen={isCreateBoardOpen}
+ closeModal={() => setIsCreateBoardOpen(false)} />
setIsSettingsOpen(false)} />
- { setIsModerationOpen(false); setDeletePost(false) }}
- deletePost={deletePost} />
+ selectedStyle={selectedStyle}
+ isOpen={isSettingsOpen}
+ closeModal={() => setIsSettingsOpen(false)} />
+ {setIsModerationOpen(false); setDeletePost(false)}}
+ deletePost={deletePost} />
setIsEditModalOpen(false)}
- originalCommentContent={originalCommentContent} />
+ selectedStyle={selectedStyle}
+ isOpen={isEditModalOpen}
+ closeModal={() => setIsEditModalOpen(false)}
+ originalCommentContent={originalCommentContent} />
<>
-
- [
+
+ [
window.scrollTo(0, 0)}>All
- /
+ /
window.scrollTo(0, 0)}>Subscriptions
- ] [
- {defaultSubplebbits.map((subplebbit, index) => (
-
- {index === 0 ? null : "\u00a0"}
- {
- setSelectedTitle(subplebbit.title);
- setSelectedAddress(subplebbit.address);
- }}
- >{subplebbit.title ? subplebbit.title : subplebbit.address}
- {index !== defaultSubplebbits.length - 1 ? " /" : null}
-
- ))}
- ]
-
+ ] [
+ {defaultSubplebbits.map((subplebbit, index) => (
+
+ {index === 0 ? null : "\u00a0"}
+ {
+ setSelectedTitle(subplebbit.title);
+ setSelectedAddress(subplebbit.address);
+ }}
+ >{subplebbit.title ? subplebbit.title : subplebbit.address}
+ {index !== defaultSubplebbits.length - 1 ? " /" : null}
+
+ ))}
+ ]
+
[
- {
- window.electron && window.electron.isElectron ? (
- setIsCreateBoardOpen(true)
- ) : (
- alert(
- 'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n'
- )
+ {
+ window.electron && window.electron.isElectron ? (
+ setIsCreateBoardOpen(true)
+ ) : (
+ alert(
+ 'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n'
)
- }
+ )
+ }
}>Create Board
]
[
@@ -622,20 +655,20 @@ const SubscriptionsCatalog = () => {
{defaultSubplebbits.map(subplebbit => (
-
- ))}
-
- alert(
- 'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n'
+
+ ))}
+
+ alert(
+ 'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n'
)
}>Create Board
setIsSettingsOpen(true)}>Settings
- { handleStyleChange({ target: { value: "Yotsuba" } }); window.scrollTo(0, 0); }}>Home
+ {handleStyleChange({target: {value: "Yotsuba"}}); window.scrollTo(0, 0);}}>Home
@@ -648,7 +681,7 @@ const SubscriptionsCatalog = () => {
- <>
+ <>
Subscriptions
{account?.subscriptions.length < 1 ? (
You haven't subscribed to any board yet.
@@ -657,7 +690,7 @@ const SubscriptionsCatalog = () => {
You have subscribed to {account?.subscriptions.length} board{account?.subscriptions.length > 1 ? "s" : null}.
)}
- >
+ >
>
@@ -665,7 +698,7 @@ const SubscriptionsCatalog = () => {
Style:
-
+
@@ -688,7 +721,7 @@ const SubscriptionsCatalog = () => {
{subplebbits.state === "succeeded" ? (
null
) : (
-
+
{stateString}
)}
@@ -698,13 +731,13 @@ const SubscriptionsCatalog = () => {
{feed.length > 1 ? (
}
useWindowScroll={true}
- components={{ Footer: () => hasMore ? : null }}
+ components={{ Footer: () => hasMore ? : null}}
endReached={loadMore}
ref={virtuosoRef}
restoreStateFrom={lastVirtuosoState}
@@ -725,7 +758,7 @@ const SubscriptionsCatalog = () => {
marginTop: "2px",
}}>
Style:
-
+
@@ -738,40 +771,40 @@ const SubscriptionsCatalog = () => {
- <>
-
- [
+ <>
+
+ [
window.scrollTo(0, 0)}>Subscriptions
- ] [
- {defaultSubplebbits.map((subplebbit, index) => (
-
- {index === 0 ? null : "\u00a0"}
- handleClickTitle(subplebbit.title, subplebbit.address)}
- >{subplebbit.title ? subplebbit.title : subplebbit.address}
- {index !== defaultSubplebbits.length - 1 ? " /" : null}
-
- ))}
- ]
-
+ ] [
+ {defaultSubplebbits.map((subplebbit, index) => (
+
+ {index === 0 ? null : "\u00a0"}
+ handleClickTitle(subplebbit.title, subplebbit.address)}
+ >{subplebbit.title ? subplebbit.title : subplebbit.address}
+ {index !== defaultSubplebbits.length - 1 ? " /" : null}
+
+ ))}
+ ]
+
- [
- {
- window.electron && window.electron.isElectron ? (
- setIsCreateBoardOpen(true)
- ) : (
- alert(
- 'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n'
- )
- )
- }
- }>Create Board
- ]
+ [
+ {
+ window.electron && window.electron.isElectron ? (
+ setIsCreateBoardOpen(true)
+ ) : (
+ alert(
+ 'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n'
+ )
+ )
+ }
+ }>Create Board
+ ]
[
setIsSettingsOpen(true)}>Settings
]
[
- handleStyleChange({ target: { value: "Yotsuba" } }
+ handleStyleChange({target: {value: "Yotsuba"}}
)}>Home
]
@@ -788,13 +821,13 @@ const SubscriptionsCatalog = () => {
marginTop: "5px",
marginBottom: "15px",
}}>
- About
+ About
+ •
+ App
•
- App
- •
- Twitter
- •
- Telegram
+ Twitter
+ •
+ Telegram
diff --git a/src/components/views/Thread.jsx b/src/components/views/Thread.jsx
index 5ed440d0..a4a8bdc7 100755
--- a/src/components/views/Thread.jsx
+++ b/src/components/views/Thread.jsx
@@ -104,6 +104,7 @@ const Thread = () => {
const [prevScrollPos, setPrevScrollPos] = useState(0);
const [visible, setVisible] = useState(true);
const [isImageSearchOpen, setIsImageSearchOpen] = useState(false);
+ const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false);
const [isModerator, setIsModerator] = useState(false);
const [commentCid, setCommentCid] = useState(null);
const [menuPosition, setMenuPosition] = useState({top: 0, left: 0});
@@ -1125,6 +1126,32 @@ const Thread = () => {
) : null
}
+ {setIsClientRedirectMenuOpen(true)}}
+ onMouseLeave={() => {setIsClientRedirectMenuOpen(false)}}>
+ View on »
+
+ - handleOptionClick(comment.cid)}>
+ Plebbit
+
+ {/* - handleOptionClick(comment.cid)}>
+ Seedit
+
*/}
+ - handleOptionClick(comment.cid)}>
+ Plebones
+
+
+
, document.body
@@ -1386,6 +1413,32 @@ const Thread = () => {
) : null
}
+ {setIsClientRedirectMenuOpen(true)}}
+ onMouseLeave={() => {setIsClientRedirectMenuOpen(false)}}>
+ View on »
+
+ - handleOptionClick(reply.cid)}>
+ Plebbit
+
+ {/* - handleOptionClick(reply.cid)}>
+ Seedit
+
*/}
+ - handleOptionClick(reply.cid)}>
+ Plebones
+
+
+
, document.body
diff --git a/src/hooks/stores/useGeneralStore.js b/src/hooks/stores/useGeneralStore.js
index 789a112a..1fabcd4a 100644
--- a/src/hooks/stores/useGeneralStore.js
+++ b/src/hooks/stores/useGeneralStore.js
@@ -20,6 +20,9 @@ const useGeneralStore = create((set) => ({
defaultSubplebbits: [],
setDefaultSubplebbits: (subplebbits) => set({ defaultSubplebbits: subplebbits }),
+ deletePost: false,
+ setDeletePost: (deletePost) => set({ deletePost }),
+
editedComment: '',
setEditedComment: (comment) => set({ editedComment: comment }),
@@ -40,6 +43,12 @@ const useGeneralStore = create((set) => ({
isCaptchaOpen: false,
setIsCaptchaOpen: (isOpen) => set({ isCaptchaOpen: isOpen }),
+ isEditModalOpen: false,
+ setIsEditModalOpen: (isOpen) => set({ isEditModalOpen: isOpen }),
+
+ isModerator: false,
+ setIsModerator: (isModerator) => set({ isModerator }),
+
isModerationOpen: false,
setIsModerationOpen: (isOpen) => set({ isModerationOpen: isOpen }),
@@ -52,6 +61,9 @@ const useGeneralStore = create((set) => ({
moderatingCommentCid: '',
setModeratingCommentCid: (cid) => set({ moderatingCommentCid: cid }),
+ originalCommentContent: null,
+ setOriginalCommentContent: (content) => set({ originalCommentContent: content }),
+
pendingComment: '',
setPendingComment: (comment) => set({ pendingComment: comment }),
diff --git a/yarn.lock b/yarn.lock
index 9ca9c88d..458c1da8 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -3410,9 +3410,9 @@
form-data "^3.0.0"
"@types/node@*", "@types/node@>=13.7.0":
- version "20.4.7"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-20.4.7.tgz#74d323a93f1391a63477b27b9aec56669c98b2ab"
- integrity sha512-bUBrPjEry2QUTsnuEjzjbS7voGWCc30W0qzgMf90GPeDGFRakvrz47ju+oqDAKCXLUCe39u57/ORMl/O/04/9g==
+ version "20.4.8"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-20.4.8.tgz#b5dda19adaa473a9bf0ab5cbd8f30ec7d43f5c85"
+ integrity sha512-0mHckf6D2DiIAzh8fM8f3HQCvMKDpK94YQ0DSVkfWTG9BZleYIWudw9cJxX8oCk9bM+vAkDyujDV6dmKHbvQpg==
"@types/node@18.15.13":
version "18.15.13"
@@ -6745,13 +6745,13 @@ eslint-config-react-app@7.0.1, eslint-config-react-app@^7.0.1:
eslint-plugin-testing-library "^5.0.1"
eslint-import-resolver-node@^0.3.7:
- version "0.3.7"
- resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz#83b375187d412324a1963d84fa664377a23eb4d7"
- integrity sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==
+ version "0.3.8"
+ resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.8.tgz#be719e72f5e96dcef7a60f74147c842db0c74b06"
+ integrity sha512-tEe+Pok22qIGaK3KoMP+N96GVDS66B/zreoVVmiavLvRUEmGRtvb4B8wO9jwnb8d2lvHtrkhZ7UD73dWBVnf/Q==
dependencies:
debug "^3.2.7"
- is-core-module "^2.11.0"
- resolve "^1.22.1"
+ is-core-module "^2.13.0"
+ resolve "^1.22.4"
eslint-module-utils@^2.8.0:
version "2.8.0"
@@ -6848,9 +6848,9 @@ eslint-plugin-react@^7.27.1:
string.prototype.matchall "^4.0.8"
eslint-plugin-testing-library@^5.0.1:
- version "5.11.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.11.0.tgz#0bad7668e216e20dd12f8c3652ca353009163121"
- integrity sha512-ELY7Gefo+61OfXKlQeXNIDVVLPcvKTeiQOoMZG9TeuWa7Ln4dUNRv8JdRWBQI9Mbb427XGlVB1aa1QPZxBJM8Q==
+ version "5.11.1"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-testing-library/-/eslint-plugin-testing-library-5.11.1.tgz#5b46cdae96d4a78918711c0b4792f90088e62d20"
+ integrity sha512-5eX9e1Kc2PqVRed3taaLnAAqPZGEX75C+M/rXzUAI3wIg/ZxzUm1OVAwfe/O+vE+6YXOLetSe9g5GKD2ecXipw==
dependencies:
"@typescript-eslint/utils" "^5.58.0"
@@ -8592,10 +8592,10 @@ is-ci@^3.0.0:
dependencies:
ci-info "^3.2.0"
-is-core-module@^2.11.0, is-core-module@^2.12.0, is-core-module@^2.12.1, is-core-module@^2.5.0, is-core-module@^2.9.0:
- version "2.12.1"
- resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.12.1.tgz#0c0b6885b6f80011c71541ce15c8d66cf5a4f9fd"
- integrity sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg==
+is-core-module@^2.12.1, is-core-module@^2.13.0, is-core-module@^2.5.0, is-core-module@^2.9.0:
+ version "2.13.0"
+ resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.0.tgz#bb52aa6e2cbd49a30c2ba68c42bf3435ba6072db"
+ integrity sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==
dependencies:
has "^1.0.3"
@@ -12813,21 +12813,12 @@ resolve.exports@^1.1.0:
resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.1.tgz#05cfd5b3edf641571fd46fa608b610dda9ead999"
integrity sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ==
-resolve@^1.1.7, resolve@^1.10.0, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.1, resolve@^1.22.2:
- version "1.22.2"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f"
- integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==
+resolve@^1.1.7, resolve@^1.10.0, resolve@^1.14.2, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.2, resolve@^1.22.3, resolve@^1.22.4:
+ version "1.22.4"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.4.tgz#1dc40df46554cdaf8948a486a10f6ba1e2026c34"
+ integrity sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==
dependencies:
- is-core-module "^2.11.0"
- path-parse "^1.0.7"
- supports-preserve-symlinks-flag "^1.0.0"
-
-resolve@^1.22.3:
- version "1.22.3"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.3.tgz#4b4055349ffb962600972da1fdc33c46a4eb3283"
- integrity sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw==
- dependencies:
- is-core-module "^2.12.0"
+ is-core-module "^2.13.0"
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"