-
+
+ {embedded && (
+
{t('Quotes')}
+ )}
+
{events.slice(0, showCount).map((event) => {
if (hideUntrustedInteractions && !isUserTrusted(event.pubkey)) {
@@ -201,7 +214,8 @@ export default function QuoteList({ event, className }: { event: Event; classNam
{t('no more notes')}
)}
-
+ {!embedded &&
}
+ {embedded &&
}
)
}
diff --git a/src/components/RelayInfo/RelayReviewCard.tsx b/src/components/RelayInfo/RelayReviewCard.tsx
index ab2a762a..40ec16a8 100644
--- a/src/components/RelayInfo/RelayReviewCard.tsx
+++ b/src/components/RelayInfo/RelayReviewCard.tsx
@@ -1,8 +1,10 @@
-import { useSmartNoteNavigation } from '@/PageManager'
-import { getStarsFromRelayReviewEvent } from '@/lib/event-metadata'
-import { toNote } from '@/lib/link'
+import { useSmartNoteNavigation, useSmartRelayNavigation } from '@/PageManager'
+import { getRelayUrlFromRelayReviewEvent, getStarsFromRelayReviewEvent } from '@/lib/event-metadata'
+import { toNote, toRelay } from '@/lib/link'
+import { simplifyUrl } from '@/lib/url'
import { cn } from '@/lib/utils'
import client from '@/services/client.service'
+import { Link2 } from 'lucide-react'
import { NostrEvent } from 'nostr-tools'
import { useMemo } from 'react'
import ClientTag from '../ClientTag'
@@ -21,7 +23,9 @@ export default function RelayReviewCard({
className?: string
}) {
const { navigateToNote } = useSmartNoteNavigation()
+ const { navigateToRelay } = useSmartRelayNavigation()
const stars = useMemo(() => getStarsFromRelayReviewEvent(event), [event])
+ const relayUrl = useMemo(() => getRelayUrlFromRelayReviewEvent(event), [event])
return (
-
+
+
+ {relayUrl ? (
+
+ ) : null}
+
)
diff --git a/src/components/ReplyNoteList/index.tsx b/src/components/ReplyNoteList/index.tsx
index d256c6a0..de0b3ce1 100644
--- a/src/components/ReplyNoteList/index.tsx
+++ b/src/components/ReplyNoteList/index.tsx
@@ -30,6 +30,7 @@ import { useNoteStatsById } from '@/hooks/useNoteStatsById'
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { LoadingBar } from '../LoadingBar'
+import QuoteList from '../QuoteList'
import ReplyNote, { ReplyNoteSkeleton } from '../ReplyNote'
import ZapReplyFeedRow from './ZapReplyFeedRow'
@@ -41,7 +42,18 @@ type TRootInfo =
const LIMIT = 100
const SHOW_COUNT = 10
-function ReplyNoteList({ index, event, sort = 'oldest' }: { index?: number; event: NEvent; sort?: 'newest' | 'oldest' | 'top' | 'controversial' | 'most-zapped' }) {
+function ReplyNoteList({
+ index,
+ event,
+ sort = 'oldest',
+ showQuotes = true
+}: {
+ index?: number
+ event: NEvent
+ sort?: 'newest' | 'oldest' | 'top' | 'controversial' | 'most-zapped'
+ /** When false, omit the quotes section (e.g. discussion threads). */
+ showQuotes?: boolean
+}) {
const { t } = useTranslation()
const { navigateToNote } = useSmartNoteNavigation()
const { currentIndex } = useSecondaryPage()
@@ -564,6 +576,7 @@ function ReplyNoteList({ index, event, sort = 'oldest' }: { index?: number; even
)}
{loading &&
}
+ {showQuotes &&
}
)
}
diff --git a/src/i18n/locales/ar.ts b/src/i18n/locales/ar.ts
index 0f7528b8..f6a1914d 100644
--- a/src/i18n/locales/ar.ts
+++ b/src/i18n/locales/ar.ts
@@ -162,6 +162,7 @@ export default {
'Send only to r': 'إرسال فقط إلى {{r}}',
'Send only to these relays': 'إرسال فقط إلى هذه الريلايات',
Explore: 'استكشاف',
+ 'Relay reviews': 'مراجعات الترحيل',
'Search relays': 'البحث في الريلايات',
relayInfoBadgeAuth: 'مصادقة',
relayInfoBadgeSearch: 'بحث',
diff --git a/src/i18n/locales/de.ts b/src/i18n/locales/de.ts
index 25c8cb35..0913298f 100644
--- a/src/i18n/locales/de.ts
+++ b/src/i18n/locales/de.ts
@@ -251,6 +251,7 @@ export default {
'Send only to r': 'Nur an {{r}} senden',
'Send only to these relays': 'Nur an diese Relays senden',
Explore: 'Entdecken',
+ 'Relay reviews': 'Bewertungen',
'Search relays': 'Relays suchen',
relayInfoBadgeAuth: 'Auth',
relayInfoBadgeSearch: 'Suche',
diff --git a/src/i18n/locales/en.ts b/src/i18n/locales/en.ts
index 9779a724..b062cd08 100644
--- a/src/i18n/locales/en.ts
+++ b/src/i18n/locales/en.ts
@@ -310,6 +310,7 @@ export default {
'Send only to r': 'Send only to {{r}}',
'Send only to these relays': 'Send only to these relays',
Explore: 'Explore',
+ 'Relay reviews': 'Relay reviews',
'Search relays': 'Search relays',
relayInfoBadgeAuth: 'Auth',
relayInfoBadgeSearch: 'Search',
diff --git a/src/i18n/locales/es.ts b/src/i18n/locales/es.ts
index de3534ff..d817ef73 100644
--- a/src/i18n/locales/es.ts
+++ b/src/i18n/locales/es.ts
@@ -166,6 +166,7 @@ export default {
'Send only to r': 'Enviar únicamente a {{r}}',
'Send only to these relays': 'Enviar únicamente a estos relés',
Explore: 'Explorar',
+ 'Relay reviews': 'Reseñas de relays',
'Search relays': 'Buscar relés',
relayInfoBadgeAuth: 'Autenticación',
relayInfoBadgeSearch: 'Búsqueda',
diff --git a/src/i18n/locales/fa.ts b/src/i18n/locales/fa.ts
index 435ae2f2..b06bf24a 100644
--- a/src/i18n/locales/fa.ts
+++ b/src/i18n/locales/fa.ts
@@ -164,6 +164,7 @@ export default {
'Send only to r': 'فقط به {{r}} ارسال شود',
'Send only to these relays': 'فقط به این رلهها ارسال شود',
Explore: 'کاوش',
+ 'Relay reviews': 'نقد رلهها',
'Search relays': 'جستجو رلهها',
relayInfoBadgeAuth: 'احراز هویت',
relayInfoBadgeSearch: 'جستجو',
diff --git a/src/i18n/locales/fr.ts b/src/i18n/locales/fr.ts
index 312598b7..5fcca787 100644
--- a/src/i18n/locales/fr.ts
+++ b/src/i18n/locales/fr.ts
@@ -165,6 +165,7 @@ export default {
'Send only to r': 'Envoyer uniquement à {{r}}',
'Send only to these relays': 'Envoyer uniquement à ces relais',
Explore: 'Explorer',
+ 'Relay reviews': 'Avis sur les relais',
'Search relays': 'Rechercher des relais',
relayInfoBadgeAuth: 'Auth',
relayInfoBadgeSearch: 'Recherche',
diff --git a/src/i18n/locales/hi.ts b/src/i18n/locales/hi.ts
index 1939ebbb..ca11af0e 100644
--- a/src/i18n/locales/hi.ts
+++ b/src/i18n/locales/hi.ts
@@ -165,6 +165,7 @@ export default {
'Send only to r': 'केवल {{r}} को भेजें',
'Send only to these relays': 'केवल इन रिले को भेजें',
Explore: 'एक्सप्लोर करें',
+ 'Relay reviews': 'रिले समीक्षाएँ',
'Search relays': 'रिले खोजें',
relayInfoBadgeAuth: 'प्रमाणीकरण',
relayInfoBadgeSearch: 'खोज',
diff --git a/src/i18n/locales/it.ts b/src/i18n/locales/it.ts
index 32138855..cf402b1b 100644
--- a/src/i18n/locales/it.ts
+++ b/src/i18n/locales/it.ts
@@ -165,6 +165,7 @@ export default {
'Send only to r': 'Invia solo a {{r}}',
'Send only to these relays': 'Invia solo a questi relay',
Explore: 'Esplora',
+ 'Relay reviews': 'Recensioni relay',
'Search relays': 'Ricerca relay',
relayInfoBadgeAuth: 'Autorizzazione',
relayInfoBadgeSearch: 'Ricerca',
diff --git a/src/i18n/locales/ja.ts b/src/i18n/locales/ja.ts
index 170f5fd5..8d01f290 100644
--- a/src/i18n/locales/ja.ts
+++ b/src/i18n/locales/ja.ts
@@ -164,6 +164,7 @@ export default {
'Send only to r': '{{r}} にのみ送信',
'Send only to these relays': 'これらのリレイにのみ送信',
Explore: '探索',
+ 'Relay reviews': 'リレーレビュー',
'Search relays': 'リレイを検索',
relayInfoBadgeAuth: '認証',
relayInfoBadgeSearch: '検索',
diff --git a/src/i18n/locales/ko.ts b/src/i18n/locales/ko.ts
index cfa08e95..52244112 100644
--- a/src/i18n/locales/ko.ts
+++ b/src/i18n/locales/ko.ts
@@ -165,6 +165,7 @@ export default {
'Send only to r': '{{r}}에만 전송',
'Send only to these relays': '이 릴레이에만 전송',
Explore: '탐색',
+ 'Relay reviews': '릴레이 리뷰',
'Search relays': '릴레이 검색',
relayInfoBadgeAuth: '로그인 필요',
relayInfoBadgeSearch: '검색 지원',
diff --git a/src/i18n/locales/pl.ts b/src/i18n/locales/pl.ts
index 12729108..d09402e5 100644
--- a/src/i18n/locales/pl.ts
+++ b/src/i18n/locales/pl.ts
@@ -162,6 +162,7 @@ export default {
'Send only to r': 'Wyślij tylko do {{r}}',
'Send only to these relays': 'Wyślij tylko do tych transmiterów',
Explore: 'Transmitery',
+ 'Relay reviews': 'Opinie o relayach',
'Search relays': 'Wyszukaj transmiter',
relayInfoBadgeAuth: '✔️',
relayInfoBadgeSearch: 'Wyszukiwarka',
diff --git a/src/i18n/locales/pt-BR.ts b/src/i18n/locales/pt-BR.ts
index f3c25462..cc02b165 100644
--- a/src/i18n/locales/pt-BR.ts
+++ b/src/i18n/locales/pt-BR.ts
@@ -164,6 +164,7 @@ export default {
'Send only to r': 'Enviar apenas para {{r}}',
'Send only to these relays': 'Enviar apenas para estes relays',
Explore: 'Explorar',
+ 'Relay reviews': 'Avaliações de relays',
'Search relays': 'Pesquisar relays',
relayInfoBadgeAuth: 'Auth',
relayInfoBadgeSearch: 'Pesquisar',
diff --git a/src/i18n/locales/pt-PT.ts b/src/i18n/locales/pt-PT.ts
index 266e8924..c9cc9c64 100644
--- a/src/i18n/locales/pt-PT.ts
+++ b/src/i18n/locales/pt-PT.ts
@@ -165,6 +165,7 @@ export default {
'Send only to r': 'Enviar apenas para {{r}}',
'Send only to these relays': 'Enviar apenas para estes relés',
Explore: 'Explorar',
+ 'Relay reviews': 'Avaliações de relays',
'Search relays': 'Pesquisar relés',
relayInfoBadgeAuth: 'Auth',
relayInfoBadgeSearch: 'Pesquisar',
diff --git a/src/i18n/locales/ru.ts b/src/i18n/locales/ru.ts
index bca79a9d..bcc82f12 100644
--- a/src/i18n/locales/ru.ts
+++ b/src/i18n/locales/ru.ts
@@ -167,6 +167,7 @@ export default {
'Send only to r': 'Отправить только на {{r}}',
'Send only to these relays': 'Отправить только на эти ретрансляторы',
Explore: 'Обзор',
+ 'Relay reviews': 'Отзывы о ретрансляторах',
'Search relays': 'Поиск ретрансляторов',
relayInfoBadgeAuth: 'Авторизация',
relayInfoBadgeSearch: 'Поиск',
diff --git a/src/i18n/locales/th.ts b/src/i18n/locales/th.ts
index 81ec6db8..520b29e8 100644
--- a/src/i18n/locales/th.ts
+++ b/src/i18n/locales/th.ts
@@ -162,6 +162,7 @@ export default {
'Send only to r': 'ส่งเฉพาะไปยัง {{r}}',
'Send only to these relays': 'ส่งเฉพาะไปยังรีเลย์เหล่านี้',
Explore: 'สำรวจ',
+ 'Relay reviews': 'รีวิวรีเลย์',
'Search relays': 'ค้นหารีเลย์',
relayInfoBadgeAuth: 'ยืนยันตัวตน',
relayInfoBadgeSearch: 'ค้นหา',
diff --git a/src/i18n/locales/zh.ts b/src/i18n/locales/zh.ts
index a2e7e416..476db1f5 100644
--- a/src/i18n/locales/zh.ts
+++ b/src/i18n/locales/zh.ts
@@ -164,6 +164,7 @@ export default {
'Send only to r': '只发送到 {{r}}',
'Send only to these relays': '只发送到这些服务器',
Explore: '探索',
+ 'Relay reviews': '中继评价',
'Search relays': '搜索服务器',
relayInfoBadgeAuth: '需登陆',
relayInfoBadgeSearch: '支持搜索',
diff --git a/src/lib/event-metadata.ts b/src/lib/event-metadata.ts
index d15dd27b..c5a2eec8 100644
--- a/src/lib/event-metadata.ts
+++ b/src/lib/event-metadata.ts
@@ -577,3 +577,10 @@ export function getStarsFromRelayReviewEvent(event: Event): number {
}
return 0
}
+
+/** Relay URL from the `d` tag (NIP for relay reviews). */
+export function getRelayUrlFromRelayReviewEvent(event: Event): string | undefined {
+ const d = event.tags.find((t) => t[0] === 'd')?.[1]?.trim()
+ if (!d) return undefined
+ return normalizeUrl(d) || d
+}
diff --git a/src/pages/primary/ExplorePage/index.tsx b/src/pages/primary/ExplorePage/index.tsx
index ffe4184e..526f9d34 100644
--- a/src/pages/primary/ExplorePage/index.tsx
+++ b/src/pages/primary/ExplorePage/index.tsx
@@ -1,5 +1,6 @@
import Explore from '@/components/Explore'
import ExploreFavoriteRelays from '@/components/Explore/ExploreFavoriteRelays'
+import ExploreRelayReviews from '@/components/Explore/ExploreRelayReviews'
import FollowingFavoriteRelayList from '@/components/FollowingFavoriteRelayList'
import Tabs from '@/components/Tabs'
import VersionUpdateBanner from '@/components/VersionUpdateBanner'
@@ -55,10 +56,11 @@ function filterMonitoringRelaySuggestions(urls: string[], rawQuery: string): str
return matches.slice(0, RELAY_SUGGESTION_LIMIT)
}
-type TExploreTabs = 'explore' | 'following'
+type TExploreTabs = 'explore' | 'reviews' | 'following'
function normalizeHomeTab(restored: string): TExploreTabs {
if (restored === 'following') return 'following'
+ if (restored === 'reviews') return 'reviews'
// Removed "favorites" tab — treat saved state as Explore
return 'explore'
}
@@ -88,6 +90,7 @@ const ExplorePage = forwardRef((_, ref) => {
value={tab}
tabs={[
{ value: 'explore', label: t('Explore') },
+ { value: 'reviews', label: t('Relay reviews') },
{ value: 'following', label: t("Following's Favorites") }
]}
onTabChange={(next) => {
@@ -113,6 +116,7 @@ const ExplorePage = forwardRef((_, ref) => {