feat(reply): add inbox reply design for notifications

This commit is contained in:
plebeius.eth
2023-12-24 16:10:47 +01:00
parent 1bdfe447b8
commit e7daa04886
4 changed files with 155 additions and 61 deletions

View File

@@ -1,4 +1,4 @@
import { Link } from 'react-router-dom';
import { Link, useLocation } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { Author, useAccount, useComment, useSubplebbit } from '@plebbit/plebbit-react-hooks';
import styles from './comment-tools.module.css';
@@ -6,6 +6,7 @@ import HideMenu from './hide-menu';
import ModTools from './mod-menu';
import ShareMenu from './share-menu';
import { FailedLabel, PendingLabel, SpoilerLabel } from '../label';
import { isInboxView } from '../../../lib/utils/view-utils';
interface CommentToolsProps {
author?: Author;
@@ -115,9 +116,10 @@ const CommentTools = ({
const authorRole = useSubplebbit({ subplebbitAddress })?.roles?.[account?.author?.address]?.role;
const isMod = authorRole === 'admin' || authorRole === 'owner' || authorRole === 'moderator';
hasLabel = spoiler || (cid === undefined && !isReply);
const isInboxPage = isInboxView(useLocation().pathname);
return (
<ul className={`${styles.buttons} ${isReply ? styles.buttonsReply : ''} ${hasLabel ? styles.buttonsLabel : ''}`}>
<ul className={`${styles.buttons} ${isReply && !isInboxPage ? styles.buttonsReply : ''} ${hasLabel ? styles.buttonsLabel : ''}`}>
{hasLabel && <CommentToolsLabel cid={cid} failed={failed} isReply={isReply} spoiler={spoiler} subplebbitAddress={subplebbitAddress} />}
{isReply ? (
isSingleReply ? (

View File

@@ -14,11 +14,11 @@
.unreadNotification {
background-color: var(--gray-overlay);
border: 1px solid var(--gray-border);
border: 1px solid var(--gray-overlay-border);
margin-left: 30px;
margin-right: 15px;
padding: 6px;
padding: 10px 5px;
margin-bottom: 10px;
margin-top: 2px;
margin-bottom: 5px;
}
.midcol {
@@ -184,4 +184,44 @@
.parentSubplebbit {
color: var(--text-primary)
}
.inboxParentLinkSubject {
color: var(--text);
font-size: 12px;
font-weight: bold;
}
.inboxParentLink {
font-weight: normal;
font-style: italic;
margin-left: 10px;
font-size: 12px;
color: var(--link);
outline: none;
overflow: hidden;
unicode-bidi: isolate;
}
.inboxParentLinkWrapper {
margin-left: 7px;
}
.inboxParentInfo {
color: var(--green);
font-weight: 700;
}
.inboxParentInfo a {
color: var(--text-primary);
}
.inboxParentInfoButton {
cursor: pointer;
font-weight: 700;
color: var(--text-primary);
}
.addMargin {
margin-left: 29px;
}

View File

@@ -1,7 +1,7 @@
import { useMemo, useState } from 'react';
import { Comment, useAccountComment, useAuthorAddress, useComment, useSubplebbit } from '@plebbit/plebbit-react-hooks';
import { flattenCommentsPages } from '@plebbit/plebbit-react-hooks/dist/lib/utils';
import { Link } from 'react-router-dom';
import { Link, useLocation } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import styles from './reply.module.css';
import useReplies from '../../hooks/use-replies';
@@ -18,6 +18,7 @@ import ReplyForm from '../reply-form';
import useDownvote from '../../hooks/use-downvote';
import useStateString from '../../hooks/use-state-string';
import useUpvote from '../../hooks/use-upvote';
import { isInboxView } from '../../lib/utils/view-utils';
interface ReplyAuthorProps {
address: string;
@@ -103,7 +104,8 @@ const ReplyMedia = ({ commentMediaInfo, content, expanded, hasThumbnail, link, l
};
type ParentLinkProps = {
postCid: string;
commentCid?: string;
postCid?: string;
};
const ParentLink = ({ postCid }: ParentLinkProps) => {
@@ -129,6 +131,49 @@ const ParentLink = ({ postCid }: ParentLinkProps) => {
);
};
const InboxParentLink = ({ commentCid }: ParentLinkProps) => {
const inboxComment = useComment({ commentCid });
const { postCid, parentCid } = inboxComment || {};
const parentComment = useComment({ commentCid: inboxComment?.postCid });
const { cid, content, title, subplebbitAddress } = parentComment || {};
// const { t } = useTranslation();
const postTitle = (title?.length > 300 ? title?.slice(0, 300) + '...' : title) || (content?.length > 300 ? content?.slice(0, 300) + '...' : content);
const isInboxCommentReply = postCid !== parentCid;
const isInboxPostReply = postCid === parentCid;
return (
<div className={styles.inboxParentLinkWrapper}>
<span className={styles.inboxParentLinkSubject}>{isInboxCommentReply ? 'comment reply' : isInboxPostReply ? 'post reply' : ''}</span>
<Link to={`/p/${subplebbitAddress}/c/${cid}`} className={styles.inboxParentLink}>
{postTitle}
</Link>
</div>
);
};
const InboxParentInfo = ({ commentCid }: ParentLinkProps) => {
const parent = useComment({ commentCid });
const { author, cid, subplebbitAddress, timestamp } = parent || {};
return (
<>
<div className={styles.inboxParentInfo}>
from{' '}
<Link to={`/u/${author?.address}/c/${cid}`} className={styles.inboxParentAuthor}>
u/{author?.shortAddress}{' '}
</Link>
via{' '}
<Link to={`/p/${subplebbitAddress}`} className={styles.inboxParentSubplebbit}>
p/{subplebbitAddress}{' '}
</Link>
sent {getFormattedTimeAgo(timestamp)}
</div>
<div className={styles.inboxParentInfoButton}>show parent</div>
</>
);
};
interface ReplyProps {
depth?: number;
index?: number;
@@ -196,72 +241,77 @@ const Reply = ({ depth = 0, isSingle, isNotification = false, reply = {} }: Repl
const pendingReply = useAccountComment({ commentIndex: reply?.index });
const parentOfPendingReply = useComment({ commentCid: pendingReply?.parentCid });
const location = useLocation();
const isInboxPage = isInboxView(location.pathname);
return (
<div className={styles.reply}>
{isSingle && <ParentLink postCid={cid ? postCid : parentOfPendingReply?.postCid} />}
<div
className={`${!isSingle ? styles.replyWrapper : styles.singleReplyWrapper} ${depth > 1 && styles.nested} ${
isNotification && !markedAsRead ? styles.unreadNotification : ''
}`}
>
{isSingle && !isInboxPage && <ParentLink postCid={cid ? postCid : parentOfPendingReply?.postCid} />}
{isInboxPage && <InboxParentLink commentCid={cid} />}
<div className={`${!isSingle ? styles.replyWrapper : styles.singleReplyWrapper} ${depth > 1 && styles.nested}`}>
{!collapsed && (
<div className={styles.midcol}>
<div className={`${styles.arrow} ${upvoted ? styles.upvoted : styles.arrowUp}`} onClick={() => cid && upvote()} />
<div className={`${styles.arrow} ${downvoted ? styles.downvoted : styles.arrowDown}`} onClick={() => cid && downvote()} />
</div>
)}
<div className={`${styles.entry} ${collapsed && styles.collapsedEntry}`}>
<p className={styles.tagline}>
<span className={styles.expand} onClick={() => setCollapsed(!collapsed)}>
[{collapsed ? '+' : ''}]
</span>
<ReplyAuthor address={author?.address} authorRole={authorRole} cid={cid} displayName={author.displayName} shortAuthorAddress={shortAuthorAddress} />
<span className={styles.score}>{scoreString}</span> <span className={styles.time}>{getFormattedTimeAgo(timestamp)}</span>
{collapsed && <span className={styles.children}> ({childrenString})</span>}
{stateLabel}
{!collapsed && flair && (
<>
{' '}
<Flair flair={flair} />
</>
<div className={`${isNotification && !markedAsRead ? styles.unreadNotification : ''}`}>
<div className={`${styles.entry} ${collapsed && styles.collapsedEntry}`}>
{!isInboxPage && (
<p className={styles.tagline}>
<span className={styles.expand} onClick={() => setCollapsed(!collapsed)}>
[{collapsed ? '+' : ''}]
</span>
<ReplyAuthor address={author?.address} authorRole={authorRole} cid={cid} displayName={author.displayName} shortAuthorAddress={shortAuthorAddress} />
<span className={styles.score}>{scoreString}</span> <span className={styles.time}>{getFormattedTimeAgo(timestamp)}</span>
{collapsed && <span className={styles.children}> ({childrenString})</span>}
{stateLabel}
{!collapsed && flair && (
<>
{' '}
<Flair flair={flair} />
</>
)}
{state === 'pending' && loadingString}
</p>
)}
{state === 'pending' && loadingString}
</p>
{isInboxPage && <InboxParentInfo commentCid={cid} />}
{!collapsed && (
<div className={styles.usertext}>
{commentMediaInfo && (
<ReplyMedia
commentMediaInfo={commentMediaInfo}
content={content}
expanded={expanded}
hasThumbnail={hasThumbnail}
link={link}
linkHeight={linkHeight}
linkWidth={linkWidth}
toggleExpanded={toggleExpanded}
/>
)}
<div className={styles.md}>{contentString}</div>
</div>
)}
</div>
{!collapsed && (
<div className={styles.usertext}>
{commentMediaInfo && (
<ReplyMedia
commentMediaInfo={commentMediaInfo}
content={content}
expanded={expanded}
hasThumbnail={hasThumbnail}
link={link}
linkHeight={linkHeight}
linkWidth={linkWidth}
toggleExpanded={toggleExpanded}
/>
)}
<div className={styles.md}>{contentString}</div>
<div className={isInboxPage && markedAsRead ? styles.addMargin : ''}>
<CommentTools
cid={reply.cid}
isReply={true}
isSingleReply={isSingle}
index={reply?.index}
parentCid={reply?.postCid}
replyCount={replies.length}
spoiler={spoiler}
subplebbitAddress={reply.subplebbitAddress}
showReplyForm={showReplyForm}
/>
{isReplying && <ReplyForm cid={cid} isReplyingToReply={true} hideReplyForm={hideReplyForm} />}
{!isSingle && replies.map((reply, index) => <Reply key={`${index}${reply.cid}`} reply={reply} depth={(reply.depth || 1) + 1} />)}
</div>
)}
</div>
{!collapsed && (
<>
<CommentTools
cid={reply.cid}
isReply={true}
isSingleReply={isSingle}
index={reply?.index}
parentCid={reply?.postCid}
replyCount={replies.length}
spoiler={spoiler}
subplebbitAddress={reply.subplebbitAddress}
showReplyForm={showReplyForm}
/>
{isReplying && <ReplyForm cid={cid} isReplyingToReply={true} hideReplyForm={hideReplyForm} />}
{!isSingle && replies.map((reply, index) => <Reply key={`${index}${reply.cid}`} reply={reply} depth={(reply.depth || 1) + 1} />)}
</>
)}
</div>
</div>
);

View File

@@ -5,6 +5,7 @@
--red: red;
--gray-contrast: #888;
--gray-overlay: #F7F7F7;
--gray-overlay-border: #E9E9E9;
--gray-border: #ddd;
--gray-light: #CCCCCA;
--box-shadow-modal: 4px 4px 4px #ccc;
@@ -52,6 +53,7 @@
--red: rgb(200, 0, 0);
--gray-contrast: #c7c7c7;
--gray-overlay: #1f1f1f;
--gray-overlay-border: #3e3e3e;
--gray-border: #3e3e3e;
--gray-light: #3e3e3e9d;
--box-shadow-modal: 4px 4px 4px #000;