Re-engineer UI in TypeScript (#89)

* Re-engineer UI in TypeScript
* Switch to named imports where possible
* Restructure file system layout
* Update depencencies
* Update README.md
* Change explicit colors for better support for dark theme
This commit is contained in:
rjwats
2020-02-09 10:21:13 +00:00
committed by GitHub
parent ea6aa78d60
commit 260e9a18d0
121 changed files with 7450 additions and 5963 deletions

View File

@ -1,83 +0,0 @@
import React, { Component } from 'react';
import { ValidatorForm } from 'react-material-ui-form-validator';
import { ENDPOINT_ROOT } from '../constants/Env';
import SectionContent from '../components/SectionContent';
import { restComponent } from '../components/RestComponent';
import LoadingNotification from '../components/LoadingNotification';
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
import Slider from '@material-ui/core/Slider';
import { makeStyles } from '@material-ui/core/styles';
import SaveIcon from '@material-ui/icons/Save';
export const DEMO_SETTINGS_ENDPOINT = ENDPOINT_ROOT + "demoSettings";
const valueToPercentage = (value) => `${Math.round(value / 255 * 100)}%`;
class DemoController extends Component {
componentDidMount() {
this.props.loadData();
}
render() {
const { data, fetched, errorMessage, saveData, loadData, handleSliderChange } = this.props;
return (
<SectionContent title="Controller" titleGutter>
<LoadingNotification
onReset={loadData}
fetched={fetched}
errorMessage={errorMessage}
render={() =>
<DemoControllerForm
demoSettings={data}
onReset={loadData}
onSubmit={saveData}
handleSliderChange={handleSliderChange}
/>
}
/>
</SectionContent>
)
}
}
const useStyles = makeStyles(theme => ({
button: {
marginRight: theme.spacing(2),
marginTop: theme.spacing(2),
},
blinkSpeedLabel: {
marginBottom: theme.spacing(5),
}
}));
function DemoControllerForm(props) {
const { demoSettings, onSubmit, onReset, handleSliderChange } = props;
const classes = useStyles();
return (
<ValidatorForm onSubmit={onSubmit}>
<Typography id="blink-speed-slider" className={classes.blinkSpeedLabel}>
Blink Speed
</Typography>
<Slider
value={demoSettings.blink_speed}
valueLabelFormat={valueToPercentage}
aria-labelledby="blink-speed-slider"
valueLabelDisplay="on"
min={0}
max={255}
onChange={handleSliderChange('blink_speed')}
/>
<Button startIcon={<SaveIcon />} variant="contained" color="primary" className={classes.button} type="submit">
Save
</Button>
<Button variant="contained" color="secondary" className={classes.button} onClick={onReset}>
Reset
</Button>
</ValidatorForm>
);
}
export default restComponent(DEMO_SETTINGS_ENDPOINT, DemoController);

View File

@ -0,0 +1,75 @@
import React, { Component } from 'react';
import { ValidatorForm } from 'react-material-ui-form-validator';
import { Typography, Slider, Box } from '@material-ui/core';
import SaveIcon from '@material-ui/icons/Save';
import { ENDPOINT_ROOT } from '../api';
import { restController, RestControllerProps, RestFormLoader, RestFormProps, FormActions, FormButton, SectionContent } from '../components';
export const DEMO_SETTINGS_ENDPOINT = ENDPOINT_ROOT + "demoSettings";
interface DemoSettings {
blink_speed: number;
}
type DemoControllerProps = RestControllerProps<DemoSettings>;
class DemoController extends Component<DemoControllerProps> {
componentDidMount() {
this.props.loadData();
}
render() {
return (
<SectionContent title='Demo Controller' titleGutter>
<RestFormLoader
{...this.props}
render={props => (
<DemoControllerForm {...props} />
)}
/>
</SectionContent>
)
}
}
export default restController(DEMO_SETTINGS_ENDPOINT, DemoController);
const valueToPercentage = (value: number) => `${Math.round(value / 255 * 100)}%`;
type DemoControllerFormProps = RestFormProps<DemoSettings>;
function DemoControllerForm(props: DemoControllerFormProps) {
const { data, saveData, loadData, handleSliderChange } = props;
return (
<ValidatorForm onSubmit={saveData}>
<Typography id="blink-speed-slider">
Blink Speed
</Typography>
<Box pt={5}>
<Slider
value={data.blink_speed}
valueLabelFormat={valueToPercentage}
aria-labelledby="blink-speed-slider"
valueLabelDisplay="on"
min={0}
max={255}
onChange={handleSliderChange('blink_speed')}
/>
</Box>
<FormActions>
<FormButton startIcon={<SaveIcon />} variant="contained" color="primary" type="submit">
Save
</FormButton>
<FormButton variant="contained" color="secondary" onClick={loadData}>
Reset
</FormButton>
</FormActions>
</ValidatorForm>
);
}

View File

@ -1,29 +1,14 @@
import React, { Component } from 'react';
import { withStyles } from '@material-ui/core/styles';
import Table from '@material-ui/core/Table';
import TableHead from '@material-ui/core/TableHead';
import TableCell from '@material-ui/core/TableCell';
import TableBody from '@material-ui/core/TableBody';
import TableRow from '@material-ui/core/TableRow';
import Typography from '@material-ui/core/Typography';
import SectionContent from '../components/SectionContent';
const styles = theme => ({
fileTable: {
marginBottom: theme.spacing(2)
}
});
import { Typography, TableRow, TableBody, TableCell, TableHead, Table, Box } from '@material-ui/core';
import { SectionContent } from '../components';
class DemoInformation extends Component {
render() {
const { classes } = this.props;
return (
<SectionContent title="Demo Project - Blink Speed Controller" titleGutter>
<SectionContent title='Demo Information' titleGutter>
<Typography variant="body1" paragraph>
This simple demo project allows you to control the blink speed of the built-in LED.
This simple demo project allows you to control the blink speed of the built-in LED.
It demonstrates how the esp8266-react framework may be extended for your own IoT project.
</Typography>
<Typography variant="body1" paragraph>
@ -34,7 +19,7 @@ class DemoInformation extends Component {
<Typography variant="body1" paragraph>
The demo project interface code stored in the interface/project directory:
</Typography>
<Table className={classes.fileTable}>
<Table>
<TableHead>
<TableRow>
<TableCell>
@ -48,7 +33,7 @@ class DemoInformation extends Component {
<TableBody>
<TableRow>
<TableCell>
ProjectMenu.js
ProjectMenu.tsx
</TableCell>
<TableCell>
You can add your project's screens to the side bar here.
@ -56,7 +41,7 @@ class DemoInformation extends Component {
</TableRow>
<TableRow>
<TableCell>
ProjectRouting.js
ProjectRouting.tsx
</TableCell>
<TableCell>
The routing which controls the screens of your project.
@ -64,7 +49,7 @@ class DemoInformation extends Component {
</TableRow>
<TableRow>
<TableCell>
DemoProject.js
DemoProject.tsx
</TableCell>
<TableCell>
This screen, with tabs and tab routing.
@ -72,29 +57,31 @@ class DemoInformation extends Component {
</TableRow>
<TableRow>
<TableCell>
DemoInformation.js
DemoInformation.tsx
</TableCell>
<TableCell>
The demo information tab.
The demo information page.
</TableCell>
</TableRow>
<TableRow>
<TableCell>
DemoController.js
DemoController.tsx
</TableCell>
<TableCell>
The demo controller tab, to control the built-in LED.
</TableCell>
</TableRow>
</TableRow>
</TableBody>
</Table>
<Typography variant="body1" paragraph>
See the project <a href="https://github.com/rjwats/esp8266-react/">README</a> for a full description of the demo project.
</Typography>
<Box mt={2}>
<Typography variant="body1">
See the project <a href="https://github.com/rjwats/esp8266-react/">README</a> for a full description of the demo project.
</Typography>
</Box>
</SectionContent>
)
}
}
export default withStyles(styles)(DemoInformation);
export default DemoInformation;

View File

@ -1,36 +1,36 @@
import React, { Component } from 'react';
import { Redirect, Switch } from 'react-router-dom'
import { Redirect, Switch, RouteComponentProps } from 'react-router-dom'
import { Tabs, Tab } from '@material-ui/core';
import { PROJECT_PATH } from '../api';
import { MenuAppBar } from '../components';
import { AuthenticatedRoute } from '../authentication';
import { PROJECT_PATH } from '../constants/Env';
import MenuAppBar from '../components/MenuAppBar';
import AuthenticatedRoute from '../authentication/AuthenticatedRoute';
import DemoInformation from './DemoInformation';
import DemoController from './DemoController';
import Tabs from '@material-ui/core/Tabs';
import Tab from '@material-ui/core/Tab';
class DemoProject extends Component<RouteComponentProps> {
class DemoProject extends Component {
handleTabChange = (event, path) => {
handleTabChange = (event: React.ChangeEvent<{}>, path: string) => {
this.props.history.push(path);
};
render() {
return (
<MenuAppBar sectionTitle="Demo Project">
<Tabs value={this.props.match.url} onChange={this.handleTabChange} indicatorColor="primary" textColor="primary" variant="fullWidth">
<Tab value={`/${PROJECT_PATH}/demo/information`} label="Information" />
<Tab value={`/${PROJECT_PATH}/demo/controller`} label="Controller" />
<Tabs value={this.props.match.url} onChange={this.handleTabChange} variant="fullWidth">
<Tab value={`/${PROJECT_PATH}/demo/information`} label="Demo Information" />
<Tab value={`/${PROJECT_PATH}/demo/controller`} label="Demo Controller" />
</Tabs>
<Switch>
<AuthenticatedRoute exact path={`/${PROJECT_PATH}/demo/information`} component={DemoInformation} />
<AuthenticatedRoute exact path={`/${PROJECT_PATH}/demo/controller`} component={DemoController} />
<Redirect to={`/${PROJECT_PATH}/demo/information`} />
<Redirect to={`/${PROJECT_PATH}/demo/information`} />
</Switch>
</MenuAppBar>
)
}
}
}

View File

@ -1,15 +1,12 @@
import React, { Component } from 'react';
import { Link, withRouter } from 'react-router-dom';
import { Link, withRouter, RouteComponentProps } from 'react-router-dom';
import { PROJECT_PATH } from '../constants/Env';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import ListItemIcon from '@material-ui/core/ListItemIcon';
import ListItemText from '@material-ui/core/ListItemText';
import {List, ListItem, ListItemIcon, ListItemText} from '@material-ui/core';
import SettingsRemoteIcon from '@material-ui/icons/SettingsRemote';
class ProjectMenu extends Component {
import { PROJECT_PATH } from '../api';
class ProjectMenu extends Component<RouteComponentProps> {
render() {
const path = this.props.match.url;

View File

@ -1,8 +1,9 @@
import React, { Component } from 'react';
import { Redirect, Switch } from 'react-router';
import { PROJECT_PATH } from '../constants/Env';
import AuthenticatedRoute from '../authentication/AuthenticatedRoute';
import { PROJECT_PATH } from '../api';
import { AuthenticatedRoute } from '../authentication';
import DemoProject from './DemoProject';
class ProjectRouting extends Component {