diff --git a/package.json b/package.json index 4b57ea92..ef90e6c1 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "**/*.{ts, tsx, css, md, html, json}": "prettier --cache --write" }, "dependencies": { + "@dnd-kit/core": "^6.0.8", "@getalby/sdk": "^2.4.0", "@nostr-dev-kit/ndk": "^1.3.0", "@nostr-fetch/adapter-ndk": "^0.12.2", @@ -29,7 +30,6 @@ "@radix-ui/react-popover": "^1.0.7", "@radix-ui/react-tooltip": "^1.0.7", "@tanstack/react-query": "^4.35.3", - "@tanstack/react-virtual": "3.0.0-beta.54", "@tauri-apps/api": "^1.4.0", "@tiptap/extension-image": "^2.1.11", "@tiptap/extension-mention": "^2.1.11", @@ -56,7 +56,6 @@ "react-player": "^2.13.0", "react-router-dom": "^6.16.0", "react-textarea-autosize": "^8.5.3", - "react-virtuoso": "^4.6.0", "reactflow": "^11.8.3", "remark-gfm": "^3.0.1", "tauri-plugin-sql-api": "github:tauri-apps/tauri-plugin-sql#v1", @@ -64,6 +63,7 @@ "tauri-plugin-stronghold-api": "github:tauri-apps/tauri-plugin-stronghold#v1", "tauri-plugin-upload-api": "github:tauri-apps/tauri-plugin-upload#v1", "tippy.js": "^6.3.7", + "virtua": "^0.9.1", "zustand": "^4.4.1" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cf98d3a7..5e34ad8d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,6 +5,9 @@ settings: excludeLinksFromLockfile: false dependencies: + '@dnd-kit/core': + specifier: ^6.0.8 + version: 6.0.8(react-dom@18.2.0)(react@18.2.0) '@getalby/sdk': specifier: ^2.4.0 version: 2.4.0 @@ -38,9 +41,6 @@ dependencies: '@tanstack/react-query': specifier: ^4.35.3 version: 4.35.3(react-dom@18.2.0)(react@18.2.0) - '@tanstack/react-virtual': - specifier: 3.0.0-beta.54 - version: 3.0.0-beta.54(react@18.2.0) '@tauri-apps/api': specifier: ^1.4.0 version: 1.4.0 @@ -119,9 +119,6 @@ dependencies: react-textarea-autosize: specifier: ^8.5.3 version: 8.5.3(@types/react@18.2.22)(react@18.2.0) - react-virtuoso: - specifier: ^4.6.0 - version: 4.6.0(react-dom@18.2.0)(react@18.2.0) reactflow: specifier: ^11.8.3 version: 11.8.3(@types/react@18.2.22)(react-dom@18.2.0)(react@18.2.0) @@ -130,19 +127,22 @@ dependencies: version: 3.0.1 tauri-plugin-sql-api: specifier: github:tauri-apps/tauri-plugin-sql#v1 - version: github.com/tauri-apps/tauri-plugin-sql/51e39b0b6ba542ffc6af1fa438933fdc1ae265a0 + version: github.com/tauri-apps/tauri-plugin-sql/533198dd3b6cfca36d876918d22efcdaac43065a tauri-plugin-store-api: specifier: github:tauri-apps/tauri-plugin-store#v1 - version: github.com/tauri-apps/tauri-plugin-store/a65ce9bfb168a9a3cd7ed4102b9f22770cc3abfa + version: github.com/tauri-apps/tauri-plugin-store/66e06b7830037fdae0b42b5499e23334eaf4e017 tauri-plugin-stronghold-api: specifier: github:tauri-apps/tauri-plugin-stronghold#v1 - version: github.com/tauri-apps/tauri-plugin-stronghold/96dd2cc891915e6fdfb78868b0bef6c5648335a2 + version: github.com/tauri-apps/tauri-plugin-stronghold/4684fed1f5e7eb01885e40114accdcecb61962ed tauri-plugin-upload-api: specifier: github:tauri-apps/tauri-plugin-upload#v1 - version: github.com/tauri-apps/tauri-plugin-upload/b53ebc6c2e716d95fd94b64d3b4b87cd57ae4feb + version: github.com/tauri-apps/tauri-plugin-upload/40c0bc302a9dd8304762951e450ee84d53c2037b tippy.js: specifier: ^6.3.7 version: 6.3.7 + virtua: + specifier: ^0.9.1 + version: 0.9.1(react-dom@18.2.0)(react@18.2.0) zustand: specifier: ^4.4.1 version: 4.4.1(@types/react@18.2.22)(react@18.2.0) @@ -378,6 +378,37 @@ packages: to-fast-properties: 2.0.0 dev: true + /@dnd-kit/accessibility@3.0.1(react@18.2.0): + resolution: {integrity: sha512-HXRrwS9YUYQO9lFRc/49uO/VICbM+O+ZRpFDe9Pd1rwVv2PCNkRiTZRdxrDgng/UkvdC3Re9r2vwPpXXrWeFzg==} + peerDependencies: + react: '>=16.8.0' + dependencies: + react: 18.2.0 + tslib: 2.6.2 + dev: false + + /@dnd-kit/core@6.0.8(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-lYaoP8yHTQSLlZe6Rr9qogouGUz9oRUj4AHhDQGQzq/hqaJRpFo65X+JKsdHf8oUFBzx5A+SJPUvxAwTF2OabA==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + dependencies: + '@dnd-kit/accessibility': 3.0.1(react@18.2.0) + '@dnd-kit/utilities': 3.2.1(react@18.2.0) + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + tslib: 2.6.2 + dev: false + + /@dnd-kit/utilities@3.2.1(react@18.2.0): + resolution: {integrity: sha512-OOXqISfvBw/1REtkSK2N3Fi2EQiLMlWUlqnOK/UpOISqBZPWpE6TqL+jcPtMOkE8TqYGiURvRdPSI9hltNUjEA==} + peerDependencies: + react: '>=16.8.0' + dependencies: + react: 18.2.0 + tslib: 2.6.2 + dev: false + /@esbuild/android-arm64@0.18.20: resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} engines: {node: '>=12'} @@ -1799,19 +1830,6 @@ packages: use-sync-external-store: 1.2.0(react@18.2.0) dev: false - /@tanstack/react-virtual@3.0.0-beta.54(react@18.2.0): - resolution: {integrity: sha512-D1mDMf4UPbrtHRZZriCly5bXTBMhylslm4dhcHqTtDJ6brQcgGmk8YD9JdWBGWfGSWPKoh2x1H3e7eh+hgPXtQ==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - dependencies: - '@tanstack/virtual-core': 3.0.0-beta.54 - react: 18.2.0 - dev: false - - /@tanstack/virtual-core@3.0.0-beta.54: - resolution: {integrity: sha512-jtkwqdP2rY2iCCDVAFuaNBH3fiEi29aTn2RhtIoky8DTTiCdc48plpHHreLwmv1PICJ4AJUUESaq3xa8fZH8+g==} - dev: false - /@tauri-apps/api@1.4.0: resolution: {integrity: sha512-Jd6HPoTM1PZSFIzq7FB8VmMu3qSSyo/3lSwLpoapW+lQ41CL5Dow2KryLg+gyazA/58DRWI9vu/XpEeHK4uMdw==} engines: {node: '>= 14.6.0', npm: '>= 6.6.0', yarn: '>= 1.19.1'} @@ -5671,17 +5689,6 @@ packages: - '@types/react' dev: false - /react-virtuoso@4.6.0(react-dom@18.2.0)(react@18.2.0): - resolution: {integrity: sha512-paQbkLA8U6dRe9srltWgPeoFCtNKqUYIcOpUR01JyznzaXWVzgZQE0M9KGi9vMoq8vHvHkGzuxJ6jDCS6uzePg==} - engines: {node: '>=10'} - peerDependencies: - react: '>=16 || >=17 || >= 18' - react-dom: '>=16 || >=17 || >= 18' - dependencies: - react: 18.2.0 - react-dom: 18.2.0(react@18.2.0) - dev: false - /react@18.2.0: resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} engines: {node: '>=0.10.0'} @@ -6467,6 +6474,16 @@ packages: vfile-message: 3.1.4 dev: false + /virtua@0.9.1(react-dom@18.2.0)(react@18.2.0): + resolution: {integrity: sha512-uaFvh+5zCDEenQDgxfIs67kpci7d/3XjdnWP/TdDYLcoXdWKr5ddwiP1g+wybHpXmLqbfJ0X0njmlAvP7GwMdw==} + peerDependencies: + react: '>=16.14.0' + react-dom: '>=16.14.0' + dependencies: + react: 18.2.0 + react-dom: 18.2.0(react@18.2.0) + dev: false + /vite-tsconfig-paths@4.2.1(typescript@5.2.2)(vite@4.4.9): resolution: {integrity: sha512-GNUI6ZgPqT3oervkvzU+qtys83+75N/OuDaQl7HmOqFTb0pjZsuARrRipsyJhJ3enqV8beI1xhGbToR4o78nSQ==} peerDependencies: @@ -6669,32 +6686,32 @@ packages: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} dev: false - github.com/tauri-apps/tauri-plugin-sql/51e39b0b6ba542ffc6af1fa438933fdc1ae265a0: - resolution: {tarball: https://codeload.github.com/tauri-apps/tauri-plugin-sql/tar.gz/51e39b0b6ba542ffc6af1fa438933fdc1ae265a0} + github.com/tauri-apps/tauri-plugin-sql/533198dd3b6cfca36d876918d22efcdaac43065a: + resolution: {tarball: https://codeload.github.com/tauri-apps/tauri-plugin-sql/tar.gz/533198dd3b6cfca36d876918d22efcdaac43065a} name: tauri-plugin-sql-api version: 0.0.0 dependencies: '@tauri-apps/api': 1.4.0 dev: false - github.com/tauri-apps/tauri-plugin-store/a65ce9bfb168a9a3cd7ed4102b9f22770cc3abfa: - resolution: {tarball: https://codeload.github.com/tauri-apps/tauri-plugin-store/tar.gz/a65ce9bfb168a9a3cd7ed4102b9f22770cc3abfa} + github.com/tauri-apps/tauri-plugin-store/66e06b7830037fdae0b42b5499e23334eaf4e017: + resolution: {tarball: https://codeload.github.com/tauri-apps/tauri-plugin-store/tar.gz/66e06b7830037fdae0b42b5499e23334eaf4e017} name: tauri-plugin-store-api version: 0.0.0 dependencies: '@tauri-apps/api': 1.4.0 dev: false - github.com/tauri-apps/tauri-plugin-stronghold/96dd2cc891915e6fdfb78868b0bef6c5648335a2: - resolution: {tarball: https://codeload.github.com/tauri-apps/tauri-plugin-stronghold/tar.gz/96dd2cc891915e6fdfb78868b0bef6c5648335a2} + github.com/tauri-apps/tauri-plugin-stronghold/4684fed1f5e7eb01885e40114accdcecb61962ed: + resolution: {tarball: https://codeload.github.com/tauri-apps/tauri-plugin-stronghold/tar.gz/4684fed1f5e7eb01885e40114accdcecb61962ed} name: tauri-plugin-stronghold-api version: 0.0.0 dependencies: '@tauri-apps/api': 1.4.0 dev: false - github.com/tauri-apps/tauri-plugin-upload/b53ebc6c2e716d95fd94b64d3b4b87cd57ae4feb: - resolution: {tarball: https://codeload.github.com/tauri-apps/tauri-plugin-upload/tar.gz/b53ebc6c2e716d95fd94b64d3b4b87cd57ae4feb} + github.com/tauri-apps/tauri-plugin-upload/40c0bc302a9dd8304762951e450ee84d53c2037b: + resolution: {tarball: https://codeload.github.com/tauri-apps/tauri-plugin-upload/tar.gz/40c0bc302a9dd8304762951e450ee84d53c2037b} name: tauri-plugin-upload-api version: 0.0.0 dependencies: diff --git a/src/app/browse/components/userLatestPosts.tsx b/src/app/browse/components/userLatestPosts.tsx index 0c728a7c..ac54220d 100644 --- a/src/app/browse/components/userLatestPosts.tsx +++ b/src/app/browse/components/userLatestPosts.tsx @@ -26,7 +26,7 @@ export function UserLatestPosts({ pubkey }: { pubkey: string }) { case NDKKind.Text: return ( - + ); case NDKKind.Repost: @@ -34,19 +34,19 @@ export function UserLatestPosts({ pubkey }: { pubkey: string }) { case 1063: return ( - + ); case NDKKind.Article: return ( - + ); default: return ( - + ); } diff --git a/src/app/browse/components/userWithDrawer.tsx b/src/app/browse/components/userWithDrawer.tsx index b31b8b33..4d0e5d17 100644 --- a/src/app/browse/components/userWithDrawer.tsx +++ b/src/app/browse/components/userWithDrawer.tsx @@ -60,7 +60,7 @@ export const UserWithDrawer = memo(function UserWithDrawer({ - +
{status === 'loading' ? (
diff --git a/src/app/browse/index.tsx b/src/app/browse/index.tsx index 3f095f29..cb538e5e 100644 --- a/src/app/browse/index.tsx +++ b/src/app/browse/index.tsx @@ -13,7 +13,7 @@ export function BrowseScreen() { to="/browse/" className={({ isActive }) => twMerge( - 'inline-flex h-8 w-20 items-center justify-center rounded-full text-sm font-semibold', + 'inline-flex h-7 w-20 items-center justify-center rounded-full text-sm font-semibold', isActive ? 'bg-white/10 hover:bg-white/20' : ' hover:bg-white/5' ) } @@ -24,7 +24,7 @@ export function BrowseScreen() { to="/browse/relays" className={({ isActive }) => twMerge( - 'inline-flex h-8 w-20 items-center justify-center rounded-full text-sm font-semibold', + 'inline-flex h-7 w-20 items-center justify-center rounded-full text-sm font-semibold', isActive ? 'bg-white/10 hover:bg-white/20' : ' hover:bg-white/5' ) } diff --git a/src/app/browse/relays.tsx b/src/app/browse/relays.tsx index 203a142e..6047990b 100644 --- a/src/app/browse/relays.tsx +++ b/src/app/browse/relays.tsx @@ -1,7 +1,12 @@ export function BrowseRelaysScreen() { return ( -
-

TODO

+
+
+

Content

+
+
+

Your relays

+
); } diff --git a/src/app/chats/components/list.tsx b/src/app/chats/components/list.tsx index 86fbccf7..8335b7b5 100644 --- a/src/app/chats/components/list.tsx +++ b/src/app/chats/components/list.tsx @@ -7,6 +7,8 @@ import { UnknownsModal } from '@app/chats/components/unknowns'; import { useStorage } from '@libs/storage/provider'; +import { LoaderIcon } from '@shared/icons'; + import { useNostr } from '@utils/hooks/useNostr'; export function ChatsList() { @@ -33,8 +35,10 @@ export function ChatsList() { return (
-
-
+
+ +
+
Loading messages...
); diff --git a/src/app/chats/components/messages/item.tsx b/src/app/chats/components/messages/item.tsx index 0455e511..94abb01f 100644 --- a/src/app/chats/components/messages/item.tsx +++ b/src/app/chats/components/messages/item.tsx @@ -2,6 +2,7 @@ import { NDKEvent } from '@nostr-dev-kit/ndk'; import { useDecryptMessage } from '@app/chats/hooks/useDecryptMessage'; +import { TextNote } from '@shared/notes'; import { User } from '@shared/user'; export function ChatMessageItem({ @@ -20,13 +21,12 @@ export function ChatMessageItem({ } return ( -
+
-
-

- {message.content} -

+
+
+
diff --git a/src/app/chats/index.tsx b/src/app/chats/index.tsx index 2076e382..c4bd0dd7 100644 --- a/src/app/chats/index.tsx +++ b/src/app/chats/index.tsx @@ -1,8 +1,8 @@ -import { NDKSubscription } from '@nostr-dev-kit/ndk'; +import { NDKEvent, NDKSubscription } from '@nostr-dev-kit/ndk'; import { useQuery } from '@tanstack/react-query'; import { useCallback, useEffect, useRef } from 'react'; import { useParams } from 'react-router-dom'; -import { Virtuoso } from 'react-virtuoso'; +import { VList, VListHandle } from 'virtua'; import { ChatMessageForm } from '@app/chats/components/messages/form'; import { ChatMessageItem } from '@app/chats/components/messages/item'; @@ -18,7 +18,7 @@ import { useStronghold } from '@stores/stronghold'; import { useNostr } from '@utils/hooks/useNostr'; export function ChatScreen() { - const virtuosoRef = useRef(null); + const listRef = useRef(null); const userPrivkey = useStronghold((state) => state.privkey); const { db } = useStorage(); @@ -29,10 +29,8 @@ export function ChatScreen() { return await fetchNIP04Messages(pubkey); }); - const itemContent = useCallback( - (index: string | number) => { - const message = data[index]; - if (!message) return; + const renderItem = useCallback( + (message: NDKEvent) => { return ( { - return data[index].id; - }, - [data] - ); + useEffect(() => { + if (data.length > 0) listRef.current?.scrollToIndex(data.length); + }, [data]); useEffect(() => { const sub: NDKSubscription = ndk.subscribe( @@ -86,22 +81,17 @@ export function ChatScreen() {

Loading messages

+ ) : data.length === 0 ? ( +
+

🙌

+

+ You two didn't talk yet, let's send first message +

+
) : ( - Empty, - }} - /> + + {data.map((message) => renderItem(message))} + )}
@@ -120,12 +110,3 @@ export function ChatScreen() {
); } - -const Empty = ( -
-

🙌

-

- You two didn't talk yet, let's send first message -

-
-); diff --git a/src/app/users/index.tsx b/src/app/users/index.tsx index d05a53ba..12bc7973 100644 --- a/src/app/users/index.tsx +++ b/src/app/users/index.tsx @@ -1,8 +1,8 @@ import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk'; import { useQuery } from '@tanstack/react-query'; -import { useVirtualizer } from '@tanstack/react-virtual'; -import { useCallback, useRef } from 'react'; +import { useCallback } from 'react'; import { useParams } from 'react-router-dom'; +import { VList } from 'virtua'; import { UserProfile } from '@app/users/components/profile'; @@ -32,79 +32,35 @@ export function UserScreen() { return [...events] as unknown as NDKEvent[]; }); - const parentRef = useRef(); - const virtualizer = useVirtualizer({ - count: data ? data.length : 0, - getScrollElement: () => parentRef.current, - estimateSize: () => 650, - overscan: 4, - }); - const items = virtualizer.getVirtualItems(); - // render event match event kind const renderItem = useCallback( - (index: string | number) => { - const event: NDKEvent = data[index]; - if (!event) return; - + (event: NDKEvent) => { switch (event.kind) { case NDKKind.Text: return ( -
- - - -
+ + + ); case NDKKind.Repost: - return ( -
- -
- ); + return ; case 1063: return ( -
- - - -
+ + + ); case NDKKind.Article: return ( -
- - - -
+ + + ); default: return ( -
- - - -
+ + + ); } }, @@ -112,10 +68,7 @@ export function UserScreen() { ); return ( -
+
@@ -129,7 +82,7 @@ export function UserScreen() {
- ) : items.length === 0 ? ( + ) : data.length === 0 ? (
@@ -140,22 +93,10 @@ export function UserScreen() {
) : ( -
-
- {items.map((item) => renderItem(item.index))} -
-
+ + {data.map((item) => renderItem(item))} +
+ )}
diff --git a/src/libs/ndk/instance.ts b/src/libs/ndk/instance.ts index d8306f91..01709c76 100644 --- a/src/libs/ndk/instance.ts +++ b/src/libs/ndk/instance.ts @@ -21,6 +21,7 @@ export const NDKInstance = () => { ); // TODO: fully support NIP-11 + // eslint-disable-next-line @typescript-eslint/no-unused-vars async function getExplicitRelays() { try { // get relays @@ -62,7 +63,7 @@ export const NDKInstance = () => { } async function initNDK() { - const explicitRelayUrls = await getExplicitRelays(); + const explicitRelayUrls = await db.getExplicitRelayUrls(); const instance = new NDK({ explicitRelayUrls, cacheAdapter, diff --git a/src/shared/navigation.tsx b/src/shared/navigation.tsx index 2844924f..4fd9029e 100644 --- a/src/shared/navigation.tsx +++ b/src/shared/navigation.tsx @@ -23,7 +23,10 @@ export function Navigation() { ]); return ( - +
{ - const title = event.tags.find((tag) => tag[0] === 'title')?.[1]; - const image = event.tags.find((tag) => tag[0] === 'image')?.[1]; - const summary = event.tags.find((tag) => tag[0] === 'summary')?.[1]; + const title = props.event.tags.find((tag) => tag[0] === 'title')?.[1]; + const image = props.event.tags.find((tag) => tag[0] === 'image')?.[1]; + const summary = props.event.tags.find((tag) => tag[0] === 'summary')?.[1]; - let publishedAt: Date | string | number = event.tags.find( + let publishedAt: Date | string | number = props.event.tags.find( (tag) => tag[0] === 'published_at' )?.[1]; if (publishedAt) { publishedAt = new Date(parseInt(publishedAt)).toLocaleDateString('en-US'); } else { - publishedAt = new Date(event.created_at * 1000).toLocaleDateString('en-US'); + publishedAt = new Date(props.event.created_at * 1000).toLocaleDateString('en-US'); } return { @@ -25,11 +25,11 @@ export function ArticleNote({ event }: { event: NDKEvent }) { publishedAt, summary, }; - }, [event.id]); + }, [props.event.id]); return ( diff --git a/src/shared/notes/kinds/file.tsx b/src/shared/notes/kinds/file.tsx index 7df8a3c3..9595338f 100644 --- a/src/shared/notes/kinds/file.tsx +++ b/src/shared/notes/kinds/file.tsx @@ -6,8 +6,8 @@ import { Image } from '@shared/image'; import { fileType } from '@utils/nip94'; -export function FileNote({ event }: { event: NDKEvent }) { - const url = event.tags.find((el) => el[0] === 'url')[1]; +export function FileNote(props: { event?: NDKEvent }) { + const url = props.event.tags.find((el) => el[0] === 'url')[1]; const type = fileType(url); if (type === 'image') { @@ -15,7 +15,7 @@ export function FileNote({ event }: { event: NDKEvent }) {
{event.content}
diff --git a/src/shared/notes/kinds/text.tsx b/src/shared/notes/kinds/text.tsx index 6064f073..a572c082 100644 --- a/src/shared/notes/kinds/text.tsx +++ b/src/shared/notes/kinds/text.tsx @@ -13,8 +13,8 @@ import { import { parser } from '@utils/parser'; -export function TextNote({ content }: { content: string }) { - const richContent = parser(content) ?? null; +export function TextNote(props: { content?: string }) { + const richContent = parser(props.content) ?? null; if (!richContent) { return ( @@ -26,7 +26,7 @@ export function TextNote({ content }: { content: string }) { unwrapDisallowed={true} linkTarget={'_blank'} > - {content} + {props.content}
); diff --git a/src/shared/notes/kinds/unknown.tsx b/src/shared/notes/kinds/unknown.tsx index 243e244d..0be00b35 100644 --- a/src/shared/notes/kinds/unknown.tsx +++ b/src/shared/notes/kinds/unknown.tsx @@ -1,18 +1,18 @@ import { NDKEvent } from '@nostr-dev-kit/ndk'; -export function UnknownNote({ event }: { event: NDKEvent }) { +export function UnknownNote(props: { event?: NDKEvent }) { return (
- Unknown kind: {event.kind} + Unknown kind: {props.event.kind}

Lume isn't fully support this kind

-

{event.content.toString()}

+

{props.event.content.toString()}

); diff --git a/src/shared/notes/replies/sub.tsx b/src/shared/notes/replies/sub.tsx index 004aa474..e98b88f3 100644 --- a/src/shared/notes/replies/sub.tsx +++ b/src/shared/notes/replies/sub.tsx @@ -10,7 +10,7 @@ export function SubReply({ event }: { event: NDKEvent }) {
- +
diff --git a/src/shared/notes/wrapper.tsx b/src/shared/notes/wrapper.tsx index 3d6ff4ce..5fb5b38f 100644 --- a/src/shared/notes/wrapper.tsx +++ b/src/shared/notes/wrapper.tsx @@ -1,5 +1,5 @@ import { NDKEvent } from '@nostr-dev-kit/ndk'; -import { ReactNode } from 'react'; +import { ReactElement, cloneElement } from 'react'; import { twMerge } from 'tailwind-merge'; import { ChildNote, NoteActions } from '@shared/notes'; @@ -13,7 +13,7 @@ export function NoteWrapper({ lighter = false, }: { event: NDKEvent; - children: ReactNode; + children: ReactElement; repost?: boolean; root?: string; reply?: string; @@ -34,7 +34,10 @@ export function NoteWrapper({
- {children} + {cloneElement( + children, + event.kind === 1 ? { content: event.content } : { event: event } + )}
diff --git a/src/shared/widgets/global/articles.tsx b/src/shared/widgets/global/articles.tsx index fa19b01f..a303e818 100644 --- a/src/shared/widgets/global/articles.tsx +++ b/src/shared/widgets/global/articles.tsx @@ -1,7 +1,7 @@ import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk'; import { useQuery } from '@tanstack/react-query'; -import { useVirtualizer } from '@tanstack/react-virtual'; -import { useCallback, useRef } from 'react'; +import { useCallback } from 'react'; +import { VList } from 'virtua'; import { useNDK } from '@libs/ndk/provider'; @@ -25,27 +25,13 @@ export function GlobalArticlesWidget({ params }: { params: Widget }) { { refetchOnWindowFocus: false } ); - const parentRef = useRef(null); - const virtualizer = useVirtualizer({ - count: data ? data.length : 0, - getScrollElement: () => parentRef.current, - estimateSize: () => 650, - overscan: 4, - }); - const items = virtualizer.getVirtualItems(); - // render event match event kind const renderItem = useCallback( - (index: string | number) => { - const event: NDKEvent = data[index]; - if (!event) return; - + (event: NDKEvent) => { return ( -
- - - -
+ + + ); }, [data] @@ -54,40 +40,32 @@ export function GlobalArticlesWidget({ params }: { params: Widget }) { return ( -
+
{status === 'loading' ? (
- ) : items.length === 0 ? ( -
-
-
-

- There have been no new articles in the last 24 hours. + ) : data.length === 0 ? ( +

+
+ empty feeds +
+

+ Your newsfeed is empty +

+

+ Connect more people to explore more content

) : ( -
-
- {items.map((item) => renderItem(item.index))} -
-
+ + {data.map((item) => renderItem(item))} +
+ )}
diff --git a/src/shared/widgets/global/files.tsx b/src/shared/widgets/global/files.tsx index 56011e19..f6ce8c91 100644 --- a/src/shared/widgets/global/files.tsx +++ b/src/shared/widgets/global/files.tsx @@ -1,7 +1,7 @@ import { NDKEvent } from '@nostr-dev-kit/ndk'; import { useQuery } from '@tanstack/react-query'; -import { useVirtualizer } from '@tanstack/react-virtual'; -import { useCallback, useRef } from 'react'; +import { useCallback } from 'react'; +import { VList } from 'virtua'; import { useNDK } from '@libs/ndk/provider'; @@ -26,27 +26,13 @@ export function GlobalFilesWidget({ params }: { params: Widget }) { { refetchOnWindowFocus: false } ); - const parentRef = useRef(null); - const virtualizer = useVirtualizer({ - count: data ? data.length : 0, - getScrollElement: () => parentRef.current, - estimateSize: () => 650, - overscan: 4, - }); - const items = virtualizer.getVirtualItems(); - // render event match event kind const renderItem = useCallback( - (index: string | number) => { - const event: NDKEvent = data[index]; - if (!event) return; - + (event: NDKEvent) => { return ( -
- - - -
+ + + ); }, [data] @@ -55,40 +41,32 @@ export function GlobalFilesWidget({ params }: { params: Widget }) { return ( -
+
{status === 'loading' ? (
- ) : items.length === 0 ? ( -
-
-
-

- There have been no new files in the last 24 hours. + ) : data.length === 0 ? ( +

+
+ empty feeds +
+

+ Your newsfeed is empty +

+

+ Connect more people to explore more content

) : ( -
-
- {items.map((item) => renderItem(item.index))} -
-
+ + {data.map((item) => renderItem(item))} +
+ )}
diff --git a/src/shared/widgets/global/hashtag.tsx b/src/shared/widgets/global/hashtag.tsx index 374b87c0..60e828de 100644 --- a/src/shared/widgets/global/hashtag.tsx +++ b/src/shared/widgets/global/hashtag.tsx @@ -1,7 +1,7 @@ import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk'; import { useQuery } from '@tanstack/react-query'; -import { useVirtualizer } from '@tanstack/react-virtual'; -import { useCallback, useRef } from 'react'; +import { useCallback } from 'react'; +import { VList } from 'virtua'; import { useNDK } from '@libs/ndk/provider'; @@ -35,79 +35,35 @@ export function GlobalHashtagWidget({ params }: { params: Widget }) { { refetchOnWindowFocus: false } ); - const parentRef = useRef(null); - const virtualizer = useVirtualizer({ - count: data ? data.length : 0, - getScrollElement: () => parentRef.current, - estimateSize: () => 650, - overscan: 4, - }); - const items = virtualizer.getVirtualItems(); - // render event match event kind const renderItem = useCallback( - (index: string | number) => { - const event: NDKEvent = data[index]; - if (!event) return; - + (event: NDKEvent) => { switch (event.kind) { case NDKKind.Text: return ( -
- - - -
+ + + ); case NDKKind.Repost: - return ( -
- -
- ); + return ; case 1063: return ( -
- - - -
+ + + ); case NDKKind.Article: return ( -
- - - -
+ + + ); default: return ( -
- - - -
+ + + ); } }, @@ -117,40 +73,33 @@ export function GlobalHashtagWidget({ params }: { params: Widget }) { return ( -
+
{status === 'loading' ? (
- ) : items.length === 0 ? ( -
-
-
-

- There have been no new posts with this hashtag in the last 24 hours. + ) : data.length === 0 ? ( +

+
+ empty feeds +
+

+ Your newsfeed is empty +

+

+ Connect more people to explore more content

) : ( -
-
- {items.map((item) => renderItem(item.index))} -
-
+ + {data.map((item) => renderItem(item))} + +
+ )}
diff --git a/src/shared/widgets/local/articles.tsx b/src/shared/widgets/local/articles.tsx index fd49fc1e..035112bc 100644 --- a/src/shared/widgets/local/articles.tsx +++ b/src/shared/widgets/local/articles.tsx @@ -1,7 +1,7 @@ import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk'; import { useInfiniteQuery } from '@tanstack/react-query'; -import { useVirtualizer } from '@tanstack/react-virtual'; -import { useCallback, useMemo, useRef } from 'react'; +import { useCallback, useMemo } from 'react'; +import { VList } from 'virtua'; import { useStorage } from '@libs/storage/provider'; @@ -27,27 +27,15 @@ export function LocalArticlesWidget({ params }: { params: Widget }) { () => (data ? data.pages.flatMap((d: { data: DBEvent[] }) => d.data) : []), [data] ); - const parentRef = useRef(); - const virtualizer = useVirtualizer({ - count: hasNextPage ? dbEvents.length : dbEvents.length, - getScrollElement: () => parentRef.current, - estimateSize: () => 650, - overscan: 4, - }); - const items = virtualizer.getVirtualItems(); // render event match event kind const renderItem = useCallback( - (index: string | number) => { - const event: NDKEvent = data[index]; - if (!event) return; - + (dbEvent: DBEvent) => { + const event: NDKEvent = JSON.parse(dbEvent.event as string); return ( -
- - - -
+ + + ); }, [data] @@ -56,75 +44,59 @@ export function LocalArticlesWidget({ params }: { params: Widget }) { return ( -
+
{status === 'loading' ? (
- ) : items.length === 0 ? ( -
-
-
-

- There have been no new posts. + ) : dbEvents.length === 0 ? ( +

+
+ empty feeds +
+

+ Your newsfeed is empty +

+

+ Connect more people to explore more content

) : ( -
-
- {items.map((item) => renderItem(item.index))} + + {dbEvents.map((item) => renderItem(item))} +
+ {dbEvents.length > 0 ? ( + + ) : null}
-
+
+ )} - {isFetchingNextPage && ( -
-
- -
-
- )} -
- -
); diff --git a/src/shared/widgets/local/feeds.tsx b/src/shared/widgets/local/feeds.tsx index 23a4bf9a..5f0afa2e 100644 --- a/src/shared/widgets/local/feeds.tsx +++ b/src/shared/widgets/local/feeds.tsx @@ -1,7 +1,7 @@ import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk'; import { useInfiniteQuery } from '@tanstack/react-query'; -import { useVirtualizer } from '@tanstack/react-virtual'; -import { useCallback, useMemo, useRef } from 'react'; +import { useCallback, useMemo } from 'react'; +import { VList } from 'virtua'; import { useStorage } from '@libs/storage/provider'; @@ -36,80 +36,42 @@ export function LocalFeedsWidget({ params }: { params: Widget }) { () => (data ? data.pages.flatMap((d: { data: DBEvent[] }) => d.data) : []), [data] ); - const parentRef = useRef(); - const virtualizer = useVirtualizer({ - count: hasNextPage ? dbEvents.length : dbEvents.length, - getScrollElement: () => parentRef.current, - estimateSize: () => 650, - overscan: 4, - }); - const items = virtualizer.getVirtualItems(); // render event match event kind const renderItem = useCallback( - (index: string | number) => { - const dbEvent: DBEvent = dbEvents[index]; - if (!dbEvent) return; - + (dbEvent: DBEvent) => { const event: NDKEvent = JSON.parse(dbEvent.event as string); switch (event.kind) { case NDKKind.Text: return ( -
- - - -
+ + ); case NDKKind.Repost: - return ( -
- -
- ); + return ; case 1063: return ( -
- - - -
+ + + ); case NDKKind.Article: return ( -
- - - -
+ + + ); default: return ( -
- - - -
+ + + ); } }, @@ -119,75 +81,59 @@ export function LocalFeedsWidget({ params }: { params: Widget }) { return ( -
+
{status === 'loading' ? (
- ) : items.length === 0 ? ( -
-
-
-

- There have been no new posts. + ) : dbEvents.length === 0 ? ( +

+
+ empty feeds +
+

+ Your newsfeed is empty +

+

+ Connect more people to explore more content

) : ( -
-
- {items.map((item) => renderItem(item.index))} + + {dbEvents.map((item) => renderItem(item))} +
+ {dbEvents.length > 0 ? ( + + ) : null}
-
+
+ )} - {isFetchingNextPage && ( -
-
- -
-
- )} -
- -
); diff --git a/src/shared/widgets/local/files.tsx b/src/shared/widgets/local/files.tsx index d8328cc0..3282e753 100644 --- a/src/shared/widgets/local/files.tsx +++ b/src/shared/widgets/local/files.tsx @@ -1,7 +1,7 @@ import { NDKEvent } from '@nostr-dev-kit/ndk'; import { useInfiniteQuery } from '@tanstack/react-query'; -import { useVirtualizer } from '@tanstack/react-virtual'; -import { useCallback, useMemo, useRef } from 'react'; +import { useCallback, useMemo } from 'react'; +import { VList } from 'virtua'; import { useStorage } from '@libs/storage/provider'; @@ -27,27 +27,15 @@ export function LocalFilesWidget({ params }: { params: Widget }) { () => (data ? data.pages.flatMap((d: { data: DBEvent[] }) => d.data) : []), [data] ); - const parentRef = useRef(); - const virtualizer = useVirtualizer({ - count: hasNextPage ? dbEvents.length : dbEvents.length, - getScrollElement: () => parentRef.current, - estimateSize: () => 650, - overscan: 4, - }); - const items = virtualizer.getVirtualItems(); // render event match event kind const renderItem = useCallback( - (index: string | number) => { - const event: NDKEvent = data[index]; - if (!event) return; - + (dbEvent: DBEvent) => { + const event: NDKEvent = JSON.parse(dbEvent.event as string); return ( -
- - - -
+ + + ); }, [data] @@ -56,75 +44,59 @@ export function LocalFilesWidget({ params }: { params: Widget }) { return ( -
+
{status === 'loading' ? (
- ) : items.length === 0 ? ( -
-
-
-

- There have been no new posts. + ) : dbEvents.length === 0 ? ( +

+
+ empty feeds +
+

+ Your newsfeed is empty +

+

+ Connect more people to explore more content

) : ( -
-
- {items.map((item) => renderItem(item.index))} + + {dbEvents.map((item) => renderItem(item))} +
+ {dbEvents.length > 0 ? ( + + ) : null}
-
+
+ )} - {isFetchingNextPage && ( -
-
- -
-
- )} -
- -
); diff --git a/src/shared/widgets/local/follows.tsx b/src/shared/widgets/local/follows.tsx index 0d22b0f8..4f56762e 100644 --- a/src/shared/widgets/local/follows.tsx +++ b/src/shared/widgets/local/follows.tsx @@ -1,7 +1,7 @@ import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk'; import { useInfiniteQuery } from '@tanstack/react-query'; -import { useVirtualizer } from '@tanstack/react-virtual'; -import { useCallback, useMemo, useRef } from 'react'; +import { useCallback, useMemo } from 'react'; +import { VList } from 'virtua'; import { useStorage } from '@libs/storage/provider'; @@ -35,80 +35,42 @@ export function LocalFollowsWidget({ params }: { params: Widget }) { () => (data ? data.pages.flatMap((d: { data: DBEvent[] }) => d.data) : []), [data] ); - const parentRef = useRef(); - const virtualizer = useVirtualizer({ - count: hasNextPage ? dbEvents.length : dbEvents.length, - getScrollElement: () => parentRef.current, - estimateSize: () => 650, - overscan: 4, - }); - const items = virtualizer.getVirtualItems(); // render event match event kind const renderItem = useCallback( - (index: string | number) => { - const dbEvent: DBEvent = dbEvents[index]; - if (!dbEvent) return; - + (dbEvent: DBEvent) => { const event: NDKEvent = JSON.parse(dbEvent.event as string); switch (event.kind) { case NDKKind.Text: return ( -
- - - -
+ + ); case NDKKind.Repost: - return ( -
- -
- ); + return ; case 1063: return ( -
- - - -
+ + + ); case NDKKind.Article: return ( -
- - - -
+ + + ); default: return ( -
- - - -
+ + + ); } }, @@ -118,7 +80,7 @@ export function LocalFollowsWidget({ params }: { params: Widget }) { return ( -
+
{status === 'loading' ? (
@@ -140,59 +102,37 @@ export function LocalFollowsWidget({ params }: { params: Widget }) {
) : ( -
-
- {items.map((item) => renderItem(item.index))} + + {dbEvents.map((item) => renderItem(item))} +
+ {dbEvents.length > 0 ? ( + + ) : null}
-
+
+ )} - {isFetchingNextPage && ( -
-
- -
-
- )} -
- {dbEvents.length > 0 ? ( - - ) : null} -
); diff --git a/src/shared/widgets/local/network.tsx b/src/shared/widgets/local/network.tsx index 61e8c213..e0938d5f 100644 --- a/src/shared/widgets/local/network.tsx +++ b/src/shared/widgets/local/network.tsx @@ -1,7 +1,7 @@ import { NDKEvent, NDKFilter, NDKKind } from '@nostr-dev-kit/ndk'; import { useInfiniteQuery } from '@tanstack/react-query'; -import { useVirtualizer } from '@tanstack/react-virtual'; -import { useCallback, useEffect, useMemo, useRef } from 'react'; +import { useCallback, useEffect, useMemo } from 'react'; +import { VList } from 'virtua'; import { useStorage } from '@libs/storage/provider'; @@ -38,80 +38,42 @@ export function LocalNetworkWidget() { () => (data ? data.pages.flatMap((d: { data: DBEvent[] }) => d.data) : []), [data] ); - const parentRef = useRef(); - const virtualizer = useVirtualizer({ - count: hasNextPage ? dbEvents.length : dbEvents.length, - getScrollElement: () => parentRef.current, - estimateSize: () => 650, - overscan: 4, - }); - const items = virtualizer.getVirtualItems(); // render event match event kind const renderItem = useCallback( - (index: string | number) => { - const dbEvent: DBEvent = dbEvents[index]; - if (!dbEvent) return; - + (dbEvent: DBEvent) => { const event: NDKEvent = JSON.parse(dbEvent.event as string); switch (event.kind) { case NDKKind.Text: return ( -
- - - -
+ + ); case NDKKind.Repost: - return ( -
- -
- ); + return ; case 1063: return ( -
- - - -
+ + + ); case NDKKind.Article: return ( -
- - - -
+ + + ); default: return ( -
- - - -
+ + + ); } }, @@ -125,7 +87,7 @@ export function LocalNetworkWidget() { const filter: NDKFilter = { kinds: [NDKKind.Text, NDKKind.Repost], authors: db.account.network, - since: db.account.last_login_at ?? Math.floor(Date.now() / 1000), + since: Math.floor(Date.now() / 1000), }; sub(filter, async (event) => { @@ -138,7 +100,7 @@ export function LocalNetworkWidget() { return ( -
+
{status === 'loading' ? (
@@ -160,59 +122,37 @@ export function LocalNetworkWidget() {
) : ( -
-
- {items.map((item) => renderItem(item.index))} + + {dbEvents.map((item) => renderItem(item))} +
+ {dbEvents.length > 0 ? ( + + ) : null}
-
+
+ )} - {isFetchingNextPage && ( -
-
- -
-
- )} -
- {dbEvents.length > 0 ? ( - - ) : null} -
); diff --git a/src/shared/widgets/local/user.tsx b/src/shared/widgets/local/user.tsx index fc920bc9..682339be 100644 --- a/src/shared/widgets/local/user.tsx +++ b/src/shared/widgets/local/user.tsx @@ -1,7 +1,7 @@ import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk'; import { useQuery } from '@tanstack/react-query'; -import { useVirtualizer } from '@tanstack/react-virtual'; -import { useCallback, useRef } from 'react'; +import { useCallback } from 'react'; +import { VList } from 'virtua'; import { useNDK } from '@libs/ndk/provider'; @@ -41,79 +41,35 @@ export function LocalUserWidget({ params }: { params: Widget }) { } ); - const parentRef = useRef(null); - const virtualizer = useVirtualizer({ - count: data ? data.length : 0, - getScrollElement: () => parentRef.current, - estimateSize: () => 650, - overscan: 4, - }); - const items = virtualizer.getVirtualItems(); - // render event match event kind const renderItem = useCallback( - (index: string | number) => { - const event: NDKEvent = data[index]; - if (!event) return; - + (event: NDKEvent) => { switch (event.kind) { case NDKKind.Text: return ( -
- - - -
+ + + ); case NDKKind.Repost: - return ( -
- -
- ); + return ; case 1063: return ( -
- - - -
+ + + ); case NDKKind.Article: return ( -
- - - -
+ + + ); default: return ( -
- - - -
+ + + ); } }, @@ -123,7 +79,7 @@ export function LocalUserWidget({ params }: { params: Widget }) { return ( -
+
@@ -136,7 +92,7 @@ export function LocalUserWidget({ params }: { params: Widget }) {
- ) : items.length === 0 ? ( + ) : data.length === 0 ? (
@@ -147,22 +103,10 @@ export function LocalUserWidget({ params }: { params: Widget }) {
) : ( -
-
- {items.map((item) => renderItem(item.index))} -
-
+ + {data.map((item) => renderItem(item))} +
+ )}
diff --git a/src/utils/hooks/useNostr.ts b/src/utils/hooks/useNostr.ts index 4afbdcad..98b54626 100644 --- a/src/utils/hooks/useNostr.ts +++ b/src/utils/hooks/useNostr.ts @@ -9,6 +9,7 @@ import { import { message, open } from '@tauri-apps/api/dialog'; import { Body, fetch } from '@tauri-apps/api/http'; import { LRUCache } from 'lru-cache'; +import { NostrEventExt } from 'nostr-fetch'; import { nip19 } from 'nostr-tools'; import { useMemo } from 'react'; @@ -220,15 +221,19 @@ export function useNostr() { }; const fetchNIP04Messages = async (sender: string) => { - const senderMessages = await fetcher.fetchAllEvents( - relayUrls, - { - kinds: [NDKKind.EncryptedDirectMessage], - authors: [sender], - '#p': [db.account.pubkey], - }, - { since: 0 } - ); + let senderMessages: NostrEventExt[] = []; + + if (sender !== db.account.pubkey) { + senderMessages = await fetcher.fetchAllEvents( + relayUrls, + { + kinds: [NDKKind.EncryptedDirectMessage], + authors: [sender], + '#p': [db.account.pubkey], + }, + { since: 0 } + ); + } const userMessages = await fetcher.fetchAllEvents( relayUrls,