Ver código fonte

Merge branch 'tusooa/date-absolute' into 'develop'

Support displaying time in absolute format

See merge request pleroma/pleroma-fe!1938
HJ 2 meses atrás
pai
commit
537145e934

+ 1 - 0
changelog.d/date-absolute.add

@@ -0,0 +1 @@
+Support displaying time in absolute format

+ 23 - 0
src/components/settings_modal/tabs/general_tab.vue

@@ -217,6 +217,29 @@
             {{ $t('settings.no_rich_text_description') }}
           </BooleanSetting>
         </li>
+        <li>
+          <BooleanSetting
+            path="useAbsoluteTimeFormat"
+            expert="1"
+          >
+            {{ $t('settings.absolute_time_format') }}
+          </BooleanSetting>
+        </li>
+        <ul
+          class="setting-list suboptions"
+          v-if="mergedConfig.useAbsoluteTimeFormat"
+        >
+          <li>
+            <UnitSetting
+              path="absoluteTimeFormatMinAge"
+              unit-set="time"
+              :units="['s', 'm', 'h', 'd']"
+              :min="0"
+            >
+              {{ $t('settings.absolute_time_format_min_age') }}
+            </UnitSetting>
+          </li>
+        </ul>
         <h3>{{ $t('settings.attachments') }}</h3>
         <li>
           <BooleanSetting

+ 52 - 5
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)

+ 2 - 0
src/i18n/en.json

@@ -506,6 +506,8 @@
     "autocomplete_select_first": "Automatically select the first candidate when autocomplete results are available",
     "emoji_reactions_on_timeline": "Show emoji reactions on timeline",
     "emoji_reactions_scale": "Reactions scale factor",
+    "absolute_time_format": "Use absolute time format",
+    "absolute_time_format_min_age": "Only use for time older than this amount of time",
     "export_theme": "Save preset",
     "filtering": "Filtering",
     "wordfilter": "Wordfilter",

+ 3 - 1
src/modules/config.js

@@ -180,7 +180,9 @@ export const defaultState = {
   autocompleteSelect: undefined, // instance default
   closingDrawerMarksAsSeen: undefined, // instance default
   unseenAtTop: undefined, // instance default
-  ignoreInactionableSeen: undefined // instance default
+  ignoreInactionableSeen: undefined, // instance default
+  useAbsoluteTimeFormat: undefined, // instance defualt
+  absoluteTimeFormatMinAge: undefined // instance default
 }
 
 // caching the instance default properties

+ 2 - 0
src/modules/instance.js

@@ -119,6 +119,8 @@ const defaultState = {
   closingDrawerMarksAsSeen: true,
   unseenAtTop: false,
   ignoreInactionableSeen: false,
+  useAbsoluteTimeFormat: false,
+  absoluteTimeFormatMinAge: '0d',
 
   // Nasty stuff
   customEmoji: [],

+ 41 - 2
src/services/date_utils/date_utils.js

@@ -6,10 +6,13 @@ export const WEEK = 7 * DAY
 export const MONTH = 30 * DAY
 export const YEAR = 365.25 * DAY
 
-export const relativeTime = (date, nowThreshold = 1) => {
+export const relativeTimeMs = (date) => {
   if (typeof date === 'string') date = Date.parse(date)
+  return Math.abs(Date.now() - date)
+}
+export const relativeTime = (date, nowThreshold = 1) => {
   const round = Date.now() > date ? Math.floor : Math.ceil
-  const d = Math.abs(Date.now() - date)
+  const d = relativeTimeMs(date)
   const r = { num: round(d / YEAR), key: 'time.unit.years' }
   if (d < nowThreshold * SECOND) {
     r.num = 0
@@ -57,3 +60,39 @@ export const secondsToUnit = (unit, amount) => {
     case 'days': return (1000 * amount) / DAY
   }
 }
+
+export const isSameYear = (a, b) => {
+  return a.getFullYear() === b.getFullYear()
+}
+
+export const isSameMonth = (a, b) => {
+  return a.getFullYear() === b.getFullYear() &&
+    a.getMonth() === b.getMonth()
+}
+
+export const isSameDay = (a, b) => {
+  return a.getFullYear() === b.getFullYear() &&
+    a.getMonth() === b.getMonth() &&
+    a.getDate() === b.getDate()
+}
+
+export const durationStrToMs = (str) => {
+  if (typeof str !== 'string') {
+    return 0
+  }
+
+  const unit = str.replace(/[0-9,.]+/, '')
+  const value = str.replace(/[^0-9,.]+/, '')
+  switch (unit) {
+    case 'd':
+      return value * DAY
+    case 'h':
+      return value * HOUR
+    case 'm':
+      return value * MINUTE
+    case 's':
+      return value * SECOND
+    default:
+      return 0
+  }
+}