add timestamp component

This commit is contained in:
hzrd149 2023-09-08 16:27:45 -05:00
parent 076b89e1b6
commit c5f3398627
24 changed files with 96 additions and 49 deletions

View File

@ -1,6 +1,5 @@
import { useRef } from "react";
import { Card, CardProps, Flex, Image, LinkBox, LinkOverlay, Tag, Text } from "@chakra-ui/react";
import dayjs from "dayjs";
import {
getArticleImage,
@ -15,6 +14,7 @@ import { buildAppSelectUrl } from "../../../helpers/nostr/apps";
import { getSharableEventAddress } from "../../../helpers/nip19";
import { UserAvatarLink } from "../../user-avatar-link";
import { UserLink } from "../../user-link";
import Timestamp from "../../timestamp";
export default function EmbeddedArticle({ article, ...props }: Omit<CardProps, "children"> & { article: NostrEvent }) {
const title = getArticleTitle(article);
@ -37,7 +37,9 @@ export default function EmbeddedArticle({ article, ...props }: Omit<CardProps, "
</LinkOverlay>
<Text>by:</Text>
<UserLink pubkey={article.pubkey} />
<Text>| {dayjs.unix(getArticlePublishDate(article) ?? article.created_at).fromNow()}</Text>
<Text>
| <Timestamp timestamp={getArticlePublishDate(article) ?? article.created_at} />
</Text>
</Flex>
<Text flex={1}>{summary}</Text>
<Flex gap="2" alignItems="center">

View File

@ -12,7 +12,6 @@ import {
Text,
} from "@chakra-ui/react";
import { Link as RouterLink } from "react-router-dom";
import dayjs from "dayjs";
import { getSharableEventAddress } from "../../../helpers/nip19";
import { getEmojisFromPack, getPackName } from "../../../helpers/nostr/emoji-packs";
@ -21,6 +20,7 @@ import { UserLink } from "../../user-link";
import EmojiPackFavoriteButton from "../../../views/emoji-packs/components/emoji-pack-favorite-button";
import EmojiPackMenu from "../../../views/emoji-packs/components/emoji-pack-menu";
import { NostrEvent } from "../../../types/nostr-event";
import Timestamp from "../../timestamp";
export default function EmbeddedEmojiPack({ pack, ...props }: Omit<CardProps, "children"> & { pack: NostrEvent }) {
const emojis = getEmojisFromPack(pack);
@ -52,7 +52,9 @@ export default function EmbeddedEmojiPack({ pack, ...props }: Omit<CardProps, "c
)}
</CardBody>
<CardFooter p="2" display="flex" pt="0">
<Text>Updated: {dayjs.unix(pack.created_at).fromNow()}</Text>
<Text>
Updated: <Timestamp timestamp={pack.created_at} />
</Text>
</CardFooter>
</Card>
);

View File

@ -1,4 +1,3 @@
import dayjs from "dayjs";
import { Button, Card, CardBody, CardHeader, Spacer, useDisclosure } from "@chakra-ui/react";
import { NoteContents } from "../../note/note-contents";
@ -12,6 +11,7 @@ import EventVerificationIcon from "../../event-verification-icon";
import { TrustProvider } from "../../../providers/trust";
import { NoteLink } from "../../note-link";
import { ArrowDownSIcon, ArrowUpSIcon } from "../../icons";
import Timestamp from "../../timestamp";
export default function EmbeddedNote({ event }: { event: NostrEvent }) {
const { showSignatureVerification } = useSubject(appSettings);
@ -30,7 +30,7 @@ export default function EmbeddedNote({ event }: { event: NostrEvent }) {
<Spacer />
{showSignatureVerification && <EventVerificationIcon event={event} />}
<NoteLink noteId={event.id} color="current" whiteSpace="nowrap">
{dayjs.unix(event.created_at).fromNow()}
<Timestamp timestamp={event.created_at} />
</NoteLink>
</CardHeader>
<CardBody p="0">{expand.isOpen && <NoteContents px="2" event={event} />}</CardBody>

View File

@ -1,6 +1,5 @@
import { Card, CardBody, CardProps, Flex, Heading, Image, Link, Tag, Text, useBreakpointValue } from "@chakra-ui/react";
import { Link as RouterLink, useNavigate } from "react-router-dom";
import dayjs from "dayjs";
import { parseStreamEvent } from "../../../helpers/nostr/stream";
import { NostrEvent } from "../../../types/nostr-event";
@ -8,6 +7,7 @@ import StreamStatusBadge from "../../../views/streams/components/status-badge";
import { UserLink } from "../../user-link";
import { UserAvatar } from "../../user-avatar";
import useEventNaddr from "../../../hooks/use-event-naddr";
import Timestamp from "../../timestamp";
export default function EmbeddedStream({ event, ...props }: Omit<CardProps, "children"> & { event: NostrEvent }) {
const stream = parseStreamEvent(event);
@ -54,7 +54,11 @@ export default function EmbeddedStream({ event, ...props }: Omit<CardProps, "chi
</Heading>
</Flex>
{stream.starts && <Text>Started: {dayjs.unix(stream.starts).fromNow()}</Text>}
{stream.starts && (
<Text>
Started: <Timestamp timestamp={stream.starts} />
</Text>
)}
{stream.tags.length > 0 && (
<Flex gap="2" wrap="wrap">
{stream.tags.map((tag) => (

View File

@ -1,5 +1,4 @@
import { Box, Card, CardBody, CardHeader, CardProps, Flex, Heading, Link, Text } from "@chakra-ui/react";
import dayjs from "dayjs";
import { Box, Card, CardBody, CardHeader, CardProps, Flex, Link, Text } from "@chakra-ui/react";
import { getSharableEventAddress } from "../../../helpers/nip19";
import { NostrEvent } from "../../../types/nostr-event";
@ -11,6 +10,7 @@ import { UserDnsIdentityIcon } from "../../user-dns-identity-icon";
import { useMemo } from "react";
import { embedEmoji, embedNostrHashtags, embedNostrLinks, embedNostrMentions } from "../../embed-types";
import { EmbedableContent } from "../../../helpers/embeds";
import Timestamp from "../../timestamp";
export default function EmbeddedUnknown({ event, ...props }: Omit<CardProps, "children"> & { event: NostrEvent }) {
const address = getSharableEventAddress(event);
@ -32,7 +32,7 @@ export default function EmbeddedUnknown({ event, ...props }: Omit<CardProps, "ch
<UserLink pubkey={event.pubkey} isTruncated fontWeight="bold" fontSize="md" />
<UserDnsIdentityIcon pubkey={event.pubkey} onlyIcon />
<Link ml="auto" href={address ? buildAppSelectUrl(address) : ""} isExternal>
{dayjs.unix(event.created_at).fromNow()}
<Timestamp timestamp={event.created_at} />
</Link>
</CardHeader>
<CardBody p="2">

View File

@ -1,5 +1,4 @@
import React, { useMemo, useRef } from "react";
import dayjs from "dayjs";
import {
Box,
ButtonGroup,
@ -38,6 +37,7 @@ import { useCurrentAccount } from "../../hooks/use-current-account";
import NoteReactions from "./components/note-reactions";
import ReplyForm from "../../views/note/components/reply-form";
import { getReferences } from "../../helpers/nostr/events";
import Timestamp from "../timestamp";
export type NoteProps = {
event: NostrEvent;
@ -72,7 +72,7 @@ export const Note = React.memo(({ event, variant = "outline", showReplyButton }:
<Flex grow={1} />
{showSignatureVerification && <EventVerificationIcon event={event} />}
<NoteLink noteId={event.id} whiteSpace="nowrap" color="current">
{dayjs.unix(event.created_at).fromNow()}
<Timestamp timestamp={event.created_at} />
</NoteLink>
</Flex>
</CardHeader>

View File

@ -15,12 +15,12 @@ import {
import { NostrEvent } from "../../types/nostr-event";
import { UserAvatarLink } from "../user-avatar-link";
import { UserLink } from "../user-link";
import dayjs from "dayjs";
import { DislikeIcon, LightningIcon, LikeIcon } from "../icons";
import { ParsedZap } from "../../helpers/zaps";
import { readablizeSats } from "../../helpers/bolt11";
import useEventReactions from "../../hooks/use-event-reactions";
import useEventZaps from "../../hooks/use-event-zaps";
import Timestamp from "../timestamp";
function getReactionIcon(content: string) {
switch (content) {
@ -41,7 +41,7 @@ const ReactionEvent = React.memo(({ event }: { event: NostrEvent }) => (
<UserLink pubkey={event.pubkey} />
</Flex>
<Text ml="auto" flexShrink={0}>
{dayjs.unix(event.created_at).fromNow()}
<Timestamp timestamp={event.created_at} />
</Text>
</Flex>
));

View File

@ -15,7 +15,6 @@ import {
Text,
} from "@chakra-ui/react";
import { Link as RouterLink } from "react-router-dom";
import dayjs from "dayjs";
import { NostrEvent } from "../../../types/nostr-event";
import { parseStreamEvent } from "../../../helpers/nostr/stream";
import useEventNaddr from "../../../hooks/use-event-naddr";
@ -26,6 +25,7 @@ import StreamStatusBadge from "../../../views/streams/components/status-badge";
import { EventRelays } from "../../note/note-relays";
import { useAsync } from "react-use";
import { getEventUID } from "../../../helpers/nostr/events";
import Timestamp from "../../timestamp";
export default function StreamNote({ event, ...props }: CardProps & { event: NostrEvent }) {
const { value: stream, error } = useAsync(async () => parseStreamEvent(event), [event]);
@ -64,7 +64,10 @@ export default function StreamNote({ event, ...props }: CardProps & { event: Nos
))}
</Flex>
)}
<Text>Updated: {dayjs.unix(stream.updated).fromNow()}</Text>
<Text>
Updated:
<Timestamp timestamp={stream.updated} />
</Text>
</LinkBox>
<Divider />
<CardFooter p="2" display="flex" gap="2" alignItems="center">

View File

@ -14,6 +14,7 @@ import {
Tr,
useColorMode,
} from "@chakra-ui/react";
import { TimelineLoader } from "../../../classes/timeline-loader";
import useSubject from "../../../hooks/use-subject";
import { getEventRelays, handleEventFromRelay } from "../../../services/event-relays";
@ -21,10 +22,10 @@ import { NostrEvent } from "../../../types/nostr-event";
import { useRegisterIntersectionEntity } from "../../../providers/intersection-observer";
import { RelayFavicon } from "../../relay-favicon";
import { NoteLink } from "../../note-link";
import dayjs from "dayjs";
import NostrPublishAction from "../../../classes/nostr-publish-action";
import { RelayIcon } from "../../icons";
import { getEventUID } from "../../../helpers/nostr/events";
import Timestamp from "../../timestamp";
function EventRow({
event,
@ -63,7 +64,7 @@ function EventRow({
return (
<Tr ref={ref} {...props}>
<Td isTruncated p="2">
{dayjs.unix(event.created_at).fromNow()}
<Timestamp timestamp={event.created_at} />
</Td>
<Td isTruncated p="2">
<NoteLink noteId={event.id} />

View File

@ -0,0 +1,11 @@
import dayjs from "dayjs";
import { Box, BoxProps } from "@chakra-ui/react";
export default function Timestamp({ timestamp, ...props }: { timestamp: number } & Omit<BoxProps, "children">) {
const date = dayjs.unix(timestamp);
return (
<Box as="time" dateTime={date.toISOString()} title={date.format("LLL")} {...props}>
{date.fromNow()}
</Box>
);
}

View File

@ -7,6 +7,8 @@ import { GlobalProviders } from "./providers";
import dayjs from "dayjs";
import relativeTimePlugin from "dayjs/plugin/relativeTime";
dayjs.extend(relativeTimePlugin);
import localizedFormat from "dayjs/plugin/localizedFormat";
dayjs.extend(localizedFormat);
// register nostr: protocol handler
if (import.meta.env.PROD) {

View File

@ -10,7 +10,6 @@ import { getBadgeDescription, getBadgeImage, getBadgeName } from "../../helpers/
import BadgeMenu from "./components/badge-menu";
import BadgeAwardCard from "./components/award-card";
import useTimelineLoader from "../../hooks/use-timeline-loader";
import { createCoordinate } from "../../services/replaceable-event-requester";
import { useReadRelayUrls } from "../../hooks/use-client-relays";
import IntersectionObserverProvider from "../../providers/intersection-observer";
import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";
@ -20,8 +19,8 @@ import { NostrEvent } from "../../types/nostr-event";
import { getEventCoordinate } from "../../helpers/nostr/events";
import { UserAvatarLink } from "../../components/user-avatar-link";
import { UserLink } from "../../components/user-link";
import dayjs from "dayjs";
import { ErrorBoundary } from "../../components/error-boundary";
import Timestamp from "../../components/timestamp";
function BadgeDetailsPage({ badge }: { badge: NostrEvent }) {
const navigate = useNavigate();
@ -77,7 +76,9 @@ function BadgeDetailsPage({ badge }: { badge: NostrEvent }) {
Created by: <UserAvatarLink pubkey={badge.pubkey} size="xs" />{" "}
<UserLink fontWeight="bold" pubkey={badge.pubkey} />
</Text>
<Text>Last Updated: {dayjs.unix(badge.created_at).fromNow()}</Text>
<Text>
Last Updated: <Timestamp timestamp={badge.created_at} />
</Text>
{description && <Text pb="2">{description}</Text>}
</Flex>
</Flex>

View File

@ -1,7 +1,6 @@
import { memo, useRef } from "react";
import { Link as RouterLink, useNavigate } from "react-router-dom";
import { ButtonGroup, Card, CardBody, CardHeader, CardProps, Flex, Heading, Image, Link, Text } from "@chakra-ui/react";
import dayjs from "dayjs";
import { UserAvatarLink } from "../../../components/user-avatar-link";
import { UserLink } from "../../../components/user-link";
@ -11,6 +10,7 @@ import { useRegisterIntersectionEntity } from "../../../providers/intersection-o
import { getEventUID } from "../../../helpers/nostr/events";
import BadgeMenu from "./badge-menu";
import { getBadgeImage, getBadgeName } from "../../../helpers/nostr/badges";
import Timestamp from "../../../components/timestamp";
function BadgeCard({ badge, ...props }: Omit<CardProps, "children"> & { badge: NostrEvent }) {
const naddr = getSharableEventAddress(badge);
@ -40,7 +40,9 @@ function BadgeCard({ badge, ...props }: Omit<CardProps, "children"> & { badge: N
<UserAvatarLink pubkey={badge.pubkey} size="xs" />
<UserLink pubkey={badge.pubkey} isTruncated fontWeight="bold" fontSize="lg" />
</Flex>
<Text>Updated: {dayjs.unix(badge.created_at).fromNow()}</Text>
<Text>
Updated: <Timestamp timestamp={badge.created_at} />
</Text>
</CardBody>
</Card>
);

View File

@ -13,7 +13,6 @@ import {
Link,
Text,
} from "@chakra-ui/react";
import dayjs from "dayjs";
import { UserAvatarLink } from "../../../components/user-avatar-link";
import { UserLink } from "../../../components/user-link";
@ -24,6 +23,7 @@ import EmojiPackFavoriteButton from "./emoji-pack-favorite-button";
import { getEventUID } from "../../../helpers/nostr/events";
import { getEmojisFromPack, getPackName } from "../../../helpers/nostr/emoji-packs";
import EmojiPackMenu from "./emoji-pack-menu";
import Timestamp from "../../../components/timestamp";
export default function EmojiPackCard({ pack, ...props }: Omit<CardProps, "children"> & { pack: NostrEvent }) {
const emojis = getEmojisFromPack(pack);
@ -59,7 +59,9 @@ export default function EmojiPackCard({ pack, ...props }: Omit<CardProps, "child
)}
</CardBody>
<CardFooter p="2" display="flex" pt="0">
<Text>Updated: {dayjs.unix(pack.created_at).fromNow()}</Text>
<Text>
Updated: <Timestamp timestamp={pack.created_at} />
</Text>
</CardFooter>
</Card>
);

View File

@ -15,6 +15,7 @@ import GoalContents from "./goal-contents";
import dayjs from "dayjs";
import GoalZapButton from "./goal-zap-button";
import GoalTopZappers from "./goal-top-zappers";
import Timestamp from "../../../components/timestamp";
function GoalCard({ goal, ...props }: Omit<CardProps, "children"> & { goal: NostrEvent }) {
const nevent = getSharableEventAddress(goal);
@ -41,7 +42,11 @@ function GoalCard({ goal, ...props }: Omit<CardProps, "children"> & { goal: Nost
</ButtonGroup>
</CardHeader>
<CardBody p="2" display="flex" gap="2" flexDirection="column">
{closed && <Text>Ends: {dayjs.unix(closed).fromNow()}</Text>}
{closed && (
<Text>
Ends: <Timestamp timestamp={closed} />
</Text>
)}
<GoalProgress goal={goal} />
<GoalContents goal={goal} />
<Flex gap="2" alignItems="flex-end" flex={1}>

View File

@ -7,7 +7,7 @@ import { UserAvatarLink } from "../../../components/user-avatar-link";
import { UserLink } from "../../../components/user-link";
import { readablizeSats } from "../../../helpers/bolt11";
import { LightningIcon } from "../../../components/icons";
import dayjs from "dayjs";
import Timestamp from "../../../components/timestamp";
export default function GoalZapList({ goal }: { goal: NostrEvent }) {
const zaps = useEventZaps(getEventUID(goal), getGoalRelays(goal), true);
@ -21,7 +21,7 @@ export default function GoalZapList({ goal }: { goal: NostrEvent }) {
<Box>
<Text>
<UserLink fontSize="lg" fontWeight="bold" pubkey={zap.request.pubkey} mr="2" />
<Text as="span">{dayjs.unix(zap.event.created_at).fromNow()}</Text>
<Timestamp timestamp={zap.event.created_at} />
</Text>
{zap.request.content && <Text>{zap.request.content}</Text>}
</Box>

View File

@ -13,7 +13,6 @@ import {
Link,
Text,
} from "@chakra-ui/react";
import dayjs from "dayjs";
import { UserAvatarLink } from "../../../components/user-avatar-link";
import { UserLink } from "../../../components/user-link";
@ -28,6 +27,7 @@ import { useRegisterIntersectionEntity } from "../../../providers/intersection-o
import ListFavoriteButton from "./list-favorite-button";
import { getEventUID } from "../../../helpers/nostr/events";
import ListMenu from "./list-menu";
import Timestamp from "../../../components/timestamp";
function ListCardRender({ event, ...props }: Omit<CardProps, "children"> & { event: NostrEvent }) {
const people = getPubkeysFromList(event);
@ -59,7 +59,9 @@ function ListCardRender({ event, ...props }: Omit<CardProps, "children"> & { eve
<UserAvatarLink pubkey={event.pubkey} size="xs" />
<UserLink pubkey={event.pubkey} isTruncated fontWeight="bold" fontSize="lg" />
</Flex>
<Text>Updated: {dayjs.unix(event.created_at).fromNow()}</Text>
<Text>
Updated: <Timestamp timestamp={event.created_at} />
</Text>
{people.length > 0 && (
<>
<Text>People ({people.length}):</Text>

View File

@ -24,6 +24,7 @@ import directMessagesService from "../../services/direct-messages";
import { ExternalLinkIcon } from "../../components/icons";
import RequireCurrentAccount from "../../providers/require-current-account";
import { nip19 } from "nostr-tools";
import Timestamp from "../../components/timestamp";
function ContactCard({ pubkey }: { pubkey: string }) {
const subject = useMemo(() => directMessagesService.getUserMessages(pubkey), [pubkey]);
@ -36,7 +37,7 @@ function ContactCard({ pubkey }: { pubkey: string }) {
<UserAvatar pubkey={pubkey} />
<Flex direction="column" gap="1" overflow="hidden" flex={1}>
<Text flex={1}>{getUserDisplayName(metadata, pubkey)}</Text>
{messages[0] && <Text flexShrink={0}>{dayjs.unix(messages[0].created_at).fromNow()}</Text>}
{messages[0] && <Timestamp flexShrink={0} timestamp={messages[0].created_at} />}
</Flex>
</CardBody>
<LinkOverlay as={RouterLink} to={`/dm/${nip19.npubEncode(pubkey)}`} />

View File

@ -1,16 +1,17 @@
import { useRef } from "react";
import { Box, Card, CardBody, CardHeader, CardProps, Flex, Heading, Text } from "@chakra-ui/react";
import dayjs from "dayjs";
import { useCurrentAccount } from "../../hooks/use-current-account";
import { getMessageRecipient } from "../../services/direct-messages";
import { NostrEvent } from "../../types/nostr-event";
import DecryptPlaceholder from "./decrypt-placeholder";
import { EmbedableContent, embedUrls } from "../../helpers/embeds";
import { embedNostrLinks, renderGenericUrl, renderImageUrl, renderVideoUrl } from "../../components/embed-types";
import { useRef } from "react";
import { useRegisterIntersectionEntity } from "../../providers/intersection-observer";
import { UserAvatar } from "../../components/user-avatar";
import { UserLink } from "../../components/user-link";
import { getEventUID } from "../../helpers/nostr/events";
import Timestamp from "../../components/timestamp";
export function MessageContent({ event, text }: { event: NostrEvent; text: string }) {
let content: EmbedableContent = [text];
@ -36,7 +37,7 @@ export function Message({ event }: { event: NostrEvent } & Omit<CardProps, "chil
<Heading size="md">
<UserLink pubkey={event.pubkey} />
</Heading>
<Text ml="auto">{dayjs.unix(event.created_at).fromNow()}</Text>
<Timestamp ml="auto" timestamp={event.created_at} />
</CardHeader>
<CardBody position="relative">
<DecryptPlaceholder

View File

@ -1,6 +1,5 @@
import { memo, useCallback, useMemo, useRef } from "react";
import { Card, CardBody, CardHeader, Flex, Text } from "@chakra-ui/react";
import dayjs from "dayjs";
import { Kind } from "nostr-tools";
import { UserAvatar } from "../../components/user-avatar";
@ -17,6 +16,7 @@ import { useNotificationTimeline } from "../../providers/notification-timeline";
import { parseZapEvent } from "../../helpers/zaps";
import { readablizeSats } from "../../helpers/bolt11";
import { getEventUID, getReferences } from "../../helpers/nostr/events";
import Timestamp from "../../components/timestamp";
const Kind1Notification = ({ event }: { event: NostrEvent }) => (
<Card size="sm" variant="outline">
@ -26,7 +26,7 @@ const Kind1Notification = ({ event }: { event: NostrEvent }) => (
<UserLink pubkey={event.pubkey} />
<Text>replied to your post</Text>
<NoteLink noteId={event.id} color="current" ml="auto">
{dayjs.unix(event.created_at).fromNow()}
<Timestamp timestamp={event.created_at} />
</NoteLink>
</Flex>
</CardHeader>
@ -45,7 +45,7 @@ const ReactionNotification = ({ event }: { event: NostrEvent }) => {
<UserLink pubkey={event.pubkey} />
<Text>reacted {event.content} to your post</Text>
<NoteLink noteId={refs.replyId || event.id} color="current" ml="auto">
{dayjs.unix(event.created_at).fromNow()}
<Timestamp timestamp={event.created_at} />
</NoteLink>
</Flex>
);
@ -81,9 +81,7 @@ const ZapNotification = ({ event }: { event: NostrEvent }) => {
</span>
)}
</Text>
<Text color="current" ml="auto">
{dayjs.unix(zap.request.created_at).fromNow()}
</Text>
<Timestamp color="current" ml="auto" timestamp={zap.request.created_at} />
</Flex>
);
};

View File

@ -1,6 +1,5 @@
import dayjs from "dayjs";
import { useRef } from "react";
import { Card, CardBody, CardHeader, Link, Text } from "@chakra-ui/react";
import { Card, CardBody, CardHeader, Link } from "@chakra-ui/react";
import { Link as RouterLink } from "react-router-dom";
import { UserAvatarLink } from "../../../components/user-avatar-link";
@ -13,6 +12,7 @@ import { useRegisterIntersectionEntity } from "../../../providers/intersection-o
import { NoteContents } from "../../../components/note/note-contents";
import { Metadata } from "./relay-card";
import { getEventUID } from "../../../helpers/nostr/events";
import Timestamp from "../../../components/timestamp";
export default function RelayReviewNote({ event, hideUrl }: { event: NostrEvent; hideUrl?: boolean }) {
const ratingJson = event.tags.find((t) => t[0] === "l" && t[3])?.[3];
@ -29,7 +29,7 @@ export default function RelayReviewNote({ event, hideUrl }: { event: NostrEvent;
<UserAvatarLink pubkey={event.pubkey} size="xs" />
<UserLink pubkey={event.pubkey} isTruncated fontWeight="bold" fontSize="lg" />
<UserDnsIdentityIcon pubkey={event.pubkey} onlyIcon />
<Text ml="auto">{dayjs.unix(event.created_at).fromNow()}</Text>
<Timestamp ml="auto" timestamp={event.created_at} />
</CardHeader>
<CardBody p="2">
{!hideUrl && url && (

View File

@ -1,5 +1,4 @@
import { memo, useRef } from "react";
import dayjs from "dayjs";
import { Box, Card, CardBody, CardProps, Flex, Heading, LinkBox, LinkOverlay, Text } from "@chakra-ui/react";
import { ParsedStream } from "../../../helpers/nostr/stream";
@ -11,6 +10,7 @@ import { useRegisterIntersectionEntity } from "../../../providers/intersection-o
import useEventNaddr from "../../../hooks/use-event-naddr";
import { getEventUID } from "../../../helpers/nostr/events";
import StreamHashtags from "./stream-hashtags";
import Timestamp from "../../../components/timestamp";
function StreamCard({ stream, ...props }: CardProps & { stream: ParsedStream }) {
const { title, image } = stream;
@ -49,7 +49,11 @@ function StreamCard({ stream, ...props }: CardProps & { stream: ParsedStream })
<StreamHashtags stream={stream} />
</Flex>
)}
{stream.starts && <Text>Started: {dayjs.unix(stream.starts).fromNow()}</Text>}
{stream.starts && (
<Text>
Started: <Timestamp timestamp={stream.starts} />
</Text>
)}
</LinkBox>
</Card>
);

View File

@ -1,5 +1,4 @@
import { useOutletContext, Link as RouterLink } from "react-router-dom";
import dayjs from "dayjs";
import {
Accordion,
AccordionButton,
@ -46,6 +45,7 @@ import { UserProfileMenu } from "./components/user-profile-menu";
import { useSharableProfileId } from "../../hooks/use-shareable-profile-id";
import useUserContactList from "../../hooks/use-user-contact-list";
import { getPubkeysFromList } from "../../helpers/nostr/lists";
import Timestamp from "../../components/timestamp";
function buildDescriptionContent(description: string) {
let content: EmbedableContent = [description.trim()];
@ -190,7 +190,11 @@ export default function UserAboutTab() {
<Stat>
<StatLabel>Following</StatLabel>
<StatNumber>{contacts ? readablizeSats(getPubkeysFromList(contacts).length) : "Unknown"}</StatNumber>
{contacts && <StatHelpText>Updated {dayjs.unix(contacts.created_at).fromNow()}</StatHelpText>}
{contacts && (
<StatHelpText>
Updated <Timestamp timestamp={contacts.created_at} />
</StatHelpText>
)}
</Stat>
{stats && (

View File

@ -2,6 +2,7 @@ import { Box, Flex, Select, Text } from "@chakra-ui/react";
import dayjs from "dayjs";
import { useCallback, useMemo, useRef, useState } from "react";
import { useOutletContext } from "react-router-dom";
import { ErrorBoundary, ErrorFallback } from "../../components/error-boundary";
import { LightningIcon } from "../../components/icons";
import { NoteLink } from "../../components/note-link";
@ -19,6 +20,7 @@ import IntersectionObserverProvider, { useRegisterIntersectionEntity } from "../
import { useTimelineCurserIntersectionCallback } from "../../hooks/use-timeline-cursor-intersection-callback";
import { EmbedableContent, embedUrls } from "../../helpers/embeds";
import { embedNostrLinks, renderGenericUrl } from "../../components/embed-types";
import Timestamp from "../../components/timestamp";
const Zap = ({ zapEvent }: { zapEvent: NostrEvent }) => {
const ref = useRef<HTMLDivElement | null>(null);
@ -55,7 +57,7 @@ const Zap = ({ zapEvent }: { zapEvent: NostrEvent }) => {
<Text>{readablizeSats(payment.amount / 1000)} sats</Text>
</Flex>
)}
<Text ml="auto">{dayjs.unix(request.created_at).fromNow()}</Text>
<Timestamp ml="auto" timestamp={request.created_at} />
</Flex>
{embedContent && <Box>{embedContent}</Box>}
</Box>