Skip to content

Commit

Permalink
Merge pull request Place1#8 from vincentbitter/Design
Browse files Browse the repository at this point in the history
Design improvements
  • Loading branch information
Place1 authored Dec 12, 2019
2 parents b13b7db + 35d917a commit 248f8e5
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 85 deletions.
Binary file modified screenshots/get-connected-ios.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified screenshots/get-connected-windows.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion website/public/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="viewport" content="minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
Expand Down
181 changes: 120 additions & 61 deletions website/src/components/AddDevice.tsx
Original file line number Diff line number Diff line change
@@ -1,47 +1,77 @@
import React from 'react';
import Card from '@material-ui/core/Card';
import CardHeader from '@material-ui/core/CardHeader';
import CardContent from '@material-ui/core/CardContent';

import AddIcon from '@material-ui/icons/Add';
import CardActions from '@material-ui/core/CardActions';
import Button from '@material-ui/core/Button';
import TextField from '@material-ui/core/TextField';
import Container from '@material-ui/core/Container';
import Dialog from '@material-ui/core/Dialog';
import DialogTitle from '@material-ui/core/DialogTitle';
import DialogContent from '@material-ui/core/DialogContent';
import DialogActions from '@material-ui/core/DialogActions';
import Fab from '@material-ui/core/Fab';
import FormControl from '@material-ui/core/FormControl';
import FormHelperText from '@material-ui/core/FormHelperText';
import Grid from '@material-ui/core/Grid';
import Input from '@material-ui/core/Input';
import InputLabel from '@material-ui/core/InputLabel';
import Paper from '@material-ui/core/Paper';
import Typography from '@material-ui/core/Typography';

import qrcode from 'qrcode';
import { view } from 'react-easy-state';
import { box_keyPair } from 'tweetnacl-ts';
import { codeBlock } from 'common-tags';
import { FormHelperText } from '@material-ui/core';
import { makeStyles } from '@material-ui/core/styles';

import { GetConnected } from './GetConnected';
import { IDevice, AppState } from '../Store';

