From 10f2f530c798aaabfb3ba533b742caf429eab607 Mon Sep 17 00:00:00 2001 From: Ren Amamiya <123083837+reyamir@users.noreply.github.com> Date: Mon, 12 Jun 2023 13:40:40 +0700 Subject: [PATCH] add thread --- pnpm-lock.yaml | 14 +-- src/app/channel/components/item.tsx | 4 +- src/app/channel/components/messages/item.tsx | 6 +- src/app/chat/components/messages/item.tsx | 6 +- src/app/note/_default.page.tsx | 1 - src/app/note/components/metadata.tsx | 82 ------------- src/app/note/components/replies/list.tsx | 63 ---------- src/app/note/components/wrapper.tsx | 22 ---- src/app/note/layout.tsx | 14 --- src/app/note/pages/index.page.tsx | 63 ---------- src/app/space/components/add.tsx | 1 - src/app/space/components/blocks/feed.tsx | 20 +++- src/app/space/components/blocks/following.tsx | 22 ++-- src/app/space/components/blocks/image.tsx | 2 +- src/app/space/components/blocks/thread.tsx | 65 ++++++++++ .../components/notes}/base.tsx | 24 ++-- .../components/notes}/kind1.tsx | 8 +- .../components/notes}/kind1063.tsx | 0 .../components/notes}/mentions/note.tsx | 10 +- .../components/notes}/mentions/user.tsx | 0 src/app/space/components/notes/metadata.tsx | 113 ++++++++++++++++++ .../components/notes}/metadata/reply.tsx | 8 +- .../components/notes}/metadata/repost.tsx | 8 +- .../components/notes}/metadata/zap.tsx | 8 +- .../components/notes}/parent.tsx | 10 +- .../components/notes}/preview/image.tsx | 0 .../components/notes}/preview/link.tsx | 9 +- .../components/notes}/preview/video.tsx | 0 .../components/notes}/quoteRepost.tsx | 14 ++- .../components/notes}/replies/form.tsx | 0 .../components/notes}/replies/item.tsx | 6 +- .../space/components/notes/replies/list.tsx | 42 +++++++ .../components/notes}/rootNote.tsx | 10 +- .../components/notes}/skeleton.tsx | 0 src/app/space/components/notes/wrapper.tsx | 34 ++++++ .../components/user/default.tsx | 0 .../{note => space}/components/user/quote.tsx | 0 .../{note => space}/components/user/reply.tsx | 0 .../components/user/repost.tsx | 0 src/app/space/pages/index.page.tsx | 28 +++-- src/shared/icons/index.tsx | 1 + src/shared/icons/loader.tsx | 29 +++++ src/shared/navigation.tsx | 2 +- src/stores/accounts.tsx | 29 ++++- 44 files changed, 432 insertions(+), 346 deletions(-) delete mode 100644 src/app/note/_default.page.tsx delete mode 100644 src/app/note/components/metadata.tsx delete mode 100644 src/app/note/components/replies/list.tsx delete mode 100644 src/app/note/components/wrapper.tsx delete mode 100644 src/app/note/layout.tsx delete mode 100644 src/app/note/pages/index.page.tsx create mode 100644 src/app/space/components/blocks/thread.tsx rename src/app/{note/components => space/components/notes}/base.tsx (57%) rename src/app/{note/components => space/components/notes}/kind1.tsx (79%) rename src/app/{note/components => space/components/notes}/kind1063.tsx (100%) rename src/app/{note/components => space/components/notes}/mentions/note.tsx (80%) rename src/app/{note/components => space/components/notes}/mentions/user.tsx (100%) create mode 100644 src/app/space/components/notes/metadata.tsx rename src/app/{note/components => space/components/notes}/metadata/reply.tsx (96%) rename src/app/{note/components => space/components/notes}/metadata/repost.tsx (89%) rename src/app/{note/components => space/components/notes}/metadata/zap.tsx (71%) rename src/app/{note/components => space/components/notes}/parent.tsx (81%) rename src/app/{note/components => space/components/notes}/preview/image.tsx (100%) rename src/app/{note/components => space/components/notes}/preview/link.tsx (74%) rename src/app/{note/components => space/components/notes}/preview/video.tsx (100%) rename src/app/{note/components => space/components/notes}/quoteRepost.tsx (62%) rename src/app/{note/components => space/components/notes}/replies/form.tsx (100%) rename src/app/{note/components => space/components/notes}/replies/item.tsx (72%) create mode 100644 src/app/space/components/notes/replies/list.tsx rename src/app/{note/components => space/components/notes}/rootNote.tsx (89%) rename src/app/{note/components => space/components/notes}/skeleton.tsx (100%) create mode 100644 src/app/space/components/notes/wrapper.tsx rename src/app/{note => space}/components/user/default.tsx (100%) rename src/app/{note => space}/components/user/quote.tsx (100%) rename src/app/{note => space}/components/user/reply.tsx (100%) rename src/app/{note => space}/components/user/repost.tsx (100%) create mode 100644 src/shared/icons/loader.tsx diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 25a6bd92..07418696 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1322,7 +1322,7 @@ packages: postcss: ^8.1.0 dependencies: browserslist: 4.21.7 - caniuse-lite: 1.0.30001498 + caniuse-lite: 1.0.30001500 fraction.js: 4.2.0 normalize-range: 0.1.2 picocolors: 1.0.0 @@ -1364,7 +1364,7 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001498 + caniuse-lite: 1.0.30001500 electron-to-chromium: 1.4.427 node-releases: 2.0.12 update-browserslist-db: 1.0.11(browserslist@4.21.7) @@ -1414,8 +1414,8 @@ packages: engines: {node: '>=6'} dev: false - /caniuse-lite@1.0.30001498: - resolution: {integrity: sha512-LFInN2zAwx3ANrGCDZ5AKKJroHqNKyjXitdV5zRIVIaQlXKj3GmxUKagoKsjqUfckpAObPCEWnk5EeMlyMWcgw==} + /caniuse-lite@1.0.30001500: + resolution: {integrity: sha512-wSpY0RQnEwFwVZ063ggl3M4ALRP9OSknL0enldDEydIGzuShbtuWwaedB/RfkxsGF3P0kf1Tnv/nTtJEbjzc4Q==} dev: true /ccount@2.0.1: @@ -4022,8 +4022,8 @@ packages: glob: 7.2.3 dev: false - /rollup@3.24.1: - resolution: {integrity: sha512-REHe5dx30ERBRFS0iENPHy+t6wtSEYkjrhwNsLyh3qpRaZ1+aylvMUdMBUHWUD/RjjLmLzEvY8Z9XRlpcdIkHA==} + /rollup@3.25.1: + resolution: {integrity: sha512-tywOR+rwIt5m2ZAWSe5AIJcTat8vGlnPFAv15ycCrw33t6iFsXZ6mzHVFh2psSjxQPmI+xgzMZZizUAukBI4aQ==} engines: {node: '>=14.18.0', npm: '>=8.0.0'} hasBin: true optionalDependencies: @@ -4852,7 +4852,7 @@ packages: '@types/node': 18.16.17 esbuild: 0.17.19 postcss: 8.4.24 - rollup: 3.24.1 + rollup: 3.25.1 optionalDependencies: fsevents: 2.3.2 dev: true diff --git a/src/app/channel/components/item.tsx b/src/app/channel/components/item.tsx index e2419fa9..053ffc81 100644 --- a/src/app/channel/components/item.tsx +++ b/src/app/channel/components/item.tsx @@ -21,13 +21,13 @@ export function ChannelsListItem({ data }: { data: any }) { >
- # + #
{channel?.name}
diff --git a/src/app/channel/components/messages/item.tsx b/src/app/channel/components/messages/item.tsx index 905f3da9..195df236 100644 --- a/src/app/channel/components/messages/item.tsx +++ b/src/app/channel/components/messages/item.tsx @@ -3,9 +3,9 @@ import { MessageMuteButton } from "@app/channel/components/messages/muteButton"; import { MessageReplyButton } from "@app/channel/components/messages/replyButton"; import { ChannelMessageUser } from "@app/channel/components/messages/user"; import { ChannelMessageUserMute } from "@app/channel/components/messages/userMute"; -import { MentionNote } from "@app/note/components/mentions/note"; -import { ImagePreview } from "@app/note/components/preview/image"; -import { VideoPreview } from "@app/note/components/preview/video"; +import { MentionNote } from "@app/space/components/notes/mentions/note"; +import { ImagePreview } from "@app/space/components/notes/preview/image"; +import { VideoPreview } from "@app/space/components/notes/preview/video"; import { noteParser } from "@utils/parser"; import { useMemo, useState } from "react"; diff --git a/src/app/chat/components/messages/item.tsx b/src/app/chat/components/messages/item.tsx index 73456eec..921c4176 100644 --- a/src/app/chat/components/messages/item.tsx +++ b/src/app/chat/components/messages/item.tsx @@ -1,8 +1,8 @@ import { ChatMessageUser } from "@app/chat/components/messages/user"; import { useDecryptMessage } from "@app/chat/hooks/useDecryptMessage"; -import { MentionNote } from "@app/note/components/mentions/note"; -import { ImagePreview } from "@app/note/components/preview/image"; -import { VideoPreview } from "@app/note/components/preview/video"; +import { MentionNote } from "@app/space/components/notes/mentions/note"; +import { ImagePreview } from "@app/space/components/notes/preview/image"; +import { VideoPreview } from "@app/space/components/notes/preview/video"; import { noteParser } from "@utils/parser"; import { memo } from "react"; diff --git a/src/app/note/_default.page.tsx b/src/app/note/_default.page.tsx deleted file mode 100644 index a2814770..00000000 --- a/src/app/note/_default.page.tsx +++ /dev/null @@ -1 +0,0 @@ -export { LayoutNewsfeed as Layout } from "./layout"; diff --git a/src/app/note/components/metadata.tsx b/src/app/note/components/metadata.tsx deleted file mode 100644 index 0c0a2b1c..00000000 --- a/src/app/note/components/metadata.tsx +++ /dev/null @@ -1,82 +0,0 @@ -import { NoteReply } from "@app/note/components/metadata/reply"; -import { NoteRepost } from "@app/note/components/metadata/repost"; -import { NoteZap } from "@app/note/components/metadata/zap"; -import { createReplyNote } from "@libs/storage"; -import { NDKEvent } from "@nostr-dev-kit/ndk"; -import { NDKSubscription } from "@nostr-dev-kit/ndk"; -import { RelayContext } from "@shared/relayProvider"; -import { decode } from "light-bolt11-decoder"; -import { useContext, useState } from "react"; -import useSWRSubscription from "swr/subscription"; - -export function NoteMetadata({ - id, - eventPubkey, -}: { - id: string; - eventPubkey: string; -}) { - const ndk = useContext(RelayContext); - - const [replies, setReplies] = useState(0); - const [reposts, setReposts] = useState(0); - const [zaps, setZaps] = useState(0); - - useSWRSubscription(id ? ["note-metadata", id] : null, () => { - const sub: NDKSubscription = ndk.subscribe( - { - "#e": [id], - kinds: [1, 6, 9735], - limit: 20, - }, - { closeOnEose: false }, - ); - - sub.addListener("event", (event: NDKEvent) => { - switch (event.kind) { - case 1: - setReplies((replies) => replies + 1); - createReplyNote( - event.id, - event.pubkey, - event.kind, - event.tags, - event.content, - event.created_at, - id, - ); - break; - case 6: - setReposts((reposts) => reposts + 1); - break; - case 9735: { - const bolt11 = event.tags.find((tag) => tag[0] === "bolt11")[1]; - if (bolt11) { - const decoded = decode(bolt11); - const amount = decoded.sections.find( - (item) => item.name === "amount", - ); - setZaps(amount.value / 1000); - } - break; - } - default: - break; - } - }); - - return () => { - sub.stop(); - }; - }); - - return ( -
- - -
- -
-
- ); -} diff --git a/src/app/note/components/replies/list.tsx b/src/app/note/components/replies/list.tsx deleted file mode 100644 index 3bc931d1..00000000 --- a/src/app/note/components/replies/list.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { NoteReplyForm } from "@app/note/components/replies/form"; -import { Reply } from "@app/note/components/replies/item"; -import { NostrEvent } from "@nostr-dev-kit/ndk"; -import { RelayContext } from "@shared/relayProvider"; -import { sortEvents } from "@utils/transform"; -import { useContext } from "react"; -import useSWRSubscription from "swr/subscription"; - -export function RepliesList({ id }: { id: string }) { - const ndk = useContext(RelayContext); - - const { data, error } = useSWRSubscription( - id ? ["note-replies", id] : null, - ([, key], { next }) => { - // subscribe to note - const sub = ndk.subscribe( - { - "#e": [key], - kinds: [1], - limit: 20, - }, - { - closeOnEose: true, - }, - ); - - sub.addListener("event", (event: NostrEvent) => { - next(null, (prev: any) => (prev ? [...prev, event] : [event])); - }); - - return () => { - sub.stop(); - }; - }, - ); - - return ( -
-
-
Replies
-
-
- - {error &&
failed to load
} - {!data ? ( -
-
-
-
-
-
-
-
-
- ) : ( - sortEvents(data).map((event: any) => { - return ; - }) - )} -
-
- ); -} diff --git a/src/app/note/components/wrapper.tsx b/src/app/note/components/wrapper.tsx deleted file mode 100644 index bf364fec..00000000 --- a/src/app/note/components/wrapper.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { navigate } from "vite-plugin-ssr/client/router"; - -export function NoteWrapper({ - children, - href, - className, -}: { - children: React.ReactNode; - href: string; - className: string; -}) { - const openThread = (event: any, href: string) => { - const selection = window.getSelection(); - if (selection.toString().length === 0) { - navigate(href, { keepScrollPosition: true }); - } else { - event.stopPropagation(); - } - }; - - return
{children}
; -} diff --git a/src/app/note/layout.tsx b/src/app/note/layout.tsx deleted file mode 100644 index cc18e057..00000000 --- a/src/app/note/layout.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import { MultiAccounts } from "@shared/multiAccounts"; -import { Navigation } from "@shared/navigation"; - -export function LayoutNewsfeed({ children }: { children: React.ReactNode }) { - return ( -
-
- - -
-
{children}
-
- ); -} diff --git a/src/app/note/pages/index.page.tsx b/src/app/note/pages/index.page.tsx deleted file mode 100644 index 63ab27f3..00000000 --- a/src/app/note/pages/index.page.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { Kind1 } from "@app/note/components/kind1"; -import { NoteMetadata } from "@app/note/components/metadata"; -import { RepliesList } from "@app/note/components/replies/list"; -import { NoteDefaultUser } from "@app/note/components/user/default"; -import { getNoteByID } from "@libs/storage"; -import { usePageContext } from "@utils/hooks/usePageContext"; -import { noteParser } from "@utils/parser"; -import useSWR from "swr"; - -const fetcher = ([, id]) => getNoteByID(id); - -export function Page() { - const pageContext = usePageContext(); - const searchParams: any = pageContext.urlParsed.search; - const noteID = searchParams.id; - - const { data, error } = useSWR(["note", noteID], fetcher); - - const content = !error && data ? noteParser(data) : null; - - return ( -
-
-
- {!data || error ? ( -
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- ) : ( -
-
- -
- - -
-
-
- )} -
- -
-
- ); -} diff --git a/src/app/space/components/add.tsx b/src/app/space/components/add.tsx index 33d3909c..21e0e82c 100644 --- a/src/app/space/components/add.tsx +++ b/src/app/space/components/add.tsx @@ -59,7 +59,6 @@ export function AddBlock() { - {imageModal && } {feedModal && } diff --git a/src/app/space/components/blocks/feed.tsx b/src/app/space/components/blocks/feed.tsx index 361ba637..be10c6f5 100644 --- a/src/app/space/components/blocks/feed.tsx +++ b/src/app/space/components/blocks/feed.tsx @@ -1,6 +1,6 @@ -import { NoteBase } from "@app/note/components/base"; -import { NoteQuoteRepost } from "@app/note/components/quoteRepost"; -import { NoteSkeleton } from "@app/note/components/skeleton"; +import { NoteBase } from "@app/space/components/notes/base"; +import { NoteQuoteRepost } from "@app/space/components/notes/quoteRepost"; +import { NoteSkeleton } from "@app/space/components/notes/skeleton"; import { getNotesByAuthor } from "@libs/storage"; import { CancelIcon } from "@shared/icons"; import { useActiveAccount } from "@stores/accounts"; @@ -73,7 +73,7 @@ export function FeedBlock({ params }: { params: any }) {
{!data || isLoading ? ( @@ -108,7 +108,11 @@ export function FeedBlock({ params }: { params: any }) { data-index={virtualRow.index} ref={rowVirtualizer.measureElement} > - +
); } else { @@ -118,7 +122,11 @@ export function FeedBlock({ params }: { params: any }) { data-index={virtualRow.index} ref={rowVirtualizer.measureElement} > - +
); } diff --git a/src/app/space/components/blocks/following.tsx b/src/app/space/components/blocks/following.tsx index e5fd2783..bad6e4fe 100644 --- a/src/app/space/components/blocks/following.tsx +++ b/src/app/space/components/blocks/following.tsx @@ -1,6 +1,6 @@ -import { NoteBase } from "@app/note/components/base"; -import { NoteQuoteRepost } from "@app/note/components/quoteRepost"; -import { NoteSkeleton } from "@app/note/components/skeleton"; +import { NoteBase } from "@app/space/components/notes/base"; +import { NoteQuoteRepost } from "@app/space/components/notes/quoteRepost"; +import { NoteSkeleton } from "@app/space/components/notes/skeleton"; import { getNotes } from "@libs/storage"; import { useVirtualizer } from "@tanstack/react-virtual"; import { useEffect, useMemo, useRef } from "react"; @@ -11,7 +11,7 @@ const TIME = Math.floor(Date.now() / 1000); const fetcher = async ([, offset]) => getNotes(TIME, ITEM_PER_PAGE, offset); -export function FollowingBlock() { +export function FollowingBlock({ block }: { block: number }) { const getKey = (pageIndex, previousPageData) => { if (previousPageData && !previousPageData.data) return null; if (pageIndex === 0) return ["following", 0]; @@ -56,7 +56,7 @@ export function FollowingBlock() {
{!data || isLoading ? ( @@ -91,7 +91,11 @@ export function FollowingBlock() { data-index={virtualRow.index} ref={rowVirtualizer.measureElement} > - +
); } else { @@ -101,7 +105,11 @@ export function FollowingBlock() { data-index={virtualRow.index} ref={rowVirtualizer.measureElement} > - +
); } diff --git a/src/app/space/components/blocks/image.tsx b/src/app/space/components/blocks/image.tsx index 0efd3ae8..45d83983 100644 --- a/src/app/space/components/blocks/image.tsx +++ b/src/app/space/components/blocks/image.tsx @@ -20,7 +20,7 @@ export function ImageBlock({ params }: { params: any }) { diff --git a/src/app/space/components/blocks/thread.tsx b/src/app/space/components/blocks/thread.tsx new file mode 100644 index 00000000..3eeeac49 --- /dev/null +++ b/src/app/space/components/blocks/thread.tsx @@ -0,0 +1,65 @@ +import { Kind1 } from "@app/space/components/notes/kind1"; +import { Kind1063 } from "@app/space/components/notes/kind1063"; +import { NoteMetadata } from "@app/space/components/notes/metadata"; +import { RepliesList } from "@app/space/components/notes/replies/list"; +import { NoteSkeleton } from "@app/space/components/notes/skeleton"; +import { NoteDefaultUser } from "@app/space/components/user/default"; +import { getNoteByID } from "@libs/storage"; +import { ArrowLeftIcon } from "@shared/icons"; +import { useActiveAccount } from "@stores/accounts"; +import { noteParser } from "@utils/parser"; +import useSWR from "swr"; + +const fetcher = ([, id]) => getNoteByID(id); + +export function ThreadBlock({ params }: { params: any }) { + const { data } = useSWR(["thread", params.content], fetcher); + const removeBlock = useActiveAccount((state: any) => state.removeBlock); + const content = data ? noteParser(data) : null; + + const close = () => { + removeBlock(params.id, false); + }; + + return ( +
+
+ +

{params.title}

+
+
+
+ {!data ? ( +
+
+ +
+
+ ) : ( +
+
+ +
+ {data.kind === 1 && } + {data.kind === 1063 && } + +
+
+
+ )} +
+ +
+
+
+ ); +} diff --git a/src/app/note/components/base.tsx b/src/app/space/components/notes/base.tsx similarity index 57% rename from src/app/note/components/base.tsx rename to src/app/space/components/notes/base.tsx index 2e11b719..c4ea8978 100644 --- a/src/app/note/components/base.tsx +++ b/src/app/space/components/notes/base.tsx @@ -1,25 +1,27 @@ -import { Kind1 } from "@app/note/components/kind1"; -import { Kind1063 } from "@app/note/components/kind1063"; -import { NoteMetadata } from "@app/note/components/metadata"; -import { NoteParent } from "@app/note/components/parent"; -import { NoteDefaultUser } from "@app/note/components/user/default"; -import { NoteWrapper } from "@app/note/components/wrapper"; +import { Kind1 } from "@app/space/components/notes/kind1"; +import { Kind1063 } from "@app/space/components/notes/kind1063"; +import { NoteMetadata } from "@app/space/components/notes/metadata"; +import { NoteParent } from "@app/space/components/notes/parent"; +import { NoteWrapper } from "@app/space/components/notes/wrapper"; +import { NoteDefaultUser } from "@app/space/components/user/default"; import { noteParser } from "@utils/parser"; import { isTagsIncludeID } from "@utils/transform"; import { useMemo } from "react"; -export function NoteBase({ event }: { event: any }) { +export function NoteBase({ block, event }: { block: number; event: any }) { const content = useMemo(() => noteParser(event), [event]); const checkParentID = isTagsIncludeID(event.parent_id, event.tags); - const href = event.parent_id - ? `/app/note?id=${event.parent_id}` - : `/app/note?id=${event.event_id}`; + const threadID = event.parent_id ? event.parent_id : event.event_id; return ( - +
{event.parent_id && (event.parent_id !== event.event_id || checkParentID) ? ( diff --git a/src/app/note/components/kind1.tsx b/src/app/space/components/notes/kind1.tsx similarity index 79% rename from src/app/note/components/kind1.tsx rename to src/app/space/components/notes/kind1.tsx index 7492c4a7..4a59b73c 100644 --- a/src/app/note/components/kind1.tsx +++ b/src/app/space/components/notes/kind1.tsx @@ -1,8 +1,8 @@ import { LinkPreview } from "./preview/link"; -import { MentionNote } from "@app/note/components/mentions/note"; -import { MentionUser } from "@app/note/components/mentions/user"; -import { ImagePreview } from "@app/note/components/preview/image"; -import { VideoPreview } from "@app/note/components/preview/video"; +import { MentionNote } from "@app/space/components/notes/mentions/note"; +import { MentionUser } from "@app/space/components/notes/mentions/user"; +import { ImagePreview } from "@app/space/components/notes/preview/image"; +import { VideoPreview } from "@app/space/components/notes/preview/video"; import { truncateContent } from "@utils/transform"; import ReactMarkdown from "react-markdown"; import remarkGfm from "remark-gfm"; diff --git a/src/app/note/components/kind1063.tsx b/src/app/space/components/notes/kind1063.tsx similarity index 100% rename from src/app/note/components/kind1063.tsx rename to src/app/space/components/notes/kind1063.tsx diff --git a/src/app/note/components/mentions/note.tsx b/src/app/space/components/notes/mentions/note.tsx similarity index 80% rename from src/app/note/components/mentions/note.tsx rename to src/app/space/components/notes/mentions/note.tsx index 72fd80f9..e69bd018 100644 --- a/src/app/note/components/mentions/note.tsx +++ b/src/app/space/components/notes/mentions/note.tsx @@ -1,8 +1,8 @@ -import { Kind1 } from "@app/note/components/kind1"; -import { Kind1063 } from "@app/note/components/kind1063"; -import { NoteSkeleton } from "@app/note/components/skeleton"; -import { NoteQuoteUser } from "@app/note/components/user/quote"; -import { NoteWrapper } from "@app/note/components/wrapper"; +import { Kind1 } from "@app/space/components/notes/kind1"; +import { Kind1063 } from "@app/space/components/notes/kind1063"; +import { NoteSkeleton } from "@app/space/components/notes/skeleton"; +import { NoteWrapper } from "@app/space/components/notes/wrapper"; +import { NoteQuoteUser } from "@app/space/components/user/quote"; import { useEvent } from "@utils/hooks/useEvent"; import { noteParser } from "@utils/parser"; import { memo } from "react"; diff --git a/src/app/note/components/mentions/user.tsx b/src/app/space/components/notes/mentions/user.tsx similarity index 100% rename from src/app/note/components/mentions/user.tsx rename to src/app/space/components/notes/mentions/user.tsx diff --git a/src/app/space/components/notes/metadata.tsx b/src/app/space/components/notes/metadata.tsx new file mode 100644 index 00000000..eef4a942 --- /dev/null +++ b/src/app/space/components/notes/metadata.tsx @@ -0,0 +1,113 @@ +import { NoteReply } from "@app/space/components/notes/metadata/reply"; +import { NoteRepost } from "@app/space/components/notes/metadata/repost"; +import { NoteZap } from "@app/space/components/notes/metadata/zap"; +import { createReplyNote } from "@libs/storage"; +import { NDKEvent, NDKFilter } from "@nostr-dev-kit/ndk"; +import { LoaderIcon, ReplyIcon, RepostIcon } from "@shared/icons"; +import { RelayContext } from "@shared/relayProvider"; +import { decode } from "light-bolt11-decoder"; +import { useContext } from "react"; +import useSWR from "swr"; + +const fetcher = async ([, ndk, id]) => { + let replies = 0; + let reposts = 0; + let zap = 0; + + const filter: NDKFilter = { + "#e": [id], + kinds: [1, 6, 9735], + }; + + const events = await ndk.fetchEvents(filter); + events.forEach((event: NDKEvent) => { + switch (event.kind) { + case 1: + replies += 1; + createReplyNote( + event.id, + event.pubkey, + event.kind, + event.tags, + event.content, + event.created_at, + id, + ); + break; + case 6: + reposts += 1; + break; + case 9735: { + const bolt11 = event.tags.find((tag) => tag[0] === "bolt11")[1]; + if (bolt11) { + const decoded = decode(bolt11); + const amount = decoded.sections.find( + (item) => item.name === "amount", + ); + const sats = amount.value / 1000; + zap += sats; + } + break; + } + default: + break; + } + }); + + return { replies, reposts, zap }; +}; + +export function NoteMetadata({ + id, + eventPubkey, +}: { + id: string; + eventPubkey: string; +}) { + const ndk = useContext(RelayContext); + const { data } = useSWR(["note-metadata", ndk, id], fetcher); + + return ( +
+ {!data ? ( + <> +
+ + +
+
+ + +
+
+
+
+ + ) : ( + <> + + +
+ +
+ + )} +
+ ); +} diff --git a/src/app/note/components/metadata/reply.tsx b/src/app/space/components/notes/metadata/reply.tsx similarity index 96% rename from src/app/note/components/metadata/reply.tsx rename to src/app/space/components/notes/metadata/reply.tsx index eebe0d71..5f99407f 100644 --- a/src/app/note/components/metadata/reply.tsx +++ b/src/app/space/components/notes/metadata/reply.tsx @@ -6,13 +6,13 @@ import { RelayContext } from "@shared/relayProvider"; import { useActiveAccount } from "@stores/accounts"; import { dateToUnix } from "@utils/date"; import { compactNumber } from "@utils/number"; -import { Fragment, useContext, useEffect, useState } from "react"; +import { Fragment, useContext, useState } from "react"; export function NoteReply({ id, replies }: { id: string; replies: number }) { const ndk = useContext(RelayContext); const account = useActiveAccount((state: any) => state.account); - const [count, setCount] = useState(0); + const [count, setCount] = useState(replies); const [isOpen, setIsOpen] = useState(false); const [value, setValue] = useState(""); @@ -45,10 +45,6 @@ export function NoteReply({ id, replies }: { id: string; replies: number }) { setCount(count + 1); }; - useEffect(() => { - setCount(replies); - }, [replies]); - return ( <>