feat: followed by

This commit is contained in:
codytseng
2025-06-04 09:17:00 +08:00
parent 74986b1c6e
commit 30a32ca94f
15 changed files with 88 additions and 22 deletions

View File

@@ -0,0 +1,50 @@
import UserAvatar from '@/components/UserAvatar'
import { useNostr } from '@/providers/NostrProvider'
import { useScreenSize } from '@/providers/ScreenSizeProvider'
import client from '@/services/client.service'
import { useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
export default function FollowedBy({ pubkey }: { pubkey: string }) {
const { t } = useTranslation()
const { isSmallScreen } = useScreenSize()
const [followedBy, setFollowedBy] = useState<string[]>([])
const { pubkey: accountPubkey } = useNostr()
useEffect(() => {
if (!pubkey || !accountPubkey) return
const init = async () => {
const followings = (await client.fetchFollowings(accountPubkey)).reverse()
const followingsOfFollowings = await Promise.all(
followings.map(async (following) => {
return client.fetchFollowings(following)
})
)
const _followedBy: string[] = []
const limit = isSmallScreen ? 3 : 5
for (const [index, following] of followings.entries()) {
if (following === pubkey) continue
if (followingsOfFollowings[index].includes(pubkey)) {
_followedBy.push(following)
}
if (_followedBy.length >= limit) {
break
}
}
setFollowedBy(_followedBy)
}
init()
}, [pubkey, accountPubkey])
if (followedBy.length === 0) return null
return (
<div className="flex items-center gap-1">
<div className="text-muted-foreground">{t('Followed by')}</div>
{followedBy.map((p) => (
<UserAvatar userId={p} key={p} size="xSmall" />
))}
</div>
)
}

View File

@@ -23,6 +23,7 @@ import { Link, Zap } from 'lucide-react'
import { forwardRef, useCallback, useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import NotFoundPage from '../NotFoundPage'
import FollowedBy from './FollowedBy'
import Followings from './Followings'
import Relays from './Relays'
@@ -176,15 +177,18 @@ const ProfilePage = forwardRef(({ id, index }: { id?: string; index?: number },
</a>
</div>
)}
<div className="flex gap-4 items-center mt-2 text-sm">
<Followings pubkey={pubkey} />
<Relays pubkey={pubkey} />
{isSelf && (
<SecondaryPageLink to={toMuteList()} className="flex gap-1 hover:underline w-fit">
{mutePubkeys.length}
<div className="text-muted-foreground">{t('Muted')}</div>
</SecondaryPageLink>
)}
<div className="flex justify-between items-center mt-2 text-sm">
<div className="flex gap-4 items-center">
<Followings pubkey={pubkey} />
<Relays pubkey={pubkey} />
{isSelf && (
<SecondaryPageLink to={toMuteList()} className="flex gap-1 hover:underline w-fit">
{mutePubkeys.length}
<div className="text-muted-foreground">{t('Muted')}</div>
</SecondaryPageLink>
)}
</div>
{!isSelf && <FollowedBy pubkey={pubkey} />}
</div>
</div>
</div>