diff --git a/.gitignore b/.gitignore index 680c904..273210c 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ npm-debug.log* yarn-debug.log* yarn-error.log* package-lock.json +package-lock.json diff --git a/package.json b/package.json index a0bd31d..6a3180b 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "@testing-library/react": "^9.5.0", "@testing-library/user-event": "^7.2.1", "blockly": "^3.20200625.2", + "prismjs": "^1.20.0", "react": "^16.13.1", "react-dom": "^16.13.1", "react-redux": "^7.2.0", diff --git a/public/favicon.ico b/public/favicon.ico deleted file mode 100644 index bcd5dfd..0000000 Binary files a/public/favicon.ico and /dev/null differ diff --git a/public/favicon.png b/public/favicon.png new file mode 100644 index 0000000..5dc7b7b Binary files /dev/null and b/public/favicon.png differ diff --git a/public/index.html b/public/index.html index aa069f2..3cc5778 100644 --- a/public/index.html +++ b/public/index.html @@ -2,13 +2,9 @@ - + - - + - React App + senseBox Blockly diff --git a/public/manifest.json b/public/manifest.json index 080d6c7..b5ec843 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -3,9 +3,9 @@ "name": "Create React App Sample", "icons": [ { - "src": "favicon.ico", + "src": "favicon.png", "sizes": "64x64 32x32 24x24 16x16", - "type": "image/x-icon" + "type": "image/png" }, { "src": "logo192.png", @@ -20,6 +20,6 @@ ], "start_url": ".", "display": "standalone", - "theme_color": "#000000", - "background_color": "#ffffff" + "theme_color": "#4EAF47", + "background_color": "#4EAF47" } diff --git a/public/media/1x1.gif b/public/media/1x1.gif new file mode 100644 index 0000000..3085511 Binary files /dev/null and b/public/media/1x1.gif differ diff --git a/public/media/click.mp3 b/public/media/click.mp3 new file mode 100644 index 0000000..4534b0d Binary files /dev/null and b/public/media/click.mp3 differ diff --git a/public/media/click.ogg b/public/media/click.ogg new file mode 100644 index 0000000..e8ae42a Binary files /dev/null and b/public/media/click.ogg differ diff --git a/public/media/click.wav b/public/media/click.wav new file mode 100644 index 0000000..41a50cd Binary files /dev/null and b/public/media/click.wav differ diff --git a/public/media/delete.mp3 b/public/media/delete.mp3 new file mode 100644 index 0000000..442bd9c Binary files /dev/null and b/public/media/delete.mp3 differ diff --git a/public/media/delete.ogg b/public/media/delete.ogg new file mode 100644 index 0000000..67f84ac Binary files /dev/null and b/public/media/delete.ogg differ diff --git a/public/media/delete.wav b/public/media/delete.wav new file mode 100644 index 0000000..18debcf Binary files /dev/null and b/public/media/delete.wav differ diff --git a/public/media/disconnect.mp3 b/public/media/disconnect.mp3 new file mode 100644 index 0000000..8cfaff6 Binary files /dev/null and b/public/media/disconnect.mp3 differ diff --git a/public/media/disconnect.ogg b/public/media/disconnect.ogg new file mode 100644 index 0000000..467b527 Binary files /dev/null and b/public/media/disconnect.ogg differ diff --git a/public/media/disconnect.wav b/public/media/disconnect.wav new file mode 100644 index 0000000..af5c254 Binary files /dev/null and b/public/media/disconnect.wav differ diff --git a/public/media/dropdown-arrow.svg b/public/media/dropdown-arrow.svg new file mode 100644 index 0000000..4e6ce19 --- /dev/null +++ b/public/media/dropdown-arrow.svg @@ -0,0 +1 @@ +dropdown-arrow \ No newline at end of file diff --git a/public/media/handclosed.cur b/public/media/handclosed.cur new file mode 100644 index 0000000..4851755 Binary files /dev/null and b/public/media/handclosed.cur differ diff --git a/public/media/handdelete.cur b/public/media/handdelete.cur new file mode 100644 index 0000000..170320f Binary files /dev/null and b/public/media/handdelete.cur differ diff --git a/public/media/handopen.cur b/public/media/handopen.cur new file mode 100644 index 0000000..da44588 Binary files /dev/null and b/public/media/handopen.cur differ diff --git a/public/media/pilcrow.png b/public/media/pilcrow.png new file mode 100644 index 0000000..f224c35 Binary files /dev/null and b/public/media/pilcrow.png differ diff --git a/public/media/quote0.png b/public/media/quote0.png new file mode 100644 index 0000000..c7820d6 Binary files /dev/null and b/public/media/quote0.png differ diff --git a/public/media/quote1.png b/public/media/quote1.png new file mode 100644 index 0000000..826583e Binary files /dev/null and b/public/media/quote1.png differ diff --git a/public/media/sprites.png b/public/media/sprites.png new file mode 100644 index 0000000..20aadb6 Binary files /dev/null and b/public/media/sprites.png differ diff --git a/public/media/sprites.svg b/public/media/sprites.svg new file mode 100644 index 0000000..3f09ef3 --- /dev/null +++ b/public/media/sprites.svg @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/App.css b/src/App.css index 36f46af..a8c8f37 100644 --- a/src/App.css +++ b/src/App.css @@ -3,5 +3,5 @@ overflow: hidden; display: block; position: relative; - padding-bottom: 60px; /* height of your footer + 30px*/y + /* padding-bottom: 60px; /* height of your footer + 30px*/ } diff --git a/src/App.js b/src/App.js index e340af7..67e20d0 100644 --- a/src/App.js +++ b/src/App.js @@ -5,6 +5,8 @@ import { BrowserRouter as Router } from 'react-router-dom'; import { Provider } from 'react-redux'; import store from './store'; +import './App.css'; + import { ThemeProvider, createMuiTheme } from '@material-ui/core/styles'; import Navbar from './components/Navbar'; @@ -15,6 +17,9 @@ const theme = createMuiTheme({ palette: { primary: { main: '#4EAF47', + }, + secondary: { + main: '#DDDDDD' } } }); @@ -27,9 +32,7 @@ function App() {
-
- -
+
diff --git a/src/actions/types.js b/src/actions/types.js index 0c9a0a7..c0be6c2 100644 --- a/src/actions/types.js +++ b/src/actions/types.js @@ -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 MOVE_BLOCK = 'MOVE_BLOCK'; export const CHANGE_BLOCK = 'CHANGE_BLOCK'; export const DELETE_BLOCK = 'DELETE_BLOCK'; export const CLEAR_STATS = 'CLEAR_STATS'; diff --git a/src/actions/workspaceActions.js b/src/actions/workspaceActions.js index 905a699..006d15f 100644 --- a/src/actions/workspaceActions.js +++ b/src/actions/workspaceActions.js @@ -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) => { - var oldWorkspace = getState().workspace.new; // stored 'new workspace' is from now on old - var newWorkspace = window.Ardublockly.workspace; dispatch({ - type: NEW_WORKSPACE, - payload: {new: newWorkspace, old: oldWorkspace} + type: CHANGE_WORKSPACE, + }) + 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; - if (event.type === window.Blockly.Events.CREATE){ + if (event.type === Blockly.Events.BLOCK_CREATE){ stats.create += event.ids.length; dispatch({ type: CREATE_BLOCK, 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; dispatch({ type: CHANGE_BLOCK, payload: stats }); } - else if (event.type === window.Blockly.Events.DELETE){ + else if (event.type === Blockly.Events.BLOCK_DELETE){ if(stats.create > 0){ stats.delete += event.ids.length; dispatch({ @@ -37,17 +59,11 @@ export const clearStats = () => (dispatch) => { var stats = { create: 0, change: 0, - delete: 0 + delete: 0, + move: 0 }; dispatch({ type: CLEAR_STATS, payload: stats }); }; - -export const setWorkspace = (workspace) => (dispatch, getState) => { - dispatch({ - type: NEW_WORKSPACE, - payload: {new: workspace, old: getState().workspace.new} - }); -}; diff --git a/src/components/Blockly/BlocklyComponent.css b/src/components/Blockly/BlocklyComponent.css index 6f8e099..14db59a 100644 --- a/src/components/Blockly/BlocklyComponent.css +++ b/src/components/Blockly/BlocklyComponent.css @@ -1,6 +1,6 @@ #blocklyDiv { - height: 90vH; - width: 50%; - position: absolute; - bottom: 0; + height: 100%; + min-height: 500px; + width: 100%; + border: 1px solid #4EAF47; } diff --git a/src/components/Blockly/BlocklyWindow.js b/src/components/Blockly/BlocklyWindow.js new file mode 100644 index 0000000..8ad7486 --- /dev/null +++ b/src/components/Blockly/BlocklyWindow.js @@ -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 ( + + + + + + + + + + + + + + + + + + + + + + ); + }; +} + +BlocklyWindow.propTypes = { + onChangeWorkspace: PropTypes.func.isRequired +}; + + +export default connect(null, { onChangeWorkspace })(BlocklyWindow); diff --git a/src/components/ClearWorkspace.js b/src/components/ClearWorkspace.js index 9ab4c57..5b48648 100644 --- a/src/components/ClearWorkspace.js +++ b/src/components/ClearWorkspace.js @@ -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); diff --git a/src/components/CodeViewer.js b/src/components/CodeViewer.js new file mode 100644 index 0000000..0a62b12 --- /dev/null +++ b/src/components/CodeViewer.js @@ -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 ( +
+ + + {curlyBrackets} +
Arduino Quellcode
+
+ +
+              
+                {this.props.arduino}
+              
+            
+
+
+ + + {unequal} +
XML Blöcke
+
+ +
+              
+                {`${this.props.xml}`}
+              
+            
+
+
+
+ ); + }; +} + +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); diff --git a/src/components/Footer.js b/src/components/Footer.js index 46466eb..fa068da 100644 --- a/src/components/Footer.js +++ b/src/components/Footer.js @@ -8,7 +8,7 @@ class Footer extends Component { render() { return (