limit displayed comment depth

This commit is contained in:
keyan 2022-05-17 17:09:15 -05:00
parent 35b533c572
commit cef8a33267
7 changed files with 76 additions and 38 deletions

View File

@ -2,7 +2,7 @@ import itemStyles from './item.module.css'
import styles from './comment.module.css' import styles from './comment.module.css'
import Text from './text' import Text from './text'
import Link from 'next/link' import Link from 'next/link'
import Reply from './reply' import Reply, { ReplyOnAnotherPage } from './reply'
import { useEffect, useRef, useState } from 'react' import { useEffect, useRef, useState } from 'react'
import { timeSince } from '../lib/time' import { timeSince } from '../lib/time'
import UpVote from './upvote' import UpVote from './upvote'
@ -11,7 +11,7 @@ import EyeClose from '../svgs/eye-close-line.svg'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import CommentEdit from './comment-edit' import CommentEdit from './comment-edit'
import Countdown from './countdown' import Countdown from './countdown'
import { NOFOLLOW_LIMIT } from '../lib/constants' import { COMMENT_DEPTH_LIMIT, NOFOLLOW_LIMIT } from '../lib/constants'
import { ignoreClick } from '../lib/clicks' import { ignoreClick } from '../lib/clicks'
function Parent ({ item, rootText }) { function Parent ({ item, rootText }) {
@ -53,10 +53,17 @@ export function CommentFlat ({ item, ...props }) {
if (ignoreClick(e)) { if (ignoreClick(e)) {
return return
} }
router.push({ if (item.path.split('.').length > COMMENT_DEPTH_LIMIT + 1) {
pathname: '/items/[id]', router.push({
query: { id: item.root.id, commentId: item.id } pathname: '/items/[id]',
}, `/items/${item.root.id}`) query: { id: item.parentId, commentId: item.id }
}, `/items/${item.parentId}`)
} else {
router.push({
pathname: '/items/[id]',
query: { id: item.root.id, commentId: item.id }
}, `/items/${item.root.id}`)
}
}} }}
> >
<Comment item={item} {...props} /> <Comment item={item} {...props} />
@ -66,7 +73,7 @@ export function CommentFlat ({ item, ...props }) {
export default function Comment ({ export default function Comment ({
item, children, replyOpen, includeParent, item, children, replyOpen, includeParent,
rootText, noComments, noReply, truncate rootText, noComments, noReply, truncate, depth
}) { }) {
const [edit, setEdit] = useState() const [edit, setEdit] = useState()
const [collapse, setCollapse] = useState(false) const [collapse, setCollapse] = useState(false)
@ -89,6 +96,8 @@ export default function Comment ({
setCollapse(localStorage.getItem(`commentCollapse:${item.id}`)) setCollapse(localStorage.getItem(`commentCollapse:${item.id}`))
}, [item]) }, [item])
const bottomedOut = depth === COMMENT_DEPTH_LIMIT
const op = item.root.user.name === item.user.name const op = item.root.user.name === item.user.name
return ( return (
@ -171,20 +180,40 @@ export default function Comment ({
)} )}
</div> </div>
</div> </div>
<div className={`${styles.children}`}> {bottomedOut
{!noReply && ? <DepthLimit item={item} />
<Reply : (
parentId={item.id} meComments={item.meComments} replyOpen={replyOpen} <div className={`${styles.children}`}>
/>} {!noReply &&
{children} <Reply
<div className={`${styles.comments} ml-sm-1 ml-md-3`}> depth={depth + 1} parentId={item.id} meComments={item.meComments} replyOpen={replyOpen}
{item.comments && !noComments />}
? item.comments.map((item) => ( {children}
<Comment key={item.id} item={item} /> <div className={`${styles.comments} ml-sm-1 ml-md-3`}>
)) {item.comments && !noComments
: null} ? item.comments.map((item) => (
</div> <Comment depth={depth + 1} key={item.id} item={item} />
</div> ))
: null}
</div>
</div>
)}
</div>
)
}
function DepthLimit ({ item }) {
if (item.ncomments > 0) {
return (
<Link href={`/items/${item.id}`} passHref>
<a className='d-block p-3 font-weight-bold text-muted w-100 text-center'>view replies</a>
</Link>
)
}
return (
<div className={`${styles.children}`}>
<ReplyOnAnotherPage parentId={item.id} />
</div> </div>
) )
} }

View File

