mirror of
https://github.com/bitsocialnet/5chan.git
synced 2026-08-03 07:41:04 +02:00
feat(post): add "time ago" tooltip to dates
This commit is contained in:
@@ -5,7 +5,6 @@ import { Comment, useAccount, useBlock, useComment } from '@plebbit/plebbit-reac
|
|||||||
import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js';
|
import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js';
|
||||||
import styles from '../post.module.css';
|
import styles from '../post.module.css';
|
||||||
import { getCommentMediaInfo, getDisplayMediaInfoType, getHasThumbnail } from '../../../lib/utils/media-utils';
|
import { getCommentMediaInfo, getDisplayMediaInfoType, getHasThumbnail } from '../../../lib/utils/media-utils';
|
||||||
import { getFormattedDate } 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';
|
||||||
import useCountLinksInReplies from '../../../hooks/use-count-links-in-replies';
|
import useCountLinksInReplies from '../../../hooks/use-count-links-in-replies';
|
||||||
@@ -20,6 +19,7 @@ import PostMenuDesktop from './post-menu-desktop/';
|
|||||||
import EditMenu from '../edit-menu/edit-menu';
|
import EditMenu from '../edit-menu/edit-menu';
|
||||||
import ReplyQuotePreview from '../reply-quote-preview';
|
import ReplyQuotePreview from '../reply-quote-preview';
|
||||||
import { PostProps } from '../post';
|
import { PostProps } from '../post';
|
||||||
|
import Timestamp from '../timestamp';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
const PostInfo = ({ openReplyModal, post, roles, isHidden }: PostProps) => {
|
const PostInfo = ({ openReplyModal, post, roles, isHidden }: PostProps) => {
|
||||||
@@ -58,7 +58,7 @@ const PostInfo = ({ openReplyModal, post, roles, isHidden }: PostProps) => {
|
|||||||
{!(isDescription || isRules) && <span className={styles.userAddress}>(u/{shortAddress || accountShortAddress}) </span>}
|
{!(isDescription || isRules) && <span className={styles.userAddress}>(u/{shortAddress || accountShortAddress}) </span>}
|
||||||
</span>
|
</span>
|
||||||
<span className={styles.dateTime}>
|
<span className={styles.dateTime}>
|
||||||
{getFormattedDate(timestamp)}
|
<Timestamp timestamp={timestamp} />
|
||||||
{isDescription || isRules ? '' : ' '}
|
{isDescription || isRules ? '' : ' '}
|
||||||
</span>
|
</span>
|
||||||
<span className={styles.postNum}>
|
<span className={styles.postNum}>
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import { Comment, useAccount, useComment } from '@plebbit/plebbit-react-hooks';
|
|||||||
import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js';
|
import Plebbit from '@plebbit/plebbit-js/dist/browser/index.js';
|
||||||
import styles from '../post.module.css';
|
import styles from '../post.module.css';
|
||||||
import { getCommentMediaInfo, getHasThumbnail } from '../../../lib/utils/media-utils';
|
import { getCommentMediaInfo, getHasThumbnail } from '../../../lib/utils/media-utils';
|
||||||
import { getFormattedDate } 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 useCountLinksInReplies from '../../../hooks/use-count-links-in-replies';
|
import useCountLinksInReplies from '../../../hooks/use-count-links-in-replies';
|
||||||
import useReplies from '../../../hooks/use-replies';
|
import useReplies from '../../../hooks/use-replies';
|
||||||
@@ -16,6 +15,7 @@ import Markdown from '../../markdown';
|
|||||||
import ReplyQuotePreview from '../reply-quote-preview';
|
import ReplyQuotePreview from '../reply-quote-preview';
|
||||||
import PostMenuMobile from './post-menu-mobile';
|
import PostMenuMobile from './post-menu-mobile';
|
||||||
import { PostProps } from '../post';
|
import { PostProps } from '../post';
|
||||||
|
import Timestamp from '../timestamp';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
const PostInfoAndMedia = ({ openReplyModal, post, roles }: PostProps) => {
|
const PostInfoAndMedia = ({ openReplyModal, post, roles }: PostProps) => {
|
||||||
@@ -78,7 +78,7 @@ const PostInfoAndMedia = ({ openReplyModal, post, roles }: PostProps) => {
|
|||||||
<Link to={`/p/${subplebbitAddress}`}>p/{subplebbitAddress && Plebbit.getShortAddress(subplebbitAddress)}</Link>
|
<Link to={`/p/${subplebbitAddress}`}>p/{subplebbitAddress && Plebbit.getShortAddress(subplebbitAddress)}</Link>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{getFormattedDate(timestamp)}{' '}
|
<Timestamp timestamp={timestamp} />{' '}
|
||||||
{!(isDescription || isRules) && (
|
{!(isDescription || isRules) && (
|
||||||
<span className={styles.postNumLink}>
|
<span className={styles.postNumLink}>
|
||||||
<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()}>
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
export { default } from './timestamp';
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
import { getFormattedDate, getFormattedTimeAgo } from '../../../lib/utils/time-utils';
|
||||||
|
import { useFloating, autoUpdate, offset, flip, shift, useHover, useFocus, useDismiss, useRole, useInteractions, FloatingPortal } from '@floating-ui/react';
|
||||||
|
|
||||||
|
const Timestamp = ({ timestamp }: { timestamp: number }) => {
|
||||||
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
|
||||||
|
const { refs, floatingStyles, context } = useFloating({
|
||||||
|
open: isOpen,
|
||||||
|
onOpenChange: setIsOpen,
|
||||||
|
placement: 'top',
|
||||||
|
whileElementsMounted: autoUpdate,
|
||||||
|
middleware: [
|
||||||
|
offset(5),
|
||||||
|
flip({
|
||||||
|
fallbackAxisSideDirection: 'start',
|
||||||
|
}),
|
||||||
|
shift(),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const hover = useHover(context, { move: false, delay: { open: 250, close: 0 } });
|
||||||
|
const focus = useFocus(context);
|
||||||
|
const dismiss = useDismiss(context);
|
||||||
|
const role = useRole(context, { role: 'tooltip' });
|
||||||
|
|
||||||
|
const { getReferenceProps, getFloatingProps } = useInteractions([hover, focus, dismiss, role]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<span ref={refs.setReference} {...getReferenceProps()}>
|
||||||
|
{getFormattedDate(timestamp)}
|
||||||
|
</span>
|
||||||
|
<FloatingPortal>
|
||||||
|
{isOpen && (
|
||||||
|
<div className='tooltip' ref={refs.setFloating} style={floatingStyles} {...getFloatingProps()}>
|
||||||
|
{getFormattedTimeAgo(timestamp)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</FloatingPortal>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Timestamp;
|
||||||
@@ -34,6 +34,34 @@ hr {
|
|||||||
text-transform: capitalize;
|
text-transform: capitalize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.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%;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 640px) {
|
@media (max-width: 640px) {
|
||||||
.button {
|
.button {
|
||||||
font-size: var(--button-font-size-mobile);
|
font-size: var(--button-font-size-mobile);
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ const BoardsBox = ({ multisub, subplebbits }: { multisub: Subplebbit[]; subplebb
|
|||||||
return (
|
return (
|
||||||
<div className={`${styles.box} ${styles.boardsBox}`}>
|
<div className={`${styles.box} ${styles.boardsBox}`}>
|
||||||
<div className={styles.boxBar}>
|
<div className={styles.boxBar}>
|
||||||
<h2 className={styles.capitalize}>{t('boards')}</h2>
|
<h2 className='capitalize'>{t('boards')}</h2>
|
||||||
<BoxModal isBoardsBoxModal={true} />
|
<BoxModal isBoardsBoxModal={true} />
|
||||||
</div>
|
</div>
|
||||||
<div className={styles.boardsBoxContent}>
|
<div className={styles.boardsBoxContent}>
|
||||||
|
|||||||
@@ -150,10 +150,6 @@
|
|||||||
content: '✔ ';
|
content: '✔ ';
|
||||||
}
|
}
|
||||||
|
|
||||||
.capitalize {
|
|
||||||
text-transform: capitalize;
|
|
||||||
}
|
|
||||||
|
|
||||||
.list a {
|
.list a {
|
||||||
color: var(--homepage-box-link-text-color);
|
color: var(--homepage-box-link-text-color);
|
||||||
text-decoration: var(--homepage-box-link-text-decoration);
|
text-decoration: var(--homepage-box-link-text-decoration);
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ const Stats = ({ multisub, subplebbitAddresses }: { multisub: any; subplebbitAdd
|
|||||||
return (
|
return (
|
||||||
<div className={styles.box}>
|
<div className={styles.box}>
|
||||||
<div className={`${styles.boxBar} ${styles.color2ColorBar}`}>
|
<div className={`${styles.boxBar} ${styles.color2ColorBar}`}>
|
||||||
<h2 className={styles.capitalize}>{t('stats')}</h2>
|
<h2 className='capitalize'>{t('stats')}</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className={`${styles.boxContent} ${enoughStats ? styles.stats : ''}`}>
|
<div className={`${styles.boxContent} ${enoughStats ? styles.stats : ''}`}>
|
||||||
{enoughStats ? (
|
{enoughStats ? (
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ const PopularThreadsBox = ({ multisub, subplebbits }: { multisub: Subplebbit[];
|
|||||||
return (
|
return (
|
||||||
<div className={styles.box}>
|
<div className={styles.box}>
|
||||||
<div className={`${styles.boxBar} ${styles.color2ColorBar}`}>
|
<div className={`${styles.boxBar} ${styles.color2ColorBar}`}>
|
||||||
<h2 className={styles.capitalize}>{t('popular_threads')}</h2>
|
<h2 className='capitalize'>{t('popular_threads')}</h2>
|
||||||
<BoxModal isBoardsBoxModal={false} />
|
<BoxModal isBoardsBoxModal={false} />
|
||||||
</div>
|
</div>
|
||||||
<div className={`${styles.boxContent} ${popularPosts.length === 8 ? styles.popularThreads : ''}`}>
|
<div className={`${styles.boxContent} ${popularPosts.length === 8 ? styles.popularThreads : ''}`}>
|
||||||
|
|||||||
Reference in New Issue
Block a user