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,119 +1,88 @@ | ||||
| import React, { Component } from 'react'; | ||||
| 
 | ||||
| import { withRouter } from 'react-router-dom'; | ||||
| 
 | ||||
| import Breadcrumbs from '../Breadcrumbs'; | ||||
| import StepperHorizontal from './StepperHorizontal'; | ||||
| import StepperVertical from './StepperVertical'; | ||||
| import BlocklyWindow from '../Blockly/BlocklyWindow'; | ||||
| import CodeViewer from '../CodeViewer'; | ||||
| import NotFound from '../NotFound'; | ||||
| 
 | ||||
| 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 Tab from '@material-ui/core/Tab'; | ||||
| import Grid from '@material-ui/core/Grid'; | ||||
| 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 { | ||||
| 
 | ||||
|   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) => { | ||||
|     console.log(value); | ||||
|     this.setState({ value: value }); | ||||
|   } | ||||
| 
 | ||||
|   render() { | ||||
|     var tutorialId = Number(this.props.match.params.tutorialId); | ||||
|     var tutorialId = this.state.tutorialId; | ||||
|     return ( | ||||
|       !Number.isInteger(tutorialId) || tutorialId < 1 || tutorialId > tutorials.length ? | ||||
|       <NotFound button={{title: 'Zurück zur Tutorials-Übersicht', link: '/tutorial'}}/> | ||||
|         : | ||||
|       <div> | ||||
|         <Breadcrumbs content={[{link: '/', title: 'Home'},{link: '/tutorial', title: 'Tutorial'}, {link: `/tutorial/${tutorialId}`, title: tutorials[tutorialId-1].title}]}/> | ||||
|         <NotFound button={{title: 'Zurück zur Tutorials-Übersicht', link: '/tutorial'}}/> | ||||
|       : | ||||
|         <div> | ||||
|           <Breadcrumbs content={[{link: '/', title: 'Home'},{link: '/tutorial', title: 'Tutorial'}, {link: `/tutorial/${tutorialId}`, title: tutorials[tutorialId-1].title}]}/> | ||||
| 
 | ||||
|         {/* Stepper */} | ||||
|         <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> | ||||
|           <StepperHorizontal /> | ||||
| 
 | ||||
|           <div style={{display: 'flex'}}> | ||||
|             <StepperVertical /> | ||||
| 
 | ||||
|             {/* width of vertical stepper is 30px*/} | ||||
|             <Card style={{width: 'calc(100% - 30px)', padding: '10px'}}> | ||||
|               <Tabs | ||||
|                 value={this.state.value} | ||||
|                 indicatorColor="primary" | ||||
|                 textColor="inherit" | ||||
|                 variant='fullWidth' | ||||
|                 onChange={this.onChange} | ||||
|               > | ||||
|                 <Tab label="Anleitung" value='introduction' disableRipple/> | ||||
|                 <Tab label="Aufgabe" value='assessment' disableRipple/> | ||||
|               </Tabs> | ||||
| 
 | ||||
|               <div style={{marginTop: '20px'}}> | ||||
|                 {this.state.value === 'introduction' ? | ||||
|                   'Hier könnte eine Anleitung stehen.': null } | ||||
|                 {this.state.value === 'assessment' ? | ||||
|                   <Grid container spacing={2}> | ||||
|                     <Grid item xs={12} md={6} lg={8}> | ||||
|                       <BlocklyWindow /> | ||||
|                     </Grid> | ||||
|                     <Grid item xs={12} md={6} lg={4}> | ||||
|                       <Card style={{height: 'calc(50% - 30px)', padding: '10px', marginBottom: '10px'}}> | ||||
|                         Hier könnte die Problemstellung stehen. | ||||
|                       </Card> | ||||
|                       <div style={{height: '50%'}}> | ||||
|                         <CodeViewer /> | ||||
|                       </div> | ||||
|                     </Grid> | ||||
|                   </Grid> | ||||
|                 : null } | ||||
|               </div> | ||||
|             </Card> | ||||
|           </div> | ||||
|         </div> | ||||
| 
 | ||||
| 
 | ||||
|         <Tabs | ||||
|           value={this.state.value} | ||||
|           indicatorColor="primary" | ||||
|           textColor="inherit" | ||||
|           variant='fullWidth' | ||||
|           onChange={this.onChange} | ||||
|         > | ||||
|           <Tab label="Anleitung" value='introduction' disableRipple/> | ||||
|           <Tab label="Aufgabe" value='assessment' disableRipple/> | ||||
|         </Tabs> | ||||
| 
 | ||||
|         <div style={{marginTop: '20px'}}> | ||||
|           {this.state.value === 'introduction' ? | ||||
|             'Hier könnte eine Anleitung stehen.': null } | ||||
|           {this.state.value === 'assessment' ? | ||||
|             <Grid container spacing={2}> | ||||
|               <Grid item xs={12} md={6} lg={8}> | ||||
|                 <BlocklyWindow /> | ||||
|               </Grid> | ||||
|               <Grid item xs={12} md={6} lg={4}> | ||||
|                 <Card style={{height: 'calc(50% - 30px)', padding: '10px', marginBottom: '10px'}}> | ||||
|                   Hier könnte die Problemstellung stehen. | ||||
|                 </Card> | ||||
|                 <div style={{height: '50%'}}> | ||||
|                   <CodeViewer /> | ||||
|                 </div> | ||||
|               </Grid> | ||||
|             </Grid> | ||||
|           : null } | ||||
|         </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" | ||||
|   }, | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user