Merge pull request #285 from plebbit/development

Development
This commit is contained in:
plebeius.eth
2023-10-04 11:10:30 +02:00
committed by GitHub
18 changed files with 1937 additions and 906 deletions
+27 -2
View File
@@ -28,8 +28,18 @@ import packageJson from '../package.json';
const commitRef = process?.env?.REACT_APP_COMMIT_REF || '';
export default function App() {
const { bodyStyle, setBodyStyle, setDefaultSubplebbits, isCaptchaOpen, setIsCaptchaOpen, setIsSettingsOpen, selectedStyle, setShowPostForm, setShowPostFormLink } =
useGeneralStore((state) => state);
const {
bodyStyle,
setBodyStyle,
setDefaultSubplebbits,
setDefaultNsfwSubplebbits,
isCaptchaOpen,
setIsCaptchaOpen,
setIsSettingsOpen,
selectedStyle,
setShowPostForm,
setShowPostFormLink,
} = useGeneralStore((state) => state);
const location = useLocation();
const isElectron = window.electron && window.electron.isElectron;
@@ -116,6 +126,21 @@ export default function App() {
};
}, [setDefaultSubplebbits]);
// fetch default NSFW subplebbits
useEffect(() => {
let didCancel = false;
fetch('https://raw.githubusercontent.com/plebbit/temporary-default-subplebbits/master/subplebbits-nsfw.json', { cache: 'no-cache' })
.then((res) => res.json())
.then((res) => {
if (!didCancel) {
setDefaultNsfwSubplebbits(res);
}
});
return () => {
didCancel = true;
};
}, [setDefaultNsfwSubplebbits]);
// handle nested routes
useEffect(() => {
const path = location.pathname;
+259 -259
View File
@@ -9,307 +9,307 @@ import useAnonModeStore from '../../hooks/stores/useAnonModeStore';
import useGeneralStore from '../../hooks/stores/useGeneralStore';
const ReplyModal = ({ isOpen, closeModal }) => {
const {
captchaResponse,
setCaptchaResponse,
setChallengesArray,
setIsCaptchaOpen,
setPendingComment,
setPendingCommentIndex,
replyQuoteCid,
setResolveCaptchaPromise,
selectedAddress,
selectedParentCid,
selectedShortCid,
selectedStyle,
selectedText,
setSelectedText,
triggerInsertion,
} = useGeneralStore((state) => state);
const {
captchaResponse,
setCaptchaResponse,
setChallengesArray,
setIsCaptchaOpen,
setPendingComment,
setPendingCommentIndex,
replyQuoteCid,
setResolveCaptchaPromise,
selectedAddress,
selectedParentCid,
selectedShortCid,
selectedStyle,
selectedText,
setSelectedText,
triggerInsertion,
} = useGeneralStore((state) => state);
const { anonymousMode } = useAnonModeStore();
const { anonymousMode } = useAnonModeStore();
const account = useAccount();
const account = useAccount();
const [, setNewErrorMessage] = useError();
const [, setNewErrorMessage] = useError();
const nodeRef = useRef(null);
const nameRef = useRef();
const commentRef = useRef();
const linkRef = useRef();
const nodeRef = useRef(null);
const nameRef = useRef();
const commentRef = useRef();
const linkRef = useRef();
const [triggerPublishComment, setTriggerPublishComment] = useState(false);
const [isMobile, setIsMobile] = useState(window.innerWidth <= 480);
const [executeAnonMode, setExecuteAnonMode] = useState(false);
const [triggerPublishComment, setTriggerPublishComment] = useState(false);
const [isMobile, setIsMobile] = useState(window.innerWidth <= 480);
const [executeAnonMode, setExecuteAnonMode] = useState(false);
useAnonMode(selectedParentCid, anonymousMode && executeAnonMode);
useAnonMode(selectedParentCid, anonymousMode && executeAnonMode);
useEffect(() => {
const handleResize = () => setIsMobile(window.innerWidth <= 480);
window.addEventListener('resize', handleResize);
useEffect(() => {
const handleResize = () => setIsMobile(window.innerWidth <= 480);
window.addEventListener('resize', handleResize);
// Cleanup function
return () => {
window.removeEventListener('resize', handleResize);
};
}, [setIsMobile]);
// Cleanup function
return () => {
window.removeEventListener('resize', handleResize);
};
}, [setIsMobile]);
const onModalOpen = () => {
if (commentRef.current) {
if (selectedText) {
commentRef.current.value += '\n';
}
commentRef.current.focus();
const len = commentRef.current.value.length;
commentRef.current.setSelectionRange(len, len);
}
};
const onModalOpen = () => {
if (commentRef.current) {
if (selectedText) {
commentRef.current.value += '\n';
}
commentRef.current.focus();
const len = commentRef.current.value.length;
commentRef.current.setSelectionRange(len, len);
}
};
const insertAtCursor = (inputElement, valueToInsert) => {
const startPos = inputElement.selectionStart || inputElement.value.length;
const endPos = startPos + valueToInsert.length;
inputElement.setRangeText(valueToInsert, startPos, startPos, 'end');
inputElement.setSelectionRange(endPos, endPos);
};
const insertAtCursor = (inputElement, valueToInsert) => {
const startPos = inputElement.selectionStart || inputElement.value.length;
const endPos = startPos + valueToInsert.length;
inputElement.setRangeText(valueToInsert, startPos, startPos, 'end');
inputElement.setSelectionRange(endPos, endPos);
};
useEffect(() => {
if (replyQuoteCid && commentRef.current) {
const prefixedReplyQuoteCid = `c/${replyQuoteCid}\n`;
insertAtCursor(commentRef.current, prefixedReplyQuoteCid);
}
}, [triggerInsertion, replyQuoteCid]);
useEffect(() => {
if (replyQuoteCid && commentRef.current) {
const prefixedReplyQuoteCid = `c/${replyQuoteCid}\n`;
insertAtCursor(commentRef.current, prefixedReplyQuoteCid);
}
}, [triggerInsertion, replyQuoteCid]);
const getSelectedText = useCallback(() => {
const text = document.getSelection().toString();
setSelectedText(text ? `>${text}\n` : '');
}, [setSelectedText]);
const getSelectedText = useCallback(() => {
const text = document.getSelection().toString();
setSelectedText(text ? `>${text}\n` : '');
}, [setSelectedText]);
useEffect(() => {
if (isOpen) {
setTimeout(getSelectedText, 0);
} else {
setSelectedText('');
}
}, [isOpen, getSelectedText, setSelectedText]);
useEffect(() => {
if (isOpen) {
setTimeout(getSelectedText, 0);
} else {
setSelectedText('');
}
}, [isOpen, getSelectedText, setSelectedText]);
const onChallengeVerification = (challengeVerification) => {
if (challengeVerification.challengeSuccess === true) {
return;
} else if (challengeVerification.challengeSuccess === false) {
setNewErrorMessage(`Challenge Failed, reason: ${challengeVerification.reason}. Errors: ${challengeVerification.errors}`);
console.log('challenge failed', challengeVerification);
}
};
const onChallengeVerification = (challengeVerification) => {
if (challengeVerification.challengeSuccess === true) {
return;
} else if (challengeVerification.challengeSuccess === false) {
setNewErrorMessage(`Challenge Failed, reason: ${challengeVerification.reason}. Errors: ${challengeVerification.errors}`);
console.log('challenge failed', challengeVerification);
}
};
const onChallenge = async (challenges, comment) => {
setPendingComment(comment);
let challengeAnswers = [];
const onChallenge = async (challenges, comment) => {
setPendingComment(comment);
let challengeAnswers = [];
try {
challengeAnswers = await getChallengeAnswersFromUser(challenges);
} catch (error) {
setNewErrorMessage(error.message);
console.log(error);
}
if (challengeAnswers) {
await comment.publishChallengeAnswers(challengeAnswers);
}
};
try {
challengeAnswers = await getChallengeAnswersFromUser(challenges);
} catch (error) {
setNewErrorMessage(error.message);
console.log(error);
}
if (challengeAnswers) {
await comment.publishChallengeAnswers(challengeAnswers);
}
};
useEffect(() => {
setPublishCommentOptions((prevPublishCommentOptions) => ({
...prevPublishCommentOptions,
subplebbitAddress: selectedAddress,
}));
}, [selectedAddress]);
useEffect(() => {
setPublishCommentOptions((prevPublishCommentOptions) => ({
...prevPublishCommentOptions,
subplebbitAddress: selectedAddress,
}));
}, [selectedAddress]);
const [publishCommentOptions, setPublishCommentOptions] = useState({
subplebbitAddress: selectedAddress,
onChallenge,
onChallengeVerification,
onError: (error) => {
setNewErrorMessage(error.message);
console.log(error);
},
});
const [publishCommentOptions, setPublishCommentOptions] = useState({
subplebbitAddress: selectedAddress,
onChallenge,
onChallengeVerification,
onError: (error) => {
setNewErrorMessage(error.message);
console.log(error);
},
});
const { publishComment, index } = usePublishComment(publishCommentOptions);
const { publishComment, index } = usePublishComment(publishCommentOptions);
useEffect(() => {
if (index !== undefined) {
setPendingCommentIndex(index);
}
}, [index, setPendingCommentIndex]);
useEffect(() => {
if (index !== undefined) {
setPendingCommentIndex(index);
}
}, [index, setPendingCommentIndex]);
const resetFields = useCallback(() => {
if (nameRef.current) {
nameRef.current.value = '';
}
if (commentRef.current) {
commentRef.current.value = '';
}
if (linkRef.current) {
linkRef.current.value = '';
}
}, []);
const resetFields = useCallback(() => {
if (nameRef.current) {
nameRef.current.value = '';
}
if (commentRef.current) {
commentRef.current.value = '';
}
if (linkRef.current) {
linkRef.current.value = '';
}
}, []);
const handleSubmit = async (event) => {
event.preventDefault();
const handleSubmit = async (event) => {
event.preventDefault();
if (commentRef.current.value === '' && linkRef.current.value === '') {
setNewErrorMessage('Please enter a comment or link.');
return;
}
if (commentRef.current.value === '' && linkRef.current.value === '') {
setNewErrorMessage('Please enter a comment or link.');
return;
}
setPublishCommentOptions((prevPublishCommentOptions) => ({
...prevPublishCommentOptions,
author: {
displayName: nameRef.current.value || undefined,
...(anonymousMode ? {} : { address: account?.author.address }),
},
content: commentRef.current.value || undefined,
link: linkRef.current.value || undefined,
parentCid: selectedParentCid,
}));
setPublishCommentOptions((prevPublishCommentOptions) => ({
...prevPublishCommentOptions,
author: {
displayName: nameRef.current.value || undefined,
...(anonymousMode ? {} : { address: account?.author.address }),
},
content: commentRef.current.value || undefined,
link: linkRef.current.value || undefined,
parentCid: selectedParentCid,
}));
setTriggerPublishComment(true);
};
setTriggerPublishComment(true);
};
const updateSigner = useCallback(async () => {
if (anonymousMode) {
setExecuteAnonMode(true);
const updateSigner = useCallback(async () => {
if (anonymousMode) {
setExecuteAnonMode(true);
let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {};
let signer;
let storedSigners = JSON.parse(localStorage.getItem('storedSigners')) || {};
let signer;
if (!storedSigners[selectedParentCid]) {
signer = await account?.plebbit.createSigner();
storedSigners[selectedParentCid] = { privateKey: signer?.privateKey, address: signer?.address };
localStorage.setItem('storedSigners', JSON.stringify(storedSigners));
} else {
const signerPrivateKey = storedSigners[selectedParentCid].privateKey;
if (!storedSigners[selectedParentCid]) {
signer = await account?.plebbit.createSigner();
storedSigners[selectedParentCid] = { privateKey: signer?.privateKey, address: signer?.address };
localStorage.setItem('storedSigners', JSON.stringify(storedSigners));
} else {
const signerPrivateKey = storedSigners[selectedParentCid].privateKey;
try {
signer = await account?.plebbit.createSigner({ type: 'ed25519', privateKey: signerPrivateKey });
} catch (error) {
console.log(error);
}
}
try {
signer = await account?.plebbit.createSigner({ type: 'ed25519', privateKey: signerPrivateKey });
} catch (error) {
console.log(error);
}
}
setPublishCommentOptions((prevPublishCommentOptions) => {
const newPublishCommentOptions = {
...prevPublishCommentOptions,
signer,
author: {
...prevPublishCommentOptions.author,
address: signer?.address,
},
};
setPublishCommentOptions((prevPublishCommentOptions) => {
const newPublishCommentOptions = {
...prevPublishCommentOptions,
signer,
author: {
...prevPublishCommentOptions.author,
address: signer?.address,
},
};
if (JSON.stringify(prevPublishCommentOptions) !== JSON.stringify(newPublishCommentOptions)) {
return newPublishCommentOptions;
}
if (JSON.stringify(prevPublishCommentOptions) !== JSON.stringify(newPublishCommentOptions)) {
return newPublishCommentOptions;
}
return prevPublishCommentOptions;
});
}
}, [selectedParentCid, anonymousMode, account]);
return prevPublishCommentOptions;
});
}
}, [selectedParentCid, anonymousMode, account]);
useEffect(() => {
if (anonymousMode) {
updateSigner();
}
}, [updateSigner, anonymousMode]);
useEffect(() => {
if (anonymousMode) {
updateSigner();
}
}, [updateSigner, anonymousMode]);
useEffect(() => {
if (publishCommentOptions && triggerPublishComment) {
(async () => {
await publishComment();
resetFields();
closeModal();
})();
setTriggerPublishComment(false);
setExecuteAnonMode(false);
}
}, [publishCommentOptions, triggerPublishComment, publishComment, resetFields, closeModal]);
useEffect(() => {
if (publishCommentOptions && triggerPublishComment) {
(async () => {
await publishComment();
resetFields();
closeModal();
})();
setTriggerPublishComment(false);
setExecuteAnonMode(false);
}
}, [publishCommentOptions, triggerPublishComment, publishComment, resetFields, closeModal]);
const getChallengeAnswersFromUser = async (challenges) => {
setChallengesArray(challenges);
const getChallengeAnswersFromUser = async (challenges) => {
setChallengesArray(challenges);
return new Promise((resolve, reject) => {
const imageString = challenges?.challenges[0].challenge;
const imageSource = `data:image/png;base64,${imageString}`;
const challengeImg = new Image();
challengeImg.src = imageSource;
return new Promise((resolve, reject) => {
const imageString = challenges?.challenges[0].challenge;
const imageSource = `data:image/png;base64,${imageString}`;
const challengeImg = new Image();
challengeImg.src = imageSource;
challengeImg.onload = () => {
setIsCaptchaOpen(true);
challengeImg.onload = () => {
setIsCaptchaOpen(true);
const handleKeyDown = async (event) => {
if (event.key === 'Enter') {
const currentCaptchaResponse = captchaResponse;
resolve(currentCaptchaResponse);
setIsCaptchaOpen(false);
document.removeEventListener('keydown', handleKeyDown);
event.preventDefault();
}
};
const handleKeyDown = async (event) => {
if (event.key === 'Enter') {
const currentCaptchaResponse = captchaResponse;
resolve(currentCaptchaResponse);
setIsCaptchaOpen(false);
document.removeEventListener('keydown', handleKeyDown);
event.preventDefault();
}
};
setCaptchaResponse('');
document.addEventListener('keydown', handleKeyDown);
setCaptchaResponse('');
document.addEventListener('keydown', handleKeyDown);
setResolveCaptchaPromise(resolve);
};
setResolveCaptchaPromise(resolve);
};
challengeImg.onerror = () => {
reject(setNewErrorMessage('Could not load challenges'));
};
});
};
challengeImg.onerror = () => {
reject(setNewErrorMessage('Could not load challenges'));
};
});
};
return (
<StyledModal
isOpen={isOpen}
onAfterOpen={onModalOpen}
onRequestClose={closeModal}
contentLabel='Reply Modal'
shouldCloseOnEsc={true}
shouldCloseOnOverlayClick={isMobile}
selectedStyle={selectedStyle}
overlayClassName='overlay'
style={isMobile ? { overlay: { backgroundColor: 'rgba(0,0,0,.25)' } } : { overlay: { backgroundColor: 'rgba(0,0,0,0)' } }}
>
<Draggable handle='.modal-header' nodeRef={nodeRef} disabled={isMobile}>
<div className='modal-content' ref={nodeRef}>
<div className='modal-header'>
Reply to c/{selectedShortCid}
<button className='icon' onClick={() => closeModal()} title='close' />
</div>
<div id='form'>
<div>
{account?.author.displayName ? (
<input id='name' type='text' defaultValue={account?.author?.displayName} ref={nameRef} />
) : (
<input id='name' type='text' placeholder='Anonymous' ref={nameRef} />
)}
</div>
<div>
<input id='name' type='text' placeholder='Embed link' ref={linkRef} />
</div>
<div className='textarea-wrapper'>
<span className='fixed-text'>{`c/${selectedShortCid}`}</span>
<textarea className='textarea' rows='4' placeholder='Comment' defaultValue={selectedText} wrap='soft' ref={commentRef} />
</div>
<div>
<button id='next' onClick={handleSubmit}>
Post
</button>
</div>
</div>
</div>
</Draggable>
</StyledModal>
);
return (
<StyledModal
isOpen={isOpen}
onAfterOpen={onModalOpen}
onRequestClose={closeModal}
contentLabel='Reply Modal'
shouldCloseOnEsc={true}
shouldCloseOnOverlayClick={isMobile}
selectedStyle={selectedStyle}
overlayClassName='overlay'
style={isMobile ? { overlay: { backgroundColor: 'rgba(0,0,0,.25)' } } : { overlay: { backgroundColor: 'rgba(0,0,0,0)' } }}
>
<Draggable handle='.modal-header' nodeRef={nodeRef} disabled={isMobile}>
<div className='modal-content' ref={nodeRef}>
<div className='modal-header'>
Reply to c/{selectedShortCid}
<button className='icon' onClick={() => closeModal()} title='close' />
</div>
<div id='form'>
<div>
{account?.author.displayName ? (
<input id='name' type='text' defaultValue={account?.author?.displayName} ref={nameRef} />
) : (
<input id='name' type='text' placeholder='Anonymous' ref={nameRef} />
)}
</div>
<div>
<input id='name' type='text' placeholder='Link' ref={linkRef} />
</div>
<div className='textarea-wrapper'>
<span className='fixed-text'>{`c/${selectedShortCid}`}</span>
<textarea className='textarea' rows='4' placeholder='Comment' defaultValue={selectedText} wrap='soft' ref={commentRef} />
</div>
<div>
<button id='next' onClick={handleSubmit}>
Post
</button>
</div>
</div>
</div>
</Draggable>
</StyledModal>
);
};
Modal.setAppElement('#root');
@@ -44,7 +44,6 @@ export const GlobalStyle = createGlobalStyle`
.poster-address {
display: inline-block;
overflow: clip;
}
.author-address-hidden {
+127 -58
View File
@@ -44,7 +44,7 @@ export const Search = styled.div`
text-align: center;
margin-bottom: 20px;
input[type="text"] {
input[type='text'] {
width: 400px;
height: 30px;
font-size: 18px;
@@ -60,27 +60,27 @@ export const Search = styled.div`
font-family: arial, helvetica, sans-serif;
}
input[type="submit"] {
width: 60px;
input[type='submit'] {
width: 70px;
height: 30px;
font-size: 14px;
margin-left: 5px;
}
@-moz-document url-prefix() {
input[type="submit"] {
input[type='submit'] {
vertical-align: top;
}
}
@media screen and (-webkit-min-device-pixel-ratio:0) {
input[type="submit"] {
@media screen and (-webkit-min-device-pixel-ratio: 0) {
input[type='submit'] {
vertical-align: center;
}
}
@media not all and (min-resolution:.001dpcm) {
input[type="submit"] {
@media not all and (min-resolution: 0.001dpcm) {
input[type='submit'] {
vertical-align: top;
}
}
@@ -88,7 +88,7 @@ export const Search = styled.div`
@media only screen and (max-width: 480px) {
text-align: center;
input[type="text"] {
input[type='text'] {
width: 80%;
height: 35px;
font-size: 20px;
@@ -96,18 +96,17 @@ export const Search = styled.div`
box-sizing: border-box;
border-radius: 0;
}
input[type="submit"] {
input[type='submit'] {
height: 35px;
font-size: 14px;
padding: 5px;
box-sizing: border-box;
vertical-align: top;
width: 60px;
width: 70px;
-webkit-appearance: none;
}
}
`;
export const Page = styled.div`
@@ -119,15 +118,15 @@ export const About = styled.div`
background: #fff;
color: #000;
border: 1px solid;
margin-bottom: .5em;
padding-bottom: .5em;
margin-bottom: 0.5em;
padding-bottom: 0.5em;
`;
export const AboutTitle = styled.div`
background: #800;
color: #fff;
position: relative;
padding-left: .5em;
padding-left: 0.5em;
line-height: 2em;
h2 {
@@ -141,8 +140,8 @@ export const AboutTitle = styled.div`
export const AboutContent = styled.div`
line-height: 1.5em;
font-size: 93%;
padding: .5em;
padding-top: .25em;
padding: 0.5em;
padding-top: 0.25em;
padding-bottom: 0;
min-height: 91px;
@@ -165,39 +164,110 @@ export const AboutContent = styled.div`
}
`;
export const Boards = styled.div`
export const BoardsBox = styled.div`
border: 1px solid;
margin: 0;
padding: 0;
padding-bottom: .5em;
padding-bottom: 0.5em;
background: #fff;
word-wrap: break-word;
margin-bottom: 6px;
#subscriptions {
text-align: left;
&:after {
content: '';
display: table;
clear: both;
}
`;
export const BoardsTitle = styled.div`
background: #fca;
color: #800;
position: relative;
padding-left: .5em;
line-height: 2em;
.boxbar {
background: #fca;
color: #800;
padding-left: 0.5em;
line-height: 2em;
h2 {
font-size: 131%;
font-weight: 700;
margin: 0;
padding: 0;
h2 {
font-size: 131%;
font-weight: 700;
margin: 0;
padding: 0;
}
}
.boxcontent {
font-size: 93%;
padding: 0.5em;
padding-top: 0.25em;
padding-bottom: 0;
line-height: 130%;
.column {
float: left;
width: 163px;
margin-right: 20px;
overflow: hidden;
h3 {
font-size: 100%;
font-weight: 700;
}
ul {
padding: 0;
margin: 0;
li {
list-style: none;
white-space: nowrap;
a {
color: #800;
text-decoration: none;
:hover {
text-decoration: underline;
color: #e00;
}
}
}
.disconnected {
width: 13px;
margin: 0 2px -3px 0;
position: relative;
}
}
}
#button {
color: #800;
font-weight: 700;
text-decoration: none;
cursor: pointer;
:hover {
color: #e00;
}
}
}
@media (max-width: 480px) {
.boxbar {
padding-left: 0.25em;
}
.boxcontent {
font-size: 1.05em;
padding: 0.25em;
line-height: 2em;
.column {
width: 44%;
margin-bottom: 10px;
margin-right: 20px;
}
}
}
`;
export const BoardsContent = styled.div`
font-size: 93%;
padding: .5em;
padding-top: .25em;
padding: 0.5em;
padding-top: 0.25em;
padding-bottom: 0;
line-height: 130%;
text-align: center;
@@ -225,19 +295,19 @@ export const BoardsContent = styled.div`
}
.board-avatar-container {
width: 150px;
height: 150px;
width: auto;
height: auto;
border: 1px solid #800;
display: inline-block;
overflow: hidden;
position: relative;
line-height: 0;
}
.board-avatar-container img.board-avatar {
width: 100%;
height: 100%;
object-fit: cover;
img,
video {
max-width: 150px;
max-height: 150px;
}
.offline-indicator {
@@ -265,7 +335,7 @@ export const BoardsContent = styled.div`
:hover {
text-decoration: underline;
color: #e00
color: #e00;
}
}
@@ -280,7 +350,8 @@ export const BoardsContent = styled.div`
}
@media (max-width: 480px) {
.boardlink, #view-all {
.boardlink,
#view-all {
font-size: 1.2em;
}
@@ -302,15 +373,13 @@ export const BoardsContent = styled.div`
position: absolute;
}
}
`;
export const Footer = styled.div`
font-size: 93%;
text-align: center;
clear: both;
padding-top: .5em;
padding-top: 0.5em;
padding-bottom: 2em;
ul {
@@ -320,7 +389,7 @@ export const Footer = styled.div`
width: 750px;
padding: 0;
}
li {
background: #fed;
display: block;
@@ -331,7 +400,7 @@ export const Footer = styled.div`
margin-top: -1px;
list-style: none;
}
.fill {
border-top: 1x solid;
border-right: 0;
@@ -340,16 +409,16 @@ export const Footer = styled.div`
background: #ffe;
width: 10.5%;
}
.first {
border-left: 1px solid;
}
a {
color: #800;
text-decoration: none;
}
@media (max-device-width: 640px) {
padding-top: 2em;
padding-bottom: 3em;
@@ -386,4 +455,4 @@ export const Footer = styled.div`
text-decoration: underline;
}
}
`;
`;
+203 -7
View File
@@ -607,7 +607,7 @@ const All = () => {
window.electron && window.electron.isElectron
? setIsCreateBoardOpen(true)
: alert(
'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n',
'HOW TO CREATE A BOARD (currently via CLI only):\n\n(1) have a computer you can use as server, because users will connect to your board peer-to-peer;\n\n(2) go to https://github.com/plebbit/plebbit-cli#install and follow the instructions to run your daemon, create a subplebbit (board) and edit its settings;\n\n(3) users can always connect to your board via its address, but it can be added below by submitting a pull request here: https://github.com/plebbit/temporary-default-subplebbits. This will be automated with a plebbit DAO using the plebbit token.',
);
}}
>
@@ -639,7 +639,7 @@ const All = () => {
style={{ cursor: 'pointer' }}
onClick={() =>
alert(
'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n',
'HOW TO CREATE A BOARD (currently via CLI only):\n\n(1) have a computer you can use as server, because users will connect to your board peer-to-peer;\n\n(2) go to https://github.com/plebbit/plebbit-cli#install and follow the instructions to run your daemon, create a subplebbit (board) and edit its settings;\n\n(3) users can always connect to your board via its address, but it can be added below by submitting a pull request here: https://github.com/plebbit/temporary-default-subplebbits. This will be automated with a plebbit DAO using the plebbit token.',
)
}
>
@@ -1214,7 +1214,56 @@ const All = () => {
thread.content?.length > 1000 ? (
<Fragment key={`fragment5-${index}`}>
<blockquote key={`bq-${index}`}>
<Post content={thread.content?.slice(0, 1000)} key={`post-${index}`} />
<Post
key={`post-${thread.cid}`}
content={thread.content?.slice(0, 1000)}
postQuoteRef={(quoteShortParentCid, ref) => {
postRefs.current[quoteShortParentCid] = ref;
}}
postQuoteOnClick={(quoteShortParentCid) => {
handleQuoteClick(thread, quoteShortParentCid, null);
}}
postQuoteOnOver={(quoteShortParentCid) => {
const quoteParentCid = cidTracker[quoteShortParentCid];
if (outOfViewCid !== quoteParentCid) {
handleQuoteHover(thread, 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);
}}
/>
<span key={`ttl-s-${index}`} className='ttl'>
{' '}
(...)
@@ -1237,7 +1286,56 @@ const All = () => {
</Fragment>
) : (
<blockquote key={`bq-${index}`}>
<Post content={thread.content} key={`post-${index}`} />
<Post
key={`post-${thread.cid}`}
content={thread.content}
postQuoteRef={(quoteShortParentCid, ref) => {
postRefs.current[quoteShortParentCid] = ref;
}}
postQuoteOnClick={(quoteShortParentCid) => {
handleQuoteClick(thread, quoteShortParentCid, null);
}}
postQuoteOnOver={(quoteShortParentCid) => {
const quoteParentCid = cidTracker[quoteShortParentCid];
if (outOfViewCid !== quoteParentCid) {
handleQuoteHover(thread, 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);
}}
/>
<EditLabel key={`edit-label-thread-${index}`} commentCid={thread.cid} className='ttl' />
<StateLabel key={`state-label-thread-${index}`} commentIndex={thread.index} className='ttl ellipsis' />
</blockquote>
@@ -2431,7 +2529,56 @@ const All = () => {
thread.content?.length > 500 ? (
<Fragment key={`fragment12-${index}`}>
<blockquote key={`mob-bq-${index}`} className='post-message-mobile'>
<Post content={thread.content?.slice(0, 500)} key={`post-mobile-${index}`} />
<Post
key={`post-mobile-${thread.cid}`}
content={thread.content?.slice(0, 500)}
postQuoteRef={(quoteShortParentCid, ref) => {
postRefs.current[quoteShortParentCid] = ref;
}}
postQuoteOnClick={(quoteShortParentCid) => {
handleQuoteClick(thread, quoteShortParentCid, null);
}}
postQuoteOnOver={(quoteShortParentCid) => {
const quoteParentCid = cidTracker[quoteShortParentCid];
if (outOfViewCid !== quoteParentCid) {
handleQuoteHover(thread, 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);
}}
/>
<span key={`mob-ttl-s-${index}`} className='ttl'>
{' '}
(...)
@@ -2454,7 +2601,56 @@ const All = () => {
</Fragment>
) : (
<blockquote key={`mob-bq-${index}`} className='post-message-mobile'>
<Post content={thread.content} key={`post-mobile-${index}`} />
<Post
key={`post-mobile-${thread.cid}`}
content={thread.content}
postQuoteRef={(quoteShortParentCid, ref) => {
postRefs.current[quoteShortParentCid] = ref;
}}
postQuoteOnClick={(quoteShortParentCid) => {
handleQuoteClick(thread, quoteShortParentCid, null);
}}
postQuoteOnOver={(quoteShortParentCid) => {
const quoteParentCid = cidTracker[quoteShortParentCid];
if (outOfViewCid !== quoteParentCid) {
handleQuoteHover(thread, 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);
}}
/>
<EditLabel key={`edit-label-thread-mob-${index}`} commentCid={thread.cid} className='ttl' />
<StateLabel key={`state-label-thread-mob-${index}`} commentIndex={thread.index} className='ttl ellipsis' />
</blockquote>
@@ -3318,7 +3514,7 @@ const All = () => {
window.electron && window.electron.isElectron
? setIsCreateBoardOpen(true)
: alert(
'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n',
'HOW TO CREATE A BOARD (currently via CLI only):\n\n(1) have a computer you can use as server, because users will connect to your board peer-to-peer;\n\n(2) go to https://github.com/plebbit/plebbit-cli#install and follow the instructions to run your daemon, create a subplebbit (board) and edit its settings;\n\n(3) users can always connect to your board via its address, but it can be added below by submitting a pull request here: https://github.com/plebbit/temporary-default-subplebbits. This will be automated with a plebbit DAO using the plebbit token.',
);
}}
>
+3 -3
View File
@@ -849,7 +849,7 @@ const AllCatalog = () => {
window.electron && window.electron.isElectron
? setIsCreateBoardOpen(true)
: alert(
'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n',
'HOW TO CREATE A BOARD (currently via CLI only):\n\n(1) have a computer you can use as server, because users will connect to your board peer-to-peer;\n\n(2) go to https://github.com/plebbit/plebbit-cli#install and follow the instructions to run your daemon, create a subplebbit (board) and edit its settings;\n\n(3) users can always connect to your board via its address, but it can be added below by submitting a pull request here: https://github.com/plebbit/temporary-default-subplebbits. This will be automated with a plebbit DAO using the plebbit token.',
);
}}
>
@@ -881,7 +881,7 @@ const AllCatalog = () => {
style={{ cursor: 'pointer' }}
onClick={() =>
alert(
'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n',
'HOW TO CREATE A BOARD (currently via CLI only):\n\n(1) have a computer you can use as server, because users will connect to your board peer-to-peer;\n\n(2) go to https://github.com/plebbit/plebbit-cli#install and follow the instructions to run your daemon, create a subplebbit (board) and edit its settings;\n\n(3) users can always connect to your board via its address, but it can be added below by submitting a pull request here: https://github.com/plebbit/temporary-default-subplebbits. This will be automated with a plebbit DAO using the plebbit token.',
)
}
>
@@ -1037,7 +1037,7 @@ const AllCatalog = () => {
window.electron && window.electron.isElectron
? setIsCreateBoardOpen(true)
: alert(
'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n',
'HOW TO CREATE A BOARD (currently via CLI only):\n\n(1) have a computer you can use as server, because users will connect to your board peer-to-peer;\n\n(2) go to https://github.com/plebbit/plebbit-cli#install and follow the instructions to run your daemon, create a subplebbit (board) and edit its settings;\n\n(3) users can always connect to your board via its address, but it can be added below by submitting a pull request here: https://github.com/plebbit/temporary-default-subplebbits. This will be automated with a plebbit DAO using the plebbit token.',
);
}}
>
+204 -8
View File
@@ -765,7 +765,7 @@ const Board = () => {
window.electron && window.electron.isElectron
? setIsCreateBoardOpen(true)
: alert(
'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n',
'HOW TO CREATE A BOARD (currently via CLI only):\n\n(1) have a computer you can use as server, because users will connect to your board peer-to-peer;\n\n(2) go to https://github.com/plebbit/plebbit-cli#install and follow the instructions to run your daemon, create a subplebbit (board) and edit its settings;\n\n(3) users can always connect to your board via its address, but it can be added below by submitting a pull request here: https://github.com/plebbit/temporary-default-subplebbits. This will be automated with a plebbit DAO using the plebbit token.',
);
}}
>
@@ -800,7 +800,7 @@ const Board = () => {
window.electron && window.electron.isElectron
? setIsCreateBoardOpen(true)
: alert(
'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n',
'HOW TO CREATE A BOARD (currently via CLI only):\n\n(1) have a computer you can use as server, because users will connect to your board peer-to-peer;\n\n(2) go to https://github.com/plebbit/plebbit-cli#install and follow the instructions to run your daemon, create a subplebbit (board) and edit its settings;\n\n(3) users can always connect to your board via its address, but it can be added below by submitting a pull request here: https://github.com/plebbit/temporary-default-subplebbits. This will be automated with a plebbit DAO using the plebbit token.',
);
}}
>
@@ -884,7 +884,7 @@ const Board = () => {
</td>
</tr>
<tr data-type='File'>
<td>Embed File</td>
<td>Link</td>
<td>
<input name='embed' type='text' tabIndex={7} placeholder='Paste link' ref={linkRef} />
<button
@@ -2247,7 +2247,56 @@ const Board = () => {
thread.content?.length > 1000 ? (
<Fragment key={`fragment5-${index}`}>
<blockquote key={`bq-${index}`}>
<Post content={thread.content?.slice(0, 1000)} key={`post-${index}`} />
<Post
key={`post-${thread.cid}`}
content={thread.content?.slice(0, 1000)}
postQuoteRef={(quoteShortParentCid, ref) => {
postRefs.current[quoteShortParentCid] = ref;
}}
postQuoteOnClick={(quoteShortParentCid) => {
handleQuoteClick(thread, quoteShortParentCid, null);
}}
postQuoteOnOver={(quoteShortParentCid) => {
const quoteParentCid = cidTracker[quoteShortParentCid];
if (outOfViewCid !== quoteParentCid) {
handleQuoteHover(thread, 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);
}}
/>
<span key={`ttl-s-${index}`} className='ttl'>
{' '}
(...)
@@ -2270,7 +2319,56 @@ const Board = () => {
</Fragment>
) : (
<blockquote key={`bq-${index}`}>
<Post content={thread.content} key={`post-${index}`} />
<Post
key={`post-${thread.cid}`}
content={thread.content}
postQuoteRef={(quoteShortParentCid, ref) => {
postRefs.current[quoteShortParentCid] = ref;
}}
postQuoteOnClick={(quoteShortParentCid) => {
handleQuoteClick(thread, quoteShortParentCid, null);
}}
postQuoteOnOver={(quoteShortParentCid) => {
const quoteParentCid = cidTracker[quoteShortParentCid];
if (outOfViewCid !== quoteParentCid) {
handleQuoteHover(thread, 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);
}}
/>
<EditLabel key={`edit-label-thread-${index}`} commentCid={thread.cid} className='ttl' />
<StateLabel key={`state-label-thread-${index}`} commentIndex={thread.index} className='ttl ellipsis' />
</blockquote>
@@ -3488,7 +3586,56 @@ const Board = () => {
thread.content?.length > 500 ? (
<Fragment key={`fragment12-${index}`}>
<blockquote key={`mob-bq-${index}`} className='post-message-mobile'>
<Post content={thread.content?.slice(0, 500)} key={`post-mobile-${index}`} />
<Post
key={`post-mobile-${thread.cid}`}
content={thread.content?.slice(0, 500)}
postQuoteRef={(quoteShortParentCid, ref) => {
postRefs.current[quoteShortParentCid] = ref;
}}
postQuoteOnClick={(quoteShortParentCid) => {
handleQuoteClick(thread, quoteShortParentCid, null);
}}
postQuoteOnOver={(quoteShortParentCid) => {
const quoteParentCid = cidTracker[quoteShortParentCid];
if (outOfViewCid !== quoteParentCid) {
handleQuoteHover(thread, 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);
}}
/>
<span key={`mob-ttl-s-${index}`} className='ttl'>
{' '}
(...)
@@ -3511,7 +3658,56 @@ const Board = () => {
</Fragment>
) : (
<blockquote key={`mob-bq-${index}`} className='post-message-mobile'>
<Post content={thread.content} key={`post-mobile-${index}`} />
<Post
key={`post-mobile-${thread.cid}`}
content={thread.content?.slice(0, 1000)}
postQuoteRef={(quoteShortParentCid, ref) => {
postRefs.current[quoteShortParentCid] = ref;
}}
postQuoteOnClick={(quoteShortParentCid) => {
handleQuoteClick(thread, quoteShortParentCid, null);
}}
postQuoteOnOver={(quoteShortParentCid) => {
const quoteParentCid = cidTracker[quoteShortParentCid];
if (outOfViewCid !== quoteParentCid) {
handleQuoteHover(thread, 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);
}}
/>
<EditLabel key={`edit-label-thread-mob-${index}`} commentCid={thread.cid} className='ttl' />
<StateLabel key={`state-label-thread-mob-${index}`} commentIndex={thread.index} className='ttl ellipsis' />
</blockquote>
@@ -4370,7 +4566,7 @@ const Board = () => {
window.electron && window.electron.isElectron
? setIsCreateBoardOpen(true)
: alert(
'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n',
'HOW TO CREATE A BOARD (currently via CLI only):\n\n(1) have a computer you can use as server, because users will connect to your board peer-to-peer;\n\n(2) go to https://github.com/plebbit/plebbit-cli#install and follow the instructions to run your daemon, create a subplebbit (board) and edit its settings;\n\n(3) users can always connect to your board via its address, but it can be added below by submitting a pull request here: https://github.com/plebbit/temporary-default-subplebbits. This will be automated with a plebbit DAO using the plebbit token.',
);
}}
>
+4 -4
View File
@@ -1534,7 +1534,7 @@ const Catalog = () => {
window.electron && window.electron.isElectron
? setIsCreateBoardOpen(true)
: alert(
'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n',
'HOW TO CREATE A BOARD (currently via CLI only):\n\n(1) have a computer you can use as server, because users will connect to your board peer-to-peer;\n\n(2) go to https://github.com/plebbit/plebbit-cli#install and follow the instructions to run your daemon, create a subplebbit (board) and edit its settings;\n\n(3) users can always connect to your board via its address, but it can be added below by submitting a pull request here: https://github.com/plebbit/temporary-default-subplebbits. This will be automated with a plebbit DAO using the plebbit token.',
);
}}
>
@@ -1567,7 +1567,7 @@ const Catalog = () => {
style={{ cursor: 'pointer' }}
onClick={() =>
alert(
'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n',
'HOW TO CREATE A BOARD (currently via CLI only):\n\n(1) have a computer you can use as server, because users will connect to your board peer-to-peer;\n\n(2) go to https://github.com/plebbit/plebbit-cli#install and follow the instructions to run your daemon, create a subplebbit (board) and edit its settings;\n\n(3) users can always connect to your board via its address, but it can be added below by submitting a pull request here: https://github.com/plebbit/temporary-default-subplebbits. This will be automated with a plebbit DAO using the plebbit token.',
)
}
>
@@ -1653,7 +1653,7 @@ const Catalog = () => {
</td>
</tr>
<tr data-type='File'>
<td>Embed File</td>
<td>Link</td>
<td>
<input name='embed' type='text' tabIndex={7} placeholder='Paste link' ref={linkRef} />
<button
@@ -1828,7 +1828,7 @@ const Catalog = () => {
window.electron && window.electron.isElectron
? setIsCreateBoardOpen(true)
: alert(
'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n',
'HOW TO CREATE A BOARD (currently via CLI only):\n\n(1) have a computer you can use as server, because users will connect to your board peer-to-peer;\n\n(2) go to https://github.com/plebbit/plebbit-cli#install and follow the instructions to run your daemon, create a subplebbit (board) and edit its settings;\n\n(3) users can always connect to your board via its address, but it can be added below by submitting a pull request here: https://github.com/plebbit/temporary-default-subplebbits. This will be automated with a plebbit DAO using the plebbit token.',
);
}}
>
+3 -3
View File
@@ -196,7 +196,7 @@ const Description = () => {
window.electron && window.electron.isElectron
? setIsCreateBoardOpen(true)
: alert(
'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n',
'HOW TO CREATE A BOARD (currently via CLI only):\n\n(1) have a computer you can use as server, because users will connect to your board peer-to-peer;\n\n(2) go to https://github.com/plebbit/plebbit-cli#install and follow the instructions to run your daemon, create a subplebbit (board) and edit its settings;\n\n(3) users can always connect to your board via its address, but it can be added below by submitting a pull request here: https://github.com/plebbit/temporary-default-subplebbits. This will be automated with a plebbit DAO using the plebbit token.',
);
}}
>
@@ -229,7 +229,7 @@ const Description = () => {
style={{ cursor: 'pointer' }}
onClick={() =>
alert(
'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n',
'HOW TO CREATE A BOARD (currently via CLI only):\n\n(1) have a computer you can use as server, because users will connect to your board peer-to-peer;\n\n(2) go to https://github.com/plebbit/plebbit-cli#install and follow the instructions to run your daemon, create a subplebbit (board) and edit its settings;\n\n(3) users can always connect to your board via its address, but it can be added below by submitting a pull request here: https://github.com/plebbit/temporary-default-subplebbits. This will be automated with a plebbit DAO using the plebbit token.',
)
}
>
@@ -719,7 +719,7 @@ const Description = () => {
window.electron && window.electron.isElectron
? setIsCreateBoardOpen(true)
: alert(
'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n',
'HOW TO CREATE A BOARD (currently via CLI only):\n\n(1) have a computer you can use as server, because users will connect to your board peer-to-peer;\n\n(2) go to https://github.com/plebbit/plebbit-cli#install and follow the instructions to run your daemon, create a subplebbit (board) and edit its settings;\n\n(3) users can always connect to your board via its address, but it can be added below by submitting a pull request here: https://github.com/plebbit/temporary-default-subplebbits. This will be automated with a plebbit DAO using the plebbit token.',
);
}}
>
+216 -98
View File
@@ -1,36 +1,93 @@
import React, { Fragment, useEffect, useRef, useState } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import { Helmet } from 'react-helmet-async';
import { useAccount, useSubplebbit } from '@plebbit/plebbit-react-hooks';
import { useAccount, useComment, useSubplebbit, useSubplebbits } from '@plebbit/plebbit-react-hooks';
import { Link, useNavigate } from 'react-router-dom';
import { Container, Header, Logo, Page, Search, About, AboutTitle, AboutContent, Boards, BoardsTitle, BoardsContent, Footer } from '../styled/views/Home.styled';
import { Container, Header, Logo, Page, Search, About, AboutTitle, AboutContent, BoardsBox, BoardsContent, Footer } from '../styled/views/Home.styled';
import BoardAvatar from '../BoardAvatar';
import OfflineIndicator from '../OfflineIndicator';
import CreateBoardModal from '../modals/CreateBoardModal';
import useGeneralStore from '../../hooks/stores/useGeneralStore';
import packageJson from '../../../package.json';
import getCommentMediaInfo from '../../utils/getCommentMediaInfo';
import { Tooltip } from 'react-tooltip';
const { version } = packageJson;
const commitRef = process?.env?.REACT_APP_COMMIT_REF ? ` ${process.env.REACT_APP_COMMIT_REF.slice(0, 7)}` : '';
const SubplebbitTitle = ({ address }) => {
const subplebbitAddress = address;
const subplebbit = useSubplebbit({ subplebbitAddress });
const title = subplebbit.title ?? null;
const RecentThread = ({ commentCid }) => {
const comment = useComment({ commentCid });
const subplebbit = useSubplebbit({ subplebbitAddress: comment?.subplebbitAddress });
const { setSelectedAddress, setSelectedTitle } = useGeneralStore((state) => state);
const commentMediaInfo = getCommentMediaInfo(comment);
const isMediaShowed =
comment.link &&
commentMediaInfo &&
(commentMediaInfo.type === 'image' ||
commentMediaInfo.type === 'video' ||
(commentMediaInfo.type === 'webpage' && commentMediaInfo.thumbnail) ||
(commentMediaInfo.type === 'iframe' && commentMediaInfo.thumbnail))
? true
: false;
return <>{title ? <span>{title}</span> : <span style={{ userSelect: 'none' }}>&nbsp;</span>}</>;
return (
<>
{isMediaShowed && comment.replyCount > 0 && !comment.removed ? (
<div className='board'>
<div className='board-title' key='board-title'>
<span>{subplebbit.title || subplebbit.address}</span>
</div>
<div className='board-avatar-container' key='board-avatar-container'>
<Link
to={`/p/${comment?.subplebbitAddress}/c/${comment?.cid}`}
key='link'
onClick={() => {
setSelectedTitle(subplebbit?.title);
setSelectedAddress(comment?.subplebbitAddress);
window.scrollTo(0, 0);
}}
>
{commentMediaInfo?.type === 'webpage' && comment.thumbnailUrl ? (
<img className='board-avatar' src={commentMediaInfo?.thumbnail} alt='post' />
) : commentMediaInfo?.type === 'image' ? (
<img className='board-avatar' src={commentMediaInfo?.url} alt='post' />
) : commentMediaInfo?.type === 'video' ? (
<video className='board-avatar' src={commentMediaInfo?.url} alt='post' />
) : commentMediaInfo?.type === 'iframe' ? (
<img className='board-avatar' src={commentMediaInfo?.thumbnail} alt='post' />
) : (
<BoardAvatar address={comment.subplebbitAddress} />
)}
</Link>
<OfflineIndicator address={comment?.subplebbitAddress} className='offline-indicator' tooltipPlace='top' key='oi2' />
</div>
<div className='board-text' key='bt'>
{comment?.title ? <b>{comment?.title}</b> : null}
{comment?.content ? (comment.content.length > 99 ? `: ${comment.content.substring(0, 99)}...` : `: ${comment.content}`) : null}
</div>
</div>
) : null}
</>
);
};
const Home = () => {
const { bodyStyle, setBodyStyle, defaultSubplebbits, setSelectedAddress, selectedStyle, setSelectedStyle, setSelectedTitle } = useGeneralStore((state) => state);
const { bodyStyle, setBodyStyle, defaultSubplebbits, defaultNsfwSubplebbits, setSelectedAddress, selectedStyle, setSelectedStyle } = useGeneralStore((state) => state);
const sfwAddresses = defaultSubplebbits.map((subplebbit) => subplebbit.address);
const sfwSubs = useSubplebbits({ subplebbitAddresses: sfwAddresses });
const sfwList = sfwSubs.subplebbits.map((subplebbit) => subplebbit?.address);
const sfwListCids = sfwSubs.subplebbits.map((s) => s?.lastPostCid);
const account = useAccount();
const navigate = useNavigate();
const isElectron = window.electron && window.electron.isElectron;
const inputRef = useRef(null);
const prevStyle = useRef(selectedStyle);
const prevBodyStyle = useRef(bodyStyle);
const [isCreateBoardOpen, setIsCreateBoardOpen] = useState(false);
const [showAllSFWBoards, setShowAllSFWBoards] = useState(false);
const [showAllSubscriptions, setShowAllSubscriptions] = useState(false);
// prevent dark mode
useEffect(() => {
@@ -84,7 +141,7 @@ const Home = () => {
/>
<input
type='submit'
value='Search'
value='Connect'
onClick={() => {
const address = inputRef.current.value;
if (address) {
@@ -101,58 +158,112 @@ const Home = () => {
<AboutContent>
<div id='content'>
<p>
Plebchan is the only serverless, adminless, fully decentralized 4chan alternative where any pleb can create and own unlimited boards, and nobody can
take them down. Boards can always find competition, and board owners can monetize freely, so janitors aren't needed. Plebchan is a client for{' '}
Plebchan is a serverless, adminless, decentralized 4chan alternative where any pleb can create and own unlimited boards. All data comes from the 
<a href='https://plebbit.com' target='_blank' rel='noreferrer'>
plebbit
</a>
, a pure P2P protocol and tooling for creating decentralized forum applications. All data is just text, and plebchan's speed depends on how many users
are{' '}
<button
style={{ all: 'unset', cursor: 'pointer' }}
onClick={() => {
alert(
'You can seed automatically simply by using the plebchan desktop app, which is a plebbit full node. Download it here:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, you can use plebbit-cli with the --seed flag:\nhttps://github.com/plebbit/plebbit-cli\n\n',
);
}}
>
seeding
</button>
. Search for any board address above, or feel free to click on a popular board below that interests you and jump right in!{' '}
</a>{' '}
protocol, it's all text including links from which media is embedded, shared peer-to-peer. Users do not need to register an account before participating
in the community. Feel free to click on a board below that interests you and jump right in!{' '}
</p>
<br />
<p>There are no global rules, each board is completely independent and its owner decides how/if it should be moderated.</p>
<br />
<p>
{' '}
HOW TO RUN A BOARD (currently via CLI only): <strong>(1)</strong> have a computer you can use as server, because users will connect to your board
peer-to-peer; <strong>(2)</strong> go to{' '}
<a href='https://github.com/plebbit/plebbit-cli#install' target='_blank' rel='noreferrer'>
https://github.com/plebbit/plebbit-cli#install
</a>{' '}
and follow the instructions to run your daemon, create a subplebbit (board) and edit its settings; <strong>(3)</strong> users can always connect to your
board via its address, but it can be added below by submitting a pull request here:{' '}
<a href='https://github.com/plebbit/temporary-default-subplebbits' target='_blank' rel='noreferrer'>
https://github.com/plebbit/temporary-default-subplebbits
</a>{' '}
this will be automated with a plebbit DAO using the plebbit token.
</p>
</div>
</AboutContent>
</About>
{account?.subscriptions?.length > 0 ? (
<Boards>
<BoardsTitle>
<h2>Subscriptions</h2>
</BoardsTitle>
<BoardsContent id='subscriptions'>
<BoardsBox>
<div className='boxbar'>
<h2>Boards</h2>
</div>
<div class='boxcontent'>
<div class='column'>
<h3 style={{ textDecoration: 'underline', display: 'inline' }}>
You have subscribed to {account?.subscriptions?.length} board{account?.subscriptions?.length > 1 ? 's' : null}
<a
href='https://github.com/plebbit/temporary-default-subplebbits'
target='_blank'
rel='noopener noreferrer'
style={{ all: 'unset', cursor: 'pointer' }}
>
Default SFW
</a>
</h3>
&nbsp;
<Link
to='/p/all'
id='button'
onClick={() => {
window.scrollTo(0, 0);
}}
>
[view all]
</Link>
<ul>
{sfwList.slice(0, showAllSFWBoards ? undefined : 18).map((address, index) => (
<li key={`default-${index}`}>
<OfflineIndicator address={address} className='disconnected' isText={true} />
<Link
key={`default-link-${index}`}
className='boardlink'
onClick={() => {
window.scrollTo(0, 0);
}}
to={`/p/${address}`}
>
{address}
</Link>
&nbsp;
</li>
))}
{sfwList.length > 17 && (
<li onClick={() => setShowAllSFWBoards(!showAllSFWBoards)}>
{!showAllSFWBoards ? '... ' : null}
<span id='button'>{showAllSFWBoards ? '[show less]' : '[show more]'}</span>
</li>
)}
</ul>
</div>
<div class='column'>
<h3 style={{ textDecoration: 'underline', display: 'inline' }}>
<a
href='https://github.com/plebbit/temporary-default-subplebbits'
target='_blank'
rel='noopener noreferrer'
style={{ all: 'unset', cursor: 'pointer' }}
>
Default NSFW
</a>
</h3>
<ul>
{defaultNsfwSubplebbits.length === 0 && <li style={{ color: 'black' }}>No boards yet in this list.</li>}
{defaultNsfwSubplebbits.slice(0, showAllSFWBoards ? undefined : 18).map((subplebbit, index) => (
<li key={`default-${index}`}>
<OfflineIndicator address={subplebbit.address} className='disconnected' isText={true} />
<Link
key={`default-link-${index}`}
className='boardlink'
onClick={() => {
window.scrollTo(0, 0);
}}
to={`/p/${subplebbit.address}`}
>
{subplebbit.address}
</Link>
&nbsp;
</li>
))}
{defaultNsfwSubplebbits.length > 17 && (
<li onClick={() => setShowAllSFWBoards(!showAllSFWBoards)}>
{!showAllSFWBoards ? '... ' : null}
<span id='button'>{showAllSFWBoards ? '[show less]' : '[show more]'}</span>
</li>
)}
</ul>
</div>
<div class='column'>
<h3 style={{ textDecoration: 'underline', display: 'inline' }}>Subscriptions</h3>
&nbsp;
<Link
to='/p/subscriptions'
id='view-all'
id='button'
onClick={() => {
window.scrollTo(0, 0);
}}
@@ -160,58 +271,65 @@ const Home = () => {
[view all]
</Link>
<br />
{account?.subscriptions?.map((subscription, index) => (
<Fragment key={`frag-${index}`}>
<Link
key={`sub-${index}`}
className='boardlink'
onClick={() => {
window.scrollTo(0, 0);
}}
to={`/p/${subscription}`}
>
<br id='mobile-br' />
{subscription}&nbsp;
</Link>
<OfflineIndicator key={`offline-${index}`} address={subscription} className='disconnected' isText={true} />
<br key={`br-${index}`} />
</Fragment>
))}
<br id='mobile-br' />
</BoardsContent>
</Boards>
) : null}
<Boards>
<BoardsTitle>
<h2>Default Boards</h2>
</BoardsTitle>
<ul>
{account?.subscriptions?.length === 0 && <li style={{ color: 'black' }}>Not subscribed to any board.</li>}
{account?.subscriptions?.slice(0, showAllSubscriptions ? undefined : 18).map((subscription, index) => (
<li key={`sub-${index}`}>
<OfflineIndicator address={subscription} className='disconnected' isText={true} />
<Link
key={`sub-link-${index}`}
className='boardlink'
onClick={() => {
window.scrollTo(0, 0);
}}
to={`/p/${subscription}`}
>
{subscription}
</Link>
&nbsp;
</li>
))}
{account?.subscriptions?.length > 17 && (
<li onClick={() => setShowAllSubscriptions(!showAllSubscriptions)}>
{!showAllSubscriptions ? '... ' : null}
<span id='button'>{showAllSubscriptions ? '[show less]' : '[show more]'}</span>
</li>
)}
</ul>
</div>
<div class='column'>
<h3 style={{ textDecoration: 'underline', display: 'inline' }}>Moderating</h3>
<ul>
{!isElectron ? (
<li style={{ color: 'black' }}>
Visible on{' '}
<a
style={{ color: 'blue', textDecoration: 'underline' }}
href='https://github.com/plebbit/plebchan/releases/latest'
target='_blank'
rel='noopener noreferrer'
>
full node (desktop)
</a>
.
</li>
) : (
<div>WIP</div>
)}
</ul>
</div>
</div>
</BoardsBox>
<BoardsBox>
<div className='boxbar'>
<h2>Popular Threads</h2>
</div>
<BoardsContent>
{defaultSubplebbits.map((subplebbit, index) => (
<div className='board' key={`board-${index}`}>
<div className='board-title' key='board-title'>
{subplebbit.title ?? <SubplebbitTitle address={subplebbit.address} />}
</div>
<div className='board-avatar-container' key='board-avatar-container'>
<Link
to={`/p/${subplebbit.address}`}
key='link'
onClick={() => {
setSelectedTitle(subplebbit.title);
setSelectedAddress(subplebbit.address);
window.scrollTo(0, 0);
}}
>
<BoardAvatar key='baordavatar' address={subplebbit.address} />
</Link>
<OfflineIndicator address={subplebbit.address} className='offline-indicator' tooltipPlace='top' key='oi2' />
</div>
<div className='board-text' key='bt'>
<b key='b'>{subplebbit.address}</b>
</div>
</div>
{sfwListCids.map((cid) => (
<RecentThread commentCid={cid} />
))}
</BoardsContent>
</Boards>
</BoardsBox>
</Page>
<Footer>
<ul>
+35 -29
View File
@@ -1,23 +1,22 @@
import React, { useEffect } from 'react';
import { Helmet } from 'react-helmet-async';
import { Link } from "react-router-dom";
import { Container, Header, Logo, Page, Boards, BoardsTitle } from '../styled/views/Home.styled';
import { Link } from 'react-router-dom';
import { Container, Header, Logo, Page, BoardsBox } from '../styled/views/Home.styled';
import packageJson from '../../../package.json';
const {version} = packageJson;
const { version } = packageJson;
const commitRef = process?.env?.REACT_APP_COMMIT_REF ? ` ${process.env.REACT_APP_COMMIT_REF.slice(0, 7)}` : '';
const NotFound = () => {
useEffect(() => {
const yotsubaBodyStyle = {
background: "#ffe url(assets/fade.png) top repeat-x",
color: "maroon",
fontFamily: "Arial, Helvetica, sans-serif"
background: '#ffe url(assets/fade.png) top repeat-x',
color: 'maroon',
fontFamily: 'Arial, Helvetica, sans-serif',
};
const originalBodyStyles = {
background: document.body.style.background,
color: document.body.style.color,
fontFamily: document.body.style.fontFamily
fontFamily: document.body.style.fontFamily,
};
for (const [key, value] of Object.entries(yotsubaBodyStyle)) {
@@ -39,34 +38,41 @@ const NotFound = () => {
<Container>
<Header>
<Logo>
<Link to="/">
<img alt="plebchan" src="assets/logo/logo-transparent.png" />
<Link to='/'>
<img alt='plebchan' src='assets/logo/logo-transparent.png' />
</Link>
</Logo>
</Header>
<Page>
<Boards>
<BoardsTitle>
<h2 style={{textAlign: 'center'}}>404 Not Found</h2>
</BoardsTitle>
<img src="assets/plebchan-husbando.jpg" alt="plebchan" style={{
display: "block",
margin: "auto",
padding: "15px",
width: "50%"
}}></img>
</Boards>
<BoardsBox>
<div className='boxbar'>
<h2 style={{ textAlign: 'center' }}>404 Not Found</h2>
</div>
<img
src='assets/plebchan-husbando.jpg'
alt='plebchan'
style={{
display: 'block',
margin: 'auto',
padding: '15px',
width: '50%',
}}
></img>
</BoardsBox>
</Page>
<div style={{
textAlign: "center",
fontSize: "11px",
marginTop: "2em",
}}>
plebchan v{version}{commitRef}. GPL-2.0
<div
style={{
textAlign: 'center',
fontSize: '11px',
marginTop: '2em',
}}
>
plebchan v{version}
{commitRef}. GPL-2.0
</div>
</Container>
</>
);
}
};
export default NotFound;
export default NotFound;
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -206,7 +206,7 @@ const Rules = () => {
window.electron && window.electron.isElectron
? setIsCreateBoardOpen(true)
: alert(
'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n',
'HOW TO CREATE A BOARD (currently via CLI only):\n\n(1) have a computer you can use as server, because users will connect to your board peer-to-peer;\n\n(2) go to https://github.com/plebbit/plebbit-cli#install and follow the instructions to run your daemon, create a subplebbit (board) and edit its settings;\n\n(3) users can always connect to your board via its address, but it can be added below by submitting a pull request here: https://github.com/plebbit/temporary-default-subplebbits. This will be automated with a plebbit DAO using the plebbit token.',
);
}}
>
@@ -239,7 +239,7 @@ const Rules = () => {
style={{ cursor: 'pointer' }}
onClick={() =>
alert(
'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n',
'HOW TO CREATE A BOARD (currently via CLI only):\n\n(1) have a computer you can use as server, because users will connect to your board peer-to-peer;\n\n(2) go to https://github.com/plebbit/plebbit-cli#install and follow the instructions to run your daemon, create a subplebbit (board) and edit its settings;\n\n(3) users can always connect to your board via its address, but it can be added below by submitting a pull request here: https://github.com/plebbit/temporary-default-subplebbits. This will be automated with a plebbit DAO using the plebbit token.',
)
}
>
@@ -655,7 +655,7 @@ const Rules = () => {
window.electron && window.electron.isElectron
? setIsCreateBoardOpen(true)
: alert(
'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n',
'HOW TO CREATE A BOARD (currently via CLI only):\n\n(1) have a computer you can use as server, because users will connect to your board peer-to-peer;\n\n(2) go to https://github.com/plebbit/plebbit-cli#install and follow the instructions to run your daemon, create a subplebbit (board) and edit its settings;\n\n(3) users can always connect to your board via its address, but it can be added below by submitting a pull request here: https://github.com/plebbit/temporary-default-subplebbits. This will be automated with a plebbit DAO using the plebbit token.',
);
}}
>
+203 -7
View File
@@ -606,7 +606,7 @@ const Subscriptions = () => {
window.electron && window.electron.isElectron
? setIsCreateBoardOpen(true)
: alert(
'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n',
'HOW TO CREATE A BOARD (currently via CLI only):\n\n(1) have a computer you can use as server, because users will connect to your board peer-to-peer;\n\n(2) go to https://github.com/plebbit/plebbit-cli#install and follow the instructions to run your daemon, create a subplebbit (board) and edit its settings;\n\n(3) users can always connect to your board via its address, but it can be added below by submitting a pull request here: https://github.com/plebbit/temporary-default-subplebbits. This will be automated with a plebbit DAO using the plebbit token.',
);
}}
>
@@ -638,7 +638,7 @@ const Subscriptions = () => {
style={{ cursor: 'pointer' }}
onClick={() =>
alert(
'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n',
'HOW TO CREATE A BOARD (currently via CLI only):\n\n(1) have a computer you can use as server, because users will connect to your board peer-to-peer;\n\n(2) go to https://github.com/plebbit/plebbit-cli#install and follow the instructions to run your daemon, create a subplebbit (board) and edit its settings;\n\n(3) users can always connect to your board via its address, but it can be added below by submitting a pull request here: https://github.com/plebbit/temporary-default-subplebbits. This will be automated with a plebbit DAO using the plebbit token.',
)
}
>
@@ -1224,7 +1224,56 @@ const Subscriptions = () => {
thread.content?.length > 1000 ? (
<Fragment key={`fragment5-${index}`}>
<blockquote key={`bq-${index}`}>
<Post content={thread.content?.slice(0, 1000)} key={`post-${index}`} />
<Post
key={`post-${thread.cid}`}
content={thread.content?.slice(0, 1000)}
postQuoteRef={(quoteShortParentCid, ref) => {
postRefs.current[quoteShortParentCid] = ref;
}}
postQuoteOnClick={(quoteShortParentCid) => {
handleQuoteClick(thread, quoteShortParentCid, null);
}}
postQuoteOnOver={(quoteShortParentCid) => {
const quoteParentCid = cidTracker[quoteShortParentCid];
if (outOfViewCid !== quoteParentCid) {
handleQuoteHover(thread, 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);
}}
/>
<span key={`ttl-s-${index}`} className='ttl'>
{' '}
(...)
@@ -1247,7 +1296,56 @@ const Subscriptions = () => {
</Fragment>
) : (
<blockquote key={`bq-${index}`}>
<Post content={thread.content} key={`post-${index}`} />
<Post
key={`post-${thread.cid}`}
content={thread.content}
postQuoteRef={(quoteShortParentCid, ref) => {
postRefs.current[quoteShortParentCid] = ref;
}}
postQuoteOnClick={(quoteShortParentCid) => {
handleQuoteClick(thread, quoteShortParentCid, null);
}}
postQuoteOnOver={(quoteShortParentCid) => {
const quoteParentCid = cidTracker[quoteShortParentCid];
if (outOfViewCid !== quoteParentCid) {
handleQuoteHover(thread, 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);
}}
/>
<EditLabel key={`edit-label-thread-${index}`} commentCid={thread.cid} className='ttl' />
<StateLabel key={`state-label-thread-${index}`} commentIndex={thread.index} className='ttl ellipsis' />
</blockquote>
@@ -2441,7 +2539,56 @@ const Subscriptions = () => {
thread.content?.length > 500 ? (
<Fragment key={`fragment12-${index}`}>
<blockquote key={`mob-bq-${index}`} className='post-message-mobile'>
<Post content={thread.content?.slice(0, 500)} key={`post-mobile-${index}`} />
<Post
key={`post-mobile-${thread.cid}`}
content={thread.content?.slice(0, 500)}
postQuoteRef={(quoteShortParentCid, ref) => {
postRefs.current[quoteShortParentCid] = ref;
}}
postQuoteOnClick={(quoteShortParentCid) => {
handleQuoteClick(thread, quoteShortParentCid, null);
}}
postQuoteOnOver={(quoteShortParentCid) => {
const quoteParentCid = cidTracker[quoteShortParentCid];
if (outOfViewCid !== quoteParentCid) {
handleQuoteHover(thread, 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);
}}
/>
<span key={`mob-ttl-s-${index}`} className='ttl'>
{' '}
(...)
@@ -2464,7 +2611,56 @@ const Subscriptions = () => {
</Fragment>
) : (
<blockquote key={`mob-bq-${index}`} className='post-message-mobile'>
<Post content={thread.content} key={`post-mobile-${index}`} />
<Post
key={`post-mobile-${thread.cid}`}
content={thread.content}
postQuoteRef={(quoteShortParentCid, ref) => {
postRefs.current[quoteShortParentCid] = ref;
}}
postQuoteOnClick={(quoteShortParentCid) => {
handleQuoteClick(thread, quoteShortParentCid, null);
}}
postQuoteOnOver={(quoteShortParentCid) => {
const quoteParentCid = cidTracker[quoteShortParentCid];
if (outOfViewCid !== quoteParentCid) {
handleQuoteHover(thread, 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);
}}
/>
<EditLabel key={`edit-label-thread-mob-${index}`} commentCid={thread.cid} className='ttl' />
<StateLabel key={`state-label-thread-mob-${index}`} commentIndex={thread.index} className='ttl ellipsis' />
</blockquote>
@@ -3322,7 +3518,7 @@ const Subscriptions = () => {
window.electron && window.electron.isElectron
? setIsCreateBoardOpen(true)
: alert(
'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n',
'HOW TO CREATE A BOARD (currently via CLI only):\n\n(1) have a computer you can use as server, because users will connect to your board peer-to-peer;\n\n(2) go to https://github.com/plebbit/plebbit-cli#install and follow the instructions to run your daemon, create a subplebbit (board) and edit its settings;\n\n(3) users can always connect to your board via its address, but it can be added below by submitting a pull request here: https://github.com/plebbit/temporary-default-subplebbits. This will be automated with a plebbit DAO using the plebbit token.',
);
}}
>
@@ -849,7 +849,7 @@ const SubscriptionsCatalog = () => {
window.electron && window.electron.isElectron
? setIsCreateBoardOpen(true)
: alert(
'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n',
'HOW TO CREATE A BOARD (currently via CLI only):\n\n(1) have a computer you can use as server, because users will connect to your board peer-to-peer;\n\n(2) go to https://github.com/plebbit/plebbit-cli#install and follow the instructions to run your daemon, create a subplebbit (board) and edit its settings;\n\n(3) users can always connect to your board via its address, but it can be added below by submitting a pull request here: https://github.com/plebbit/temporary-default-subplebbits. This will be automated with a plebbit DAO using the plebbit token.',
);
}}
>
@@ -881,7 +881,7 @@ const SubscriptionsCatalog = () => {
style={{ cursor: 'pointer' }}
onClick={() =>
alert(
'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n',
'HOW TO CREATE A BOARD (currently via CLI only):\n\n(1) have a computer you can use as server, because users will connect to your board peer-to-peer;\n\n(2) go to https://github.com/plebbit/plebbit-cli#install and follow the instructions to run your daemon, create a subplebbit (board) and edit its settings;\n\n(3) users can always connect to your board via its address, but it can be added below by submitting a pull request here: https://github.com/plebbit/temporary-default-subplebbits. This will be automated with a plebbit DAO using the plebbit token.',
)
}
>
@@ -1040,7 +1040,7 @@ const SubscriptionsCatalog = () => {
window.electron && window.electron.isElectron
? setIsCreateBoardOpen(true)
: alert(
'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n',
'HOW TO CREATE A BOARD (currently via CLI only):\n\n(1) have a computer you can use as server, because users will connect to your board peer-to-peer;\n\n(2) go to https://github.com/plebbit/plebbit-cli#install and follow the instructions to run your daemon, create a subplebbit (board) and edit its settings;\n\n(3) users can always connect to your board via its address, but it can be added below by submitting a pull request here: https://github.com/plebbit/temporary-default-subplebbits. This will be automated with a plebbit DAO using the plebbit token.',
);
}}
>
+104 -6
View File
@@ -700,7 +700,7 @@ const Thread = () => {
window.electron && window.electron.isElectron
? setIsCreateBoardOpen(true)
: alert(
'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n',
'HOW TO CREATE A BOARD (currently via CLI only):\n\n(1) have a computer you can use as server, because users will connect to your board peer-to-peer;\n\n(2) go to https://github.com/plebbit/plebbit-cli#install and follow the instructions to run your daemon, create a subplebbit (board) and edit its settings;\n\n(3) users can always connect to your board via its address, but it can be added below by submitting a pull request here: https://github.com/plebbit/temporary-default-subplebbits. This will be automated with a plebbit DAO using the plebbit token.',
);
}}
>
@@ -733,7 +733,7 @@ const Thread = () => {
style={{ cursor: 'pointer' }}
onClick={() =>
alert(
'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n',
'HOW TO CREATE A BOARD (currently via CLI only):\n\n(1) have a computer you can use as server, because users will connect to your board peer-to-peer;\n\n(2) go to https://github.com/plebbit/plebbit-cli#install and follow the instructions to run your daemon, create a subplebbit (board) and edit its settings;\n\n(3) users can always connect to your board via its address, but it can be added below by submitting a pull request here: https://github.com/plebbit/temporary-default-subplebbits. This will be automated with a plebbit DAO using the plebbit token.',
)
}
>
@@ -860,7 +860,7 @@ const Thread = () => {
</td>
</tr>
<tr data-type='File'>
<td>Embed File</td>
<td>Link</td>
<td>
<input name='embed' type='text' tabIndex={7} placeholder='Paste link' ref={linkRef} />
<button
@@ -1376,7 +1376,56 @@ const Thread = () => {
</div>
</span>
<blockquote key={`blockquote-${comment.cid}`}>
<Post content={comment.content} comment={comment} key={`post-${comment.cid}`} />
<Post
key={`post-${comment.cid}`}
content={comment.content}
postQuoteRef={(quoteShortParentCid, ref) => {
postRefs.current[quoteShortParentCid] = ref;
}}
postQuoteOnClick={(quoteShortParentCid) => {
handleQuoteClick(comment, quoteShortParentCid, null);
}}
postQuoteOnOver={(quoteShortParentCid) => {
const quoteParentCid = cidTracker[quoteShortParentCid];
if (outOfViewCid !== quoteParentCid) {
handleQuoteHover(comment, 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);
}}
/>
<EditLabel key={`edit-label-thread-${index}`} commentCid={comment.cid} className='ttl' />
<StateLabel key={`state-label-thread-${index}`} commentIndex={comment.index} className='ttl ellipsis' />
</blockquote>
@@ -2376,7 +2425,56 @@ const Thread = () => {
<blockquote key={`mob-bq-${comment.cid}`} className='post-message-mobile'>
{comment.content ? (
<>
<Post content={comment.content} comment={comment} key={`post-mobile-${comment.cid}`} />
<Post
key={`post-${comment.cid}`}
content={comment.content}
postQuoteRef={(quoteShortParentCid, ref) => {
postRefs.current[quoteShortParentCid] = ref;
}}
postQuoteOnClick={(quoteShortParentCid) => {
handleQuoteClick(comment, quoteShortParentCid, null);
}}
postQuoteOnOver={(quoteShortParentCid) => {
const quoteParentCid = cidTracker[quoteShortParentCid];
if (outOfViewCid !== quoteParentCid) {
handleQuoteHover(comment, 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);
}}
/>
<EditLabel key={`edit-label-thread-mob-${index}`} commentCid={comment.cid} className='ttl' />
<StateLabel key={`state-label-thread-mob-${index}`} commentIndex={comment.index} className='ttl ellipsis' />
</>
@@ -3159,7 +3257,7 @@ const Thread = () => {
window.electron && window.electron.isElectron
? setIsCreateBoardOpen(true)
: alert(
'You can create a board with the desktop version of plebchan:\nhttps://github.com/plebbit/plebchan/releases/latest\n\nIf you are comfortable with the command line, use plebbit-cli:\nhttps://github.com/plebbit/plebbit-cli\n\n',
'HOW TO CREATE A BOARD (currently via CLI only):\n\n(1) have a computer you can use as server, because users will connect to your board peer-to-peer;\n\n(2) go to https://github.com/plebbit/plebbit-cli#install and follow the instructions to run your daemon, create a subplebbit (board) and edit its settings;\n\n(3) users can always connect to your board via its address, but it can be added below by submitting a pull request here: https://github.com/plebbit/temporary-default-subplebbits. This will be automated with a plebbit DAO using the plebbit token.',
);
}}
>
+3
View File
@@ -20,6 +20,9 @@ const useGeneralStore = create((set) => ({
defaultSubplebbits: [],
setDefaultSubplebbits: (subplebbits) => set({ defaultSubplebbits: subplebbits }),
defaultNsfwSubplebbits: [],
setDefaultNsfwSubplebbits: (subplebbits) => set({ defaultNsfwSubplebbits: subplebbits }),
deletePost: false,
setDeletePost: (deletePost) => set({ deletePost }),
-15
View File
@@ -2817,21 +2817,6 @@
dependencies:
debug "4.3.3"
"@plebbit/plebbit-react-hooks@https://github.com/plebbit/plebbit-react-hooks.git#0024401c390929e47b44331a8dadd61ba212b871":
version "0.0.1"
resolved "https://github.com/plebbit/plebbit-react-hooks.git#0024401c390929e47b44331a8dadd61ba212b871"
dependencies:
"@plebbit/plebbit-js" "https://github.com/plebbit/plebbit-js.git#6985b2a4194328752c6d76e80470c8079c562869"
"@plebbit/plebbit-logger" "https://github.com/plebbit/plebbit-logger.git"
assert "2.0.0"
ethers "5.6.9"
localforage "1.10.0"
lodash.isequal "4.5.0"
memoizee "0.4.15"
quick-lru "5.1.1"
uuid "8.3.2"
zustand "4.0.0"
"@plebbit/plebbit-react-hooks@https://github.com/plebbit/plebbit-react-hooks.git#b6477148191a501aa0b0c11acfc4761aca0dcc1e":
version "0.0.1"
resolved "https://github.com/plebbit/plebbit-react-hooks.git#b6477148191a501aa0b0c11acfc4761aca0dcc1e"