small timeline improvements

This commit is contained in:
hzrd149
2024-01-19 10:44:07 +00:00
parent 72e70476a3
commit 30ee065ef7
4 changed files with 103 additions and 105 deletions

View File

@@ -1,4 +1,4 @@
import React from "react"; import React, { memo } from "react";
import { ErrorBoundary as ErrorBoundaryHelper, FallbackProps } from "react-error-boundary"; import { ErrorBoundary as ErrorBoundaryHelper, FallbackProps } from "react-error-boundary";
import { Alert, AlertIcon, AlertTitle, AlertDescription } from "@chakra-ui/react"; import { Alert, AlertIcon, AlertTitle, AlertDescription } from "@chakra-ui/react";
@@ -12,8 +12,8 @@ export function ErrorFallback({ error, resetErrorBoundary }: Partial<FallbackPro
); );
} }
export const ErrorBoundary = ({ children, ...props }: { children: React.ReactNode }) => ( export const ErrorBoundary = memo(({ children, ...props }: { children: React.ReactNode }) => (
<ErrorBoundaryHelper FallbackComponent={ErrorFallback} {...props}> <ErrorBoundaryHelper FallbackComponent={ErrorFallback} {...props}>
{children} {children}
</ErrorBoundaryHelper> </ErrorBoundaryHelper>
); ));

View File

