mirror of
https://github.com/bitburner-official/bitburner-src.git
synced 2024-11-18 13:43:49 +01:00
parent
c2dacedcb3
commit
709875d9ca
@ -1,6 +1,4 @@
|
||||
import React, { useState } from "react";
|
||||
import { Options, WordWrapOptions } from "./Options";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import React from "react";
|
||||
|
||||
import Button from "@mui/material/Button";
|
||||
import Typography from "@mui/material/Typography";
|
||||
@ -9,62 +7,41 @@ import Switch from "@mui/material/Switch";
|
||||
import MenuItem from "@mui/material/MenuItem";
|
||||
import TextField from "@mui/material/TextField";
|
||||
import EditIcon from "@mui/icons-material/Edit";
|
||||
import SaveIcon from "@mui/icons-material/Save";
|
||||
|
||||
import { useBoolean } from "../../ui/React/hooks";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { ThemeEditorModal } from "./ThemeEditorModal";
|
||||
import { Options } from "./Options";
|
||||
|
||||
interface IProps {
|
||||
options: Options;
|
||||
save: (options: Options) => void;
|
||||
onClose: () => void;
|
||||
export type OptionsModalProps = {
|
||||
open: boolean;
|
||||
}
|
||||
options: Options;
|
||||
onClose: () => void;
|
||||
onOptionChange: (option: keyof Options, value: Options[keyof Options]) => void;
|
||||
onThemeChange: () => void;
|
||||
};
|
||||
|
||||
export function OptionsModal(props: IProps): React.ReactElement {
|
||||
const [theme, setTheme] = useState(props.options.theme);
|
||||
const [insertSpaces, setInsertSpaces] = useState(props.options.insertSpaces);
|
||||
const [tabSize, setTabSize] = useState(props.options.tabSize);
|
||||
const [detectIndentation, setDetectIndentation] = useState(props.options.detectIndentation);
|
||||
const [fontFamily, setFontFamily] = useState(props.options.fontFamily);
|
||||
const [fontSize, setFontSize] = useState(props.options.fontSize);
|
||||
const [fontLigatures, setFontLigatures] = useState(props.options.fontLigatures);
|
||||
const [wordWrap, setWordWrap] = useState(props.options.wordWrap);
|
||||
const [vim, setVim] = useState(props.options.vim);
|
||||
const [themeEditorOpen, setThemeEditorOpen] = useState(false);
|
||||
export function OptionsModal(props: OptionsModalProps): React.ReactElement {
|
||||
const [themeEditorOpen, { on: openThemeEditor, off: closeThemeEditor }] = useBoolean(false);
|
||||
|
||||
function save(): void {
|
||||
props.save({
|
||||
theme,
|
||||
insertSpaces,
|
||||
tabSize,
|
||||
detectIndentation,
|
||||
fontFamily,
|
||||
fontSize,
|
||||
fontLigatures,
|
||||
wordWrap,
|
||||
vim,
|
||||
});
|
||||
props.onClose();
|
||||
}
|
||||
const onFontSizeChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const fontSize = parseInt(event.target.value);
|
||||
if (!Number.isFinite(fontSize) || fontSize < 1) return;
|
||||
props.onOptionChange("fontSize", fontSize);
|
||||
};
|
||||
|
||||
function onFontSizeChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
const n = parseInt(event.target.value);
|
||||
if (!Number.isFinite(n) || n < 1) return;
|
||||
setFontSize(n);
|
||||
}
|
||||
|
||||
function onTabSizeChange(event: React.ChangeEvent<HTMLInputElement>): void {
|
||||
const n = parseInt(event.target.value);
|
||||
if (!Number.isFinite(n) || n < 1) return;
|
||||
setTabSize(n);
|
||||
}
|
||||
const onTabSizeChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const tabSize = parseInt(event.target.value);
|
||||
if (!Number.isFinite(tabSize) || tabSize < 1) return;
|
||||
props.onOptionChange("tabSize", tabSize);
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<ThemeEditorModal open={themeEditorOpen} onClose={() => setThemeEditorOpen(false)} />
|
||||
<ThemeEditorModal open={themeEditorOpen} onChange={props.onThemeChange} onClose={closeThemeEditor} />
|
||||
<div style={{ display: "flex", alignItems: "center" }}>
|
||||
<Typography>Theme: </Typography>
|
||||
<Select onChange={(event) => setTheme(event.target.value)} value={theme}>
|
||||
<Select onChange={(event) => props.onOptionChange("theme", event.target.value)} value={props.options.theme}>
|
||||
<MenuItem value="monokai">monokai</MenuItem>
|
||||
<MenuItem value="solarized-dark">solarized-dark</MenuItem>
|
||||
<MenuItem value="solarized-light">solarized-light</MenuItem>
|
||||
@ -74,29 +51,38 @@ export function OptionsModal(props: IProps): React.ReactElement {
|
||||
<MenuItem value="one-dark">one-dark</MenuItem>
|
||||
<MenuItem value="customTheme">Custom theme</MenuItem>
|
||||
</Select>
|
||||
<Button onClick={() => setThemeEditorOpen(true)} sx={{ ml: 1 }} startIcon={<EditIcon />}>
|
||||
<Button onClick={openThemeEditor} sx={{ ml: 1 }} startIcon={<EditIcon />}>
|
||||
Edit custom theme
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div style={{ display: "flex", alignItems: "center" }}>
|
||||
<Typography marginRight={"auto"}>Indent using tabs: </Typography>
|
||||
<Switch onChange={(e) => setInsertSpaces(e.target.checked)} checked={insertSpaces} />
|
||||
<Switch
|
||||
onChange={(e) => props.onOptionChange("insertSpaces", e.target.checked)}
|
||||
checked={props.options.insertSpaces}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style={{ display: "flex", alignItems: "center" }}>
|
||||
<Typography marginRight={"auto"}>Tab size: </Typography>
|
||||
<TextField type="number" value={tabSize} onChange={onTabSizeChange} />
|
||||
<TextField type="number" value={props.options.tabSize} onChange={onTabSizeChange} />
|
||||
</div>
|
||||
|
||||
<div style={{ display: "flex", alignItems: "center" }}>
|
||||
<Typography marginRight={"auto"}>Auto-detect indentation: </Typography>
|
||||
<Switch onChange={(e) => setDetectIndentation(e.target.checked)} checked={detectIndentation} />
|
||||
<Switch
|
||||
onChange={(e) => props.onOptionChange("detectIndentation", e.target.checked)}
|
||||
checked={props.options.detectIndentation}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style={{ display: "flex", alignItems: "center" }}>
|
||||
<Typography marginRight={"auto"}>Word wrap: </Typography>
|
||||
<Select onChange={(event) => setWordWrap(event.target.value as WordWrapOptions)} value={wordWrap}>
|
||||
<Select
|
||||
onChange={(event) => props.onOptionChange("wordWrap", event.target.value)}
|
||||
value={props.options.wordWrap}
|
||||
>
|
||||
<MenuItem value={"off"}>Off</MenuItem>
|
||||
<MenuItem value={"on"}>On</MenuItem>
|
||||
<MenuItem value={"bounded"}>Bounded</MenuItem>
|
||||
@ -106,28 +92,30 @@ export function OptionsModal(props: IProps): React.ReactElement {
|
||||
|
||||
<div style={{ display: "flex", alignItems: "center" }}>
|
||||
<Typography marginRight={"auto"}>Enable vim mode: </Typography>
|
||||
<Switch onChange={(e) => setVim(e.target.checked)} checked={vim} />
|
||||
<Switch onChange={(e) => props.onOptionChange("vim", e.target.checked)} checked={props.options.vim} />
|
||||
</div>
|
||||
|
||||
<div style={{ display: "flex", alignItems: "center" }}>
|
||||
<Typography marginRight={"auto"}>Font family: </Typography>
|
||||
<TextField type="text" value={fontFamily} onChange={(e) => setFontFamily(e.target.value)} />
|
||||
<TextField
|
||||
type="text"
|
||||
value={props.options.fontFamily}
|
||||
onChange={(e) => props.onOptionChange("fontFamily", e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div style={{ display: "flex", alignItems: "center" }}>
|
||||
<Typography marginRight={"auto"}>Font size: </Typography>
|
||||
<TextField type="number" value={fontSize} onChange={onFontSizeChange} />
|
||||
<TextField type="number" value={props.options.fontSize} onChange={onFontSizeChange} />
|
||||
</div>
|
||||
|
||||
<div style={{ display: "flex", alignItems: "center" }}>
|
||||
<Typography marginRight={"auto"}>Enable font ligatures: </Typography>
|
||||
<Switch onChange={(e) => setFontLigatures(e.target.checked)} checked={fontLigatures} />
|
||||
<Switch
|
||||
onChange={(e) => props.onOptionChange("fontLigatures", e.target.checked)}
|
||||
checked={props.options.fontLigatures}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<br />
|
||||
<Button onClick={save} startIcon={<SaveIcon />}>
|
||||
Save
|
||||
</Button>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
@ -1,78 +1,74 @@
|
||||
import { History, Reply, Save } from "@mui/icons-material";
|
||||
import { Box, Button, Paper, TextField, Tooltip, Typography } from "@mui/material";
|
||||
import IconButton from "@mui/material/IconButton";
|
||||
import React from "react";
|
||||
import _ from "lodash";
|
||||
|
||||
import { Grid, Box, Button, IconButton, Paper, TextField, Tooltip, Typography } from "@mui/material";
|
||||
import { History, Reply } from "@mui/icons-material";
|
||||
import { Color, ColorPicker } from "material-ui-color";
|
||||
import React, { useState } from "react";
|
||||
import { useRerender } from "../../ui/React/hooks";
|
||||
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
import { useRerender } from "../../ui/React/hooks";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { OptionSwitch } from "../../ui/React/OptionSwitch";
|
||||
import { defaultMonacoTheme, IScriptEditorTheme } from "./themes";
|
||||
|
||||
interface IProps {
|
||||
onClose: () => void;
|
||||
open: boolean;
|
||||
}
|
||||
import { defaultMonacoTheme } from "./themes";
|
||||
|
||||
interface IColorEditorProps {
|
||||
type ColorEditorProps = {
|
||||
label: string;
|
||||
themePath: string;
|
||||
color: string | undefined;
|
||||
onColorChange: (name: string, value: string) => void;
|
||||
defaultColor: string;
|
||||
}
|
||||
};
|
||||
|
||||
// Slightly tweaked version of the same function found in game options
|
||||
function ColorEditor({ label, themePath, onColorChange, color, defaultColor }: IColorEditorProps): React.ReactElement {
|
||||
function ColorEditor({ label, themePath, onColorChange, color, defaultColor }: ColorEditorProps): React.ReactElement {
|
||||
if (color === undefined) {
|
||||
console.error(`color ${themePath} was undefined, reverting to default`);
|
||||
color = defaultColor;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Tooltip title={label}>
|
||||
<span>
|
||||
<TextField
|
||||
label={themePath}
|
||||
value={"#" + color}
|
||||
sx={{ display: "block", my: 1 }}
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<>
|
||||
<ColorPicker
|
||||
hideTextfield
|
||||
deferred
|
||||
value={"#" + color}
|
||||
onChange={(newColor: Color) => onColorChange(themePath, newColor.hex)}
|
||||
disableAlpha
|
||||
/>
|
||||
</>
|
||||
),
|
||||
endAdornment: (
|
||||
<>
|
||||
<IconButton onClick={() => onColorChange(themePath, defaultColor)}>
|
||||
<Reply color="primary" />
|
||||
</IconButton>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
</Tooltip>
|
||||
</>
|
||||
<Tooltip title={label}>
|
||||
<span>
|
||||
<TextField
|
||||
label={themePath}
|
||||
value={"#" + color}
|
||||
sx={{ display: "block", my: 1 }}
|
||||
InputProps={{
|
||||
readOnly: true,
|
||||
startAdornment: (
|
||||
<ColorPicker
|
||||
hideTextfield
|
||||
deferred
|
||||
value={"#" + color}
|
||||
onChange={(newColor: Color) => onColorChange(themePath, newColor.hex)}
|
||||
disableAlpha
|
||||
/>
|
||||
),
|
||||
endAdornment: (
|
||||
<IconButton onClick={() => onColorChange(themePath, defaultColor)}>
|
||||
<Reply color="primary" />
|
||||
</IconButton>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
export function ThemeEditorModal(props: IProps): React.ReactElement {
|
||||
type ThemeEditorProps = {
|
||||
onClose: () => void;
|
||||
onChange: () => void;
|
||||
open: boolean;
|
||||
};
|
||||
|
||||
export function ThemeEditorModal(props: ThemeEditorProps): React.ReactElement {
|
||||
const rerender = useRerender();
|
||||
|
||||
// Need to deep copy the object since it has nested attributes
|
||||
const [themeCopy, setThemeCopy] = useState<IScriptEditorTheme>(JSON.parse(JSON.stringify(Settings.EditorTheme)));
|
||||
|
||||
function onColorChange(name: string, value: string): void {
|
||||
setThemeCopy(_.set(themeCopy, name, value));
|
||||
function onThemePropChange(prop: string, value: string): void {
|
||||
_.set(Settings.EditorTheme, prop, value);
|
||||
props.onChange();
|
||||
rerender();
|
||||
}
|
||||
|
||||
@ -80,28 +76,28 @@ export function ThemeEditorModal(props: IProps): React.ReactElement {
|
||||
try {
|
||||
const importedTheme = JSON.parse(event.target.value);
|
||||
if (typeof importedTheme !== "object") return;
|
||||
setThemeCopy(importedTheme);
|
||||
Settings.EditorTheme = importedTheme;
|
||||
props.onChange();
|
||||
} catch (err) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
const onResetToDefault = () => {
|
||||
Settings.EditorTheme = defaultMonacoTheme;
|
||||
props.onChange();
|
||||
rerender();
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
open={props.open}
|
||||
onClose={() => {
|
||||
setThemeCopy(Settings.EditorTheme);
|
||||
props.onClose();
|
||||
}}
|
||||
>
|
||||
<Modal open={props.open} onClose={props.onClose}>
|
||||
<Typography variant="h4">Customize Editor theme</Typography>
|
||||
<Typography>Hover over input boxes for more information</Typography>
|
||||
<Paper sx={{ p: 1, my: 1 }}>
|
||||
<OptionSwitch
|
||||
checked={themeCopy.base === "vs"}
|
||||
checked={Settings.EditorTheme.base === "vs"}
|
||||
onChange={(val) => {
|
||||
setThemeCopy(_.set(themeCopy, "base", val ? "vs" : "vs-dark"));
|
||||
rerender();
|
||||
onThemePropChange("base", val ? "vs" : "vs-dark");
|
||||
}}
|
||||
text="Use light theme as base"
|
||||
tooltip={
|
||||
@ -111,133 +107,133 @@ export function ThemeEditorModal(props: IProps): React.ReactElement {
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<Box display="grid" sx={{ gridTemplateColumns: "1fr 1fr", width: "fit-content", gap: 1 }}>
|
||||
<Box>
|
||||
<Grid container gap={1} columns={2}>
|
||||
<Grid item>
|
||||
<Typography variant="h6">UI</Typography>
|
||||
<ColorEditor
|
||||
label="Background color"
|
||||
themePath="common.bg"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.common.bg}
|
||||
onColorChange={onThemePropChange}
|
||||
color={Settings.EditorTheme.common.bg}
|
||||
defaultColor={defaultMonacoTheme.common.bg}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Current line and minimap background color"
|
||||
themePath="ui.line"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.ui.line}
|
||||
onColorChange={onThemePropChange}
|
||||
color={Settings.EditorTheme.ui.line}
|
||||
defaultColor={defaultMonacoTheme.ui.line}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Base text color"
|
||||
themePath="common.fg"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.common.fg}
|
||||
onColorChange={onThemePropChange}
|
||||
color={Settings.EditorTheme.common.fg}
|
||||
defaultColor={defaultMonacoTheme.common.fg}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Popup background color"
|
||||
themePath="ui.panel.bg"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.ui.panel.bg}
|
||||
onColorChange={onThemePropChange}
|
||||
color={Settings.EditorTheme.ui.panel.bg}
|
||||
defaultColor={defaultMonacoTheme.ui.panel.bg}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Background color for selected item in popup"
|
||||
themePath="ui.panel.selected"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.ui.panel.selected}
|
||||
onColorChange={onThemePropChange}
|
||||
color={Settings.EditorTheme.ui.panel.selected}
|
||||
defaultColor={defaultMonacoTheme.ui.panel.selected}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Popup border color"
|
||||
themePath="ui.panel.border"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.ui.panel.border}
|
||||
onColorChange={onThemePropChange}
|
||||
color={Settings.EditorTheme.ui.panel.border}
|
||||
defaultColor={defaultMonacoTheme.ui.panel.border}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Background color of highlighted text"
|
||||
themePath="ui.selection.bg"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.ui.selection.bg}
|
||||
onColorChange={onThemePropChange}
|
||||
color={Settings.EditorTheme.ui.selection.bg}
|
||||
defaultColor={defaultMonacoTheme.ui.selection.bg}
|
||||
/>
|
||||
</Box>
|
||||
<Box>
|
||||
</Grid>
|
||||
<Grid item>
|
||||
<Typography variant="h6">Syntax</Typography>
|
||||
<ColorEditor
|
||||
label="Numbers, function names, and other key vars"
|
||||
themePath="common.accent"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.common.accent}
|
||||
onColorChange={onThemePropChange}
|
||||
color={Settings.EditorTheme.common.accent}
|
||||
defaultColor={defaultMonacoTheme.common.accent}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Keywords"
|
||||
themePath="syntax.keyword"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.syntax.keyword}
|
||||
onColorChange={onThemePropChange}
|
||||
color={Settings.EditorTheme.syntax.keyword}
|
||||
defaultColor={defaultMonacoTheme.syntax.keyword}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Strings"
|
||||
themePath="syntax.string"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.syntax.string}
|
||||
onColorChange={onThemePropChange}
|
||||
color={Settings.EditorTheme.syntax.string}
|
||||
defaultColor={defaultMonacoTheme.syntax.string}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Regexp literals as well as escapes within strings"
|
||||
themePath="syntax.regexp"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.syntax.regexp}
|
||||
onColorChange={onThemePropChange}
|
||||
color={Settings.EditorTheme.syntax.regexp}
|
||||
defaultColor={defaultMonacoTheme.syntax.regexp}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Constants"
|
||||
themePath="syntax.constant"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.syntax.constant}
|
||||
onColorChange={onThemePropChange}
|
||||
color={Settings.EditorTheme.syntax.constant}
|
||||
defaultColor={defaultMonacoTheme.syntax.constant}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Entities"
|
||||
themePath="syntax.entity"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.syntax.entity}
|
||||
onColorChange={onThemePropChange}
|
||||
color={Settings.EditorTheme.syntax.entity}
|
||||
defaultColor={defaultMonacoTheme.syntax.entity}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="'this', 'ns', types, and tags"
|
||||
themePath="syntax.tag"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.syntax.tag}
|
||||
onColorChange={onThemePropChange}
|
||||
color={Settings.EditorTheme.syntax.tag}
|
||||
defaultColor={defaultMonacoTheme.syntax.tag}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Netscript functions and constructors"
|
||||
themePath="syntax.markup"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.syntax.markup}
|
||||
onColorChange={onThemePropChange}
|
||||
color={Settings.EditorTheme.syntax.markup}
|
||||
defaultColor={defaultMonacoTheme.syntax.markup}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Errors"
|
||||
themePath="syntax.error"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.syntax.error}
|
||||
onColorChange={onThemePropChange}
|
||||
color={Settings.EditorTheme.syntax.error}
|
||||
defaultColor={defaultMonacoTheme.syntax.error}
|
||||
/>
|
||||
<ColorEditor
|
||||
label="Comments"
|
||||
themePath="syntax.comment"
|
||||
onColorChange={onColorChange}
|
||||
color={themeCopy.syntax.comment}
|
||||
onColorChange={onThemePropChange}
|
||||
color={Settings.EditorTheme.syntax.comment}
|
||||
defaultColor={defaultMonacoTheme.syntax.comment}
|
||||
/>
|
||||
</Box>
|
||||
</Box>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Paper>
|
||||
<Paper sx={{ p: 1 }}>
|
||||
<TextField
|
||||
@ -245,26 +241,11 @@ export function ThemeEditorModal(props: IProps): React.ReactElement {
|
||||
fullWidth
|
||||
maxRows={10}
|
||||
label={"import / export theme"}
|
||||
value={JSON.stringify(themeCopy, undefined, 2)}
|
||||
value={JSON.stringify(Settings.EditorTheme, undefined, 2)}
|
||||
onChange={onThemeChange}
|
||||
/>
|
||||
<Box sx={{ mt: 1 }}>
|
||||
<Button
|
||||
onClick={() => {
|
||||
Settings.EditorTheme = { ...themeCopy };
|
||||
props.onClose();
|
||||
}}
|
||||
startIcon={<Save />}
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setThemeCopy(defaultMonacoTheme);
|
||||
rerender();
|
||||
}}
|
||||
startIcon={<History />}
|
||||
>
|
||||
<Button onClick={onResetToDefault} startIcon={<History />}>
|
||||
Reset to default
|
||||
</Button>
|
||||
</Box>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useState } from "react";
|
||||
import React from "react";
|
||||
import * as monaco from "monaco-editor";
|
||||
|
||||
import Box from "@mui/material/Box";
|
||||
@ -17,9 +17,9 @@ import { makeTheme, sanitizeTheme } from "./themes";
|
||||
import { Modal } from "../../ui/React/Modal";
|
||||
import { Page } from "../../ui/Router";
|
||||
import { Router } from "../../ui/GameRoot";
|
||||
import { useBoolean } from "../../ui/React/hooks";
|
||||
import { Settings } from "../../Settings/Settings";
|
||||
import { OptionsModal } from "./OptionsModal";
|
||||
import { Options } from "./Options";
|
||||
import { OptionsModal, OptionsModalProps } from "./OptionsModal";
|
||||
import { useScriptEditorContext } from "./ScriptEditorContext";
|
||||
|
||||
type IStandaloneCodeEditor = monaco.editor.IStandaloneCodeEditor;
|
||||
@ -30,8 +30,8 @@ interface IProps {
|
||||
}
|
||||
|
||||
export function Toolbar({ editor, onSave }: IProps) {
|
||||
const [ramInfoOpen, setRamInfoOpen] = useState(false);
|
||||
const [optionsOpen, setOptionsOpen] = useState(false);
|
||||
const [ramInfoOpen, { on: openRAMInfo, off: closeRAMInfo }] = useBoolean(false);
|
||||
const [optionsOpen, { on: openOptions, off: closeOptions }] = useBoolean(false);
|
||||
|
||||
function beautify(): void {
|
||||
editor?.getAction("editor.action.formatDocument")?.run();
|
||||
@ -39,20 +39,24 @@ export function Toolbar({ editor, onSave }: IProps) {
|
||||
|
||||
const { ram, ramEntries, isUpdatingRAM, options, saveOptions } = useScriptEditorContext();
|
||||
|
||||
const onOptionChange: OptionsModalProps["onOptionChange"] = (option, value) => {
|
||||
saveOptions({ ...options, [option]: value });
|
||||
editor?.updateOptions(options);
|
||||
};
|
||||
|
||||
const onThemeChange = () => {
|
||||
sanitizeTheme(Settings.EditorTheme);
|
||||
monaco.editor.defineTheme("customTheme", makeTheme(Settings.EditorTheme));
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Box display="flex" flexDirection="row" sx={{ m: 1 }} alignItems="center">
|
||||
<Button startIcon={<SettingsIcon />} onClick={() => setOptionsOpen(true)} sx={{ mr: 1 }}>
|
||||
<Button startIcon={<SettingsIcon />} onClick={openOptions} sx={{ mr: 1 }}>
|
||||
Options
|
||||
</Button>
|
||||
<Button onClick={beautify}>Beautify</Button>
|
||||
<Button
|
||||
color={isUpdatingRAM ? "secondary" : "primary"}
|
||||
sx={{ mx: 1 }}
|
||||
onClick={() => {
|
||||
setRamInfoOpen(true);
|
||||
}}
|
||||
>
|
||||
<Button color={isUpdatingRAM ? "secondary" : "primary"} sx={{ mx: 1 }} onClick={openRAMInfo}>
|
||||
{ram}
|
||||
</Button>
|
||||
<Button onClick={onSave}>Save (Ctrl/Cmd + s)</Button>
|
||||
@ -76,20 +80,12 @@ export function Toolbar({ editor, onSave }: IProps) {
|
||||
</Box>
|
||||
<OptionsModal
|
||||
open={optionsOpen}
|
||||
onClose={() => {
|
||||
sanitizeTheme(Settings.EditorTheme);
|
||||
monaco.editor.defineTheme("customTheme", makeTheme(Settings.EditorTheme));
|
||||
setOptionsOpen(false);
|
||||
}}
|
||||
options={{ ...options }}
|
||||
save={(options: Options) => {
|
||||
sanitizeTheme(Settings.EditorTheme);
|
||||
monaco.editor.defineTheme("customTheme", makeTheme(Settings.EditorTheme));
|
||||
editor?.updateOptions(options);
|
||||
saveOptions(options);
|
||||
}}
|
||||
options={options}
|
||||
onClose={closeOptions}
|
||||
onOptionChange={onOptionChange}
|
||||
onThemeChange={onThemeChange}
|
||||
/>
|
||||
<Modal open={ramInfoOpen} onClose={() => setRamInfoOpen(false)}>
|
||||
<Modal open={ramInfoOpen} onClose={closeRAMInfo}>
|
||||
<Table>
|
||||
<TableBody>
|
||||
{ramEntries.map(([n, r]) => (
|
||||
|
@ -79,19 +79,21 @@ import { useRerender } from "./React/hooks";
|
||||
|
||||
const htmlLocation = location;
|
||||
|
||||
const useStyles = makeStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
root: {
|
||||
"-ms-overflow-style": "none" /* for Internet Explorer, Edge */,
|
||||
"scrollbar-width": "none" /* for Firefox */,
|
||||
margin: theme.spacing(0),
|
||||
flexGrow: 1,
|
||||
padding: "8px",
|
||||
minHeight: "100vh",
|
||||
boxSizing: "border-box",
|
||||
width: "1px",
|
||||
},
|
||||
}),
|
||||
const useStyles = makeStyles(
|
||||
(theme: Theme) =>
|
||||
createStyles({
|
||||
root: {
|
||||
"-ms-overflow-style": "none" /* for Internet Explorer, Edge */,
|
||||
"scrollbar-width": "none" /* for Firefox */,
|
||||
margin: theme.spacing(0),
|
||||
flexGrow: 1,
|
||||
padding: "8px",
|
||||
minHeight: "100vh",
|
||||
boxSizing: "border-box",
|
||||
width: "1px",
|
||||
},
|
||||
}),
|
||||
{ name: "GameRoot" },
|
||||
);
|
||||
|
||||
const uninitialized = (): void => {
|
||||
|
Loading…
Reference in New Issue
Block a user