feat(short posts): add recent posts with image preview
All checks were successful
Release to Staging / build_and_release (push) Successful in 1m16s

This commit is contained in:
en 2025-02-25 13:56:14 +01:00
parent 840247f0b7
commit 78e679b7b0

View File

@ -1,7 +1,7 @@
import { FALLBACK_PROFILE_IMAGE } from 'constants.ts' import { FALLBACK_PROFILE_IMAGE } from 'constants.ts'
import { Event, Filter, kinds, nip19, UnsignedEvent } from 'nostr-tools' import { Event, Filter, kinds, nip19, UnsignedEvent } from 'nostr-tools'
import { QRCodeSVG } from 'qrcode.react' import { QRCodeSVG } from 'qrcode.react'
import { Fragment, useMemo, useState } from 'react' import { Fragment, useEffect, useMemo, useState } from 'react'
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
import { toast } from 'react-toastify' import { toast } from 'react-toastify'
import { import {
@ -10,7 +10,7 @@ import {
useDidMount, useDidMount,
useNDKContext useNDKContext
} from '../hooks' } from '../hooks'
import { appRoutes, getProfilePageRoute } from '../routes' import { appRoutes, getFeedNotePageRoute, getProfilePageRoute } from '../routes'
import '../styles/author.css' import '../styles/author.css'
import '../styles/innerPage.css' import '../styles/innerPage.css'
import '../styles/socialPosts.css' import '../styles/socialPosts.css'
@ -18,6 +18,8 @@ import { UserRelaysType } from '../types'
import { import {
copyTextToClipboard, copyTextToClipboard,
hexToNpub, hexToNpub,
isValidImageUrl,
isValidUrl,
log, log,
LogType, LogType,
now, now,
@ -26,8 +28,12 @@ import {
} from '../utils' } from '../utils'
import { LoadingSpinner } from './LoadingSpinner' import { LoadingSpinner } from './LoadingSpinner'
import { ZapPopUp } from './Zap' import { ZapPopUp } from './Zap'
import placeholder from '../assets/img/DEGMods Placeholder Img.png' import {
import { NDKEvent, NDKSubscriptionCacheUsage } from '@nostr-dev-kit/ndk' NDKEvent,
NDKFilter,
NDKKind,
NDKSubscriptionCacheUsage
} from '@nostr-dev-kit/ndk'
import { useProfile } from 'hooks/useProfile' import { useProfile } from 'hooks/useProfile'
import { createPortal } from 'react-dom' import { createPortal } from 'react-dom'
@ -36,12 +42,60 @@ type Props = {
} }
export const ProfileSection = ({ pubkey }: Props) => { export const ProfileSection = ({ pubkey }: Props) => {
const { ndk } = useNDKContext()
const profile = useProfile(pubkey, {
cacheUsage: NDKSubscriptionCacheUsage.PARALLEL
})
const displayName =
profile?.displayName || profile?.name || '[name not set up]'
const [posts, setPosts] = useState<Post[]>([])
useEffect(() => {
const filter: NDKFilter = {
authors: [pubkey],
kinds: [NDKKind.Text],
limit: 10
}
ndk
.fetchEvents(filter, {
closeOnEose: true,
cacheUsage: NDKSubscriptionCacheUsage.PARALLEL
})
.then((ndkEventSet) => {
const ndkEvents = Array.from(ndkEventSet)
const posts: Post[] = ndkEvents
.sort((a, b) => (b.created_at ?? 0) - (a.created_at ?? 0))
.map((ndkEvent) => ({
content: ndkEvent.content,
link: getFeedNotePageRoute(ndkEvent.encode()),
name: displayName
}))
posts.splice(5)
for (const post of posts) {
const imageUrls = post.content.match(
new RegExp(
/(?:https?:\/\/|www\.)(?:[a-zA-Z0-9.-]+\.[a-zA-Z]+(?::\d+)?)(?:[/?#][\p{L}\p{N}\p{M}&.-/?=#\-@%+_,:!~*]*)?/gu
)
)
if (imageUrls) {
for (const url of imageUrls) {
if (isValidUrl(url) && isValidImageUrl(url)) {
post.imageUrl = url
break
}
}
}
}
setPosts(posts)
})
}, [displayName, ndk, pubkey])
return ( return (
<div className='IBMSMSplitMainSmallSide'> <div className='IBMSMSplitMainSmallSide'>
<div className='IBMSMSplitMainSmallSideSecWrapper'> <div className='IBMSMSplitMainSmallSideSecWrapper'>
<div className='IBMSMSplitMainSmallSideSec'> <div className='IBMSMSplitMainSmallSideSec'>
<Profile pubkey={pubkey} /> <Profile pubkey={pubkey} />
</div> </div>
{posts.length > 0 && (
<div className='IBMSMSplitMainSmallSideSec'> <div className='IBMSMSplitMainSmallSideSec'>
<div className='IBMSMSMSSS_ShortPosts'> <div className='IBMSMSMSSS_ShortPosts'>
{posts.map((post, index) => ( {posts.map((post, index) => (
@ -85,6 +139,7 @@ export const ProfileSection = ({ pubkey }: Props) => {
))} ))}
</div> </div>
</div> </div>
)}
</div> </div>
</div> </div>
) )
@ -222,25 +277,6 @@ interface Post {
imageUrl?: string imageUrl?: string
} }
const posts: Post[] = [
{
name: 'User name',
link: `feed-note.html`,
content: `user text, this is a long string of temporary text that would be replaced with the user post from their short posts`
},
{
name: 'User name',
link: 'feed-note.html',
content: `user text, this is a long string of temporary text that would be replaced with the user post from their short posts`
},
{
name: 'User name',
link: `feed-note.html`,
content: `user text, this is a long string of temporary text that would be replaced with the user post from their short posts`,
imageUrl: placeholder
}
]
type QRButtonWithPopUpProps = { type QRButtonWithPopUpProps = {
nprofile: string nprofile: string
} }