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 ")