Building components for battle centre

This commit is contained in:
Cmdr McDonald
2017-03-10 17:17:37 +00:00
parent ec0cd37896
commit 6f67267fec
11 changed files with 846 additions and 19 deletions

View File

@@ -0,0 +1,98 @@
import React from 'react';
import TranslatedComponent from './TranslatedComponent';
import { Ships } from 'coriolis-data/dist';
import Slider from '../components/Slider';
import Pips from '../components/Pips';
import Fuel from '../components/Fuel';
import Cargo from '../components/Cargo';
import EngagementRange from '../components/EngagementRange';
/**
* Battle centre allows you to pit your current build against another ship,
* adjust pips and engagement range, and see a wide variety of information
*/
export default class BattleCentre extends TranslatedComponent {
static PropTypes = {
ship: React.PropTypes.object.isRequired
};
static DEFAULT_OPPONENT = { ship: Ships['anaconda'] };
/**
* Constructor
* @param {Object} props React Component properties
* @param {Object} context React Component context
*/
constructor(props, context) {
super(props);
const { ship } = this.props;
const opponent = BattleCentre.DEFAULT_OPPONENT;
this.state = { };
}
componentWillReceiveProps(nextProps) {
// Rather than try to keep track of what changes our children require we force an update and let them work it out
this.forceUpdate();
return true;
}
/**
* Triggered when pips have been updated
*/
_pipsUpdated(sys, eng, wep) {
console.log('Pips are now ' + sys + '/' + eng + '/' + wep);
}
/**
* Triggered when fuel has been updated
*/
_fuelUpdated(fuel) {
console.log('Fuel is now ' + fuel);
}
/**
* Triggered when cargo has been updated
*/
_cargoUpdated(cargo) {
console.log('Cargo is now ' + cargo);
}
/**
* Triggered when engagement range has been updated
*/
_engagementRangeUpdated(engagementRange) {
console.log('Engagement range is now ' + engagementRange);
}
/**
* Render
* @return {React.Component} contents
*/
render() {
const { language, onWindowResize, sizeRatio, tooltip, termtip } = this.context;
const { formats, translate, units } = language;
const { against, expanded, maxRange, range, totals } = this.state;
const { ship } = this.props;
const shipUpdated = this._shipUpdated;
const pipsUpdated = this._pipsUpdated;
const fuelUpdated = this._fuelUpdated;
const cargoUpdated = this._cargoUpdated;
const engagementRangeUpdated = this._engagementRangeUpdated;
return (
<span>
<h1>{translate('battle centre')}</h1>
<div className='group third'>
<Pips ship={ship} onChange={pipsUpdated}/>
</div>
<div className='group twothirds'>
<Fuel ship={ship} onChange={fuelUpdated}/>
<Cargo ship={ship} onChange={cargoUpdated}/>
<EngagementRange ship={ship} onChange={engagementRangeUpdated}/>
</div>
</span>
);
}
}

View File

@@ -0,0 +1,102 @@
import React from 'react';
import TranslatedComponent from './TranslatedComponent';
import { Ships } from 'coriolis-data/dist';
import Slider from '../components/Slider';
/**
* Cargo slider
* Requires an onChange() function of the form onChange(cargo), providing the cargo in tonnes, which is triggered on cargo level change
*/
export default class Cargo extends TranslatedComponent {
static PropTypes = {
ship: React.PropTypes.object.isRequired,
onChange: React.PropTypes.func.isRequired
};
/**
* Constructor
* @param {Object} props React Component properties
* @param {Object} context React Component context
*/
constructor(props, context) {
super(props);
const ship = this.props.ship;
this.state = {
cargoCapacity: ship.cargoCapacity,
cargoLevel: 1,
};
}
/**
* Update the state if our ship changes
* @param {Object} nextProps Incoming/Next properties
* @return {boolean} Returns true if the component should be rerendered
*/
componentWillReceiveProps(nextProps) {
const { cargoLevel, cargoCapacity } = this.state;
const nextCargoCapacity = nextProps.ship.cargoCapacity;
if (nextCargoCapacity != cargoCapacity) {
// We keep the absolute cargo amount the same if possible so recalculate the relative level
const nextCargoLevel = Math.min((cargoLevel * cargoCapacity) / nextCargoCapacity, 1);
this.setState({ cargoLevel: nextCargoLevel, cargoCapacity: nextCargoCapacity });
// Notify if appropriate
if (nextCargoLevel * nextCargoCapacity != cargoLevel * cargoCapacity) {
this.props.onChange(Math.round(nextCargoLevel * nextCargoCapacity));
}
}
return true;
}
/**
* Update cargo level
* @param {number} cargoLevel percentage level from 0 to 1
*/
_cargoChange(cargoLevel) {
const { cargoCapacity } = this.state;
// We round the cargo level to a suitable value given the capacity
cargoLevel = Math.round(cargoLevel * cargoCapacity) / cargoCapacity;
if (cargoLevel != this.state.cargoLevel) {
this.setState({ cargoLevel });
this.props.onChange(Math.round(cargoLevel * cargoCapacity));
}
}
/**
* Render cargo slider
* @return {React.Component} contents
*/
render() {
const { language, onWindowResize, sizeRatio, tooltip, termtip } = this.context;
const { formats, translate, units } = language;
const { cargoLevel, cargoCapacity } = this.state;
return (
<span>
<h3>{translate('cargo carried')}: {formats.int(cargoLevel * cargoCapacity)}{units.T}</h3>
<table style={{ width: '100%', lineHeight: '1em', backgroundColor: 'transparent' }}>
<tbody >
<tr>
<td>
<Slider
axis={true}
onChange={this._cargoChange.bind(this)}
axisUnit={translate('T')}
percent={cargoLevel}
max={cargoCapacity}
scale={sizeRatio}
onResize={onWindowResize}
/>
</td>
</tr>
</tbody>
</table>
</span>
);
}
}

