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

@@ -229,7 +229,7 @@ export default function NoteList({
return () => { return () => {
promise.then((closer) => closer()) promise.then((closer) => closer())
} }
}, [JSON.stringify(relayUrls), filterType, refreshCount]) }, [JSON.stringify(relayUrls), filterType, refreshCount, JSON.stringify(filter)])
useEffect(() => { useEffect(() => {
const options = { const options = {

View File

@@ -236,6 +236,7 @@ export default {
'View on njump.me': 'عرض على njump.me', 'View on njump.me': 'عرض على njump.me',
'Hide content from untrusted users': 'إخفاء المحتوى من المستخدمين غير الموثوقين', 'Hide content from untrusted users': 'إخفاء المحتوى من المستخدمين غير الموثوقين',
'Only show content from your followed users and the users they follow': 'Only show content from your followed users and the users they follow':
'فقط عرض المحتوى من المستخدمين الذين تتابعهم والمستخدمين الذين يتابعونهم' 'فقط عرض المحتوى من المستخدمين الذين تتابعهم والمستخدمين الذين يتابعونهم',
'Followed by': 'متابع من قبل'
} }
} }

View File

@@ -243,6 +243,7 @@ export default {
'Hide content from untrusted users': 'Hide content from untrusted users':
'Inhalte von nicht vertrauenswürdigen Benutzern ausblenden', 'Inhalte von nicht vertrauenswürdigen Benutzern ausblenden',
'Only show content from your followed users and the users they follow': 'Only show content from your followed users and the users they follow':
'Nur Inhalte von Benutzern anzeigen, denen du folgst und die sie folgen' 'Nur Inhalte von Benutzern anzeigen, denen du folgst und die sie folgen',
'Followed by': 'Gefolgt von'
} }
} }

View File

@@ -236,6 +236,7 @@ export default {
'View on njump.me': 'View on njump.me', 'View on njump.me': 'View on njump.me',
'Hide content from untrusted users': 'Hide content from untrusted users', 'Hide content from untrusted users': 'Hide content from untrusted users',
'Only show content from your followed users and the users they follow': 'Only show content from your followed users and the users they follow':
'Only show content from your followed users and the users they follow' 'Only show content from your followed users and the users they follow',
'Followed by': 'Followed by'
} }
} }

View File

@@ -241,6 +241,7 @@ export default {
'View on njump.me': 'Ver en njump.me', 'View on njump.me': 'Ver en njump.me',
'Hide content from untrusted users': 'Ocultar contenido de usuarios no confiables', 'Hide content from untrusted users': 'Ocultar contenido de usuarios no confiables',
'Only show content from your followed users and the users they follow': 'Only show content from your followed users and the users they follow':
'Solo mostrar contenido de tus usuarios seguidos y los usuarios que ellos siguen' 'Solo mostrar contenido de tus usuarios seguidos y los usuarios que ellos siguen',
'Followed by': 'Seguidos por'
} }
} }

View File

@@ -241,6 +241,7 @@ export default {
'View on njump.me': 'Voir sur njump.me', 'View on njump.me': 'Voir sur njump.me',
'Hide content from untrusted users': 'Hider le contenu des utilisateurs non fiables', 'Hide content from untrusted users': 'Hider le contenu des utilisateurs non fiables',
'Only show content from your followed users and the users they follow': 'Only show content from your followed users and the users they follow':
'Afficher uniquement le contenu de vos utilisateurs suivis et des utilisateurs quils suivent' 'Afficher uniquement le contenu de vos utilisateurs suivis et des utilisateurs quils suivent',
'Followed by': 'Suivi par'
} }
} }

View File

@@ -240,6 +240,7 @@ export default {
'View on njump.me': 'Visualizza su njump.me', 'View on njump.me': 'Visualizza su njump.me',
'Hide content from untrusted users': 'Nascondi contenuti da utenti non fidati', 'Hide content from untrusted users': 'Nascondi contenuti da utenti non fidati',
'Only show content from your followed users and the users they follow': 'Only show content from your followed users and the users they follow':
'Mostra solo contenuti dai tuoi utenti seguiti e dagli utenti che seguono' 'Mostra solo contenuti dai tuoi utenti seguiti e dagli utenti che seguono',
'Followed by': 'Seguito da'
} }
} }

View File

@@ -237,6 +237,7 @@ export default {
'View on njump.me': 'njump.meで表示', 'View on njump.me': 'njump.meで表示',
'Hide content from untrusted users': '信頼できないユーザーのコンテンツを非表示', 'Hide content from untrusted users': '信頼できないユーザーのコンテンツを非表示',
'Only show content from your followed users and the users they follow': 'Only show content from your followed users and the users they follow':
'フォローしているユーザーとそのユーザーがフォローしているユーザーのコンテンツのみを表示' 'フォローしているユーザーとそのユーザーがフォローしているユーザーのコンテンツのみを表示',
'Followed by': 'フォロワー'
} }
} }

