From b24b3802b338bb1b37b26dadc07528e82c860a7c Mon Sep 17 00:00:00 2001 From: highperfocused Date: Tue, 27 May 2025 12:28:43 +0200 Subject: [PATCH] feat: add relative time formatting for createdAt in KIND20Card and NoteCard components --- components/KIND20Card.tsx | 46 ++++++++++++++++++++++++--- components/NoteCard.tsx | 24 ++++++++++++-- utils/dateUtils.ts | 67 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 131 insertions(+), 6 deletions(-) create mode 100644 utils/dateUtils.ts diff --git a/components/KIND20Card.tsx b/components/KIND20Card.tsx index 350b8c5..e76acb2 100644 --- a/components/KIND20Card.tsx +++ b/components/KIND20Card.tsx @@ -15,6 +15,8 @@ import Image from "next/image" import CardOptionsDropdown from "./CardOptionsDropdown" import { renderTextWithLinkedTags } from "@/utils/textUtils" import { getProxiedImageUrl } from "@/utils/utils" +import { formatRelativeTime } from "@/utils/dateUtils" +import { Clock, UploadCloud } from "lucide-react" // Function to extract all images from a kind 20 event's imeta tags const extractImagesFromEvent = (tags: string[][]): string[] => { @@ -197,11 +199,47 @@ const KIND20Card: React.FC = ({ - -
- {createdAt.toLocaleString()} - {uploadedVia && Uploaded via {uploadedVia}} + +
+
+ + {formatRelativeTime(createdAt)} +
+ + {uploadedVia && ( +
+ {/* + + */} + + via {uploadedVia} +
+ )}
+ + + + +
+ {createdAt.toLocaleString()} +
+
+ +

Full timestamp

+
+
+
diff --git a/components/NoteCard.tsx b/components/NoteCard.tsx index e47bb28..b3e40fc 100644 --- a/components/NoteCard.tsx +++ b/components/NoteCard.tsx @@ -31,6 +31,8 @@ import { Event as NostrEvent } from "nostr-tools"; import ZapButton from './ZapButton'; import CardOptionsDropdown from './CardOptionsDropdown'; import { renderTextWithLinkedTags } from '@/utils/textUtils'; +import { Clock } from 'lucide-react'; +import { formatRelativeTime } from '@/utils/dateUtils'; interface NoteCardProps { pubkey: string; @@ -155,8 +157,26 @@ const NoteCard: React.FC = ({ pubkey, text, eventId, tags, event, - - {createdAt.toLocaleString()} + +
+
+ + {formatRelativeTime(createdAt)} +
+
+ + + + +
+ {createdAt.toLocaleString()} +
+
+ +

Full timestamp

+
+
+
diff --git a/utils/dateUtils.ts b/utils/dateUtils.ts new file mode 100644 index 0000000..2d9d73a --- /dev/null +++ b/utils/dateUtils.ts @@ -0,0 +1,67 @@ +/** + * Formats a date into a readable format + * + * Examples: + * - Just now (less than 1 minute ago) + * - 5 minutes ago + * - 2 hours ago + * - Yesterday at 2:30 PM + * - May 25 at 3:45 PM + * - May 25, 2024 at 3:45 PM (if not current year) + */ +export function formatRelativeTime(date: Date): string { + const now = new Date(); + const diffInSeconds = Math.floor((now.getTime() - date.getTime()) / 1000); + + // Just now - less than 1 minute + if (diffInSeconds < 60) { + return 'Just now'; + } + + // Minutes ago - less than 1 hour + if (diffInSeconds < 3600) { + const minutes = Math.floor(diffInSeconds / 60); + return `${minutes} ${minutes === 1 ? 'minute' : 'minutes'} ago`; + } + + // Hours ago - less than 24 hours + if (diffInSeconds < 86400) { + const hours = Math.floor(diffInSeconds / 3600); + return `${hours} ${hours === 1 ? 'hour' : 'hours'} ago`; + } + + // Format the time part (e.g., "3:45 PM") + const timeFormatted = date.toLocaleTimeString([], { + hour: 'numeric', + minute: '2-digit', + hour12: true + }); + + // Yesterday - less than 48 hours, but different calendar day + if (diffInSeconds < 172800 && + date.getDate() === now.getDate() - 1 && + date.getMonth() === now.getMonth() && + date.getFullYear() === now.getFullYear()) { + return `Yesterday at ${timeFormatted}`; + } + + // Format the date part + const isCurrentYear = date.getFullYear() === now.getFullYear(); + + if (isCurrentYear) { + // Same year - show month and day (e.g., "May 25 at 3:45 PM") + const dateFormatted = date.toLocaleDateString([], { + month: 'short', + day: 'numeric' + }); + return `${dateFormatted} at ${timeFormatted}`; + } else { + // Different year - show full date (e.g., "May 25, 2024 at 3:45 PM") + const dateFormatted = date.toLocaleDateString([], { + month: 'short', + day: 'numeric', + year: 'numeric' + }); + return `${dateFormatted} at ${timeFormatted}`; + } +}