View File

@@ -0,0 +1,123 @@
import React from 'react';
import TranslatedComponent from './TranslatedComponent';
import { Ships } from 'coriolis-data/dist';
import Slider from '../components/Slider';
/**
* Engagement range slider
* Requires an onChange() function of the form onChange(range), providing the range in metres, which is triggered on range change
*/
export default class Range extends TranslatedComponent {
static PropTypes = {
ship: React.PropTypes.object.isRequired,
onChange: React.PropTypes.func.isRequired
};
/**
* Constructor
* @param {Object} props React Component properties
* @param {Object} context React Component context
*/
constructor(props, context) {
super(props);
const ship = this.props.ship;
const maxRange = this._calcMaxRange(ship);
this.state = {
maxRange: maxRange,
rangeLevel: 1,
};
}
/**
* Update the state if our ship changes
* @param {Object} nextProps Incoming/Next properties
* @return {boolean} Returns true if the component should be rerendered
*/
componentWillReceiveProps(nextProps) {
const { rangeLevel, maxRange } = this.state;
const nextMaxRange = this._calcMaxRange(nextProps.ship);
if (nextMaxRange != maxRange) {
// We keep the absolute range amount the same if possible so recalculate the relative level
const nextRangeLevel = Math.min((rangeLevel * maxRange) / nextMaxRange, 1);
this.setState({ rangeLevel: nextRangeLevel, maxRange: nextMaxRange });
// Notify if appropriate
if (nextRangeLevel * nextMaxRange != rangeLevel * maxRange) {
this.props.onChange(Math.round(nextRangeLevel * nextMaxRange));
}
}
return true;
}
/**
* Calculate the maximum range of a ship's weapons
* @param {Object} ship The ship
* @returns {int} The maximum range, in metres
*/
_calcMaxRange(ship) {
let maxRange = 1000;
for (let i = 0; i < ship.hardpoints.length; i++) {
if (ship.hardpoints[i].maxClass > 0 && ship.hardpoints[i].m && ship.hardpoints[i].enabled) {
const thisRange = ship.hardpoints[i].m.getRange();
if (thisRange > maxRange) {
maxRange = thisRange;
}
}
}
return maxRange;
}
/**
* Update range
* @param {number} range percentage level from 0 to 1
*/
_rangeChange(rangeLevel) {
const { maxRange } = this.state;
// We round the range to an integer value
rangeLevel = Math.round(rangeLevel * maxRange) / maxRange;
if (rangeLevel != this.state.rangeLevel) {
this.setState({ rangeLevel });
this.props.onChange(Math.round(rangeLevel * maxRange));
}
}
/**
* Render range slider
* @return {React.Component} contents
*/
render() {
const { language, onWindowResize, sizeRatio, tooltip, termtip } = this.context;
const { formats, translate, units } = language;
const { rangeLevel, maxRange } = this.state;
return (
<span>
<h3>{translate('engagement range')}: {formats.int(rangeLevel * maxRange)}{translate('m')}</h3>
<table style={{ width: '100%', lineHeight: '1em', backgroundColor: 'transparent' }}>
<tbody >
<tr>
<td>
<Slider
axis={true}
onChange={this._rangeChange.bind(this)}
axisUnit={translate('m')}
percent={rangeLevel}
max={maxRange}
scale={sizeRatio}
onResize={onWindowResize}
/>
</td>
</tr>
</tbody>
</table>
</span>
);
}
}

View File

@@ -0,0 +1,96 @@
import React from 'react';
import TranslatedComponent from './TranslatedComponent';
import { Ships } from 'coriolis-data/dist';
import Slider from '../components/Slider';
/**
* Fuel slider
* Requires an onChange() function of the form onChange(fuel), providing the fuel in tonnes, which is triggered on fuel level change
*/
export default class Fuel extends TranslatedComponent {
static PropTypes = {
ship: React.PropTypes.object.isRequired,
onChange: React.PropTypes.func.isRequired
};
/**
* Constructor
* @param {Object} props React Component properties
* @param {Object} context React Component context
*/
constructor(props, context) {
super(props);
const ship = this.props.ship;
this.state = {
fuelCapacity: ship.fuelCapacity,
fuelLevel: 1,
};
}
/**
* Update the state if our ship changes
* @param {Object} nextProps Incoming/Next properties
* @return {boolean} Returns true if the component should be rerendered
*/
componentWillReceiveProps(nextProps) {
const { fuelLevel, fuelCapacity } = this.state;
const nextFuelCapacity = nextProps.ship.fuelCapacity;
if (nextFuelCapacity != fuelCapacity) {
// We keep the absolute fuel amount the same if possible so recalculate the relative level
const nextFuelLevel = Math.min((fuelLevel * fuelCapacity) / nextFuelCapacity, 1);
this.setState({ fuelLevel: nextFuelLevel, fuelCapacity: nextFuelCapacity });
// Notify if appropriate
if (nextFuelLevel * nextFuelCapacity != fuelLevel * fuelCapacity) {
this.props.onChange(nextFuelLevel * nextFuelCapacity);
}
}
return true;
}
/**
* Update fuel level
* @param {number} fuelLevel percentage level from 0 to 1
*/
_fuelChange(fuelLevel) {
this.setState({ fuelLevel });
this.props.onChange(fuelLevel * this.state.fuelCapacity);
}
/**
* Render fuel slider
* @return {React.Component} contents
*/
render() {
const { language, onWindowResize, sizeRatio, tooltip, termtip } = this.context;
const { formats, translate, units } = language;
const { fuelLevel, fuelCapacity } = this.state;
return (
<span>
<h3>{translate('fuel carried')}: {formats.f2(fuelLevel * fuelCapacity)}{units.T}</h3>
<table style={{ width: '100%', lineHeight: '1em', backgroundColor: 'transparent' }}>
<tbody >
<tr>
<td>
<Slider
axis={true}
onChange={this._fuelChange.bind(this)}
axisUnit={translate('T')}
percent={fuelLevel}
max={fuelCapacity}
scale={sizeRatio}
onResize={onWindowResize}
/>
</td>
</tr>
</tbody>
</table>
</span>
);
}
}

358
src/app/components/Pips.jsx Normal file
View File