@@ -1,4 +1,4 @@
import React, { useRef } from "react"; import { useRef, memo } from "react";
import { import {
Box, Box,
ButtonGroup, ButtonGroup,
@@ -111,106 +111,104 @@ export type NoteProps = Omit<CardProps, "children"> & {
registerIntersectionEntity?: boolean; registerIntersectionEntity?: boolean;
clickable?: boolean; clickable?: boolean;
}; };
export const Note = React.memo( export function Note({
({ event,
event, variant = "outline",
variant = "outline", showReplyButton,
showReplyButton, showReplyLine = true,
showReplyLine = true, hideDrawerButton,
hideDrawerButton, registerIntersectionEntity = true,
registerIntersectionEntity = true, clickable = true,
clickable = true, ...props
...props }: NoteProps) {
}: NoteProps) => { const account = useCurrentAccount();
const account = useCurrentAccount(); const { showReactions, showSignatureVerification } = useSubject(appSettings);
const { showReactions, showSignatureVerification } = useSubject(appSettings); const replyForm = useDisclosure();
const replyForm = useDisclosure(); const detailsModal = useDisclosure();
const detailsModal = useDisclosure();
const ref = useRef<HTMLDivElement | null>(null); const ref = useRef<HTMLDivElement | null>(null);
useRegisterIntersectionEntity(ref, event.id); useRegisterIntersectionEntity(ref, event.id);
const showReactionsOnNewLine = useBreakpointValue({ base: true, lg: false }); const showReactionsOnNewLine = useBreakpointValue({ base: true, lg: false });
const reactionButtons = showReactions && <NoteReactions event={event} flexWrap="wrap" variant="ghost" size="sm" />; const reactionButtons = showReactions && <NoteReactions event={event} flexWrap="wrap" variant="ghost" size="sm" />;
return ( return (
<TrustProvider event={event}> <TrustProvider event={event}>
<ExpandProvider> <ExpandProvider>
<Card <Card
as={LinkBox} as={LinkBox}
variant={variant} variant={variant}
ref={registerIntersectionEntity ? ref : undefined} ref={registerIntersectionEntity ? ref : undefined}
data-event-id={event.id} data-event-id={event.id}
{...props} {...props}
> >
{clickable && ( {clickable && (
<HoverLinkOverlay <HoverLinkOverlay
as={RouterLink} as={RouterLink}
to={`/n/${getSharableEventAddress(event)}`} to={`/n/${getSharableEventAddress(event)}`}
onClick={() => singleEventService.handleEvent(event)} onClick={() => singleEventService.handleEvent(event)}
/> />
)} )}
<CardHeader p="2"> <CardHeader p="2">
<Flex flex="1" gap="2" alignItems="center"> <Flex flex="1" gap="2" alignItems="center">
<UserAvatarLink pubkey={event.pubkey} size={["xs", "sm"]} /> <UserAvatarLink pubkey={event.pubkey} size={["xs", "sm"]} />
<UserLink pubkey={event.pubkey} isTruncated fontWeight="bold" fontSize="lg" /> <UserLink pubkey={event.pubkey} isTruncated fontWeight="bold" fontSize="lg" />
<UserDnsIdentityIcon pubkey={event.pubkey} onlyIcon /> <UserDnsIdentityIcon pubkey={event.pubkey} onlyIcon />
<POWIcon event={event} boxSize={5} /> <POWIcon event={event} boxSize={5} />
<Flex grow={1} /> <Flex grow={1} />
{showSignatureVerification && <EventVerificationIcon event={event} />} {showSignatureVerification && <EventVerificationIcon event={event} />}
{!hideDrawerButton && ( {!hideDrawerButton && (
<OpenInDrawerButton <OpenInDrawerButton
to={`/n/${getSharableEventAddress(event)}`} to={`/n/${getSharableEventAddress(event)}`}
size="sm" size="sm"
variant="ghost" variant="ghost"
onClick={() => singleEventService.handleEvent(event)} onClick={() => singleEventService.handleEvent(event)}
/> />
)}
<Link as={RouterLink} whiteSpace="nowrap" color="current" to={`/n/${getSharableEventAddress(event)}`}>
<Timestamp timestamp={event.created_at} />
</Link>
</Flex>
<NoteCommunityMetadata event={event} />
{showReplyLine && <ReplyLine event={event} />}
</CardHeader>
<CardBody p="0">
<NoteContentWithWarning event={event} />
</CardBody>
<CardFooter padding="2" display="flex" gap="2" flexDirection="column" alignItems="flex-start">
{showReactionsOnNewLine && reactionButtons}
<Flex gap="2" w="full" alignItems="center">
<ButtonGroup size="sm" variant="ghost" isDisabled={account?.readonly ?? true}>
{showReplyButton && (
<IconButton icon={<ReplyIcon />} aria-label="Reply" title="Reply" onClick={replyForm.onOpen} />
)} )}
<Link as={RouterLink} whiteSpace="nowrap" color="current" to={`/n/${getSharableEventAddress(event)}`}> <RepostButton event={event} />
<Timestamp timestamp={event.created_at} /> <QuoteRepostButton event={event} />
</Link> <NoteZapButton event={event} />
</Flex> </ButtonGroup>
<NoteCommunityMetadata event={event} /> {!showReactionsOnNewLine && reactionButtons}
{showReplyLine && <ReplyLine event={event} />} <Box flexGrow={1} />
</CardHeader> <ButtonGroup size="sm" variant="ghost">
<CardBody p="0"> <NoteProxyLink event={event} />
<NoteContentWithWarning event={event} /> <NoteDetailsButton event={event} onClick={detailsModal.onOpen} />
</CardBody> <BookmarkButton event={event} aria-label="Bookmark note" />
<CardFooter padding="2" display="flex" gap="2" flexDirection="column" alignItems="flex-start"> <NoteMenu event={event} aria-label="More Options" detailsClick={detailsModal.onOpen} />
{showReactionsOnNewLine && reactionButtons} </ButtonGroup>
<Flex gap="2" w="full" alignItems="center"> </Flex>
<ButtonGroup size="sm" variant="ghost" isDisabled={account?.readonly ?? true}> </CardFooter>
{showReplyButton && ( </Card>
<IconButton icon={<ReplyIcon />} aria-label="Reply" title="Reply" onClick={replyForm.onOpen} /> </ExpandProvider>
)} {replyForm.isOpen && (
<RepostButton event={event} /> <ReplyForm
<QuoteRepostButton event={event} /> item={{ event, replies: [], refs: getThreadReferences(event) }}
<NoteZapButton event={event} /> onCancel={replyForm.onClose}
</ButtonGroup> onSubmitted={replyForm.onClose}
{!showReactionsOnNewLine && reactionButtons} />
<Box flexGrow={1} /> )}
<ButtonGroup size="sm" variant="ghost"> {detailsModal.isOpen && <EventInteractionDetailsModal isOpen onClose={detailsModal.onClose} event={event} />}
<NoteProxyLink event={event} /> </TrustProvider>
<NoteDetailsButton event={event} onClick={detailsModal.onOpen} /> );
<BookmarkButton event={event} aria-label="Bookmark note" /> }
<NoteMenu event={event} aria-label="More Options" detailsClick={detailsModal.onOpen} />
</ButtonGroup>
</Flex>
</CardFooter>
</Card>
</ExpandProvider>
{replyForm.isOpen && (
<ReplyForm
item={{ event, replies: [], refs: getThreadReferences(event) }}
onCancel={replyForm.onClose}
onSubmitted={replyForm.onClose}
/>
)}
{detailsModal.isOpen && <EventInteractionDetailsModal isOpen onClose={detailsModal.onClose} event={event} />}
</TrustProvider>
);
},
);
export default Note; export default memo(Note);

View File

@@ -1,4 +1,4 @@
import { useRef } from "react"; import { memo, useRef } from "react";
import { Flex, Heading, Link, Text } from "@chakra-ui/react"; import { Flex, Heading, Link, Text } from "@chakra-ui/react";
import { kinds, nip18 } from "nostr-tools"; import { kinds, nip18 } from "nostr-tools";
import { Link as RouterLink } from "react-router-dom"; import { Link as RouterLink } from "react-router-dom";
@@ -18,7 +18,7 @@ import { parseHardcodedNoteContent } from "../../../helpers/nostr/events";
import { getEventCommunityPointer } from "../../../helpers/nostr/communities"; import { getEventCommunityPointer } from "../../../helpers/nostr/communities";
import LoadingNostrLink from "../../loading-nostr-link"; import LoadingNostrLink from "../../loading-nostr-link";
export default function RepostEvent({ event }: { event: NostrEvent }) { function RepostEvent({ event }: { event: NostrEvent }) {
const muteFilter = useUserMuteFilter(); const muteFilter = useUserMuteFilter();
const hardCodedNote = parseHardcodedNoteContent(event); const hardCodedNote = parseHardcodedNoteContent(event);
@@ -68,3 +68,5 @@ export default function RepostEvent({ event }: { event: NostrEvent }) {
</TrustProvider> </TrustProvider>
); );
} }
export default memo(RepostEvent);

View File

@@ -27,8 +27,6 @@ function TimelineItem({ event, visible, minHeight }: { event: NostrEvent; visibl
content = isReply(event) ? <ReplyNote event={event} /> : <Note event={event} showReplyButton />; content = isReply(event) ? <ReplyNote event={event} /> : <Note event={event} showReplyButton />;
break; break;
case kinds.Repost: case kinds.Repost:
content = <RepostEvent event={event} />;
break;
case kinds.GenericRepost: case kinds.GenericRepost:
content = <RepostEvent event={event} />; content = <RepostEvent event={event} />;
break; break;