Merge pull request #19 from sensebox/feat/blockly-gallery

add blockly project gallery
This commit is contained in:
Mario Pesch 2020-10-29 10:58:40 +01:00 committed by GitHub
commit b07d753e6c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 907 additions and 122 deletions

1
.env
View File

@ -1,2 +1,3 @@
REACT_APP_COMPILER_URL=https://compiler.sensebox.de
REACT_APP_BOARD=sensebox-mcu
REACT_APP_BLOCKLY_API=https://api.blockly.sensebox.de

32
package-lock.json generated
View File

@ -8720,6 +8720,11 @@
"minimist": "^1.2.5"
}
},
"mnemonic-id": {
"version": "3.2.7",
"resolved": "https://registry.npmjs.org/mnemonic-id/-/mnemonic-id-3.2.7.tgz",
"integrity": "sha512-kysx9gAGbvrzuFYxKkcRjnsg/NK61ovJOV4F1cHTRl9T5leg+bo6WI0pWIvOFh1Z/yDL0cjA5R3EEGPPLDv/XA=="
},
"moment": {
"version": "2.29.0",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.0.tgz",
@ -11394,6 +11399,13 @@
"tough-cookie": "~2.5.0",
"tunnel-agent": "^0.6.0",
"uuid": "^3.3.2"
},
"dependencies": {
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
}
}
},
"request-promise-core": {
@ -12125,6 +12137,13 @@
"requires": {
"faye-websocket": "^0.10.0",
"uuid": "^3.0.1"
},
"dependencies": {
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
}
}
},
"sockjs-client": {
@ -13269,9 +13288,9 @@
"integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
},
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
"version": "8.3.1",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz",
"integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg=="
},
"v8-compile-cache": {
"version": "2.1.1",
@ -13929,6 +13948,13 @@
"requires": {
"ansi-colors": "^3.0.0",
"uuid": "^3.3.2"
},
"dependencies": {
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
}
}
},
"webpack-manifest-plugin": {

View File

@ -15,6 +15,7 @@
"@testing-library/user-event": "^7.2.1",
"blockly": "^3.20200924.0",
"file-saver": "^2.0.2",
"mnemonic-id": "^3.2.7",
"moment": "^2.28.0",
"prismjs": "^1.20.0",
"react": "^16.13.1",
@ -23,7 +24,8 @@
"react-router-dom": "^5.2.0",
"react-scripts": "3.4.1",
"redux": "^4.0.5",
"redux-thunk": "^2.3.0"
"redux-thunk": "^2.3.0",
"uuid": "^8.3.1"
},
"scripts": {
"start": "react-scripts start",

View File

@ -24,14 +24,12 @@
import React from 'react';
import Blockly from 'blockly/core';
import locale from 'blockly/msg/en';
import 'blockly/blocks';
import Toolbox from './toolbox/Toolbox';
import { Card } from '@material-ui/core';
Blockly.setLocale(locale);
class BlocklyComponent extends React.Component {

View File

@ -2,8 +2,8 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { onChangeWorkspace, clearStats } from '../../actions/workspaceActions';
// import * as De from 'blockly/msg/de';
import { De } from './msg/de';
import { En } from './msg/en';
import BlocklyComponent from './BlocklyComponent';
import BlocklySvg from './BlocklySvg';
import * as Blockly from 'blockly/core';
@ -18,10 +18,26 @@ class BlocklyWindow extends Component {
constructor(props) {
super(props);
this.simpleWorkspace = React.createRef();
var locale = window.localStorage.getItem('locale');
this.state = {
renderer: window.localStorage.getItem('renderer'),
};
if (locale === null) {
if (navigator.language === 'de-DE') {
locale = 'de';
} else {
locale = 'en';
}
}
if (locale === 'de') {
Blockly.setLocale(De);
} else if (locale === 'en') {
Blockly.setLocale(En);
}
}
componentDidMount() {
const workspace = Blockly.getMainWorkspace();
this.props.onChangeWorkspace({});
this.props.clearStats();
@ -56,7 +72,7 @@ class BlocklyWindow extends Component {
style={this.props.svg ? { height: 0 } : this.props.blocklyCSS}
readOnly={this.props.readOnly !== undefined ? this.props.readOnly : false}
trashcan={this.props.trashcan !== undefined ? this.props.trashcan : true}
renderer='geras'
renderer={this.state.renderer}
zoom={{ // https://developers.google.com/blockly/guides/configure/web/zoom
controls: this.props.zoomControls !== undefined ? this.props.zoomControls : true,
wheel: false,

View File

@ -17,5 +17,6 @@ import './map';
import './procedures';
import './time';
import './variables';
import './lists';
import '../helpers/types'

View File

@ -0,0 +1,60 @@
import Blockly, { FieldDropdown } from 'blockly/core';
import { selectedBoard } from '../helpers/board'
import * as Types from '../helpers/types'
import { getColour } from '../helpers/colour';
Blockly.Blocks['lists_create_empty'] = {
/**
* Elapsed time in milliseconds block definition
* @this Blockly.Block
*/
init: function () {
this.setHelpUrl('http://arduino.cc/en/Reference/Millis');
this.setColour(getColour().arrays);
this.appendDummyInput()
.appendField("create List with")
this.appendValueInput('NUMBER');
this.appendDummyInput()
.appendField("Items of Type")
.appendField(new FieldDropdown(Types.VARIABLE_TYPES), 'type');
this.setOutput(true, Types.ARRAY.typeId);
this.setTooltip(Blockly.Msg.ARD_TIME_MILLIS_TIP);
},
};
Blockly.Blocks['array_getIndex'] = {
/**
* Elapsed time in milliseconds block definition
* @this Blockly.Block
*/
init: function () {
this.setHelpUrl('http://arduino.cc/en/Reference/Millis');
this.setColour(getColour().arrays);
this.appendDummyInput()
.appendField(new Blockly.FieldVariable(
'X',
null,
['Array'],
'Array'
), 'FIELDNAME');
this.setOutput(true, Types.ARRAY.typeId);
this.setTooltip(Blockly.Msg.ARD_TIME_MILLIS_TIP);
},
};
Blockly.Blocks['lists_length'] = {
/**
* Elapsed time in milliseconds block definition
* @this Blockly.Block
*/
init: function () {
this.setHelpUrl('http://arduino.cc/en/Reference/Millis');
this.setColour(getColour().arrays);
this.appendValueInput('ARRAY')
.appendField('length of')
.setCheck(Types.ARRAY.compatibleTypes);
this.setOutput(true, Types.NUMBER.typeName);
this.setTooltip(Blockly.Msg.ARD_TIME_MILLIS_TIP);
},
};

View File

@ -81,6 +81,54 @@ Blockly.Blocks['sensebox_display_printDisplay'] = {
LOOP_TYPES: ['sensebox_display_show'],
};
Blockly.Blocks['sensebox_display_fastPrint'] = {
init: function (block) {
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_display_fastPrint_show);
this.appendValueInput("Title1", 'Title1')
.appendField(Blockly.Msg.senseBox_display_fastPrint_title);
this.appendValueInput("Value1", 'Value1')
.appendField(Blockly.Msg.senseBox_display_fastPrint_value);
this.appendValueInput("Dimension1", 'Dimension1')
.appendField(Blockly.Msg.senseBox_display_fastPrint_dimension);
this.appendValueInput("Title2", 'Title2')
.appendField(Blockly.Msg.senseBox_display_fastPrint_title);
this.appendValueInput("Value2", 'Value2')
.appendField(Blockly.Msg.senseBox_display_fastPrint_value);
this.appendValueInput("Dimension2", 'Dimension2')
.appendField(Blockly.Msg.senseBox_display_fastPrint_dimension);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setTooltip(Blockly.Msg.sensebox_display_fastPrint_tip);
this.setHelpUrl('https://sensebox.de/books');
},
/**
* Called whenever anything on the workspace changes.
* Add warning if block is not nested inside a the correct loop.
* @param {!Blockly.Events.Abstract} e Change event.
* @this Blockly.Block
*/
onchange: function (e) {
var legal = false;
// Is the block nested in a loop?
var block = this;
do {
if (this.LOOP_TYPES.indexOf(block.type) != -1) {
legal = true;
break;
}
block = block.getSurroundParent();
} while (block);
if (legal) {
this.setWarningText(null);
} else {
this.setWarningText(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_WARNING);
}
},
LOOP_TYPES: ['sensebox_display_show'],
};
Blockly.Blocks['sensebox_display_plotDisplay'] = {
init: function () {

View File

@ -42,3 +42,32 @@ Blockly.Blocks['sensebox_rgb_led'] = {
this.setHelpUrl('https://sensebox.de/books');
}
};
Blockly.Blocks['sensebox_ws2818_led'] = {
init: function () {
var dropdownOptions = [[Blockly.Msg.senseBox_ultrasonic_port_A, '1'],
[Blockly.Msg.senseBox_ultrasonic_port_B, '3'], [Blockly.Msg.senseBox_ultrasonic_port_C, '5']];
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_ws2818_rgb_led)
.appendField("Pin:")
.appendField(new Blockly.FieldDropdown(dropdownOptions), "Port")
this.appendValueInput("BRIGHTNESS", "brightness")
.appendField((Blockly.Msg.senseBox_ws2818_rgb_led_brightness));
this.appendValueInput("POSITION", "position")
.appendField((Blockly.Msg.senseBox_ws2818_rgb_led_position));
this.appendValueInput("RED", 'Number')
.appendField(Blockly.Msg.COLOUR_RGB_RED);//Blockly.Msg.senseBox_basic_red
this.appendValueInput("GREEN", 'Number')
.appendField(Blockly.Msg.COLOUR_RGB_GREEN);//Blockly.Msg.senseBox_basic_green
this.appendValueInput("BLUE", 'Number')
.appendField(Blockly.Msg.COLOUR_RGB_BLUE);
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
this.setTooltip(Blockly.Msg.senseBox_rgb_led_tip);
this.setHelpUrl('https://sensebox.de/books');
}
};

View File

@ -1,6 +1,7 @@
import * as Blockly from 'blockly/core';
import { getColour } from '../helpers/colour';
var apiData = '[{"_id":"5e6073fe57703e001bb99453","createdAt":"2020-03-05T03:37:34.151Z","updatedAt":"2020-10-17T10:49:51.636Z","name":"Vtuzgorodok","currentLocation":{"timestamp":"2020-03-05T03:37:34.146Z","coordinates":[60.658676,56.833041,51],"type":"Point"},"exposure":"outdoor","sensors":[{"title":"PM10","unit":"µg/m³","sensorType":"SDS 011","icon":"osem-cloud","_id":"5e6073fe57703e001bb99458","lastMeasurement":{"value":"3.30","createdAt":"2020-10-17T10:49:51.627Z"}},{"title":"PM2.5","unit":"µg/m³","sensorType":"SDS 011","icon":"osem-cloud","_id":"5e6073fe57703e001bb99457","lastMeasurement":{"value":"0.90","createdAt":"2020-10-17T10:49:51.627Z"}},{"title":"Temperatur","unit":"°C","sensorType":"BME280","icon":"osem-thermometer","_id":"5e6073fe57703e001bb99456","lastMeasurement":{"value":"6.58","createdAt":"2020-10-17T10:49:51.627Z"}},{"title":"rel. Luftfeuchte","unit":"%","sensorType":"BME280","icon":"osem-humidity","_id":"5e6073fe57703e001bb99455","lastMeasurement":{"value":"53.76","createdAt":"2020-10-17T10:49:51.627Z"}},{"title":"Luftdruck","unit":"Pa","sensorType":"BME280","icon":"osem-barometer","_id":"5e6073fe57703e001bb99454","lastMeasurement":{"value":"96937.66","createdAt":"2020-10-17T10:49:51.627Z"}}],"model":"luftdaten_sds011_bme280","lastMeasurementAt":"2020-10-17T10:49:51.627Z","loc":[{"geometry":{"timestamp":"2020-03-05T03:37:34.146Z","coordinates":[60.658676,56.833041,51],"type":"Point"},"type":"Feature"}]}]';
Blockly.Blocks['sensebox_osem_connection'] = {
init: function () {
@ -20,6 +21,10 @@ Blockly.Blocks['sensebox_osem_connection'] = {
.setAlign(Blockly.ALIGN_LEFT)
.appendField("senseBox ID")
.appendField(new Blockly.FieldTextInput("senseBox ID"), "BoxID");
this.appendDummyInput()
.setAlign(Blockly.ALIGN_LEFT)
.appendField(Blockly.Msg.senseBox_osem_access_token)
.appendField(new Blockly.FieldTextInput("access_token"), "access_token");
this.appendStatementInput('DO')
.appendField(Blockly.Msg.senseBox_sensor)
.setCheck(null);
@ -27,9 +32,14 @@ Blockly.Blocks['sensebox_osem_connection'] = {
this.setNextStatement(true, null);
},
onchange: function (e) {
//Blockly.Blocks.sensebox.getDescendants = blocks;
let boxID = this.getFieldValue('BoxID');
if (boxID !== 'senseBox ID') {
fetch('https://api.opensensemap.org/boxes/ ' + boxID)
.then(res => res.json())
.then((data) => {
apiData = data;
})
}
},
mutationToDom: function () {
var container = document.createElement('mutation');
@ -73,25 +83,47 @@ Blockly.Blocks['sensebox_osem_connection'] = {
};
Blockly.Blocks['sensebox_send_to_osem'] = {
init: function () {
this.setTooltip(Blockly.Msg.senseBox_send_to_osem_tip);
this.setHelpUrl('');
this.setColour(getColour().sensebox);
this.appendDummyInput()
.appendField(Blockly.Msg.senseBox_send_to_osem);
this.appendValueInput('Value')
.setCheck(null)
.appendField('Sensor ID')
.appendField(new Blockly.FieldTextInput('Sensor ID'), 'SensorID');
.appendField('Phänomen')
.appendField(new Blockly.FieldDropdown(
this.generateOptions), 'SensorID');
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
},
generateOptions: function () {
var options = [['', '']];
if (apiData.sensors != undefined) {
for (var i = 0; i < apiData.sensors.length; i++) {
options.push([apiData.sensors[i].title, apiData.sensors[i]._id]);
}
console.log(options);
}
if (options.length > 1) {
var dropdown = options.slice(1)
console.log(dropdown);
return dropdown;
} else
return options;
},
/**
* Called whenever anything on the workspace changes.
* Add warning if block is not nested inside a the correct loop.
* @param {!Blockly.Events.Abstract} e Change event.
* @this Blockly.Block
*/
onchange: function (e) {
onchange: function () {
var legal = false;
// Is the block nested in a loop?
var block = this;
@ -108,5 +140,10 @@ Blockly.Blocks['sensebox_send_to_osem'] = {
this.setWarningText(Blockly.Msg.CONTROLS_FLOW_STATEMENTS_WARNING);
}
},
LOOP_TYPES: ['sensebox_osem_connection'],
/**
* List of block types that are loops and thus do not need warnings.
* To add a new loop type add this to your code:
* Blockly.Blocks['controls_flow_statements'].LOOP_TYPES.push('custom_loop');
*/
LOOP_TYPES: ['sensebox_osem_connection']
};

View File

@ -17,5 +17,6 @@ import './audio';
import './procedures';
import './time';
import './variables';
import './lists';

View File

@ -0,0 +1,19 @@
import * as Blockly from 'blockly/core';
Blockly.Arduino['lists_create_empty'] = function () {
var code = '';
return [code, Blockly.Arduino.ORDER_ATOMIC];
}
Blockly.Arduino['array_getIndex'] = function () {
var code = '';
return [code, Blockly.Arduino.ORDER_ATOMIC];
}
Blockly.Arduino['lists_length'] = function () {
var array = Blockly.Arduino.valueToCode(this, 'ARRAY', Blockly.Arduino.ORDER_ATOMIC);
var code = `${array}.length`;
return [code, Blockly.Arduino.ORDER_ATOMIC];
}

View File

@ -31,6 +31,42 @@ Blockly.Arduino.sensebox_display_printDisplay = function () {
return code;
};
Blockly.Arduino.sensebox_display_fastPrint = function () {
var title1 = Blockly.Arduino.valueToCode(this, 'Title1', Blockly.Arduino.ORDER_ATOMIC) || '0'
var value1 = Blockly.Arduino.valueToCode(this, 'Value1', Blockly.Arduino.ORDER_ATOMIC);
var dimension1 = Blockly.Arduino.valueToCode(this, 'Dimension1', Blockly.Arduino.ORDER_ATOMIC) || '0'
var title2 = Blockly.Arduino.valueToCode(this, 'Title2', Blockly.Arduino.ORDER_ATOMIC) || '0'
var value2 = Blockly.Arduino.valueToCode(this, 'Value2', Blockly.Arduino.ORDER_ATOMIC);
var dimension2 = Blockly.Arduino.valueToCode(this, 'Dimension2', Blockly.Arduino.ORDER_ATOMIC) || '0'
Blockly.Arduino.codeFunctions_['sensebox_fastPrint'] = `
void printOnDisplay(String title1, String measurement1, String unit1, String title2, String measurement2, String unit2) {
display.setCursor(0, 0);
display.setTextSize(1);
display.setTextColor(WHITE, BLACK);
display.println(title1);
display.setCursor(0, 10);
display.setTextSize(2);
display.print(measurement1);
display.print(" ");
display.setTextSize(1);
display.println(unit1);
display.setCursor(0, 30);
display.setTextSize(1);
display.println(title2);
display.setCursor(0, 40);
display.setTextSize(2);
display.print(measurement2);
display.print(" ");
display.setTextSize(1);
display.println(unit2);
}
`
var code = ` printOnDisplay(${title1}, String(${value1}), ${dimension1}, ${title2}, String(${value2}), ${dimension2});\n`;
return code;
};
Blockly.Arduino.sensebox_display_show = function (block) {
var show = Blockly.Arduino.statementToCode(block, 'SHOW');
var code = '';

View File

@ -20,3 +20,27 @@ Blockly.Arduino.sensebox_rgb_led = function () {
code += 'rgb_led_' + dropdown_pin + '.show();';
return code;
};
Blockly.Arduino.sensebox_ws2818_led = function () {
var dropdown_pin = this.getFieldValue('Port');
var blocks = Blockly.mainWorkspace.getAllBlocks();
var count = 0;
for (var i = 0; i < blocks.length; i++) {
if (blocks[i].type === 'sensebox_ws2818_led' && blocks[i].getFieldValue('Port') === dropdown_pin) {
count++;
}
}
var numPixel = count;
var brightness = Blockly.Arduino.valueToCode(this, 'BRIGHTNESS', Blockly.Arduino.ORDER_ATOMIC) || '50'
var position = Blockly.Arduino.valueToCode(this, 'POSITION', Blockly.Arduino.ORDER_ATOMIC) || '0';
var red = Blockly.Arduino.valueToCode(this, 'RED', Blockly.Arduino.ORDER_ATOMIC) || '0'
var green = Blockly.Arduino.valueToCode(this, 'GREEN', Blockly.Arduino.ORDER_ATOMIC) || '0'
var blue = Blockly.Arduino.valueToCode(this, 'BLUE', Blockly.Arduino.ORDER_ATOMIC) || '0'
Blockly.Arduino.definitions_['define_rgb_led' + dropdown_pin] = `#include <Adafruit_NeoPixel.h>\n Adafruit_NeoPixel rgb_led_${dropdown_pin}= Adafruit_NeoPixel(${numPixel}, ${dropdown_pin},NEO_GRB + NEO_KHZ800);\n`;
Blockly.Arduino.setupCode_['setup_rgb_led' + dropdown_pin] = 'rgb_led_' + dropdown_pin + '.begin();\n';
Blockly.Arduino.setupCode_['setup_rgb_led_brightness' + dropdown_pin] = `rgb_led_${dropdown_pin}.setBrightness(${brightness});\n`;
var code = `rgb_led_${dropdown_pin}.setPixelColor(${position},rgb_led_${dropdown_pin}.Color(${red},${green},${blue}));\nrgb_led_${dropdown_pin}.show();\n`;
return code;
};

View File

@ -18,17 +18,20 @@ Blockly.Arduino.sensebox_osem_connection = function (Block) {
var box_id = this.getFieldValue('BoxID');
var host = this.getFieldValue('host');
var branch = Blockly.Arduino.statementToCode(Block, 'DO');
//var blocks = Blockly.Block.getDescendants;
var access_token = this.getFieldValue('access_token');
var blocks = this.getDescendants();
var type = this.getFieldValue('type');
var ssl = this.getFieldValue('SSL');
var port = 0;
var count = 0;
// for (var i = 0; i < blocks.length; i++) {
// if (blocks[i].type === 'sensebox_send_to_osem') {
// count++;
if (blocks != undefined) {
for (var i = 0; i < blocks.length; i++) {
if (blocks[i].type === 'sensebox_send_to_osem') {
count++;
// }
// }
}
}
}
var num_sensors = count;
Blockly.Arduino.libraries_['library_senseBoxMCU'] = '#include "SenseBoxMCU.h"';
Blockly.Arduino.definitions_['num_sensors'] = 'static const uint8_t NUM_SENSORS = ' + num_sensors + ';'
@ -84,7 +87,7 @@ Blockly.Arduino.sensebox_osem_connection = function (Block) {
if (connected == true) {
// construct the HTTP POST request:
sprintf_P(buffer,
PSTR("POST /boxes/%s/data HTTP/1.1\\nHost: %s\\nContent-Type: "
PSTR("POST /boxes/%s/data HTTP/1.1\\nAuthorization: ${access_token}\\nHost: %s\\nContent-Type: "
"text/csv\\nConnection: close\\nContent-Length: %i\\n\\n"),
SENSEBOX_ID, server, num_measurements * lengthMultiplikator);
// send the HTTP POST request:
@ -144,7 +147,7 @@ Blockly.Arduino.sensebox_osem_connection = function (Block) {
if (connected == true) {
// construct the HTTP POST request:
sprintf_P(buffer,
PSTR("POST /boxes/%s/data HTTP/1.1\\nHost: %s\\nContent-Type: "
PSTR("POST /boxes/%s/data HTTP/1.1\\nAuthorization: ${access_token}\\nHost: %s\\nContent-Type: "
"text/csv\\nConnection: close\\nContent-Length: %i\\n\\n"),
SENSEBOX_ID, server, num_measurements * lengthMultiplikator);
// send the HTTP POST request:

View File

@ -14,9 +14,28 @@ const setVariableFunction = function (defaultValue) {
const allVars = Blockly.getMainWorkspace().getVariableMap().getAllVariables();
const myVar = allVars.filter(v => v.name === variableName)[0]
var code = ''
switch (myVar.type) {
default:
Blockly.Arduino.variables_[myVar + myVar.type] = myVar.type + " " + myVar.name + ';\n';
return variableName + ' = ' + (variableValue || defaultValue) + ';\n';
code = variableName + ' = ' + (variableValue || defaultValue) + ';\n';
break;
case 'Array':
var arrayType;
var number;
if (this.getChildren().length > 0) {
if (this.getChildren()[0].type === 'lists_create_empty') {
arrayType = this.getChildren()[0].getFieldValue('type');
number = Blockly.Arduino.valueToCode(this.getChildren()[0], 'NUMBER', Blockly['Arduino'].ORDER_ATOMIC);
Blockly.Arduino.variables_[myVar + myVar.type] = `${arrayType} ${myVar.name} [${number}];\n`;
}
}
break;
}
return code;
};
};
@ -25,8 +44,8 @@ const getVariableFunction = function (block) {
block.getFieldValue('VAR'),
Blockly.Variables.NAME_TYPE
);
return [variableName, Blockly['Arduino'].ORDER_ATOMIC];
var code = variableName;
return [code, Blockly['Arduino'].ORDER_ATOMIC];
};
Blockly['Arduino']['variables_set_dynamic'] = setVariableFunction()

View File

@ -10,6 +10,7 @@ const colours = {
text: 160,
variables: 330,
audio: 250,
arrays: 33
}

View File

@ -60,7 +60,7 @@ export const DECIMAL = {
/** Array/List of items. */
export const ARRAY = {
typeId: 'Array',
typeName: 'array',
typeName: 'Array',
typeMsgName: 'ARD_TYPE_ARRAY',
compatibleTypes: []
}
@ -87,6 +87,7 @@ export const CHILD_BLOCK_MISSING = {
}
const compatibleTypes = {
Array: ['Array'],
boolean: ['boolean'],
int: ['int'],
char: ['char'],

View File

@ -1,7 +1,3 @@
// import * as Blockly from 'blockly/core';
// https://developers.google.com/blockly/guides/configure/web/translations
const Blockly = {};
Blockly.Msg = {};
@ -610,6 +606,7 @@ Blockly.Msg.senseBox_osem_connection = "Verbinde mit openSenseMap";
Blockly.Msg.senseBox_osem_exposure = "Typ";
Blockly.Msg.senseBox_osem_stationary = "Stationär";
Blockly.Msg.senseBox_osem_mobile = "Mobil";
Blockly.Msg.senseBox_osem_access_token = "API Schlüssel";
Blockly.Msg.senseBox_sds011 = "Feinstaubsensor";
Blockly.Msg.senseBox_sds011_dimension = "in µg/m³ an";
Blockly.Msg.senseBox_sds011_pm25 = "PM2.5";
@ -650,7 +647,11 @@ Blockly.Msg.sensebox_display_fillCircle_radius = "Radius";
Blockly.Msg.sensebox_display_drawRectangle = "Zeichne Rechteck";
Blockly.Msg.sensebox_display_drawRectangle_width = "Breite";
Blockly.Msg.sensebox_display_drawRectangle_height = "Höhe";
Blockly.Msg.senseBox_display_filled = "Ausgefüllt"
Blockly.Msg.senseBox_display_filled = "Ausgefüllt";
Blockly.Msg.senseBox_display_fastPrint_show = "Zeige Messwerte";
Blockly.Msg.senseBox_display_fastPrint_title = "Titel";
Blockly.Msg.senseBox_display_fastPrint_value = "Messwert";
Blockly.Msg.senseBox_display_fastPrint_dimension = "Einheit";
// GPS
Blockly.Msg.senseBox_gps_getValues = "GPS Modul";
Blockly.Msg.senseBox_gps_getValues_tip = "ruft das GPS Signal ab";
@ -771,7 +772,11 @@ Blockly.Msg.senseBox_telegram_do = "Telegram mache"
Blockly.Msg.senseBox_telegram_do_on_message = "bei Nachricht"
Blockly.Msg.senseBox_telegram_message = "Nachricht"
Blockly.Msg.senseBox_telegram_send = "Sende Nachricht"
//SCD30 CO2 Sensor
Blockly.Msg.senseBox_scd30 = "CO2 Sensor (Sensirion SCD30)";
//WS2818 RGB LED
Blockly.Msg.senseBox_ws2818_rgb_led = "senseBox WS2812 - RGB LED";
Blockly.Msg.senseBox_ws2818_rgb_led_position = "Position";
Blockly.Msg.senseBox_ws2818_rgb_led_brightness = "Helligkeit";
export const De = Blockly.Msg;

View File

@ -1,7 +1,3 @@
// import * as Blockly from 'blockly/core';
// https://developers.google.com/blockly/guides/configure/web/translations
const Blockly = {};
Blockly.Msg = {};
@ -613,6 +609,11 @@ Blockly.Msg.senseBox_display_printDisplay_y = "y-coordinates";
Blockly.Msg.senseBox_display_setSize = "set font size to";
Blockly.Msg.senseBox_display_setSize_tip = "Change the font size. Set a Value between 1-10.";
Blockly.Msg.senseBox_display_white = "White";
Blockly.Msg.senseBox_display_fastPrint_dimension = "Unit";
Blockly.Msg.senseBox_display_fastPrint_show = "Show Measurements";
Blockly.Msg.senseBox_display_fastPrint_tip = "Show two measurements with title and dimension on the display";
Blockly.Msg.senseBox_display_fastPrint_title = "Title";
Blockly.Msg.senseBox_display_fastPrint_value = "Measurement";
Blockly.Msg.senseBox_foto = "Light Dependent Resistor";
Blockly.Msg.senseBox_foto_tip = "simple light depending resistor, gives values between 0 and 1023";
Blockly.Msg.senseBox_gas = "Gas (VOC)";
@ -676,6 +677,7 @@ Blockly.Msg.senseBox_osem_host = "opensensemap.org";
Blockly.Msg.senseBox_osem_host_workshop = "workshop.opensensemap.org";
Blockly.Msg.senseBox_osem_mobile = "Mobile";
Blockly.Msg.senseBox_osem_stationary = "Stationary";
Blockly.Msg.senseBox_osem_access_token = "API Key";
Blockly.Msg.senseBox_output_filename = "filename";
Blockly.Msg.senseBox_output_format = "format:";
Blockly.Msg.senseBox_output_linebreak = "linebreak";
@ -753,7 +755,13 @@ Blockly.Msg.sensebox_display_show_tip = "Print on Display";
Blockly.Msg.sensebox_sd_filename = "data";
Blockly.Msg.sensebox_soil_smt50 = "Soil Moisture and Temperature (SMT50)";
Blockly.Msg.sensebox_web_readHTML_filename = "File:";
//SCD30 CO2 Sensor
Blockly.Msg.senseBox_scd30 = "CO2 Sensor (Sensirion SCD30)";
//WS2818 RGB LED
Blockly.Msg.senseBox_ws2818_rgb_led = "senseBox WS2812 - RGB LED";
Blockly.Msg.senseBox_ws2818_rgb_led_brightness = "Helligkeit";
Blockly.Msg.senseBox_ws2818_rgb_led_position = "Position";
export const En = Blockly.Msg;

View File

@ -2,7 +2,6 @@ import React from 'react';
import { Block, Value, Field, Shadow, Category } from '../';
import { getColour } from '../helpers/colour'
import '@blockly/block-plus-minus';
import { TypedVariableModal } from '@blockly/plugin-typed-variable-modal';
import * as Blockly from 'blockly/core';
@ -14,12 +13,14 @@ class Toolbox extends React.Component {
componentDidUpdate() {
this.props.workspace.registerToolboxCategoryCallback('CREATE_TYPED_VARIABLE', this.createFlyout);
const typedVarModal = new TypedVariableModal(this.props.workspace, 'callbackName', [['SHORT_NUMBER', 'char'], ['NUMBER', 'int'], ['DECIMAL', 'float'], ['TEXT', 'String'], ['CHARACTER', 'char'], ['BOOLEAN', 'boolean'], ['NULL', 'void'], ['UNDEF', 'undefined']]);
const typedVarModal = new TypedVariableModal(this.props.workspace, 'callbackName', [['SHORT_NUMBER', 'char'], ['NUMBER', 'int'], ['DECIMAL', 'float'], ['TEXT', 'String'], ['ARRAY', 'Array'], ['CHARACTER', 'char'], ['BOOLEAN', 'boolean'], ['NULL', 'void'], ['UNDEF', 'undefined']]);
typedVarModal.init();
}
createFlyout(workspace) {
let xmlList = [];
// Add your button and give it a callback name.
const button = document.createElement('button');
button.setAttribute('text', 'Create Typed Variable');
@ -61,6 +62,33 @@ class Toolbox extends React.Component {
<Category name="LED" colour={getColour().sensebox}>
<Block type="sensebox_rgb_led" />
<Block type="sensebox_led" />
<Block type="sensebox_ws2818_led">
<Value name="POSITION">
<Block type="math_number">
<Field name="NUM">0</Field>
</Block>
</Value>
<Value name="BRIGHTNESS">
<Block type="math_number">
<Field name="NUM">30</Field>
</Block>
</Value>
<Value name="RED">
<Block type="math_number">
<Field name="NUM">0</Field>
</Block>
</Value>
<Value name="GREEN">
<Block type="math_number">
<Field name="NUM">0</Field>
</Block>
</Value>
<Value name="BLUE">
<Block type="math_number">
<Field name="NUM">0</Field>
</Block>
</Value>
</Block>
</Category>
<Category name="Display" colour={getColour().sensebox}>
<Block type="sensebox_display_beginDisplay" />
@ -83,6 +111,28 @@ class Toolbox extends React.Component {
</Block>
</Value>
</Block>
<Block type="sensebox_display_fastPrint">
<Value name="Title1">
<Block type="text">
<Field name="TEXT">Title</Field>
</Block>
</Value>
<Value name="Dimension1">
<Block type="text">
<Field name="TEXT">Unit</Field>
</Block>
</Value>
<Value name="Title2">
<Block type="text">
<Field name="TEXT">Title</Field>
</Block>
</Value>
<Value name="Dimension2">
<Block type="text">
<Field name="TEXT">Unit</Field>
</Block>
</Value>
</Block >
<Block type="sensebox_display_plotDisplay">
<Value name="Title">
<Block type="text">
@ -323,7 +373,12 @@ class Toolbox extends React.Component {
</Block>
<Block type="io_notone"></Block>
</Category>
<Category name="Variablen" colour={getColour().variables} custom="CREATE_TYPED_VARIABLE"></Category>;
<Category name="Variablen" colour={getColour().variables} custom="CREATE_TYPED_VARIABLE"></Category>
<Category name="Arrays" colour={getColour().arrays} >
<Block type="lists_create_empty" />
<Block type="array_getIndex" />
<Block type="lists_length" />
</Category>
<sep></sep>
<Category name="Eingang/Ausgang" colour={getColour().io}>
<Block type="io_digitalwrite"></Block>

View File

@ -0,0 +1,122 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import clsx from 'clsx';
import Breadcrumbs from '../Breadcrumbs';
// import gallery from './gallery.json';
// import tutorials from '../../data/tutorials.json';
import { Link } from 'react-router-dom';
import { fade } from '@material-ui/core/styles/colorManipulator';
import { withStyles } from '@material-ui/core/styles';
import Grid from '@material-ui/core/Grid';
import Paper from '@material-ui/core/Paper';
import BlocklyWindow from '../Blockly/BlocklyWindow';
import Divider from '@material-ui/core/Divider';
const styles = (theme) => ({
outerDiv: {
position: 'absolute',
right: '-30px',
bottom: '-30px',
width: '160px',
height: '160px',
color: fade(theme.palette.secondary.main, 0.6)
},
outerDivError: {
stroke: fade(theme.palette.error.dark, 0.6),
color: fade(theme.palette.error.dark, 0.6)
},
outerDivSuccess: {
stroke: fade(theme.palette.primary.main, 0.6),
color: fade(theme.palette.primary.main, 0.6)
},
outerDivOther: {
stroke: fade(theme.palette.secondary.main, 0.6)
},
innerDiv: {
width: 'inherit',
height: 'inherit',
display: 'table-cell',
verticalAlign: 'middle',
textAlign: 'center'
}
});
class GalleryHome extends Component {
state = {
gallery: []
}
componentDidMount() {
console.log(process.env.REACT_APP_BLOCKLY_API)
fetch(process.env.REACT_APP_BLOCKLY_API + this.props.location.pathname)
.then(res => res.json())
.then((data) => {
this.setState({ gallery: data })
})
}
render() {
return (
<div>
<Breadcrumbs content={[{ link: '/gallery', title: 'Gallery' }]} />
<h1>Gallery</h1>
<Grid container spacing={2}>
{this.state.gallery.map((gallery, i) => {
return (
<Grid item xs={12} sm={6} md={4} xl={3} key={i} style={{}}>
<Link to={`/gallery/${gallery.id}`} style={{ textDecoration: 'none', color: 'inherit' }}>
<Paper style={{ height: '400px', padding: '2rem', position: 'relative', overflow: 'hidden' }}>
<h3>{gallery.title}</h3>
<Divider />
<Grid container spacing={10} style={{ marginBottom: '5px' }}>
<Grid item xs={12}>
<BlocklyWindow
trashcan={false}
zoomControls={false}
blockDisabled
blocklyCSS={{ height: '18vH' }}
initialXml={gallery.xml}
/>
</Grid>
</Grid>
<p>{gallery.text}</p>
<Divider />
<div className={clsx(this.props.classes.outerDiv)} style={{ width: '160px', height: '160px', border: 0 }}>
</div>
</Paper>
</Link>
</Grid>
)
})}
</Grid>
</div>
);
};
}
GalleryHome.propTypes = {
status: PropTypes.array.isRequired,
change: PropTypes.number.isRequired,
};
const mapStateToProps = state => ({
change: state.tutorial.change,
status: state.tutorial.status
});
export default connect(mapStateToProps, null)(withStyles(styles, { withTheme: true })(GalleryHome));

View File

@ -0,0 +1,37 @@
[
{
"id": 15212,
"title": "Das senseBox Buch Kapitel 1",
"name": "Mario",
"text": "Die Blöcke findest du in der Kategorie \"Schleifen\". Die einfachste Schleife, die du Verwenden kannst, ist der Block \"Wiederhole 10 mal\". Bei diesem Block kannst du die Blöcke, die eine bestimmte Zahl wiederholt werden soll einfach in den offenen Block abschnitt ziehen. ",
"xml": "<xml xmlns=\"https://developers.google.com/blockly/xml\">\n <block type=\"controls_repeat_ext\" id=\"!|`dyF$`~*!l~D[TUc4N\" x=\"38\" y=\"32\">\n <value name=\"TIMES\">\n <block type=\"math_number\" id=\"ktgQ[7pD~M{sq;r^kLuz\">\n <field name=\"NUM\">10</field>\n </block>\n </value>\n </block>\n</xml>"
},
{
"id": 25451,
"title": "Das senseBox Buch Kapitel 2",
"name": "Mario",
"text": "",
"xml": "<xml xmlns=\"https://developers.google.com/blockly/xml\">\n <block type=\"arduino_functions\" id=\"5KebY,-ltvxB7K^El}1(\" x=\"30\" y=\"34\">\n <statement name=\"LOOP_FUNC\">\n <block type=\"sensebox_led\" id=\"Y(DUYI_.t1V!_9Qf7lgl\">\n <field name=\"PIN\">1</field>\n <field name=\"STAT\">HIGH</field>\n <next>\n <block type=\"time_delay\" id=\"C2.adlos#1/Ns)1@K!Or\">\n <value name=\"DELAY_TIME_MILI\">\n <block type=\"math_number\" id=\")uPzh6_L+SQaIr+v8B,\">\n <field name=\"NUM\">1000</field>\n </block>\n </value>\n <next>\n <block type=\"sensebox_led\" id=\"w215h=etDdQ(Aao86qG2\">\n <field name=\"PIN\">1</field>\n <field name=\"STAT\">LOW</field>\n <next>\n <block type=\"time_delay\" id=\"1pPNxT#ag6fFP|=fy(,%\">\n <value name=\"DELAY_TIME_MILI\">\n <block type=\"math_number\" id=\"%xCj(nr,]@f{ALe^{vH}\">\n <field name=\"NUM\">1000</field>\n </block>\n </value>\n </block>\n </next>\n </block>\n </next>\n </block>\n </next>\n </block>\n </statement>\n </block>\n</xml>"
},
{
"id": 3541512,
"title": "Das senseBox Buch Kapitel 3",
"name": "Mario",
"text": "",
"xml": "<xml xmlns=\"http://www.w3.org/1999/xhtml\">\n <block type=\"arduino_functions\" id=\"5KebY,-ltvxB7K^El}1(\" x=\"30\" y=\"34\">\n <statement name=\"SETUP_FUNC\">\n <block type=\"sensebox_display_beginDisplay\" id=\")Z4]CI*ibRqWkqLr^pjb\"></block>\n </statement>\n <statement name=\"LOOP_FUNC\">\n <block type=\"sensebox_display_show\" id=\"r)I#b]xjcH,b@8g*,Pf^\">\n <statement name=\"SHOW\">\n <block type=\"sensebox_display_printDisplay\" id=\"o{6DR6H4f;Qj%n=@XgaW\">\n <field name=\"COLOR\">WHITE,BLACK</field>\n <value name=\"SIZE\">\n <block type=\"math_number\" id=\"u}2t2rIa6Wx2)42.Ij]}\">\n <field name=\"NUM\">1</field>\n </block>\n </value>\n <value name=\"X\">\n <block type=\"math_number\" id=\"6n/}z0xXtJLhHm0E9kF/\">\n <field name=\"NUM\">0</field>\n </block>\n </value>\n <value name=\"Y\">\n <block type=\"math_number\" id=\"Y-NwVU`0,j73ON)ODL^Y\">\n <field name=\"NUM\">0</field>\n </block>\n </value>\n <value name=\"printDisplay\">\n <block type=\"text_join\" id=\"t*`nvkah#B@JrGRge`u[\">\n <mutation items=\"2\"></mutation>\n <value name=\"ADD0\">\n <block type=\"text\" id=\"*n^fD@DZEq^eLPc|CvJ[\">\n <field name=\"TEXT\">Helligkeit:</field>\n </block>\n </value>\n <value name=\"ADD1\">\n <block type=\"sensebox_sensor_uv_light\" id=\"tT8cG:UHho:SUKZQLVG{\">\n <field name=\"NAME\">Illuminance</field>\n </block>\n </value>\n </block>\n </value>\n </block>\n </statement>\n </block>\n </statement>\n </block>\n</xml>"
},
{
"id": 7487454,
"title": "Das senseBox Buch Kapitel 4",
"name": "Mario",
"text": "",
"xml": "<xml xmlns=\"http://www.w3.org/1999/xhtml\">\n <block type=\"arduino_functions\" id=\"5KebY,-ltvxB7K^El}1(\" x=\"30\" y=\"34\">\n <statement name=\"SETUP_FUNC\">\n <block type=\"sensebox_display_beginDisplay\" id=\")Z4]CI*ibRqWkqLr^pjb\"></block>\n </statement>\n <statement name=\"LOOP_FUNC\">\n <block type=\"sensebox_display_show\" id=\"r)I#b]xjcH,b@8g*,Pf^\">\n <statement name=\"SHOW\">\n <block type=\"sensebox_display_printDisplay\" id=\"o{6DR6H4f;Qj%n=@XgaW\">\n <field name=\"COLOR\">WHITE,BLACK</field>\n <value name=\"SIZE\">\n <block type=\"math_number\" id=\"u}2t2rIa6Wx2)42.Ij]}\">\n <field name=\"NUM\">1</field>\n </block>\n </value>\n <value name=\"X\">\n <block type=\"math_number\" id=\"6n/}z0xXtJLhHm0E9kF/\">\n <field name=\"NUM\">0</field>\n </block>\n </value>\n <value name=\"Y\">\n <block type=\"math_number\" id=\"Y-NwVU`0,j73ON)ODL^Y\">\n <field name=\"NUM\">0</field>\n </block>\n </value>\n <value name=\"printDisplay\">\n <block type=\"text_join\" id=\"t*`nvkah#B@JrGRge`u[\">\n <mutation items=\"2\"></mutation>\n <value name=\"ADD0\">\n <block type=\"text\" id=\"*n^fD@DZEq^eLPc|CvJ[\">\n <field name=\"TEXT\">Helligkeit:</field>\n </block>\n </value>\n <value name=\"ADD1\">\n <block type=\"sensebox_sensor_uv_light\" id=\"tT8cG:UHho:SUKZQLVG{\">\n <field name=\"NAME\">Illuminance</field>\n </block>\n </value>\n </block>\n </value>\n </block>\n </statement>\n </block>\n </statement>\n </block>\n</xml>"
},
{
"id": 54541251,
"title": "Das senseBox Buch Kapitel 5",
"name": "Mario",
"text": "",
"xml": ""
}
]

View File

@ -10,6 +10,7 @@ import WorkspaceFunc from './WorkspaceFunc';
import BlocklyWindow from './Blockly/BlocklyWindow';
import CodeViewer from './CodeViewer';
import TrashcanButtons from './TrashcanButtons';
import { createNameId } from 'mnemonic-id';
import HintTutorialExists from './Tutorial/HintTutorialExists';
import Grid from '@material-ui/core/Grid';
@ -45,14 +46,29 @@ const styles = (theme) => ({
class Home extends Component {
state = {
codeOn: false
codeOn: false,
gallery: [],
share: [],
projectToLoad: undefined
}
componentDidMount() {
this.props.workspaceName(createNameId());
fetch(process.env.REACT_APP_BLOCKLY_API + this.props.location.pathname)
.then(res => res.json())
.then((data) => {
this.setState({ projectToLoad: data })
})
}
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);
}
@ -72,6 +88,13 @@ class Home extends Component {
}
render() {
// console.log(this.props.match.params.galleryId);
// console.log(gallery);
// console.log(gallery.filter(project => project.id == this.props.match.params.galleryId));
if (this.state.projectToLoad) {
console.log(this.state.projectToLoad.xml)
}
console.log(this.props);
return (
<div>
<div style={{ float: 'right', height: '40px', marginBottom: '20px' }}><WorkspaceFunc /></div>
@ -88,7 +111,10 @@ class Home extends Component {
</IconButton>
</Tooltip>
<TrashcanButtons />
<BlocklyWindow blocklyCSS={{ height: '80vH' }} blockDisabled />
{this.state.projectToLoad ?
< BlocklyWindow blocklyCSS={{ height: '80vH' }} initialXml={this.state.projectToLoad.xml} /> : < BlocklyWindow blocklyCSS={{ height: '80vH' }} />
}
</Grid>
{this.state.codeOn ?
<Grid item xs={12} md={6}>

View File

@ -96,7 +96,7 @@ class Navbar extends Component {
</div>
</div>
<List>
{[{text: 'Tutorials', icon: faChalkboardTeacher, link: "/tutorial"}, {text: 'Tutorial-Builder', icon: faFolderPlus, link: "/tutorial/builder"}, {text: 'Einstellungen', icon: faCog, link: "/settings"}].map((item, index) => (
{[{ text: 'Tutorials', icon: faChalkboardTeacher, link: "/tutorial" }, { text: 'Tutorial-Builder', icon: faFolderPlus, link: "/tutorial/builder" }, { text: 'Gallery', icon: faFolderPlus, link: "/gallery" }, { text: 'Einstellungen', icon: faCog, link: "/settings" }].map((item, index) => (
<Link to={item.link} key={index} style={{ textDecoration: 'none', color: 'inherit' }}>
<ListItem button onClick={this.toggleDrawer}>
<ListItemIcon><FontAwesomeIcon icon={item.icon} /></ListItemIcon>

View File

@ -10,6 +10,9 @@ import Tutorial from './Tutorial/Tutorial';
import TutorialHome from './Tutorial/TutorialHome';
import Builder from './Tutorial/Builder/Builder';
import NotFound from './NotFound';
import GalleryHome from './Gallery/GalleryHome';
import Settings from './Settings/Settings';
class Routes extends Component {
@ -23,6 +26,10 @@ class Routes extends Component {
<Switch>
<Route path="/" exact component={Home} />
<Route path="/tutorial" exact component={TutorialHome} />
<Route path="/settings" exact component={Settings} />
<Route path="/gallery" exact component={GalleryHome} />
<Route path="/gallery/:galleryId" exact component={Home} />
<Route path="/share/:shareId" exact component={Home} />
<Route path="/tutorial/builder" exact component={Builder} />
<Route path="/tutorial/:tutorialId" exact component={Tutorial} />
<Route component={NotFound} />

View File

@ -0,0 +1,43 @@
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import InputLabel from '@material-ui/core/InputLabel';
import MenuItem from '@material-ui/core/MenuItem';
import FormControl from '@material-ui/core/FormControl';
import Select from '@material-ui/core/Select';
const useStyles = makeStyles((theme) => ({
formControl: {
margin: theme.spacing(1),
minWidth: 120,
},
selectEmpty: {
marginTop: theme.spacing(2),
},
}));
export default function LanguageSelector() {
const classes = useStyles();
const [lang, setLang] = React.useState(window.localStorage.getItem('locale'));
const handleChange = (event) => {
setLang(event.target.value);
window.localStorage.setItem('locale', event.target.value);
};
return (
<div>
<FormControl className={classes.formControl}>
<InputLabel id="demo-simple-select-label">Sprache</InputLabel>
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
value={lang}
onChange={handleChange}
>
<MenuItem value={'de'}>Deutsch</MenuItem>
<MenuItem value={'en'}>English</MenuItem>
</Select>
</FormControl>
</div>
);
}

View File

@ -0,0 +1,45 @@
import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import InputLabel from '@material-ui/core/InputLabel';
import MenuItem from '@material-ui/core/MenuItem';
import FormControl from '@material-ui/core/FormControl';
import Select from '@material-ui/core/Select';
const useStyles = makeStyles((theme) => ({
formControl: {
margin: theme.spacing(1),
minWidth: 400,
},
selectEmpty: {
marginTop: theme.spacing(2),
},
}));
export default function LanguageSelector() {
const classes = useStyles();
const [renderer, setRenderer] = React.useState(window.localStorage.getItem('renderer'));
const handleChange = (event) => {
setRenderer(event.target.value);
window.localStorage.setItem('renderer', event.target.value);
};
return (
<div>
<FormControl className={classes.formControl}>
<InputLabel id="demo-simple-select-label">Renderer</InputLabel>
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
value={renderer}
onChange={handleChange}
>
<MenuItem value={'geras'}>Geras</MenuItem>
<MenuItem value={'zelos'}>Zelos</MenuItem>
</Select>
</FormControl>
<p>Der Renderer bestimmt das aussehen der Blöcke</p>
</div>
);
}

View File

@ -0,0 +1,30 @@
import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
import LanguageSelector from './LanguageSelector';
import RenderSelector from './RenderSelector';
class Settings extends Component {
render() {
return (
<div>
<Typography variant='h4' style={{ marginBottom: '5px' }}>Einstellungen</Typography>
<LanguageSelector />
<RenderSelector />
<Button
style={{ marginTop: '20px' }}
variant="contained"
color="primary"
onClick={() => { this.props.history.push('/') }}
>
Zurück zur Startseite
</Button>
</div>
);
};
}
export default withRouter(Settings);

View File

@ -12,7 +12,6 @@ import { initialXml } from './Blockly/initialXml.js';
import Compile from './Compile';
import SolutionCheck from './Tutorial/SolutionCheck';
import Dialog from './Dialog';
import Snackbar from './Snackbar';
import withWidth, { isWidthDown } from '@material-ui/core/withWidth';
@ -22,8 +21,19 @@ import IconButton from '@material-ui/core/IconButton';
import Tooltip from '@material-ui/core/Tooltip';
import TextField from '@material-ui/core/TextField';
import Typography from '@material-ui/core/Typography';
import { createId } from 'mnemonic-id';
import { faPen, faSave, faUpload, faCamera, faShare } from "@fortawesome/free-solid-svg-icons";
import Dialog from './Dialog';
// import Dialog from '@material-ui/core/Dialog';
import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import DialogContentText from '@material-ui/core/DialogContentText';
import DialogTitle from '@material-ui/core/DialogTitle';
import { faPen, faSave, faUpload, faCamera, faShare, faShareAlt } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
const styles = (theme) => ({
@ -49,6 +59,7 @@ const styles = (theme) => ({
});
class WorkspaceFunc extends Component {
constructor(props) {
@ -60,13 +71,17 @@ class WorkspaceFunc extends Component {
open: false,
file: false,
saveFile: false,
share: false,
name: props.name,
snackbar: false,
key: '',
message: ''
message: '',
id: ''
};
}
componentDidUpdate(props) {
if (props.name !== this.props.name) {
this.setState({ name: this.props.name });
@ -74,7 +89,7 @@ class WorkspaceFunc extends Component {
}
toggleDialog = () => {
this.setState({ open: !this.state });
this.setState({ open: !this.state, share: false });
}
saveXmlFile = () => {
@ -87,6 +102,41 @@ class WorkspaceFunc extends Component {
saveAs(blob, fileName);
}
shareBlocks = () => {
let code = this.props.xml;
let requestOptions = '';
let id = '';
if (this.state.id !== '') {
requestOptions = {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
id: this.state.id,
name: this.state.name,
xml: code
})
};
fetch(process.env.REACT_APP_BLOCKLY_API + '/share' + this.state.id, requestOptions)
.then(response => response.json())
.then(data => this.setState({ share: true }));
}
else {
id = createId(10);
requestOptions = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
id: id,
name: this.state.name,
xml: code
})
};
fetch(process.env.REACT_APP_BLOCKLY_API + '/share', requestOptions)
.then(response => response.json())
.then(data => this.setState({ id: data.id, share: true }));
}
}
getSvg = () => {
const workspace = Blockly.getMainWorkspace();
var canvas = workspace.svgBlockCanvas_.cloneNode(true);
@ -201,6 +251,8 @@ class WorkspaceFunc extends Component {
this.setState({ snackbar: true, key: Date.now(), message: 'Das Projekt wurde erfolgreich zurückgesetzt.' });
}
render() {
return (
<div style={{ width: 'max-content', display: 'flex' }}>
@ -233,9 +285,11 @@ class WorkspaceFunc extends Component {
/>
<label htmlFor="open-blocks">
<Tooltip title='Blöcke öffnen' arrow style={{ marginRight: '5px' }}>
<div className={this.props.classes.button} style={{borderRadius: '50%', cursor: 'pointer', display: 'table-cell',
<div className={this.props.classes.button} style={{
borderRadius: '50%', cursor: 'pointer', display: 'table-cell',
verticalAlign: 'middle',
textAlign: 'center'}}>
textAlign: 'center'
}}>
<FontAwesomeIcon icon={faUpload} style={{ width: '18px', height: '18px' }} />
</div>
</Tooltip>
@ -249,7 +303,7 @@ class WorkspaceFunc extends Component {
<FontAwesomeIcon icon={faCamera} size="xs" />
</IconButton>
</Tooltip>
<Tooltip title='Workspace zurücksetzen' arrow>
<Tooltip title='Workspace zurücksetzen' arrow style={{ marginRight: '5px' }}>
<IconButton
className={this.props.classes.button}
onClick={() => this.resetWorkspace()}
@ -257,6 +311,37 @@ class WorkspaceFunc extends Component {
<FontAwesomeIcon icon={faShare} size="xs" flip='horizontal' />
</IconButton>
</Tooltip>
<Tooltip title='Blöcke teilen' arrow>
<IconButton
className={this.props.classes.button}
onClick={() => this.shareBlocks()}
>
<FontAwesomeIcon icon={faShareAlt} size="xs" flip='horizontal' />
</IconButton>
</Tooltip>
<Dialog open={this.state.share} onClose={this.toggleDialog} aria-labelledby="form-dialog-title">
<DialogTitle id="form-dialog-title">Dein Link wurde erstellt.</DialogTitle>
<DialogContent>
<DialogContentText>
Über den folgenden Link kannst du dein Programm teilen.
</DialogContentText>
<TextField
autoFocus
margin="dense"
id="name"
defaultValue={window.location.origin + "/share/" + this.state.id}
label="url"
type="email"
fullWidth
/>
</DialogContent>
<DialogActions>
<Button onClick={this.toggleDialog} color="primary">
Cancel
</Button>
</DialogActions>
</Dialog>
<Dialog
open={this.state.open}