relative-time.jsx
1 // Twitter-style relative time component 2 // Seconds = 1s 3 // Minutes = 1m 4 // Hours = 1h 5 // Days = 1d 6 // After 7 days, use DD/MM/YYYY or MM/DD/YYYY 7 import dayjs from 'dayjs'; 8 import dayjsTwitter from 'dayjs-twitter'; 9 import localizedFormat from 'dayjs/plugin/localizedFormat'; 10 import relativeTime from 'dayjs/plugin/relativeTime'; 11 import { useEffect, useState } from 'preact/hooks'; 12 13 dayjs.extend(dayjsTwitter); 14 dayjs.extend(localizedFormat); 15 dayjs.extend(relativeTime); 16 17 const dtf = new Intl.DateTimeFormat(); 18 19 export default function RelativeTime({ datetime, format }) { 20 if (!datetime) return null; 21 const date = dayjs(datetime); 22 const [dateStr, setDateStr] = useState(''); 23 24 useEffect(() => { 25 let timer, raf; 26 const update = () => { 27 raf = requestAnimationFrame(() => { 28 let str; 29 if (format === 'micro') { 30 // If date <= 1 day ago or day is within this year 31 const now = dayjs(); 32 const dayDiff = now.diff(date, 'day'); 33 if (dayDiff <= 1 || now.year() === date.year()) { 34 str = date.twitter(); 35 } else { 36 str = dtf.format(date.toDate()); 37 } 38 } else { 39 str = date.fromNow(); 40 } 41 setDateStr(str); 42 43 timer = setTimeout(update, 30_000); 44 }); 45 }; 46 raf = requestAnimationFrame(update); 47 return () => { 48 clearTimeout(timer); 49 cancelAnimationFrame(raf); 50 }; 51 }, [date]); 52 53 return ( 54 <time datetime={date.toISOString()} title={date.format('LLLL')}> 55 {dateStr} 56 </time> 57 ); 58 }