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
+1
View File
@@ -22,3 +22,4 @@ npm-debug.log*
yarn-debug.log* yarn-debug.log*
yarn-error.log* yarn-error.log*
package-lock.json package-lock.json
package-lock.json
+1
View File
@@ -11,6 +11,7 @@
"@testing-library/react": "^9.5.0", "@testing-library/react": "^9.5.0",
"@testing-library/user-event": "^7.2.1", "@testing-library/user-event": "^7.2.1",
"blockly": "^3.20200625.2", "blockly": "^3.20200625.2",
"prismjs": "^1.20.0",
"react": "^16.13.1", "react": "^16.13.1",
"react-dom": "^16.13.1", "react-dom": "^16.13.1",
"react-redux": "^7.2.0", "react-redux": "^7.2.0",
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

+3 -7
View File
@@ -2,13 +2,9 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> <link rel="icon" href="%PUBLIC_URL%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" /> <meta name="theme-color" content="#4EAF47" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!-- <!--
manifest.json provides metadata used when your web app is installed on a manifest.json provides metadata used when your web app is installed on a
@@ -24,7 +20,7 @@
work correctly both with client-side routing and a non-root public URL. work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`. Learn how to configure a non-root public URL by running `npm run build`.
--> -->
<title>React App</title> <title>senseBox Blockly</title>
</head> </head>
<body> <body>
<noscript>You need to enable JavaScript to run this app.</noscript> <noscript>You need to enable JavaScript to run this app.</noscript>
+4 -4
View File
@@ -3,9 +3,9 @@
"name": "Create React App Sample", "name": "Create React App Sample",
"icons": [ "icons": [
{ {
"src": "favicon.ico", "src": "favicon.png",
"sizes": "64x64 32x32 24x24 16x16", "sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon" "type": "image/png"
}, },
{ {
"src": "logo192.png", "src": "logo192.png",
@@ -20,6 +20,6 @@
], ],
"start_url": ".", "start_url": ".",
"display": "standalone", "display": "standalone",
"theme_color": "#000000", "theme_color": "#4EAF47",
"background_color": "#ffffff" "background_color": "#4EAF47"
} }
Binary file not shown.

After

Width:  |  Height:  |  Size: 43 B

Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" width="12.71" height="8.79" viewBox="0 0 12.71 8.79"><title>dropdown-arrow</title><g opacity="0.1"><path d="M12.71,2.44A2.41,2.41,0,0,1,12,4.16L8.08,8.08a2.45,2.45,0,0,1-3.45,0L0.72,4.16A2.42,2.42,0,0,1,0,2.44,2.48,2.48,0,0,1,.71.71C1,0.47,1.43,0,6.36,0S11.75,0.46,12,.71A2.44,2.44,0,0,1,12.71,2.44Z" fill="#231f20"/></g><path d="M6.36,7.79a1.43,1.43,0,0,1-1-.42L1.42,3.45a1.44,1.44,0,0,1,0-2c0.56-.56,9.31-0.56,9.87,0a1.44,1.44,0,0,1,0,2L7.37,7.37A1.43,1.43,0,0,1,6.36,7.79Z" fill="#fff"/></svg>

After

Width:  |  Height:  |  Size: 569 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 766 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1010 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 771 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 738 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

+74
View File
@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="96px" height="124px">
<style type="text/css">
#background {
fill: none;
}
.arrows {
fill: #000;
stroke: none;
}
.selected>.arrows {
fill: #fff;
}
.checkmark {
fill: #000;
font-family: sans-serif;
font-size: 10pt;
text-anchor: middle;
}
.trash {
fill: #888;
}
.zoom {
fill: none;
stroke: #888;
stroke-width: 2;
stroke-linecap: round;
}
.zoom>.center {
fill: #888;
stroke-width: 0;
}
</style>
<rect id="background" width="96" height="124" x="0" y="0" />
<g>
<path class="arrows" d="M 13,1.5 13,14.5 1.74,8 z" />
<path class="arrows" d="M 17.5,3 30.5,3 24,14.26 z" />
<path class="arrows" d="M 35,1.5 35,14.5 46.26,8 z" />
</g>
<g class="selected" transform="translate(0, 16)">
<path class="arrows" d="M 13,1.5 13,14.5 1.74,8 z" />
<path class="arrows" d="M 17.5,3 30.5,3 24,14.26 z" />
<path class="arrows" d="M 35,1.5 35,14.5 46.26,8 z" />
</g>
<text class="checkmark" x="55.5" y="28">&#10003;</text>
<g class="trash">
<path d="M 2,41 v 6 h 42 v -6 h -10.5 l -3,-3 h -15 l -3,3 z" />
<rect width="36" height="20" x="5" y="50" />
<rect width="36" height="42" x="5" y="50" rx="4" ry="4" />
</g>
<g class="zoom">
<circle r="11.5" cx="16" cy="108" />
<circle r="4.3" cx="16" cy="108" class="center" />
<path d="m 28,108 h3" />
<path d="m 1,108 h3" />
<path d="m 16,120 v3" />
<path d="m 16,93 v3" />
</g>
<g class="zoom">
<circle r="15" cx="48" cy="108" />
<path d="m 48,101.6 v12.8" />
<path d="m 41.6,108 h12.8" />
</g>
<g class="zoom">
<circle r="15" cx="80" cy="108" />
<path d="m 73.6,108 h12.8" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

+1 -1
View File
@@ -3,5 +3,5 @@
overflow: hidden; overflow: hidden;
display: block; display: block;
position: relative; position: relative;
padding-bottom: 60px; /* height of your footer + 30px*/y /* padding-bottom: 60px; /* height of your footer + 30px*/
} }
+6 -3
View File
@@ -5,6 +5,8 @@ import { BrowserRouter as Router } from 'react-router-dom';
import { Provider } from 'react-redux'; import { Provider } from 'react-redux';
import store from './store'; import store from './store';
import './App.css';
import { ThemeProvider, createMuiTheme } from '@material-ui/core/styles'; import { ThemeProvider, createMuiTheme } from '@material-ui/core/styles';
import Navbar from './components/Navbar'; import Navbar from './components/Navbar';
@@ -15,6 +17,9 @@ const theme = createMuiTheme({
palette: { palette: {
primary: { primary: {
main: '#4EAF47', main: '#4EAF47',
},
secondary: {
main: '#DDDDDD'
} }
} }
}); });
@@ -27,9 +32,7 @@ function App() {
<Router> <Router>
<div className="wrapper"> <div className="wrapper">
<Navbar /> <Navbar />
<div style={{ margin: '0 22px' }}> <Routes />
<Routes />
</div>
<Footer /> <Footer />
</div> </div>
</Router> </Router>
+3 -1
View File
@@ -1,5 +1,7 @@
export const NEW_WORKSPACE = 'NEW_WORKSPACE'; export const NEW_CODE = 'NEW_CODE';
export const CHANGE_WORKSPACE = 'CHANGE_WORKSPACE';
export const CREATE_BLOCK = 'CREATE_BLOCK'; export const CREATE_BLOCK = 'CREATE_BLOCK';
export const MOVE_BLOCK = 'MOVE_BLOCK';
export const CHANGE_BLOCK = 'CHANGE_BLOCK'; export const CHANGE_BLOCK = 'CHANGE_BLOCK';
export const DELETE_BLOCK = 'DELETE_BLOCK'; export const DELETE_BLOCK = 'DELETE_BLOCK';
export const CLEAR_STATS = 'CLEAR_STATS'; export const CLEAR_STATS = 'CLEAR_STATS';
+32 -16
View File
@@ -1,28 +1,50 @@
import { NEW_WORKSPACE, CREATE_BLOCK, CHANGE_BLOCK, DELETE_BLOCK, CLEAR_STATS } from './types'; import { NEW_CODE, CHANGE_WORKSPACE, CREATE_BLOCK, MOVE_BLOCK, CHANGE_BLOCK, DELETE_BLOCK, CLEAR_STATS } from './types';
import * as Blockly from 'blockly/core';
export const workspaceChange = () => (dispatch) => {
dispatch({
type: CHANGE_WORKSPACE
})
}
export const onChangeWorkspace = (event) => (dispatch, getState) => { export const onChangeWorkspace = (event) => (dispatch, getState) => {
var oldWorkspace = getState().workspace.new; // stored 'new workspace' is from now on old
var newWorkspace = window.Ardublockly.workspace;
dispatch({ dispatch({
type: NEW_WORKSPACE, type: CHANGE_WORKSPACE,
payload: {new: newWorkspace, old: oldWorkspace} })
const workspace = Blockly.getMainWorkspace();
var code = getState().workspace.code;
code.arduino = Blockly.Arduino.workspaceToCode(workspace);
var xmlDom = Blockly.Xml.workspaceToDom(workspace);
code.xml = Blockly.Xml.domToPrettyText(xmlDom);
dispatch({
type: NEW_CODE,
payload: code
}); });
var stats = getState().workspace.stats; var stats = getState().workspace.stats;
if (event.type === window.Blockly.Events.CREATE){ if (event.type === Blockly.Events.BLOCK_CREATE){
stats.create += event.ids.length; stats.create += event.ids.length;
dispatch({ dispatch({
type: CREATE_BLOCK, type: CREATE_BLOCK,
payload: stats payload: stats
}); });
} }
else if (event.type === window.Blockly.Events.CHANGE){ else if (event.type === Blockly.Events.BLOCK_MOVE){
stats.move += 1;
dispatch({
type: MOVE_BLOCK,
payload: stats
});
}
else if (event.type === Blockly.Events.BLOCK_CHANGE){
stats.change += 1; stats.change += 1;
dispatch({ dispatch({
type: CHANGE_BLOCK, type: CHANGE_BLOCK,
payload: stats payload: stats
}); });
} }
else if (event.type === window.Blockly.Events.DELETE){ else if (event.type === Blockly.Events.BLOCK_DELETE){
if(stats.create > 0){ if(stats.create > 0){
stats.delete += event.ids.length; stats.delete += event.ids.length;
dispatch({ dispatch({
@@ -37,17 +59,11 @@ export const clearStats = () => (dispatch) => {
var stats = { var stats = {
create: 0, create: 0,
change: 0, change: 0,
delete: 0 delete: 0,
move: 0
}; };
dispatch({ dispatch({
type: CLEAR_STATS, type: CLEAR_STATS,
payload: stats payload: stats
}); });
}; };
export const setWorkspace = (workspace) => (dispatch, getState) => {
dispatch({
type: NEW_WORKSPACE,
payload: {new: workspace, old: getState().workspace.new}
});
};
+4 -4
View File
@@ -1,6 +1,6 @@
#blocklyDiv { #blocklyDiv {
height: 90vH; height: 100%;
width: 50%; min-height: 500px;
position: absolute; width: 100%;
bottom: 0; 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 React, {Component} from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { connect } from 'react-redux'; 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 ListItem from '@material-ui/core/ListItem';
import ListItemIcon from '@material-ui/core/ListItemIcon'; import ListItemIcon from '@material-ui/core/ListItemIcon';
@@ -13,7 +15,10 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
class ClearWorkspace extends Component { class ClearWorkspace extends Component {
clearWorkspace = () => { clearWorkspace = () => {
this.props.newWorkspace.clear(); const workspace = Blockly.getMainWorkspace();
workspace.clear();
workspace.options.maxBlocks = Infinity;
this.props.workspaceChange();
this.props.clearStats(); this.props.clearStats();
} }
@@ -28,12 +33,9 @@ class ClearWorkspace extends Component {
} }
ClearWorkspace.propTypes = { 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() { render() {
return ( return (
<footer style={{position:'absolute', bottom: '0', width: '100%'}}> <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%'}}> <div style={{color: 'grey', height: '100%'}}>
<Link to={"/impressum"} style={{textDecoration: 'none', color: 'inherit'}}>Impressum</Link> <Link to={"/impressum"} style={{textDecoration: 'none', color: 'inherit'}}>Impressum</Link>
<Typography style={{margin: '0px 10px 0px 10px', display: 'initial', fontSize: '1rem'}}>|</Typography> <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 React, { Component } from 'react';
import * as Blockly from 'blockly/core';
import WorkspaceStats from './WorkspaceStats'; import WorkspaceStats from './WorkspaceStats';
import WorkspaceFunc from './WorkspaceFunc'; import WorkspaceFunc from './WorkspaceFunc';
import BlocklyWindow from './Blockly/BlocklyWindow';
import CodeViewer from './CodeViewer';
import BlocklyComponent, { Block, Value, Field, Shadow, Category } from './Blockly'; import Grid from '@material-ui/core/Grid';
import * as Blockly from 'blockly/core'; import FormControlLabel from '@material-ui/core/FormControlLabel';
import * as De from './Blockly/msg/de'; // de locale files import Switch from '@material-ui/core/Switch';
//import * as En from './Blockly/msg/en'; // de locale files
import './Blockly/blocks/';
import './Blockly/generator/';
class Home extends Component {
state = {
codeOn: false
class Home extends React.Component {
constructor(props) {
super(props);
this.simpleWorkspace = React.createRef();
this.state = { generatedCode: 'Click text' }
} }
componentDidMount() { componentDidUpdate() {
/* Resize and reposition all of the workspace chrome (toolbox, trash,
let workspace = Blockly.getMainWorkspace(); scrollbars etc.) This should be called when something changes that requires
workspace.addChangeListener(this.generateCode); recalculating dimensions and positions of the trash, zoom, toolbox, etc.
(e.g. window resize). */
const workspace = Blockly.getMainWorkspace();
Blockly.svgResize(workspace);
} }
generateCode = () => { onChange = () => {
var code = Blockly.Arduino.workspaceToCode(this.workspace); this.setState({ codeOn: !this.state.codeOn });
console.log(code);
this.setState({ generatedCode: code })
} }
render() { render() {
return ( return (
<div> <div>
<WorkspaceStats /> <WorkspaceStats />
<BlocklyComponent ref={this.simpleWorkspace} <Grid container spacing={2}>
readOnly={false} trashcan={true} media={'media/'} <Grid item xs={12} md={this.state.codeOn ? 6 : 12} style={{ position: 'relative' }}>
move={{ <FormControlLabel
scrollbars: true, style={{ margin: '5px 10px 0 0', position: 'absolute', top: 0, right: 0, zIndex: 1 }}
drag: true, control={<Switch checked={this.state.codeOn} onChange={this.onChange} color='primary' />}
wheel: true label="Code"
}} />
initialXml={''} /> <BlocklyWindow />
<WorkspaceFunc generateCode={this.generateCode} /> </Grid>
{this.state.codeOn ?
<Grid item xs={12} md={6}>
<CodeViewer />
</Grid>
: null}
</Grid>
<WorkspaceFunc />
</div> </div>
); );
}; };
+13 -13
View File
@@ -1,7 +1,9 @@
import React, {Component} from 'react'; import React, {Component} from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { connect } from 'react-redux'; 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 TextField from '@material-ui/core/TextField';
import Button from '@material-ui/core/Button'; import Button from '@material-ui/core/Button';
@@ -16,20 +18,23 @@ class MaxBlocks extends Component {
this.setState({ [e.target.name]: e.target.value}); this.setState({ [e.target.name]: e.target.value});
} }
setMaxBlocks = () => {
const workspace = Blockly.getMainWorkspace();
workspace.options.maxBlocks = this.state.max;
this.props.workspaceChange();
}
render() { 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 ( return (
<div style={{display: 'inline', marginLeft: '10px'}}> <div style={{display: 'inline', marginLeft: '10px'}}>
<TextField <TextField
style={{width: '50px'}} style={{width: '50px', marginRight: '5px'}}
name="max" name="max"
type="number" type="number"
onChange={this.onChange} onChange={this.onChange}
value={this.state.max} 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 Maximale Blöcke
</Button> </Button>
</div> </div>
@@ -38,12 +43,7 @@ class MaxBlocks extends Component {
} }
MaxBlocks.propTypes = { MaxBlocks.propTypes = {
newWorkspace: PropTypes.object.isRequired, workspaceChange: PropTypes.func.isRequired
setWorkspace: PropTypes.func.isRequired
}; };
const mapStateToProps = state => ({ export default connect(null, { workspaceChange })(MaxBlocks);
newWorkspace: state.workspace.new
});
export default connect(mapStateToProps, { setWorkspace })(MaxBlocks);
+5 -1
View File
@@ -2,6 +2,7 @@ import React, { Component } from 'react';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import ClearWorkspace from './ClearWorkspace'; import ClearWorkspace from './ClearWorkspace';
import senseboxLogo from './sensebox_logo.svg';
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from '@material-ui/core/styles';
import Drawer from '@material-ui/core/Drawer'; import Drawer from '@material-ui/core/Drawer';
@@ -51,7 +52,7 @@ class Navbar extends Component {
style={{height: '50px', marginBottom: '30px'}} style={{height: '50px', marginBottom: '30px'}}
classes={{root: this.props.classes.appBarColor}} 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 <IconButton
color="inherit" color="inherit"
onClick={this.toggleDrawer} onClick={this.toggleDrawer}
@@ -64,6 +65,9 @@ class Navbar extends Component {
senseBox Blockly senseBox Blockly
</Typography> </Typography>
</Link> </Link>
<Link to={"/"} style={{marginLeft: '10px'}}>
<img src={senseboxLogo} alt="senseBox-Logo" width="30"/>
</Link>
</Toolbar> </Toolbar>
</AppBar> </AppBar>
<Drawer <Drawer
+6 -4
View File
@@ -9,10 +9,12 @@ class Routes extends Component {
render() { render() {
return ( return (
<Switch> <div style={{ margin: '0 22px' }}>
<Route path="/" exact component={Home} /> <Switch>
<Route component={NotFound} /> <Route path="/" exact component={Home} />
</Switch> <Route component={NotFound} />
</Switch>
</div>
); );
} }
} }
+10 -10
View File
@@ -18,11 +18,12 @@ class WorkspaceFunc extends Component {
open: false open: false
} }
getArduinoCode = () => {
this.setState({ title: 'Adurino Code', content: this.props.arduino, open: true });
}
getXMLCode = () => { getXMLCode = () => {
var code = window.Ardublockly.generateXml(); this.setState({ title: 'XML Code', content: this.props.xml, open: true });
this.setState({ title: 'XML Code', content: code, open: true });
} }
toggleDialog = () => { toggleDialog = () => {
@@ -43,15 +44,12 @@ class WorkspaceFunc extends Component {
</Button> </Button>
</DialogActions> </DialogActions>
</Dialog> </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 Get Adurino Code
</Button> </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 Get XML Code
</Button> </Button>
<Button variant="contained" color="primary" onClick={() => { var blocks = this.props.newWorkspace; console.log(blocks); }}>
Get workspace
</Button>
<MaxBlocks /> <MaxBlocks />
</div> </div>
); );
@@ -59,11 +57,13 @@ class WorkspaceFunc extends Component {
} }
WorkspaceFunc.propTypes = { WorkspaceFunc.propTypes = {
newWorkspace: PropTypes.object.isRequired arduino: PropTypes.string.isRequired,
xml: PropTypes.string.isRequired
}; };
const mapStateToProps = state => ({ const mapStateToProps = state => ({
newWorkspace: state.workspace.new arduino: state.workspace.code.arduino,
xml: state.workspace.code.xml
}); });
export default connect(mapStateToProps, null)(WorkspaceFunc); 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 PropTypes from 'prop-types';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import * as Blockly from 'blockly/core';
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from '@material-ui/core/styles';
import Tooltip from '@material-ui/core/Tooltip'; import Tooltip from '@material-ui/core/Tooltip';
import Typography from '@material-ui/core/Typography'; 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"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
const styles = (theme) => ({ const styles = (theme) => ({
@@ -22,13 +24,14 @@ const styles = (theme) => ({
class WorkspaceStats extends Component { class WorkspaceStats extends Component {
render() { 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 ( 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}> <Tooltip title="Anzahl aktueller Blöcke" style={{marginLeft: 0}} className={this.props.classes.stats}>
<div> <div>
<FontAwesomeIcon icon={faPuzzlePiece} /> <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> </div>
</Tooltip> </Tooltip>
<Tooltip title="Anzahl neuer Blöcke" className={this.props.classes.stats}> <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> <Typography style={{display: 'inline'}}> {this.props.change}</Typography>
</div> </div>
</Tooltip> </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}> <Tooltip title="Anzahl gelöschter Blöcke" className={this.props.classes.stats}>
<div> <div>
<FontAwesomeIcon icon={faTrash} style={{marginRight: '5px'}}/> <FontAwesomeIcon icon={faTrash} style={{marginRight: '5px'}}/>
@@ -52,29 +62,29 @@ class WorkspaceStats extends Component {
<Typography style={{display: 'inline'}}> {this.props.delete}</Typography> <Typography style={{display: 'inline'}}> {this.props.delete}</Typography>
</div> </div>
</Tooltip> </Tooltip>
{Object.keys(this.props.newWorkspace).length > 0 ? this.props.newWorkspace.remainingCapacity() !== Infinity ? {remainingBlocksInfinity ?
<Tooltip title="verbleibende Blöcke" className={this.props.classes.stats}> <Tooltip title="verbleibende Blöcke" className={this.props.classes.stats}>
<Typography style={{display: 'inline'}}>{this.props.delete} verbleibende Blöcke</Typography> <Typography style={{display: 'inline'}}>{workspace.remainingCapacity()} verbleibende Blöcke</Typography>
</Tooltip> : null : null} </Tooltip> : null}
</div> </div>
); );
}; };
} }
WorkspaceStats.propTypes = { WorkspaceStats.propTypes = {
newWorkspace: PropTypes.object.isRequired,
create: PropTypes.number.isRequired, create: PropTypes.number.isRequired,
change: PropTypes.number.isRequired, change: PropTypes.number.isRequired,
delete: PropTypes.number.isRequired, delete: PropTypes.number.isRequired,
test: PropTypes.number.isRequired move: PropTypes.number.isRequired,
worskpaceChange: PropTypes.number.isRequired
}; };
const mapStateToProps = state => ({ const mapStateToProps = state => ({
newWorkspace: state.workspace.new,
create: state.workspace.stats.create, create: state.workspace.stats.create,
change: state.workspace.stats.change, change: state.workspace.stats.change,
delete: state.workspace.stats.delete, 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)); 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

+15 -8
View File
@@ -1,27 +1,34 @@
import { NEW_WORKSPACE, CREATE_BLOCK, CHANGE_BLOCK, DELETE_BLOCK, CLEAR_STATS } from '../actions/types'; import { CHANGE_WORKSPACE, NEW_CODE, CREATE_BLOCK, MOVE_BLOCK, CHANGE_BLOCK, DELETE_BLOCK, CLEAR_STATS } from '../actions/types';
const initialState = { const initialState = {
old: {}, code: {
new: {}, arduino: '',
xml: ''
},
stats: { stats: {
create: 0, create: 0,
change: 0, change: 0,
delete: 0, delete: 0,
move: 0
}, },
test: 0 change: 0
}; };
export default function(state = initialState, action){ export default function(state = initialState, action){
switch(action.type){ switch(action.type){
case NEW_WORKSPACE: case NEW_CODE:
return { return {
...state, ...state,
old: action.payload.old, code: action.payload
new: action.payload.new, };
test: state.test += 1 case CHANGE_WORKSPACE:
return {
...state,
change: state.change += 1
}; };
case CREATE_BLOCK: case CREATE_BLOCK:
case MOVE_BLOCK:
case CHANGE_BLOCK: case CHANGE_BLOCK:
case DELETE_BLOCK: case DELETE_BLOCK:
case CLEAR_STATS: case CLEAR_STATS: