SRPT

by Sam Fereday

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/phaser/2.6.2/custom/phaser-arcade-physics.min.js"></script>
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/recompose/0.26.0/Recompose.min.js"></script>
<div id="container"></div>

CSS

/*
* Skeleton V2.0.4
* Copyright 2014, Dave Gamache
* www.getskeleton.com
* Free to use under the MIT license.
* http://www.opensource.org/licenses/mit-license.php
* 12/29/2014
*/


/* Table of contents
––––––––––––––––––––––––––––––––––––––––––––––––––
- Grid
- Base Styles
- Typography
- Links
- Buttons
- Forms
- Lists
- Code
- Tables
- Spacing
- Utilities
- Clearing
- Media Queries
*/


/* Grid
–––––––––––––––––––––––––––––––––––––––––––––––––– */

.container {
  position: relative;
  width: 100%;
  max-width: 960px;
  margin: 0 auto;
  padding: 0 20px;
  box-sizing: border-box;
}

.column,
.columns {
  width: 100%;
  float: left;
  box-sizing: border-box;
}


/* For devices larger than 400px */

@media (min-width: 400px) {
  .container {
    width: 85%;
    padding: 0;
  }
}


/* For devices larger than 550px */

@media (min-width: 550px) {
  .container {
    width: 80%;
  }
  .column,
  .columns {
    margin-left: 4%;
  }
  .column:first-child,
  .columns:first-child {
    margin-left: 0;
  }
  .one.column,
  .one.columns {
    width: 4.66666666667%;
  }
  .two.columns {
    width: 13.3333333333%;
  }
  .three.columns {
    width: 22%;
  }
  .four.columns {
    width: 30.6666666667%;
  }
  .five.columns {
    width: 39.3333333333%;
  }
  .six.columns {
    width: 48%;
  }
  .seven.columns {
    width: 56.6666666667%;
  }
  .eight.columns {
    width: 65.3333333333%;
  }
  .nine.columns {
    width: 74.0%;
  }
  .ten.columns {
    width: 82.6666666667%;
  }
  .eleven.columns {
    width: 91.3333333333%;
  }
  .twelve.columns {
    width: 100%;
    margin-left: 0;
  }
  .one-third.column {
    width: 30.6666666667%;
  }
  .two-thirds.column {
    width: 65.3333333333%;
  }
  .one-half.column {
    width: 48%;
  }
  /* Offsets */
  .offset-by-one.column,
  .offset-by-one.columns {
    margin-left: 8.66666666667%;
  }
  .offset-by-two.column,
  .offset-by-two.columns {
    margin-left: 17.3333333333%;
  }
  .offset-by-three.column,
  .offset-by-three.columns {
  ...

Babel + JSX

// DATA AREA
// Default location is anywhere that isn't found in locations list, and its coordinates can be generated
// when the ship has left warp. 0 is just a placeholder.
const DEFAULT_LOCATION = {
  id: 'unknown',
  x: 0,
  y: 0,
  meta: {
    name: 'Unknown Quadrant'
  }
};

// Assume light years for now :P
const LOCATIONS = [{
  id: 'loc-1',
  x: 100,
  y: 2,
  meta: {
    name: 'Erebus Terminal'
  }
}, {
  id: 'loc-2',
  x: 1,
  y: 5,
  meta: {
    name: 'Novis Alpha'
  }
}, {
  id: 'loc-3',
  x: 200,
  y: 300,
  meta: {
    name: 'Heliuos Prime'
  }
}];

// UTILS
const findLocationById = (id, arr) => {
  return arr.find(x => x.id === id);
};

const distanceApprox = (p1, p2) => {
  // https://gist.github.com/aurbano/4693462
  const x = p2.x - p1.x;
  const y = p2.y - p1.y;
  return 1.426776695 * Math.min(0.7071067812 * (Math.abs(x) + Math.abs(y)), Math.max(Math.abs(x), Math.abs(y)));
};

// EVENTS GLOBAL
class Events {

	constructor()
  {
  	this.events = [];
  	this.subscribers = [];
  }
  
  getEventById(id) {
  	return this.events.find(ev => ev === id);
  }
  
  subscribe(id, cb) {
  	if(this.subscribers.some(x => x.id === id)) {
    	return;
    }
    this.subscribers.push({
    	id, cb
    });
  }
  
  add(id) {
  	if(this.getEventById(id)) {
    	return;
    }
  	this.events.push(id);
  }
  
  trigger(eventId, ...args) {
    const ev = this.getEventById(eventId);
    const subscribed = this.subscribers.filter(sub => sub.id === ev);
    for(let i = 0; i < subscribed.length; i++) {
    	let { cb, ctx } = subscribed[i];
      if(typeof cb === 'function') {
      	cb(...args);
      }
    }
  }

}

const events = new Events();

// REACT UI AREA
const { compose, withState, withHandlers, lifecycle } = Recompose;

const AppComponent = ({
	locations,
  nextLocationId,
  currentLocationId,
  onHandleChange,
  onTravelRequest
}) => {
	return (
  [
    <select onChange={onHandleChange}>
      {locations && locations.length &&
        locations.map(({id, meta:...