feat: add more buttons to reply
This commit is contained in:
@@ -11,11 +11,9 @@ import { formatCount } from './utils'
|
|||||||
|
|
||||||
export default function LikeButton({
|
export default function LikeButton({
|
||||||
event,
|
event,
|
||||||
variant = 'normal',
|
|
||||||
canFetch = false
|
canFetch = false
|
||||||
}: {
|
}: {
|
||||||
event: Event
|
event: Event
|
||||||
variant?: 'normal' | 'reply'
|
|
||||||
canFetch?: boolean
|
canFetch?: boolean
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
@@ -70,8 +68,7 @@ export default function LikeButton({
|
|||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex items-center enabled:hover:text-red-400',
|
'flex items-center enabled:hover:text-red-400 gap-1',
|
||||||
variant === 'normal' ? 'gap-1' : 'flex-col',
|
|
||||||
hasLiked ? 'text-red-400' : 'text-muted-foreground'
|
hasLiked ? 'text-red-400' : 'text-muted-foreground'
|
||||||
)}
|
)}
|
||||||
onClick={like}
|
onClick={like}
|
||||||
|
|||||||
@@ -7,11 +7,20 @@ import { useTranslation } from 'react-i18next'
|
|||||||
import PostEditor from '../PostEditor'
|
import PostEditor from '../PostEditor'
|
||||||
import { formatCount } from './utils'
|
import { formatCount } from './utils'
|
||||||
|
|
||||||
export default function ReplyButton({ event }: { event: Event }) {
|
export default function ReplyButton({
|
||||||
|
event,
|
||||||
|
variant = 'note'
|
||||||
|
}: {
|
||||||
|
event: Event
|
||||||
|
variant?: 'note' | 'reply'
|
||||||
|
}) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const { checkLogin } = useNostr()
|
const { checkLogin } = useNostr()
|
||||||
const { noteStatsMap } = useNoteStats()
|
const { noteStatsMap } = useNoteStats()
|
||||||
const { replyCount } = useMemo(() => noteStatsMap.get(event.id) ?? {}, [noteStatsMap, event.id])
|
const { replyCount } = useMemo(
|
||||||
|
() => (variant === 'reply' ? {} : (noteStatsMap.get(event.id) ?? {})),
|
||||||
|
[noteStatsMap, event.id, variant]
|
||||||
|
)
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(false)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -27,7 +36,9 @@ export default function ReplyButton({ event }: { event: Event }) {
|
|||||||
title={t('Reply')}
|
title={t('Reply')}
|
||||||
>
|
>
|
||||||
<MessageCircle size={16} />
|
<MessageCircle size={16} />
|
||||||
{!!replyCount && <div className="text-sm">{formatCount(replyCount)}</div>}
|
{variant !== 'reply' && !!replyCount && (
|
||||||
|
<div className="text-sm">{formatCount(replyCount)}</div>
|
||||||
|
)}
|
||||||
</button>
|
</button>
|
||||||
<PostEditor parentEvent={event} open={open} setOpen={setOpen} />
|
<PostEditor parentEvent={event} open={open} setOpen={setOpen} />
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -8,16 +8,18 @@ import RepostButton from './RepostButton'
|
|||||||
export default function NoteStats({
|
export default function NoteStats({
|
||||||
event,
|
event,
|
||||||
className,
|
className,
|
||||||
fetchIfNotExisting = false
|
fetchIfNotExisting = false,
|
||||||
|
variant = 'note'
|
||||||
}: {
|
}: {
|
||||||
event: Event
|
event: Event
|
||||||
className?: string
|
className?: string
|
||||||
fetchIfNotExisting?: boolean
|
fetchIfNotExisting?: boolean
|
||||||
|
variant?: 'note' | 'reply'
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div className={cn('flex justify-between', className)}>
|
<div className={cn('flex justify-between', className)}>
|
||||||
<div className="flex gap-4 h-4 items-center" onClick={(e) => e.stopPropagation()}>
|
<div className="flex gap-5 h-4 items-center" onClick={(e) => e.stopPropagation()}>
|
||||||
<ReplyButton event={event} />
|
<ReplyButton event={event} variant={variant} />
|
||||||
<RepostButton event={event} canFetch={fetchIfNotExisting} />
|
<RepostButton event={event} canFetch={fetchIfNotExisting} />
|
||||||
<LikeButton event={event} canFetch={fetchIfNotExisting} />
|
<LikeButton event={event} canFetch={fetchIfNotExisting} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,14 +1,8 @@
|
|||||||
import { useSecondaryPage } from '@/PageManager'
|
|
||||||
import { toNote } from '@/lib/link'
|
|
||||||
import { useNostr } from '@/providers/NostrProvider'
|
|
||||||
import { Event } from 'nostr-tools'
|
import { Event } from 'nostr-tools'
|
||||||
import { useState } from 'react'
|
|
||||||
import { useTranslation } from 'react-i18next'
|
|
||||||
import Content from '../Content'
|
import Content from '../Content'
|
||||||
import { FormattedTimestamp } from '../FormattedTimestamp'
|
import { FormattedTimestamp } from '../FormattedTimestamp'
|
||||||
import LikeButton from '../NoteStats/LikeButton'
|
import NoteStats from '../NoteStats'
|
||||||
import ParentNotePreview from '../ParentNotePreview'
|
import ParentNotePreview from '../ParentNotePreview'
|
||||||
import PostEditor from '../PostEditor'
|
|
||||||
import UserAvatar from '../UserAvatar'
|
import UserAvatar from '../UserAvatar'
|
||||||
import Username from '../Username'
|
import Username from '../Username'
|
||||||
|
|
||||||
@@ -23,25 +17,25 @@ export default function ReplyNote({
|
|||||||
onClickParent?: (eventId: string) => void
|
onClickParent?: (eventId: string) => void
|
||||||
highlight?: boolean
|
highlight?: boolean
|
||||||
}) {
|
}) {
|
||||||
const { t } = useTranslation()
|
|
||||||
const { checkLogin } = useNostr()
|
|
||||||
const { push } = useSecondaryPage()
|
|
||||||
const [isPostDialogOpen, setIsPostDialogOpen] = useState(false)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={`flex space-x-2 items-start rounded-lg p-2 transition-colors duration-500 clickable ${highlight ? 'bg-highlight/50' : ''}`}
|
className={`flex space-x-2 items-start rounded-lg p-2 transition-colors duration-500 ${highlight ? 'bg-highlight/50' : ''}`}
|
||||||
onClick={() => push(toNote(event.id))}
|
|
||||||
>
|
>
|
||||||
<UserAvatar userId={event.pubkey} size="small" className="shrink-0" />
|
<UserAvatar userId={event.pubkey} size="small" className="shrink-0" />
|
||||||
<div className="w-full overflow-hidden space-y-1">
|
<div className="w-full overflow-hidden">
|
||||||
|
<div className="flex gap-2 items-center">
|
||||||
<Username
|
<Username
|
||||||
userId={event.pubkey}
|
userId={event.pubkey}
|
||||||
className="text-sm font-semibold text-muted-foreground hover:text-foreground truncate"
|
className="text-sm font-semibold text-muted-foreground hover:text-foreground truncate"
|
||||||
skeletonClassName="h-3"
|
skeletonClassName="h-3"
|
||||||
/>
|
/>
|
||||||
|
<div className="text-xs text-muted-foreground">
|
||||||
|
<FormattedTimestamp timestamp={event.created_at} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{parentEvent && (
|
{parentEvent && (
|
||||||
<ParentNotePreview
|
<ParentNotePreview
|
||||||
|
className="mt-1"
|
||||||
event={parentEvent}
|
event={parentEvent}
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
@@ -49,24 +43,9 @@ export default function ReplyNote({
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<Content event={event} size="small" />
|
<Content className="mt-1" event={event} size="small" />
|
||||||
<div className="flex gap-2 text-xs">
|
<NoteStats className="mt-2" event={event} variant="reply" />
|
||||||
<div className="text-muted-foreground/60">
|
|
||||||
<FormattedTimestamp timestamp={event.created_at} />
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
|
||||||
className="text-muted-foreground hover:text-primary cursor-pointer"
|
|
||||||
onClick={(e) => {
|
|
||||||
e.stopPropagation()
|
|
||||||
checkLogin(() => setIsPostDialogOpen(true))
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('reply')}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<LikeButton event={event} variant="reply" />
|
|
||||||
<PostEditor parentEvent={event} open={isPostDialogOpen} setOpen={setIsPostDialogOpen} />
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user