Show list embeds in notes

This commit is contained in:
hzrd149 2023-09-08 11:16:19 -05:00
parent 3d5d23407d
commit 6b4fd8ab42
7 changed files with 97 additions and 28 deletions

View File

@ -0,0 +1,5 @@
---
"nostrudel": minor
---
Show list embeds in notes

View File

@ -0,0 +1,51 @@
import { AvatarGroup, Card, CardBody, CardHeader, CardProps, Flex, Heading, Link, Text } from "@chakra-ui/react";
import { Link as RouterLink } from "react-router-dom";
import { NostrEvent } from "../../../types/nostr-event";
import { getEventsFromList, getListName, getPubkeysFromList, isSpecialListKind } from "../../../helpers/nostr/lists";
import { createCoordinate } from "../../../services/replaceable-event-requester";
import { getSharableEventAddress } from "../../../helpers/nip19";
import { UserAvatarLink } from "../../user-avatar-link";
import { UserLink } from "../../user-link";
import { NoteLink } from "../../note-link";
import ListFeedButton from "../../../views/lists/components/list-feed-button";
export default function EmbeddedList({ list: list, ...props }: Omit<CardProps, "children"> & { list: NostrEvent }) {
const people = getPubkeysFromList(list);
const notes = getEventsFromList(list);
const link = isSpecialListKind(list.kind) ? createCoordinate(list.kind, list.pubkey) : getSharableEventAddress(list);
return (
<Card {...props}>
<CardHeader display="flex" alignItems="center" p="2" pb="0" gap="2">
<Heading size="md">
<Link as={RouterLink} to={`/lists/${link}`}>
{getListName(list)}
</Link>
</Heading>
<ListFeedButton list={list} ml="auto" size="sm" />
</CardHeader>
<CardBody p="2">
<Flex gap="2">
<Text>Created by:</Text>
<UserAvatarLink pubkey={list.pubkey} size="xs" />
<UserLink pubkey={list.pubkey} isTruncated fontWeight="bold" fontSize="lg" />
</Flex>
{people.length > 0 && (
<AvatarGroup overflow="hidden" mb="2" max={16} size="sm">
{people.map(({ pubkey, relay }) => (
<UserAvatarLink key={pubkey} pubkey={pubkey} relay={relay} />
))}
</AvatarGroup>
)}
{notes.length > 0 && (
<Flex gap="2" overflow="hidden">
{notes.map(({ id, relay }) => (
<NoteLink key={id} noteId={id} />
))}
</Flex>
)}
</CardBody>
</Card>
);
}

View File

