add basic about dialog

This commit is contained in:
David Lechner
2021-01-15 12:51:52 -06:00
parent efb474b727
commit dcb432583c
12 changed files with 172 additions and 7 deletions
+63
View File
@@ -0,0 +1,63 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2021 The Pybricks Authors
// The about dialog
import { AnchorButton, Classes, Dialog } 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 { closeAboutDialog } from '../actions/app';
import { RootState } from '../reducers';
import {
appName,
legoDisclaimer,
pybricksCopyright,
pybricksWebsiteUrl,
} from '../settings/ui';
import { AboutStringId } from './about-i18n';
import en from './about-i18n.en.json';
type StateProps = { showAboutDialog: boolean };
type DispatchProps = { onClose: () => void };
type AboutDialogProps = StateProps & DispatchProps & WithI18nProps;
class AboutDialog extends React.Component<AboutDialogProps> {
render(): JSX.Element {
const { i18n, showAboutDialog, onClose } = this.props;
return (
<Dialog title={appName} isOpen={showAboutDialog} onClose={() => onClose()}>
<div className={Classes.DIALOG_BODY}>
<p>
<strong>{i18n.translate(AboutStringId.Description)}</strong>
</p>
<p>{pybricksCopyright}</p>
</div>
<div className={Classes.DIALOG_FOOTER}>
<p>{legoDisclaimer}</p>
<div className={Classes.DIALOG_FOOTER_ACTIONS}>
<AnchorButton href={pybricksWebsiteUrl} target="blank_">
{i18n.translate(AboutStringId.WebsiteButtonLabel)}
</AnchorButton>
</div>
</div>
</Dialog>
);
}
}
const mapStateToProps = (state: RootState): StateProps => ({
showAboutDialog: state.app.showAboutDialog,
});
const mapDispatchToProps = (dispatch: Dispatch): DispatchProps => ({
onClose: (): Action => dispatch(closeAboutDialog()),
});
export default connect(
mapStateToProps,
mapDispatchToProps,
)(withI18n({ id: 'about', fallback: en, translations: { en } })(AboutDialog));
+2
View File
@@ -5,6 +5,7 @@ import React, { useState } from 'react';
import { useSelector } from 'react-redux';
import SplitterLayout from 'react-splitter-layout';
import { RootState } from '../reducers';
import AboutDialog from './AboutDialog';
import Editor from './Editor';
import SettingsDrawer from './SettingsDrawer';
import StatusBar from './StatusBar';
@@ -64,6 +65,7 @@ function App(): JSX.Element {
</SplitterLayout>
<StatusBar />
<SettingsDrawer />
<AboutDialog key="about" />
</div>
);
}
+14 -1
View File
@@ -6,7 +6,7 @@ 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 { closeSettings, openAboutDialog } from '../actions/app';
import { setBoolean } from '../actions/settings';
import { RootState } from '../reducers';
import { tooltipDelay } from '../settings/ui';
@@ -29,6 +29,7 @@ type DispatchProps = {
onShowDocsChanged: (checked: boolean) => void;
onDarkModeChanged: (checked: boolean) => void;
onFlashCurrentProgramChanged: (checked: boolean) => void;
onAbout: () => void;
};
type SettingsProps = StateProps & DispatchProps & WithI18nProps;
@@ -45,6 +46,7 @@ class SettingsDrawer extends React.PureComponent<SettingsProps> {
onDarkModeChanged,
flashCurrentProgram,
onFlashCurrentProgramChanged,
onAbout,
} = this.props;
return (
<Drawer
@@ -131,6 +133,16 @@ class SettingsDrawer extends React.PureComponent<SettingsProps> {
/>
</Tooltip>
</FormGroup>
<FormGroup label={i18n.translate(SettingsStringId.HelpTitle)}>
<a
onClick={() => {
onAbout();
return true;
}}
>
{i18n.translate(SettingsStringId.HelpAboutLabel)}
</a>
</FormGroup>
</div>
</Drawer>
);
@@ -152,6 +164,7 @@ const mapDispatchToProps = (dispatch: Dispatch): DispatchProps => ({
dispatch(setBoolean(SettingId.DarkMode, checked)),
onFlashCurrentProgramChanged: (checked): Action =>
dispatch(setBoolean(SettingId.FlashCurrentProgram, checked)),
onAbout: (): Action => dispatch(openAboutDialog()),
});
export default connect(
+6
View File
@@ -0,0 +1,6 @@
{
"about": {
"description": "A simple web app for programming LEGO® Powered Up smart hubs using Pybricks MicroPython.",
"websiteButton": { "label": "Pybricks Website" }
}
}
+12
View File
@@ -0,0 +1,12 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2021 The Pybricks Authors
import { lookup } from '../../test';
import { AboutStringId } from './about-i18n';
import en from './about-i18n.en.json';
describe('Ensure .json file has matches for AboutStringId', () => {
test.each(Object.values(AboutStringId))('%s', (id) => {
expect(lookup(en, id)).toBeDefined();
});
});
+9
View File
@@ -0,0 +1,9 @@
// SPDX-License-Identifier: MIT
// Copyright (c) 2021 The Pybricks Authors
// About dialog translation keys.
export enum AboutStringId {
Description = 'about.description',
WebsiteButtonLabel = 'about.websiteButton.label',
}
+7 -1
View File
@@ -1,6 +1,6 @@
{
"settings": {
"title": "Settings",
"title": "Settings & Help",
"appearance": {
"title": "Appearance",
"documentation": {
@@ -21,6 +21,12 @@
"label": "Include current program",
"tooltip": "Select to include your program when installing the firmware."
}
},
"help": {
"title": "Help",
"about": {
"label": "About"
}
}
}
}
+2
View File
@@ -14,4 +14,6 @@ export enum SettingsStringId {
FirmwareTitle = 'settings.firmware.title',
FirmwareCurrentProgramLabel = 'settings.firmware.flash-current-program.label',
FirmwareCurrentProgramTooltip = 'settings.firmware.flash-current-program.tooltip',
HelpTitle = 'settings.help.title',
HelpAboutLabel = 'settings.help.about.label',
}
+4
View File
@@ -15,3 +15,7 @@
.pb-settings .bp3-form-helper-text {
font-size: 14px;
}
.pb-settings a {
font-size: 16px;
}