feat: 24h pulse

This commit is contained in:
codytseng 2025-11-29 00:34:53 +08:00
parent b21855c294
commit ce7afeb250
31 changed files with 1086 additions and 123 deletions

View file

@ -16,12 +16,12 @@ import { useTranslation } from 'react-i18next'
const NoteListPage = forwardRef(({ index }: { index?: number }, ref) => {
const { t } = useTranslation()
const { push } = useSecondaryPage()
const { relayList, pubkey } = useNostr()
const { pubkey } = useNostr()
const [title, setTitle] = useState<React.ReactNode>(null)
const [controls, setControls] = useState<React.ReactNode>(null)
const [data, setData] = useState<
| {
type: 'hashtag' | 'search' | 'externalContent'
type: 'hashtag' | 'search'
kinds?: number[]
}
| {
@ -64,18 +64,6 @@ const NoteListPage = forwardRef(({ index }: { index?: number }, ref) => {
])
return
}
const externalContentId = searchParams.get('i')
if (externalContentId) {
setData({ type: 'externalContent' })
setTitle(externalContentId)
setSubRequests([
{
filter: { '#I': [externalContentId], ...(kinds.length > 0 ? { kinds } : {}) },
urls: BIG_RELAY_URLS.concat(relayList?.write || [])
}
])
return
}
const domain = searchParams.get('d')
if (domain) {
setTitle(
@ -119,7 +107,7 @@ const NoteListPage = forwardRef(({ index }: { index?: number }, ref) => {
</div>
)
} else if (data) {
content = <NormalFeed subRequests={subRequests} />
content = <NormalFeed subRequests={subRequests} disable24hMode={data.type !== 'domain'} />
}
return (

View file

@ -0,0 +1,86 @@
import NoteCard from '@/components/NoteCard'
import { SimpleUsername } from '@/components/Username'
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
import userAggregationService from '@/services/user-aggregation.service'
import { nip19, NostrEvent } from 'nostr-tools'
import { forwardRef, useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
const UserAggregationDetailPage = forwardRef(
(
{
feedId,
npub,
index
}: {
feedId?: string
npub?: string
index?: number
},
ref
) => {
const { t } = useTranslation()
const [aggregation, setAggregation] = useState<NostrEvent[]>([])
const pubkey = useMemo(() => {
if (!npub) return undefined
try {
const { type, data } = nip19.decode(npub)
if (type === 'npub') return data
if (type === 'nprofile') return data.pubkey
} catch {
return undefined
}
}, [npub])
useEffect(() => {
if (!feedId || !pubkey) {
setAggregation([])
return
}
const updateEvents = () => {
const events = userAggregationService.getAggregation(feedId, pubkey)
setAggregation(events)
}
const unSub = userAggregationService.subscribeAggregationChange(feedId, pubkey, () => {
updateEvents()
})
updateEvents()
return unSub
}, [feedId, pubkey, setAggregation])
if (!pubkey || !feedId) {
return (
<SecondaryPageLayout ref={ref} index={index} title={t('User Posts')}>
<div className="flex justify-center items-center h-40 text-muted-foreground">
{t('Invalid user')}
</div>
</SecondaryPageLayout>
)
}
return (
<SecondaryPageLayout
ref={ref}
index={index}
title={<SimpleUsername userId={pubkey} className="truncate" />}
displayScrollToTopButton
>
<div className="min-h-screen">
{aggregation.map((event) => (
<NoteCard key={event.id} className="w-full" event={event} filterMutedNotes={false} />
))}
<div className="text-center text-sm text-muted-foreground mt-2">{t('no more notes')}</div>
</div>
</SecondaryPageLayout>
)
}
)
UserAggregationDetailPage.displayName = 'UserAggregationDetailPage'
export default UserAggregationDetailPage