diff --git a/src/lib/components/PostComponent.svelte b/src/lib/components/PostComponent.svelte index 5bc09d2..f15245a 100644 --- a/src/lib/components/PostComponent.svelte +++ b/src/lib/components/PostComponent.svelte @@ -2,10 +2,24 @@ import type { Post } from '$lib/mastodon/response'; import AvatarComponent from '$lib/components/AvatarComponent.svelte'; import AccountComponent from '$lib/components/AccountComponent.svelte'; + import { secondsSince, relativeTime } from '$lib/relativeTime'; + import { onMount } from "svelte"; export let post: Post; - let dateCreated: string; - $: dateCreated = new Date(post.created_at).toLocaleString(); + let displayRelativeTime = false; + const absoluteDate = new Date(post.created_at).toLocaleString(); + let dateCreated = absoluteDate; + const timePassed = secondsSince(new Date(post.created_at)); + $: if(displayRelativeTime) { + dateCreated = relativeTime($timePassed) ?? absoluteDate; + } + + onMount(() => { + // Display relative time only after mount: + // When JS is disabled the server-side rendered absolute date will be shown, + // otherwise the relative date would be outdated very quickly + displayRelativeTime = true; + }) @@ -14,7 +28,7 @@
- {dateCreated} + {dateCreated}
{@html post.content}
diff --git a/src/lib/relativeTime.ts b/src/lib/relativeTime.ts new file mode 100644 index 0000000..c0955c7 --- /dev/null +++ b/src/lib/relativeTime.ts @@ -0,0 +1,40 @@ +import { derived, readable, type Readable } from 'svelte/store'; + +export const time = readable(new Date(), function start(set) { + const interval = setInterval(() => { + set(new Date()); + }, 10000); //Every 10sec is enough, we don't need that much granularity + + return function stop() { + clearInterval(interval); + }; +}); + +export function secondsSince(date: Date): Readable { + return derived( + time, + $time => Math.round(($time.getTime() - date.getTime()) / 1000) + ); +} + +export function relativeTime(seconds: number): string | null { + const min = 60; + if (seconds < min) { + return 'just now'; + } + + const hour = 60 * min; + if (seconds < hour) { + return `${Math.floor(seconds / min)}min`; + } + + const day = hour * 24; + if (seconds < day) { + return `${(Math.floor(seconds / hour))}h`; + } + const maxRelative = day * 31; + if (seconds < maxRelative) { + return `${seconds % day}d`; + } + return null; +} \ No newline at end of file diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 97dbe9e..bd4e83e 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -30,7 +30,7 @@ let loadingOlderPosts = false; // Needed, so that edgeFly() can do its thing: // To determine whether a newly loaded post is older than the existing ones, is required to know what the oldest // post was, before the fetch happened. -let oldestBeforeLastFetch: number | null = null; +let oldestBeforeLastFetch: number | null = null; /** * Animate either from the top, or the bottom of the window, depending if the post is