mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
@@ -2,6 +2,7 @@
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding: 3px 7px 3px 4px;
|
padding: 3px 7px 3px 4px;
|
||||||
filter: var(--filter80);
|
filter: var(--filter80);
|
||||||
|
color-scheme: var(--color-scheme, revert) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal {
|
.modal {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { Comment, useAccount, useAccountComments, useAuthorAvatar, useComment, u
|
|||||||
import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js';
|
import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js';
|
||||||
import styles from '../../views/post/post.module.css';
|
import styles from '../../views/post/post.module.css';
|
||||||
import { getCommentMediaInfo, getDisplayMediaInfoType, getHasThumbnail } from '../../lib/utils/media-utils';
|
import { getCommentMediaInfo, getDisplayMediaInfoType, getHasThumbnail } from '../../lib/utils/media-utils';
|
||||||
|
import { hashStringToColor, getTextColorForBackground } from '../../lib/utils/post-utils';
|
||||||
import { getFormattedDate, getFormattedTimeAgo } from '../../lib/utils/time-utils';
|
import { getFormattedDate, getFormattedTimeAgo } from '../../lib/utils/time-utils';
|
||||||
import { isValidURL } from '../../lib/utils/url-utils';
|
import { isValidURL } from '../../lib/utils/url-utils';
|
||||||
import { isAllView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
import { isAllView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
||||||
@@ -71,6 +72,9 @@ const PostInfo = ({ openReplyModal, post, postReplyCount = 0, roles, isHidden }:
|
|||||||
const handleUserAddressClick = useAuthorAddressClick();
|
const handleUserAddressClick = useAuthorAddressClick();
|
||||||
const numberOfPostsByAuthor = document.querySelectorAll(`[data-author-address="${shortAddress}"][data-post-cid="${postCid}"]`).length;
|
const numberOfPostsByAuthor = document.querySelectorAll(`[data-author-address="${shortAddress}"][data-post-cid="${postCid}"]`).length;
|
||||||
|
|
||||||
|
const userIDBackgroundColor = hashStringToColor(shortAddress || accountShortAddress);
|
||||||
|
const userIDTextColor = getTextColorForBackground(userIDBackgroundColor);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.postInfo}>
|
<div className={styles.postInfo}>
|
||||||
{!isHidden && <EditMenu isAccountCommentAuthor={isAccountCommentAuthor} isAccountMod={isAccountMod} isCommentAuthorMod={isCommentAuthorMod} post={post} />}
|
{!isHidden && <EditMenu isAccountCommentAuthor={isAccountCommentAuthor} isAccountMod={isAccountMod} isCommentAuthorMod={isCommentAuthorMod} post={post} />}
|
||||||
@@ -106,10 +110,15 @@ const PostInfo = ({ openReplyModal, post, postReplyCount = 0, roles, isHidden }:
|
|||||||
<img src={avatarImageUrl} alt='' />
|
<img src={avatarImageUrl} alt='' />
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
(u/
|
(ID: {''}
|
||||||
<Tooltip
|
<Tooltip
|
||||||
children={
|
children={
|
||||||
<span title={t('highlight_posts')} className={styles.userAddress} onClick={() => handleUserAddressClick(shortAddress || accountShortAddress, postCid)}>
|
<span
|
||||||
|
title={t('highlight_posts')}
|
||||||
|
className={styles.userAddress}
|
||||||
|
onClick={() => handleUserAddressClick(shortAddress || accountShortAddress, postCid)}
|
||||||
|
style={{ backgroundColor: userIDBackgroundColor, color: userIDTextColor }}
|
||||||
|
>
|
||||||
{shortAddress || accountShortAddress}
|
{shortAddress || accountShortAddress}
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
@@ -138,7 +147,7 @@ const PostInfo = ({ openReplyModal, post, postReplyCount = 0, roles, isHidden }:
|
|||||||
<Link to={`/p/${subplebbitAddress}/c/${cid}`} className={styles.linkToPost} title={t('link_to_post')} onClick={(e) => !cid && e.preventDefault()}>
|
<Link to={`/p/${subplebbitAddress}/c/${cid}`} className={styles.linkToPost} title={t('link_to_post')} onClick={(e) => !cid && e.preventDefault()}>
|
||||||
c/
|
c/
|
||||||
</Link>
|
</Link>
|
||||||
<span className={styles.replyToPost} title={t('reply_to_post')} onMouseDown={() => openReplyModal && openReplyModal(cid, postCid)}>
|
<span className={styles.replyToPost} title={t('reply_to_post')} onMouseDown={() => openReplyModal && openReplyModal(cid, postCid, subplebbitAddress)}>
|
||||||
{shortCid}
|
{shortCid}
|
||||||
</span>
|
</span>
|
||||||
</>
|
</>
|
||||||
@@ -239,8 +248,7 @@ const PostMedia = ({ post }: PostProps) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const PostMessage = ({ post }: PostProps) => {
|
const PostMessage = ({ post }: PostProps) => {
|
||||||
const { cid, content, deleted, edit, original, parentCid, postCid, reason, removed, state, subplebbitAddress } = post || {};
|
const { cid, content, deleted, edit, original, parentCid, postCid, reason, removed, state } = post || {};
|
||||||
const { isDescription, isRules } = post || {}; // custom properties, not from api
|
|
||||||
// TODO: commentAuthor is not available outside of editedComment, update when available
|
// TODO: commentAuthor is not available outside of editedComment, update when available
|
||||||
// const banned = !!post?.commentAuthor?.banExpiresAt;
|
// const banned = !!post?.commentAuthor?.banExpiresAt;
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
@@ -249,7 +257,8 @@ const PostMessage = ({ post }: PostProps) => {
|
|||||||
const isInPostView = isPostPageView(location.pathname, params);
|
const isInPostView = isPostPageView(location.pathname, params);
|
||||||
const [showOriginal, setShowOriginal] = useState(false);
|
const [showOriginal, setShowOriginal] = useState(false);
|
||||||
|
|
||||||
const displayContent = content && !isInPostView && content.length > 1000 ? content?.slice(0, 1000) + '(...)' : content;
|
const [showFullComment, setShowFullComment] = useState(false);
|
||||||
|
const displayContent = content && !isInPostView && content.length > 1000 && !showFullComment ? content.slice(0, 1000) : content;
|
||||||
|
|
||||||
const quotelinkReply = useComment({ commentCid: parentCid });
|
const quotelinkReply = useComment({ commentCid: parentCid });
|
||||||
const isReply = parentCid;
|
const isReply = parentCid;
|
||||||
@@ -318,14 +327,10 @@ const PostMessage = ({ post }: PostProps) => {
|
|||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
)} */}
|
)} */}
|
||||||
{!isReply && content.length > 1000 && !isInPostView && (
|
{content?.length > 1000 && !isInPostView && !showFullComment && (
|
||||||
<span className={styles.abbr}>
|
<span className={styles.abbr}>
|
||||||
<br />
|
<br />
|
||||||
<Trans
|
<Trans i18nKey={'comment_too_long'} shouldUnescape={true} components={{ 1: <span onClick={() => setShowFullComment(true)} /> }} />
|
||||||
i18nKey={'comment_too_long'}
|
|
||||||
shouldUnescape={true}
|
|
||||||
components={{ 1: <Link to={`/p/${subplebbitAddress}/${isDescription ? 'description' : isRules ? 'rules' : `c/${cid}`}`} /> }}
|
|
||||||
/>
|
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{!cid && state === 'pending' && stateString !== 'Failed' && (
|
{!cid && state === 'pending' && stateString !== 'Failed' && (
|
||||||
|
|||||||
@@ -73,7 +73,20 @@ const ImageSearchButton = ({ url, onClose }: { url: string; onClose: () => void
|
|||||||
const ViewOnButton = ({ cid, isDescription, isInAllView, isInSubscriptionsView, isRules, subplebbitAddress, onClose }: PostMenuDesktopProps) => {
|
const ViewOnButton = ({ cid, isDescription, isInAllView, isInSubscriptionsView, isRules, subplebbitAddress, onClose }: PostMenuDesktopProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false);
|
const [isClientRedirectMenuOpen, setIsClientRedirectMenuOpen] = useState(false);
|
||||||
const viewOnOtherClientLink = `p/${isInAllView ? 'all' : isInSubscriptionsView ? 'subscriptions' : subplebbitAddress}${isDescription || isRules ? '' : `/c/${cid}`}`;
|
|
||||||
|
const getViewOnOtherClientLink = () => {
|
||||||
|
if (isDescription || isRules) {
|
||||||
|
if (isInAllView || isInSubscriptionsView) {
|
||||||
|
return `${isInAllView ? 'all' : isInSubscriptionsView && 'subscriptions'}`;
|
||||||
|
} else {
|
||||||
|
return `${subplebbitAddress}/${isDescription ? 'description' : isRules && 'rules'}`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return `${subplebbitAddress}/c/${cid}`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const viewOnOtherClientLink = getViewOnOtherClientLink();
|
||||||
|
|
||||||
const { refs, floatingStyles } = useFloating({
|
const { refs, floatingStyles } = useFloating({
|
||||||
placement: 'right-start',
|
placement: 'right-start',
|
||||||
@@ -91,10 +104,10 @@ const ViewOnButton = ({ cid, isDescription, isInAllView, isInSubscriptionsView,
|
|||||||
{_.capitalize(t('view_on'))} »
|
{_.capitalize(t('view_on'))} »
|
||||||
{isClientRedirectMenuOpen && (
|
{isClientRedirectMenuOpen && (
|
||||||
<div ref={refs.setFloating} style={floatingStyles} className={styles.dropdownMenu}>
|
<div ref={refs.setFloating} style={floatingStyles} className={styles.dropdownMenu}>
|
||||||
<a href={`https://seedit.eth.limo/#/${viewOnOtherClientLink}`} target='_blank' rel='noreferrer'>
|
<a href={`https://seedit.eth.limo/#/p/${viewOnOtherClientLink}`} target='_blank' rel='noreferrer'>
|
||||||
<div className={styles.postMenuItem}>Seedit</div>
|
<div className={styles.postMenuItem}>Seedit</div>
|
||||||
</a>
|
</a>
|
||||||
<a href={`https://plebones.eth.limo/#/${viewOnOtherClientLink}`} target='_blank' rel='noreferrer'>
|
<a href={`https://plebones.eth.limo/#/p/${viewOnOtherClientLink}`} target='_blank' rel='noreferrer'>
|
||||||
<div className={styles.postMenuItem}>Plebones</div>
|
<div className={styles.postMenuItem}>Plebones</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -171,7 +184,7 @@ const PostMenuDesktop = ({ post }: { post: Comment }) => {
|
|||||||
<FloatingFocusManager context={context} modal={false}>
|
<FloatingFocusManager context={context} modal={false}>
|
||||||
<div className={styles.postMenu} ref={refs.setFloating} style={floatingStyles} aria-labelledby={headingId} {...getFloatingProps()}>
|
<div className={styles.postMenu} ref={refs.setFloating} style={floatingStyles} aria-labelledby={headingId} {...getFloatingProps()}>
|
||||||
{cid && subplebbitAddress && <CopyLinkButton cid={cid} subplebbitAddress={subplebbitAddress} onClose={handleClose} />}
|
{cid && subplebbitAddress && <CopyLinkButton cid={cid} subplebbitAddress={subplebbitAddress} onClose={handleClose} />}
|
||||||
{!isInPostPageView && !isDescription && !isRules && (
|
{!(isInPostPageView && postCid === cid) && !isDescription && !isRules && (
|
||||||
<div
|
<div
|
||||||
className={styles.postMenuItem}
|
className={styles.postMenuItem}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|||||||
@@ -160,12 +160,11 @@ const PostFormTable = ({ closeForm, postCid }: { closeForm: () => void; postCid:
|
|||||||
setSubmitStore({
|
setSubmitStore({
|
||||||
signer: newSigner,
|
signer: newSigner,
|
||||||
author: {
|
author: {
|
||||||
displayName,
|
|
||||||
address: newSigner.address,
|
address: newSigner.address,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [anonMode, getNewSigner, setSubmitStore, displayName]);
|
}, [anonMode, getNewSigner, setSubmitStore]);
|
||||||
|
|
||||||
const onPublishPost = async () => {
|
const onPublishPost = async () => {
|
||||||
if (!title && !content && !link) {
|
if (!title && !content && !link) {
|
||||||
@@ -212,7 +211,6 @@ const PostFormTable = ({ closeForm, postCid }: { closeForm: () => void; postCid:
|
|||||||
setPublishReplyOptions({
|
setPublishReplyOptions({
|
||||||
signer: existingSigner,
|
signer: existingSigner,
|
||||||
author: {
|
author: {
|
||||||
displayName,
|
|
||||||
address: existingSigner.address,
|
address: existingSigner.address,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -221,13 +219,12 @@ const PostFormTable = ({ closeForm, postCid }: { closeForm: () => void; postCid:
|
|||||||
setPublishReplyOptions({
|
setPublishReplyOptions({
|
||||||
signer: newSigner,
|
signer: newSigner,
|
||||||
author: {
|
author: {
|
||||||
displayName,
|
|
||||||
address: newSigner.address,
|
address: newSigner.address,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [address, getExistingSigner, getNewSigner, setPublishReplyOptions, displayName, anonMode]);
|
}, [address, getExistingSigner, getNewSigner, setPublishReplyOptions, anonMode]);
|
||||||
|
|
||||||
const onPublishReply = () => {
|
const onPublishReply = () => {
|
||||||
const currentContent = textRef.current?.value || '';
|
const currentContent = textRef.current?.value || '';
|
||||||
@@ -246,6 +243,14 @@ const PostFormTable = ({ closeForm, postCid }: { closeForm: () => void; postCid:
|
|||||||
publishReply();
|
publishReply();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const hasSetInitialDisplayName = useRef(false);
|
||||||
|
useEffect(() => {
|
||||||
|
if (!hasSetInitialDisplayName.current && displayName) {
|
||||||
|
setPublishReplyOptions({ displayName });
|
||||||
|
hasSetInitialDisplayName.current = true;
|
||||||
|
}
|
||||||
|
}, [displayName, setPublishReplyOptions]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (typeof replyIndex === 'number') {
|
if (typeof replyIndex === 'number') {
|
||||||
resetPublishReplyOptions();
|
resetPublishReplyOptions();
|
||||||
@@ -276,7 +281,11 @@ const PostFormTable = ({ closeForm, postCid }: { closeForm: () => void; postCid:
|
|||||||
defaultValue={displayName || undefined}
|
defaultValue={displayName || undefined}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setAccount({ ...account, author: { ...account?.author, displayName: e.target.value } });
|
setAccount({ ...account, author: { ...account?.author, displayName: e.target.value } });
|
||||||
setSubmitStore({ displayName: e.target.value });
|
if (isInPostView) {
|
||||||
|
setPublishReplyOptions({ displayName: e.target.value });
|
||||||
|
} else {
|
||||||
|
setSubmitStore({ displayName: e.target.value });
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{isInPostView && <button onClick={onPublishReply}>{t('post')}</button>}
|
{isInPostView && <button onClick={onPublishReply}>{t('post')}</button>}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { copyShareLinkToClipboard, isValidURL } from '../../../lib/utils/url-uti
|
|||||||
import useEditCommentPrivileges from '../../../hooks/use-author-privileges';
|
import useEditCommentPrivileges from '../../../hooks/use-author-privileges';
|
||||||
import useHide from '../../../hooks/use-hide';
|
import useHide from '../../../hooks/use-hide';
|
||||||
import EditMenu from '../../edit-menu/edit-menu';
|
import EditMenu from '../../edit-menu/edit-menu';
|
||||||
import { isBoardView, isPostPageView } from '../../../lib/utils/view-utils';
|
import { isAllView, isBoardView, isPostPageView, isSubscriptionsView } from '../../../lib/utils/view-utils';
|
||||||
import { useLocation, useParams } from 'react-router-dom';
|
import { useLocation, useParams } from 'react-router-dom';
|
||||||
|
|
||||||
interface PostMenuMobileProps {
|
interface PostMenuMobileProps {
|
||||||
@@ -57,7 +57,25 @@ const ImageSearchButtons = ({ url, onClose }: { url: string; onClose: () => void
|
|||||||
|
|
||||||
const ViewOnButtons = ({ cid, isDescription, isRules, subplebbitAddress, onClose }: PostMenuMobileProps) => {
|
const ViewOnButtons = ({ cid, isDescription, isRules, subplebbitAddress, onClose }: PostMenuMobileProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const viewOnOtherClientLink = `p/${subplebbitAddress}${isDescription || isRules ? '' : `/c/${cid}`}`;
|
const location = useLocation();
|
||||||
|
const params = useParams();
|
||||||
|
const isInAllView = isAllView(location.pathname, params);
|
||||||
|
const isInSubscriptionsView = isSubscriptionsView(location.pathname, params);
|
||||||
|
|
||||||
|
const getViewOnOtherClientLink = () => {
|
||||||
|
if (isDescription || isRules) {
|
||||||
|
if (isInAllView || isInSubscriptionsView) {
|
||||||
|
return `${isInAllView ? 'all' : isInSubscriptionsView && 'subscriptions'}`;
|
||||||
|
} else {
|
||||||
|
return `${subplebbitAddress}/${isDescription ? 'description' : isRules && 'rules'}`;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return `${subplebbitAddress}/c/${cid}`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const viewOnOtherClientLink = getViewOnOtherClientLink();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div onClick={onClose}>
|
<div onClick={onClose}>
|
||||||
<a href={`https://seedit.eth.limo/#/${viewOnOtherClientLink}`} target='_blank' rel='noreferrer'>
|
<a href={`https://seedit.eth.limo/#/${viewOnOtherClientLink}`} target='_blank' rel='noreferrer'>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { Comment, useAccount, useAuthorAvatar, useComment, useEditedComment } fr
|
|||||||
import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js';
|
import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js';
|
||||||
import styles from '../../views/post/post.module.css';
|
import styles from '../../views/post/post.module.css';
|
||||||
import { getCommentMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils';
|
import { getCommentMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils';
|
||||||
|
import { getTextColorForBackground, hashStringToColor } from '../../lib/utils/post-utils';
|
||||||
import { getFormattedDate, getFormattedTimeAgo } from '../../lib/utils/time-utils';
|
import { getFormattedDate, getFormattedTimeAgo } from '../../lib/utils/time-utils';
|
||||||
import { isAllView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
import { isAllView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
||||||
import useAuthorAddressClick from '../../hooks/use-author-address-click';
|
import useAuthorAddressClick from '../../hooks/use-author-address-click';
|
||||||
@@ -52,6 +53,9 @@ const PostInfoAndMedia = ({ openReplyModal, post, postReplyCount = 0, roles }: P
|
|||||||
const handleUserAddressClick = useAuthorAddressClick();
|
const handleUserAddressClick = useAuthorAddressClick();
|
||||||
const numberOfPostsByAuthor = document.querySelectorAll(`[data-author-address="${shortAddress}"][data-post-cid="${postCid}"]`).length;
|
const numberOfPostsByAuthor = document.querySelectorAll(`[data-author-address="${shortAddress}"][data-post-cid="${postCid}"]`).length;
|
||||||
|
|
||||||
|
const userIDBackgroundColor = hashStringToColor(shortAddress || accountShortAddress);
|
||||||
|
const userIDTextColor = getTextColorForBackground(userIDBackgroundColor);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={styles.postInfo}>
|
<div className={styles.postInfo}>
|
||||||
@@ -79,10 +83,15 @@ const PostInfoAndMedia = ({ openReplyModal, post, postReplyCount = 0, roles }: P
|
|||||||
<img src={avatarImageUrl} alt='' />
|
<img src={avatarImageUrl} alt='' />
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
(u/
|
(ID: {''}
|
||||||
<Tooltip
|
<Tooltip
|
||||||
children={
|
children={
|
||||||
<span title={t('highlight_posts')} className={styles.userAddress} onClick={() => handleUserAddressClick(shortAddress || accountShortAddress, postCid)}>
|
<span
|
||||||
|
title={t('highlight_posts')}
|
||||||
|
className={styles.userAddress}
|
||||||
|
onClick={() => handleUserAddressClick(shortAddress || accountShortAddress, postCid)}
|
||||||
|
style={{ backgroundColor: userIDBackgroundColor, color: userIDTextColor }}
|
||||||
|
>
|
||||||
{shortAddress || accountShortAddress}
|
{shortAddress || accountShortAddress}
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
@@ -127,7 +136,7 @@ const PostInfoAndMedia = ({ openReplyModal, post, postReplyCount = 0, roles }: P
|
|||||||
<Link to={`/p/${subplebbitAddress}/c/${cid}`} className={styles.linkToPost} title={t('link_to_post')} onClick={(e) => !cid && e.preventDefault()}>
|
<Link to={`/p/${subplebbitAddress}/c/${cid}`} className={styles.linkToPost} title={t('link_to_post')} onClick={(e) => !cid && e.preventDefault()}>
|
||||||
c/
|
c/
|
||||||
</Link>
|
</Link>
|
||||||
<span className={styles.replyToPost} title={t('reply_to_post')} onMouseDown={() => openReplyModal && openReplyModal(cid, postCid)}>
|
<span className={styles.replyToPost} title={t('reply_to_post')} onMouseDown={() => openReplyModal && openReplyModal(cid, postCid, subplebbitAddress)}>
|
||||||
{shortCid}
|
{shortCid}
|
||||||
</span>
|
</span>
|
||||||
</>
|
</>
|
||||||
@@ -163,8 +172,7 @@ const ReplyBacklinks = ({ post }: PostProps) => {
|
|||||||
|
|
||||||
const PostMessageMobile = ({ post }: PostProps) => {
|
const PostMessageMobile = ({ post }: PostProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { cid, content, deleted, edit, original, parentCid, postCid, reason, removed, state, subplebbitAddress } = post || {};
|
const { cid, content, deleted, edit, original, parentCid, postCid, reason, removed, state } = post || {};
|
||||||
const { isDescription, isRules } = post || {}; // custom properties, not from api
|
|
||||||
// TODO: commentAuthor is not available outside of editedComment, update when available
|
// TODO: commentAuthor is not available outside of editedComment, update when available
|
||||||
// const banned = !!post?.commentAuthor?.banExpiresAt;
|
// const banned = !!post?.commentAuthor?.banExpiresAt;
|
||||||
const [showOriginal, setShowOriginal] = useState(false);
|
const [showOriginal, setShowOriginal] = useState(false);
|
||||||
@@ -173,7 +181,8 @@ const PostMessageMobile = ({ post }: PostProps) => {
|
|||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
const isInPostView = isPostPageView(location.pathname, params);
|
const isInPostView = isPostPageView(location.pathname, params);
|
||||||
|
|
||||||
const displayContent = content && !isInPostView && content.length > 1000 ? content?.slice(0, 1000) : content;
|
const [showFullComment, setShowFullComment] = useState(false);
|
||||||
|
const displayContent = content && !isInPostView && content.length > 1000 && !showFullComment ? content.slice(0, 1000) : content;
|
||||||
|
|
||||||
const quotelinkReply = useComment({ commentCid: parentCid });
|
const quotelinkReply = useComment({ commentCid: parentCid });
|
||||||
const isReply = parentCid;
|
const isReply = parentCid;
|
||||||
@@ -242,14 +251,10 @@ const PostMessageMobile = ({ post }: PostProps) => {
|
|||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
)} */}
|
)} */}
|
||||||
{!isReply && content.length > 1000 && !isInPostView && (
|
{content?.length > 1000 && !isInPostView && !showFullComment && (
|
||||||
<span className={styles.abbr}>
|
<span className={styles.abbr}>
|
||||||
<br />
|
<br />
|
||||||
<Trans
|
<Trans i18nKey={'comment_too_long'} shouldUnescape={true} components={{ 1: <span onClick={() => setShowFullComment(true)} /> }} />
|
||||||
i18nKey={'comment_too_long'}
|
|
||||||
shouldUnescape={true}
|
|
||||||
components={{ 1: <Link to={`/p/${subplebbitAddress}/${isDescription ? 'description' : isRules ? 'rules' : `c/${cid}`}`} /> }}
|
|
||||||
/>
|
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{!cid && state === 'pending' && stateString !== 'Failed' && (
|
{!cid && state === 'pending' && stateString !== 'Failed' && (
|
||||||
|
|||||||
@@ -17,14 +17,15 @@ import useAnonMode from '../../hooks/use-anon-mode';
|
|||||||
|
|
||||||
interface ReplyModalProps {
|
interface ReplyModalProps {
|
||||||
closeModal: () => void;
|
closeModal: () => void;
|
||||||
|
showReplyModal: boolean;
|
||||||
parentCid: string;
|
parentCid: string;
|
||||||
postCid: string;
|
postCid: string;
|
||||||
scrollY: number;
|
scrollY: number;
|
||||||
|
subplebbitAddress: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ReplyModal = ({ closeModal, parentCid, postCid, scrollY }: ReplyModalProps) => {
|
const ReplyModal = ({ closeModal, showReplyModal, parentCid, postCid, scrollY, subplebbitAddress }: ReplyModalProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { subplebbitAddress } = useParams() as { subplebbitAddress: string };
|
|
||||||
const { setPublishReplyOptions, publishReply } = usePublishReply({ cid: parentCid, subplebbitAddress });
|
const { setPublishReplyOptions, publishReply } = usePublishReply({ cid: parentCid, subplebbitAddress });
|
||||||
const account = useAccount();
|
const account = useAccount();
|
||||||
const { displayName } = account?.author || {};
|
const { displayName } = account?.author || {};
|
||||||
@@ -47,7 +48,6 @@ const ReplyModal = ({ closeModal, parentCid, postCid, scrollY }: ReplyModalProps
|
|||||||
setPublishReplyOptions({
|
setPublishReplyOptions({
|
||||||
signer: existingSigner,
|
signer: existingSigner,
|
||||||
author: {
|
author: {
|
||||||
displayName,
|
|
||||||
address: existingSigner.address,
|
address: existingSigner.address,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -56,13 +56,12 @@ const ReplyModal = ({ closeModal, parentCid, postCid, scrollY }: ReplyModalProps
|
|||||||
setPublishReplyOptions({
|
setPublishReplyOptions({
|
||||||
signer: newSigner,
|
signer: newSigner,
|
||||||
author: {
|
author: {
|
||||||
displayName,
|
|
||||||
address: newSigner.address,
|
address: newSigner.address,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [anonMode, address, getExistingSigner, getNewSigner, displayName, setPublishReplyOptions]);
|
}, [anonMode, address, getExistingSigner, getNewSigner, setPublishReplyOptions]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (anonMode) {
|
if (anonMode) {
|
||||||
@@ -88,10 +87,17 @@ const ReplyModal = ({ closeModal, parentCid, postCid, scrollY }: ReplyModalProps
|
|||||||
closeModal();
|
closeModal();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const hasSetInitialDisplayName = useRef(false);
|
||||||
|
useEffect(() => {
|
||||||
|
if (!hasSetInitialDisplayName.current && displayName) {
|
||||||
|
setPublishReplyOptions({ displayName });
|
||||||
|
hasSetInitialDisplayName.current = true;
|
||||||
|
}
|
||||||
|
}, [displayName, setPublishReplyOptions]);
|
||||||
|
|
||||||
const nodeRef = useRef<HTMLDivElement>(null);
|
const nodeRef = useRef<HTMLDivElement>(null);
|
||||||
const isMobile = useIsMobile();
|
const isMobile = useIsMobile();
|
||||||
|
|
||||||
// on mobile, the position is absolute instead of fixed, so we need to calculate the top position
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (nodeRef.current && isMobile) {
|
if (nodeRef.current && isMobile) {
|
||||||
const viewportHeight = window.innerHeight;
|
const viewportHeight = window.innerHeight;
|
||||||
@@ -122,14 +128,15 @@ const ReplyModal = ({ closeModal, parentCid, postCid, scrollY }: ReplyModalProps
|
|||||||
)
|
)
|
||||||
: `The subplebbit might be offline and publishing might fail.`;
|
: `The subplebbit might be offline and publishing might fail.`;
|
||||||
|
|
||||||
const setTextRef = (ref: HTMLTextAreaElement | null) => {
|
useEffect(() => {
|
||||||
if (ref) {
|
if (showReplyModal && !isMobile) {
|
||||||
textRef.current = ref;
|
setTimeout(() => {
|
||||||
// if (!isMobile && !urlRef.current?.value) {
|
if (textRef.current) {
|
||||||
// ref.focus();
|
textRef.current.focus();
|
||||||
// }
|
}
|
||||||
|
}, 0);
|
||||||
}
|
}
|
||||||
};
|
}, [showReplyModal, isMobile]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (textRef.current) {
|
if (textRef.current) {
|
||||||
@@ -148,7 +155,6 @@ const ReplyModal = ({ closeModal, parentCid, postCid, scrollY }: ReplyModalProps
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleContentChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
|
const handleContentChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||||
// remove the prefix from the content to publish, and also add newlines for markdown
|
|
||||||
const contentWithoutPrefix = e.target.value.slice(contentPrefix.length).replace(/\n/g, '\n\n');
|
const contentWithoutPrefix = e.target.value.slice(contentPrefix.length).replace(/\n/g, '\n\n');
|
||||||
if (textRef.current && textRef.current.value !== contentWithoutPrefix) {
|
if (textRef.current && textRef.current.value !== contentWithoutPrefix) {
|
||||||
setPublishReplyOptions({ content: contentWithoutPrefix });
|
setPublishReplyOptions({ content: contentWithoutPrefix });
|
||||||
@@ -196,7 +202,7 @@ const ReplyModal = ({ closeModal, parentCid, postCid, scrollY }: ReplyModalProps
|
|||||||
cols={48}
|
cols={48}
|
||||||
rows={4}
|
rows={4}
|
||||||
wrap='soft'
|
wrap='soft'
|
||||||
ref={setTextRef}
|
ref={textRef}
|
||||||
spellCheck={false}
|
spellCheck={false}
|
||||||
defaultValue={contentPrefix + selectedText}
|
defaultValue={contentPrefix + selectedText}
|
||||||
onInput={handleContentInput}
|
onInput={handleContentInput}
|
||||||
@@ -227,12 +233,15 @@ const ReplyModal = ({ closeModal, parentCid, postCid, scrollY }: ReplyModalProps
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
return isMobile ? (
|
return (
|
||||||
modalContent
|
showReplyModal &&
|
||||||
) : (
|
(isMobile ? (
|
||||||
<Draggable handle='.replyModalHandle' nodeRef={nodeRef}>
|
modalContent
|
||||||
{modalContent}
|
) : (
|
||||||
</Draggable>
|
<Draggable handle='.replyModalHandle' nodeRef={nodeRef}>
|
||||||
|
{modalContent}
|
||||||
|
</Draggable>
|
||||||
|
))
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -36,15 +36,21 @@ const useReplyStore = create<ReplyState>((set) => ({
|
|||||||
signer: {},
|
signer: {},
|
||||||
spoiler: {},
|
spoiler: {},
|
||||||
publishCommentOptions: {},
|
publishCommentOptions: {},
|
||||||
|
|
||||||
setReplyStore: (data: SetReplyStoreData) =>
|
setReplyStore: (data: SetReplyStoreData) =>
|
||||||
set((state) => {
|
set((state) => {
|
||||||
const { subplebbitAddress, parentCid, author, displayName, content, link, signer, spoiler } = data;
|
const { subplebbitAddress, parentCid, author, displayName, content, link, signer, spoiler } = data;
|
||||||
const updatedAuthor = displayName ? { ...author, displayName } : author;
|
|
||||||
|
const updatedAuthor = {
|
||||||
|
...(state.author[parentCid] || author),
|
||||||
|
...(displayName ? { displayName } : {}),
|
||||||
|
};
|
||||||
|
|
||||||
const publishCommentOptions = {
|
const publishCommentOptions = {
|
||||||
subplebbitAddress,
|
subplebbitAddress,
|
||||||
parentCid,
|
parentCid,
|
||||||
...(data.author ? { author: updatedAuthor } : {}),
|
...(updatedAuthor ? { author: updatedAuthor } : {}),
|
||||||
...(data.signer ? { signer: data.signer } : {}),
|
...(signer ? { signer } : {}),
|
||||||
content,
|
content,
|
||||||
link,
|
link,
|
||||||
spoiler,
|
spoiler,
|
||||||
@@ -57,11 +63,12 @@ const useReplyStore = create<ReplyState>((set) => ({
|
|||||||
alert(error.message);
|
alert(error.message);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
author: { ...state.author, [parentCid]: updatedAuthor },
|
author: { ...state.author, [parentCid]: updatedAuthor },
|
||||||
signer: { ...state.signer, [parentCid]: signer },
|
|
||||||
content: { ...state.content, [parentCid]: content },
|
content: { ...state.content, [parentCid]: content },
|
||||||
link: { ...state.link, [parentCid]: link },
|
link: { ...state.link, [parentCid]: link },
|
||||||
|
signer: { ...state.signer, [parentCid]: signer },
|
||||||
spoiler: { ...state.spoiler, [parentCid]: spoiler },
|
spoiler: { ...state.spoiler, [parentCid]: spoiler },
|
||||||
publishCommentOptions: { ...state.publishCommentOptions, [parentCid]: publishCommentOptions },
|
publishCommentOptions: { ...state.publishCommentOptions, [parentCid]: publishCommentOptions },
|
||||||
};
|
};
|
||||||
@@ -70,9 +77,9 @@ const useReplyStore = create<ReplyState>((set) => ({
|
|||||||
resetReplyStore: (parentCid) =>
|
resetReplyStore: (parentCid) =>
|
||||||
set((state) => ({
|
set((state) => ({
|
||||||
author: { ...state.author, [parentCid]: undefined },
|
author: { ...state.author, [parentCid]: undefined },
|
||||||
signer: { ...state.signer, [parentCid]: undefined },
|
|
||||||
content: { ...state.content, [parentCid]: undefined },
|
content: { ...state.content, [parentCid]: undefined },
|
||||||
link: { ...state.link, [parentCid]: undefined },
|
link: { ...state.link, [parentCid]: undefined },
|
||||||
|
signer: { ...state.signer, [parentCid]: undefined },
|
||||||
spoiler: { ...state.spoiler, [parentCid]: undefined },
|
spoiler: { ...state.spoiler, [parentCid]: undefined },
|
||||||
publishCommentOptions: { ...state.publishCommentOptions, [parentCid]: undefined },
|
publishCommentOptions: { ...state.publishCommentOptions, [parentCid]: undefined },
|
||||||
})),
|
})),
|
||||||
@@ -80,8 +87,9 @@ const useReplyStore = create<ReplyState>((set) => ({
|
|||||||
|
|
||||||
const useReply = ({ cid, subplebbitAddress }: { cid: string; subplebbitAddress: string }) => {
|
const useReply = ({ cid, subplebbitAddress }: { cid: string; subplebbitAddress: string }) => {
|
||||||
const parentCid = cid;
|
const parentCid = cid;
|
||||||
const { author, signer, content, link, spoiler, publishCommentOptions } = useReplyStore((state) => ({
|
const { author, displayName, signer, content, link, spoiler, publishCommentOptions } = useReplyStore((state) => ({
|
||||||
author: state.author[parentCid],
|
author: state.author[parentCid],
|
||||||
|
displayName: state.author[parentCid]?.displayName,
|
||||||
signer: state.signer[parentCid],
|
signer: state.signer[parentCid],
|
||||||
content: state.content[parentCid],
|
content: state.content[parentCid],
|
||||||
link: state.link[parentCid],
|
link: state.link[parentCid],
|
||||||
@@ -99,6 +107,7 @@ const useReply = ({ cid, subplebbitAddress }: { cid: string; subplebbitAddress:
|
|||||||
setReplyStore({
|
setReplyStore({
|
||||||
subplebbitAddress,
|
subplebbitAddress,
|
||||||
parentCid,
|
parentCid,
|
||||||
|
...(anonMode ? { displayName } : {}),
|
||||||
...(anonMode ? { author } : {}),
|
...(anonMode ? { author } : {}),
|
||||||
content,
|
content,
|
||||||
link,
|
link,
|
||||||
@@ -107,7 +116,7 @@ const useReply = ({ cid, subplebbitAddress }: { cid: string; subplebbitAddress:
|
|||||||
...options,
|
...options,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[subplebbitAddress, parentCid, author, signer, content, link, spoiler, setReplyStore, anonMode],
|
[subplebbitAddress, parentCid, author, displayName, signer, content, link, spoiler, setReplyStore, anonMode],
|
||||||
);
|
);
|
||||||
|
|
||||||
const resetPublishReplyOptions = useCallback(() => resetReplyStore(parentCid), [parentCid, resetReplyStore]);
|
const resetPublishReplyOptions = useCallback(() => resetReplyStore(parentCid), [parentCid, resetReplyStore]);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ const useReplyModal = () => {
|
|||||||
const [showReplyModal, setShowReplyModal] = useState(false);
|
const [showReplyModal, setShowReplyModal] = useState(false);
|
||||||
const [activeCid, setActiveCid] = useState<string | null>(null);
|
const [activeCid, setActiveCid] = useState<string | null>(null);
|
||||||
const [threadCid, setThreadCid] = useState<string | null>(null);
|
const [threadCid, setThreadCid] = useState<string | null>(null);
|
||||||
|
const [subplebbitAddress, setSubplebbitAddress] = useState<string | null>(null);
|
||||||
const { resetSelectedText, setSelectedText } = useSelectedTextStore();
|
const { resetSelectedText, setSelectedText } = useSelectedTextStore();
|
||||||
|
|
||||||
// on mobile, the css position is absolute instead of fixed, so we need to calculate the top position
|
// on mobile, the css position is absolute instead of fixed, so we need to calculate the top position
|
||||||
@@ -23,7 +24,7 @@ const useReplyModal = () => {
|
|||||||
text && setSelectedText(`>${text}\n`);
|
text && setSelectedText(`>${text}\n`);
|
||||||
};
|
};
|
||||||
|
|
||||||
const openReplyModal = (parentCid: string, postCid: string) => {
|
const openReplyModal = (parentCid: string, postCid: string, subplebbitAddress: string) => {
|
||||||
getSelectedText();
|
getSelectedText();
|
||||||
|
|
||||||
if (isMobile) {
|
if (isMobile) {
|
||||||
@@ -37,9 +38,10 @@ const useReplyModal = () => {
|
|||||||
setActiveCid(parentCid);
|
setActiveCid(parentCid);
|
||||||
setThreadCid(postCid);
|
setThreadCid(postCid);
|
||||||
setShowReplyModal(true);
|
setShowReplyModal(true);
|
||||||
|
setSubplebbitAddress(subplebbitAddress);
|
||||||
};
|
};
|
||||||
|
|
||||||
return { activeCid, threadCid, closeModal, openReplyModal, scrollY, showReplyModal };
|
return { activeCid, threadCid, closeModal, openReplyModal, scrollY, showReplyModal, subplebbitAddress };
|
||||||
};
|
};
|
||||||
|
|
||||||
export default useReplyModal;
|
export default useReplyModal;
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
export function hashStringToColor(str: string): string {
|
||||||
|
if (!str) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
let hash = 0;
|
||||||
|
for (let i = 0; i < str.length; i++) {
|
||||||
|
hash = str.charCodeAt(i) + ((hash << 5) - hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
const r = (hash >> 24) & 0xff;
|
||||||
|
const g = (hash >> 16) & 0xff;
|
||||||
|
const b = (hash >> 8) & 0xff;
|
||||||
|
|
||||||
|
return `rgb(${r}, ${g}, ${b})`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTextColorForBackground(rgb: string): string {
|
||||||
|
const [r, g, b] = rgb.match(/\d+/g)?.map(Number) || [0, 0, 0];
|
||||||
|
const brightness = r * 0.299 + g * 0.587 + b * 0.114;
|
||||||
|
return brightness > 125 ? 'black' : 'white';
|
||||||
|
}
|
||||||
+6
-6
@@ -23,7 +23,7 @@
|
|||||||
--body-background-pattern-image: url("/public/assets/background-fade.png");
|
--body-background-pattern-image: url("/public/assets/background-fade.png");
|
||||||
--body-font-color: maroon;
|
--body-font-color: maroon;
|
||||||
--body-font-family: arial, helvetica, sans-serif;
|
--body-font-family: arial, helvetica, sans-serif;
|
||||||
--body-font-size: 13px;
|
--body-font-size: 10pt;
|
||||||
|
|
||||||
/* catalog post */
|
/* catalog post */
|
||||||
--catalog-post-menu-desktop-btn-color: navy;
|
--catalog-post-menu-desktop-btn-color: navy;
|
||||||
@@ -232,7 +232,7 @@
|
|||||||
--body-background-pattern-image: url("/public/assets/background-fade-blue.png");
|
--body-background-pattern-image: url("/public/assets/background-fade-blue.png");
|
||||||
--body-font-color: #000;
|
--body-font-color: #000;
|
||||||
--body-font-family: arial, helvetica, sans-serif;
|
--body-font-family: arial, helvetica, sans-serif;
|
||||||
--body-font-size: 13px;
|
--body-font-size: 10pt;
|
||||||
|
|
||||||
/* catalog post */
|
/* catalog post */
|
||||||
--catalog-post-menu-desktop-btn-color: navy;
|
--catalog-post-menu-desktop-btn-color: navy;
|
||||||
@@ -434,7 +434,7 @@
|
|||||||
--body-background-pattern-image: none;
|
--body-background-pattern-image: none;
|
||||||
--body-font-color: maroon;
|
--body-font-color: maroon;
|
||||||
--body-font-family: times new roman, serif;
|
--body-font-family: times new roman, serif;
|
||||||
--body-font-size: 16px;
|
--body-font-size: 12pt;
|
||||||
|
|
||||||
/* board banner */
|
/* board banner */
|
||||||
--banner-image-border: none;
|
--banner-image-border: none;
|
||||||
@@ -616,7 +616,7 @@
|
|||||||
--body-background-pattern-image: none;
|
--body-background-pattern-image: none;
|
||||||
--body-font-color: #000;
|
--body-font-color: #000;
|
||||||
--body-font-family: times new roman, serif;
|
--body-font-family: times new roman, serif;
|
||||||
--body-font-size: 16px;
|
--body-font-size: 12pt;
|
||||||
|
|
||||||
/* catalog post */
|
/* catalog post */
|
||||||
--catalog-post-menu-desktop-btn-color: navy;
|
--catalog-post-menu-desktop-btn-color: navy;
|
||||||
@@ -795,7 +795,7 @@
|
|||||||
--body-background-pattern-image: none;
|
--body-background-pattern-image: none;
|
||||||
--body-font-color: #c5c8c6;
|
--body-font-color: #c5c8c6;
|
||||||
--body-font-family: arial, helvetica, sans-serif;
|
--body-font-family: arial, helvetica, sans-serif;
|
||||||
--body-font-size: 13px;
|
--body-font-size: 10pt;
|
||||||
|
|
||||||
/* board banner */
|
/* board banner */
|
||||||
--banner-image-border: none;
|
--banner-image-border: none;
|
||||||
@@ -1008,7 +1008,7 @@
|
|||||||
--body-background-pattern-image: none;
|
--body-background-pattern-image: none;
|
||||||
--body-font-color: #333;
|
--body-font-color: #333;
|
||||||
--body-font-family: arial, helvetica, sans-serif;
|
--body-font-family: arial, helvetica, sans-serif;
|
||||||
--body-font-size: 13px;
|
--body-font-size: 10pt;
|
||||||
|
|
||||||
/* board banner */
|
/* board banner */
|
||||||
--banner-image-border: none;
|
--banner-image-border: none;
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ const Board = () => {
|
|||||||
const { createdAt, description, error, rules, shortAddress, state, suggested } = subplebbit || {};
|
const { createdAt, description, error, rules, shortAddress, state, suggested } = subplebbit || {};
|
||||||
const title = isInAllView ? t('all') : isInSubscriptionsView ? t('subscriptions') : subplebbit?.title;
|
const title = isInAllView ? t('all') : isInSubscriptionsView ? t('subscriptions') : subplebbit?.title;
|
||||||
|
|
||||||
const { activeCid, threadCid, closeModal, openReplyModal, showReplyModal, scrollY } = useReplyModal();
|
const { activeCid, threadCid, closeModal, openReplyModal, showReplyModal, scrollY, subplebbitAddress: postSubplebbitAddress } = useReplyModal();
|
||||||
|
|
||||||
const { blocked, unblock } = useBlock({ address: subplebbitAddress });
|
const { blocked, unblock } = useBlock({ address: subplebbitAddress });
|
||||||
const loadingStateString = useFeedStateString(subplebbitAddresses) || t('loading');
|
const loadingStateString = useFeedStateString(subplebbitAddresses) || t('loading');
|
||||||
@@ -158,7 +158,16 @@ const Board = () => {
|
|||||||
return (
|
return (
|
||||||
<div className={styles.content}>
|
<div className={styles.content}>
|
||||||
{location.pathname.endsWith('/settings') && <SettingsModal />}
|
{location.pathname.endsWith('/settings') && <SettingsModal />}
|
||||||
{showReplyModal && activeCid && threadCid && <ReplyModal closeModal={closeModal} parentCid={activeCid} postCid={threadCid} scrollY={scrollY} />}
|
{activeCid && threadCid && postSubplebbitAddress && (
|
||||||
|
<ReplyModal
|
||||||
|
closeModal={closeModal}
|
||||||
|
parentCid={activeCid}
|
||||||
|
postCid={threadCid}
|
||||||
|
scrollY={scrollY}
|
||||||
|
showReplyModal={showReplyModal}
|
||||||
|
subplebbitAddress={postSubplebbitAddress}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{feed.length !== 0 ? (
|
{feed.length !== 0 ? (
|
||||||
<>
|
<>
|
||||||
{rules && rules.length > 0 && <SubplebbitRules subplebbitAddress={subplebbitAddress} createdAt={createdAt} rules={rules} />}
|
{rules && rules.length > 0 && <SubplebbitRules subplebbitAddress={subplebbitAddress} createdAt={createdAt} rules={rules} />}
|
||||||
|
|||||||
@@ -18,9 +18,11 @@ interface PopularThreadProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const PopularThreadCard = ({ post, boardTitle, boardShortAddress }: PopularThreadProps) => {
|
const PopularThreadCard = ({ post, boardTitle, boardShortAddress }: PopularThreadProps) => {
|
||||||
const { cid, content, subplebbitAddress, title } = post || {};
|
const { cid, subplebbitAddress, title } = post || {};
|
||||||
const commentMediaInfo = getCommentMediaInfo(post);
|
const commentMediaInfo = getCommentMediaInfo(post);
|
||||||
|
|
||||||
|
let content = post?.content?.replace(/\n\n/g, '\n');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.popularThread} key={cid}>
|
<div className={styles.popularThread} key={cid}>
|
||||||
<div className={styles.title}>{boardTitle || boardShortAddress}</div>
|
<div className={styles.title}>{boardTitle || boardShortAddress}</div>
|
||||||
|
|||||||
@@ -73,11 +73,14 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.userAddress {
|
.userAddress {
|
||||||
|
padding: 0 5px;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: 0.8em;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
.postDesktop .userAddress:hover {
|
.userAddress:hover {
|
||||||
color: var(--button-desktop-text-color-hover);
|
color: var(--post-quotelink-text-color-hover) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.postDesktop .subject {
|
.postDesktop .subject {
|
||||||
@@ -164,12 +167,13 @@
|
|||||||
font-size: var(--post-mobile-abbr-font-size);
|
font-size: var(--post-mobile-abbr-font-size);
|
||||||
}
|
}
|
||||||
|
|
||||||
.postDesktop .abbr a {
|
.postDesktop .abbr a, .postDesktop .abbr span {
|
||||||
color: var(--post-link-text-color);
|
color: var(--post-link-text-color);
|
||||||
text-decoration: var(--post-content-link-text-decoration);
|
text-decoration: var(--post-content-link-text-decoration);
|
||||||
}
|
}
|
||||||
|
|
||||||
.postDesktop .abbr a:hover {
|
.postDesktop .abbr a:hover, .postDesktop .abbr span:hover {
|
||||||
|
cursor: pointer;
|
||||||
color: var(--post-link-text-color-hover);
|
color: var(--post-link-text-color-hover);
|
||||||
text-decoration: var(--post-content-link-text-decoration-hover);
|
text-decoration: var(--post-content-link-text-decoration-hover);
|
||||||
}
|
}
|
||||||
@@ -344,13 +348,14 @@
|
|||||||
font-size: var(--post-mobile-abbr-font-size);
|
font-size: var(--post-mobile-abbr-font-size);
|
||||||
}
|
}
|
||||||
|
|
||||||
.postMobile .abbr a {
|
.postMobile .abbr a, .postMobile .abbr span {
|
||||||
color: var(--post-link-text-color);
|
color: var(--post-link-text-color);
|
||||||
text-decoration: var(--post-content-link-text-decoration);
|
text-decoration: var(--post-content-link-text-decoration);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.postMobile .abbr a:hover {
|
.postMobile .abbr a:hover, .postMobile .abbr span:hover {
|
||||||
|
cursor: pointer;
|
||||||
color: var(--post-link-text-color-hover);
|
color: var(--post-link-text-color-hover);
|
||||||
text-decoration: var(--post-content-link-text-decoration-hover);
|
text-decoration: var(--post-content-link-text-decoration-hover);
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-3
@@ -22,7 +22,7 @@ export interface PostProps {
|
|||||||
roles?: Role[];
|
roles?: Role[];
|
||||||
showAllReplies?: boolean;
|
showAllReplies?: boolean;
|
||||||
showReplies?: boolean;
|
showReplies?: boolean;
|
||||||
openReplyModal?: (parentCid: string, postCid: string) => void;
|
openReplyModal?: (parentCid: string, postCid: string, subplebbitAddress: string) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Post = ({ post, showAllReplies = false, showReplies = true, openReplyModal }: PostProps) => {
|
export const Post = ({ post, showAllReplies = false, showReplies = true, openReplyModal }: PostProps) => {
|
||||||
@@ -62,7 +62,7 @@ const PostPage = () => {
|
|||||||
const subplebbit = useSubplebbit({ subplebbitAddress });
|
const subplebbit = useSubplebbit({ subplebbitAddress });
|
||||||
const { createdAt, description, rules, shortAddress, suggested, title } = subplebbit;
|
const { createdAt, description, rules, shortAddress, suggested, title } = subplebbit;
|
||||||
|
|
||||||
const { activeCid, threadCid, closeModal, openReplyModal, showReplyModal, scrollY } = useReplyModal();
|
const { activeCid, threadCid, closeModal, openReplyModal, showReplyModal, scrollY, subplebbitAddress: postSubplebbitAddress } = useReplyModal();
|
||||||
|
|
||||||
const comment = useComment({ commentCid });
|
const comment = useComment({ commentCid });
|
||||||
|
|
||||||
@@ -91,7 +91,16 @@ const PostPage = () => {
|
|||||||
return (
|
return (
|
||||||
<div className={styles.content}>
|
<div className={styles.content}>
|
||||||
{isInSettigsView && <SettingsModal />}
|
{isInSettigsView && <SettingsModal />}
|
||||||
{showReplyModal && activeCid && threadCid && <ReplyModal closeModal={closeModal} parentCid={activeCid} postCid={threadCid} scrollY={scrollY} />}
|
{activeCid && threadCid && postSubplebbitAddress && (
|
||||||
|
<ReplyModal
|
||||||
|
closeModal={closeModal}
|
||||||
|
parentCid={activeCid}
|
||||||
|
postCid={threadCid}
|
||||||
|
scrollY={scrollY}
|
||||||
|
showReplyModal={showReplyModal}
|
||||||
|
subplebbitAddress={postSubplebbitAddress}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
{/* TODO: remove this replyCount error once api supports scrolling replies pages */}
|
{/* TODO: remove this replyCount error once api supports scrolling replies pages */}
|
||||||
{replyCount > 60 && <span className={styles.error}>Error: this thread has too many replies, some of them cannot be displayed right now.</span>}
|
{replyCount > 60 && <span className={styles.error}>Error: this thread has too many replies, some of them cannot be displayed right now.</span>}
|
||||||
{error && <span className={styles.error}>Error: {error.message}</span>}
|
{error && <span className={styles.error}>Error: {error.message}</span>}
|
||||||
|
|||||||
Reference in New Issue
Block a user