Skip to content

Commit 30b9d83

Browse files
feat(home-page): make items' dates dynamic
Fixes #38
1 parent dc71f70 commit 30b9d83

File tree

1 file changed

+72
-7
lines changed

1 file changed

+72
-7
lines changed

src/routes/package/[...package]/ReleaseCard.svelte

Lines changed: 72 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
<script lang="ts">
2+
import { untrack } from "svelte";
23
import { page } from "$app/state";
34
import { ArrowUpRight } from "@lucide/svelte";
45
import { confetti } from "@neoconfetti/svelte";
@@ -54,6 +55,75 @@
5455
);
5556
let isOlderThanAWeek = $derived(releaseDate.getTime() < Date.now() - 1000 * 60 * 60 * 24 * 7);
5657
58+
$effect(() => {
59+
const interval = setInterval(
60+
() => (releaseDate = new Date(releaseDate)),
61+
// this can become wrong when the unit changes
62+
// and refresh too frequently for the now greater
63+
// unit as this function is only call on client render,
64+
// but it's an edge case I'm ready to accept
65+
// as the user experience remains "live", it's just
66+
// a matter of a small optimization
67+
getRefreshPeriod(untrack(() => releaseDate))
68+
);
69+
70+
return () => clearInterval(interval);
71+
});
72+
73+
/**
74+
* Small utility function to get the diff between two dates
75+
* @param first The initial date
76+
* @param second The date to compare the first one to
77+
* @returns A diff object with every unit from second to year
78+
*/
79+
function getDiffBetween(first: Date, second: Date) {
80+
return {
81+
get seconds() {
82+
return (second.getTime() - first.getTime()) / 1000;
83+
},
84+
get minutes() {
85+
return Math.floor(this.seconds / 60);
86+
},
87+
get hours() {
88+
return Math.floor(this.minutes / 60);
89+
},
90+
get days() {
91+
return Math.floor(this.hours / 24);
92+
},
93+
get months() {
94+
return Math.floor(this.days / 30);
95+
},
96+
get years() {
97+
return Math.floor(this.months / 12);
98+
}
99+
};
100+
}
101+
102+
/**
103+
* Get the refresh period needed for a "live feel"
104+
* when displaying a date. Mainly meant to be used inside
105+
* a {@link setInterval}.
106+
*
107+
* @param date The date to get the period for
108+
* @returns The number of milliseconds to wait for before refreshing
109+
*/
110+
function getRefreshPeriod(date: Date) {
111+
const { minutes, hours, days, months, years } = getDiffBetween(date, new Date());
112+
113+
if (years > 0) {
114+
return 12 * 30 * 24 * 60 * 60 * 1_000;
115+
} else if (months > 0) {
116+
return 30 * 24 * 60 * 60 * 1_000;
117+
} else if (days > 0) {
118+
return 24 * 60 * 60 * 1_000;
119+
} else if (hours > 0) {
120+
return 60 * 60 * 1_000;
121+
} else if (minutes > 0) {
122+
return 60 * 1_000;
123+
}
124+
return 1_000;
125+
}
126+
57127
/**
58128
* Converts a date to a relative date string.
59129
* e.g., "2 days ago", "3 hours ago", "1 minute ago"
@@ -63,12 +133,7 @@
63133
* @returns the relative date
64134
*/
65135
function timeAgo(date: Date, locale = "en") {
66-
const diff = (Date.now() - date.getTime()) / 1000;
67-
const minutes = Math.floor(diff / 60);
68-
const hours = Math.floor(minutes / 60);
69-
const days = Math.floor(hours / 24);
70-
const months = Math.floor(days / 30);
71-
const years = Math.floor(months / 12);
136+
const { seconds, minutes, hours, days, months, years } = getDiffBetween(date, new Date());
72137
const formatter = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
73138
74139
if (years > 0) {
@@ -82,7 +147,7 @@
82147
} else if (minutes > 0) {
83148
return formatter.format(-minutes, "minute");
84149
}
85-
return formatter.format(0, "second"); // "now" if < 1 minute
150+
return formatter.format(-Math.floor(seconds), "second");
86151
}
87152
</script>
88153

0 commit comments

Comments
 (0)