found the file lol
This commit is contained in:
commit
bd514ab6d0
7
.browserslistrc
Normal file
7
.browserslistrc
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
>0.2%
|
||||||
|
not op_mini all
|
||||||
|
Safari > 15
|
||||||
|
Firefox >= 115
|
||||||
|
Firefox ESR
|
||||||
|
Android > 4
|
||||||
|
not dead
|
|
@ -45,6 +45,7 @@ test:
|
||||||
stage: test
|
stage: test
|
||||||
tags:
|
tags:
|
||||||
- amd64
|
- amd64
|
||||||
|
- himem
|
||||||
variables:
|
variables:
|
||||||
APT_CACHE_DIR: apt-cache
|
APT_CACHE_DIR: apt-cache
|
||||||
script:
|
script:
|
||||||
|
@ -58,6 +59,7 @@ build:
|
||||||
stage: build
|
stage: build
|
||||||
tags:
|
tags:
|
||||||
- amd64
|
- amd64
|
||||||
|
- himem
|
||||||
script:
|
script:
|
||||||
- yarn
|
- yarn
|
||||||
- npm run build
|
- npm run build
|
||||||
|
|
9
changelog.d/browsers-support.change
Normal file
9
changelog.d/browsers-support.change
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
Updated our build system to support browsers:
|
||||||
|
Safari >= 15
|
||||||
|
Firefox >= 115
|
||||||
|
Android > 4
|
||||||
|
no Opera Mini support
|
||||||
|
no IE support
|
||||||
|
no "dead" (unmaintained) browsers support
|
||||||
|
|
||||||
|
This does not guarantee that browsers will or will not work.
|
1
changelog.d/date-absolute.add
Normal file
1
changelog.d/date-absolute.add
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Support displaying time in absolute format
|
|
@ -217,6 +217,29 @@
|
||||||
{{ $t('settings.no_rich_text_description') }}
|
{{ $t('settings.no_rich_text_description') }}
|
||||||
</BooleanSetting>
|
</BooleanSetting>
|
||||||
</li>
|
</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>
|
<h3>{{ $t('settings.attachments') }}</h3>
|
||||||
<li>
|
<li>
|
||||||
<BooleanSetting
|
<BooleanSetting
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
:datetime="time"
|
:datetime="time"
|
||||||
:title="localeDateString"
|
:title="localeDateString"
|
||||||
>
|
>
|
||||||
{{ relativeTimeString }}
|
{{ relativeOrAbsoluteTimeString }}
|
||||||
</time>
|
</time>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -16,16 +16,28 @@ export default {
|
||||||
props: ['time', 'autoUpdate', 'longFormat', 'nowThreshold', 'templateKey'],
|
props: ['time', 'autoUpdate', 'longFormat', 'nowThreshold', 'templateKey'],
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
|
relativeTimeMs: 0,
|
||||||
relativeTime: { key: 'time.now', num: 0 },
|
relativeTime: { key: 'time.now', num: 0 },
|
||||||
interval: null
|
interval: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
localeDateString () {
|
shouldUseAbsoluteTimeFormat () {
|
||||||
const browserLocale = localeService.internalToBrowserLocale(this.$i18n.locale)
|
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'
|
return typeof this.time === 'string'
|
||||||
? new Date(Date.parse(this.time)).toLocaleString(browserLocale)
|
? new Date(Date.parse(this.time))
|
||||||
: this.time.toLocaleString(browserLocale)
|
: this.time
|
||||||
|
},
|
||||||
|
localeDateString () {
|
||||||
|
return this.timeAsDate.toLocaleString(this.browserLocale)
|
||||||
},
|
},
|
||||||
relativeTimeString () {
|
relativeTimeString () {
|
||||||
const timeString = this.$i18n.tc(this.relativeTime.key, this.relativeTime.num, [this.relativeTime.num])
|
const timeString = this.$i18n.tc(this.relativeTime.key, this.relativeTime.num, [this.relativeTime.num])
|
||||||
|
@ -35,6 +47,40 @@ export default {
|
||||||
}
|
}
|
||||||
|
|
||||||
return timeString
|
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: {
|
watch: {
|
||||||
|
@ -54,6 +100,7 @@ export default {
|
||||||
methods: {
|
methods: {
|
||||||
refreshRelativeTimeObject () {
|
refreshRelativeTimeObject () {
|
||||||
const nowThreshold = typeof this.nowThreshold === 'number' ? this.nowThreshold : 1
|
const nowThreshold = typeof this.nowThreshold === 'number' ? this.nowThreshold : 1
|
||||||
|
this.relativeTimeMs = DateUtils.relativeTimeMs(this.time)
|
||||||
this.relativeTime = this.longFormat
|
this.relativeTime = this.longFormat
|
||||||
? DateUtils.relativeTime(this.time, nowThreshold)
|
? DateUtils.relativeTime(this.time, nowThreshold)
|
||||||
: DateUtils.relativeTimeShort(this.time, nowThreshold)
|
: DateUtils.relativeTimeShort(this.time, nowThreshold)
|
||||||
|
|
|
@ -506,6 +506,8 @@
|
||||||
"autocomplete_select_first": "Automatically select the first candidate when autocomplete results are available",
|
"autocomplete_select_first": "Automatically select the first candidate when autocomplete results are available",
|
||||||
"emoji_reactions_on_timeline": "Show emoji reactions on timeline",
|
"emoji_reactions_on_timeline": "Show emoji reactions on timeline",
|
||||||
"emoji_reactions_scale": "Reactions scale factor",
|
"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",
|
"export_theme": "Save preset",
|
||||||
"filtering": "Filtering",
|
"filtering": "Filtering",
|
||||||
"wordfilter": "Wordfilter",
|
"wordfilter": "Wordfilter",
|
||||||
|
|
|
@ -180,7 +180,9 @@ export const defaultState = {
|
||||||
autocompleteSelect: undefined, // instance default
|
autocompleteSelect: undefined, // instance default
|
||||||
closingDrawerMarksAsSeen: undefined, // instance default
|
closingDrawerMarksAsSeen: undefined, // instance default
|
||||||
unseenAtTop: 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
|
// caching the instance default properties
|
||||||
|
|
|
@ -119,6 +119,8 @@ const defaultState = {
|
||||||
closingDrawerMarksAsSeen: true,
|
closingDrawerMarksAsSeen: true,
|
||||||
unseenAtTop: false,
|
unseenAtTop: false,
|
||||||
ignoreInactionableSeen: false,
|
ignoreInactionableSeen: false,
|
||||||
|
useAbsoluteTimeFormat: false,
|
||||||
|
absoluteTimeFormatMinAge: '0d',
|
||||||
|
|
||||||
// Nasty stuff
|
// Nasty stuff
|
||||||
customEmoji: [],
|
customEmoji: [],
|
||||||
|
|
|
@ -6,10 +6,13 @@ export const WEEK = 7 * DAY
|
||||||
export const MONTH = 30 * DAY
|
export const MONTH = 30 * DAY
|
||||||
export const YEAR = 365.25 * 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)
|
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 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' }
|
const r = { num: round(d / YEAR), key: 'time.unit.years' }
|
||||||
if (d < nowThreshold * SECOND) {
|
if (d < nowThreshold * SECOND) {
|
||||||
r.num = 0
|
r.num = 0
|
||||||
|
@ -57,3 +60,39 @@ export const secondsToUnit = (unit, amount) => {
|
||||||
case 'days': return (1000 * amount) / DAY
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
28
yarn.lock
28
yarn.lock
|
@ -3144,30 +3144,10 @@ caniuse-api@^3.0.0:
|
||||||
lodash.memoize "^4.1.2"
|
lodash.memoize "^4.1.2"
|
||||||
lodash.uniq "^4.5.0"
|
lodash.uniq "^4.5.0"
|
||||||
|
|
||||||
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001370:
|
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001359, caniuse-lite@^1.0.30001370, caniuse-lite@^1.0.30001400, caniuse-lite@^1.0.30001587, caniuse-lite@^1.0.30001599:
|
||||||
version "1.0.30001376"
|
version "1.0.30001662"
|
||||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001376.tgz#af2450833e5a06873fbb030a9556ca9461a2736d"
|
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001662.tgz"
|
||||||
integrity sha512-I27WhtOQ3X3v3it9gNs/oTpoE5KpwmqKR5oKPA8M0G7uMXh9Ty81Q904HpKUrM30ei7zfcL5jE7AXefgbOfMig==
|
integrity sha512-sgMUVwLmGseH8ZIrm1d51UbrhqMCH3jvS7gF/M6byuHOnKyLOBL7W8yz5V02OHwgLGA36o/AFhWzzh4uc5aqTA==
|
||||||
|
|
||||||
caniuse-lite@^1.0.30001359:
|
|
||||||
version "1.0.30001366"
|
|
||||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001366.tgz#c73352c83830a9eaf2dea0ff71fb4b9a4bbaa89c"
|
|
||||||
integrity sha512-yy7XLWCubDobokgzudpkKux8e0UOOnLHE6mlNJBzT3lZJz6s5atSEzjoL+fsCPkI0G8MP5uVdDx1ur/fXEWkZA==
|
|
||||||
|
|
||||||
caniuse-lite@^1.0.30001400:
|
|
||||||
version "1.0.30001418"
|
|
||||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001418.tgz#5f459215192a024c99e3e3a53aac310fc7cf24e6"
|
|
||||||
integrity sha512-oIs7+JL3K9JRQ3jPZjlH6qyYDp+nBTCais7hjh0s+fuBwufc7uZ7hPYMXrDOJhV360KGMTcczMRObk0/iMqZRg==
|
|
||||||
|
|
||||||
caniuse-lite@^1.0.30001587:
|
|
||||||
version "1.0.30001591"
|
|
||||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001591.tgz#16745e50263edc9f395895a7cd468b9f3767cf33"
|
|
||||||
integrity sha512-PCzRMei/vXjJyL5mJtzNiUCKP59dm8Apqc3PH8gJkMnMXZGox93RbE76jHsmLwmIo6/3nsYIpJtx0O7u5PqFuQ==
|
|
||||||
|
|
||||||
caniuse-lite@^1.0.30001599:
|
|
||||||
version "1.0.30001599"
|
|
||||||
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001599.tgz#571cf4f3f1506df9bf41fcbb6d10d5d017817bce"
|
|
||||||
integrity sha512-LRAQHZ4yT1+f9LemSMeqdMpMxZcc4RMWdj4tiFe3G8tNkWK+E58g+/tzotb5cU6TbcVJLr4fySiAW7XmxQvZQA==
|
|
||||||
|
|
||||||
chai-nightwatch@0.5.3:
|
chai-nightwatch@0.5.3:
|
||||||
version "0.5.3"
|
version "0.5.3"
|
||||||
|
|
Loading…
Reference in a new issue