diff --git a/web/src/ui/timeline/content/PinnedEventsBody.tsx b/web/src/ui/timeline/content/PinnedEventsBody.tsx
index 80ee124..da67aca 100644
--- a/web/src/ui/timeline/content/PinnedEventsBody.tsx
+++ b/web/src/ui/timeline/content/PinnedEventsBody.tsx
@@ -15,17 +15,18 @@
// along with this program. If not, see .
import { PinnedEventsContent } from "@/api/types"
import { listDiff } from "@/util/diff.ts"
+import { oxfordHumanJoin } from "@/util/join.ts"
import EventContentProps from "./props.ts"
function renderPinChanges(content: PinnedEventsContent, prevContent?: PinnedEventsContent): string {
const { added, removed } = listDiff(content.pinned ?? [], prevContent?.pinned ?? [])
if (added.length) {
if (removed.length) {
- return `pinned ${added.join(", ")} and unpinned ${removed.join(", ")}`
+ return `pinned ${oxfordHumanJoin(added)} and unpinned ${oxfordHumanJoin(removed)}`
}
- return `pinned ${added.join(", ")}`
+ return `pinned ${oxfordHumanJoin(added)}`
} else if (removed.length) {
- return `unpinned ${removed.join(", ")}`
+ return `unpinned ${oxfordHumanJoin(removed)}`
} else {
return "sent a no-op pin event"
}
diff --git a/web/src/ui/timeline/content/PowerLevelBody.tsx b/web/src/ui/timeline/content/PowerLevelBody.tsx
index 780b9b7..3598075 100644
--- a/web/src/ui/timeline/content/PowerLevelBody.tsx
+++ b/web/src/ui/timeline/content/PowerLevelBody.tsx
@@ -15,6 +15,7 @@
// along with this program. If not, see .
import { PowerLevelEventContent } from "@/api/types"
import { objectDiff } from "@/util/diff.ts"
+import { humanJoin } from "@/util/join.ts"
import EventContentProps from "./props.ts"
function intDiff(messageParts: TemplateStringsArray, oldVal: number, newVal: number): string | null {
@@ -67,7 +68,7 @@ const PowerLevelBody = ({ event, sender }: EventContentProps) => {
const content = event.content as PowerLevelEventContent
const prevContent = event.unsigned.prev_content as PowerLevelEventContent | undefined
return
- {sender?.content.displayname ?? event.sender} {renderPowerLevels(content, prevContent).join(", ")}
+ {sender?.content.displayname ?? event.sender} {humanJoin(renderPowerLevels(content, prevContent))}
}
diff --git a/web/src/util/join.ts b/web/src/util/join.ts
new file mode 100644
index 0000000..0a05ea7
--- /dev/null
+++ b/web/src/util/join.ts
@@ -0,0 +1,29 @@
+// gomuks - A Matrix client written in Go.
+// Copyright (C) 2024 Tulir Asokan
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+export function humanJoin(arr: string[], sep: string = ", ", lastSep: string = " and "): string {
+ if (arr.length === 0) {
+ return ""
+ }
+ if (arr.length === 1) {
+ return arr[0]
+ }
+ if (arr.length === 2) {
+ return arr.join(lastSep)
+ }
+ return arr.slice(0, -1).join(sep) + lastSep + arr[arr.length - 1]
+}
+
+export const oxfordHumanJoin = (arr: string[]) => humanJoin(arr, ", ", ", and ")