Skip to content

Commit

Permalink
+ <RelativeTime> that extracted from <PostBadgeTimeView> to only …
Browse files Browse the repository at this point in the history
…invoking expensive `DateTime.toRelative()` moment/luxon#959 for components in viewport

* now will return the ref `timer[unit]` being bound
* replace the null forgive operator for unmatched units with fallbacking to year unit
* remove param `options`
* renamed from `registerRelative()`
@ `registerTimerDep()` @ `store/relativeTime.ts`

- scoped style for `span` that being unused since 4d82a0a @ `<PostBadgeTimeView>`
@ fe
  • Loading branch information
n0099 committed Sep 1, 2024
1 parent ca674de commit 7a7775c
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 26 deletions.
39 changes: 39 additions & 0 deletions fe/src/components/RelativeTime.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<template>
<span :ref="el => relativeEl = (el as HTMLElement)">
<template v-if="hydrationStore.isHydratingOrSSR || !relativeElIsVisible">
{{ dateTimeInChina.toLocaleString({
year: 'numeric',
...keysWithSameValue(['month', 'day', 'hour', 'minute', 'second'], '2-digit')
}) }}
</template>
<template v-else>
{{ current.toRelative({ base: relativeTo, round: false }) }}
</template>
</span>
</template>

<script setup lang="ts">
import type { DateTime } from 'luxon';
const props = defineProps<{
dateTime: DateTime<true>,
relativeTo?: DateTime<true>
}>();
const hydrationStore = useHydrationStore();
const relativeEl = ref<HTMLElement>();
const relativeElIsVisible = ref(false);
const dateTimeInChina = computed(() => setDateTimeZoneAndLocale()(props.dateTime));
const { pause, resume } = useIntersectionObserver(
relativeEl,
([{ isIntersecting }]) => {
relativeElIsVisible.value = isIntersecting;
}
);
watchEffect(() => {
if (props.relativeTo === undefined)
pause();
else
resume();
});
</script>
20 changes: 1 addition & 19 deletions fe/src/components/post/badge/TimeView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,7 @@
v-tippy="tippyContent" :datetime="currentInChina.toISO() ?? undefined"
class="ms-1 fw-normal badge rounded-pill user-select-all">
<component :is="$slots.default" />
<template v-if="hydrationStore.isHydratingOrSSR">
{{ currentInChina.toLocaleString({
year: 'numeric',
...keysWithSameValue(['month', 'day', 'hour', 'minute', 'second'], '2-digit')
}) }}
</template>
<template v-else>
{{ relativeTo === undefined
? relativeTimeStore.registerRelative(current)
: current.toRelative({ base: relativeTo, round: false }) }}
</template>
<RelativeTime :dateTime="current" :relativeTo="relativeTo" />
</time>
</template>

Expand All @@ -32,7 +22,6 @@ const props = defineProps<{
: 'postedAt' extends TPostTimeKey ? '发帖时间' : never
}>();
const hydrationStore = useHydrationStore();
const relativeTimeStore = useRelativeTimeStore();
const currentInChina = computed(() => setDateTimeZoneAndLocale()(props.current));
const tippyContentRelativeTo = computed(() => {
Expand Down Expand Up @@ -72,10 +61,3 @@ const tippyContent = () => {
${tippyContentRelativeTo.value}`;
};
</script>

<style scoped>
span {
padding-inline-start: .75rem;
padding-inline-end: .75rem;
}
</style>
13 changes: 6 additions & 7 deletions fe/src/stores/relativeTime.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { ToRelativeOptions, ToRelativeUnit } from 'luxon';
import type { ToRelativeUnit } from 'luxon';
import { DateTime, Duration } from 'luxon';

export const useRelativeTimeStore = defineStore('relativeTime', () => {
Expand All @@ -12,18 +12,17 @@ export const useRelativeTimeStore = defineStore('relativeTime', () => {
);
});
}
const registerRelative = (dateTime: DateTime, options?: ToRelativeOptions) => computed(() => {
const registerTimerDep = (dateTime: DateTime) => computed(() => {
const relativeDuration = dateTime
.diff(DateTime.now(), undefined, { conversionAccuracy: 'longterm' })
.shiftTo(...units);
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const { unit } = units
.map(unit => ({ unit, value: relativeDuration.get(unit) }))
.find(unit => unit.value !== 0)!;
void timers[unit]; // track this computed ref as dependency of reactive timers[unit]
.find(unit => unit.value !== 0)
?? { unit: 'years' };

return dateTime.toRelative({ ...options, round: false });
return timers[unit];
});

return { timers, registerRelative };
return { timers, registerTimerDep };
});

0 comments on commit 7a7775c

Please sign in to comment.