diff --git a/src/components/LoginDialog/index.tsx b/src/components/LoginDialog/index.tsx index cd90bc43..a6c4387c 100644 --- a/src/components/LoginDialog/index.tsx +++ b/src/components/LoginDialog/index.tsx @@ -33,7 +33,7 @@ export default function LoginDialog({ return ( - + diff --git a/src/components/RelaySetsSetting/PullFromRelaysButton.tsx b/src/components/RelaySetsSetting/PullFromRelaysButton.tsx index 2b0514f3..27636582 100644 --- a/src/components/RelaySetsSetting/PullFromRelaysButton.tsx +++ b/src/components/RelaySetsSetting/PullFromRelaysButton.tsx @@ -19,6 +19,7 @@ import { BIG_RELAY_URLS } from '@/constants' import { tagNameEquals } from '@/lib/tag' import { isWebsocketUrl, simplifyUrl } from '@/lib/url' import { useNostr } from '@/providers/NostrProvider' +import { useRelaySets } from '@/providers/RelaySetsProvider' import { useScreenSize } from '@/providers/ScreenSizeProvider' import client from '@/services/client.service' import { TRelaySet } from '@/types' @@ -26,7 +27,6 @@ import { CloudDownload } from 'lucide-react' import { kinds } from 'nostr-tools' import { useEffect, useState } from 'react' import RelaySetCard from '../RelaySetCard' -import { useRelaySets } from '@/providers/RelaySetsProvider' export default function PullFromRelaysButton() { const { pubkey } = useNostr() @@ -60,7 +60,7 @@ export default function PullFromRelaysButton() { return ( {trigger} - + Select the relay sets you want to pull diff --git a/src/components/RelaySetsSetting/RelayUrl.tsx b/src/components/RelaySetsSetting/RelayUrl.tsx index 57dd5e2b..62b76973 100644 --- a/src/components/RelaySetsSetting/RelayUrl.tsx +++ b/src/components/RelaySetsSetting/RelayUrl.tsx @@ -2,66 +2,40 @@ import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { useFetchRelayInfos } from '@/hooks' import { isWebsocketUrl, normalizeUrl } from '@/lib/url' -import { useFeed } from '@/providers/FeedProvider' import { useRelaySets } from '@/providers/RelaySetsProvider' -import client from '@/services/client.service' import { CircleX, SearchCheck } from 'lucide-react' -import { useEffect, useMemo, useState } from 'react' +import { useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' export default function RelayUrls({ relaySetId }: { relaySetId: string }) { const { t } = useTranslation() const { relaySets, updateRelaySet } = useRelaySets() - const { activeRelaySetId } = useFeed() const [newRelayUrl, setNewRelayUrl] = useState('') const [newRelayUrlError, setNewRelayUrlError] = useState(null) const relaySet = useMemo( () => relaySets.find((r) => r.id === relaySetId), [relaySets, relaySetId] ) - const [relays, setRelays] = useState< - { - url: string - isConnected: boolean - }[] - >(relaySet?.relayUrls.map((url) => ({ url, isConnected: false })) ?? []) - const isActive = relaySet?.id === activeRelaySetId - - useEffect(() => { - const interval = setInterval(() => { - const connectionStatusMap = client.listConnectionStatus() - setRelays((pre) => { - return pre.map((relay) => { - const isConnected = connectionStatusMap.get(relay.url) || false - return { ...relay, isConnected } - }) - }) - }, 1000) - - return () => clearInterval(interval) - }, []) if (!relaySet) return null const removeRelayUrl = (url: string) => { - setRelays((relays) => relays.filter((relay) => relay.url !== url)) updateRelaySet({ ...relaySet, - relayUrls: relays.map(({ url }) => url).filter((u) => u !== url) + relayUrls: relaySet.relayUrls.filter((u) => u !== url) }) } const saveNewRelayUrl = () => { if (newRelayUrl === '') return const normalizedUrl = normalizeUrl(newRelayUrl) - if (relays.some(({ url }) => url === normalizedUrl)) { + if (relaySet.relayUrls.includes(normalizedUrl)) { return setNewRelayUrlError(t('Relay already exists')) } if (!isWebsocketUrl(normalizedUrl)) { return setNewRelayUrlError(t('invalid relay URL')) } - setRelays((pre) => [...pre, { url: normalizedUrl, isConnected: false }]) - const newRelayUrls = [...relays.map(({ url }) => url), normalizedUrl] + const newRelayUrls = [...relaySet.relayUrls, normalizedUrl] updateRelaySet({ ...relaySet, relayUrls: newRelayUrls }) setNewRelayUrl('') } @@ -81,14 +55,8 @@ export default function RelayUrls({ relaySetId }: { relaySetId: string }) { return ( <>
- {relays.map(({ url, isConnected: isConnected }, index) => ( - removeRelayUrl(url)} - /> + {relaySet.relayUrls.map((url, index) => ( + removeRelayUrl(url)} /> ))}
@@ -107,17 +75,7 @@ export default function RelayUrls({ relaySetId }: { relaySetId: string }) { ) } -function RelayUrl({ - isActive, - url, - isConnected, - onRemove -}: { - isActive: boolean - url: string - isConnected: boolean - onRemove: () => void -}) { +function RelayUrl({ url, onRemove }: { url: string; onRemove: () => void }) { const { t } = useTranslation() const { relayInfos: [relayInfo] @@ -126,13 +84,6 @@ function RelayUrl({ return (
- {!isActive ? ( -
- ) : isConnected ? ( -
- ) : ( -
- )}
{url}
{relayInfo?.supported_nips?.includes(50) && (
diff --git a/src/components/Sidebar/AccountButton.tsx b/src/components/Sidebar/AccountButton.tsx index 2ceea084..b2d63cc0 100644 --- a/src/components/Sidebar/AccountButton.tsx +++ b/src/components/Sidebar/AccountButton.tsx @@ -7,7 +7,7 @@ import { DropdownMenuTrigger } from '@/components/ui/dropdown-menu' import { useFetchProfile } from '@/hooks' -import { toProfile, toSettings } from '@/lib/link' +import { toProfile } from '@/lib/link' import { formatPubkey, generateImageByPubkey } from '@/lib/pubkey' import { useSecondaryPage } from '@/PageManager' import { useNostr } from '@/providers/NostrProvider' @@ -61,7 +61,6 @@ function ProfileButton() { push(toProfile(pubkey))}>{t('Profile')} - push(toSettings())}>{t('Settings')} setLoginDialogOpen(true)}> {t('Switch account')} diff --git a/src/components/Sidebar/PostButton.tsx b/src/components/Sidebar/PostButton.tsx index b829eda8..19dcdf0c 100644 --- a/src/components/Sidebar/PostButton.tsx +++ b/src/components/Sidebar/PostButton.tsx @@ -15,6 +15,8 @@ export default function PostButton() { e.stopPropagation() setOpen(true) }} + variant="default" + className="bg-primary" > diff --git a/src/components/Sidebar/SettingsButton.tsx b/src/components/Sidebar/SettingsButton.tsx new file mode 100644 index 00000000..e373a3a5 --- /dev/null +++ b/src/components/Sidebar/SettingsButton.tsx @@ -0,0 +1,14 @@ +import { toSettings } from '@/lib/link' +import { useSecondaryPage } from '@/PageManager' +import { Settings } from 'lucide-react' +import SidebarItem from './SidebarItem' + +export default function SettingsButton() { + const { push } = useSecondaryPage() + + return ( + push(toSettings())}> + + + ) +} diff --git a/src/components/Sidebar/index.tsx b/src/components/Sidebar/index.tsx index c7df2023..4ed64954 100644 --- a/src/components/Sidebar/index.tsx +++ b/src/components/Sidebar/index.tsx @@ -5,18 +5,20 @@ import HomeButton from './HomeButton' import NotificationsButton from './NotificationButton' import PostButton from './PostButton' import SearchButton from './SearchButton' +import SettingsButton from './SettingsButton' export default function PrimaryPageSidebar() { return (
-
+
+
diff --git a/src/i18n/en.ts b/src/i18n/en.ts index efc2c258..3f5418a4 100644 --- a/src/i18n/en.ts +++ b/src/i18n/en.ts @@ -103,6 +103,7 @@ export default { 'Picture note': 'Picture note', 'A special note for picture-first clients like Olas': 'A special note for picture-first clients like Olas', - 'Picture note requires images': 'Picture note requires images' + 'Picture note requires images': 'Picture note requires images', + Relays: 'Relays' } } diff --git a/src/i18n/zh.ts b/src/i18n/zh.ts index 7bc2da72..36d9228d 100644 --- a/src/i18n/zh.ts +++ b/src/i18n/zh.ts @@ -102,6 +102,7 @@ export default { 'Picture note': '图片笔记', 'A special note for picture-first clients like Olas': '一种可以在图片优先客户端 (如 Olas) 中显示的特殊笔记', - 'Picture note requires images': '图片笔记需要有图片' + 'Picture note requires images': '图片笔记需要有图片', + Relays: '服务器' } } diff --git a/src/pages/primary/MePage/index.tsx b/src/pages/primary/MePage/index.tsx index f881738e..e3ced1e7 100644 --- a/src/pages/primary/MePage/index.tsx +++ b/src/pages/primary/MePage/index.tsx @@ -3,6 +3,7 @@ import LoginDialog from '@/components/LoginDialog' import LogoutDialog from '@/components/LogoutDialog' import PubkeyCopy from '@/components/PubkeyCopy' import QrCodePopover from '@/components/QrCodePopover' +import { Button } from '@/components/ui/button' import { Separator } from '@/components/ui/separator' import { SimpleUserAvatar } from '@/components/UserAvatar' import { SimpleUsername } from '@/components/Username' @@ -24,7 +25,7 @@ export default function MePage() { if (!pubkey) { return ( - + }>
@@ -33,7 +34,7 @@ export default function MePage() { } return ( - + }>
@@ -49,32 +50,22 @@ export default function MePage() {
- - push(toProfile(pubkey))}> - - {t('Profile')} - - - - push(toSettings())}> - - {t('Settings')} - - - - setLoginDialogOpen(true)}> - {t('Switch account')} - - - setLogoutDialogOpen(true)} - hideChevron - > - - {t('Logout')} - - + push(toProfile(pubkey))}> + + {t('Profile')} + + setLoginDialogOpen(true)}> + {t('Switch account')} + + + setLogoutDialogOpen(true)} + hideChevron + > + + {t('Logout')} +
@@ -82,6 +73,17 @@ export default function MePage() { ) } +function MePageTitlebar() { + const { push } = useSecondaryPage() + return ( +
+ +
+ ) +} + function Item({ children, className, @@ -91,7 +93,7 @@ function Item({ return (
) } - -function ItemGroup({ children }: { children: React.ReactNode }) { - return
{children}
-} diff --git a/src/pages/secondary/SettingsPage/index.tsx b/src/pages/secondary/SettingsPage/index.tsx index fdd6cd60..9f2072ad 100644 --- a/src/pages/secondary/SettingsPage/index.tsx +++ b/src/pages/secondary/SettingsPage/index.tsx @@ -1,15 +1,19 @@ import AboutInfoDialog from '@/components/AboutInfoDialog' import { Select, SelectContent, SelectItem, SelectTrigger } from '@/components/ui/select' import SecondaryPageLayout from '@/layouts/SecondaryPageLayout' +import { toRelaySettings } from '@/lib/link' +import { cn } from '@/lib/utils' +import { useSecondaryPage } from '@/PageManager' import { useTheme } from '@/providers/ThemeProvider' import { TLanguage } from '@/types' import { SelectValue } from '@radix-ui/react-select' -import { ChevronRight, Info, Languages, SunMoon } from 'lucide-react' -import { useState } from 'react' +import { ChevronRight, Info, Languages, Server, SunMoon } from 'lucide-react' +import { HTMLProps, useState } from 'react' import { useTranslation } from 'react-i18next' export default function SettingsPage({ index }: { index?: number }) { const { t, i18n } = useTranslation() + const { push } = useSecondaryPage() const [language, setLanguage] = useState(i18n.language as TLanguage) const { themeSetting, setThemeSetting } = useTheme() @@ -20,7 +24,7 @@ export default function SettingsPage({ index }: { index?: number }) { return ( -
+
{t('Languages')}
@@ -34,8 +38,8 @@ export default function SettingsPage({ index }: { index?: number }) { 简体中文 -
-
+ +
{t('Theme')}
@@ -50,9 +54,16 @@ export default function SettingsPage({ index }: { index?: number }) { {t('Dark')} -
+
+ push(toRelaySettings())}> +
+ +
{t('Relays')}
+
+ +
-
+
{t('About')}
@@ -63,8 +74,22 @@ export default function SettingsPage({ index }: { index?: number }) {
-
+
) } + +function Item({ children, className, ...props }: HTMLProps) { + return ( +
+ {children} +
+ ) +}