From 4c3d04140e3ba035478399a4f6b94fefd690efe2 Mon Sep 17 00:00:00 2001 From: hzrd149 Date: Tue, 2 Apr 2024 17:07:22 -0500 Subject: [PATCH] Add details tabs under thread post Show individual zaps on notes --- .changeset/early-shoes-admire.md | 5 + .changeset/famous-walls-warn.md | 5 + .../event-interactions-modal/index.tsx | 104 ------------------ .../repost-details.tsx | 33 ------ src/components/note/note-menu.tsx | 12 +- .../components/note-details-button.tsx | 20 ---- .../components/reply-context.tsx | 58 ++++++++++ .../timeline-note/components/zap-bubbles.tsx | 37 +++++++ src/components/note/timeline-note/index.tsx | 72 ++---------- src/components/user/user-avatar.tsx | 14 ++- src/views/thread/components/details-tabs.tsx | 93 ++++++++++++++++ src/views/thread/components/tabs/quotes.tsx | 30 +++++ .../thread/components/tabs/reactions.tsx} | 30 ++--- src/views/thread/components/tabs/reposts.tsx | 33 ++++++ src/views/thread/components/tabs/zaps.tsx | 44 ++++++++ src/views/thread/components/thread-post.tsx | 37 ++++--- .../components/torrent-comment-menu.tsx | 3 +- .../torrents/components/torrents-comments.tsx | 5 +- src/views/tracks/components/track-menu.tsx | 6 +- 19 files changed, 364 insertions(+), 277 deletions(-) create mode 100644 .changeset/early-shoes-admire.md create mode 100644 .changeset/famous-walls-warn.md delete mode 100644 src/components/event-interactions-modal/index.tsx delete mode 100644 src/components/event-interactions-modal/repost-details.tsx delete mode 100644 src/components/note/timeline-note/components/note-details-button.tsx create mode 100644 src/components/note/timeline-note/components/reply-context.tsx create mode 100644 src/components/note/timeline-note/components/zap-bubbles.tsx create mode 100644 src/views/thread/components/details-tabs.tsx create mode 100644 src/views/thread/components/tabs/quotes.tsx rename src/{components/event-interactions-modal/reaction-details.tsx => views/thread/components/tabs/reactions.tsx} (54%) create mode 100644 src/views/thread/components/tabs/reposts.tsx create mode 100644 src/views/thread/components/tabs/zaps.tsx diff --git a/.changeset/early-shoes-admire.md b/.changeset/early-shoes-admire.md new file mode 100644 index 000000000..e4b1e863d --- /dev/null +++ b/.changeset/early-shoes-admire.md @@ -0,0 +1,5 @@ +--- +"nostrudel": minor +--- + +Show individual zaps on notes diff --git a/.changeset/famous-walls-warn.md b/.changeset/famous-walls-warn.md new file mode 100644 index 000000000..998783427 --- /dev/null +++ b/.changeset/famous-walls-warn.md @@ -0,0 +1,5 @@ +--- +"nostrudel": minor +--- + +Add details tabs under thread post diff --git a/src/components/event-interactions-modal/index.tsx b/src/components/event-interactions-modal/index.tsx deleted file mode 100644 index 22565e85a..000000000 --- a/src/components/event-interactions-modal/index.tsx +++ /dev/null @@ -1,104 +0,0 @@ -import React, { useState } from "react"; -import { - Modal, - ModalOverlay, - ModalContent, - ModalBody, - ModalCloseButton, - Button, - ModalProps, - Text, - Flex, - ButtonGroup, - Spacer, - ModalHeader, -} from "@chakra-ui/react"; - -import { NostrEvent } from "../../types/nostr-event"; -import UserAvatarLink from "../user/user-avatar-link"; -import UserLink from "../user/user-link"; -import { LightningIcon } from "../icons"; -import { ParsedZap } from "../../helpers/nostr/zaps"; -import { readablizeSats } from "../../helpers/bolt11"; -import useEventReactions from "../../hooks/use-event-reactions"; -import useEventZaps from "../../hooks/use-event-zaps"; -import Timestamp from "../timestamp"; -import { getEventUID } from "../../helpers/nostr/event"; -import ReactionDetails from "./reaction-details"; -import RepostDetails from "./repost-details"; - -const ZapEvent = React.memo(({ zap }: { zap: ParsedZap }) => { - if (!zap.payment.amount) return null; - - return ( - <> - - - - - - - {readablizeSats(zap.payment.amount / 1000)} - - {zap.request.content} - - ); -}); - -export default function EventInteractionDetailsModal({ - isOpen, - onClose, - event, - size = "2xl", - ...props -}: Omit & { event: NostrEvent }) { - const uuid = getEventUID(event); - const zaps = useEventZaps(uuid, [], true) ?? []; - const reactions = useEventReactions(uuid, [], true) ?? []; - - const [tab, setTab] = useState(zaps.length > 0 ? "zaps" : "reactions"); - - const renderTab = () => { - switch (tab) { - case "reposts": - return ; - case "reactions": - return ; - case "zaps": - return ( - <> - {zaps - .sort((a, b) => b.request.created_at - a.request.created_at) - .map((zap) => ( - - ))} - - ); - } - }; - - return ( - - - - - - - - - - - - - {renderTab()} - - - - ); -} diff --git a/src/components/event-interactions-modal/repost-details.tsx b/src/components/event-interactions-modal/repost-details.tsx deleted file mode 100644 index d1ad144a0..000000000 --- a/src/components/event-interactions-modal/repost-details.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import { Flex, Text } from "@chakra-ui/react"; -import { kinds } from "nostr-tools"; - -import { NostrEvent } from "../../types/nostr-event"; -import UserAvatarLink from "../user/user-avatar-link"; -import UserLink from "../user/user-link"; -import useTimelineLoader from "../../hooks/use-timeline-loader"; -import { useReadRelays } from "../../hooks/use-client-relays"; -import useSubject from "../../hooks/use-subject"; -import Timestamp from "../timestamp"; - -export default function RepostDetails({ event }: { event: NostrEvent }) { - const readRelays = useReadRelays(); - const timeline = useTimelineLoader(`${event.id}-reposts`, readRelays, { - kinds: [kinds.Repost, kinds.GenericRepost], - "#e": [event.id], - }); - - const reposts = useSubject(timeline.timeline); - - return ( - <> - {reposts.map((repost) => ( - - - - Shared - - - ))} - - ); -} diff --git a/src/components/note/note-menu.tsx b/src/components/note/note-menu.tsx index 40768f06c..3c757a36d 100644 --- a/src/components/note/note-menu.tsx +++ b/src/components/note/note-menu.tsx @@ -7,7 +7,6 @@ import { NostrEvent } from "../../types/nostr-event"; import { DotsMenuButton, MenuIconButtonProps } from "../dots-menu-button"; import NoteTranslationModal from "../../views/tools/transform-note/translation"; import Translate01 from "../icons/translate-01"; -import InfoCircle from "../icons/info-circle"; import PinNoteMenuItem from "../common-menu-items/pin-note"; import CopyShareLinkMenuItem from "../common-menu-items/copy-share-link"; import OpenInAppMenuItem from "../common-menu-items/open-in-app"; @@ -19,11 +18,7 @@ import Recording02 from "../icons/recording-02"; import { usePublishEvent } from "../../providers/global/publish-provider"; import DebugEventMenuItem from "../debug-modal/debug-event-menu-item"; -export default function NoteMenu({ - event, - detailsClick, - ...props -}: { event: NostrEvent; detailsClick?: () => void } & Omit) { +export default function NoteMenu({ event, ...props }: { event: NostrEvent } & Omit) { const translationsModal = useDisclosure(); const publish = usePublishEvent(); @@ -59,11 +54,6 @@ export default function NoteMenu({ Broadcast - {detailsClick && ( - }> - Details - - )} diff --git a/src/components/note/timeline-note/components/note-details-button.tsx b/src/components/note/timeline-note/components/note-details-button.tsx deleted file mode 100644 index 6a84ddbee..000000000 --- a/src/components/note/timeline-note/components/note-details-button.tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { IconButton, IconButtonProps } from "@chakra-ui/react"; -import { NostrEvent } from "nostr-tools"; - -import InfoCircle from "../../../icons/info-circle"; -import useEventReactions from "../../../../hooks/use-event-reactions"; -import { getEventUID } from "../../../../helpers/nostr/event"; -import useEventZaps from "../../../../hooks/use-event-zaps"; - -export function NoteDetailsButton({ - event, - ...props -}: { event: NostrEvent } & Omit) { - const uuid = getEventUID(event); - const reactions = useEventReactions(uuid) ?? []; - const zaps = useEventZaps(uuid); - - if (reactions.length === 0 && zaps.length === 0) return null; - - return } aria-label="Note Details" title="Note Details" {...props} />; -} diff --git a/src/components/note/timeline-note/components/reply-context.tsx b/src/components/note/timeline-note/components/reply-context.tsx new file mode 100644 index 000000000..12debb8f6 --- /dev/null +++ b/src/components/note/timeline-note/components/reply-context.tsx @@ -0,0 +1,58 @@ +import { NostrEvent, nip19 } from "nostr-tools"; +import { Flex, Link, Text } from "@chakra-ui/react"; +import { Link as RouterLink } from "react-router-dom"; + +import { getThreadReferences, truncatedId } from "../../../../helpers/nostr/event"; +import UserLink from "../../../user/user-link"; +import useSingleEvent from "../../../../hooks/use-single-event"; +import { CompactNoteContent } from "../../../compact-note-content"; +import { ReplyIcon } from "../../../icons"; + +function ReplyToE({ pointer }: { pointer: nip19.EventPointer }) { + const event = useSingleEvent(pointer.id, pointer.relays); + + if (!event) { + const nevent = nip19.neventEncode(pointer); + return ( + + Replying to{" "} + + {truncatedId(nevent)} + + + ); + } + + return ( + <> + + Replying to + + + + ); +} +function ReplyToA({ pointer }: { pointer: nip19.AddressPointer }) { + const naddr = nip19.naddrEncode(pointer); + + return ( + + Replying to{" "} + + {truncatedId(naddr)} + + + ); +} + +export default function ReplyContext({ event }: { event: NostrEvent }) { + const refs = getThreadReferences(event); + if (!refs.reply) return null; + + return ( + + + {refs.reply.e ? : } + + ); +} diff --git a/src/components/note/timeline-note/components/zap-bubbles.tsx b/src/components/note/timeline-note/components/zap-bubbles.tsx new file mode 100644 index 000000000..d2cd8e740 --- /dev/null +++ b/src/components/note/timeline-note/components/zap-bubbles.tsx @@ -0,0 +1,37 @@ +import { Flex, Tag, TagLabel } from "@chakra-ui/react"; +import { NostrEvent } from "nostr-tools"; +import { getEventUID } from "nostr-idb"; +import styled from "@emotion/styled"; + +import useEventZaps from "../../../../hooks/use-event-zaps"; +import UserAvatar from "../../../user/user-avatar"; +import { readablizeSats } from "../../../../helpers/bolt11"; +import { LightningIcon } from "../../../icons"; + +const HiddenScrollbar = styled(Flex)` + -ms-overflow-style: none; /* IE and Edge */ + scrollbar-width: none; /* Firefox */ + &::-webkit-scrollbar { + display: none; + } +`; + +export default function ZapBubbles({ event }: { event: NostrEvent }) { + const zaps = useEventZaps(getEventUID(event)); + + if (zaps.length === 0) return null; + + const sorted = zaps.sort((a, b) => (b.payment.amount ?? 0) - (a.payment.amount ?? 0)); + + return ( + + {sorted.map((zap) => ( + + + {readablizeSats((zap.payment.amount ?? 0) / 1000)} + + + ))} + + ); +} diff --git a/src/components/note/timeline-note/index.tsx b/src/components/note/timeline-note/index.tsx index 80f0b8129..6c408a80d 100644 --- a/src/components/note/timeline-note/index.tsx +++ b/src/components/note/timeline-note/index.tsx @@ -11,7 +11,6 @@ import { IconButton, Link, LinkBox, - Text, useDisclosure, } from "@chakra-ui/react"; import { NostrEvent } from "../../../types/nostr-event"; @@ -35,73 +34,20 @@ import BookmarkButton from "../bookmark-button"; import useCurrentAccount from "../../../hooks/use-current-account"; import NoteReactions from "./components/note-reactions"; import ReplyForm from "../../../views/thread/components/reply-form"; -import { getThreadReferences, truncatedId } from "../../../helpers/nostr/event"; +import { getThreadReferences } from "../../../helpers/nostr/event"; import Timestamp from "../../timestamp"; import OpenInDrawerButton from "../open-in-drawer-button"; import { getSharableEventAddress } from "../../../helpers/nip19"; import { useBreakpointValue } from "../../../providers/global/breakpoint-provider"; import HoverLinkOverlay from "../../hover-link-overlay"; import NoteCommunityMetadata from "./note-community-metadata"; -import useSingleEvent from "../../../hooks/use-single-event"; -import { CompactNoteContent } from "../../compact-note-content"; import NoteProxyLink from "./components/note-proxy-link"; -import { NoteDetailsButton } from "./components/note-details-button"; -import EventInteractionDetailsModal from "../../event-interactions-modal"; import singleEventService from "../../../services/single-event"; -import { AddressPointer, EventPointer } from "nostr-tools/lib/types/nip19"; -import { nip19 } from "nostr-tools"; import POWIcon from "../../pow/pow-icon"; +import ReplyContext from "./components/reply-context"; +import ZapBubbles from "./components/zap-bubbles"; -function ReplyToE({ pointer }: { pointer: EventPointer }) { - const event = useSingleEvent(pointer.id, pointer.relays); - - if (!event) { - const nevent = nip19.neventEncode(pointer); - return ( - - Replying to{" "} - - {truncatedId(nevent)} - - - ); - } - - return ( - <> - - Replying to - - - - ); -} -function ReplyToA({ pointer }: { pointer: AddressPointer }) { - const naddr = nip19.naddrEncode(pointer); - - return ( - - Replying to{" "} - - {truncatedId(naddr)} - - - ); -} - -function ReplyLine({ event }: { event: NostrEvent }) { - const refs = getThreadReferences(event); - if (!refs.reply) return null; - - return ( - - - {refs.reply.e ? : } - - ); -} - -export type NoteProps = Omit & { +export type TimelineNoteProps = Omit & { event: NostrEvent; variant?: CardProps["variant"]; showReplyButton?: boolean; @@ -119,11 +65,10 @@ export function TimelineNote({ registerIntersectionEntity = true, clickable = true, ...props -}: NoteProps) { +}: TimelineNoteProps) { const account = useCurrentAccount(); const { showReactions, showSignatureVerification } = useSubject(appSettings); const replyForm = useDisclosure(); - const detailsModal = useDisclosure(); const ref = useRef(null); useRegisterIntersectionEntity(ref, event.id); @@ -169,12 +114,13 @@ export function TimelineNote({ )} - {showReplyLine && } + {showReplyLine && } + {showReactionsOnNewLine && reactionButtons} @@ -189,9 +135,8 @@ export function TimelineNote({ - - + @@ -204,7 +149,6 @@ export function TimelineNote({ onSubmitted={replyForm.onClose} /> )} - {detailsModal.isOpen && } ); } diff --git a/src/components/user/user-avatar.tsx b/src/components/user/user-avatar.tsx index a6d26282c..511d56640 100644 --- a/src/components/user/user-avatar.tsx +++ b/src/components/user/user-avatar.tsx @@ -41,7 +41,7 @@ export const UserAvatar = forwardRef( metadata={metadata} noProxy={noProxy} ref={ref} - borderColor={color} + borderColor={size !== "xs" ? color : undefined} borderStyle="none" size={size} {...props} @@ -63,7 +63,7 @@ export const UserAvatar = forwardRef( ); UserAvatar.displayName = "UserAvatar"; -const StyledAvatar = styled(Avatar)` +const SquareAvatar = styled(Avatar)` img { border-radius: var(--chakra-radii-lg); border-width: 0.18rem; @@ -75,9 +75,10 @@ export type MetadataAvatarProps = Omit & { metadata?: Kind0ParsedContent; pubkey?: string; noProxy?: boolean; + square?: boolean; }; export const MetadataAvatar = forwardRef( - ({ pubkey, metadata, noProxy, children, ...props }, ref) => { + ({ pubkey, metadata, noProxy, children, square = true, ...props }, ref) => { const { imageProxy, proxyUserMedia, hideUsernames } = useAppSettings(); const account = useCurrentAccount(); const picture = useMemo(() => { @@ -95,8 +96,10 @@ export const MetadataAvatar = forwardRef( } }, [metadata?.picture, imageProxy, proxyUserMedia, hideUsernames, account]); + const AvatarComponent = square ? SquareAvatar : Avatar; + return ( - : undefined} // overflow="hidden" @@ -105,10 +108,9 @@ export const MetadataAvatar = forwardRef( {...props} > {children} - + ); }, ); -UserAvatar.displayName = "UserAvatar"; export default memo(UserAvatar); diff --git a/src/views/thread/components/details-tabs.tsx b/src/views/thread/components/details-tabs.tsx new file mode 100644 index 000000000..43211c967 --- /dev/null +++ b/src/views/thread/components/details-tabs.tsx @@ -0,0 +1,93 @@ +import { useState } from "react"; +import { Button, Flex } from "@chakra-ui/react"; +import { kinds } from "nostr-tools"; +import { getEventUID } from "nostr-idb"; + +import { ThreadItem } from "../../../helpers/thread"; +import useEventCount from "../../../hooks/use-event-count"; +import PostZapsTab from "./tabs/zaps"; +import { ThreadPost } from "./thread-post"; +import useEventZaps from "../../../hooks/use-event-zaps"; +import PostReactionsTab from "./tabs/reactions"; +import useEventReactions from "../../../hooks/use-event-reactions"; +import PostRepostsTab from "./tabs/reposts"; +import PostQuotesTab from "./tabs/quotes"; + +export default function DetailsTabs({ post }: { post: ThreadItem }) { + const [selected, setSelected] = useState("replies"); + const repostCount = useEventCount({ "#e": [post.event.id], kinds: [kinds.Repost, kinds.GenericRepost] }); + + const zaps = useEventZaps(getEventUID(post.event)); + const reactions = useEventReactions(getEventUID(post.event)) ?? []; + + const renderContent = () => { + switch (selected) { + case "replies": + return ( + + {post.replies.map((child) => ( + + ))} + + ); + case "quotes": + return ; + case "reactions": + return ; + case "reposts": + return ; + case "zaps": + return ; + } + return null; + }; + + return ( + <> + + + + + + + + + {renderContent()} + + ); +} diff --git a/src/views/thread/components/tabs/quotes.tsx b/src/views/thread/components/tabs/quotes.tsx new file mode 100644 index 000000000..0451f5ae3 --- /dev/null +++ b/src/views/thread/components/tabs/quotes.tsx @@ -0,0 +1,30 @@ +import { kinds } from "nostr-tools"; +import { Flex } from "@chakra-ui/react"; + +import { ThreadItem } from "../../../../helpers/thread"; +import { useReadRelays } from "../../../../hooks/use-client-relays"; +import useTimelineLoader from "../../../../hooks/use-timeline-loader"; +import useSubject from "../../../../hooks/use-subject"; +import { getContentTagRefs } from "../../../../helpers/nostr/event"; +import { TimelineNote } from "../../../../components/note/timeline-note"; + +export default function PostQuotesTab({ post }: { post: ThreadItem }) { + const readRelays = useReadRelays(); + const timeline = useTimelineLoader(`${post.event.id}-quotes`, readRelays, { + kinds: [kinds.ShortTextNote], + "#e": [post.event.id], + }); + + const events = useSubject(timeline.timeline); + const quotes = events.filter((e) => { + return getContentTagRefs(e.content, e.tags).some((t) => t[0] === "e" && t[1] === post.event.id); + }); + + return ( + + {quotes.map((quote) => ( + + ))} + + ); +} diff --git a/src/components/event-interactions-modal/reaction-details.tsx b/src/views/thread/components/tabs/reactions.tsx similarity index 54% rename from src/components/event-interactions-modal/reaction-details.tsx rename to src/views/thread/components/tabs/reactions.tsx index aea542a2e..19395773f 100644 --- a/src/components/event-interactions-modal/reaction-details.tsx +++ b/src/views/thread/components/tabs/reactions.tsx @@ -1,11 +1,13 @@ -import { Box, Button, Divider, Flex, SimpleGrid, SimpleGridProps, useDisclosure } from "@chakra-ui/react"; import { useMemo } from "react"; +import { getEventUID } from "nostr-idb"; +import { Box, Button, Divider, Flex, SimpleGrid, SimpleGridProps, useDisclosure } from "@chakra-ui/react"; -import { NostrEvent } from "../../types/nostr-event"; -import { groupReactions } from "../../helpers/nostr/reactions"; -import UserAvatarLink from "../user/user-avatar-link"; -import UserLink from "../user/user-link"; -import ReactionIcon from "../event-reactions/reaction-icon"; +import useEventReactions from "../../../../hooks/use-event-reactions"; +import { ThreadItem } from "../../../../helpers/thread"; +import { groupReactions } from "../../../../helpers/nostr/reactions"; +import ReactionIcon from "../../../../components/event-reactions/reaction-icon"; +import UserLink from "../../../../components/user/user-link"; +import UserAvatarLink from "../../../../components/user/user-avatar-link"; function ShowMoreGrid({ pubkeys, @@ -19,9 +21,9 @@ function ShowMoreGrid({ <> {limited.map((pubkey) => ( - - - + + + ))} @@ -34,20 +36,22 @@ function ShowMoreGrid({ ); } -export default function ReactionDetails({ reactions }: { reactions: NostrEvent[] }) { +export default function PostReactionsTab({ post }: { post: ThreadItem }) { + const reactions = useEventReactions(getEventUID(post.event)) ?? []; const groups = useMemo(() => groupReactions(reactions), [reactions]); return ( - + {groups.map((group) => ( - + + {group.url ? group.emoji : ""} - + ))} diff --git a/src/views/thread/components/tabs/reposts.tsx b/src/views/thread/components/tabs/reposts.tsx new file mode 100644 index 000000000..8fd15899c --- /dev/null +++ b/src/views/thread/components/tabs/reposts.tsx @@ -0,0 +1,33 @@ +import { Flex, Text } from "@chakra-ui/react"; +import { kinds } from "nostr-tools"; + +import UserAvatarLink from "../../../../components/user/user-avatar-link"; +import UserLink from "../../../../components/user/user-link"; +import useTimelineLoader from "../../../../hooks/use-timeline-loader"; +import { useReadRelays } from "../../../../hooks/use-client-relays"; +import useSubject from "../../../../hooks/use-subject"; +import Timestamp from "../../../../components/timestamp"; +import { ThreadItem } from "../../../../helpers/thread"; + +export default function PostRepostsTab({ post }: { post: ThreadItem }) { + const readRelays = useReadRelays(); + const timeline = useTimelineLoader(`${post.event.id}-reposts`, readRelays, { + kinds: [kinds.Repost, kinds.GenericRepost], + "#e": [post.event.id], + }); + + const reposts = useSubject(timeline.timeline); + + return ( + + {reposts.map((repost) => ( + + + + Shared + + + ))} + + ); +} diff --git a/src/views/thread/components/tabs/zaps.tsx b/src/views/thread/components/tabs/zaps.tsx new file mode 100644 index 000000000..acad65785 --- /dev/null +++ b/src/views/thread/components/tabs/zaps.tsx @@ -0,0 +1,44 @@ +import { memo } from "react"; +import { Box, Flex, Text } from "@chakra-ui/react"; + +import { ThreadItem } from "../../../../helpers/thread"; +import { ParsedZap } from "../../../../helpers/nostr/zaps"; +import UserAvatarLink from "../../../../components/user/user-avatar-link"; +import UserLink from "../../../../components/user/user-link"; +import Timestamp from "../../../../components/timestamp"; +import { LightningIcon } from "../../../../components/icons"; +import { readablizeSats } from "../../../../helpers/bolt11"; +import useEventZaps from "../../../../hooks/use-event-zaps"; +import { getEventUID } from "nostr-idb"; + +const ZapEvent = memo(({ zap }: { zap: ParsedZap }) => { + if (!zap.payment.amount) return null; + + return ( + <> + + + + + + {readablizeSats(zap.payment.amount / 1000)} + + + + + {zap.request.content && {zap.request.content}} + + ); +}); + +export default function PostZapsTab({ post }: { post: ThreadItem }) { + const zaps = useEventZaps(getEventUID(post.event)); + + return ( + + {zaps.map((zap) => ( + + ))} + + ); +} diff --git a/src/views/thread/components/thread-post.tsx b/src/views/thread/components/thread-post.tsx index 0ff39127e..ffac62375 100644 --- a/src/views/thread/components/thread-post.tsx +++ b/src/views/thread/components/thread-post.tsx @@ -14,7 +14,6 @@ import Expand01 from "../../../components/icons/expand-01"; import Minus from "../../../components/icons/minus"; import { useBreakpointValue } from "../../../providers/global/breakpoint-provider"; import UserDnsIdentity from "../../../components/user/user-dns-identity"; -import EventInteractionDetailsModal from "../../../components/event-interactions-modal"; import { getSharableEventAddress } from "../../../helpers/nip19"; import { useRegisterIntersectionEntity } from "../../../providers/local/intersection-observer"; import useAppSettings from "../../../hooks/use-app-settings"; @@ -24,12 +23,13 @@ import RepostButton from "../../../components/note/timeline-note/components/repo import QuoteRepostButton from "../../../components/note/quote-repost-button"; import NoteZapButton from "../../../components/note/note-zap-button"; import NoteProxyLink from "../../../components/note/timeline-note/components/note-proxy-link"; -import { NoteDetailsButton } from "../../../components/note/timeline-note/components/note-details-button"; import BookmarkButton from "../../../components/note/bookmark-button"; import NoteMenu from "../../../components/note/note-menu"; import NoteCommunityMetadata from "../../../components/note/timeline-note/note-community-metadata"; import { TextNoteContents } from "../../../components/note/timeline-note/text-note-contents"; import NoteReactions from "../../../components/note/timeline-note/components/note-reactions"; +import ZapBubbles from "../../../components/note/timeline-note/components/zap-bubbles"; +import DetailsTabs from "./details-tabs"; export type ThreadItemProps = { post: ThreadItem; @@ -42,7 +42,6 @@ export const ThreadPost = memo(({ post, initShowReplies, focusId, level = -1 }: const { showReactions } = useAppSettings(); const expanded = useDisclosure({ defaultIsOpen: initShowReplies ?? (level < 2 || post.replies.length <= 1) }); const replyForm = useDisclosure(); - const detailsModal = useDisclosure(); const muteFilter = useClientSideMuteFilter(); @@ -117,9 +116,8 @@ export const ThreadPost = memo(({ post, initShowReplies, focusId, level = -1 }: - - + ); @@ -141,19 +139,28 @@ export const ThreadPost = memo(({ post, initShowReplies, focusId, level = -1 }: ref={ref} > {header} - {expanded.isOpen && renderContent()} - {expanded.isOpen && showReactionsOnNewLine && reactionButtons} - {expanded.isOpen && footer} + {expanded.isOpen && ( + <> + {renderContent()} + + {showReactionsOnNewLine && reactionButtons} + {footer} + + )} {replyForm.isOpen && } - {post.replies.length > 0 && expanded.isOpen && ( - - {post.replies.map((child) => ( - - ))} - + {level === -1 ? ( + + ) : ( + expanded.isOpen && + post.replies.length > 0 && ( + + {post.replies.map((child) => ( + + ))} + + ) )} - {detailsModal.isOpen && } ); }); diff --git a/src/views/torrents/components/torrent-comment-menu.tsx b/src/views/torrents/components/torrent-comment-menu.tsx index 2da6cb7e1..76b2c1d97 100644 --- a/src/views/torrents/components/torrent-comment-menu.tsx +++ b/src/views/torrents/components/torrent-comment-menu.tsx @@ -9,9 +9,8 @@ import DebugEventMenuItem from "../../../components/debug-modal/debug-event-menu export default function TorrentCommentMenu({ comment, - detailsClick, ...props -}: { comment: NostrEvent; detailsClick?: () => void } & Omit) { +}: { comment: NostrEvent } & Omit) { return ( <> diff --git a/src/views/torrents/components/torrents-comments.tsx b/src/views/torrents/components/torrents-comments.tsx index e85b8457d..47d641bf2 100644 --- a/src/views/torrents/components/torrents-comments.tsx +++ b/src/views/torrents/components/torrents-comments.tsx @@ -31,7 +31,6 @@ import Expand01 from "../../../components/icons/expand-01"; import { TrustProvider } from "../../../providers/local/trust"; import { ReplyIcon } from "../../../components/icons"; import ReplyForm from "../../thread/components/reply-form"; -import EventInteractionDetailsModal from "../../../components/event-interactions-modal"; import useThreadColorLevelProps from "../../../hooks/use-thread-color-level-props"; import TorrentCommentMenu from "./torrent-comment-menu"; import NoteReactions from "../../../components/note/timeline-note/components/note-reactions"; @@ -42,7 +41,6 @@ export const ThreadPost = memo(({ post, level = -1 }: { post: ThreadItem; level? const { showReactions } = useAppSettings(); const expanded = useDisclosure({ defaultIsOpen: level < 2 || post.replies.length <= 1 }); const replyForm = useDisclosure(); - const detailsModal = useDisclosure(); const muteFilter = useClientSideMuteFilter(); @@ -110,7 +108,7 @@ export const ThreadPost = memo(({ post, level = -1 }: { post: ThreadItem; level? {!showReactionsOnNewLine && reactionButtons} - + ); @@ -151,7 +149,6 @@ export const ThreadPost = memo(({ post, level = -1 }: { post: ThreadItem; level? ))} )} - {detailsModal.isOpen && } ); }); diff --git a/src/views/tracks/components/track-menu.tsx b/src/views/tracks/components/track-menu.tsx index e57265b07..12fb79a61 100644 --- a/src/views/tracks/components/track-menu.tsx +++ b/src/views/tracks/components/track-menu.tsx @@ -6,11 +6,7 @@ import CopyEmbedCodeMenuItem from "../../../components/common-menu-items/copy-em import MuteUserMenuItem from "../../../components/common-menu-items/mute-user"; import DebugEventMenuItem from "../../../components/debug-modal/debug-event-menu-item"; -export default function TrackMenu({ - track, - detailsClick, - ...props -}: { track: NostrEvent; detailsClick?: () => void } & Omit) { +export default function TrackMenu({ track, ...props }: { track: NostrEvent } & Omit) { return ( <>