diff --git a/src/app.tsx b/src/app.tsx
index 29b122683..9dae6c00a 100644
--- a/src/app.tsx
+++ b/src/app.tsx
@@ -106,9 +106,6 @@ const StreamView = lazy(() => import("./views/streams/stream"));
const SearchView = lazy(() => import("./views/search"));
const MapView = lazy(() => import("./views/map"));
-const ThingsView = lazy(() => import("./views/things/index"));
-const ThingUploadView = lazy(() => import("./views/things/upload"));
-
const ChannelsHomeView = lazy(() => import("./views/channels"));
const ChannelView = lazy(() => import("./views/channels/channel"));
@@ -322,13 +319,6 @@ const router = createHashRouter([
{ path: "unknown", element: },
],
},
- {
- path: "things",
- children: [
- { path: "", element: },
- { path: "upload", element: },
- ],
- },
{
path: "lists",
children: [
diff --git a/src/components/debug-modal/event-debug-modal.tsx b/src/components/debug-modal/event-debug-modal.tsx
index 06f394592..5c13bcadb 100644
--- a/src/components/debug-modal/event-debug-modal.tsx
+++ b/src/components/debug-modal/event-debug-modal.tsx
@@ -84,7 +84,7 @@ export default function EventDebugModal({ event, ...props }: { event: NostrEvent
{event.id}
-
+
diff --git a/src/components/event-zap-modal/index.tsx b/src/components/event-zap-modal/index.tsx
index 6cc11413a..aa8322473 100644
--- a/src/components/event-zap-modal/index.tsx
+++ b/src/components/event-zap-modal/index.tsx
@@ -36,7 +36,7 @@ async function getPayRequestForPubkey(
event: NostrEvent | undefined,
amount: number,
comment?: string,
- additionalRelays?: string[],
+ additionalRelays?: Iterable,
): Promise {
const metadata = userMetadataService.getSubject(pubkey).value;
const address = metadata?.lud16 || metadata?.lud06;
@@ -106,7 +106,7 @@ async function getPayRequestsForEvent(
amount: number,
comment?: string,
fallbackPubkey?: string,
- additionalRelays?: string[],
+ additionalRelays?: Iterable,
) {
const splits = getZapSplits(event, fallbackPubkey);
@@ -133,7 +133,7 @@ export type ZapModalProps = Omit & {
allowComment?: boolean;
showEmbed?: boolean;
embedProps?: EmbedProps;
- additionalRelays?: string[];
+ additionalRelays?: Iterable;
onZapped: () => void;
};
diff --git a/src/components/layout/nav-items.tsx b/src/components/layout/nav-items.tsx
index 824974034..a0a043705 100644
--- a/src/components/layout/nav-items.tsx
+++ b/src/components/layout/nav-items.tsx
@@ -58,7 +58,6 @@ export default function NavItems() {
else if (location.pathname.startsWith("/goals")) active = "goals";
else if (location.pathname.startsWith("/badges")) active = "badges";
else if (location.pathname.startsWith("/emojis")) active = "emojis";
- else if (location.pathname.startsWith("/things")) active = "things";
else if (location.pathname.startsWith("/settings")) active = "settings";
else if (location.pathname.startsWith("/tools")) active = "tools";
else if (location.pathname.startsWith("/search")) active = "search";
diff --git a/src/components/magic-textarea.tsx b/src/components/magic-textarea.tsx
index d0ef8dc36..8f108e229 100644
--- a/src/components/magic-textarea.tsx
+++ b/src/components/magic-textarea.tsx
@@ -1,5 +1,6 @@
import React, { LegacyRef, forwardRef } from "react";
-import { Image, InputProps, Textarea, TextareaProps } from "@chakra-ui/react";
+// NOTE: Do not remove Textarea or Input from the imports. they are used
+import { Image, InputProps, Textarea, Input, TextareaProps } from "@chakra-ui/react";
import ReactTextareaAutocomplete, {
ItemComponentProps,
TextareaProps as ReactTextareaAutocompleteProps,
diff --git a/src/components/relay-selection/relay-selection-button.tsx b/src/components/relay-selection/relay-selection-button.tsx
index 91949b9db..233f6d9a4 100644
--- a/src/components/relay-selection/relay-selection-button.tsx
+++ b/src/components/relay-selection/relay-selection-button.tsx
@@ -3,6 +3,7 @@ import { ButtonProps, IconButton, useDisclosure } from "@chakra-ui/react";
import { RelayIcon } from "../icons";
import RelayManagementDrawer from "../relay-management-drawer";
+/** @deprecated */
export default function RelaySelectionButton({ ...props }: ButtonProps) {
const relaysModal = useDisclosure();
return (
diff --git a/src/providers/local/relay-selection-provider.tsx b/src/providers/local/relay-selection-provider.tsx
deleted file mode 100644
index 4e0a11e5f..000000000
--- a/src/providers/local/relay-selection-provider.tsx
+++ /dev/null
@@ -1,61 +0,0 @@
-import { PropsWithChildren, createContext, useCallback, useContext, useMemo } from "react";
-import { useLocation, useNavigate } from "react-router-dom";
-
-import { useReadRelays } from "../../hooks/use-client-relays";
-import { unique } from "../../helpers/array";
-
-type RelaySelectionContextType = {
- relays: string[];
- setSelected: (relays: string[]) => void;
-};
-
-export const RelaySelectionContext = createContext({
- relays: [],
- setSelected: () => {},
-});
-
-export function useRelaySelectionContext() {
- return useContext(RelaySelectionContext);
-}
-export function useRelaySelectionRelays() {
- return useContext(RelaySelectionContext).relays;
-}
-
-export type RelaySelectionProviderProps = PropsWithChildren & {
- overrideDefault?: Iterable;
- additionalDefaults?: Iterable;
-};
-
-export default function RelaySelectionProvider({
- children,
- overrideDefault,
- additionalDefaults,
-}: RelaySelectionProviderProps) {
- const navigate = useNavigate();
- const location = useLocation();
-
- const readRelays = useReadRelays();
- const relays = useMemo(() => {
- if (location.state?.relays) return location.state.relays as string[];
- if (overrideDefault) return Array.from(overrideDefault);
- if (additionalDefaults) return unique([...readRelays, ...additionalDefaults]);
- return readRelays.urls;
- }, [location.state?.relays, overrideDefault, readRelays.urls.join("|"), additionalDefaults]);
-
- const setSelected = useCallback(
- (relays: string[]) => {
- navigate(location.pathname + location.search, { state: { relays }, replace: true });
- },
- [navigate, location],
- );
-
- const context = useMemo(
- () => ({
- relays,
- setSelected,
- }),
- [relays.join("|"), setSelected],
- );
-
- return {children};
-}
diff --git a/src/views/channels/channel.tsx b/src/views/channels/channel.tsx
index f7bd5082d..1c87fc774 100644
--- a/src/views/channels/channel.tsx
+++ b/src/views/channels/channel.tsx
@@ -7,9 +7,7 @@ import useSingleEvent from "../../hooks/use-single-event";
import { ErrorBoundary } from "../../components/error-boundary";
import { NostrEvent } from "../../types/nostr-event";
import useChannelMetadata from "../../hooks/use-channel-metadata";
-import RelaySelectionProvider, { useRelaySelectionContext } from "../../providers/local/relay-selection-provider";
import { ChevronLeftIcon } from "../../components/icons";
-import RelaySelectionButton from "../../components/relay-selection/relay-selection-button";
import ChannelMetadataDrawer from "./components/channel-metadata-drawer";
import ChannelJoinButton from "./components/channel-join-button";
import ChannelMenu from "./components/channel-menu";
@@ -25,6 +23,7 @@ import ChannelMessageBlock from "./components/channel-message-block";
import TimelineActionAndStatus from "../../components/timeline-page/timeline-action-and-status";
import ChannelMessageForm from "./components/send-message-form";
import useParamsEventPointer from "../../hooks/use-params-event-pointer";
+import { useReadRelays } from "../../hooks/use-client-relays";
const ChannelChatLog = memo(({ timeline, channel }: { timeline: TimelineLoader; channel: NostrEvent }) => {
const messages = useSubject(timeline.timeline);
@@ -45,7 +44,7 @@ const ChannelChatLog = memo(({ timeline, channel }: { timeline: TimelineLoader;
function ChannelPage({ channel }: { channel: NostrEvent }) {
const navigate = useNavigate();
- const { relays } = useRelaySelectionContext();
+ const relays = useReadRelays();
const { metadata } = useChannelMetadata(channel.id, relays);
const drawer = useDisclosure();
@@ -76,7 +75,6 @@ function ChannelPage({ channel }: { channel: NostrEvent }) {
} onClick={() => navigate(-1)}>
Back
-
{metadata?.name}
@@ -116,9 +114,7 @@ export default function ChannelView() {
return (
-
-
-
+
);
}
diff --git a/src/views/channels/components/channel-card.tsx b/src/views/channels/components/channel-card.tsx
index c4ef65f1f..fb61a5965 100644
--- a/src/views/channels/components/channel-card.tsx
+++ b/src/views/channels/components/channel-card.tsx
@@ -30,7 +30,7 @@ export default function ChannelCard({
channel,
additionalRelays,
...props
-}: Omit & { channel: NostrEvent; additionalRelays?: string[] }) {
+}: Omit & { channel: NostrEvent; additionalRelays?: Iterable }) {
const readRelays = useReadRelays(additionalRelays);
const { metadata } = useChannelMetadata(channel.id, readRelays);
diff --git a/src/views/channels/components/channel-metadata-drawer.tsx b/src/views/channels/components/channel-metadata-drawer.tsx
index 682ef0052..632d0621e 100644
--- a/src/views/channels/components/channel-metadata-drawer.tsx
+++ b/src/views/channels/components/channel-metadata-drawer.tsx
@@ -25,11 +25,12 @@ import IntersectionObserverProvider from "../../../providers/local/intersection-
import UserLink from "../../../components/user-link";
import HoverLinkOverlay from "../../../components/hover-link-overlay";
import UserAvatar from "../../../components/user-avatar";
-import { useRelaySelectionContext } from "../../../providers/local/relay-selection-provider";
import { UserDnsIdentityIcon } from "../../../components/user-dns-identity-icon";
import ChannelJoinButton from "./channel-join-button";
import { ExternalLinkIcon } from "../../../components/icons";
import { CHANNELS_LIST_KIND } from "../../../helpers/nostr/lists";
+import { useReadRelays } from "../../../hooks/use-client-relays";
+import { useAdditionalRelayContext } from "../../../providers/local/additional-relay-context";
function UserCard({ pubkey }: { pubkey: string }) {
return (
@@ -40,7 +41,7 @@ function UserCard({ pubkey }: { pubkey: string }) {
);
}
-function ChannelMembers({ channel, relays }: { channel: NostrEvent; relays: string[] }) {
+function ChannelMembers({ channel, relays }: { channel: NostrEvent; relays: Iterable }) {
const timeline = useTimelineLoader(`${channel.id}-members`, relays, {
kinds: [CHANNELS_LIST_KIND],
"#e": [channel.id],
@@ -67,7 +68,7 @@ export default function ChannelMetadataDrawer({
...props
}: Omit & { channel: NostrEvent }) {
const { metadata } = useChannelMetadata(channel.id);
- const { relays } = useRelaySelectionContext();
+ const relays = useReadRelays(useAdditionalRelayContext());
return (
diff --git a/src/views/channels/index.tsx b/src/views/channels/index.tsx
index fd98207ad..afbd63635 100644
--- a/src/views/channels/index.tsx
+++ b/src/views/channels/index.tsx
@@ -3,21 +3,20 @@ import { kinds } from "nostr-tools";
import { Flex } from "@chakra-ui/react";
import useTimelineLoader from "../../hooks/use-timeline-loader";
-import RelaySelectionProvider, { useRelaySelectionContext } from "../../providers/local/relay-selection-provider";
import useSubject from "../../hooks/use-subject";
import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";
import VerticalPageLayout from "../../components/vertical-page-layout";
import IntersectionObserverProvider from "../../providers/local/intersection-observer";
import { NostrEvent } from "../../types/nostr-event";
import { ErrorBoundary } from "../../components/error-boundary";
-import RelaySelectionButton from "../../components/relay-selection/relay-selection-button";
import useClientSideMuteFilter from "../../hooks/use-client-side-mute-filter";
import PeopleListProvider, { usePeopleListContext } from "../../providers/local/people-list-provider";
import PeopleListSelection from "../../components/people-list-selection/people-list-selection";
import ChannelCard from "./components/channel-card";
+import { useReadRelays } from "../../hooks/use-client-relays";
function ChannelsHomePage() {
- const { relays } = useRelaySelectionContext();
+ const relays = useReadRelays();
const { filter, listId } = usePeopleListContext();
const clientMuteFilter = useClientSideMuteFilter();
@@ -42,7 +41,6 @@ function ChannelsHomePage() {
-
{channels.map((channel) => (
@@ -57,10 +55,8 @@ function ChannelsHomePage() {
export default function ChannelsHomeView() {
return (
-
-
-
-
-
+
+
+
);
}
diff --git a/src/views/files/index.tsx b/src/views/files/index.tsx
index 91c927085..33d608d56 100644
--- a/src/views/files/index.tsx
+++ b/src/views/files/index.tsx
@@ -10,9 +10,7 @@ import useAppSettings from "../../hooks/use-app-settings";
import { TrustProvider, useTrusted } from "../../providers/local/trust";
import BlurredImage from "../../components/blured-image";
import PeopleListProvider, { usePeopleListContext } from "../../providers/local/people-list-provider";
-import RelaySelectionProvider, { useRelaySelectionContext } from "../../providers/local/relay-selection-provider";
import PeopleListSelection from "../../components/people-list-selection/people-list-selection";
-import RelaySelectionButton from "../../components/relay-selection/relay-selection-button";
import { UserAvatarLink } from "../../components/user-avatar-link";
import UserLink from "../../components/user-link";
import MimeTypePicker from "./mime-type-picker";
@@ -24,6 +22,7 @@ import IntersectionObserverProvider, {
useRegisterIntersectionEntity,
} from "../../providers/local/intersection-observer";
import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";
+import { useReadRelays } from "../../hooks/use-client-relays";
function ImageFile({ event }: { event: NostrEvent }) {
const parsed = parseImageFile(event);
@@ -112,7 +111,7 @@ function FileType({ event }: { event: NostrEvent }) {
function FilesPage() {
const { listId, filter } = usePeopleListContext();
- const { relays } = useRelaySelectionContext();
+ const relays = useReadRelays();
const [selectedTypes, setSelectedTypes] = useState(IMAGE_TYPES);
@@ -131,7 +130,6 @@ function FilesPage() {
setSelectedTypes(v)} />
-
@@ -151,9 +149,7 @@ function FilesPage() {
export default function FilesView() {
return (
-
-
-
+
);
}
diff --git a/src/views/hashtag/index.tsx b/src/views/hashtag/index.tsx
index 9f6287d6c..945cae54b 100644
--- a/src/views/hashtag/index.tsx
+++ b/src/views/hashtag/index.tsx
@@ -18,8 +18,6 @@ import useTimelineLoader from "../../hooks/use-timeline-loader";
import { isReply, isRepost } from "../../helpers/nostr/events";
import { CheckIcon, EditIcon } from "../../components/icons";
import { NostrEvent } from "../../types/nostr-event";
-import RelaySelectionButton from "../../components/relay-selection/relay-selection-button";
-import RelaySelectionProvider, { useRelaySelectionRelays } from "../../providers/local/relay-selection-provider";
import useRelaysChanged from "../../hooks/use-relays-changed";
import TimelinePage, { useTimelinePageEventFilter } from "../../components/timeline-page";
import TimelineViewTypeButtons from "../../components/timeline-page/timeline-view-type";
@@ -28,6 +26,7 @@ import PeopleListProvider, { usePeopleListContext } from "../../providers/local/
import PeopleListSelection from "../../components/people-list-selection/people-list-selection";
import NoteFilterTypeButtons from "../../components/note-filter-type-buttons";
import { useRouteStateBoolean } from "../../hooks/use-route-state-value";
+import { useReadRelays } from "../../hooks/use-client-relays";
function EditableControls() {
const { isEditing, getSubmitButtonProps, getCancelButtonProps, getEditButtonProps } = useEditableControls();
@@ -54,7 +53,7 @@ function HashTagPage() {
const showReplies = useRouteStateBoolean("show-replies", true);
const showReposts = useRouteStateBoolean("show-reposts", true);
- const readRelays = useRelaySelectionRelays();
+ const readRelays = useReadRelays().urls;
const { listId, filter } = usePeopleListContext();
const timelinePageEventFilter = useTimelinePageEventFilter();
@@ -98,7 +97,6 @@ function HashTagPage() {
-
@@ -110,10 +108,8 @@ function HashTagPage() {
export default function HashTagView() {
return (
-
-
-
-
-
+
+
+
);
}
diff --git a/src/views/home/index.tsx b/src/views/home/index.tsx
index 99992dbd7..4a8114132 100644
--- a/src/views/home/index.tsx
+++ b/src/views/home/index.tsx
@@ -1,5 +1,5 @@
-import { useCallback, useEffect, useMemo } from "react";
-import { Flex, useDisclosure } from "@chakra-ui/react";
+import { useCallback, useEffect } from "react";
+import { Flex, Spacer, useDisclosure } from "@chakra-ui/react";
import { kinds } from "nostr-tools";
import { isReply, isRepost } from "../../helpers/nostr/events";
@@ -8,12 +8,11 @@ import { NostrEvent } from "../../types/nostr-event";
import TimelinePage, { useTimelinePageEventFilter } from "../../components/timeline-page";
import TimelineViewTypeButtons from "../../components/timeline-page/timeline-view-type";
import PeopleListSelection from "../../components/people-list-selection/people-list-selection";
-import RelaySelectionButton from "../../components/relay-selection/relay-selection-button";
import PeopleListProvider, { usePeopleListContext } from "../../providers/local/people-list-provider";
-import RelaySelectionProvider, { useRelaySelectionContext } from "../../providers/local/relay-selection-provider";
import useClientSideMuteFilter from "../../hooks/use-client-side-mute-filter";
import NoteFilterTypeButtons from "../../components/note-filter-type-buttons";
import KindSelectionProvider, { useKindSelectionContext } from "../../providers/local/kind-selection-provider";
+import { useReadRelays } from "../../hooks/use-client-relays";
const defaultKinds = [
kinds.ShortTextNote,
@@ -46,7 +45,7 @@ function HomePage() {
[timelinePageEventFilter, showReplies.isOpen, showReposts.isOpen, muteFilter],
);
- const { relays } = useRelaySelectionContext();
+ const relays = useReadRelays();
const { listId, filter } = usePeopleListContext();
const { kinds } = useKindSelectionContext();
@@ -58,7 +57,7 @@ function HomePage() {
-
+
);
@@ -69,11 +68,9 @@ function HomePage() {
export default function HomeView() {
return (
-
-
-
-
-
+
+
+
);
}
diff --git a/src/views/other-stuff/apps.ts b/src/views/other-stuff/apps.ts
index ac2b2756e..134de469d 100644
--- a/src/views/other-stuff/apps.ts
+++ b/src/views/other-stuff/apps.ts
@@ -42,7 +42,6 @@ export const internalApps: App[] = [
{ title: "Lists", description: "Browse and create lists", icon: ListsIcon, id: "lists", to: "/lists" },
{ title: "Tracks", description: "Browse stemstr tracks", icon: TrackIcon, id: "tracks", to: "/tracks" },
{ title: "Videos", description: "Browse flare videos", icon: Film02, id: "videos", to: "/videos" },
- // { title: "Things", icon: ThingsIcon, id: "things", to: "/things" },
];
export const internalTools: App[] = [
diff --git a/src/views/relays/app/index.tsx b/src/views/relays/app/index.tsx
index df9d6d9f5..0c6fb5c32 100644
--- a/src/views/relays/app/index.tsx
+++ b/src/views/relays/app/index.tsx
@@ -1,72 +1,19 @@
import { useMemo } from "react";
-import { Link as RouterLink } from "react-router-dom";
-import { CloseIcon } from "@chakra-ui/icons";
-import { Button, Flex, Heading, IconButton, Link } from "@chakra-ui/react";
+import { Button, Flex, Heading } from "@chakra-ui/react";
import useSubject from "../../../hooks/use-subject";
import { offlineMode } from "../../../services/offline-mode";
import WifiOff from "../../../components/icons/wifi-off";
import Wifi from "../../../components/icons/wifi";
import BackButton from "../../../components/back-button";
import AddRelayForm from "./add-relay-form";
-import relayPoolService from "../../../services/relay-pool";
import clientRelaysService from "../../../services/client-relays";
import { RelayMode } from "../../../classes/relay";
-import { RelayFavicon } from "../../../components/relay-favicon";
-import UploadCloud01 from "../../../components/icons/upload-cloud-01";
import RelaySet from "../../../classes/relay-set";
import { useReadRelays, useWriteRelays } from "../../../hooks/use-client-relays";
import useCurrentAccount from "../../../hooks/use-current-account";
-
-function RelayControl({ url }: { url: string }) {
- const relay = useMemo(() => relayPoolService.requestRelay(url, false), [url]);
- const status = useSubject(relay.status);
- const writeRelays = useSubject(clientRelaysService.writeRelays);
-
- let color = "gray";
- switch (status) {
- case WebSocket.OPEN:
- color = "green";
- break;
- case WebSocket.CONNECTING:
- color = "yellow";
- break;
- case WebSocket.CLOSED:
- color = "red";
- break;
- }
-
- const onChange = () => {
- if (writeRelays.has(url)) clientRelaysService.removeRelay(url, RelayMode.WRITE);
- else clientRelaysService.addRelay(url, RelayMode.WRITE);
- };
-
- return (
-
-
-
- {url}
-
- }
- size="sm"
- variant={writeRelays.has(url) ? "solid" : "ghost"}
- colorScheme={writeRelays.has(url) ? "green" : "gray"}
- onClick={onChange}
- title="Toggle Write"
- />
- }
- size="sm"
- colorScheme="red"
- onClick={() => clientRelaysService.removeRelay(url, RelayMode.ALL)}
- />
-
- );
-}
+import RelayControl from "./relay-control";
+import SelectRelaySet from "./select-relay-set";
export default function AppRelays() {
const account = useCurrentAccount();
@@ -99,6 +46,15 @@ export default function AppRelays() {
clientRelaysService.addRelay(url, RelayMode.ALL);
}}
/>
+
+ {/* {account && (
+ <>
+
+ Use relay set
+
+ set && clientRelaysService.setRelaysFromRelaySet(set)} />
+ >
+ )} */}
);
}
diff --git a/src/views/relays/app/relay-control.tsx b/src/views/relays/app/relay-control.tsx
new file mode 100644
index 000000000..59c5446b7
--- /dev/null
+++ b/src/views/relays/app/relay-control.tsx
@@ -0,0 +1,61 @@
+import { useMemo } from "react";
+import { Link as RouterLink } from "react-router-dom";
+import { CloseIcon } from "@chakra-ui/icons";
+
+import { Flex, IconButton, Link } from "@chakra-ui/react";
+import useSubject from "../../../hooks/use-subject";
+import relayPoolService from "../../../services/relay-pool";
+import clientRelaysService from "../../../services/client-relays";
+import { RelayMode } from "../../../classes/relay";
+import { RelayFavicon } from "../../../components/relay-favicon";
+import UploadCloud01 from "../../../components/icons/upload-cloud-01";
+
+export default function RelayControl({ url }: { url: string }) {
+ const relay = useMemo(() => relayPoolService.requestRelay(url, false), [url]);
+ const status = useSubject(relay.status);
+ const writeRelays = useSubject(clientRelaysService.writeRelays);
+
+ let color = "gray";
+ switch (status) {
+ case WebSocket.OPEN:
+ color = "green";
+ break;
+ case WebSocket.CONNECTING:
+ color = "yellow";
+ break;
+ case WebSocket.CLOSED:
+ color = "red";
+ break;
+ }
+
+ const onChange = () => {
+ if (writeRelays.has(url)) clientRelaysService.removeRelay(url, RelayMode.WRITE);
+ else clientRelaysService.addRelay(url, RelayMode.WRITE);
+ };
+
+ return (
+
+
+
+ {url}
+
+ }
+ size="sm"
+ variant={writeRelays.has(url) ? "solid" : "ghost"}
+ colorScheme={writeRelays.has(url) ? "green" : "gray"}
+ onClick={onChange}
+ title="Toggle Write"
+ />
+ }
+ size="sm"
+ colorScheme="red"
+ onClick={() => clientRelaysService.removeRelay(url, RelayMode.ALL)}
+ />
+
+ );
+}
diff --git a/src/views/relays/app/select-relay-set.tsx b/src/views/relays/app/select-relay-set.tsx
new file mode 100644
index 000000000..c3eb8ebb5
--- /dev/null
+++ b/src/views/relays/app/select-relay-set.tsx
@@ -0,0 +1,41 @@
+import { Select } from "@chakra-ui/react";
+import { NostrEvent } from "nostr-tools";
+
+import useCurrentAccount from "../../../hooks/use-current-account";
+import useUserRelaySets from "../../../hooks/use-user-relay-sets";
+import { getEventCoordinate } from "../../../helpers/nostr/events";
+import { getListName } from "../../../helpers/nostr/lists";
+
+export default function SelectRelaySet({
+ value,
+ onChange,
+ pubkey,
+}: {
+ value?: string;
+ onChange: (cord: string, set?: NostrEvent) => void;
+ pubkey?: string;
+}) {
+ const account = useCurrentAccount();
+ const relaySets = useUserRelaySets(pubkey || account?.pubkey);
+
+ return (
+
+ );
+}
diff --git a/src/views/relays/browse-sets.tsx b/src/views/relays/browse-sets.tsx
index dc9d8d220..2c6903d57 100644
--- a/src/views/relays/browse-sets.tsx
+++ b/src/views/relays/browse-sets.tsx
@@ -4,8 +4,6 @@ import { getEventUID } from "nostr-idb";
import VerticalPageLayout from "../../components/vertical-page-layout";
import PeopleListProvider, { usePeopleListContext } from "../../providers/local/people-list-provider";
-import RelaySelectionProvider, { useRelaySelectionRelays } from "../../providers/local/relay-selection-provider";
-import RelaySelectionButton from "../../components/relay-selection/relay-selection-button";
import PeopleListSelection from "../../components/people-list-selection/people-list-selection";
import useTimelineLoader from "../../hooks/use-timeline-loader";
import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";
@@ -15,6 +13,7 @@ import { NostrEvent } from "../../types/nostr-event";
import { getListName, getRelaysFromList } from "../../helpers/nostr/lists";
import { RelayFavicon } from "../../components/relay-favicon";
import TimelineActionAndStatus from "../../components/timeline-page/timeline-action-and-status";
+import { useReadRelays } from "../../hooks/use-client-relays";
function RelaySetCard({ set }: { set: NostrEvent }) {
const name = getListName(set);
@@ -35,7 +34,7 @@ function RelaySetCard({ set }: { set: NostrEvent }) {
}
function BrowseRelaySetsPage() {
- const relays = useRelaySelectionRelays();
+ const relays = useReadRelays();
const { filter } = usePeopleListContext();
const timeline = useTimelineLoader("relay-sets", relays, filter && { kinds: [kinds.Relaysets], ...filter }, {
eventFilter: (e) => getRelaysFromList(e).length > 0,
@@ -47,7 +46,6 @@ function BrowseRelaySetsPage() {
return (
-
@@ -62,10 +60,8 @@ function BrowseRelaySetsPage() {
export default function BrowseRelaySetsView() {
return (
-
-
-
-
-
+
+
+
);
}
diff --git a/src/views/relays/index.tsx b/src/views/relays/index.tsx
index 7602931af..8f5d3eacc 100644
--- a/src/views/relays/index.tsx
+++ b/src/views/relays/index.tsx
@@ -54,7 +54,7 @@ export default function RelaysView() {
Mailboxes
)}
- {account && (
+ {/* {account && (
<>
Relay Sets
@@ -70,7 +70,7 @@ export default function RelaysView() {
))}
>
- )}
+ )} */}
);
if (vertical) {
diff --git a/src/views/search/article-results.tsx b/src/views/search/article-results.tsx
index 0ae2f4563..1aae780c0 100644
--- a/src/views/search/article-results.tsx
+++ b/src/views/search/article-results.tsx
@@ -1,14 +1,14 @@
import { kinds } from "nostr-tools";
-import { useRelaySelectionRelays } from "../../providers/local/relay-selection-provider";
import useTimelineLoader from "../../hooks/use-timeline-loader";
import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";
import IntersectionObserverProvider from "../../providers/local/intersection-observer";
import GenericNoteTimeline from "../../components/timeline-page/generic-note-timeline";
import { usePeopleListContext } from "../../providers/local/people-list-provider";
+import { useAdditionalRelayContext } from "../../providers/local/additional-relay-context";
export default function ArticleSearchResults({ search }: { search: string }) {
- const searchRelays = useRelaySelectionRelays();
+ const searchRelays = useAdditionalRelayContext();
const { listId, filter } = usePeopleListContext();
const timeline = useTimelineLoader(
diff --git a/src/views/search/community-results.tsx b/src/views/search/community-results.tsx
index b5e1a5bcc..71c2b213a 100644
--- a/src/views/search/community-results.tsx
+++ b/src/views/search/community-results.tsx
@@ -1,16 +1,17 @@
-import { useRelaySelectionRelays } from "../../providers/local/relay-selection-provider";
+import { useRef } from "react";
+
import useTimelineLoader from "../../hooks/use-timeline-loader";
import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";
import IntersectionObserverProvider, {
useRegisterIntersectionEntity,
} from "../../providers/local/intersection-observer";
import { COMMUNITY_DEFINITION_KIND } from "../../helpers/nostr/communities";
-import { useRef } from "react";
import { getEventUID } from "../../helpers/nostr/events";
import { NostrEvent } from "../../types/nostr-event";
import CommunityCard from "../communities/components/community-card";
import useSubject from "../../hooks/use-subject";
import { usePeopleListContext } from "../../providers/local/people-list-provider";
+import { useAdditionalRelayContext } from "../../providers/local/additional-relay-context";
function CommunityResult({ community }: { community: NostrEvent }) {
const ref = useRef(null);
@@ -24,7 +25,7 @@ function CommunityResult({ community }: { community: NostrEvent }) {
}
export default function CommunitySearchResults({ search }: { search: string }) {
- const searchRelays = useRelaySelectionRelays();
+ const searchRelays = useAdditionalRelayContext();
const { listId, filter } = usePeopleListContext();
const timeline = useTimelineLoader(
diff --git a/src/views/search/index.tsx b/src/views/search/index.tsx
index 02bd00399..e10811c4a 100644
--- a/src/views/search/index.tsx
+++ b/src/views/search/index.tsx
@@ -6,7 +6,6 @@ import { SEARCH_RELAYS } from "../../const";
import { safeDecode } from "../../helpers/nip19";
import { getMatchHashtag } from "../../helpers/regexp";
import { CommunityIcon, CopyToClipboardIcon, NotesIcon } from "../../components/icons";
-import RelaySelectionProvider from "../../providers/local/relay-selection-provider";
import VerticalPageLayout from "../../components/vertical-page-layout";
import User01 from "../../components/icons/user-01";
import Feather from "../../components/icons/feather";
@@ -19,6 +18,7 @@ import PeopleListSelection from "../../components/people-list-selection/people-l
import useRouteSearchValue from "../../hooks/use-route-search-value";
import { useBreakpointValue } from "../../providers/global/breakpoint-provider";
import QRCodeScannerButton from "../../components/qr-code-scanner-button";
+import { AdditionalRelayProvider } from "../../providers/local/additional-relay-context";
export function SearchPage() {
const navigate = useNavigate();
@@ -147,10 +147,10 @@ export function SearchPage() {
export default function SearchView() {
return (
-
+
-
+
);
}
diff --git a/src/views/search/note-results.tsx b/src/views/search/note-results.tsx
index 7c654e907..1ff4cf819 100644
--- a/src/views/search/note-results.tsx
+++ b/src/views/search/note-results.tsx
@@ -1,14 +1,14 @@
import { kinds } from "nostr-tools";
-import { useRelaySelectionRelays } from "../../providers/local/relay-selection-provider";
import useTimelineLoader from "../../hooks/use-timeline-loader";
import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";
import IntersectionObserverProvider from "../../providers/local/intersection-observer";
import GenericNoteTimeline from "../../components/timeline-page/generic-note-timeline";
import { usePeopleListContext } from "../../providers/local/people-list-provider";
+import { useAdditionalRelayContext } from "../../providers/local/additional-relay-context";
export default function NoteSearchResults({ search }: { search: string }) {
- const searchRelays = useRelaySelectionRelays();
+ const searchRelays = useAdditionalRelayContext();
const { listId, filter } = usePeopleListContext();
const timeline = useTimelineLoader(
diff --git a/src/views/search/profile-results.tsx b/src/views/search/profile-results.tsx
index e51596671..73c18a7a6 100644
--- a/src/views/search/profile-results.tsx
+++ b/src/views/search/profile-results.tsx
@@ -12,13 +12,13 @@ import { UserDnsIdentityIcon } from "../../components/user-dns-identity-icon";
import { embedNostrLinks, renderGenericUrl } from "../../components/embed-types";
import UserLink from "../../components/user-link";
import trustedUserStatsService, { NostrBandUserStats } from "../../services/trusted-user-stats";
-import { useRelaySelectionRelays } from "../../providers/local/relay-selection-provider";
import useTimelineLoader from "../../hooks/use-timeline-loader";
import useSubject from "../../hooks/use-subject";
import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";
import IntersectionObserverProvider from "../../providers/local/intersection-observer";
import TimelineActionAndStatus from "../../components/timeline-page/timeline-action-and-status";
import { usePeopleListContext } from "../../providers/local/people-list-provider";
+import { useAdditionalRelayContext } from "../../providers/local/additional-relay-context";
function ProfileResult({ profile }: { profile: NostrEvent }) {
const metadata = parseKind0Event(profile);
@@ -51,7 +51,7 @@ function ProfileResult({ profile }: { profile: NostrEvent }) {
}
export default function ProfileSearchResults({ search }: { search: string }) {
- const searchRelays = useRelaySelectionRelays();
+ const searchRelays = useAdditionalRelayContext();
const { listId, filter } = usePeopleListContext();
const timeline = useTimelineLoader(
diff --git a/src/views/streams/components/stream-debug-button.tsx b/src/views/streams/components/stream-debug-button.tsx
deleted file mode 100644
index 8388ddb4c..000000000
--- a/src/views/streams/components/stream-debug-button.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-import {
- Flex,
- IconButton,
- IconButtonProps,
- Modal,
- ModalBody,
- ModalCloseButton,
- ModalContent,
- ModalHeader,
- ModalOverlay,
- useDisclosure,
-} from "@chakra-ui/react";
-import { CodeIcon } from "../../../components/icons";
-import RawValue from "../../../components/debug-modal/raw-value";
-import RawJson from "../../../components/debug-modal/raw-json";
-import { ParsedStream } from "../../../helpers/nostr/stream";
-import useEventNaddr from "../../../hooks/use-event-naddr";
-
-export default function StreamDebugButton({
- stream,
- ...props
-}: { stream: ParsedStream } & Omit) {
- const debugModal = useDisclosure();
- const naddr = useEventNaddr(stream.event);
-
- return (
- <>
- } aria-label="Show raw event" onClick={debugModal.onOpen} {...props} />
-
-
-
-
- Raw event
-
-
-
-
-
-
-
-
-
-
-
- >
- );
-}
diff --git a/src/views/streams/components/stream-zap-button.tsx b/src/views/streams/components/stream-zap-button.tsx
index 926bb1a36..3f391ec7c 100644
--- a/src/views/streams/components/stream-zap-button.tsx
+++ b/src/views/streams/components/stream-zap-button.tsx
@@ -3,8 +3,9 @@ import { ParsedStream } from "../../../helpers/nostr/stream";
import { LightningIcon } from "../../../components/icons";
import useUserLNURLMetadata from "../../../hooks/use-user-lnurl-metadata";
import ZapModal from "../../../components/event-zap-modal";
-import { useRelaySelectionRelays } from "../../../providers/local/relay-selection-provider";
import useStreamGoal from "../../../hooks/use-stream-goal";
+import { useReadRelays } from "../../../hooks/use-client-relays";
+import { useAdditionalRelayContext } from "../../../providers/local/additional-relay-context";
export default function StreamZapButton({
stream,
@@ -19,7 +20,7 @@ export default function StreamZapButton({
}) {
const zapModal = useDisclosure();
const zapMetadata = useUserLNURLMetadata(stream.host);
- const relays = useRelaySelectionRelays();
+ const relays = useReadRelays(useAdditionalRelayContext());
const goal = useStreamGoal(stream);
const commonProps = {
diff --git a/src/views/streams/components/streamer-cards.tsx b/src/views/streams/components/streamer-cards.tsx
index 1835a1761..89e960447 100644
--- a/src/views/streams/components/streamer-cards.tsx
+++ b/src/views/streams/components/streamer-cards.tsx
@@ -2,13 +2,13 @@ import { useMemo } from "react";
import { Card, CardBody, CardHeader, CardProps, Heading, Image, LinkBox, LinkOverlay } from "@chakra-ui/react";
import { useReadRelays } from "../../../hooks/use-client-relays";
-import { useRelaySelectionRelays } from "../../../providers/local/relay-selection-provider";
import replaceableEventLoaderService from "../../../services/replaceable-event-requester";
import useSubject from "../../../hooks/use-subject";
import { NoteContents } from "../../../components/note/text-note-contents";
import { isATag } from "../../../types/nostr-event";
import useReplaceableEvent from "../../../hooks/use-replaceable-event";
import OpenGraphCard from "../../../components/open-graph-card";
+import { useAdditionalRelayContext } from "../../../providers/local/additional-relay-context";
export const STREAMER_CARDS_TYPE = 17777;
export const STREAMER_CARD_TYPE = 37777;
@@ -24,7 +24,7 @@ function useStreamerCardsCords(pubkey: string, relays: Iterable) {
}
function StreamerCard({ cord, relay, ...props }: { cord: string; relay?: string } & CardProps) {
- const contextRelays = useRelaySelectionRelays();
+ const contextRelays = useAdditionalRelayContext();
const readRelays = useReadRelays(relay ? [...contextRelays, relay] : contextRelays);
const card = useReplaceableEvent(cord, readRelays);
@@ -61,7 +61,7 @@ function StreamerCard({ cord, relay, ...props }: { cord: string; relay?: string
}
export default function StreamerCards({ pubkey, ...props }: Omit & { pubkey: string }) {
- const contextRelays = useRelaySelectionRelays();
+ const contextRelays = useAdditionalRelayContext();
const readRelays = useReadRelays(contextRelays);
const cardCords = useStreamerCardsCords(pubkey, readRelays);
diff --git a/src/views/streams/dashboard/index.tsx b/src/views/streams/dashboard/index.tsx
index df1c666a9..343904dad 100644
--- a/src/views/streams/dashboard/index.tsx
+++ b/src/views/streams/dashboard/index.tsx
@@ -15,7 +15,7 @@ import useCurrentAccount from "../../../hooks/use-current-account";
import { getEventUID } from "../../../helpers/nostr/events";
import { useReadRelays } from "../../../hooks/use-client-relays";
import { ChevronLeftIcon } from "../../../components/icons";
-import RelaySelectionProvider from "../../../providers/local/relay-selection-provider";
+import { AdditionalRelayProvider } from "../../../providers/local/additional-relay-context";
import UsersCard from "./users-card";
import ZapsCard from "./zaps-card";
import ChatCard from "./chat-card";
@@ -105,9 +105,9 @@ function StreamModerationPage() {
{selected && (
-
+
-
+
)}
);
diff --git a/src/views/streams/index.tsx b/src/views/streams/index.tsx
index fe58703d7..12d1c8921 100644
--- a/src/views/streams/index.tsx
+++ b/src/views/streams/index.tsx
@@ -1,5 +1,5 @@
import { useCallback, useMemo } from "react";
-import { Divider, Flex, Heading, SimpleGrid, Switch } from "@chakra-ui/react";
+import { Flex, Heading, SimpleGrid, Switch } from "@chakra-ui/react";
import useTimelineLoader from "../../hooks/use-timeline-loader";
import IntersectionObserverProvider from "../../providers/local/intersection-observer";
@@ -7,8 +7,6 @@ import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-
import useSubject from "../../hooks/use-subject";
import StreamCard from "./components/stream-card";
import { STREAM_KIND } from "../../helpers/nostr/stream";
-import RelaySelectionButton from "../../components/relay-selection/relay-selection-button";
-import RelaySelectionProvider, { useRelaySelectionRelays } from "../../providers/local/relay-selection-provider";
import useRelaysChanged from "../../hooks/use-relays-changed";
import PeopleListSelection from "../../components/people-list-selection/people-list-selection";
import PeopleListProvider, { usePeopleListContext } from "../../providers/local/people-list-provider";
@@ -20,10 +18,12 @@ import { NostrEvent } from "../../types/nostr-event";
import VerticalPageLayout from "../../components/vertical-page-layout";
import useClientSideMuteFilter from "../../hooks/use-client-side-mute-filter";
import { useRouteStateBoolean } from "../../hooks/use-route-state-value";
+import { useReadRelays } from "../../hooks/use-client-relays";
+import { AdditionalRelayProvider, useAdditionalRelayContext } from "../../providers/local/additional-relay-context";
function StreamsPage() {
useAppTitle("Streams");
- const relays = useRelaySelectionRelays();
+ const relays = useReadRelays(useAdditionalRelayContext()).urls;
const userMuteFilter = useClientSideMuteFilter();
const showEnded = useRouteStateBoolean("ended", false);
@@ -63,7 +63,6 @@ function StreamsPage() {
Show Ended
-
@@ -93,12 +92,12 @@ function StreamsPage() {
}
export default function StreamsView() {
return (
-
-
+
);
}
diff --git a/src/views/streams/stream/index.tsx b/src/views/streams/stream/index.tsx
index 7dc11ccc6..ba0e75a3f 100644
--- a/src/views/streams/stream/index.tsx
+++ b/src/views/streams/stream/index.tsx
@@ -31,11 +31,8 @@ import StreamSummaryContent from "../components/stream-summary-content";
import { ChevronLeftIcon, ExternalLinkIcon } from "../../../components/icons";
import useSetColorMode from "../../../hooks/use-set-color-mode";
import { CopyIconButton } from "../../../components/copy-icon-button";
-import StreamDebugButton from "../components/stream-debug-button";
import replaceableEventLoaderService from "../../../services/replaceable-event-requester";
import useSubject from "../../../hooks/use-subject";
-import RelaySelectionButton from "../../../components/relay-selection/relay-selection-button";
-import RelaySelectionProvider from "../../../providers/local/relay-selection-provider";
import StreamerCards from "../components/streamer-cards";
import { useAppTitle } from "../../../hooks/use-app-title";
import StreamSatsPerMinute from "../components/stream-sats-per-minute";
@@ -50,6 +47,8 @@ import StreamGoal from "../components/stream-goal";
import StreamShareButton from "../components/stream-share-button";
import VerticalPageLayout from "../../../components/vertical-page-layout";
import { useBreakpointValue } from "../../../providers/global/breakpoint-provider";
+import { AdditionalRelayProvider } from "../../../providers/local/additional-relay-context";
+import DebugEventButton from "../../../components/debug-modal/debug-event-button";
function DesktopStreamPage({ stream }: { stream: ParsedStream }) {
useAppTitle(stream.title);
@@ -96,8 +95,7 @@ function DesktopStreamPage({ stream }: { stream: ParsedStream }) {
-
-
+
@@ -278,10 +276,10 @@ export default function StreamView() {
if (!stream) return ;
return (
// add snort and damus relays so zap.stream will always see zaps
-
+
{displayMode ? : }
-
+
);
}
diff --git a/src/views/streams/stream/stream-chat/stream-chat-form.tsx b/src/views/streams/stream/stream-chat/stream-chat-form.tsx
index 29e41c55a..3b195c21d 100644
--- a/src/views/streams/stream/stream-chat/stream-chat-form.tsx
+++ b/src/views/streams/stream/stream-chat/stream-chat-form.tsx
@@ -3,7 +3,6 @@ import { Box, Button, Flex, useToast } from "@chakra-ui/react";
import { useForm } from "react-hook-form";
import { ParsedStream, buildChatMessage } from "../../../../helpers/nostr/stream";
-import { useRelaySelectionRelays } from "../../../../providers/local/relay-selection-provider";
import { unique } from "../../../../helpers/array";
import { useSigningContext } from "../../../../providers/global/signing-provider";
import { createEmojiTags, ensureNotifyContentMentions } from "../../../../helpers/nostr/post";
@@ -13,12 +12,14 @@ import StreamZapButton from "../../components/stream-zap-button";
import { nostrBuildUploadImage } from "../../../../helpers/nostr-build";
import { useUserInbox } from "../../../../hooks/use-user-mailboxes";
import { usePublishEvent } from "../../../../providers/global/publish-provider";
+import { useReadRelays } from "../../../../hooks/use-client-relays";
+import { useAdditionalRelayContext } from "../../../../providers/local/additional-relay-context";
export default function ChatMessageForm({ stream, hideZapButton }: { stream: ParsedStream; hideZapButton?: boolean }) {
const toast = useToast();
const publish = usePublishEvent();
const emojis = useContextEmojis();
- const streamRelays = useRelaySelectionRelays();
+ const streamRelays = useReadRelays(useAdditionalRelayContext());
const hostReadRelays = useUserInbox(stream.host);
const relays = useMemo(() => unique([...streamRelays, ...hostReadRelays]), [hostReadRelays, streamRelays]);
diff --git a/src/views/streams/stream/stream-chat/use-stream-chat-timeline.ts b/src/views/streams/stream/stream-chat/use-stream-chat-timeline.ts
index 420f18a1f..80e5ef974 100644
--- a/src/views/streams/stream/stream-chat/use-stream-chat-timeline.ts
+++ b/src/views/streams/stream/stream-chat/use-stream-chat-timeline.ts
@@ -5,14 +5,15 @@ import { getEventUID } from "../../../../helpers/nostr/events";
import { ParsedStream, STREAM_CHAT_MESSAGE_KIND, getATag } from "../../../../helpers/nostr/stream";
import useTimelineLoader from "../../../../hooks/use-timeline-loader";
import { NostrEvent } from "../../../../types/nostr-event";
-import { useRelaySelectionRelays } from "../../../../providers/local/relay-selection-provider";
import useStreamGoal from "../../../../hooks/use-stream-goal";
import { NostrQuery } from "../../../../types/nostr-query";
import useUserMuteFilter from "../../../../hooks/use-user-mute-filter";
import useClientSideMuteFilter from "../../../../hooks/use-client-side-mute-filter";
+import { useReadRelays } from "../../../../hooks/use-client-relays";
+import { useAdditionalRelayContext } from "../../../../providers/local/additional-relay-context";
export default function useStreamChatTimeline(stream: ParsedStream) {
- const streamRelays = useRelaySelectionRelays();
+ const streamRelays = useReadRelays(useAdditionalRelayContext());
const hostMuteFilter = useUserMuteFilter(stream.host, [], { alwaysRequest: true });
const muteFilter = useClientSideMuteFilter();
diff --git a/src/views/things/index.tsx b/src/views/things/index.tsx
deleted file mode 100644
index 3840acf1e..000000000
--- a/src/views/things/index.tsx
+++ /dev/null
@@ -1,56 +0,0 @@
-import { Button, Flex, SimpleGrid } from "@chakra-ui/react";
-import { Link as RouterLink } from "react-router-dom";
-
-import useTimelineLoader from "../../hooks/use-timeline-loader";
-import useSubject from "../../hooks/use-subject";
-import { FILE_KIND } from "../../helpers/nostr/files";
-import PeopleListProvider, { usePeopleListContext } from "../../providers/local/people-list-provider";
-import RelaySelectionProvider, { useRelaySelectionContext } from "../../providers/local/relay-selection-provider";
-import PeopleListSelection from "../../components/people-list-selection/people-list-selection";
-import RelaySelectionButton from "../../components/relay-selection/relay-selection-button";
-import TimelineActionAndStatus from "../../components/timeline-page/timeline-action-and-status";
-import VerticalPageLayout from "../../components/vertical-page-layout";
-import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";
-import Upload01 from "../../components/icons/upload-01";
-import IntersectionObserverProvider from "../../providers/local/intersection-observer";
-
-function FilesPage() {
- const { listId, filter } = usePeopleListContext();
- const { relays } = useRelaySelectionContext();
-
- const timeline = useTimelineLoader(
- `${listId}-files`,
- relays,
- filter && { kinds: [FILE_KIND], "#m": ["model/stl"], ...filter },
- );
-
- const files = useSubject(timeline.timeline);
- const callback = useTimelineCurserIntersectionCallback(timeline);
-
- return (
-
-
-
-
- } to="/things/upload">
- New Thing
-
-
-
-
-
-
-
-
- );
-}
-
-export default function FilesView() {
- return (
-
-
-
-
-
- );
-}
diff --git a/src/views/things/upload/confirm-step.tsx b/src/views/things/upload/confirm-step.tsx
deleted file mode 100644
index 534dae673..000000000
--- a/src/views/things/upload/confirm-step.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-import { useState } from "react";
-import { Button, ButtonGroup, Flex, Heading, Image, Text } from "@chakra-ui/react";
-
-import useObjectURL from "../../../hooks/use-object-url";
-import BackButton from "../../../components/back-button";
-
-export default function ConfirmStep({
- screenshot,
- name,
- hash,
- summary,
- onConfirm,
-}: {
- screenshot: Blob;
- name: string;
- summary: string;
- hash: string;
- onConfirm: () => Promise;
-}) {
- const [loading, setLoading] = useState(false);
- const objectURL = useObjectURL(screenshot);
-
- const confirm = async () => {
- setLoading(true);
- await onConfirm();
- setLoading(false);
- };
-
- return (
-
-
- {name}
- File Hash: {hash}
- {summary}
-
-
-
-
-
- );
-}
diff --git a/src/views/things/upload/details-step.tsx b/src/views/things/upload/details-step.tsx
deleted file mode 100644
index cfcc898b0..000000000
--- a/src/views/things/upload/details-step.tsx
+++ /dev/null
@@ -1,46 +0,0 @@
-import { Button, ButtonGroup, Flex, FormControl, FormLabel, Input, Textarea } from "@chakra-ui/react";
-import { useForm } from "react-hook-form";
-
-import BackButton from "../../../components/back-button";
-
-type FormValues = {
- name: string;
- summary: string;
-};
-
-export default function DetailsStep({ onSubmit }: { onSubmit: (values: FormValues) => void }) {
- const { register, getValues, setValue, handleSubmit, watch } = useForm({
- defaultValues: {
- name: "",
- summary: "",
- },
- mode: "all",
- });
-
- const submit = handleSubmit(onSubmit);
-
- return (
-
-
- Name
-
-
-
- Summary
-
-
-
-
-
-
-
- );
-}
diff --git a/src/views/things/upload/index.tsx b/src/views/things/upload/index.tsx
deleted file mode 100644
index cb5453608..000000000
--- a/src/views/things/upload/index.tsx
+++ /dev/null
@@ -1,99 +0,0 @@
-import { useState } from "react";
-import {
- Box,
- Step,
- StepIcon,
- StepIndicator,
- StepNumber,
- StepSeparator,
- StepStatus,
- StepTitle,
- Stepper,
-} from "@chakra-ui/react";
-
-import VerticalPageLayout from "../../../components/vertical-page-layout";
-import { useNavigate } from "react-router-dom";
-import useRouteStateValue from "../../../hooks/use-route-state-value";
-import SelectFileStep from "./select-file-step";
-import DetailsStep from "./details-step";
-import PreviewStep from "./preview-step";
-import ConfirmStep from "./confirm-step";
-
-const steps = [{ title: "Select File" }, { title: "Details" }, { title: "Upload" }];
-
-export default function ThingUploadView() {
- const navigate = useNavigate();
-
- const step = useRouteStateValue("step", 0);
-
- const [file, setFile] = useState();
- const [fileURL, setFileURL] = useState();
- const [hash, setHash] = useState();
- const [name, setName] = useState();
- const [summary, setSummary] = useState();
- const [screenshot, setScreenshot] = useState();
-
- const upload = async () => {
- // await publish("Post", draft);
- };
-
- const renderContent = () => {
- switch (step.value) {
- case 0:
- return (
- {
- setFile(values.file);
- if (values.fileURL) setFileURL(values.fileURL);
- setHash(values.hash);
- step.setValue(1, false);
- }}
- />
- );
- case 1:
- return (
- {
- setName(values.name);
- setSummary(values.summary);
- step.setValue(2, false);
- }}
- />
- );
- case 2:
- return (
- {
- setScreenshot(values.screenshot);
- step.setValue(3, false);
- }}
- />
- );
- case 3:
- return ;
- }
- };
-
- return (
-
-
- {steps.map((step, index) => (
-
-
- } incomplete={} active={} />
-
-
-
- {step.title}
- {/* {step.description && {step.description}} */}
-
-
-
-
- ))}
-
- {renderContent()}
-
- );
-}
diff --git a/src/views/things/upload/preview-step.tsx b/src/views/things/upload/preview-step.tsx
deleted file mode 100644
index df441546c..000000000
--- a/src/views/things/upload/preview-step.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-import { useRef } from "react";
-import { Button, ButtonGroup, Flex, useToast } from "@chakra-ui/react";
-
-import STLViewer from "../../../components/stl-viewer";
-import useObjectURL from "../../../hooks/use-object-url";
-import BackButton from "../../../components/back-button";
-
-type FormValues = {
- screenshot: Blob;
-};
-
-function canvasToBlob(canvas: HTMLCanvasElement, type?: string): Promise {
- return new Promise((res, rej) => {
- canvas.toBlob((blob) => {
- if (blob) res(blob);
- else rej(new Error("Failed to get blob"));
- }, type);
- });
-}
-
-export default function PreviewStep({ file, onSubmit }: { file: Blob; onSubmit: (values: FormValues) => void }) {
- const toast = useToast();
-
- const canvasRef = useRef(null);
- const takeScreenshot = async () => {
- if (!canvasRef.current) return;
- try {
- const blob = await canvasToBlob(canvasRef.current, "image/jpeg");
- onSubmit({ screenshot: blob });
- } catch (e) {
- if (e instanceof Error) {
- toast({ description: e.message, status: "error" });
- }
- }
- };
-
- const previewURL = useObjectURL(file);
-
- return (
-
- {previewURL && (
- <>
-
-
-
-
-
- >
- )}
-
- );
-}
diff --git a/src/views/things/upload/select-file-step.tsx b/src/views/things/upload/select-file-step.tsx
deleted file mode 100644
index 16adedc43..000000000
--- a/src/views/things/upload/select-file-step.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-import { ChangeEventHandler, useCallback } from "react";
-import { Button, ButtonGroup, Divider, Flex, FormControl, FormLabel, Heading, Input } from "@chakra-ui/react";
-import { useForm } from "react-hook-form";
-
-import useObjectURL from "../../../hooks/use-object-url";
-import { arrayBufferToHex } from "../../../helpers/array";
-import BackButton from "../../../components/back-button";
-
-type FormValues = {
- file: Blob;
- fileURL?: string;
- hash: string;
-};
-
-// example file https://tonybox.net/objects/keystone/keystone.stl
-
-export default function SelectFileStep({ onSubmit }: { onSubmit: (values: FormValues) => void }) {
- const { register, getValues, setValue, handleSubmit, watch, resetField } = useForm({
- defaultValues: {
- fileURL: "",
- },
- mode: "all",
- });
- watch("file");
- watch("fileURL");
-
- const handleFileChange = useCallback>(
- (e) => {
- const file = e.target.files?.[0];
- if (file) setValue("file", file);
- else resetField("file");
- },
- [setValue, resetField],
- );
-
- const submit = handleSubmit(async (values) => {
- let file: Blob | undefined = values.file;
- if (!file && values.fileURL) file = await fetch(values.fileURL).then((res) => res.blob());
- if (!file) throw new Error("Cant access file");
-
- // get file hash
- const buffer = await file.arrayBuffer();
- const hash = await window.crypto.subtle.digest("SHA-256", buffer);
- onSubmit({ hash: arrayBufferToHex(hash), file, fileURL: values.fileURL });
-
- // const pub = await publish("Post", draft);
- });
-
- const fileObjectURL = useObjectURL(getValues().file);
- const stlURL = fileObjectURL || getValues().fileURL;
- let step = 0;
- if (getValues().file) step = 1;
-
- return (
-
- Upload File
-
-
-
- OR
-
-
- Use Remote File
- str && str.endsWith(".stl"), required: true })}
- placeholder="https://example.com/files/things/cube.stl"
- onChange={handleFileChange}
- autoComplete="off"
- />
-
-
-
-
-
- );
-}
diff --git a/src/views/tools/network-dm-graph.tsx b/src/views/tools/network-dm-graph.tsx
index 82e126380..5b97fb31c 100644
--- a/src/views/tools/network-dm-graph.tsx
+++ b/src/views/tools/network-dm-graph.tsx
@@ -25,18 +25,17 @@ import { useUserMetadata } from "../../hooks/use-user-metadata";
import EventStore from "../../classes/event-store";
import NostrRequest from "../../classes/nostr-request";
import { isPTag } from "../../types/nostr-event";
-import RelaySelectionProvider, { useRelaySelectionContext } from "../../providers/local/relay-selection-provider";
-import RelaySelectionButton from "../../components/relay-selection/relay-selection-button";
import { useDebounce } from "react-use";
import useSubject from "../../hooks/use-subject";
import { ChevronLeftIcon } from "../../components/icons";
+import { useReadRelays } from "../../hooks/use-client-relays";
type NodeType = { id: string; image?: string; name?: string };
function NetworkDMGraphPage() {
const navigate = useNavigate();
const account = useCurrentAccount()!;
- const { relays } = useRelaySelectionContext();
+ const relays = useReadRelays();
const contacts = useUserContactList(account.pubkey);
const contactsPubkeys = useMemo(
@@ -123,7 +122,6 @@ function NetworkDMGraphPage() {
onChange={(e) => setSince(dayjs(e.target.value).unix())}
/>
Showing all direct messages between contacts in the last {dayjs.unix(since).fromNow(true)}
-
@@ -170,9 +168,7 @@ function NetworkDMGraphPage() {
export default function NetworkDMGraphView() {
return (
-
-
-
+
);
}
diff --git a/src/views/torrents/index.tsx b/src/views/torrents/index.tsx
index db2b33cb0..9727e7e47 100644
--- a/src/views/torrents/index.tsx
+++ b/src/views/torrents/index.tsx
@@ -6,9 +6,7 @@ import { bytesToHex } from "@noble/hashes/utils";
import PeopleListSelection from "../../components/people-list-selection/people-list-selection";
import VerticalPageLayout from "../../components/vertical-page-layout";
-import RelaySelectionProvider, { useRelaySelectionContext } from "../../providers/local/relay-selection-provider";
import PeopleListProvider, { usePeopleListContext } from "../../providers/local/people-list-provider";
-import RelaySelectionButton from "../../components/relay-selection/relay-selection-button";
import useTimelineLoader from "../../hooks/use-timeline-loader";
import useClientSideMuteFilter from "../../hooks/use-client-side-mute-filter";
import { NostrEvent } from "../../types/nostr-event";
@@ -23,6 +21,7 @@ import accountService from "../../services/account";
import signingService from "../../services/signing";
import CategorySelect from "./components/category-select";
import useRouteSearchValue from "../../hooks/use-route-search-value";
+import { useReadRelays } from "../../hooks/use-client-relays";
function Warning() {
const navigate = useNavigate();
@@ -60,7 +59,7 @@ function Warning() {
function TorrentsPage() {
const { filter, listId } = usePeopleListContext();
- const { relays } = useRelaySelectionContext();
+ const relays = useReadRelays();
const tagsParam = useRouteSearchValue("tags");
const tags = tagsParam.value?.split(",") ?? [];
@@ -100,7 +99,6 @@ function TorrentsPage() {
{!!account && }
-
@@ -135,10 +133,8 @@ function TorrentsPage() {
export default function TorrentsView() {
return (
-
-
-
-
-
+
+
+
);
}
diff --git a/src/views/tracks/index.tsx b/src/views/tracks/index.tsx
index 5f47d9d31..84f63ef52 100644
--- a/src/views/tracks/index.tsx
+++ b/src/views/tracks/index.tsx
@@ -6,17 +6,18 @@ import { STEMSTR_RELAY, STEMSTR_TRACK_KIND } from "../../helpers/nostr/stemstr";
import useSubject from "../../hooks/use-subject";
import useTimelineLoader from "../../hooks/use-timeline-loader";
import PeopleListProvider, { usePeopleListContext } from "../../providers/local/people-list-provider";
-import RelaySelectionProvider, { useRelaySelectionContext } from "../../providers/local/relay-selection-provider";
import PeopleListSelection from "../../components/people-list-selection/people-list-selection";
import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";
import IntersectionObserverProvider from "../../providers/local/intersection-observer";
import TrackCard from "./components/track-card";
import useClientSideMuteFilter from "../../hooks/use-client-side-mute-filter";
import { NostrEvent } from "../../types/nostr-event";
+import { AdditionalRelayProvider, useAdditionalRelayContext } from "../../providers/local/additional-relay-context";
+import { useReadRelays } from "../../hooks/use-client-relays";
function TracksPage() {
const { listId, filter } = usePeopleListContext();
- const { relays } = useRelaySelectionContext();
+ const relays = useReadRelays(useAdditionalRelayContext());
const clientMuteFilter = useClientSideMuteFilter();
const eventFilter = useCallback(
@@ -50,9 +51,9 @@ function TracksPage() {
export default function TracksView() {
return (
-
+
-
+
);
}
diff --git a/src/views/videos/index.tsx b/src/views/videos/index.tsx
index 9b9766525..027672746 100644
--- a/src/views/videos/index.tsx
+++ b/src/views/videos/index.tsx
@@ -4,9 +4,7 @@ import { Link as RouterLink } from "react-router-dom";
import useTimelineLoader from "../../hooks/use-timeline-loader";
import useSubject from "../../hooks/use-subject";
import PeopleListProvider, { usePeopleListContext } from "../../providers/local/people-list-provider";
-import RelaySelectionProvider, { useRelaySelectionContext } from "../../providers/local/relay-selection-provider";
import PeopleListSelection from "../../components/people-list-selection/people-list-selection";
-import RelaySelectionButton from "../../components/relay-selection/relay-selection-button";
import TimelineActionAndStatus from "../../components/timeline-page/timeline-action-and-status";
import VerticalPageLayout from "../../components/vertical-page-layout";
import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";
@@ -16,10 +14,11 @@ import { FLARE_VIDEO_KIND } from "../../helpers/nostr/flare";
import VideoCard from "./components/video-card";
import { getEventUID } from "../../helpers/nostr/events";
import { ErrorBoundary } from "../../components/error-boundary";
+import { useReadRelays } from "../../hooks/use-client-relays";
function VideosPage() {
const { listId, filter } = usePeopleListContext();
- const { relays } = useRelaySelectionContext();
+ const relays = useReadRelays();
const timeline = useTimelineLoader(`${listId}-videos`, relays, filter && { kinds: [FLARE_VIDEO_KIND], ...filter });
@@ -30,10 +29,6 @@ function VideosPage() {
-
- } to="/things/upload">
- New Thing
-
@@ -53,9 +48,7 @@ function VideosPage() {
export default function VideosView() {
return (
-
-
-
+
);
}