diff --git a/apps/desktop2/src/components/balance.tsx b/apps/desktop2/src/components/balance.tsx index e4cb027e..f117f619 100644 --- a/apps/desktop2/src/components/balance.tsx +++ b/apps/desktop2/src/components/balance.tsx @@ -4,39 +4,39 @@ import { useRouteContext } from "@tanstack/react-router"; import { useEffect, useMemo, useState } from "react"; export function Balance({ account }: { account: string }) { - const { ark } = useRouteContext({ strict: false }); - const [balance, setBalance] = useState(0); - const value = useMemo(() => getBitcoinDisplayValues(balance), [balance]); + const { ark } = useRouteContext({ strict: false }); + const [balance, setBalance] = useState(0); + const value = useMemo(() => getBitcoinDisplayValues(balance), [balance]); - useEffect(() => { - async function getBalance() { - const val = await ark.get_balance(); - setBalance(val); - } + useEffect(() => { + async function getBalance() { + const val = await ark.get_balance(); + setBalance(val); + } - getBalance(); - }, []); + getBalance(); + }, []); - return ( -
-
-
-
- Your balance -
-
- ₿ {value.bitcoinFormatted} -
-
- - - - - -
-
- ); + return ( +
+
+
+
+ Your balance +
+
+ ₿ {value.bitcoinFormatted} +
+
+ + + + + +
+
+ ); } diff --git a/apps/desktop2/src/components/column.tsx b/apps/desktop2/src/components/column.tsx index bc7eef47..a6add5e0 100644 --- a/apps/desktop2/src/components/column.tsx +++ b/apps/desktop2/src/components/column.tsx @@ -6,142 +6,142 @@ import { getCurrent } from "@tauri-apps/api/webviewWindow"; import { useEffect, useRef, useState } from "react"; export function Column({ - column, - account, - isScroll, - isResize, + column, + account, + isScroll, + isResize, }: { - column: LumeColumn; - account: string; - isScroll: boolean; - isResize: boolean; + column: LumeColumn; + account: string; + isScroll: boolean; + isResize: boolean; }) { - const container = useRef(null); - const webviewLabel = `column-${account}_${column.label}`; + const container = useRef(null); + const webviewLabel = `column-${account}_${column.label}`; - const [isCreated, setIsCreated] = useState(false); + const [isCreated, setIsCreated] = useState(false); - const repositionWebview = async () => { - const newRect = container.current.getBoundingClientRect(); - await invoke("reposition_column", { - label: webviewLabel, - x: newRect.x, - y: newRect.y, - }); - }; + const repositionWebview = async () => { + const newRect = container.current.getBoundingClientRect(); + await invoke("reposition_column", { + label: webviewLabel, + x: newRect.x, + y: newRect.y, + }); + }; - const resizeWebview = async () => { - const newRect = container.current.getBoundingClientRect(); - await invoke("resize_column", { - label: webviewLabel, - width: newRect.width, - height: newRect.height, - }); - }; + const resizeWebview = async () => { + const newRect = container.current.getBoundingClientRect(); + await invoke("resize_column", { + label: webviewLabel, + width: newRect.width, + height: newRect.height, + }); + }; - useEffect(() => { - if (isCreated) resizeWebview(); - }, [isResize]); + useEffect(() => { + if (isCreated) resizeWebview(); + }, [isResize]); - useEffect(() => { - if (isScroll && isCreated) repositionWebview(); - }, [isScroll]); + useEffect(() => { + if (isScroll && isCreated) repositionWebview(); + }, [isScroll]); - useEffect(() => { - const rect = container.current.getBoundingClientRect(); - const url = `${column.content}?account=${account}&label=${column.label}&name=${column.name}`; + useEffect(() => { + const rect = container.current.getBoundingClientRect(); + const url = `${column.content}?account=${account}&label=${column.label}&name=${column.name}`; - // create new webview - invoke("create_column", { - label: webviewLabel, - x: rect.x, - y: rect.y, - width: rect.width, - height: rect.height, - url, - }).then(() => setIsCreated(true)); + // create new webview + invoke("create_column", { + label: webviewLabel, + x: rect.x, + y: rect.y, + width: rect.width, + height: rect.height, + url, + }).then(() => setIsCreated(true)); - // close webview when unmounted - return () => { - invoke("close_column", { label: webviewLabel }); - }; - }, [account]); + // close webview when unmounted + return () => { + invoke("close_column", { label: webviewLabel }); + }; + }, [account]); - return ( -
-
- {column.label !== "open" ? ( -
- ) : null} -
-
-
- ); + return ( +
+
+ {column.label !== "open" ? ( +
+ ) : null} +
+
+
+ ); } function Header({ label, name }: { label: string; name: string }) { - const [title, setTitle] = useState(name); - const [isChanged, setIsChanged] = useState(false); + const [title, setTitle] = useState(name); + const [isChanged, setIsChanged] = useState(false); - const saveNewTitle = async () => { - const mainWindow = getCurrent(); - await mainWindow.emit("columns", { type: "set_title", label, title }); + const saveNewTitle = async () => { + const mainWindow = getCurrent(); + await mainWindow.emit("columns", { type: "set_title", label, title }); - // update search params - // @ts-ignore, hahaha - search.name = title; + // update search params + // @ts-ignore, hahaha + search.name = title; - // reset state - setIsChanged(false); - }; + // reset state + setIsChanged(false); + }; - const close = async () => { - const mainWindow = getCurrent(); - await mainWindow.emit("columns", { type: "remove", label }); - }; + const close = async () => { + const mainWindow = getCurrent(); + await mainWindow.emit("columns", { type: "remove", label }); + }; - useEffect(() => { - if (title.length !== name.length) setIsChanged(true); - }, [title]); + useEffect(() => { + if (title.length !== name.length) setIsChanged(true); + }, [title]); - return ( -
-
-
-
-
setTitle(e.currentTarget.textContent)} - className="text-sm font-medium focus:outline-none" - > - {name} -
- {isChanged ? ( - - ) : null} -
-
- -
- ); + return ( +
+
+
+
+
setTitle(e.currentTarget.textContent)} + className="text-sm font-medium focus:outline-none" + > + {name} +
+ {isChanged ? ( + + ) : null} +
+
+ +
+ ); } diff --git a/apps/desktop2/src/components/conversation.tsx b/apps/desktop2/src/components/conversation.tsx index 879cd091..2f9c30b6 100644 --- a/apps/desktop2/src/components/conversation.tsx +++ b/apps/desktop2/src/components/conversation.tsx @@ -5,44 +5,44 @@ import { cn } from "@lume/utils"; import { useRouteContext } from "@tanstack/react-router"; export function Conversation({ - event, - className, + event, + className, }: { - event: Event; - className?: string; + event: Event; + className?: string; }) { - const { ark } = useRouteContext({ strict: false }); - const thread = ark.parse_event_thread(event.tags); + const { ark } = useRouteContext({ strict: false }); + const thread = ark.parse_event_thread(event.tags); - return ( - - -
- {thread?.root ? : null} -
-
- - Thread -
-
-
- {thread?.reply ? : null} -
-
- -
- -
-
-
- -
- - - ); + return ( + + +
+ {thread?.root ? : null} +
+
+ + Thread +
+
+
+ {thread?.reply ? : null} +
+
+ +
+ +
+
+
+ +
+ + + ); } diff --git a/apps/desktop2/src/components/note/index.ts b/apps/desktop2/src/components/note/index.ts index 0112a7e4..c52887b0 100644 --- a/apps/desktop2/src/components/note/index.ts +++ b/apps/desktop2/src/components/note/index.ts @@ -12,16 +12,16 @@ import { NoteRoot } from "./root"; import { NoteUser } from "./user"; export const Note = { - Provider: NoteProvider, - Root: NoteRoot, - User: NoteUser, - Menu: NoteMenu, - Reply: NoteReply, - Repost: NoteRepost, - Content: NoteContent, - ContentLarge: NoteContentLarge, - Zap: NoteZap, - Open: NoteOpenThread, - Child: NoteChild, - Activity: NoteActivity, + Provider: NoteProvider, + Root: NoteRoot, + User: NoteUser, + Menu: NoteMenu, + Reply: NoteReply, + Repost: NoteRepost, + Content: NoteContent, + ContentLarge: NoteContentLarge, + Zap: NoteZap, + Open: NoteOpenThread, + Child: NoteChild, + Activity: NoteActivity, }; diff --git a/apps/desktop2/src/components/notification.tsx b/apps/desktop2/src/components/notification.tsx index 7daf6d6b..3b1d6e04 100644 --- a/apps/desktop2/src/components/notification.tsx +++ b/apps/desktop2/src/components/notification.tsx @@ -3,30 +3,30 @@ import { Note } from "@/components/note"; import { cn } from "@lume/utils"; export function Notification({ - event, - className, + event, + className, }: { - event: Event; - className?: string; + event: Event; + className?: string; }) { - return ( - - -
-
- -
- -
-
- -
-
-
- ); + return ( + + +
+
+ +
+ +
+
+ +
+
+
+ ); } diff --git a/apps/desktop2/src/components/quote.tsx b/apps/desktop2/src/components/quote.tsx index d4a2913e..60655ee2 100644 --- a/apps/desktop2/src/components/quote.tsx +++ b/apps/desktop2/src/components/quote.tsx @@ -4,44 +4,44 @@ import { Note } from "@/components/note"; import { cn } from "@lume/utils"; export function Quote({ - event, - className, + event, + className, }: { - event: Event; - className?: string; + event: Event; + className?: string; }) { - const quoteEventId = event.tags.find( - (tag) => tag[0] === "q" || tag[3] === "mention", - )?.[1]; + const quoteEventId = event.tags.find( + (tag) => tag[0] === "q" || tag[3] === "mention", + )?.[1]; - return ( - - -
- -
-
- - Quote -
-
-
-
-
- -
- -
-
-
- -
- - - ); + return ( + + +
+ +
+
+ + Quote +
+
+
+
+
+ +
+ +
+
+
+ +
+ + + ); } diff --git a/apps/desktop2/src/components/repost.tsx b/apps/desktop2/src/components/repost.tsx index 43ee5302..479005b0 100644 --- a/apps/desktop2/src/components/repost.tsx +++ b/apps/desktop2/src/components/repost.tsx @@ -7,79 +7,79 @@ import { useQuery } from "@tanstack/react-query"; import { useRouteContext } from "@tanstack/react-router"; export function RepostNote({ - event, - className, + event, + className, }: { - event: Event; - className?: string; + event: Event; + className?: string; }) { - const { ark } = useRouteContext({ strict: false }); - const { - isLoading, - isError, - data: repostEvent, - } = useQuery({ - queryKey: ["repost", event.id], - queryFn: async () => { - try { - if (event.content.length > 50) { - const embed: Event = JSON.parse(event.content); - return embed; - } + const { ark } = useRouteContext({ strict: false }); + const { + isLoading, + isError, + data: repostEvent, + } = useQuery({ + queryKey: ["repost", event.id], + queryFn: async () => { + try { + if (event.content.length > 50) { + const embed: Event = JSON.parse(event.content); + return embed; + } - const id = event.tags.find((el) => el[0] === "e")?.[1]; - const repostEvent = await ark.get_event(id); + const id = event.tags.find((el) => el[0] === "e")?.[1]; + const repostEvent = await ark.get_event(id); - return repostEvent; - } catch (e) { - throw new Error(e); - } - }, - refetchOnWindowFocus: false, - refetchOnMount: false, - }); + return repostEvent; + } catch (e) { + throw new Error(e); + } + }, + refetchOnWindowFocus: false, + refetchOnMount: false, + }); - return ( - - - -
- Reposted by -
- -
-
- {isLoading ? ( -
- - Loading event... -
- ) : isError || !repostEvent ? ( -
- Event not found within your current relay set -
- ) : ( - - -
- - -
- -
- - - - -
-
-
- )} -
- ); + return ( + + + +
+ Reposted by +
+ +
+
+ {isLoading ? ( +
+ + Loading event... +
+ ) : isError || !repostEvent ? ( +
+ Event not found within your current relay set +
+ ) : ( + + +
+ + +
+ +
+ + + + +
+
+
+ )} +
+ ); } diff --git a/apps/desktop2/src/components/text.tsx b/apps/desktop2/src/components/text.tsx index 8b91b639..087e6e29 100644 --- a/apps/desktop2/src/components/text.tsx +++ b/apps/desktop2/src/components/text.tsx @@ -3,32 +3,32 @@ import { cn } from "@lume/utils"; import { Note } from "@/components/note"; export function TextNote({ - event, - className, + event, + className, }: { - event: Event; - className?: string; + event: Event; + className?: string; }) { - return ( - - -
- - -
- -
- - - - -
-
-
- ); + return ( + + +
+ + +
+ +
+ + + + +
+
+
+ ); } diff --git a/apps/desktop2/src/routes/$account.home.tsx b/apps/desktop2/src/routes/$account.home.tsx index fea4fa0d..d10736a7 100644 --- a/apps/desktop2/src/routes/$account.home.tsx +++ b/apps/desktop2/src/routes/$account.home.tsx @@ -13,175 +13,175 @@ import { useDebouncedCallback } from "use-debounce"; import { VList, type VListHandle } from "virtua"; export const Route = createFileRoute("/$account/home")({ - loader: async ({ context }) => { - try { - const userColumns = await context.ark.get_columns(); - if (userColumns.length > 0) { - return userColumns; - } else { - const systemPath = "resources/system_columns.json"; - const resourcePath = await resolveResource(systemPath); - const resourceFile = await readTextFile(resourcePath); - const systemColumns: LumeColumn[] = JSON.parse(resourceFile); + loader: async ({ context }) => { + try { + const userColumns = await context.ark.get_columns(); + if (userColumns.length > 0) { + return userColumns; + } else { + const systemPath = "resources/system_columns.json"; + const resourcePath = await resolveResource(systemPath); + const resourceFile = await readTextFile(resourcePath); + const systemColumns: LumeColumn[] = JSON.parse(resourceFile); - return systemColumns; - } - } catch (e) { - console.error(String(e)); - } - }, - component: Screen, + return systemColumns; + } + } catch (e) { + console.error(String(e)); + } + }, + component: Screen, }); function Screen() { - const userSavedColumns = Route.useLoaderData(); - const vlistRef = useRef(null); + const userSavedColumns = Route.useLoaderData(); + const vlistRef = useRef(null); - const { account } = Route.useParams(); - const { ark } = Route.useRouteContext(); + const { account } = Route.useParams(); + const { ark } = Route.useRouteContext(); - const [selectedIndex, setSelectedIndex] = useState(-1); - const [columns, setColumns] = useState([]); - const [isScroll, setIsScroll] = useState(false); - const [isResize, setIsResize] = useState(false); + const [selectedIndex, setSelectedIndex] = useState(-1); + const [columns, setColumns] = useState([]); + const [isScroll, setIsScroll] = useState(false); + const [isResize, setIsResize] = useState(false); - const goLeft = () => { - const prevIndex = Math.max(selectedIndex - 1, 0); - setSelectedIndex(prevIndex); - vlistRef.current.scrollToIndex(prevIndex, { - align: "center", - }); - }; + const goLeft = () => { + const prevIndex = Math.max(selectedIndex - 1, 0); + setSelectedIndex(prevIndex); + vlistRef.current.scrollToIndex(prevIndex, { + align: "center", + }); + }; - const goRight = () => { - const nextIndex = Math.min(selectedIndex + 1, columns.length - 1); - setSelectedIndex(nextIndex); - vlistRef.current.scrollToIndex(nextIndex, { - align: "center", - }); - }; + const goRight = () => { + const nextIndex = Math.min(selectedIndex + 1, columns.length - 1); + setSelectedIndex(nextIndex); + vlistRef.current.scrollToIndex(nextIndex, { + align: "center", + }); + }; - const add = useDebouncedCallback((column: LumeColumn) => { - // update col label - column.label = `${column.label}-${nanoid()}`; + const add = useDebouncedCallback((column: LumeColumn) => { + // update col label + column.label = `${column.label}-${nanoid()}`; - // create new cols - const cols = [...columns]; - const openColIndex = cols.findIndex((col) => col.label === "open"); - const newCols = [ - ...cols.slice(0, openColIndex), - column, - ...cols.slice(openColIndex), - ]; + // create new cols + const cols = [...columns]; + const openColIndex = cols.findIndex((col) => col.label === "open"); + const newCols = [ + ...cols.slice(0, openColIndex), + column, + ...cols.slice(openColIndex), + ]; - setColumns(newCols); - setSelectedIndex(newCols.length); - setIsScroll(true); + setColumns(newCols); + setSelectedIndex(newCols.length); + setIsScroll(true); - // scroll to the newest column - vlistRef.current.scrollToIndex(newCols.length - 1, { - align: "end", - }); - }, 150); + // scroll to the newest column + vlistRef.current.scrollToIndex(newCols.length - 1, { + align: "end", + }); + }, 150); - const remove = useDebouncedCallback((label: string) => { - const newCols = columns.filter((t) => t.label !== label); + const remove = useDebouncedCallback((label: string) => { + const newCols = columns.filter((t) => t.label !== label); - setColumns(newCols); - setSelectedIndex(newCols.length); - setIsScroll(true); + setColumns(newCols); + setSelectedIndex(newCols.length); + setIsScroll(true); - // scroll to the first column - vlistRef.current.scrollToIndex(newCols.length - 1, { - align: "start", - }); - }, 150); + // scroll to the first column + vlistRef.current.scrollToIndex(newCols.length - 1, { + align: "start", + }); + }, 150); - const updateName = useDebouncedCallback((label: string, title: string) => { - const currentColIndex = columns.findIndex((col) => col.label === label); + const updateName = useDebouncedCallback((label: string, title: string) => { + const currentColIndex = columns.findIndex((col) => col.label === label); - const updatedCol = Object.assign({}, columns[currentColIndex]); - updatedCol.name = title; + const updatedCol = Object.assign({}, columns[currentColIndex]); + updatedCol.name = title; - const newCols = columns.slice(); - newCols[currentColIndex] = updatedCol; + const newCols = columns.slice(); + newCols[currentColIndex] = updatedCol; - setColumns(newCols); - }, 150); + setColumns(newCols); + }, 150); - const startResize = useDebouncedCallback( - () => setIsResize((prev) => !prev), - 150, - ); + const startResize = useDebouncedCallback( + () => setIsResize((prev) => !prev), + 150, + ); - useEffect(() => { - setColumns(userSavedColumns); - }, [userSavedColumns]); + useEffect(() => { + setColumns(userSavedColumns); + }, [userSavedColumns]); - useEffect(() => { - // save state - ark.set_columns(columns); - }, [columns]); + useEffect(() => { + // save state + ark.set_columns(columns); + }, [columns]); - useEffect(() => { - const unlistenColEvent = listen("columns", (data) => { - if (data.payload.type === "add") add(data.payload.column); - if (data.payload.type === "remove") remove(data.payload.label); - if (data.payload.type === "set_title") - updateName(data.payload.label, data.payload.title); - }); + useEffect(() => { + const unlistenColEvent = listen("columns", (data) => { + if (data.payload.type === "add") add(data.payload.column); + if (data.payload.type === "remove") remove(data.payload.label); + if (data.payload.type === "set_title") + updateName(data.payload.label, data.payload.title); + }); - const unlistenWindowResize = getCurrent().listen("tauri://resize", () => { - startResize(); - }); + const unlistenWindowResize = getCurrent().listen("tauri://resize", () => { + startResize(); + }); - return () => { - unlistenColEvent.then((f) => f()); - unlistenWindowResize.then((f) => f()); - }; - }, []); + return () => { + unlistenColEvent.then((f) => f()); + unlistenWindowResize.then((f) => f()); + }; + }, []); - return ( -
- setIsScroll(true)} - onScrollEnd={() => setIsScroll(false)} - className="scrollbar-none h-full w-full overflow-x-auto focus:outline-none" - cache={null} - > - {columns.map((column) => ( - - ))} - - -
- - -
-
-
- ); + return ( +
+ setIsScroll(true)} + onScrollEnd={() => setIsScroll(false)} + className="scrollbar-none h-full w-full overflow-x-auto focus:outline-none" + cache={null} + > + {columns.map((column) => ( + + ))} + + +
+ + +
+
+
+ ); } diff --git a/apps/desktop2/src/routes/$account.tsx b/apps/desktop2/src/routes/$account.tsx index 4da85563..f1c034f9 100644 --- a/apps/desktop2/src/routes/$account.tsx +++ b/apps/desktop2/src/routes/$account.tsx @@ -2,10 +2,10 @@ import { BellIcon, ComposeFilledIcon, PlusIcon, SearchIcon } from "@lume/icons"; import { Event, Kind } from "@lume/types"; import { User } from "@/components/user"; import { - cn, - decodeZapInvoice, - displayNpub, - sendNativeNotification, + cn, + decodeZapInvoice, + displayNpub, + sendNativeNotification, } from "@lume/utils"; import { Outlet, createFileRoute } from "@tanstack/react-router"; import { invoke } from "@tauri-apps/api/core"; @@ -14,171 +14,171 @@ import { useEffect, useState } from "react"; import { toast } from "sonner"; export const Route = createFileRoute("/$account")({ - beforeLoad: async ({ context }) => { - const ark = context.ark; - const accounts = await ark.get_all_accounts(); + beforeLoad: async ({ context }) => { + const ark = context.ark; + const accounts = await ark.get_all_accounts(); - return { accounts }; - }, - component: Screen, + return { accounts }; + }, + component: Screen, }); function Screen() { - const { ark, platform } = Route.useRouteContext(); - const navigate = Route.useNavigate(); + const { ark, platform } = Route.useRouteContext(); + const navigate = Route.useNavigate(); - return ( -
-
-
- - -
-
- - - -
-
-
-
- -
-
- ); + return ( +
+
+
+ + +
+
+ + + +
+
+
+
+ +
+
+ ); } function Accounts() { - const navigate = Route.useNavigate(); - const { ark, accounts } = Route.useRouteContext(); - const { account } = Route.useParams(); + const navigate = Route.useNavigate(); + const { ark, accounts } = Route.useRouteContext(); + const { account } = Route.useParams(); - const changeAccount = async (npub: string) => { - if (npub === account) { - return await ark.open_profile(account); - } + const changeAccount = async (npub: string) => { + if (npub === account) { + return await ark.open_profile(account); + } - // change current account and update signer - const select = await ark.load_selected_account(npub); + // change current account and update signer + const select = await ark.load_selected_account(npub); - if (select) { - return navigate({ to: "/$account/home", params: { account: npub } }); - } else { - toast.warning("Something wrong."); - } - }; + if (select) { + return navigate({ to: "/$account/home", params: { account: npub } }); + } else { + toast.warning("Something wrong."); + } + }; - return ( -
- {accounts.map((user) => ( - - ))} -
- ); + return ( +
+ {accounts.map((user) => ( + + ))} +
+ ); } function Bell() { - const { ark } = Route.useRouteContext(); - const { account } = Route.useParams(); + const { ark } = Route.useRouteContext(); + const { account } = Route.useParams(); - const [count, setCount] = useState(0); + const [count, setCount] = useState(0); - useEffect(() => { - const unlisten = getCurrent().listen( - "activity", - async (payload) => { - setCount((prevCount) => prevCount + 1); - await invoke("set_badge", { count }); + useEffect(() => { + const unlisten = getCurrent().listen( + "activity", + async (payload) => { + setCount((prevCount) => prevCount + 1); + await invoke("set_badge", { count }); - const event: Event = JSON.parse(payload.payload); - const user = await ark.get_profile(event.pubkey); - const userName = - user.display_name || user.name || displayNpub(event.pubkey, 16); + const event: Event = JSON.parse(payload.payload); + const user = await ark.get_profile(event.pubkey); + const userName = + user.display_name || user.name || displayNpub(event.pubkey, 16); - switch (event.kind) { - case Kind.Text: { - sendNativeNotification("Mentioned you in a note", userName); - break; - } - case Kind.Repost: { - sendNativeNotification("Reposted your note", userName); - break; - } - case Kind.ZapReceipt: { - const amount = decodeZapInvoice(event.tags); - sendNativeNotification( - `Zapped ₿ ${amount.bitcoinFormatted}`, - userName, - ); - break; - } - default: - break; - } - }, - ); + switch (event.kind) { + case Kind.Text: { + sendNativeNotification("Mentioned you in a note", userName); + break; + } + case Kind.Repost: { + sendNativeNotification("Reposted your note", userName); + break; + } + case Kind.ZapReceipt: { + const amount = decodeZapInvoice(event.tags); + sendNativeNotification( + `Zapped ₿ ${amount.bitcoinFormatted}`, + userName, + ); + break; + } + default: + break; + } + }, + ); - return () => { - unlisten.then((f) => f()); - }; - }, []); + return () => { + unlisten.then((f) => f()); + }; + }, []); - return ( - - ); + return ( + + ); } diff --git a/apps/desktop2/src/routes/editor/index.tsx b/apps/desktop2/src/routes/editor/index.tsx index 2515bc71..8f7c120b 100644 --- a/apps/desktop2/src/routes/editor/index.tsx +++ b/apps/desktop2/src/routes/editor/index.tsx @@ -25,6 +25,7 @@ import { MediaButton } from "./-components/media"; import { NsfwToggle } from "./-components/nsfw"; import { MentionButton } from "./-components/mention"; import { MentionNote } from "@/components/note/mentions/note"; +import { toast } from "sonner"; type EditorSearch = { reply_to: string; diff --git a/packages/ark/src/ark.ts b/packages/ark/src/ark.ts index 6837a300..59d4434f 100644 --- a/packages/ark/src/ark.ts +++ b/packages/ark/src/ark.ts @@ -207,12 +207,10 @@ export class Ark { global?: boolean, ) { try { - let until: string = undefined; + const until: string = asOf && asOf > 0 ? asOf.toString() : undefined; const isGlobal = global ?? false; + const seens = new Set(); - if (asOf && asOf > 0) until = asOf.toString(); - - const seenIds = new Set(); const nostrEvents: Event[] = await invoke("get_events", { limit, until, @@ -220,39 +218,31 @@ export class Ark { global: isGlobal, }); - // remove duplicate event - for (const event of nostrEvents) { - if (event.kind === Kind.Repost) { - const repostId = event.tags.find((tag) => tag[0] === "e")?.[1]; - seenIds.add(repostId); + const events = nostrEvents.filter((event) => { + const eTags = event.tags.filter((el) => el[0] === "e"); + const ids = eTags.map((item) => item[1]); + const isDup = ids.some((id) => seens.has(id)); + + // Add found ids to seen list + for (const id of ids) { + seens.add(id); } - const eventIds = event.tags - .filter((el) => el[0] === "e") - ?.map((item) => item[1]); + // Filter NSFW event + if (this.settings?.nsfw) { + const wTags = event.tags.filter((t) => t[0] === "content-warning"); + const isLewd = wTags.length > 0; - if (eventIds?.length) { - for (const id of eventIds) { - seenIds.add(id); - } + return !isDup && !isLewd; } - } - const events = nostrEvents - .filter((event) => !seenIds.has(event.id)) - .sort((a, b) => b.created_at - a.created_at); - - if (this.settings?.nsfw) { - return events.filter( - (event) => - event.tags.filter((event) => event[0] === "content-warning") - .length > 0, - ); - } + // Filter duplicate event + return !isDup; + }); return events; } catch (e) { - console.info(String(e)); + console.error("[get_events] failed", String(e)); return []; } } diff --git a/src-tauri/src/nostr/event.rs b/src-tauri/src/nostr/event.rs index 38ed3028..4c53bed6 100644 --- a/src-tauri/src/nostr/event.rs +++ b/src-tauri/src/nostr/event.rs @@ -9,7 +9,15 @@ pub async fn get_event(id: &str, state: State<'_, Nostr>) -> Result = match Nip19::from_bech32(id) { Ok(val) => match val { Nip19::EventId(id) => Some(id), - Nip19::Event(event) => Some(event.event_id), + Nip19::Event(event) => { + let relays = event.relays; + for relay in relays.into_iter() { + let url = Url::from_str(&relay).unwrap(); + let _ = client.add_relay(url.clone()).await.unwrap_or_default(); + client.connect_relay(url).await.unwrap_or_default(); + } + Some(event.event_id) + } _ => None, }, Err(_) => match EventId::from_hex(id) { @@ -18,23 +26,25 @@ pub async fn get_event(id: &str, state: State<'_, Nostr>) -> Result { + let filter = Filter::new().id(id); - if let Ok(events) = &client - .get_events_of(vec![filter], Some(Duration::from_secs(10))) - .await - { - if let Some(event) = events.first() { - Ok(event.as_json()) - } else { - Err("Event not found with current relay list".into()) + match &client + .get_events_of(vec![filter], Some(Duration::from_secs(10))) + .await + { + Ok(events) => { + if let Some(event) = events.first() { + Ok(event.as_json()) + } else { + Err("Cannot found this event with current relay list".into()) + } + } + Err(err) => Err(err.to_string()), } - } else { - Err("Event not found with current relay list".into()) } - } else { - Err("EventId is not valid".into()) + None => Err("Event ID is not valid.".into()), } } @@ -213,8 +223,6 @@ pub async fn search( limit: usize, state: State<'_, Nostr>, ) -> Result, String> { - println!("search: {}", content); - let client = &state.client; let filter = Filter::new() .kinds(vec![Kind::TextNote, Kind::Metadata]) diff --git a/src-tauri/src/nostr/keys.rs b/src-tauri/src/nostr/keys.rs index fceb89bf..501779c7 100644 --- a/src-tauri/src/nostr/keys.rs +++ b/src-tauri/src/nostr/keys.rs @@ -206,15 +206,12 @@ pub async fn load_selected_account(npub: &str, state: State<'_, Nostr>) -> Resul // Add relay to relay pool let _ = client - .add_relay_with_opts(relay_url, opts) + .add_relay_with_opts(relay_url.clone(), opts) .await .unwrap_or_default(); // Connect relay - client - .connect_relay(item.0.to_string()) - .await - .unwrap_or_default(); + client.connect_relay(relay_url).await.unwrap_or_default(); } } } @@ -251,14 +248,10 @@ pub fn to_npub(hex: &str) -> Result { Ok(npub.to_bech32().unwrap()) } -#[tauri::command(async)] +#[tauri::command] pub async fn verify_nip05(key: &str, nip05: &str) -> Result { let public_key = PublicKey::from_str(key).unwrap(); let status = nip05::verify(public_key, nip05, None).await; - if status.is_ok() { - Ok(true) - } else { - Ok(false) - } + Ok(status.is_ok()) } diff --git a/src-tauri/src/nostr/metadata.rs b/src-tauri/src/nostr/metadata.rs index a5102f15..19d588b5 100644 --- a/src-tauri/src/nostr/metadata.rs +++ b/src-tauri/src/nostr/metadata.rs @@ -104,8 +104,6 @@ pub async fn friend_to_friend(npub: &str, state: State<'_, Nostr>) -> Result Ok(true), Err(err) => Err(err.to_string()), @@ -289,7 +287,7 @@ pub async fn unfollow(id: &str, state: State<'_, Nostr>) -> Result