class AddDevice extends React.Component {
state = {
name: '',
open: false,
qrCodeUri: '',
configFileUri: '',
error: '',
const useStyles = makeStyles(theme => ({
hidden: {
display: 'none',
},
button: {
margin: theme.spacing(1),
},
fabButton: {
position: 'absolute',
margin: '0 auto',
left: 0,
right: 0,
},
paper: {
padding: theme.spacing(2),
},
}));

export default function AddDevice() {
const classes = useStyles();
const [formOpen, setFormOpen] = React.useState(false);
const [dialogOpen, setDialogOpen] = React.useState(false);
const [error, setError] = React.useState('');
const [name, setName] = React.useState('');
const [qrCodeUri, setQrCodeUri] = React.useState('');
const [configFileUri, setConfigFileUri] = React.useState('');

var closeForm = () => {
setFormOpen(false);
setName('');
};

onAdd = async (event: React.FormEvent) => {
var addDevice = async (event: React.FormEvent) => {
event.preventDefault();

const keypair = box_keyPair();
const b64PublicKey = window.btoa(String.fromCharCode(...(new Uint8Array(keypair.publicKey) as any)));
const b64PrivateKey = window.btoa(String.fromCharCode(...(new Uint8Array(keypair.secretKey) as any)));

const res = await fetch('/api/devices', {
method: 'POST',
body: JSON.stringify({
name: this.state.name,
name: name,
publicKey: b64PublicKey,
}),
});
if (res.status >= 400) {
this.setState({ error: await res.text() });
setError(await res.text());
return;
}
const { device } = (await res.json()) as { device: IDevice };
Expand All @@ -60,49 +90,78 @@ class AddDevice extends React.Component {
Endpoint = ${device.endpoint || `${window.location.hostname}:51820`}
`;

this.setState({
open: true,
qrCodeUri: await qrcode.toDataURL(configFile),
configFileUri: URL.createObjectURL(new Blob([configFile])),
});
};
setQrCodeUri(await qrcode.toDataURL(configFile));
setConfigFileUri(URL.createObjectURL(new Blob([configFile])));

render() {
return (
<form onSubmit={this.onAdd}>
<Card>
<CardHeader title="Add a device" />
<CardContent>
<TextField
label="Device Name"
error={this.state.error !== ''}
value={this.state.name}
onChange={event => this.setState({ name: event.currentTarget.value })}
style={{ marginTop: -20, marginBottom: 8 }}
fullWidth
/>
{this.state.error !== '' && <FormHelperText>{this.state.error}</FormHelperText>}
</CardContent>
<CardActions>
<Button color="primary" variant="contained" endIcon={<AddIcon />} type="submit">
Add
</Button>
<Dialog disableBackdropClick disableEscapeKeyDown maxWidth="xl" open={this.state.open}>
<DialogTitle>Get Connected</DialogTitle>
<DialogContent>
<GetConnected qrCodeUri={this.state.qrCodeUri} configFileUri={this.state.configFileUri} />
</DialogContent>
<DialogActions>
<Button color="secondary" variant="outlined" onClick={() => this.setState({ open: false })}>
Done
</Button>
</DialogActions>
</Dialog>
</CardActions>
</Card>
</form>
);
}
}
closeForm();
setDialogOpen(true);
};

export default view(AddDevice);
return (
<React.Fragment>
<Grid container spacing={3}>
<Grid item xs></Grid>
<Grid item xs={12} md={4} lg={6}>
<Container hidden={formOpen}>
<Fab color="secondary" aria-label="add" className={classes.fabButton} onClick={() => setFormOpen(true)}>
<AddIcon />
</Fab>
</Container>
<Paper hidden={!formOpen} className={classes.paper}>
<form onSubmit={addDevice}>
<FormControl error={error != ''} fullWidth>
<InputLabel htmlFor="device-name">Device Name</InputLabel>
<Input
id="device-name"
value={name}
onChange={(event) => setName(event.currentTarget.value)}
aria-describedby="device-name-text"
/>
<FormHelperText id="device-name-text">{error}</FormHelperText>
</FormControl>
<Typography component="div" align="right">
<Button
color="secondary"
type="button"
onClick={closeForm}
className={classes.button}
>
Cancel
</Button>
<Button
color="primary"
variant="contained"
endIcon={<AddIcon />}
type="submit"
className={classes.button}
>
Next
</Button>
</Typography>
</form>
</Paper>
</Grid>
<Grid item xs></Grid>
</Grid>
<Dialog
disableBackdropClick
disableEscapeKeyDown
maxWidth="xl"
open={dialogOpen}
>
<DialogTitle>Get Connected</DialogTitle>
<DialogContent>
<GetConnected
qrCodeUri={qrCodeUri}
configFileUri={configFileUri}
/>
</DialogContent>
<DialogActions>
<Button color="secondary" variant="outlined" onClick={() => setDialogOpen(false)}>
Done
</Button>
</DialogActions>
</Dialog>
</React.Fragment>
);
}
10 changes: 2 additions & 8 deletions website/src/components/Devices.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,9 @@ class Devices extends React.Component {

render() {
return (
<Grid container spacing={3} style={{ padding: '1rem' }}>
<Grid item xs={12} sm={6}>
<h1>Your Devices</h1>
</Grid>
<Grid item xs={12} sm={6}>
<AddDevice />
</Grid>
<Grid container spacing={3}>
{AppState.devices.map((device, i) => (
<Grid key={i} item xs={12} sm={6}>
<Grid key={i} item xs={12} sm={6} md={4} lg={3}>
<Device device={device} />
</Grid>
))}
Expand Down
25 changes: 25 additions & 0 deletions website/src/components/Navigation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import Typography from '@material-ui/core/Typography';

const useStyles = makeStyles(theme => ({
title: {
flexGrow: 1,
},
}));

export default function Navigation() {
const classes = useStyles();

return (
<AppBar position="static">
<Toolbar>
<Typography variant="h6" className={classes.title}>
Your Devices
</Typography>
</Toolbar>
</AppBar>
);
}
13 changes: 0 additions & 13 deletions website/src/index.css

This file was deleted.

16 changes: 14 additions & 2 deletions website/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
import React from 'react';
import ReactDOM from 'react-dom';
import CssBaseline from '@material-ui/core/CssBaseline';
import Box from '@material-ui/core/Box';
import AddDevice from './components/AddDevice';
import Devices from './components/Devices';
import Navigation from './components/Navigation';
import { view } from 'react-easy-state';
import 'typeface-roboto';
import './index.css';

const App = view(() => {
return <Devices />;
return (
<React.Fragment>
<CssBaseline />
<Navigation />
<Box component="div" m={3}>
<Devices />
<AddDevice />
</Box>
</React.Fragment>
);
});

ReactDOM.render(<App />, document.getElementById('root'));

0 comments on commit 248f8e5

Please sign in to comment.