mirror of
https://github.com/hzrd149/nostrudel.git
synced 2025-04-10 04:39:19 +02:00
fixes for web of trust
This commit is contained in:
parent
36db83d3d7
commit
fb3fd90224
@ -103,6 +103,7 @@ export default class AccountNotifications {
|
||||
for (const event of sorted) {
|
||||
if (!Object.hasOwn(event, typeSymbol)) continue;
|
||||
if (mutedPubkeys.includes(event.pubkey)) continue;
|
||||
if (event.pubkey === this.pubkey) continue;
|
||||
const e = event as CategorizedEvent;
|
||||
|
||||
switch (e[typeSymbol]) {
|
||||
|
@ -1,8 +1,11 @@
|
||||
import { NostrEvent } from "nostr-tools";
|
||||
import _throttle from "lodash.throttle";
|
||||
import { logger } from "../helpers/debug";
|
||||
|
||||
export class PubkeyGraph {
|
||||
/** the pubkey at the center of it all */
|
||||
root: string;
|
||||
log = logger.extend("PubkeyGraph");
|
||||
|
||||
connections = new Map<string, string[]>();
|
||||
distance = new Map<string, number>();
|
||||
@ -87,6 +90,8 @@ export class PubkeyGraph {
|
||||
return 0;
|
||||
}
|
||||
|
||||
throttleCompute = _throttle(this.compute.bind(this), 5_000, { leading: false });
|
||||
|
||||
changed = new Set<string>();
|
||||
compute() {
|
||||
this.distance.clear();
|
||||
|
@ -14,7 +14,7 @@ import { Emoji, useContextEmojis } from "../providers/global/emoji-provider";
|
||||
import { useUserSearchDirectoryContext } from "../providers/global/user-directory-provider";
|
||||
import UserAvatar from "./user/user-avatar";
|
||||
import UserDnsIdentity from "./user/user-dns-identity";
|
||||
import { getWebOfTrust } from "../services/web-of-trust";
|
||||
import { useWebOfTrust } from "../providers/global/web-of-trust-provider";
|
||||
|
||||
export type PeopleToken = { pubkey: string; names: string[] };
|
||||
type Token = Emoji | PeopleToken;
|
||||
@ -60,6 +60,7 @@ const Loading: ReactTextareaAutocompleteProps<
|
||||
>["loadingComponent"] = ({ data }) => <div>Loading</div>;
|
||||
|
||||
function useAutocompleteTriggers() {
|
||||
const webOfTrust = useWebOfTrust();
|
||||
const emojis = useContextEmojis();
|
||||
const getDirectory = useUserSearchDirectoryContext();
|
||||
|
||||
@ -77,10 +78,12 @@ function useAutocompleteTriggers() {
|
||||
return matchSorter(dir, token.trim(), {
|
||||
keys: ["names"],
|
||||
sorter: (items) =>
|
||||
getWebOfTrust().sortByDistanceAndConnections(
|
||||
items.sort((a, b) => b.rank - a.rank),
|
||||
(i) => i.item.pubkey,
|
||||
),
|
||||
webOfTrust
|
||||
? webOfTrust.sortByDistanceAndConnections(
|
||||
items.sort((a, b) => b.rank - a.rank),
|
||||
(i) => i.item.pubkey,
|
||||
)
|
||||
: items,
|
||||
}).slice(0, 10);
|
||||
},
|
||||
component: Item,
|
||||
|
@ -4,7 +4,6 @@ import { App } from "./app";
|
||||
import { GlobalProviders } from "./providers/global";
|
||||
import "./services/user-event-sync";
|
||||
import "./services/username-search";
|
||||
import "./services/web-of-trust";
|
||||
|
||||
// setup bitcoin connect
|
||||
import { init, onConnected } from "@getalby/bitcoin-connect-react";
|
||||
|
@ -11,6 +11,7 @@ import BreakpointProvider from "./breakpoint-provider";
|
||||
import DecryptionProvider from "./dycryption-provider";
|
||||
import DMTimelineProvider from "./dms-provider";
|
||||
import PublishProvider from "./publish-provider";
|
||||
import WebOfTrustProvider from "./web-of-trust-provider";
|
||||
|
||||
// Top level providers, should be render as close to the root as possible
|
||||
export const GlobalProviders = ({ children }: { children: React.ReactNode }) => {
|
||||
@ -30,7 +31,9 @@ export const GlobalProviders = ({ children }: { children: React.ReactNode }) =>
|
||||
<DMTimelineProvider>
|
||||
<DefaultEmojiProvider>
|
||||
<UserEmojiProvider>
|
||||
<AllUserSearchDirectoryProvider>{children}</AllUserSearchDirectoryProvider>
|
||||
<AllUserSearchDirectoryProvider>
|
||||
<WebOfTrustProvider>{children}</WebOfTrustProvider>
|
||||
</AllUserSearchDirectoryProvider>
|
||||
</UserEmojiProvider>
|
||||
</DefaultEmojiProvider>
|
||||
</DMTimelineProvider>
|
||||
|
77
src/providers/global/web-of-trust-provider.tsx
Normal file
77
src/providers/global/web-of-trust-provider.tsx
Normal file
@ -0,0 +1,77 @@
|
||||
import { PropsWithChildren, createContext, useContext, useEffect, useMemo } from "react";
|
||||
import { NostrEvent, kinds } from "nostr-tools";
|
||||
import _throttle from "lodash.throttle";
|
||||
|
||||
import { getPubkeysFromList } from "../../helpers/nostr/lists";
|
||||
import useCurrentAccount from "../../hooks/use-current-account";
|
||||
import { PubkeyGraph } from "../../classes/pubkey-graph";
|
||||
import replaceableEventsService from "../../services/replaceable-events";
|
||||
import { COMMON_CONTACT_RELAY } from "../../const";
|
||||
|
||||
export function loadSocialGraph(
|
||||
graph: PubkeyGraph,
|
||||
kind: number,
|
||||
pubkey: string,
|
||||
relay?: string,
|
||||
maxLvl = 0,
|
||||
walked: Set<string> = new Set(),
|
||||
) {
|
||||
let newEvents = 0;
|
||||
|
||||
const contacts = replaceableEventsService.requestEvent(
|
||||
relay ? [relay, COMMON_CONTACT_RELAY] : [COMMON_CONTACT_RELAY],
|
||||
kind,
|
||||
pubkey,
|
||||
);
|
||||
|
||||
walked.add(pubkey);
|
||||
|
||||
const handleEvent = (event: NostrEvent) => {
|
||||
graph.handleEvent(event);
|
||||
newEvents++;
|
||||
graph.throttleCompute();
|
||||
|
||||
if (maxLvl > 0) {
|
||||
for (const person of getPubkeysFromList(event)) {
|
||||
if (walked.has(person.pubkey)) continue;
|
||||
|
||||
loadSocialGraph(graph, kind, person.pubkey, person.relay, maxLvl - 1, walked);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (contacts.value) {
|
||||
handleEvent(contacts.value);
|
||||
} else {
|
||||
contacts.once((event) => handleEvent(event));
|
||||
}
|
||||
}
|
||||
|
||||
const WebOfTrustContext = createContext<PubkeyGraph | null>(null);
|
||||
|
||||
export function useWebOfTrust() {
|
||||
return useContext(WebOfTrustContext);
|
||||
}
|
||||
|
||||
export default function WebOfTrustProvider({ pubkey, children }: PropsWithChildren<{ pubkey?: string }>) {
|
||||
const account = useCurrentAccount();
|
||||
if (account && !pubkey) pubkey = account.pubkey;
|
||||
|
||||
const graph = useMemo(() => {
|
||||
return pubkey ? new PubkeyGraph(pubkey) : null;
|
||||
}, [pubkey]);
|
||||
|
||||
// load the graph when it changes
|
||||
useEffect(() => {
|
||||
if (!graph) return;
|
||||
|
||||
if (import.meta.env.DEV) {
|
||||
//@ts-expect-error
|
||||
window.webOfTrust = graph;
|
||||
}
|
||||
|
||||
loadSocialGraph(graph, kinds.Contacts, graph.root, undefined, 1);
|
||||
}, [graph]);
|
||||
|
||||
return <WebOfTrustContext.Provider value={graph}>{children}</WebOfTrustContext.Provider>;
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
import { NostrEvent, kinds } from "nostr-tools";
|
||||
import _throttle from "lodash.throttle";
|
||||
|
||||
import { PubkeyGraph } from "../classes/pubkey-graph";
|
||||
import { COMMON_CONTACT_RELAY } from "../const";
|
||||
import { logger } from "../helpers/debug";
|
||||
import accountService from "./account";
|
||||
import replaceableEventsService from "./replaceable-events";
|
||||
import { getPubkeysFromList } from "../helpers/nostr/lists";
|
||||
|
||||
const log = logger.extend("web-of-trust");
|
||||
let webOfTrust = new PubkeyGraph("");
|
||||
|
||||
let newEvents = 0;
|
||||
const throttleUpdateWebOfTrust = _throttle(() => {
|
||||
log("Computing web-of-trust with", newEvents, "new events");
|
||||
webOfTrust.compute();
|
||||
newEvents = 0;
|
||||
}, 5_000);
|
||||
|
||||
export function loadSocialGraph(
|
||||
web: PubkeyGraph,
|
||||
kind: number,
|
||||
pubkey: string,
|
||||
relay?: string,
|
||||
maxLvl = 0,
|
||||
walked: Set<string> = new Set(),
|
||||
) {
|
||||
const contacts = replaceableEventsService.requestEvent(
|
||||
relay ? [relay, COMMON_CONTACT_RELAY] : [COMMON_CONTACT_RELAY],
|
||||
kind,
|
||||
pubkey,
|
||||
);
|
||||
|
||||
walked.add(pubkey);
|
||||
|
||||
const handleEvent = (event: NostrEvent) => {
|
||||
web.handleEvent(event);
|
||||
newEvents++;
|
||||
throttleUpdateWebOfTrust();
|
||||
|
||||
if (maxLvl > 0) {
|
||||
for (const person of getPubkeysFromList(event)) {
|
||||
if (walked.has(person.pubkey)) continue;
|
||||
|
||||
loadSocialGraph(web, kind, person.pubkey, person.relay, maxLvl - 1, walked);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (contacts.value) {
|
||||
handleEvent(contacts.value);
|
||||
} else {
|
||||
contacts.once((event) => handleEvent(event));
|
||||
}
|
||||
}
|
||||
|
||||
accountService.current.subscribe((account) => {
|
||||
if (!account) return;
|
||||
|
||||
webOfTrust = new PubkeyGraph(account.pubkey);
|
||||
|
||||
if (import.meta.env.DEV) {
|
||||
//@ts-expect-error
|
||||
window.webOfTrust = webOfTrust;
|
||||
}
|
||||
|
||||
loadSocialGraph(webOfTrust, kinds.Contacts, account.pubkey, undefined, 1);
|
||||
});
|
||||
|
||||
export function getWebOfTrust() {
|
||||
return webOfTrust;
|
||||
}
|
@ -10,7 +10,7 @@ import { useUserSearchDirectoryContext } from "../../../providers/global/user-di
|
||||
import UserAvatar from "../../../components/user/user-avatar";
|
||||
import UserName from "../../../components/user/user-name";
|
||||
import KeyboardShortcut from "../../../components/keyboard-shortcut";
|
||||
import { getWebOfTrust } from "../../../services/web-of-trust";
|
||||
import { useWebOfTrust } from "../../../providers/global/web-of-trust-provider";
|
||||
|
||||
function UserOption({ pubkey }: { pubkey: string }) {
|
||||
return (
|
||||
@ -22,6 +22,7 @@ function UserOption({ pubkey }: { pubkey: string }) {
|
||||
}
|
||||
|
||||
export default function SearchForm({ ...props }: Omit<FlexProps, "children">) {
|
||||
const webOfTrust = useWebOfTrust();
|
||||
const getDirectory = useUserSearchDirectoryContext();
|
||||
const navigate = useNavigate();
|
||||
const autoComplete = useDisclosure();
|
||||
@ -32,17 +33,18 @@ export default function SearchForm({ ...props }: Omit<FlexProps, "children">) {
|
||||
const { value: localUsers = [] } = useAsync(async () => {
|
||||
if (queryThrottle.trim().length < 2) return [];
|
||||
|
||||
const webOfTrust = getWebOfTrust();
|
||||
const dir = await getDirectory();
|
||||
return matchSorter(dir, queryThrottle.trim(), {
|
||||
keys: ["names"],
|
||||
sorter: (items) =>
|
||||
webOfTrust.sortByDistanceAndConnections(
|
||||
items.sort((a, b) => b.rank - a.rank),
|
||||
(i) => i.item.pubkey,
|
||||
),
|
||||
webOfTrust
|
||||
? webOfTrust.sortByDistanceAndConnections(
|
||||
items.sort((a, b) => b.rank - a.rank),
|
||||
(i) => i.item.pubkey,
|
||||
)
|
||||
: items,
|
||||
}).slice(0, 10);
|
||||
}, [queryThrottle]);
|
||||
}, [queryThrottle, webOfTrust]);
|
||||
useEffect(() => {
|
||||
if (localUsers.length > 0 && !autoComplete.isOpen) autoComplete.onOpen();
|
||||
}, [localUsers, autoComplete.isOpen]);
|
||||
|
@ -5,16 +5,17 @@ import { UserCard } from "./components/user-card";
|
||||
import { useAdditionalRelayContext } from "../../providers/local/additional-relay-context";
|
||||
import useUserContactList from "../../hooks/use-user-contact-list";
|
||||
import { getPubkeysFromList } from "../../helpers/nostr/lists";
|
||||
import { getWebOfTrust } from "../../services/web-of-trust";
|
||||
import { useWebOfTrust } from "../../providers/global/web-of-trust-provider";
|
||||
|
||||
export default function UserFollowingTab() {
|
||||
const webOfTrust = useWebOfTrust();
|
||||
const { pubkey } = useOutletContext() as { pubkey: string };
|
||||
const contextRelays = useAdditionalRelayContext();
|
||||
|
||||
const contactsList = useUserContactList(pubkey, contextRelays, { alwaysRequest: true });
|
||||
|
||||
const people = contactsList ? getPubkeysFromList(contactsList) : [];
|
||||
const sorted = getWebOfTrust().sortByDistanceAndConnections(people, (p) => p.pubkey);
|
||||
const sorted = webOfTrust ? webOfTrust.sortByDistanceAndConnections(people, (p) => p.pubkey) : people;
|
||||
|
||||
if (!contactsList) return <Spinner />;
|
||||
|
||||
|
@ -22,10 +22,9 @@ import { Link as RouterLink } from "react-router-dom";
|
||||
import { useReadRelays } from "../../../hooks/use-client-relays";
|
||||
import { getPageSummary } from "../../../helpers/nostr/wiki";
|
||||
import UserName from "../../../components/user/user-name";
|
||||
import { getWebOfTrust } from "../../../services/web-of-trust";
|
||||
import { getSharableEventAddress } from "../../../helpers/nip19";
|
||||
import dictionaryService from "../../../services/dictionary";
|
||||
import useSubject from "../../../hooks/use-subject";
|
||||
import { useWebOfTrust } from "../../../providers/global/web-of-trust-provider";
|
||||
|
||||
export default function WikiLink({
|
||||
children,
|
||||
@ -35,6 +34,7 @@ export default function WikiLink({
|
||||
topic,
|
||||
...props
|
||||
}: LinkProps & ExtraProps & { maxVersions?: number; topic?: string }) {
|
||||
const webOfTrust = useWebOfTrust();
|
||||
const { isOpen, onClose, onOpen } = useDisclosure();
|
||||
const readRelays = useReadRelays();
|
||||
|
||||
@ -51,7 +51,10 @@ export default function WikiLink({
|
||||
|
||||
const sorted = useMemo(() => {
|
||||
if (!events) return [];
|
||||
const arr = getWebOfTrust().sortByDistanceAndConnections(Array.from(events.values()), (e) => e.pubkey);
|
||||
|
||||
let arr = Array.from(events.values());
|
||||
if (webOfTrust) arr = webOfTrust.sortByDistanceAndConnections(arr, (e) => e.pubkey);
|
||||
|
||||
const seen = new Set<string>();
|
||||
const unique: NostrEvent[] = [];
|
||||
|
||||
@ -65,15 +68,19 @@ export default function WikiLink({
|
||||
}
|
||||
|
||||
return unique;
|
||||
}, [events]);
|
||||
|
||||
// if there is only one result, redirect to it
|
||||
const to = sorted?.length === 1 ? "/wiki/page/" + getSharableEventAddress(sorted[0]) : "/wiki/topic/" + topic;
|
||||
}, [events, maxVersions, webOfTrust]);
|
||||
|
||||
return (
|
||||
<Popover returnFocusOnClose={false} isOpen={isOpen} onClose={onClose} placement="top" closeOnBlur={true}>
|
||||
<PopoverTrigger>
|
||||
<Link as={RouterLink} color="blue.500" {...props} to={to} onMouseEnter={onOpen} onMouseLeave={onClose}>
|
||||
<Link
|
||||
as={RouterLink}
|
||||
color="blue.500"
|
||||
{...props}
|
||||
to={"/wiki/topic/" + topic}
|
||||
onMouseEnter={onOpen}
|
||||
onMouseLeave={onClose}
|
||||
>
|
||||
{children}
|
||||
</Link>
|
||||
</PopoverTrigger>
|
||||
|
@ -1,35 +1,32 @@
|
||||
import { useMemo, useRef, useState } from "react";
|
||||
import { Button, Flex, FormControl, FormLabel, Heading, Input, VisuallyHidden, useToast } from "@chakra-ui/react";
|
||||
import SimpleMDE, { SimpleMDEReactProps } from "react-simplemde-editor";
|
||||
import {
|
||||
Button,
|
||||
Flex,
|
||||
FormControl,
|
||||
FormHelperText,
|
||||
FormLabel,
|
||||
Heading,
|
||||
Input,
|
||||
Textarea,
|
||||
useToast,
|
||||
} from "@chakra-ui/react";
|
||||
import { useNavigate, useSearchParams } from "react-router-dom";
|
||||
import ReactDOMServer from "react-dom/server";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { EventTemplate } from "nostr-tools";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
import EasyMDE from "easymde";
|
||||
import "easymde/dist/easymde.min.css";
|
||||
|
||||
import { WIKI_RELAYS } from "../../const";
|
||||
import VerticalPageLayout from "../../components/vertical-page-layout";
|
||||
import { removeNonASCIIChar } from "../../helpers/string";
|
||||
import { usePublishEvent } from "../../providers/global/publish-provider";
|
||||
import { WIKI_PAGE_KIND } from "../../helpers/nostr/wiki";
|
||||
import { getSharableEventAddress } from "../../helpers/nip19";
|
||||
import { WIKI_RELAYS } from "../../const";
|
||||
import useAppSettings from "../../hooks/use-app-settings";
|
||||
import { uploadFileToServers } from "../../helpers/media-upload/blossom";
|
||||
import useUsersMediaServers from "../../hooks/use-user-media-servers";
|
||||
import { useSigningContext } from "../../providers/global/signing-provider";
|
||||
import useCurrentAccount from "../../hooks/use-current-account";
|
||||
import useCacheForm from "../../hooks/use-cache-form";
|
||||
import MarkdownEditor from "./components/markdown-editor";
|
||||
|
||||
export default function CreateWikiPageView() {
|
||||
const account = useCurrentAccount();
|
||||
const { mediaUploadService } = useAppSettings();
|
||||
const { servers } = useUsersMediaServers(account?.pubkey);
|
||||
const toast = useToast();
|
||||
const { requestSignature } = useSigningContext();
|
||||
const publish = usePublishEvent();
|
||||
const navigate = useNavigate();
|
||||
const [search] = useSearchParams();
|
||||
@ -37,7 +34,7 @@ export default function CreateWikiPageView() {
|
||||
const presetTitle = search.get("title");
|
||||
|
||||
const { register, setValue, getValues, handleSubmit, watch, formState, reset } = useForm({
|
||||
defaultValues: { content: "", title: presetTitle || presetTopic || "", topic: presetTopic || "" },
|
||||
defaultValues: { content: "", title: presetTitle || presetTopic || "", topic: presetTopic || "", summary: "" },
|
||||
mode: "all",
|
||||
});
|
||||
|
||||
@ -99,6 +96,11 @@ export default function CreateWikiPageView() {
|
||||
<Input {...register("title", { required: true })} autoComplete="off" />
|
||||
</FormControl>
|
||||
</Flex>
|
||||
<FormControl>
|
||||
<FormLabel>Summary</FormLabel>
|
||||
<Textarea {...register("summary", { required: true })} isRequired />
|
||||
<FormHelperText>We'll never share your email.</FormHelperText>
|
||||
</FormControl>
|
||||
<MarkdownEditor value={getValues().content} onChange={(v) => setValue("content", v)} />
|
||||
<Flex gap="2" justifyContent="flex-end">
|
||||
<Button onClick={() => navigate(-1)}>Cancel</Button>
|
||||
|
@ -21,7 +21,6 @@ import VerticalPageLayout from "../../components/vertical-page-layout";
|
||||
import { getPageDefer, getPageForks, getPageTitle, getPageTopic } from "../../helpers/nostr/wiki";
|
||||
import MarkdownContent from "./components/markdown";
|
||||
import UserLink from "../../components/user/user-link";
|
||||
import { getWebOfTrust } from "../../services/web-of-trust";
|
||||
import useSubject from "../../hooks/use-subject";
|
||||
import WikiPageResult from "./components/wiki-page-result";
|
||||
import Timestamp from "../../components/timestamp";
|
||||
@ -38,6 +37,7 @@ import EventVoteButtons from "../../components/reactions/event-vote-buttions";
|
||||
import useCurrentAccount from "../../hooks/use-current-account";
|
||||
import dictionaryService from "../../services/dictionary";
|
||||
import { useReadRelays } from "../../hooks/use-client-relays";
|
||||
import { useWebOfTrust } from "../../providers/global/web-of-trust-provider";
|
||||
|
||||
function ForkAlert({ page, address }: { page: NostrEvent; address: nip19.AddressPointer }) {
|
||||
const topic = getPageTopic(page);
|
||||
@ -91,8 +91,6 @@ export function WikiPagePage({ page }: { page: NostrEvent }) {
|
||||
const topic = getPageTopic(page);
|
||||
|
||||
const readRelays = useReadRelays();
|
||||
const subject = useMemo(() => dictionaryService.requestTopic(topic, readRelays), [topic, readRelays]);
|
||||
const pages = useSubject(subject);
|
||||
const { address } = getPageForks(page);
|
||||
const defer = getPageDefer(page);
|
||||
|
||||
@ -133,24 +131,18 @@ export function WikiPagePage({ page }: { page: NostrEvent }) {
|
||||
}
|
||||
|
||||
function WikiPageFooter({ page }: { page: NostrEvent }) {
|
||||
const webOfTrust = useWebOfTrust();
|
||||
const topic = getPageTopic(page);
|
||||
|
||||
const readRelays = useReadRelays();
|
||||
const subject = useMemo(() => dictionaryService.requestTopic(topic, readRelays), [topic, readRelays]);
|
||||
const pages = useSubject(subject);
|
||||
|
||||
const forks = pages
|
||||
? getWebOfTrust().sortByDistanceAndConnections(
|
||||
Array.from(pages.values()).filter((p) => getPageForks(p).address?.pubkey === page.pubkey),
|
||||
(p) => p.pubkey,
|
||||
)
|
||||
: [];
|
||||
const other = pages
|
||||
? getWebOfTrust().sortByDistanceAndConnections(
|
||||
Array.from(pages.values()).filter((p) => !forks.includes(p) && p.pubkey !== page.pubkey),
|
||||
(p) => p.pubkey,
|
||||
)
|
||||
: [];
|
||||
let forks = pages ? Array.from(pages.values()).filter((p) => getPageForks(p).address?.pubkey === page.pubkey) : [];
|
||||
if (webOfTrust) forks = webOfTrust.sortByDistanceAndConnections(forks, (p) => p.pubkey);
|
||||
|
||||
let other = pages ? Array.from(pages.values()).filter((p) => !forks.includes(p) && p.pubkey !== page.pubkey) : [];
|
||||
if (webOfTrust) other = webOfTrust.sortByDistanceAndConnections(other, (p) => p.pubkey);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
@ -12,11 +12,12 @@ import { subscribeMany } from "../../helpers/relay";
|
||||
import { SEARCH_RELAYS, WIKI_RELAYS } from "../../const";
|
||||
import { WIKI_PAGE_KIND } from "../../helpers/nostr/wiki";
|
||||
import { localRelay } from "../../services/local-relay";
|
||||
import { getWebOfTrust } from "../../services/web-of-trust";
|
||||
import WikiPageResult from "./components/wiki-page-result";
|
||||
import dictionaryService from "../../services/dictionary";
|
||||
import { useWebOfTrust } from "../../providers/global/web-of-trust-provider";
|
||||
|
||||
export default function WikiSearchView() {
|
||||
const webOfTrust = useWebOfTrust();
|
||||
const { value: query, setValue: setQuery } = useRouteSearchValue("q");
|
||||
if (!query) return <Navigate to="/wiki" />;
|
||||
|
||||
@ -53,7 +54,7 @@ export default function WikiSearchView() {
|
||||
}
|
||||
}, [query, setResults]);
|
||||
|
||||
const sorted = getWebOfTrust().sortByDistanceAndConnections(results, (p) => p.pubkey);
|
||||
const sorted = webOfTrust ? webOfTrust.sortByDistanceAndConnections(results, (p) => p.pubkey) : results;
|
||||
|
||||
return (
|
||||
<VerticalPageLayout>
|
||||
|
@ -4,7 +4,6 @@ import { NostrEvent } from "nostr-tools";
|
||||
|
||||
import VerticalPageLayout from "../../components/vertical-page-layout";
|
||||
import useSubject from "../../hooks/use-subject";
|
||||
import { getWebOfTrust } from "../../services/web-of-trust";
|
||||
import { useEffect, useMemo, useState } from "react";
|
||||
import dictionaryService from "../../services/dictionary";
|
||||
import { useReadRelays } from "../../hooks/use-client-relays";
|
||||
@ -12,18 +11,20 @@ import WikiPageHeader from "./components/wiki-page-header";
|
||||
import UserAvatar from "../../components/user/user-avatar";
|
||||
import UserName from "../../components/user/user-name";
|
||||
import { WikiPagePage } from "./page";
|
||||
import { useWebOfTrust } from "../../providers/global/web-of-trust-provider";
|
||||
|
||||
export default function WikiTopicView() {
|
||||
const { topic } = useParams();
|
||||
if (!topic) return <Navigate to="/wiki" />;
|
||||
|
||||
const webOfTrust = useWebOfTrust();
|
||||
const readRelays = useReadRelays();
|
||||
const subject = useMemo(() => dictionaryService.requestTopic(topic, readRelays), [topic, readRelays]);
|
||||
|
||||
const pages = useSubject(subject);
|
||||
const sorted = pages
|
||||
? getWebOfTrust().sortByDistanceAndConnections(Array.from(pages?.values()), (p) => p.pubkey)
|
||||
: [];
|
||||
|
||||
let sorted = pages ? Array.from(pages.values()) : [];
|
||||
if (webOfTrust) sorted = webOfTrust.sortByDistanceAndConnections(sorted, (p) => p.pubkey);
|
||||
|
||||
const [selected, setSelected] = useState<NostrEvent>();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user