mirror of
https://github.com/hzrd149/nostrudel.git
synced 2025-04-10 12:49:29 +02:00
add date picker to notifications
make user avatars square
This commit is contained in:
parent
8d46272558
commit
f9443afccc
5
.changeset/curvy-cherries-exercise.md
Normal file
5
.changeset/curvy-cherries-exercise.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"nostrudel": minor
|
||||
---
|
||||
|
||||
Add date picker to notifictions
|
5
.changeset/gentle-eyes-tap.md
Normal file
5
.changeset/gentle-eyes-tap.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"nostrudel": minor
|
||||
---
|
||||
|
||||
Make user avatars square
|
@ -8,7 +8,7 @@ import { aTagToAddressPointer, eTagToEventPointer } from "../../helpers/nostr/ev
|
||||
import { EmbedEventPointer } from "../embed-event";
|
||||
import UserAvatarLink from "../user/user-avatar-link";
|
||||
import UserLink from "../user/user-link";
|
||||
import { UserDnsIdentityIcon } from "../user/user-dns-identity-icon";
|
||||
import UserDnsIdentity from "../user/user-dns-identity";
|
||||
|
||||
function EventTag({ tag }: { tag: Tag }) {
|
||||
const expand = useDisclosure();
|
||||
@ -62,7 +62,7 @@ function EventTag({ tag }: { tag: Tag }) {
|
||||
<Box>
|
||||
<UserLink pubkey={pubkey} fontWeight="bold" />
|
||||
<br />
|
||||
<UserDnsIdentityIcon pubkey={pubkey} />
|
||||
<UserDnsIdentity pubkey={pubkey} />
|
||||
</Box>
|
||||
</Flex>
|
||||
)}
|
||||
|
@ -5,7 +5,6 @@ import { Link as RouterLink } from "react-router-dom";
|
||||
import { NostrEvent } from "../../../types/nostr-event";
|
||||
import UserAvatarLink from "../../user/user-avatar-link";
|
||||
import UserLink from "../../user/user-link";
|
||||
import { UserDnsIdentityIcon } from "../../user/user-dns-identity-icon";
|
||||
import useSubject from "../../../hooks/use-subject";
|
||||
import appSettings from "../../../services/settings/app-settings";
|
||||
import EventVerificationIcon from "../../common-event/event-verification-icon";
|
||||
@ -36,15 +35,14 @@ export default function EmbeddedNote({ event, ...props }: Omit<CardProps, "child
|
||||
<TrustProvider event={event}>
|
||||
<Card as={LinkBox} {...props}>
|
||||
<Flex p="2" gap="2" alignItems="center">
|
||||
<UserAvatarLink pubkey={event.pubkey} size="xs" />
|
||||
<UserAvatarLink pubkey={event.pubkey} size="sm" />
|
||||
<UserLink pubkey={event.pubkey} fontWeight="bold" isTruncated fontSize="lg" />
|
||||
<UserDnsIdentityIcon pubkey={event.pubkey} onlyIcon />
|
||||
<HoverLinkOverlay as={RouterLink} to={to} onClick={handleClick} />
|
||||
<Spacer />
|
||||
{showSignatureVerification && <EventVerificationIcon event={event} />}
|
||||
<NoteLink noteId={event.id} color="current" whiteSpace="nowrap">
|
||||
<Timestamp timestamp={event.created_at} />
|
||||
</NoteLink>
|
||||
<HoverLinkOverlay as={RouterLink} to={to} onClick={handleClick} />
|
||||
<Spacer />
|
||||
{showSignatureVerification && <EventVerificationIcon event={event} />}
|
||||
</Flex>
|
||||
<CompactNoteContent px="2" event={event} maxLength={96} />
|
||||
</Card>
|
||||
|
@ -5,7 +5,7 @@ import { getSharableEventAddress } from "../../../helpers/nip19";
|
||||
import { NostrEvent } from "../../../types/nostr-event";
|
||||
import UserAvatarLink from "../../user/user-avatar-link";
|
||||
import UserLink from "../../user/user-link";
|
||||
import { UserDnsIdentityIcon } from "../../user/user-dns-identity-icon";
|
||||
import UserDnsIdentity from "../../user/user-dns-identity";
|
||||
import {
|
||||
embedEmoji,
|
||||
embedNostrHashtags,
|
||||
@ -44,7 +44,7 @@ export default function EmbeddedUnknown({ event, ...props }: Omit<CardProps, "ch
|
||||
<CardHeader display="flex" gap="2" alignItems="center" p="2" pb="0" flexWrap="wrap">
|
||||
<UserAvatarLink pubkey={event.pubkey} size="xs" />
|
||||
<UserLink pubkey={event.pubkey} isTruncated fontWeight="bold" fontSize="md" />
|
||||
<UserDnsIdentityIcon pubkey={event.pubkey} onlyIcon />
|
||||
<UserDnsIdentity pubkey={event.pubkey} onlyIcon />
|
||||
<Text>kind: {event.kind}</Text>
|
||||
<Timestamp timestamp={event.created_at} />
|
||||
<ButtonGroup ml="auto">
|
||||
|
@ -56,14 +56,15 @@ export default function AccountSwitcher() {
|
||||
<Flex direction="column" gap="2">
|
||||
<Box
|
||||
as="button"
|
||||
borderRadius="30"
|
||||
borderRadius="lg"
|
||||
borderWidth={1}
|
||||
display="flex"
|
||||
gap="2"
|
||||
mb="2"
|
||||
alignItems="center"
|
||||
flexGrow={1}
|
||||
overflow="hidden"
|
||||
overflowX="hidden"
|
||||
overflowY="visible"
|
||||
onClick={onToggle}
|
||||
>
|
||||
<UserAvatar pubkey={account.pubkey} noProxy size="md" />
|
||||
|
@ -32,7 +32,6 @@ declare module "yet-another-react-lightbox" {
|
||||
import { NostrEvent } from "../types/nostr-event";
|
||||
import UserAvatarLink from "./user/user-avatar-link";
|
||||
import UserLink from "./user/user-link";
|
||||
import { UserDnsIdentityIcon } from "./user/user-dns-identity-icon";
|
||||
import styled from "@emotion/styled";
|
||||
import { getSharableEventAddress } from "../helpers/nip19";
|
||||
|
||||
@ -107,7 +106,6 @@ function EventSlideHeader({ event, ...props }: { event: NostrEvent } & Omit<Flex
|
||||
<Flex gap="2" alignItems="center" p="2" {...props}>
|
||||
<UserAvatarLink pubkey={event.pubkey} size={["xs", "sm"]} />
|
||||
<UserLink pubkey={event.pubkey} isTruncated fontWeight="bold" fontSize="lg" />
|
||||
<UserDnsIdentityIcon pubkey={event.pubkey} onlyIcon />
|
||||
<Spacer />
|
||||
<Button as={RouterLink} to={`/n/${encoded}`} colorScheme="primary" size="sm">
|
||||
View Note
|
||||
|
@ -13,7 +13,7 @@ import { matchSorter } from "match-sorter";
|
||||
import { Emoji, useContextEmojis } from "../providers/global/emoji-provider";
|
||||
import { useUserSearchDirectoryContext } from "../providers/global/user-directory-provider";
|
||||
import UserAvatar from "./user/user-avatar";
|
||||
import { UserDnsIdentityIcon } from "./user/user-dns-identity-icon";
|
||||
import UserDnsIdentity from "./user/user-dns-identity";
|
||||
|
||||
export type PeopleToken = { pubkey: string; names: string[] };
|
||||
type Token = Emoji | PeopleToken;
|
||||
@ -39,7 +39,7 @@ const Item = ({ entity }: ItemComponentProps<Token>) => {
|
||||
return (
|
||||
<span>
|
||||
<UserAvatar pubkey={entity.pubkey} size="xs" /> {entity.names[0]}{" "}
|
||||
<UserDnsIdentityIcon pubkey={entity.pubkey} onlyIcon />
|
||||
<UserDnsIdentity pubkey={entity.pubkey} onlyIcon />
|
||||
</span>
|
||||
);
|
||||
} else return null;
|
||||
|
@ -6,7 +6,7 @@ import { useRegisterIntersectionEntity } from "../../providers/local/intersectio
|
||||
import { getEventUID } from "../../helpers/nostr/event";
|
||||
import Timestamp from "../timestamp";
|
||||
import UserLink from "../user/user-link";
|
||||
import { UserDnsIdentityIcon } from "../user/user-dns-identity-icon";
|
||||
import UserDnsIdentity from "../user/user-dns-identity";
|
||||
import useEventReactions from "../../hooks/use-event-reactions";
|
||||
import EventReactionButtons from "../event-reactions/event-reactions";
|
||||
import { IconThreadButton } from "../../views/dms/components/thread-button";
|
||||
@ -49,7 +49,7 @@ export default function MessageBubble({
|
||||
{showHeader && (
|
||||
<CardHeader px="2" pt="2" pb="0" gap="2" display="flex" alignItems="center">
|
||||
<UserLink pubkey={message.pubkey} fontWeight="bold" />
|
||||
<UserDnsIdentityIcon pubkey={message.pubkey} onlyIcon />
|
||||
<UserDnsIdentity pubkey={message.pubkey} onlyIcon />
|
||||
{actionPosition === "header" && (
|
||||
<ButtonGroup size="xs" variant="ghost" ml="auto">
|
||||
{actions}
|
||||
|
@ -20,7 +20,6 @@ import { Link as RouterLink } from "react-router-dom";
|
||||
|
||||
import NoteMenu from "../note-menu";
|
||||
import UserLink from "../../user/user-link";
|
||||
import { UserDnsIdentityIcon } from "../../user/user-dns-identity-icon";
|
||||
import NoteZapButton from "../note-zap-button";
|
||||
import { ExpandProvider } from "../../../providers/local/expanded";
|
||||
import useSubject from "../../../hooks/use-subject";
|
||||
@ -152,9 +151,11 @@ export function TimelineNote({
|
||||
)}
|
||||
<CardHeader p="2">
|
||||
<Flex flex="1" gap="2" alignItems="center">
|
||||
<UserAvatarLink pubkey={event.pubkey} size={["xs", "sm"]} />
|
||||
<UserAvatarLink pubkey={event.pubkey} size="sm" />
|
||||
<UserLink pubkey={event.pubkey} isTruncated fontWeight="bold" fontSize="lg" />
|
||||
<UserDnsIdentityIcon pubkey={event.pubkey} onlyIcon />
|
||||
<Link as={RouterLink} whiteSpace="nowrap" color="current" to={`/n/${getSharableEventAddress(event)}`}>
|
||||
<Timestamp timestamp={event.created_at} />
|
||||
</Link>
|
||||
<POWIcon event={event} boxSize={5} />
|
||||
<Flex grow={1} />
|
||||
{showSignatureVerification && <EventVerificationIcon event={event} />}
|
||||
@ -166,9 +167,6 @@ export function TimelineNote({
|
||||
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} />}
|
||||
|
@ -6,7 +6,7 @@ import { Link as RouterLink } from "react-router-dom";
|
||||
import { NostrEvent } from "../../../types/nostr-event";
|
||||
import TimelineNote from "../../note/timeline-note";
|
||||
import UserAvatar from "../../user/user-avatar";
|
||||
import { UserDnsIdentityIcon } from "../../user/user-dns-identity-icon";
|
||||
import UserDnsIdentity from "../../user/user-dns-identity";
|
||||
import UserLink from "../../user/user-link";
|
||||
import { TrustProvider } from "../../../providers/local/trust";
|
||||
import { useRegisterIntersectionEntity } from "../../../providers/local/intersection-observer";
|
||||
@ -41,7 +41,7 @@ function RepostEvent({ event }: { event: NostrEvent }) {
|
||||
<Heading size="sm" display="inline" isTruncated whiteSpace="pre">
|
||||
<UserLink pubkey={event.pubkey} />
|
||||
</Heading>
|
||||
<UserDnsIdentityIcon pubkey={event.pubkey} onlyIcon />
|
||||
<UserDnsIdentity pubkey={event.pubkey} onlyIcon />
|
||||
<Text as="span" whiteSpace="pre">
|
||||
{communityCoordinate ? `Shared to` : `Shared`}
|
||||
</Text>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { forwardRef, memo, useMemo } from "react";
|
||||
import { Avatar, AvatarProps } from "@chakra-ui/react";
|
||||
import { Avatar, AvatarBadge, AvatarProps } from "@chakra-ui/react";
|
||||
import { useAsync } from "react-use";
|
||||
|
||||
import useUserMetadata from "../../hooks/use-user-metadata";
|
||||
@ -9,11 +9,19 @@ import { Kind0ParsedContent, getUserDisplayName } from "../../helpers/nostr/user
|
||||
import useAppSettings from "../../hooks/use-app-settings";
|
||||
import useCurrentAccount from "../../hooks/use-current-account";
|
||||
import { buildImageProxyURL } from "../../helpers/image";
|
||||
import UserDnsIdentityIcon, { useDnsIdentityColor } from "./user-dns-identity-icon";
|
||||
import styled from "@emotion/styled";
|
||||
|
||||
export const UserIdenticon = memo(({ pubkey }: { pubkey: string }) => {
|
||||
const { value: identicon } = useAsync(() => getIdenticon(pubkey), [pubkey]);
|
||||
|
||||
return identicon ? <img src={`data:image/svg+xml;base64,${identicon}`} width="100%" /> : null;
|
||||
return identicon ? (
|
||||
<img
|
||||
src={`data:image/svg+xml;base64,${identicon}`}
|
||||
width="100%"
|
||||
style={{ borderRadius: "var(--chakra-radii-lg)" }}
|
||||
/>
|
||||
) : null;
|
||||
});
|
||||
|
||||
const RESIZE_PROFILE_SIZE = 96;
|
||||
@ -22,19 +30,54 @@ export type UserAvatarProps = Omit<MetadataAvatarProps, "pubkey" | "metadata"> &
|
||||
pubkey: string;
|
||||
relay?: string;
|
||||
};
|
||||
export const UserAvatar = forwardRef<HTMLDivElement, UserAvatarProps>(({ pubkey, noProxy, relay, ...props }, ref) => {
|
||||
const metadata = useUserMetadata(pubkey, relay ? [relay] : undefined);
|
||||
return <MetadataAvatar pubkey={pubkey} metadata={metadata} noProxy={noProxy} ref={ref} {...props} />;
|
||||
});
|
||||
export const UserAvatar = forwardRef<HTMLDivElement, UserAvatarProps>(
|
||||
({ pubkey, noProxy, relay, size, ...props }, ref) => {
|
||||
const metadata = useUserMetadata(pubkey, relay ? [relay] : undefined);
|
||||
const color = useDnsIdentityColor(pubkey);
|
||||
|
||||
return (
|
||||
<MetadataAvatar
|
||||
pubkey={pubkey}
|
||||
metadata={metadata}
|
||||
noProxy={noProxy}
|
||||
ref={ref}
|
||||
borderColor={color}
|
||||
borderStyle="none"
|
||||
size={size}
|
||||
{...props}
|
||||
>
|
||||
{size !== "xs" && (
|
||||
<UserDnsIdentityIcon
|
||||
pubkey={pubkey}
|
||||
position="absolute"
|
||||
right={-1}
|
||||
bottom={-1}
|
||||
bgColor="white"
|
||||
borderRadius="50%"
|
||||
boxSize="1em"
|
||||
/>
|
||||
)}
|
||||
</MetadataAvatar>
|
||||
);
|
||||
},
|
||||
);
|
||||
UserAvatar.displayName = "UserAvatar";
|
||||
|
||||
const StyledAvatar = styled(Avatar)`
|
||||
img {
|
||||
border-radius: var(--chakra-radii-lg);
|
||||
border-width: 0.18rem;
|
||||
border-color: inherit;
|
||||
border-style: solid;
|
||||
}
|
||||
`;
|
||||
export type MetadataAvatarProps = Omit<AvatarProps, "src"> & {
|
||||
metadata?: Kind0ParsedContent;
|
||||
pubkey?: string;
|
||||
noProxy?: boolean;
|
||||
};
|
||||
export const MetadataAvatar = forwardRef<HTMLDivElement, MetadataAvatarProps>(
|
||||
({ pubkey, metadata, noProxy, ...props }, ref) => {
|
||||
({ pubkey, metadata, noProxy, children, ...props }, ref) => {
|
||||
const { imageProxy, proxyUserMedia, hideUsernames } = useAppSettings();
|
||||
const account = useCurrentAccount();
|
||||
const picture = useMemo(() => {
|
||||
@ -53,14 +96,16 @@ export const MetadataAvatar = forwardRef<HTMLDivElement, MetadataAvatarProps>(
|
||||
}, [metadata?.picture, imageProxy, proxyUserMedia, hideUsernames, account]);
|
||||
|
||||
return (
|
||||
<Avatar
|
||||
<StyledAvatar
|
||||
src={picture}
|
||||
icon={pubkey ? <UserIdenticon pubkey={pubkey} /> : undefined}
|
||||
overflow="hidden"
|
||||
// overflow="hidden"
|
||||
title={getUserDisplayName(metadata, pubkey ?? "")}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
>
|
||||
{children}
|
||||
</StyledAvatar>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
@ -1,10 +1,31 @@
|
||||
import { Text, Tooltip } from "@chakra-ui/react";
|
||||
import { IconProps, useColorMode } from "@chakra-ui/react";
|
||||
import { QuestionIcon, QuestionOutlineIcon } from "@chakra-ui/icons";
|
||||
|
||||
import useDnsIdentity from "../../hooks/use-dns-identity";
|
||||
import useUserMetadata from "../../hooks/use-user-metadata";
|
||||
import { VerificationFailed, VerificationMissing, VerifiedIcon } from "../icons";
|
||||
|
||||
export function UserDnsIdentityIcon({ pubkey, onlyIcon }: { pubkey: string; onlyIcon?: boolean }) {
|
||||
export function useDnsIdentityColor(pubkey: string) {
|
||||
const metadata = useUserMetadata(pubkey);
|
||||
const identity = useDnsIdentity(metadata?.nip05);
|
||||
const { colorMode } = useColorMode();
|
||||
|
||||
if (!metadata?.nip05) {
|
||||
return colorMode === "light" ? "gray.200" : "gray.800";
|
||||
}
|
||||
|
||||
if (identity === undefined) {
|
||||
return "yellow.500";
|
||||
} else if (identity === null) {
|
||||
return "red.500";
|
||||
} else if (pubkey === identity.pubkey) {
|
||||
return "purple.500";
|
||||
} else {
|
||||
return "red.500";
|
||||
}
|
||||
}
|
||||
|
||||
export default function UserDnsIdentityIcon({ pubkey, ...props }: { pubkey: string } & IconProps) {
|
||||
const metadata = useUserMetadata(pubkey);
|
||||
const identity = useDnsIdentity(metadata?.nip05);
|
||||
|
||||
@ -12,26 +33,13 @@ export function UserDnsIdentityIcon({ pubkey, onlyIcon }: { pubkey: string; only
|
||||
return null;
|
||||
}
|
||||
|
||||
const renderIcon = () => {
|
||||
if (identity === undefined) {
|
||||
return <VerificationFailed color="yellow.500" />;
|
||||
} else if (identity === null) {
|
||||
return <VerificationMissing color="red.500" />;
|
||||
} else if (pubkey === identity.pubkey) {
|
||||
return <VerifiedIcon color="purple.500" />;
|
||||
} else {
|
||||
return <VerificationFailed color="red.500" />;
|
||||
}
|
||||
};
|
||||
|
||||
if (onlyIcon) {
|
||||
return <Tooltip label={metadata.nip05}>{renderIcon()}</Tooltip>;
|
||||
if (identity === undefined) {
|
||||
return <VerificationFailed color="yellow.500" {...props} />;
|
||||
} else if (identity === null) {
|
||||
return <VerificationMissing color="red.500" {...props} />;
|
||||
} else if (pubkey === identity.pubkey) {
|
||||
return <VerifiedIcon color="purple.500" {...props} />;
|
||||
} else {
|
||||
return <VerificationFailed color="red.500" {...props} />;
|
||||
}
|
||||
return (
|
||||
<Text as="span" whiteSpace="nowrap">
|
||||
{metadata.nip05.startsWith("_@") ? metadata.nip05.substr(2) : metadata.nip05} {renderIcon()}
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
|
||||
export default UserDnsIdentityIcon;
|
||||
|
25
src/components/user/user-dns-identity.tsx
Normal file
25
src/components/user/user-dns-identity.tsx
Normal file
@ -0,0 +1,25 @@
|
||||
import { Text, Tooltip } from "@chakra-ui/react";
|
||||
|
||||
import useUserMetadata from "../../hooks/use-user-metadata";
|
||||
import UserDnsIdentityIcon from "./user-dns-identity-icon";
|
||||
|
||||
export default function UserDnsIdentity({ pubkey, onlyIcon }: { pubkey: string; onlyIcon?: boolean }) {
|
||||
const metadata = useUserMetadata(pubkey);
|
||||
if (!metadata?.nip05) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (onlyIcon) {
|
||||
return (
|
||||
<Tooltip label={metadata.nip05}>
|
||||
<UserDnsIdentityIcon pubkey={pubkey} />
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Text as="span" whiteSpace="nowrap">
|
||||
{metadata.nip05.startsWith("_@") ? metadata.nip05.substr(2) : metadata.nip05}{" "}
|
||||
<UserDnsIdentityIcon pubkey={pubkey} />
|
||||
</Text>
|
||||
);
|
||||
}
|
@ -25,7 +25,7 @@ import IntersectionObserverProvider from "../../../providers/local/intersection-
|
||||
import UserLink from "../../../components/user/user-link";
|
||||
import HoverLinkOverlay from "../../../components/hover-link-overlay";
|
||||
import UserAvatar from "../../../components/user/user-avatar";
|
||||
import { UserDnsIdentityIcon } from "../../../components/user/user-dns-identity-icon";
|
||||
import UserDnsIdentity from "../../../components/user/user-dns-identity";
|
||||
import ChannelJoinButton from "./channel-join-button";
|
||||
import { ExternalLinkIcon } from "../../../components/icons";
|
||||
import { CHANNELS_LIST_KIND } from "../../../helpers/nostr/lists";
|
||||
@ -37,7 +37,7 @@ function UserCard({ pubkey }: { pubkey: string }) {
|
||||
<Card as={LinkBox} direction="row" alignItems="center" gap="2" p="2">
|
||||
<UserAvatar pubkey={pubkey} size="sm" />
|
||||
<HoverLinkOverlay as={UserLink} pubkey={pubkey} fontWeight="bold" />
|
||||
<UserDnsIdentityIcon pubkey={pubkey} onlyIcon />
|
||||
<UserDnsIdentity pubkey={pubkey} onlyIcon />
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ import useSubject from "../../../hooks/use-subject";
|
||||
import { useTimelineCurserIntersectionCallback } from "../../../hooks/use-timeline-cursor-intersection-callback";
|
||||
import TimelineActionAndStatus from "../../../components/timeline-page/timeline-action-and-status";
|
||||
import UserLink from "../../../components/user/user-link";
|
||||
import { UserDnsIdentityIcon } from "../../../components/user/user-dns-identity-icon";
|
||||
import UserDnsIdentity from "../../../components/user/user-dns-identity";
|
||||
import UserAvatarLink from "../../../components/user/user-avatar-link";
|
||||
|
||||
function UserCard({ pubkey }: { pubkey: string }) {
|
||||
@ -32,7 +32,7 @@ function UserCard({ pubkey }: { pubkey: string }) {
|
||||
<UserAvatarLink pubkey={pubkey} />
|
||||
<Flex direction="column" flex={1} overflow="hidden">
|
||||
<UserLink pubkey={pubkey} fontWeight="bold" />
|
||||
<UserDnsIdentityIcon pubkey={pubkey} />
|
||||
<UserDnsIdentity pubkey={pubkey} />
|
||||
</Flex>
|
||||
</Flex>
|
||||
);
|
||||
|
@ -13,7 +13,7 @@ import useCurrentAccount from "../../hooks/use-current-account";
|
||||
import IntersectionObserverProvider from "../../providers/local/intersection-observer";
|
||||
import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";
|
||||
import TimelineActionAndStatus from "../../components/timeline-page/timeline-action-and-status";
|
||||
import { UserDnsIdentityIcon } from "../../components/user/user-dns-identity-icon";
|
||||
import UserDnsIdentity from "../../components/user/user-dns-identity";
|
||||
import { useDecryptionContext } from "../../providers/global/dycryption-provider";
|
||||
import SendMessageForm from "./components/send-message-form";
|
||||
import { groupMessages } from "../../helpers/nostr/dms";
|
||||
@ -123,7 +123,7 @@ function DirectMessageChatPage({ pubkey }: { pubkey: string }) {
|
||||
/>
|
||||
<UserAvatar pubkey={pubkey} size="sm" />
|
||||
<UserLink pubkey={pubkey} fontWeight="bold" />
|
||||
<UserDnsIdentityIcon pubkey={pubkey} onlyIcon />
|
||||
<UserDnsIdentity pubkey={pubkey} onlyIcon />
|
||||
</Flex>
|
||||
<ButtonGroup ml="auto">
|
||||
{!autoDecryptDMs && (
|
||||
|
@ -21,7 +21,7 @@ import UserName from "../../components/user/user-name";
|
||||
import { useDecryptionContainer } from "../../providers/global/dycryption-provider";
|
||||
import { NostrEvent } from "../../types/nostr-event";
|
||||
import { CheckIcon } from "../../components/icons";
|
||||
import { UserDnsIdentityIcon } from "../../components/user/user-dns-identity-icon";
|
||||
import UserDnsIdentity from "../../components/user/user-dns-identity";
|
||||
|
||||
function MessagePreview({ message, pubkey }: { message: NostrEvent; pubkey: string }) {
|
||||
const ref = useRef<HTMLParagraphElement | null>(null);
|
||||
@ -50,7 +50,7 @@ function ConversationCard({ conversation }: { conversation: KnownConversation })
|
||||
<Flex direction="column" gap="1" overflow="hidden" flex={1}>
|
||||
<Flex gap="2" alignItems="center" overflow="hidden">
|
||||
<UserName pubkey={conversation.correspondent} isTruncated />
|
||||
<UserDnsIdentityIcon onlyIcon pubkey={conversation.correspondent} />
|
||||
<UserDnsIdentity onlyIcon pubkey={conversation.correspondent} />
|
||||
<Timestamp flexShrink={0} timestamp={lastMessage.created_at} ml="auto" />
|
||||
{hasResponded(conversation) && <CheckIcon boxSize={4} color="green.500" />}
|
||||
</Flex>
|
||||
|
@ -17,7 +17,7 @@ import { NostrEvent } from "../../../types/nostr-event";
|
||||
import UserAvatar from "../../../components/user/user-avatar";
|
||||
import HoverLinkOverlay from "../../../components/hover-link-overlay";
|
||||
import UserName from "../../../components/user/user-name";
|
||||
import { UserDnsIdentityIcon } from "../../../components/user/user-dns-identity-icon";
|
||||
import UserDnsIdentity from "../../../components/user/user-dns-identity";
|
||||
import { nip19 } from "nostr-tools";
|
||||
import { useDecryptionContainer, useDecryptionContext } from "../../../providers/global/dycryption-provider";
|
||||
import Timestamp from "../../../components/timestamp";
|
||||
@ -38,7 +38,7 @@ function Conversation({ conversation }: { conversation: KnownConversation }) {
|
||||
<HoverLinkOverlay as={RouterLink} to={`/dm/${nip19.npubEncode(conversation.correspondent)}`}>
|
||||
<UserName pubkey={conversation.correspondent} />
|
||||
</HoverLinkOverlay>
|
||||
<UserDnsIdentityIcon pubkey={conversation.correspondent} onlyIcon />
|
||||
<UserDnsIdentity pubkey={conversation.correspondent} onlyIcon />
|
||||
</Flex>
|
||||
{lastReceived && <MessagePreview message={lastReceived} pubkey={conversation.correspondent} />}
|
||||
</Flex>
|
||||
|
@ -5,7 +5,7 @@ import { nip19 } from "nostr-tools";
|
||||
import useUserMetadata from "../../../hooks/use-user-metadata";
|
||||
import { getUserDisplayName } from "../../../helpers/nostr/user-metadata";
|
||||
import UserAvatar from "../../../components/user/user-avatar";
|
||||
import { UserDnsIdentityIcon } from "../../../components/user/user-dns-identity-icon";
|
||||
import UserDnsIdentity from "../../../components/user/user-dns-identity";
|
||||
import { NostrEvent } from "../../../types/nostr-event";
|
||||
import useAsyncErrorHandler from "../../../hooks/use-async-error-handler";
|
||||
import { listRemovePerson } from "../../../helpers/nostr/lists";
|
||||
@ -35,7 +35,7 @@ export default function UserCard({ pubkey, relay, list, ...props }: UserCardProp
|
||||
{getUserDisplayName(metadata, pubkey)}
|
||||
</Heading>
|
||||
</Link>
|
||||
<UserDnsIdentityIcon pubkey={pubkey} />
|
||||
<UserDnsIdentity pubkey={pubkey} />
|
||||
</Flex>
|
||||
{account?.pubkey === list.pubkey ? (
|
||||
<Button variant="outline" colorScheme="orange" onClick={handleRemoveFromList} size="sm">
|
||||
|
@ -2,7 +2,7 @@ import { MutableRefObject, PropsWithChildren, forwardRef } from "react";
|
||||
import { Divider, Flex, Heading, useDisclosure } from "@chakra-ui/react";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
import { ExpandableToggleButton } from "../notification-item";
|
||||
import { ExpandableToggleButton } from "./notification-item";
|
||||
|
||||
const specialNames = {
|
||||
[dayjs().startOf("day").unix()]: "Today",
|
||||
|
@ -2,23 +2,30 @@ import { ReactNode, forwardRef, memo, useMemo, useRef } from "react";
|
||||
import { AvatarGroup, Flex, IconButton, IconButtonProps, Text, useDisclosure } from "@chakra-ui/react";
|
||||
import { kinds, nip18, nip25 } from "nostr-tools";
|
||||
|
||||
import useCurrentAccount from "../../hooks/use-current-account";
|
||||
import { NostrEvent, isATag, isETag } from "../../types/nostr-event";
|
||||
import { useRegisterIntersectionEntity } from "../../providers/local/intersection-observer";
|
||||
import { parseZapEvent } from "../../helpers/nostr/zaps";
|
||||
import { readablizeSats } from "../../helpers/bolt11";
|
||||
import { getEventUID, getThreadReferences, isMentionedInContent, parseCoordinate } from "../../helpers/nostr/event";
|
||||
import { EmbedEvent, EmbedEventPointer } from "../../components/embed-event";
|
||||
import EmbeddedUnknown from "../../components/embed-event/event-types/embedded-unknown";
|
||||
import { ErrorBoundary } from "../../components/error-boundary";
|
||||
import { TrustProvider } from "../../providers/local/trust";
|
||||
import Heart from "../../components/icons/heart";
|
||||
import UserAvatarLink from "../../components/user/user-avatar-link";
|
||||
import { AtIcon, ChevronDownIcon, ChevronUpIcon, LightningIcon, ReplyIcon, RepostIcon } from "../../components/icons";
|
||||
import useSingleEvent from "../../hooks/use-single-event";
|
||||
import { TORRENT_COMMENT_KIND } from "../../helpers/nostr/torrents";
|
||||
import NotificationIconEntry from "./components/notification-icon-entry";
|
||||
import { getPubkeysMentionedInContent } from "../../helpers/nostr/post";
|
||||
import useCurrentAccount from "../../../hooks/use-current-account";
|
||||
import { NostrEvent, isATag, isETag } from "../../../types/nostr-event";
|
||||
import { useRegisterIntersectionEntity } from "../../../providers/local/intersection-observer";
|
||||
import { parseZapEvent } from "../../../helpers/nostr/zaps";
|
||||
import { readablizeSats } from "../../../helpers/bolt11";
|
||||
import { getEventUID, getThreadReferences, isMentionedInContent, parseCoordinate } from "../../../helpers/nostr/event";
|
||||
import { EmbedEvent, EmbedEventPointer } from "../../../components/embed-event";
|
||||
import EmbeddedUnknown from "../../../components/embed-event/event-types/embedded-unknown";
|
||||
import { ErrorBoundary } from "../../../components/error-boundary";
|
||||
import { TrustProvider } from "../../../providers/local/trust";
|
||||
import Heart from "../../../components/icons/heart";
|
||||
import UserAvatarLink from "../../../components/user/user-avatar-link";
|
||||
import {
|
||||
AtIcon,
|
||||
ChevronDownIcon,
|
||||
ChevronUpIcon,
|
||||
LightningIcon,
|
||||
ReplyIcon,
|
||||
RepostIcon,
|
||||
} from "../../../components/icons";
|
||||
import useSingleEvent from "../../../hooks/use-single-event";
|
||||
import { TORRENT_COMMENT_KIND } from "../../../helpers/nostr/torrents";
|
||||
import NotificationIconEntry from "./notification-icon-entry";
|
||||
import { getPubkeysMentionedInContent } from "../../../helpers/nostr/post";
|
||||
|
||||
export const ExpandableToggleButton = ({
|
||||
toggle,
|
@ -1,7 +1,9 @@
|
||||
import { memo, useEffect, useMemo, useRef } from "react";
|
||||
import { Button, ButtonGroup, Flex, useDisclosure } from "@chakra-ui/react";
|
||||
import { Button, ButtonGroup, Flex, IconButton, Input, useDisclosure } from "@chakra-ui/react";
|
||||
import { kinds } from "nostr-tools";
|
||||
import { Link as RouterLink } from "react-router-dom";
|
||||
import dayjs from "dayjs";
|
||||
import { useThrottle } from "react-use";
|
||||
|
||||
import RequireCurrentAccount from "../../providers/route/require-current-account";
|
||||
import TimelineActionAndStatus from "../../components/timeline-page/timeline-action-and-status";
|
||||
@ -11,17 +13,20 @@ import IntersectionObserverProvider, {
|
||||
import useSubject from "../../hooks/use-subject";
|
||||
import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";
|
||||
import { useNotificationTimeline } from "../../providers/global/notification-timeline";
|
||||
import { getEventUID, isReply, isRepost } from "../../helpers/nostr/event";
|
||||
import { getEventUID, isReply } from "../../helpers/nostr/event";
|
||||
import PeopleListProvider, { usePeopleListContext } from "../../providers/local/people-list-provider";
|
||||
import PeopleListSelection from "../../components/people-list-selection/people-list-selection";
|
||||
import VerticalPageLayout from "../../components/vertical-page-layout";
|
||||
import NotificationItem from "./notification-item";
|
||||
import NotificationItem from "./components/notification-item";
|
||||
import NotificationTypeToggles from "./notification-type-toggles";
|
||||
import { NostrEvent } from "../../types/nostr-event";
|
||||
import { groupByTime } from "../../helpers/notification";
|
||||
import DayGroup from "./components/day-group";
|
||||
import { useThrottle } from "react-use";
|
||||
import TimelineLoader from "../../classes/timeline-loader";
|
||||
import { ChevronLeftIcon, ChevronRightIcon } from "../../components/icons";
|
||||
import useRouteSearchValue from "../../hooks/use-route-search-value";
|
||||
|
||||
const DATE_FORMAT = "YYYY-MM-DD";
|
||||
|
||||
const NotificationDay = memo(({ day, events }: { day: number; events: NostrEvent[] }) => {
|
||||
const ref = useRef<HTMLDivElement | null>(null);
|
||||
@ -39,6 +44,7 @@ const NotificationDay = memo(({ day, events }: { day: number; events: NostrEvent
|
||||
const NotificationsTimeline = memo(
|
||||
({
|
||||
timeline,
|
||||
day,
|
||||
showReplies,
|
||||
showMentions,
|
||||
showZaps,
|
||||
@ -46,6 +52,7 @@ const NotificationsTimeline = memo(
|
||||
showReactions,
|
||||
}: {
|
||||
timeline: TimelineLoader;
|
||||
day: string;
|
||||
showReplies: boolean;
|
||||
showMentions: boolean;
|
||||
showZaps: boolean;
|
||||
@ -54,6 +61,8 @@ const NotificationsTimeline = memo(
|
||||
}) => {
|
||||
const { people } = usePeopleListContext();
|
||||
const peoplePubkeys = useMemo(() => people?.map((p) => p.pubkey), [people]);
|
||||
const minTimestamp = dayjs(day, DATE_FORMAT).startOf("day").unix();
|
||||
const maxTimestamp = dayjs(day, DATE_FORMAT).endOf("day").unix();
|
||||
|
||||
const events = useSubject(timeline.timeline);
|
||||
|
||||
@ -61,6 +70,7 @@ const NotificationsTimeline = memo(
|
||||
const filteredEvents = useMemo(
|
||||
() =>
|
||||
throttledEvents.filter((e) => {
|
||||
if (e.created_at < minTimestamp || e.created_at > maxTimestamp) return false;
|
||||
if (peoplePubkeys && e.kind !== kinds.Zap && !peoplePubkeys.includes(e.pubkey)) return false;
|
||||
|
||||
if (e.kind === kinds.ShortTextNote) {
|
||||
@ -73,17 +83,42 @@ const NotificationsTimeline = memo(
|
||||
|
||||
return true;
|
||||
}),
|
||||
[throttledEvents, peoplePubkeys, showReplies, showMentions, showReactions, showReposts, showZaps],
|
||||
[
|
||||
throttledEvents,
|
||||
peoplePubkeys,
|
||||
showReplies,
|
||||
showMentions,
|
||||
showReactions,
|
||||
showReposts,
|
||||
showZaps,
|
||||
minTimestamp,
|
||||
maxTimestamp,
|
||||
],
|
||||
);
|
||||
const sortedDays = useMemo(() => groupByTime(filteredEvents), [filteredEvents]);
|
||||
// const sortedDays = useMemo(() => groupByTime(filteredEvents), [filteredEvents]);
|
||||
|
||||
if (filteredEvents.length === 0)
|
||||
return (
|
||||
<Flex alignItems="center" justifyContent="center" minH="25vh" fontWeight="bold" fontSize="4xl">
|
||||
Nothing...
|
||||
</Flex>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{sortedDays.map(([day, events]) => (
|
||||
<NotificationDay key={day} day={day} events={events} />
|
||||
{filteredEvents.map((event) => (
|
||||
<NotificationItem key={event.id} event={event} />
|
||||
))}
|
||||
</>
|
||||
);
|
||||
|
||||
// return (
|
||||
// <>
|
||||
// {sortedDays.map(([day, events]) => (
|
||||
// <NotificationDay key={day} day={day} events={events} />
|
||||
// ))}
|
||||
// </>
|
||||
// );
|
||||
},
|
||||
);
|
||||
|
||||
@ -98,6 +133,24 @@ function NotificationsPage() {
|
||||
defaultIsOpen: localStorage.getItem("notifications-show-reactions") !== "false",
|
||||
});
|
||||
|
||||
const today = dayjs().format(DATE_FORMAT);
|
||||
const { value: day, setValue: setDay } = useRouteSearchValue("date", dayjs().format(DATE_FORMAT));
|
||||
|
||||
const nextDay = () => {
|
||||
setDay((date) =>
|
||||
dayjs(date ?? today, DATE_FORMAT)
|
||||
.add(1, "day")
|
||||
.format(DATE_FORMAT),
|
||||
);
|
||||
};
|
||||
const perviousDay = () => {
|
||||
setDay((date) =>
|
||||
dayjs(date ?? today, DATE_FORMAT)
|
||||
.subtract(1, "day")
|
||||
.format(DATE_FORMAT),
|
||||
);
|
||||
};
|
||||
|
||||
// save toggles to localStorage when changed
|
||||
useEffect(() => {
|
||||
localStorage.setItem("notifications-show-replies", String(showReplies.isOpen));
|
||||
@ -111,9 +164,27 @@ function NotificationsPage() {
|
||||
const callback = useTimelineCurserIntersectionCallback(timeline);
|
||||
|
||||
return (
|
||||
<IntersectionObserverProvider callback={callback}>
|
||||
<VerticalPageLayout>
|
||||
<Flex gap="2" wrap="wrap">
|
||||
<VerticalPageLayout>
|
||||
<Flex direction={{ base: "column", lg: "row-reverse" }} gap="2" justifyContent="space-between">
|
||||
<Flex gap="2" justifyContent="space-between">
|
||||
<IconButton aria-label="Pervious" icon={<ChevronLeftIcon boxSize={6} />} onClick={perviousDay} />
|
||||
<Input
|
||||
maxW="xs"
|
||||
minW="64"
|
||||
type="date"
|
||||
value={day}
|
||||
onChange={(e) => e.target.value && setDay(e.target.value)}
|
||||
max={today}
|
||||
/>
|
||||
<IconButton
|
||||
aria-label="Next"
|
||||
icon={<ChevronRightIcon boxSize={6} />}
|
||||
onClick={nextDay}
|
||||
isDisabled={day === today}
|
||||
/>
|
||||
</Flex>
|
||||
|
||||
<Flex gap="2" wrap="wrap" flex={1}>
|
||||
<NotificationTypeToggles
|
||||
showReplies={showReplies}
|
||||
showMentions={showMentions}
|
||||
@ -128,18 +199,33 @@ function NotificationsPage() {
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
<IntersectionObserverProvider callback={callback}>
|
||||
<NotificationsTimeline
|
||||
timeline={timeline}
|
||||
day={day}
|
||||
showReplies={showReplies.isOpen}
|
||||
showMentions={showMentions.isOpen}
|
||||
showZaps={showZaps.isOpen}
|
||||
showReposts={showReposts.isOpen}
|
||||
showReactions={showReactions.isOpen}
|
||||
/>
|
||||
<TimelineActionAndStatus timeline={timeline} />
|
||||
</VerticalPageLayout>
|
||||
</IntersectionObserverProvider>
|
||||
</IntersectionObserverProvider>
|
||||
|
||||
{/* <TimelineActionAndStatus timeline={timeline} /> */}
|
||||
|
||||
<ButtonGroup mx="auto" mt="4">
|
||||
<Button leftIcon={<ChevronLeftIcon boxSize={6} />} onClick={perviousDay}>
|
||||
Pervious
|
||||
</Button>
|
||||
{day !== today && (
|
||||
<Button rightIcon={<ChevronRightIcon boxSize={6} />} onClick={nextDay}>
|
||||
Next
|
||||
</Button>
|
||||
)}
|
||||
</ButtonGroup>
|
||||
</VerticalPageLayout>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { useState } from "react";
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
@ -19,12 +20,12 @@ import {
|
||||
Text,
|
||||
useDisclosure,
|
||||
} from "@chakra-ui/react";
|
||||
import { useState } from "react";
|
||||
import { useDebounce } from "react-use";
|
||||
|
||||
import { useRelayInfo } from "../../../hooks/use-relay-info";
|
||||
import UserAvatar from "../../../components/user/user-avatar";
|
||||
import UserLink from "../../../components/user/user-link";
|
||||
import { useDebounce } from "react-use";
|
||||
import { UserDnsIdentityIcon } from "../../../components/user/user-dns-identity-icon";
|
||||
import UserDnsIdentity from "../../../components/user/user-dns-identity";
|
||||
import { CodeIcon } from "../../../components/icons";
|
||||
import { Metadata } from "./relay-card";
|
||||
import { safeRelayUrl } from "../../../helpers/relay";
|
||||
@ -43,7 +44,7 @@ function RelayDetails({ url, debug }: { url: string; debug?: boolean }) {
|
||||
<Text fontWeight="bold">Owner: </Text>
|
||||
<UserAvatar pubkey={info.pubkey} size="xs" />
|
||||
<UserLink pubkey={info.pubkey} />
|
||||
<UserDnsIdentityIcon pubkey={info.pubkey} onlyIcon />
|
||||
<UserDnsIdentity pubkey={info.pubkey} onlyIcon />
|
||||
</Flex>
|
||||
)}
|
||||
<Metadata name="NIPs">{info.supported_nips?.join(", ")}</Metadata>
|
||||
|
@ -27,9 +27,8 @@ import { RelayFavicon } from "../../../components/relay-favicon";
|
||||
import { CodeIcon } from "../../../components/icons";
|
||||
import UserLink from "../../../components/user/user-link";
|
||||
import UserAvatar from "../../../components/user/user-avatar";
|
||||
import { UserDnsIdentityIcon } from "../../../components/user/user-dns-identity-icon";
|
||||
import UserDnsIdentity from "../../../components/user/user-dns-identity";
|
||||
import RawJson from "../../../components/debug-modal/raw-json";
|
||||
import { RelayShareButton } from "./relay-share-button";
|
||||
import useRelayStats from "../../../hooks/use-relay-stats";
|
||||
import { getNetwork } from "../../../helpers/nostr/relay-stats";
|
||||
|
||||
@ -56,7 +55,7 @@ export function RelayMetadata({ url, extended }: { url: string; extended?: boole
|
||||
<B>Owner:</B>
|
||||
<UserAvatar pubkey={info.pubkey} size="xs" noProxy />
|
||||
<UserLink pubkey={info.pubkey} />
|
||||
<UserDnsIdentityIcon pubkey={info.pubkey} onlyIcon />
|
||||
<UserDnsIdentity pubkey={info.pubkey} onlyIcon />
|
||||
</Flex>
|
||||
)}
|
||||
{extended && (
|
||||
|
@ -4,7 +4,7 @@ import { Link as RouterLink } from "react-router-dom";
|
||||
|
||||
import UserAvatarLink from "../../../components/user/user-avatar-link";
|
||||
import UserLink from "../../../components/user/user-link";
|
||||
import { UserDnsIdentityIcon } from "../../../components/user/user-dns-identity-icon";
|
||||
import UserDnsIdentity from "../../../components/user/user-dns-identity";
|
||||
import StarRating from "../../../components/star-rating";
|
||||
import { safeJson } from "../../../helpers/parse";
|
||||
import { NostrEvent } from "../../../types/nostr-event";
|
||||
@ -28,7 +28,7 @@ export default function RelayReviewNote({ event, hideUrl }: { event: NostrEvent;
|
||||
<CardHeader display="flex" gap="2" px="2" pt="2" pb="0">
|
||||
<UserAvatarLink pubkey={event.pubkey} size="xs" />
|
||||
<UserLink pubkey={event.pubkey} isTruncated fontWeight="bold" fontSize="lg" />
|
||||
<UserDnsIdentityIcon pubkey={event.pubkey} onlyIcon />
|
||||
<UserDnsIdentity pubkey={event.pubkey} onlyIcon />
|
||||
<Timestamp ml="auto" timestamp={event.created_at} />
|
||||
</CardHeader>
|
||||
<CardBody p="2">
|
||||
|
@ -14,7 +14,7 @@ import useSubject from "../../../hooks/use-subject";
|
||||
import { useTimelineCurserIntersectionCallback } from "../../../hooks/use-timeline-cursor-intersection-callback";
|
||||
import TimelineActionAndStatus from "../../../components/timeline-page/timeline-action-and-status";
|
||||
import UserAvatarLink from "../../../components/user/user-avatar-link";
|
||||
import { UserDnsIdentityIcon } from "../../../components/user/user-dns-identity-icon";
|
||||
import UserDnsIdentity from "../../../components/user/user-dns-identity";
|
||||
import HoverLinkOverlay from "../../../components/hover-link-overlay";
|
||||
import UserLink from "../../../components/user/user-link";
|
||||
import { getRelaysFromList } from "../../../helpers/nostr/lists";
|
||||
@ -30,7 +30,7 @@ function UserCard({ list, pubkey }: { list: NostrEvent; pubkey: string }) {
|
||||
<UserAvatarLink pubkey={pubkey} />
|
||||
<Flex direction="column" overflow="hidden">
|
||||
<HoverLinkOverlay as={UserLink} pubkey={pubkey} fontWeight="bold" isTruncated />
|
||||
<UserDnsIdentityIcon pubkey={pubkey} />
|
||||
<UserDnsIdentity pubkey={pubkey} />
|
||||
</Flex>
|
||||
</Card>
|
||||
);
|
||||
|
@ -8,7 +8,7 @@ import { parseMetadataContent } from "../../helpers/nostr/user-metadata";
|
||||
import { readablizeSats } from "../../helpers/bolt11";
|
||||
import { EmbedableContent, embedUrls } from "../../helpers/embeds";
|
||||
import UserAvatar from "../../components/user/user-avatar";
|
||||
import { UserDnsIdentityIcon } from "../../components/user/user-dns-identity-icon";
|
||||
import UserDnsIdentity from "../../components/user/user-dns-identity";
|
||||
import { embedNostrLinks, renderGenericUrl } from "../../components/embed-types";
|
||||
import UserLink from "../../components/user/user-link";
|
||||
import trustedUserStatsService, { NostrBandUserStats } from "../../services/trusted-user-stats";
|
||||
@ -38,7 +38,7 @@ function ProfileResult({ profile }: { profile: NostrEvent }) {
|
||||
<UserAvatar pubkey={profile.pubkey} noProxy mr="2" float="left" />
|
||||
<UserLink pubkey={profile.pubkey} fontWeight="bold" fontSize="xl" isTruncated />
|
||||
<br />
|
||||
<UserDnsIdentityIcon pubkey={profile.pubkey} />
|
||||
<UserDnsIdentity pubkey={profile.pubkey} />
|
||||
<br />
|
||||
<Box whiteSpace="pre" overflow="hidden" maxH="xs" isTruncated>
|
||||
{aboutContent}
|
||||
|
@ -7,7 +7,7 @@ import UserLink from "../../components/user/user-link";
|
||||
import { containerProps } from "./common";
|
||||
import { UserFollowButton } from "../../components/user/user-follow-button";
|
||||
import { Kind0ParsedContent } from "../../helpers/nostr/user-metadata";
|
||||
import { UserDnsIdentityIcon } from "../../components/user/user-dns-identity-icon";
|
||||
import UserDnsIdentity from "../../components/user/user-dns-identity";
|
||||
|
||||
type TrendingApi = {
|
||||
profiles: {
|
||||
@ -45,7 +45,7 @@ export default function FinishedStep() {
|
||||
<UserAvatarLink pubkey={pubkey} />
|
||||
<Flex direction="column" overflow="hidden">
|
||||
<UserLink pubkey={pubkey} fontWeight="bold" fontSize="lg" isTruncated />
|
||||
<UserDnsIdentityIcon pubkey={pubkey} />
|
||||
<UserDnsIdentity pubkey={pubkey} />
|
||||
</Flex>
|
||||
<UserFollowButton pubkey={pubkey} flexShrink={0} ml="auto" />
|
||||
</Flex>
|
||||
|
@ -13,7 +13,7 @@ import Timestamp from "../../../components/timestamp";
|
||||
import Expand01 from "../../../components/icons/expand-01";
|
||||
import Minus from "../../../components/icons/minus";
|
||||
import { useBreakpointValue } from "../../../providers/global/breakpoint-provider";
|
||||
import { UserDnsIdentityIcon } from "../../../components/user/user-dns-identity-icon";
|
||||
import UserDnsIdentity from "../../../components/user/user-dns-identity";
|
||||
import EventInteractionDetailsModal from "../../../components/event-interactions-modal";
|
||||
import { getSharableEventAddress } from "../../../helpers/nip19";
|
||||
import { useRegisterIntersectionEntity } from "../../../providers/local/intersection-observer";
|
||||
@ -67,7 +67,7 @@ export const ThreadPost = memo(({ post, initShowReplies, focusId, level = -1 }:
|
||||
<Flex gap="2" alignItems="center">
|
||||
<UserAvatarLink pubkey={post.event.pubkey} size="sm" />
|
||||
<UserLink pubkey={post.event.pubkey} fontWeight="bold" isTruncated />
|
||||
<UserDnsIdentityIcon pubkey={post.event.pubkey} onlyIcon />
|
||||
<UserDnsIdentity pubkey={post.event.pubkey} onlyIcon />
|
||||
<POWIcon event={post.event} boxSize={5} />
|
||||
<Link as={RouterLink} whiteSpace="nowrap" color="current" to={`/n/${getSharableEventAddress(post.event)}`}>
|
||||
<Timestamp timestamp={post.event.created_at} />
|
||||
|
@ -5,7 +5,7 @@ import { NostrEvent } from "../../../types/nostr-event";
|
||||
import useSingleEvent from "../../../hooks/use-single-event";
|
||||
import { NoteTranslationsPage } from "./translation";
|
||||
import UserAvatarLink from "../../../components/user/user-avatar-link";
|
||||
import { UserDnsIdentityIcon } from "../../../components/user/user-dns-identity-icon";
|
||||
import UserDnsIdentity from "../../../components/user/user-dns-identity";
|
||||
import UserLink from "../../../components/user/user-link";
|
||||
import NoteTextToSpeechPage from "./text-to-speech";
|
||||
import useRouteSearchValue from "../../../hooks/use-route-search-value";
|
||||
@ -36,7 +36,7 @@ function TransformNotePage({ note }: { note: NostrEvent }) {
|
||||
<Flex gap="2" alignItems="center">
|
||||
<UserAvatarLink pubkey={note.pubkey} size={["xs", "sm"]} />
|
||||
<UserLink pubkey={note.pubkey} isTruncated fontWeight="bold" fontSize="lg" />
|
||||
<UserDnsIdentityIcon pubkey={note.pubkey} onlyIcon />
|
||||
<UserDnsIdentity pubkey={note.pubkey} onlyIcon />
|
||||
<Spacer />
|
||||
<NoteMenu event={note} aria-label="Note Options" />
|
||||
</Flex>
|
||||
|
@ -24,7 +24,7 @@ import {
|
||||
import useClientSideMuteFilter from "../../../hooks/use-client-side-mute-filter";
|
||||
import UserAvatarLink from "../../../components/user/user-avatar-link";
|
||||
import UserLink from "../../../components/user/user-link";
|
||||
import { UserDnsIdentityIcon } from "../../../components/user/user-dns-identity-icon";
|
||||
import UserDnsIdentity from "../../../components/user/user-dns-identity";
|
||||
import Timestamp from "../../../components/timestamp";
|
||||
import Minus from "../../../components/icons/minus";
|
||||
import Expand01 from "../../../components/icons/expand-01";
|
||||
@ -67,7 +67,7 @@ export const ThreadPost = memo(({ post, level = -1 }: { post: ThreadItem; level?
|
||||
<Flex gap="2" alignItems="center">
|
||||
<UserAvatarLink pubkey={post.event.pubkey} size="sm" />
|
||||
<UserLink pubkey={post.event.pubkey} fontWeight="bold" isTruncated />
|
||||
<UserDnsIdentityIcon pubkey={post.event.pubkey} onlyIcon />
|
||||
<UserDnsIdentity pubkey={post.event.pubkey} onlyIcon />
|
||||
<Timestamp timestamp={post.event.created_at} />
|
||||
{replies.length > 0 ? (
|
||||
<Button variant="ghost" onClick={expanded.onToggle} rightIcon={expanded.isOpen ? <Minus /> : <Expand01 />}>
|
||||
|
@ -13,7 +13,7 @@ import { ReplyIcon } from "../../../components/icons";
|
||||
import TrackStemstrButton from "./track-stemstr-button";
|
||||
import TrackDownloadButton from "./track-download-button";
|
||||
import TrackPlayer from "./track-player";
|
||||
import { UserDnsIdentityIcon } from "../../../components/user/user-dns-identity-icon";
|
||||
import UserDnsIdentity from "../../../components/user/user-dns-identity";
|
||||
import TrackMenu from "./track-menu";
|
||||
import QuoteRepostButton from "../../../components/note/quote-repost-button";
|
||||
import NoteZapButton from "../../../components/note/note-zap-button";
|
||||
@ -29,7 +29,7 @@ export default function TrackCard({ track, ...props }: { track: NostrEvent } & O
|
||||
<CardHeader display="flex" alignItems="center" p="2" pb="0" gap="2">
|
||||
<UserAvatarLink pubkey={track.pubkey} size="sm" />
|
||||
<UserLink pubkey={track.pubkey} isTruncated fontWeight="bold" fontSize="lg" />
|
||||
<UserDnsIdentityIcon pubkey={track.pubkey} onlyIcon />
|
||||
<UserDnsIdentity pubkey={track.pubkey} onlyIcon />
|
||||
<Timestamp ml="auto" timestamp={track.created_at} />
|
||||
</CardHeader>
|
||||
<CardBody p="2" display="flex" gap="2" flexDirection="column">
|
||||
|
@ -20,7 +20,7 @@ import {
|
||||
} from "../../../components/icons";
|
||||
import { CopyIconButton } from "../../../components/copy-icon-button";
|
||||
import { QrIconButton } from "../components/share-qr-button";
|
||||
import { UserDnsIdentityIcon } from "../../../components/user/user-dns-identity-icon";
|
||||
import UserDnsIdentity from "../../../components/user/user-dns-identity";
|
||||
import UserAvatar from "../../../components/user/user-avatar";
|
||||
import { ChatIcon } from "@chakra-ui/icons";
|
||||
import { UserFollowButton } from "../../../components/user/user-follow-button";
|
||||
@ -90,7 +90,7 @@ export default function UserAboutTab() {
|
||||
<UserAvatar pubkey={pubkey} size={["lg", "lg", "xl"]} noProxy />
|
||||
<Box overflow="hidden">
|
||||
<Heading isTruncated>{getUserDisplayName(metadata, pubkey)}</Heading>
|
||||
<UserDnsIdentityIcon pubkey={pubkey} />
|
||||
<UserDnsIdentity pubkey={pubkey} />
|
||||
</Box>
|
||||
|
||||
<Flex gap="2" ml="auto">
|
||||
@ -136,7 +136,7 @@ export default function UserAboutTab() {
|
||||
<Flex gap="2">
|
||||
<AtIcon />
|
||||
<Link href={`//${parsedNip05.domain}/.well-known/nostr.json?name=${parsedNip05.name}`} isExternal>
|
||||
<UserDnsIdentityIcon pubkey={pubkey} />
|
||||
<UserDnsIdentity pubkey={pubkey} />
|
||||
</Link>
|
||||
</Flex>
|
||||
)}
|
||||
|
@ -3,7 +3,7 @@ import { useNavigate } from "react-router-dom";
|
||||
|
||||
import { EditIcon, GhostIcon } from "../../../components/icons";
|
||||
import UserAvatar from "../../../components/user/user-avatar";
|
||||
import { UserDnsIdentityIcon } from "../../../components/user/user-dns-identity-icon";
|
||||
import UserDnsIdentity from "../../../components/user/user-dns-identity";
|
||||
import { getUserDisplayName } from "../../../helpers/nostr/user-metadata";
|
||||
import useCurrentAccount from "../../../hooks/use-current-account";
|
||||
import useUserMetadata from "../../../hooks/use-user-metadata";
|
||||
@ -36,7 +36,7 @@ export default function Header({
|
||||
<Heading size="md" isTruncated>
|
||||
{getUserDisplayName(metadata, pubkey)}
|
||||
</Heading>
|
||||
<UserDnsIdentityIcon pubkey={pubkey} onlyIcon={showFullNip05} />
|
||||
<UserDnsIdentity pubkey={pubkey} onlyIcon={showFullNip05} />
|
||||
<Spacer />
|
||||
{isSelf && !account.readonly && (
|
||||
<IconButton
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Flex, FlexProps } from "@chakra-ui/react";
|
||||
|
||||
import { UserDnsIdentityIcon } from "../../../components/user/user-dns-identity-icon";
|
||||
import UserDnsIdentity from "../../../components/user/user-dns-identity";
|
||||
import { UserFollowButton } from "../../../components/user/user-follow-button";
|
||||
import UserLink from "../../../components/user/user-link";
|
||||
import UserAvatarLink from "../../../components/user/user-avatar-link";
|
||||
@ -24,7 +24,7 @@ export const UserCard = ({ pubkey, relay, ...props }: UserCardProps) => {
|
||||
<UserAvatarLink pubkey={pubkey} />
|
||||
<Flex direction="column" flex={1} overflow="hidden">
|
||||
<UserLink pubkey={pubkey} fontWeight="bold" />
|
||||
<UserDnsIdentityIcon pubkey={pubkey} />
|
||||
<UserDnsIdentity pubkey={pubkey} />
|
||||
</Flex>
|
||||
<UserFollowButton pubkey={pubkey} size="sm" variant="outline" flexShrink={0} />
|
||||
</Flex>
|
||||
|
@ -13,7 +13,7 @@ import useParamsAddressPointer from "../../hooks/use-params-address-pointer";
|
||||
import useReplaceableEvent from "../../hooks/use-replaceable-event";
|
||||
import UserAvatarLink from "../../components/user/user-avatar-link";
|
||||
import UserLink from "../../components/user/user-link";
|
||||
import { UserDnsIdentityIcon } from "../../components/user/user-dns-identity-icon";
|
||||
import UserDnsIdentity from "../../components/user/user-dns-identity";
|
||||
import { UserFollowButton } from "../../components/user/user-follow-button";
|
||||
import VideoMenu from "./components/video-menu";
|
||||
import SimpleLikeButton from "../../components/event-reactions/simple-like-button";
|
||||
@ -73,7 +73,7 @@ function VideoDetailsPage({ video }: { video: NostrEvent }) {
|
||||
<Flex gap="2" alignItems="center">
|
||||
<UserAvatarLink pubkey={video.pubkey} size="sm" />
|
||||
<UserLink pubkey={video.pubkey} fontSize="lg" tab="videos" />
|
||||
<UserDnsIdentityIcon pubkey={video.pubkey} onlyIcon />
|
||||
<UserDnsIdentity pubkey={video.pubkey} onlyIcon />
|
||||
<UserFollowButton pubkey={video.pubkey} size="sm" />
|
||||
<ButtonGroup ml="auto" size="sm" variant="ghost">
|
||||
<SimpleBookmarkButton event={video} aria-label="Bookmark video" title="Bookmark video" />
|
||||
|
Loading…
x
Reference in New Issue
Block a user