From 803505385a3a25f4d19c71a486df230c89af9476 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Fri, 6 Dec 2024 02:26:16 +0200 Subject: [PATCH] web/settings: embed vs code for editing custom css Not meant for mobile yet --- web/package-lock.json | 7 +++ web/package.json | 1 + web/src/api/types/preferences/types.ts | 15 ++++++ web/src/ui/settings/SettingsView.css | 6 +++ web/src/ui/settings/SettingsView.tsx | 63 ++++++++++++++++++++-- web/src/ui/util/monaco.tsx | 72 ++++++++++++++++++++++++++ web/vite.config.ts | 5 +- 7 files changed, 163 insertions(+), 6 deletions(-) create mode 100644 web/src/ui/util/monaco.tsx diff --git a/web/package-lock.json b/web/package-lock.json index 4fadaa4..6b9fac3 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -13,6 +13,7 @@ "blurhash": "^2.0.5", "katex": "^0.16.11", "leaflet": "^1.9.4", + "monaco-editor": "^0.52.0", "react": "^19.0.0", "react-blurhash": "^0.3.0", "react-dom": "^19.0.0", @@ -4301,6 +4302,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/monaco-editor": { + "version": "0.52.0", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.52.0.tgz", + "integrity": "sha512-OeWhNpABLCeTqubfqLMXGsqf6OmPU6pHM85kF3dhy6kq5hnhuVS1p3VrEW/XhWHc71P2tHyS5JFySD8mgs1crw==", + "license": "MIT" + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", diff --git a/web/package.json b/web/package.json index fe2c631..2f2a78e 100644 --- a/web/package.json +++ b/web/package.json @@ -15,6 +15,7 @@ "blurhash": "^2.0.5", "katex": "^0.16.11", "leaflet": "^1.9.4", + "monaco-editor": "^0.52.0", "react": "^19.0.0", "react-blurhash": "^0.3.0", "react-dom": "^19.0.0", diff --git a/web/src/api/types/preferences/types.ts b/web/src/api/types/preferences/types.ts index 1b0e0a0..50211a1 100644 --- a/web/src/api/types/preferences/types.ts +++ b/web/src/api/types/preferences/types.ts @@ -21,6 +21,21 @@ export enum PreferenceContext { RoomDevice = "room_device", } +export function preferenceContextToInt(context: PreferenceContext): number { + switch (context) { + case PreferenceContext.Config: + return 0 + case PreferenceContext.Account: + return 1 + case PreferenceContext.Device: + return 2 + case PreferenceContext.RoomAccount: + return 3 + case PreferenceContext.RoomDevice: + return 4 + } +} + export const anyContext = [ PreferenceContext.RoomDevice, PreferenceContext.RoomAccount, diff --git a/web/src/ui/settings/SettingsView.css b/web/src/ui/settings/SettingsView.css index 61ae52e..cc0e7e7 100644 --- a/web/src/ui/settings/SettingsView.css +++ b/web/src/ui/settings/SettingsView.css @@ -56,6 +56,12 @@ div.settings-view { font-family: var(--monospace-font-stack); } + > div.vscode-wrapper { + position: fixed; + inset: 0; + z-index: 10; + } + > div.buttons { display: flex; justify-content: right; diff --git a/web/src/ui/settings/SettingsView.tsx b/web/src/ui/settings/SettingsView.tsx index 0c1d3fe..657d1c9 100644 --- a/web/src/ui/settings/SettingsView.tsx +++ b/web/src/ui/settings/SettingsView.tsx @@ -13,9 +13,17 @@ // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -import { use, useCallback, useState } from "react" +import { lazy, use, useCallback, useRef, useState } from "react" +import Client from "@/api/client.ts" import { RoomStateStore, usePreferences } from "@/api/statestore" -import { Preference, PreferenceContext, PreferenceValueType, Preferences, preferences } from "@/api/types/preferences" +import { + Preference, + PreferenceContext, + PreferenceValueType, + Preferences, + preferenceContextToInt, + preferences, +} from "@/api/types/preferences" import useEvent from "@/util/useEvent.ts" import ClientContext from "../ClientContext.ts" import JSONView from "../util/JSONView.tsx" @@ -155,9 +163,24 @@ interface SettingsViewProps { room: RoomStateStore } +function getActiveCSSContext(client: Client, room: RoomStateStore): PreferenceContext { + if (room.localPreferenceCache.custom_css !== undefined) { + return PreferenceContext.RoomDevice + } else if (room.serverPreferenceCache.custom_css !== undefined) { + return PreferenceContext.RoomAccount + } else if (client.store.localPreferenceCache.custom_css !== undefined) { + return PreferenceContext.Device + } else { + return PreferenceContext.Account + } +} + +const Monaco = lazy(() => import("../util/monaco.tsx")) + const CustomCSSInput = ({ setPref, room }: { setPref: SetPrefFunc, room: RoomStateStore }) => { const client = use(ClientContext)! - const [context, setContext] = useState(PreferenceContext.Account) + const appliedContext = getActiveCSSContext(client, room) + const [context, setContext] = useState(appliedContext) const getContextText = useCallback((context: PreferenceContext) => { if (context === PreferenceContext.Account) { return client.store.serverPreferenceCache.custom_css @@ -180,12 +203,30 @@ const CustomCSSInput = ({ setPref, room }: { setPref: SetPrefFunc, room: RoomSta setText(evt.target.value) }, []) const onSave = useEvent(() => { - setPref(context, "custom_css", text) + if (vscodeOpen) { + setText(vscodeContentRef.current) + setPref(context, "custom_css", vscodeContentRef.current) + } else { + setPref(context, "custom_css", text) + } }) const onDelete = useEvent(() => { setPref(context, "custom_css", undefined) setText("") }) + const [vscodeOpen, setVSCodeOpen] = useState(false) + const vscodeContentRef = useRef("") + const vscodeInitialContentRef = useRef("") + const onClickVSCode = useEvent(() => { + vscodeContentRef.current = text + vscodeInitialContentRef.current = text + setVSCodeOpen(true) + }) + const closeVSCode = useCallback(() => { + setVSCodeOpen(false) + setText(vscodeContentRef.current) + vscodeContentRef.current = "" + }, []) return

Custom CSS

@@ -195,9 +236,21 @@ const CustomCSSInput = ({ setPref, room }: { setPref: SetPrefFunc, room: RoomSta + {preferenceContextToInt(context) < preferenceContextToInt(appliedContext) && + + ⚠️ This context will not be applied, {appliedContext} has content + }
-