Benoit Sida 3 år sedan
förälder
incheckning
9108395cce

+ 1
- 0
.meteor/packages Visa fil

@@ -22,3 +22,4 @@ insecure@1.0.7                # Allow all DB writes from clients (for prototypin
22 22
 meyerweb-reset
23 23
 fourseven:scss
24 24
 maxharris9:classnames
25
+momentjs:moment

+ 1
- 0
.meteor/versions Visa fil

@@ -47,6 +47,7 @@ mobile-experience@1.0.4
47 47
 mobile-status-bar@1.0.14
48 48
 modules@0.7.9
49 49
 modules-runtime@0.7.9
50
+momentjs:moment@2.10.6
50 51
 mongo@1.1.16
51 52
 mongo-id@1.0.6
52 53
 npm-mongo@2.2.24

+ 1
- 1
imports/ui/App.jsx Visa fil

@@ -6,7 +6,7 @@ export default class App extends Component {
6 6
 	render() {
7 7
 		return (
8 8
 			<div id="app-container">
9
-				<header>-</header>
9
+				<header>ESPTrainer</header>
10 10
 				<main id="content">
11 11
 					{/*<div className="left" />*/}
12 12
 					<div className="center">

+ 18
- 10
imports/ui/Board.jsx Visa fil

@@ -7,19 +7,18 @@ class Board extends Component {
7 7
 	constructor(props) {
8 8
 		super(props);
9 9
 		this.state = {
10
-			end: false,
11
-			win: false,
12
-			trials: 0,
13
-			score: 0,
10
+			end: false, win: false,
11
+			trials: 0, score: 0,
14 12
 			squares: [ false, false, false, false ],
15
-			image: "/images/img1.jpg"
13
+			image: "/images/img1.jpg",
14
+			scores: JSON.parse(localStorage.getItem('esp-scores') || "{}")
16 15
 		};
17 16
 		this.actions = [
18 17
 			{ label: 'Reset', action: this.reset.bind(this), active: () => true },
19
-			{ label: 'Pass', action: this.pass.bind(this), active: () => !this.state.end }
18
+			{ label: 'Pass', action: this.pass.bind(this), active: () => !this.state.end },
19
+			{ label: 'AddScore', action: () => this.registerScore(Math.floor(Math.random() * 100) % 24), active: () => true }
20 20
 		];
21
-		this.choices = [];
22
-		[0, 1, 2, 3].map(i => this.choices.push(this.choice.bind(this, i)));
21
+		this.choices = [0, 1, 2, 3].map(i => this.choice.bind(this, i));
23 22
 	}
24 23
 
25 24
 	fail(corrected) {
@@ -34,12 +33,21 @@ class Board extends Component {
34 33
 		this.props.setTimeout(() => this.setState({ win: false }), 2000);
35 34
 	}
36 35
 
36
+	registerScore(score) {
37
+		this.setState({ scores: update(this.state.scores, {
38
+			$merge: { [moment().unix()]: score } })
39
+		}, () => localStorage.setItem('esp-scores', JSON.stringify(this.state.scores)));
40
+	}
41
+
37 42
 	choice(answer) {
38 43
 		let corrected = Math.floor(Math.random() * 10) % 4;
39 44
 		this.setState({
40 45
 			trials: this.state.trials + 1,
41 46
 			image: `images/img${this.state.trials + 1}.jpg`,
42 47
 			end: this.state.trials + 1 >= 24
48
+		}, () => {
49
+			if (this.state.trials >= 24)
50
+				this.registerScore(this.state.score);
43 51
 		});
44 52
 		if (answer === corrected)
45 53
 			this.win();
@@ -48,7 +56,7 @@ class Board extends Component {
48 56
 	}
49 57
 
50 58
 	reset() {
51
-		this.setState({ trials: 0, image: 'images/img0.jpg', score: 0 });
59
+		this.setState({ trials: 0, image: 'images/img0.jpg', score: 0, end: false });
52 60
 	}
53 61
 
54 62
 	pass() {
@@ -59,7 +67,7 @@ class Board extends Component {
59 67
 	render() {
60 68
 		return <BoardLayout win={this.state.win} choices={this.choices} score={this.state.score}
61 69
 							highlighted={this.state.squares} actions={this.actions} active={!this.state.end}
62
-							trials={this.state.trials} image={this.state.image} />;
70
+							trials={this.state.trials} image={this.state.image} scores={this.state.scores}/>;
63 71
 	}
64 72
 }
65 73
 

+ 4
- 1
imports/ui/BoardLayout.jsx Visa fil

@@ -5,9 +5,10 @@ import Trials from './Trials';
5 5
 import Actions from './Actions';
6 6
 import Image from './Image';
7 7
 import Score from './Score';
8
+import ScoreChart from './ScoreChart';
8 9
 import './styles/Board';
9 10
 
10
-const BoardLayout = ({ active, win, actions, trials, score, image, choices, highlighted }) =>
11
+const BoardLayout = ({ active, win, actions, trials, score, scores, image, choices, highlighted }) =>
11 12
 	<div className="board">
12 13
 		<Score score={score} />
13 14
 		<div className="squares">
@@ -25,6 +26,7 @@ const BoardLayout = ({ active, win, actions, trials, score, image, choices, high
25 26
 		</div>
26 27
 		<Trials count={trials} />
27 28
 		<Actions actions={actions} />
29
+		<ScoreChart id="scoreChart" data={scores}/>
28 30
 	</div>;
29 31
 
30 32
 BoardLayout.propTypes = {
@@ -33,6 +35,7 @@ BoardLayout.propTypes = {
33 35
 	actions: Actions.propTypes.actions,
34 36
 	trials: Trials.propTypes.count,
35 37
 	score: Trials.propTypes.count,
38
+	scores: Chart.propTypes.data,
36 39
 	image: Image.propTypes.src,
37 40
 	choices: PropTypes.arrayOf(PropTypes.func).isRequired,
38 41
 	highlighted: PropTypes.arrayOf(PropTypes.bool).isRequired

+ 2
- 4
imports/ui/Score.jsx Visa fil

@@ -4,11 +4,9 @@ import './styles/Score';
4 4
 const Score = ({ score }) =>
5 5
 	<div className="score">
6 6
 		<div className="scale">
7
-			{
8
-				[...Array(25).keys()].map(x => <div key={x} className="grade" style={{left: (x * 20) + 'px'}} />)
9
-			}
7
+			{ [...Array(25).keys()].map(x => <div key={x} className="grade" />) }
10 8
 		</div>
11
-		<div className="current-score" style={{ width: (score * 20) + 'px' }} />
9
+		<div className="current-score" style={{ width: (score / 24) * 100 + '%' }} />
12 10
 	</div>;
13 11
 
14 12
 Score.propTypes = { score: PropTypes.number.isRequired };

+ 77
- 0
imports/ui/ScoreChart.jsx Visa fil

@@ -0,0 +1,77 @@
1
+import React, { Component, PropTypes} from 'react';
2
+import Chart from 'chart.js';
3
+
4
+Chart.defaults.global.legend.labels.fontColor = '#fff';
5
+const dateFormat = 'DD/MM/YYYY H:ss';
6
+const ScoreScales = {
7
+	yAxes: [{
8
+		ticks: {
9
+			fontColor: "#fff",
10
+			stepSize: 6,
11
+			max: 24,
12
+		}
13
+	}],
14
+	xAxes: [{
15
+		type: 'time',
16
+		time: {
17
+			fontColor: "#fff",
18
+			fontSize: 10,
19
+			parser: moment.unix,
20
+			tooltipFormat: dateFormat,
21
+			//unit: 'day'
22
+		},
23
+		ticks: {
24
+			fontColor: "#fff"
25
+		}
26
+	}]
27
+};
28
+
29
+
30
+export default class ScoreChart extends Component {
31
+	constructor(props) {
32
+		super(props);
33
+		this.chart = null;
34
+	}
35
+
36
+	shouldComponentUpdate(nextProps) {
37
+		return this.props.data !== nextProps.data;
38
+	}
39
+
40
+	componentDidMount() {
41
+		let labels = Object.keys(this.props.data);
42
+		const data = labels.map(key => this.props.data[key]);
43
+		// labels = labels.map(d => moment.unix(d).format(dateFormat).split(' '));
44
+		this.chart = new Chart(this.canvas, {
45
+			type: 'line',
46
+			data: {
47
+				labels: labels,
48
+				datasets: [{
49
+					label: 'Progression',
50
+					data: data,
51
+					backgroundColor: 'rgba(255, 99, 132, 0.2)',
52
+					borderColor: 'rgba(255,99,132,1)',
53
+					borderWidth: 1
54
+				}]
55
+			},
56
+			options: { scales: ScoreScales }
57
+		});
58
+	}
59
+
60
+	componentDidUpdate() {
61
+		let labels = Object.keys(this.props.data);
62
+		const data = labels.map(key => this.props.data[key]);
63
+		// labels = labels.map(d => moment.unix(d).format(dateFormat).split(' '));
64
+		this.chart.data.labels = labels;
65
+		this.chart.data.datasets[0].data = data;
66
+		this.chart.update();
67
+	}
68
+
69
+	render() {
70
+		return <canvas ref={(node) => this.canvas = node} width={400}/>;
71
+	}
72
+}
73
+
74
+Chart.propTypes = {
75
+	id: PropTypes.string.isRequired,
76
+	data: PropTypes.object.isRequired
77
+};

+ 0
- 1
imports/ui/styles/Actions.scss Visa fil

@@ -4,7 +4,6 @@
4 4
   display: flex;
5 5
   justify-content: center;
6 6
   flex-wrap: wrap;
7
-  width: 300px;
8 7
   margin-top: 20px;
9 8
 
10 9
   button {

+ 6
- 2
imports/ui/styles/App.scss Visa fil

@@ -10,8 +10,9 @@
10 10
 main {
11 11
     flex: 1;
12 12
     display: flex;
13
+    flex-direction: row;
13 14
     justify-content: center;
14
-    flex-direction: column;
15
+    align-items: stretch;
15 16
 }
16 17
 
17 18
 header {
@@ -31,7 +32,8 @@ header {
31 32
     margin: 30px;
32 33
     padding: 20px;
33 34
     display: flex;
34
-    flex: 1;
35
+    min-width: 440px;
36
+    align-items: stretch;
35 37
     flex-direction: column;
36 38
     background-color: rgba(0,0,0,0.1);
37 39
 }
@@ -43,6 +45,8 @@ header {
43 45
 
44 46
     main {
45 47
         flex-direction: row;
48
+        justify-content: center;
49
+        align-items: flex-start;
46 50
     }
47 51
 
48 52
     .center {

+ 2
- 1
imports/ui/styles/Board.scss Visa fil

@@ -1,7 +1,8 @@
1 1
 .board {
2 2
     display: flex;
3 3
     flex-direction: column;
4
-    align-items: center;
4
+    align-items: stretch;
5
+    max-width: 800px;
5 6
 
6 7
     .squares {
7 8
         position: relative;

+ 1
- 1
imports/ui/styles/Image.scss Visa fil

@@ -3,7 +3,7 @@
3 3
 .image {
4 4
   position: absolute;
5 5
   top: 9px;
6
-  left: 9px;
6
+  left: calc(50% - 112px);
7 7
   width: 224px;
8 8
   border-radius: 5px;
9 9
   border: 1px solid rgba(255, 255, 255, 0.5);

+ 40
- 19
imports/ui/styles/Score.scss Visa fil

@@ -1,33 +1,54 @@
1
+@import "gradient";
2
+
1 3
 .score {
2 4
   display: flex;
3
-  width: 480px;
4 5
   flex-direction: column;
5 6
   margin-bottom: 50px;
6 7
 
8
+  .current-score {
9
+    background: #fff;
10
+    height: 3px;
11
+    margin-top: 3px;
12
+  }
13
+
7 14
   .scale {
15
+    display: flex;
8 16
     flex: 1;
9
-    position: relative;
10
-    //width: 220px;
11 17
     height: 3px;
12
-    background: red; /* For browsers that do not support gradients */
13
-    background: -webkit-linear-gradient(left, cyan, blue, green, yellow, orange, red, violet); /* For Safari 5.1 to 6.0 */
14
-    background: -o-linear-gradient(right, cyan, blue, green, yellow, orange, red, violet); /* For Opera 11.1 to 12.0 */
15
-    background: -moz-linear-gradient(right, cyan, blue, green, yellow, orange, red, violet); /* For Firefox 3.6 to 15 */
16
-    background: linear-gradient(to right, cyan, blue, green, yellow, orange, red, violet); /* Standard syntax (must be last) */
18
+    justify-content: space-between;
19
+    margin-top: 1em;
20
+    position: relative;
21
+    @include rainbow-gradient();
17 22
 
18 23
     .grade {
19
-      height:5px;
20
-      position: absolute;
21
-      top: 0;
22
-    }
24
+      position: relative;
23 25
 
24
-  }
26
+      &:after {
27
+        background: white;
28
+        content: ' ';
29
+        display: block;
30
+        height: 5px;
31
+        position: absolute;
32
+        top: -1px;
33
+        width: 1px;
34
+      }
25 35
 
26
-  .current-score {
27
-    background: #fff;
28
-    height: 3px;
29
-    //width: 480px;
30
-    margin-top: 3px;
31
-  }
36
+      @mixin grade-label($number) {
37
+        content: quote(inspect($number));
38
+        position: absolute;
39
+        top: -20px;
40
+        @if($number > 10) { left: -8px; }
41
+        @else { left: -4px; }
42
+        color: white;
43
+      }
44
+
45
+      @mixin grade-labels($numbers...) {
46
+        @each $number in $numbers {
47
+          &:nth-child(#{$number + 1}):before { @include grade-label($number); }
48
+        }
49
+      }
32 50
 
51
+      @include grade-labels(0, 6, 12, 18, 24);
52
+    }
53
+  }
33 54
 }

+ 8
- 0
imports/ui/styles/_gradient.scss Visa fil

@@ -40,4 +40,12 @@
40 40
   background: -ms-radial-gradient(center, ellipse cover, $lighten 0%, $color 100%);
41 41
   background: radial-gradient(ellipse at center, $lighten 0%, $color 100%);
42 42
   filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#{ie_hex_str($lighten)}', endColorstr='#{ie_hex_str($color)}', GradientType=1 );
43
+}
44
+
45
+@mixin rainbow-gradient() {
46
+  background: cyan; /* For browsers that do not support gradients */
47
+  background: -webkit-linear-gradient(left, cyan, blue, green, yellow, orange, red, violet); /* For Safari 5.1 to 6.0 */
48
+  background: -o-linear-gradient(right, cyan, blue, green, yellow, orange, red, violet); /* For Opera 11.1 to 12.0 */
49
+  background: -moz-linear-gradient(right, cyan, blue, green, yellow, orange, red, violet); /* For Firefox 3.6 to 15 */
50
+  background: linear-gradient(to right, cyan, blue, green, yellow, orange, red, violet); /* Standard syntax (must be last) */
43 51
 }

+ 1
- 0
package.json Visa fil

@@ -6,6 +6,7 @@
6 6
   },
7 7
   "dependencies": {
8 8
     "babel-runtime": "^6.20.0",
9
+    "chart.js": "^2.5.0",
9 10
     "meteor-node-stubs": "~0.2.4",
10 11
     "react": "^15.4.2",
11 12
     "react-addons-css-transition-group": "^15.4.2",