diff --git a/.changeset/slimy-stingrays-behave.md b/.changeset/slimy-stingrays-behave.md new file mode 100644 index 000000000..343cfd938 --- /dev/null +++ b/.changeset/slimy-stingrays-behave.md @@ -0,0 +1,5 @@ +--- +"nostrudel": minor +--- + +Show relay recommendations in timeline diff --git a/src/components/timeline-page/generic-note-timeline/index.tsx b/src/components/timeline-page/generic-note-timeline/index.tsx index 490316e8c..369ece93c 100644 --- a/src/components/timeline-page/generic-note-timeline/index.tsx +++ b/src/components/timeline-page/generic-note-timeline/index.tsx @@ -9,6 +9,8 @@ import { Kind } from "nostr-tools"; import { STREAM_KIND } from "../../../helpers/nostr/stream"; import StreamNote from "./stream-note"; import { ErrorBoundary } from "../../error-boundary"; +import RelayCard from "../../../views/relays/components/relay-card"; +import { safeRelayUrl } from "../../../helpers/url"; const RenderEvent = React.memo(({ event }: { event: NostrEvent }) => { switch (event.kind) { @@ -18,6 +20,9 @@ const RenderEvent = React.memo(({ event }: { event: NostrEvent }) => { return ; case STREAM_KIND: return ; + case 2: + const safeUrl = safeRelayUrl(event.content); + return safeUrl ? : null; default: return Unknown event kind: {event.kind}; } diff --git a/src/views/home/following-tab.tsx b/src/views/home/following-tab.tsx index 401482f5f..b21e7199c 100644 --- a/src/views/home/following-tab.tsx +++ b/src/views/home/following-tab.tsx @@ -1,9 +1,11 @@ +import { useCallback } from "react"; import { Flex, FormControl, FormLabel, Switch } from "@chakra-ui/react"; import { useSearchParams } from "react-router-dom"; +import { Kind } from "nostr-tools"; + import { isReply, truncatedId } from "../../helpers/nostr/event"; import useTimelineLoader from "../../hooks/use-timeline-loader"; import { useUserContacts } from "../../hooks/use-user-contacts"; -import { useCallback } from "react"; import { useReadRelayUrls } from "../../hooks/use-client-relays"; import { useCurrentAccount } from "../../hooks/use-current-account"; import RequireCurrentAccount from "../../providers/require-current-account"; @@ -34,7 +36,7 @@ function FollowingTabBody() { const timeline = useTimelineLoader( `${truncatedId(account.pubkey)}-following`, readRelays, - { authors: following, kinds: [1, 6] }, + { authors: following, kinds: [Kind.Text, Kind.Repost, 2] }, { enabled: following.length > 0, eventFilter } ); diff --git a/src/views/relays/components/relay-card.tsx b/src/views/relays/components/relay-card.tsx index 9cacb30ef..12b46ba41 100644 --- a/src/views/relays/components/relay-card.tsx +++ b/src/views/relays/components/relay-card.tsx @@ -19,11 +19,12 @@ import { ModalOverlay, ModalProps, useDisclosure, + useToast, } from "@chakra-ui/react"; import { Link as RouterLink } from "react-router-dom"; import { useRelayInfo } from "../../../hooks/use-relay-info"; import { RelayFavicon } from "../../../components/relay-favicon"; -import { CodeIcon, ExternalLinkIcon } from "../../../components/icons"; +import { CodeIcon, ExternalLinkIcon, RepostIcon } from "../../../components/icons"; import { UserLink } from "../../../components/user-link"; import { UserAvatar } from "../../../components/user-avatar"; import { useClientRelays, useReadRelayUrls } from "../../../hooks/use-client-relays"; @@ -35,8 +36,12 @@ import useSubject from "../../../hooks/use-subject"; import useTimelineLoader from "../../../hooks/use-timeline-loader"; import RelayReviewNote from "./relay-review-note"; import styled from "@emotion/styled"; -import { PropsWithChildren } from "react"; +import { PropsWithChildren, useCallback } from "react"; import RawJson from "../../../components/debug-modals/raw-json"; +import { DraftNostrEvent } from "../../../types/nostr-event"; +import dayjs from "dayjs"; +import { useSigningContext } from "../../../providers/signing-provider"; +import { nostrPostAction } from "../../../classes/nostr-post-action"; const B = styled.span` font-weight: bold; @@ -116,10 +121,50 @@ export function RelayDebugButton({ url, ...props }: { url: string } & Omit) { + const toast = useToast(); + const { requestSignature } = useSigningContext(); + + const recommendRelay = useCallback(async () => { + try { + const writeRelays = clientRelaysService.getWriteUrls(); + + const draft: DraftNostrEvent = { + kind: 2, + content: relay, + tags: [], + created_at: dayjs().unix(), + }; + + const signed = await requestSignature(draft); + if (!signed) return; + + const post = nostrPostAction(writeRelays, signed); + await post.onComplete; + } catch (e) { + if (e instanceof Error) toast({ description: e.message, status: "error" }); + } + }, []); + + return ( + } + aria-label="Recommend Relay" + title="Recommend Relay" + onClick={recommendRelay} + variant="ghost" + {...props} + /> + ); +} + export default function RelayCard({ url, ...props }: { url: string } & Omit) { return ( <> - + @@ -132,7 +177,8 @@ export default function RelayCard({ url, ...props }: { url: string } & Omit - + + - - + diff --git a/src/views/user/streams.tsx b/src/views/user/streams.tsx index fc0a2f9ee..1041695d6 100644 --- a/src/views/user/streams.tsx +++ b/src/views/user/streams.tsx @@ -33,7 +33,7 @@ export default function UserStreamsTab() { callback={callback}> {streams.map((stream) => ( - + ))}