mirror of
https://github.com/hzrd149/nostrudel.git
synced 2025-10-10 21:03:39 +02:00
105 lines
3.1 KiB
TypeScript
105 lines
3.1 KiB
TypeScript
import { forwardRef, useState } from "react";
|
|
import {
|
|
Button,
|
|
Flex,
|
|
IconButton,
|
|
Input,
|
|
InputGroup,
|
|
InputLeftElement,
|
|
InputProps,
|
|
InputRightElement,
|
|
Modal,
|
|
ModalBody,
|
|
ModalCloseButton,
|
|
ModalContent,
|
|
ModalHeader,
|
|
ModalOverlay,
|
|
ModalProps,
|
|
useDisclosure,
|
|
} from "@chakra-ui/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 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) => (
|
|
<Button
|
|
value={url}
|
|
onClick={() => {
|
|
onSelect(url);
|
|
onClose();
|
|
}}
|
|
variant="outline"
|
|
size="sm"
|
|
>
|
|
{url}
|
|
</Button>
|
|
))}
|
|
</Flex>
|
|
</ModalBody>
|
|
</ModalContent>
|
|
</Modal>
|
|
);
|
|
}
|
|
|
|
export type RelayUrlInputProps = Omit<InputProps, "type">;
|
|
|
|
export const RelayUrlInput = forwardRef(
|
|
({ onChange, ...props }: Omit<RelayUrlInputProps, "onChange"> & { onChange: (url: string) => void }, ref) => {
|
|
const { isOpen, onClose, onOpen } = useDisclosure();
|
|
const { value: relaysJson } = useAsync(async () =>
|
|
fetch("https://api.nostr.watch/v1/online").then((res) => res.json() as Promise<string[]>)
|
|
);
|
|
const relaySuggestions = unique(relaysJson ?? []);
|
|
|
|
return (
|
|
<>
|
|
<InputGroup>
|
|
<Input ref={ref} 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" />
|
|
</>
|
|
);
|
|
}
|
|
);
|