├── .gitignore
├── LICENSE
├── Makefile
├── README.md
├── app.js
├── components
├── Blinds.js
├── Clock.js
├── Debts.js
├── Logger.js
├── Pot.js
└── Timer.js
├── index.html
├── package.json
├── react-poker-screenshot.png
├── style.css
├── variables.js
└── webpack.config.js
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | bundle.js
3 | node_modules/
4 | build/
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Jeff Pickelman
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 |
2 | all: build
3 |
4 | build:
5 | npm install
6 | npm install webpack
7 | ./node_modules/.bin/webpack
8 | mkdir build
9 | cp index.html bundle.js style.css ./node_modules/normalize.css/normalize.css build/
10 |
11 | clean:
12 | rm -rf build/
13 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-poker
2 | A React component simulating a Texas holdem tournament game.
3 |
4 | ### Usage
5 | Run `npm install`, `npm install -g webpack`, `webpack` to generate `bundle.js`.
6 |
7 | ### Screenshot of the app:
8 |
9 | 
10 |
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 |
2 | 'use strict';
3 |
4 | import React from 'react';
5 | import Timer from './components/Timer.js';
6 | import Blinds from './components/Blinds.js';
7 | import Pot from './components/Pot.js';
8 | import Debts from './components/Debts.js';
9 | import Clock from './components/Clock.js';
10 |
11 | import { startingSeconds, payouts, buyIn, smallBlinds } from './variables.js';
12 |
13 | class App extends React.Component {
14 | componentWillMount() {
15 | window.addEventListener( 'blinds-up', this.handleBlindsUp, false );
16 | }
17 |
18 | componentWillUnmount() {
19 | window.removeEventListener( 'blinds-up', this.handleBlindsUp, false );
20 | }
21 |
22 | handleBlindsUp() {
23 | let body = document.getElementsByTagName( 'body' )[0];
24 | body.classList.add( 'flashing' );
25 | setTimeout( function() { body.classList.remove( 'flashing' ); }, 1700 );
26 | setTimeout( function() { body.classList.add( 'flashing' ); }, 1800 );
27 | setTimeout( function() { body.classList.remove( 'flashing' ); }, 3500 );
28 | }
29 |
30 | render() {
31 | return (
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
Poker Simulator
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
58 |
59 |
60 |
61 | );
62 | }
63 | }
64 |
65 | React.render( , document.getElementById( 'app' ) );
66 |
--------------------------------------------------------------------------------
/components/Blinds.js:
--------------------------------------------------------------------------------
1 |
2 |
3 | import React from 'react';
4 |
5 | class Blind extends React.Component {
6 | render() {
7 | let classString = '';
8 | if ( this.props.active ) {
9 | classString += 'active';
10 | }
11 | return { this.props.blind } / { this.props.blind * 2 }
12 | }
13 | }
14 |
15 | class Blinds extends React.Component {
16 | constructor( props ) {
17 | this.state = { activeIndex: 0 };
18 | this.raiseBlinds = this.raiseBlinds.bind( this );
19 | this.lowerBlinds = this.lowerBlinds.bind( this );
20 | }
21 |
22 | componentWillMount() {
23 | window.addEventListener( 'blinds-up', this.raiseBlinds, false );
24 | }
25 |
26 | componentWillUnmount() {
27 | window.removeEventListener( 'blinds-up', this.raiseBlinds, false );
28 | }
29 |
30 | raiseBlinds() {
31 | if ( this.state.activeIndex + 1 > this.props.smallBlinds.length - 1 ) { return; }
32 | this.setState( { activeIndex: this.state.activeIndex + 1 } );
33 | }
34 |
35 | lowerBlinds() {
36 | if ( this.state.activeIndex === 0 ) { return; }
37 | this.setState( { activeIndex: this.state.activeIndex - 1 } );
38 | }
39 |
40 | render() {
41 | return (
42 |
43 |
Blinds:
44 |
45 | - Current Blind:
46 |
47 |
48 |
49 | { this.props.smallBlinds.map( ( blind, index ) => {
50 | return
51 | } ) }
52 |
53 |
54 |
55 |
56 | );
57 | }
58 | }
59 |
60 | export default Blinds;
61 |
--------------------------------------------------------------------------------
/components/Clock.js:
--------------------------------------------------------------------------------
1 |
2 | 'use strict';
3 |
4 | import React from 'react';
5 |
6 | class Clock extends React.Component {
7 | constructor() {
8 | this.state = ( { now: new Date() } );
9 |
10 | this.updateClock = this.updateClock.bind( this );
11 | setInterval( this.updateClock, 1000 );
12 | }
13 |
14 | // componentDidRender() {
15 | // this.updateClock();
16 | // setTimeout( this.updateClock, 1000 );
17 | // }
18 |
19 | updateClock() {
20 | this.setState( { now: new Date() } );
21 | }
22 |
23 | render() {
24 | let now = this.state.now;
25 | let hours = now.getHours();
26 | let minutes = now.getMinutes();
27 | let seconds = now.getSeconds();
28 | return { hours > 12 ? hours - 12 : hours }:{ minutes < 10 ? '0' + minutes : minutes } PM
29 | }
30 | }
31 |
32 | // Seconds: :{ seconds < 10 ? '0' + seconds : seconds }
33 |
34 | export default Clock;
35 |
--------------------------------------------------------------------------------
/components/Debts.js:
--------------------------------------------------------------------------------
1 |
2 | 'use strict';
3 |
4 | import React from 'react';
5 |
6 | let debts = [];
7 |
8 | class Debt extends React.Component {
9 | constructor( props ) {
10 | this.state = { paid: false };
11 |
12 | this.togglePaid = this.togglePaid.bind( this );
13 | }
14 |
15 | togglePaid() {
16 | this.setState( { paid: !this.state.paid } );
17 | }
18 |
19 | render() {
20 | let classString = '';
21 | if ( this.state.paid ) {
22 | classString += 'paid';
23 | }
24 | return { this.props.debt };
25 | }
26 | }
27 |
28 | class Debts extends React.Component {
29 | constructor( props ) {
30 | this.state = { debts: debts };
31 | this.handleSubmit = this.handleSubmit.bind( this );
32 | }
33 |
34 | handleSubmit( event ) {
35 | event.preventDefault();
36 | let debt = React.findDOMNode( this.refs['debt-input'] ).value.trim();
37 | this.state.debts.push( debt );
38 | this.setState( { debts: this.state.debts } );
39 | React.findDOMNode( this.refs['debt-input'] ).value = '';
40 | return;
41 | }
42 |
43 | listDebts() {
44 | let debtsList = [];
45 | if ( !debts.length ) {
46 | return (No debts!);
47 | }
48 | debts.map( ( debt, index ) => {
49 | debtsList.push( );
50 | } );
51 | return debtsList;
52 | }
53 |
54 | render() {
55 | return (
56 |
57 |
Debts:
58 |
59 | { this.listDebts() }
60 |
61 |
64 |
Settle debts with cash or Venmo.
65 |
66 | );
67 | }
68 | }
69 |
70 | export default Debts;
71 |
--------------------------------------------------------------------------------
/components/Logger.js:
--------------------------------------------------------------------------------
1 |
2 | 'use strict';
3 |
4 | import React from 'react';
5 |
6 | class Logger extends React.Component {
7 | componentWillMount() {
8 | console.log('Logger logging!!');
9 | }
10 | }
11 |
12 | export default Logger;
13 |
--------------------------------------------------------------------------------
/components/Pot.js:
--------------------------------------------------------------------------------
1 |
2 | 'use strict';
3 |
4 | import React from 'react';
5 |
6 | let ordinalAbbrev = ( ordinal ) => {
7 | if ( ordinal === 1 ) {
8 | return 'st';
9 | } else if ( ordinal === 2 ) {
10 | return 'nd';
11 | } else if ( ordinal === 3 ) {
12 | return 'rd';
13 | } else {
14 | return 'th';
15 | }
16 | }
17 |
18 | class Pot extends React.Component {
19 | constructor() {
20 | this.state = { pot: 0 };
21 | }
22 |
23 | registerBuyIn( modifier ) {
24 | if ( this.state.pot + modifier * this.props.buyIn < 0 ) {
25 | return;
26 | }
27 | this.setState( { pot: this.state.pot + modifier * this.props.buyIn } );
28 | }
29 |
30 | render() {
31 | return (
32 |
33 |
Pot:
34 |
35 | { this.props.payouts( this.state.pot ).map( ( payout, index ) => {
36 | return (
37 |
38 |
{ index + 1 }{ ordinalAbbrev( index + 1) }:
39 |
${ payout }
40 |
41 |
42 | );
43 | } ) }
44 |
45 |
46 |
Pot:
47 |
${ this.state.pot }
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | );
56 | }
57 | }
58 |
59 | export default Pot;
60 |
--------------------------------------------------------------------------------
/components/Timer.js:
--------------------------------------------------------------------------------
1 |
2 | 'use strict';
3 |
4 | import React from 'react';
5 |
6 | class Timer extends React.Component {
7 | constructor(props) {
8 | this.state = { secondsLeft: props.startingTime };
9 | this.tickInterval;
10 |
11 | this.resetTimer = this.resetTimer.bind( this );
12 | this.tick = this.tick.bind( this );
13 | this.play = this.play.bind( this );
14 | this.pause = this.pause.bind( this );
15 | }
16 |
17 | resetTimer() {
18 | this.setState( { secondsLeft: this.props.startingTime } );
19 | this.play();
20 | }
21 |
22 | tick() {
23 | let nextSecondsLeft = this.state.secondsLeft - 1;
24 | if ( nextSecondsLeft === 0 ) {
25 | this.resetTimer();
26 | window.dispatchEvent( new Event( 'blinds-up' ) );
27 | }
28 | this.setState( { secondsLeft: this.state.secondsLeft - 1 } );
29 | }
30 |
31 | play() {
32 | this.pause();
33 | this.tickInterval = setInterval( this.tick, 1000 );
34 | }
35 |
36 | pause() {
37 | clearInterval( this.tickInterval );
38 | }
39 |
40 | displayTime( secondsLeft ) {
41 | let displayMinutes = Math.floor( secondsLeft / 60 );
42 | let displaySeconds = ( secondsLeft % 60 ) < 10 ? '0' + secondsLeft % 60 : secondsLeft % 60;
43 | return displayMinutes + ':' + displaySeconds;
44 | }
45 |
46 | render() {
47 | return (
48 |
49 |
Blinds raise in:
50 |
{ this.displayTime( this.state.secondsLeft ) }
51 |
52 |
53 |
54 |
55 |
56 |
57 | );
58 | }
59 | }
60 |
61 | export default Timer;
62 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Poker Simulator
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-poker",
3 | "version": "0.0.1",
4 | "description": "A React component simulating a Texas holdem tournament game",
5 | "main": "app.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "license": "MIT",
10 | "devDependencies": {
11 | "babel-core": "^4.7.16",
12 | "babel-loader": "^4.2.0",
13 | "babel-runtime": "^5.0.0-beta1",
14 | "normalize.css": "^3.0.3",
15 | "webpack": "^1.7.3"
16 | },
17 | "dependencies": {
18 | "react": "^0.13.1"
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/react-poker-screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/pattern/react-poker/aabcbb2c944166285216c783a91be13fdd516fb4/react-poker-screenshot.png
--------------------------------------------------------------------------------
/style.css:
--------------------------------------------------------------------------------
1 |
2 | /* General */
3 |
4 | ul { list-style-type: none; margin: 0; padding: 0; }
5 | ol { margin: 0; margin-left: 23px; padding: 0; }
6 | ol li { padding: 3px 0; }
7 |
8 | button {
9 | padding: 6px 10px 5px 10px;
10 | margin-right: 20px;
11 | background: #4479BA;
12 | color: #FFF;
13 | -webkit-border-radius: 4px;
14 | -moz-border-radius: 4px;
15 | border-radius: 4px;
16 | border: solid 1px #20538D;
17 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.4);
18 | -webkit-user-select:none;
19 | -moz-user-select:none;
20 | -ms-user-select:none;
21 | user-select:none;
22 | }
23 | button:hover {
24 | background: #356094;
25 | border: solid 1px #2A4E77;
26 | text-decoration: none;
27 | }
28 | button:active {
29 | -webkit-box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.6);
30 | -moz-box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.6);
31 | box-shadow: inset 0 1px 4px rgba(0, 0, 0, 0.6);
32 | background: #2E5481;
33 | border: solid 1px #203E5F;
34 | }
35 |
36 | button:focus { outline:0; }
37 |
38 | /* App / Containers */
39 |
40 | .container { width: 1000px; margin-left: auto; margin-right: auto; }
41 | .orange-bg { background-color: #ff5800; margin-bottom: 40px; }
42 | .header { color: #fff; font-size: 20px; padding-top: 15px; padding-bottom: 15px; }
43 | .col1 { float: left; width: 250px; }
44 | .col2 { float: left; width: 550px; }
45 | .col3 { float: left; width: 200px; }
46 | .clear-both { clear: both; }
47 | .poker-title { margin: 0; -webkit-margin-before: 0; -webkit-margin-after: 0; }
48 |
49 | body.flashing {
50 | -webkit-animation-name: flashing; /* Chrome, Safari, Opera */
51 | -webkit-animation-duration: 1.5s; /* Chrome, Safari, Opera */
52 | animation-name: flashing;
53 | animation-duration: 1.5s;
54 | }
55 |
56 | /* Chrome, Safari, Opera */
57 | @-webkit-keyframes flashing {
58 | 0% { background-color:red; }
59 | 25% { background-color:yellow; }
60 | 50% { background-color:blue; }
61 | 75% { background-color:green; }
62 | 100% { background-color:red; }
63 | }
64 |
65 | /* Standard syntax */
66 | @keyframes flashing {
67 | 0% { background-color:red; }
68 | 25% { background-color:yellow; }
69 | 50% { background-color:blue; }
70 | 75% { background-color:green; }
71 | 100% { background-color:red; }
72 | }
73 |
74 |
75 | /* Timer */
76 |
77 | .current-time { font-size: 200px; margin-top: 50px; margin-bottom: 30px; }
78 | .timer .buttons { margin-left: 50px; }
79 |
80 |
81 | /* Clock */
82 |
83 | .clock { margin-top: 6px; }
84 |
85 |
86 | /* Blinds */
87 |
88 | li.active { font-weight: bold; color: #ff5800; }
89 | .current-blinds { margin-bottom: 30px; }
90 | .current-blinds li:first-child { margin-bottom: 3px;}
91 | .current-blinds li:nth-child(2) { font-size: 40px; }
92 | .blinds-list { margin-bottom: 30px; }
93 | .blinds-list li { margin: 7px 0;}
94 |
95 | /* Debts */
96 |
97 | .debts { margin-top: 80px; }
98 | .debts li { cursor: pointer; }
99 | li.paid { color: #999; text-decoration: line-through; }
100 | .debts input { margin-top: 15px; margin-bottom: 10px; }
101 | .settle { font-size: 12px; color: #999; }
102 | .no-debts { color: #999; }
103 |
104 | /* Pot */
105 |
106 | .designation { float: left; width: 60px; }
107 | .payouts > div { margin-bottom: 10px; }
108 | .payout { font-size: 20px; }
109 | .payout div:first-child { float: left; width: 60px; }
110 | .payout div:nth-child(2) { float: left; width: 60px; font-weight: bold; }
111 | .pot .buttons { margin-top: 20px; }
112 |
113 |
--------------------------------------------------------------------------------
/variables.js:
--------------------------------------------------------------------------------
1 |
2 | 'use strict';
3 |
4 | export const buyIn = 20;
5 |
6 | export const startingSeconds = 15 * 60;
7 |
8 | export const smallBlinds = [ 100, 200, 300, 400, 500, 800, 1000, 1500, 2000, 3000, 5000];
9 |
10 | export function payouts( pot ) {
11 | return [ pot * 0.5, pot * 0.3, pot * 0.2 ];
12 | }
13 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 |
2 | 'use strict';
3 |
4 | module.exports = {
5 | entry: './app.js',
6 |
7 | output: {
8 | path: __dirname,
9 | filename: 'bundle.js'
10 | },
11 |
12 | module: {
13 | loaders: [
14 | {
15 | test: /\.js$/,
16 | exclude: /node_modules/,
17 | loaders: [ 'babel-loader?experimental' ]
18 | }
19 | ]
20 | }
21 | };
22 |
--------------------------------------------------------------------------------