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:
@ -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);
|
75
interface/src/project/DemoController.tsx
Normal file
75
interface/src/project/DemoController.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -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;
|
@ -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>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
@ -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 {
|
Reference in New Issue
Block a user