Initial commit
This commit is contained in:
parent
feb91c8122
commit
2577d56f90
4
.babelrc
4
.babelrc
|
@ -1,4 +1,4 @@
|
||||||
{
|
{
|
||||||
"presets": ["es2015", "react"],
|
"presets": ["react"],
|
||||||
"plugins": ["transform-object-rest-spread", "transform-flow-strip-types"]
|
"plugins": ["transform-es2015-modules-commonjs", "transform-object-rest-spread", "transform-flow-strip-types"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1 @@
|
||||||
[ignore]
|
[ignore]
|
||||||
.*/node_modules/fbjs/*
|
|
||||||
.*/node_modules/react-motion/*
|
|
|
@ -2,12 +2,10 @@
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<title>Shell game</title>
|
<title>Title</title>
|
||||||
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
|
</head>
|
||||||
</head>
|
|
||||||
<body>
|
<body>
|
||||||
<div id="react-shell-game"></div>
|
|
||||||
</body>
|
|
||||||
|
|
||||||
<script src="./shell-game.bundle.js"></script>
|
</body>
|
||||||
|
<script src="test.bundle.js"></script>
|
||||||
</html>
|
</html>
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,587 @@
|
||||||
|
/******/ (function(modules) { // webpackBootstrap
|
||||||
|
/******/ var parentHotUpdateCallback = this["webpackHotUpdate"];
|
||||||
|
/******/ this["webpackHotUpdate"] = function webpackHotUpdateCallback(chunkId, moreModules) { // eslint-disable-line no-unused-vars
|
||||||
|
/******/ hotAddUpdateChunk(chunkId, moreModules);
|
||||||
|
/******/ if(parentHotUpdateCallback) parentHotUpdateCallback(chunkId, moreModules);
|
||||||
|
/******/ }
|
||||||
|
|
||||||
|
/******/ function hotDownloadUpdateChunk(chunkId) { // eslint-disable-line no-unused-vars
|
||||||
|
/******/ var head = document.getElementsByTagName("head")[0];
|
||||||
|
/******/ var script = document.createElement("script");
|
||||||
|
/******/ script.type = "text/javascript";
|
||||||
|
/******/ script.charset = "utf-8";
|
||||||
|
/******/ script.src = __webpack_require__.p + "" + chunkId + "." + hotCurrentHash + ".hot-update.js";
|
||||||
|
/******/ head.appendChild(script);
|
||||||
|
/******/ }
|
||||||
|
|
||||||
|
/******/ function hotDownloadManifest(callback) { // eslint-disable-line no-unused-vars
|
||||||
|
/******/ if(typeof XMLHttpRequest === "undefined")
|
||||||
|
/******/ return callback(new Error("No browser support"));
|
||||||
|
/******/ try {
|
||||||
|
/******/ var request = new XMLHttpRequest();
|
||||||
|
/******/ var requestPath = __webpack_require__.p + "" + hotCurrentHash + ".hot-update.json";
|
||||||
|
/******/ request.open("GET", requestPath, true);
|
||||||
|
/******/ request.timeout = 10000;
|
||||||
|
/******/ request.send(null);
|
||||||
|
/******/ } catch(err) {
|
||||||
|
/******/ return callback(err);
|
||||||
|
/******/ }
|
||||||
|
/******/ request.onreadystatechange = function() {
|
||||||
|
/******/ if(request.readyState !== 4) return;
|
||||||
|
/******/ if(request.status === 0) {
|
||||||
|
/******/ // timeout
|
||||||
|
/******/ callback(new Error("Manifest request to " + requestPath + " timed out."));
|
||||||
|
/******/ } else if(request.status === 404) {
|
||||||
|
/******/ // no update available
|
||||||
|
/******/ callback();
|
||||||
|
/******/ } else if(request.status !== 200 && request.status !== 304) {
|
||||||
|
/******/ // other failure
|
||||||
|
/******/ callback(new Error("Manifest request to " + requestPath + " failed."));
|
||||||
|
/******/ } else {
|
||||||
|
/******/ // success
|
||||||
|
/******/ try {
|
||||||
|
/******/ var update = JSON.parse(request.responseText);
|
||||||
|
/******/ } catch(e) {
|
||||||
|
/******/ callback(e);
|
||||||
|
/******/ return;
|
||||||
|
/******/ }
|
||||||
|
/******/ callback(null, update);
|
||||||
|
/******/ }
|
||||||
|
/******/ };
|
||||||
|
/******/ }
|
||||||
|
|
||||||
|
|
||||||
|
/******/ // Copied from https://github.com/facebook/react/blob/bef45b0/src/shared/utils/canDefineProperty.js
|
||||||
|
/******/ var canDefineProperty = false;
|
||||||
|
/******/ try {
|
||||||
|
/******/ Object.defineProperty({}, "x", {
|
||||||
|
/******/ get: function() {}
|
||||||
|
/******/ });
|
||||||
|
/******/ canDefineProperty = true;
|
||||||
|
/******/ } catch(x) {
|
||||||
|
/******/ // IE will fail on defineProperty
|
||||||
|
/******/ }
|
||||||
|
|
||||||
|
/******/ var hotApplyOnUpdate = true;
|
||||||
|
/******/ var hotCurrentHash = "1bc1531991c33fda3a04"; // eslint-disable-line no-unused-vars
|
||||||
|
/******/ var hotCurrentModuleData = {};
|
||||||
|
/******/ var hotCurrentParents = []; // eslint-disable-line no-unused-vars
|
||||||
|
|
||||||
|
/******/ function hotCreateRequire(moduleId) { // eslint-disable-line no-unused-vars
|
||||||
|
/******/ var me = installedModules[moduleId];
|
||||||
|
/******/ if(!me) return __webpack_require__;
|
||||||
|
/******/ var fn = function(request) {
|
||||||
|
/******/ if(me.hot.active) {
|
||||||
|
/******/ if(installedModules[request]) {
|
||||||
|
/******/ if(installedModules[request].parents.indexOf(moduleId) < 0)
|
||||||
|
/******/ installedModules[request].parents.push(moduleId);
|
||||||
|
/******/ if(me.children.indexOf(request) < 0)
|
||||||
|
/******/ me.children.push(request);
|
||||||
|
/******/ } else hotCurrentParents = [moduleId];
|
||||||
|
/******/ } else {
|
||||||
|
/******/ console.warn("[HMR] unexpected require(" + request + ") from disposed module " + moduleId);
|
||||||
|
/******/ hotCurrentParents = [];
|
||||||
|
/******/ }
|
||||||
|
/******/ return __webpack_require__(request);
|
||||||
|
/******/ };
|
||||||
|
/******/ for(var name in __webpack_require__) {
|
||||||
|
/******/ if(Object.prototype.hasOwnProperty.call(__webpack_require__, name)) {
|
||||||
|
/******/ if(canDefineProperty) {
|
||||||
|
/******/ Object.defineProperty(fn, name, (function(name) {
|
||||||
|
/******/ return {
|
||||||
|
/******/ configurable: true,
|
||||||
|
/******/ enumerable: true,
|
||||||
|
/******/ get: function() {
|
||||||
|
/******/ return __webpack_require__[name];
|
||||||
|
/******/ },
|
||||||
|
/******/ set: function(value) {
|
||||||
|
/******/ __webpack_require__[name] = value;
|
||||||
|
/******/ }
|
||||||
|
/******/ };
|
||||||
|
/******/ }(name)));
|
||||||
|
/******/ } else {
|
||||||
|
/******/ fn[name] = __webpack_require__[name];
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
|
||||||
|
/******/ function ensure(chunkId, callback) {
|
||||||
|
/******/ if(hotStatus === "ready")
|
||||||
|
/******/ hotSetStatus("prepare");
|
||||||
|
/******/ hotChunksLoading++;
|
||||||
|
/******/ __webpack_require__.e(chunkId, function() {
|
||||||
|
/******/ try {
|
||||||
|
/******/ callback.call(null, fn);
|
||||||
|
/******/ } finally {
|
||||||
|
/******/ finishChunkLoading();
|
||||||
|
/******/ }
|
||||||
|
|
||||||
|
/******/ function finishChunkLoading() {
|
||||||
|
/******/ hotChunksLoading--;
|
||||||
|
/******/ if(hotStatus === "prepare") {
|
||||||
|
/******/ if(!hotWaitingFilesMap[chunkId]) {
|
||||||
|
/******/ hotEnsureUpdateChunk(chunkId);
|
||||||
|
/******/ }
|
||||||
|
/******/ if(hotChunksLoading === 0 && hotWaitingFiles === 0) {
|
||||||
|
/******/ hotUpdateDownloaded();
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
/******/ });
|
||||||
|
/******/ }
|
||||||
|
/******/ if(canDefineProperty) {
|
||||||
|
/******/ Object.defineProperty(fn, "e", {
|
||||||
|
/******/ enumerable: true,
|
||||||
|
/******/ value: ensure
|
||||||
|
/******/ });
|
||||||
|
/******/ } else {
|
||||||
|
/******/ fn.e = ensure;
|
||||||
|
/******/ }
|
||||||
|
/******/ return fn;
|
||||||
|
/******/ }
|
||||||
|
|
||||||
|
/******/ function hotCreateModule(moduleId) { // eslint-disable-line no-unused-vars
|
||||||
|
/******/ var hot = {
|
||||||
|
/******/ // private stuff
|
||||||
|
/******/ _acceptedDependencies: {},
|
||||||
|
/******/ _declinedDependencies: {},
|
||||||
|
/******/ _selfAccepted: false,
|
||||||
|
/******/ _selfDeclined: false,
|
||||||
|
/******/ _disposeHandlers: [],
|
||||||
|
|
||||||
|
/******/ // Module API
|
||||||
|
/******/ active: true,
|
||||||
|
/******/ accept: function(dep, callback) {
|
||||||
|
/******/ if(typeof dep === "undefined")
|
||||||
|
/******/ hot._selfAccepted = true;
|
||||||
|
/******/ else if(typeof dep === "function")
|
||||||
|
/******/ hot._selfAccepted = dep;
|
||||||
|
/******/ else if(typeof dep === "object")
|
||||||
|
/******/ for(var i = 0; i < dep.length; i++)
|
||||||
|
/******/ hot._acceptedDependencies[dep[i]] = callback;
|
||||||
|
/******/ else
|
||||||
|
/******/ hot._acceptedDependencies[dep] = callback;
|
||||||
|
/******/ },
|
||||||
|
/******/ decline: function(dep) {
|
||||||
|
/******/ if(typeof dep === "undefined")
|
||||||
|
/******/ hot._selfDeclined = true;
|
||||||
|
/******/ else if(typeof dep === "number")
|
||||||
|
/******/ hot._declinedDependencies[dep] = true;
|
||||||
|
/******/ else
|
||||||
|
/******/ for(var i = 0; i < dep.length; i++)
|
||||||
|
/******/ hot._declinedDependencies[dep[i]] = true;
|
||||||
|
/******/ },
|
||||||
|
/******/ dispose: function(callback) {
|
||||||
|
/******/ hot._disposeHandlers.push(callback);
|
||||||
|
/******/ },
|
||||||
|
/******/ addDisposeHandler: function(callback) {
|
||||||
|
/******/ hot._disposeHandlers.push(callback);
|
||||||
|
/******/ },
|
||||||
|
/******/ removeDisposeHandler: function(callback) {
|
||||||
|
/******/ var idx = hot._disposeHandlers.indexOf(callback);
|
||||||
|
/******/ if(idx >= 0) hot._disposeHandlers.splice(idx, 1);
|
||||||
|
/******/ },
|
||||||
|
|
||||||
|
/******/ // Management API
|
||||||
|
/******/ check: hotCheck,
|
||||||
|
/******/ apply: hotApply,
|
||||||
|
/******/ status: function(l) {
|
||||||
|
/******/ if(!l) return hotStatus;
|
||||||
|
/******/ hotStatusHandlers.push(l);
|
||||||
|
/******/ },
|
||||||
|
/******/ addStatusHandler: function(l) {
|
||||||
|
/******/ hotStatusHandlers.push(l);
|
||||||
|
/******/ },
|
||||||
|
/******/ removeStatusHandler: function(l) {
|
||||||
|
/******/ var idx = hotStatusHandlers.indexOf(l);
|
||||||
|
/******/ if(idx >= 0) hotStatusHandlers.splice(idx, 1);
|
||||||
|
/******/ },
|
||||||
|
|
||||||
|
/******/ //inherit from previous dispose call
|
||||||
|
/******/ data: hotCurrentModuleData[moduleId]
|
||||||
|
/******/ };
|
||||||
|
/******/ return hot;
|
||||||
|
/******/ }
|
||||||
|
|
||||||
|
/******/ var hotStatusHandlers = [];
|
||||||
|
/******/ var hotStatus = "idle";
|
||||||
|
|
||||||
|
/******/ function hotSetStatus(newStatus) {
|
||||||
|
/******/ hotStatus = newStatus;
|
||||||
|
/******/ for(var i = 0; i < hotStatusHandlers.length; i++)
|
||||||
|
/******/ hotStatusHandlers[i].call(null, newStatus);
|
||||||
|
/******/ }
|
||||||
|
|
||||||
|
/******/ // while downloading
|
||||||
|
/******/ var hotWaitingFiles = 0;
|
||||||
|
/******/ var hotChunksLoading = 0;
|
||||||
|
/******/ var hotWaitingFilesMap = {};
|
||||||
|
/******/ var hotRequestedFilesMap = {};
|
||||||
|
/******/ var hotAvailibleFilesMap = {};
|
||||||
|
/******/ var hotCallback;
|
||||||
|
|
||||||
|
/******/ // The update info
|
||||||
|
/******/ var hotUpdate, hotUpdateNewHash;
|
||||||
|
|
||||||
|
/******/ function toModuleId(id) {
|
||||||
|
/******/ var isNumber = (+id) + "" === id;
|
||||||
|
/******/ return isNumber ? +id : id;
|
||||||
|
/******/ }
|
||||||
|
|
||||||
|
/******/ function hotCheck(apply, callback) {
|
||||||
|
/******/ if(hotStatus !== "idle") throw new Error("check() is only allowed in idle status");
|
||||||
|
/******/ if(typeof apply === "function") {
|
||||||
|
/******/ hotApplyOnUpdate = false;
|
||||||
|
/******/ callback = apply;
|
||||||
|
/******/ } else {
|
||||||
|
/******/ hotApplyOnUpdate = apply;
|
||||||
|
/******/ callback = callback || function(err) {
|
||||||
|
/******/ if(err) throw err;
|
||||||
|
/******/ };
|
||||||
|
/******/ }
|
||||||
|
/******/ hotSetStatus("check");
|
||||||
|
/******/ hotDownloadManifest(function(err, update) {
|
||||||
|
/******/ if(err) return callback(err);
|
||||||
|
/******/ if(!update) {
|
||||||
|
/******/ hotSetStatus("idle");
|
||||||
|
/******/ callback(null, null);
|
||||||
|
/******/ return;
|
||||||
|
/******/ }
|
||||||
|
|
||||||
|
/******/ hotRequestedFilesMap = {};
|
||||||
|
/******/ hotAvailibleFilesMap = {};
|
||||||
|
/******/ hotWaitingFilesMap = {};
|
||||||
|
/******/ for(var i = 0; i < update.c.length; i++)
|
||||||
|
/******/ hotAvailibleFilesMap[update.c[i]] = true;
|
||||||
|
/******/ hotUpdateNewHash = update.h;
|
||||||
|
|
||||||
|
/******/ hotSetStatus("prepare");
|
||||||
|
/******/ hotCallback = callback;
|
||||||
|
/******/ hotUpdate = {};
|
||||||
|
/******/ var chunkId = 0;
|
||||||
|
/******/ { // eslint-disable-line no-lone-blocks
|
||||||
|
/******/ /*globals chunkId */
|
||||||
|
/******/ hotEnsureUpdateChunk(chunkId);
|
||||||
|
/******/ }
|
||||||
|
/******/ if(hotStatus === "prepare" && hotChunksLoading === 0 && hotWaitingFiles === 0) {
|
||||||
|
/******/ hotUpdateDownloaded();
|
||||||
|
/******/ }
|
||||||
|
/******/ });
|
||||||
|
/******/ }
|
||||||
|
|
||||||
|
/******/ function hotAddUpdateChunk(chunkId, moreModules) { // eslint-disable-line no-unused-vars
|
||||||
|
/******/ if(!hotAvailibleFilesMap[chunkId] || !hotRequestedFilesMap[chunkId])
|
||||||
|
/******/ return;
|
||||||
|
/******/ hotRequestedFilesMap[chunkId] = false;
|
||||||
|
/******/ for(var moduleId in moreModules) {
|
||||||
|
/******/ if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
|
||||||
|
/******/ hotUpdate[moduleId] = moreModules[moduleId];
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
/******/ if(--hotWaitingFiles === 0 && hotChunksLoading === 0) {
|
||||||
|
/******/ hotUpdateDownloaded();
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
|
||||||
|
/******/ function hotEnsureUpdateChunk(chunkId) {
|
||||||
|
/******/ if(!hotAvailibleFilesMap[chunkId]) {
|
||||||
|
/******/ hotWaitingFilesMap[chunkId] = true;
|
||||||
|
/******/ } else {
|
||||||
|
/******/ hotRequestedFilesMap[chunkId] = true;
|
||||||
|
/******/ hotWaitingFiles++;
|
||||||
|
/******/ hotDownloadUpdateChunk(chunkId);
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
|
||||||
|
/******/ function hotUpdateDownloaded() {
|
||||||
|
/******/ hotSetStatus("ready");
|
||||||
|
/******/ var callback = hotCallback;
|
||||||
|
/******/ hotCallback = null;
|
||||||
|
/******/ if(!callback) return;
|
||||||
|
/******/ if(hotApplyOnUpdate) {
|
||||||
|
/******/ hotApply(hotApplyOnUpdate, callback);
|
||||||
|
/******/ } else {
|
||||||
|
/******/ var outdatedModules = [];
|
||||||
|
/******/ for(var id in hotUpdate) {
|
||||||
|
/******/ if(Object.prototype.hasOwnProperty.call(hotUpdate, id)) {
|
||||||
|
/******/ outdatedModules.push(toModuleId(id));
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
/******/ callback(null, outdatedModules);
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
|
||||||
|
/******/ function hotApply(options, callback) {
|
||||||
|
/******/ if(hotStatus !== "ready") throw new Error("apply() is only allowed in ready status");
|
||||||
|
/******/ if(typeof options === "function") {
|
||||||
|
/******/ callback = options;
|
||||||
|
/******/ options = {};
|
||||||
|
/******/ } else if(options && typeof options === "object") {
|
||||||
|
/******/ callback = callback || function(err) {
|
||||||
|
/******/ if(err) throw err;
|
||||||
|
/******/ };
|
||||||
|
/******/ } else {
|
||||||
|
/******/ options = {};
|
||||||
|
/******/ callback = callback || function(err) {
|
||||||
|
/******/ if(err) throw err;
|
||||||
|
/******/ };
|
||||||
|
/******/ }
|
||||||
|
|
||||||
|
/******/ function getAffectedStuff(module) {
|
||||||
|
/******/ var outdatedModules = [module];
|
||||||
|
/******/ var outdatedDependencies = {};
|
||||||
|
|
||||||
|
/******/ var queue = outdatedModules.slice();
|
||||||
|
/******/ while(queue.length > 0) {
|
||||||
|
/******/ var moduleId = queue.pop();
|
||||||
|
/******/ var module = installedModules[moduleId];
|
||||||
|
/******/ if(!module || module.hot._selfAccepted)
|
||||||
|
/******/ continue;
|
||||||
|
/******/ if(module.hot._selfDeclined) {
|
||||||
|
/******/ return new Error("Aborted because of self decline: " + moduleId);
|
||||||
|
/******/ }
|
||||||
|
/******/ if(moduleId === 0) {
|
||||||
|
/******/ return;
|
||||||
|
/******/ }
|
||||||
|
/******/ for(var i = 0; i < module.parents.length; i++) {
|
||||||
|
/******/ var parentId = module.parents[i];
|
||||||
|
/******/ var parent = installedModules[parentId];
|
||||||
|
/******/ if(parent.hot._declinedDependencies[moduleId]) {
|
||||||
|
/******/ return new Error("Aborted because of declined dependency: " + moduleId + " in " + parentId);
|
||||||
|
/******/ }
|
||||||
|
/******/ if(outdatedModules.indexOf(parentId) >= 0) continue;
|
||||||
|
/******/ if(parent.hot._acceptedDependencies[moduleId]) {
|
||||||
|
/******/ if(!outdatedDependencies[parentId])
|
||||||
|
/******/ outdatedDependencies[parentId] = [];
|
||||||
|
/******/ addAllToSet(outdatedDependencies[parentId], [moduleId]);
|
||||||
|
/******/ continue;
|
||||||
|
/******/ }
|
||||||
|
/******/ delete outdatedDependencies[parentId];
|
||||||
|
/******/ outdatedModules.push(parentId);
|
||||||
|
/******/ queue.push(parentId);
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
|
||||||
|
/******/ return [outdatedModules, outdatedDependencies];
|
||||||
|
/******/ }
|
||||||
|
|
||||||
|
/******/ function addAllToSet(a, b) {
|
||||||
|
/******/ for(var i = 0; i < b.length; i++) {
|
||||||
|
/******/ var item = b[i];
|
||||||
|
/******/ if(a.indexOf(item) < 0)
|
||||||
|
/******/ a.push(item);
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
|
||||||
|
/******/ // at begin all updates modules are outdated
|
||||||
|
/******/ // the "outdated" status can propagate to parents if they don't accept the children
|
||||||
|
/******/ var outdatedDependencies = {};
|
||||||
|
/******/ var outdatedModules = [];
|
||||||
|
/******/ var appliedUpdate = {};
|
||||||
|
/******/ for(var id in hotUpdate) {
|
||||||
|
/******/ if(Object.prototype.hasOwnProperty.call(hotUpdate, id)) {
|
||||||
|
/******/ var moduleId = toModuleId(id);
|
||||||
|
/******/ var result = getAffectedStuff(moduleId);
|
||||||
|
/******/ if(!result) {
|
||||||
|
/******/ if(options.ignoreUnaccepted)
|
||||||
|
/******/ continue;
|
||||||
|
/******/ hotSetStatus("abort");
|
||||||
|
/******/ return callback(new Error("Aborted because " + moduleId + " is not accepted"));
|
||||||
|
/******/ }
|
||||||
|
/******/ if(result instanceof Error) {
|
||||||
|
/******/ hotSetStatus("abort");
|
||||||
|
/******/ return callback(result);
|
||||||
|
/******/ }
|
||||||
|
/******/ appliedUpdate[moduleId] = hotUpdate[moduleId];
|
||||||
|
/******/ addAllToSet(outdatedModules, result[0]);
|
||||||
|
/******/ for(var moduleId in result[1]) {
|
||||||
|
/******/ if(Object.prototype.hasOwnProperty.call(result[1], moduleId)) {
|
||||||
|
/******/ if(!outdatedDependencies[moduleId])
|
||||||
|
/******/ outdatedDependencies[moduleId] = [];
|
||||||
|
/******/ addAllToSet(outdatedDependencies[moduleId], result[1][moduleId]);
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
|
||||||
|
/******/ // Store self accepted outdated modules to require them later by the module system
|
||||||
|
/******/ var outdatedSelfAcceptedModules = [];
|
||||||
|
/******/ for(var i = 0; i < outdatedModules.length; i++) {
|
||||||
|
/******/ var moduleId = outdatedModules[i];
|
||||||
|
/******/ if(installedModules[moduleId] && installedModules[moduleId].hot._selfAccepted)
|
||||||
|
/******/ outdatedSelfAcceptedModules.push({
|
||||||
|
/******/ module: moduleId,
|
||||||
|
/******/ errorHandler: installedModules[moduleId].hot._selfAccepted
|
||||||
|
/******/ });
|
||||||
|
/******/ }
|
||||||
|
|
||||||
|
/******/ // Now in "dispose" phase
|
||||||
|
/******/ hotSetStatus("dispose");
|
||||||
|
/******/ var queue = outdatedModules.slice();
|
||||||
|
/******/ while(queue.length > 0) {
|
||||||
|
/******/ var moduleId = queue.pop();
|
||||||
|
/******/ var module = installedModules[moduleId];
|
||||||
|
/******/ if(!module) continue;
|
||||||
|
|
||||||
|
/******/ var data = {};
|
||||||
|
|
||||||
|
/******/ // Call dispose handlers
|
||||||
|
/******/ var disposeHandlers = module.hot._disposeHandlers;
|
||||||
|
/******/ for(var j = 0; j < disposeHandlers.length; j++) {
|
||||||
|
/******/ var cb = disposeHandlers[j];
|
||||||
|
/******/ cb(data);
|
||||||
|
/******/ }
|
||||||
|
/******/ hotCurrentModuleData[moduleId] = data;
|
||||||
|
|
||||||
|
/******/ // disable module (this disables requires from this module)
|
||||||
|
/******/ module.hot.active = false;
|
||||||
|
|
||||||
|
/******/ // remove module from cache
|
||||||
|
/******/ delete installedModules[moduleId];
|
||||||
|
|
||||||
|
/******/ // remove "parents" references from all children
|
||||||
|
/******/ for(var j = 0; j < module.children.length; j++) {
|
||||||
|
/******/ var child = installedModules[module.children[j]];
|
||||||
|
/******/ if(!child) continue;
|
||||||
|
/******/ var idx = child.parents.indexOf(moduleId);
|
||||||
|
/******/ if(idx >= 0) {
|
||||||
|
/******/ child.parents.splice(idx, 1);
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
|
||||||
|
/******/ // remove outdated dependency from module children
|
||||||
|
/******/ for(var moduleId in outdatedDependencies) {
|
||||||
|
/******/ if(Object.prototype.hasOwnProperty.call(outdatedDependencies, moduleId)) {
|
||||||
|
/******/ var module = installedModules[moduleId];
|
||||||
|
/******/ var moduleOutdatedDependencies = outdatedDependencies[moduleId];
|
||||||
|
/******/ for(var j = 0; j < moduleOutdatedDependencies.length; j++) {
|
||||||
|
/******/ var dependency = moduleOutdatedDependencies[j];
|
||||||
|
/******/ var idx = module.children.indexOf(dependency);
|
||||||
|
/******/ if(idx >= 0) module.children.splice(idx, 1);
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
|
||||||
|
/******/ // Not in "apply" phase
|
||||||
|
/******/ hotSetStatus("apply");
|
||||||
|
|
||||||
|
/******/ hotCurrentHash = hotUpdateNewHash;
|
||||||
|
|
||||||
|
/******/ // insert new code
|
||||||
|
/******/ for(var moduleId in appliedUpdate) {
|
||||||
|
/******/ if(Object.prototype.hasOwnProperty.call(appliedUpdate, moduleId)) {
|
||||||
|
/******/ modules[moduleId] = appliedUpdate[moduleId];
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
|
||||||
|
/******/ // call accept handlers
|
||||||
|
/******/ var error = null;
|
||||||
|
/******/ for(var moduleId in outdatedDependencies) {
|
||||||
|
/******/ if(Object.prototype.hasOwnProperty.call(outdatedDependencies, moduleId)) {
|
||||||
|
/******/ var module = installedModules[moduleId];
|
||||||
|
/******/ var moduleOutdatedDependencies = outdatedDependencies[moduleId];
|
||||||
|
/******/ var callbacks = [];
|
||||||
|
/******/ for(var i = 0; i < moduleOutdatedDependencies.length; i++) {
|
||||||
|
/******/ var dependency = moduleOutdatedDependencies[i];
|
||||||
|
/******/ var cb = module.hot._acceptedDependencies[dependency];
|
||||||
|
/******/ if(callbacks.indexOf(cb) >= 0) continue;
|
||||||
|
/******/ callbacks.push(cb);
|
||||||
|
/******/ }
|
||||||
|
/******/ for(var i = 0; i < callbacks.length; i++) {
|
||||||
|
/******/ var cb = callbacks[i];
|
||||||
|
/******/ try {
|
||||||
|
/******/ cb(outdatedDependencies);
|
||||||
|
/******/ } catch(err) {
|
||||||
|
/******/ if(!error)
|
||||||
|
/******/ error = err;
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
|
||||||
|
/******/ // Load self accepted modules
|
||||||
|
/******/ for(var i = 0; i < outdatedSelfAcceptedModules.length; i++) {
|
||||||
|
/******/ var item = outdatedSelfAcceptedModules[i];
|
||||||
|
/******/ var moduleId = item.module;
|
||||||
|
/******/ hotCurrentParents = [moduleId];
|
||||||
|
/******/ try {
|
||||||
|
/******/ __webpack_require__(moduleId);
|
||||||
|
/******/ } catch(err) {
|
||||||
|
/******/ if(typeof item.errorHandler === "function") {
|
||||||
|
/******/ try {
|
||||||
|
/******/ item.errorHandler(err);
|
||||||
|
/******/ } catch(err) {
|
||||||
|
/******/ if(!error)
|
||||||
|
/******/ error = err;
|
||||||
|
/******/ }
|
||||||
|
/******/ } else if(!error)
|
||||||
|
/******/ error = err;
|
||||||
|
/******/ }
|
||||||
|
/******/ }
|
||||||
|
|
||||||
|
/******/ // handle errors in accept handlers and self accepted module load
|
||||||
|
/******/ if(error) {
|
||||||
|
/******/ hotSetStatus("fail");
|
||||||
|
/******/ return callback(error);
|
||||||
|
/******/ }
|
||||||
|
|
||||||
|
/******/ hotSetStatus("idle");
|
||||||
|
/******/ callback(null, outdatedModules);
|
||||||
|
/******/ }
|
||||||
|
|
||||||
|
/******/ // The module cache
|
||||||
|
/******/ var installedModules = {};
|
||||||
|
|
||||||
|
/******/ // The require function
|
||||||
|
/******/ function __webpack_require__(moduleId) {
|
||||||
|
|
||||||
|
/******/ // Check if module is in cache
|
||||||
|
/******/ if(installedModules[moduleId])
|
||||||
|
/******/ return installedModules[moduleId].exports;
|
||||||
|
|
||||||
|
/******/ // Create a new module (and put it into the cache)
|
||||||
|
/******/ var module = installedModules[moduleId] = {
|
||||||
|
/******/ exports: {},
|
||||||
|
/******/ id: moduleId,
|
||||||
|
/******/ loaded: false,
|
||||||
|
/******/ hot: hotCreateModule(moduleId),
|
||||||
|
/******/ parents: hotCurrentParents,
|
||||||
|
/******/ children: []
|
||||||
|
/******/ };
|
||||||
|
|
||||||
|
/******/ // Execute the module function
|
||||||
|
/******/ modules[moduleId].call(module.exports, module, module.exports, hotCreateRequire(moduleId));
|
||||||
|
|
||||||
|
/******/ // Flag the module as loaded
|
||||||
|
/******/ module.loaded = true;
|
||||||
|
|
||||||
|
/******/ // Return the exports of the module
|
||||||
|
/******/ return module.exports;
|
||||||
|
/******/ }
|
||||||
|
|
||||||
|
|
||||||
|
/******/ // expose the modules object (__webpack_modules__)
|
||||||
|
/******/ __webpack_require__.m = modules;
|
||||||
|
|
||||||
|
/******/ // expose the module cache
|
||||||
|
/******/ __webpack_require__.c = installedModules;
|
||||||
|
|
||||||
|
/******/ // __webpack_public_path__
|
||||||
|
/******/ __webpack_require__.p = "";
|
||||||
|
|
||||||
|
/******/ // __webpack_hash__
|
||||||
|
/******/ __webpack_require__.h = function() { return hotCurrentHash; };
|
||||||
|
|
||||||
|
/******/ // Load entry module and return exports
|
||||||
|
/******/ return hotCreateRequire(0)(0);
|
||||||
|
/******/ })
|
||||||
|
/************************************************************************/
|
||||||
|
/******/ ([
|
||||||
|
/* 0 */
|
||||||
|
/***/ function(module, exports) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/***/ }
|
||||||
|
/******/ ]);
|
17
package.json
17
package.json
|
@ -5,17 +5,18 @@
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "webpack-dev-server --progress --content-base dist/",
|
"start": "webpack-dev-server --progress --content-base dist/",
|
||||||
"build": "webpack --progress --prod",
|
"build": "webpack --progress",
|
||||||
"test": "jest"
|
"test": "jest"
|
||||||
},
|
},
|
||||||
"author": "Kai Moseley",
|
"author": "Kai Moseley",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"babel-core": "^6.18.2",
|
||||||
"babel-eslint": "^6.1.2",
|
"babel-eslint": "^6.1.2",
|
||||||
"babel-loader": "^6.2.5",
|
"babel-loader": "^6.2.5",
|
||||||
|
"babel-plugin-transform-es2015-modules-commonjs": "^6.18.0",
|
||||||
"babel-plugin-transform-flow-strip-types": "^6.14.0",
|
"babel-plugin-transform-flow-strip-types": "^6.14.0",
|
||||||
"babel-plugin-transform-object-rest-spread": "^6.8.0",
|
"babel-plugin-transform-object-rest-spread": "^6.8.0",
|
||||||
"babel-preset-es2015": "^6.14.0",
|
|
||||||
"babel-preset-react": "^6.11.1",
|
"babel-preset-react": "^6.11.1",
|
||||||
"css-loader": "^0.24.0",
|
"css-loader": "^0.24.0",
|
||||||
"eslint": "^3.2.2",
|
"eslint": "^3.2.2",
|
||||||
|
@ -24,12 +25,14 @@
|
||||||
"eslint-plugin-flowtype": "^2.18.1",
|
"eslint-plugin-flowtype": "^2.18.1",
|
||||||
"eslint-plugin-react": "^6.0.0",
|
"eslint-plugin-react": "^6.0.0",
|
||||||
"node-sass": "^3.8.0",
|
"node-sass": "^3.8.0",
|
||||||
"react": "^15.3.1",
|
|
||||||
"react-dom": "^15.3.1",
|
|
||||||
"react-motion": "^0.4.4",
|
|
||||||
"sass-loader": "^4.0.0",
|
|
||||||
"style-loader": "^0.13.1",
|
|
||||||
"webpack": "^1.13.2",
|
"webpack": "^1.13.2",
|
||||||
"webpack-dev-server": "^1.16.1"
|
"webpack-dev-server": "^1.16.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"global": "^4.3.1",
|
||||||
|
"lodash": "^4.17.2",
|
||||||
|
"redux": "^3.6.0",
|
||||||
|
"webpack": "^1.13.3",
|
||||||
|
"webpack-dev-server": "^1.16.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
.board {
|
|
||||||
box-shadow: 0 0 3px 1px rgba(0,0,0,0.4);
|
|
||||||
background-color: #efefef;
|
|
||||||
margin: 0 auto 1rem;
|
|
||||||
text-align: center;
|
|
||||||
overflow: hidden;
|
|
||||||
height: 150px;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.play {
|
|
||||||
background-color: #295e80;
|
|
||||||
padding: 0.75rem 1rem;
|
|
||||||
color: #fff;
|
|
||||||
font-size: 1.2rem;
|
|
||||||
border: 1px solid #fff;
|
|
||||||
cursor: pointer;
|
|
||||||
box-shadow: 0 0 5px 0 rgba(0,0,0,0.7), inset 60px 0 50px -50px rgba(33, 199, 255, 0.48), inset -60px 0 50px -50px rgba(33, 199, 255, 0.48);
|
|
||||||
transition-property: box-shadow;
|
|
||||||
transition-duration: 350ms;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
box-shadow: 0 0 3px 0 rgba(0,0,0,0.7), inset 75px 0 50px -50px rgba(33, 199, 255, 0.48), inset -75px 0 50px -50px rgba(33, 199, 255, 0.48);
|
|
||||||
transition-property: box-shadow;
|
|
||||||
transition-duration: 350ms;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:disabled {
|
|
||||||
opacity: 0.5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.output {
|
|
||||||
border-top: 1px solid #295e80;
|
|
||||||
border-bottom: 1px solid #295e80;
|
|
||||||
padding: 1rem;
|
|
||||||
}
|
|
|
@ -1,42 +0,0 @@
|
||||||
//@flow
|
|
||||||
import React from 'react';
|
|
||||||
import { Shell as ShellComponent } from '../Shell';
|
|
||||||
import styles from './game.scss';
|
|
||||||
|
|
||||||
type Shell = {
|
|
||||||
id: number,
|
|
||||||
}
|
|
||||||
|
|
||||||
type GameProps = {
|
|
||||||
shells: Shell[],
|
|
||||||
shellClickHandler: (id: number) => void,
|
|
||||||
startGameClickHandler: () => void,
|
|
||||||
output: string,
|
|
||||||
ballShellId: number,
|
|
||||||
inProgress: boolean,
|
|
||||||
shuffled: boolean,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Game = (props: GameProps) => (
|
|
||||||
<div>
|
|
||||||
<div className={ styles.board } style={{ width: 10 + (props.shells.length * 110) }}>
|
|
||||||
{ props.shells.map((shell, idx) =>
|
|
||||||
<ShellComponent
|
|
||||||
key={ shell.id }
|
|
||||||
onClick={ () => props.shellClickHandler(shell.id) }
|
|
||||||
position={ 10 + (idx * 110) }
|
|
||||||
containsBall={ props.ballShellId === shell.id }
|
|
||||||
displayBall={ !props.shuffling && !props.shuffled }
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
className={ styles.play }
|
|
||||||
onClick={ props.startGameClickHandler }
|
|
||||||
disabled={ props.inProgress }
|
|
||||||
>
|
|
||||||
Play!
|
|
||||||
</button>
|
|
||||||
<p className={ styles.output }>{ props.output }</p>
|
|
||||||
</div>
|
|
||||||
);
|
|
|
@ -1,175 +0,0 @@
|
||||||
//@flow
|
|
||||||
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import {
|
|
||||||
createRandomNumberFn,
|
|
||||||
createShells,
|
|
||||||
randomizeArrayOrder,
|
|
||||||
} from '../utils/gameUtils';
|
|
||||||
import { Game } from './Game';
|
|
||||||
import { isEqual } from 'lodash';
|
|
||||||
|
|
||||||
//=====================
|
|
||||||
// Flow types
|
|
||||||
//=====================
|
|
||||||
type GameContainerState = {
|
|
||||||
ballShellId: number,
|
|
||||||
shells: Shell[],
|
|
||||||
output: string,
|
|
||||||
shuffleCount: number,
|
|
||||||
shuffled: boolean,
|
|
||||||
shuffling: boolean,
|
|
||||||
inProgress: boolean,
|
|
||||||
};
|
|
||||||
|
|
||||||
type GameContainerProps = {
|
|
||||||
numberOfShells: number,
|
|
||||||
shuffles: number,
|
|
||||||
};
|
|
||||||
|
|
||||||
type Shell = {
|
|
||||||
id: number,
|
|
||||||
};
|
|
||||||
|
|
||||||
//======================
|
|
||||||
// Game component
|
|
||||||
//======================
|
|
||||||
export class GameContainer extends Component {
|
|
||||||
//Flow types
|
|
||||||
state: GameContainerState;
|
|
||||||
props: GameContainerProps;
|
|
||||||
selectRandomShell: ?() => number;
|
|
||||||
shufflingTimeout: ?number;
|
|
||||||
_initializeGame: (numberOfShells: number) => void;
|
|
||||||
_startGame: () => void;
|
|
||||||
_setWinningShell: () => void;
|
|
||||||
_shellClickHandler: (shellId: number) => void;
|
|
||||||
_shuffleShells: () => Promise<boolean>;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this.state = {
|
|
||||||
ballShellId: 0,
|
|
||||||
shells: [],
|
|
||||||
inProgress: false,
|
|
||||||
shuffleCount: 0,
|
|
||||||
shuffled: false,
|
|
||||||
shuffling: false,
|
|
||||||
output: `Click on 'Play' to begin!`,
|
|
||||||
};
|
|
||||||
this.selectRandomShell = null;
|
|
||||||
this.shufflingTimeout = null;
|
|
||||||
|
|
||||||
//In general it's a good idea to bind methods which refer to this in the
|
|
||||||
//constructor. It means, amongst other things, that the functions can be
|
|
||||||
//used as direct event handlers rather than wrapping them in a function.
|
|
||||||
this._initializeGame = this._initializeGame.bind(this);
|
|
||||||
this._startGame = this._startGame.bind(this);
|
|
||||||
this._setWinningShell = this._setWinningShell.bind(this);
|
|
||||||
this._shellClickHandler = this._shellClickHandler.bind(this);
|
|
||||||
this._shuffleShells = this._shuffleShells.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
_initializeGame(numberOfShells: number): void {
|
|
||||||
//This is designed to initialize the game whenever the component first mounts, or
|
|
||||||
//whenever a new set of options are passed in via props.
|
|
||||||
this.setState({
|
|
||||||
ballShellId: 0,
|
|
||||||
shells: createShells(numberOfShells),
|
|
||||||
output: `Click on 'Play' to begin!`,
|
|
||||||
shuffleCount: 0,
|
|
||||||
shuffling: false,
|
|
||||||
shuffled: false,
|
|
||||||
inProgress: false,
|
|
||||||
});
|
|
||||||
this.selectRandomShell = createRandomNumberFn(0, numberOfShells - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
_startGame(): void {
|
|
||||||
this._setWinningShell();
|
|
||||||
this.setState({
|
|
||||||
inProgress: true,
|
|
||||||
shuffleCount: 0,
|
|
||||||
output: 'Keep an eye on the ball!',
|
|
||||||
shuffling: false,
|
|
||||||
shuffled: false,
|
|
||||||
});
|
|
||||||
setTimeout(() => this._shuffleShells().then(() =>
|
|
||||||
this.setState({
|
|
||||||
output: 'Pick a shell!',
|
|
||||||
})), 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
_setWinningShell(): void {
|
|
||||||
//Randomly determine the winning shell (this is the shell which has the ball at the beginning of a round)
|
|
||||||
if (!this.selectRandomShell) throw new Error('selectRandomShell not properly initialized!');
|
|
||||||
this.setState({
|
|
||||||
ballShellId: this.selectRandomShell(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
_shellClickHandler(shellId: number): void {
|
|
||||||
//We only need to check if the shell is a winning shell if it is in progress and has been shuffled
|
|
||||||
if (!this.state.inProgress) return this.setState({ output: `Click on 'Play' to begin!`});
|
|
||||||
if (this.state.shuffling) return this.setState({ output: `Wait a second, I'm still shuffling!`});
|
|
||||||
this.setState({
|
|
||||||
output: this.state.ballShellId === shellId ? `You won! Click 'Play' to play again` : `Better luck next time! Click 'Play' to play again`,
|
|
||||||
inProgress: false,
|
|
||||||
shuffled: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
_shuffleShells(): Promise<boolean> {
|
|
||||||
//Shuffle the shells in a time based loop (the animation functionality uses springs, so there's no strict timer
|
|
||||||
//on how long the animation plays for).
|
|
||||||
this.setState({
|
|
||||||
shuffling: true,
|
|
||||||
output: 'Shuffling...',
|
|
||||||
});
|
|
||||||
|
|
||||||
//Return a promise as this is an async operation
|
|
||||||
return new Promise(res => {
|
|
||||||
const shuffle = () => {
|
|
||||||
const shuffleCount = this.state.shuffleCount + 1;
|
|
||||||
this.setState({
|
|
||||||
shells: randomizeArrayOrder(this.state.shells),
|
|
||||||
shuffled: shuffleCount == this.props.shuffles,
|
|
||||||
shuffleCount,
|
|
||||||
shuffling: shuffleCount < this.props.shuffles,
|
|
||||||
});
|
|
||||||
if (this.state.shuffled) return res(true);
|
|
||||||
this.shufflingTimeout = setTimeout(shuffle, 1000);
|
|
||||||
};
|
|
||||||
this.shufflingTimeout = setTimeout(shuffle, 1000);
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillMount() {
|
|
||||||
this._initializeGame(this.props.numberOfShells);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillReceiveProps(newProps: GameContainerProps) {
|
|
||||||
if(!isEqual(newProps, this.props)) {
|
|
||||||
//If the input properties change mid shuffle, cancel the shuffling function
|
|
||||||
if (this.shufflingTimeout) clearTimeout(this.shufflingTimeout);
|
|
||||||
this._initializeGame(newProps.numberOfShells);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<Game
|
|
||||||
shells={ this.state.shells }
|
|
||||||
output={ this.state.output }
|
|
||||||
ballShellId={ this.state.ballShellId }
|
|
||||||
inProgress={ this.state.inProgress }
|
|
||||||
shuffling={ this.state.shuffling }
|
|
||||||
shuffled={ this.state.shuffled }
|
|
||||||
shellClickHandler={ this._shellClickHandler }
|
|
||||||
startGameClickHandler={ this._startGame }
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
//@flow
|
|
||||||
import React from 'react';
|
|
||||||
import styles from './options.scss';
|
|
||||||
|
|
||||||
type OptionsProps = {
|
|
||||||
numberOfShells: number,
|
|
||||||
shuffles: number,
|
|
||||||
onInputChange: (event: Object) => void,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Options = (props: OptionsProps) => (
|
|
||||||
<div>
|
|
||||||
<div className={ styles.input }>
|
|
||||||
<label htmlFor="numberOfShells">Number of shells: </label>
|
|
||||||
<select
|
|
||||||
name="numberOfShells"
|
|
||||||
value={ props.numberOfShells }
|
|
||||||
onChange={ props.onInputChange }
|
|
||||||
>
|
|
||||||
<option value={3}>3</option>
|
|
||||||
<option value={4}>4</option>
|
|
||||||
<option value={5}>5</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div className={ styles.input }>
|
|
||||||
<label htmlFor="shuffles">Number of shuffles: </label>
|
|
||||||
<select
|
|
||||||
name="shuffles"
|
|
||||||
value={ props.shuffles }
|
|
||||||
onChange={ props.onInputChange }
|
|
||||||
>
|
|
||||||
<option value={3}>3</option>
|
|
||||||
<option value={5}>5</option>
|
|
||||||
<option value={7}>7</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
|
@ -1,9 +0,0 @@
|
||||||
.input {
|
|
||||||
|
|
||||||
margin-bottom: 1rem;
|
|
||||||
|
|
||||||
select {
|
|
||||||
margin-left: 0.5rem;
|
|
||||||
font-size: 1.2rem;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
//@flow
|
|
||||||
import React from 'react';
|
|
||||||
import styles from './shell.scss';
|
|
||||||
import { Motion, spring } from 'react-motion';
|
|
||||||
|
|
||||||
type ShellProps = {
|
|
||||||
onClick: () => void,
|
|
||||||
position: number,
|
|
||||||
containsBall: boolean,
|
|
||||||
displayBall: boolean,
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Shell = (props: ShellProps) =>
|
|
||||||
<Motion style={{x: spring(props.position, { stiffness: 276, damping: 26 })}}>
|
|
||||||
{ ({ x }) => (
|
|
||||||
<div>
|
|
||||||
<div
|
|
||||||
style={ {
|
|
||||||
left: x
|
|
||||||
} }
|
|
||||||
className={ styles.shell }
|
|
||||||
onClick={ props.onClick }
|
|
||||||
>
|
|
||||||
{ props.containsBall && props.displayBall &&
|
|
||||||
<div className={ styles.ball } /> }
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</Motion>;
|
|
||||||
|
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
.shell {
|
|
||||||
background-color: #295e80;
|
|
||||||
box-shadow: 0 0 3px 1px rgba(0, 0, 0, 0.4), inset 0 60px 50px -50px rgba(33, 199, 255, 0.48), inset 0 -60px 50px -50px rgba(33, 199, 255, 0.48);
|
|
||||||
height: 100px;
|
|
||||||
width: 100px;
|
|
||||||
display: inline-block;
|
|
||||||
transition: 350ms;
|
|
||||||
cursor: pointer;
|
|
||||||
position: absolute;
|
|
||||||
top: 25px;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
box-shadow: 0 0 3px 1px rgba(0, 0, 0, 0.4), inset 0 90px 50px -50px rgba(33, 199, 255, 0.48), inset 0 -90px 50px -50px rgba(33, 199, 255, 0.48);
|
|
||||||
transition: 350ms;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.ball {
|
|
||||||
background-color: #b00000;
|
|
||||||
height: 50px;
|
|
||||||
width: 50px;
|
|
||||||
border-radius: 25px;
|
|
||||||
box-shadow: 0 0 10px 3px rgba(0,0,0,0.4), inset 0 0 20px 2px rgba(255,255,255,0.4);
|
|
||||||
position: absolute;
|
|
||||||
top: 25px;
|
|
||||||
left: 25px
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
//@flow
|
|
||||||
import React from 'react';
|
|
||||||
import { GameContainer } from '../GameContainer';
|
|
||||||
import { Options } from '../Options';
|
|
||||||
import styles from './shellGameApp.scss';
|
|
||||||
|
|
||||||
type ShellGameAppProps = {
|
|
||||||
numberOfShells: number,
|
|
||||||
shuffles: number,
|
|
||||||
onInputChange: (event: Object) => void,
|
|
||||||
};
|
|
||||||
|
|
||||||
export const ShellGameApp = (props: ShellGameAppProps) => (
|
|
||||||
<div className={ styles.app }>
|
|
||||||
<h1>The game of shells</h1>
|
|
||||||
<GameContainer
|
|
||||||
numberOfShells={ props.numberOfShells }
|
|
||||||
shuffles={ props.shuffles }
|
|
||||||
/>
|
|
||||||
<Options
|
|
||||||
numberOfShells={ props.numberOfShells }
|
|
||||||
shuffles={ props.shuffles }
|
|
||||||
onInputChange={ props.onInputChange }
|
|
||||||
/>
|
|
||||||
<p className={ styles.info }>Built using React, and React-motion for the shuffling animations.</p>
|
|
||||||
</div>
|
|
||||||
);
|
|
|
@ -1,13 +0,0 @@
|
||||||
.app {
|
|
||||||
font-family: 'Roboto', sans-serif;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 1.2rem;
|
|
||||||
width: 700px;
|
|
||||||
margin: 5rem auto;
|
|
||||||
box-shadow: 0 0 3px 1px rgba(0,0,0,0.4);
|
|
||||||
padding: 1.5rem 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.info {
|
|
||||||
font-size: 0.9rem;
|
|
||||||
}
|
|
|
@ -1,40 +0,0 @@
|
||||||
//@flow
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import { ShellGameApp } from './ShellGameApp';
|
|
||||||
|
|
||||||
type ShellGameAppContainerState = {
|
|
||||||
numberOfShells: number,
|
|
||||||
shuffles: number,
|
|
||||||
}
|
|
||||||
|
|
||||||
export class ShellGameAppContainer extends Component {
|
|
||||||
state: ShellGameAppContainerState;
|
|
||||||
_handleInputUpdate: (event: Object) => void;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
this.state = {
|
|
||||||
numberOfShells: 3,
|
|
||||||
shuffles: 5,
|
|
||||||
};
|
|
||||||
this._handleInputUpdate = this._handleInputUpdate.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
//Simple form handler (takes the name and value of an input and adds it to the state if preset).
|
|
||||||
_handleInputUpdate(e: Object): void {
|
|
||||||
if (!this.state.hasOwnProperty(e.target.name)) throw new Error('Form input name should be on the GameShellAppContainer state');
|
|
||||||
this.setState({
|
|
||||||
[e.target.name]: e.target.value,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<ShellGameApp
|
|
||||||
numberOfShells={ this.state.numberOfShells }
|
|
||||||
shuffles={ this.state.shuffles }
|
|
||||||
onInputChange={ this._handleInputUpdate }
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
import { Game } from './Game';
|
|
||||||
import { GameContainer } from './GameContainer';
|
|
||||||
import { ShellGameApp } from './ShellGameApp';
|
|
||||||
import { ShellGameAppContainer } from './ShellGameAppContainer';
|
|
||||||
import { Shell } from './Shell';
|
|
||||||
import { Options } from './Options';
|
|
||||||
|
|
||||||
export {
|
|
||||||
Game,
|
|
||||||
GameContainer,
|
|
||||||
ShellGameApp,
|
|
||||||
ShellGameAppContainer,
|
|
||||||
Shell,
|
|
||||||
Options,
|
|
||||||
}
|
|
28
src/index.js
28
src/index.js
|
@ -1,9 +1,21 @@
|
||||||
//@flow
|
import { generateReducer } from './redux-arg/generateReducer';
|
||||||
import React from 'react';
|
import { createStore, compose } from 'redux';
|
||||||
import ReactDOM from 'react-dom';
|
|
||||||
import { ShellGameAppContainer } from './components';
|
const config = {
|
||||||
|
anObject: {
|
||||||
|
lowerLevelStuff: '',
|
||||||
|
moreLowerLevelStuff: '',
|
||||||
|
},
|
||||||
|
anotherObject: {
|
||||||
|
more: '',
|
||||||
|
andAgain: '',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
createStore(
|
||||||
|
generateReducer(config),
|
||||||
|
compose(window.devToolsExtension ? window.devToolsExtension() : f => f)
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ReactDOM.render(
|
|
||||||
<ShellGameAppContainer />,
|
|
||||||
document.getElementById('react-shell-game'
|
|
||||||
));
|
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
//@flow
|
||||||
|
import { combineReducers } from 'redux';
|
||||||
|
import { reduce } from 'lodash';
|
||||||
|
|
||||||
|
export function generateReducer(reducerMap: Object): (Object) => Object {
|
||||||
|
return combineReducers(reduce(reducerMap, (memo, propValue, propName) => ({
|
||||||
|
...memo,
|
||||||
|
[propName]: objectReducer(propValue),
|
||||||
|
}), reducerMap));
|
||||||
|
}
|
||||||
|
|
||||||
|
function objectReducer(initialState: Object): (Object) => (Object, Object) => Object {
|
||||||
|
return (state = initialState, { type } = {} ) => {
|
||||||
|
switch(type) {
|
||||||
|
case 'BLARG!':
|
||||||
|
return state;
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,38 +0,0 @@
|
||||||
//@flow
|
|
||||||
type Shell = {
|
|
||||||
id: number,
|
|
||||||
};
|
|
||||||
//======================
|
|
||||||
// Utility functions
|
|
||||||
//======================
|
|
||||||
//Generate a random number generator which will return values within a given range.
|
|
||||||
export function createRandomNumberFn(minimum: number, maximum: number): () => number {
|
|
||||||
return () => minimum + Math.floor(Math.random() * ((maximum-minimum) + 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//Create a randomized array based on an input array.
|
|
||||||
export function randomizeArrayOrder(array: []): [] {
|
|
||||||
let oldArray = [ ...array ];
|
|
||||||
let newArr = [];
|
|
||||||
|
|
||||||
while(oldArray.length) {
|
|
||||||
newArr = [...newArr, ...oldArray.splice(createRandomNumberFn(0, oldArray.length)(), 1)];
|
|
||||||
}
|
|
||||||
|
|
||||||
return newArr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export function createShells(numberOfShells: number): Shell[] {
|
|
||||||
/* The shell containing the ball will be tracked independently of shells, but
|
|
||||||
in order to properly keep track of components (particularly useful with certain animation libraries),
|
|
||||||
a fixed id is desirable. */
|
|
||||||
let newShellArr = [];
|
|
||||||
for (let i=0; i<numberOfShells; i++) {
|
|
||||||
newShellArr = [ ...newShellArr, {
|
|
||||||
id: i,
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
return newShellArr;
|
|
||||||
}
|
|
|
@ -4,21 +4,10 @@ const path = require('path');
|
||||||
const PATH_ESLINT = path.join(__dirname, '.eslintrc.js');
|
const PATH_ESLINT = path.join(__dirname, '.eslintrc.js');
|
||||||
const PATH_SRC = path.join(__dirname, 'src');
|
const PATH_SRC = path.join(__dirname, 'src');
|
||||||
|
|
||||||
const isProd = process.argv.indexOf('--prod') >= 0;
|
module.exports = {
|
||||||
const envPlugins = isProd ? [
|
|
||||||
new webpack.optimize.OccurrenceOrderPlugin(true),
|
|
||||||
new webpack.optimize.DedupePlugin(),
|
|
||||||
new webpack.optimize.UglifyJsPlugin({
|
|
||||||
compress: { warnings: false, unused: true, dead_code: true },
|
|
||||||
output: { comments: false }
|
|
||||||
}),
|
|
||||||
] : [];
|
|
||||||
const envOptions = isProd ? {} : { devtool: 'inline-source-map' };
|
|
||||||
|
|
||||||
module.exports = Object.assign(envOptions, {
|
|
||||||
context: __dirname,
|
context: __dirname,
|
||||||
entry: {
|
entry: {
|
||||||
'shell-game': PATH_SRC
|
'test': PATH_SRC
|
||||||
},
|
},
|
||||||
devServer: {
|
devServer: {
|
||||||
inline: true,
|
inline: true,
|
||||||
|
@ -38,18 +27,6 @@ module.exports = Object.assign(envOptions, {
|
||||||
exclude: [],
|
exclude: [],
|
||||||
loader: "babel-loader",
|
loader: "babel-loader",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
test: /\.css$/,
|
|
||||||
loaders: ['style', 'css', 'sass']
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.scss$/,
|
|
||||||
loaders: [
|
|
||||||
'style',
|
|
||||||
'css?modules&importLoaders=1&localIdentName=[path]___[name]__[local]___[hash:base64:5]',
|
|
||||||
'sass'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
preLoaders: [ { test: /\.js$/, include: [PATH_SRC], loader: 'eslint-loader' } ]
|
preLoaders: [ { test: /\.js$/, include: [PATH_SRC], loader: 'eslint-loader' } ]
|
||||||
},
|
},
|
||||||
|
@ -60,7 +37,6 @@ module.exports = Object.assign(envOptions, {
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
...envPlugins,
|
|
||||||
function () {
|
function () {
|
||||||
this.plugin('done', () =>
|
this.plugin('done', () =>
|
||||||
setTimeout(() => console.log('\nFinished at ' + (new Date).toLocaleTimeString() + '\n'), 10)
|
setTimeout(() => console.log('\nFinished at ' + (new Date).toLocaleTimeString() + '\n'), 10)
|
||||||
|
@ -68,4 +44,4 @@ module.exports = Object.assign(envOptions, {
|
||||||
},
|
},
|
||||||
new webpack.HotModuleReplacementPlugin(),
|
new webpack.HotModuleReplacementPlugin(),
|
||||||
]
|
]
|
||||||
});
|
};
|
Loading…
Reference in New Issue