diff --git a/frontend/deno.json b/frontend/deno.json index 1a2fec1cb..bffefd6c9 100644 --- a/frontend/deno.json +++ b/frontend/deno.json @@ -26,7 +26,6 @@ "@std/front-matter": "jsr:@std/front-matter@1", "@std/semver": "jsr:@std/semver@1", - "twas": "npm:twas@^2.1.3", "$imagescript": "https://deno.land/x/imagescript@1.3.0/mod.ts", "@deno/gfm": "jsr:@deno/gfm@0.10", diff --git a/frontend/deno.lock b/frontend/deno.lock index f587c6963..4afabcef5 100644 --- a/frontend/deno.lock +++ b/frontend/deno.lock @@ -67,8 +67,7 @@ "npm:prismjs@^1.29.0": "1.29.0", "npm:sanitize-html@^2.13.0": "2.13.1", "npm:tailwindcss@3.4": "3.4.14_postcss@8.4.47", - "npm:tailwindcss@^3.4.1": "3.4.14_postcss@8.4.47", - "npm:twas@^2.1.3": "2.1.3" + "npm:tailwindcss@^3.4.1": "3.4.14_postcss@8.4.47" }, "jsr": { "@deno/gfm@0.10.0": { @@ -1672,9 +1671,6 @@ "ts-interface-checker@0.1.13": { "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==" }, - "twas@2.1.3": { - "integrity": "sha512-4Spnweu5OEBG9ZZIfabEh0js2x1p+34QsLLz+vHjER/nQX0L/+b7H6gelZbT+Ewi2KVNHcBy5gGhib9DeVAqpA==" - }, "undici-types@5.26.5": { "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, @@ -1890,8 +1886,7 @@ "npm:preact-render-to-string@6.3.1", "npm:preact@10", "npm:prismjs@^1.29.0", - "npm:tailwindcss@3.4", - "npm:twas@^2.1.3" + "npm:tailwindcss@3.4" ] } } diff --git a/frontend/islands/admin/ScopeEdit.tsx b/frontend/islands/admin/ScopeEdit.tsx index b7c239658..2cb963eda 100644 --- a/frontend/islands/admin/ScopeEdit.tsx +++ b/frontend/islands/admin/ScopeEdit.tsx @@ -1,7 +1,7 @@ // Copyright 2024 the JSR authors. All rights reserved. MIT license. import type { FullScope } from "../../utils/api_types.ts"; import { useState } from "preact/hooks"; -import twas from "twas"; +import { timeAgo } from "../../utils/timeAgo.ts"; import { api, path } from "../../utils/api.ts"; import { TableData, TableRow } from "../../components/Table.tsx"; @@ -71,7 +71,7 @@ export default function AdminScopeEdit({ scope }: { scope: FullScope }) { : publishAttemptsPerWeekLimit} - {twas(new Date(scope.createdAt).getTime())} + {timeAgo(new Date(scope.createdAt))} {edit diff --git a/frontend/islands/admin/UserEdit.tsx b/frontend/islands/admin/UserEdit.tsx index 7dc8ec841..cd1447a8c 100644 --- a/frontend/islands/admin/UserEdit.tsx +++ b/frontend/islands/admin/UserEdit.tsx @@ -1,6 +1,6 @@ // Copyright 2024 the JSR authors. All rights reserved. MIT license. import { useState } from "preact/hooks"; -import twas from "twas"; +import { timeAgo } from "../../utils/timeAgo.ts"; import { FullUser } from "../../utils/api_types.ts"; import { api, path } from "../../utils/api.ts"; import { TableData, TableRow } from "../../components/Table.tsx"; @@ -68,7 +68,7 @@ export default function UserEdit({ user }: { user: FullUser }) { : String(isBlocked)} - {twas(new Date(user.createdAt).getTime())} + {timeAgo(new Date(user.createdAt))} {edit diff --git a/frontend/islands/new.tsx b/frontend/islands/new.tsx index cc80f1f37..7f45fabb2 100644 --- a/frontend/islands/new.tsx +++ b/frontend/islands/new.tsx @@ -8,7 +8,7 @@ import { import { Package, Scope } from "../utils/api_types.ts"; import { api, path } from "../utils/api.ts"; import { ComponentChildren } from "preact"; -import twas from "twas"; +import { timeAgo } from "../utils/timeAgo.ts"; interface IconColorProps { done: Signal; @@ -419,7 +419,7 @@ export function CreatePackage({ scope, name, pkg, fromCli }: {

{pkg.value.description || No description}

- Created {twas(new Date(pkg.value.createdAt).getTime())}. + Created {timeAgo(pkg.value.createdAt)}.

{fromCli && (

diff --git a/frontend/routes/account/(_components)/AccountLayout.tsx b/frontend/routes/account/(_components)/AccountLayout.tsx index 3248c2fe8..b7f01c213 100644 --- a/frontend/routes/account/(_components)/AccountLayout.tsx +++ b/frontend/routes/account/(_components)/AccountLayout.tsx @@ -1,6 +1,6 @@ // Copyright 2024 the JSR authors. All rights reserved. MIT license. import { ComponentChildren } from "preact"; -import twas from "twas"; +import { timeAgo } from "../../../utils/timeAgo.ts"; import { AccountNav, AccountNavTab } from "./AccountNav.tsx"; import { FullUser, User } from "../../../utils/api_types.ts"; import { GitHubUserLink } from "../../../islands/GithubUserLink.tsx"; @@ -25,7 +25,7 @@ export function AccountLayout({ user, active, children }: AccountLayoutProps) { {user.name}

- Created account {twas(new Date(user.createdAt).getTime())} + Created account {timeAgo(new Date(user.createdAt))}

diff --git a/frontend/routes/account/tokens/index.tsx b/frontend/routes/account/tokens/index.tsx index 0da983a7b..28c3dd0e6 100644 --- a/frontend/routes/account/tokens/index.tsx +++ b/frontend/routes/account/tokens/index.tsx @@ -5,7 +5,7 @@ import { define } from "../../../util.ts"; import { path } from "../../../utils/api.ts"; import { Token } from "../../../utils/api_types.ts"; import { AccountLayout } from "../(_components)/AccountLayout.tsx"; -import twas from "twas"; +import { timeAgo } from "../../../utils/timeAgo.ts"; import { RevokeToken } from "./(_islands)/RevokeToken.tsx"; import TbPlus from "@preact-icons/tb/TbPlus"; @@ -105,7 +105,7 @@ function PersonalTokenRow({ token }: { token: Token }) { Active {expiresAt === null ? "forever" : `– expires ${ - twas(new Date().getTime(), expiresAt.getTime()).replace( + timeAgo(expiresAt).replace( "ago", "from now", ) @@ -114,12 +114,12 @@ function PersonalTokenRow({ token }: { token: Token }) { ) : ( - Inactive - expired {twas(expiresAt.getTime())} + Inactive - expired {timeAgo(expiresAt)} )}

- Created {twas(new Date(token.createdAt).getTime())} + Created {timeAgo(new Date(token.createdAt))}

@@ -160,7 +160,7 @@ function SessionRow({ token }: { token: Token }) { Active {expiresAt === null ? "forever" : `– expires ${ - twas(new Date().getTime(), expiresAt.getTime()).replace( + timeAgo(expiresAt).replace( "ago", "from now", ) @@ -169,7 +169,7 @@ function SessionRow({ token }: { token: Token }) { ) : ( - Inactive - expired {twas(expiresAt.getTime())} + Inactive - expired {timeAgo(expiresAt)} )} @@ -178,7 +178,7 @@ function SessionRow({ token }: { token: Token }) {

- Created {twas(new Date(token.createdAt).getTime())} + Created {timeAgo(new Date(token.createdAt))}

diff --git a/frontend/routes/admin/publishingTasks.tsx b/frontend/routes/admin/publishingTasks.tsx index 1356cf8c7..66d3f3528 100644 --- a/frontend/routes/admin/publishingTasks.tsx +++ b/frontend/routes/admin/publishingTasks.tsx @@ -5,7 +5,7 @@ import { AdminNav } from "./(_components)/AdminNav.tsx"; import { path } from "../../utils/api.ts"; import { List, PublishingTask } from "../../utils/api_types.ts"; import { URLQuerySearch } from "../../components/URLQuerySearch.tsx"; -import twas from "twas"; +import { timeAgo } from "../../utils/timeAgo.ts"; import PublishingTaskRequeue from "../../islands/PublishingTaskRequeue.tsx"; export default define.page(function PublishingTasks({ @@ -77,7 +77,7 @@ export default define.page(function PublishingTasks({ 10, )} > - {twas(new Date(publishingTask.createdAt).getTime())} + {timeAgo(new Date(publishingTask.createdAt))}
(function PublishingTasks({ 10, )} > - {twas(new Date(publishingTask.updatedAt).getTime())} + {timeAgo(new Date(publishingTask.updatedAt))} diff --git a/frontend/routes/package/(_components)/PackageHeader.tsx b/frontend/routes/package/(_components)/PackageHeader.tsx index cd179228f..9909521f3 100644 --- a/frontend/routes/package/(_components)/PackageHeader.tsx +++ b/frontend/routes/package/(_components)/PackageHeader.tsx @@ -9,7 +9,7 @@ import { TbRosetteDiscountCheck, } from "@preact-icons/tb"; import { Tooltip } from "../../../components/Tooltip.tsx"; -import twas from "twas"; +import { timeAgo } from "../../../utils/timeAgo.ts"; import { greaterThan, parse } from "@std/semver"; interface PackageHeaderProps { @@ -207,7 +207,7 @@ export function PackageHeader({ )} > {`${ - twas(new Date(selectedVersion.createdAt).getTime()) + timeAgo(new Date(selectedVersion.createdAt)) } (${selectedVersion.version})`} diff --git a/frontend/routes/package/og.ts b/frontend/routes/package/og.ts index ce84177f0..bdc61a548 100644 --- a/frontend/routes/package/og.ts +++ b/frontend/routes/package/og.ts @@ -2,7 +2,7 @@ import { HttpError, RouteConfig } from "fresh"; import { Image } from "$imagescript"; -import twas from "twas"; +import { timeAgo } from "../../utils/timeAgo.ts"; import { packageDataWithVersion } from "../../utils/data.ts"; import { define } from "../../util.ts"; @@ -263,7 +263,7 @@ export const handler = define.handlers({ const publishDateText = Image.renderText( dmmonoFont, 25, - twas(new Date(selectedVersion.createdAt).getTime()), + timeAgo(new Date(selectedVersion.createdAt)), COLOR_GRAY, ); const result = new Image( diff --git a/frontend/routes/package/versions.tsx b/frontend/routes/package/versions.tsx index d58475c2e..d521df901 100644 --- a/frontend/routes/package/versions.tsx +++ b/frontend/routes/package/versions.tsx @@ -7,7 +7,7 @@ import type { } from "../../utils/api_types.ts"; import { define } from "../../util.ts"; import { compare, equals, format, lessThan, parse, SemVer } from "@std/semver"; -import twas from "twas"; +import { timeAgo } from "../../utils/timeAgo.ts"; import { packageData } from "../../utils/data.ts"; import { PackageHeader } from "./(_components)/PackageHeader.tsx"; import { PackageNav, Params } from "./(_components)/PackageNav.tsx"; @@ -239,7 +239,7 @@ function Version({ {" "} )} - {twas(new Date(version.createdAt).getTime())} + {timeAgo(new Date(version.createdAt))} )} @@ -268,8 +268,7 @@ function Version({ : } {ordinalNumber(tasks.length - i)} publishing attempt{" "} - {statusVerb[task.status]}{" "} - {twas(new Date(task.updatedAt).getTime())} + {statusVerb[task.status]} {timeAgo(new Date(task.updatedAt))} Details diff --git a/frontend/routes/status.tsx b/frontend/routes/status.tsx index 5be14136f..1c3640734 100644 --- a/frontend/routes/status.tsx +++ b/frontend/routes/status.tsx @@ -9,7 +9,7 @@ import { path } from "../utils/api.ts"; import { packageData } from "../utils/data.ts"; import { PackageHeader } from "./package/(_components)/PackageHeader.tsx"; import { PackageNav } from "./package/(_components)/PackageNav.tsx"; -import twas from "twas"; +import { timeAgo } from "../utils/timeAgo.ts"; import PublishingTaskRequeue from "../islands/PublishingTaskRequeue.tsx"; import { TbAlertCircle, TbCheck, TbClockHour3 } from "@preact-icons/tb"; import { scopeIAM } from "../utils/iam.ts"; @@ -48,7 +48,7 @@ export default define.page(function PackageListPage({

Created:{" "} - {twas(new Date(data.publishingTask.createdAt).getTime())} + {timeAgo(new Date(data.publishingTask.createdAt))}

{data.publishingTask.userId && (

diff --git a/frontend/utils/timeAgo.ts b/frontend/utils/timeAgo.ts new file mode 100644 index 000000000..f61ffe77c --- /dev/null +++ b/frontend/utils/timeAgo.ts @@ -0,0 +1,24 @@ +// Copyright 2024 the JSR authors. All rights reserved. MIT license. +export function timeAgo(date: Date | string): string { + const now = new Date(); + const past = new Date(date); + const diff = Math.abs(now.getTime() - past.getTime()); + + const duration = { + years: Math.floor(diff / (1000 * 60 * 60 * 24 * 365)), + months: Math.floor( + (diff % (1000 * 60 * 60 * 24 * 365)) / (1000 * 60 * 60 * 24 * 30), + ), + days: Math.floor( + (diff % (1000 * 60 * 60 * 24 * 30)) / (1000 * 60 * 60 * 24), + ), + hours: Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)), + minutes: Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60)), + seconds: Math.floor((diff % (1000 * 60)) / 1000), + }; + + // Force english because JSR is an English-only project + // @ts-ignore - TS doesn't know about this API yet + const formatter = new Intl.DurationFormat("en", { style: "long" }); + return formatter.format(duration) + " ago"; +}