add show replies switch to home feed

This commit is contained in:
hzrd149 2023-09-09 10:56:41 -05:00
parent 409f219c54
commit 57e5229db3
7 changed files with 70 additions and 25 deletions

View File

@ -1,4 +1,4 @@
import { Button, Card, CardBody, CardHeader, Spacer, useDisclosure } from "@chakra-ui/react";
import { Button, Card, CardBody, CardHeader, CardProps, Spacer, useDisclosure } from "@chakra-ui/react";
import { NoteContents } from "../../note/note-contents";
import { NostrEvent } from "../../../types/nostr-event";
@ -13,13 +13,13 @@ import { NoteLink } from "../../note-link";
import { ArrowDownSIcon, ArrowUpSIcon } from "../../icons";
import Timestamp from "../../timestamp";
export default function EmbeddedNote({ event }: { event: NostrEvent }) {
export default function EmbeddedNote({ event, ...props }: Omit<CardProps, "children"> & { event: NostrEvent }) {
const { showSignatureVerification } = useSubject(appSettings);
const expand = useDisclosure();
return (
<TrustProvider event={event}>
<Card variant="outline">
<Card {...props}>
<CardHeader padding="2" display="flex" gap="2" alignItems="center" flexWrap="wrap">
<UserAvatarLink pubkey={event.pubkey} size="sm" />
<UserLink pubkey={event.pubkey} fontWeight="bold" isTruncated fontSize="lg" />

View File

@ -1,4 +1,5 @@
import type { DecodeResult } from "nostr-tools/lib/nip19";
import { CardProps } from "@chakra-ui/react";
import EmbeddedNote from "./event-types/embedded-note";
import useSingleEvent from "../../hooks/use-single-event";
@ -24,26 +25,30 @@ export type EmbedProps = {
goalProps?: EmbeddedGoalOptions;
};
export function EmbedEvent({ event, goalProps }: { event: NostrEvent } & EmbedProps) {
export function EmbedEvent({
event,
goalProps,
...cardProps
}: Omit<CardProps, "children"> & { event: NostrEvent } & EmbedProps) {
switch (event.kind) {
case Kind.Text:
return <EmbeddedNote event={event} />;
return <EmbeddedNote event={event} {...cardProps} />;
case STREAM_KIND:
return <EmbeddedStream event={event} />;
return <EmbeddedStream event={event} {...cardProps} />;
case GOAL_KIND:
return <EmbeddedGoal goal={event} {...goalProps} />;
return <EmbeddedGoal goal={event} {...cardProps} {...goalProps} />;
case EMOJI_PACK_KIND:
return <EmbeddedEmojiPack pack={event} />;
return <EmbeddedEmojiPack pack={event} {...cardProps} />;
case PEOPLE_LIST_KIND:
case NOTE_LIST_KIND:
return <EmbeddedList list={event} />;
return <EmbeddedList list={event} {...cardProps} />;
case Kind.Article:
return <EmbeddedArticle article={event} />;
return <EmbeddedArticle article={event} {...cardProps} />;
case Kind.BadgeDefinition:
return <EmbeddedBadge badge={event} />;
return <EmbeddedBadge badge={event} {...cardProps} />;
}
return <EmbeddedUnknown event={event} />;
return <EmbeddedUnknown event={event} {...cardProps} />;
}
export function EmbedEventPointer({ pointer, ...props }: { pointer: DecodeResult } & EmbedProps) {

View File

@ -39,12 +39,12 @@ import ReplyForm from "../../views/note/components/reply-form";
import { getReferences } from "../../helpers/nostr/events";
import Timestamp from "../timestamp";
export type NoteProps = {
export type NoteProps = Omit<CardProps, "children"> & {
event: NostrEvent;
variant?: CardProps["variant"];
showReplyButton?: boolean;
};
export const Note = React.memo(({ event, variant = "outline", showReplyButton }: NoteProps) => {
export const Note = React.memo(({ event, variant = "outline", showReplyButton, ...props }: NoteProps) => {
const account = useCurrentAccount();
const { showReactions, showSignatureVerification } = useSubject(appSettings);
const replyForm = useDisclosure();
@ -63,7 +63,7 @@ export const Note = React.memo(({ event, variant = "outline", showReplyButton }:
return (
<TrustProvider event={event}>
<ExpandProvider>
<Card variant={variant} ref={ref} data-event-id={event.id}>
<Card variant={variant} ref={ref} data-event-id={event.id} {...props}>
<CardHeader padding="2">
<Flex flex="1" gap="2" alignItems="center">
<UserAvatarLink pubkey={event.pubkey} size={["xs", "sm"]} />

View File

@ -1,22 +1,25 @@
import React from "react";
import { Text } from "@chakra-ui/react";
import { Kind } from "nostr-tools";
import useSubject from "../../../hooks/use-subject";
import { TimelineLoader } from "../../../classes/timeline-loader";
import RepostNote from "./repost-note";
import { Note } from "../../note";
import { NostrEvent } from "../../../types/nostr-event";
import { Text } from "@chakra-ui/react";
import { Kind } from "nostr-tools";
import { STREAM_KIND } from "../../../helpers/nostr/stream";
import StreamNote from "./stream-note";
import { ErrorBoundary } from "../../error-boundary";
import RelayCard from "../../../views/relays/components/relay-card";
import { safeRelayUrl } from "../../../helpers/url";
import EmbeddedArticle from "../../embed-event/event-types/embedded-article";
import { isReply } from "../../../helpers/nostr/events";
import ReplyNote from "./reply-note";
const RenderEvent = React.memo(({ event }: { event: NostrEvent }) => {
switch (event.kind) {
case Kind.Text:
return <Note event={event} showReplyButton />;
return isReply(event) ? <ReplyNote event={event} /> : <Note event={event} showReplyButton />;
case Kind.Repost:
return <RepostNote event={event} />;
case Kind.Article:

View File

@ -0,0 +1,33 @@
import { memo, useRef } from "react";
import { Flex, SkeletonText, Text } from "@chakra-ui/react";
import { getReferences } from "../../../helpers/nostr/events";
import useSingleEvent from "../../../hooks/use-single-event";
import { NostrEvent } from "../../../types/nostr-event";
import { EmbedEvent } from "../../embed-event";
import { useRegisterIntersectionEntity } from "../../../providers/intersection-observer";
import Note from "../../note";
import { UserAvatar } from "../../user-avatar";
import { UserLink } from "../../user-link";
function ReplyNote({ event }: { event: NostrEvent }) {
const refs = getReferences(event);
const { event: parent } = useSingleEvent(refs.replyId);
// if there is a parent intersection observer, register this card
const ref = useRef<HTMLDivElement | null>(null);
useRegisterIntersectionEntity(ref, event.id);
return (
<Flex gap="2" direction="column" ref={ref}>
<Flex gap="2">
<UserAvatar pubkey={event.pubkey} size="xs" alignItems="center" />
<UserLink pubkey={event.pubkey} />
<Text>Replied to:</Text>
</Flex>
{parent ? <EmbedEvent event={parent} ml="4" /> : <SkeletonText />}
<Note event={event} />
</Flex>
);
}
export default memo(ReplyNote);

View File

@ -1,13 +1,13 @@
import { useCallback } from "react";
import { Flex, FlexProps, SimpleGrid } from "@chakra-ui/react";
import { Flex, FlexProps } from "@chakra-ui/react";
import { useSearchParams } from "react-router-dom";
import IntersectionObserverProvider from "../../providers/intersection-observer";
import GenericNoteTimeline from "./generic-note-timeline";
import { LightboxProvider } from "../lightbox-provider";
import MediaTimeline from "./media-timeline";
import { TimelineLoader } from "../../classes/timeline-loader";
import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";
import TimelineActionAndStatus from "./timeline-action-and-status";
import { useSearchParams } from "react-router-dom";
import { NostrEvent } from "../../types/nostr-event";
import { getMatchLink } from "../../helpers/regexp";
import TimelineHealth from "./timeline-health";

View File

@ -1,5 +1,5 @@
import { useCallback, useMemo } from "react";
import { Flex } from "@chakra-ui/react";
import { Flex, Switch, useDisclosure } from "@chakra-ui/react";
import { Kind } from "nostr-tools";
import { isReply } from "../../helpers/nostr/events";
@ -15,12 +15,13 @@ import { NostrRequestFilter } from "../../types/nostr-query";
function HomePage() {
const timelinePageEventFilter = useTimelinePageEventFilter();
const showReplies = useDisclosure();
const eventFilter = useCallback(
(event: NostrEvent) => {
if (isReply(event)) return false;
if (!showReplies.isOpen && isReply(event)) return false;
return timelinePageEventFilter(event);
},
[timelinePageEventFilter],
[timelinePageEventFilter, showReplies.isOpen],
);
const { relays } = useRelaySelectionContext();
@ -38,8 +39,11 @@ function HomePage() {
});
const header = (
<Flex gap="2" wrap="wrap" px={["2", 0]}>
<Flex gap="2" wrap="wrap" px={["2", 0]} alignItems="center">
<PeopleListSelection />
<Switch checked={showReplies.isOpen} onChange={showReplies.onToggle}>
Show Replies
</Switch>
<RelaySelectionButton ml="auto" />
<TimelineViewTypeButtons />
</Flex>