feat: add support for NIP-09

This commit is contained in:
2024-10-08 16:30:26 +07:00
parent d2b5ae0507
commit c40762cc04
13 changed files with 270 additions and 436 deletions

View File

@@ -390,6 +390,14 @@ async isDeletedEvent(id: string) : Promise<Result<boolean, string>> {
else return { status: "error", error: e as any };
}
},
async requestDelete(id: string) : Promise<Result<null, string>> {
try {
return { status: "ok", data: await TAURI_INVOKE("request_delete", { id }) };
} catch (e) {
if(e instanceof Error) throw e;
else return { status: "error", error: e as any };
}
},
async search(query: string, until: string | null) : Promise<Result<RichEvent[], string>> {
try {
return { status: "ok", data: await TAURI_INVOKE("search", { query, until }) };

View File

@@ -13,14 +13,17 @@ export const MentionNote = memo(function MentionNote({
return (
<div className="relative my-2">
<div className="pl-3 before:content-[''] before:absolute before:top-1.5 before:bottom-1.5 before:left-0 before:border-l-[2px] before:border-black/10 dark:before:border-white/10">
<div className="min-h-[64px] pl-3 before:content-[''] before:absolute before:top-1.5 before:bottom-1.5 before:left-0 before:border-l-[2px] before:border-black/10 dark:before:border-white/10">
{isLoading ? (
<Spinner />
<div className="h-[64px] flex items-center">
<Spinner />
</div>
) : isError || !event ? (
<p className="text-sm font-medium text-red-500">
{error.message ||
"Quoted note is not found with your current relay set"}
</p>
<div className="h-[64px] flex items-center">
<p className="text-sm font-medium text-red-500">
{error.message || "Note can be found with your current relay set"}
</p>
</div>
) : (
<Note.Provider event={event}>
<User.Provider pubkey={event.pubkey}>

View File

@@ -1,51 +1,68 @@
import { commands } from "@/commands.gen";
import { DotsThree } from "@phosphor-icons/react";
import { useSearch } from "@tanstack/react-router";
import { Menu, MenuItem, PredefinedMenuItem } from "@tauri-apps/api/menu";
import { writeText } from "@tauri-apps/plugin-clipboard-manager";
import { nip19 } from "nostr-tools";
import { useCallback } from "react";
import { useNoteContext } from "./provider";
export function NoteMenu() {
const event = useNoteContext();
const { account }: { account: string } = useSearch({ strict: false });
const showContextMenu = useCallback(async (e: React.MouseEvent) => {
e.preventDefault();
const menuItems = await Promise.all([
const list = [
MenuItem.new({
text: "Copy Sharable Link",
action: async () => {
const eventId = await event.idAsBech32();
await writeText(`https://njump.me/${eventId}`);
},
}),
MenuItem.new({
text: "Copy Event ID",
text: "Copy ID",
action: async () => {
const eventId = await event.idAsBech32();
await writeText(eventId);
},
}),
MenuItem.new({
text: "Copy Public Key",
text: "Copy author",
action: async () => {
const pubkey = await event.pubkeyAsBech32();
await writeText(pubkey);
},
}),
PredefinedMenuItem.new({ item: "Separator" }),
MenuItem.new({
text: "Copy Raw Event",
text: "Copy sharable link",
action: async () => {
event.meta = undefined;
const raw = JSON.stringify(event);
await writeText(raw);
const eventId = await event.idAsBech32();
await writeText(`https://njump.me/${eventId}`);
},
}),
]);
PredefinedMenuItem.new({ item: "Separator" }),
MenuItem.new({
text: "Copy raw event",
action: async () => {
event.meta = undefined;
await writeText(JSON.stringify(event));
},
}),
];
const menu = await Menu.new({
items: menuItems,
});
if (account?.length) {
const pubkey = nip19.decode(account).data;
if (event.pubkey === pubkey) {
list.push(
MenuItem.new({
text: "Request delete",
action: async () => {
await commands.requestDelete(event.id);
},
}),
);
}
}
const items = await Promise.all(list);
const menu = await Menu.new({ items });
await menu.popup().catch((e) => console.error(e));
}, []);

View File

@@ -1,6 +1,6 @@
import { commands } from "@/commands.gen";
import { toLumeEvents } from "@/commons";
import { Quote, RepostNote, Spinner, TextNote } from "@/components";
import { RepostNote, Spinner, TextNote } from "@/components";
import type { LumeEvent } from "@/system";
import { Kind } from "@/types";
import { ArrowDown } from "@phosphor-icons/react";
@@ -55,25 +55,14 @@ export function Screen() {
className="border-b-[.5px] border-neutral-300 dark:border-neutral-700"
/>
);
default: {
if (event.isQuote) {
return (
<Quote
key={event.id}
event={event}
className="border-b-[.5px] border-neutral-300 dark:border-neutral-700"
/>
);
} else {
return (
<TextNote
key={event.id}
event={event}
className="border-b-[.5px] border-neutral-300 dark:border-neutral-700"
/>
);
}
}
default:
return (
<TextNote
key={event.id}
event={event}
className="border-b-[.5px] border-neutral-300 dark:border-neutral-700"
/>
);
}
},
[data],

View File

@@ -1,6 +1,6 @@
import { commands } from "@/commands.gen";
import { toLumeEvents } from "@/commons";
import { Quote, RepostNote, Spinner, TextNote } from "@/components";
import { RepostNote, Spinner, TextNote } from "@/components";
import type { LumeEvent } from "@/system";
import { Kind } from "@/types";
import { ArrowDown } from "@phosphor-icons/react";
@@ -58,25 +58,14 @@ export function Screen() {
className="border-b-[.5px] border-neutral-300 dark:border-neutral-700"
/>
);
default: {
if (event.isQuote) {
return (
<Quote
key={event.id}
event={event}
className="border-b-[.5px] border-neutral-300 dark:border-neutral-700"
/>
);
} else {
return (
<TextNote
key={event.id}
event={event}
className="border-b-[.5px] border-neutral-300 dark:border-neutral-700"
/>
);
}
}
default:
return (
<TextNote
key={event.id}
event={event}
className="border-b-[.5px] border-neutral-300 dark:border-neutral-700"
/>
);
}
},
[data],

View File

@@ -1,6 +1,6 @@
import { commands } from "@/commands.gen";
import { toLumeEvents } from "@/commons";
import { Quote, RepostNote, Spinner, TextNote } from "@/components";
import { RepostNote, Spinner, TextNote } from "@/components";
import type { LumeEvent } from "@/system";
import { Kind } from "@/types";
import { ArrowDown } from "@phosphor-icons/react";
@@ -58,25 +58,14 @@ export function Screen() {
className="border-b-[.5px] border-neutral-300 dark:border-neutral-700"
/>
);
default: {
if (event.isQuote) {
return (
<Quote
key={event.id}
event={event}
className="border-b-[.5px] border-neutral-300 dark:border-neutral-700"
/>
);
} else {
return (
<TextNote
key={event.id}
event={event}
className="border-b-[.5px] border-neutral-300 dark:border-neutral-700"
/>
);
}
}
default:
return (
<TextNote
key={event.id}
event={event}
className="border-b-[.5px] border-neutral-300 dark:border-neutral-700"
/>
);
}
},
[data],

View File

@@ -1,6 +1,6 @@
import { events, commands } from "@/commands.gen";
import { toLumeEvents } from "@/commons";
import { Quote, RepostNote, Spinner, TextNote } from "@/components";
import { RepostNote, Spinner, TextNote } from "@/components";
import { LumeEvent } from "@/system";
import { Kind, type Meta } from "@/types";
import { ArrowDown, ArrowUp } from "@phosphor-icons/react";
@@ -69,25 +69,14 @@ export function Screen() {
className="border-b-[.5px] border-neutral-300 dark:border-neutral-700"
/>
);
default: {
if (event.isQuote) {
return (
<Quote
key={event.id}
event={event}
className="border-b-[.5px] border-neutral-300 dark:border-neutral-700"
/>
);
} else {
return (
<TextNote
key={event.id}
event={event}
className="border-b-[.5px] border-neutral-300 dark:border-neutral-700"
/>
);
}
}
default:
return (
<TextNote
key={event.id}
event={event}
className="border-b-[.5px] border-neutral-300 dark:border-neutral-700"
/>
);
}
},
[data],

View File

@@ -1,4 +1,4 @@
import { Quote, RepostNote, Spinner, TextNote } from "@/components";
import { RepostNote, Spinner, TextNote } from "@/components";
import { LumeEvent } from "@/system";
import { Kind, type NostrEvent } from "@/types";
import * as ScrollArea from "@radix-ui/react-scroll-area";
@@ -50,25 +50,14 @@ function Screen() {
className="border-b-[.5px] border-neutral-300 dark:border-neutral-700"
/>
);
default: {
if (event.isQuote) {
return (
<Quote
key={event.id}
event={event}
className="border-b-[.5px] border-neutral-300 dark:border-neutral-700"
/>
);
} else {
return (
<TextNote
key={event.id}
event={event}
className="border-b-[.5px] border-neutral-300 dark:border-neutral-700"
/>
);
}
}
default:
return (
<TextNote
key={event.id}
event={event}
className="border-b-[.5px] border-neutral-300 dark:border-neutral-700"
/>
);
}
},
[data],

View File

@@ -1,10 +1,6 @@
import { commands } from "@/commands.gen";
import { toLumeEvents } from "@/commons";
import { Spinner } from "@/components";
import { Quote } from "@/components/quote";
import { RepostNote } from "@/components/repost";
import { TextNote } from "@/components/text";
import { User } from "@/components/user";
import { RepostNote, Spinner, TextNote, User } from "@/components";
import type { LumeEvent } from "@/system";
import { Kind } from "@/types";
import * as ScrollArea from "@radix-ui/react-scroll-area";
@@ -48,16 +44,7 @@ function Screen() {
className="border-b-[.5px] border-neutral-300 dark:border-neutral-700"
/>
);
default: {
if (event.isQuote) {
return (
<Quote
key={event.id}
event={event}
className="border-b-[.5px] border-neutral-300 dark:border-neutral-700"
/>
);
}
default:
return (
<TextNote
key={event.id}
@@ -65,7 +52,6 @@ function Screen() {
className="border-b-[.5px] border-neutral-300 dark:border-neutral-700"
/>
);
}
}
},
[events],