@ -15,6 +15,8 @@ import { EMOJI_PACK_KIND } from "../../helpers/nostr/emoji-packs";
import EmbeddedEmojiPack from "./event-types/embedded-emoji-pack";
import EmbeddedGoal, { EmbeddedGoalOptions } from "./event-types/embedded-goal";
import EmbeddedUnknown from "./event-types/embedded-unknown";
import { NOTE_LIST_KIND, PEOPLE_LIST_KIND } from "../../helpers/nostr/lists";
import EmbeddedList from "./event-types/embedded-list";
export type EmbedProps = {
goalProps?: EmbeddedGoalOptions;
@ -30,6 +32,9 @@ export function EmbedEvent({ event, goalProps }: { event: NostrEvent } & EmbedPr
return <EmbeddedGoal goal={event} {...goalProps} />;
case EMOJI_PACK_KIND:
return <EmbeddedEmojiPack pack={event} />;
case PEOPLE_LIST_KIND:
case NOTE_LIST_KIND:
return <EmbeddedList list={event} />;
}
return <EmbeddedUnknown event={event} />;

View File

@ -20,6 +20,7 @@ import clientRelaysService from "../../../services/client-relays";
import QuoteNote from "../quote-note";
import NostrPublishAction from "../../../classes/nostr-publish-action";
import { useSigningContext } from "../../../providers/signing-provider";
import { EmbedEvent } from "../../embed-event";
export function RepostButton({ event }: { event: NostrEvent }) {
const { isOpen, onClose, onOpen } = useDisclosure();
@ -51,7 +52,7 @@ export function RepostButton({ event }: { event: NostrEvent }) {
isLoading={loading}
/>
{isOpen && (
<Modal isOpen={isOpen} onClose={onClose}>
<Modal isOpen={isOpen} onClose={onClose} size="2xl">
<ModalOverlay />
<ModalContent>
<ModalHeader px="4" py="2">
@ -59,7 +60,7 @@ export function RepostButton({ event }: { event: NostrEvent }) {
</ModalHeader>
<ModalCloseButton />
<ModalBody px="4" py="0">
<QuoteNote noteId={event.id} />
<EmbedEvent event={event} />
</ModalBody>
<ModalFooter px="4" py="4">

View File

@ -7,7 +7,6 @@ import {
AccordionPanel,
Box,
Button,
Code,
Flex,
Input,
Link,
@ -21,12 +20,11 @@ import {
Text,
useToast,
} from "@chakra-ui/react";
import { Event, Kind, nip19 } from "nostr-tools";
import { Event, Kind } from "nostr-tools";
import dayjs from "dayjs";
import { useCurrentAccount } from "../hooks/use-current-account";
import signingService from "../services/signing";
import QuoteNote from "../components/note/quote-note";
import createDefer, { Deferred } from "../classes/deferred";
import useEventRelays from "../hooks/use-event-relays";
import { useWriteRelayUrls } from "../hooks/use-client-relays";
@ -36,6 +34,7 @@ import { getEventCoordinate, getEventUID, isReplaceable } from "../helpers/nostr
import NostrPublishAction from "../classes/nostr-publish-action";
import { Tag } from "../types/nostr-event";
import deleteEventService from "../services/delete-events";
import { EmbedEvent } from "../components/embed-event";
type DeleteEventContextType = {
isLoading: boolean;
@ -51,13 +50,6 @@ export function useDeleteEventContext() {
return useContext(DeleteEventContext);
}
function EventPreview({ event }: { event: Event }) {
if (event.kind === Kind.Text) {
return <QuoteNote noteId={event.id} />;
}
return <Code>{nip19.noteEncode(event.id)}</Code>;
}
export default function DeleteEventProvider({ children }: PropsWithChildren) {
const toast = useToast();
const account = useCurrentAccount();
@ -124,11 +116,11 @@ export default function DeleteEventProvider({ children }: PropsWithChildren) {
<ModalOverlay />
<ModalContent>
<ModalHeader px="4" py="2">
Delete Note?
Delete Event?
</ModalHeader>
<ModalCloseButton />
<ModalBody px="4" py="0">
<EventPreview event={event} />
<EmbedEvent event={event} />
<Input
name="reason"
value={reason}

View File

@ -0,0 +1,23 @@
import { Button, ButtonProps } from "@chakra-ui/react";
import { Link as RouterLink } from "react-router-dom";
import { Kind } from "nostr-tools";
import { NostrEvent } from "../../../types/nostr-event";
import { getEventCoordinate } from "../../../helpers/nostr/events";
import { PEOPLE_LIST_KIND } from "../../../helpers/nostr/lists";
export default function ListFeedButton({ list, ...props }: { list: NostrEvent } & Omit<ButtonProps, "children">) {
const shouldShowFeedButton = list.kind === PEOPLE_LIST_KIND || list.kind === Kind.Contacts;
if (!shouldShowFeedButton) return null;
return (
<Button
as={RouterLink}
to={{ pathname: "/", search: new URLSearchParams({ people: getEventCoordinate(list) }).toString() }}
{...props}
>
View Feed
</Button>
);
}

View File

@ -1,14 +1,13 @@
import { Link as RouterList, useNavigate, useParams } from "react-router-dom";
import { Kind, nip19 } from "nostr-tools";
import { Link as RouterLink } from "react-router-dom";
import { useNavigate, useParams } from "react-router-dom";
import { nip19 } from "nostr-tools";
import { UserLink } from "../../components/user-link";
import { Button, Divider, Flex, Heading, SimpleGrid, Spacer } from "@chakra-ui/react";
import { ArrowLeftSIcon } from "../../components/icons";
import { useCurrentAccount } from "../../hooks/use-current-account";
import { useDeleteEventContext } from "../../providers/delete-event-provider";
import { getEventCoordinate, parseCoordinate } from "../../helpers/nostr/events";
import { PEOPLE_LIST_KIND, getEventsFromList, getListName, getPubkeysFromList } from "../../helpers/nostr/lists";
import { parseCoordinate } from "../../helpers/nostr/events";
import { getEventsFromList, getListName, getPubkeysFromList } from "../../helpers/nostr/lists";
import useReplaceableEvent from "../../hooks/use-replaceable-event";
import { EventRelays } from "../../components/note/note-relays";
import UserCard from "./components/user-card";
@ -16,6 +15,7 @@ import NoteCard from "./components/note-card";
import { TrustProvider } from "../../providers/trust";
import ListMenu from "./components/list-menu";
import ListFavoriteButton from "./components/list-favorite-button";
import ListFeedButton from "./components/list-feed-button";
function useListCoordinate() {
const { addr } = useParams() as { addr: string };
@ -47,7 +47,6 @@ export default function ListDetailsView() {
);
const isAuthor = account?.pubkey === event.pubkey;
const shouldShowFeedButton = event.kind === PEOPLE_LIST_KIND || event.kind === Kind.Contacts;
const people = getPubkeysFromList(event);
const notes = getEventsFromList(event);
@ -67,14 +66,7 @@ export default function ListDetailsView() {
<EventRelays event={event} />
{shouldShowFeedButton && (
<Button
as={RouterLink}
to={{ pathname: "/", search: new URLSearchParams({ people: getEventCoordinate(event) }).toString() }}
>
View Feed
</Button>
)}
<ListFeedButton list={event} />
{isAuthor && (
<Button colorScheme="red" onClick={() => deleteEvent(event).then(() => navigate("/lists"))}>
Delete