add dark mode setting

This commit is contained in:
David Lechner
2021-01-11 23:36:48 -06:00
parent 41a1cee092
commit d7dbaaa12d
12 changed files with 156 additions and 21 deletions
+15 -5
View File
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020 The Pybricks Authors
// Copyright (c) 2020-2021 The Pybricks Authors
import {
ContextMenuTarget,
@@ -16,10 +16,12 @@ import { IAceEditor } from 'react-ace/lib/types';
import { connect } from 'react-redux';
import { Action, Dispatch } from '../actions';
import { setEditSession, storageChanged } from '../actions/editor';
import { RootState } from '../reducers';
import { EditorStringId } from './editor-i18n';
import en from './editor-i18n.en.json';
import 'ace-builds/src-noconflict/mode-python';
import 'ace-builds/src-noconflict/theme-tomorrow_night_eighties';
import 'ace-builds/src-noconflict/theme-xcode';
import 'ace-builds/src-noconflict/ext-searchbox';
import 'ace-builds/src-noconflict/ext-keybinding_menu';
@@ -27,12 +29,16 @@ import 'ace-builds/src-noconflict/ext-language_tools';
import './editor-snippets';
type StateProps = {
darkMode: boolean;
};
type DispatchProps = {
onSessionChanged: (session?: Ace.EditSession) => void;
onProgramStorageChanged: (newValue: string) => void;
};
type EditorProps = DispatchProps & WithI18nProps;
type EditorProps = StateProps & DispatchProps & WithI18nProps;
@ContextMenuTarget
class Editor extends React.Component<EditorProps> {
@@ -68,14 +74,14 @@ class Editor extends React.Component<EditorProps> {
}
render(): JSX.Element {
const { i18n, onSessionChanged } = this.props;
const { darkMode, i18n, onSessionChanged } = this.props;
return (
<div className="h-100 watermark">
<ResizeSensor onResize={(): void => this.editor?.resize()}>
<AceEditor
ref={this.editorRef}
mode="python"
theme="xcode"
theme={darkMode ? 'tomorrow_night_eighties' : 'xcode'}
fontSize="16pt"
width="100%"
height="100%"
@@ -171,12 +177,16 @@ class Editor extends React.Component<EditorProps> {
}
}
const mapStateToProps = (state: RootState): StateProps => ({
darkMode: state.settings.darkMode,
});
const mapDispatchToProps = (dispatch: Dispatch): DispatchProps => ({
onSessionChanged: (s): Action => dispatch(setEditSession(s)),
onProgramStorageChanged: (v): Action => dispatch(storageChanged(v)),
});
export default connect(
undefined,
mapStateToProps,
mapDispatchToProps,
)(withI18n({ id: 'editor', fallback: en, translations: { en } })(Editor));
+23 -3
View File
@@ -1,46 +1,66 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2021 The Pybricks Authors
import { Drawer } from '@blueprintjs/core';
import { Drawer, FormGroup, Switch } from '@blueprintjs/core';
import { WithI18nProps, withI18n } from '@shopify/react-i18n';
import React from 'react';
import { connect } from 'react-redux';
import { Action, Dispatch } from '../actions';
import { closeSettings } from '../actions/app';
import { toggleDarkMode } from '../actions/settings';
import { RootState } from '../reducers';
import { SettingsStringId } from './settings-i18n';
import en from './settings-i18n.en.json';
import './settings.scss';
type StateProps = {
open: boolean;
darkMode: boolean;
};
type DispatchProps = {
onClose: () => void;
onDarkModeChanged: () => void;
};
type SettingsProps = StateProps & DispatchProps & WithI18nProps;
class SettingsDrawer extends React.PureComponent<SettingsProps> {
render(): JSX.Element {
const { i18n, open, onClose } = this.props;
const { i18n, open, onClose, darkMode, onDarkModeChanged } = this.props;
return (
<Drawer
isOpen={open}
icon="cog"
title={i18n.translate(SettingsStringId.Title)}
onClose={() => onClose()}
></Drawer>
>
<div className="pb-settings">
<FormGroup label={i18n.translate(SettingsStringId.AppearanceTitle)}>
<Switch
label={i18n.translate(
SettingsStringId.AppearanceDarkModeLabel,
)}
large={true}
checked={darkMode}
onChange={() => onDarkModeChanged()}
/>
</FormGroup>
</div>
</Drawer>
);
}
}
const mapStateToProps = (state: RootState): StateProps => ({
open: state.app.showSettings,
darkMode: state.settings.darkMode,
});
const mapDispatchToProps = (dispatch: Dispatch): DispatchProps => ({
onClose: (): Action => dispatch(closeSettings()),
onDarkModeChanged: (): Action => dispatch(toggleDarkMode()),
});
export default connect(
+12 -8
View File
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2020 The Pybricks Authors
// Copyright (c) 2020-2021 The Pybricks Authors
import {
ContextMenuTarget,
@@ -24,6 +24,7 @@ import 'xterm/css/xterm.css';
interface StateProps {
dataSource: Observable<string> | null;
darkMode: boolean;
}
interface DispatchProps {
@@ -45,13 +46,6 @@ class Terminal extends React.Component<TerminalProps> {
cursorBlink: true,
cursorStyle: 'underline',
fontSize: 18,
theme: {
background: 'white',
foreground: 'black',
cursor: 'black',
// transparency is needed to work around https://github.com/xtermjs/xterm.js/issues/2808
selection: 'rgba(181,213,255,0.5)', // this should match AceEditor theme
},
});
this.fitAddon = new FitAddon();
this.xterm.loadAddon(this.fitAddon);
@@ -112,6 +106,15 @@ class Terminal extends React.Component<TerminalProps> {
}
render(): JSX.Element {
this.xterm.setOption('theme', {
background: this.props.darkMode ? 'black' : 'white',
foreground: this.props.darkMode ? 'white' : 'black',
cursor: this.props.darkMode ? 'white' : 'black',
// transparency is needed to work around https://github.com/xtermjs/xterm.js/issues/2808
selection: this.props.darkMode
? 'rgb(81,81,81,0.5)'
: 'rgba(181,213,255,0.5)', // this should match AceEditor theme
});
return (
<div className="h-100">
<ResizeSensor onResize={(): void => this.fitAddon.fit()}>
@@ -163,6 +166,7 @@ class Terminal extends React.Component<TerminalProps> {
const mapStateToProps = (state: RootState): StateProps => ({
dataSource: state.terminal.dataSource,
darkMode: state.settings.darkMode,
});
const mapDispatchToProps = (dispatch: Dispatch): DispatchProps => ({
+7 -1
View File
@@ -1,5 +1,11 @@
{
"settings": {
"title": "Settings"
"title": "Settings",
"appearance": {
"title": "Appearance",
"dark-mode": {
"label": "Dark mode"
}
}
}
}
+2
View File
@@ -5,4 +5,6 @@
export enum SettingsStringId {
Title = 'settings.title',
AppearanceTitle = 'settings.appearance.title',
AppearanceDarkModeLabel = 'settings.appearance.dark-mode.label',
}
+6
View File
@@ -0,0 +1,6 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2021 The Pybricks Authors
.pb-settings {
margin: 25px;
}