cleanup code and update some packages

This commit is contained in:
Mario Pesch 2022-01-31 19:12:34 +01:00
parent 557d66d7d6
commit b44d858fe6
17 changed files with 7379 additions and 24021 deletions

17557
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -3,12 +3,12 @@
"version": "1.0.0", "version": "1.0.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@blockly/block-plus-minus": "^2.0.39", "@blockly/block-plus-minus": "^3.0.5",
"@blockly/field-slider": "^2.1.30", "@blockly/field-slider": "^3.0.5",
"@blockly/plugin-scroll-options": "^1.0.4", "@blockly/plugin-scroll-options": "^2.0.5",
"@blockly/plugin-typed-variable-modal": "^3.1.29", "@blockly/plugin-typed-variable-modal": "^4.0.5",
"@blockly/workspace-backpack": "^1.0.12", "@blockly/workspace-backpack": "^1.0.14",
"@blockly/zoom-to-fit": "^2.0.9", "@blockly/zoom-to-fit": "^2.0.14",
"@fortawesome/fontawesome-svg-core": "^1.2.30", "@fortawesome/fontawesome-svg-core": "^1.2.30",
"@fortawesome/free-solid-svg-icons": "^5.14.0", "@fortawesome/free-solid-svg-icons": "^5.14.0",
"@fortawesome/react-fontawesome": "^0.1.11", "@fortawesome/react-fontawesome": "^0.1.11",
@ -26,18 +26,23 @@
"moment": "^2.28.0", "moment": "^2.28.0",
"prismjs": "^1.25.0", "prismjs": "^1.25.0",
"react": "^17.0.2", "react": "^17.0.2",
"react-cookie-consent": "^5.2.0", "react-cookie-consent": "^7.2.1",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"react-markdown": "^5.0.2", "react-markdown": "^5.0.2",
"react-mde": "^11.5.0", "react-mde": "^11.5.0",
"react-redux": "^7.2.4", "react-redux": "^7.2.4",
"react-router-dom": "^5.2.0", "react-router-dom": "^5.2.0",
"react-scripts": "^4.0.3", "react-scripts": "^4.0.3",
"reactour": "^1.18.0", "reactour": "^1.18.7",
"redux": "^4.0.5", "redux": "^4.0.5",
"redux-thunk": "^2.3.0", "redux-thunk": "^2.3.0",
"styled-components": "^4.4.1", "styled-components": "^4.4.1",
"uuid": "^8.3.1" "uuid": "^8.3.1",
"watchpack": "^2.3.1"
},
"resolutions": {
"//": "See https://github.com/facebook/create-react-app/issues/11773",
"react-error-overlay": "6.0.9"
}, },
"scripts": { "scripts": {
"start": "react-scripts start", "start": "react-scripts start",
@ -49,11 +54,9 @@
"eslintConfig": { "eslintConfig": {
"extends": "react-app" "extends": "react-app"
}, },
"browserslist": "browserslist": [
[ ">0.2%",
">0.2%", "not dead",
"not dead", "not op_mini all"
"not op_mini all" ]
]
} }

View File

