Merge branch 'master' into add-new-blocks

This commit is contained in:
Mario
2020-07-26 12:15:57 +02:00
42 changed files with 462 additions and 123 deletions
+4 -4
View File
@@ -1,6 +1,6 @@
#blocklyDiv {
height: 90vH;
width: 50%;
position: absolute;
bottom: 0;
height: 100%;
min-height: 500px;
width: 100%;
border: 1px solid #4EAF47;
}
+85
View File
@@ -0,0 +1,85 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { onChangeWorkspace } from '../../actions/workspaceActions';
import BlocklyComponent, { Block, Value, Field, Shadow, Category } from './';
import * as Blockly from 'blockly/core';
import * as De from './msg/de'; // de locale files
//import * as En from './Blockly/msg/en'; // de locale files
import './blocks/index';
import './generator/index';
class BlocklyWindow extends Component {
constructor(props) {
super(props);
this.simpleWorkspace = React.createRef();
}
componentDidMount() {
const workspace = Blockly.getMainWorkspace();
this.props.onChangeWorkspace({});
workspace.addChangeListener((event) => {
this.props.onChangeWorkspace(event);
});
}
render() {
return (
<BlocklyComponent ref={this.simpleWorkspace}
readOnly={false}
trashcan={true}
zoom={{ // https://developers.google.com/blockly/guides/configure/web/zoom
controls: true,
wheel: true,
startScale: 1.0,
maxScale: 3,
minScale: 0.3,
scaleSpeed: 1.2
}}
grid={{ // https://developers.google.com/blockly/guides/configure/web/grid
spacing: 20,
length: 1,
colour: '#4EAF47', // senseBox-green
snap: false
}}
media={'media/'}
move={{ // https://developers.google.com/blockly/guides/configure/web/move
scrollbars: true,
drag: true,
wheel: false
}}
initialXml={''}
>
<Category name="loops" >
<Block type="controls_for" />
<Block type="controls_repeat_ext" />
<Block type="controls_whileUntil" />
</Category>
<Category name="senseBox" colour="120" >
<Category name="Sensoren" colour="120" >
<Block type="sensebox_sensor_temp_hum"></Block>
</Category>
<Block type="sensebox_telegram" />
</Category>
<Category name="Logic" colour="#b063c5">
<Block type="control_if"></Block>
<Block type="controls_ifelse"></Block>
<Block type="logic_compare"></Block>
<Block type="logic_operation"></Block>
<Block type="logic_negate"></Block>
<Block type="logic_boolean"></Block>
</Category>
</BlocklyComponent>
);
};
}
BlocklyWindow.propTypes = {
onChangeWorkspace: PropTypes.func.isRequired
};
export default connect(null, { onChangeWorkspace })(BlocklyWindow);
+10 -8
View File
@@ -1,7 +1,9 @@
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { clearStats } from '../actions/workspaceActions';
import { clearStats, workspaceChange } from '../actions/workspaceActions';
import * as Blockly from 'blockly/core';
import ListItem from '@material-ui/core/ListItem';
import ListItemIcon from '@material-ui/core/ListItemIcon';
@@ -13,7 +15,10 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
class ClearWorkspace extends Component {
clearWorkspace = () => {
this.props.newWorkspace.clear();
const workspace = Blockly.getMainWorkspace();
workspace.clear();
workspace.options.maxBlocks = Infinity;
this.props.workspaceChange();
this.props.clearStats();
}
@@ -28,12 +33,9 @@ class ClearWorkspace extends Component {
}
ClearWorkspace.propTypes = {
newWorkspace: PropTypes.object.isRequired,
clearStats: PropTypes.func.isRequired
clearStats: PropTypes.func.isRequired,
workspaceChange: PropTypes.func.isRequired
};
const mapStateToProps = state => ({
newWorkspace: state.workspace.new
});
export default connect(mapStateToProps, { clearStats })(ClearWorkspace);
export default connect(null, { clearStats, workspaceChange })(ClearWorkspace);
+128
View File
@@ -0,0 +1,128 @@
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import Prism from "prismjs";
import "prismjs/themes/prism.css";
import "prismjs/plugins/line-numbers/prism-line-numbers";
import "prismjs/plugins/line-numbers/prism-line-numbers.css";
import { withStyles } from '@material-ui/core/styles';
import MuiAccordion from '@material-ui/core/Accordion';
import MuiAccordionSummary from '@material-ui/core/AccordionSummary';
import MuiAccordionDetails from '@material-ui/core/AccordionDetails';
const Accordion = withStyles((theme) => ({
root: {
border: `1px solid ${theme.palette.secondary.main}`,
boxShadow: 'none',
'&:before': {
display: 'none',
},
'&$expanded': {
margin: 'auto',
},
},
expanded: {},
}))(MuiAccordion);
const AccordionSummary = withStyles((theme) => ({
root: {
backgroundColor: theme.palette.secondary.main,
borderBottom: `1px solid white`,
marginBottom: -1,
minHeight: 50,
'&$expanded': {
minHeight: 50,
},
},
content: {
'&$expanded': {
margin: '12px 0',
},
},
expanded: {},
}))(MuiAccordionSummary);
const AccordionDetails = withStyles((theme) => ({
root: {
padding: theme.spacing(2),
},
}))(MuiAccordionDetails);
class CodeViewer extends Component {
state = {
expanded: true
}
componentDidMount() {
Prism.highlightAll();
}
componentDidUpdate() {
Prism.highlightAll();
}
onChange = () => {
this.setState({ expanded: !this.state.expanded });
}
render() {
var curlyBrackets = '{ }';
var unequal = '<>';
return (
<div style={{height: '500px'}}>
<Accordion
square={true}
style={{margin: 0}}
expanded={this.state.expanded}
onChange={this.onChange}
>
<AccordionSummary>
<b style={{fontSize: '20px', marginRight: '5px', width: '35px'}}>{curlyBrackets}</b>
<div style={{margin: 'auto 5px 2px 0px'}}>Arduino Quellcode</div>
</AccordionSummary>
<AccordionDetails style={{padding: 0, height: 'calc(500px - 50px - 50px)', backgroundColor: 'white'}}>
<pre className="line-numbers" style={{paddingBottom: 0, width: '100%', overflow: 'auto', scrollbarWidth: 'thin', height: 'calc(100% - 30px)', margin: '15px 0', paddingTop: 0, whiteSpace: 'pre-wrap', backgroundColor: 'white'}}>
<code className="language-clike">
{this.props.arduino}
</code>
</pre>
</AccordionDetails>
</Accordion>
<Accordion
square={true}
style={{margin: 0}}
expanded={!this.state.expanded}
onChange={this.onChange}
>
<AccordionSummary>
<b style={{fontSize: '20px', marginRight: '5px', width: '35px'}}>{unequal}</b>
<div style={{margin: 'auto 5px 2px 0px'}}>XML Blöcke</div>
</AccordionSummary>
<AccordionDetails style={{padding: 0, height: 'calc(500px - 50px - 50px)', backgroundColor: 'white'}}>
<pre className="line-numbers" style={{paddingBottom: 0, width: '100%', overflow: 'auto', scrollbarWidth: 'thin', height: 'calc(100% - 30px)', margin: '15px 0', paddingTop: 0, whiteSpace: 'pre-wrap', backgroundColor: 'white'}}>
<code className="language-xml">
{`${this.props.xml}`}
</code>
</pre>
</AccordionDetails>
</Accordion>
</div>
);
};
}
CodeViewer.propTypes = {
arduino: PropTypes.string.isRequired,
xml: PropTypes.string.isRequired
};
const mapStateToProps = state => ({
arduino: state.workspace.code.arduino,
xml: state.workspace.code.xml
});
export default connect(mapStateToProps, null)(CodeViewer);
+1 -1
View File
@@ -8,7 +8,7 @@ class Footer extends Component {
render() {
return (
<footer style={{position:'absolute', bottom: '0', width: '100%'}}>
<div style={{minHeight:'30px', backgroundColor:'lightgrey', textAlign: 'center', paddingTop: '2px'}}>
<div style={{minHeight:'30px', backgroundColor:'#DDDDDD', textAlign: 'center', paddingTop: '2px'}}>
<div style={{color: 'grey', height: '100%'}}>
<Link to={"/impressum"} style={{textDecoration: 'none', color: 'inherit'}}>Impressum</Link>
<Typography style={{margin: '0px 10px 0px 10px', display: 'initial', fontSize: '1rem'}}>|</Typography>
+35 -31
View File
@@ -1,51 +1,55 @@
import React, { Component } from 'react';
import * as Blockly from 'blockly/core';
import WorkspaceStats from './WorkspaceStats';
import WorkspaceFunc from './WorkspaceFunc';
import BlocklyWindow from './Blockly/BlocklyWindow';
import CodeViewer from './CodeViewer';
import BlocklyComponent, { Block, Value, Field, Shadow, Category } from './Blockly';
import * as Blockly from 'blockly/core';
import * as De from './Blockly/msg/de'; // de locale files
//import * as En from './Blockly/msg/en'; // de locale files
import './Blockly/blocks/';
import './Blockly/generator/';
import Grid from '@material-ui/core/Grid';
import FormControlLabel from '@material-ui/core/FormControlLabel';
import Switch from '@material-ui/core/Switch';
class Home extends Component {
class Home extends React.Component {
constructor(props) {
super(props);
this.simpleWorkspace = React.createRef();
this.state = { generatedCode: 'Click text' }
state = {
codeOn: false
}
componentDidMount() {
let workspace = Blockly.getMainWorkspace();
workspace.addChangeListener(this.generateCode);
componentDidUpdate() {
/* Resize and reposition all of the workspace chrome (toolbox, trash,
scrollbars etc.) This should be called when something changes that requires
recalculating dimensions and positions of the trash, zoom, toolbox, etc.
(e.g. window resize). */
const workspace = Blockly.getMainWorkspace();
Blockly.svgResize(workspace);
}
generateCode = () => {
var code = Blockly.Arduino.workspaceToCode(this.workspace);
console.log(code);
this.setState({ generatedCode: code })
onChange = () => {
this.setState({ codeOn: !this.state.codeOn });
}
render() {
return (
<div>
<WorkspaceStats />
<BlocklyComponent ref={this.simpleWorkspace}
readOnly={false} trashcan={true} media={'media/'}
move={{
scrollbars: true,
drag: true,
wheel: true
}}
initialXml={''} />
<WorkspaceFunc generateCode={this.generateCode} />
<Grid container spacing={2}>
<Grid item xs={12} md={this.state.codeOn ? 6 : 12} style={{ position: 'relative' }}>
<FormControlLabel
style={{ margin: '5px 10px 0 0', position: 'absolute', top: 0, right: 0, zIndex: 1 }}
control={<Switch checked={this.state.codeOn} onChange={this.onChange} color='primary' />}
label="Code"
/>
<BlocklyWindow />
</Grid>
{this.state.codeOn ?
<Grid item xs={12} md={6}>
<CodeViewer />
</Grid>
: null}
</Grid>
<WorkspaceFunc />
</div>
);
};
+13 -13
View File
@@ -1,7 +1,9 @@
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { setWorkspace } from '../actions/workspaceActions';
import { workspaceChange } from '../actions/workspaceActions';
import * as Blockly from 'blockly/core';
import TextField from '@material-ui/core/TextField';
import Button from '@material-ui/core/Button';
@@ -16,20 +18,23 @@ class MaxBlocks extends Component {
this.setState({ [e.target.name]: e.target.value});
}
setMaxBlocks = () => {
const workspace = Blockly.getMainWorkspace();
workspace.options.maxBlocks = this.state.max;
this.props.workspaceChange();
}
render() {
// var blockLeft = Object.keys(this.props.newWorkspace).length > 0 ? <p>{this.props.newWorkspace.remainingCapacity()} verbleibende Blöcke möglich</p> : null
// var error = this.state.error ? <div>{this.state.error}</div> : null;
return (
<div style={{display: 'inline', marginLeft: '10px'}}>
<TextField
style={{width: '50px'}}
style={{width: '50px', marginRight: '5px'}}
name="max"
type="number"
onChange={this.onChange}
value={this.state.max}
variant='filled'
/>
<Button style={{marginRight: '10px'}} variant="contained" color="primary" onClick={() => {this.props.newWorkspace.options.maxBlocks = this.state.max; this.props.setWorkspace(this.props.newWorkspace)}}>
<Button style={{marginRight: '10px', color: 'white'}} variant="contained" color="primary" onClick={this.setMaxBlocks}>
Maximale Blöcke
</Button>
</div>
@@ -38,12 +43,7 @@ class MaxBlocks extends Component {
}
MaxBlocks.propTypes = {
newWorkspace: PropTypes.object.isRequired,
setWorkspace: PropTypes.func.isRequired
workspaceChange: PropTypes.func.isRequired
};
const mapStateToProps = state => ({
newWorkspace: state.workspace.new
});
export default connect(mapStateToProps, { setWorkspace })(MaxBlocks);
export default connect(null, { workspaceChange })(MaxBlocks);
+5 -1
View File
@@ -2,6 +2,7 @@ import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import ClearWorkspace from './ClearWorkspace';
import senseboxLogo from './sensebox_logo.svg';
import { withStyles } from '@material-ui/core/styles';
import Drawer from '@material-ui/core/Drawer';
@@ -51,7 +52,7 @@ class Navbar extends Component {
style={{height: '50px', marginBottom: '30px'}}
classes={{root: this.props.classes.appBarColor}}
>
<Toolbar style={{height: '50px', minHeight: '50px', padding: 0}}>
<Toolbar style={{height: '50px', minHeight: '50px', padding: 0, color: 'white'}}>
<IconButton
color="inherit"
onClick={this.toggleDrawer}
@@ -64,6 +65,9 @@ class Navbar extends Component {
senseBox Blockly
</Typography>
</Link>
<Link to={"/"} style={{marginLeft: '10px'}}>
<img src={senseboxLogo} alt="senseBox-Logo" width="30"/>
</Link>
</Toolbar>
</AppBar>
<Drawer
+6 -4
View File
@@ -9,10 +9,12 @@ class Routes extends Component {
render() {
return (
<Switch>
<Route path="/" exact component={Home} />
<Route component={NotFound} />
</Switch>
<div style={{ margin: '0 22px' }}>
<Switch>
<Route path="/" exact component={Home} />
<Route component={NotFound} />
</Switch>
</div>
);
}
}
+10 -10
View File
@@ -18,11 +18,12 @@ class WorkspaceFunc extends Component {
open: false
}
getArduinoCode = () => {
this.setState({ title: 'Adurino Code', content: this.props.arduino, open: true });
}
getXMLCode = () => {
var code = window.Ardublockly.generateXml();
this.setState({ title: 'XML Code', content: code, open: true });
this.setState({ title: 'XML Code', content: this.props.xml, open: true });
}
toggleDialog = () => {
@@ -43,15 +44,12 @@ class WorkspaceFunc extends Component {
</Button>
</DialogActions>
</Dialog>
<Button style={{ marginRight: '10px' }} variant="contained" color="primary" onClick={() => this.props.generateCode()}>
<Button style={{ marginRight: '10px', color: 'white' }} variant="contained" color="primary" onClick={() => this.getArduinoCode()}>
Get Adurino Code
</Button>
<Button style={{ marginRight: '10px' }} variant="contained" color="primary" onClick={() => this.getXMLCode()}>
<Button style={{ marginRight: '10px', color: 'white' }} variant="contained" color="primary" onClick={() => this.getXMLCode()}>
Get XML Code
</Button>
<Button variant="contained" color="primary" onClick={() => { var blocks = this.props.newWorkspace; console.log(blocks); }}>
Get workspace
</Button>
<MaxBlocks />
</div>
);
@@ -59,11 +57,13 @@ class WorkspaceFunc extends Component {
}
WorkspaceFunc.propTypes = {
newWorkspace: PropTypes.object.isRequired
arduino: PropTypes.string.isRequired,
xml: PropTypes.string.isRequired
};
const mapStateToProps = state => ({
newWorkspace: state.workspace.new
arduino: state.workspace.code.arduino,
xml: state.workspace.code.xml
});
export default connect(mapStateToProps, null)(WorkspaceFunc);
+21 -11
View File
@@ -2,11 +2,13 @@ import React, {Component} from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import * as Blockly from 'blockly/core';
import { withStyles } from '@material-ui/core/styles';
import Tooltip from '@material-ui/core/Tooltip';
import Typography from '@material-ui/core/Typography';
import { faPuzzlePiece, faTrash, faPlus, faPen } from "@fortawesome/free-solid-svg-icons";
import { faPuzzlePiece, faTrash, faPlus, faPen, faArrowsAlt } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
const styles = (theme) => ({
@@ -22,13 +24,14 @@ const styles = (theme) => ({
class WorkspaceStats extends Component {
render() {
// var check = Object.keys(this.props.newWorkspace).length > 0 && this.props.create - this.props.delete !== this.props.newWorkspace.getAllBlocks().length ? <h1>FEHLER!</h1> : null;
const workspace = Blockly.getMainWorkspace();
const remainingBlocksInfinity = workspace ? workspace.remainingCapacity() !== Infinity : null;
return (
<div style={{marginBottom: '20px'}}>
<div style={{marginBottom: '20px', color: 'white'}}>
<Tooltip title="Anzahl aktueller Blöcke" style={{marginLeft: 0}} className={this.props.classes.stats}>
<div>
<FontAwesomeIcon icon={faPuzzlePiece} />
<Typography style={{display: 'inline'}}> {Object.keys(this.props.newWorkspace).length > 0 ? this.props.newWorkspace.getAllBlocks().length : 0}</Typography>
<Typography style={{display: 'inline'}}> {workspace ? workspace.getAllBlocks().length : 0}</Typography>
</div>
</Tooltip>
<Tooltip title="Anzahl neuer Blöcke" className={this.props.classes.stats}>
@@ -45,6 +48,13 @@ class WorkspaceStats extends Component {
<Typography style={{display: 'inline'}}> {this.props.change}</Typography>
</div>
</Tooltip>
<Tooltip title="Anzahl bewegter Blöcke" className={this.props.classes.stats}>
<div>
<FontAwesomeIcon icon={faArrowsAlt} style={{marginRight: '5px'}}/>
<FontAwesomeIcon icon={faPuzzlePiece} />
<Typography style={{display: 'inline'}}> {this.props.move}</Typography>
</div>
</Tooltip>
<Tooltip title="Anzahl gelöschter Blöcke" className={this.props.classes.stats}>
<div>
<FontAwesomeIcon icon={faTrash} style={{marginRight: '5px'}}/>
@@ -52,29 +62,29 @@ class WorkspaceStats extends Component {
<Typography style={{display: 'inline'}}> {this.props.delete}</Typography>
</div>
</Tooltip>
{Object.keys(this.props.newWorkspace).length > 0 ? this.props.newWorkspace.remainingCapacity() !== Infinity ?
{remainingBlocksInfinity ?
<Tooltip title="verbleibende Blöcke" className={this.props.classes.stats}>
<Typography style={{display: 'inline'}}>{this.props.delete} verbleibende Blöcke</Typography>
</Tooltip> : null : null}
<Typography style={{display: 'inline'}}>{workspace.remainingCapacity()} verbleibende Blöcke</Typography>
</Tooltip> : null}
</div>
);
};
}
WorkspaceStats.propTypes = {
newWorkspace: PropTypes.object.isRequired,
create: PropTypes.number.isRequired,
change: PropTypes.number.isRequired,
delete: PropTypes.number.isRequired,
test: PropTypes.number.isRequired
move: PropTypes.number.isRequired,
worskpaceChange: PropTypes.number.isRequired
};
const mapStateToProps = state => ({
newWorkspace: state.workspace.new,
create: state.workspace.stats.create,
change: state.workspace.stats.change,
delete: state.workspace.stats.delete,
test: state.workspace.test
move: state.workspace.stats.move,
worskpaceChange: state.workspace.change
});
export default connect(mapStateToProps, null)(withStyles(styles, {withTheme: true})(WorkspaceStats));
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.1 KiB