mirror of
https://github.com/hzrd149/nostrudel.git
synced 2025-06-23 07:11:12 +02:00
make list card component more compact
hide empty lists events created by other clients only show list favorite button for people lists
This commit is contained in:
parent
2d41abf44a
commit
af973af93e
@ -18,6 +18,12 @@ export function getListName(event: NostrEvent) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isJunkList(event: NostrEvent) {
|
||||||
|
const name = event.tags.find(isDTag)?.[1];
|
||||||
|
if (!name) return false;
|
||||||
|
if (event.kind !== PEOPLE_LIST_KIND) return false;
|
||||||
|
return /^(chats\/([0-9a-f]{64}|null)|notifications)\/lastOpened$/.test(name);
|
||||||
|
}
|
||||||
export function isSpecialListKind(kind: number) {
|
export function isSpecialListKind(kind: number) {
|
||||||
return kind === Kind.Contacts || kind === PIN_LIST_KIND || kind === MUTE_LIST_KIND;
|
return kind === Kind.Contacts || kind === PIN_LIST_KIND || kind === MUTE_LIST_KIND;
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,8 @@ export default function useFavoriteLists() {
|
|||||||
const account = useCurrentAccount();
|
const account = useCurrentAccount();
|
||||||
const favoriteList = useReplaceableEvent(
|
const favoriteList = useReplaceableEvent(
|
||||||
account ? { kind: 30078, pubkey: account.pubkey, identifier: FAVORITE_LISTS_IDENTIFIER } : undefined,
|
account ? { kind: 30078, pubkey: account.pubkey, identifier: FAVORITE_LISTS_IDENTIFIER } : undefined,
|
||||||
|
[],
|
||||||
|
true,
|
||||||
);
|
);
|
||||||
|
|
||||||
const lists = useReplaceableEvents(favoriteList ? getCoordinatesFromList(favoriteList).map((a) => a.coordinate) : []);
|
const lists = useReplaceableEvents(favoriteList ? getCoordinatesFromList(favoriteList).map((a) => a.coordinate) : []);
|
||||||
|
@ -1,10 +1,15 @@
|
|||||||
import { NOTE_LIST_KIND, PEOPLE_LIST_KIND } from "../helpers/nostr/lists";
|
import { useCallback } from "react";
|
||||||
|
import { NOTE_LIST_KIND, PEOPLE_LIST_KIND, isJunkList } from "../helpers/nostr/lists";
|
||||||
import { useReadRelayUrls } from "./use-client-relays";
|
import { useReadRelayUrls } from "./use-client-relays";
|
||||||
import useSubject from "./use-subject";
|
import useSubject from "./use-subject";
|
||||||
import useTimelineLoader from "./use-timeline-loader";
|
import useTimelineLoader from "./use-timeline-loader";
|
||||||
|
import { NostrEvent } from "../types/nostr-event";
|
||||||
|
|
||||||
export default function useUserLists(pubkey?: string, additionalRelays: string[] = []) {
|
export default function useUserLists(pubkey?: string, additionalRelays: string[] = []) {
|
||||||
const readRelays = useReadRelayUrls(additionalRelays);
|
const readRelays = useReadRelayUrls(additionalRelays);
|
||||||
|
const eventFilter = useCallback((event: NostrEvent) => {
|
||||||
|
return !isJunkList(event);
|
||||||
|
}, []);
|
||||||
const timeline = useTimelineLoader(
|
const timeline = useTimelineLoader(
|
||||||
`${pubkey}-lists`,
|
`${pubkey}-lists`,
|
||||||
readRelays,
|
readRelays,
|
||||||
@ -12,7 +17,7 @@ export default function useUserLists(pubkey?: string, additionalRelays: string[]
|
|||||||
authors: pubkey ? [pubkey] : [],
|
authors: pubkey ? [pubkey] : [],
|
||||||
kinds: [PEOPLE_LIST_KIND, NOTE_LIST_KIND],
|
kinds: [PEOPLE_LIST_KIND, NOTE_LIST_KIND],
|
||||||
},
|
},
|
||||||
{ enabled: !!pubkey },
|
{ enabled: !!pubkey, eventFilter },
|
||||||
);
|
);
|
||||||
|
|
||||||
return useSubject(timeline.timeline);
|
return useSubject(timeline.timeline);
|
||||||
|
@ -55,20 +55,11 @@ function ListCardRender({ event, ...props }: Omit<CardProps, "children"> & { eve
|
|||||||
{getListName(event)}
|
{getListName(event)}
|
||||||
</Link>
|
</Link>
|
||||||
</Heading>
|
</Heading>
|
||||||
<ButtonGroup size="sm" ml="auto">
|
<Link as={RouterLink} to={`/lists/${link}`} ml="auto">
|
||||||
<ListFavoriteButton list={event} />
|
<Timestamp timestamp={event.created_at} />
|
||||||
<ListMenu list={event} aria-label="list menu" />
|
</Link>
|
||||||
</ButtonGroup>
|
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<CardBody p="2">
|
<CardBody py="0" px="2">
|
||||||
<Flex gap="2">
|
|
||||||
<Text>Created by:</Text>
|
|
||||||
<UserAvatarLink pubkey={event.pubkey} size="xs" />
|
|
||||||
<UserLink pubkey={event.pubkey} isTruncated fontWeight="bold" fontSize="lg" />
|
|
||||||
</Flex>
|
|
||||||
<Text>
|
|
||||||
Updated: <Timestamp timestamp={event.created_at} />
|
|
||||||
</Text>
|
|
||||||
{people.length > 0 && (
|
{people.length > 0 && (
|
||||||
<>
|
<>
|
||||||
<Text>People ({people.length}):</Text>
|
<Text>People ({people.length}):</Text>
|
||||||
@ -83,7 +74,7 @@ function ListCardRender({ event, ...props }: Omit<CardProps, "children"> & { eve
|
|||||||
<>
|
<>
|
||||||
<Text>Notes ({notes.length}):</Text>
|
<Text>Notes ({notes.length}):</Text>
|
||||||
<Flex gap="2" overflow="hidden">
|
<Flex gap="2" overflow="hidden">
|
||||||
{notes.map(({ id, relay }) => (
|
{notes.slice(0, 4).map(({ id, relay }) => (
|
||||||
<NoteLink key={id} noteId={id} />
|
<NoteLink key={id} noteId={id} />
|
||||||
))}
|
))}
|
||||||
</Flex>
|
</Flex>
|
||||||
@ -92,11 +83,24 @@ function ListCardRender({ event, ...props }: Omit<CardProps, "children"> & { eve
|
|||||||
{references.length > 0 && (
|
{references.length > 0 && (
|
||||||
<>
|
<>
|
||||||
<Text>References ({references.length})</Text>
|
<Text>References ({references.length})</Text>
|
||||||
|
<Flex gap="2" overflow="hidden">
|
||||||
|
{references.slice(0, 3).map(({ url, petname }) => (
|
||||||
|
<Link maxW="200" href={url} isExternal whiteSpace="pre" color="blue.500" isTruncated>
|
||||||
|
{petname || url}
|
||||||
|
</Link>
|
||||||
|
))}
|
||||||
|
</Flex>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</CardBody>
|
</CardBody>
|
||||||
<CardFooter p="2" display="flex" pt="0">
|
<CardFooter p="2" display="flex" alignItems="center" whiteSpace="pre" gap="2">
|
||||||
<EventRelays event={event} ml="auto" />
|
<Text>Created by:</Text>
|
||||||
|
<UserAvatarLink pubkey={event.pubkey} size="xs" />
|
||||||
|
<UserLink pubkey={event.pubkey} isTruncated fontWeight="bold" fontSize="lg" />
|
||||||
|
<ButtonGroup size="xs" variant="ghost" ml="auto">
|
||||||
|
<ListFavoriteButton list={event} />
|
||||||
|
<ListMenu list={event} aria-label="list menu" />
|
||||||
|
</ButtonGroup>
|
||||||
</CardFooter>
|
</CardFooter>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
@ -10,6 +10,7 @@ import NostrPublishAction from "../../../classes/nostr-publish-action";
|
|||||||
import clientRelaysService from "../../../services/client-relays";
|
import clientRelaysService from "../../../services/client-relays";
|
||||||
import replaceableEventLoaderService from "../../../services/replaceable-event-requester";
|
import replaceableEventLoaderService from "../../../services/replaceable-event-requester";
|
||||||
import useFavoriteLists, { FAVORITE_LISTS_IDENTIFIER } from "../../../hooks/use-favorite-lists";
|
import useFavoriteLists, { FAVORITE_LISTS_IDENTIFIER } from "../../../hooks/use-favorite-lists";
|
||||||
|
import { NOTE_LIST_KIND, isSpecialListKind } from "../../../helpers/nostr/lists";
|
||||||
|
|
||||||
export default function ListFavoriteButton({
|
export default function ListFavoriteButton({
|
||||||
list,
|
list,
|
||||||
@ -22,6 +23,11 @@ export default function ListFavoriteButton({
|
|||||||
const isFavorite = favoriteList?.tags.some((t) => t[1] === coordinate);
|
const isFavorite = favoriteList?.tags.some((t) => t[1] === coordinate);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
|
if (isSpecialListKind(list.kind)) return null;
|
||||||
|
|
||||||
|
// NOTE: dont show favorite button for note lists
|
||||||
|
if (list.kind === NOTE_LIST_KIND) return null;
|
||||||
|
|
||||||
const handleClick = async () => {
|
const handleClick = async () => {
|
||||||
const prev: DraftNostrEvent = favoriteList || {
|
const prev: DraftNostrEvent = favoriteList || {
|
||||||
kind: 30078,
|
kind: 30078,
|
||||||
|
@ -1,25 +1,35 @@
|
|||||||
|
import { useCallback } from "react";
|
||||||
import { useOutletContext } from "react-router-dom";
|
import { useOutletContext } from "react-router-dom";
|
||||||
import { Divider, Flex, Heading, SimpleGrid } from "@chakra-ui/react";
|
import { Divider, Heading, SimpleGrid } from "@chakra-ui/react";
|
||||||
|
|
||||||
import { useAdditionalRelayContext } from "../../providers/additional-relay-context";
|
import { useAdditionalRelayContext } from "../../providers/additional-relay-context";
|
||||||
import useTimelineLoader from "../../hooks/use-timeline-loader";
|
import useTimelineLoader from "../../hooks/use-timeline-loader";
|
||||||
import useSubject from "../../hooks/use-subject";
|
import useSubject from "../../hooks/use-subject";
|
||||||
import { MUTE_LIST_KIND, NOTE_LIST_KIND, PEOPLE_LIST_KIND, PIN_LIST_KIND } from "../../helpers/nostr/lists";
|
import { MUTE_LIST_KIND, NOTE_LIST_KIND, PEOPLE_LIST_KIND, PIN_LIST_KIND, isJunkList } from "../../helpers/nostr/lists";
|
||||||
import { getEventUID } from "../../helpers/nostr/events";
|
import { getEventUID } from "../../helpers/nostr/events";
|
||||||
import ListCard from "../lists/components/list-card";
|
import ListCard from "../lists/components/list-card";
|
||||||
import IntersectionObserverProvider from "../../providers/intersection-observer";
|
import IntersectionObserverProvider from "../../providers/intersection-observer";
|
||||||
import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";
|
import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";
|
||||||
import { Kind } from "nostr-tools";
|
import { Kind } from "nostr-tools";
|
||||||
import VerticalPageLayout from "../../components/vertical-page-layout";
|
import VerticalPageLayout from "../../components/vertical-page-layout";
|
||||||
|
import { NostrEvent } from "../../types/nostr-event";
|
||||||
|
|
||||||
export default function UserListsTab() {
|
export default function UserListsTab() {
|
||||||
const { pubkey } = useOutletContext() as { pubkey: string };
|
const { pubkey } = useOutletContext() as { pubkey: string };
|
||||||
const readRelays = useAdditionalRelayContext();
|
const readRelays = useAdditionalRelayContext();
|
||||||
|
|
||||||
const timeline = useTimelineLoader(pubkey + "-lists", readRelays, {
|
const eventFilter = useCallback((event: NostrEvent) => {
|
||||||
authors: [pubkey],
|
return !isJunkList(event);
|
||||||
kinds: [PEOPLE_LIST_KIND, NOTE_LIST_KIND],
|
}, []);
|
||||||
});
|
const timeline = useTimelineLoader(
|
||||||
|
pubkey + "-lists",
|
||||||
|
readRelays,
|
||||||
|
{
|
||||||
|
authors: [pubkey],
|
||||||
|
kinds: [PEOPLE_LIST_KIND, NOTE_LIST_KIND],
|
||||||
|
},
|
||||||
|
{ eventFilter },
|
||||||
|
);
|
||||||
|
|
||||||
const lists = useSubject(timeline.timeline);
|
const lists = useSubject(timeline.timeline);
|
||||||
const callback = useTimelineCurserIntersectionCallback(timeline);
|
const callback = useTimelineCurserIntersectionCallback(timeline);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user