From 5ecdf618d10f9013b0db539b4d9ee18eaf4a4e6b Mon Sep 17 00:00:00 2001 From: joneugster Date: Wed, 22 Nov 2023 11:08:00 +0100 Subject: [PATCH] option to load custom theme --- client/src/Editor.tsx | 4 +-- client/src/Settings.tsx | 51 ++++++++++++++++++++++++++++++++++--- client/src/config/config.ts | 3 ++- client/src/css/Modal.css | 19 ++++++++++---- 4 files changed, 66 insertions(+), 11 deletions(-) diff --git a/client/src/Editor.tsx b/client/src/Editor.tsx index beae1f61..6219fa26 100644 --- a/client/src/Editor.tsx +++ b/client/src/Editor.tsx @@ -29,8 +29,8 @@ const Editor: React.FC<{setRestart?, onDidChangeContent?, value: string, theme: const [restartMessage, setRestartMessage] = useState(false) useEffect(() => { - if (theme == 'lightPlus') { - monaco.editor.setTheme('lightPlus') + if (['lightPlus', 'custom'].includes(theme)) { + monaco.editor.setTheme(theme) } else { //monaco.editor.setTheme(theme) fetch(`./themes/${theme}.json`,{ diff --git a/client/src/Settings.tsx b/client/src/Settings.tsx index dec255d1..f604ed82 100644 --- a/client/src/Settings.tsx +++ b/client/src/Settings.tsx @@ -6,7 +6,8 @@ import { useEffect } from 'react' import Switch from '@mui/material/Switch'; import Select from '@mui/material/Select'; import { useWindowDimensions } from './window_width'; -import { FormControl, InputLabel, MenuItem } from '@mui/material'; +import { Button, FormControl, InputLabel, MenuItem } from '@mui/material'; +import * as monaco from 'monaco-editor/esm/vs/editor/editor.api.js' const Settings: React.FC<{closeNav, theme, setTheme}> = ({closeNav, theme, setTheme}) => { @@ -22,6 +23,7 @@ const Settings: React.FC<{closeNav, theme, setTheme}> = If screen width is below 800, default to vertical layout instead. */ const {width, height} = useWindowDimensions() const [verticalLayout, setVerticalLayout] = React.useState(width < 800) + const [customTheme, setCustomTheme] = React.useState('initial') // Synchronize state with initial local store useEffect(() => { @@ -29,6 +31,7 @@ const Settings: React.FC<{closeNav, theme, setTheme}> = let _verticalLayout = window.localStorage.getItem("verticalLayout") let _theme = window.localStorage.getItem("theme") let _savingAllowed = window.localStorage.getItem("savingAllowed") + let _customTheme = window.localStorage.getItem("customTheme") if (_abbreviationCharacter) { setAbbreviationCharacter(_abbreviationCharacter) setSavingAllowed(true) @@ -41,7 +44,18 @@ const Settings: React.FC<{closeNav, theme, setTheme}> = setTheme(_theme) setSavingAllowed(true) } - + if (_customTheme) { + setCustomTheme(_customTheme) + setSavingAllowed(true) + try { + var loadedTheme = JSON.parse(_customTheme) + monaco.editor.defineTheme('custom', loadedTheme) + } catch (error) { + // invalid custom theme + setCustomTheme('') + if (_theme == 'custom') {setTheme('lightPlus')} + } + } }, []) /** Synchronize config and local store whenever there is a change to any of the config @@ -55,10 +69,12 @@ const Settings: React.FC<{closeNav, theme, setTheme}> = window.localStorage.setItem("abbreviationCharacter", abbreviationCharacter) window.localStorage.setItem("verticalLayout", verticalLayout ? 'true' : 'false') window.localStorage.setItem("theme", theme) + window.localStorage.setItem("customTheme", customTheme) } else { window.localStorage.removeItem("abbreviationCharacter") window.localStorage.removeItem("verticalLayout") window.localStorage.removeItem("theme") + window.localStorage.removeItem("customTheme") } }, [savingAllowed, abbreviationCharacter, verticalLayout, theme]) @@ -75,6 +91,26 @@ const Settings: React.FC<{closeNav, theme, setTheme}> = // ev.stopPropagation() } + /** Load a custom monaco theme, store it in local storage and activate it */ + function uploadTheme(ev) { + const fileToLoad = ev.target.files[0] + var fileReader = new FileReader() + fileReader.onload = (fileLoadedEvent) => { + var loadedThemeRaw = fileLoadedEvent.target.result as string + window.localStorage.setItem("customTheme", loadedThemeRaw) + try { + var loadedTheme = JSON.parse(loadedThemeRaw) + } catch (error) { + return + } + setTheme('custom') + setCustomTheme(loadedThemeRaw) + monaco.editor.defineTheme('custom', loadedTheme) + monaco.editor.setTheme('custom') + } + fileReader.readAsText(fileToLoad, "UTF-8") + } + return <> Settings @@ -91,7 +127,7 @@ const Settings: React.FC<{closeNav, theme, setTheme}> = {setAbbreviationCharacter(ev.target.value)}} value={abbreviationCharacter} />

-

+

+ + + + + {/* */}

diff --git a/client/src/config/config.ts b/client/src/config/config.ts index 8b625223..fd9a3773 100644 --- a/client/src/config/config.ts +++ b/client/src/config/config.ts @@ -7,5 +7,6 @@ export const config = { 'inputModeCustomTranslations': {}, 'eagerReplacementEnabled': true, 'verticalLayout': false, // value here irrelevant, will be overwritten with `width < 800` in Settings.tsx - 'theme': 'light', // options: light, dark + 'theme': 'lightPlus', + 'customTheme': '', } diff --git a/client/src/css/Modal.css b/client/src/css/Modal.css index b662bfa4..7fa86a46 100644 --- a/client/src/css/Modal.css +++ b/client/src/css/Modal.css @@ -52,10 +52,6 @@ input[type="file"] { width: 100%; } -.modal select { - float: right; -} - .modal textarea { height: 10em; } @@ -65,17 +61,30 @@ input[type="file"] { font-weight: bold; } -.modal input[type="submit"] { +.modal input[type="submit"], .modal .file-upload-button { border: none; color: var(--vscode-button-foreground); background: var(--vscode-button-background); cursor: pointer; padding: .5rem 1rem; border-radius: .2rem; +} + +.modal input[type="submit"]{ display: block; margin: 1rem auto; } +.modal .flex { + display: flex; + justify-content: space-between; +} + +.modal .flex label { + margin-top: auto; + margin-bottom: auto; +} + .modal-close { float: right; scale: 2;