mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
feat(post): add post count and highlight functionality to u/address
This commit is contained in:
@@ -20,7 +20,6 @@
|
||||
}
|
||||
|
||||
.boardSubtitle {
|
||||
margin-top: 3px;
|
||||
font-size: var(--board-address-font-size);
|
||||
color: var(--board-address-text-color);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { getCommentMediaInfo, getDisplayMediaInfoType, getHasThumbnail } from '.
|
||||
import { getFormattedDate, getFormattedTimeAgo } from '../../lib/utils/time-utils';
|
||||
import { isValidURL } from '../../lib/utils/url-utils';
|
||||
import { isAllView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
||||
import useAuthorAddressClick from '../../hooks/use-author-address-click';
|
||||
import useEditCommentPrivileges from '../../hooks/use-author-privileges';
|
||||
import useCountLinksInReplies from '../../hooks/use-count-links-in-replies';
|
||||
import useHide from '../../hooks/use-hide';
|
||||
@@ -47,6 +48,9 @@ const PostInfo = ({ openReplyModal, post, roles, isHidden }: PostProps) => {
|
||||
|
||||
const { isCommentAuthorMod, isAccountMod, isAccountCommentAuthor } = useEditCommentPrivileges({ commentAuthorAddress: address, subplebbitAddress });
|
||||
|
||||
const handleUserAddressClick = useAuthorAddressClick();
|
||||
const numberOfPostsByAuthor = document.querySelectorAll(`.${shortAddress}`).length;
|
||||
|
||||
return (
|
||||
<div className={styles.postInfo}>
|
||||
{!isHidden && <EditMenu isAccountCommentAuthor={isAccountCommentAuthor} isAccountMod={isAccountMod} isCommentAuthorMod={isCommentAuthorMod} post={post} />}
|
||||
@@ -75,7 +79,24 @@ const PostInfo = ({ openReplyModal, post, roles, isHidden }: PostProps) => {
|
||||
)}
|
||||
{authorRole && ` ## Board ${authorRole}`}{' '}
|
||||
</span>
|
||||
{!(isDescription || isRules) && <span className={styles.userAddress}>(u/{shortAddress || accountShortAddress}) </span>}
|
||||
{!(isDescription || isRules) && (
|
||||
<>
|
||||
(u/
|
||||
<Tooltip
|
||||
children={
|
||||
<span
|
||||
title='Highlight posts by this user address'
|
||||
className={styles.userAddress}
|
||||
onClick={() => handleUserAddressClick(shortAddress || accountShortAddress)}
|
||||
>
|
||||
{shortAddress || accountShortAddress}
|
||||
</span>
|
||||
}
|
||||
content={`${numberOfPostsByAuthor} ${numberOfPostsByAuthor === 1 ? 'post' : 'posts'} by this user address`}
|
||||
/>
|
||||
){' '}
|
||||
</>
|
||||
)}
|
||||
</span>
|
||||
<span className={styles.dateTime}>
|
||||
<Tooltip children={<span>{getFormattedDate(timestamp)}</span>} content={getFormattedTimeAgo(timestamp)} />
|
||||
@@ -272,7 +293,15 @@ const Reply = ({ openReplyModal, reply, roles }: PostProps) => {
|
||||
return (
|
||||
<div className={styles.replyDesktop}>
|
||||
<div className={styles.sideArrows}>{'>>'}</div>
|
||||
<div className={`${styles.reply} ${isRouteLinkToReply && styles.highlight} ${hidden && styles.postDesktopHidden}`} id={cid}>
|
||||
<div
|
||||
className={`
|
||||
${styles.reply}
|
||||
${isRouteLinkToReply && styles.highlight}
|
||||
${hidden && styles.postDesktopHidden}
|
||||
${cid}
|
||||
${post?.author?.shortAddress}
|
||||
`}
|
||||
>
|
||||
<PostInfo openReplyModal={openReplyModal} post={post} roles={roles} />
|
||||
{link && !hidden && isValidURL(link) && <PostMedia post={post} />}
|
||||
{content && !hidden && <PostMessage post={post} />}
|
||||
|
||||
@@ -7,6 +7,7 @@ import styles from '../../views/post/post.module.css';
|
||||
import { getCommentMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils';
|
||||
import { getFormattedDate, getFormattedTimeAgo } from '../../lib/utils/time-utils';
|
||||
import { isAllView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
||||
import useAuthorAddressClick from '../../hooks/use-author-address-click';
|
||||
import useCountLinksInReplies from '../../hooks/use-count-links-in-replies';
|
||||
import useHide from '../../hooks/use-hide';
|
||||
import useReplies from '../../hooks/use-replies';
|
||||
@@ -45,6 +46,9 @@ const PostInfoAndMedia = ({ openReplyModal, post, roles }: PostProps) => {
|
||||
|
||||
const stateString = useStateString(post);
|
||||
|
||||
const handleUserAddressClick = useAuthorAddressClick();
|
||||
const numberOfPostsByAuthor = document.querySelectorAll(`.${shortAddress}`).length;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={styles.postInfo}>
|
||||
@@ -65,7 +69,24 @@ const PostInfoAndMedia = ({ openReplyModal, post, roles }: PostProps) => {
|
||||
)}
|
||||
{authorRole && ` ## Board ${authorRole}`}{' '}
|
||||
</span>
|
||||
{!(isDescription || isRules) && <span className={styles.address}>(u/{shortAddress || accountShortAddress})</span>}
|
||||
{!(isDescription || isRules) && (
|
||||
<>
|
||||
(u/
|
||||
<Tooltip
|
||||
children={
|
||||
<span
|
||||
title='Highlight posts by this user address'
|
||||
className={styles.userAddress}
|
||||
onClick={() => handleUserAddressClick(shortAddress || accountShortAddress)}
|
||||
>
|
||||
{shortAddress || accountShortAddress}
|
||||
</span>
|
||||
}
|
||||
content={`${numberOfPostsByAuthor} ${numberOfPostsByAuthor === 1 ? 'post' : 'posts'} by this user address`}
|
||||
/>
|
||||
){' '}
|
||||
</>
|
||||
)}
|
||||
{pinned && (
|
||||
<span className={styles.stickyIconWrapper}>
|
||||
<img src='assets/icons/sticky.gif' alt='' className={styles.stickyIcon} title={t('sticky')} />
|
||||
@@ -224,7 +245,15 @@ const Reply = ({ openReplyModal, reply, roles }: PostProps) => {
|
||||
return (
|
||||
<div className={styles.replyMobile}>
|
||||
<div className={styles.reply}>
|
||||
<div className={`${styles.replyContainer} ${isRouteLinkToReply && styles.highlight}`} id={cid}>
|
||||
<div
|
||||
className={`
|
||||
${styles.replyContainer}
|
||||
${isRouteLinkToReply && styles.highlight}
|
||||
${hidden && styles.postDesktopHidden}
|
||||
${cid}
|
||||
${post?.author?.shortAddress}
|
||||
`}
|
||||
>
|
||||
<PostInfoAndMedia openReplyModal={openReplyModal} post={post} roles={roles} />
|
||||
{content && !hidden && <PostMessageMobile post={post} />}
|
||||
<ReplyBacklinks post={reply} />
|
||||
|
||||
@@ -15,9 +15,9 @@ interface ReplyQuotePreviewProps {
|
||||
}
|
||||
|
||||
const handleQuoteHover = (cid: string, onElementOutOfView: () => void) => {
|
||||
const targetElement = document.getElementById(cid);
|
||||
const targetElements = document.querySelectorAll(`.${cid}`);
|
||||
|
||||
if (!targetElement) return;
|
||||
if (targetElements.length === 0) return;
|
||||
|
||||
const isInViewport = (element: HTMLElement) => {
|
||||
const bounding = element.getBoundingClientRect();
|
||||
@@ -29,10 +29,19 @@ const handleQuoteHover = (cid: string, onElementOutOfView: () => void) => {
|
||||
);
|
||||
};
|
||||
|
||||
if (isInViewport(targetElement)) {
|
||||
targetElement.classList.add('highlight');
|
||||
} else {
|
||||
targetElement.classList.remove('highlight');
|
||||
let anyInView = false;
|
||||
|
||||
targetElements.forEach((element) => {
|
||||
const htmlElement = element as HTMLElement;
|
||||
if (isInViewport(htmlElement)) {
|
||||
htmlElement.classList.add('highlight');
|
||||
anyInView = true;
|
||||
} else {
|
||||
htmlElement.classList.remove('highlight');
|
||||
}
|
||||
});
|
||||
|
||||
if (!anyInView) {
|
||||
onElementOutOfView();
|
||||
}
|
||||
};
|
||||
@@ -88,10 +97,10 @@ const DesktopQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, i
|
||||
|
||||
const handleMouseLeave = (cid: string | null) => {
|
||||
if (cid) {
|
||||
const targetElement = document.getElementById(cid);
|
||||
if (targetElement) {
|
||||
targetElement.classList.remove('highlight');
|
||||
}
|
||||
const targetElements = document.querySelectorAll(`.${cid}`);
|
||||
targetElements.forEach((element) => {
|
||||
element.classList.remove('highlight');
|
||||
});
|
||||
}
|
||||
setHoveredCid(null);
|
||||
setOutOfViewCid(null);
|
||||
@@ -174,10 +183,10 @@ const MobileQuotePreview = ({ backlinkReply, quotelinkReply, isBacklinkReply, is
|
||||
|
||||
const handleMouseLeave = (cid: string | null) => {
|
||||
if (cid) {
|
||||
const targetElement = document.getElementById(cid);
|
||||
if (targetElement) {
|
||||
targetElement.classList.remove('highlight');
|
||||
}
|
||||
const targetElements = document.querySelectorAll(`.${cid}`);
|
||||
targetElements.forEach((element) => {
|
||||
element.classList.remove('highlight');
|
||||
});
|
||||
}
|
||||
setHoveredCid(null);
|
||||
setOutOfViewCid(null);
|
||||
|
||||
@@ -24,7 +24,7 @@ const Tooltip = ({ content, children }: TooltipProps) => {
|
||||
],
|
||||
});
|
||||
|
||||
const hover = useHover(context, { move: false, delay: { open: 250, close: 0 } });
|
||||
const hover = useHover(context, { move: false, delay: { open: 500, close: 0 } });
|
||||
const focus = useFocus(context);
|
||||
const dismiss = useDismiss(context);
|
||||
const role = useRole(context, { role: 'tooltip' });
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
const useAuthorAddressClick = () => {
|
||||
const handleUserAddressClick = (shortAddress: string | undefined) => {
|
||||
if (!shortAddress) return;
|
||||
|
||||
// Select the elements corresponding to the clicked short address
|
||||
const elements = document.querySelectorAll(`.${shortAddress}`);
|
||||
|
||||
// Check if the clicked address is already highlighted
|
||||
const isAlreadyHighlighted = Array.from(elements).some((element) => element.classList.contains('highlight'));
|
||||
|
||||
// Remove highlight from all elements with the .highlight class
|
||||
const prevElements = document.querySelectorAll('.highlight');
|
||||
prevElements.forEach((element) => {
|
||||
element.classList.remove('highlight');
|
||||
});
|
||||
|
||||
// If the clicked address was already highlighted, don't add the highlight back
|
||||
if (isAlreadyHighlighted) return;
|
||||
|
||||
// Highlight the new elements
|
||||
elements.forEach((element) => {
|
||||
element.classList.add('highlight');
|
||||
});
|
||||
};
|
||||
|
||||
return handleUserAddressClick;
|
||||
};
|
||||
|
||||
export default useAuthorAddressClick;
|
||||
+16
-10
@@ -143,10 +143,23 @@ const Footer = () => {
|
||||
{t('about')}
|
||||
</a>
|
||||
</li>
|
||||
{downloadAppLink && (
|
||||
<li>
|
||||
<a href={downloadAppLink} target='_blank' rel='noopener noreferrer'>
|
||||
{t('download_app')}
|
||||
</a>
|
||||
</li>
|
||||
)}
|
||||
<li>
|
||||
<a href='https://twitter.com/getplebchan' target='_blank' rel='noopener noreferrer'>
|
||||
Twitter
|
||||
</a>
|
||||
<Link
|
||||
to='/faq'
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
alert('work in progress');
|
||||
}}
|
||||
>
|
||||
FAQ
|
||||
</Link>
|
||||
</li>
|
||||
<li>
|
||||
<a href='https://t.me/plebbit' target='_blank' rel='noopener noreferrer'>
|
||||
@@ -163,13 +176,6 @@ const Footer = () => {
|
||||
GitHub
|
||||
</a>
|
||||
</li>
|
||||
{downloadAppLink && (
|
||||
<li>
|
||||
<a href={downloadAppLink} target='_blank' rel='noopener noreferrer'>
|
||||
{t('download_app')}
|
||||
</a>
|
||||
</li>
|
||||
)}
|
||||
<li>
|
||||
<a href='https://etherscan.io/token/0xEA81DaB2e0EcBc6B5c4172DE4c22B6Ef6E55Bd8f' target='_blank' rel='noopener noreferrer'>
|
||||
{t('token')}
|
||||
|
||||
@@ -66,6 +66,14 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.userAddress {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.postDesktop .userAddress:hover {
|
||||
color: var(--button-desktop-text-color-hover);
|
||||
}
|
||||
|
||||
.postDesktop .subject {
|
||||
color: var(--post-subject-text-color);
|
||||
font-weight: var(--post-subject-font-weight);
|
||||
|
||||
Reference in New Issue
Block a user