refactor replies and full items
This commit is contained in:
parent
e7787e3e67
commit
02c44dca63
|
@ -3,7 +3,6 @@ import * as Yup from 'yup'
|
|||
import { gql, useMutation } from '@apollo/client'
|
||||
import styles from './reply.module.css'
|
||||
import TextareaAutosize from 'react-textarea-autosize'
|
||||
import Countdown from '../components/countdown'
|
||||
|
||||
export const CommentSchema = Yup.object({
|
||||
text: Yup.string().required('required').trim()
|
||||
|
@ -53,19 +52,8 @@ export default function CommentEdit ({ comment, editThreshold, onSuccess, onCanc
|
|||
minRows={4}
|
||||
autoFocus
|
||||
required
|
||||
groupClassName='mb-0'
|
||||
hint={<Countdown date={editThreshold} />}
|
||||
/>
|
||||
<div className='d-flex align-items-center justify-content-between'>
|
||||
<SubmitButton variant='secondary' className='mt-1'>save</SubmitButton>
|
||||
<div
|
||||
className='font-weight-bold text-muted mr-3'
|
||||
style={{ fontSize: '80%', cursor: 'pointer' }}
|
||||
onClick={onCancel}
|
||||
>
|
||||
cancel
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -41,9 +41,8 @@ function Parent ({ item, rootText }) {
|
|||
|
||||
export default function Comment ({
|
||||
item, children, replyOpen, includeParent,
|
||||
rootText, noComments, noReply
|
||||
rootText, noComments
|
||||
}) {
|
||||
const [reply, setReply] = useState(replyOpen)
|
||||
const [edit, setEdit] = useState()
|
||||
const [collapse, setCollapse] = useState(false)
|
||||
const ref = useRef(null)
|
||||
|
@ -92,28 +91,36 @@ export default function Comment ({
|
|||
<span> </span>
|
||||
<span>{timeSince(new Date(item.createdAt))}</span>
|
||||
{includeParent && <Parent item={item} rootText={rootText} />}
|
||||
{canEdit &&
|
||||
<>
|
||||
<span> \ </span>
|
||||
<div
|
||||
className={styles.edit}
|
||||
onClick={() => setEdit(!edit)}
|
||||
>
|
||||
{edit ? 'cancel' : 'edit'}
|
||||
<Countdown
|
||||
date={editThreshold}
|
||||
onComplete={() => {
|
||||
setCanEdit(false)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</>}
|
||||
</div>
|
||||
{!includeParent && (collapse
|
||||
? <Eye className={styles.collapser} height={10} width={10} onClick={() => setCollapse(false)} />
|
||||
: <EyeClose className={styles.collapser} height={10} width={10} onClick={() => setCollapse(true)} />)}
|
||||
|
||||
</div>
|
||||
{edit
|
||||
? (
|
||||
<div className={styles.replyWrapper}>
|
||||
<CommentEdit
|
||||
comment={item}
|
||||
onSuccess={() => {
|
||||
setEdit(!edit)
|
||||
setCanEdit(mine && (Date.now() < editThreshold))
|
||||
}}
|
||||
onCancel={() => {
|
||||
setEdit(!edit)
|
||||
setCanEdit(mine && (Date.now() < editThreshold))
|
||||
}}
|
||||
editThreshold={editThreshold}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
: (
|
||||
<div className={styles.text}>
|
||||
|
@ -123,40 +130,9 @@ export default function Comment ({
|
|||
</div>
|
||||
</div>
|
||||
<div className={`${styles.children}`}>
|
||||
{!noReply && !edit && (
|
||||
<div className={`${itemStyles.other} ${styles.reply}`}>
|
||||
<div
|
||||
className='d-inline-block'
|
||||
onClick={() => setReply(!reply)}
|
||||
>
|
||||
{reply ? 'cancel' : 'reply'}
|
||||
</div>
|
||||
{canEdit && !reply && !edit &&
|
||||
<>
|
||||
<span> \ </span>
|
||||
<div
|
||||
className='d-inline-block'
|
||||
onClick={() => setEdit(!edit)}
|
||||
>
|
||||
edit
|
||||
<Countdown
|
||||
date={editThreshold}
|
||||
className=' '
|
||||
onComplete={() => {
|
||||
setCanEdit(false)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</>}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className={reply ? styles.replyWrapper : 'd-none'}>
|
||||
<Reply
|
||||
parentId={item.id} autoFocus={!replyOpen}
|
||||
onSuccess={() => setReply(replyOpen || false)}
|
||||
parentId={item.id} replyOpen={replyOpen}
|
||||
/>
|
||||
</div>
|
||||
{children}
|
||||
<div className={`${styles.comments} ml-sm-1 ml-md-3`}>
|
||||
{item.comments && !noComments
|
||||
|
|
|
@ -11,6 +11,11 @@
|
|||
padding-right: 15px;
|
||||
}
|
||||
|
||||
.edit {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.collapsed .hunk {
|
||||
margin-bottom: .5rem;
|
||||
}
|
||||
|
@ -33,20 +38,8 @@
|
|||
user-select: none;
|
||||
}
|
||||
|
||||
.reply {
|
||||
font-weight: bold;
|
||||
cursor: pointer;
|
||||
padding-bottom: .5rem;
|
||||
}
|
||||
|
||||
.replyWrapper {
|
||||
padding-right: 15px;
|
||||
padding-bottom: .5rem;
|
||||
}
|
||||
|
||||
.children {
|
||||
margin-top: 0;
|
||||
padding-top: .25rem;
|
||||
margin-left: 24px;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import Countdown from 'react-countdown'
|
|||
|
||||
export default function SimpleCountdown ({ className, onComplete, date }) {
|
||||
return (
|
||||
<span className={className || 'text-muted font-weight-bold'}>
|
||||
<span className={className}>
|
||||
<Countdown
|
||||
date={date}
|
||||
renderer={props => <span> {props.formatted.minutes}:{props.formatted.seconds}</span>}
|
||||
|
|
|
@ -10,7 +10,33 @@ import styles from '../styles/item.module.css'
|
|||
import { NOFOLLOW_LIMIT } from '../lib/constants'
|
||||
import { useRouter } from 'next/router'
|
||||
|
||||
export default function ItemFull ({ item: qItem, minimal }) {
|
||||
function BioItem ({ item }) {
|
||||
if (!item.text) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<ItemText item={item} />
|
||||
<Reply parentId={item.id} />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function TopLevelItem ({ item }) {
|
||||
return (
|
||||
<Item item={item}>
|
||||
{item.text && <ItemText item={item} />}
|
||||
<Reply parentId={item.id} replyOpen />
|
||||
</Item>
|
||||
)
|
||||
}
|
||||
|
||||
function ItemText ({ item }) {
|
||||
return <Text nofollow={item.sats + item.boost < NOFOLLOW_LIMIT}>{item.text}</Text>
|
||||
}
|
||||
|
||||
export default function ItemFull ({ item: qItem, bio }) {
|
||||
const query = gql`
|
||||
${ITEM_FIELDS}
|
||||
${COMMENTS}
|
||||
|
@ -49,24 +75,9 @@ export default function ItemFull ({ item: qItem, minimal }) {
|
|||
<>
|
||||
{item.parentId
|
||||
? <Comment item={item} replyOpen includeParent noComments />
|
||||
: (minimal
|
||||
? (
|
||||
<>
|
||||
{item.text &&
|
||||
<div className='mb-3'>
|
||||
<Text nofollow={item.sats + item.boost < NOFOLLOW_LIMIT}>{item.text}</Text>
|
||||
</div>}
|
||||
</>)
|
||||
: (
|
||||
<>
|
||||
<Item item={item}>
|
||||
{item.text &&
|
||||
<div className='mb-3'>
|
||||
<Text nofollow={item.sats + item.boost < NOFOLLOW_LIMIT}>{item.text}</Text>
|
||||
</div>}
|
||||
<Reply parentId={item.id} />
|
||||
</Item>
|
||||
</>)
|
||||
: (bio
|
||||
? <BioItem item={item} />
|
||||
: <TopLevelItem item={item} />
|
||||
)}
|
||||
<div className={styles.comments}>
|
||||
<Comments comments={item.comments} />
|
||||
|
|
|
@ -6,12 +6,14 @@ import { COMMENTS } from '../fragments/comments'
|
|||
import { useMe } from './me'
|
||||
import ActionTooltip from './action-tooltip'
|
||||
import TextareaAutosize from 'react-textarea-autosize'
|
||||
import { useState } from 'react'
|
||||
|
||||
export const CommentSchema = Yup.object({
|
||||
text: Yup.string().required('required').trim()
|
||||
})
|
||||
|
||||
export default function Reply ({ parentId, onSuccess, autoFocus }) {
|
||||
export default function Reply ({ parentId, onSuccess, replyOpen }) {
|
||||
const [reply, setReply] = useState(replyOpen)
|
||||
const me = useMe()
|
||||
|
||||
const [createComment] = useMutation(
|
||||
|
@ -47,7 +49,14 @@ export default function Reply ({ parentId, onSuccess, autoFocus }) {
|
|||
)
|
||||
|
||||
return (
|
||||
<div className={`${styles.reply} mb-1`}>
|
||||
<div>
|
||||
<div
|
||||
className={styles.replyButtons}
|
||||
onClick={() => setReply(!reply)}
|
||||
>
|
||||
{reply ? 'cancel' : 'reply'}
|
||||
</div>
|
||||
<div className={reply ? `${styles.reply}` : 'd-none'}>
|
||||
<Form
|
||||
initial={{
|
||||
text: ''
|
||||
|
@ -59,16 +68,14 @@ export default function Reply ({ parentId, onSuccess, autoFocus }) {
|
|||
throw new Error({ message: error.toString() })
|
||||
}
|
||||
resetForm({ text: '' })
|
||||
if (onSuccess) {
|
||||
onSuccess()
|
||||
}
|
||||
setReply(replyOpen || false)
|
||||
}}
|
||||
>
|
||||
<MarkdownInput
|
||||
name='text'
|
||||
as={TextareaAutosize}
|
||||
minRows={4}
|
||||
autoFocus={autoFocus}
|
||||
autoFocus={!replyOpen}
|
||||
required
|
||||
hint={me?.freeComments ? <span className='text-success'>{me.freeComments} free comments left</span> : null}
|
||||
/>
|
||||
|
@ -77,6 +84,7 @@ export default function Reply ({ parentId, onSuccess, autoFocus }) {
|
|||
</ActionTooltip>
|
||||
</Form>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
.reply {
|
||||
max-width: 600px;
|
||||
padding-right: 15px;
|
||||
padding-bottom: .5rem;
|
||||
}
|
||||
|
||||
.replyButtons {
|
||||
font-size: 70%;
|
||||
color: grey;
|
||||
font-weight: bold;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
padding-bottom: .5rem;
|
||||
}
|
||||
|
||||
.skeleton .input {
|
||||
|
|
|
@ -85,12 +85,14 @@ export default function User ({ user }) {
|
|||
const [create, setCreate] = useState(false)
|
||||
const [session] = useSession()
|
||||
|
||||
// need to check if this is the user's page
|
||||
|
||||
return (
|
||||
<Layout noSeo containClassName={styles.contain}>
|
||||
<Seo user={user} />
|
||||
<UserHeader user={user} />
|
||||
{user.bio
|
||||
? <ItemFull item={user.bio} minimal />
|
||||
? <ItemFull item={user.bio} bio />
|
||||
: (
|
||||
<div className={styles.create}>
|
||||
{create
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
.comments {
|
||||
margin-top: 3rem;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 600px) {
|
||||
.comments {
|
||||
margin-top: 3rem;
|
||||
margin-top: 1rem;
|
||||
margin-left: -15px;
|
||||
margin-right: -15px;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue