diff --git a/src/components/embed-event/event-types/embedded-community.tsx b/src/components/embed-event/event-types/embedded-community.tsx new file mode 100644 index 000000000..bdb9ae31a --- /dev/null +++ b/src/components/embed-event/event-types/embedded-community.tsx @@ -0,0 +1,49 @@ +import { Link as RouterLink } from "react-router-dom"; +import { Box, Card, CardProps, Center, Flex, Heading, LinkBox, LinkOverlay, Text } from "@chakra-ui/react"; +import { nip19 } from "nostr-tools"; + +import { UserAvatarLink } from "../../../components/user-avatar-link"; +import { UserLink } from "../../../components/user-link"; +import { NostrEvent } from "../../../types/nostr-event"; +import { getCommunityImage, getCommunityName } from "../../../helpers/nostr/communities"; +import CommunityDescription from "../../../views/communities/components/community-description"; + +export default function EmbeddedCommunity({ + community, + ...props +}: Omit & { community: NostrEvent }) { + const image = getCommunityImage(community); + + return ( + + {image ? ( + + ) : ( +
+ {getCommunityName(community)} +
+ )} + + + + + {getCommunityName(community)} + + + Created by: + + + + +
+ ); +} diff --git a/src/components/embed-event/index.tsx b/src/components/embed-event/index.tsx index 53ef2cad3..b3b6d13e6 100644 --- a/src/components/embed-event/index.tsx +++ b/src/components/embed-event/index.tsx @@ -21,6 +21,8 @@ import EmbeddedList from "./event-types/embedded-list"; import EmbeddedArticle from "./event-types/embedded-article"; import EmbeddedBadge from "./event-types/embedded-badge"; import EmbeddedStreamMessage from "./event-types/embedded-stream-message"; +import { COMMUNITY_DEFINITION_KIND } from "../../helpers/nostr/communities"; +import EmbeddedCommunity from "./event-types/embedded-community"; export type EmbedProps = { goalProps?: EmbeddedGoalOptions; @@ -49,6 +51,8 @@ export function EmbedEvent({ return ; case STREAM_CHAT_MESSAGE_KIND: return ; + case COMMUNITY_DEFINITION_KIND: + return ; } return ; diff --git a/src/components/note/components/bookmark-button.tsx b/src/components/note/components/bookmark-button.tsx index 01aaa48cd..b7d9c26a8 100644 --- a/src/components/note/components/bookmark-button.tsx +++ b/src/components/note/components/bookmark-button.tsx @@ -18,8 +18,8 @@ import { useSigningContext } from "../../../providers/signing-provider"; import useUserLists from "../../../hooks/use-user-lists"; import { NOTE_LIST_KIND, - draftAddEvent, - draftRemoveEvent, + listAddEvent, + listRemoveEvent, getEventsFromList, getListName, } from "../../../helpers/nostr/lists"; @@ -55,11 +55,11 @@ export default function BookmarkButton({ event, ...props }: { event: NostrEvent ); if (addToList) { - const draft = draftAddEvent(addToList, event.id); + const draft = listAddEvent(addToList, event.id); const signed = await requestSignature(draft); const pub = new NostrPublishAction("Add to list", writeRelays, signed); } else if (removeFromList) { - const draft = draftRemoveEvent(removeFromList, event.id); + const draft = listRemoveEvent(removeFromList, event.id); const signed = await requestSignature(draft); const pub = new NostrPublishAction("Remove from list", writeRelays, signed); } diff --git a/src/components/user-follow-button.tsx b/src/components/user-follow-button.tsx index 4dfab7934..19a8ffae9 100644 --- a/src/components/user-follow-button.tsx +++ b/src/components/user-follow-button.tsx @@ -20,8 +20,8 @@ import { PEOPLE_LIST_KIND, createEmptyContactList, createEmptyMuteList, - draftAddPerson, - draftRemovePerson, + listAddPerson, + listRemovePerson, getListName, getPubkeysFromList, isPubkeyInList, @@ -62,11 +62,11 @@ function UsersLists({ pubkey }: { pubkey: string }) { ); if (addToList) { - const draft = draftAddPerson(addToList, pubkey); + const draft = listAddPerson(addToList, pubkey); const signed = await requestSignature(draft); const pub = new NostrPublishAction("Add to list", writeRelays, signed); } else if (removeFromList) { - const draft = draftRemovePerson(removeFromList, pubkey); + const draft = listRemovePerson(removeFromList, pubkey); const signed = await requestSignature(draft); const pub = new NostrPublishAction("Remove from list", writeRelays, signed); } @@ -125,13 +125,13 @@ export const UserFollowButton = ({ pubkey, showLists, ...props }: UserFollowButt const isDisabled = account?.readonly ?? true; const handleFollow = useAsyncErrorHandler(async () => { - const draft = draftAddPerson(contacts || createEmptyContactList(), pubkey); + const draft = listAddPerson(contacts || createEmptyContactList(), pubkey); const signed = await requestSignature(draft); const pub = new NostrPublishAction("Follow", clientRelaysService.getWriteUrls(), signed); replaceableEventLoaderService.handleEvent(signed); }); const handleUnfollow = useAsyncErrorHandler(async () => { - const draft = draftRemovePerson(contacts || createEmptyContactList(), pubkey); + const draft = listRemovePerson(contacts || createEmptyContactList(), pubkey); const signed = await requestSignature(draft); const pub = new NostrPublishAction("Unfollow", clientRelaysService.getWriteUrls(), signed); replaceableEventLoaderService.handleEvent(signed); diff --git a/src/helpers/nostr/communities.ts b/src/helpers/nostr/communities.ts index ff6441910..74e0c3108 100644 --- a/src/helpers/nostr/communities.ts +++ b/src/helpers/nostr/communities.ts @@ -1,5 +1,6 @@ import { NostrEvent, isDTag, isPTag } from "../../types/nostr-event"; +export const SUBSCRIBED_COMMUNITIES_LIST_IDENTIFIER = "communities"; export const COMMUNITY_DEFINITION_KIND = 34550; export const COMMUNITY_APPROVAL_KIND = 4550; diff --git a/src/helpers/nostr/lists.ts b/src/helpers/nostr/lists.ts index d7e432348..d2ff28dc6 100644 --- a/src/helpers/nostr/lists.ts +++ b/src/helpers/nostr/lists.ts @@ -1,6 +1,9 @@ import dayjs from "dayjs"; -import { Kind } from "nostr-tools"; +import { Kind, nip19 } from "nostr-tools"; +import { AddressPointer } from "nostr-tools/lib/nip19"; + import { DraftNostrEvent, NostrEvent, isATag, isDTag, isETag, isPTag } from "../../types/nostr-event"; +import { parseCoordinate } from "./events"; export const PEOPLE_LIST_KIND = 30000; export const NOTE_LIST_KIND = 30001; @@ -31,6 +34,20 @@ export function getEventsFromList(event: NostrEvent) { export function getCoordinatesFromList(event: NostrEvent) { return event.tags.filter(isATag).map((t) => ({ coordinate: t[1], relay: t[2] })); } +export function getParsedCordsFromList(event: NostrEvent) { + const pointers: AddressPointer[] = []; + + for (const tag of event.tags) { + if (!tag[1]) continue; + const relay = tag[2]; + const parsed = parseCoordinate(tag[1]); + if (!parsed?.identifier) continue; + + pointers.push({ ...parsed, identifier: parsed?.identifier, relays: relay ? [relay] : undefined }); + } + + return pointers; +} export function isPubkeyInList(event?: NostrEvent, pubkey?: string) { if (!pubkey || !event) return false; @@ -54,50 +71,63 @@ export function createEmptyMuteList(): DraftNostrEvent { }; } -export function draftAddPerson(list: NostrEvent | DraftNostrEvent, pubkey: string, relay?: string) { +export function listAddPerson(list: NostrEvent | DraftNostrEvent, pubkey: string, relay?: string): DraftNostrEvent { if (list.tags.some((t) => t[0] === "p" && t[1] === pubkey)) throw new Error("person already in list"); - - const draft: DraftNostrEvent = { + return { created_at: dayjs().unix(), kind: list.kind, content: list.content, tags: [...list.tags, relay ? ["p", pubkey, relay] : ["p", pubkey]], }; - - return draft; } -export function draftRemovePerson(list: NostrEvent | DraftNostrEvent, pubkey: string) { - const draft: DraftNostrEvent = { +export function listRemovePerson(list: NostrEvent | DraftNostrEvent, pubkey: string): DraftNostrEvent { + return { created_at: dayjs().unix(), kind: list.kind, content: list.content, tags: list.tags.filter((t) => !(t[0] === "p" && t[1] === pubkey)), }; - - return draft; } -export function draftAddEvent(list: NostrEvent | DraftNostrEvent, event: string, relay?: string) { +export function listAddEvent(list: NostrEvent | DraftNostrEvent, event: string, relay?: string): DraftNostrEvent { if (list.tags.some((t) => t[0] === "e" && t[1] === event)) throw new Error("event already in list"); - - const draft: DraftNostrEvent = { + return { created_at: dayjs().unix(), kind: list.kind, content: list.content, tags: [...list.tags, relay ? ["e", event, relay] : ["e", event]], }; - - return draft; } -export function draftRemoveEvent(list: NostrEvent | DraftNostrEvent, event: string) { - const draft: DraftNostrEvent = { +export function listRemoveEvent(list: NostrEvent | DraftNostrEvent, event: string): DraftNostrEvent { + return { created_at: dayjs().unix(), kind: list.kind, content: list.content, tags: list.tags.filter((t) => !(t[0] === "e" && t[1] === event)), }; - - return draft; +} + +export function listAddCoordinate( + list: NostrEvent | DraftNostrEvent, + coordinate: string, + relay?: string, +): DraftNostrEvent { + if (list.tags.some((t) => t[0] === "a" && t[1] === coordinate)) throw new Error("coordinate already in list"); + return { + created_at: dayjs().unix(), + kind: list.kind, + content: list.content, + tags: [...list.tags, relay ? ["a", coordinate, relay] : ["a", coordinate]], + }; +} + +export function listRemoveCoordinate(list: NostrEvent | DraftNostrEvent, coordinate: string): DraftNostrEvent { + return { + created_at: dayjs().unix(), + kind: list.kind, + content: list.content, + tags: list.tags.filter((t) => !(t[0] === "a" && t[1] === coordinate)), + }; } diff --git a/src/hooks/use-subscribed-communities-list.ts b/src/hooks/use-subscribed-communities-list.ts new file mode 100644 index 000000000..686a88a62 --- /dev/null +++ b/src/hooks/use-subscribed-communities-list.ts @@ -0,0 +1,26 @@ +import { COMMUNITY_DEFINITION_KIND, SUBSCRIBED_COMMUNITIES_LIST_IDENTIFIER } from "../helpers/nostr/communities"; +import { NOTE_LIST_KIND, getParsedCordsFromList } from "../helpers/nostr/lists"; +import { useCurrentAccount } from "./use-current-account"; +import useReplaceableEvent from "./use-replaceable-event"; + +export default function useSubscribedCommunitiesList(pubkey?: string) { + const account = useCurrentAccount(); + const key = pubkey ?? account?.pubkey; + + const list = useReplaceableEvent( + key + ? { + kind: NOTE_LIST_KIND, + identifier: SUBSCRIBED_COMMUNITIES_LIST_IDENTIFIER, + pubkey: key, + } + : undefined, + ); + + const pointers = list ? getParsedCordsFromList(list).filter((cord) => cord.kind === COMMUNITY_DEFINITION_KIND) : []; + + return { + list, + pointers, + }; +} diff --git a/src/hooks/use-user-mute-functions.ts b/src/hooks/use-user-mute-functions.ts index 73bf96caa..6a2c26315 100644 --- a/src/hooks/use-user-mute-functions.ts +++ b/src/hooks/use-user-mute-functions.ts @@ -1,5 +1,5 @@ import NostrPublishAction from "../classes/nostr-publish-action"; -import { createEmptyMuteList, draftAddPerson, draftRemovePerson, isPubkeyInList } from "../helpers/nostr/lists"; +import { createEmptyMuteList, listAddPerson, listRemovePerson, isPubkeyInList } from "../helpers/nostr/lists"; import { useSigningContext } from "../providers/signing-provider"; import clientRelaysService from "../services/client-relays"; import replaceableEventLoaderService from "../services/replaceable-event-requester"; @@ -15,13 +15,13 @@ export default function useUserMuteFunctions(pubkey: string) { const isMuted = isPubkeyInList(muteList, pubkey); const mute = useAsyncErrorHandler(async () => { - const draft = draftAddPerson(muteList || createEmptyMuteList(), pubkey); + const draft = listAddPerson(muteList || createEmptyMuteList(), pubkey); const signed = await requestSignature(draft); new NostrPublishAction("Mute", clientRelaysService.getWriteUrls(), signed); replaceableEventLoaderService.handleEvent(signed); }); const unmute = useAsyncErrorHandler(async () => { - const draft = draftRemovePerson(muteList || createEmptyMuteList(), pubkey); + const draft = listRemovePerson(muteList || createEmptyMuteList(), pubkey); const signed = await requestSignature(draft); new NostrPublishAction("Unmute", clientRelaysService.getWriteUrls(), signed); replaceableEventLoaderService.handleEvent(signed); diff --git a/src/views/communities/components/community-card.tsx b/src/views/communities/components/community-card.tsx index 414d20157..fdb68de21 100644 --- a/src/views/communities/components/community-card.tsx +++ b/src/views/communities/components/community-card.tsx @@ -1,18 +1,6 @@ import { memo, useRef } from "react"; import { Link as RouterLink } from "react-router-dom"; -import { - Avatar, - Box, - Card, - CardProps, - Center, - Flex, - Heading, - Image, - LinkBox, - LinkOverlay, - Text, -} from "@chakra-ui/react"; +import { Box, Card, CardProps, Center, Flex, Heading, LinkBox, LinkOverlay, Text } from "@chakra-ui/react"; import { UserAvatarLink } from "../../../components/user-avatar-link"; import { UserLink } from "../../../components/user-link"; @@ -39,10 +27,10 @@ function CommunityCard({ community, ...props }: Omit & { backgroundRepeat="no-repeat" backgroundSize="cover" backgroundPosition="center" - aspectRatio={4 / 1} + aspectRatio={3 / 1} /> ) : ( -
+
{getCommunityName(community)}
)} diff --git a/src/views/communities/components/community-subscribe-button.tsx b/src/views/communities/components/community-subscribe-button.tsx new file mode 100644 index 000000000..b0620e593 --- /dev/null +++ b/src/views/communities/components/community-subscribe-button.tsx @@ -0,0 +1,58 @@ +import { useCallback } from "react"; +import dayjs from "dayjs"; +import { Button, ButtonProps, useToast } from "@chakra-ui/react"; + +import { DraftNostrEvent, NostrEvent } from "../../../types/nostr-event"; +import useSubscribedCommunitiesList from "../../../hooks/use-subscribed-communities-list"; +import { useCurrentAccount } from "../../../hooks/use-current-account"; +import { SUBSCRIBED_COMMUNITIES_LIST_IDENTIFIER, getCommunityName } from "../../../helpers/nostr/communities"; +import { NOTE_LIST_KIND, listAddCoordinate, listRemoveCoordinate } from "../../../helpers/nostr/lists"; +import { getEventCoordinate } from "../../../helpers/nostr/events"; +import { useSigningContext } from "../../../providers/signing-provider"; +import NostrPublishAction from "../../../classes/nostr-publish-action"; +import clientRelaysService from "../../../services/client-relays"; + +export default function CommunityJoinButton({ + community, + ...props +}: Omit & { community: NostrEvent }) { + const account = useCurrentAccount(); + const { list, pointers } = useSubscribedCommunitiesList(account?.pubkey); + const { requestSignature } = useSigningContext(); + const toast = useToast(); + + const isSubscribed = pointers.find( + (cord) => cord.identifier === getCommunityName(community) && cord.pubkey === community.pubkey, + ); + + const handleClick = useCallback(async () => { + try { + const favList = list || { + kind: NOTE_LIST_KIND, + content: "", + created_at: dayjs().unix(), + tags: [["d", SUBSCRIBED_COMMUNITIES_LIST_IDENTIFIER]], + }; + + let draft: DraftNostrEvent; + if (isSubscribed) { + draft = listRemoveCoordinate(favList, getEventCoordinate(community)); + } else { + draft = listAddCoordinate(favList, getEventCoordinate(community)); + } + + const signed = await requestSignature(draft); + console.log(signed); + + new NostrPublishAction(isSubscribed ? "Unsubscribe" : "Subscribe", clientRelaysService.getWriteUrls(), signed); + } catch (e) { + if (e instanceof Error) toast({ description: e.message, status: "error" }); + } + }, [isSubscribed, list, community]); + + return ( + + ); +} diff --git a/src/views/communities/index.tsx b/src/views/communities/index.tsx index 2fbea13c9..9db7f4a4b 100644 --- a/src/views/communities/index.tsx +++ b/src/views/communities/index.tsx @@ -45,7 +45,7 @@ function CommunitiesHomePage() { - + {communities.map((event) => ( ))} diff --git a/src/views/community/community-home.tsx b/src/views/community/community-home.tsx index 8e7bec69a..1856e77e4 100644 --- a/src/views/community/community-home.tsx +++ b/src/views/community/community-home.tsx @@ -20,6 +20,7 @@ import useSubject from "../../hooks/use-subject"; import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback"; import IntersectionObserverProvider from "../../providers/intersection-observer"; import Note from "../../components/note"; +import CommunityJoinButton from "../communities/components/community-subscribe-button"; export default function CommunityHomePage({ community }: { community: NostrEvent }) { const mods = getCommunityMods(community); @@ -52,6 +53,7 @@ export default function CommunityHomePage({ community }: { community: NostrEvent + diff --git a/src/views/community/find-by-name.tsx b/src/views/community/find-by-name.tsx index 1a5e72fae..997229035 100644 --- a/src/views/community/find-by-name.tsx +++ b/src/views/community/find-by-name.tsx @@ -11,7 +11,7 @@ import IntersectionObserverProvider from "../../providers/intersection-observer" import VerticalPageLayout from "../../components/vertical-page-layout"; import CommunityCard from "../communities/components/community-card"; import { getEventUID } from "../../helpers/nostr/events"; -import { Divider, Heading } from "@chakra-ui/react"; +import { Divider, Heading, SimpleGrid } from "@chakra-ui/react"; export default function CommunityFindByNameView() { const { community } = useParams() as { community: string }; @@ -35,9 +35,11 @@ export default function CommunityFindByNameView() { Select Community: - {communities.map((event) => ( - - ))} + + {communities.map((event) => ( + + ))} + ); diff --git a/src/views/lists/browse.tsx b/src/views/lists/browse.tsx index ff41f1dfd..116d6e79f 100644 --- a/src/views/lists/browse.tsx +++ b/src/views/lists/browse.tsx @@ -71,7 +71,7 @@ function BrowseListPage() { {lists.map((event) => ( - + ))} diff --git a/src/views/lists/components/list-card.tsx b/src/views/lists/components/list-card.tsx index 5ffd91583..6cbe2eec6 100644 --- a/src/views/lists/components/list-card.tsx +++ b/src/views/lists/components/list-card.tsx @@ -13,10 +13,17 @@ import { Link, Text, } from "@chakra-ui/react"; +import { nip19 } from "nostr-tools"; import { UserAvatarLink } from "../../../components/user-avatar-link"; import { UserLink } from "../../../components/user-link"; -import { getEventsFromList, getListName, getPubkeysFromList, isSpecialListKind } from "../../../helpers/nostr/lists"; +import { + getEventsFromList, + getListName, + getParsedCordsFromList, + getPubkeysFromList, + isSpecialListKind, +} from "../../../helpers/nostr/lists"; import { getSharableEventAddress } from "../../../helpers/nip19"; import { NostrEvent } from "../../../types/nostr-event"; import useReplaceableEvent from "../../../hooks/use-replaceable-event"; @@ -28,39 +35,40 @@ import ListFavoriteButton from "./list-favorite-button"; import { getEventUID } from "../../../helpers/nostr/events"; import ListMenu from "./list-menu"; import Timestamp from "../../../components/timestamp"; +import { COMMUNITY_DEFINITION_KIND } from "../../../helpers/nostr/communities"; -function ListCardRender({ event, ...props }: Omit & { event: NostrEvent }) { - const people = getPubkeysFromList(event); - const notes = getEventsFromList(event); - const link = isSpecialListKind(event.kind) - ? createCoordinate(event.kind, event.pubkey) - : getSharableEventAddress(event); +function ListCardRender({ list, ...props }: Omit & { list: NostrEvent }) { + const people = getPubkeysFromList(list); + const notes = getEventsFromList(list); + const coordinates = getParsedCordsFromList(list); + const communities = coordinates.filter((cord) => cord.kind === COMMUNITY_DEFINITION_KIND); + const link = isSpecialListKind(list.kind) ? createCoordinate(list.kind, list.pubkey) : getSharableEventAddress(list); // if there is a parent intersection observer, register this card const ref = useRef(null); - useRegisterIntersectionEntity(ref, getEventUID(event)); + useRegisterIntersectionEntity(ref, getEventUID(list)); return ( - {getListName(event)} + {getListName(list)} - - + + Created by: - - + + - Updated: + Updated: {people.length > 0 && ( <> @@ -82,18 +90,34 @@ function ListCardRender({ event, ...props }: Omit & { eve )} + {communities.length > 0 && ( + <> + Communities ({communities.length}): + + {communities.map((pointer) => ( + + {pointer.identifier} + + ))} + + + )} - + ); } -function ListCard({ cord, event: maybeEvent }: { cord?: string; event?: NostrEvent }) { +function ListCard({ cord, list: maybeEvent }: { cord?: string; list?: NostrEvent }) { const event = maybeEvent ?? (cord ? useReplaceableEvent(cord as string) : undefined); if (!event) return null; - else return ; + else return ; } export default memo(ListCard); diff --git a/src/views/lists/components/user-card.tsx b/src/views/lists/components/user-card.tsx index 3f43d4634..48ccf38b6 100644 --- a/src/views/lists/components/user-card.tsx +++ b/src/views/lists/components/user-card.tsx @@ -8,7 +8,7 @@ import { UserAvatar } from "../../../components/user-avatar"; import { UserDnsIdentityIcon } from "../../../components/user-dns-identity-icon"; import { NostrEvent } from "../../../types/nostr-event"; import useAsyncErrorHandler from "../../../hooks/use-async-error-handler"; -import { draftRemovePerson } from "../../../helpers/nostr/lists"; +import { listRemovePerson } from "../../../helpers/nostr/lists"; import { useSigningContext } from "../../../providers/signing-provider"; import NostrPublishAction from "../../../classes/nostr-publish-action"; import clientRelaysService from "../../../services/client-relays"; @@ -23,7 +23,7 @@ export default function UserCard({ pubkey, relay, list, ...props }: UserCardProp const { requestSignature } = useSigningContext(); const handleRemoveFromList = useAsyncErrorHandler(async () => { - const draft = draftRemovePerson(list, pubkey); + const draft = listRemovePerson(list, pubkey); const signed = await requestSignature(draft); const pub = new NostrPublishAction("Remove from list", clientRelaysService.getWriteUrls(), signed); }, [list]); diff --git a/src/views/lists/index.tsx b/src/views/lists/index.tsx index 3a7c34722..a8b21469c 100644 --- a/src/views/lists/index.tsx +++ b/src/views/lists/index.tsx @@ -58,7 +58,7 @@ function ListsPage() { {peopleLists.map((event) => ( - + ))} @@ -69,7 +69,7 @@ function ListsPage() { {noteLists.map((event) => ( - + ))} @@ -80,7 +80,7 @@ function ListsPage() { {favoriteLists.map((event) => ( - + ))} diff --git a/src/views/lists/list-details.tsx b/src/views/lists/list-details.tsx index 1ef0a64ff..add0f6928 100644 --- a/src/views/lists/list-details.tsx +++ b/src/views/lists/list-details.tsx @@ -7,7 +7,7 @@ import { ArrowLeftSIcon } from "../../components/icons"; import { useCurrentAccount } from "../../hooks/use-current-account"; import { useDeleteEventContext } from "../../providers/delete-event-provider"; import { parseCoordinate } from "../../helpers/nostr/events"; -import { getEventsFromList, getListName, getPubkeysFromList } from "../../helpers/nostr/lists"; +import { getEventsFromList, getListName, getParsedCordsFromList, getPubkeysFromList } from "../../helpers/nostr/lists"; import useReplaceableEvent from "../../hooks/use-replaceable-event"; import UserCard from "./components/user-card"; import NoteCard from "./components/note-card"; @@ -16,6 +16,8 @@ import ListMenu from "./components/list-menu"; import ListFavoriteButton from "./components/list-favorite-button"; import ListFeedButton from "./components/list-feed-button"; import VerticalPageLayout from "../../components/vertical-page-layout"; +import { COMMUNITY_DEFINITION_KIND } from "../../helpers/nostr/communities"; +import { EmbedEventPointer } from "../../components/embed-event"; function useListCoordinate() { const { addr } = useParams() as { addr: string }; @@ -37,18 +39,20 @@ export default function ListDetailsView() { const { deleteEvent } = useDeleteEventContext(); const account = useCurrentAccount(); - const event = useReplaceableEvent(coordinate); + const list = useReplaceableEvent(coordinate); - if (!event) + if (!list) return ( <> Looking for list "{coordinate.identifier}" created by ); - const isAuthor = account?.pubkey === event.pubkey; - const people = getPubkeysFromList(event); - const notes = getEventsFromList(event); + const isAuthor = account?.pubkey === list.pubkey; + const people = getPubkeysFromList(list); + const notes = getEventsFromList(list); + const coordinates = getParsedCordsFromList(list); + const communities = coordinates.filter((cord) => cord.kind === COMMUNITY_DEFINITION_KIND); return ( @@ -58,19 +62,19 @@ export default function ListDetailsView() { - {getListName(event)} + {getListName(list)} - + - + {isAuthor && ( - )} - + {people.length > 0 && ( @@ -79,7 +83,7 @@ export default function ListDetailsView() { {people.map(({ pubkey, relay }) => ( - + ))} @@ -98,6 +102,18 @@ export default function ListDetailsView() { )} + + {communities.length > 0 && ( + <> + Communities + + + {communities.map((pointer) => ( + + ))} + + + )} ); } diff --git a/src/views/user/lists.tsx b/src/views/user/lists.tsx index 03ac94e2d..91652fc96 100644 --- a/src/views/user/lists.tsx +++ b/src/views/user/lists.tsx @@ -48,7 +48,7 @@ export default function UserListsTab() { {peopleLists.map((event) => ( - + ))} @@ -62,7 +62,7 @@ export default function UserListsTab() { {noteLists.map((event) => ( - + ))}