From b14ba1725612ee5ddaa40626c4fcd32212f0cc7f Mon Sep 17 00:00:00 2001
From: tusooa <tusooa@kazv.moe>
Date: Sat, 14 Sep 2024 00:00:18 -0400
Subject: Support displaying time in absolute format

This adds two config items: useAbsoluteTimeFormat (boolean) and
absoluteTimeFormatMinAge (string, number + unit ('d'|'h'|'m'|'s')).

When `useAbsoluteTimeFormat` is true, the Timeago component will display
absolute time if the time is at least `absoluteTimeFormatMinAge`
from now. If `longFormat` prop is true, the fully formatted time
is displayed. Otherwise, the format is determined by the `time` prop:
(1) if `time` is on the same day of now, display hour and minute;
(2) if `time` is in the same month of now, display day and hour;
(3) if `time` is in the same year of now, display month and day;
(4) otherwise, display year and month.

If it should display relative time, the format is the same as before.
---
 src/components/timeago/timeago.vue | 57 ++++++++++++++++++++++++++++++++++----
 1 file changed, 52 insertions(+), 5 deletions(-)

(limited to 'src/components/timeago/timeago.vue')

diff --git a/src/components/timeago/timeago.vue b/src/components/timeago/timeago.vue
index b5f49515..bf918441 100644
--- a/src/components/timeago/timeago.vue
+++ b/src/components/timeago/timeago.vue
@@ -3,7 +3,7 @@
     :datetime="time"
     :title="localeDateString"
   >
-    {{ relativeTimeString }}
+    {{ relativeOrAbsoluteTimeString }}
   </time>
 </template>
 
@@ -16,16 +16,28 @@ export default {
   props: ['time', 'autoUpdate', 'longFormat', 'nowThreshold', 'templateKey'],
   data () {
     return {
+      relativeTimeMs: 0,
       relativeTime: { key: 'time.now', num: 0 },
       interval: null
     }
   },
   computed: {
-    localeDateString () {
-      const browserLocale = localeService.internalToBrowserLocale(this.$i18n.locale)
+    shouldUseAbsoluteTimeFormat () {
+      if (!this.$store.getters.mergedConfig.useAbsoluteTimeFormat) {
+        return false
+      }
+      return DateUtils.durationStrToMs(this.$store.getters.mergedConfig.absoluteTimeFormatMinAge) <= this.relativeTimeMs
+    },
+    browserLocale () {
+      return localeService.internalToBrowserLocale(this.$i18n.locale)
+    },
+    timeAsDate () {
       return typeof this.time === 'string'
-        ? new Date(Date.parse(this.time)).toLocaleString(browserLocale)
-        : this.time.toLocaleString(browserLocale)
+        ? new Date(Date.parse(this.time))
+        : this.time
+    },
+    localeDateString () {
+      return this.timeAsDate.toLocaleString(this.browserLocale)
     },
     relativeTimeString () {
       const timeString = this.$i18n.tc(this.relativeTime.key, this.relativeTime.num, [this.relativeTime.num])
@@ -35,6 +47,40 @@ export default {
       }
 
       return timeString
+    },
+    absoluteTimeString () {
+      if (this.longFormat) {
+        return this.localeDateString
+      }
+      const now = new Date()
+      const formatter = (() => {
+        if (DateUtils.isSameDay(this.timeAsDate, now)) {
+          return new Intl.DateTimeFormat(this.browserLocale, {
+            minute: 'numeric',
+            hour: 'numeric'
+          })
+        } else if (DateUtils.isSameMonth(this.timeAsDate, now)) {
+          return new Intl.DateTimeFormat(this.browserLocale, {
+            hour: 'numeric',
+            day: 'numeric'
+          })
+        } else if (DateUtils.isSameYear(this.timeAsDate, now)) {
+          return new Intl.DateTimeFormat(this.browserLocale, {
+            month: 'short',
+            day: 'numeric'
+          })
+        } else {
+          return new Intl.DateTimeFormat(this.browserLocale, {
+            year: 'numeric',
+            month: 'short'
+          })
+        }
+      })()
+
+      return formatter.format(this.timeAsDate)
+    },
+    relativeOrAbsoluteTimeString () {
+      return this.shouldUseAbsoluteTimeFormat ? this.absoluteTimeString : this.relativeTimeString
     }
   },
   watch: {
@@ -54,6 +100,7 @@ export default {
   methods: {
     refreshRelativeTimeObject () {
       const nowThreshold = typeof this.nowThreshold === 'number' ? this.nowThreshold : 1
+      this.relativeTimeMs = DateUtils.relativeTimeMs(this.time)
       this.relativeTime = this.longFormat
         ? DateUtils.relativeTime(this.time, nowThreshold)
         : DateUtils.relativeTimeShort(this.time, nowThreshold)
-- 
cgit v1.2.3-70-g09d2

