mirror of
https://github.com/pybricks/pybricks-code.git
synced 2026-09-12 01:23:52 +00:00
add dark mode setting
This commit is contained in:
@@ -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));
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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 => ({
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
{
|
||||
"settings": {
|
||||
"title": "Settings"
|
||||
"title": "Settings",
|
||||
"appearance": {
|
||||
"title": "Appearance",
|
||||
"dark-mode": {
|
||||
"label": "Dark mode"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,4 +5,6 @@
|
||||
|
||||
export enum SettingsStringId {
|
||||
Title = 'settings.title',
|
||||
AppearanceTitle = 'settings.appearance.title',
|
||||
AppearanceDarkModeLabel = 'settings.appearance.dark-mode.label',
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright (c) 2021 The Pybricks Authors
|
||||
|
||||
.pb-settings {
|
||||
margin: 25px;
|
||||
}
|
||||
Reference in New Issue
Block a user