Nested comments
This commit is contained in:
parent
2f252da9db
commit
1ddfc8e9a5
|
@ -1,4 +1,5 @@
|
|||
import styles from './Comment.module.scss'
|
||||
import type { JSX } from 'solid-js/jsx-runtime'
|
||||
import { Icon } from '../_shared/Icon'
|
||||
import { AuthorCard } from '../Author/Card'
|
||||
import { Show, createMemo, createSignal } from 'solid-js'
|
||||
|
@ -12,13 +13,13 @@ import { formatDate } from '../../utils'
|
|||
import { SharePopup } from './SharePopup'
|
||||
import stylesHeader from '../Nav/Header.module.scss'
|
||||
import Userpic from '../Author/Userpic'
|
||||
import CommentWrapper from './CommentWrapper'
|
||||
|
||||
export default (props: {
|
||||
level?: number
|
||||
comment: Partial<Point>
|
||||
canEdit?: boolean
|
||||
compact?: boolean
|
||||
children?: JSX.Element[]
|
||||
}) => {
|
||||
const [isReplyVisible, setIsReplyVisible] = createSignal(false)
|
||||
|
||||
|
@ -35,116 +36,117 @@ export default (props: {
|
|||
)
|
||||
|
||||
return (
|
||||
<CommentWrapper level={props.level}>
|
||||
<li class={clsx(styles.comment, { [styles[`commentLevel${props.level}`]]: Boolean(props.level) })}>
|
||||
<Show when={!!body()}>
|
||||
<div class={styles.commentContent}>
|
||||
<Show
|
||||
when={!props.compact}
|
||||
fallback={
|
||||
<div>
|
||||
<Userpic user={comment().createdBy as Author} isBig={false} isAuthorsList={false} />
|
||||
<small class={styles.commentArticle}>
|
||||
<a href={`#comment-${comment()?.id}`}>{comment()?.shout.title || ''}</a>
|
||||
</small>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div class={styles.commentDetails}>
|
||||
<div class={styles.commentAuthor}>
|
||||
<AuthorCard
|
||||
author={comment()?.createdBy as Author}
|
||||
hideDescription={true}
|
||||
hideFollow={true}
|
||||
isComments={true}
|
||||
hasLink={true}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class={styles.commentDate}>{formattedDate()}</div>
|
||||
<div
|
||||
class={styles.commentRating}
|
||||
classList={{
|
||||
[styles.commentRatingPositive]: comment().stat?.rating > 0,
|
||||
[styles.commentRatingNegative]: comment().stat?.rating < 0
|
||||
}}
|
||||
>
|
||||
<button class={clsx(styles.commentRatingControl, styles.commentRatingControlUp)} />
|
||||
<div class={styles.commentRatingValue}>{comment().stat?.rating || 0}</div>
|
||||
<button class={clsx(styles.commentRatingControl, styles.commentRatingControlDown)} />
|
||||
</div>
|
||||
<li class={clsx(styles.comment, { [styles[`commentLevel${props.level}`]]: Boolean(props.level) })}>
|
||||
<Show when={!!body()}>
|
||||
<div class={styles.commentContent}>
|
||||
<Show
|
||||
when={!props.compact}
|
||||
fallback={
|
||||
<div>
|
||||
<Userpic user={comment().createdBy as Author} isBig={false} isAuthorsList={false} />
|
||||
<small class={styles.commentArticle}>
|
||||
<a href={`#comment-${comment()?.id}`}>{comment()?.shout.title || ''}</a>
|
||||
</small>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<div class={styles.commentDetails}>
|
||||
<div class={styles.commentAuthor}>
|
||||
<AuthorCard
|
||||
author={comment()?.createdBy as Author}
|
||||
hideDescription={true}
|
||||
hideFollow={true}
|
||||
isComments={true}
|
||||
hasLink={true}
|
||||
/>
|
||||
</div>
|
||||
</Show>
|
||||
|
||||
<div
|
||||
class={styles.commentBody}
|
||||
contenteditable={props.canEdit}
|
||||
id={'comment-' + (comment().id || '')}
|
||||
>
|
||||
<MD body={body()} />
|
||||
<div class={styles.commentDate}>{formattedDate()}</div>
|
||||
<div
|
||||
class={styles.commentRating}
|
||||
classList={{
|
||||
[styles.commentRatingPositive]: comment().stat?.rating > 0,
|
||||
[styles.commentRatingNegative]: comment().stat?.rating < 0
|
||||
}}
|
||||
>
|
||||
<button class={clsx(styles.commentRatingControl, styles.commentRatingControlUp)} />
|
||||
<div class={styles.commentRatingValue}>{comment().stat?.rating || 0}</div>
|
||||
<button class={clsx(styles.commentRatingControl, styles.commentRatingControlDown)} />
|
||||
</div>
|
||||
</div>
|
||||
</Show>
|
||||
|
||||
<div
|
||||
class={styles.commentBody}
|
||||
contenteditable={props.canEdit}
|
||||
id={'comment-' + (comment().id || '')}
|
||||
>
|
||||
<MD body={body()} />
|
||||
</div>
|
||||
|
||||
<Show when={!props.compact}>
|
||||
<div class={styles.commentControls}>
|
||||
<button
|
||||
class={clsx(styles.commentControl, styles.commentControlReply)}
|
||||
onClick={() => setIsReplyVisible(!isReplyVisible())}
|
||||
>
|
||||
<Icon name="reply" class={styles.icon} />
|
||||
{t('Reply')}
|
||||
</button>
|
||||
|
||||
<Show when={props.canEdit}>
|
||||
{/*FIXME implement edit comment modal*/}
|
||||
{/*<button*/}
|
||||
{/* class={clsx(styles.commentControl, styles.commentControlEdit)}*/}
|
||||
{/* onClick={() => showModal('editComment')}*/}
|
||||
{/*>*/}
|
||||
{/* <Icon name="edit" class={styles.icon} />*/}
|
||||
{/* {t('Edit')}*/}
|
||||
{/*</button>*/}
|
||||
<button
|
||||
class={clsx(styles.commentControl, styles.commentControlDelete)}
|
||||
onClick={() => remove()}
|
||||
>
|
||||
<Icon name="delete" class={styles.icon} />
|
||||
{t('Delete')}
|
||||
</button>
|
||||
</Show>
|
||||
|
||||
<SharePopup
|
||||
containerCssClass={stylesHeader.control}
|
||||
trigger={
|
||||
<button class={clsx(styles.commentControl, styles.commentControlShare)}>
|
||||
<Icon name="share" class={styles.icon} />
|
||||
{t('Share')}
|
||||
</button>
|
||||
}
|
||||
/>
|
||||
|
||||
{/*<button*/}
|
||||
{/* class={clsx(styles.commentControl, styles.commentControlComplain)}*/}
|
||||
{/* onClick={() => showModal('reportComment')}*/}
|
||||
{/*>*/}
|
||||
{/* {t('Report')}*/}
|
||||
{/*</button>*/}
|
||||
</div>
|
||||
|
||||
<Show when={!props.compact}>
|
||||
<div class={styles.commentControls}>
|
||||
<button
|
||||
class={clsx(styles.commentControl, styles.commentControlReply)}
|
||||
onClick={() => setIsReplyVisible(!isReplyVisible())}
|
||||
>
|
||||
<Icon name="reply" class={styles.icon} />
|
||||
{t('Reply')}
|
||||
</button>
|
||||
|
||||
<Show when={props.canEdit}>
|
||||
{/*FIXME implement edit comment modal*/}
|
||||
{/*<button*/}
|
||||
{/* class={clsx(styles.commentControl, styles.commentControlEdit)}*/}
|
||||
{/* onClick={() => showModal('editComment')}*/}
|
||||
{/*>*/}
|
||||
{/* <Icon name="edit" class={styles.icon} />*/}
|
||||
{/* {t('Edit')}*/}
|
||||
{/*</button>*/}
|
||||
<button
|
||||
class={clsx(styles.commentControl, styles.commentControlDelete)}
|
||||
onClick={() => remove()}
|
||||
>
|
||||
<Icon name="delete" class={styles.icon} />
|
||||
{t('Delete')}
|
||||
<Show when={isReplyVisible()}>
|
||||
<form class={styles.replyForm}>
|
||||
<textarea name="reply" id="reply" rows="5" />
|
||||
<div class={styles.replyFormControls}>
|
||||
<button class="button button--light" onClick={() => setIsReplyVisible(false)}>
|
||||
{t('Cancel')}
|
||||
</button>
|
||||
</Show>
|
||||
|
||||
<SharePopup
|
||||
containerCssClass={stylesHeader.control}
|
||||
trigger={
|
||||
<button class={clsx(styles.commentControl, styles.commentControlShare)}>
|
||||
<Icon name="share" class={styles.icon} />
|
||||
{t('Share')}
|
||||
</button>
|
||||
}
|
||||
/>
|
||||
|
||||
{/*<button*/}
|
||||
{/* class={clsx(styles.commentControl, styles.commentControlComplain)}*/}
|
||||
{/* onClick={() => showModal('reportComment')}*/}
|
||||
{/*>*/}
|
||||
{/* {t('Report')}*/}
|
||||
{/*</button>*/}
|
||||
</div>
|
||||
|
||||
<Show when={isReplyVisible()}>
|
||||
<form class={styles.replyForm}>
|
||||
<textarea name="reply" id="reply" rows="5" />
|
||||
<div class={styles.replyFormControls}>
|
||||
<button class="button button--light" onClick={() => setIsReplyVisible(false)}>
|
||||
{t('Cancel')}
|
||||
</button>
|
||||
<button class="button">{t('Send')}</button>
|
||||
</div>
|
||||
</form>
|
||||
</Show>
|
||||
<button class="button">{t('Send')}</button>
|
||||
</div>
|
||||
</form>
|
||||
</Show>
|
||||
</div>
|
||||
</Show>
|
||||
</li>
|
||||
</CommentWrapper>
|
||||
</Show>
|
||||
</div>
|
||||
</Show>
|
||||
<Show when={props.children}>
|
||||
<ul>{props.children}</ul>
|
||||
</Show>
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
import type { JSX } from 'solid-js/jsx-runtime'
|
||||
import { Switch, Match } from 'solid-js'
|
||||
|
||||
type Props = {
|
||||
level?: number
|
||||
children: JSX.Element
|
||||
}
|
||||
|
||||
const CommentWrapper = (props: Props) => {
|
||||
return (
|
||||
<Switch fallback={props.children}>
|
||||
<Match when={props.level === 1}>
|
||||
<ul>{props.children}</ul>
|
||||
</Match>
|
||||
<Match when={props.level === 2}>
|
||||
<ul>
|
||||
<li>
|
||||
<ul>{props.children}</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</Match>
|
||||
<Match when={props.level === 3}>
|
||||
<ul>
|
||||
<li>
|
||||
<ul>
|
||||
<li>
|
||||
<ul>{props.children}</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</Match>
|
||||
<Match when={props.level === 4}>
|
||||
<ul>
|
||||
<li>
|
||||
<ul>
|
||||
<li>
|
||||
<ul>
|
||||
<li>
|
||||
<ul>{props.children}</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</Match>
|
||||
<Match when={props.level === 5}>
|
||||
<ul>
|
||||
<li>
|
||||
<ul>
|
||||
<li>
|
||||
<ul>
|
||||
<li>
|
||||
<ul>
|
||||
<li>
|
||||
<ul>{props.children}</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</Match>
|
||||
</Switch>
|
||||
)
|
||||
}
|
||||
|
||||
export default CommentWrapper
|
|
@ -10,6 +10,10 @@ import { clsx } from 'clsx'
|
|||
import { byCreated, byStat } from '../../utils/sortby'
|
||||
import { Loading } from '../Loading'
|
||||
|
||||
type NestedReaction = {
|
||||
children: Reaction[]
|
||||
} & Reaction
|
||||
|
||||
const ARTICLE_COMMENTS_PAGE_SIZE = 50
|
||||
const MAX_COMMENT_LEVEL = 6
|
||||
|
||||
|
@ -103,16 +107,16 @@ export const CommentsTree = (props: { shoutSlug: string }) => {
|
|||
</div>
|
||||
|
||||
<ul>
|
||||
<For each={reactions().reverse()}>
|
||||
{(reaction: Reaction) => (
|
||||
<>
|
||||
{JSON.stringify(getCommentLevel(reaction))}
|
||||
<Comment
|
||||
comment={reaction}
|
||||
level={getCommentLevel(reaction)}
|
||||
canEdit={reaction.createdBy?.slug === session()?.user?.slug}
|
||||
/>
|
||||
</>
|
||||
<For each={nestComments(reactions().reverse())}>
|
||||
{(reaction: NestedReaction) => (
|
||||
<Comment
|
||||
comment={reaction}
|
||||
level={getCommentLevel(reaction)}
|
||||
canEdit={reaction?.createdBy?.slug === session()?.user?.slug}
|
||||
children={(reaction.children || []).map((r) => {
|
||||
return <Comment comment={r} />
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
</For>
|
||||
</ul>
|
||||
|
|
Loading…
Reference in New Issue
Block a user