create and display projects
This commit is contained in:
parent
e600c19679
commit
a8e36a4f06
@ -99,7 +99,7 @@ class Compile extends Component {
|
|||||||
this.download();
|
this.download();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.setState({ file: true, open: true, title: 'Blöcke kompilieren', content: 'Bitte gib einen Namen für die Bennenung des zu kompilierenden Programms ein und bestätige diesen mit einem Klick auf \'Eingabe\'.' });
|
this.setState({ file: true, open: true, title: 'Projekt kompilieren', content: 'Bitte gib einen Namen für die Bennenung des zu kompilierenden Programms ein und bestätige diesen mit einem Klick auf \'Eingabe\'.' });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,7 +111,7 @@ class Compile extends Component {
|
|||||||
return (
|
return (
|
||||||
<div style={{}}>
|
<div style={{}}>
|
||||||
{this.props.iconButton ?
|
{this.props.iconButton ?
|
||||||
<Tooltip title='Blöcke kompilieren' arrow style={{ marginRight: '5px' }}>
|
<Tooltip title='Projekt kompilieren' arrow style={{ marginRight: '5px' }}>
|
||||||
<IconButton
|
<IconButton
|
||||||
className={this.props.classes.button}
|
className={this.props.classes.button}
|
||||||
onClick={() => this.compile()}
|
onClick={() => this.compile()}
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
[
|
|
||||||
{
|
|
||||||
"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": ""
|
|
||||||
}
|
|
||||||
]
|
|
@ -4,23 +4,19 @@ import { connect } from 'react-redux';
|
|||||||
import { clearStats, workspaceName } from '../actions/workspaceActions';
|
import { clearStats, workspaceName } from '../actions/workspaceActions';
|
||||||
|
|
||||||
import * as Blockly from 'blockly/core';
|
import * as Blockly from 'blockly/core';
|
||||||
|
import { createNameId } from 'mnemonic-id';
|
||||||
import axios from 'axios';
|
|
||||||
|
|
||||||
import WorkspaceStats from './WorkspaceStats';
|
import WorkspaceStats from './WorkspaceStats';
|
||||||
import WorkspaceFunc from './WorkspaceFunc';
|
import WorkspaceFunc from './WorkspaceFunc';
|
||||||
import BlocklyWindow from './Blockly/BlocklyWindow';
|
import BlocklyWindow from './Blockly/BlocklyWindow';
|
||||||
import CodeViewer from './CodeViewer';
|
import CodeViewer from './CodeViewer';
|
||||||
import TrashcanButtons from './TrashcanButtons';
|
import TrashcanButtons from './TrashcanButtons';
|
||||||
import { createNameId } from 'mnemonic-id';
|
|
||||||
import HintTutorialExists from './Tutorial/HintTutorialExists';
|
import HintTutorialExists from './Tutorial/HintTutorialExists';
|
||||||
|
|
||||||
import Grid from '@material-ui/core/Grid';
|
import Grid from '@material-ui/core/Grid';
|
||||||
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 { withStyles } from '@material-ui/core/styles';
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
import Backdrop from '@material-ui/core/Backdrop';
|
|
||||||
import CircularProgress from '@material-ui/core/CircularProgress';
|
|
||||||
|
|
||||||
import { faCode } from "@fortawesome/free-solid-svg-icons";
|
import { faCode } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
@ -51,22 +47,17 @@ class Home extends Component {
|
|||||||
|
|
||||||
state = {
|
state = {
|
||||||
codeOn: false,
|
codeOn: false,
|
||||||
gallery: [],
|
stats: window.localStorage.getItem('stats')
|
||||||
share: [],
|
|
||||||
projectToLoad: undefined,
|
|
||||||
progress: false,
|
|
||||||
stats: window.localStorage.getItem('stats'),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.setState({ stats: window.localStorage.getItem('stats') })
|
this.setState({ stats: window.localStorage.getItem('stats') });
|
||||||
this.getProject();
|
if(!this.props.project){
|
||||||
|
this.props.workspaceName(createNameId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(props) {
|
componentDidUpdate(props) {
|
||||||
if(props.location.path !== this.props.location.path){
|
|
||||||
this.getProject();
|
|
||||||
}
|
|
||||||
/* Resize and reposition all of the workspace chrome (toolbox, trash,
|
/* Resize and reposition all of the workspace chrome (toolbox, trash,
|
||||||
scrollbars etc.) This should be called when something changes that requires
|
scrollbars etc.) This should be called when something changes that requires
|
||||||
recalculating dimensions and positions of the trash, zoom, toolbox, etc.
|
recalculating dimensions and positions of the trash, zoom, toolbox, etc.
|
||||||
@ -80,37 +71,6 @@ class Home extends Component {
|
|||||||
this.props.workspaceName(null);
|
this.props.workspaceName(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
getProject = () => {
|
|
||||||
if(this.props.match.params.shareId || this.props.match.params.galleryId){
|
|
||||||
var param = this.props.match.params.shareId ? 'share' : 'gallery';
|
|
||||||
var id = this.props.match.params[`${param}Id`];
|
|
||||||
this.setState({progress: true});
|
|
||||||
axios.get(`${process.env.REACT_APP_BLOCKLY_API}/${param}/${id}`)
|
|
||||||
.then(res => {
|
|
||||||
var data = param === 'share' ? 'content' : param;
|
|
||||||
if(res.data[data]){
|
|
||||||
this.props.workspaceName(res.data[data].name ? res.data[data].name : res.data[data].title);
|
|
||||||
this.setState({ projectToLoad: res.data[data], progress: false });
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.props.workspaceName(createNameId());
|
|
||||||
this.setState({ progress: false });
|
|
||||||
this.props.history.push('/');
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
// TODO:
|
|
||||||
this.setState({ progress: false, snackbar: true, key: Date.now(), message: `Fehler beim Aufrufen des angeforderten Programms. Versuche es noch einmal.`, type: 'error' });
|
|
||||||
this.props.workspaceName(createNameId());
|
|
||||||
this.props.history.push('/');
|
|
||||||
window.scrollTo(0, 0);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.props.workspaceName(createNameId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onChange = () => {
|
onChange = () => {
|
||||||
this.setState({ codeOn: !this.state.codeOn });
|
this.setState({ codeOn: !this.state.codeOn });
|
||||||
const workspace = Blockly.getMainWorkspace();
|
const workspace = Blockly.getMainWorkspace();
|
||||||
@ -123,44 +83,35 @@ class Home extends Component {
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
{this.state.progress ?
|
{this.state.stats ?
|
||||||
<Backdrop open invisible>
|
<div style={{ float: 'left', height: '40px', position: 'relative' }}><WorkspaceStats /></div>
|
||||||
<CircularProgress color="primary" />
|
: null
|
||||||
</Backdrop>
|
}
|
||||||
:
|
<div style={{ float: 'right', height: '40px', marginBottom: '20px' }}><WorkspaceFunc /></div>
|
||||||
<div>
|
<Grid container spacing={2}>
|
||||||
{this.state.stats ?
|
<Grid item xs={12} md={this.state.codeOn ? 8 : 12} style={{ position: 'relative' }}>
|
||||||
<div style={{ float: 'left', height: '40px', position: 'relative' }}><WorkspaceStats /></div>
|
<Tooltip title={this.state.codeOn ? 'Code ausblenden' : 'Code anzeigen'} >
|
||||||
: null
|
<IconButton
|
||||||
}
|
className={this.state.codeOn ? this.props.classes.codeOn : this.props.classes.codeOff}
|
||||||
<div style={{ float: 'right', height: '40px', marginBottom: '20px' }}><WorkspaceFunc /></div>
|
style={{ width: '40px', height: '40px', position: 'absolute', top: -12, right: 8, zIndex: 21 }}
|
||||||
<Grid container spacing={2}>
|
onClick={() => this.onChange()}
|
||||||
<Grid item xs={12} md={this.state.codeOn ? 8 : 12} style={{ position: 'relative' }}>
|
>
|
||||||
<Tooltip title={this.state.codeOn ? 'Code ausblenden' : 'Code anzeigen'} >
|
<FontAwesomeIcon icon={faCode} size="xs" />
|
||||||
<IconButton
|
</IconButton>
|
||||||
className={this.state.codeOn ? this.props.classes.codeOn : this.props.classes.codeOff}
|
</Tooltip>
|
||||||
style={{ width: '40px', height: '40px', position: 'absolute', top: -12, right: 8, zIndex: 21 }}
|
<TrashcanButtons />
|
||||||
onClick={() => this.onChange()}
|
{this.props.project ?
|
||||||
>
|
< BlocklyWindow blocklyCSS={{ height: '80vH' }} initialXml={this.props.project} />
|
||||||
<FontAwesomeIcon icon={faCode} size="xs" />
|
: < BlocklyWindow blocklyCSS={{ height: '80vH' }} />
|
||||||
</IconButton>
|
}
|
||||||
</Tooltip>
|
|
||||||
<TrashcanButtons />
|
|
||||||
{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={4}>
|
|
||||||
<CodeViewer />
|
|
||||||
</Grid>
|
|
||||||
: null}
|
|
||||||
</Grid>
|
</Grid>
|
||||||
<HintTutorialExists />
|
{this.state.codeOn ?
|
||||||
</div>
|
<Grid item xs={12} md={4}>
|
||||||
}
|
<CodeViewer />
|
||||||
|
</Grid>
|
||||||
|
: null}
|
||||||
|
</Grid>
|
||||||
|
<HintTutorialExists />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -20,7 +20,7 @@ import ListItemIcon from '@material-ui/core/ListItemIcon';
|
|||||||
import ListItemText from '@material-ui/core/ListItemText';
|
import ListItemText from '@material-ui/core/ListItemText';
|
||||||
import LinearProgress from '@material-ui/core/LinearProgress';
|
import LinearProgress from '@material-ui/core/LinearProgress';
|
||||||
|
|
||||||
import { faBars, faChevronLeft, faBuilding, faIdCard, faEnvelope, faCog, faChalkboardTeacher, faFolderPlus, faTools, faLightbulb } from "@fortawesome/free-solid-svg-icons";
|
import { faBars, faChevronLeft, faLayerGroup, faBuilding, faIdCard, faEnvelope, faCog, faChalkboardTeacher, faFolderPlus, faTools, faLightbulb } from "@fortawesome/free-solid-svg-icons";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
|
||||||
const styles = (theme) => ({
|
const styles = (theme) => ({
|
||||||
@ -99,7 +99,11 @@ class Navbar extends Component {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<List>
|
<List>
|
||||||
{[{ text: 'Tutorials', icon: faChalkboardTeacher, link: "/tutorial" }, { text: 'Tutorial-Builder', icon: faTools, link: "/tutorial/builder" }, { text: 'Gallery', icon: faLightbulb, link: "/gallery" }, { text: 'Einstellungen', icon: faCog, link: "/settings" }].map((item, index) => (
|
{[{ text: 'Tutorials', icon: faChalkboardTeacher, link: "/tutorial" },
|
||||||
|
{ text: 'Tutorial-Builder', icon: faTools, link: "/tutorial/builder" },
|
||||||
|
{ text: 'Galerie', icon: faLightbulb, link: "/gallery" },
|
||||||
|
{ text: 'Projekte', icon: faLayerGroup, link: "/project" },
|
||||||
|
{ text: 'Einstellungen', icon: faCog, link: "/settings" }].map((item, index) => (
|
||||||
<Link to={item.link} key={index} style={{ textDecoration: 'none', color: 'inherit' }}>
|
<Link to={item.link} key={index} style={{ textDecoration: 'none', color: 'inherit' }}>
|
||||||
<ListItem button onClick={this.toggleDrawer}>
|
<ListItem button onClick={this.toggleDrawer}>
|
||||||
<ListItemIcon><FontAwesomeIcon icon={item.icon} /></ListItemIcon>
|
<ListItemIcon><FontAwesomeIcon icon={item.icon} /></ListItemIcon>
|
||||||
|
83
src/components/Project/Project.js
Normal file
83
src/components/Project/Project.js
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { workspaceName } from '../../actions/workspaceActions';
|
||||||
|
|
||||||
|
import axios from 'axios';
|
||||||
|
import { createNameId } from 'mnemonic-id';
|
||||||
|
|
||||||
|
import Home from '../Home';
|
||||||
|
import Breadcrumbs from '../Breadcrumbs';
|
||||||
|
|
||||||
|
import Backdrop from '@material-ui/core/Backdrop';
|
||||||
|
import CircularProgress from '@material-ui/core/CircularProgress';
|
||||||
|
|
||||||
|
|
||||||
|
class Project extends Component {
|
||||||
|
|
||||||
|
state = {
|
||||||
|
project: {},
|
||||||
|
progress: false,
|
||||||
|
type: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.getProject();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(props) {
|
||||||
|
if(props.location.path !== this.props.location.path){
|
||||||
|
this.getProject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getProject = () => {
|
||||||
|
var param = this.props.match.params.shareId ? 'share' : this.props.match.params.galleryId ? 'gallery' : 'project';
|
||||||
|
this.setState({ type: param, progress: true });
|
||||||
|
var id = this.props.match.params[`${param}Id`];
|
||||||
|
axios.get(`${process.env.REACT_APP_BLOCKLY_API}/${param}/${id}`)
|
||||||
|
.then(res => {
|
||||||
|
var data = param === 'share' ? 'content' : param;
|
||||||
|
if(res.data[data]){
|
||||||
|
this.props.workspaceName(res.data[data].title);
|
||||||
|
this.setState({ project: res.data[data], progress: false });
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.props.workspaceName(createNameId());
|
||||||
|
this.setState({ progress: false });
|
||||||
|
this.props.history.push('/');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
// TODO:
|
||||||
|
this.setState({ progress: false, snackbar: true, key: Date.now(), message: `Fehler beim Aufrufen des angeforderten Programms. Versuche es noch einmal.`, type: 'error' });
|
||||||
|
this.props.workspaceName(createNameId());
|
||||||
|
this.props.history.push('/');
|
||||||
|
window.scrollTo(0, 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
var data = this.state.type === 'project' ? 'Projekte' : 'Galerie';
|
||||||
|
return (
|
||||||
|
this.state.progress ?
|
||||||
|
<Backdrop open invisible>
|
||||||
|
<CircularProgress color="primary" />
|
||||||
|
</Backdrop>
|
||||||
|
:
|
||||||
|
<div>
|
||||||
|
{this.state.type !== 'share' ?
|
||||||
|
<Breadcrumbs content={[{ link: `/${this.state.type}`, title: data },{ link: this.props.location.path, title: this.state.project.title }]} />
|
||||||
|
: null}
|
||||||
|
<Home project={this.state.project.xml}/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Project.propTypes = {
|
||||||
|
workspaceName: PropTypes.func.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export default connect(null, { workspaceName })(Project);
|
@ -12,16 +12,28 @@ import Divider from '@material-ui/core/Divider';
|
|||||||
import Typography from '@material-ui/core/Typography';
|
import Typography from '@material-ui/core/Typography';
|
||||||
|
|
||||||
|
|
||||||
class GalleryHome extends Component {
|
class ProjectHome extends Component {
|
||||||
|
|
||||||
state = {
|
state = {
|
||||||
gallery: []
|
projects: []
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
axios.get(`${process.env.REACT_APP_BLOCKLY_API}/gallery`)
|
this.getProjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(props) {
|
||||||
|
if(props.match.path !== this.props.match.path){
|
||||||
|
this.setState({projects: []});
|
||||||
|
this.getProjects();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getProjects = () => {
|
||||||
|
var data = this.props.match.path === '/project' ? 'projects' : 'galleries';
|
||||||
|
axios.get(`${process.env.REACT_APP_BLOCKLY_API}${this.props.match.path}`)
|
||||||
.then(res => {
|
.then(res => {
|
||||||
this.setState({ gallery: res.data.galleries });
|
this.setState({ projects: res.data[data] });
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
// TODO:
|
// TODO:
|
||||||
@ -29,25 +41,26 @@ class GalleryHome extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
var data = this.props.match.path === '/project' ? 'Projekte' : 'Galerie';
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Breadcrumbs content={[{ link: '/gallery', title: 'Gallery' }]} />
|
<Breadcrumbs content={[{ link: this.props.match.path, title: data }]} />
|
||||||
|
|
||||||
<h1>Gallery</h1>
|
<h1>{data}</h1>
|
||||||
<Grid container spacing={2}>
|
<Grid container spacing={2}>
|
||||||
{this.state.gallery.map((gallery, i) => {
|
{this.state.projects.map((project, i) => {
|
||||||
return (
|
return (
|
||||||
<Grid item xs={12} sm={6} md={4} xl={3} key={i}>
|
<Grid item xs={12} sm={6} md={4} xl={3} key={i}>
|
||||||
<Link to={`/gallery/${gallery._id}`} style={{ textDecoration: 'none', color: 'inherit' }}>
|
<Link to={`/${data === 'Projekte' ? 'project' : 'gallery'}/${project._id}`} style={{ textDecoration: 'none', color: 'inherit' }}>
|
||||||
<Paper style={{ padding: '1rem', position: 'relative', overflow: 'hidden' }}>
|
<Paper style={{ padding: '1rem', position: 'relative', overflow: 'hidden' }}>
|
||||||
<h3 style={{marginTop: 0}}>{gallery.title}</h3>
|
<h3 style={{marginTop: 0}}>{project.title}</h3>
|
||||||
<Divider style={{marginTop: '1rem', marginBottom: '10px'}}/>
|
<Divider style={{marginTop: '1rem', marginBottom: '10px'}}/>
|
||||||
<BlocklyWindow
|
<BlocklyWindow
|
||||||
svg
|
svg
|
||||||
blockDisabled
|
blockDisabled
|
||||||
initialXml={gallery.xml}
|
initialXml={project.xml}
|
||||||
/>
|
/>
|
||||||
<Typography variant='body2' style={{fontStyle: 'italic', margin: 0, marginTop: '-30px'}}>{gallery.description}</Typography>
|
<Typography variant='body2' style={{fontStyle: 'italic', margin: 0, marginTop: '-30px'}}>{project.description}</Typography>
|
||||||
</Paper>
|
</Paper>
|
||||||
</Link>
|
</Link>
|
||||||
</Grid>
|
</Grid>
|
||||||
@ -59,4 +72,4 @@ class GalleryHome extends Component {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default GalleryHome;
|
export default ProjectHome;
|
@ -10,7 +10,8 @@ import Tutorial from './Tutorial/Tutorial';
|
|||||||
import TutorialHome from './Tutorial/TutorialHome';
|
import TutorialHome from './Tutorial/TutorialHome';
|
||||||
import Builder from './Tutorial/Builder/Builder';
|
import Builder from './Tutorial/Builder/Builder';
|
||||||
import NotFound from './NotFound';
|
import NotFound from './NotFound';
|
||||||
import GalleryHome from './Gallery/GalleryHome';
|
import ProjectHome from './Project/ProjectHome';
|
||||||
|
import Project from './Project/Project';
|
||||||
import Settings from './Settings/Settings';
|
import Settings from './Settings/Settings';
|
||||||
import Impressum from './Impressum';
|
import Impressum from './Impressum';
|
||||||
import Privacy from './Privacy';
|
import Privacy from './Privacy';
|
||||||
@ -27,15 +28,24 @@ class Routes extends Component {
|
|||||||
<div style={{ margin: '0 22px' }}>
|
<div style={{ margin: '0 22px' }}>
|
||||||
<Switch>
|
<Switch>
|
||||||
<Route path="/" exact component={Home} />
|
<Route path="/" exact component={Home} />
|
||||||
|
// Tutorials
|
||||||
<Route path="/tutorial" exact component={TutorialHome} />
|
<Route path="/tutorial" exact component={TutorialHome} />
|
||||||
|
<Route path="/tutorial/:tutorialId" exact component={Tutorial} />
|
||||||
|
<Route path="/tutorial/builder" exact component={Builder} />
|
||||||
|
// Sharing
|
||||||
|
<Route path="/share/:shareId" exact component={Project} />
|
||||||
|
// Gallery-Projects
|
||||||
|
<Route path="/gallery" exact component={ProjectHome} />
|
||||||
|
<Route path="/gallery/:galleryId" exact component={Project} />
|
||||||
|
// User-Projects
|
||||||
|
<Route path="/project" exact component={ProjectHome} />
|
||||||
|
<Route path="/project/:projectId" exact component={Project} />
|
||||||
|
// settings
|
||||||
<Route path="/settings" exact component={Settings} />
|
<Route path="/settings" exact component={Settings} />
|
||||||
<Route path="/gallery" exact component={GalleryHome} />
|
// privacy
|
||||||
<Route path="/gallery/:galleryId" exact component={Home} />
|
|
||||||
<Route path="/impressum" exact component={Impressum} />
|
<Route path="/impressum" exact component={Impressum} />
|
||||||
<Route path="/privacy" exact component={Privacy} />
|
<Route path="/privacy" exact component={Privacy} />
|
||||||
<Route path="/share/:shareId" exact component={Home} />
|
// Not Found
|
||||||
<Route path="/tutorial/builder" exact component={Builder} />
|
|
||||||
<Route path="/tutorial/:tutorialId" exact component={Tutorial} />
|
|
||||||
<Route component={NotFound} />
|
<Route component={NotFound} />
|
||||||
</Switch>
|
</Switch>
|
||||||
</div>
|
</div>
|
||||||
|
@ -5,6 +5,7 @@ import { clearStats, onChangeCode, workspaceName } from '../actions/workspaceAct
|
|||||||
|
|
||||||
import * as Blockly from 'blockly/core';
|
import * as Blockly from 'blockly/core';
|
||||||
|
|
||||||
|
import { withRouter } from 'react-router-dom';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { saveAs } from 'file-saver';
|
import { saveAs } from 'file-saver';
|
||||||
|
|
||||||
@ -14,6 +15,7 @@ import { initialXml } from './Blockly/initialXml.js';
|
|||||||
import Compile from './Compile';
|
import Compile from './Compile';
|
||||||
import SolutionCheck from './Tutorial/SolutionCheck';
|
import SolutionCheck from './Tutorial/SolutionCheck';
|
||||||
import Snackbar from './Snackbar';
|
import Snackbar from './Snackbar';
|
||||||
|
import Dialog from './Dialog';
|
||||||
|
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
@ -25,17 +27,7 @@ import Tooltip from '@material-ui/core/Tooltip';
|
|||||||
import TextField from '@material-ui/core/TextField';
|
import TextField from '@material-ui/core/TextField';
|
||||||
import Typography from '@material-ui/core/Typography';
|
import Typography from '@material-ui/core/Typography';
|
||||||
|
|
||||||
|
import { faPen, faSave, faUpload, faFileDownload, faCamera, faShare, faShareAlt, faCopy } 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, faCopy } from "@fortawesome/free-solid-svg-icons";
|
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
|
||||||
const styles = (theme) => ({
|
const styles = (theme) => ({
|
||||||
@ -101,7 +93,23 @@ class WorkspaceFunc extends Component {
|
|||||||
this.setState({ open: !this.state, share: false, file: false, saveFile: false, title: '', content: '' });
|
this.setState({ open: !this.state, share: false, file: false, saveFile: false, title: '', content: '' });
|
||||||
}
|
}
|
||||||
|
|
||||||
saveXmlFile = () => {
|
saveProject = () => {
|
||||||
|
var body = {
|
||||||
|
xml: this.props.xml,
|
||||||
|
title: this.props.name
|
||||||
|
};
|
||||||
|
axios.post(`${process.env.REACT_APP_BLOCKLY_API}/project`, body)
|
||||||
|
.then(res => {
|
||||||
|
var project = res.data.project;
|
||||||
|
this.props.history.push(`/project/${project._id}`);
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
this.setState({ snackbar: true, key: Date.now(), message: `Fehler beim Speichern des Projektes. Versuche es noch einmal.`, type: 'error' });
|
||||||
|
window.scrollTo(0, 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
downloadXmlFile = () => {
|
||||||
var code = this.props.xml;
|
var code = this.props.xml;
|
||||||
this.toggleDialog();
|
this.toggleDialog();
|
||||||
var fileName = detectWhitespacesAndReturnReadableResult(this.state.name);
|
var fileName = detectWhitespacesAndReturnReadableResult(this.state.name);
|
||||||
@ -173,10 +181,10 @@ class WorkspaceFunc extends Component {
|
|||||||
createFileName = (filetype) => {
|
createFileName = (filetype) => {
|
||||||
this.setState({ file: filetype }, () => {
|
this.setState({ file: filetype }, () => {
|
||||||
if (this.state.name) {
|
if (this.state.name) {
|
||||||
this.state.file === 'xml' ? this.saveXmlFile() : this.getSvg()
|
this.state.file === 'xml' ? this.downloadXmlFile() : this.getSvg()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.setState({ saveFile: true, file: filetype, open: true, title: this.state.file === 'xml' ? 'Blöcke speichern' : 'Screenshot erstellen', content: `Bitte gib einen Namen für die Bennenung der ${this.state.file === 'xml' ? 'XML' : 'SVG'}-Datei ein und bestätige diesen mit einem Klick auf 'Eingabe'.` });
|
this.setState({ saveFile: true, file: filetype, open: true, title: this.state.file === 'xml' ? 'Projekt herunterladen' : 'Screenshot erstellen', content: `Bitte gib einen Namen für die Bennenung der ${this.state.file === 'xml' ? 'XML' : 'SVG'}-Datei ein und bestätige diesen mit einem Klick auf 'Eingabe'.` });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -247,7 +255,7 @@ class WorkspaceFunc extends Component {
|
|||||||
return (
|
return (
|
||||||
<div style={{ width: 'max-content', display: 'flex' }}>
|
<div style={{ width: 'max-content', display: 'flex' }}>
|
||||||
{!this.props.assessment ?
|
{!this.props.assessment ?
|
||||||
<Tooltip title={`Name des Projekts${this.props.name ? `: ${this.props.name}` : ''}`} arrow style={{ marginRight: '5px' }}>
|
<Tooltip title={`Name des Projektes${this.props.name ? `: ${this.props.name}` : ''}`} arrow style={{ marginRight: '5px' }}>
|
||||||
<div className={this.props.classes.workspaceName} onClick={() => { this.setState({ file: true, open: true, saveFile: false, title: 'Projekt benennen', content: 'Bitte gib einen Namen für das Projekt ein und bestätige diesen mit einem Klick auf \'Eingabe\'.' }) }}>
|
<div className={this.props.classes.workspaceName} onClick={() => { this.setState({ file: true, open: true, saveFile: false, title: 'Projekt benennen', content: 'Bitte gib einen Namen für das Projekt ein und bestätige diesen mit einem Klick auf \'Eingabe\'.' }) }}>
|
||||||
{this.props.name && !isWidthDown('xs', this.props.width) ? <Typography style={{ margin: 'auto -3px auto 12px' }}>{this.props.name}</Typography> : null}
|
{this.props.name && !isWidthDown('xs', this.props.width) ? <Typography style={{ margin: 'auto -3px auto 12px' }}>{this.props.name}</Typography> : null}
|
||||||
<div style={{ width: '40px', display: 'flex' }}>
|
<div style={{ width: '40px', display: 'flex' }}>
|
||||||
@ -257,12 +265,20 @@ class WorkspaceFunc extends Component {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
: null}
|
: null}
|
||||||
{this.props.assessment ? <SolutionCheck /> : <Compile iconButton />}
|
{this.props.assessment ? <SolutionCheck /> : <Compile iconButton />}
|
||||||
<Tooltip title='Blöcke speichern' arrow style={{ marginRight: '5px' }}>
|
<Tooltip title='Projekt speichern' arrow style={{ marginRight: '5px' }}>
|
||||||
|
<IconButton
|
||||||
|
className={this.props.classes.button}
|
||||||
|
onClick={() => this.saveProject()}
|
||||||
|
>
|
||||||
|
<FontAwesomeIcon icon={faSave} size="xs" />
|
||||||
|
</IconButton>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip title='Projekt herunterladen' arrow style={{ marginRight: '5px' }}>
|
||||||
<IconButton
|
<IconButton
|
||||||
className={this.props.classes.button}
|
className={this.props.classes.button}
|
||||||
onClick={() => { this.createFileName('xml'); }}
|
onClick={() => { this.createFileName('xml'); }}
|
||||||
>
|
>
|
||||||
<FontAwesomeIcon icon={faSave} size="xs" />
|
<FontAwesomeIcon icon={faFileDownload} size="xs" />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
{!this.props.assessment?
|
{!this.props.assessment?
|
||||||
@ -275,7 +291,7 @@ class WorkspaceFunc extends Component {
|
|||||||
type="file"
|
type="file"
|
||||||
/>
|
/>
|
||||||
<label htmlFor="open-blocks">
|
<label htmlFor="open-blocks">
|
||||||
<Tooltip title='Blöcke öffnen' arrow style={{ marginRight: '5px' }}>
|
<Tooltip title='Projekt öffnen' arrow style={{ marginRight: '5px' }}>
|
||||||
<div className={this.props.classes.button} style={{
|
<div className={this.props.classes.button} style={{
|
||||||
borderRadius: '50%', cursor: 'pointer', display: 'table-cell',
|
borderRadius: '50%', cursor: 'pointer', display: 'table-cell',
|
||||||
verticalAlign: 'middle',
|
verticalAlign: 'middle',
|
||||||
@ -306,7 +322,7 @@ class WorkspaceFunc extends Component {
|
|||||||
</IconButton>
|
</IconButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
{!this.props.assessment?
|
{!this.props.assessment?
|
||||||
<Tooltip title='Blöcke teilen' arrow>
|
<Tooltip title='Projekt teilen' arrow>
|
||||||
<IconButton
|
<IconButton
|
||||||
className={this.props.classes.button}
|
className={this.props.classes.button}
|
||||||
onClick={() => this.shareBlocks()}
|
onClick={() => this.shareBlocks()}
|
||||||
@ -327,7 +343,7 @@ class WorkspaceFunc extends Component {
|
|||||||
{this.state.file ?
|
{this.state.file ?
|
||||||
<div style={{ marginTop: '10px' }}>
|
<div style={{ marginTop: '10px' }}>
|
||||||
<TextField autoFocus placeholder={this.state.saveXml ? 'Dateiname' : 'Projektname'} value={this.state.name} onChange={this.setFileName} style={{ marginRight: '10px' }} />
|
<TextField autoFocus placeholder={this.state.saveXml ? 'Dateiname' : 'Projektname'} value={this.state.name} onChange={this.setFileName} style={{ marginRight: '10px' }} />
|
||||||
<Button disabled={!this.state.name} variant='contained' color='primary' onClick={() => { this.state.saveFile ? this.state.file === 'xml' ? this.saveXmlFile() : this.getSvg() : this.renameWorkspace(); this.toggleDialog(); }}>Eingabe</Button>
|
<Button disabled={!this.state.name} variant='contained' color='primary' onClick={() => { this.state.saveFile ? this.state.file === 'xml' ? this.downloadXmlFile() : this.getSvg() : this.renameWorkspace(); this.toggleDialog(); }}>Eingabe</Button>
|
||||||
</div>
|
</div>
|
||||||
: this.state.share ?
|
: this.state.share ?
|
||||||
<div style={{ marginTop: '10px' }}>
|
<div style={{ marginTop: '10px' }}>
|
||||||
@ -374,4 +390,4 @@ const mapStateToProps = state => ({
|
|||||||
name: state.workspace.name
|
name: state.workspace.name
|
||||||
});
|
});
|
||||||
|
|
||||||
export default connect(mapStateToProps, { clearStats, onChangeCode, workspaceName })(withStyles(styles, { withTheme: true })(withWidth()(WorkspaceFunc)));
|
export default connect(mapStateToProps, { clearStats, onChangeCode, workspaceName })(withStyles(styles, { withTheme: true })(withWidth()(withRouter(WorkspaceFunc))));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user