@@ -0,0 +1,358 @@
import React from 'react';
import TranslatedComponent from './TranslatedComponent';
import { Ships } from 'coriolis-data/dist';
import ShipSelector from './ShipSelector';
import { nameComparator } from '../utils/SlotFunctions';
import { Pip } from './SvgIcons';
import LineChart from '../components/LineChart';
import Slider from '../components/Slider';
import * as ModuleUtils from '../shipyard/ModuleUtils';
import Module from '../shipyard/Module';
/**
* Pips displays SYS/ENG/WEP pips and allows users to change them with key presses by clicking on the relevant area.
* Requires an onChange() function of the form onChange(sys, eng, wep) which is triggered whenever the pips change.
*/
export default class Pips extends TranslatedComponent {
static PropTypes = {
ship: React.PropTypes.object.isRequired,
onChange: React.PropTypes.func.isRequired
};
/**
* Constructor
* @param {Object} props React Component properties
* @param {Object} context React Component context
*/
constructor(props, context) {
super(props);
const ship = props.ship;
const pd = ship.standard[4].m;
this._keyDown = this._keyDown.bind(this);
let pipsSvg = this._renderPips(2, 2, 2);
this.state = {
sys: 2,
eng: 2,
wep: 2,
sysCap: pd.getSystemsCapacity(),
engCap: pd.getEnginesCapacity(),
wepCap: pd.getWeaponsCapacity(),
sysRate: pd.getSystemsRechargeRate(),
engRate: pd.getEnginesRechargeRate(),
wepRate: pd.getWeaponsRechargeRate(),
pipsSvg
};
}
/**
* Add listeners after mounting
*/
componentDidMount() {
document.addEventListener('keydown', this._keyDown);
}
/**
* Remove listeners before unmounting
*/
componentWillUnmount() {
document.removeEventListener('keydown', this._keyDown);
}
/**
* Update values if we change ship
* @param {Object} nextProps Incoming/Next properties
* @returns {boolean} Returns true if the component should be rerendered
*/
componentWillReceiveProps(nextProps) {
const { sysCap, engCap, wepCap, sysRate, engRate, wepRate } = this.state;
const ship = nextProps.ship;
const pd = ship.standard[4].m;
const nextSysCap = pd.getSystemsCapacity();
const nextEngCap = pd.getEnginesCapacity();
const nextWepCap = pd.getWeaponsCapacity();
const nextSysRate = pd.getSystemsRechargeRate();
const nextEngRate = pd.getEnginesRechargeRate();
const nextWepRate = pd.getWeaponsRechargeRate();
if (nextSysCap != sysCap ||
nextEngCap != engCap ||
nextWepCap != wepCap ||
nextSysRate != sysRate ||
nextEngRate != engRate ||
nextWepRate != wepRate) {
this.setState({
sysCap: nextSysCap,
engCap: nextEngCap,
wepCap: nextWepCap,
sysRate: nextSysRate,
engRate: nextEngRate,
wepRate: nextWepRate
});
}
return true;
}
/**
* Handle Key Down
* @param {Event} e Keyboard Event
*/
_keyDown(e) {
switch (e.keyCode) {
case 37: // Left arrow == increase SYS
e.preventDefault();
this._incSys();
break;
case 38: // Up arrow == increase ENG
e.preventDefault();
this._incEng();
break;
case 39: // Right arrow == increase WEP
e.preventDefault();
this._incWep();
break;
case 40: // Down arrow == reset
e.preventDefault();
this._reset();
break;
}
}
/**
* Reset the capacitor
*/
_reset() {
let { sys, eng, wep } = this.state;
if (sys != 2 || eng != 2 || wep != 2) {
sys = eng = wep = 2;
this.setState({ sys, eng, wep, pipsSvg: this._renderPips(sys, eng, wep) });
this.props.onChange(sys, eng, wep);
}
}
/**
* Increment the SYS capacitor
*/
_incSys() {
let { sys, eng, wep } = this.state;
const required = Math.min(1, 4 - sys);
if (required > 0) {
if (required == 0.5) {
// Take from whichever is larger
if (eng > wep) {
eng -= 0.5;
sys += 0.5;
} else {
wep -= 0.5;
sys += 0.5;
}
} else {
// Required is 1 - take from both if possible
if (eng == 0) {
wep -= 1;
sys += 1;
} else if (wep == 0) {
eng -= 1;
sys += 1;
} else {
eng -= 0.5;
wep -= 0.5;
sys += 1;
}
}
this.setState({ sys, eng, wep, pipsSvg: this._renderPips(sys, eng, wep) });
this.props.onChange(sys, eng, wep);
}
}
/**
* Increment the ENG capacitor
*/
_incEng() {
let { sys, eng, wep } = this.state;
const required = Math.min(1, 4 - eng);
if (required > 0) {
if (required == 0.5) {
// Take from whichever is larger
if (sys > wep) {
sys -= 0.5;
eng += 0.5;
} else {
wep -= 0.5;
eng += 0.5;
}
} else {
// Required is 1 - take from both if possible
if (sys == 0) {
wep -= 1;
eng += 1;
} else if (wep == 0) {
sys -= 1;
eng += 1;
} else {
sys -= 0.5;
wep -= 0.5;
eng += 1;
}
}
this.setState({ sys, eng, wep, pipsSvg: this._renderPips(sys, eng, wep) });
this.props.onChange(sys, eng, wep);
}
}
/**
* Increment the WEP capacitor
*/
_incWep() {
let { sys, eng, wep } = this.state;
const required = Math.min(1, 4 - wep);
if (required > 0) {
if (required == 0.5) {
// Take from whichever is larger
if (sys > eng) {
sys -= 0.5;
wep += 0.5;
} else {
eng -= 0.5;
wep += 0.5;
}
} else {
// Required is 1 - take from both if possible
if (sys == 0) {
eng -= 1;
wep += 1;
} else if (eng == 0) {
sys -= 1;
wep += 1;
} else {
sys -= 0.5;
eng -= 0.5;
wep += 1;
}
}
this.setState({ sys, eng, wep, pipsSvg: this._renderPips(sys, eng, wep) });
this.props.onChange(sys, eng, wep);
}
}
/**
* Handle a click
*/
onClick(which) {
if (which == 'SYS') {
this._incSys();
} else if (which == 'ENG') {
this._incEng();
} else if (which == 'WEP') {
this._incWep();
} else if (which == 'RST') {
this._reset();
}
}
/**
* Set up the rendering for pips
* @param {int} sys the SYS pips
* @param {int} eng the ENG pips
* @param {int} wep the WEP pips
* @returns {Object} Object containing the rendering for the pips
*/
_renderPips(sys, eng, wep) {
const pipsSvg = {};
// SYS
pipsSvg['SYS'] = [];
for (let i = 0; i < Math.floor(sys); i++) {
pipsSvg['SYS'].push(<Pip className='fullpip' key={i} />);
}
if (sys > Math.floor(sys)) {
pipsSvg['SYS'].push(<Pip className='halfpip' key={'half'} />);
}
for (let i = Math.floor(sys + 0.5); i < 4; i++) {
pipsSvg['SYS'].push(<Pip className='emptypip' key={i} />);
}
// ENG
pipsSvg['ENG'] = [];
for (let i = 0; i < Math.floor(eng); i++) {
pipsSvg['ENG'].push(<Pip className='fullpip' key={i} />);
}
if (eng > Math.floor(eng)) {
pipsSvg['ENG'].push(<Pip className='halfpip' key={'half'} />);
}
for (let i = Math.floor(eng + 0.5); i < 4; i++) {
pipsSvg['ENG'].push(<Pip className='emptypip' key={i} />);
}
// WEP
pipsSvg['WEP'] = [];
for (let i = 0; i < Math.floor(wep); i++) {
pipsSvg['WEP'].push(<Pip className='fullpip' key={i} />);
}
if (wep > Math.floor(wep)) {
pipsSvg['WEP'].push(<Pip className='halfpip' key={'half'} />);
}
for (let i = Math.floor(wep + 0.5); i < 4; i++) {
pipsSvg['WEP'].push(<Pip className='emptypip' key={i} />);
}
return pipsSvg;
}
/**
* Render pips
* @return {React.Component} contents
*/
render() {
const { formats, translate, units } = this.context.language;
const { ship } = this.props;
const { sys, eng, wep, sysCap, engCap, wepCap, sysRate, engRate, wepRate, pipsSvg } = this.state;
const onSysClicked = this.onClick.bind(this, 'SYS');
const onEngClicked = this.onClick.bind(this, 'ENG');
const onWepClicked = this.onClick.bind(this, 'WEP');
const onRstClicked = this.onClick.bind(this, 'RST');
return (
<table className='pipstable'>
<tbody>
<tr>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td className = 'pipsclickable' onClick={onEngClicked}>{pipsSvg['ENG']}</td>
<td>&nbsp;</td>
</tr>
<tr>
<td>&nbsp;</td>
<td className = 'pipsclickable' onClick={onSysClicked}>{pipsSvg['SYS']}</td>
<td className = 'pipsclickable' onClick={onEngClicked}>{translate('ENG')}</td>
<td className = 'pipsclickable' onClick={onWepClicked}>{pipsSvg['WEP']}</td>
</tr>
<tr>
<td>&nbsp;</td>
<td className = 'pipsclickable' onClick={onSysClicked}>{translate('SYS')}</td>
<td className = 'pipsclickable' onClick={onRstClicked}>{translate('RST')}</td>
<td className = 'pipsclickable' onClick={onWepClicked}>{translate('WEP')}</td>
</tr>
<tr>
<td>{translate('capacity')} ({units.MJ})</td>
<td>{formats.f1(sysCap)}</td>
<td>{formats.f1(engCap)}</td>
<td>{formats.f1(wepCap)}</td>
</tr>
<tr>
<td>{translate('recharge')} ({units.MW})</td>
<td>{formats.f1(sysRate * (sys / 4))}</td>
<td>{formats.f1(engRate * (eng / 4))}</td>
<td>{formats.f1(wepRate * (wep / 4))}</td>
</tr>
</tbody>
</table>
);
}
}

