{sender?.content.displayname ?? event.sender} changed the server ACLs: {changeString}
diff --git a/web/src/ui/timeline/content/PinnedEventsBody.tsx b/web/src/ui/timeline/content/PinnedEventsBody.tsx
index c46908d0..87167005 100644
--- a/web/src/ui/timeline/content/PinnedEventsBody.tsx
+++ b/web/src/ui/timeline/content/PinnedEventsBody.tsx
@@ -13,30 +13,35 @@
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see
.
+import { IntlShape, useIntl } from "react-intl"
import { PinnedEventsContent } from "@/api/types"
import { listDiff } from "@/util/diff.ts"
-import { humanJoin } from "@/util/join.ts"
import EventContentProps from "./props.ts"
-function renderPinChanges(content: PinnedEventsContent, prevContent?: PinnedEventsContent): string {
+function renderPinChanges(intl: IntlShape, content: PinnedEventsContent, prevContent?: PinnedEventsContent): string {
+ const list = (items: ReadonlyArray
) => intl.formatList(items, { type: "conjunction" })
const [added, removed] = listDiff(content.pinned ?? [], prevContent?.pinned ?? [])
- if (added.length) {
+ if (added.length || removed.length) {
+ const items = []
+ if (added.length) {
+ items.push(`pinned ${list(added)}`)
+ }
if (removed.length) {
- return `pinned ${humanJoin(added)} and unpinned ${humanJoin(removed)}`
+ items.push(`unpinned ${list(removed)}`)
}
- return `pinned ${humanJoin(added)}`
- } else if (removed.length) {
- return `unpinned ${humanJoin(removed)}`
+ return list(items)
} else {
return "sent a no-op pin event"
}
}
const PinnedEventsBody = ({ event, sender }: EventContentProps) => {
+
+ const intl = useIntl()
const content = event.content as PinnedEventsContent
const prevContent = event.unsigned.prev_content as PinnedEventsContent | undefined
return
- {sender?.content.displayname ?? event.sender} {renderPinChanges(content, prevContent)}
+ {sender?.content.displayname ?? event.sender} {renderPinChanges(intl, content, prevContent)}
}
diff --git a/web/src/ui/timeline/content/PowerLevelBody.tsx b/web/src/ui/timeline/content/PowerLevelBody.tsx
index 35980759..f6adcc47 100644
--- a/web/src/ui/timeline/content/PowerLevelBody.tsx
+++ b/web/src/ui/timeline/content/PowerLevelBody.tsx
@@ -13,9 +13,9 @@
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
+import { FormattedList } from "react-intl"
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 {
@@ -68,7 +68,8 @@ 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} {humanJoin(renderPowerLevels(content, prevContent))}
+ {sender?.content.displayname ?? event.sender}
+
}
diff --git a/web/src/util/join.ts b/web/src/util/join.ts
deleted file mode 100644
index 2252efb4..00000000
--- a/web/src/util/join.ts
+++ /dev/null
@@ -1,27 +0,0 @@
-// 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]
-}
diff --git a/web/src/util/reactjoin.tsx b/web/src/util/reactjoin.tsx
deleted file mode 100644
index 96f450d5..00000000
--- a/web/src/util/reactjoin.tsx
+++ /dev/null
@@ -1,30 +0,0 @@
-// 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 .
-import { Fragment, JSX } from "react"
-
-export function humanJoinReact(
- arr: (string | JSX.Element)[],
- sep: string | JSX.Element = ", ",
- lastSep: string | JSX.Element = " and ",
-): JSX.Element[] {
- return arr.map((elem, idx) =>
-
- {elem}
- {idx < arr.length - 1 ? (idx === arr.length - 2 ? lastSep : sep) : null}
- )
-}
-
-export const joinReact = (arr: (string | JSX.Element)[]) => humanJoinReact(arr, " ", " ")
diff --git a/web/vite.config.ts b/web/vite.config.ts
index 5d88b2d8..063daa92 100644
--- a/web/vite.config.ts
+++ b/web/vite.config.ts
@@ -7,6 +7,7 @@ const splitDeps = ["katex", "leaflet", "monaco-editor"]
export default defineConfig({
base: "./",
build: {
+
target: ["esnext", "firefox128", "chrome131", "safari18"],
chunkSizeWarningLimit: 3500,
rollupOptions: {
@@ -36,6 +37,7 @@ export default defineConfig({
resolve: {
alias: {
"@": "/src",
+ "@formatjs/icu-messageformat-parser": "@formatjs/icu-messageformat-parser/no-parser",
},
},
server: {