diff --git a/electron/main.js b/electron/main.js
index 69d1620b..66083c3c 100644
--- a/electron/main.js
+++ b/electron/main.js
@@ -117,15 +117,18 @@ const createMainWindow = () => {
// only open valid https urls to prevent remote execution
// will throw if url isn't valid
const validatedUrl = new URL(originalUrl);
- if (validatedUrl.protocol !== 'https:') {
- throw Error(`can't open url '${originalUrl}' not https`);
+ let serializedUrl = '';
+
+ // make an exception for ipfs stats
+ if (validatedUrl.toString() === 'http://localhost:5001/webui/') {
+ serializedUrl = validatedUrl.toString();
+ } else if (validatedUrl.protocol === 'https:') {
+ // open serialized url to prevent remote execution
+ serializedUrl = validatedUrl.toString();
+ } else {
+ throw Error(`can't open url '${originalUrl}', it's not https and not the allowed http exception`);
}
- // do not open http protocol, not private
- // do not open any other protocol, will lead to remote execution
-
- // open serialized url to prevent remote execution
- const serializedUrl = validatedUrl.toString();
shell.openExternal(serializedUrl);
} catch (e) {
console.warn(e);
@@ -136,7 +139,7 @@ const createMainWindow = () => {
// open links (with target="_blank") in external browser
// do not open links in plebchan or will lead to remote execution
mainWindow.webContents.setWindowOpenHandler(({url}) => {
- const originalUrl = url
+ const originalUrl = url;
try {
// do not let the user open any url with shell.openExternal
// or it will lead to remote execution https://benjamin-altpeter.de/shell-openexternal-dangers/
@@ -144,25 +147,26 @@ const createMainWindow = () => {
// only open valid https urls to prevent remote execution
// will throw if url isn't valid
const validatedUrl = new URL(originalUrl);
- if (validatedUrl.protocol !== 'https:') {
- throw Error(`can't open url '${originalUrl}' not https`);
+ let serializedUrl = '';
+
+ // make an exception for ipfs stats
+ if (validatedUrl.toString() === 'http://localhost:5001/webui/') {
+ serializedUrl = validatedUrl.toString();
+ } else if (validatedUrl.protocol === 'https:') {
+ // open serialized url to prevent remote execution
+ serializedUrl = validatedUrl.toString();
+ } else {
+ throw Error(`can't open url '${originalUrl}', it's not https and not the allowed http exception`);
}
- // do not open http protocol, not private
- // do not open any other protocol, will lead to remote execution
-
- // open serialized url to prevent remote execution
- const serializedUrl = validatedUrl.toString();
shell.openExternal(serializedUrl);
- setImmediate(() => {
- shell.openExternal(serializedUrl)
- })
} catch (e) {
console.warn(e);
}
- return {action: 'deny'}
+ return {action: 'deny'};
})
+
// deny permissions like location, notifications, etc https://www.electronjs.org/docs/latest/tutorial/security#5-handle-session-permission-requests-from-remote-content
mainWindow.webContents.session.setPermissionRequestHandler((webContents, permission, callback) => {
// deny all permissions
diff --git a/electron/preload.js b/electron/preload.js
index ee5de106..80bf9917 100644
--- a/electron/preload.js
+++ b/electron/preload.js
@@ -38,6 +38,9 @@ const defaultPlebbitOptions = {
ipfsGatewayUrls: ['http://localhost:11028'] || undefined,
};
+// expose a flag to indicate that we are running in electron
+contextBridge.exposeInMainWorld('electron', { isElectron: true });
+
// expose plebbit-js native functions into electron's renderer
contextBridge.exposeInMainWorld('plebbitJsNativeFunctions', require('@plebbit/plebbit-js').nativeFunctions.node)
contextBridge.exposeInMainWorld('defaultPlebbitOptions', defaultPlebbitOptions)
@@ -47,4 +50,4 @@ try {
if (isDev) localStorage.debug = 'plebbit-js:*,plebbit-react-hooks:*,plebchan:*';
} catch (e) {
console.log(e);
-}
+}
\ No newline at end of file
diff --git a/src/components/VerifiedAuthor.jsx b/src/components/VerifiedAuthor.jsx
new file mode 100644
index 00000000..5a832381
--- /dev/null
+++ b/src/components/VerifiedAuthor.jsx
@@ -0,0 +1,10 @@
+import {useComment, useAuthorAddress} from '@plebbit/plebbit-react-hooks';
+
+function VerifiedAuthor({ commentCid, children }) {
+ const comment = useComment({commentCid});
+ const {authorAddress, shortAuthorAddress} = useAuthorAddress({comment});
+
+ return children({ authorAddress, shortAuthorAddress });
+}
+
+export default VerifiedAuthor;
\ No newline at end of file
diff --git a/src/components/modals/CaptchaModal.jsx b/src/components/modals/CaptchaModal.jsx
index 4477766c..91a7dc2d 100644
--- a/src/components/modals/CaptchaModal.jsx
+++ b/src/components/modals/CaptchaModal.jsx
@@ -95,6 +95,7 @@ const CaptchaModal = () => {
const handleCloseModal = () => {
setImageSources([]);
setChallengesArray([]);
+ setCurrentChallengeIndex(0);
setIsCaptchaOpen(false);
};
diff --git a/src/components/modals/ModerationModal.jsx b/src/components/modals/ModerationModal.jsx
index 44caad8d..9188516a 100755
--- a/src/components/modals/ModerationModal.jsx
+++ b/src/components/modals/ModerationModal.jsx
@@ -50,7 +50,8 @@ const ModerationModal = ({ isOpen, closeModal, deletePost }) => {
if (challengeVerification.challengeSuccess === true) {
setNewSuccessMessage('Challenge Success');
} else if (challengeVerification.challengeSuccess === false) {
- setNewErrorMessage('Challenge Failed', {reason: challengeVerification.reason, errors: challengeVerification.errors});
+ setNewErrorMessage(`Challenge Failed, reason: ${challengeVerification.reason}. Errors: ${challengeVerification.errors}`);
+ console.log('challenge failed', challengeVerification);
}
};
@@ -63,7 +64,7 @@ const ModerationModal = ({ isOpen, closeModal, deletePost }) => {
challengeAnswers = await getChallengeAnswersFromUser(challenges)
}
catch (error) {
- setNewErrorMessage(error);
+ setNewErrorMessage(error.message); console.log(error);
}
if (challengeAnswers) {
await comment.publishChallengeAnswers(challengeAnswers)
@@ -113,9 +114,19 @@ const ModerationModal = ({ isOpen, closeModal, deletePost }) => {
onChallenge,
onChallengeVerification,
onError: (error) => {
- setNewErrorMessage(error);
+ setNewErrorMessage(error.message); console.log(error);
},
});
+
+
+ useEffect(() => {
+ if (selectedAddress) {
+ setPublishCommentEditOptions((prevOptions) => ({
+ ...prevOptions,
+ subplebbitAddress: selectedAddress,
+ }));
+ }
+ }, [selectedAddress]);
const { publishCommentEdit } = usePublishCommentEdit(publishCommentEditOptions);
diff --git a/src/components/modals/ReplyModal.jsx b/src/components/modals/ReplyModal.jsx
index a73ed331..96fb2235 100755
--- a/src/components/modals/ReplyModal.jsx
+++ b/src/components/modals/ReplyModal.jsx
@@ -99,10 +99,10 @@ const ReplyModal = ({ isOpen, closeModal }) => {
const onChallengeVerification = (challengeVerification) => {
if (challengeVerification.challengeSuccess === true) {
- console.log('challenge success');
- }
- else if (challengeVerification.challengeSuccess === false) {
- setNewErrorMessage('challenge failed', {reason: challengeVerification.reason, errors: challengeVerification.errors});
+ return;
+ } else if (challengeVerification.challengeSuccess === false) {
+ setNewErrorMessage(`Challenge Failed, reason: ${challengeVerification.reason}. Errors: ${challengeVerification.errors}`);
+ console.log('challenge failed', challengeVerification);
}
};
@@ -115,7 +115,7 @@ const ReplyModal = ({ isOpen, closeModal }) => {
challengeAnswers = await getChallengeAnswersFromUser(challenges)
}
catch (error) {
- setNewErrorMessage(error);
+ setNewErrorMessage(error.message); console.log(error);
}
if (challengeAnswers) {
await comment.publishChallengeAnswers(challengeAnswers)
@@ -136,7 +136,7 @@ const ReplyModal = ({ isOpen, closeModal }) => {
onChallenge,
onChallengeVerification,
onError: (error) => {
- setNewErrorMessage(error);
+ setNewErrorMessage(error.message); console.log(error);
},
});
@@ -229,8 +229,10 @@ const ReplyModal = ({ isOpen, closeModal }) => {
}, [selectedParentCid, anonymousMode, account]);
useEffect(() => {
- updateSigner();
- }, [updateSigner]);
+ if (anonymousMode) {
+ updateSigner();
+ }
+ }, [updateSigner, anonymousMode]);
useEffect(() => {
diff --git a/src/components/modals/SettingsModal.jsx b/src/components/modals/SettingsModal.jsx
index f60d28bc..144e847d 100755
--- a/src/components/modals/SettingsModal.jsx
+++ b/src/components/modals/SettingsModal.jsx
@@ -36,6 +36,17 @@ const SettingsModal = ({ isOpen, closeModal }) => {
const importRef = useRef();
const nameRef = useRef();
+ const defaultGatewayUrls = [
+ 'https://ipfs.io',
+ 'https://ipfsgateway.xyz',
+ 'https://cloudflare-ipfs.com',
+ 'https://plebpubsub.live'
+ ];
+ const defaultPubsubHttpClientsOptions = [
+ 'https://pubsubprovider.xyz/api/v0',
+ 'https://plebpubsub.live/api/v0'
+ ];
+
const isValidURL = (url) => {
try {
new URL(url);
@@ -46,14 +57,26 @@ const SettingsModal = ({ isOpen, closeModal }) => {
};
const handleSavePlebbitOptions = async () => {
- const gatewayUrls = gatewayRef.current.value.split('\n').filter(url => url.trim());
- const ipfsClientsOptions = ipfsRef.current.value.split('\n').filter(url => url.trim()) || undefined;
- const pubsubClientsOptions = pubsubRef.current.value.split('\n').filter(url => url.trim());
+ let gatewayUrls = gatewayRef.current.value.split('\n').filter(url => url.trim());
+ let ipfsClientsOptions = ipfsRef.current.value.split('\n').filter(url => url.trim());
+ let pubsubClientsOptions = pubsubRef.current.value.split('\n').filter(url => url.trim());
+
+ if (!gatewayUrls.length) {
+ gatewayUrls = defaultGatewayUrls;
+ }
+
+ if (!ipfsClientsOptions.length) {
+ ipfsClientsOptions = undefined;
+ }
+
+ if (!pubsubClientsOptions.length) {
+ pubsubClientsOptions = defaultPubsubHttpClientsOptions;
+ }
const invalidUrls = [
- ...gatewayUrls,
+ ...gatewayUrls || defaultGatewayUrls,
...(ipfsClientsOptions || []),
- ...pubsubClientsOptions,
+ ...pubsubClientsOptions || defaultPubsubHttpClientsOptions,
].filter((url) => !isValidURL(url));
if (invalidUrls.length > 0) {
@@ -72,7 +95,7 @@ const SettingsModal = ({ isOpen, closeModal }) => {
localStorage.setItem("successToast", "Settings Saved");
window.location.reload();
} catch (error) {
- setNewErrorMessage(error.message);
+ setNewErrorMessage(error.message); console.log(error);
}
};
@@ -81,13 +104,6 @@ const SettingsModal = ({ isOpen, closeModal }) => {
setNewErrorMessage(null);
setNewSuccessMessage(null);
- const defaultGatewayUrls = [
- 'https://ipfs.io',
- 'https://ipfsgateway.xyz',
- 'https://cloudflare-ipfs.com'
- ];
- const defaultPubsubHttpClientsOptions = ['https://pubsubprovider.xyz/api/v0'];
-
gatewayRef.current.value = defaultGatewayUrls.join('\n');
ipfsRef.current.value = "";
pubsubRef.current.value = defaultPubsubHttpClientsOptions.join('\n');
@@ -105,7 +121,7 @@ const SettingsModal = ({ isOpen, closeModal }) => {
localStorage.setItem("successToast", "Settings Reset");
window.location.reload();
} catch (error) {
- setNewErrorMessage(error.message);
+ setNewErrorMessage(error.message); console.log(error);
}
};
@@ -169,7 +185,7 @@ const SettingsModal = ({ isOpen, closeModal }) => {
setNewSuccessMessage("Account Imported");
} catch (error) {
- setNewErrorMessage(error.message);
+ setNewErrorMessage(error.message); console.log(error);
}
};
@@ -190,7 +206,7 @@ const SettingsModal = ({ isOpen, closeModal }) => {
}});
setNewSuccessMessage("Account Name Saved");
} catch (error) {
- setNewErrorMessage(error.message);
+ setNewErrorMessage(error.message); console.log(error);
}
};
@@ -207,7 +223,13 @@ const SettingsModal = ({ isOpen, closeModal }) => {
- v{version}
+ v{version} -
+ {window.electron && window.electron.isElectron ? (
+
+ full node
+
+ ) : (web )
+ }
Settings
diff --git a/src/components/styled/modals/SettingsModal.styled.jsx b/src/components/styled/modals/SettingsModal.styled.jsx
index 094a4b5e..806afb47 100644
--- a/src/components/styled/modals/SettingsModal.styled.jsx
+++ b/src/components/styled/modals/SettingsModal.styled.jsx
@@ -417,4 +417,8 @@ export const StyledModal = styled(Modal)`
return '';
}
}}
+
+ #node-stats {
+ text-decoration: none;
+ }
`;
\ No newline at end of file
diff --git a/src/components/styled/views/Board.styled.jsx b/src/components/styled/views/Board.styled.jsx
index f3ef6856..c2cb1312 100644
--- a/src/components/styled/views/Board.styled.jsx
+++ b/src/components/styled/views/Board.styled.jsx
@@ -267,7 +267,7 @@ export const Header = styled.div`
clear: both;
.banner {
- border: 1px solid #800;
+ border: 1px solid #34345c;
margin: 5px auto;
width: 300px;
height: 100px;
@@ -2016,6 +2016,16 @@ export const BoardForm = styled.div`
}
video {
+ width: 100%;
+ height: auto;
+ }
+
+ iframe {
+ width: 100%;
+ height: auto;
+ }
+
+ #video-thumbnail-mobile {
width: 100px;
}
@@ -3804,7 +3814,7 @@ export const BoardForm = styled.div`
color: #707070;
font-weight: 700;
background-color: rgb(27,28,30);
- border: 1px solid #282A2E;
+ border: 1px solid #2D2F33;
background-image: url(assets/buttonfade-dark.png);
background-repeat: repeat-x;
text-decoration: none;
diff --git a/src/components/styled/views/Thread.styled.jsx b/src/components/styled/views/Thread.styled.jsx
index 6c1f8cc2..09b9c343 100644
--- a/src/components/styled/views/Thread.styled.jsx
+++ b/src/components/styled/views/Thread.styled.jsx
@@ -1193,7 +1193,13 @@ export const BoardForm = styled.div`
}
video {
- width: 100px;
+ width: 100%;
+ height: auto;
+ }
+
+ iframe {
+ width: 100%;
+ height: auto;
}
img {
@@ -2932,7 +2938,7 @@ export const BoardForm = styled.div`
color: #707070;
font-weight: 700;
background-color: rgb(27,28,30);
- border: 1px solid #282A2E;
+ border: 1px solid #2D2F33;
background-image: url(assets/buttonfade-dark.png);
background-repeat: repeat-x;
text-decoration: none;
diff --git a/src/components/views/All.jsx b/src/components/views/All.jsx
index 34dd3b47..d984ba16 100755
--- a/src/components/views/All.jsx
+++ b/src/components/views/All.jsx
@@ -1,4 +1,4 @@
-import React, { Fragment, useCallback, useEffect, useLayoutEffect, useMemo, useState, useRef } from 'react';
+import React, { Fragment, useCallback, useEffect, useMemo, useState, useRef } from 'react';
import { confirmAlert } from 'react-confirm-alert';
import { createPortal } from 'react-dom';
import { Helmet } from 'react-helmet-async';
@@ -21,6 +21,7 @@ import Post from '../Post';
import PostLoader from '../PostLoader';
import PostOnHover from '../PostOnHover';
import StateLabel from '../StateLabel';
+import VerifiedAuthor from '../VerifiedAuthor';
import ReplyModal from '../modals/ReplyModal';
import SettingsModal from '../modals/SettingsModal';
import findShortParentCid from '../../utils/findShortParentCid';
@@ -102,6 +103,8 @@ const All = () => {
const [moderatorPermissions, setModeratorPermissions] = useState({});
const [executeAnonMode, setExecuteAnonMode] = useState(false);
const [cidTracker, setCidTracker] = useState({});
+ const [isThumbnailClicked, setIsThumbnailClicked] = useState({});
+ const [isMobileThumbnailClicked, setIsMobileThumbnailClicked] = useState({});
const setSelectedThreadCid = (cid) => {
selectedThreadCidRef.current = cid;
@@ -117,6 +120,20 @@ const All = () => {
const stateString = useFeedStateString(subplebbits);
+ const handleThumbnailClick = (index, isMobile=false) => {
+ if (isMobile) {
+ setIsMobileThumbnailClicked(prevState => ({
+ ...prevState,
+ [index]: !prevState[index],
+ }));
+ } else {
+ setIsThumbnailClicked(prevState => ({
+ ...prevState,
+ [index]: !prevState[index],
+ }));
+ }
+ };
+
useEffect(() => {
let permissions = {};
@@ -163,6 +180,14 @@ const All = () => {
}, [openMenuCid, handleOutsideClick]);
+ useEffect(() => {
+ if (postOnHoverRef.current) {
+ const rect = postOnHoverRef.current.getBoundingClientRect();
+ setPostOnHoverHeight(rect.height);
+ }
+ }, [outOfViewCid]);
+
+
const errorString = useMemo(() => {
for (const subplebbit of subplebbits) {
if (subplebbit?.updatingState !== 'failed') {
@@ -279,7 +304,8 @@ const All = () => {
setNewSuccessMessage('Challenge Success');
}
else if (challengeVerification.challengeSuccess === false) {
- setNewErrorMessage('Challenge Failed', {reason: challengeVerification.reason, errors: challengeVerification.errors});
+ setNewErrorMessage(`Challenge Failed, reason: ${challengeVerification.reason}. Errors: ${challengeVerification.errors}`);
+ console.log('challenge failed', challengeVerification);
}
};
@@ -290,7 +316,7 @@ const All = () => {
challengeAnswers = await getChallengeAnswersFromUser(challenges)
}
catch (error) {
- setNewErrorMessage(error);
+ setNewErrorMessage(error.message); console.log(error);
}
if (challengeAnswers) {
await comment.publishChallengeAnswers(challengeAnswers)
@@ -347,7 +373,7 @@ const All = () => {
onChallenge,
onChallengeVerification,
onError: (error) => {
- setNewErrorMessage(error);
+ setNewErrorMessage(error.message); console.log(error);
},
});
@@ -355,8 +381,8 @@ const All = () => {
const { publishCommentEdit } = usePublishCommentEdit(publishCommentEditOptions);
- const handleAuthorDeleteClick = (cid) => {
- handleOptionClick(cid);
+ const handleAuthorDeleteClick = (comment) => {
+ handleOptionClick(comment.cid);
confirmAlert({
customUI: ({ onClose }) => {
@@ -370,9 +396,10 @@ const All = () => {
onClick={() => {
setIsAuthorDelete(true);
setIsAuthorEdit(false);
- setCommentCid(cid);
setPublishCommentEditOptions(prevOptions => ({
...prevOptions,
+ commentCid: comment.cid,
+ subplebbitAddress: comment.subplebbitAddress,
deleted: true,
}));
setTriggerPublishCommentEdit(true);
@@ -457,14 +484,6 @@ const All = () => {
};
- useLayoutEffect(() => {
- if (postOnHoverRef.current) {
- const rect = postOnHoverRef.current.getBoundingClientRect();
- setPostOnHoverHeight(rect.height);
- }
- }, [outOfViewCid]);
-
-
return (
<>
@@ -583,7 +602,7 @@ const All = () => {
Catalog
]
- {feed.length > 0 ? (
+ {feed ? (
null
) : (
@@ -599,7 +618,7 @@ const All = () => {
- {feed.length > 0 ? (
+ {feed ? (
{
{commentMediaInfo?.url ? (
-
-
- {commentMediaInfo?.type === "webpage" ? (
-
-
- {thread.thumbnailUrl ? (
+
+
+ {commentMediaInfo?.type === 'iframe' && (
+
+
+ {(isThumbnailClicked[index] || !commentMediaInfo.thumbnail) && commentMediaInfo.embedUrl ? (
+
+ ) : (
+ {handleThumbnailClick(index)}}
+ style={{cursor: "pointer"}}
+ onError={(e) => e.target.src = fallbackImgUrl} />
+ )}
+
+
+ )}
+ {commentMediaInfo?.type === "webpage" ? (
+
+
+ {thread.thumbnailUrl ? (
+ e.target.src = fallbackImgUrl} />
+ ) : null}
+
+
+ ) : null}
+ {commentMediaInfo?.type === "image" ? (
+
+
e.target.src = fallbackImgUrl} />
- ) : null}
+
+
+ ) : null}
+ {commentMediaInfo?.type === "video" ? (
+
+
+ {isThumbnailClicked[index] ? (
+ e.target.src = fallbackImgUrl}
+ />
+ ) : (
+ {handleThumbnailClick(index)}}
+ style={{cursor: "pointer"}}
+ onError={(e) => e.target.src = fallbackImgUrl}
+ />
+ )}
- ) : null}
- {commentMediaInfo?.type === "image" ? (
-
+ ) : null}
+ {commentMediaInfo?.type === "audio" ? (
- e.target.src = fallbackImgUrl} />
-
- ) : null}
- {commentMediaInfo?.type === "video" ? (
-
- e.target.src = fallbackImgUrl} />
-
- ) : null}
- {commentMediaInfo?.type === "audio" ? (
-
- e.target.src = fallbackImgUrl} />
-
- ) : null}
-
- ) : null}
+ ) : null}
+
+ ) : null}
{thread.title ? (
thread.title.length > 75 ?
@@ -699,9 +772,9 @@ const All = () => {
(u/
handleAddressClick(thread.author.shortAddress)}
+ onClick={() => handleAddressClick({({ shortAuthorAddress }) => (shortAuthorAddress)} )}
>
- {thread.author.shortAddress}
+ {{({ shortAuthorAddress }) => (shortAuthorAddress)} }
)
{getDate(thread.timestamp)}
@@ -776,38 +849,44 @@ const All = () => {
>
handleOptionClick(thread.cid)}>Hide thread
- {thread.author.shortAddress === account?.author.shortAddress ? (
+ {({ authorAddress }) => (
<>
- {handleAuthorEditClick(thread); setSelectedAddress(thread.subplebbitAddress);}}>Edit post
- {handleAuthorDeleteClick(thread.cid); setSelectedAddress(thread.subplebbitAddress);}}>Delete post
+ {authorAddress === account?.author.address ||
+ authorAddress === account?.signer.address ? (
+ <>
+ handleAuthorEditClick(thread)}>Edit post
+ handleAuthorDeleteClick(thread)}>Delete post
+ >
+ ) : null}
+ {isModerator ? (
+ <>
+ {authorAddress === account?.author.address ||
+ authorAddress === account?.signer.address ? (
+ null
+ ) : (
+ {
+ setSelectedAddress(thread.subplebbitAddress);
+ setModeratingCommentCid(thread.cid)
+ setIsModerationOpen(true);
+ handleOptionClick(thread.cid);
+ setDeletePost(true);
+ }}>
+ Delete post
+
+ )}
+ {
+ setSelectedAddress(thread.subplebbitAddress);
+ setModeratingCommentCid(thread.cid)
+ setIsModerationOpen(true);
+ handleOptionClick(thread.cid);
+ }}>
+ Mod tools
+
+ >
+ ) : null}
>
- ) : null}
- {isModerator ? (
- <>
- {thread.author.shortAddress === account?.author.shortAddress ? (
- null
- ) : (
- {
- setSelectedAddress(thread.subplebbitAddress);
- setModeratingCommentCid(thread.cid)
- setIsModerationOpen(true);
- handleOptionClick(thread.cid);
- setDeletePost(true);
- }}>
- Delete post
-
- )}
- {
- setSelectedAddress(thread.subplebbitAddress);
- setModeratingCommentCid(thread.cid)
- setIsModerationOpen(true);
- handleOptionClick(thread.cid);
- }}>
- Mod tools
-
- >
- ) : null}
+ )}
{(commentMediaInfo && (
commentMediaInfo.type === 'image' ||
(commentMediaInfo.type === 'webpage' &&
@@ -969,7 +1048,7 @@ const All = () => {
handleAddressClick(reply.author.shortAddress)}
+ onClick={() => handleAddressClick({({ shortAuthorAddress }) => (shortAuthorAddress)} )}
>
(u/
{reply.author?.shortAddress ?
@@ -1064,38 +1143,44 @@ const All = () => {
>
handleOptionClick(reply.cid)}>Hide post
- {reply.author.shortAddress === account?.author.shortAddress ? (
+ {({ authorAddress }) => (
<>
- {handleAuthorEditClick(reply); setSelectedAddress(thread.subplebbitAddress);}}>Edit post
- {handleAuthorDeleteClick(reply.cid); setSelectedAddress(thread.subplebbitAddress);}}>Delete post
- >
- ) : null}
- {isModerator ? (
- <>
- {reply.author.shortAddress === account?.author.shortAddress ? (
- null
- ) : (
- {
+ {authorAddress === account?.author.address ||
+ authorAddress === account?.signer.address ? (
+ <>
+ handleAuthorEditClick(reply)}>Edit post
+ handleAuthorDeleteClick(reply)}>Delete post
+ >
+ ) : null}
+ {isModerator ? (
+ <>
+ {authorAddress === account?.author.address ||
+ authorAddress === account?.signer.address ? (
+ null
+ ) : (
+ {
setSelectedAddress(thread.subplebbitAddress);
setModeratingCommentCid(reply.cid)
setIsModerationOpen(true);
handleOptionClick(reply.cid);
setDeletePost(true);
+ }}>
+ Delete post
+
+ )}
+ {
+ setSelectedAddress(thread.subplebbitAddress);
+ setModeratingCommentCid(reply.cid)
+ setIsModerationOpen(true);
+ handleOptionClick(reply.cid);
}}>
- Delete post
+ Mod tools
- )}
- {
- setSelectedAddress(thread.subplebbitAddress);
- setModeratingCommentCid(reply.cid)
- setIsModerationOpen(true);
- handleOptionClick(reply.cid);
- }}>
- Mod tools
-
+ >
+ ) : null}
>
- ) : null}
+ )}
{(replyMediaInfo && (
replyMediaInfo.type === 'image' ||
(replyMediaInfo.type === 'webpage' &&
@@ -1487,11 +1572,11 @@ const All = () => {
handleAddressClick(thread.author.shortAddress)}
+ onClick={() => handleAddressClick({({ shortAuthorAddress }) => (shortAuthorAddress)} )}
>
(u/
- {thread.author.shortAddress}
+ {{({ shortAuthorAddress }) => (shortAuthorAddress)} }
)
@@ -1556,51 +1641,108 @@ const All = () => {
{thread.link ? (
-
- {commentMediaInfo?.url ? (
- commentMediaInfo.type === "webpage" ? (
-
-
- {thread.thumbnailUrl ? (
+
+ {commentMediaInfo?.type === 'iframe' && (
+
+
+ {(isMobileThumbnailClicked[index] || !commentMediaInfo.thumbnail) && commentMediaInfo.embedUrl ? (
+
+
+
+ ) : (
+ {handleThumbnailClick(index, true)}}
+ style={{cursor: "pointer"}}
+ onError={(e) => e.target.src = fallbackImgUrl} />
+ )}
+ {commentMediaInfo?.type === "video" || "iframe" ? (
+ isMobileThumbnailClicked[index] ? (
+
+ {handleThumbnailClick(index, true)}}
+ >Close
+
+ ) : (
+ video
+ )) : video
}
+
+
+ )}
+ {commentMediaInfo?.url ? (
+ commentMediaInfo.type === "webpage" ? (
+
+
+ {thread.thumbnailUrl ? (
+ e.target.src = fallbackImgUrl} />
+ ) : null}
+ {commentMediaInfo?.type}
+
+
+ ) : commentMediaInfo.type === "image" ? (
+
+
e.target.src = fallbackImgUrl} />
- ) : null}
- {commentMediaInfo?.type}
-
-
- ) : commentMediaInfo.type === "image" ? (
-
-
- e.target.src = fallbackImgUrl} />
- {commentMediaInfo?.type}
-
-
- ) : commentMediaInfo.type === "video" ? (
-
- e.target.src = fallbackImgUrl} />
- {commentMediaInfo?.type}
-
- ) : commentMediaInfo.type === "audio" ? (
-
- e.target.src = fallbackImgUrl} />
- {commentMediaInfo?.type}
-
- ) : null
- ) : null}
-
- ) : null}
+ {commentMediaInfo?.type}
+
+
+ ) : commentMediaInfo.type === "video" ? (
+
+ {isMobileThumbnailClicked[index] ? (
+ e.target.src = fallbackImgUrl} />
+ ) : (
+ {handleThumbnailClick(index, true)}}
+ style={{cursor: "pointer"}}
+ id="video-thumbnail-mobile"
+ onError={(e) => e.target.src = fallbackImgUrl}
+ />
+ )}
+ {commentMediaInfo?.type === "video" || "iframe" ? (
+ isMobileThumbnailClicked[index] ? (
+
+ {handleThumbnailClick(index, true)}}
+ >Close
+
+ ) : (
+ video
+ )) : video
}
+
+ ) : commentMediaInfo.type === "audio" ? (
+
+ e.target.src = fallbackImgUrl} />
+ {commentMediaInfo?.type}
+
+ ) : null
+ ) : null}
+
+ ) : null}
{thread.content ? (
thread.content?.length > 500 ?
@@ -1670,7 +1812,7 @@ const All = () => {
handleAddressClick(reply.author.shortAddress)}
+ onClick={() => handleAddressClick({({ shortAuthorAddress }) => (shortAuthorAddress)} )}
>
(u/
{reply.author?.shortAddress ?
@@ -2062,7 +2204,7 @@ const All = () => {
}}
endReached={tryLoadMore}
useWindowScroll={true}
- components={{ Footer: hasMore ? () => : null }}
+ components={{ Footer: hasMore && feed.length > 0 ? () => : null }}
/>
) : (
diff --git a/src/components/views/AllCatalog.jsx b/src/components/views/AllCatalog.jsx
index 63fa7b1c..88819ac8 100755
--- a/src/components/views/AllCatalog.jsx
+++ b/src/components/views/AllCatalog.jsx
@@ -13,6 +13,7 @@ import { TopBar, Footer, AuthorDeleteAlert } from '../styled/views/Thread.styled
import CatalogLoader from '../CatalogLoader';
import EditModal from '../modals/EditModal';
import ImageBanner from '../ImageBanner';
+import VerifiedAuthor from '../VerifiedAuthor';
import ModerationModal from '../modals/ModerationModal';
import OfflineIndicator from '../OfflineIndicator';
import SettingsModal from '../modals/SettingsModal';
@@ -149,7 +150,8 @@ const AllCatalog = () => {
setNewSuccessMessage('Challenge Success');
}
else if (challengeVerification.challengeSuccess === false) {
- setNewErrorMessage('Challenge Failed', {reason: challengeVerification.reason, errors: challengeVerification.errors});
+ setNewErrorMessage(`Challenge Failed, reason: ${challengeVerification.reason}. Errors: ${challengeVerification.errors}`);
+ console.log('challenge failed', challengeVerification);
}
};
@@ -160,7 +162,7 @@ const AllCatalog = () => {
challengeAnswers = await getChallengeAnswersFromUser(challenges)
}
catch (error) {
- setNewErrorMessage(error);
+ setNewErrorMessage(error.message); console.log(error);
}
if (challengeAnswers) {
await comment.publishChallengeAnswers(challengeAnswers)
@@ -209,7 +211,7 @@ const AllCatalog = () => {
onChallenge,
onChallengeVerification,
onError: (error) => {
- setNewErrorMessage(error);
+ setNewErrorMessage(error.message); console.log(error);
},
});
@@ -232,9 +234,10 @@ const AllCatalog = () => {
onClick={() => {
setIsAuthorDelete(true);
setIsAuthorEdit(false);
- setCommentCid(comment.cid);
setPublishCommentEditOptions(prevOptions => ({
...prevOptions,
+ commentCid: comment.cid,
+ subplebbitAddress: comment.subplebbitAddress,
deleted: true,
}));
setTriggerPublishCommentEdit(true);
@@ -440,7 +443,7 @@ const AllCatalog = () => {
Return
- {feed.length > 0 ? (
+ {feed ? (
null
) : (
@@ -451,7 +454,7 @@ const AllCatalog = () => {
- {feed.length > 0 ? (
+ {feed ? (
{
>
handleOptionClick(thread.cid)}>Hide thread
- {thread.author.shortAddress === account?.author.shortAddress ? (
+ {({ authorAddress }) => (
<>
- handleAuthorEditClick(thread)}>Edit post
- handleAuthorDeleteClick(thread)}>Delete post
+ {authorAddress === account?.author.address ||
+ authorAddress === account?.signer.address ? (
+ <>
+ handleAuthorEditClick(thread)}>Edit post
+ handleAuthorDeleteClick(thread)}>Delete post
+ >
+ ) : null}
+ {isModerator ? (
+ <>
+ {authorAddress === account?.author.address ||
+ authorAddress === account?.signer.address ? (
+ null
+ ) : (
+ {
+ setSelectedAddress(thread.subplebbitAddress);
+ setModeratingCommentCid(thread.cid)
+ setIsModerationOpen(true);
+ handleOptionClick(thread.cid);
+ setDeletePost(true);
+ }}>
+ Delete post
+
+ )}
+ {
+ setSelectedAddress(thread.subplebbitAddress);
+ setModeratingCommentCid(thread.cid)
+ setIsModerationOpen(true);
+ handleOptionClick(thread.cid);
+ }}>
+ Mod tools
+
+ >
+ ) : null}
>
- ) : null}
- {isModerator ? (
- <>
- {thread.author.shortAddress === account?.author.shortAddress ? (
- null
- ) : (
- {
- setSelectedAddress(thread.subplebbitAddress);
- setModeratingCommentCid(thread.cid)
- setIsModerationOpen(true);
- handleOptionClick(thread.cid);
- setDeletePost(true);
- }}>
- Delete post
-
- )}
- {
- setSelectedAddress(thread.subplebbitAddress);
- setModeratingCommentCid(thread.cid)
- setIsModerationOpen(true);
- handleOptionClick(thread.cid);
- }}>
- Mod tools
-
- >
- ) : null}
+ )}
{(commentMediaInfo && (
commentMediaInfo.type === 'image' ||
(commentMediaInfo.type === 'webpage' &&
diff --git a/src/components/views/Board.jsx b/src/components/views/Board.jsx
index c645eaf4..140e5b27 100755
--- a/src/components/views/Board.jsx
+++ b/src/components/views/Board.jsx
@@ -1,4 +1,4 @@
-import React, { Fragment, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
+import React, { Fragment, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import { Helmet } from 'react-helmet-async';
import { Link, useNavigate, useParams } from 'react-router-dom';
@@ -22,6 +22,7 @@ import Post from '../Post';
import PostLoader from '../PostLoader';
import PostOnHover from '../PostOnHover';
import StateLabel from '../StateLabel';
+import VerifiedAuthor from '../VerifiedAuthor';
import ReplyModal from '../modals/ReplyModal';
import SettingsModal from '../modals/SettingsModal';
import findShortParentCid from '../../utils/findShortParentCid';
@@ -128,6 +129,8 @@ const Board = () => {
const [postOnHoverHeight, setPostOnHoverHeight] = useState(0);
const [executeAnonMode, setExecuteAnonMode] = useState(false);
const [cidTracker, setCidTracker] = useState({});
+ const [isThumbnailClicked, setIsThumbnailClicked] = useState({});
+ const [isMobileThumbnailClicked, setIsMobileThumbnailClicked] = useState({});
const setSelectedThreadCid = (cid) => { selectedThreadCidRef.current = cid;}
@@ -147,10 +150,26 @@ const Board = () => {
}, [account?.author.address, subplebbit.roles]);
+ const handleThumbnailClick = (index, isMobile=false) => {
+ if (isMobile) {
+ setIsMobileThumbnailClicked(prevState => ({
+ ...prevState,
+ [index]: !prevState[index],
+ }));
+ } else {
+ setIsThumbnailClicked(prevState => ({
+ ...prevState,
+ [index]: !prevState[index],
+ }));
+ }
+ };
+
+
const handleOptionClick = () => {
setOpenMenuCid(null);
};
+
const handleOutsideClick = useCallback((e) => {
if (openMenuCid !== null && !postMenuCatalogRef.current.contains(e.target)) {
setOpenMenuCid(null);
@@ -169,7 +188,14 @@ const Board = () => {
document.removeEventListener('click', handleOutsideClick);
};
}, [openMenuCid, handleOutsideClick]);
-
+
+
+ useEffect(() => {
+ if (postOnHoverRef.current) {
+ const rect = postOnHoverRef.current.getBoundingClientRect();
+ setPostOnHoverHeight(rect.height);
+ }
+ }, [outOfViewCid]);
const errorString = useMemo(() => {
@@ -303,7 +329,8 @@ const Board = () => {
}
}
else if (challengeVerification.challengeSuccess === false) {
- setNewErrorMessage('Challenge Failed', {reason: challengeVerification.reason, errors: challengeVerification.errors});
+ setNewErrorMessage(`Challenge Failed, reason: ${challengeVerification.reason}. Errors: ${challengeVerification.errors}`);
+ console.log('challenge failed', challengeVerification);
}
};
@@ -316,7 +343,7 @@ const Board = () => {
challengeAnswers = await getChallengeAnswersFromUser(challenges)
}
catch (error) {
- setNewErrorMessage(error);
+ setNewErrorMessage(error.message); console.log(error);
}
if (challengeAnswers) {
await comment.publishChallengeAnswers(challengeAnswers)
@@ -337,7 +364,7 @@ const Board = () => {
onChallenge,
onChallengeVerification,
onError: (error) => {
- setNewErrorMessage(error);
+ setNewErrorMessage(error.message); console.log(error);
},
});
@@ -431,8 +458,10 @@ const Board = () => {
}, [selectedThreadCidRef, anonymousMode, account]);
useEffect(() => {
- updateSigner();
- }, [updateSigner]);
+ if (anonymousMode) {
+ updateSigner();
+ }
+ }, [updateSigner, anonymousMode]);
@@ -490,7 +519,7 @@ const Board = () => {
onChallenge,
onChallengeVerification,
onError: (error) => {
- setNewErrorMessage(error);
+ setNewErrorMessage(error.message); console.log(error);
},
});
@@ -498,8 +527,8 @@ const Board = () => {
const { publishCommentEdit } = usePublishCommentEdit(publishCommentEditOptions);
- const handleAuthorDeleteClick = (cid) => {
- handleOptionClick(cid);
+ const handleAuthorDeleteClick = (comment) => {
+ handleOptionClick(comment.cid);
confirmAlert({
customUI: ({ onClose }) => {
@@ -513,9 +542,10 @@ const Board = () => {
onClick={() => {
setIsAuthorDelete(true);
setIsAuthorEdit(false);
- setCommentCid(cid);
setPublishCommentEditOptions(prevOptions => ({
...prevOptions,
+ commentCid: comment.cid,
+ subplebbitAddress: comment.subplebbitAddress,
deleted: true,
}));
setTriggerPublishCommentEdit(true);
@@ -613,18 +643,11 @@ const Board = () => {
await unsubscribe(selectedAddress);
}
} catch (error) {
- setNewErrorMessage(error);
+ setNewErrorMessage(error.message); console.log(error);
}
};
- useLayoutEffect(() => {
- if (postOnHoverRef.current) {
- const rect = postOnHoverRef.current.getBoundingClientRect();
- setPostOnHoverHeight(rect.height);
- }
- }, [outOfViewCid]);
-
return (
@@ -804,7 +827,7 @@ const Board = () => {
{window.scrollTo(0, 0)}}>Catalog
]
- {feed.length > 0 ? (
+ {subplebbit?.state === "succeeded" ? (
<>
[
@@ -838,7 +861,7 @@ const Board = () => {
{subplebbit?.state === "failed" ? (
null
) : (
- subplebbit?.state === "succeeded" ? (
+ feed ? (
<>
{subplebbit.rules ?
<>
@@ -1251,407 +1274,159 @@ const Board = () => {
const commentMediaInfo = getCommentMediaInfo(thread);
const fallbackImgUrl = "assets/filedeleted-res.gif";
return (
-
-
-
-
-
-
- {commentMediaInfo?.url ? (
-
-
- {commentMediaInfo?.type === "webpage" ? (
-
-
- {thread.thumbnailUrl ? (
- e.target.src = fallbackImgUrl} />
- ) : null}
-
-
- ) : null}
- {commentMediaInfo?.type === "image" ? (
-
-
- e.target.src = fallbackImgUrl} />
-
-
- ) : null}
- {commentMediaInfo?.type === "video" ? (
-
- e.target.src = fallbackImgUrl} />
-
- ) : null}
- {commentMediaInfo?.type === "audio" ? (
-
- e.target.src = fallbackImgUrl} />
-
- ) : null}
-
- ) : null}
-
- {thread.title ? (
- thread.title.length > 75 ?
-
-
- {thread.title.slice(0, 75) + " (...)"}
-
-
- :
- {thread.title}
- )
- : null}
- {thread.author.displayName
- ? thread.author.displayName.length > 20
- ?
-
- {thread.author.displayName.slice(0, 20) + " (...)"}
-
-
- :
- {thread.author.displayName}
- :
- Anonymous }
-
- (u/
- handleAddressClick(thread.author.shortAddress)}
- >
- {thread.author.shortAddress}
- )
-
- {getDate(thread.timestamp)}
-
-
- c/
- {
- if (e.button === 2) return;
- e.preventDefault();
- setSelectedThreadCid(thread.cid);
- let text = document.getSelection().toString();
- text = text ? `>${text}` : text;
- setSelectedText(text);
- if (isReplyOpen) {
- setReplyQuoteCid(thread.shortCid);
- setTriggerInsertion(Date.now());
- } else {
- setIsReplyOpen(true);
- setSelectedShortCid(thread.shortCid);
- setSelectedParentCid(thread.cid);
- }
- }} title="Reply to this post">{thread.shortCid}
-
- {thread.pinned ? (
- <>
-
-
- >
- ) : null}
- {thread.locked ? (
- <>
-
-
- >
- ) : null}
-
- [
- setSelectedThread(thread.cid)} className="reply-link" >Reply
- ]
-
-
- {
- threadMenuRefs.current[thread.cid] = el;
- }}
- className='post-menu-button'
- rotated={openMenuCid === thread.cid}
- onClick={(event) => {
- event.stopPropagation();
- const rect = threadMenuRefs.current[thread.cid].getBoundingClientRect();
- setMenuPosition({top: rect.top + window.scrollY, left: rect.left});
- setOpenMenuCid(prevCid => (prevCid === thread.cid ? null : thread.cid));
- }}
- >
- â–¶
-
- {createPortal(
- {postMenuCatalogRef.current = el}}
- onClick={(event) => event.stopPropagation()}
- style={{position: "absolute",
- top: menuPosition.top + 7,
- left: menuPosition.left}}>
-
-
- handleOptionClick(thread.cid)}>Hide thread
- {thread.author.shortAddress === account?.author.shortAddress ? (
- <>
- handleAuthorEditClick(thread)}>Edit post
- handleAuthorDeleteClick(thread.cid)}>Delete post
- >
- ) : null}
- {isModerator ? (
- <>
- {thread.author.shortAddress === account?.author.shortAddress ? (
- null
- ) : (
- {
- setModeratingCommentCid(thread.cid)
- setIsModerationOpen(true);
- handleOptionClick(thread.cid);
- setDeletePost(true);
- }}>
- Delete post
-
- )}
- {
- setModeratingCommentCid(thread.cid)
- setIsModerationOpen(true);
- handleOptionClick(thread.cid);
- }}>
- Mod tools
-
- >
- ) : null}
- {(commentMediaInfo && (
- commentMediaInfo.type === 'image' ||
- (commentMediaInfo.type === 'webpage' &&
- commentMediaInfo.thumbnail))) ? (
- {setIsImageSearchOpen(true)}}
- onMouseLeave={() => {setIsImageSearchOpen(false)}}>
- Image search »
-
- handleOptionClick(thread.cid)}>
- Google
-
- handleOptionClick(thread.cid)}>
- Yandex
-
- handleOptionClick(thread.cid)}>
- SauceNAO
-
-
-
- ) : null
- }
-
-
- , document.body
- )}
-
- {thread.replies?.pages?.topAll.comments
- .sort((a, b) => a.timestamp - b.timestamp)
- .map((reply, index) => (
-
{
- backlinkRefs.current[reply.cid] = el;
- }}>
- {}}
- className="quote-link"
- onClick={(event) => handleQuoteClick(reply, null, event)}
- onMouseOver={(event) => {
- event.stopPropagation();
- handleQuoteHover(reply, null, () => {
- const rect = backlinkRefs.current[reply.cid].getBoundingClientRect();
- const distanceToRight = window.innerWidth - rect.right;
- const distanceToTop = rect.top;
- const distanceToBottom = window.innerHeight - rect.bottom;
- let top;
-
- if (distanceToTop < postOnHoverHeight / 2) {
- top = window.scrollY - 5;
- } else if (distanceToBottom < postOnHoverHeight / 2) {
- top = window.scrollY - postOnHoverHeight + window.innerHeight - 10;
- } else {
- top = rect.top + window.scrollY - postOnHoverHeight / 2;
- }
-
- if (distanceToRight < 200) {
- setOutOfViewPosition({
- top,
- right: window.innerWidth - rect.left - 10,
- maxWidth: rect.left - 5
- });
- } else {
- setOutOfViewPosition({
- top,
- left: rect.left + rect.width + 5,
- maxWidth: window.innerWidth - rect.left - rect.width - 5
- });
- }
- setOutOfViewCid(reply.cid);
- });
- }}
- onMouseLeave={() => {
- removeHighlight();
- setOutOfViewCid(null);
- }}>
- c/{reply.shortCid}
-
-
- ))
- }
-
-
- {thread.content ? (
- thread.content?.length > 1000 ?
-
-
-
- (...)
-
-
-
-
- Post too long.
- setSelectedThread(thread.cid)} className="ttl-link">Click here
- to view.
-
-
-
- :
-
-
-
- )
- : null}
-
-
-
-
- {omittedCount > 0 ? (
- <>
- {thread.content ? null : }
-
-
- {omittedCount} post{omittedCount > 1 ? "s" : ""} omitted. Click
- setSelectedThread(thread.cid)} className="ttl-link">here
- to view.
-
-
- >
- ) : null}
-
- {displayedReplies?.map((reply, index) => {
- const replyMediaInfo = getCommentMediaInfo(reply);
- const fallbackImgUrl = "assets/filedeleted-res.gif";
- const shortParentCid = findShortParentCid(reply.parentCid, selectedFeed);
- let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {};
- let signerAddress;
- if (storedSigners[reply.parentCid]) {
- signerAddress = storedSigners[reply.parentCid].address;
- }
- return (
-
-
{'>>'}
-
+
+
+
+
+
-
- {reply.author.displayName
- ? reply.author.displayName.length > 20
- ?
-
- {reply.author.displayName.slice(0, 20) + " (...)"}
-
-
- :
- {reply.author.displayName}
- :
- Anonymous }
-
- handleAddressClick(reply.author.shortAddress)}
- >
- (u/
- {reply.author?.shortAddress ?
- (
-
- {reply.author?.shortAddress}
-
+ {commentMediaInfo?.url ? (
+
+
+ {commentMediaInfo?.type === 'iframe' && (
+
+
+ {(isThumbnailClicked[index] || !commentMediaInfo.thumbnail) && commentMediaInfo.embedUrl ? (
+
) : (
- anonymousMode ? (
-
- {signerAddress?.slice(8, 20)}
-
- ) : (
-
- {account?.author?.shortAddress}
-
- )
- )
- }
- )
-
-
-
-
{getDate(reply.timestamp)}
-
-
- c/
- {reply.shortCid ? (
+ {handleThumbnailClick(index)}}
+ style={{cursor: "pointer"}}
+ onError={(e) => e.target.src = fallbackImgUrl} />
+ )}
+
+
+ )}
+ {commentMediaInfo?.type === "webpage" ? (
+
+
+ {thread.thumbnailUrl ? (
+ e.target.src = fallbackImgUrl} />
+ ) : null}
+
+
+ ) : null}
+ {commentMediaInfo?.type === "image" ? (
+
+
+ e.target.src = fallbackImgUrl} />
+
+
+ ) : null}
+ {commentMediaInfo?.type === "video" ? (
+
+
+ {isThumbnailClicked[index] ? (
+ e.target.src = fallbackImgUrl}
+ />
+ ) : (
+ {handleThumbnailClick(index)}}
+ style={{cursor: "pointer"}}
+ onError={(e) => e.target.src = fallbackImgUrl}
+ />
+ )}
+
+
+ ) : null}
+ {commentMediaInfo?.type === "audio" ? (
+
+ e.target.src = fallbackImgUrl} />
+
+ ) : null}
+
+ ) : null}
+
+ {thread.title ? (
+ thread.title.length > 75 ?
+
+
+ {thread.title.slice(0, 75) + " (...)"}
+
+
+ :
+ {thread.title}
+ )
+ : null}
+ {thread.author.displayName
+ ? thread.author.displayName.length > 20
+ ?
+
+ {thread.author.displayName.slice(0, 20) + " (...)"}
+
+
+ :
+ {thread.author.displayName}
+ :
+ Anonymous }
+
+ (u/
+ handleAddressClick({({ shortAuthorAddress }) => (shortAuthorAddress)} )}
+ >
+ {({ shortAuthorAddress }) => (shortAuthorAddress)}
+ )
+
+ {getDate(thread.timestamp)}
+
+
+ c/
{
if (e.button === 2) return;
@@ -1661,129 +1436,1134 @@ const Board = () => {
text = text ? `>${text}` : text;
setSelectedText(text);
if (isReplyOpen) {
- setReplyQuoteCid(reply.shortCid);
+ setReplyQuoteCid(thread.shortCid);
setTriggerInsertion(Date.now());
} else {
setIsReplyOpen(true);
- setSelectedShortCid(reply.shortCid);
- setSelectedParentCid(reply.cid);
+ setSelectedShortCid(thread.shortCid);
+ setSelectedParentCid(thread.cid);
}
- }} title="Reply to this post">{reply.shortCid}
- ) : (
-
+ }} title="Reply to this post">{thread.shortCid}
+
+ {thread.pinned ? (
+ <>
+
+
+ >
+ ) : null}
+ {thread.locked ? (
+ <>
+
+
+ >
+ ) : null}
+
+ [
+ setSelectedThread(thread.cid)} className="reply-link" >Reply
+ ]
+
+
+ {
+ threadMenuRefs.current[thread.cid] = el;
+ }}
+ className='post-menu-button'
+ rotated={openMenuCid === thread.cid}
+ onClick={(event) => {
+ event.stopPropagation();
+ const rect = threadMenuRefs.current[thread.cid].getBoundingClientRect();
+ setMenuPosition({top: rect.top + window.scrollY, left: rect.left});
+ setOpenMenuCid(prevCid => (prevCid === thread.cid ? null : thread.cid));
+ }}
+ >
+ â–¶
+
+ {createPortal(
+ {postMenuCatalogRef.current = el}}
+ onClick={(event) => event.stopPropagation()}
+ style={{position: "absolute",
+ top: menuPosition.top + 7,
+ left: menuPosition.left}}>
+
+
+ handleOptionClick(thread.cid)}>Hide thread
+ {({ authorAddress }) => (
+ <>
+ {authorAddress === account?.author.address ||
+ authorAddress === account?.signer.address ? (
+ <>
+ handleAuthorEditClick(thread)}>Edit post
+ handleAuthorDeleteClick(thread)}>Delete post
+ >
+ ) : null}
+ {isModerator ? (
+ <>
+ {authorAddress === account?.author.address ||
+ authorAddress === account?.signer.address ? (
+ null
+ ) : (
+ {
+ setModeratingCommentCid(thread.cid)
+ setIsModerationOpen(true);
+ handleOptionClick(thread.cid);
+ setDeletePost(true);
+ }}>
+ Delete post
+
+ )}
+ {
+ setModeratingCommentCid(thread.cid)
+ setIsModerationOpen(true);
+ handleOptionClick(thread.cid);
+ }}>
+ Mod tools
+
+ >
+ ) : null}
+ >
+ )}
+ {(commentMediaInfo && (
+ commentMediaInfo.type === 'image' ||
+ (commentMediaInfo.type === 'webpage' &&
+ commentMediaInfo.thumbnail))) ? (
+ {setIsImageSearchOpen(true)}}
+ onMouseLeave={() => {setIsImageSearchOpen(false)}}>
+ Image search »
+
+ handleOptionClick(thread.cid)}>
+ Google
+
+ handleOptionClick(thread.cid)}>
+ Yandex
+
+ handleOptionClick(thread.cid)}>
+ SauceNAO
+
+
+
+ ) : null
+ }
+
+
+ , document.body
)}
-
- {
- replyMenuRefs.current[reply.cid] = el;
- }}
- className='post-menu-button'
- rotated={openMenuCid === reply.cid}
- onClick={(event) => {
- event.stopPropagation();
- const rect = replyMenuRefs.current[reply.cid].getBoundingClientRect();
- setMenuPosition({top: rect.top + window.scrollY, left: rect.left});
- setOpenMenuCid(prevCid => (prevCid === reply.cid ? null : reply.cid));
- }}
- >
- â–¶
-
- {createPortal(
- {postMenuCatalogRef.current = el}}
- onClick={(event) => event.stopPropagation()}
- style={{position: "absolute",
- top: menuPosition.top + 7,
- left: menuPosition.left}}>
-
-
- handleOptionClick(reply.cid)}>Hide post
- {reply.author.shortAddress === account?.author.shortAddress ? (
- <>
- handleAuthorEditClick(reply)}>Edit post
- handleAuthorDeleteClick(reply.cid)}>Delete post
- >
- ) : null}
- {isModerator ? (
- <>
- {reply.author.shortAddress === account?.author.shortAddress ? (
- null
- ) : (
- {
- setModeratingCommentCid(reply.cid)
- setIsModerationOpen(true);
- handleOptionClick(reply.cid);
- setDeletePost(true);
- }}>
- Delete post
-
- )}
- {
- setModeratingCommentCid(reply.cid)
- setIsModerationOpen(true);
- handleOptionClick(reply.cid);
+
+ {thread.replies?.pages?.topAll.comments
+ .sort((a, b) => a.timestamp - b.timestamp)
+ .map((reply, index) => (
+
{
+ backlinkRefs.current[reply.cid] = el;
}}>
- Mod tools
-
- >
- ) : null}
- {(replyMediaInfo && (
- replyMediaInfo.type === 'image' ||
- (replyMediaInfo.type === 'webpage' &&
- replyMediaInfo.thumbnail))) ? (
-
{setIsImageSearchOpen(true)}}
- onMouseLeave={() => {setIsImageSearchOpen(false)}}>
- Image search »
-
- handleOptionClick(reply.cid)}>
- Google
-
- handleOptionClick(reply.cid)}>
- Yandex
-
- handleOptionClick(reply.cid)}>
- SauceNAO
-
-
-
- ) : null
+
{}}
+ className="quote-link"
+ onClick={(event) => handleQuoteClick(reply, null, event)}
+ onMouseOver={(event) => {
+ event.stopPropagation();
+ handleQuoteHover(reply, null, () => {
+ const rect = backlinkRefs.current[reply.cid].getBoundingClientRect();
+ const distanceToRight = window.innerWidth - rect.right;
+ const distanceToTop = rect.top;
+ const distanceToBottom = window.innerHeight - rect.bottom;
+ let top;
+
+ if (distanceToTop < postOnHoverHeight / 2) {
+ top = window.scrollY - 5;
+ } else if (distanceToBottom < postOnHoverHeight / 2) {
+ top = window.scrollY - postOnHoverHeight + window.innerHeight - 10;
+ } else {
+ top = rect.top + window.scrollY - postOnHoverHeight / 2;
+ }
+
+ if (distanceToRight < 200) {
+ setOutOfViewPosition({
+ top,
+ right: window.innerWidth - rect.left - 10,
+ maxWidth: rect.left - 5
+ });
+ } else {
+ setOutOfViewPosition({
+ top,
+ left: rect.left + rect.width + 5,
+ maxWidth: window.innerWidth - rect.left - rect.width - 5
+ });
+ }
+ setOutOfViewCid(reply.cid);
+ });
+ }}
+ onMouseLeave={() => {
+ removeHighlight();
+ setOutOfViewCid(null);
+ }}>
+ c/{reply.shortCid}
+
+
+ ))
}
-
+
+
+ {thread.content ? (
+ thread.content?.length > 1000 ?
+
+
+
+ (...)
+
+
+
+
+ Post too long.
+ setSelectedThread(thread.cid)} className="ttl-link">Click here
+ to view.
+
+
+
+ :
+
+
+
+ )
+ : null}
+
+
+
+
+ {omittedCount > 0 ? (
+ <>
+ {thread.content ? null : }
+
+
+ {omittedCount} post{omittedCount > 1 ? "s" : ""} omitted. Click
+ setSelectedThread(thread.cid)} className="ttl-link">here
+ to view.
+
+
+ >
+ ) : null}
+
+ {displayedReplies?.map((reply, index) => {
+ const replyMediaInfo = getCommentMediaInfo(reply);
+ const fallbackImgUrl = "assets/filedeleted-res.gif";
+ const shortParentCid = findShortParentCid(reply.parentCid, selectedFeed);
+ let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {};
+ let signerAddress;
+ if (storedSigners[reply.parentCid]) {
+ signerAddress = storedSigners[reply.parentCid].address;
+ }
+ return (
+
+
+
{'>>'}
+
+
+
+ {reply.author.displayName
+ ? reply.author.displayName.length > 20
+ ?
+
+ {reply.author.displayName.slice(0, 20) + " (...)"}
+
+
+ :
+ {reply.author.displayName}
+ :
+ Anonymous }
+
+ handleAddressClick({({ shortAuthorAddress }) => (shortAuthorAddress)} )}
+ >
+ (u/
+ {reply.author?.shortAddress ?
+ (
+
+ {reply.author?.shortAddress}
+
+ ) : (
+ anonymousMode ? (
+
+ {signerAddress?.slice(8, 20)}
+
+ ) : (
+
+ {account?.author?.shortAddress}
+
+ )
+ )
+ }
+ )
+
+
+
+
{getDate(reply.timestamp)}
+
+
+ c/
+ {reply.shortCid ? (
+ {
+ if (e.button === 2) return;
+ e.preventDefault();
+ setSelectedThreadCid(thread.cid);
+ let text = document.getSelection().toString();
+ text = text ? `>${text}` : text;
+ setSelectedText(text);
+ if (isReplyOpen) {
+ setReplyQuoteCid(reply.shortCid);
+ setTriggerInsertion(Date.now());
+ } else {
+ setIsReplyOpen(true);
+ setSelectedShortCid(reply.shortCid);
+ setSelectedParentCid(reply.cid);
+ }
+ }} title="Reply to this post">{reply.shortCid}
+ ) : (
+
+ )}
+
+
{
+ replyMenuRefs.current[reply.cid] = el;
+ }}
+ className='post-menu-button'
+ rotated={openMenuCid === reply.cid}
+ onClick={(event) => {
+ event.stopPropagation();
+ const rect = replyMenuRefs.current[reply.cid].getBoundingClientRect();
+ setMenuPosition({top: rect.top + window.scrollY, left: rect.left});
+ setOpenMenuCid(prevCid => (prevCid === reply.cid ? null : reply.cid));
+ }}
+ >
+ â–¶
+
+ {createPortal(
+
{postMenuCatalogRef.current = el}}
+ onClick={(event) => event.stopPropagation()}
+ style={{position: "absolute",
+ top: menuPosition.top + 7,
+ left: menuPosition.left}}>
+
+
+ handleOptionClick(reply.cid)}>Hide post
+ {({ authorAddress }) => (
+ <>
+ {authorAddress === account?.author.address ||
+ authorAddress === account?.signer.address ? (
+ <>
+ handleAuthorEditClick(reply)}>Edit post
+ handleAuthorDeleteClick(reply)}>Delete post
+ >
+ ) : null}
+ {isModerator ? (
+ <>
+ {authorAddress === account?.author.address ||
+ authorAddress === account?.signer.address ? (
+ null
+ ) : (
+ {
+ setModeratingCommentCid(reply.cid)
+ setIsModerationOpen(true);
+ handleOptionClick(reply.cid);
+ setDeletePost(true);
+ }}>
+ Delete post
+
+ )}
+ {
+ setModeratingCommentCid(reply.cid)
+ setIsModerationOpen(true);
+ handleOptionClick(reply.cid);
+ }}>
+ Mod tools
+
+ >
+ ) : null}
+ >
+ )}
+ {(replyMediaInfo && (
+ replyMediaInfo.type === 'image' ||
+ (replyMediaInfo.type === 'webpage' &&
+ replyMediaInfo.thumbnail))) ? (
+ {setIsImageSearchOpen(true)}}
+ onMouseLeave={() => {setIsImageSearchOpen(false)}}>
+ Image search »
+
+ handleOptionClick(reply.cid)}>
+ Google
+
+ handleOptionClick(reply.cid)}>
+ Yandex
+
+ handleOptionClick(reply.cid)}>
+ SauceNAO
+
+
+
+ ) : null
+ }
+
+
+ , document.body
+ )}
+
+ {reply.replies?.pages?.topAll.comments
+ .sort((a, b) => a.timestamp - b.timestamp)
+ .map((reply, index) => (
+
{
+ backlinkRefs.current[reply.cid] = el;
+ }}>
+ {}} className="quote-link"
+ onClick={(event) => handleQuoteClick(reply, null, event)}
+ onMouseOver={(event) => {
+ event.stopPropagation();
+ handleQuoteHover(reply, null, () => {
+ setOutOfViewCid(reply.cid);
+ const rect = backlinkRefs.current[reply.cid].getBoundingClientRect();
+ const distanceToRight = window.innerWidth - rect.right;
+ const distanceToTop = rect.top;
+ const distanceToBottom = window.innerHeight - rect.bottom;
+ let top;
+
+ if (distanceToTop < postOnHoverHeight / 2) {
+ top = window.scrollY - 5;
+ } else if (distanceToBottom < postOnHoverHeight / 2) {
+ top = window.scrollY - postOnHoverHeight + window.innerHeight - 10;
+ } else {
+ top = rect.top + window.scrollY - postOnHoverHeight / 2;
+ }
+
+ if (distanceToRight < 200) {
+ setOutOfViewPosition({
+ top,
+ right: window.innerWidth - rect.left - 10,
+ maxWidth: rect.left - 5
+ });
+ } else {
+ setOutOfViewPosition({
+ top,
+ left: rect.left + rect.width + 5,
+ maxWidth: window.innerWidth - rect.left - rect.width - 5
+ });
+ }
+ });
+ }}
+ onMouseLeave={() => {
+ removeHighlight();
+ setOutOfViewCid(null);
+ }}>
+ c/{reply.shortCid}
+
+
+ ))
+ }
+
+
+ {replyMediaInfo?.url ? (
+
+
+ {replyMediaInfo?.type === "webpage" ? (
+
+
+ {reply.thumbnailUrl ? (
+ e.target.src = fallbackImgUrl} />
+ ) : null}
+
+
+ ) : null}
+ {replyMediaInfo?.type === "image" ? (
+
+
+ e.target.src = fallbackImgUrl} />
+
+
+ ) : null}
+ {replyMediaInfo?.type === "video" ? (
+
+ e.target.src = fallbackImgUrl} />
+
+ ) : null}
+ {replyMediaInfo?.type === "audio" ? (
+
+ e.target.src = fallbackImgUrl} />
+
+ ) : null}
+
+ ) : null}
+ {reply.content ? (
+ reply.content?.length > 500 ?
+
+
+ {}} key={`r-pm-${index}`} className="quotelink"
+ ref={el => {
+ quoteRefs.current[reply.cid] = el;
+ }}
+ onClick={(event) => handleQuoteClick(reply, shortParentCid, event)}
+ onMouseOver={(event) => {
+ event.stopPropagation();
+ handleQuoteHover(reply, shortParentCid, () => {
+ setOutOfViewCid(reply.parentCid);
+ const rect = quoteRefs.current[reply.cid].getBoundingClientRect();
+ const distanceToRight = window.innerWidth - rect.right;
+ const distanceToTop = rect.top;
+ const distanceToBottom = window.innerHeight - rect.bottom;
+ let top;
+
+ if (distanceToTop < postOnHoverHeight / 2) {
+ top = window.scrollY - 5;
+ } else if (distanceToBottom < postOnHoverHeight / 2) {
+ top = window.scrollY - postOnHoverHeight + window.innerHeight - 10;
+ } else {
+ top = rect.top + window.scrollY - postOnHoverHeight / 2;
+ }
+
+ if (distanceToRight < 200) {
+ setOutOfViewPosition({
+ top,
+ right: window.innerWidth - rect.left - 10,
+ maxWidth: rect.left - 5
+ });
+ } else {
+ setOutOfViewPosition({
+ top,
+ left: rect.left + rect.width + 5,
+ maxWidth: window.innerWidth - rect.left - rect.width - 5
+ });
+ }
+ });
+ }}
+ onMouseLeave={() => {
+ removeHighlight();
+ setOutOfViewCid(null);
+ }}>
+ {`c/${shortParentCid}`}{shortParentCid === thread.shortCid ? " (OP)" : null}
+
+ {
+ postRefs.current[quoteShortParentCid] = ref;
+ }}
+ postQuoteOnClick={(quoteShortParentCid) => {
+ handleQuoteClick(reply, quoteShortParentCid, null)
+ }}
+ postQuoteOnOver={(quoteShortParentCid) => {
+ const quoteParentCid = cidTracker[quoteShortParentCid];
+ if (outOfViewCid !== quoteParentCid) {
+ handleQuoteHover(reply, quoteShortParentCid, () => {
+ setOutOfViewCid(quoteParentCid);
+
+ const rect = postRefs.current[quoteShortParentCid].getBoundingClientRect();
+ const distanceToRight = window.innerWidth - rect.right;
+ const distanceToTop = rect.top;
+ const distanceToBottom = window.innerHeight - rect.bottom;
+ let top;
+
+ if (distanceToTop < postOnHoverHeight / 2) {
+ top = window.scrollY - 5;
+ } else if (distanceToBottom < postOnHoverHeight / 2) {
+ top = window.scrollY - postOnHoverHeight + window.innerHeight - 10;
+ } else {
+ top = rect.top + window.scrollY - postOnHoverHeight / 2;
+ }
+
+ if (distanceToRight < 200) {
+ setOutOfViewPosition({
+ top,
+ right: window.innerWidth - rect.left - 10,
+ maxWidth: rect.left - 5
+ });
+ } else {
+ setOutOfViewPosition({
+ top,
+ left: rect.left + rect.width + 5,
+ maxWidth: window.innerWidth - rect.left - rect.width - 5
+ });
+ }
+ })
+ }}
+ }
+ postQuoteOnLeave={() => {
+ removeHighlight();
+ setOutOfViewCid(null);
+ }}
+ />
+ (...)
+
+
+
+
+ Comment too long.
+ setSelectedThread(thread.cid)} className="ttl-link">Click here
+ to view.
+
+
+ :
+ {}} key={`r-pm-${index}`} className="quotelink"
+ ref={el => {
+ quoteRefs.current[reply.cid] = el;
+ }}
+ onClick={() => handleQuoteClick(reply, shortParentCid, null)}
+ onMouseOver={(event) => {
+ event.stopPropagation();
+ handleQuoteHover(reply, shortParentCid, () => {
+ setOutOfViewCid(reply.parentCid);
+ const rect = quoteRefs.current[reply.cid].getBoundingClientRect();
+ const distanceToRight = window.innerWidth - rect.right;
+ const distanceToTop = rect.top;
+ const distanceToBottom = window.innerHeight - rect.bottom;
+ let top;
+
+ if (distanceToTop < postOnHoverHeight / 2) {
+ top = window.scrollY - 5;
+ } else if (distanceToBottom < postOnHoverHeight / 2) {
+ top = window.scrollY - postOnHoverHeight + window.innerHeight - 10;
+ } else {
+ top = rect.top + window.scrollY - postOnHoverHeight / 2;
+ }
+
+ if (distanceToRight < 200) {
+ setOutOfViewPosition({
+ top,
+ right: window.innerWidth - rect.left - 10,
+ maxWidth: rect.left - 5
+ });
+ } else {
+ setOutOfViewPosition({
+ top,
+ left: rect.left + rect.width + 5,
+ maxWidth: window.innerWidth - rect.left - rect.width - 5
+ });
+ }
+ });
+ }}
+ onMouseLeave={() => {
+ removeHighlight();
+ setOutOfViewCid(null);
+ }}>
+ {`c/${shortParentCid}`}{shortParentCid === thread.shortCid ? " (OP)" : null}
+
+ {
+ postRefs.current[quoteShortParentCid] = ref;
+ }}
+ postQuoteOnClick={(quoteShortParentCid) => {
+ handleQuoteClick(reply, quoteShortParentCid, null)
+ }}
+ postQuoteOnOver={(quoteShortParentCid) => {
+ const quoteParentCid = cidTracker[quoteShortParentCid];
+ if (outOfViewCid !== quoteParentCid) {
+ handleQuoteHover(reply, quoteShortParentCid, () => {
+ setOutOfViewCid(quoteParentCid);
+
+ const rect = postRefs.current[quoteShortParentCid].getBoundingClientRect();
+ const distanceToRight = window.innerWidth - rect.right;
+ const distanceToTop = rect.top;
+ const distanceToBottom = window.innerHeight - rect.bottom;
+ let top;
+
+ if (distanceToTop < postOnHoverHeight / 2) {
+ top = window.scrollY - 5;
+ } else if (distanceToBottom < postOnHoverHeight / 2) {
+ top = window.scrollY - postOnHoverHeight + window.innerHeight - 10;
+ } else {
+ top = rect.top + window.scrollY - postOnHoverHeight / 2;
+ }
+
+ if (distanceToRight < 200) {
+ setOutOfViewPosition({
+ top,
+ right: window.innerWidth - rect.left - 10,
+ maxWidth: rect.left - 5
+ });
+ } else {
+ setOutOfViewPosition({
+ top,
+ left: rect.left + rect.width + 5,
+ maxWidth: window.innerWidth - rect.left - rect.width - 5
+ });
+ }
+ })
+ }}
+ }
+ postQuoteOnLeave={() => {
+ removeHighlight();
+ setOutOfViewCid(null);
+ }}
+ />
+
+
+ )
+ : null}
+
- , document.body
- )}
-
- {reply.replies?.pages?.topAll.comments
- .sort((a, b) => a.timestamp - b.timestamp)
- .map((reply, index) => (
-
+ )
+ })}
+
+
+ {index === 0 && (!subplebbit.rules && !subplebbit.description) ? (
+
+ ) : (
+
+ )}
+
+
+
+
...
+
+ {thread.author.displayName
+ ? thread.author.displayName.length > 20
+ ?
+
+ {thread.author.displayName.slice(0, 20) + " (...)"}
+
+
+ :
+ {thread.author.displayName}
+ :
+ Anonymous }
+
+ handleAddressClick({({ shortAuthorAddress }) => (shortAuthorAddress)} )}
+ >
+ (u/
+
+ {{({ shortAuthorAddress }) => (shortAuthorAddress)} }
+
+ )
+
+
+ {thread.pinned ? (
+
+ ) : null}
+ {thread.locked ? (
+
+ ) : null}
+
+
+ {thread.title ? (
+ thread.title.length > 30 ?
+
+
+ {thread.title.slice(0, 30) + " (...)"}
+
+
+ :
+ {thread.title}
+ )
+ : null}
+
+
+ {getDate(thread.timestamp)}
+
+ c/
+ {
+ if (e.button === 2) return;
+ e.preventDefault();
+ setSelectedThreadCid(thread.cid);
+ let text = document.getSelection().toString();
+ text = text ? `>${text}` : text;
+ setSelectedText(text);
+ if (isReplyOpen) {
+ setReplyQuoteCid(thread.shortCid);
+ setTriggerInsertion(Date.now());
+ } else {
+ setIsReplyOpen(true);
+ setSelectedShortCid(thread.shortCid);
+ setSelectedParentCid(thread.cid);
+ }
+ }} title="Reply to this post">{thread.shortCid}
+
+
+
+ {thread.link ? (
+
+ {commentMediaInfo?.type === 'iframe' && (
+
+
+ {(isMobileThumbnailClicked[index] || !commentMediaInfo.thumbnail) && commentMediaInfo.embedUrl ? (
+
+
+
+ ) : (
+ {handleThumbnailClick(index, true)}}
+ style={{cursor: "pointer"}}
+ onError={(e) => e.target.src = fallbackImgUrl} />
+ )}
+ {commentMediaInfo?.type === "video" || "iframe" ? (
+ isMobileThumbnailClicked[index] ? (
+
+ {handleThumbnailClick(index, true)}}
+ >Close
+
+ ) : (
+ video
+ )) : video
}
+
+
+ )}
+ {commentMediaInfo?.url ? (
+ commentMediaInfo.type === "webpage" ? (
+
+
+ {thread.thumbnailUrl ? (
+ e.target.src = fallbackImgUrl} />
+ ) : null}
+ {commentMediaInfo?.type}
+
+
+ ) : commentMediaInfo.type === "image" ? (
+
+
+ e.target.src = fallbackImgUrl} />
+ {commentMediaInfo?.type}
+
+
+ ) : commentMediaInfo.type === "video" ? (
+
+ {isMobileThumbnailClicked[index] ? (
+ e.target.src = fallbackImgUrl} />
+ ) : (
+ {handleThumbnailClick(index, true)}}
+ style={{cursor: "pointer"}}
+ id="video-thumbnail-mobile"
+ onError={(e) => e.target.src = fallbackImgUrl}
+ />
+ )}
+ {commentMediaInfo?.type === "video" || "iframe" ? (
+ isMobileThumbnailClicked[index] ? (
+
+ {handleThumbnailClick(index, true)}}
+ >Close
+
+ ) : (
+ video
+ )) : video
}
+
+ ) : commentMediaInfo.type === "audio" ? (
+
+ e.target.src = fallbackImgUrl} />
+ {commentMediaInfo?.type}
+
+ ) : null
+ ) : null}
+
+ ) : null}
+ {thread.content ? (
+ thread.content?.length > 500 ?
+
+
+
+ (...)
+
+
+
+
+ Post too long.
+ setSelectedThread(thread.cid)} className="ttl-link">Click here
+ to view.
+
+
+ :
+
+
+
+ )
+ : null}
+
+
+ {
+ (thread.replyCount + pendingReplyCounts[thread.cid]) === 0 ?
+ ("No replies")
+ : (thread.replyCount + pendingReplyCounts[thread.cid]) === 1 ?
+ ("1 reply")
+ : (thread.replyCount + pendingReplyCounts[thread.cid]) > 1 ?
+ ((thread.replyCount + pendingReplyCounts[thread.cid]) + " replies")
+ : null
+ }
+ {setSelectedThread(thread.cid); window.scrollTo(0, 0);}}
+ className="button-mobile" >View Thread
+
+
+ {displayedReplies?.map((reply, index) => {
+ const replyMediaInfo = getCommentMediaInfo(reply);
+ const shortParentCid = findShortParentCid(reply.parentCid, selectedFeed);
+ let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {};
+ let signerAddress;
+ if (storedSigners[selectedThreadCidRef]) {
+ signerAddress = storedSigners[selectedThreadCidRef].address;
+ }
+ return (
+
+
+
+
...
+
+ {reply.author.displayName
+ ? reply.author.displayName.length > 20
+ ?
+
+ {reply.author.displayName.slice(0, 20) + " (...)"}
+
+
+ :
+ {reply.author.displayName}
+ :
+ Anonymous }
+
+ handleAddressClick({({ shortAuthorAddress }) => (shortAuthorAddress)} )}
+ >
+ (u/
+ {reply.author?.shortAddress ?
+ (
+
+ {reply.author?.shortAddress}
+
+ ) : (
+ anonymousMode ? (
+
+ {signerAddress?.slice(8, 20)}
+
+ ) : (
+
+ {account?.author?.shortAddress}
+
+ )
+ )
+ }
+ )
+
+
+
+
+ {getDate(reply.timestamp)}
+ c/
+ {reply.shortCid ? (
+ {
+ if (e.button === 2) return;
+ e.preventDefault();
+ setSelectedThreadCid(thread.cid);
+ let text = document.getSelection().toString();
+ text = text ? `>${text}` : text;
+ setSelectedText(text);
+ if (isReplyOpen) {
+ setReplyQuoteCid(reply.shortCid);
+ setTriggerInsertion(Date.now());
+ } else {
+ setIsReplyOpen(true);
+ setSelectedShortCid(reply.shortCid);
+ setSelectedParentCid(reply.cid);
+ }
+ }} title="Reply to this post">{reply.shortCid}
+
+ ) : (
+
+ )}
+
+
+ {reply.link ? (
+
+ {replyMediaInfo?.url ? (
+ replyMediaInfo.type === "webpage" ? (
+
+
+ {reply.thumbnailUrl ? (
+ e.target.src = fallbackImgUrl} />
+ ) : null}
+ {replyMediaInfo.type}
+
+
+ ) : replyMediaInfo.type === "image" ? (
+
+
+ e.target.src = fallbackImgUrl} />
+ {replyMediaInfo.type}
+
+
+ ) : replyMediaInfo.type === "video" ? (
+
+ e.target.src = fallbackImgUrl} />
+ {replyMediaInfo.type}
+
+ ) : replyMediaInfo.type === "audio" ? (
+
+ e.target.src = fallbackImgUrl} />
+ {replyMediaInfo.type}
+
+ ) : null
+ ) : null}
+
+ ) : null}
+ {reply.content ? (
+ reply.content?.length > 500 ?
+
+
+ {}} key={`mob-r-pm-${index}`} className="quotelink"
ref={el => {
- backlinkRefs.current[reply.cid] = el;
- }}>
- {}} className="quote-link"
- onClick={(event) => handleQuoteClick(reply, null, event)}
+ quoteRefsMobile.current[reply.cid] = el;
+ }}
+ onClick={(event) => handleQuoteClick(reply, shortParentCid, event)}
onMouseOver={(event) => {
event.stopPropagation();
- handleQuoteHover(reply, null, () => {
- setOutOfViewCid(reply.cid);
- const rect = backlinkRefs.current[reply.cid].getBoundingClientRect();
+ handleQuoteHover(reply, shortParentCid, () => {
+ setOutOfViewCid(reply.parentCid);
+ const rect = quoteRefsMobile.current[reply.cid].getBoundingClientRect();
const distanceToRight = window.innerWidth - rect.right;
const distanceToTop = rect.top;
const distanceToBottom = window.innerHeight - rect.bottom;
@@ -1816,86 +2596,28 @@ const Board = () => {
removeHighlight();
setOutOfViewCid(null);
}}>
- c/{reply.shortCid}
-
-
- ))
- }
-
-
- {replyMediaInfo?.url ? (
-
-
- {replyMediaInfo?.type === "webpage" ? (
-
-
- {reply.thumbnailUrl ? (
- e.target.src = fallbackImgUrl} />
- ) : null}
-
-
- ) : null}
- {replyMediaInfo?.type === "image" ? (
-
-
- e.target.src = fallbackImgUrl} />
-
-
- ) : null}
- {replyMediaInfo?.type === "video" ? (
-
- e.target.src = fallbackImgUrl} />
-
- ) : null}
- {replyMediaInfo?.type === "audio" ? (
-
- e.target.src = fallbackImgUrl} />
-
- ) : null}
-
- ) : null}
- {reply.content ? (
- reply.content?.length > 500 ?
-
-
- {}} key={`r-pm-${index}`} className="quotelink"
- ref={el => {
- quoteRefs.current[reply.cid] = el;
- }}
- onClick={(event) => handleQuoteClick(reply, shortParentCid, event)}
- onMouseOver={(event) => {
- event.stopPropagation();
- handleQuoteHover(reply, shortParentCid, () => {
- setOutOfViewCid(reply.parentCid);
- const rect = quoteRefs.current[reply.cid].getBoundingClientRect();
+ {`c/${shortParentCid}`}{shortParentCid === thread.shortCid ? " (OP)" : null}
+
+ {
+ postRefs.current[quoteShortParentCid] = ref;
+ }}
+ postQuoteOnClick={(quoteShortParentCid) => {
+ handleQuoteClick(reply, quoteShortParentCid, null)
+ }}
+ postQuoteOnOver={(quoteShortParentCid) => {
+ const quoteParentCid = cidTracker[quoteShortParentCid];
+ if (outOfViewCid !== quoteParentCid) {
+ handleQuoteHover(reply, quoteShortParentCid, () => {
+ setOutOfViewCid(quoteParentCid);
+
+ const rect = postRefs.current[quoteShortParentCid].getBoundingClientRect();
const distanceToRight = window.innerWidth - rect.right;
const distanceToTop = rect.top;
const distanceToBottom = window.innerHeight - rect.bottom;
let top;
-
+
if (distanceToTop < postOnHoverHeight / 2) {
top = window.scrollY - 5;
} else if (distanceToBottom < postOnHoverHeight / 2) {
@@ -1917,16 +2639,75 @@ const Board = () => {
maxWidth: window.innerWidth - rect.left - rect.width - 5
});
}
+ })
+ }}
+ }
+ postQuoteOnLeave={() => {
+ removeHighlight();
+ setOutOfViewCid(null);
+ }}
+ />
+ (...)
+
+
+
+
+ Comment too long.
+ setSelectedThread(thread.cid)} className="ttl-link">Click here
+ to view.
+
+
+ :
+ {}} key={`mob-r-pm-${index}`} className="quotelink"
+ ref={el => {
+ quoteRefsMobile.current[reply.cid] = el;
+ }}
+ onClick={(event) => handleQuoteClick(reply, shortParentCid, event)}
+ onMouseOver={(event) => {
+ event.stopPropagation();
+ handleQuoteHover(reply, shortParentCid, () => {
+ setOutOfViewCid(reply.parentCid);
+ const rect = quoteRefsMobile.current[reply.cid].getBoundingClientRect();
+ const distanceToRight = window.innerWidth - rect.right;
+ const distanceToTop = rect.top;
+ const distanceToBottom = window.innerHeight - rect.bottom;
+ let top;
+
+ if (distanceToTop < postOnHoverHeight / 2) {
+ top = window.scrollY - 5;
+ } else if (distanceToBottom < postOnHoverHeight / 2) {
+ top = window.scrollY - postOnHoverHeight + window.innerHeight - 10;
+ } else {
+ top = rect.top + window.scrollY - postOnHoverHeight / 2;
+ }
+
+ if (distanceToRight < 200) {
+ setOutOfViewPosition({
+ top,
+ right: window.innerWidth - rect.left - 10,
+ maxWidth: rect.left - 5
});
- }}
- onMouseLeave={() => {
- removeHighlight();
- setOutOfViewCid(null);
- }}>
- {`c/${shortParentCid}`}{shortParentCid === thread.shortCid ? " (OP)" : null}
+ } else {
+ setOutOfViewPosition({
+ top,
+ left: rect.left + rect.width + 5,
+ maxWidth: window.innerWidth - rect.left - rect.width - 5
+ });
+ }
+ });
+ }}
+ onMouseLeave={() => {
+ removeHighlight();
+ setOutOfViewCid(null);
+ }}>
+ {`c/${shortParentCid}`}{shortParentCid === thread.shortCid ? " (OP)" : null}
- {
postRefs.current[quoteShortParentCid] = ref;
}}
@@ -1974,31 +2755,30 @@ const Board = () => {
setOutOfViewCid(null);
}}
/>
- (...)
-
-
-
-
- Comment too long.
- setSelectedThread(thread.cid)} className="ttl-link">Click here
- to view.
-
-
- :
- {}} key={`r-pm-${index}`} className="quotelink"
- ref={el => {
- quoteRefs.current[reply.cid] = el;
- }}
- onClick={() => handleQuoteClick(reply, shortParentCid, null)}
- onMouseOver={(event) => {
- event.stopPropagation();
- handleQuoteHover(reply, shortParentCid, () => {
- setOutOfViewCid(reply.parentCid);
- const rect = quoteRefs.current[reply.cid].getBoundingClientRect();
+ )
+ : null}
+ {reply.replyCount > 0 ? (
+
+ {reply.replies?.pages?.topAll.comments
+ .sort((a, b) => a.timestamp - b.timestamp)
+ .map((reply, index) => (
+
{
+ backlinkRefsMobile.current[reply.cid] = el;
+ }}>
+
{}}
+ onClick={(event) => handleQuoteClick(reply, reply.shortCid, event)}
+ onMouseOver={(event) => {
+ event.stopPropagation();
+ handleQuoteHover(reply, reply.shortCid, () => {
+ setOutOfViewCid(reply.cid)
+ const rect = backlinkRefsMobile.current[reply.cid].getBoundingClientRect();
const distanceToRight = window.innerWidth - rect.right;
const distanceToTop = rect.top;
const distanceToBottom = window.innerHeight - rect.bottom;
@@ -2025,656 +2805,24 @@ const Board = () => {
maxWidth: window.innerWidth - rect.left - rect.width - 5
});
}
- });
- }}
- onMouseLeave={() => {
- removeHighlight();
- setOutOfViewCid(null);
- }}>
- {`c/${shortParentCid}`}{shortParentCid === thread.shortCid ? " (OP)" : null}
-
-
{
- postRefs.current[quoteShortParentCid] = ref;
- }}
- postQuoteOnClick={(quoteShortParentCid) => {
- handleQuoteClick(reply, quoteShortParentCid, null)
- }}
- postQuoteOnOver={(quoteShortParentCid) => {
- const quoteParentCid = cidTracker[quoteShortParentCid];
- if (outOfViewCid !== quoteParentCid) {
- handleQuoteHover(reply, quoteShortParentCid, () => {
- setOutOfViewCid(quoteParentCid);
-
- const rect = postRefs.current[quoteShortParentCid].getBoundingClientRect();
- const distanceToRight = window.innerWidth - rect.right;
- const distanceToTop = rect.top;
- const distanceToBottom = window.innerHeight - rect.bottom;
- let top;
-
- if (distanceToTop < postOnHoverHeight / 2) {
- top = window.scrollY - 5;
- } else if (distanceToBottom < postOnHoverHeight / 2) {
- top = window.scrollY - postOnHoverHeight + window.innerHeight - 10;
- } else {
- top = rect.top + window.scrollY - postOnHoverHeight / 2;
- }
-
- if (distanceToRight < 200) {
- setOutOfViewPosition({
- top,
- right: window.innerWidth - rect.left - 10,
- maxWidth: rect.left - 5
- });
- } else {
- setOutOfViewPosition({
- top,
- left: rect.left + rect.width + 5,
- maxWidth: window.innerWidth - rect.left - rect.width - 5
- });
- }
- })
- }}
- }
- postQuoteOnLeave={() => {
- removeHighlight();
- setOutOfViewCid(null);
- }}
- />
-
-
- )
- : null}
-
-
- )
- })}
-
-
- {index === 0 && (!subplebbit.rules && !subplebbit.description) ? (
-
- ) : (
-
- )}
-
-
-
-
...
-
- {thread.author.displayName
- ? thread.author.displayName.length > 20
- ?
-
- {thread.author.displayName.slice(0, 20) + " (...)"}
-
-
- :
- {thread.author.displayName}
- :
- Anonymous }
-
- handleAddressClick(thread.author.shortAddress)}
- >
- (u/
-
- {thread.author.shortAddress}
-
- )
-
-
- {thread.pinned ? (
-
- ) : null}
- {thread.locked ? (
-
- ) : null}
-
-
- {thread.title ? (
- thread.title.length > 30 ?
-
-
- {thread.title.slice(0, 30) + " (...)"}
-
-
- :
- {thread.title}
- )
- : null}
-
-
- {getDate(thread.timestamp)}
-
- c/
- {
- if (e.button === 2) return;
- e.preventDefault();
- setSelectedThreadCid(thread.cid);
- let text = document.getSelection().toString();
- text = text ? `>${text}` : text;
- setSelectedText(text);
- if (isReplyOpen) {
- setReplyQuoteCid(thread.shortCid);
- setTriggerInsertion(Date.now());
- } else {
- setIsReplyOpen(true);
- setSelectedShortCid(thread.shortCid);
- setSelectedParentCid(thread.cid);
- }
- }} title="Reply to this post">{thread.shortCid}
-
-
-
- {thread.link ? (
-
- {commentMediaInfo?.url ? (
- commentMediaInfo.type === "webpage" ? (
-
-
- {thread.thumbnailUrl ? (
- e.target.src = fallbackImgUrl} />
- ) : null}
- {commentMediaInfo?.type}
-
-
- ) : commentMediaInfo.type === "image" ? (
-
-
- e.target.src = fallbackImgUrl} />
- {commentMediaInfo?.type}
-
-
- ) : commentMediaInfo.type === "video" ? (
-
- e.target.src = fallbackImgUrl} />
- {commentMediaInfo?.type}
-
- ) : commentMediaInfo.type === "audio" ? (
-
- e.target.src = fallbackImgUrl} />
- {commentMediaInfo?.type}
-
- ) : null
- ) : null}
-
- ) : null}
- {thread.content ? (
- thread.content?.length > 500 ?
-
-
-
- (...)
-
-
-
-
- Post too long.
- setSelectedThread(thread.cid)} className="ttl-link">Click here
- to view.
-
-
- :
-
-
-
- )
- : null}
-
-
- {
- (thread.replyCount + pendingReplyCounts[thread.cid]) === 0 ?
- ("No replies")
- : (thread.replyCount + pendingReplyCounts[thread.cid]) === 1 ?
- ("1 reply")
- : (thread.replyCount + pendingReplyCounts[thread.cid]) > 1 ?
- ((thread.replyCount + pendingReplyCounts[thread.cid]) + " replies")
- : null
- }
- {setSelectedThread(thread.cid); window.scrollTo(0, 0);}}
- className="button-mobile" >View Thread
-
-
- {displayedReplies?.map((reply, index) => {
- const replyMediaInfo = getCommentMediaInfo(reply);
- const shortParentCid = findShortParentCid(reply.parentCid, selectedFeed);
- let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {};
- let signerAddress;
- if (storedSigners[selectedThreadCidRef]) {
- signerAddress = storedSigners[selectedThreadCidRef].address;
- }
- return (
-
-
-
-
...
-
- {reply.author.displayName
- ? reply.author.displayName.length > 20
- ?
-
- {reply.author.displayName.slice(0, 20) + " (...)"}
-
-
- :
- {reply.author.displayName}
- :
- Anonymous }
-
- handleAddressClick(reply.author.shortAddress)}
- >
- (u/
- {reply.author?.shortAddress ?
- (
-
- {reply.author?.shortAddress}
-
- ) : (
- anonymousMode ? (
-
- {signerAddress?.slice(8, 20)}
-
- ) : (
-
- {account?.author?.shortAddress}
-
- )
- )
- }
- )
-
-
-
-
- {getDate(reply.timestamp)}
- c/
- {reply.shortCid ? (
- {
- if (e.button === 2) return;
- e.preventDefault();
- setSelectedThreadCid(thread.cid);
- let text = document.getSelection().toString();
- text = text ? `>${text}` : text;
- setSelectedText(text);
- if (isReplyOpen) {
- setReplyQuoteCid(reply.shortCid);
- setTriggerInsertion(Date.now());
- } else {
- setIsReplyOpen(true);
- setSelectedShortCid(reply.shortCid);
- setSelectedParentCid(reply.cid);
- }
- }} title="Reply to this post">{reply.shortCid}
-
- ) : (
-
- )}
-
-
- {reply.link ? (
-
- {replyMediaInfo?.url ? (
- replyMediaInfo.type === "webpage" ? (
-
-
- {reply.thumbnailUrl ? (
- e.target.src = fallbackImgUrl} />
- ) : null}
- {replyMediaInfo.type}
-
+ });
+ }}
+ onMouseLeave={() => {
+ removeHighlight();
+ setOutOfViewCid(null);
+ }}
+ className="quote-link">
+ c/{reply.shortCid}
+
- ) : replyMediaInfo.type === "image" ? (
-
-
- e.target.src = fallbackImgUrl} />
- {replyMediaInfo.type}
-
-
- ) : replyMediaInfo.type === "video" ? (
-
- e.target.src = fallbackImgUrl} />
- {replyMediaInfo.type}
-
- ) : replyMediaInfo.type === "audio" ? (
-
- e.target.src = fallbackImgUrl} />
- {replyMediaInfo.type}
-
- ) : null
+ ))}
+
) : null}
- ) : null}
- {reply.content ? (
- reply.content?.length > 500 ?
-
-
- {}} key={`mob-r-pm-${index}`} className="quotelink"
- ref={el => {
- quoteRefsMobile.current[reply.cid] = el;
- }}
- onClick={(event) => handleQuoteClick(reply, shortParentCid, event)}
- onMouseOver={(event) => {
- event.stopPropagation();
- handleQuoteHover(reply, shortParentCid, () => {
- setOutOfViewCid(reply.parentCid);
- const rect = quoteRefsMobile.current[reply.cid].getBoundingClientRect();
- const distanceToRight = window.innerWidth - rect.right;
- const distanceToTop = rect.top;
- const distanceToBottom = window.innerHeight - rect.bottom;
- let top;
-
- if (distanceToTop < postOnHoverHeight / 2) {
- top = window.scrollY - 5;
- } else if (distanceToBottom < postOnHoverHeight / 2) {
- top = window.scrollY - postOnHoverHeight + window.innerHeight - 10;
- } else {
- top = rect.top + window.scrollY - postOnHoverHeight / 2;
- }
-
- if (distanceToRight < 200) {
- setOutOfViewPosition({
- top,
- right: window.innerWidth - rect.left - 10,
- maxWidth: rect.left - 5
- });
- } else {
- setOutOfViewPosition({
- top,
- left: rect.left + rect.width + 5,
- maxWidth: window.innerWidth - rect.left - rect.width - 5
- });
- }
- });
- }}
- onMouseLeave={() => {
- removeHighlight();
- setOutOfViewCid(null);
- }}>
- {`c/${shortParentCid}`}{shortParentCid === thread.shortCid ? " (OP)" : null}
-
- {
- postRefs.current[quoteShortParentCid] = ref;
- }}
- postQuoteOnClick={(quoteShortParentCid) => {
- handleQuoteClick(reply, quoteShortParentCid, null)
- }}
- postQuoteOnOver={(quoteShortParentCid) => {
- const quoteParentCid = cidTracker[quoteShortParentCid];
- if (outOfViewCid !== quoteParentCid) {
- handleQuoteHover(reply, quoteShortParentCid, () => {
- setOutOfViewCid(quoteParentCid);
-
- const rect = postRefs.current[quoteShortParentCid].getBoundingClientRect();
- const distanceToRight = window.innerWidth - rect.right;
- const distanceToTop = rect.top;
- const distanceToBottom = window.innerHeight - rect.bottom;
- let top;
-
- if (distanceToTop < postOnHoverHeight / 2) {
- top = window.scrollY - 5;
- } else if (distanceToBottom < postOnHoverHeight / 2) {
- top = window.scrollY - postOnHoverHeight + window.innerHeight - 10;
- } else {
- top = rect.top + window.scrollY - postOnHoverHeight / 2;
- }
-
- if (distanceToRight < 200) {
- setOutOfViewPosition({
- top,
- right: window.innerWidth - rect.left - 10,
- maxWidth: rect.left - 5
- });
- } else {
- setOutOfViewPosition({
- top,
- left: rect.left + rect.width + 5,
- maxWidth: window.innerWidth - rect.left - rect.width - 5
- });
- }
- })
- }}
- }
- postQuoteOnLeave={() => {
- removeHighlight();
- setOutOfViewCid(null);
- }}
- />
- (...)
-
-
-
-
- Comment too long.
- setSelectedThread(thread.cid)} className="ttl-link">Click here
- to view.
-
-
- :
- {}} key={`mob-r-pm-${index}`} className="quotelink"
- ref={el => {
- quoteRefsMobile.current[reply.cid] = el;
- }}
- onClick={(event) => handleQuoteClick(reply, shortParentCid, event)}
- onMouseOver={(event) => {
- event.stopPropagation();
- handleQuoteHover(reply, shortParentCid, () => {
- setOutOfViewCid(reply.parentCid);
- const rect = quoteRefsMobile.current[reply.cid].getBoundingClientRect();
- const distanceToRight = window.innerWidth - rect.right;
- const distanceToTop = rect.top;
- const distanceToBottom = window.innerHeight - rect.bottom;
- let top;
-
- if (distanceToTop < postOnHoverHeight / 2) {
- top = window.scrollY - 5;
- } else if (distanceToBottom < postOnHoverHeight / 2) {
- top = window.scrollY - postOnHoverHeight + window.innerHeight - 10;
- } else {
- top = rect.top + window.scrollY - postOnHoverHeight / 2;
- }
-
- if (distanceToRight < 200) {
- setOutOfViewPosition({
- top,
- right: window.innerWidth - rect.left - 10,
- maxWidth: rect.left - 5
- });
- } else {
- setOutOfViewPosition({
- top,
- left: rect.left + rect.width + 5,
- maxWidth: window.innerWidth - rect.left - rect.width - 5
- });
- }
- });
- }}
- onMouseLeave={() => {
- removeHighlight();
- setOutOfViewCid(null);
- }}>
- {`c/${shortParentCid}`}{shortParentCid === thread.shortCid ? " (OP)" : null}
-
- {
- postRefs.current[quoteShortParentCid] = ref;
- }}
- postQuoteOnClick={(quoteShortParentCid) => {
- handleQuoteClick(reply, quoteShortParentCid, null)
- }}
- postQuoteOnOver={(quoteShortParentCid) => {
- const quoteParentCid = cidTracker[quoteShortParentCid];
- if (outOfViewCid !== quoteParentCid) {
- handleQuoteHover(reply, quoteShortParentCid, () => {
- setOutOfViewCid(quoteParentCid);
-
- const rect = postRefs.current[quoteShortParentCid].getBoundingClientRect();
- const distanceToRight = window.innerWidth - rect.right;
- const distanceToTop = rect.top;
- const distanceToBottom = window.innerHeight - rect.bottom;
- let top;
-
- if (distanceToTop < postOnHoverHeight / 2) {
- top = window.scrollY - 5;
- } else if (distanceToBottom < postOnHoverHeight / 2) {
- top = window.scrollY - postOnHoverHeight + window.innerHeight - 10;
- } else {
- top = rect.top + window.scrollY - postOnHoverHeight / 2;
- }
-
- if (distanceToRight < 200) {
- setOutOfViewPosition({
- top,
- right: window.innerWidth - rect.left - 10,
- maxWidth: rect.left - 5
- });
- } else {
- setOutOfViewPosition({
- top,
- left: rect.left + rect.width + 5,
- maxWidth: window.innerWidth - rect.left - rect.width - 5
- });
- }
- })
- }}
- }
- postQuoteOnLeave={() => {
- removeHighlight();
- setOutOfViewCid(null);
- }}
- />
-
-
- )
- : null}
- {reply.replyCount > 0 ? (
-
- {reply.replies?.pages?.topAll.comments
- .sort((a, b) => a.timestamp - b.timestamp)
- .map((reply, index) => (
-
{
- backlinkRefsMobile.current[reply.cid] = el;
- }}>
- {}}
- onClick={(event) => handleQuoteClick(reply, reply.shortCid, event)}
- onMouseOver={(event) => {
- event.stopPropagation();
- handleQuoteHover(reply, reply.shortCid, () => {
- setOutOfViewCid(reply.cid)
- const rect = backlinkRefsMobile.current[reply.cid].getBoundingClientRect();
- const distanceToRight = window.innerWidth - rect.right;
- const distanceToTop = rect.top;
- const distanceToBottom = window.innerHeight - rect.bottom;
- let top;
-
- if (distanceToTop < postOnHoverHeight / 2) {
- top = window.scrollY - 5;
- } else if (distanceToBottom < postOnHoverHeight / 2) {
- top = window.scrollY - postOnHoverHeight + window.innerHeight - 10;
- } else {
- top = rect.top + window.scrollY - postOnHoverHeight / 2;
- }
-
- if (distanceToRight < 200) {
- setOutOfViewPosition({
- top,
- right: window.innerWidth - rect.left - 10,
- maxWidth: rect.left - 5
- });
- } else {
- setOutOfViewPosition({
- top,
- left: rect.left + rect.width + 5,
- maxWidth: window.innerWidth - rect.left - rect.width - 5
- });
- }
- });
- }}
- onMouseLeave={() => {
- removeHighlight();
- setOutOfViewCid(null);
- }}
- className="quote-link">
- c/{reply.shortCid}
-
-
- ))}
-
- ) : null}
-
+
+ )})}
- )})}
-
-
+
);
}}
endReached={tryLoadMore}
diff --git a/src/components/views/Catalog.jsx b/src/components/views/Catalog.jsx
index 40b175cf..e5238b1d 100755
--- a/src/components/views/Catalog.jsx
+++ b/src/components/views/Catalog.jsx
@@ -13,6 +13,7 @@ import { TopBar, Footer, AuthorDeleteAlert } from '../styled/views/Thread.styled
import CatalogLoader from '../CatalogLoader';
import EditModal from '../modals/EditModal';
import ImageBanner from '../ImageBanner';
+import VerifiedAuthor from '../VerifiedAuthor';
import ModerationModal from '../modals/ModerationModal';
import OfflineIndicator from '../OfflineIndicator';
import SettingsModal from '../modals/SettingsModal';
@@ -195,7 +196,8 @@ const Catalog = () => {
}
}
else if (challengeVerification.challengeSuccess === false) {
- setNewErrorMessage('Challenge Failed', {reason: challengeVerification.reason, errors: challengeVerification.errors});
+ setNewErrorMessage(`Challenge Failed, reason: ${challengeVerification.reason}. Errors: ${challengeVerification.errors}`);
+ console.log('challenge failed', challengeVerification);
}
};
@@ -208,7 +210,7 @@ const Catalog = () => {
challengeAnswers = await getChallengeAnswersFromUser(challenges)
}
catch (error) {
- setNewErrorMessage(error);
+ setNewErrorMessage(error.message); console.log(error);
}
if (challengeAnswers) {
await comment.publishChallengeAnswers(challengeAnswers)
@@ -229,7 +231,7 @@ const Catalog = () => {
onChallenge,
onChallengeVerification,
onError: (error) => {
- setNewErrorMessage(error);
+ setNewErrorMessage(error.message); console.log(error);
},
});
@@ -381,7 +383,7 @@ const Catalog = () => {
onChallenge,
onChallengeVerification,
onError: (error) => {
- setNewErrorMessage(error);
+ setNewErrorMessage(error.message); console.log(error);
},
});
@@ -404,9 +406,10 @@ const Catalog = () => {
onClick={() => {
setIsAuthorDelete(true);
setIsAuthorEdit(false);
- setCommentCid(comment.cid);
setPublishCommentEditOptions(prevOptions => ({
...prevOptions,
+ commentCid: comment.cid,
+ subplebbitAddress: comment.subplebbitAddress,
deleted: true,
}));
setTriggerPublishCommentEdit(true);
@@ -485,7 +488,7 @@ const Catalog = () => {
await unsubscribe(selectedAddress);
}
} catch (error) {
- setNewErrorMessage(error);
+ setNewErrorMessage(error.message); console.log(error);
}
};
@@ -663,7 +666,7 @@ const Catalog = () => {
{window.scrollTo(0, 0)}}>Return
]
- {feed.length > 0 ? (
+ {feed ? (
<>
[
@@ -697,7 +700,7 @@ const Catalog = () => {
{subplebbit?.state === "failed" ? (
null
) : (
- feed.length > 0 ? (
+ feed ? (
{
>
handleOptionClick(thread.cid)}>Hide thread
- {thread.author.shortAddress === account?.author.shortAddress ? (
+ {({ authorAddress }) => (
<>
- handleAuthorEditClick(thread)}>Edit post
- handleAuthorDeleteClick(thread)}>Delete post
+ {authorAddress === account?.author.address ||
+ authorAddress === account?.signer.address ? (
+ <>
+ handleAuthorEditClick(thread)}>Edit post
+ handleAuthorDeleteClick(thread)}>Delete post
+ >
+ ) : null}
+ {isModerator ? (
+ <>
+ {authorAddress === account?.author.address ||
+ authorAddress === account?.signer.address ? (
+ null
+ ) : (
+ {
+ setModeratingCommentCid(thread.cid)
+ setIsModerationOpen(true);
+ handleOptionClick(thread.cid);
+ setDeletePost(true);
+ }}>
+ Delete post
+
+ )}
+ {
+ setModeratingCommentCid(thread.cid)
+ setIsModerationOpen(true);
+ handleOptionClick(thread.cid);
+ }}>
+ Mod tools
+
+ >
+ ) : null}
>
- ) : null}
- {isModerator ? (
- <>
- {thread.author.shortAddress === account?.author.shortAddress ? (
- null
- ) : (
- {
- setModeratingCommentCid(thread.cid)
- setIsModerationOpen(true);
- handleOptionClick(thread.cid);
- setDeletePost(true);
- }}>
- Delete post
-
- )}
- {
- setModeratingCommentCid(thread.cid)
- setIsModerationOpen(true);
- handleOptionClick(thread.cid);
- }}>
- Mod tools
-
- >
- ) : null}
+ )}
{(commentMediaInfo && (
commentMediaInfo.type === 'image' ||
(commentMediaInfo.type === 'webpage' &&
diff --git a/src/components/views/Pending.jsx b/src/components/views/Pending.jsx
index 51ab0d2f..f2f4b07f 100755
--- a/src/components/views/Pending.jsx
+++ b/src/components/views/Pending.jsx
@@ -12,6 +12,7 @@ import PostLoader from '../PostLoader';
import SettingsModal from '../modals/SettingsModal';
import getCommentMediaInfo from '../../utils/getCommentMediaInfo';
import getDate from '../../utils/getDate';
+import handleImageClick from '../../utils/handleImageClick';
import handleQuoteClick from '../../utils/handleQuoteClick';
import handleStyleChange from '../../utils/handleStyleChange';
import useError from '../../hooks/useError';
@@ -35,6 +36,23 @@ const Pending = () => {
const account = useAccount();
const comment = useAccountComment({commentIndex: index});
const [, setNewErrorMessage] = useError();
+ const [isThumbnailClicked, setIsThumbnailClicked] = useState({});
+ const [isMobileThumbnailClicked, setIsMobileThumbnailClicked] = useState({});
+
+
+ const handleThumbnailClick = (index, isMobile=false) => {
+ if (isMobile) {
+ setIsMobileThumbnailClicked(prevState => ({
+ ...prevState,
+ [index]: !prevState[index],
+ }));
+ } else {
+ setIsThumbnailClicked(prevState => ({
+ ...prevState,
+ [index]: !prevState[index],
+ }));
+ }
+ };
useEffect(() => {
setSelectedAddress(comment?.subplebbitAddress);
@@ -138,28 +156,29 @@ const Pending = () => {
]
-
-
Board
-
-
- All
- Subscriptions
- {defaultSubplebbits.map(subplebbit => (
- {subplebbit.title ? subplebbit.title : subplebbit.address}
- ))}
-
-
+
+ Board
+
+
+ All
+ Subscriptions
+ {defaultSubplebbits.map(subplebbit => (
+ {subplebbit.title ? subplebbit.title : subplebbit.address}
+ ))}
+ Â
+ alert(
'To create a board, first you have to run a full node.\nYou can run a full node by simply browsing with the plebbit desktop app. After you download it, open it, wait for it loading, then click on "Home" in the top left, then "Create Community".\n\nAfter you create the community, you can go back to plebchan at any time to see it as a board by pasting its address (begins with p/12D3KooW...) in the search bar, which is in the Home.\n\nNote:\n\n- Your community will be online for as long as you leave the app open, because it functions like a server for the community.\n- The longer you leave the app open, the more data you are seeding to the protocol, which helps performance for everybody.\n - All the data in the plebbit protocol is just text, which is extremely lightweight. All media is generated by links, which is text, embedded by the clients.\n\nDownload the plebbit app here: https://github.com/plebbit/plebbit-react/releases\n\nYou can also use a CLI: https://github.com/plebbit/plebbit-cli\n\nRunning boards in the plebchan app is a planned feature.\n\n'
)
- }>Create Board
-
-
- setIsSettingsOpen(true)}>Settings
-
- handleStyleChange({target: {value: "Yotsuba"}}
- )}>Home
+ }>Create Board
+
+
+ setIsSettingsOpen(true)}>Settings
+
+ {handleStyleChange({target: {value: "Yotsuba"}}); window.scrollTo(0, 0);}}>Home
+
@@ -228,35 +247,107 @@ const Pending = () => {
- {commentMediaInfo?.url ? (
-
-
+ {commentMediaInfo?.url ? (
+
+
+ {commentMediaInfo?.type === 'iframe' && (
+
+
+ {(isThumbnailClicked[index] || !commentMediaInfo.thumbnail) && commentMediaInfo.embedUrl ? (
+
+ ) : (
+ {handleThumbnailClick(index)}}
+ style={{cursor: "pointer"}}
+ onError={(e) => e.target.src = fallbackImgUrl} />
+ )}
+
+
+ )}
{commentMediaInfo?.type === "webpage" ? (
-
- e.target.src = fallbackImgUrl} />
-
+
+
+ {comment.thumbnailUrl ? (
+ e.target.src = fallbackImgUrl} />
+ ) : null}
+
+
) : null}
{commentMediaInfo?.type === "image" ? (
-
- e.target.src = fallbackImgUrl} />
-
+
+
+ e.target.src = fallbackImgUrl} />
+
+
) : null}
{commentMediaInfo?.type === "video" ? (
-
- e.target.src = fallbackImgUrl} />
+
+
+ {isThumbnailClicked[index] ? (
+ e.target.src = fallbackImgUrl}
+ />
+ ) : (
+ {handleThumbnailClick(index)}}
+ style={{cursor: "pointer"}}
+ onError={(e) => e.target.src = fallbackImgUrl}
+ />
+ )}
+
) : null}
{commentMediaInfo?.type === "audio" ? (
-
- e.target.src = fallbackImgUrl} />
+
+ e.target.src = fallbackImgUrl} />
) : null}
@@ -360,37 +451,109 @@ const Pending = () => {
Pending
- {commentMediaInfo?.url ? (
- commentMediaInfo.type === "webpage" ? (
-
-
- e.target.src = fallbackImgUrl} />
- {commentMediaInfo.type}
-
+ {comment.link ? (
+
+ {commentMediaInfo?.type === 'iframe' && (
+
+
+ {(isMobileThumbnailClicked[index] || !commentMediaInfo.thumbnail) && commentMediaInfo.embedUrl ? (
+
+
+
+ ) : (
+ {handleThumbnailClick(index, true)}}
+ style={{cursor: "pointer"}}
+ onError={(e) => e.target.src = fallbackImgUrl} />
+ )}
+ {commentMediaInfo?.type === "video" || "iframe" ? (
+ isMobileThumbnailClicked[index] ? (
+
+ {handleThumbnailClick(index, true)}}
+ >Close
+
+ ) : (
+ video
+ )) : video
}
+
+
+ )}
+ {commentMediaInfo?.url ? (
+ commentMediaInfo.type === "webpage" ? (
+
+
+ {comment.thumbnailUrl ? (
+ e.target.src = fallbackImgUrl} />
+ ) : null}
+ {commentMediaInfo?.type}
+
+
+ ) : commentMediaInfo.type === "image" ? (
+
+
+ e.target.src = fallbackImgUrl} />
+ {commentMediaInfo?.type}
+
+
+ ) : commentMediaInfo.type === "video" ? (
+
+ {isMobileThumbnailClicked[index] ? (
+ e.target.src = fallbackImgUrl} />
+ ) : (
+ {handleThumbnailClick(index, true)}}
+ style={{cursor: "pointer"}}
+ id="video-thumbnail-mobile"
+ onError={(e) => e.target.src = fallbackImgUrl}
+ />
+ )}
+ {commentMediaInfo?.type === "video" || "iframe" ? (
+ isMobileThumbnailClicked[index] ? (
+
+ {handleThumbnailClick(index, true)}}
+ >Close
+
+ ) : (
+ video
+ )) : video
}
+
+ ) : commentMediaInfo.type === "audio" ? (
+
+ e.target.src = fallbackImgUrl} />
+ {commentMediaInfo?.type}
+
+ ) : null
+ ) : null}
- ) : commentMediaInfo.type === "image" ? (
-
-
- e.target.src = fallbackImgUrl} />
- {commentMediaInfo.type}
-
-
- ) : commentMediaInfo.type === "video" ? (
-
-
- e.target.src = fallbackImgUrl} />
- {commentMediaInfo.type}
-
-
- ) : commentMediaInfo.type === "audio" ? (
-
-
- e.target.src = fallbackImgUrl} />
- {commentMediaInfo.type}
-
-
- ) : null
- ) : null}
+ ) : null}
{comment.content ? (
<>
diff --git a/src/components/views/Subscriptions.jsx b/src/components/views/Subscriptions.jsx
index a6067f87..33be2a40 100755
--- a/src/components/views/Subscriptions.jsx
+++ b/src/components/views/Subscriptions.jsx
@@ -1,4 +1,4 @@
-import React, { Fragment, useCallback, useEffect, useLayoutEffect, useMemo, useState, useRef } from 'react';
+import React, { Fragment, useCallback, useEffect, useMemo, useState, useRef } from 'react';
import { confirmAlert } from 'react-confirm-alert';
import { createPortal } from 'react-dom';
import { Helmet } from 'react-helmet-async';
@@ -22,6 +22,7 @@ import Post from '../Post';
import PostLoader from '../PostLoader';
import PostOnHover from '../PostOnHover';
import StateLabel from '../StateLabel';
+import VerifiedAuthor from '../VerifiedAuthor';
import ReplyModal from '../modals/ReplyModal';
import SettingsModal from '../modals/SettingsModal';
import findShortParentCid from '../../utils/findShortParentCid';
@@ -102,6 +103,8 @@ const Subscriptions = () => {
const [moderatorPermissions, setModeratorPermissions] = useState({});
const [executeAnonMode, setExecuteAnonMode] = useState(false);
const [cidTracker, setCidTracker] = useState({});
+ const [isThumbnailClicked, setIsThumbnailClicked] = useState({});
+ const [isMobileThumbnailClicked, setIsMobileThumbnailClicked] = useState({});
const setSelectedThreadCid = (cid) => {
selectedThreadCidRef.current = cid;
@@ -116,6 +119,21 @@ const Subscriptions = () => {
const stateString = useFeedStateString(subplebbits);
+ const handleThumbnailClick = (index, isMobile=false) => {
+ if (isMobile) {
+ setIsMobileThumbnailClicked(prevState => ({
+ ...prevState,
+ [index]: !prevState[index],
+ }));
+ } else {
+ setIsThumbnailClicked(prevState => ({
+ ...prevState,
+ [index]: !prevState[index],
+ }));
+ }
+ };
+
+
useEffect(() => {
let permissions = {};
@@ -161,6 +179,14 @@ const Subscriptions = () => {
};
}, [openMenuCid, handleOutsideClick]);
+
+ useEffect(() => {
+ if (postOnHoverRef.current) {
+ const rect = postOnHoverRef.current.getBoundingClientRect();
+ setPostOnHoverHeight(rect.height);
+ }
+ }, [outOfViewCid]);
+
const errorString = useMemo(() => {
for (const subplebbit of subplebbits) {
@@ -280,7 +306,8 @@ const Subscriptions = () => {
setNewSuccessMessage('Challenge Success');
}
else if (challengeVerification.challengeSuccess === false) {
- setNewErrorMessage('Challenge Failed', {reason: challengeVerification.reason, errors: challengeVerification.errors});
+ setNewErrorMessage(`Challenge Failed, reason: ${challengeVerification.reason}. Errors: ${challengeVerification.errors}`);
+ console.log('challenge failed', challengeVerification);
}
};
@@ -291,7 +318,7 @@ const Subscriptions = () => {
challengeAnswers = await getChallengeAnswersFromUser(challenges)
}
catch (error) {
- setNewErrorMessage(error);
+ setNewErrorMessage(error.message); console.log(error);
}
if (challengeAnswers) {
await comment.publishChallengeAnswers(challengeAnswers)
@@ -341,7 +368,7 @@ const Subscriptions = () => {
onChallenge,
onChallengeVerification,
onError: (error) => {
- setNewErrorMessage(error);
+ setNewErrorMessage(error.message); console.log(error);
},
});
@@ -356,8 +383,8 @@ const Subscriptions = () => {
const { publishCommentEdit } = usePublishCommentEdit(publishCommentEditOptions);
- const handleAuthorDeleteClick = (cid) => {
- handleOptionClick(cid);
+ const handleAuthorDeleteClick = (comment) => {
+ handleOptionClick(comment.cid);
confirmAlert({
customUI: ({ onClose }) => {
@@ -371,9 +398,10 @@ const Subscriptions = () => {
onClick={() => {
setIsAuthorDelete(true);
setIsAuthorEdit(false);
- setCommentCid(cid);
setPublishCommentEditOptions(prevOptions => ({
...prevOptions,
+ commentCid: comment.cid,
+ subplebbitAddress: comment.subplebbitAddress,
deleted: true,
}));
setTriggerPublishCommentEdit(true);
@@ -398,9 +426,9 @@ const Subscriptions = () => {
setCommentCid(comment.cid);
setOriginalCommentContent(comment.content);
setIsEditModalOpen(true);
- }
-
-
+ };
+
+
useEffect(() => {
setPublishCommentEditOptions((prevOptions) => ({
...prevOptions,
@@ -458,14 +486,6 @@ const Subscriptions = () => {
navigate(`/p/${selected}`);
};
-
- useLayoutEffect(() => {
- if (postOnHoverRef.current) {
- const rect = postOnHoverRef.current.getBoundingClientRect();
- setPostOnHoverHeight(rect.height);
- }
- }, [outOfViewCid]);
-
return (
<>
@@ -561,11 +581,11 @@ const Subscriptions = () => {
<>
Subscriptions
- {feed.length < 1 ? (
+ {account?.subscriptions.length < 1 ? (
You haven't subscribed to any board yet.
) : (
- You have subscribed to {account.subscriptions.length} board{account.subscriptions.length > 1 ? "s" : null}.
+ You have subscribed to {account?.subscriptions.length} board{account?.subscriptions.length > 1 ? "s" : null}.
)}
>
@@ -591,7 +611,7 @@ const Subscriptions = () => {
Catalog
]
- {feed.length > 0 ? (
+ {feed ? (
null
) : (
@@ -607,7 +627,7 @@ const Subscriptions = () => {
- { feed.length < 1 ? (
+ { !feed ? (
null
) : (
{
{commentMediaInfo?.url ? (
-
-
- {commentMediaInfo?.type === "webpage" ? (
-
-
- {thread.thumbnailUrl ? (
+
+
+ {commentMediaInfo?.type === 'iframe' && (
+
+
+ {(isThumbnailClicked[index] || !commentMediaInfo.thumbnail) && commentMediaInfo.embedUrl ? (
+
+ ) : (
+ {handleThumbnailClick(index)}}
+ style={{cursor: "pointer"}}
+ onError={(e) => e.target.src = fallbackImgUrl} />
+ )}
+
+
+ )}
+ {commentMediaInfo?.type === "webpage" ? (
+
+
+ {thread.thumbnailUrl ? (
+ e.target.src = fallbackImgUrl} />
+ ) : null}
+
+
+ ) : null}
+ {commentMediaInfo?.type === "image" ? (
+
+
e.target.src = fallbackImgUrl} />
- ) : null}
+
+
+ ) : null}
+ {commentMediaInfo?.type === "video" ? (
+
+
+ {isThumbnailClicked[index] ? (
+ e.target.src = fallbackImgUrl}
+ />
+ ) : (
+ {handleThumbnailClick(index)}}
+ style={{cursor: "pointer"}}
+ onError={(e) => e.target.src = fallbackImgUrl}
+ />
+ )}
- ) : null}
- {commentMediaInfo?.type === "image" ? (
-
+ ) : null}
+ {commentMediaInfo?.type === "audio" ? (
- e.target.src = fallbackImgUrl} />
-
- ) : null}
- {commentMediaInfo?.type === "video" ? (
-
- e.target.src = fallbackImgUrl} />
-
- ) : null}
- {commentMediaInfo?.type === "audio" ? (
-
- e.target.src = fallbackImgUrl} />
-
- ) : null}
-
- ) : null}
+ ) : null}
+
+ ) : null}
{thread.title ? (
thread.title.length > 75 ?
@@ -709,9 +783,9 @@ const Subscriptions = () => {
(u/
handleAddressClick(thread.author.shortAddress)}
+ onClick={() => handleAddressClick({({ shortAuthorAddress }) => (shortAuthorAddress)} )}
>
- {thread.author.shortAddress}
+ {{({ shortAuthorAddress }) => (shortAuthorAddress)} }
)
{getDate(thread.timestamp)}
@@ -786,38 +860,44 @@ const Subscriptions = () => {
>
handleOptionClick(thread.cid)}>Hide thread
- {thread.author.shortAddress === account?.author.shortAddress ? (
+ {({ authorAddress }) => (
<>
- {handleAuthorEditClick(thread); setSelectedAddress(thread.subplebbitAddress);}}>Edit post
- {handleAuthorDeleteClick(thread.cid); setSelectedAddress(thread.subplebbitAddress);}}>Delete post
+ {authorAddress === account?.author.address ||
+ authorAddress === account?.signer.address ? (
+ <>
+ handleAuthorEditClick(thread)}>Edit post
+ handleAuthorDeleteClick(thread)}>Delete post
+ >
+ ) : null}
+ {isModerator ? (
+ <>
+ {authorAddress === account?.author.address ||
+ authorAddress === account?.signer.address ? (
+ null
+ ) : (
+ {
+ setSelectedAddress(thread.subplebbitAddress);
+ setModeratingCommentCid(thread.cid)
+ setIsModerationOpen(true);
+ handleOptionClick(thread.cid);
+ setDeletePost(true);
+ }}>
+ Delete post
+
+ )}
+ {
+ setSelectedAddress(thread.subplebbitAddress);
+ setModeratingCommentCid(thread.cid)
+ setIsModerationOpen(true);
+ handleOptionClick(thread.cid);
+ }}>
+ Mod tools
+
+ >
+ ) : null}
>
- ) : null}
- {isModerator ? (
- <>
- {thread.author.shortAddress === account?.author.shortAddress ? (
- null
- ) : (
- {
- setSelectedAddress(thread.subplebbitAddress);
- setModeratingCommentCid(thread.cid)
- setIsModerationOpen(true);
- handleOptionClick(thread.cid);
- setDeletePost(true);
- }}>
- Delete post
-
- )}
- {
- setSelectedAddress(thread.subplebbitAddress);
- setModeratingCommentCid(thread.cid)
- setIsModerationOpen(true);
- handleOptionClick(thread.cid);
- }}>
- Mod tools
-
- >
- ) : null}
+ )}
{(commentMediaInfo && (
commentMediaInfo.type === 'image' ||
(commentMediaInfo.type === 'webpage' &&
@@ -979,7 +1059,7 @@ const Subscriptions = () => {
handleAddressClick(reply.author.shortAddress)}
+ onClick={() => handleAddressClick({({ shortAuthorAddress }) => (shortAuthorAddress)} )}
>
(u/
{reply.author?.shortAddress ?
@@ -1074,38 +1154,44 @@ const Subscriptions = () => {
>
handleOptionClick(reply.cid)}>Hide post
- {reply.author.shortAddress === account?.author.shortAddress ? (
+ {({ authorAddress }) => (
<>
- {handleAuthorEditClick(reply); setSelectedAddress(thread.subplebbitAddress);}}>Edit post
- {handleAuthorDeleteClick(reply.cid); setSelectedAddress(thread.subplebbitAddress);}}>Delete post
- >
- ) : null}
- {isModerator ? (
- <>
- {reply.author.shortAddress === account?.author.shortAddress ? (
- null
- ) : (
- {
+ {authorAddress === account?.author.address ||
+ authorAddress === account?.signer.address ? (
+ <>
+ handleAuthorEditClick(reply)}>Edit post
+ handleAuthorDeleteClick(reply)}>Delete post
+ >
+ ) : null}
+ {isModerator ? (
+ <>
+ {authorAddress === account?.author.address ||
+ authorAddress === account?.signer.address ? (
+ null
+ ) : (
+ {
setSelectedAddress(thread.subplebbitAddress);
setModeratingCommentCid(reply.cid)
setIsModerationOpen(true);
handleOptionClick(reply.cid);
setDeletePost(true);
+ }}>
+ Delete post
+
+ )}
+ {
+ setSelectedAddress(thread.subplebbitAddress);
+ setModeratingCommentCid(reply.cid)
+ setIsModerationOpen(true);
+ handleOptionClick(reply.cid);
}}>
- Delete post
+ Mod tools
- )}
- {
- setSelectedAddress(thread.subplebbitAddress);
- setModeratingCommentCid(reply.cid)
- setIsModerationOpen(true);
- handleOptionClick(reply.cid);
- }}>
- Mod tools
-
+ >
+ ) : null}
>
- ) : null}
+ )}
{(replyMediaInfo && (
replyMediaInfo.type === 'image' ||
(replyMediaInfo.type === 'webpage' &&
@@ -1497,11 +1583,11 @@ const Subscriptions = () => {
handleAddressClick(thread.author.shortAddress)}
+ onClick={() => handleAddressClick({({ shortAuthorAddress }) => (shortAuthorAddress)} )}
>
(u/
- {thread.author.shortAddress}
+ {{({ shortAuthorAddress }) => (shortAuthorAddress)} }
)
@@ -1566,51 +1652,108 @@ const Subscriptions = () => {
{thread.link ? (
-
- {commentMediaInfo?.url ? (
- commentMediaInfo.type === "webpage" ? (
-
-
- {thread.thumbnailUrl ? (
+
+ {commentMediaInfo?.type === 'iframe' && (
+
+
+ {(isMobileThumbnailClicked[index] || !commentMediaInfo.thumbnail) && commentMediaInfo.embedUrl ? (
+
+
+
+ ) : (
+ {handleThumbnailClick(index, true)}}
+ style={{cursor: "pointer"}}
+ onError={(e) => e.target.src = fallbackImgUrl} />
+ )}
+ {commentMediaInfo?.type === "video" || "iframe" ? (
+ isMobileThumbnailClicked[index] ? (
+
+ {handleThumbnailClick(index, true)}}
+ >Close
+
+ ) : (
+ video
+ )) : video
}
+
+
+ )}
+ {commentMediaInfo?.url ? (
+ commentMediaInfo.type === "webpage" ? (
+
+
+ {thread.thumbnailUrl ? (
+ e.target.src = fallbackImgUrl} />
+ ) : null}
+ {commentMediaInfo?.type}
+
+
+ ) : commentMediaInfo.type === "image" ? (
+
+
e.target.src = fallbackImgUrl} />
- ) : null}
- {commentMediaInfo?.type}
-
-
- ) : commentMediaInfo.type === "image" ? (
-
-
- e.target.src = fallbackImgUrl} />
- {commentMediaInfo?.type}
-
-
- ) : commentMediaInfo.type === "video" ? (
-
- e.target.src = fallbackImgUrl} />
- {commentMediaInfo?.type}
-
- ) : commentMediaInfo.type === "audio" ? (
-
- e.target.src = fallbackImgUrl} />
- {commentMediaInfo?.type}
-
- ) : null
- ) : null}
-
- ) : null}
+ {commentMediaInfo?.type}
+
+
+ ) : commentMediaInfo.type === "video" ? (
+
+ {isMobileThumbnailClicked[index] ? (
+ e.target.src = fallbackImgUrl} />
+ ) : (
+ {handleThumbnailClick(index, true)}}
+ style={{cursor: "pointer"}}
+ id="video-thumbnail-mobile"
+ onError={(e) => e.target.src = fallbackImgUrl}
+ />
+ )}
+ {commentMediaInfo?.type === "video" || "iframe" ? (
+ isMobileThumbnailClicked[index] ? (
+
+ {handleThumbnailClick(index, true)}}
+ >Close
+
+ ) : (
+ video
+ )) : video
}
+
+ ) : commentMediaInfo.type === "audio" ? (
+
+ e.target.src = fallbackImgUrl} />
+ {commentMediaInfo?.type}
+
+ ) : null
+ ) : null}
+
+ ) : null}
{thread.content ? (
thread.content?.length > 500 ?
@@ -1680,7 +1823,7 @@ const Subscriptions = () => {
handleAddressClick(reply.author.shortAddress)}
+ onClick={() => handleAddressClick({({ shortAuthorAddress }) => (shortAuthorAddress)} )}
>
(u/
{reply.author?.shortAddress ?
@@ -2072,7 +2215,7 @@ const Subscriptions = () => {
}}
endReached={tryLoadMore}
useWindowScroll={true}
- components={{ Footer: hasMore ? () => : null }}
+ components={{ Footer: hasMore && feed.length > 0 ? () => : null }}
/>
)}
diff --git a/src/components/views/SubscriptionsCatalog.jsx b/src/components/views/SubscriptionsCatalog.jsx
index 34ee696a..42312209 100755
--- a/src/components/views/SubscriptionsCatalog.jsx
+++ b/src/components/views/SubscriptionsCatalog.jsx
@@ -14,6 +14,7 @@ import { TopBar, Footer, AuthorDeleteAlert } from '../styled/views/Thread.styled
import CatalogLoader from '../CatalogLoader';
import EditModal from '../modals/EditModal';
import ImageBanner from '../ImageBanner';
+import VerifiedAuthor from '../VerifiedAuthor';
import ModerationModal from '../modals/ModerationModal';
import OfflineIndicator from '../OfflineIndicator';
import SettingsModal from '../modals/SettingsModal';
@@ -146,7 +147,8 @@ const SubscriptionsCatalog = () => {
setNewSuccessMessage('Challenge Success');
}
else if (challengeVerification.challengeSuccess === false) {
- setNewErrorMessage('Challenge Failed', {reason: challengeVerification.reason, errors: challengeVerification.errors});
+ setNewErrorMessage(`Challenge Failed, reason: ${challengeVerification.reason}. Errors: ${challengeVerification.errors}`);
+ console.log('challenge failed', challengeVerification);
}
};
@@ -157,7 +159,7 @@ const SubscriptionsCatalog = () => {
challengeAnswers = await getChallengeAnswersFromUser(challenges)
}
catch (error) {
- setNewErrorMessage(error);
+ setNewErrorMessage(error.message); console.log(error);
}
if (challengeAnswers) {
await comment.publishChallengeAnswers(challengeAnswers)
@@ -206,7 +208,7 @@ const SubscriptionsCatalog = () => {
onChallenge,
onChallengeVerification,
onError: (error) => {
- setNewErrorMessage(error);
+ setNewErrorMessage(error.message); console.log(error);
},
});
@@ -229,9 +231,10 @@ const SubscriptionsCatalog = () => {
onClick={() => {
setIsAuthorDelete(true);
setIsAuthorEdit(false);
- setCommentCid(comment.cid);
setPublishCommentEditOptions(prevOptions => ({
...prevOptions,
+ commentCid: comment.cid,
+ subplebbitAddress: comment.subplebbitAddress,
deleted: true,
}));
setTriggerPublishCommentEdit(true);
@@ -409,7 +412,7 @@ const SubscriptionsCatalog = () => {
<>
Subscriptions
- {feed.length < 1 ? (
+ {account.subscriptions.length < 1 ? (
You haven't subscribed to any board yet.
) : (
@@ -444,7 +447,7 @@ const SubscriptionsCatalog = () => {
Return
- {feed.length > 0 ? (
+ {feed ? (
null
) : (
@@ -455,7 +458,7 @@ const SubscriptionsCatalog = () => {
- {feed.length > 0 ? (
+ {feed ? (
{
>
handleOptionClick(thread.cid)}>Hide thread
- {thread.author.shortAddress === account?.author.shortAddress ? (
+ {({ authorAddress }) => (
<>
- handleAuthorEditClick(thread)}>Edit post
- handleAuthorDeleteClick(thread)}>Delete post
+ {authorAddress === account?.author.address ||
+ authorAddress === account?.signer.address ? (
+ <>
+ handleAuthorEditClick(thread)}>Edit post
+ handleAuthorDeleteClick(thread)}>Delete post
+ >
+ ) : null}
+ {isModerator ? (
+ <>
+ {authorAddress === account?.author.address ||
+ authorAddress === account?.signer.address ? (
+ null
+ ) : (
+ {
+ setSelectedAddress(thread.subplebbitAddress);
+ setModeratingCommentCid(thread.cid)
+ setIsModerationOpen(true);
+ handleOptionClick(thread.cid);
+ setDeletePost(true);
+ }}>
+ Delete post
+
+ )}
+ {
+ setSelectedAddress(thread.subplebbitAddress);
+ setModeratingCommentCid(thread.cid)
+ setIsModerationOpen(true);
+ handleOptionClick(thread.cid);
+ }}>
+ Mod tools
+
+ >
+ ) : null}
>
- ) : null}
- {isModerator ? (
- <>
- {thread.author.shortAddress === account?.author.shortAddress ? (
- null
- ) : (
- {
- setSelectedAddress(thread.subplebbitAddress);
- setModeratingCommentCid(thread.cid)
- setIsModerationOpen(true);
- handleOptionClick(thread.cid);
- setDeletePost(true);
- }}>
- Delete post
-
- )}
- {
- setSelectedAddress(thread.subplebbitAddress);
- setModeratingCommentCid(thread.cid)
- setIsModerationOpen(true);
- handleOptionClick(thread.cid);
- }}>
- Mod tools
-
- >
- ) : null}
+ )}
{(commentMediaInfo && (
commentMediaInfo.type === 'image' ||
(commentMediaInfo.type === 'webpage' &&
diff --git a/src/components/views/Thread.jsx b/src/components/views/Thread.jsx
index b714d8be..178ed2a3 100755
--- a/src/components/views/Thread.jsx
+++ b/src/components/views/Thread.jsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';
+import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import { Helmet } from 'react-helmet-async';
import { Link, useNavigate, useParams } from 'react-router-dom';
@@ -20,6 +20,7 @@ import Post from '../Post';
import PostLoader from '../PostLoader';
import PostOnHover from '../PostOnHover';
import StateLabel from '../StateLabel';
+import VerifiedAuthor from '../VerifiedAuthor';
import ReplyModal from '../modals/ReplyModal';
import SettingsModal from '../modals/SettingsModal';
import findShortParentCid from '../../utils/findShortParentCid';
@@ -111,6 +112,8 @@ const Thread = () => {
const [postOnHoverHeight, setPostOnHoverHeight] = useState(0);
const [executeAnonMode, setExecuteAnonMode] = useState(false);
const [cidTracker, setCidTracker] = useState({});
+ const [isThumbnailClicked, setIsThumbnailClicked] = useState({});
+ const [isMobileThumbnailClicked, setIsMobileThumbnailClicked] = useState({});
useAnonMode(selectedThread, anonymousMode && executeAnonMode);
@@ -126,6 +129,21 @@ const Thread = () => {
const fallbackImgUrl = "assets/filedeleted-res.gif";
+ const handleThumbnailClick = (index, isMobile=false) => {
+ if (isMobile) {
+ setIsMobileThumbnailClicked(prevState => ({
+ ...prevState,
+ [index]: !prevState[index],
+ }));
+ } else {
+ setIsThumbnailClicked(prevState => ({
+ ...prevState,
+ [index]: !prevState[index],
+ }));
+ }
+ };
+
+
useEffect(() => {
if (subplebbit.roles !== undefined) {
const role = subplebbit.roles[account?.author?.address]?.role;
@@ -161,6 +179,14 @@ const Thread = () => {
};
}, [openMenuCid, handleOutsideClick]);
+
+ useEffect(() => {
+ if (postOnHoverRef.current) {
+ const rect = postOnHoverRef.current.getBoundingClientRect();
+ setPostOnHoverHeight(rect.height);
+ }
+ }, [outOfViewCid]);
+
useEffect(() => {
window.scrollTo(0, 0);
@@ -259,7 +285,8 @@ const Thread = () => {
setNewSuccessMessage('Challenge Success');
}
} else if (challengeVerification.challengeSuccess === false) {
- setNewErrorMessage('Challenge Failed', {reason: challengeVerification.reason, errors: challengeVerification.errors});
+ setNewErrorMessage(`Challenge Failed, reason: ${challengeVerification.reason}. Errors: ${challengeVerification.errors}`);
+ console.log('challenge failed', challengeVerification);
}
};
@@ -272,7 +299,7 @@ const Thread = () => {
challengeAnswers = await getChallengeAnswersFromUser(challenges)
}
catch (error) {
- setNewErrorMessage(error);
+ setNewErrorMessage(error.message); console.log(error);
}
if (challengeAnswers) {
await comment.publishChallengeAnswers(challengeAnswers)
@@ -293,7 +320,7 @@ const Thread = () => {
onChallenge,
onChallengeVerification,
onError: (error) => {
- setNewErrorMessage(error);
+ setNewErrorMessage(error.message); console.log(error);
},
});
@@ -388,8 +415,10 @@ const Thread = () => {
}, [selectedThread, anonymousMode, account]);
useEffect(() => {
- updateSigner();
- }, [updateSigner]);
+ if (anonymousMode) {
+ updateSigner();
+ }
+ }, [updateSigner, anonymousMode]);
useEffect(() => {
@@ -446,7 +475,7 @@ const Thread = () => {
onChallenge,
onChallengeVerification,
onError: (error) => {
- setNewErrorMessage(error);
+ setNewErrorMessage(error.message); console.log(error);
},
});
@@ -454,8 +483,8 @@ const Thread = () => {
const { publishCommentEdit } = usePublishCommentEdit(publishCommentEditOptions);
- const handleAuthorDeleteClick = (cid) => {
- handleOptionClick(cid);
+ const handleAuthorDeleteClick = (comment) => {
+ handleOptionClick(comment.cid);
confirmAlert({
customUI: ({ onClose }) => {
@@ -469,9 +498,10 @@ const Thread = () => {
onClick={() => {
setIsAuthorDelete(true);
setIsAuthorEdit(false);
- setCommentCid(cid);
setPublishCommentEditOptions(prevOptions => ({
...prevOptions,
+ commentCid: comment.cid,
+ subplebbitAddress: comment.subplebbitAddress,
deleted: true,
}));
setTriggerPublishCommentEdit(true);
@@ -549,14 +579,6 @@ const Thread = () => {
};
- useLayoutEffect(() => {
- if (postOnHoverRef.current) {
- const rect = postOnHoverRef.current.getBoundingClientRect();
- setPostOnHoverHeight(rect.height);
- }
- }, [outOfViewCid]);
-
-
return (
<>
@@ -792,52 +814,106 @@ const Thread = () => {
- {commentMediaInfo?.url ? (
-
-
+ {commentMediaInfo?.url ? (
+
+
+ {commentMediaInfo?.type === 'iframe' && (
+
+
+ {(isThumbnailClicked[index] || !commentMediaInfo.thumbnail) && commentMediaInfo.embedUrl ? (
+
+ ) : (
+ {handleThumbnailClick(index)}}
+ style={{cursor: "pointer"}}
+ onError={(e) => e.target.src = fallbackImgUrl} />
+ )}
+
+
+ )}
{commentMediaInfo?.type === "webpage" ? (
-
-
+
+
{comment.thumbnailUrl ? (
- e.target.src = fallbackImgUrl} />
) : null}
) : null}
{commentMediaInfo?.type === "image" ? (
-
-
-
+
+ e.target.src = fallbackImgUrl} />
) : null}
{commentMediaInfo?.type === "video" ? (
-
- e.target.src = fallbackImgUrl} />
+
+
+ {isThumbnailClicked[index] ? (
+ e.target.src = fallbackImgUrl}
+ />
+ ) : (
+ {handleThumbnailClick(index)}}
+ style={{cursor: "pointer"}}
+ onError={(e) => e.target.src = fallbackImgUrl}
+ />
+ )}
+
) : null}
{commentMediaInfo?.type === "audio" ? (
-
-
+ e.target.src = fallbackImgUrl} />
) : null}
@@ -877,10 +953,10 @@ const Thread = () => {
handleAddressClick(comment?.author?.shortAddress)}>
+ onClick={() => handleAddressClick({({ shortAuthorAddress }) => (shortAuthorAddress)} )}>
(u/
- {comment?.author?.shortAddress}
+ {{({ shortAuthorAddress }) => (shortAuthorAddress)} }
)
@@ -948,36 +1024,42 @@ const Thread = () => {
>
handleOptionClick(comment.cid)}>Hide thread
- {comment.author?.shortAddress === account?.author.shortAddress ? (
+ {({ authorAddress }) => (
<>
- handleAuthorEditClick(comment)}>Edit post
- handleAuthorDeleteClick(comment.cid)}>Delete post
- >
- ) : null}
- {isModerator ? (
- <>
- {comment.author?.shortAddress === account?.author.shortAddress ? (
- null
- ) : (
- {
+ {authorAddress === account?.author.address ||
+ authorAddress === account?.signer.address ? (
+ <>
+ handleAuthorEditClick(comment)}>Edit post
+ handleAuthorDeleteClick(comment)}>Delete post
+ >
+ ) : null}
+ {isModerator ? (
+ <>
+ {authorAddress === account?.author.address ||
+ authorAddress === account?.signer.address ? (
+ null
+ ) : (
+ {
+ setModeratingCommentCid(comment.cid)
+ setIsModerationOpen(true);
+ handleOptionClick(comment.cid);
+ setDeletePost(true);
+ }}>
+ Delete post
+
+ )}
+ {
setModeratingCommentCid(comment.cid)
setIsModerationOpen(true);
handleOptionClick(comment.cid);
- setDeletePost(true);
}}>
- Delete post
+ Mod tools
- )}
- {
- setModeratingCommentCid(comment.cid)
- setIsModerationOpen(true);
- handleOptionClick(comment.cid);
- }}>
- Mod tools
-
- >
- ) : null}
+ >
+ ) : null}
+ >
+ )}
{(commentMediaInfo && (
commentMediaInfo.type === 'image' ||
(commentMediaInfo.type === 'webpage' &&
@@ -1194,36 +1276,42 @@ const Thread = () => {
>
handleOptionClick(reply.cid)}>Hide post
- {reply.author.shortAddress === account?.author.shortAddress ? (
+ {({ authorAddress }) => (
<>
- handleAuthorEditClick(reply)}>Edit post
- handleAuthorDeleteClick(reply.cid)}>Delete post
+ {authorAddress === account?.author.address ||
+ authorAddress === account?.signer.address ? (
+ <>
+ handleAuthorEditClick(reply)}>Edit post
+ handleAuthorDeleteClick(reply)}>Delete post
+ >
+ ) : null}
+ {isModerator ? (
+ <>
+ {authorAddress === account?.author.address ||
+ authorAddress === account?.signer.address ? (
+ null
+ ) : (
+ {
+ setModeratingCommentCid(reply.cid)
+ setIsModerationOpen(true);
+ handleOptionClick(reply.cid);
+ setDeletePost(true);
+ }}>
+ Delete post
+
+ )}
+ {
+ setModeratingCommentCid(reply.cid)
+ setIsModerationOpen(true);
+ handleOptionClick(reply.cid);
+ }}>
+ Mod tools
+
+ >
+ ) : null}
>
- ) : null}
- {isModerator ? (
- <>
- {reply.author.shortAddress === account?.author.shortAddress ? (
- null
- ) : (
- {
- setModeratingCommentCid(reply.cid)
- setIsModerationOpen(true);
- handleOptionClick(reply.cid);
- setDeletePost(true);
- }}>
- Delete post
-
- )}
- {
- setModeratingCommentCid(reply.cid)
- setIsModerationOpen(true);
- handleOptionClick(reply.cid);
- }}>
- Mod tools
-
- >
- ) : null}
+ )}
{(replyMediaInfo && (
replyMediaInfo.type === 'image' ||
(replyMediaInfo.type === 'webpage' &&
@@ -1499,11 +1587,11 @@ const Thread = () => {
handleAddressClick(comment?.author?.shortAddress)}
+ onClick={() => handleAddressClick({({ shortAuthorAddress }) => (shortAuthorAddress)} )}
>
(u/
- {comment?.author?.shortAddress}
+ {{({ shortAuthorAddress }) => (shortAuthorAddress)} }
)
@@ -1553,54 +1641,108 @@ const Thread = () => {
}}}>{comment.shortCid}
- {commentMediaInfo?.url ? (
- commentMediaInfo.type === "webpage" ? (
-
-
-
- {comment.thumbnailUrl ? (
-
+ {commentMediaInfo?.type === 'iframe' && (
+
+
+ {(isMobileThumbnailClicked[index] || !commentMediaInfo.thumbnail) && commentMediaInfo.embedUrl ? (
+
+
+
+ ) : (
+ {handleThumbnailClick(index, true)}}
+ style={{cursor: "pointer"}}
+ onError={(e) => e.target.src = fallbackImgUrl} />
+ )}
+ {commentMediaInfo?.type === "video" || "iframe" ? (
+ isMobileThumbnailClicked[index] ? (
+
+ {handleThumbnailClick(index, true)}}
+ >Close
+
+ ) : (
+ video
+ )) : video
}
+
+
+ )}
+ {commentMediaInfo?.url ? (
+ commentMediaInfo.type === "webpage" ? (
+
+
+ {comment.thumbnailUrl ? (
+ e.target.src = fallbackImgUrl} />
+ ) : null}
+ {commentMediaInfo?.type}
+
+
+ ) : commentMediaInfo.type === "image" ? (
+
+
+ e.target.src = fallbackImgUrl} />
- ) : null}
- {commentMediaInfo.type}
-
-
-
- ) : commentMediaInfo.type === "image" ? (
-
-
-
- e.target.src = fallbackImgUrl} />
- {commentMediaInfo.type}
-
-
-
- ) : commentMediaInfo.type === "video" ? (
-
-
- e.target.src = fallbackImgUrl} />
- {commentMediaInfo.type}
-
-
- ) : commentMediaInfo.type === "audio" ? (
-
-
- e.target.src = fallbackImgUrl} />
- {commentMediaInfo.type}
-
-
- ) : null
+
{commentMediaInfo?.type}
+
+
+ ) : commentMediaInfo.type === "video" ? (
+
+ {isMobileThumbnailClicked[index] ? (
+ e.target.src = fallbackImgUrl} />
+ ) : (
+ {handleThumbnailClick(index, true)}}
+ style={{cursor: "pointer"}}
+ id="video-thumbnail-mobile"
+ onError={(e) => e.target.src = fallbackImgUrl}
+ />
+ )}
+ {commentMediaInfo?.type === "video" || "iframe" ? (
+ isMobileThumbnailClicked[index] ? (
+
+ {handleThumbnailClick(index, true)}}
+ >Close
+
+ ) : (
+ video
+ )) : video
}
+
+ ) : commentMediaInfo.type === "audio" ? (
+
+ e.target.src = fallbackImgUrl} />
+ {commentMediaInfo?.type}
+
+ ) : null
+ ) : null}
+
) : null}
{comment.content ? (
diff --git a/src/utils/getCommentMediaInfo.js b/src/utils/getCommentMediaInfo.js
index 6d237b50..fc26ac3a 100644
--- a/src/utils/getCommentMediaInfo.js
+++ b/src/utils/getCommentMediaInfo.js
@@ -7,34 +7,80 @@ const getCommentMediaInfo = (comment) => {
if (comment?.link) {
try {
- new URL(comment.link);
+ const url = new URL(comment.link);
+ const host = url.hostname;
+ let embedUrl = null;
+
+ if (['youtube.com', 'www.youtube.com', 'youtu.be'].includes(host)) {
+ const videoId = host === 'youtu.be' ? url.pathname.slice(1) : url.searchParams.get('v');
+ embedUrl = `https://www.youtube-nocookie.com/embed/${videoId}`;
+ } else if (host.includes('odysee.com')) {
+ const pathComponents = url.pathname.split('/');
+ const channelAndId = pathComponents[1];
+ const videoAndId = pathComponents[2];
+ embedUrl = `https://odysee.com/$/embed/${channelAndId}/${videoAndId}`;
+
+ // TODO: add support for Rumble, video id is dynamic
+
+ // } else if (host.includes('rumble.com')) {
+ // const regex = /(\/v.+?)-/;
+ // const match = regex.exec(url.pathname);
+ // if (match) {
+ // const videoId = match[1].slice(1);
+ // embedUrl = `https://rumble.com/embed/${videoId}/?pub=4`;
+ // }
+
+
+ } else if (host.includes('bitchute.com')) {
+ const videoId = url.pathname.split('/')[2];
+ embedUrl = `https://www.bitchute.com/embed/${videoId}/`;
+ } else if (host.includes('streamable.com')) {
+ const videoId = url.pathname.split('/')[1];
+ embedUrl = `https://streamable.com/e/${videoId}?quality=highest`;
+
+ // TODO: Add support for Giphy (doesn't have thumbnails, size is variable)
+
+ // } else if (host.includes('giphy.com')) {
+ // const hyphenComponents = url.pathname.split('-');
+ // const gifId = hyphenComponents[hyphenComponents.length - 1];
+ // embedUrl = `https://giphy.com/embed/${gifId}`;
+ }
+
+ if (embedUrl) {
+ return {
+ url: comment.link,
+ embedUrl,
+ type: 'iframe',
+ thumbnail: comment.thumbnailUrl,
+ };
+ }
+
+ const mime = extName(url.pathname.replace('/', ''))[0]?.mime;
+
+ if (mime?.startsWith('image')) {
+ return {
+ url: comment.link,
+ type: 'image',
+ };
+ }
+
+ if (mime?.startsWith('video')) {
+ return {
+ url: comment.link,
+ type: 'video',
+ thumbnail: comment.thumbnailUrl,
+ };
+ }
+
+ if (mime?.startsWith('audio')) {
+ return {
+ url: comment.link,
+ type: 'audio',
+ };
+ }
} catch (error) {
- // console.error("Invalid URL:", comment.link);
return;
}
-
- const mime = extName(new URL(comment?.link).pathname.replace('/', ''))[0]?.mime;
-
- if (mime?.startsWith('image')) {
- return {
- url: comment.link,
- type: 'image',
- };
- }
-
- if (mime?.startsWith('video')) {
- return {
- url: comment.link,
- type: 'video',
- };
- }
-
- if (mime?.startsWith('audio')) {
- return {
- url: comment.link,
- type: 'audio',
- };
- }
}
if (comment?.thumbnailUrl && comment?.thumbnailUrl !== comment?.link) {