View File

@@ -708,6 +708,24 @@ export class Switch extends SvgIcon {
}
}
/**
* Pip
*/
export class Pip extends SvgIcon {
/**
* Overriden view box
* @return {String} view box
*/
viewBox() { return '0 0 200 200'; }
/**
* Generate the SVG
* @return {React.Component} SVG Contents
*/
svg() {
return <rect x='10' y='10' width='180' height='180'/>;
}
}
/**
* In-game Coriolis Station logo
*/

View File

@@ -58,21 +58,21 @@ export function getLanguage(langCode) {
},
translate,
units: {
CR: <u> {translate('CR')}</u>, // Credits
kg: <u> {translate('kg')}</u>, // Kilograms
kgs: <u> {translate('kg/s')}</u>, // Kilograms per second
km: <u> {translate('km')}</u>, // Kilometers
Ls: <u> {translate('Ls')}</u>, // Light Seconds
LY: <u> {translate('LY')}</u>, // Light Years
MJ: <u> {translate('MJ')}</u>, // Mega Joules
'm/s': <u> {translate('m/s')}</u>, // Meters per second
'°/s': <u> {translate('°/s')}</u>, // Degrees per second
MW: <u> {translate('MW')}</u>, // Mega Watts (same as Mega Joules per second)
CR: <u>{translate('CR')}</u>, // Credits
kg: <u>{translate('kg')}</u>, // Kilograms
kgs: <u>{translate('kg/s')}</u>, // Kilograms per second
km: <u>{translate('km')}</u>, // Kilometers
Ls: <u>{translate('Ls')}</u>, // Light Seconds
LY: <u>{translate('LY')}</u>, // Light Years
MJ: <u>{translate('MJ')}</u>, // Mega Joules
'm/s': <u>{translate('m/s')}</u>, // Meters per second
'°/s': <u>{translate('°/s')}</u>, // Degrees per second
MW: <u>{translate('MW')}</u>, // Mega Watts (same as Mega Joules per second)
mps: <u>{translate('m/s')}</u>, // Metres per second
ps: <u>{translate('/s')}</u>, // per second
pm: <u>{translate('/min')}</u>, // per minute
s: <u>{translate('secs')}</u>, // Seconds
T: <u> {translate('T')}</u>, // Metric Tons
T: <u>{translate('T')}</u>, // Metric Tons
}
};
}

