JSFiddle - React, Tailwind, and code Playground

by lchau

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.3/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/redux/3.6.0/redux.min.js"></script>
<div id='container'>
  <div class='right'>
    <span id='correct'></span> / <span id='total'></span> (<span id='percentage'></span>%)
  </div>
  <div id='letter'></div>
  <div>
    <input id='input' size=20>
    <button id='next'>next</button>
  </div>
</div>
<div id='distribution'></div>

CSS

body {
  font-family: Monaco;
  font-size: 12px;
}

.right {
  float: right;
}



#letter {
  text-align: center;
  font-size: 18px;
  padding: 20px;
}

#container {
  border: 1px solid black;
  width: 300px;
}

#input {
  display: flex;
}

Babel + JSX

// imports
// const _ = require('lodash');
const { 
  applyMiddleware, 
  compose, 
  combineReducers,
  createStore 
} = Redux;

const KeyCode = Object.freeze({
  ENTER: 13
});

const sample = (collection) => {
	const clone = _.chain(collection)
  	.cloneDeep()
  	.shuffle()
    .value();

	return () => clone.pop();
};

// Utility classes
class NATO {
  static get ALPHABET() {
    return Object.freeze({
      A: 'alpha',
      B: 'bravo',
      C: 'charlie',
      D: 'delta',
      E: 'echo',
      F: 'foxtrot',
      G: 'golf',
      H: 'hotel',
      I: 'india',
      J: 'juliet',
      K: 'kilo',
      L: 'lima',
      M: 'mike',
      N: 'november',
      O: 'oscar',
      P: 'papa',
      Q: 'quebec',
      R: 'romeo',
      S: 'sierra',
      T: 'tango',
      U: 'uniform',
      V: 'victor',
      W: 'whiskey',
      X: 'xray',
      Y: 'yankee',
      Z: 'zulu'
    });
  }

  static match(str, letter) {
    const word = NATO.ALPHABET[letter];
    if (word) {
      return String(str).toLowerCase() === word;  
    }
    return false;
  }

  // move to state store?
  static createDistribution() {
    return _.reduce(NATO.ALPHABET, (accumulator, value, key) => {
      accumulator[key] = 0;
      return accumulator;
    }, {});
  }

  static nextLetter(distribution) {
  	if (!this.cache) {
	  	this.cache = sample(NATO.ALPHABET);
    }
    const ch = this.cache().charAt(0).toUpperCase();
    if (_.isPlainObject(distribution)) {
      distribution[ch] = distribution[ch] || 0;
      distribution[ch]++; 
    }
    return ch;
  }
}

// Actions


// Initialization
const store = createStore(combineReducers({

}));


const DISTRIBUTION = NATO.createDistribution();

const $input = document.getElementById('input');
const $correct = document.getElementById('correct');
const $total = document.getElementById('total');
const $letter = document.getElementById('letter');
const $distribution = document.getElementById('distribution');
const $output =...