From 4c8497e5d985d6e7fd7fe6b649c398be8e04eee9 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 23 Dec 2024 13:25:35 +0200 Subject: [PATCH] web/preferences: add option to change window title Fixes #564 --- web/src/api/statestore/main.ts | 2 +- web/src/api/statestore/room.ts | 2 +- web/src/api/types/preferences/preferences.ts | 14 +++++++++++++- web/src/api/types/preferences/proxy.ts | 4 ++-- web/src/ui/MainScreen.tsx | 11 +++++++++-- web/src/ui/settings/SettingsView.tsx | 3 +++ 6 files changed, 29 insertions(+), 7 deletions(-) diff --git a/web/src/api/statestore/main.ts b/web/src/api/statestore/main.ts index 9ffa945..65dac61 100644 --- a/web/src/api/statestore/main.ts +++ b/web/src/api/statestore/main.ts @@ -76,7 +76,7 @@ export class StateStore { readonly accountData: Map = new Map() readonly accountDataSubs = new MultiSubscribable() readonly emojiRoomsSub = new Subscribable() - readonly preferences: Preferences = getPreferenceProxy(this) + readonly preferences = getPreferenceProxy(this) #frequentlyUsedEmoji: Map | null = null #emojiPackKeys: RoomStateGUID[] | null = null #watchedRoomEmojiPacks: Record | null = null diff --git a/web/src/api/statestore/room.ts b/web/src/api/statestore/room.ts index 23fc555..3896de7 100644 --- a/web/src/api/statestore/room.ts +++ b/web/src/api/statestore/room.ts @@ -112,7 +112,7 @@ export class RoomStateStore { readonly accountDataSubs = new MultiSubscribable() readonly openNotifications: Map = new Map() readonly #emojiPacksCache: Map = new Map() - readonly preferences: Preferences + readonly preferences: Required readonly localPreferenceCache: Preferences readonly preferenceSub = new NoDataSubscribable() serverPreferenceCache: Preferences = {} diff --git a/web/src/api/types/preferences/preferences.ts b/web/src/api/types/preferences/preferences.ts index a535817..9f7e253 100644 --- a/web/src/api/types/preferences/preferences.ts +++ b/web/src/api/types/preferences/preferences.ts @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . import type { ContentURI } from "../../types" -import { Preference, anyContext } from "./types.ts" +import { Preference, anyContext, anyGlobalContext } from "./types.ts" export const codeBlockStyles = [ "auto", "abap", "algol_nu", "algol", "arduino", "autumn", "average", "base16-snazzy", "borland", "bw", @@ -171,6 +171,18 @@ export const preferences = { allowedContexts: anyContext, defaultValue: "", }), + room_window_title: new Preference({ + displayName: "In-room window title", + description: "The title to use for the window when viewing a room. $room will be replaced with the room name", + allowedContexts: anyContext, + defaultValue: "$room - gomuks web", + }), + window_title: new Preference({ + displayName: "Default window title", + description: "The title to use for the window when not in a room.", + allowedContexts: anyGlobalContext, + defaultValue: "gomuks web", + }), } as const export const existingPreferenceKeys = new Set(Object.keys(preferences)) diff --git a/web/src/api/types/preferences/proxy.ts b/web/src/api/types/preferences/proxy.ts index d9cd11a..f7f0b68 100644 --- a/web/src/api/types/preferences/proxy.ts +++ b/web/src/api/types/preferences/proxy.ts @@ -19,7 +19,7 @@ import { PreferenceContext, PreferenceValueType } from "./types.ts" const prefKeys = Object.keys(preferences) -export function getPreferenceProxy(store: StateStore, room?: RoomStateStore): Preferences { +export function getPreferenceProxy(store: StateStore, room?: RoomStateStore): Required { return new Proxy({}, { set(): boolean { throw new Error("The preference proxy is read-only") @@ -61,5 +61,5 @@ export function getPreferenceProxy(store: StateStore, room?: RoomStateStore): Pr writable: false, } : undefined }, - }) + }) as Required } diff --git a/web/src/ui/MainScreen.tsx b/web/src/ui/MainScreen.tsx index ca2c381..2ae5194 100644 --- a/web/src/ui/MainScreen.tsx +++ b/web/src/ui/MainScreen.tsx @@ -124,6 +124,13 @@ class ContextFields implements MainScreenContextFields { } } + #getWindowTitle(room?: RoomStateStore, name?: string) { + if (!room) { + return this.client.store.preferences.window_title + } + return room.preferences.room_window_title.replace("$room", name!) + } + #setActiveRoom(room: RoomStateStore, pushState: boolean) { window.activeRoom = room this.directSetActiveRoom(room) @@ -147,7 +154,7 @@ class ContextFields implements MainScreenContextFields { if (roomNameForTitle && roomNameForTitle.length > 48) { roomNameForTitle = roomNameForTitle.slice(0, 45) + "…" } - document.title = `${roomNameForTitle} - gomuks web` + document.title = this.#getWindowTitle(room, roomNameForTitle) } #closeActiveRoom(pushState: boolean) { @@ -161,7 +168,7 @@ class ContextFields implements MainScreenContextFields { if (pushState) { history.pushState({}, "") } - document.title = "gomuks web" + document.title = this.#getWindowTitle() } clickRoom = (evt: React.MouseEvent) => { diff --git a/web/src/ui/settings/SettingsView.tsx b/web/src/ui/settings/SettingsView.tsx index e2b6b86..6f9aefc 100644 --- a/web/src/ui/settings/SettingsView.tsx +++ b/web/src/ui/settings/SettingsView.tsx @@ -110,6 +110,9 @@ const PreferenceRow = ({ val: PreferenceValueType | undefined, inheritedVal: PreferenceValueType, ) => { + if (!pref.allowedContexts.includes(context)) { + return null + } if (prefType === "boolean") { return