diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 00000000..fa4bc4b2 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,46 @@ + + + + \ No newline at end of file diff --git a/.idea/lume.iml b/.idea/lume.iml index 53020506..41569bcb 100644 --- a/.idea/lume.iml +++ b/.idea/lume.iml @@ -3,6 +3,12 @@ + + + + + + diff --git a/apps/desktop2/package.json b/apps/desktop2/package.json index e25c5c99..67529ce0 100644 --- a/apps/desktop2/package.json +++ b/apps/desktop2/package.json @@ -23,23 +23,24 @@ "@radix-ui/react-switch": "^1.0.3", "@radix-ui/react-tabs": "^1.0.4", "@radix-ui/react-tooltip": "^1.0.7", - "@tanstack/query-sync-storage-persister": "^5.40.0", - "@tanstack/react-query": "^5.40.1", - "@tanstack/react-query-persist-client": "^5.40.1", - "@tanstack/react-router": "^1.35.3", + "@tanstack/query-persist-client-core": "^5.45.0", + "@tanstack/react-query": "^5.45.0", + "@tanstack/react-router": "^1.38.1", + "embla-carousel-react": "^8.1.5", "i18next": "^23.11.5", "i18next-resources-to-backend": "^1.2.1", "minidenticons": "^4.2.1", "nanoid": "^5.0.7", + "nostr-tools": "^2.7.0", "react": "^18.3.1", "react-currency-input-field": "^3.8.0", "react-dom": "^18.3.1", - "react-hook-form": "^7.51.5", + "react-hook-form": "^7.52.0", "react-hotkeys-hook": "^4.5.0", "react-i18next": "^14.1.2", "react-string-replace": "^1.1.1", "slate": "^0.103.0", - "slate-react": "^0.104.0", + "slate-react": "^0.105.0", "sonner": "^1.5.0", "use-debounce": "^10.0.1", "virtua": "^0.31.0" @@ -48,8 +49,8 @@ "@lume/tailwindcss": "workspace:^", "@lume/tsconfig": "workspace:^", "@lume/types": "workspace:^", - "@tanstack/router-devtools": "^1.35.3", - "@tanstack/router-vite-plugin": "^1.35.4", + "@tanstack/router-devtools": "^1.38.1", + "@tanstack/router-vite-plugin": "^1.38.0", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", "@vitejs/plugin-react-swc": "^3.7.0", @@ -57,7 +58,7 @@ "postcss": "^8.4.38", "tailwindcss": "^3.4.4", "typescript": "^5.4.5", - "vite": "^5.2.13", + "vite": "^5.3.1", "vite-plugin-top-level-await": "^1.4.1", "vite-tsconfig-paths": "^4.3.2" } diff --git a/apps/desktop2/src/app.tsx b/apps/desktop2/src/app.tsx index 7dcddd18..202d74cd 100644 --- a/apps/desktop2/src/app.tsx +++ b/apps/desktop2/src/app.tsx @@ -1,6 +1,4 @@ -import { createSyncStoragePersister } from "@tanstack/query-sync-storage-persister"; -import { QueryClient } from "@tanstack/react-query"; -import { PersistQueryClientProvider } from "@tanstack/react-query-persist-client"; +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; import { RouterProvider, createRouter } from "@tanstack/react-router"; import React, { StrictMode } from "react"; import ReactDOM from "react-dom/client"; @@ -10,11 +8,8 @@ import i18n from "./locale"; import { routeTree } from "./router.gen"; // auto generated file import { type } from "@tauri-apps/plugin-os"; -const os = await type(); const queryClient = new QueryClient(); -const persister = createSyncStoragePersister({ - storage: window.localStorage, -}); +const os = await type(); // Set up a Router instance const router = createRouter({ @@ -26,12 +21,9 @@ const router = createRouter({ Wrap: ({ children }) => { return ( - + {children} - + ); }, diff --git a/apps/desktop2/src/components/column.tsx b/apps/desktop2/src/components/column.tsx index 6e58f595..19bd5373 100644 --- a/apps/desktop2/src/components/column.tsx +++ b/apps/desktop2/src/components/column.tsx @@ -2,53 +2,57 @@ import { CancelIcon, CheckIcon } from "@lume/icons"; import type { LumeColumn } from "@lume/types"; import { cn } from "@lume/utils"; import { invoke } from "@tauri-apps/api/core"; +import { listen } from "@tauri-apps/api/event"; import { getCurrent } from "@tauri-apps/api/webviewWindow"; -import { useEffect, useMemo, useRef, useState } from "react"; +import { useCallback, useEffect, useRef, useState } from "react"; + +type WindowEvent = { + scroll: boolean; + resize: boolean; +}; export function Column({ column, account, - isScroll, - isResize, }: { column: LumeColumn; account: string; - isScroll: boolean; - isResize: boolean; }) { const container = useRef(null); - const webviewLabel = useMemo( - () => `column-${account}_${column.label}`, - [account], - ); + const webviewLabel = `column-${account}_${column.label}`; const [isCreated, setIsCreated] = useState(false); - const repositionWebview = async () => { + const repositionWebview = useCallback(async () => { const newRect = container.current.getBoundingClientRect(); await invoke("reposition_column", { label: webviewLabel, x: newRect.x, y: newRect.y, }); - }; + }, []); - const resizeWebview = async () => { + const resizeWebview = useCallback(async () => { const newRect = container.current.getBoundingClientRect(); await invoke("resize_column", { label: webviewLabel, width: newRect.width, height: newRect.height, }); - }; + }, []); useEffect(() => { - if (isCreated) resizeWebview(); - }, [isResize]); + if (!isCreated) return; - useEffect(() => { - if (isScroll && isCreated) repositionWebview(); - }, [isScroll]); + const unlisten = listen("window", (data) => { + if (data.payload.scroll) repositionWebview(); + if (data.payload.resize) resizeWebview(); + }); + + return () => { + unlisten.then((f) => f()); + }; + }, [isCreated]); useEffect(() => { if (!container?.current) return; @@ -78,7 +82,7 @@ export function Column({ }, [account]); return ( -
+
- {column.label !== "open" ? ( -
- ) : null} +
@@ -122,10 +124,10 @@ function Header({ label, name }: { label: string; name: string }) { }, [title]); return ( -
+
-
-
+
+
close()} - className="size-7 inline-flex hover:bg-black/10 rounded-lg dark:hover:bg-white/10 items-center justify-center text-neutral-600 dark:text-neutral-400 hover:text-neutral-800 dark:hover:text-neutral-200" + className="inline-flex items-center justify-center rounded-lg size-7 hover:bg-black/10 dark:hover:bg-white/10 text-neutral-600 dark:text-neutral-400 hover:text-neutral-800 dark:hover:text-neutral-200" > diff --git a/apps/desktop2/src/components/conversation.tsx b/apps/desktop2/src/components/conversation.tsx index a00bf0b1..03743c0a 100644 --- a/apps/desktop2/src/components/conversation.tsx +++ b/apps/desktop2/src/components/conversation.tsx @@ -1,23 +1,17 @@ import { ThreadIcon } from "@lume/icons"; -import type { NostrEvent } from "@lume/types"; import { Note } from "@/components/note"; import { cn } from "@lume/utils"; -import { LumeEvent } from "@lume/system"; +import type { LumeEvent } from "@lume/system"; import { useMemo } from "react"; export function Conversation({ event, - gossip, className, }: { - event: NostrEvent; - gossip?: boolean; + event: LumeEvent; className?: string; }) { - const thread = useMemo( - () => LumeEvent.getEventThread(event.tags, gossip), - [event], - ); + const thread = useMemo(() => event.thread, [event]); return ( @@ -28,7 +22,7 @@ export function Conversation({ )} >
- {thread?.root ? : null} + {thread?.root?.id ? : null}
@@ -36,15 +30,15 @@ export function Conversation({
- {thread?.reply ? : null} + {thread?.reply?.id ? : null}
-
+
-
+
diff --git a/apps/desktop2/src/components/note/activity.tsx b/apps/desktop2/src/components/note/activity.tsx deleted file mode 100644 index d8febfdb..00000000 --- a/apps/desktop2/src/components/note/activity.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { cn } from "@lume/utils"; -import { useNoteContext } from "./provider"; -import { User } from "../user"; - -export function NoteActivity({ className }: { className?: string }) { - const event = useNoteContext(); - const mentions = event.mentions; - - return ( -
-
-
To:
- {mentions.splice(0, 4).map((mention) => ( - - - - - - ))} - {mentions.length > 4 ? "..." : ""} -
-
- ); -} diff --git a/apps/desktop2/src/components/note/buttons/repost.tsx b/apps/desktop2/src/components/note/buttons/repost.tsx index 46937bed..66730cce 100644 --- a/apps/desktop2/src/components/note/buttons/repost.tsx +++ b/apps/desktop2/src/components/note/buttons/repost.tsx @@ -76,7 +76,7 @@ export function NoteRepost({ large = false }: { large?: boolean }) { + ); } diff --git a/apps/desktop2/src/components/note/mentions/note.tsx b/apps/desktop2/src/components/note/mentions/note.tsx index d341fcca..d4cbaaca 100644 --- a/apps/desktop2/src/components/note/mentions/note.tsx +++ b/apps/desktop2/src/components/note/mentions/note.tsx @@ -17,7 +17,7 @@ export function MentionNote({ if (isLoading) { return ( -
+
); @@ -25,18 +25,18 @@ export function MentionNote({ if (isError || !data) { return ( -
+
{t("note.error")}
); } return ( -
+
- - -
+ + +
ยท 100 ? "max-h-[150px] gradient-mask-b-0" : "", + data.content.length > 400 ? "max-h-[150px] gradient-mask-b-0" : "", )} > {data.content}
{openable ? ( -
+
@@ -41,7 +41,7 @@ export function NoteMenu() { @@ -50,7 +50,7 @@ export function NoteMenu() { @@ -59,7 +59,7 @@ export function NoteMenu() { @@ -68,25 +68,26 @@ export function NoteMenu() { - + diff --git a/apps/desktop2/src/components/note/preview/image.tsx b/apps/desktop2/src/components/note/preview/image.tsx index 730b25fb..664c06db 100644 --- a/apps/desktop2/src/components/note/preview/image.tsx +++ b/apps/desktop2/src/components/note/preview/image.tsx @@ -25,7 +25,7 @@ export function ImagePreview({ url }: { url: string }) { }; return ( -
+
{url} open(url)} + onKeyDown={() => open(url)} onError={({ currentTarget }) => { currentTarget.onerror = null; currentTarget.src = "/404.jpg"; diff --git a/apps/desktop2/src/components/note/preview/images.tsx b/apps/desktop2/src/components/note/preview/images.tsx index a92c8541..d40333a5 100644 --- a/apps/desktop2/src/components/note/preview/images.tsx +++ b/apps/desktop2/src/components/note/preview/images.tsx @@ -27,7 +27,7 @@ export function Images({ urls }: { urls: string[] }) { if (urls.length === 1) { return ( -
+
{urls[0]} open(urls[0])} + onKeyDown={() => open(urls[0])} onError={({ currentTarget }) => { currentTarget.onerror = null; currentTarget.src = "/404.jpg"; @@ -56,8 +57,9 @@ export function Images({ urls }: { urls: string[] }) { loading="lazy" decoding="async" style={{ contentVisibility: "auto" }} - className="w-full h-full object-cover rounded-lg outline outline-1 -outline-offset-1 outline-black/15" + className="object-cover w-full h-full rounded-lg outline outline-1 -outline-offset-1 outline-black/15" onClick={() => open(item)} + onKeyDown={() => open(item)} onError={({ currentTarget }) => { currentTarget.onerror = null; currentTarget.src = "/404.jpg"; diff --git a/apps/desktop2/src/components/note/preview/video.tsx b/apps/desktop2/src/components/note/preview/video.tsx index 7ed0e50a..46a65b47 100644 --- a/apps/desktop2/src/components/note/preview/video.tsx +++ b/apps/desktop2/src/components/note/preview/video.tsx @@ -1,8 +1,8 @@ export function VideoPreview({ url }: { url: string }) { return ( -
+