| 1 | "use client"; |
| 2 | |
| 3 | import { useEffect, useState } from "react"; |
| 4 | import { cn } from "@/lib/utils"; |
| 5 | |
| 6 | function compact(from: number, now: number): string { |
| 7 | const secs = Math.max(0, Math.round((now - from) / 1000)); |
| 8 | if (secs < 60) return `${secs}s`; |
| 9 | const mins = Math.round(secs / 60); |
| 10 | if (mins < 60) return `${mins}m`; |
| 11 | const hrs = Math.round(mins / 60); |
| 12 | if (hrs < 24) return `${hrs}h`; |
| 13 | return `${Math.round(hrs / 24)}d`; |
| 14 | } |
| 15 | |
| 16 | export function RelativeTime({ iso, className }: { iso: string; className?: string }) { |
| 17 | const from = new Date(iso).getTime(); |
| 18 | const [now, setNow] = useState<number>(() => from); |
| 19 | |
| 20 | useEffect(() => { |
| 21 | setNow(Date.now()); |
| 22 | const id = window.setInterval(() => setNow(Date.now()), 1000); |
| 23 | return () => window.clearInterval(id); |
| 24 | }, []); |
| 25 | |
| 26 | const ago = compact(from, now); |
| 27 | return ( |
| 28 | <time |
| 29 | dateTime={iso} |
| 30 | title={new Date(iso).toLocaleString()} |
| 31 | className={cn("tabular font-mono text-[var(--color-fg-tertiary)]", className)} |
| 32 | > |
| 33 | {ago} ago |
| 34 | </time> |
| 35 | ); |
| 36 | } |