feat: add pinned post functionality
This commit is contained in:
parent
9c554da2da
commit
d131026af9
31 changed files with 563 additions and 56 deletions
|
|
@ -1,10 +1,12 @@
|
|||
import { Separator } from '@/components/ui/separator'
|
||||
import { toNote } from '@/lib/link'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { useSecondaryPage } from '@/PageManager'
|
||||
import { Event } from 'nostr-tools'
|
||||
import Collapsible from '../Collapsible'
|
||||
import Note from '../Note'
|
||||
import NoteStats from '../NoteStats'
|
||||
import PinnedButton from './PinnedButton'
|
||||
import RepostDescription from './RepostDescription'
|
||||
|
||||
export default function MainNoteCard({
|
||||
|
|
@ -12,13 +14,15 @@ export default function MainNoteCard({
|
|||
className,
|
||||
reposter,
|
||||
embedded,
|
||||
originalNoteId
|
||||
originalNoteId,
|
||||
pinned = false
|
||||
}: {
|
||||
event: Event
|
||||
className?: string
|
||||
reposter?: string
|
||||
embedded?: boolean
|
||||
originalNoteId?: string
|
||||
pinned?: boolean
|
||||
}) {
|
||||
const { push } = useSecondaryPage()
|
||||
|
||||
|
|
@ -30,8 +34,9 @@ export default function MainNoteCard({
|
|||
push(toNote(originalNoteId ?? event))
|
||||
}}
|
||||
>
|
||||
<div className={`clickable ${embedded ? 'p-2 sm:p-3 border rounded-lg' : 'py-3'}`}>
|
||||
<div className={cn('clickable', embedded ? 'p-2 sm:p-3 border rounded-lg' : 'py-3')}>
|
||||
<Collapsible alwaysExpand={embedded}>
|
||||
{pinned && <PinnedButton event={event} />}
|
||||
<RepostDescription className={embedded ? '' : 'px-4'} reposter={reposter} />
|
||||
<Note
|
||||
className={embedded ? '' : 'px-4'}
|
||||
|
|
|
|||
46
src/components/NoteCard/PinnedButton.tsx
Normal file
46
src/components/NoteCard/PinnedButton.tsx
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import { Button } from '@/components/ui/button'
|
||||
import { useNostr } from '@/providers/NostrProvider'
|
||||
import { usePinList } from '@/providers/PinListProvider'
|
||||
import { Loader, Pin } from 'lucide-react'
|
||||
import { NostrEvent } from 'nostr-tools'
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
export default function PinnedButton({ event }: { event: NostrEvent }) {
|
||||
const { t } = useTranslation()
|
||||
const { pubkey } = useNostr()
|
||||
const { unpin } = usePinList()
|
||||
const [hovered, setHovered] = useState(false)
|
||||
const [unpinning, setUnpinning] = useState(false)
|
||||
|
||||
if (event.pubkey !== pubkey) {
|
||||
return (
|
||||
<div className="flex gap-1 text-sm items-center text-primary mb-1 px-4 py-0 h-fit">
|
||||
<Pin size={16} className="shrink-0" />
|
||||
{t('Pinned')}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<Button
|
||||
className="flex gap-1 text-sm text-muted-foreground items-center mb-1 px-4 py-0.5 h-fit hover:text-foreground"
|
||||
variant="link"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
setUnpinning(true)
|
||||
unpin(event).finally(() => setUnpinning(false))
|
||||
}}
|
||||
disabled={unpinning}
|
||||
onMouseEnter={() => setHovered(true)}
|
||||
onMouseLeave={() => setHovered(false)}
|
||||
>
|
||||
{unpinning ? (
|
||||
<Loader size={16} className="animate-spin shrink-0" />
|
||||
) : (
|
||||
<Pin size={16} className="shrink-0" />
|
||||
)}
|
||||
{unpinning ? t('Unpinning') : hovered ? t('Unpin') : t('Pinned')}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
|
@ -10,11 +10,13 @@ import MainNoteCard from './MainNoteCard'
|
|||
export default function RepostNoteCard({
|
||||
event,
|
||||
className,
|
||||
filterMutedNotes = true
|
||||
filterMutedNotes = true,
|
||||
pinned = false
|
||||
}: {
|
||||
event: Event
|
||||
className?: string
|
||||
filterMutedNotes?: boolean
|
||||
pinned?: boolean
|
||||
}) {
|
||||
const { mutePubkeySet } = useMuteList()
|
||||
const { hideContentMentioningMutedUsers } = useContentPolicy()
|
||||
|
|
@ -71,5 +73,12 @@ export default function RepostNoteCard({
|
|||
|
||||
if (!targetEvent || shouldHide) return null
|
||||
|
||||
return <MainNoteCard className={className} reposter={event.pubkey} event={targetEvent} />
|
||||
return (
|
||||
<MainNoteCard
|
||||
className={className}
|
||||
reposter={event.pubkey}
|
||||
event={targetEvent}
|
||||
pinned={pinned}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,11 +10,13 @@ import RepostNoteCard from './RepostNoteCard'
|
|||
export default function NoteCard({
|
||||
event,
|
||||
className,
|
||||
filterMutedNotes = true
|
||||
filterMutedNotes = true,
|
||||
pinned = false
|
||||
}: {
|
||||
event: Event
|
||||
className?: string
|
||||
filterMutedNotes?: boolean
|
||||
pinned?: boolean
|
||||
}) {
|
||||
const { mutePubkeySet } = useMuteList()
|
||||
const { hideContentMentioningMutedUsers } = useContentPolicy()
|
||||
|
|
@ -31,10 +33,15 @@ export default function NoteCard({
|
|||
|
||||
if (event.kind === kinds.Repost) {
|
||||
return (
|
||||
<RepostNoteCard event={event} className={className} filterMutedNotes={filterMutedNotes} />
|
||||
<RepostNoteCard
|
||||
event={event}
|
||||
className={className}
|
||||
filterMutedNotes={filterMutedNotes}
|
||||
pinned={pinned}
|
||||
/>
|
||||
)
|
||||
}
|
||||
return <MainNoteCard event={event} className={className} />
|
||||
return <MainNoteCard event={event} className={className} pinned={pinned} />
|
||||
}
|
||||
|
||||
export function NoteCardLoadingSkeleton() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue