vertical tutorial stepper
This commit is contained in:
parent
ccf901d20b
commit
7148d66d19
70
src/components/Tutorial/StepperHorizontal.js
Normal file
70
src/components/Tutorial/StepperHorizontal.js
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
|
import { withRouter } from 'react-router-dom';
|
||||||
|
|
||||||
|
import tutorials from './tutorials.json';
|
||||||
|
|
||||||
|
import { fade } from '@material-ui/core/styles/colorManipulator';
|
||||||
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
|
import Button from '@material-ui/core/Button';
|
||||||
|
import Stepper from '@material-ui/core/Stepper';
|
||||||
|
import Step from '@material-ui/core/Step';
|
||||||
|
import StepLabel from '@material-ui/core/StepLabel';
|
||||||
|
|
||||||
|
const styles = (theme) => ({
|
||||||
|
stepper: {
|
||||||
|
backgroundColor: fade(theme.palette.primary.main, 0.6),
|
||||||
|
width: 'calc(100% - 40px)',
|
||||||
|
borderRadius: '25px',
|
||||||
|
padding: '0 20px',
|
||||||
|
margin: '20px 0',
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between'
|
||||||
|
},
|
||||||
|
color: {
|
||||||
|
backgroundColor: 'transparent '
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
class StepperHorizontal extends Component {
|
||||||
|
|
||||||
|
state={
|
||||||
|
tutorialId: Number(this.props.match.params.tutorialId),
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(props, state){
|
||||||
|
if(state.tutorialId !== Number(this.props.match.params.tutorialId)){
|
||||||
|
this.setState({tutorialId: Number(this.props.match.params.tutorialId)})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
var tutorialId = this.state.tutorialId;
|
||||||
|
return (
|
||||||
|
<div className={this.props.classes.stepper}>
|
||||||
|
<Button
|
||||||
|
disabled={tutorialId-1 === 0}
|
||||||
|
onClick={() => {this.props.history.push(`/tutorial/${tutorialId-1}`)}}
|
||||||
|
>
|
||||||
|
{'<'}
|
||||||
|
</Button>
|
||||||
|
<Stepper activeStep={tutorialId} orientation="horizontal"
|
||||||
|
style={{padding: 0}} classes={{root: this.props.classes.color}}>
|
||||||
|
<Step expanded completed={false}>
|
||||||
|
<StepLabel icon={``}>
|
||||||
|
<h1 style={{margin: 0}}>{tutorials[tutorialId-1].title}</h1>
|
||||||
|
</StepLabel>
|
||||||
|
</Step>
|
||||||
|
</Stepper>
|
||||||
|
<Button
|
||||||
|
disabled={tutorialId+1 > tutorials.length}
|
||||||
|
onClick={() => {this.props.history.push(`/tutorial/${tutorialId+1}`)}}
|
||||||
|
>
|
||||||
|
{'>'}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withRouter(withStyles(styles, {withTheme: true})(StepperHorizontal));
|
185
src/components/Tutorial/StepperVertical.js
Normal file
185
src/components/Tutorial/StepperVertical.js
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
|
import { withRouter, Link } from 'react-router-dom';
|
||||||
|
|
||||||
|
import clsx from 'clsx';
|
||||||
|
|
||||||
|
import tutorials from './tutorials.json';
|
||||||
|
|
||||||
|
import { fade } from '@material-ui/core/styles/colorManipulator';
|
||||||
|
import { withStyles } from '@material-ui/core/styles';
|
||||||
|
import Button from '@material-ui/core/Button';
|
||||||
|
import Stepper from '@material-ui/core/Stepper';
|
||||||
|
import Step from '@material-ui/core/Step';
|
||||||
|
import StepLabel from '@material-ui/core/StepLabel';
|
||||||
|
import Tooltip from '@material-ui/core/Tooltip';
|
||||||
|
import LinearProgress from '@material-ui/core/LinearProgress';
|
||||||
|
|
||||||
|
const styles = (theme) => ({
|
||||||
|
verticalStepper: {
|
||||||
|
padding: 0,
|
||||||
|
width: '30px',
|
||||||
|
},
|
||||||
|
stepIconSmall: {
|
||||||
|
border: `2px solid ${theme.palette.primary.main}`,
|
||||||
|
borderRadius: '50%',
|
||||||
|
width: '12px',
|
||||||
|
height: '12px',
|
||||||
|
margin: '0 auto'
|
||||||
|
},
|
||||||
|
stepIconMedium: {
|
||||||
|
border: `2px solid ${theme.palette.primary.main}`,
|
||||||
|
borderRadius: '50%',
|
||||||
|
width: '18px',
|
||||||
|
height: '18px',
|
||||||
|
margin: '0 auto'
|
||||||
|
},
|
||||||
|
stepIconLarge: {
|
||||||
|
border: `2px solid ${theme.palette.primary.main}`,
|
||||||
|
borderRadius: '50%',
|
||||||
|
width: '24px',
|
||||||
|
height: '24px'
|
||||||
|
},
|
||||||
|
stepIconTransparent: {
|
||||||
|
border: `2px solid transparent`,
|
||||||
|
cursor: 'default'
|
||||||
|
},
|
||||||
|
stepIconActive: {
|
||||||
|
backgroundColor: fade(theme.palette.primary.main, 0.6)
|
||||||
|
},
|
||||||
|
progress: {
|
||||||
|
position: 'absolute',
|
||||||
|
top: 0,
|
||||||
|
right: 0,
|
||||||
|
marginRight: '5px',
|
||||||
|
width: '3px',
|
||||||
|
},
|
||||||
|
progressForeground: {
|
||||||
|
backgroundColor: theme.palette.primary.main
|
||||||
|
},
|
||||||
|
progressBackground: {
|
||||||
|
backgroundColor: fade(theme.palette.primary.main, 0.2),
|
||||||
|
height: '100%'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
class StepperVertical extends Component {
|
||||||
|
|
||||||
|
state={
|
||||||
|
tutorialArray: Number(this.props.match.params.tutorialId) === 1 ?
|
||||||
|
tutorials.slice(Number(this.props.match.params.tutorialId)-1, Number(this.props.match.params.tutorialId)+4)
|
||||||
|
: Number(this.props.match.params.tutorialId) === 2 ?
|
||||||
|
tutorials.slice(Number(this.props.match.params.tutorialId)-1-1, Number(this.props.match.params.tutorialId)+3)
|
||||||
|
: Number(this.props.match.params.tutorialId) === tutorials.length ?
|
||||||
|
tutorials.slice(Number(this.props.match.params.tutorialId)-4-1, Number(this.props.match.params.tutorialId)+4)
|
||||||
|
: Number(this.props.match.params.tutorialId) === tutorials.length-1 ?
|
||||||
|
tutorials.slice(Number(this.props.match.params.tutorialId)-3-1, Number(this.props.match.params.tutorialId)+3)
|
||||||
|
: tutorials.slice(Number(this.props.match.params.tutorialId)-2-1,Number(this.props.match.params.tutorialId)+2),
|
||||||
|
tutorialId: Number(this.props.match.params.tutorialId),
|
||||||
|
verticalTutorialId: Number(this.props.match.params.tutorialId)
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(props, state){
|
||||||
|
if(state.tutorialId !== Number(this.props.match.params.tutorialId)){
|
||||||
|
this.setState({
|
||||||
|
tutorialArray: Number(this.props.match.params.tutorialId) === 1 ?
|
||||||
|
tutorials.slice(Number(this.props.match.params.tutorialId)-1, Number(this.props.match.params.tutorialId)+4)
|
||||||
|
: Number(this.props.match.params.tutorialId) === 2 ?
|
||||||
|
tutorials.slice(Number(this.props.match.params.tutorialId)-1-1, Number(this.props.match.params.tutorialId)+3)
|
||||||
|
: Number(this.props.match.params.tutorialId) === tutorials.length ?
|
||||||
|
tutorials.slice(Number(this.props.match.params.tutorialId)-4-1, Number(this.props.match.params.tutorialId)+4)
|
||||||
|
: Number(this.props.match.params.tutorialId) === tutorials.length-1 ?
|
||||||
|
tutorials.slice(Number(this.props.match.params.tutorialId)-3-1, Number(this.props.match.params.tutorialId)+3)
|
||||||
|
: tutorials.slice(Number(this.props.match.params.tutorialId)-2-1,Number(this.props.match.params.tutorialId)+2),
|
||||||
|
tutorialId: Number(this.props.match.params.tutorialId),
|
||||||
|
verticalTutorialId: Number(this.props.match.params.tutorialId)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
verticalStepper = (step) => {
|
||||||
|
var newTutorialId = this.state.verticalTutorialId + step;
|
||||||
|
var tutorialArray = Number(newTutorialId) === 1 ?
|
||||||
|
tutorials.slice(newTutorialId-1, newTutorialId+4)
|
||||||
|
: newTutorialId === 2 ?
|
||||||
|
tutorials.slice(newTutorialId-1-1, newTutorialId+3)
|
||||||
|
: newTutorialId === tutorials.length ?
|
||||||
|
tutorials.slice(newTutorialId-4-1, newTutorialId+4)
|
||||||
|
: newTutorialId === tutorials.length-1 ?
|
||||||
|
tutorials.slice(newTutorialId-3-1, newTutorialId+3)
|
||||||
|
: tutorials.slice(newTutorialId-2-1, newTutorialId+2);
|
||||||
|
this.setState({ tutorialArray: tutorialArray, verticalTutorialId: newTutorialId });
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
var tutorialId = this.state.tutorialId;
|
||||||
|
var verticalTutorialId = this.state.verticalTutorialId;
|
||||||
|
return (
|
||||||
|
<div style={{marginRight: '10px'}}>
|
||||||
|
<Button
|
||||||
|
style={{minWidth: '30px', margin: 'auto', minHeight: '25px', padding: '0', writingMode: 'vertical-rl'}}
|
||||||
|
disabled={this.state.verticalTutorialId === 1}
|
||||||
|
onClick={() => {this.verticalStepper(-1)}}
|
||||||
|
>
|
||||||
|
{'<'}
|
||||||
|
</Button>
|
||||||
|
<div style={{display: 'flex', height: 'calc(100% - 25px - 25px)', width: 'max-content'}}>
|
||||||
|
<div style={{position: 'relative'}}>
|
||||||
|
<div
|
||||||
|
className={clsx(this.props.classes.progress, this.props.classes.progressForeground)}
|
||||||
|
style={{ zIndex: 1, borderRadius: `${verticalTutorialId/tutorials.length === 1 ? '2px' : '2px 2px 0 0'}`, height: `${(verticalTutorialId/tutorials.length)*100}%`}}>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={clsx(this.props.classes.progress, this.props.classes.progressBackground)}
|
||||||
|
style={{borderRadius: `${verticalTutorialId/tutorials.length === 1 ? '2px' : '2px 2px 0 0'}`}}>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Stepper
|
||||||
|
activeStep={tutorialId}
|
||||||
|
orientation="vertical"
|
||||||
|
connector={<div style={{height: '10px'}}></div>}
|
||||||
|
classes={{root: this.props.classes.verticalStepper}}
|
||||||
|
>
|
||||||
|
{this.state.tutorialArray.map((tutorial, i) => {
|
||||||
|
var index = this.state.tutorialArray.indexOf(tutorials[verticalTutorialId-1]);
|
||||||
|
return (
|
||||||
|
<Step key={i}>
|
||||||
|
<Tooltip title={Object.keys(tutorial).length > 0 ? tutorial.title : ''} placement='right' arrow >
|
||||||
|
<Link to={`/tutorial/${i === index ? verticalTutorialId : verticalTutorialId - index + i}`}>
|
||||||
|
<StepLabel
|
||||||
|
StepIconComponent={'div'}
|
||||||
|
classes={{
|
||||||
|
root: tutorial === tutorials[verticalTutorialId-1] ?
|
||||||
|
tutorial === tutorials[tutorialId-1] ?
|
||||||
|
clsx(this.props.classes.stepIconLarge, this.props.classes.stepIconActive)
|
||||||
|
: this.props.classes.stepIconLarge
|
||||||
|
: tutorial === tutorials[verticalTutorialId-2] || tutorial === tutorials[verticalTutorialId] ?
|
||||||
|
tutorial === tutorials[tutorialId-1] ?
|
||||||
|
clsx(this.props.classes.stepIconMedium, this.props.classes.stepIconActive)
|
||||||
|
: this.props.classes.stepIconMedium
|
||||||
|
: tutorial === tutorials[tutorialId-1] ?
|
||||||
|
clsx(this.props.classes.stepIconSmall, this.props.classes.stepIconActive)
|
||||||
|
: this.props.classes.stepIconSmall
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
</StepLabel>
|
||||||
|
</Link>
|
||||||
|
</Tooltip>
|
||||||
|
</Step>
|
||||||
|
)})}
|
||||||
|
</Stepper>
|
||||||
|
</div>
|
||||||
|
<Button
|
||||||
|
style={{minWidth: '30px', minHeight: '25px', padding: '0', writingMode: 'vertical-rl'}}
|
||||||
|
disabled={this.state.verticalTutorialId === tutorials.length}
|
||||||
|
onClick={() => {this.verticalStepper(1)}}
|
||||||
|
>
|
||||||
|
{'>'}
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withRouter(withStyles(styles, {withTheme: true})(StepperVertical));
|
@ -1,54 +1,39 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
|
||||||
import { withRouter } from 'react-router-dom';
|
|
||||||
|
|
||||||
import Breadcrumbs from '../Breadcrumbs';
|
import Breadcrumbs from '../Breadcrumbs';
|
||||||
|
import StepperHorizontal from './StepperHorizontal';
|
||||||
|
import StepperVertical from './StepperVertical';
|
||||||
import BlocklyWindow from '../Blockly/BlocklyWindow';
|
import BlocklyWindow from '../Blockly/BlocklyWindow';
|
||||||
import CodeViewer from '../CodeViewer';
|
import CodeViewer from '../CodeViewer';
|
||||||
import NotFound from '../NotFound';
|
import NotFound from '../NotFound';
|
||||||
|
|
||||||
import tutorials from './tutorials.json';
|
import tutorials from './tutorials.json';
|
||||||
|
|
||||||
import { fade } from '@material-ui/core/styles/colorManipulator';
|
|
||||||
import { withStyles } from '@material-ui/core/styles';
|
|
||||||
import Tabs from '@material-ui/core/Tabs';
|
import Tabs from '@material-ui/core/Tabs';
|
||||||
import Tab from '@material-ui/core/Tab';
|
import Tab from '@material-ui/core/Tab';
|
||||||
import Grid from '@material-ui/core/Grid';
|
import Grid from '@material-ui/core/Grid';
|
||||||
import Card from '@material-ui/core/Card';
|
import Card from '@material-ui/core/Card';
|
||||||
import Button from '@material-ui/core/Button';
|
|
||||||
import Stepper from '@material-ui/core/Stepper';
|
|
||||||
import Step from '@material-ui/core/Step';
|
|
||||||
import StepLabel from '@material-ui/core/StepLabel';
|
|
||||||
|
|
||||||
|
|
||||||
const styles = (theme) => ({
|
|
||||||
stepper: {
|
|
||||||
backgroundColor: fade(theme.palette.primary.main, 0.6),
|
|
||||||
width: 'calc(100% - 40px)',
|
|
||||||
// opacity: 0.6,
|
|
||||||
borderRadius: '25px',
|
|
||||||
padding: '0 20px',
|
|
||||||
margin: '20px 0',
|
|
||||||
display: 'flex',
|
|
||||||
justifyContent: 'space-between'
|
|
||||||
},
|
|
||||||
color: {
|
|
||||||
backgroundColor: 'transparent '
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
class Tutorial extends Component {
|
class Tutorial extends Component {
|
||||||
|
|
||||||
state={
|
state={
|
||||||
value: 'introduction'
|
value: 'introduction',
|
||||||
|
tutorialId: Number(this.props.match.params.tutorialId)
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(props, state){
|
||||||
|
if(state.tutorialId !== Number(this.props.match.params.tutorialId)){
|
||||||
|
this.setState({tutorialId: Number(this.props.match.params.tutorialId)})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onChange = (e, value) => {
|
onChange = (e, value) => {
|
||||||
|
console.log(value);
|
||||||
this.setState({ value: value });
|
this.setState({ value: value });
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
var tutorialId = Number(this.props.match.params.tutorialId);
|
var tutorialId = this.state.tutorialId;
|
||||||
return (
|
return (
|
||||||
!Number.isInteger(tutorialId) || tutorialId < 1 || tutorialId > tutorials.length ?
|
!Number.isInteger(tutorialId) || tutorialId < 1 || tutorialId > tutorials.length ?
|
||||||
<NotFound button={{title: 'Zurück zur Tutorials-Übersicht', link: '/tutorial'}}/>
|
<NotFound button={{title: 'Zurück zur Tutorials-Übersicht', link: '/tutorial'}}/>
|
||||||
@ -56,31 +41,13 @@ class Tutorial extends Component {
|
|||||||
<div>
|
<div>
|
||||||
<Breadcrumbs content={[{link: '/', title: 'Home'},{link: '/tutorial', title: 'Tutorial'}, {link: `/tutorial/${tutorialId}`, title: tutorials[tutorialId-1].title}]}/>
|
<Breadcrumbs content={[{link: '/', title: 'Home'},{link: '/tutorial', title: 'Tutorial'}, {link: `/tutorial/${tutorialId}`, title: tutorials[tutorialId-1].title}]}/>
|
||||||
|
|
||||||
{/* Stepper */}
|
<StepperHorizontal />
|
||||||
<div className={this.props.classes.stepper}>
|
|
||||||
<Button
|
|
||||||
disabled={tutorialId-1 === 0}
|
|
||||||
onClick={() => {this.props.history.push(`/tutorial/${tutorialId-1}`)}}
|
|
||||||
>
|
|
||||||
{'<'}
|
|
||||||
</Button>
|
|
||||||
<Stepper activeStep={tutorialId} orientation="horizontal"
|
|
||||||
style={{padding: 0}} classes={{root: this.props.classes.color}}>
|
|
||||||
<Step expanded completed={false}>
|
|
||||||
<StepLabel icon={``}>
|
|
||||||
<h1 style={{margin: 0}}>{tutorials[tutorialId-1].title}</h1>
|
|
||||||
</StepLabel>
|
|
||||||
</Step>
|
|
||||||
</Stepper>
|
|
||||||
<Button
|
|
||||||
disabled={tutorialId+1 > tutorials.length}
|
|
||||||
onClick={() => {this.props.history.push(`/tutorial/${tutorialId+1}`)}}
|
|
||||||
>
|
|
||||||
{'>'}
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<div style={{display: 'flex'}}>
|
||||||
|
<StepperVertical />
|
||||||
|
|
||||||
|
{/* width of vertical stepper is 30px*/}
|
||||||
|
<Card style={{width: 'calc(100% - 30px)', padding: '10px'}}>
|
||||||
<Tabs
|
<Tabs
|
||||||
value={this.state.value}
|
value={this.state.value}
|
||||||
indicatorColor="primary"
|
indicatorColor="primary"
|
||||||
@ -111,9 +78,11 @@ class Tutorial extends Component {
|
|||||||
</Grid>
|
</Grid>
|
||||||
: null }
|
: null }
|
||||||
</div>
|
</div>
|
||||||
|
</Card>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withRouter(withStyles(styles, {withTheme: true})(Tutorial));
|
export default Tutorial;
|
||||||
|
@ -1,4 +1,67 @@
|
|||||||
[
|
[
|
||||||
|
{
|
||||||
|
"title": "erste Schritte"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "if-Bedingung"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "for-Schleife"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "erste Schritte"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "if-Bedingung"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "for-Schleife"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "erste Schritte"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "if-Bedingung"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "for-Schleife"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "erste Schritte"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "if-Bedingung"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "for-Schleife"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "erste Schritte"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "if-Bedingung"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "for-Schleife"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "erste Schritte"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "if-Bedingung"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "for-Schleife"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "erste Schritte"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "if-Bedingung"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "for-Schleife"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"title": "erste Schritte"
|
"title": "erste Schritte"
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user