added slightly better relay picker

This commit is contained in:
hzrd149 2023-04-11 07:51:04 -05:00
parent b9b81793e4
commit 5976315595
5 changed files with 105 additions and 14 deletions

View File

@ -1,10 +1,95 @@
import { Input, InputProps } from "@chakra-ui/react";
import {
Badge,
Box,
Button,
Flex,
Highlight,
IconButton,
Input,
InputGroup,
InputLeftElement,
InputProps,
InputRightElement,
Modal,
ModalBody,
ModalCloseButton,
ModalContent,
ModalHeader,
ModalOverlay,
ModalProps,
Text,
useDisclosure,
} from "@chakra-ui/react";
import { useState } from "react";
import { useAsync } from "react-use";
import { unique } from "../helpers/array";
import { RelayIcon, SearchIcon } from "./icons";
function RelayPickerModal({
onSelect,
onClose,
...props
}: { onSelect: (relay: string) => void } & Omit<ModalProps, "children">) {
const [search, setSearch] = useState("");
const { value: onlineRelays } = useAsync(async () =>
fetch("https://api.nostr.watch/v1/online").then((res) => res.json() as Promise<string[]>)
);
const { value: paidRelays } = useAsync(async () =>
fetch("https://api.nostr.watch/v1/paid").then((res) => res.json() as Promise<string[]>)
);
const relayList = unique(onlineRelays ?? []);
const filteredRelays = search ? relayList.filter((url) => url.includes(search)) : relayList;
return (
<Modal onClose={onClose} {...props}>
<ModalOverlay />
<ModalContent>
<ModalHeader>Pick Relay</ModalHeader>
<ModalCloseButton />
<ModalBody pt="0" px="4" pb="4">
<InputGroup mb="2">
<InputLeftElement pointerEvents="none" children={<SearchIcon />} />
<Input
type="search"
placeholder="Search"
name="relay-search"
value={search}
onChange={(e) => setSearch(e.target.value)}
/>
</InputGroup>
<Flex gap="2" direction="column">
{filteredRelays.map((url) => (
<Flex gap="2" alignItems="center">
<Button
key={url}
value={url}
onClick={() => {
onSelect(url);
onClose();
}}
variant="outline"
size="sm"
>
{url}
</Button>
{paidRelays?.includes(url) && <Badge colorScheme="green">Paid</Badge>}
</Flex>
))}
</Flex>
</ModalBody>
</ModalContent>
</Modal>
);
}
export type RelayUrlInputProps = Omit<InputProps, "type">;
export const RelayUrlInput = ({ ...props }: RelayUrlInputProps) => {
export const RelayUrlInput = ({
onChange,
...props
}: Omit<RelayUrlInputProps, "onChange"> & { onChange: (url: string) => void }) => {
const { isOpen, onClose, onOpen } = useDisclosure();
const { value: relaysJson } = useAsync(async () =>
fetch("https://api.nostr.watch/v1/online").then((res) => res.json() as Promise<string[]>)
);
@ -12,14 +97,20 @@ export const RelayUrlInput = ({ ...props }: RelayUrlInputProps) => {
return (
<>
<Input list="relay-suggestions" type="url" {...props} />
<datalist id="relay-suggestions">
{relaySuggestions.map((url) => (
<option key={url} value={url}>
{url}
</option>
))}
</datalist>
<InputGroup>
<Input list="relay-suggestions" type="url" onChange={(e) => onChange(e.target.value)} {...props} />
<datalist id="relay-suggestions">
{relaySuggestions.map((url) => (
<option key={url} value={url}>
{url}
</option>
))}
</datalist>
<InputRightElement>
<IconButton icon={<RelayIcon />} aria-label="Pick from list" size="sm" onClick={onOpen} />
</InputRightElement>
</InputGroup>
<RelayPickerModal onClose={onClose} isOpen={isOpen} onSelect={(url) => onChange(url)} size="2xl" />
</>
);
};

View File

@ -121,7 +121,7 @@ export default function LoginNip05View() {
placeholder="wss://nostr.example.com"
isRequired
value={relayUrl}
onChange={(e) => setRelayUrl(e.target.value)}
onChange={(url) => setRelayUrl(url)}
/>
<FormHelperText>The first relay to connect to.</FormHelperText>
</FormControl>

View File

@ -46,7 +46,7 @@ export default function LoginNpubView() {
placeholder="wss://nostr.example.com"
isRequired
value={relayUrl}
onChange={(e) => setRelayUrl(e.target.value)}
onChange={(url) => setRelayUrl(url)}
/>
<FormHelperText>The first relay to connect to.</FormHelperText>
</FormControl>

View File

@ -137,7 +137,7 @@ export default function LoginNsecView() {
placeholder="wss://nostr.example.com"
isRequired
value={relayUrl}
onChange={(e) => setRelayUrl(e.target.value)}
onChange={(url) => setRelayUrl(url)}
/>
<FormHelperText>The first relay to connect to.</FormHelperText>
</FormControl>

View File

@ -134,7 +134,7 @@ export default function RelaysView() {
<RelayUrlInput
id="relay-url-input"
value={relayInputValue}
onChange={(e) => setRelayInputValue(e.target.value)}
onChange={(url) => setRelayInputValue(url)}
isRequired
/>
<Button type="submit" isDisabled={saving}>