mirror of
https://github.com/hzrd149/nostrudel.git
synced 2025-09-28 12:37:23 +02:00
clean up user reactions view
This commit is contained in:
5
.changeset/perfect-moons-help.md
Normal file
5
.changeset/perfect-moons-help.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"nostrudel": minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Clean up user reactions view
|
@@ -1,4 +1,5 @@
|
|||||||
import { Card, CardBody, CardHeader, CardProps, Flex, Heading, Link, Text } from "@chakra-ui/react";
|
import { Box, Card, CardBody, CardHeader, CardProps, Flex, Heading, Link, Text } from "@chakra-ui/react";
|
||||||
|
import dayjs from "dayjs";
|
||||||
|
|
||||||
import { getSharableEventAddress } from "../../../helpers/nip19";
|
import { getSharableEventAddress } from "../../../helpers/nip19";
|
||||||
import { NostrEvent } from "../../../types/nostr-event";
|
import { NostrEvent } from "../../../types/nostr-event";
|
||||||
@@ -7,11 +8,23 @@ import { UserLink } from "../../user-link";
|
|||||||
import { truncatedId } from "../../../helpers/nostr/events";
|
import { truncatedId } from "../../../helpers/nostr/events";
|
||||||
import { buildAppSelectUrl } from "../../../helpers/nostr/apps";
|
import { buildAppSelectUrl } from "../../../helpers/nostr/apps";
|
||||||
import { UserDnsIdentityIcon } from "../../user-dns-identity-icon";
|
import { UserDnsIdentityIcon } from "../../user-dns-identity-icon";
|
||||||
import dayjs from "dayjs";
|
import { useMemo } from "react";
|
||||||
|
import { embedEmoji, embedNostrHashtags, embedNostrLinks, embedNostrMentions } from "../../embed-types";
|
||||||
|
import { EmbedableContent } from "../../../helpers/embeds";
|
||||||
|
|
||||||
export default function EmbeddedUnknown({ event, ...props }: Omit<CardProps, "children"> & { event: NostrEvent }) {
|
export default function EmbeddedUnknown({ event, ...props }: Omit<CardProps, "children"> & { event: NostrEvent }) {
|
||||||
const address = getSharableEventAddress(event);
|
const address = getSharableEventAddress(event);
|
||||||
|
|
||||||
|
const content = useMemo(() => {
|
||||||
|
let jsx: EmbedableContent = [event.content];
|
||||||
|
jsx = embedNostrLinks(jsx);
|
||||||
|
jsx = embedNostrMentions(jsx, event);
|
||||||
|
jsx = embedNostrHashtags(jsx, event);
|
||||||
|
jsx = embedEmoji(jsx, event);
|
||||||
|
|
||||||
|
return jsx;
|
||||||
|
}, [event.content]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card {...props}>
|
<Card {...props}>
|
||||||
<CardHeader display="flex" gap="2" alignItems="center" p="2" pb="0" flexWrap="wrap">
|
<CardHeader display="flex" gap="2" alignItems="center" p="2" pb="0" flexWrap="wrap">
|
||||||
@@ -29,7 +42,7 @@ export default function EmbeddedUnknown({ event, ...props }: Omit<CardProps, "ch
|
|||||||
{address && truncatedId(address)}
|
{address && truncatedId(address)}
|
||||||
</Link>
|
</Link>
|
||||||
</Flex>
|
</Flex>
|
||||||
<Text whiteSpace="pre-wrap">{event.content}</Text>
|
<Box whiteSpace="pre-wrap">{content}</Box>
|
||||||
</CardBody>
|
</CardBody>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
import { useRef } from "react";
|
import { useRef } from "react";
|
||||||
import { useOutletContext } from "react-router-dom";
|
import { useOutletContext } from "react-router-dom";
|
||||||
import { Box, Flex, SkeletonText, Spacer, Text } from "@chakra-ui/react";
|
import { Box, Flex, Spacer, Text } from "@chakra-ui/react";
|
||||||
import { Kind } from "nostr-tools";
|
|
||||||
import { nip25 } from "nostr-tools";
|
import { nip25 } from "nostr-tools";
|
||||||
|
|
||||||
import useTimelineLoader from "../../hooks/use-timeline-loader";
|
import useTimelineLoader from "../../hooks/use-timeline-loader";
|
||||||
@@ -12,43 +11,36 @@ import TimelineActionAndStatus from "../../components/timeline-page/timeline-act
|
|||||||
import useSubject from "../../hooks/use-subject";
|
import useSubject from "../../hooks/use-subject";
|
||||||
import IntersectionObserverProvider, { useRegisterIntersectionEntity } from "../../providers/intersection-observer";
|
import IntersectionObserverProvider, { useRegisterIntersectionEntity } from "../../providers/intersection-observer";
|
||||||
import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";
|
import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";
|
||||||
import useSingleEvent from "../../hooks/use-single-event";
|
|
||||||
import { Note } from "../../components/note";
|
|
||||||
import { TrustProvider } from "../../providers/trust";
|
import { TrustProvider } from "../../providers/trust";
|
||||||
import { UserAvatar } from "../../components/user-avatar";
|
import { UserAvatar } from "../../components/user-avatar";
|
||||||
import { UserLink } from "../../components/user-link";
|
import { UserLink } from "../../components/user-link";
|
||||||
import { NoteMenu } from "../../components/note/note-menu";
|
import { NoteMenu } from "../../components/note/note-menu";
|
||||||
|
import { EmbedEventPointer } from "../../components/embed-event";
|
||||||
|
import { embedEmoji } from "../../components/embed-types";
|
||||||
|
|
||||||
const Reaction = ({ event }: { event: NostrEvent }) => {
|
const Reaction = ({ reaction: reaction }: { reaction: NostrEvent }) => {
|
||||||
const ref = useRef<HTMLDivElement | null>(null);
|
const ref = useRef<HTMLDivElement | null>(null);
|
||||||
useRegisterIntersectionEntity(ref, event.id);
|
useRegisterIntersectionEntity(ref, reaction.id);
|
||||||
|
|
||||||
const contextRelays = useAdditionalRelayContext();
|
const pointer = nip25.getReactedEventPointer(reaction);
|
||||||
const readRelays = useReadRelayUrls(contextRelays);
|
if (!pointer) return null;
|
||||||
|
|
||||||
const pointer = nip25.getReactedEventPointer(event);
|
const decoded = { type: "nevent", data: pointer } as const;
|
||||||
const { event: note } = useSingleEvent(pointer?.id, readRelays);
|
|
||||||
|
|
||||||
var content = <></>;
|
return (
|
||||||
if (!note) return <SkeletonText />;
|
<Box ref={ref}>
|
||||||
|
<Flex gap="2" mb="2">
|
||||||
if (note.kind === Kind.Text) {
|
<UserAvatar pubkey={reaction.pubkey} size="xs" />
|
||||||
content = (
|
<Text>
|
||||||
<>
|
<UserLink pubkey={reaction.pubkey} /> {reaction.content === "+" ? "liked" : "reacted with "}
|
||||||
<Flex gap="2" mb="2">
|
{embedEmoji([reaction.content], reaction)}
|
||||||
<UserAvatar pubkey={event.pubkey} size="xs" />
|
</Text>
|
||||||
<Text>
|
<Spacer />
|
||||||
<UserLink pubkey={event.pubkey} /> {event.content === "+" ? "liked" : "reacted with " + event.content}
|
<NoteMenu event={reaction} aria-label="Note menu" variant="ghost" size="xs" />
|
||||||
</Text>
|
</Flex>
|
||||||
<Spacer />
|
<EmbedEventPointer pointer={decoded} />
|
||||||
<NoteMenu event={event} aria-label="Note menu" variant="ghost" size="xs" />
|
</Box>
|
||||||
</Flex>
|
);
|
||||||
<Note key={note.id} event={note} />
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
} else content = <>Unknown note type {note.kind}</>;
|
|
||||||
|
|
||||||
return <Box ref={ref}>{content}</Box>;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function UserReactionsTab() {
|
export default function UserReactionsTab() {
|
||||||
@@ -67,7 +59,7 @@ export default function UserReactionsTab() {
|
|||||||
<TrustProvider trust>
|
<TrustProvider trust>
|
||||||
<Flex direction="column" gap="2" p="2" pb="8">
|
<Flex direction="column" gap="2" p="2" pb="8">
|
||||||
{likes.map((event) => (
|
{likes.map((event) => (
|
||||||
<Reaction event={event} />
|
<Reaction reaction={event} />
|
||||||
))}
|
))}
|
||||||
|
|
||||||
<TimelineActionAndStatus timeline={timeline} />
|
<TimelineActionAndStatus timeline={timeline} />
|
||||||
|
Reference in New Issue
Block a user