From 744422fc12050e09d3cb147c2affe5e95af2056b Mon Sep 17 00:00:00 2001 From: Innei Date: Tue, 6 Aug 2024 13:08:14 +0800 Subject: [PATCH] feat: dynamic update relative time Signed-off-by: Innei --- .../src/components/ui/datetime/index.tsx | 108 ++++++++++++++++-- .../src/modules/entry-column/date-item.tsx | 65 ++++++----- 2 files changed, 136 insertions(+), 37 deletions(-) diff --git a/src/renderer/src/components/ui/datetime/index.tsx b/src/renderer/src/components/ui/datetime/index.tsx index 4ab2cd89b..02b48298f 100644 --- a/src/renderer/src/components/ui/datetime/index.tsx +++ b/src/renderer/src/components/ui/datetime/index.tsx @@ -1,8 +1,13 @@ import dayjs from "dayjs" import type { FC } from "react" -import { useEffect, useState } from "react" +import { useEffect, useRef, useState } from "react" -import { Tooltip, TooltipContent, TooltipPortal, TooltipTrigger } from "../tooltip" +import { + Tooltip, + TooltipContent, + TooltipPortal, + TooltipTrigger, +} from "../tooltip" const formatTime = (date: string | Date, relativeBeforeDay?: number) => { if ( @@ -15,23 +20,56 @@ const formatTime = (date: string | Date, relativeBeforeDay?: number) => { .duration(dayjs(date).diff(dayjs(), "minute"), "minute") .humanize() } + +const getUpdateInterval = (date: string | Date, relativeBeforeDay?: number) => { + if (!relativeBeforeDay) return null + const diffInSeconds = Math.abs(dayjs(date).diff(new Date(), "second")) + if (diffInSeconds <= 60) { + return 1000 // Update every second + } + const diffInMinutes = Math.abs(dayjs(date).diff(new Date(), "minute")) + if (diffInMinutes <= 60) { + return 60000 // Update every minute + } + const diffInHours = Math.abs(dayjs(date).diff(new Date(), "hour")) + if (diffInHours <= 24) { + return 3600000 // Update every hour + } + const diffInDays = Math.abs(dayjs(date).diff(new Date(), "day")) + if (diffInDays <= relativeBeforeDay) { + return 86400000 // Update every day + } + return null // No need to update +} + export const RelativeTime: FC<{ date: string | Date displayAbsoluteTimeAfterDay?: number }> = (props) => { const { displayAbsoluteTimeAfterDay = 29 } = props - const [relative, setRelative] = useState( + const [relative, setRelative] = useState(() => formatTime(props.date, displayAbsoluteTimeAfterDay), ) + const timerRef = useRef(null) + useEffect(() => { - setRelative(formatTime(props.date, displayAbsoluteTimeAfterDay)) - let timer: any = setInterval(() => { + const updateRelativeTime = () => { setRelative(formatTime(props.date, displayAbsoluteTimeAfterDay)) - }, 1000) + const updateInterval = getUpdateInterval( + props.date, + displayAbsoluteTimeAfterDay, + ) + + if (updateInterval !== null) { + timerRef.current = setTimeout(updateRelativeTime, updateInterval) + } + } + + updateRelativeTime() return () => { - timer = clearInterval(timer) + clearTimeout(timerRef.current) } }, [props.date, displayAbsoluteTimeAfterDay]) @@ -45,3 +83,59 @@ export const RelativeTime: FC<{ ) } + +export const RelativeDay = ({ date }: { date: Date }) => { + const formatDateString = (date: Date) => { + const now = new Date() + + // Remove the time part for comparison + const nowDate = new Date(now.getFullYear(), now.getMonth(), now.getDate()) + const inputDate = new Date( + date.getFullYear(), + date.getMonth(), + date.getDate(), + ) + + const diffTime = nowDate.getTime() - inputDate.getTime() + const diffDays = diffTime / (1000 * 3600 * 24) + + if (diffDays === 0) { + return "Today" + } else if (diffDays === 1) { + return "Yesterday" + } else { + return date.toLocaleDateString("en-US", { + weekday: "long", + month: "short", + day: "numeric", + }) + } + } + const timerRef = useRef(null) + const [dateString, setDateString] = useState(() => + formatDateString(date), + ) + + useEffect(() => { + const updateInterval = getUpdateInterval(date, 3) + + if (updateInterval !== null) { + timerRef.current = setTimeout(() => { + setDateString(formatDateString(date)) + }, updateInterval) + } + + return () => { + clearTimeout(timerRef.current) + } + }, [date]) + + return ( + + {dateString} + + {dayjs(date).format("llll")} + + + ) +} diff --git a/src/renderer/src/modules/entry-column/date-item.tsx b/src/renderer/src/modules/entry-column/date-item.tsx index 0b41ab618..40ce49ae6 100644 --- a/src/renderer/src/modules/entry-column/date-item.tsx +++ b/src/renderer/src/modules/entry-column/date-item.tsx @@ -1,3 +1,4 @@ +import { RelativeDay } from "@renderer/components/ui/datetime" import { FeedViewType } from "@renderer/lib/enum" import { cn } from "@renderer/lib/utils" import { memo } from "react" @@ -5,37 +6,41 @@ import { memo } from "react" import { MarkAllButton } from "./mark-all-button" import { SocialMediaDateItem } from "./social-media-item" -export const DateItem = memo(({ - date, - view, - isFirst, -}: { - date: string - view: FeedViewType - isFirst: boolean -}) => { - const dateObj = new Date(date) - const dateString = dateObj.toLocaleDateString("en-US", { weekday: "long", month: "short", day: "numeric" }) - const startOfDay = new Date(dateObj.setHours(0, 0, 0, 0)).getTime() - const endOfDay = new Date(dateObj.setHours(23, 59, 59, 999)).getTime() +export const DateItem = memo( + ({ + date, + view, + isFirst, + }: { + date: string + view: FeedViewType + isFirst: boolean + }) => { + const dateObj = new Date(date) - const className = cn(isFirst ? "pt-2" : "pt-8", "flex items-center gap-1 pl-2 text-sm font-bold text-zinc-800 dark:text-neutral-400") + const startOfDay = new Date(dateObj.setHours(0, 0, 0, 0)).getTime() + const endOfDay = new Date(dateObj.setHours(23, 59, 59, 999)).getTime() - if (view === FeedViewType.SocialMedia) { - return - } + const className = cn( + isFirst ? "pt-2" : "pt-8", + "flex items-center gap-1 pl-2 text-sm font-bold text-zinc-800 dark:text-neutral-400", + ) - return ( -
- - {dateString} -
- ) -}, + if (view === FeedViewType.SocialMedia) { + return + } + + return ( +
+ + +
+ ) + }, )