mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
feat(post): add tooltips for title and display names that are too long
This commit is contained in:
@@ -5,6 +5,7 @@ import { Comment, useAccount, useComment, useEditedComment } from '@plebbit/pleb
|
||||
import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js';
|
||||
import styles from '../../views/post/post.module.css';
|
||||
import { getCommentMediaInfo, getDisplayMediaInfoType, getHasThumbnail } from '../../lib/utils/media-utils';
|
||||
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 useEditCommentPrivileges from '../../hooks/use-author-privileges';
|
||||
@@ -13,22 +14,24 @@ import useHide from '../../hooks/use-hide';
|
||||
import useReplies from '../../hooks/use-replies';
|
||||
import useStateString from '../../hooks/use-state-string';
|
||||
import CommentMedia from '../comment-media';
|
||||
import EditMenu from '../edit-menu/edit-menu';
|
||||
import { canEmbed } from '../embed';
|
||||
import LoadingEllipsis from '../loading-ellipsis';
|
||||
import Markdown from '../markdown';
|
||||
import PostMenuDesktop from './post-menu-desktop';
|
||||
import EditMenu from '../edit-menu/edit-menu';
|
||||
import ReplyQuotePreview from '../reply-quote-preview';
|
||||
import Tooltip from '../tooltip';
|
||||
import { PostProps } from '../../views/post/post';
|
||||
import Timestamp from '../timestamp';
|
||||
import _ from 'lodash';
|
||||
import { getFormattedDate } from '../../lib/utils/time-utils';
|
||||
|
||||
const PostInfo = ({ openReplyModal, post, roles, isHidden }: PostProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { author, cid, locked, pinned, parentCid, postCid, replyCount, shortCid, state, subplebbitAddress, timestamp, title } = post || {};
|
||||
const { author, cid, locked, pinned, parentCid, postCid, replyCount, shortCid, state, subplebbitAddress, timestamp } = post || {};
|
||||
const title = post?.title?.trim();
|
||||
const replies = useReplies(post);
|
||||
const { address, displayName, shortAddress } = author || {};
|
||||
const { address, shortAddress } = author || {};
|
||||
const displayName = author?.displayName?.trim();
|
||||
const authorRole = roles?.[address]?.role;
|
||||
const { isDescription, isRules } = post || {}; // custom properties, not from api
|
||||
const stateString = useStateString(post);
|
||||
const isReply = parentCid;
|
||||
@@ -39,10 +42,6 @@ const PostInfo = ({ openReplyModal, post, roles, isHidden }: PostProps) => {
|
||||
const isInPostView = isPostPageView(location.pathname, params);
|
||||
const isInSubscriptionsView = isSubscriptionsView(location.pathname, useParams());
|
||||
|
||||
const shortDisplayName = displayName?.trim().length > 20 ? displayName?.trim().slice(0, 20).trim() + '...' : displayName?.trim();
|
||||
const authorRole = roles?.[address]?.role;
|
||||
const displayTitle = title && title.length > 75 ? title?.slice(0, 75) + '...' : title;
|
||||
|
||||
const account = useAccount();
|
||||
const accountShortAddress = account?.author?.shortAddress; // if reply by account is pending, it doesn't have an author yet
|
||||
|
||||
@@ -51,16 +50,35 @@ const PostInfo = ({ openReplyModal, post, roles, isHidden }: PostProps) => {
|
||||
return (
|
||||
<div className={styles.postInfo}>
|
||||
{!isHidden && <EditMenu isAccountCommentAuthor={isAccountCommentAuthor} isAccountMod={isAccountMod} isCommentAuthorMod={isCommentAuthorMod} post={post} />}
|
||||
{title && <span className={styles.subject}>{displayTitle} </span>}
|
||||
{title &&
|
||||
(title.length <= 75 ? (
|
||||
<span className={styles.subject}>{title} </span>
|
||||
) : (
|
||||
<Tooltip
|
||||
children={<span className={styles.subject}>{title.slice(0, 75) + '(...)'} </span>}
|
||||
content={title.length < 1000 ? title : title.slice(0, 1000) + '... title too long'}
|
||||
/>
|
||||
))}
|
||||
<span className={styles.nameBlock}>
|
||||
<span className={`${styles.name} ${(isDescription || isRules || authorRole) && styles.capcodeMod}`}>
|
||||
{shortDisplayName || _.capitalize(t('anonymous'))}
|
||||
{displayName ? (
|
||||
displayName.length <= 20 ? (
|
||||
<span className={styles.name}>{displayName}</span>
|
||||
) : (
|
||||
<Tooltip
|
||||
children={<span className={styles.name}>{displayName.slice(0, 20) + '(...)'}</span>}
|
||||
content={displayName.length < 1000 ? displayName : displayName.slice(0, 1000) + '... display name too long'}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
_.capitalize(t('anonymous'))
|
||||
)}
|
||||
{authorRole && ` ## Board ${authorRole}`}{' '}
|
||||
</span>
|
||||
{!(isDescription || isRules) && <span className={styles.userAddress}>(u/{shortAddress || accountShortAddress}) </span>}
|
||||
</span>
|
||||
<span className={styles.dateTime}>
|
||||
<Timestamp timestamp={timestamp} />
|
||||
<Tooltip children={<span>{getFormattedDate(timestamp)}</span>} content={getFormattedTimeAgo(timestamp)} />
|
||||
{isDescription || isRules ? '' : ' '}
|
||||
</span>
|
||||
<span className={styles.postNum}>
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Comment, useAccount, useComment, useEditedComment } from '@plebbit/pleb
|
||||
import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js';
|
||||
import styles from '../../views/post/post.module.css';
|
||||
import { getCommentMediaInfo, getHasThumbnail } from '../../lib/utils/media-utils';
|
||||
import { getFormattedDate } from '../../lib/utils/time-utils';
|
||||
import { getFormattedDate, getFormattedTimeAgo } from '../../lib/utils/time-utils';
|
||||
import { isAllView, isPendingPostView, isPostPageView, isSubscriptionsView } from '../../lib/utils/view-utils';
|
||||
import useCountLinksInReplies from '../../hooks/use-count-links-in-replies';
|
||||
import useHide from '../../hooks/use-hide';
|
||||
@@ -14,26 +14,25 @@ import useStateString from '../../hooks/use-state-string';
|
||||
import CommentMedia from '../comment-media';
|
||||
import LoadingEllipsis from '../loading-ellipsis';
|
||||
import Markdown from '../markdown';
|
||||
import ReplyQuotePreview from '../reply-quote-preview';
|
||||
import PostMenuMobile from './post-menu-mobile';
|
||||
import ReplyQuotePreview from '../reply-quote-preview';
|
||||
import Tooltip from '../tooltip';
|
||||
import { PostProps } from '../../views/post/post';
|
||||
import Timestamp from '../timestamp';
|
||||
import _ from 'lodash';
|
||||
|
||||
const PostInfoAndMedia = ({ openReplyModal, post, roles }: PostProps) => {
|
||||
const { t } = useTranslation();
|
||||
const { author, cid, link, locked, parentCid, pinned, shortCid, state, subplebbitAddress, timestamp, title } = post || {};
|
||||
const { author, cid, link, locked, parentCid, pinned, shortCid, state, subplebbitAddress, timestamp } = post || {};
|
||||
const title = post?.title?.trim();
|
||||
const { isDescription, isRules } = post || {}; // custom properties, not from api
|
||||
const { address, displayName, shortAddress } = author || {};
|
||||
const { address, shortAddress } = author || {};
|
||||
const displayName = author?.displayName?.trim();
|
||||
const authorRole = roles?.[address]?.role;
|
||||
|
||||
const location = useLocation();
|
||||
const isInAllView = isAllView(location.pathname, useParams());
|
||||
const isInSubscriptionsView = isSubscriptionsView(location.pathname, useParams());
|
||||
|
||||
const authorRole = roles?.[address]?.role;
|
||||
const shortDisplayName = displayName?.trim().length > 20 ? displayName?.trim().slice(0, 20).trim() + '...' : displayName?.trim();
|
||||
const displayTitle = title && title.length > 30 ? title?.slice(0, 30) + '(...)' : title;
|
||||
|
||||
const commentMediaInfo = getCommentMediaInfo(post);
|
||||
const hasThumbnail = getHasThumbnail(commentMediaInfo, link);
|
||||
const [showThumbnail, setShowThumbnail] = useState(true);
|
||||
@@ -52,7 +51,18 @@ const PostInfoAndMedia = ({ openReplyModal, post, roles }: PostProps) => {
|
||||
<PostMenuMobile post={post} />
|
||||
<span className={styles.nameBlock}>
|
||||
<span className={`${styles.name} ${(isDescription || isRules || authorRole) && styles.capcodeMod}`}>
|
||||
{shortDisplayName || _.capitalize(t('anonymous'))}
|
||||
{displayName ? (
|
||||
displayName.length <= 20 ? (
|
||||
<span className={styles.name}>{displayName}</span>
|
||||
) : (
|
||||
<Tooltip
|
||||
children={<span className={styles.name}>{displayName.slice(0, 20) + '(...)'}</span>}
|
||||
content={displayName.length < 1000 ? displayName : displayName.slice(0, 1000) + '... display name too long'}
|
||||
/>
|
||||
)
|
||||
) : (
|
||||
_.capitalize(t('anonymous'))
|
||||
)}
|
||||
{authorRole && ` ## Board ${authorRole}`}{' '}
|
||||
</span>
|
||||
{!(isDescription || isRules) && <span className={styles.address}>(u/{shortAddress || accountShortAddress})</span>}
|
||||
@@ -66,12 +76,15 @@ const PostInfoAndMedia = ({ openReplyModal, post, roles }: PostProps) => {
|
||||
<img src='assets/icons/closed.gif' alt='' className={styles.closedIcon} title={t('closed')} />
|
||||
</span>
|
||||
)}
|
||||
{title && (
|
||||
<>
|
||||
<br />
|
||||
<span className={styles.subject}>{displayTitle}</span>
|
||||
</>
|
||||
)}
|
||||
{title &&
|
||||
(title.length <= 30 ? (
|
||||
<span className={styles.subject}>{title}</span>
|
||||
) : (
|
||||
<Tooltip
|
||||
children={<span className={styles.subject}>{title.slice(0, 30) + '(...)'}</span>}
|
||||
content={title.length < 1000 ? title : title.slice(0, 1000) + '... title too long'}
|
||||
/>
|
||||
))}
|
||||
</span>
|
||||
<span className={styles.dateTimePostNum}>
|
||||
{subplebbitAddress && (isInAllView || isInSubscriptionsView) && !isReply && (
|
||||
@@ -80,7 +93,7 @@ const PostInfoAndMedia = ({ openReplyModal, post, roles }: PostProps) => {
|
||||
<Link to={`/p/${subplebbitAddress}`}>p/{subplebbitAddress && Plebbit.getShortAddress(subplebbitAddress)}</Link>
|
||||
</div>
|
||||
)}
|
||||
<Timestamp timestamp={timestamp} />{' '}
|
||||
<Tooltip children={<span>{getFormattedDate(timestamp)}</span>} content={getFormattedTimeAgo(timestamp)} />{' '}
|
||||
{!(isDescription || isRules) && (
|
||||
<span className={styles.postNumLink}>
|
||||
<Link to={`/p/${subplebbitAddress}/c/${cid}`} className={styles.linkToPost} title={t('link_to_post')} onClick={(e) => !cid && e.preventDefault()}>
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export { default } from './timestamp';
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from './tooltip';
|
||||
@@ -0,0 +1,27 @@
|
||||
.tooltip {
|
||||
position: absolute;
|
||||
background-color: #181f24;
|
||||
font-size: 11px;
|
||||
line-height: 13px;
|
||||
padding: 3px 6px;
|
||||
z-index: 100000;
|
||||
word-wrap: break-word;
|
||||
white-space: pre-line;
|
||||
max-width: 400px;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.tooltip::before {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 0;
|
||||
height: 0;
|
||||
position: absolute;
|
||||
border-left: 4px solid transparent;
|
||||
border-right: 4px solid transparent;
|
||||
border-top: 4px solid #181f24;
|
||||
margin-left: -4px;
|
||||
bottom: -4px;
|
||||
left: 50%;
|
||||
}
|
||||
@@ -1,8 +1,13 @@
|
||||
import { useState } from 'react';
|
||||
import { getFormattedDate, getFormattedTimeAgo } from '../../lib/utils/time-utils';
|
||||
import { useState, ReactNode } from 'react';
|
||||
import { useFloating, autoUpdate, offset, flip, shift, useHover, useFocus, useDismiss, useRole, useInteractions, FloatingPortal } from '@floating-ui/react';
|
||||
import styles from './tooltip.module.css';
|
||||
|
||||
const Timestamp = ({ timestamp }: { timestamp: number }) => {
|
||||
interface TooltipProps {
|
||||
content: string;
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
const Tooltip = ({ content, children }: TooltipProps) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const { refs, floatingStyles, context } = useFloating({
|
||||
@@ -29,12 +34,12 @@ const Timestamp = ({ timestamp }: { timestamp: number }) => {
|
||||
return (
|
||||
<>
|
||||
<span ref={refs.setReference} {...getReferenceProps()}>
|
||||
{getFormattedDate(timestamp)}
|
||||
{children}
|
||||
</span>
|
||||
<FloatingPortal>
|
||||
{isOpen && (
|
||||
<div className='tooltip' ref={refs.setFloating} style={floatingStyles} {...getFloatingProps()}>
|
||||
{getFormattedTimeAgo(timestamp)}
|
||||
<div className={styles.tooltip} ref={refs.setFloating} style={floatingStyles} {...getFloatingProps()}>
|
||||
{content}
|
||||
</div>
|
||||
)}
|
||||
</FloatingPortal>
|
||||
@@ -42,4 +47,4 @@ const Timestamp = ({ timestamp }: { timestamp: number }) => {
|
||||
);
|
||||
};
|
||||
|
||||
export default Timestamp;
|
||||
export default Tooltip;
|
||||
Reference in New Issue
Block a user