mirror of
https://github.com/fosrl/pangolin.git
synced 2026-01-31 15:19:09 +00:00
💄 show product updates list
This commit is contained in:
@@ -1282,6 +1282,8 @@
|
||||
"productUpdateMoreInfo": "{noOfUpdates} more updates",
|
||||
"productUpdateInfo": "{noOfUpdates} updates",
|
||||
"productUpdateWhatsNew": "What's New",
|
||||
"productUpdateTitle": "Product Updates",
|
||||
"dismissAll": "Dismiss all",
|
||||
"pangolinUpdateAvailable": "New version available",
|
||||
"pangolinUpdateAvailableInfo": "Version {version} is ready to install",
|
||||
"pangolinUpdateAvailableReleaseNotes": "View release notes",
|
||||
|
||||
@@ -16,6 +16,9 @@ import { useTranslations } from "next-intl";
|
||||
import { Transition } from "@headlessui/react";
|
||||
import * as React from "react";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover";
|
||||
import { Button } from "./ui/button";
|
||||
import { Badge } from "./ui/badge";
|
||||
import { timeAgoFormatter } from "@app/lib/timeAgoFormatter";
|
||||
|
||||
export default function ProductUpdates({
|
||||
isCollapsed
|
||||
@@ -158,8 +161,40 @@ function ProductUpdatesListPopup({
|
||||
</div>
|
||||
</button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent side="right" align="end">
|
||||
Hello
|
||||
<PopoverContent
|
||||
side="right"
|
||||
align="end"
|
||||
className="p-0 flex flex-col w-80"
|
||||
>
|
||||
<div className="p-3 flex justify-between border-b items-center">
|
||||
<span className="text-sm inline-flex gap-2 items-center font-medium">
|
||||
{t("productUpdateTitle")}
|
||||
<Badge variant="secondary">{updates.length}</Badge>
|
||||
</span>
|
||||
<Button variant="ghost">{t("dismissAll")}</Button>
|
||||
</div>
|
||||
<ol className="p-3 flex flex-col gap-1 max-h-112 overflow-y-auto">
|
||||
{updates.map((update) => (
|
||||
<li
|
||||
key={update.id}
|
||||
className="border rounded-md flex flex-col p-4 gap-2"
|
||||
>
|
||||
<h4 className="text-sm font-medium inline-flex items-start gap-1">
|
||||
<span>{update.title}</span>
|
||||
<Badge variant="secondary">New</Badge>
|
||||
</h4>
|
||||
<small className="text-muted-foreground">
|
||||
{update.contents}
|
||||
</small>
|
||||
<time
|
||||
dateTime={update.publishedAt.toLocaleString()}
|
||||
className="text-xs text-muted-foreground"
|
||||
>
|
||||
{timeAgoFormatter(update.publishedAt)}
|
||||
</time>
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
</PopoverContent>
|
||||
</Transition>
|
||||
</Popover>
|
||||
|
||||
48
src/lib/timeAgoFormatter.ts
Normal file
48
src/lib/timeAgoFormatter.ts
Normal file
@@ -0,0 +1,48 @@
|
||||
export function timeAgoFormatter(
|
||||
dateInput: string | Date,
|
||||
short: boolean = false
|
||||
): string {
|
||||
const date = new Date(dateInput);
|
||||
const now = new Date();
|
||||
const diffInSeconds = Math.floor((now.getTime() - date.getTime()) / 1000);
|
||||
|
||||
const secondsInMinute = 60;
|
||||
const secondsInHour = 60 * secondsInMinute;
|
||||
const secondsInDay = 24 * secondsInHour;
|
||||
const secondsInWeek = 7 * secondsInDay;
|
||||
const secondsInMonth = 30 * secondsInDay;
|
||||
const secondsInYear = 365 * secondsInDay;
|
||||
|
||||
let value: number;
|
||||
let unit: Intl.RelativeTimeFormatUnit;
|
||||
|
||||
if (diffInSeconds < secondsInMinute) {
|
||||
value = diffInSeconds;
|
||||
unit = "second";
|
||||
} else if (diffInSeconds < secondsInHour) {
|
||||
value = Math.floor(diffInSeconds / secondsInMinute);
|
||||
unit = "minute";
|
||||
} else if (diffInSeconds < secondsInDay) {
|
||||
value = Math.floor(diffInSeconds / secondsInHour);
|
||||
unit = "hour";
|
||||
} else if (diffInSeconds < secondsInWeek) {
|
||||
value = Math.floor(diffInSeconds / secondsInDay);
|
||||
unit = "day";
|
||||
} else if (diffInSeconds < secondsInMonth) {
|
||||
value = Math.floor(diffInSeconds / secondsInWeek);
|
||||
unit = "week";
|
||||
} else if (diffInSeconds < secondsInYear) {
|
||||
value = Math.floor(diffInSeconds / secondsInMonth);
|
||||
unit = "month";
|
||||
} else {
|
||||
value = Math.floor(diffInSeconds / secondsInYear);
|
||||
unit = "year";
|
||||
}
|
||||
|
||||
const rtf = new Intl.RelativeTimeFormat("en", {
|
||||
numeric: "auto",
|
||||
style: short ? "narrow" : "long"
|
||||
});
|
||||
const formatedValue = rtf.format(-value, unit);
|
||||
return formatedValue === "now" ? "Just now" : formatedValue;
|
||||
}
|
||||
Reference in New Issue
Block a user