feat: improve note details page

This commit is contained in:
codytseng
2024-11-08 18:22:41 +08:00
parent 3a3cf6d256
commit 5b0abcf380
8 changed files with 61 additions and 19 deletions

View File

@@ -1,9 +1,11 @@
import { useSecondaryPage } from '@renderer/PageManager'
import { toNote } from '@renderer/lib/link'
import { formatTimestamp } from '@renderer/lib/timestamp' import { formatTimestamp } from '@renderer/lib/timestamp'
import { Event } from 'nostr-tools' import { Event } from 'nostr-tools'
import Content from '../Content' import Content from '../Content'
import NoteStats from '../NoteStats'
import UserAvatar from '../UserAvatar' import UserAvatar from '../UserAvatar'
import Username from '../Username' import Username from '../Username'
import NoteStats from '../NoteStats'
export default function Note({ export default function Note({
event, event,
@@ -33,7 +35,7 @@ export default function Note({
</div> </div>
</div> </div>
{parentEvent && ( {parentEvent && (
<div className="text-xs text-muted-foreground truncate mt-2"> <div className="text-muted-foreground truncate mt-2">
<ParentNote event={parentEvent} /> <ParentNote event={parentEvent} />
</div> </div>
)} )}
@@ -46,8 +48,16 @@ export default function Note({
} }
function ParentNote({ event }: { event: Event }) { function ParentNote({ event }: { event: Event }) {
const { push } = useSecondaryPage()
return ( return (
<div className="flex space-x-1 items-center text-xs rounded-lg border px-1 bg-muted w-fit max-w-full"> <div
className="flex space-x-1 items-center text-xs rounded-lg px-2 bg-muted w-fit max-w-full hover:text-foreground cursor-pointer"
onClick={(e) => {
e.stopPropagation()
push(toNote(event))
}}
>
<div>reply to</div> <div>reply to</div>
<UserAvatar userId={event.pubkey} size="tiny" /> <UserAvatar userId={event.pubkey} size="tiny" />
<div className="truncate">{event.content}</div> <div className="truncate">{event.content}</div>

View File

@@ -26,7 +26,7 @@ export default function ShortTextNoteCard({
className={className} className={className}
onClick={(e) => { onClick={(e) => {
e.stopPropagation() e.stopPropagation()
push(toNote(rootEvent ?? event)) push(toNote(event))
}} }}
> >
<Card <Card

View File

@@ -0,0 +1,24 @@
import { useSecondaryPage } from '@renderer/PageManager'
import { Card } from '@renderer/components/ui/card'
import { toNote } from '@renderer/lib/link'
import { Event } from 'nostr-tools'
import UserAvatar from '../UserAvatar'
import Username from '../Username'
export default function ParentNote({ event }: { event: Event }) {
const { push } = useSecondaryPage()
return (
<div>
<Card
className="flex space-x-1 p-1 items-center hover:bg-muted/50 cursor-pointer text-xs text-muted-foreground hover:text-foreground"
onClick={() => push(toNote(event))}
>
<UserAvatar userId={event.pubkey} size="tiny" />
<Username userId={event.pubkey} className="font-semibold" />
<div className="truncate">{event.content}</div>
</Card>
<div className="ml-5 w-px h-2 bg-border" />
</div>
)
}

View File

@@ -48,7 +48,7 @@ export default function ReplyNote({
function ParentReplyNote({ event }: { event: Event }) { function ParentReplyNote({ event }: { event: Event }) {
return ( return (
<div className="flex space-x-1 items-center text-xs border rounded-lg w-fit px-1 bg-muted max-w-full"> <div className="flex space-x-1 items-center text-xs rounded-lg w-fit px-2 bg-muted max-w-full">
<div>reply to</div> <div>reply to</div>
<UserAvatar userId={event.pubkey} size="tiny" /> <UserAvatar userId={event.pubkey} size="tiny" />
<div className="truncate">{event.content}</div> <div className="truncate">{event.content}</div>

View File

@@ -56,7 +56,7 @@ export default function ReplyNoteList({ event, className }: { event: Event; clas
const onClickParent = (eventId: string) => { const onClickParent = (eventId: string) => {
const ref = replyRefs.current[eventId] const ref = replyRefs.current[eventId]
if (ref) { if (ref) {
ref.scrollIntoView({ behavior: 'smooth', block: 'center', inline: 'nearest' }) ref.scrollIntoView({ behavior: 'smooth', block: 'nearest' })
} }
setHighlightReplyId(eventId) setHighlightReplyId(eventId)
setTimeout(() => { setTimeout(() => {

View File

@@ -13,7 +13,7 @@ const UserAvatarSizeCnMap = {
large: 'w-24 h-24', large: 'w-24 h-24',
normal: 'w-10 h-10', normal: 'w-10 h-10',
small: 'w-7 h-7', small: 'w-7 h-7',
tiny: 'w-3 h-3' tiny: 'w-4 h-4'
} }
export default function UserAvatar({ export default function UserAvatar({

View File

@@ -9,15 +9,17 @@ export function isNsfwEvent(event: Event) {
} }
export function isReplyNoteEvent(event: Event) { export function isReplyNoteEvent(event: Event) {
return event.kind === kinds.ShortTextNote && event.tags.some(rootETag) return (
event.kind === kinds.ShortTextNote && event.tags.some((tag) => replyETag(tag) || rootETag(tag))
)
} }
export function getParentEventId(event: Event) { export function getParentEventId(event?: Event) {
return event.tags.find(replyETag)?.[1] return event?.tags.find(replyETag)?.[1]
} }
export function getRootEventId(event: Event) { export function getRootEventId(event?: Event) {
return event.tags.find(rootETag)?.[1] return event?.tags.find(rootETag)?.[1]
} }
export function isReplaceable(kind: number) { export function isReplaceable(kind: number) {

View File

@@ -1,19 +1,25 @@
import Note from '@renderer/components/Note' import Note from '@renderer/components/Note'
import ParentNote from '@renderer/components/ParentNote'
import ReplyNoteList from '@renderer/components/ReplyNoteList' import ReplyNoteList from '@renderer/components/ReplyNoteList'
import { Separator } from '@renderer/components/ui/separator' import { Separator } from '@renderer/components/ui/separator'
import { useFetchEventById } from '@renderer/hooks'
import SecondaryPageLayout from '@renderer/layouts/SecondaryPageLayout' import SecondaryPageLayout from '@renderer/layouts/SecondaryPageLayout'
import { getParentEventId, getRootEventId } from '@renderer/lib/event'
import { Event } from 'nostr-tools' import { Event } from 'nostr-tools'
export default function NotePage({ event }: { event?: Event }) { export default function NotePage({ event }: { event?: Event }) {
const parentEvent = useFetchEventById(getParentEventId(event))
const rootEvent = useFetchEventById(getRootEventId(event))
if (!event) return null
return ( return (
<SecondaryPageLayout titlebarContent="note"> <SecondaryPageLayout titlebarContent="note">
{event && ( {rootEvent && <ParentNote key={`root-note-${event.id}`} event={rootEvent} />}
<> {parentEvent && <ParentNote key={`parent-note-${event.id}`} event={parentEvent} />}
<Note key={`note-${event.id}`} event={event} fetchNoteStats /> <Note key={`note-${event.id}`} event={event} fetchNoteStats />
<Separator className="mt-2" /> <Separator className="my-2" />
<ReplyNoteList key={`reply-note-list-${event.id}`} event={event} /> <ReplyNoteList key={`reply-note-list-${event.id}`} event={event} />
</>
)}
</SecondaryPageLayout> </SecondaryPageLayout>
) )
} }