@ -1,4 +1,4 @@
import { gql, useApolloClient, useLazyQuery, useQuery } from '@apollo/client' import { gql, useApolloClient, useLazyQuery } from '@apollo/client'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import Comment, { CommentSkeleton } from './comment' import Comment, { CommentSkeleton } from './comment'
import styles from './header.module.css' import styles from './header.module.css'
@ -89,7 +89,7 @@ export default function Comments ({ parentId, comments, ...props }) {
{loading {loading
? <CommentsSkeleton /> ? <CommentsSkeleton />
: comments.map(item => ( : comments.map(item => (
<Comment key={item.id} item={item} {...props} /> <Comment depth={1} key={item.id} item={item} {...props} />
))} ))}
</> </>
) )
@ -98,14 +98,3 @@ export default function Comments ({ parentId, comments, ...props }) {
export function CommentsSkeleton () { export function CommentsSkeleton () {
return <CommentSkeleton skeletonChildren={7} /> return <CommentSkeleton skeletonChildren={7} />
} }
export function CommentsQuery ({ query, ...props }) {
const { error, data } = useQuery(query)
if (error) return <div>Failed to load!</div>
if (!data) {
return <CommentsSkeleton />
}
return <Comments comments={data.comments} {...props} />
}

View File

@ -10,6 +10,7 @@ import { timeSince } from '../lib/time'
import Link from 'next/link' import Link from 'next/link'
import Check from '../svgs/check-double-line.svg' import Check from '../svgs/check-double-line.svg'
import HandCoin from '../svgs/hand-coin-fill.svg' import HandCoin from '../svgs/hand-coin-fill.svg'
import { COMMENT_DEPTH_LIMIT } from '../lib/constants'
// TODO: oh man, this is a mess ... each notification type should just be a component ... // TODO: oh man, this is a mess ... each notification type should just be a component ...
function Notification ({ n }) { function Notification ({ n }) {
@ -31,10 +32,17 @@ function Notification ({ n }) {
} else if (n.__typename === 'Invitification') { } else if (n.__typename === 'Invitification') {
router.push('/invites') router.push('/invites')
} else if (!n.item.title) { } else if (!n.item.title) {
router.push({ if (n.item.path.split('.').length > COMMENT_DEPTH_LIMIT + 1) {
pathname: '/items/[id]', router.push({
query: { id: n.item.root.id, commentId: n.item.id } pathname: '/items/[id]',
}, `/items/${n.item.root.id}`) query: { id: n.item.parentId, commentId: n.item.id }
}, `/items/${n.item.parentId}`)
} else {
router.push({
pathname: '/items/[id]',
query: { id: n.item.root.id, commentId: n.item.id }
}, `/items/${n.item.root.id}`)
}
} else { } else {
router.push({ router.push({
pathname: '/items/[id]', pathname: '/items/[id]',

View File

@ -8,11 +8,20 @@ import ActionTooltip from './action-tooltip'
import TextareaAutosize from 'react-textarea-autosize' import TextareaAutosize from 'react-textarea-autosize'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import Info from './info' import Info from './info'
import Link from 'next/link'
export const CommentSchema = Yup.object({ export const CommentSchema = Yup.object({
text: Yup.string().required('required').trim() text: Yup.string().required('required').trim()
}) })
export function ReplyOnAnotherPage ({ parentId }) {
return (
<Link href={`/items/${parentId}`}>
<a className={`${styles.replyButtons} text-muted`}>reply on another page</a>
</Link>
)
}
export default function Reply ({ parentId, meComments, onSuccess, replyOpen }) { export default function Reply ({ parentId, meComments, onSuccess, replyOpen }) {
const [reply, setReply] = useState(replyOpen) const [reply, setReply] = useState(replyOpen)
const me = useMe() const me = useMe()

View File

@ -15,6 +15,7 @@ export const COMMENT_FIELDS = gql`
boost boost
meSats meSats
meComments meComments
path
mine mine
ncomments ncomments
root { root {

View File

@ -19,6 +19,7 @@ export const ITEM_FIELDS = gql`
sats sats
upvotes upvotes
boost boost
path
meSats meSats
ncomments ncomments
maxBid maxBid

View File

@ -9,3 +9,4 @@ export const UPLOAD_TYPES_ALLOW = [
'image/jpeg', 'image/jpeg',
'image/webp' 'image/webp'
] ]
export const COMMENT_DEPTH_LIMIT = 10