diff --git a/package.json b/package.json index 0c50c4b3..fda01962 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "react-hook-form": "^7.43.8", "react-player": "^2.12.0", "react-string-replace": "^1.1.0", + "react-virtuoso": "^4.1.1", "tauri-plugin-sql-api": "github:tauri-apps/tauri-plugin-sql", "unique-names-generator": "^4.7.1", "ws": "^8.13.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 96dc9c39..d55cb2c1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -52,6 +52,7 @@ specifiers: react-hook-form: ^7.43.8 react-player: ^2.12.0 react-string-replace: ^1.1.0 + react-virtuoso: ^4.1.1 tailwindcss: ^3.2.7 tauri-plugin-sql-api: github:tauri-apps/tauri-plugin-sql typescript: ^4.9.5 @@ -89,6 +90,7 @@ dependencies: react-hook-form: 7.43.8_react@18.2.0 react-player: 2.12.0_react@18.2.0 react-string-replace: 1.1.0 + react-virtuoso: 4.1.1_biqbaboplfbrettd7655fr4n2y tauri-plugin-sql-api: github.com/tauri-apps/tauri-plugin-sql/3a8b9a6b244df7512bc5ef8692cebdedbab3ccce unique-names-generator: 4.7.1 ws: 8.13.0 @@ -4514,6 +4516,18 @@ packages: tslib: 2.5.0 dev: false + /react-virtuoso/4.1.1_biqbaboplfbrettd7655fr4n2y: + resolution: + { integrity: sha512-G2lyifG5UIRZI9vgcBt+6OLDL6CO5/O6YiGS+O9z+VNRjVSTioSwfBC7sVSLspYq7iyL60aIXlVqSKVJiSVhlg== } + 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== } diff --git a/src/components/columns/navigator/messages/index.tsx b/src/components/columns/navigator/chats/index.tsx similarity index 57% rename from src/components/columns/navigator/messages/index.tsx rename to src/components/columns/navigator/chats/index.tsx index b0852b3d..f9169731 100644 --- a/src/components/columns/navigator/messages/index.tsx +++ b/src/components/columns/navigator/chats/index.tsx @@ -1,29 +1,14 @@ -import { MessageList } from '@components/columns/navigator/messages/list'; - -import { activeAccountAtom } from '@stores/account'; - -import { getAllFollowsByID } from '@utils/storage'; - import * as Collapsible from '@radix-ui/react-collapsible'; import { TriangleUpIcon } from '@radix-ui/react-icons'; -import { useAtom } from 'jotai'; -import { useEffect, useState } from 'react'; +import { useState } from 'react'; -export default function Messages() { +export default function Chats() { const [open, setOpen] = useState(true); - const [follows, setFollows] = useState([]); - const [activeAccount] = useAtom(activeAccountAtom); - - useEffect(() => { - getAllFollowsByID(activeAccount.id) - .then((res: any) => setFollows(res)) - .catch(console.error); - }, [activeAccount.id]); return (
- +
- - - +
); diff --git a/src/components/columns/navigator/index.tsx b/src/components/columns/navigator/index.tsx index 4b65af68..324e1582 100644 --- a/src/components/columns/navigator/index.tsx +++ b/src/components/columns/navigator/index.tsx @@ -1,4 +1,4 @@ -import Messages from '@components/columns/navigator/messages'; +import Chats from '@components/columns/navigator/chats'; import Newsfeed from '@components/columns/navigator/newsfeed'; export default function NavigatorColumn() { @@ -6,8 +6,8 @@ export default function NavigatorColumn() {
{/* Newsfeed */} - {/* Messages */} - + {/* Chats */} +
); } diff --git a/src/components/columns/navigator/messages/list.tsx b/src/components/columns/navigator/messages/list.tsx deleted file mode 100644 index 0dc60dc2..00000000 --- a/src/components/columns/navigator/messages/list.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { UserMini } from '@components/user/mini'; - -import { useVirtualizer } from '@tanstack/react-virtual'; -import { Suspense, memo, useRef } from 'react'; - -export const MessageList = memo(function MessageList({ data }: { data: any }) { - const parentRef = useRef(null); - - const virtualizer = useVirtualizer({ - count: data.length, - estimateSize: () => 32, - getScrollElement: () => parentRef.current, - }); - const items = virtualizer.getVirtualItems(); - - return ( -
- Loading...

}> - {items.length > 0 && ( -
-
- {items.map((virtualRow) => ( -
- -
- ))} -
-
- )} -
-
- ); -}); diff --git a/src/components/imageWithFallback.tsx b/src/components/imageWithFallback.tsx index eebf871f..dcf3ed97 100644 --- a/src/components/imageWithFallback.tsx +++ b/src/components/imageWithFallback.tsx @@ -1,4 +1,5 @@ -import Avatar from 'boring-avatars'; +import { DEFAULT_AVATAR } from '@stores/constants'; + import Image from 'next/image'; import { memo, useEffect, useState } from 'react'; @@ -20,27 +21,6 @@ export const ImageWithFallback = memo(function ImageWithFallback({ }, [src]); return ( - <> - {error ? ( - - ) : ( - {alt} - )} - + {alt} ); }); diff --git a/src/components/user/mini.tsx b/src/components/user/mini.tsx index ee29f09d..b5fa2bdd 100644 --- a/src/components/user/mini.tsx +++ b/src/components/user/mini.tsx @@ -1,59 +1,44 @@ import { ImageWithFallback } from '@components/imageWithFallback'; -import { createCacheProfile, getCacheProfile } from '@utils/storage'; +import { DEFAULT_AVATAR } from '@stores/constants'; + +import { getCacheProfile } from '@utils/storage'; import { truncate } from '@utils/truncate'; -import { fetch } from '@tauri-apps/api/http'; -import Avatar from 'boring-avatars'; -import destr from 'destr'; -import { memo, useCallback, useEffect, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; -export const UserMini = memo(function UserMini({ pubkey }: { pubkey: string }) { +export const UserMini = ({ pubkey }: { pubkey: string }) => { const [profile, setProfile] = useState(null); - const fetchProfile = useCallback(async (id: string) => { - const res = await fetch(`https://rbr.bio/${id}/metadata.json`, { - method: 'GET', - timeout: 30, - }); - return res.data; + const fetchCacheProfile = useCallback(async (id: string) => { + const res = await getCacheProfile(id); + const data = JSON.parse(res.metadata); + setProfile(data); }, []); useEffect(() => { - getCacheProfile(pubkey).then((res) => { - if (res) { - setProfile(destr(res.metadata)); - } else { - fetchProfile(pubkey) - .then((res: any) => { - setProfile(destr(res.content)); - createCacheProfile(pubkey, res.content); - }) - .catch(console.error); - } - }); - }, [fetchProfile, pubkey]); + fetchCacheProfile(pubkey).catch(console.error); + }, [fetchCacheProfile, pubkey]); - return ( -
-
- {profile?.picture ? ( - - ) : ( - +
+ - )} +
+
+

+ {profile?.display_name || profile?.name || truncate(pubkey, 16, ' .... ')} +

+
-
-

- {profile?.display_name || profile?.name || truncate(pubkey, 16, ' .... ')} -

-
-
- ); -}); + ); + } else { + return <>; + } +}; diff --git a/src/stores/constants.tsx b/src/stores/constants.tsx new file mode 100644 index 00000000..85705f9a --- /dev/null +++ b/src/stores/constants.tsx @@ -0,0 +1 @@ +export const DEFAULT_AVATAR = 'https://void.cat/d/KmypFh2fBdYCEvyJrPiN89.webp';