playball 2.2.2 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +2 -2
- package/README.md +18 -4
- package/demo.cast +95 -0
- package/demo.gif +0 -0
- package/dist/components/AllPlays.js +94 -93
- package/dist/components/App.js +45 -117
- package/dist/components/AtBat.js +44 -43
- package/dist/components/Bases.js +17 -26
- package/dist/components/Count.js +15 -26
- package/dist/components/FinishedGame.js +51 -66
- package/dist/components/Game.js +51 -114
- package/dist/components/GameList.js +161 -135
- package/dist/components/Grid.js +115 -0
- package/dist/components/HelpBar.js +13 -6
- package/dist/components/InningDisplay.js +26 -0
- package/dist/components/LineScore.js +32 -90
- package/dist/components/LiveGame.js +24 -19
- package/dist/components/LoadingSpinner.js +34 -125
- package/dist/components/Matchup.js +38 -59
- package/dist/components/PreviewGame.js +34 -55
- package/dist/components/Standings.js +91 -0
- package/dist/features/games.js +135 -0
- package/dist/features/keys.js +63 -0
- package/dist/features/schedule.js +58 -0
- package/dist/features/standings.js +57 -0
- package/dist/hooks/useKey.js +23 -0
- package/dist/logger.js +8 -10
- package/dist/main.js +13 -23
- package/dist/screen.js +22 -0
- package/dist/store/index.js +21 -7
- package/dist/style/index.js +3 -3
- package/package.json +44 -26
- package/src/components/AllPlays.jsx +95 -63
- package/src/components/App.jsx +38 -66
- package/src/components/AtBat.jsx +34 -36
- package/src/components/Bases.jsx +8 -13
- package/src/components/Count.jsx +10 -15
- package/src/components/FinishedGame.jsx +29 -40
- package/src/components/Game.jsx +48 -65
- package/src/components/GameList.jsx +125 -81
- package/src/components/Grid.jsx +91 -0
- package/src/components/HelpBar.jsx +14 -9
- package/src/components/InningDisplay.jsx +19 -0
- package/src/components/LineScore.jsx +27 -33
- package/src/components/LiveGame.jsx +7 -3
- package/src/components/LoadingSpinner.jsx +26 -60
- package/src/components/Matchup.jsx +26 -39
- package/src/components/PreviewGame.jsx +22 -37
- package/src/components/Standings.jsx +78 -0
- package/src/features/games.js +165 -0
- package/src/features/keys.js +38 -0
- package/src/features/schedule.js +59 -0
- package/src/features/standings.js +60 -0
- package/src/hooks/useKey.js +13 -0
- package/src/main.js +7 -14
- package/src/screen.js +14 -0
- package/src/store/index.js +16 -7
- package/src/style/index.js +1 -1
- package/dist/actions/game.js +0 -36
- package/dist/actions/schedule.js +0 -33
- package/dist/actions/types.js +0 -16
- package/dist/reducers/game.js +0 -70
- package/dist/reducers/index.js +0 -21
- package/dist/reducers/schedule.js +0 -35
- package/dist/selectors/game.js +0 -82
- package/dist/selectors/schedule.js +0 -25
- package/src/actions/game.js +0 -25
- package/src/actions/schedule.js +0 -21
- package/src/actions/types.js +0 -5
- package/src/reducers/game.js +0 -56
- package/src/reducers/index.js +0 -9
- package/src/reducers/schedule.js +0 -28
- package/src/selectors/game.js +0 -93
- package/src/selectors/schedule.js +0 -18
package/dist/store/index.js
CHANGED
|
@@ -3,16 +3,30 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports
|
|
6
|
+
exports.default = void 0;
|
|
7
7
|
|
|
8
|
-
var
|
|
8
|
+
var _toolkit = require("@reduxjs/toolkit");
|
|
9
9
|
|
|
10
|
-
var
|
|
10
|
+
var _schedule = _interopRequireDefault(require("../features/schedule"));
|
|
11
11
|
|
|
12
|
-
var
|
|
12
|
+
var _games = _interopRequireDefault(require("../features/games"));
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
var _keys = _interopRequireDefault(require("../features/keys"));
|
|
15
15
|
|
|
16
|
-
var
|
|
16
|
+
var _standings = _interopRequireDefault(require("../features/standings"));
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
19
|
+
|
|
20
|
+
var _default = (0, _toolkit.configureStore)({
|
|
21
|
+
reducer: {
|
|
22
|
+
schedule: _schedule.default,
|
|
23
|
+
games: _games.default,
|
|
24
|
+
keys: _keys.default,
|
|
25
|
+
standings: _standings.default
|
|
26
|
+
},
|
|
27
|
+
middleware: getDefaultMiddleware => getDefaultMiddleware({
|
|
28
|
+
serializableCheck: false
|
|
29
|
+
})
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
exports.default = _default;
|
package/dist/style/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports
|
|
6
|
+
exports.default = void 0;
|
|
7
7
|
var _default = {
|
|
8
8
|
list: {
|
|
9
9
|
selected: {
|
|
@@ -14,9 +14,9 @@ var _default = {
|
|
|
14
14
|
scrollbar: {
|
|
15
15
|
ch: ' ',
|
|
16
16
|
style: {
|
|
17
|
-
fg: '
|
|
17
|
+
fg: 'white',
|
|
18
18
|
inverse: true
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
};
|
|
22
|
-
exports
|
|
22
|
+
exports.default = _default;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "playball",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Watch MLB games from the comfort of your terminal",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"MLB",
|
|
@@ -13,9 +13,10 @@
|
|
|
13
13
|
"build": "npm run lint && npm run clean && npm run compile",
|
|
14
14
|
"clean": "rimraf ./dist",
|
|
15
15
|
"compile": "babel src --out-dir dist",
|
|
16
|
-
"lint": "eslint src",
|
|
16
|
+
"lint": "eslint --ext .jsx,.js src",
|
|
17
17
|
"start": "babel-node ./src/main.js",
|
|
18
|
-
"prepublishOnly": "npm run build"
|
|
18
|
+
"prepublishOnly": "npm run build",
|
|
19
|
+
"react-devtools": "react-devtools"
|
|
19
20
|
},
|
|
20
21
|
"main": "dist/main.js",
|
|
21
22
|
"bin": {
|
|
@@ -33,37 +34,54 @@
|
|
|
33
34
|
"preferGlobal": true,
|
|
34
35
|
"license": "MIT",
|
|
35
36
|
"dependencies": {
|
|
36
|
-
"
|
|
37
|
+
"@reduxjs/toolkit": "^1.8.0",
|
|
38
|
+
"axios": "^0.26.1",
|
|
37
39
|
"blessed": "^0.1.81",
|
|
38
|
-
"
|
|
40
|
+
"date-fns": "^2.28.0",
|
|
39
41
|
"json-patch": "^0.7.0",
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
"react": "^
|
|
43
|
-
"react-blessed": "^0.
|
|
44
|
-
"react-devtools-core": "^
|
|
45
|
-
"react-redux": "^
|
|
46
|
-
"redux": "^4.
|
|
47
|
-
"
|
|
48
|
-
"redux-thunk": "^2.3.0",
|
|
49
|
-
"reselect": "^3.0.1",
|
|
50
|
-
"winston": "^3.3.3",
|
|
51
|
-
"ws": "^6.2.1"
|
|
42
|
+
"prop-types": "^15.8.1",
|
|
43
|
+
"raf": "^3.4.1",
|
|
44
|
+
"react": "^17.0.2",
|
|
45
|
+
"react-blessed": "^0.7.2",
|
|
46
|
+
"react-devtools-core": "^4.24.7",
|
|
47
|
+
"react-redux": "^7.2.6",
|
|
48
|
+
"redux": "^4.1.2",
|
|
49
|
+
"winston": "^3.7.2"
|
|
52
50
|
},
|
|
53
51
|
"devDependencies": {
|
|
54
|
-
"@babel/cli": "^7.10
|
|
55
|
-
"@babel/core": "^7.
|
|
56
|
-
"@babel/node": "^7.10
|
|
57
|
-
"@babel/preset-env": "^7.
|
|
58
|
-
"@babel/preset-react": "^7.
|
|
59
|
-
"
|
|
60
|
-
"eslint
|
|
61
|
-
"
|
|
52
|
+
"@babel/cli": "^7.17.10",
|
|
53
|
+
"@babel/core": "^7.18.2",
|
|
54
|
+
"@babel/node": "^7.17.10",
|
|
55
|
+
"@babel/preset-env": "^7.18.2",
|
|
56
|
+
"@babel/preset-react": "^7.17.12",
|
|
57
|
+
"babel-plugin-module-resolver": "^4.1.0",
|
|
58
|
+
"eslint": "^8.12.0",
|
|
59
|
+
"eslint-plugin-react": "^7.29.4",
|
|
60
|
+
"react-devtools": "^4.24.7",
|
|
61
|
+
"rimraf": "^2.6.3",
|
|
62
|
+
"ws": "^8.5.0"
|
|
62
63
|
},
|
|
63
64
|
"babel": {
|
|
64
65
|
"presets": [
|
|
65
|
-
|
|
66
|
+
[
|
|
67
|
+
"@babel/preset-env",
|
|
68
|
+
{
|
|
69
|
+
"targets": {
|
|
70
|
+
"node": "10"
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
],
|
|
66
74
|
"@babel/preset-react"
|
|
75
|
+
],
|
|
76
|
+
"plugins": [
|
|
77
|
+
[
|
|
78
|
+
"module-resolver",
|
|
79
|
+
{
|
|
80
|
+
"alias": {
|
|
81
|
+
"react-redux": "react-redux/lib/alternate-renderers"
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
]
|
|
67
85
|
]
|
|
68
86
|
}
|
|
69
87
|
}
|
|
@@ -1,75 +1,107 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import { selectAllPlays, selectTeams } from '../selectors/game';
|
|
2
|
+
import { useSelector } from 'react-redux';
|
|
3
|
+
import { selectAllPlays, selectTeams } from '../features/games';
|
|
5
4
|
|
|
6
5
|
import style from '../style';
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
7
|
+
|
|
8
|
+
function getPlayResultColor(play) {
|
|
9
|
+
const lastPlay = play.playEvents[play.playEvents.length - 1]?.details;
|
|
10
|
+
if (!lastPlay) {
|
|
11
|
+
return 'white';
|
|
12
|
+
} else if (lastPlay.isBall) {
|
|
13
|
+
return 'green';
|
|
14
|
+
} else if (lastPlay.isStrike) {
|
|
15
|
+
return 'red';
|
|
16
|
+
} else if (lastPlay.isInPlay && !play.about.hasOut) {
|
|
17
|
+
return 'blue';
|
|
18
|
+
} else {
|
|
19
|
+
return 'white';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function formatOut(out) {
|
|
24
|
+
return ` {bold}${out} out{/bold}`;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
function AllPlays() {
|
|
29
|
+
const plays = useSelector(selectAllPlays);
|
|
30
|
+
const teams = useSelector(selectTeams);
|
|
31
|
+
|
|
32
|
+
const formatScoreDetail = (scoreObj) => (
|
|
33
|
+
' {bold}{white-bg}{black-fg} ' +
|
|
34
|
+
`${teams.away.abbreviation} ${scoreObj.awayScore} - ` +
|
|
35
|
+
`${teams.home.abbreviation} ${scoreObj.homeScore}` +
|
|
36
|
+
' {/black-fg}{/white-bg}{/bold}'
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
let inning = '';
|
|
40
|
+
const lines = [];
|
|
41
|
+
plays && plays.slice().reverse().forEach((play, playIdx, plays) => {
|
|
42
|
+
let lastPlay;
|
|
43
|
+
if (playIdx < plays.length - 1) {
|
|
44
|
+
lastPlay = plays[playIdx + 1];
|
|
45
|
+
}
|
|
46
|
+
const playInning = play.about.halfInning + ' ' + play.about.inning;
|
|
47
|
+
if (playInning !== inning) {
|
|
48
|
+
inning = playInning;
|
|
49
|
+
if (lines.length > 0) {
|
|
50
|
+
lines.push('');
|
|
51
|
+
}
|
|
52
|
+
lines.push(`{bold}[${inning.toUpperCase()}]{/bold}`);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (play.about.isComplete) {
|
|
56
|
+
const color = getPlayResultColor(play);
|
|
57
|
+
let line = `{${color}-fg}[${play.result.event}]{/${color}-fg} ${play.result.description}`;
|
|
58
|
+
if (play.about.hasOut) {
|
|
59
|
+
const lastOut = play.playEvents[play.playEvents.length - 1].count.outs;
|
|
60
|
+
if (lastOut !== play.count.outs) {
|
|
61
|
+
line += formatOut(play.count.outs);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (play.about.isScoringPlay) {
|
|
65
|
+
line += formatScoreDetail(play.result);
|
|
18
66
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
67
|
+
lines.push(line);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
play.playEvents && play.playEvents.slice().reverse().forEach((event, eventIdx, events) => {
|
|
71
|
+
if (event.type === 'action') {
|
|
72
|
+
let line = '';
|
|
73
|
+
if (event.details.event) {
|
|
74
|
+
line += `[${event.details.event}] `;
|
|
75
|
+
}
|
|
76
|
+
line += event.details.description;
|
|
77
|
+
if (event.isScoringPlay || event.details.isScoringPlay) {
|
|
78
|
+
line += formatScoreDetail(event.details);
|
|
23
79
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
80
|
+
const currentOut = event.count?.outs;
|
|
81
|
+
let prevOut = lastPlay ? lastPlay.count.outs : 0;
|
|
82
|
+
if (eventIdx < events.length - 1) {
|
|
83
|
+
prevOut = events[eventIdx + 1].count?.outs;
|
|
84
|
+
}
|
|
85
|
+
if (currentOut > prevOut) {
|
|
86
|
+
line += formatOut(currentOut);
|
|
29
87
|
}
|
|
30
88
|
lines.push(line);
|
|
31
89
|
}
|
|
32
|
-
play.get('playEvents') && play.get('playEvents').reverse().forEach(event => {
|
|
33
|
-
if (event.get('type') === 'action') {
|
|
34
|
-
let line = '';
|
|
35
|
-
if (event.getIn(['details', 'event'])) {
|
|
36
|
-
line += `[${event.getIn(['details', 'event'])}] `;
|
|
37
|
-
}
|
|
38
|
-
line += event.getIn(['details', 'description']);
|
|
39
|
-
if (event.get('isScoringPlay')) {
|
|
40
|
-
line += '{white-bg}{black-fg}{bold}' +
|
|
41
|
-
`${teams.getIn(['away', 'abbreviation'])} ${event.getIn(['details', 'awayScore'])} - ` +
|
|
42
|
-
`${teams.getIn(['home', 'abbreviation'])} ${event.getIn(['details', 'homeScore'])}` +
|
|
43
|
-
'{/bold}{/black-fg}{/white-bg}';
|
|
44
|
-
}
|
|
45
|
-
lines.push(line);
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
90
|
});
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
91
|
+
});
|
|
92
|
+
return (
|
|
93
|
+
<box
|
|
94
|
+
content={lines.join('\n')}
|
|
95
|
+
focused
|
|
96
|
+
mouse
|
|
97
|
+
keys
|
|
98
|
+
vi
|
|
99
|
+
scrollable
|
|
100
|
+
scrollbar={style.scrollbar}
|
|
101
|
+
alwaysScroll
|
|
102
|
+
tags
|
|
103
|
+
/>
|
|
104
|
+
);
|
|
63
105
|
}
|
|
64
106
|
|
|
65
|
-
|
|
66
|
-
plays: PropTypes.object,
|
|
67
|
-
teams: PropTypes.object,
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
const mapStateToProps = state => ({
|
|
71
|
-
plays: selectAllPlays(state),
|
|
72
|
-
teams: selectTeams(state),
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
export default connect(mapStateToProps)(AllPlays);
|
|
107
|
+
export default AllPlays;
|
package/src/components/App.jsx
CHANGED
|
@@ -1,71 +1,43 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import PropTypes from 'prop-types';
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import { useDispatch } from 'react-redux';
|
|
4
3
|
import GameList from './GameList';
|
|
5
|
-
import Game from './Game';
|
|
6
4
|
import HelpBar from './HelpBar';
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
import
|
|
10
|
-
import
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
5
|
+
import { setSelectedId } from '../features/games';
|
|
6
|
+
import Game from './Game';
|
|
7
|
+
import useKey from '../hooks/useKey';
|
|
8
|
+
import Standings from './Standings';
|
|
9
|
+
|
|
10
|
+
const SCHEDULE = 'schedule';
|
|
11
|
+
const STANDINGS = 'standings';
|
|
12
|
+
const GAME = 'game';
|
|
13
|
+
|
|
14
|
+
function App() {
|
|
15
|
+
const [view, setView] = useState(SCHEDULE);
|
|
16
|
+
const dispatch = useDispatch();
|
|
17
|
+
|
|
18
|
+
useKey('c', () => {
|
|
19
|
+
setView(SCHEDULE);
|
|
20
|
+
dispatch(setSelectedId(null));
|
|
21
|
+
}, { key: 'C', label: 'Schedule' });
|
|
22
|
+
useKey('s', () => setView(STANDINGS), { key: 'S', label: 'Standings'});
|
|
23
|
+
|
|
24
|
+
const handleGameSelect = (game) => {
|
|
25
|
+
dispatch(setSelectedId(game.gamePk));
|
|
26
|
+
setView(GAME);
|
|
27
|
+
};
|
|
31
28
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
<
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
<HelpBar />
|
|
45
|
-
</element>
|
|
46
|
-
</element>
|
|
47
|
-
);
|
|
48
|
-
} catch (error) {
|
|
49
|
-
this.props.debug(error);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
29
|
+
return (
|
|
30
|
+
<element>
|
|
31
|
+
<element top={0} left={0} height='100%-1'>
|
|
32
|
+
{view === STANDINGS && <Standings />}
|
|
33
|
+
{view === SCHEDULE && <GameList onGameSelect={handleGameSelect} />}
|
|
34
|
+
{view === GAME && <Game />}
|
|
35
|
+
</element>
|
|
36
|
+
<element top='100%-1' left={0} height={1}>
|
|
37
|
+
<HelpBar />
|
|
38
|
+
</element>
|
|
39
|
+
</element>
|
|
40
|
+
);
|
|
52
41
|
}
|
|
53
42
|
|
|
54
|
-
|
|
55
|
-
debug: PropTypes.func,
|
|
56
|
-
onKeyPress: PropTypes.func,
|
|
57
|
-
selectedGame: PropTypes.number,
|
|
58
|
-
setSelectedGame: PropTypes.func,
|
|
59
|
-
game: PropTypes.object,
|
|
60
|
-
};
|
|
61
|
-
|
|
62
|
-
const mapStateToProps = state => ({
|
|
63
|
-
selectedGame: selectSelectedId(state),
|
|
64
|
-
game: selectGame(state),
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
const mapDispatchToProps = {
|
|
68
|
-
setSelectedGame
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
export default connect(mapStateToProps, mapDispatchToProps)(App);
|
|
43
|
+
export default App;
|
package/src/components/AtBat.jsx
CHANGED
|
@@ -1,43 +1,41 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import { selectCurrentPlay } from '../selectors/game';
|
|
2
|
+
import { useSelector } from 'react-redux';
|
|
3
|
+
import { selectCurrentPlay } from '../features/games';
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
5
|
+
function AtBat() {
|
|
6
|
+
const currentPlay = useSelector(selectCurrentPlay);
|
|
7
|
+
const playEvents = currentPlay.playEvents;
|
|
8
|
+
const playResult = currentPlay.about.isComplete ? currentPlay.result.description : '';
|
|
9
|
+
let content = '';
|
|
10
|
+
if (playResult) {
|
|
11
|
+
content += `${playResult}\n\n`;
|
|
12
|
+
}
|
|
13
|
+
if (playEvents && playEvents.length) {
|
|
14
|
+
content += playEvents.slice().reverse().map(event => {
|
|
15
|
+
let line = '';
|
|
16
|
+
if (event.isPitch) {
|
|
17
|
+
line = `[${event.details.description}] `;
|
|
18
|
+
if (event.pitchData?.startSpeed) {
|
|
19
|
+
line += `${event.pitchData.startSpeed} MPH `;
|
|
20
|
+
}
|
|
21
|
+
if (event.details?.type?.description) {
|
|
22
|
+
line += event.details.type.description;
|
|
23
|
+
}
|
|
24
|
+
if (!event.details?.isInPlay) {
|
|
25
|
+
line += `{|} ${event.count.balls}-${event.count.strikes}`;
|
|
26
|
+
}
|
|
27
|
+
} else {
|
|
28
|
+
if (event.details?.event) {
|
|
29
|
+
line += `[${event.details.event}] `;
|
|
30
|
+
}
|
|
31
|
+
line += event.details.description;
|
|
16
32
|
}
|
|
17
|
-
line
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
} else {
|
|
22
|
-
if (event.getIn(['details', 'event'])) {
|
|
23
|
-
line += `[${event.getIn(['details', 'event'])}] `;
|
|
24
|
-
}
|
|
25
|
-
line += event.getIn(['details', 'description']);
|
|
26
|
-
}
|
|
27
|
-
return line;
|
|
28
|
-
}).join('\n') + `\n\n${playResult}`;
|
|
33
|
+
return line;
|
|
34
|
+
}).join('\n');
|
|
35
|
+
}
|
|
29
36
|
return (
|
|
30
37
|
<box content={content} tags />
|
|
31
38
|
);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
AtBat.propTypes = {
|
|
35
|
-
boxscore: PropTypes.object,
|
|
36
|
-
currentPlay: PropTypes.object,
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
const mapStateToProps = state => ({
|
|
40
|
-
currentPlay: selectCurrentPlay(state),
|
|
41
|
-
});
|
|
39
|
+
}
|
|
42
40
|
|
|
43
|
-
export default
|
|
41
|
+
export default AtBat;
|
package/src/components/Bases.jsx
CHANGED
|
@@ -1,27 +1,22 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { useSelector } from 'react-redux';
|
|
3
3
|
import PropTypes from 'prop-types';
|
|
4
|
-
import {
|
|
4
|
+
import { selectLineScore } from '../features/games';
|
|
5
5
|
|
|
6
|
-
const formatBase = (offense, base) =>
|
|
6
|
+
const formatBase = (offense, base) => (base in offense) ? '{yellow-fg}◆{/yellow-fg}' : '◇';
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
const offense =
|
|
8
|
+
function Bases({align}) {
|
|
9
|
+
const { offense } = useSelector(selectLineScore);
|
|
10
10
|
const content =
|
|
11
11
|
` ${formatBase(offense, 'second')}\n` +
|
|
12
12
|
`${formatBase(offense, 'third')} ${formatBase(offense, 'first')}`;
|
|
13
13
|
return (
|
|
14
14
|
<box align={align} content={content} tags />
|
|
15
15
|
);
|
|
16
|
-
}
|
|
16
|
+
}
|
|
17
17
|
|
|
18
18
|
Bases.propTypes = {
|
|
19
|
-
align: PropTypes.
|
|
20
|
-
game: PropTypes.object,
|
|
19
|
+
align: PropTypes.oneOf(['left', 'center', 'right']),
|
|
21
20
|
};
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
game: selectGame(state),
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
export default connect(mapStateToProps)(Bases);
|
|
22
|
+
export default Bases;
|
package/src/components/Count.jsx
CHANGED
|
@@ -1,29 +1,24 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { useSelector } from 'react-redux';
|
|
3
3
|
import PropTypes from 'prop-types';
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { selectLineScore } from '../features/games';
|
|
6
6
|
|
|
7
7
|
const formatCount = (count, total) => '● '.repeat(count) + '○ '.repeat(total - count);
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
const linescore =
|
|
9
|
+
function Count({align}) {
|
|
10
|
+
const linescore = useSelector(selectLineScore);
|
|
11
11
|
const content =
|
|
12
|
-
`B: {green-fg}${formatCount(linescore.
|
|
13
|
-
`S: {red-fg}${formatCount(linescore.
|
|
14
|
-
`O: {red-fg}${formatCount(linescore.
|
|
12
|
+
`B: {green-fg}${formatCount(linescore.balls, 4)}{/green-fg}\n` +
|
|
13
|
+
`S: {red-fg}${formatCount(linescore.strikes, 3)}{/red-fg}\n` +
|
|
14
|
+
`O: {red-fg}${formatCount(linescore.outs, 3)}{/red-fg}`;
|
|
15
15
|
return (
|
|
16
16
|
<box align={align} content={content} tags />
|
|
17
17
|
);
|
|
18
|
-
}
|
|
18
|
+
}
|
|
19
19
|
|
|
20
20
|
Count.propTypes = {
|
|
21
|
-
align: PropTypes.
|
|
22
|
-
game: PropTypes.object,
|
|
21
|
+
align: PropTypes.oneOf(['left', 'center', 'right']),
|
|
23
22
|
};
|
|
24
23
|
|
|
25
|
-
|
|
26
|
-
game: selectGame(state),
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
export default connect(mapStateToProps)(Count);
|
|
24
|
+
export default Count;
|