feat: remove default favorite relays

This commit is contained in:
codytseng 2025-11-01 15:56:11 +08:00
parent 24348d4f01
commit 38bc425d50
27 changed files with 216 additions and 172 deletions

View file

@ -54,21 +54,21 @@ const FeedSwitcherTrigger = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivEle
const { feedInfo, relayUrls } = useFeed()
const { relaySets } = useFavoriteRelays()
const activeRelaySet = useMemo(() => {
return feedInfo.feedType === 'relays' && feedInfo.id
return feedInfo?.feedType === 'relays' && feedInfo.id
? relaySets.find((set) => set.id === feedInfo.id)
: undefined
}, [feedInfo, relaySets])
const title = useMemo(() => {
if (feedInfo.feedType === 'following') {
if (feedInfo?.feedType === 'following') {
return t('Following')
}
if (relayUrls.length === 0) {
return t('Choose a relay')
return t('Choose a feed')
}
if (feedInfo.feedType === 'relay') {
return simplifyUrl(feedInfo.id ?? '')
if (feedInfo?.feedType === 'relay') {
return simplifyUrl(feedInfo?.id ?? '')
}
if (feedInfo.feedType === 'relays') {
if (feedInfo?.feedType === 'relays') {
return activeRelaySet?.name ?? activeRelaySet?.id
}
}, [feedInfo, activeRelaySet])
@ -79,7 +79,7 @@ const FeedSwitcherTrigger = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivEle
ref={ref}
{...props}
>
{feedInfo.feedType === 'following' ? <UsersRound /> : <Server />}
{feedInfo?.feedType === 'following' ? <UsersRound /> : <Server />}
<div className="text-lg font-semibold truncate">{title}</div>
<ChevronDown />
</div>

View file

@ -12,7 +12,7 @@ export default function FollowingFeed() {
useEffect(() => {
async function init() {
if (feedInfo.feedType !== 'following' || !pubkey) {
if (feedInfo?.feedType !== 'following' || !pubkey) {
setSubRequests([])
return
}
@ -22,7 +22,7 @@ export default function FollowingFeed() {
}
init()
}, [feedInfo.feedType, pubkey])
}, [feedInfo?.feedType, pubkey])
return <NormalFeed subRequests={subRequests} isMainFeed />
}

View file

@ -22,7 +22,7 @@ export default function RelaysFeed() {
return null
}
if (feedInfo.feedType !== 'relay' && feedInfo.feedType !== 'relays') {
if (!feedInfo || (feedInfo.feedType !== 'relay' && feedInfo.feedType !== 'relays')) {
return null
}

View file

@ -1,4 +1,4 @@
import { useSecondaryPage } from '@/PageManager'
import { usePrimaryPage, useSecondaryPage } from '@/PageManager'
import PostEditor from '@/components/PostEditor'
import RelayInfo from '@/components/RelayInfo'
import { Button } from '@/components/ui/button'
@ -9,7 +9,7 @@ import { useFeed } from '@/providers/FeedProvider'
import { useNostr } from '@/providers/NostrProvider'
import { useScreenSize } from '@/providers/ScreenSizeProvider'
import { TPageRef } from '@/types'
import { Info, PencilLine, Search } from 'lucide-react'
import { Compass, Info, LogIn, PencilLine, Search, Sparkles } from 'lucide-react'
import {
Dispatch,
forwardRef,
@ -28,8 +28,8 @@ const NoteListPage = forwardRef((_, ref) => {
const { t } = useTranslation()
const { addRelayUrls, removeRelayUrls } = useCurrentRelays()
const layoutRef = useRef<TPageRef>(null)
const { pubkey, checkLogin } = useNostr()
const { feedInfo, relayUrls, isReady } = useFeed()
const { pubkey } = useNostr()
const { feedInfo, relayUrls, isReady, switchFeed } = useFeed()
const [showRelayDetails, setShowRelayDetails] = useState(false)
useImperativeHandle(ref, () => layoutRef.current)
@ -48,17 +48,25 @@ const NoteListPage = forwardRef((_, ref) => {
}
}, [relayUrls])
if (!feedInfo) {
return (
<PrimaryPageLayout
pageName="home"
ref={layoutRef}
titlebar={<NoteListPageTitlebar layoutRef={layoutRef} />}
displayScrollToTopButton
>
<WelcomeGuide />
</PrimaryPageLayout>
)
}
let content: React.ReactNode = null
if (!isReady) {
content = <div className="text-center text-sm text-muted-foreground">{t('loading...')}</div>
} else if (feedInfo.feedType === 'following' && !pubkey) {
content = (
<div className="flex justify-center w-full">
<Button size="lg" onClick={() => checkLogin()}>
{t('Please login to view following feed')}
</Button>
</div>
)
switchFeed(null)
return null
} else if (feedInfo.feedType === 'following') {
content = <FollowingFeed />
} else {
@ -169,3 +177,38 @@ function SearchButton() {
</Button>
)
}
function WelcomeGuide() {
const { t } = useTranslation()
const { navigate } = usePrimaryPage()
const { checkLogin } = useNostr()
return (
<div className="flex flex-col items-center justify-center min-h-[60vh] px-4 text-center space-y-6">
<div className="space-y-2">
<div className="flex items-center w-full justify-center gap-2">
<Sparkles className="text-yellow-400" />
<h2 className="text-2xl font-bold">{t('Welcome to Jumble')}</h2>
<Sparkles className="text-yellow-400" />
</div>
<p className="text-muted-foreground max-w-md">
{t(
'Jumble is a client focused on browsing relays. Get started by exploring interesting relays or login to view your following feed.'
)}
</p>
</div>
<div className="flex flex-col sm:flex-row gap-3 w-full max-w-md">
<Button size="lg" className="w-full" onClick={() => navigate('explore')}>
<Compass className="size-5" />
{t('Explore Relays')}
</Button>
<Button size="lg" className="w-full" variant="outline" onClick={() => checkLogin()}>
<LogIn className="size-5" />
{t('Login')}
</Button>
</div>
</div>
)
}

View file

@ -1,79 +0,0 @@
import { usePrimaryPage, useSecondaryPage } from '@/PageManager'
import RelaySimpleInfo from '@/components/RelaySimpleInfo'
import { Button } from '@/components/ui/button'
import { RECOMMENDED_RELAYS } from '@/constants'
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
import { toRelay } from '@/lib/link'
import relayInfoService from '@/services/relay-info.service'
import { TRelayInfo } from '@/types'
import { ArrowRight, Server } from 'lucide-react'
import { forwardRef, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next'
const HomePage = forwardRef(({ index }: { index?: number }, ref) => {
const { t } = useTranslation()
const { navigate } = usePrimaryPage()
const { push } = useSecondaryPage()
const [recommendedRelayInfos, setRecommendedRelayInfos] = useState<TRelayInfo[]>([])
useEffect(() => {
const init = async () => {
try {
const relays = await relayInfoService.getRelayInfos(RECOMMENDED_RELAYS)
setRecommendedRelayInfos(relays.filter(Boolean) as TRelayInfo[])
} catch (error) {
console.error('Failed to fetch recommended relays:', error)
}
}
init()
}, [])
if (!recommendedRelayInfos.length) {
return (
<SecondaryPageLayout ref={ref} index={index} hideBackButton hideTitlebarBottomBorder>
<div className="text-muted-foreground w-full h-screen flex items-center justify-center">
{t('Welcome! 🥳')}
</div>
</SecondaryPageLayout>
)
}
return (
<SecondaryPageLayout
ref={ref}
index={index}
title={
<>
<Server />
<div>{t('Recommended relays')}</div>
</>
}
hideBackButton
hideTitlebarBottomBorder
>
<div className="px-4 pt-2">
<div className="grid grid-cols-2 gap-3">
{recommendedRelayInfos.map((relayInfo) => (
<RelaySimpleInfo
key={relayInfo.url}
className="clickable h-auto px-4 py-3 rounded-lg border"
relayInfo={relayInfo}
onClick={(e) => {
e.stopPropagation()
push(toRelay(relayInfo.url))
}}
/>
))}
</div>
<div className="flex mt-2 justify-center">
<Button variant="ghost" onClick={() => navigate('explore')}>
<div>{t('Explore more')}</div>
<ArrowRight />
</Button>
</div>
</div>
</SecondaryPageLayout>
)
})
HomePage.displayName = 'HomePage'
export default HomePage