View File

@@ -239,6 +239,7 @@ export default {
'View on njump.me': 'Zobacz na njump.me', 'View on njump.me': 'Zobacz na njump.me',
'Hide content from untrusted users': 'Ukryj treści od nieznanych użytkowników', 'Hide content from untrusted users': 'Ukryj treści od nieznanych użytkowników',
'Only show content from your followed users and the users they follow': 'Only show content from your followed users and the users they follow':
'Pokaż tylko treści od użytkowników, których obserwujesz i ich obserwowanych' 'Pokaż tylko treści od użytkowników, których obserwujesz i ich obserwowanych',
'Followed by': 'Obserwowany przez'
} }
} }

View File

@@ -239,6 +239,7 @@ export default {
'View on njump.me': 'Ver em njump.me', 'View on njump.me': 'Ver em njump.me',
'Hide content from untrusted users': 'Ocultar conteúdo de usuários não confiáveis', 'Hide content from untrusted users': 'Ocultar conteúdo de usuários não confiáveis',
'Only show content from your followed users and the users they follow': 'Only show content from your followed users and the users they follow':
'Mostrar apenas conteúdo dos usuários que você segue e dos usuários que eles seguem' 'Mostrar apenas conteúdo dos usuários que você segue e dos usuários que eles seguem',
'Followed by': 'Seguido por'
} }
} }

View File

@@ -240,6 +240,7 @@ export default {
'View on njump.me': 'Ver em njump.me', 'View on njump.me': 'Ver em njump.me',
'Hide content from untrusted users': 'Esconder conteúdo de usuários não confiáveis', 'Hide content from untrusted users': 'Esconder conteúdo de usuários não confiáveis',
'Only show content from your followed users and the users they follow': 'Only show content from your followed users and the users they follow':
'Mostrar apenas conteúdo dos usuários que você segue e dos usuários que eles seguem' 'Mostrar apenas conteúdo dos usuários que você segue e dos usuários que eles seguem',
'Followed by': 'Seguido por'
} }
} }

View File

@@ -240,6 +240,7 @@ export default {
'View on njump.me': 'Посмотреть на njump.me', 'View on njump.me': 'Посмотреть на njump.me',
'Hide content from untrusted users': 'Скрыть контент от недоверенных пользователей', 'Hide content from untrusted users': 'Скрыть контент от недоверенных пользователей',
'Only show content from your followed users and the users they follow': 'Only show content from your followed users and the users they follow':
'Показывать только контент от пользователей, на которых вы подписаны, и от пользователей, на которых они подписаны' 'Показывать только контент от пользователей, на которых вы подписаны, и от пользователей, на которых они подписаны',
'Followed by': 'Подписан на'
} }
} }

View File

@@ -237,6 +237,7 @@ export default {
'View on njump.me': '在 njump.me 上查看', 'View on njump.me': '在 njump.me 上查看',
'Hide content from untrusted users': '隐藏不受信任用户的内容', 'Hide content from untrusted users': '隐藏不受信任用户的内容',
'Only show content from your followed users and the users they follow': 'Only show content from your followed users and the users they follow':
'仅显示您关注的用户及其关注的用户的内容' '仅显示您关注的用户及其关注的用户的内容',
'Followed by': '关注者'
} }
} }

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 { forwardRef, useCallback, useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import NotFoundPage from '../NotFoundPage' import NotFoundPage from '../NotFoundPage'
import FollowedBy from './FollowedBy'
import Followings from './Followings' import Followings from './Followings'
import Relays from './Relays' import Relays from './Relays'
@@ -176,7 +177,8 @@ const ProfilePage = forwardRef(({ id, index }: { id?: string; index?: number },
</a> </a>
</div> </div>
)} )}
<div className="flex gap-4 items-center mt-2 text-sm"> <div className="flex justify-between items-center mt-2 text-sm">
<div className="flex gap-4 items-center">
<Followings pubkey={pubkey} /> <Followings pubkey={pubkey} />
<Relays pubkey={pubkey} /> <Relays pubkey={pubkey} />
{isSelf && ( {isSelf && (
@@ -186,6 +188,8 @@ const ProfilePage = forwardRef(({ id, index }: { id?: string; index?: number },
</SecondaryPageLink> </SecondaryPageLink>
)} )}
</div> </div>
{!isSelf && <FollowedBy pubkey={pubkey} />}
</div>
</div> </div>
</div> </div>
</div> </div>