feat: favorite relays (#250)
This commit is contained in:
parent
fab9ff88b5
commit
c739d9d28c
63 changed files with 1081 additions and 982 deletions
|
|
@ -8,11 +8,19 @@ import { Separator } from '@/components/ui/separator'
|
|||
import { SimpleUserAvatar } from '@/components/UserAvatar'
|
||||
import { SimpleUsername } from '@/components/Username'
|
||||
import PrimaryPageLayout from '@/layouts/PrimaryPageLayout'
|
||||
import { toProfile, toSettings, toWallet } from '@/lib/link'
|
||||
import { toProfile, toRelaySettings, toSettings, toWallet } from '@/lib/link'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { useSecondaryPage } from '@/PageManager'
|
||||
import { useNostr } from '@/providers/NostrProvider'
|
||||
import { ArrowDownUp, ChevronRight, LogOut, Settings, UserRound, Wallet } from 'lucide-react'
|
||||
import {
|
||||
ArrowDownUp,
|
||||
ChevronRight,
|
||||
LogOut,
|
||||
Server,
|
||||
Settings,
|
||||
UserRound,
|
||||
Wallet
|
||||
} from 'lucide-react'
|
||||
import { forwardRef, HTMLProps, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
|
|
@ -54,6 +62,9 @@ const MePage = forwardRef((_, ref) => {
|
|||
<UserRound />
|
||||
{t('Profile')}
|
||||
</Item>
|
||||
<Item onClick={() => push(toRelaySettings())}>
|
||||
<Server /> {t('Relays')}
|
||||
</Item>
|
||||
<Item onClick={() => push(toWallet())}>
|
||||
<Wallet />
|
||||
{t('Wallet')}
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ import { Drawer, DrawerContent } from '@/components/ui/drawer'
|
|||
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'
|
||||
import { simplifyUrl } from '@/lib/url'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { useFavoriteRelays } from '@/providers/FavoriteRelaysProvider'
|
||||
import { useFeed } from '@/providers/FeedProvider'
|
||||
import { useRelaySets } from '@/providers/RelaySetsProvider'
|
||||
import { useScreenSize } from '@/providers/ScreenSizeProvider'
|
||||
import { ChevronDown, Server, UsersRound } from 'lucide-react'
|
||||
import { forwardRef, HTMLAttributes, useState } from 'react'
|
||||
import { forwardRef, HTMLAttributes, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
export default function FeedButton({ className }: { className?: string }) {
|
||||
|
|
@ -20,7 +20,7 @@ export default function FeedButton({ className }: { className?: string }) {
|
|||
<FeedSwitcherTrigger className={className} onClick={() => setOpen(true)} />
|
||||
<Drawer open={open} onOpenChange={setOpen}>
|
||||
<DrawerContent className="max-h-[80vh]">
|
||||
<div className="p-4 overflow-auto">
|
||||
<div className="py-4 px-2 overflow-auto">
|
||||
<FeedSwitcher close={() => setOpen(false)} />
|
||||
</div>
|
||||
</DrawerContent>
|
||||
|
|
@ -44,21 +44,32 @@ export default function FeedButton({ className }: { className?: string }) {
|
|||
const FeedSwitcherTrigger = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivElement>>(
|
||||
({ className, ...props }, ref) => {
|
||||
const { t } = useTranslation()
|
||||
const { feedType, relayUrls, activeRelaySetId } = useFeed()
|
||||
const { relaySets } = useRelaySets()
|
||||
const activeRelaySet = activeRelaySetId
|
||||
? relaySets.find((set) => set.id === activeRelaySetId)
|
||||
: undefined
|
||||
const title =
|
||||
feedType === 'following'
|
||||
? t('Following')
|
||||
: relayUrls.length > 0
|
||||
? relayUrls.length === 1
|
||||
? simplifyUrl(relayUrls[0])
|
||||
: activeRelaySet
|
||||
? activeRelaySet.name
|
||||
: t('Temporary')
|
||||
: t('Choose a relay set')
|
||||
const { feedInfo, relayUrls } = useFeed()
|
||||
const { relaySets } = useFavoriteRelays()
|
||||
const activeRelaySet = useMemo(() => {
|
||||
return feedInfo.feedType === 'relays' && feedInfo.id
|
||||
? relaySets.find((set) => set.id === feedInfo.id)
|
||||
: undefined
|
||||
}, [feedInfo, relaySets])
|
||||
const title = useMemo(() => {
|
||||
if (feedInfo.feedType === 'following') {
|
||||
return t('Following')
|
||||
}
|
||||
if (relayUrls.length === 0) {
|
||||
return t('Choose a relay')
|
||||
}
|
||||
if (feedInfo.feedType === 'relay') {
|
||||
return simplifyUrl(feedInfo.id ?? '')
|
||||
}
|
||||
if (feedInfo.feedType === 'relays') {
|
||||
return activeRelaySet?.name ?? activeRelaySet?.id
|
||||
}
|
||||
if (feedInfo.feedType === 'temporary') {
|
||||
return relayUrls.length === 1
|
||||
? simplifyUrl(relayUrls[0])
|
||||
: (activeRelaySet?.name ?? t('Temporary'))
|
||||
}
|
||||
}, [feedInfo, activeRelaySet])
|
||||
|
||||
return (
|
||||
<div
|
||||
|
|
@ -66,7 +77,7 @@ const FeedSwitcherTrigger = forwardRef<HTMLDivElement, HTMLAttributes<HTMLDivEle
|
|||
ref={ref}
|
||||
{...props}
|
||||
>
|
||||
{feedType === 'following' ? <UsersRound /> : <Server />}
|
||||
{feedInfo.feedType === 'following' ? <UsersRound /> : <Server />}
|
||||
<div className="text-lg font-semibold truncate">{title}</div>
|
||||
<ChevronDown />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -17,17 +17,17 @@ const NoteListPage = forwardRef((_, ref) => {
|
|||
const { t } = useTranslation()
|
||||
const layoutRef = useRef<TPageRef>(null)
|
||||
const { pubkey, checkLogin } = useNostr()
|
||||
const { feedType, relayUrls, isReady, filter } = useFeed()
|
||||
const { feedInfo, relayUrls, isReady, filter } = useFeed()
|
||||
useImperativeHandle(ref, () => layoutRef.current)
|
||||
|
||||
useEffect(() => {
|
||||
if (layoutRef.current) {
|
||||
layoutRef.current.scrollToTop()
|
||||
}
|
||||
}, [JSON.stringify(relayUrls), feedType])
|
||||
}, [JSON.stringify(relayUrls), feedInfo])
|
||||
|
||||
let content = <div className="text-center text-sm text-muted-foreground">{t('loading...')}</div>
|
||||
if (feedType === 'following' && !pubkey) {
|
||||
if (feedInfo.feedType === 'following' && !pubkey) {
|
||||
content = (
|
||||
<div className="flex justify-center w-full">
|
||||
<Button size="lg" onClick={() => checkLogin()}>
|
||||
|
|
@ -40,7 +40,7 @@ const NoteListPage = forwardRef((_, ref) => {
|
|||
<NoteList
|
||||
relayUrls={relayUrls}
|
||||
filter={filter}
|
||||
needCheckAlgoRelay={feedType !== 'following'}
|
||||
needCheckAlgoRelay={feedInfo.feedType !== 'following'}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
@ -50,7 +50,9 @@ const NoteListPage = forwardRef((_, ref) => {
|
|||
pageName="home"
|
||||
ref={layoutRef}
|
||||
titlebar={
|
||||
<NoteListPageTitlebar temporaryRelayUrls={feedType === 'temporary' ? relayUrls : []} />
|
||||
<NoteListPageTitlebar
|
||||
temporaryRelayUrls={feedInfo.feedType === 'temporary' ? relayUrls : []}
|
||||
/>
|
||||
}
|
||||
displayScrollToTopButton
|
||||
>
|
||||
|
|
@ -67,7 +69,7 @@ function NoteListPageTitlebar({ temporaryRelayUrls = [] }: { temporaryRelayUrls?
|
|||
return (
|
||||
<div className="flex gap-1 items-center h-full justify-between">
|
||||
<FeedButton className="flex-1 max-w-fit w-0" />
|
||||
<div className="shrink-0">
|
||||
<div className="shrink-0 flex gap-1 items-center">
|
||||
{temporaryRelayUrls.length > 0 && (
|
||||
<SaveRelayDropdownMenu urls={temporaryRelayUrls} atTitlebar />
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import MailboxSetting from '@/components/MailboxSetting'
|
||||
import RelaySetsSetting from '@/components/RelaySetsSetting'
|
||||
import FavoriteRelaysSetting from '@/components/FavoriteRelaysSetting'
|
||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'
|
||||
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
|
||||
import { forwardRef, useEffect, useState } from 'react'
|
||||
|
|
@ -7,28 +7,28 @@ import { useTranslation } from 'react-i18next'
|
|||
|
||||
const RelaySettingsPage = forwardRef(({ index }: { index?: number }, ref) => {
|
||||
const { t } = useTranslation()
|
||||
const [tabValue, setTabValue] = useState('relay-sets')
|
||||
const [tabValue, setTabValue] = useState('favorite-relays')
|
||||
|
||||
useEffect(() => {
|
||||
switch (window.location.hash) {
|
||||
case '#mailbox':
|
||||
setTabValue('mailbox')
|
||||
break
|
||||
case '#relay-sets':
|
||||
setTabValue('relay-sets')
|
||||
case '#favorite-relays':
|
||||
setTabValue('favorite-relays')
|
||||
break
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<SecondaryPageLayout ref={ref} index={index} title={t('Relay settings')}>
|
||||
<Tabs value={tabValue} onValueChange={setTabValue} className="px-4 space-y-4">
|
||||
<Tabs value={tabValue} onValueChange={setTabValue} className="px-4 pb-4 space-y-4">
|
||||
<TabsList>
|
||||
<TabsTrigger value="relay-sets">{t('Relay Sets')}</TabsTrigger>
|
||||
<TabsTrigger value="favorite-relays">{t('Favorite Relays')}</TabsTrigger>
|
||||
<TabsTrigger value="mailbox">{t('Read & Write Relays')}</TabsTrigger>
|
||||
</TabsList>
|
||||
<TabsContent value="relay-sets">
|
||||
<RelaySetsSetting />
|
||||
<TabsContent value="favorite-relays">
|
||||
<FavoriteRelaysSetting />
|
||||
</TabsContent>
|
||||
<TabsContent value="mailbox">
|
||||
<MailboxSetting />
|
||||
|
|
|
|||
|
|
@ -73,14 +73,14 @@ const SettingsPage = forwardRef(({ index }: { index?: number }, ref) => {
|
|||
</SelectContent>
|
||||
</Select>
|
||||
</SettingItem>
|
||||
<SettingItem onClick={() => push(toRelaySettings())}>
|
||||
<SettingItem className="clickable" onClick={() => push(toRelaySettings())}>
|
||||
<div className="flex items-center gap-4">
|
||||
<Server />
|
||||
<div>{t('Relays')}</div>
|
||||
</div>
|
||||
<ChevronRight />
|
||||
</SettingItem>
|
||||
<SettingItem onClick={() => push(toWallet())}>
|
||||
<SettingItem className="clickable" onClick={() => push(toWallet())}>
|
||||
<div className="flex items-center gap-4">
|
||||
<Wallet />
|
||||
<div>{t('Wallet')}</div>
|
||||
|
|
@ -89,6 +89,7 @@ const SettingsPage = forwardRef(({ index }: { index?: number }, ref) => {
|
|||
</SettingItem>
|
||||
{!!nsec && (
|
||||
<SettingItem
|
||||
className="clickable"
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(nsec)
|
||||
setCopiedNsec(true)
|
||||
|
|
@ -104,6 +105,7 @@ const SettingsPage = forwardRef(({ index }: { index?: number }, ref) => {
|
|||
)}
|
||||
{!!ncryptsec && (
|
||||
<SettingItem
|
||||
className="clickable"
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(ncryptsec)
|
||||
setCopiedNcryptsec(true)
|
||||
|
|
@ -118,7 +120,7 @@ const SettingsPage = forwardRef(({ index }: { index?: number }, ref) => {
|
|||
</SettingItem>
|
||||
)}
|
||||
<AboutInfoDialog>
|
||||
<SettingItem>
|
||||
<SettingItem className="clickable">
|
||||
<div className="flex items-center gap-4">
|
||||
<Info />
|
||||
<div>{t('About')}</div>
|
||||
|
|
@ -145,7 +147,7 @@ const SettingItem = forwardRef<HTMLDivElement, HTMLProps<HTMLDivElement>>(
|
|||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'flex clickable justify-between items-center px-4 py-2 h-[52px] rounded-lg [&_svg]:size-4 [&_svg]:shrink-0',
|
||||
'flex justify-between select-none items-center px-4 py-2 h-[52px] rounded-lg [&_svg]:size-4 [&_svg]:shrink-0',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue