add relay icons to notes

This commit is contained in:
hzrd149 2023-06-14 15:29:31 -05:00
parent f383903bec
commit 214487eae7
8 changed files with 41 additions and 80 deletions

View File

@ -0,0 +1,5 @@
---
"nostrudel": minor
---
Add relay icons to notes

View File

@ -18,7 +18,7 @@ import { Bech32Prefix, getSharableNoteId, normalizeToBech32 } from "../../helper
import { NostrEvent } from "../../types/nostr-event";
import { MenuIconButton, MenuIconButtonProps } from "../menu-icon-button";
import { ClipboardIcon, CodeIcon, ExternalLinkIcon, LikeIcon, RepostIcon, TrashIcon } from "../icons";
import { ClipboardIcon, CodeIcon, ExternalLinkIcon, LikeIcon, RelayIcon, RepostIcon, TrashIcon } from "../icons";
import NoteReactionsModal from "./note-zaps-modal";
import NoteDebugModal from "../debug-modals/note-debug-modal";
import { useCurrentAccount } from "../../hooks/use-current-account";
@ -28,6 +28,8 @@ import { buildDeleteEvent } from "../../helpers/nostr-event";
import signingService from "../../services/signing";
import { nostrPostAction } from "../../classes/nostr-post-action";
import clientRelaysService from "../../services/client-relays";
import { handleEventFromRelay } from "../../services/event-relays";
import relayPoolService from "../../services/relay-pool";
export const NoteMenu = ({ event, ...props }: { event: NostrEvent } & Omit<MenuIconButtonProps, "children">) => {
const account = useCurrentAccount();
@ -62,6 +64,18 @@ export const NoteMenu = ({ event, ...props }: { event: NostrEvent } & Omit<MenuI
}
}, [event]);
const broadcast = useCallback(() => {
const missingRelays = clientRelaysService.getWriteUrls();
const { results, onComplete } = nostrPostAction(missingRelays, event, 5000);
results.subscribe((result) => {
if (result.status) {
handleEventFromRelay(relayPoolService.requestRelay(result.url, false), event);
}
});
}, []);
return (
<>
<MenuIconButton {...props}>
@ -87,6 +101,9 @@ export const NoteMenu = ({ event, ...props }: { event: NostrEvent } & Omit<MenuI
Delete Note
</MenuItem>
)}
<MenuItem onClick={broadcast} icon={<RelayIcon />}>
Broadcast
</MenuItem>
<MenuItem onClick={infoModal.onOpen} icon={<CodeIcon />}>
View Raw
</MenuItem>

View File

@ -1,76 +1,28 @@
import { memo, useCallback, useState } from "react";
import {
Button,
IconButton,
IconButtonProps,
Popover,
PopoverArrow,
PopoverBody,
PopoverContent,
PopoverTrigger,
Text,
Flex,
PopoverFooter,
} from "@chakra-ui/react";
import { nostrPostAction } from "../../classes/nostr-post-action";
import { getEventRelays, handleEventFromRelay } from "../../services/event-relays";
import { memo } from "react";
import { IconButton, IconButtonProps, Flex, useDisclosure } from "@chakra-ui/react";
import { getEventRelays } from "../../services/event-relays";
import { NostrEvent } from "../../types/nostr-event";
import { RelayIcon, SearchIcon } from "../icons";
import { RelayIcon } from "../icons";
import { RelayFavicon } from "../relay-favicon";
import { useReadRelayUrls, useWriteRelayUrls } from "../../hooks/use-client-relays";
import relayPoolService from "../../services/relay-pool";
import useSubject from "../../hooks/use-subject";
import { useIsMobile } from "../../hooks/use-is-mobile";
export type NoteRelaysProps = Omit<IconButtonProps, "icon" | "aria-label"> & {
event: NostrEvent;
};
export const NoteRelays = memo(({ event, ...props }: NoteRelaysProps) => {
const isMobile = useIsMobile();
const eventRelays = useSubject(getEventRelays(event.id));
const writeRelays = useWriteRelayUrls();
const { isOpen, onOpen } = useDisclosure();
const [broadcasting, setBroadcasting] = useState(false);
const broadcast = useCallback(() => {
const missingRelays = writeRelays.filter((url) => !eventRelays.includes(url));
if (missingRelays.length === 0) {
return;
}
setBroadcasting(true);
const { results, onComplete } = nostrPostAction(missingRelays, event, 5000);
results.subscribe((result) => {
if (result.status) {
handleEventFromRelay(relayPoolService.requestRelay(result.url, false), event);
}
});
onComplete.then(() => setBroadcasting(false));
}, []);
return (
<Popover isLazy>
<PopoverTrigger>
<IconButton title="Note Relays" icon={<RelayIcon />} aria-label="Note Relays" {...props} />
</PopoverTrigger>
<PopoverContent>
<PopoverArrow />
<PopoverBody>
{eventRelays.map((url) => (
<Flex alignItems="center" key={url}>
<RelayFavicon relay={url} size="2xs" mr="2" />
<Text isTruncated>{url}</Text>
</Flex>
))}
</PopoverBody>
<PopoverFooter>
<Flex gap="2">
<Button size="xs" onClick={broadcast} isLoading={broadcasting} leftIcon={<RelayIcon />}>
Broadcast
</Button>
</Flex>
</PopoverFooter>
</PopoverContent>
</Popover>
return isOpen || !isMobile ? (
<Flex alignItems="center" gap="-4">
{eventRelays.map((url) => (
<RelayFavicon key={url} relay={url} size="2xs" title={url} />
))}
</Flex>
) : (
<IconButton icon={<RelayIcon />} size="xs" aria-label="Relays" onClick={onOpen} variant="link" />
);
});

View File

@ -1,4 +1,3 @@
import moment from "moment";
import { createRoot } from "react-dom/client";
import { App } from "./app";
import { Providers } from "./providers";
@ -26,7 +25,3 @@ root.render(
<App />
</Providers>
);
if (import.meta.env.DEV) {
window.moment = moment;
}

View File

@ -10,7 +10,6 @@ import {
useDisclosure,
} from "@chakra-ui/react";
import { useParams, useSearchParams } from "react-router-dom";
import moment from "moment";
import { useAppTitle } from "../../hooks/use-app-title";
import { useReadRelayUrls } from "../../hooks/use-client-relays";
import { useTimelineLoader } from "../../hooks/use-timeline-loader";
@ -38,7 +37,7 @@ export default function HashTagView() {
`${hashtag}-hashtag`,
selectedRelay ? [selectedRelay] : defaultRelays,
{ kinds: [1], "#t": [hashtag] },
{ pageSize: moment.duration(5, "minutes").asSeconds() }
{ pageSize: 60*10 }
);
const timeline = showReplies ? events : events.filter((e) => !isReply(e));

View File

@ -1,5 +1,4 @@
import { Button, Flex, FormControl, FormLabel, Select, Spinner, Switch, useDisclosure } from "@chakra-ui/react";
import moment from "moment";
import { useSearchParams } from "react-router-dom";
import { Note } from "../../components/note";
import { unique } from "../../helpers/array";
@ -26,7 +25,7 @@ export default function GlobalTab() {
`global`,
selectedRelay ? [selectedRelay] : [],
{ kinds: [1] },
{ pageSize: moment.duration(5, "minutes").asSeconds() }
{ pageSize: 60*10 }
);
const timeline = showReplies ? events : events.filter((e) => !isReply(e));

View File

@ -1,5 +1,4 @@
import { Button, Flex, Spinner, Text } from "@chakra-ui/react";
import moment from "moment";
import { useOutletContext } from "react-router-dom";
import { NoteLink } from "../../components/note-link";
import { UserLink } from "../../components/user-link";
@ -46,7 +45,7 @@ export default function UserReportsTab() {
`${truncatedId(pubkey)}-reports`,
contextRelays,
{ authors: [pubkey], kinds: [1984] },
{ pageSize: moment.duration(1, "week").asSeconds() }
{ pageSize: 60 * 60 * 24 * 7 }
);
return (

View File

@ -4934,11 +4934,6 @@ mixme@^0.5.1:
resolved "https://registry.yarnpkg.com/mixme/-/mixme-0.5.9.tgz#a5a58e17354632179ff3ce5b0fc130899c8ba81c"
integrity sha512-VC5fg6ySUscaWUpI4gxCBTQMH2RdUpNrk+MsbpCYtIvf9SBJdiUey4qE7BXviJsJR4nDQxCZ+3yaYNW3guz/Pw==
moment@^2.29.4:
version "2.29.4"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108"
integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==
ms@2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"