@ -1,35 +1,34 @@
import React, { Component } from 'react'; import React, { Component } from "react";
import { BrowserRouter as Router } from 'react-router-dom'; import { BrowserRouter as Router } from "react-router-dom";
import { createBrowserHistory } from "history"; import { createBrowserHistory } from "history";
import { Provider } from 'react-redux'; import { Provider } from "react-redux";
import store from './store'; import store from "./store";
import { loadUser } from './actions/authActions'; import { loadUser } from "./actions/authActions";
import './App.css'; import "./App.css";
import { ThemeProvider, createMuiTheme } from '@material-ui/core/styles'; import { ThemeProvider, createTheme } from "@material-ui/core/styles";
import Content from './components/Content'; import Content from "./components/Content";
const theme = createMuiTheme({ const theme = createTheme({
palette: { palette: {
primary: { primary: {
main: '#4EAF47', main: "#4EAF47",
contrastText: '#ffffff' contrastText: "#ffffff",
}, },
secondary: { secondary: {
main: '#DDDDDD' main: "#DDDDDD",
}, },
button: { button: {
compile: '#e27136' compile: "#e27136",
} },
} },
}); });
class App extends Component { class App extends Component {
componentDidMount() { componentDidMount() {
store.dispatch(loadUser()); store.dispatch(loadUser());
} }

View File

@ -24,7 +24,6 @@ const CodeEditor = (props) => {
const [time, setTime] = useState(null); const [time, setTime] = useState(null);
const [value, setValue] = useState(""); const [value, setValue] = useState("");
const [resetDialog, setResetDialog] = useState(false); const [resetDialog, setResetDialog] = useState(false);
const [blocklyCode, setBlocklyCode] = useState("");
const [defaultValue, setDefaultValue] = useState( const [defaultValue, setDefaultValue] = useState(
localStorage.getItem("ArduinoCode") localStorage.getItem("ArduinoCode")
? localStorage.getItem("ArduinoCode") ? localStorage.getItem("ArduinoCode")
@ -62,7 +61,6 @@ void loop() {
setProgress(false); setProgress(false);
const result = data.data.id; const result = data.data.id;
setId(result); setId(result);
console.log(result);
const filename = "sketch"; const filename = "sketch";
window.open( window.open(
`${process.env.REACT_APP_COMPILER_URL}/download?id=${result}&board=${process.env.REACT_APP_BOARD}&filename=${filename}`, `${process.env.REACT_APP_COMPILER_URL}/download?id=${result}&board=${process.env.REACT_APP_BOARD}&filename=${filename}`,
@ -134,14 +132,6 @@ void loop() {
setTimeout(() => setAutoSave(false), 1000); setTimeout(() => setAutoSave(false), 1000);
}; };
const handleClose = (event, reason) => {
if (reason === "clickaway") {
return;
}
setOpen(false);
};
const getBlocklyCode = () => { const getBlocklyCode = () => {
var code = store.getState().workspace.code.arduino; var code = store.getState().workspace.code.arduino;
editorRef.current.setValue(code); editorRef.current.setValue(code);

View File

@ -190,7 +190,7 @@ class Compile extends Component {
className={`compileBlocks ${this.props.classes.iconButton}`} className={`compileBlocks ${this.props.classes.iconButton}`}
onClick={() => this.compile()} onClick={() => this.compile()}
> >
<FontAwesomeIcon icon={faClipboardCheck} size="l" /> <FontAwesomeIcon icon={faClipboardCheck} size="m" />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
) : ( ) : (

View File

@ -25,19 +25,6 @@ const Sidebar = () => {
const monaco = useMonaco(); const monaco = useMonaco();
const loadCode = (code) => { const loadCode = (code) => {
console.log(code);
console.log(monaco);
const defaultCode = `
void setup () {
}
void loop(){
}`;
var currentCode = monaco.editor.getModels()[0].getValue();
setAlert(true);
monaco.editor.getModels()[0].setValue(code); monaco.editor.getModels()[0].setValue(code);
}; };

View File

@ -11,7 +11,6 @@ import { Card } from "@material-ui/core";
import * as Blockly from "blockly"; import * as Blockly from "blockly";
import { default as MonacoEditor } from "@monaco-editor/react"; import { default as MonacoEditor } from "@monaco-editor/react";
const Accordion = withStyles((theme) => ({ const Accordion = withStyles((theme) => ({
root: { root: {
border: `1px solid ${theme.palette.secondary.main}`, border: `1px solid ${theme.palette.secondary.main}`,
@ -134,7 +133,7 @@ class CodeViewer extends Component {
options={{ options={{
readOnly: true, readOnly: true,
fontSize: "12px", fontSize: "16px",
}} }}
/> />
</AccordionDetails> </AccordionDetails>

View File

@ -54,12 +54,17 @@ class Home extends Component {
key: "", key: "",
message: "", message: "",
open: true, open: true,
resumeWork: false,
initialXml: localStorage.getItem("autoSaveXML"), initialXml: localStorage.getItem("autoSaveXML"),
}; };
} }
componentDidMount() { componentDidMount() {
console.log(this.props.platform); if (this.state.initialXml) {
this.setState({ resumeWork: true });
} else {
console.log("new work");
}
if (this.props.platform === true) { if (this.props.platform === true) {
this.setState({ codeOn: false }); this.setState({ codeOn: false });
} }
@ -95,6 +100,10 @@ class Home extends Component {
this.setState({ open: !this.state }); this.setState({ open: !this.state });
}; };
toogleResumeWork = () => {
this.setState({ resumeWork: !this.state.resumeWork });
};
onChangeCheckbox = (e) => { onChangeCheckbox = (e) => {
if (e.target.checked) { if (e.target.checked) {
window.localStorage.setItem("ota", e.target.checked); window.localStorage.setItem("ota", e.target.checked);
@ -188,6 +197,25 @@ class Home extends Component {
) : null} ) : null}
</Grid> </Grid>
<HintTutorialExists /> <HintTutorialExists />
<Dialog
style={{ zIndex: 9999999 }}
fullWidth
maxWidth={"sm"}
open={this.state.resumeWork}
title={Blockly.Msg.tabletDialog_headline}
content={""}
onClose={this.toogleResumeWork}
onClick={this.toogleResumeWork}
button={Blockly.Msg.button_close}
>
<div>{Blockly.Msg.tabletDialog_text}</div>
<div>
{Blockly.Msg.tabletDialog_more}{" "}
<a href="https://sensebox.de/app" target="_blank" rel="noreferrer">
https://sensebox.de/app
</a>
</div>
</Dialog>
{this.props.platform ? ( {this.props.platform ? (
<Dialog <Dialog
style={{ zIndex: 9999999 }} style={{ zIndex: 9999999 }}
@ -223,7 +251,7 @@ Home.propTypes = {
workspaceName: PropTypes.func.isRequired, workspaceName: PropTypes.func.isRequired,
message: PropTypes.object.isRequired, message: PropTypes.object.isRequired,
statistics: PropTypes.bool.isRequired, statistics: PropTypes.bool.isRequired,
platform: PropTypes.object.isRequired, platform: PropTypes.bool.isRequired,
}; };
const mapStateToProps = (state) => ({ const mapStateToProps = (state) => ({

View File

@ -359,9 +359,9 @@ class Navbar extends Component {
Navbar.propTypes = { Navbar.propTypes = {
tutorialIsLoading: PropTypes.bool.isRequired, tutorialIsLoading: PropTypes.bool.isRequired,
projectIsLoading: PropTypes.bool.isRequired, projectIsLoading: PropTypes.bool.isRequired,
isAuthenticated: PropTypes.bool.isRequired, isAuthenticated: PropTypes.bool,
user: PropTypes.object, user: PropTypes.object,
tutorial: PropTypes.object.isRequired, tutorial: PropTypes.object,
activeStep: PropTypes.number.isRequired, activeStep: PropTypes.number.isRequired,
}; };

View File

@ -104,7 +104,7 @@ class Routes extends Component {
} }
Home.propTypes = { Home.propTypes = {
visitPage: PropTypes.func.isRequired, visitPage: PropTypes.func,
}; };
export default connect(null, { visitPage })(withRouter(Routes)); export default connect(null, { visitPage })(withRouter(Routes));

View File

@ -1,53 +1,57 @@
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 { changeContent, deleteProperty, setError, deleteError } from '../../../actions/tutorialBuilderActions'; import {
changeContent,
deleteProperty,
setError,
deleteError,
} from "../../../actions/tutorialBuilderActions";
import moment from 'moment'; import moment from "moment";
import localization from 'moment/locale/de'; import localization from "moment/locale/de";
import * as Blockly from 'blockly/core'; import * as Blockly from "blockly/core";
import { initialXml } from '../../Blockly//initialXml.js'; import { initialXml } from "../../Blockly//initialXml.js";
import BlocklyWindow from '../../Blockly/BlocklyWindow'; import BlocklyWindow from "../../Blockly/BlocklyWindow";
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from "@material-ui/core/styles";
import Switch from '@material-ui/core/Switch'; import Switch from "@material-ui/core/Switch";
import FormControlLabel from '@material-ui/core/FormControlLabel'; import FormControlLabel from "@material-ui/core/FormControlLabel";
import FormHelperText from '@material-ui/core/FormHelperText'; import FormHelperText from "@material-ui/core/FormHelperText";
import FormLabel from '@material-ui/core/FormLabel'; import FormLabel from "@material-ui/core/FormLabel";
import Button from '@material-ui/core/Button'; import Button from "@material-ui/core/Button";
import Grid from '@material-ui/core/Grid'; import Grid from "@material-ui/core/Grid";
const styles = (theme) => ({ const styles = (theme) => ({
errorColor: { errorColor: {
color: theme.palette.error.dark color: theme.palette.error.dark,
}, },
errorBorder: { errorBorder: {
border: `1px solid ${theme.palette.error.dark}` border: `1px solid ${theme.palette.error.dark}`,
}, },
errorButton: { errorButton: {
marginTop: '5px', marginTop: "5px",
height: '40px', height: "40px",
backgroundColor: theme.palette.error.dark, backgroundColor: theme.palette.error.dark,
'&:hover': { "&:hover": {
backgroundColor: theme.palette.error.dark backgroundColor: theme.palette.error.dark,
} },
} },
}); });
class BlocklyExample extends Component { class BlocklyExample extends Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
checked: props.task ? props.task : props.value ? true : false, checked: props.task ? props.task : props.value ? true : false,
input: null, input: null,
disabled: false disabled: false,
}; };
} }
componentDidMount() { componentDidMount() {
moment.updateLocale('de', localization); moment.updateLocale("de", localization);
this.isError(); this.isError();
// if(this.props.task){ // if(this.props.task){
// this.props.setError(this.props.index, 'xml'); // this.props.setError(this.props.index, 'xml');
@ -56,7 +60,14 @@ class BlocklyExample extends Component {
componentDidUpdate(props, state) { componentDidUpdate(props, state) {
if (props.task !== this.props.task || props.value !== this.props.value) { if (props.task !== this.props.task || props.value !== this.props.value) {
this.setState({ checked: this.props.task ? this.props.task : this.props.value ? true : false }, this.setState(
{
checked: this.props.task
? this.props.task
: this.props.value
? true
: false,
},
() => this.isError() () => this.isError()
); );
} }
@ -77,12 +88,11 @@ class BlocklyExample extends Component {
// check if value is valid xml; // check if value is valid xml;
try { try {
Blockly.Xml.textToDom(xml); Blockly.Xml.textToDom(xml);
this.props.deleteError(this.props.index, 'xml'); this.props.deleteError(this.props.index, "xml");
} } catch (err) {
catch (err) {
xml = initialXml; xml = initialXml;
// not valid xml, throw error in redux store // not valid xml, throw error in redux store
this.props.setError(this.props.index, 'xml'); this.props.setError(this.props.index, "xml");
} }
if (!this.props.task) { if (!this.props.task) {
// instruction can also display only one block, which does not necessarily // instruction can also display only one block, which does not necessarily
@ -90,31 +100,38 @@ class BlocklyExample extends Component {
xml = xml.replace('deletable="false"', 'deletable="true"'); xml = xml.replace('deletable="false"', 'deletable="true"');
} }
this.setState({ xml: xml }); this.setState({ xml: xml });
} else {
this.props.deleteError(this.props.index, "xml");
} }
else { };
this.props.deleteError(this.props.index, 'xml');
}
}
onChange = (value) => { onChange = (value) => {
var oldValue = this.state.checked; var oldValue = this.state.checked;
this.setState({ checked: value }); this.setState({ checked: value });
if (oldValue !== value && !value) { if (oldValue !== value && !value) {
this.props.deleteError(this.props.index, 'xml'); this.props.deleteError(this.props.index, "xml");
this.props.deleteProperty(this.props.index, 'xml'); this.props.deleteProperty(this.props.index, "xml");
} }
} };
setXml = () => { setXml = () => {
var xml = this.props.xml; var xml = this.props.xml;
this.props.changeContent(xml, this.props.index, 'xml'); this.props.changeContent(xml, this.props.index, "xml");
this.setState({ input: moment(Date.now()).format('LTS') }); this.setState({ input: moment(Date.now()).format("LTS") });
} };
render() { render() {
return ( return (
<div style={{ marginBottom: '10px', padding: '18.5px 14px', borderRadius: '25px', border: '1px solid lightgrey', width: 'calc(100% - 28px)' }}> <div
{!this.props.task ? style={{
marginBottom: "10px",
padding: "18.5px 14px",
borderRadius: "25px",
border: "1px solid lightgrey",
width: "calc(100% - 28px)",
}}
>
{!this.props.task ? (
<FormControlLabel <FormControlLabel
labelPlacement="end" labelPlacement="end"
label={"Blockly Beispiel"} label={"Blockly Beispiel"}
@ -126,45 +143,77 @@ class BlocklyExample extends Component {
/> />
} }
/> />
: <FormLabel style={{ color: 'black' }}>{Blockly.Msg.builder_solution}</FormLabel>} ) : (
{this.state.checked ? !this.props.value || this.props.error ? <FormLabel style={{ color: "black" }}>
<FormHelperText style={{ lineHeight: 'initial' }} className={this.props.classes.errorColor}>{`Reiche deine Blöcke ein, indem du auf den '${this.props.task ? Blockly.Msg.builder_solution_submit : Blockly.Msg.builder_example_submit}'-Button klickst.`}</FormHelperText> {Blockly.Msg.builder_solution}
: this.state.input ? <FormHelperText style={{ lineHeight: 'initial' }}>Die letzte Einreichung erfolgte um {this.state.input} Uhr.</FormHelperText> : null </FormLabel>
: null} )}
{this.state.checked && !this.props.task ? {this.state.checked ? (
<FormHelperText style={{ lineHeight: 'initial' }}>{Blockly.Msg.builder_comment}</FormHelperText> !this.props.value || this.props.error ? (
: null} <FormHelperText
style={{ lineHeight: "initial" }}
className={this.props.classes.errorColor}
>{`Reiche deine Blöcke ein, indem du auf den '${
this.props.task
? Blockly.Msg.builder_solution_submit
: Blockly.Msg.builder_example_submit
}'-Button klickst.`}</FormHelperText>
) : this.state.input ? (
<FormHelperText style={{ lineHeight: "initial" }}>
Die letzte Einreichung erfolgte um {this.state.input} Uhr.
</FormHelperText>
) : null
) : null}
{this.state.checked && !this.props.task ? (
<FormHelperText style={{ lineHeight: "initial" }}>
{Blockly.Msg.builder_comment}
</FormHelperText>
) : null}
{/* ensure that the correct xml-file is displayed in the workspace */} {/* ensure that the correct xml-file is displayed in the workspace */}
{this.state.checked && this.state.xml ? (() => { {this.state.checked && this.state.xml
return ( ? (() => {
<div style={{ marginTop: '10px' }}> return (
<Grid container className={!this.props.value || this.props.error ? this.props.classes.errorBorder : null}> <div style={{ marginTop: "10px" }}>
<Grid item xs={12}> <Grid
<BlocklyWindow container
blockDisabled={this.props.task} className={
trashcan={false} !this.props.value || this.props.error
initialXml={this.state.xml} ? this.props.classes.errorBorder
blocklyCSS={{ height: '500px' }} : null
/> }
</Grid> >
</Grid> <Grid item xs={12}>
<Button <BlocklyWindow
className={!this.props.value || this.props.error ? this.props.classes.errorButton : null} blockDisabled={this.props.task}
style={{ marginTop: '5px', height: '40px' }} trashcan={false}
variant='contained' initialXml={this.state.xml}
color='primary' blocklyCSS={{ height: "500px" }}
disabled={this.state.disabled} />
onClick={() => this.setXml()} </Grid>
> </Grid>
{this.props.task ? Blockly.Msg.builder_solution_submit : Blockly.Msg.builder_example_submit} <Button
</Button> className={
</div> !this.props.value || this.props.error
) ? this.props.classes.errorButton
})() : null
}
style={{ marginTop: "5px", height: "40px" }}
variant="contained"
color="primary"
disabled={this.state.disabled}
onClick={() => this.setXml()}
>
{this.props.task
? Blockly.Msg.builder_solution_submit
: Blockly.Msg.builder_example_submit}
</Button>
</div>
);
})()
: null} : null}
</div> </div>
); );
}; }
} }
BlocklyExample.propTypes = { BlocklyExample.propTypes = {
@ -172,12 +221,16 @@ BlocklyExample.propTypes = {
deleteProperty: PropTypes.func.isRequired, deleteProperty: PropTypes.func.isRequired,
setError: PropTypes.func.isRequired, setError: PropTypes.func.isRequired,
deleteError: PropTypes.func.isRequired, deleteError: PropTypes.func.isRequired,
xml: PropTypes.string.isRequired xml: PropTypes.string.isRequired,
}; };
const mapStateToProps = state => ({ const mapStateToProps = (state) => ({
xml: state.workspace.code.xml xml: state.workspace.code.xml,
}); });
export default connect(mapStateToProps, {
export default connect(mapStateToProps, { changeContent, deleteProperty, setError, deleteError })(withStyles(styles, { withTheme: true })(BlocklyExample)); changeContent,
deleteProperty,
setError,
deleteError,
})(withStyles(styles, { withTheme: true })(BlocklyExample));

View File

@ -1,75 +1,79 @@
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 Dialog from '../Dialog'; import Dialog from "../Dialog";
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from "@material-ui/core/styles";
import Checkbox from '@material-ui/core/Checkbox'; import Checkbox from "@material-ui/core/Checkbox";
import FormControlLabel from '@material-ui/core/FormControlLabel'; import FormControlLabel from "@material-ui/core/FormControlLabel";
import * as Blockly from 'blockly' import * as Blockly from "blockly";
import ReactMarkdown from 'react-markdown'; import ReactMarkdown from "react-markdown";
const styles = (theme) => ({ const styles = (theme) => ({
link: { link: {
color: theme.palette.primary.main, color: theme.palette.primary.main,
textDecoration: 'none', textDecoration: "none",
'&:hover': { "&:hover": {
color: theme.palette.primary.main, color: theme.palette.primary.main,
textDecoration: `underline` textDecoration: `underline`,
} },
}, },
label: { label: {
fontSize: '0.9rem', fontSize: "0.9rem",
color: 'grey' color: "grey",
} },
}); });
class HintTutorialExists extends Component { class HintTutorialExists extends Component {
constructor(props) { constructor(props) {
var previousPageWasAnotherDomain = props.pageVisits === 0; var previousPageWasAnotherDomain = props.pageVisits === 0;
var userDoNotWantToSeeNews = window.localStorage.getItem('news') ? true : false; var userDoNotWantToSeeNews = window.localStorage.getItem("news")
? true
: false;
super(props); super(props);
this.state = { this.state = {
open: userDoNotWantToSeeNews ? !userDoNotWantToSeeNews : previousPageWasAnotherDomain open: userDoNotWantToSeeNews
? !userDoNotWantToSeeNews
: previousPageWasAnotherDomain,
}; };
} }
toggleDialog = () => { toggleDialog = () => {
this.setState({ open: !this.state }); this.setState({ open: !this.state });
} };
onChange = (e) => { onChange = (e) => {
if (e.target.checked) { if (e.target.checked) {
window.localStorage.setItem('news', e.target.checked); window.localStorage.setItem("news", e.target.checked);
} else {
window.localStorage.removeItem("news");
} }
else { };
window.localStorage.removeItem('news');
}
}
render() { render() {
return ( return (
<Dialog <Dialog
style={{ zIndex: 9999999 }} style={{ zIndex: 9999999 }}
fullWidth fullWidth
maxWidth={'sm'} maxWidth={"sm"}
open={this.state.open} open={this.state.open}
title={Blockly.Msg.messages_newblockly_head} title={Blockly.Msg.messages_newblockly_head}
content={''} content={""}
onClose={this.toggleDialog} onClose={this.toggleDialog}
onClick={this.toggleDialog} onClick={this.toggleDialog}
button={Blockly.Msg.button_close} button={Blockly.Msg.button_close}
> >
<div> <div>
<ReactMarkdown linkTarget="_blank">{Blockly.Msg.messages_newblockly_text}</ReactMarkdown> <ReactMarkdown linkTarget="_blank">
{Blockly.Msg.messages_newblockly_text}
</ReactMarkdown>
</div> </div>
<FormControlLabel <FormControlLabel
style={{ marginTop: '20px' }} style={{ marginTop: "20px" }}
classes={{ label: this.props.classes.label }} classes={{ label: this.props.classes.label }}
control={ control={
<Checkbox <Checkbox
size={'small'} size={"small"}
value={true} value={true}
checked={this.state.checked} checked={this.state.checked}
onChange={(e) => this.onChange(e)} onChange={(e) => this.onChange(e)}
@ -81,15 +85,18 @@ class HintTutorialExists extends Component {
/> />
</Dialog> </Dialog>
); );
}; }
} }
HintTutorialExists.propTypes = { HintTutorialExists.propTypes = {
pageVisits: PropTypes.number.isRequired pageVisits: PropTypes.number.isRequired,
}; };
const mapStateToProps = state => ({ const mapStateToProps = (state) => ({
pageVisits: state.general.pageVisits pageVisits: state.general.pageVisits,
}); });
export default connect(mapStateToProps, null)(withStyles(styles, { withTheme: true })(HintTutorialExists)); export default connect(
mapStateToProps,
null
)(withStyles(styles, { withTheme: true })(HintTutorialExists));

View File

@ -1,51 +1,49 @@
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 { tutorialCheck, tutorialStep } from '../../actions/tutorialActions'; import { tutorialCheck, tutorialStep } from "../../actions/tutorialActions";
import { withRouter } from 'react-router-dom'; import { withRouter } from "react-router-dom";
import Compile from '../Workspace/Compile'; import Compile from "../Workspace/Compile";
import Dialog from '../Dialog'; import Dialog from "../Dialog";
import { checkXml } from '../../helpers/compareXml'; import { checkXml } from "../../helpers/compareXml";
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from "@material-ui/core/styles";
import IconButton from '@material-ui/core/IconButton'; import IconButton from "@material-ui/core/IconButton";
import Tooltip from '@material-ui/core/Tooltip'; import Tooltip from "@material-ui/core/Tooltip";
import Button from '@material-ui/core/Button'; import Button from "@material-ui/core/Button";
import { faClipboardCheck } from "@fortawesome/free-solid-svg-icons"; import { faClipboardCheck } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import * as Blockly from 'blockly' import * as Blockly from "blockly";
const styles = (theme) => ({ const styles = (theme) => ({
compile: { compile: {
backgroundColor: theme.palette.button.compile, backgroundColor: theme.palette.button.compile,
color: theme.palette.primary.contrastText, color: theme.palette.primary.contrastText,
'&:hover': { "&:hover": {
backgroundColor: theme.palette.button.compile, backgroundColor: theme.palette.button.compile,
color: theme.palette.primary.contrastText, color: theme.palette.primary.contrastText,
} },
} },
}); });
class SolutionCheck extends Component { class SolutionCheck extends Component {
state = { state = {
open: false, open: false,
msg: '' msg: "",
} };
toggleDialog = () => { toggleDialog = () => {
if (this.state.open) { if (this.state.open) {
this.setState({ open: false, msg: '' }); this.setState({ open: false, msg: "" });
} } else {
else {
this.setState({ open: !this.state }); this.setState({ open: !this.state });
} }
} };
check = () => { check = () => {
const tutorial = this.props.tutorial; const tutorial = this.props.tutorial;
@ -53,7 +51,7 @@ class SolutionCheck extends Component {
var msg = checkXml(step.xml, this.props.xml); var msg = checkXml(step.xml, this.props.xml);
this.props.tutorialCheck(msg.type, step); this.props.tutorialCheck(msg.type, step);
this.setState({ msg, open: true }); this.setState({ msg, open: true });
} };
render() { render() {
const steps = this.props.tutorial.steps; const steps = this.props.tutorial.steps;
@ -62,68 +60,74 @@ class SolutionCheck extends Component {
<Tooltip title={Blockly.Msg.tooltip_check_solution} arrow> <Tooltip title={Blockly.Msg.tooltip_check_solution} arrow>
<IconButton <IconButton
className={`solutionCheck ${this.props.classes.compile}`} className={`solutionCheck ${this.props.classes.compile}`}
style={{ width: '40px', height: '40px', marginRight: '5px' }} style={{ width: "40px", height: "40px", marginRight: "5px" }}
onClick={() => this.check()} onClick={() => this.check()}
> >
<FontAwesomeIcon icon={faClipboardCheck} size="l" /> <FontAwesomeIcon icon={faClipboardCheck} size="m" />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
<Dialog <Dialog
style={{ zIndex: 9999999 }} style={{ zIndex: 9999999 }}
fullWidth fullWidth
maxWidth={'sm'} maxWidth={"sm"}
open={this.state.open} open={this.state.open}
title={this.state.msg.type === 'error' ? 'Fehler' : 'Erfolg'} title={this.state.msg.type === "error" ? "Fehler" : "Erfolg"}
content={this.state.msg.text} content={this.state.msg.text}
onClose={this.toggleDialog} onClose={this.toggleDialog}
onClick={this.toggleDialog} onClick={this.toggleDialog}
button={Blockly.Msg.button_close} button={Blockly.Msg.button_close}
> >
{this.state.msg.type === 'success' ? {this.state.msg.type === "success" ? (
<div style={{ marginTop: '20px', display: 'flex' }}> <div style={{ marginTop: "20px", display: "flex" }}>
<Compile /> <Compile />
{this.props.activeStep === steps.length - 1 ? {this.props.activeStep === steps.length - 1 ? (
<Button <Button
style={{ marginLeft: '10px' }} style={{ marginLeft: "10px" }}
variant="contained" variant="contained"
color="primary" color="primary"
onClick={() => { this.toggleDialog(); this.props.history.push(`/tutorial/`) }} onClick={() => {
this.toggleDialog();
this.props.history.push(`/tutorial/`);
}}
> >
{Blockly.Msg.button_tutorial_overview} {Blockly.Msg.button_tutorial_overview}
</Button> </Button>
: ) : (
<Button <Button
style={{ marginLeft: '10px' }} style={{ marginLeft: "10px" }}
variant="contained" variant="contained"
color="primary" color="primary"
onClick={() => { this.toggleDialog(); this.props.tutorialStep(this.props.activeStep + 1) }} onClick={() => {
this.toggleDialog();
this.props.tutorialStep(this.props.activeStep + 1);
}}
> >
{Blockly.Msg.button_next} {Blockly.Msg.button_next}
</Button> </Button>
} )}
</div> </div>
: null} ) : null}
</Dialog> </Dialog>
</div> </div>
); );
}; }
} }
SolutionCheck.propTypes = { SolutionCheck.propTypes = {
tutorialCheck: PropTypes.func.isRequired, tutorialCheck: PropTypes.func.isRequired,
tutorialStep: PropTypes.func.isRequired, tutorialStep: PropTypes.func.isRequired,
activeStep: PropTypes.number.isRequired, activeStep: PropTypes.number.isRequired,
xml: PropTypes.string.isRequired, xml: PropTypes.string.isRequired,
tutorial: PropTypes.object.isRequired tutorial: PropTypes.object.isRequired,
}; };
const mapStateToProps = state => ({ const mapStateToProps = (state) => ({
activeStep: state.tutorial.activeStep, activeStep: state.tutorial.activeStep,
xml: state.workspace.code.xml, xml: state.workspace.code.xml,
tutorial: state.tutorial.tutorials[0] tutorial: state.tutorial.tutorials[0],
}); });
export default connect(mapStateToProps, { tutorialCheck, tutorialStep })(withStyles(styles, { withTheme: true })(withRouter(SolutionCheck))); export default connect(mapStateToProps, { tutorialCheck, tutorialStep })(
withStyles(styles, { withTheme: true })(withRouter(SolutionCheck))
);

View File

@ -190,7 +190,7 @@ class Compile extends Component {
className={`compileBlocks ${this.props.classes.iconButton}`} className={`compileBlocks ${this.props.classes.iconButton}`}
onClick={() => this.compile()} onClick={() => this.compile()}
> >
<FontAwesomeIcon icon={faClipboardCheck} size="l" /> <FontAwesomeIcon icon={faClipboardCheck} size="m" />
</IconButton> </IconButton>
</Tooltip> </Tooltip>
) : ( ) : (

View File

@ -1,99 +1,110 @@
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 { workspaceName } from '../../actions/workspaceActions'; import { workspaceName } from "../../actions/workspaceActions";
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from "@material-ui/core/styles";
import Button from '@material-ui/core/Button'; import Button from "@material-ui/core/Button";
import IconButton from '@material-ui/core/IconButton'; import IconButton from "@material-ui/core/IconButton";
import Tooltip from '@material-ui/core/Tooltip'; import Tooltip from "@material-ui/core/Tooltip";
import { faCopy } from "@fortawesome/free-solid-svg-icons"; import { faCopy } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import * as Blockly from 'blockly/core'; import * as Blockly from "blockly/core";
import Snackbar from '../Snackbar'; import Snackbar from "../Snackbar";
const styles = (theme) => ({ const styles = (theme) => ({
backdrop: { backdrop: {
zIndex: theme.zIndex.drawer + 1, zIndex: theme.zIndex.drawer + 1,
color: '#fff', color: "#fff",
},
iconButton: {
backgroundColor: theme.palette.primary.main,
color: theme.palette.primary.contrastText,
width: "40px",
height: "40px",
"&:hover": {
backgroundColor: theme.palette.primary.main,
color: theme.palette.primary.contrastText,
}, },
iconButton: { },
backgroundColor: theme.palette.primary.main, button: {
color: theme.palette.primary.contrastText, backgroundColor: theme.palette.button.copycode,
width: '40px', color: theme.palette.primary.contrastText,
height: '40px', "&:hover": {
'&:hover': { backgroundColor: theme.palette.button.copycode,
backgroundColor: theme.palette.primary.main, color: theme.palette.primary.contrastText,
color: theme.palette.primary.contrastText,
}
}, },
button: { },
backgroundColor: theme.palette.button.copycode,
color: theme.palette.primary.contrastText,
'&:hover': {
backgroundColor: theme.palette.button.copycode,
color: theme.palette.primary.contrastText,
}
}
}); });
class CopyCode extends Component { class CopyCode extends Component {
constructor(props) {
constructor(props) { super(props);
super(props); this.state = {
this.state = { snackbar: false,
snackbar: false,
};
}
copyCode = () => {
navigator.clipboard.writeText(this.props.arduino)
this.setState({ snackbar: true, type: 'success', key: Date.now(), message: Blockly.Msg.messages_copy_code });
}
render() {
return (
<div style={{}}>
{this.props.iconButton ?
<Tooltip title={Blockly.Msg.tooltip_copy_code} arrow style={{ marginRight: '5px' }}>
<IconButton
className={`copyCode ${this.props.classes.iconButton}`}
onClick={() => this.copyCode()}
>
<FontAwesomeIcon icon={faCopy} size="l" />
</IconButton>
</Tooltip>
:
<Button style={{ float: 'right', color: 'white' }} variant="contained" className={this.props.classes.button} onClick={() => this.copyCode()}>
<FontAwesomeIcon icon={faCopy} style={{ marginRight: '5px' }} /> Code kopieren
</Button>
}
<Snackbar
open={this.state.snackbar}
message={this.state.message}
type={this.state.type}
key={this.state.key}
/>
</div >
);
}; };
}
copyCode = () => {
navigator.clipboard.writeText(this.props.arduino);
this.setState({
snackbar: true,
type: "success",
key: Date.now(),
message: Blockly.Msg.messages_copy_code,
});
};
render() {
return (
<div style={{}}>
{this.props.iconButton ? (
<Tooltip
title={Blockly.Msg.tooltip_copy_code}
arrow
style={{ marginRight: "5px" }}
>
<IconButton
className={`copyCode ${this.props.classes.iconButton}`}
onClick={() => this.copyCode()}
>
<FontAwesomeIcon icon={faCopy} size="m" />
</IconButton>
</Tooltip>
) : (
<Button
style={{ float: "right", color: "white" }}
variant="contained"
className={this.props.classes.button}
onClick={() => this.copyCode()}
>
<FontAwesomeIcon icon={faCopy} style={{ marginRight: "5px" }} />{" "}
Code kopieren
</Button>
)}
<Snackbar
open={this.state.snackbar}
message={this.state.message}
type={this.state.type}
key={this.state.key}
/>
</div>
);
}
} }
CopyCode.propTypes = { CopyCode.propTypes = {
arduino: PropTypes.string.isRequired, arduino: PropTypes.string.isRequired,
name: PropTypes.string, name: PropTypes.string,
workspaceName: PropTypes.func.isRequired workspaceName: PropTypes.func.isRequired,
}; };
const mapStateToProps = state => ({ const mapStateToProps = (state) => ({
arduino: state.workspace.code.arduino, arduino: state.workspace.code.arduino,
name: state.workspace.name name: state.workspace.name,
}); });
export default connect(mapStateToProps, { workspaceName })(
export default connect(mapStateToProps, { workspaceName })(withStyles(styles, { withTheme: true })(CopyCode)); withStyles(styles, { withTheme: true })(CopyCode)
);

View File

@ -1,16 +1,16 @@
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 * as Blockly from 'blockly/core'; import * as Blockly from "blockly/core";
import { saveAs } from 'file-saver'; import { saveAs } from "file-saver";
import { detectWhitespacesAndReturnReadableResult } from '../../helpers/whitespace'; import { detectWhitespacesAndReturnReadableResult } from "../../helpers/whitespace";
import { withStyles } from '@material-ui/core/styles'; import { withStyles } from "@material-ui/core/styles";
import IconButton from '@material-ui/core/IconButton'; import IconButton from "@material-ui/core/IconButton";
import Tooltip from '@material-ui/core/Tooltip'; import Tooltip from "@material-ui/core/Tooltip";
import { faCamera } from "@fortawesome/free-solid-svg-icons"; import { faCamera } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
@ -19,18 +19,16 @@ const styles = (theme) => ({
button: { button: {
backgroundColor: theme.palette.primary.main, backgroundColor: theme.palette.primary.main,
color: theme.palette.primary.contrastText, color: theme.palette.primary.contrastText,
width: '40px', width: "40px",
height: '40px', height: "40px",
'&:hover': { "&:hover": {
backgroundColor: theme.palette.primary.main, backgroundColor: theme.palette.primary.main,
color: theme.palette.primary.contrastText, color: theme.palette.primary.contrastText,
} },
} },
}); });
class Screenshot extends Component { class Screenshot extends Component {
getSvg = () => { getSvg = () => {
const workspace = Blockly.getMainWorkspace(); const workspace = Blockly.getMainWorkspace();
var canvas = workspace.svgBlockCanvas_.cloneNode(true); var canvas = workspace.svgBlockCanvas_.cloneNode(true);
@ -39,10 +37,12 @@ class Screenshot extends Component {
canvas.removeAttribute("transform"); canvas.removeAttribute("transform");
// does not work in react // does not work in react
// var cssContent = Blockly.Css.CONTENT.join(''); // var cssContent = Blockly.Css.CONTENT.join('');
var cssContent = ''; var cssContent = "";
for (var i = 0; i < document.getElementsByTagName('style').length; i++) { for (var i = 0; i < document.getElementsByTagName("style").length; i++) {
if (/^blockly.*$/.test(document.getElementsByTagName('style')[i].id)) { if (/^blockly.*$/.test(document.getElementsByTagName("style")[i].id)) {
cssContent += document.getElementsByTagName('style')[i].firstChild.data.replace(/\..* \./g, '.'); cssContent += document
.getElementsByTagName("style")
[i].firstChild.data.replace(/\..* \./g, ".");
} }
} }
// ensure that fill-opacity is 1, because there cannot be a replacing // ensure that fill-opacity is 1, because there cannot be a replacing
@ -56,19 +56,24 @@ class Screenshot extends Component {
.blocklyPathLight { .blocklyPathLight {
display: flex; display: flex;
} `; } `;
var css = '<defs><style type="text/css" xmlns="http://www.w3.org/1999/xhtml"><![CDATA[' + cssContent + ']]></style></defs>'; var css =
var bbox = document.getElementsByClassName("blocklyBlockCanvas")[0].getBBox(); '<defs><style type="text/css" xmlns="http://www.w3.org/1999/xhtml"><![CDATA[' +
cssContent +
"]]></style></defs>";
var bbox = document
.getElementsByClassName("blocklyBlockCanvas")[0]
.getBBox();
var content = new XMLSerializer().serializeToString(canvas); var content = new XMLSerializer().serializeToString(canvas);
var xml = `<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" var xml = `<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="${bbox.width}" height="${bbox.height}" viewBox="${bbox.x} ${bbox.y} ${bbox.width} ${bbox.height}"> width="${bbox.width}" height="${bbox.height}" viewBox="${bbox.x} ${bbox.y} ${bbox.width} ${bbox.height}">
${css}">${content}</svg>`; ${css}">${content}</svg>`;
var fileName = detectWhitespacesAndReturnReadableResult(this.props.name); var fileName = detectWhitespacesAndReturnReadableResult(this.props.name);
// this.props.workspaceName(this.state.name); // this.props.workspaceName(this.state.name);
fileName = `${fileName}.svg` fileName = `${fileName}.svg`;
var blob = new Blob([xml], { type: 'image/svg+xml;base64' }); var blob = new Blob([xml], { type: "image/svg+xml;base64" });
saveAs(blob, fileName); saveAs(blob, fileName);
} }
} };
render() { render() {
return ( return (
@ -83,15 +88,18 @@ class Screenshot extends Component {
</Tooltip> </Tooltip>
</div> </div>
); );
}; }
} }
Screenshot.propTypes = { Screenshot.propTypes = {
name: PropTypes.string.isRequired, name: PropTypes.string,
}; };
const mapStateToProps = state => ({ const mapStateToProps = (state) => ({
name: state.workspace.name, name: state.workspace.name,
}); });
export default connect(mapStateToProps, null)(withStyles(styles, { withTheme: true })(Screenshot)); export default connect(
mapStateToProps,
null
)(withStyles(styles, { withTheme: true })(Screenshot));

13080
yarn.lock

File diff suppressed because it is too large Load Diff