Files
bitburner-src/src/ScriptEditor/ui/ThemeEditorModal.tsx
T
2023-06-17 17:58:56 -04:00

256 lines
8.8 KiB
TypeScript

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 { Settings } from "../../Settings/Settings";
import { useRerender } from "../../ui/React/hooks";
import { Modal } from "../../ui/React/Modal";
import { OptionSwitch } from "../../ui/React/OptionSwitch";
import { defaultMonacoTheme } from "./themes";
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 }: 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={{
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>
);
}
type ThemeEditorProps = {
onClose: () => void;
onChange: () => void;
open: boolean;
};
export function ThemeEditorModal(props: ThemeEditorProps): React.ReactElement {
const rerender = useRerender();
function onThemePropChange(prop: string, value: string): void {
_.set(Settings.EditorTheme, prop, value);
props.onChange();
rerender();
}
function onThemeChange(event: React.ChangeEvent<HTMLInputElement>): void {
try {
const importedTheme = JSON.parse(event.target.value);
if (typeof importedTheme !== "object") return;
Settings.EditorTheme = importedTheme;
props.onChange();
} catch (err) {
// ignore
}
}
const onResetToDefault = () => {
Settings.EditorTheme = defaultMonacoTheme;
props.onChange();
rerender();
};
return (
<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={Settings.EditorTheme.base === "vs"}
onChange={(val) => {
onThemePropChange("base", val ? "vs" : "vs-dark");
}}
text="Use light theme as base"
tooltip={
<>
If enabled, the <code>vs</code> light theme will be used as the theme base, otherwise,{" "}
<code>vs-dark</code> will be used.
</>
}
/>
<Grid container gap={1} columns={2}>
<Grid item>
<Typography variant="h6">UI</Typography>
<ColorEditor
label="Background color"
themePath="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={onThemePropChange}
color={Settings.EditorTheme.ui.line}
defaultColor={defaultMonacoTheme.ui.line}
/>
<ColorEditor
label="Base text color"
themePath="common.fg"
onColorChange={onThemePropChange}
color={Settings.EditorTheme.common.fg}
defaultColor={defaultMonacoTheme.common.fg}
/>
<ColorEditor
label="Popup background color"
themePath="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={onThemePropChange}
color={Settings.EditorTheme.ui.panel.selected}
defaultColor={defaultMonacoTheme.ui.panel.selected}
/>
<ColorEditor
label="Popup border color"
themePath="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={onThemePropChange}
color={Settings.EditorTheme.ui.selection.bg}
defaultColor={defaultMonacoTheme.ui.selection.bg}
/>
</Grid>
<Grid item>
<Typography variant="h6">Syntax</Typography>
<ColorEditor
label="Numbers, function names, and other key vars"
themePath="common.accent"
onColorChange={onThemePropChange}
color={Settings.EditorTheme.common.accent}
defaultColor={defaultMonacoTheme.common.accent}
/>
<ColorEditor
label="Keywords"
themePath="syntax.keyword"
onColorChange={onThemePropChange}
color={Settings.EditorTheme.syntax.keyword}
defaultColor={defaultMonacoTheme.syntax.keyword}
/>
<ColorEditor
label="Strings"
themePath="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={onThemePropChange}
color={Settings.EditorTheme.syntax.regexp}
defaultColor={defaultMonacoTheme.syntax.regexp}
/>
<ColorEditor
label="Constants"
themePath="syntax.constant"
onColorChange={onThemePropChange}
color={Settings.EditorTheme.syntax.constant}
defaultColor={defaultMonacoTheme.syntax.constant}
/>
<ColorEditor
label="Entities"
themePath="syntax.entity"
onColorChange={onThemePropChange}
color={Settings.EditorTheme.syntax.entity}
defaultColor={defaultMonacoTheme.syntax.entity}
/>
<ColorEditor
label="'this', 'ns', types, and tags"
themePath="syntax.tag"
onColorChange={onThemePropChange}
color={Settings.EditorTheme.syntax.tag}
defaultColor={defaultMonacoTheme.syntax.tag}
/>
<ColorEditor
label="Netscript functions and constructors"
themePath="syntax.markup"
onColorChange={onThemePropChange}
color={Settings.EditorTheme.syntax.markup}
defaultColor={defaultMonacoTheme.syntax.markup}
/>
<ColorEditor
label="Errors"
themePath="syntax.error"
onColorChange={onThemePropChange}
color={Settings.EditorTheme.syntax.error}
defaultColor={defaultMonacoTheme.syntax.error}
/>
<ColorEditor
label="Comments"
themePath="syntax.comment"
onColorChange={onThemePropChange}
color={Settings.EditorTheme.syntax.comment}
defaultColor={defaultMonacoTheme.syntax.comment}
/>
</Grid>
</Grid>
</Paper>
<Paper sx={{ p: 1 }}>
<TextField
multiline
fullWidth
maxRows={10}
label={"import / export theme"}
value={JSON.stringify(Settings.EditorTheme, undefined, 2)}
onChange={onThemeChange}
/>
<Box sx={{ mt: 1 }}>
<Button onClick={onResetToDefault} startIcon={<History />}>
Reset to default
</Button>
</Box>
</Paper>
</Modal>
);
}