View File

@@ -20,13 +20,11 @@ import MovementSummary from '../components/MovementSummary';
import EngineProfile from '../components/EngineProfile';
import FSDProfile from '../components/FSDProfile';
import JumpRange from '../components/JumpRange';
import DamageDealt from '../components/DamageDealt';
import DamageReceived from '../components/DamageReceived';
import BattleCentre from '../components/BattleCentre';
import PowerManagement from '../components/PowerManagement';
import CostSection from '../components/CostSection';
import ModalExport from '../components/ModalExport';
import ModalPermalink from '../components/ModalPermalink';
import Slider from '../components/Slider';
/**
* Document Title Generator
@@ -373,11 +371,7 @@ export default class OutfittingPage extends Page {
</div>
<div>
<DamageDealt ship={ship} code={code} chartWidth={halfChartWidth} currentMenu={menu}/>
</div>
<div>
<DamageReceived ship={ship} code={code} currentMenu={menu}/>
<BattleCentre ship={ship} />
</div>
</div>

View File

@@ -19,6 +19,7 @@
@import 'shipselector';
@import 'sortable';
@import 'loader';
@import 'pips';
html, body {
height: 100%;

View File

@@ -198,6 +198,14 @@
});
}
&.twothirds {
width: 67%;
.smallTablet({
width: 100% !important;
});
}
.smallScreen({
.axis.x {
g.tick:nth-child(2n + 1) text {

29
src/less/pips.less Executable file
View File

@@ -0,0 +1,29 @@
// The pips table - keep the background black
.pipstable {
background-color: @bgBlack;
color: @primary;
}
// A clickable entity in the pips table
.pipsclickable {
cursor: pointer;
}
// A full pip
.fullpip {
stroke: @primary;
fill: @primary;
}
// A half pip
.halfpip {
stroke: @primary-disabled;
fill: @primary-disabled;
}
// An empty pip
.emptypip {
stroke: @primary-bg;
fill: @primary-bg;
}