mirror of
https://github.com/hzrd149/nostrudel.git
synced 2025-09-20 13:01:07 +02:00
update wasm relay
fix dm timelines not closing add summary to wiki edit page
This commit is contained in:
@@ -37,7 +37,7 @@
|
||||
"@noble/hashes": "^1.3.2",
|
||||
"@noble/secp256k1": "^1.7.0",
|
||||
"@scure/base": "^1.1.6",
|
||||
"@snort/worker-relay": "^1.0.10",
|
||||
"@snort/worker-relay": "^1.1.0",
|
||||
"@uiw/codemirror-theme-github": "^4.21.21",
|
||||
"@uiw/react-codemirror": "^4.21.21",
|
||||
"@webscopeio/react-textarea-autocomplete": "^4.9.2",
|
||||
|
@@ -1,12 +1,12 @@
|
||||
import dayjs from "dayjs";
|
||||
import { NostrEvent, isPTag } from "../../types/nostr-event";
|
||||
import { NostrEvent } from "nostr-tools";
|
||||
import { sortByDate } from "./event";
|
||||
|
||||
export function getDMSender(event: NostrEvent) {
|
||||
return event.pubkey;
|
||||
}
|
||||
export function getDMRecipient(event: NostrEvent) {
|
||||
const pubkey = event.tags.find(isPTag)?.[1];
|
||||
const pubkey = event.tags.find((t) => t[0] === "p")?.[1];
|
||||
if (!pubkey) throw new Error("Missing recipient pubkey");
|
||||
return pubkey;
|
||||
}
|
||||
@@ -47,8 +47,8 @@ export function hasResponded(conversion: KnownConversation) {
|
||||
const latestReceived = conversion.messages.find((m) => getDMSender(m) === conversion.correspondent);
|
||||
const latestSent = conversion.messages.find((m) => getDMSender(m) === conversion.myself);
|
||||
|
||||
if (latestReceived && latestSent && latestSent.created_at > latestReceived.created_at) return false;
|
||||
return true;
|
||||
if (latestReceived && latestSent && latestSent.created_at > latestReceived.created_at) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
export function sortConversationsByLastReceived(conversations: KnownConversation[]) {
|
||||
|
@@ -299,6 +299,7 @@ export function ensureDTag(draft: DraftNostrEvent, d: string = nanoid()) {
|
||||
}
|
||||
}
|
||||
|
||||
/** either replaces the existing tag or adds a new one */
|
||||
export function replaceOrAddSimpleTag(draft: DraftNostrEvent, tagName: string, value: string) {
|
||||
if (draft.tags.some((t) => t[0] === tagName)) {
|
||||
draft.tags = draft.tags.map((t) => (t[0] === tagName ? [tagName, value] : t));
|
||||
|
@@ -1,5 +1,5 @@
|
||||
import { useEffect, useMemo } from "react";
|
||||
import { useUnmount } from "react-use";
|
||||
import { usePrevious, useUnmount } from "react-use";
|
||||
import { Filter, NostrEvent } from "nostr-tools";
|
||||
|
||||
import timelineCacheService from "../services/timeline-cache";
|
||||
@@ -21,11 +21,13 @@ export default function useTimelineLoader(
|
||||
) {
|
||||
const timeline = useMemo(() => timelineCacheService.createTimeline(key), [key]);
|
||||
|
||||
// update relays
|
||||
useEffect(() => {
|
||||
timeline.setRelays(relays);
|
||||
timeline.triggerChunkLoad();
|
||||
}, [Array.from(relays).join("|")]);
|
||||
|
||||
// update filters
|
||||
useEffect(() => {
|
||||
if (filters) {
|
||||
timeline.setFilters(Array.isArray(filters) ? filters : [filters]);
|
||||
@@ -34,18 +36,33 @@ export default function useTimelineLoader(
|
||||
} else timeline.close();
|
||||
}, [timeline, JSON.stringify(filters)]);
|
||||
|
||||
// update event filter
|
||||
useEffect(() => {
|
||||
timeline.setEventFilter(opts?.eventFilter);
|
||||
}, [timeline, opts?.eventFilter]);
|
||||
|
||||
// update cursor
|
||||
// NOTE: I don't think this is used anywhere and should be removed
|
||||
useEffect(() => {
|
||||
if (opts?.cursor !== undefined) {
|
||||
timeline.setCursor(opts.cursor);
|
||||
}
|
||||
}, [timeline, opts?.cursor]);
|
||||
|
||||
// update custom sort
|
||||
useEffect(() => {
|
||||
timeline.events.customSort = opts?.customSort;
|
||||
}, [timeline, opts?.customSort]);
|
||||
|
||||
// close the old timeline when the key changes
|
||||
const oldTimeline = usePrevious(timeline);
|
||||
useEffect(() => {
|
||||
if (oldTimeline && oldTimeline !== timeline) {
|
||||
oldTimeline.close();
|
||||
}
|
||||
}, [timeline, oldTimeline]);
|
||||
|
||||
// stop the loader when unmount
|
||||
useUnmount(() => {
|
||||
timeline.close();
|
||||
});
|
||||
|
@@ -8,7 +8,7 @@ import NotificationsProvider from "./notifications-provider";
|
||||
import { DefaultEmojiProvider, UserEmojiProvider } from "./emoji-provider";
|
||||
import { AllUserSearchDirectoryProvider } from "./user-directory-provider";
|
||||
import BreakpointProvider from "./breakpoint-provider";
|
||||
import DecryptionProvider from "./dycryption-provider";
|
||||
import DecryptionProvider from "./decryption-provider";
|
||||
import DMTimelineProvider from "./dms-provider";
|
||||
import PublishProvider from "./publish-provider";
|
||||
import WebOfTrustProvider from "./web-of-trust-provider";
|
||||
|
@@ -27,7 +27,7 @@ class DictionaryService {
|
||||
});
|
||||
|
||||
constructor() {
|
||||
this.process = new Process("EventReactionsService", this);
|
||||
this.process = new Process("DictionaryService", this);
|
||||
this.process.icon = BookOpen01;
|
||||
this.process.active = true;
|
||||
|
||||
|
@@ -14,7 +14,7 @@ import IntersectionObserverProvider from "../../providers/local/intersection-obs
|
||||
import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";
|
||||
import TimelineActionAndStatus from "../../components/timeline-page/timeline-action-and-status";
|
||||
import UserDnsIdentity from "../../components/user/user-dns-identity";
|
||||
import { useDecryptionContext } from "../../providers/global/dycryption-provider";
|
||||
import { useDecryptionContext } from "../../providers/global/decryption-provider";
|
||||
import SendMessageForm from "./components/send-message-form";
|
||||
import { groupMessages } from "../../helpers/nostr/dms";
|
||||
import ThreadDrawer from "./components/thread-drawer";
|
||||
|
@@ -2,7 +2,7 @@ import { useEffect, useState } from "react";
|
||||
import { Alert, AlertDescription, AlertIcon, Button, ButtonProps } from "@chakra-ui/react";
|
||||
|
||||
import { UnlockIcon } from "../../../components/icons";
|
||||
import { useDecryptionContainer } from "../../../providers/global/dycryption-provider";
|
||||
import { useDecryptionContainer } from "../../../providers/global/decryption-provider";
|
||||
import useCurrentAccount from "../../../hooks/use-current-account";
|
||||
import { getDMRecipient, getDMSender } from "../../../helpers/nostr/dms";
|
||||
import { NostrEvent } from "../../../types/nostr-event";
|
||||
|
@@ -8,7 +8,7 @@ import { useSigningContext } from "../../../providers/global/signing-provider";
|
||||
import MagicTextArea, { RefType } from "../../../components/magic-textarea";
|
||||
import { useTextAreaUploadFileWithForm } from "../../../hooks/use-textarea-upload-file";
|
||||
import { DraftNostrEvent } from "../../../types/nostr-event";
|
||||
import { useDecryptionContext } from "../../../providers/global/dycryption-provider";
|
||||
import { useDecryptionContext } from "../../../providers/global/decryption-provider";
|
||||
import useUserMailboxes from "../../../hooks/use-user-mailboxes";
|
||||
import { usePublishEvent } from "../../../providers/global/publish-provider";
|
||||
|
||||
|
@@ -27,7 +27,7 @@ import { Thread, useThreadsContext } from "../../../providers/local/thread-provi
|
||||
import ThreadButton from "./thread-button";
|
||||
import SendMessageForm from "./send-message-form";
|
||||
import { groupMessages } from "../../../helpers/nostr/dms";
|
||||
import { useDecryptionContext } from "../../../providers/global/dycryption-provider";
|
||||
import { useDecryptionContext } from "../../../providers/global/decryption-provider";
|
||||
import DirectMessageBlock from "./direct-message-block";
|
||||
|
||||
function MessagePreview({ message, ...props }: { message: NostrEvent } & Omit<TextProps, "children">) {
|
||||
|
@@ -18,7 +18,7 @@ import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-
|
||||
import TimelineActionAndStatus from "../../components/timeline-page/timeline-action-and-status";
|
||||
import { useDMTimeline } from "../../providers/global/dms-provider";
|
||||
import UserName from "../../components/user/user-name";
|
||||
import { useDecryptionContainer } from "../../providers/global/dycryption-provider";
|
||||
import { useDecryptionContainer } from "../../providers/global/decryption-provider";
|
||||
import { NostrEvent } from "../../types/nostr-event";
|
||||
import { CheckIcon } from "../../components/icons";
|
||||
import UserDnsIdentity from "../../components/user/user-dns-identity";
|
||||
|
@@ -19,7 +19,7 @@ import HoverLinkOverlay from "../../../components/hover-link-overlay";
|
||||
import UserName from "../../../components/user/user-name";
|
||||
import UserDnsIdentity from "../../../components/user/user-dns-identity";
|
||||
import { nip19 } from "nostr-tools";
|
||||
import { useDecryptionContainer, useDecryptionContext } from "../../../providers/global/dycryption-provider";
|
||||
import { useDecryptionContainer, useDecryptionContext } from "../../../providers/global/decryption-provider";
|
||||
import Timestamp from "../../../components/timestamp";
|
||||
|
||||
function MessagePreview({ message, pubkey }: { message: NostrEvent; pubkey: string }) {
|
||||
|
@@ -99,7 +99,7 @@ export default function CreateWikiPageView() {
|
||||
<FormControl>
|
||||
<FormLabel>Summary</FormLabel>
|
||||
<Textarea {...register("summary", { required: true })} isRequired />
|
||||
<FormHelperText>We'll never share your email.</FormHelperText>
|
||||
<FormHelperText>A short summary of the page</FormHelperText>
|
||||
</FormControl>
|
||||
<MarkdownEditor value={getValues().content} onChange={(v) => setValue("content", v)} />
|
||||
<Flex gap="2" justifyContent="flex-end">
|
||||
|
@@ -1,4 +1,15 @@
|
||||
import { Button, Flex, FormControl, FormLabel, Heading, Input, Spinner, useToast } from "@chakra-ui/react";
|
||||
import {
|
||||
Button,
|
||||
Flex,
|
||||
FormControl,
|
||||
FormHelperText,
|
||||
FormLabel,
|
||||
Heading,
|
||||
Input,
|
||||
Spinner,
|
||||
Textarea,
|
||||
useToast,
|
||||
} from "@chakra-ui/react";
|
||||
import { Navigate, useNavigate, useParams } from "react-router-dom";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { NostrEvent } from "nostr-tools";
|
||||
@@ -7,13 +18,13 @@ import { WIKI_RELAYS } from "../../const";
|
||||
import useCacheForm from "../../hooks/use-cache-form";
|
||||
import useReplaceableEvent from "../../hooks/use-replaceable-event";
|
||||
import useCurrentAccount from "../../hooks/use-current-account";
|
||||
import { WIKI_PAGE_KIND, getPageTitle, getPageTopic } from "../../helpers/nostr/wiki";
|
||||
import { WIKI_PAGE_KIND, getPageSummary, getPageTitle, getPageTopic } from "../../helpers/nostr/wiki";
|
||||
import { getSharableEventAddress } from "../../helpers/nip19";
|
||||
import { usePublishEvent } from "../../providers/global/publish-provider";
|
||||
import VerticalPageLayout from "../../components/vertical-page-layout";
|
||||
import MarkdownEditor from "./components/markdown-editor";
|
||||
import { ErrorBoundary } from "../../components/error-boundary";
|
||||
import { cloneEvent } from "../../helpers/nostr/event";
|
||||
import { cloneEvent, replaceOrAddSimpleTag } from "../../helpers/nostr/event";
|
||||
|
||||
function EditWikiPagePage({ page }: { page: NostrEvent }) {
|
||||
const toast = useToast();
|
||||
@@ -23,7 +34,7 @@ function EditWikiPagePage({ page }: { page: NostrEvent }) {
|
||||
const topic = getPageTopic(page);
|
||||
|
||||
const { register, setValue, getValues, handleSubmit, watch, formState, reset } = useForm({
|
||||
defaultValues: { content: page.content, title: getPageTitle(page) ?? topic },
|
||||
defaultValues: { content: page.content, title: getPageTitle(page) ?? topic, summary: getPageSummary(page) },
|
||||
mode: "all",
|
||||
});
|
||||
|
||||
@@ -45,6 +56,7 @@ function EditWikiPagePage({ page }: { page: NostrEvent }) {
|
||||
try {
|
||||
const draft = cloneEvent(WIKI_PAGE_KIND, page);
|
||||
draft.content = values.content;
|
||||
replaceOrAddSimpleTag(draft, "summary", values.summary);
|
||||
|
||||
const pub = await publish("Publish Page", draft, WIKI_RELAYS, false);
|
||||
clearFormCache();
|
||||
@@ -67,6 +79,11 @@ function EditWikiPagePage({ page }: { page: NostrEvent }) {
|
||||
<Input {...register("title", { required: true })} autoComplete="off" />
|
||||
</FormControl>
|
||||
</Flex>
|
||||
<FormControl>
|
||||
<FormLabel>Summary</FormLabel>
|
||||
<Textarea {...register("summary", { required: true })} isRequired />
|
||||
<FormHelperText>A short summary of the page</FormHelperText>
|
||||
</FormControl>
|
||||
<MarkdownEditor value={getValues().content} onChange={(v) => setValue("content", v)} />
|
||||
<Flex gap="2" justifyContent="flex-end">
|
||||
{formState.isDirty && <Button onClick={() => reset()}>Clear</Button>}
|
||||
|
18
yarn.lock
18
yarn.lock
@@ -2793,19 +2793,19 @@
|
||||
"@noble/hashes" "~1.3.2"
|
||||
"@scure/base" "~1.1.4"
|
||||
|
||||
"@snort/worker-relay@^1.0.10":
|
||||
version "1.0.10"
|
||||
resolved "https://registry.yarnpkg.com/@snort/worker-relay/-/worker-relay-1.0.10.tgz#3f79891027ec249e9722e358fc3ef59954238cc0"
|
||||
integrity sha512-fmtLU+xSvThu4z5l9OqNlbX2HBBCCr9LYBEMXCPs/1llpA10euneTrsQndsrEP5dkDDn8TzMwaQIxl3OIahORQ==
|
||||
"@snort/worker-relay@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@snort/worker-relay/-/worker-relay-1.1.0.tgz#b1be25b164b6f90e2c0b59ce9441cd3e316a1e67"
|
||||
integrity sha512-P4U4h4zOwJ5abdjxH3eaOKy9CI8bzfcvAefYHwqGYiY+eT2UAHZYi496fXDQqjfroOrPdzoWPyLmdfdoT6+eUg==
|
||||
dependencies:
|
||||
"@sqlite.org/sqlite-wasm" "^3.45.1-build1"
|
||||
"@sqlite.org/sqlite-wasm" "^3.45.3-build3"
|
||||
eventemitter3 "^5.0.1"
|
||||
uuid "^9.0.1"
|
||||
|
||||
"@sqlite.org/sqlite-wasm@^3.45.1-build1":
|
||||
version "3.45.1-build1"
|
||||
resolved "https://registry.yarnpkg.com/@sqlite.org/sqlite-wasm/-/sqlite-wasm-3.45.1-build1.tgz#648f6a0a0a4c3a67aff24b0e1331af655b86fb60"
|
||||
integrity sha512-1EgshFNhVeBtZ9KtQPm3PzzJ2CtpmXAq2DAPywy7WZ3gOK6p5n8TY+M+mBMpQCF5cLqrdNFb3Kp9uNie9rUAHw==
|
||||
"@sqlite.org/sqlite-wasm@^3.45.3-build3":
|
||||
version "3.45.3-build3"
|
||||
resolved "https://registry.yarnpkg.com/@sqlite.org/sqlite-wasm/-/sqlite-wasm-3.45.3-build3.tgz#dac928ddd009ecf27909df3ae9539c60b1aa255f"
|
||||
integrity sha512-LZowRxDr6hipruNLmkLKyW+mnfWlRyynPbs+tDWJhBp305dE5wBIGtA31Gp1ZjlgLqusw7ePrdgLf6zaK1Dfzw==
|
||||
|
||||
"@surma/rollup-plugin-off-main-thread@^2.2.3":
|
||||
version "2.2.3"
|
||||
|
Reference in New Issue
Block a user