diff --git a/package.json b/package.json
index 86bae666..79d3620a 100644
--- a/package.json
+++ b/package.json
@@ -76,13 +76,14 @@
"react-markdown": "^8.0.7",
"react-router-dom": "^6.17.0",
"react-string-replace": "^1.1.1",
+ "react-xarrows": "^2.0.2",
"reactflow": "^11.9.4",
"remark-gfm": "^3.0.1",
"sonner": "^1.0.3",
"tailwind-scrollbar": "^3.0.5",
"tauri-controls": "^0.2.0",
"tippy.js": "^6.3.7",
- "virtua": "^0.13.0",
+ "virtua": "^0.14.0",
"zustand": "^4.4.3"
},
"devDependencies": {
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index fe3d5304..06a1b85a 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -179,6 +179,9 @@ dependencies:
react-string-replace:
specifier: ^1.1.1
version: 1.1.1
+ react-xarrows:
+ specifier: ^2.0.2
+ version: 2.0.2(react@18.2.0)
reactflow:
specifier: ^11.9.4
version: 11.9.4(@types/react@18.2.29)(react-dom@18.2.0)(react@18.2.0)
@@ -198,8 +201,8 @@ dependencies:
specifier: ^6.3.7
version: 6.3.7
virtua:
- specifier: ^0.13.0
- version: 0.13.0(react-dom@18.2.0)(react@18.2.0)
+ specifier: ^0.14.0
+ version: 0.14.0(react-dom@18.2.0)(react@18.2.0)
zustand:
specifier: ^4.4.3
version: 4.4.3(@types/react@18.2.29)(react@18.2.0)
@@ -4688,7 +4691,6 @@ packages:
/lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
- dev: true
/log-update@5.0.1:
resolution: {integrity: sha512-5UtUDQ/6edw4ofyljDNcOVJQ4c7OjDro4h3y8e1GQL5iYElYclVHJ3zeWchylvMaKnDbDilC8irOVyexnA/Slw==}
@@ -5947,6 +5949,17 @@ packages:
tslib: 2.6.2
dev: false
+ /react-xarrows@2.0.2(react@18.2.0):
+ resolution: {integrity: sha512-tDlAqaxHNmy0vegW/6NdhoWyXJq1LANX/WUAlHyzoHe9BwFVnJPPDghmDjYeVr7XWFmBrVTUrHsrW7GKYI6HtQ==}
+ peerDependencies:
+ react: '>=16.8.0'
+ dependencies:
+ '@types/prop-types': 15.7.9
+ lodash: 4.17.21
+ prop-types: 15.8.1
+ react: 18.2.0
+ dev: false
+
/react@18.2.0:
resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==}
engines: {node: '>=0.10.0'}
@@ -6728,8 +6741,8 @@ packages:
vfile-message: 3.1.4
dev: false
- /virtua@0.13.0(react-dom@18.2.0)(react@18.2.0):
- resolution: {integrity: sha512-NiM+3lhl/XMLWsT+Fc+rcMQrsAe7PDRvncu6CjP5UEgDtulIo05KAaugrJAr/ptBofP/iAnlZK/X0Bjd+UkjIQ==}
+ /virtua@0.14.0(react-dom@18.2.0)(react@18.2.0):
+ resolution: {integrity: sha512-+g3fxgFuQCqw6PpU5qzTRKhbSUGOeMEap0VbPaIRB1RiK5MfLiGXIMwID1iX1DmvUC/SqsBsJfVvlUaPNGWSVQ==}
peerDependencies:
react: '>=16.14.0'
react-dom: '>=16.14.0'
diff --git a/src/app/notes/article.tsx b/src/app/notes/article.tsx
index 5374736b..1abcf764 100644
--- a/src/app/notes/article.tsx
+++ b/src/app/notes/article.tsx
@@ -15,7 +15,7 @@ import {
NoteStats,
UnknownNote,
} from '@shared/notes';
-import { RepliesList } from '@shared/notes/replies/list';
+import { ReplyList } from '@shared/notes/replies/list';
import { NoteSkeleton } from '@shared/notes/skeleton';
import { User } from '@shared/user';
@@ -117,7 +117,7 @@ export function ArticleNoteScreen() {
-
+
>
)}
diff --git a/src/app/notes/text.tsx b/src/app/notes/text.tsx
index 1d08cdae..ca6fa72c 100644
--- a/src/app/notes/text.tsx
+++ b/src/app/notes/text.tsx
@@ -17,7 +17,7 @@ import {
TextNote,
UnknownNote,
} from '@shared/notes';
-import { RepliesList } from '@shared/notes/replies/list';
+import { ReplyList } from '@shared/notes/replies/list';
import { User } from '@shared/user';
import { useEvent } from '@utils/hooks/useEvent';
@@ -119,7 +119,7 @@ export function TextNoteScreen() {
)}
-
+
diff --git a/src/shared/accounts/active.tsx b/src/shared/accounts/active.tsx
index 8526741b..a199a835 100644
--- a/src/shared/accounts/active.tsx
+++ b/src/shared/accounts/active.tsx
@@ -7,6 +7,7 @@ import { Link } from 'react-router-dom';
import { useStorage } from '@libs/storage/provider';
import { AccountMoreActions } from '@shared/accounts/more';
+import { NetworkStatusIndicator } from '@shared/networkStatusIndicator';
import { useActivities } from '@stores/activities';
@@ -78,7 +79,7 @@ export function ActiveAccount() {
/>
-
+
diff --git a/src/shared/button.tsx b/src/shared/button.tsx
deleted file mode 100644
index c20ecb29..00000000
--- a/src/shared/button.tsx
+++ /dev/null
@@ -1,50 +0,0 @@
-import { ReactNode } from 'react';
-import { twMerge } from 'tailwind-merge';
-
-export function Button({
- preset,
- children,
- disabled = false,
- onClick = undefined,
-}: {
- preset: 'small' | 'publish' | 'large' | 'large-alt';
- children: ReactNode;
- disabled?: boolean;
- onClick?: () => void;
-}) {
- let preClass: string;
- switch (preset) {
- case 'small':
- preClass =
- 'w-min h-9 px-4 bg-neutral-400 dark:bg-neutral-600 rounded-md text-sm font-medium text-white hover:bg-blue-600';
- break;
- case 'publish':
- preClass =
- 'w-min h-9 px-4 bg-blue-500 rounded-md text-sm font-medium text-white hover:bg-blue-600';
- break;
- case 'large':
- preClass =
- 'h-11 w-full bg-blue-500 rounded-lg font-medium text-white hover:bg-blue-600';
- break;
- case 'large-alt':
- preClass =
- 'h-11 w-full bg-neutral-400 dark:bg-neutral-600 rounded-lg font-medium text-white hover:bg-white/20';
- break;
- default:
- break;
- }
-
- return (
-
- );
-}
diff --git a/src/shared/networkStatusIndicator.tsx b/src/shared/networkStatusIndicator.tsx
index dcf623ef..0f46526a 100644
--- a/src/shared/networkStatusIndicator.tsx
+++ b/src/shared/networkStatusIndicator.tsx
@@ -1,3 +1,5 @@
+import { twMerge } from 'tailwind-merge';
+
import { useNetworkStatus } from '@utils/hooks/useNetworkStatus';
export function NetworkStatusIndicator() {
@@ -5,9 +7,10 @@ export function NetworkStatusIndicator() {
return (
);
}
diff --git a/src/shared/notes/replies/form.tsx b/src/shared/notes/replies/form.tsx
index e4b92c69..0fe4fbc8 100644
--- a/src/shared/notes/replies/form.tsx
+++ b/src/shared/notes/replies/form.tsx
@@ -1,14 +1,14 @@
import { useState } from 'react';
-import { Button } from '@shared/button';
+import { useStorage } from '@libs/storage/provider';
+
+import { User } from '@shared/user';
import { useNostr } from '@utils/hooks/useNostr';
-import { useProfile } from '@utils/hooks/useProfile';
-import { displayNpub } from '@utils/shortenKey';
-export function NoteReplyForm({ id, pubkey }: { id: string; pubkey: string }) {
+export function NoteReplyForm({ id }: { id: string }) {
const { publish } = useNostr();
- const { status, user } = useProfile(pubkey);
+ const { db } = useStorage();
const [value, setValue] = useState('');
@@ -23,47 +23,23 @@ export function NoteReplyForm({ id, pubkey }: { id: string; pubkey: string }) {
};
return (
-
-
+
+
+
-
- {status === 'loading' ? (
-
Loading
- ) : (
-
-
-
-
-
-
-
Reply as
-
- {user?.name || displayNpub(pubkey, 16)}
-
-
-
-
-
-
-
- )}
+
);
diff --git a/src/shared/notes/replies/item.tsx b/src/shared/notes/replies/item.tsx
index b7c11997..07ed5e2b 100644
--- a/src/shared/notes/replies/item.tsx
+++ b/src/shared/notes/replies/item.tsx
@@ -1,34 +1,53 @@
+import * as Collapsible from '@radix-ui/react-collapsible';
+import { useState } from 'react';
+import { twMerge } from 'tailwind-merge';
+
+import { NavArrowDownIcon } from '@shared/icons';
import { MemoizedTextNote, NoteActions, SubReply } from '@shared/notes';
import { User } from '@shared/user';
import { NDKEventWithReplies } from '@utils/types';
export function Reply({ event, root }: { event: NDKEventWithReplies; root?: string }) {
+ const [open, setOpen] = useState(false);
+
return (
-
-
-
-
-
-
-
-
-
-
+
+
+
+
-
- {event.replies ? (
- event.replies.map((sub) =>
)
- ) : (
-
- )}
-
+
+
+
+ {event.replies?.length > 0 ? (
+
+
+
+
+ {event.replies?.length +
+ ' ' +
+ (event.replies?.length === 1 ? 'reply' : 'replies')}
+
+
+
+ {event.replies?.map((sub) => )}
+
+
+ ) : null}
+
);
diff --git a/src/shared/notes/replies/list.tsx b/src/shared/notes/replies/list.tsx
index c3e8b739..5f118848 100644
--- a/src/shared/notes/replies/list.tsx
+++ b/src/shared/notes/replies/list.tsx
@@ -1,11 +1,12 @@
import { useEffect, useState } from 'react';
-import { NoteSkeleton, Reply } from '@shared/notes';
+import { LoaderIcon } from '@shared/icons';
+import { Reply } from '@shared/notes';
import { useNostr } from '@utils/hooks/useNostr';
import { NDKEventWithReplies } from '@utils/types';
-export function RepliesList({ id }: { id: string }) {
+export function ReplyList({ id }: { id: string }) {
const { fetchAllReplies, sub } = useNostr();
const [data, setData] = useState
(null);
@@ -36,33 +37,28 @@ export function RepliesList({ id }: { id: string }) {
if (!data) {
return (
-
-
-
+
);
}
return (
-
-
- {data?.length || 0} replies
-
-
- {data?.length === 0 ? (
-
-
-
👋
-
- Share your thought on it...
-
-
+
+ {data?.length === 0 ? (
+
+
+
👋
+
+ Share your thought on it...
+
- ) : (
- data.map((event) =>
)
- )}
-
+
+ ) : (
+ data.map((event) =>
)
+ )}
);
}
diff --git a/src/shared/notes/replies/sub.tsx b/src/shared/notes/replies/sub.tsx
index b8424d31..552063ce 100644
--- a/src/shared/notes/replies/sub.tsx
+++ b/src/shared/notes/replies/sub.tsx
@@ -5,7 +5,7 @@ import { User } from '@shared/user';
export function SubReply({ event }: { event: NDKEvent }) {
return (
-
+
diff --git a/src/shared/user.tsx b/src/shared/user.tsx
index 93b30f91..cd804337 100644
--- a/src/shared/user.tsx
+++ b/src/shared/user.tsx
@@ -32,6 +32,7 @@ export const User = memo(function User({
| 'chat'
| 'large'
| 'thread'
+ | 'miniavatar'
| 'avatar'
| 'stacked'
| 'ministacked';
@@ -207,6 +208,28 @@ export const User = memo(function User({
);
}
+ if (variant === 'miniavatar') {
+ return (
+
+
+
+
+
+
+ );
+ }
+
if (variant === 'stacked') {
return (
diff --git a/src/shared/widgets/local/thread.tsx b/src/shared/widgets/local/thread.tsx
index 0e432061..63809270 100644
--- a/src/shared/widgets/local/thread.tsx
+++ b/src/shared/widgets/local/thread.tsx
@@ -1,8 +1,7 @@
import { NDKEvent, NDKKind } from '@nostr-dev-kit/ndk';
import { useCallback } from 'react';
-import { useStorage } from '@libs/storage/provider';
-
+import { LoaderIcon } from '@shared/icons';
import {
MemoizedArticleNote,
MemoizedFileNote,
@@ -12,8 +11,7 @@ import {
NoteStats,
UnknownNote,
} from '@shared/notes';
-import { RepliesList } from '@shared/notes/replies/list';
-import { NoteSkeleton } from '@shared/notes/skeleton';
+import { ReplyList } from '@shared/notes/replies/list';
import { TitleBar } from '@shared/titleBar';
import { User } from '@shared/user';
import { WidgetWrapper } from '@shared/widgets';
@@ -22,7 +20,6 @@ import { useEvent } from '@utils/hooks/useEvent';
import { Widget } from '@utils/types';
export function LocalThreadWidget({ params }: { params: Widget }) {
- const { db } = useStorage();
const { status, data } = useEvent(params.content);
const renderKind = useCallback(
@@ -44,31 +41,22 @@ export function LocalThreadWidget({ params }: { params: Widget }) {
return (
-
+
{status === 'loading' ? (
-
-
-
-
+
+
) : (
-
-
-
-
{renderKind(data)}
-
-
+
)}
-
-
-
-
-
+
+
+
+
);
diff --git a/src/stores/sidebar.ts b/src/stores/sidebar.ts
deleted file mode 100644
index f8486e1e..00000000
--- a/src/stores/sidebar.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-import { create } from 'zustand';
-import { createJSONStorage, persist } from 'zustand/middleware';
-
-interface SidebarState {
- feeds: boolean;
- chats: boolean;
- communities: boolean;
- integrations: boolean;
- toggleFeeds: () => void;
- toggleChats: () => void;
- toggleCommunities: () => void;
- toggleIntegrations: () => void;
-}
-
-export const useSidebar = create
()(
- persist(
- (set) => ({
- feeds: true,
- chats: false,
- communities: true,
- integrations: true,
- toggleFeeds: () => set((state) => ({ feeds: !state.feeds })),
- toggleChats: () => set((state) => ({ chats: !state.chats })),
- toggleCommunities: () => set((state) => ({ communities: !state.communities })),
- toggleIntegrations: () => set((state) => ({ integrations: !state.integrations })),
- }),
- {
- name: 'sidebar',
- storage: createJSONStorage(() => localStorage),
- }
- )
-);