UI improvements, save build feature partial implementation

This commit is contained in:
Colin McLeod
2015-05-02 00:04:57 -07:00
parent bca5ed899f
commit 71405e6cb7
21 changed files with 383 additions and 192 deletions

View File

@@ -23,11 +23,13 @@
</head> </head>
<body> <body>
<div id="bg"></div> <div id="bg"></div>
<shipyard-menu></shipyard-menu> <shipyard-header></shipyard-header>
<div id="main" ui-view ng-click="bgClicked($event)"></div> <div id="main" ui-view ng-click="bgClicked($event)"></div>
<footer> <footer>
<div class="right">Version <%= version %> - <%= date %></div> <div class="right">
<a href="https://github.com/cmmcleod/ed-shipyard" target="_blank" title="Shipyard Github Project">Version <%= version %> - <%= date %></a>
</div>
<div class="left"> <div class="left">
Coriolis Shipyard was created using assets and imagery from Elite: Dangerous, with the permission of Frontier Developments plc, for non-commercial purposes.<br> Coriolis Shipyard was created using assets and imagery from Elite: Dangerous, with the permission of Frontier Developments plc, for non-commercial purposes.<br>
It is not endorsed by nor reflects the views or opinions of Frontier Developments and no employee of Frontier Developments was involved in the making of it. It is not endorsed by nor reflects the views or opinions of Frontier Developments and no employee of Frontier Developments was involved in the making of it.

View File

@@ -1,44 +1,9 @@
angular.module('app', ['ui.router', 'shipyard', 'ngLodash', 'app.templates']) angular.module('app', ['ui.router', 'shipyard', 'ngLodash', 'app.templates'])
.config(['$stateProvider', '$urlRouterProvider', '$locationProvider', function($stateProvider, $urlRouterProvider, $locationProvider) {
$locationProvider.html5Mode(true);
$stateProvider
.state('outfit', {
url: '/outfit/:shipId/:code?bn',
params: {
// TODO: fix below, default, squash false not working
//shipId: { value: 'sidewinder', squash: false }, // Allow 'shipId' parameter to default to
code: { value: null, squash: true } // Allow 'code' parameter to be empty/optional
},
templateUrl: 'views/page-outfit.html',
controller: 'OutfitController',
resolve: {
shipId: ['$stateParams',function ($p) { // Ensure ship exists before loading controller
if (!DB.ships[$p.shipId]) {
throw { type: 404, message: 'Ship "' + $p.shipId + '" does not exist'};
}
}]
}
})
.state('shipyard', { url: '/', templateUrl: 'views/page-shipyard.html', controller: 'ShipyardController' })
.state('error', { params: {type:null, message:null, details: null }, templateUrl: 'views/page-error.html', controller: 'ErrorController' })
.state('notfound', { url: '*path', templateUrl: 'views/page-error.html', controller: 'ErrorController' });
}])
.config(['$provide',function($provide) {
// Global Error Handler, redirects uncaught errors to the error page
$provide.decorator('$exceptionHandler', ['$delegate', '$injector', function ($delegate, $injector) {
return function(exception, cause) {
$injector.get('$state').go('error', { details: exception }, {location:false, reload:true}); // Go to error state, reload the controller, keep the current URL
$delegate(exception, cause);
};
}]);
}])
.run(['$rootScope','$document','$state','commonArray','shipPurpose','shipSize','hardPointClass','internalGroupMap','hardpointsGroupMap', function ($rootScope, $doc, $state, CArr, shipPurpose, sz, hpc, igMap, hgMap) { .run(['$rootScope','$document','$state','commonArray','shipPurpose','shipSize','hardPointClass','internalGroupMap','hardpointsGroupMap', function ($rootScope, $doc, $state, CArr, shipPurpose, sz, hpc, igMap, hgMap) {
// Redirect any state transition errors to the error controller/state // Redirect any state transition errors to the error controller/state
$rootScope.$on('$stateChangeError', function(e, toState, toParams, fromState, fromParams, error){ $rootScope.$on('$stateChangeError', function(e, toState, toParams, fromState, fromParams, error){
e.preventDefault(); e.preventDefault();
$state.go('error',error, {location:false, reload:true}); // Go to error state, reload the controller, keep the current URL $state.go('error', error, {location:false, reload:true}); // Go to error state, reload the controller, keep the current URL
}); });
// Global Reference variables // Global Reference variables
@@ -47,7 +12,7 @@ angular.module('app', ['ui.router', 'shipyard', 'ngLodash', 'app.templates'])
$rootScope.SZ = sz; $rootScope.SZ = sz;
$rootScope.HPC = hpc; $rootScope.HPC = hpc;
$rootScope.igMap = igMap; $rootScope.igMap = igMap;
window.hgmap = $rootScope.hgMap = hgMap; $rootScope.hgMap = hgMap;
$rootScope.ships = DB.ships; $rootScope.ships = DB.ships;
$rootScope.title = 'Coriolis'; $rootScope.title = 'Coriolis';
@@ -61,11 +26,16 @@ angular.module('app', ['ui.router', 'shipyard', 'ngLodash', 'app.templates'])
// Global Event Listeners // Global Event Listeners
$doc.bind('keyup', function (e) { $doc.bind('keyup', function (e) {
$rootScope.$broadcast('keyup', e); if(e.keyCode == 27) { // Escape Key
$rootScope.$broadcast('close', e);
$rootScope.$apply();
} else {
$rootScope.$broadcast('keyup', e);
}
}); });
$rootScope.bgClicked = function (e) { $rootScope.bgClicked = function (e) {
$rootScope.$broadcast('bgClicked', e); $rootScope.$broadcast('close', e);
} }
}]); }]);

56
app/js/config.js Normal file
View File

@@ -0,0 +1,56 @@
/**
* Sets up the routes and handlers before the Angular app is kicked off.
*/
angular.module('app').config(['$provide','$stateProvider', '$urlRouterProvider', '$locationProvider', function ($provide, $stateProvider, $urlRouterProvider, $locationProvider) {
// Use HTML5 push and replace state if possible
$locationProvider.html5Mode(true);
/**
* Set up all states and their routes.
*/
$stateProvider
.state('outfit', {
url: '/outfit/:shipId/:code?bn',
params: {
// TODO: Squash:false not working due to UI-router issue
shipId: { value: 'sidewinder', squash: false}, // Allow 'shipId' parameter to default to
code: { value: undefined, squash: true } // Allow 'code' parameter to be empty/optional
},
templateUrl: 'views/page-outfit.html',
controller: 'OutfitController',
resolve: {
shipId: ['$stateParams',function ($p) { // Ensure ship exists before loading controller
if (!DB.ships[$p.shipId]) {
throw { type: 'no-ship', message: $p.shipId };
}
}]
}
})
.state('shipyard', { url: '/', templateUrl: 'views/page-shipyard.html', controller: 'ShipyardController' })
.state('error', { params: {type:null, message:null, details: null }, templateUrl: 'views/page-error.html', controller: 'ErrorController' })
// Redirects
$urlRouterProvider.when('/outfit','/outfit/sidewinder/');
/**
* 404 Handler - Keep current URL/ do not redirect, change to error state.
*/
$urlRouterProvider.otherwise(function ($injector, $location) {
// Go to error state, reload the controller, keep the current URL
$injector.get('$state').go('error', { type: 404, message: null, details: null }, {location:false, reload:true});
return $location.path;
});
/**
* Global Error Handler. Decorates the existing error handler such that it
* redirects uncaught errors to the error page.
*
*/
$provide.decorator('$exceptionHandler', ['$delegate', '$injector', function ($delegate, $injector) {
return function(exception, cause) {
// Go to error state, reload the controller, keep the current URL
$injector.get('$state').go('error', { details: exception }, {location:false, reload:true});
$delegate(exception, cause);
};
}]);
}]);

View File

@@ -1,15 +1,29 @@
angular.module('app') angular.module('app')
.controller('ErrorController', ['$rootScope','$scope','$stateParams', '$location', function ($rootScope, $scope, $p, $location) { .controller('ErrorController', ['$rootScope','$scope','$stateParams', '$location', function ($rootScope, $scope, $p, $location) {
$rootScope.title = 'Error'; $rootScope.title = 'Error';
$scope.path = $location.path();
$scope.type = $p.type || 'unknown';
if ($p.path) { // If path is specified, 404 switch ($scope.type) {
$scope.type = 404; // Deep Space Image... case 404:
$scope.message = "" $scope.msgPre = 'Page';
$scope.path = $p.path; $scope.msgHighlight = $scope.path;
} else { $scope.msgPost = 'Not Found';
$scope.type = $p.type || 'unknown'; $scope.image = 'deep-space';
$scope.message = $p.message || "Uh, this is bad.."; break;
$scope.path = $location.path(); case 'no-ship':
$scope.msgPre = 'Ship';
$scope.msgHighlight = $p.message;
$scope.msgPost = 'does not exist';
$scope.image = 'thargoid';
break;
case 'build-fail':
$scope.msgPre = 'Build Failure!';
$scope.image = 'ship-explode';
break;
default:
$scope.msgPre = "Uh, this is bad..";
$scope.image = 'thargoid';
} }
}]); }]);

View File

@@ -1,7 +1,8 @@
angular.module('app').controller('OutfitController', ['$rootScope','$scope', '$state', '$stateParams', 'Ship', 'Components', 'Serializer', 'Persist', function ($rootScope, $scope, $state, $p, Ship, Components, Serializer, Persist) { angular.module('app').controller('OutfitController', ['$rootScope','$scope', '$state', '$stateParams', 'Ship', 'Components', 'Serializer', 'Persist', function ($rootScope, $scope, $state, $p, Ship, Components, Serializer, Persist) {
var data = DB.ships[$p.shipId]; var data = DB.ships[$p.shipId]; // Retrieve the basic ship properties, slots and defaults
var ship = new Ship($p.shipId, data.properties, data.slots); // Create a new Ship instance var ship = new Ship($p.shipId, data.properties, data.slots); // Create a new Ship instance
// Update the ship instance with the code (if provided) or the 'factory' defaults.
if ($p.code) { if ($p.code) {
Serializer.toShip(ship, $p.code); // Populate components from 'code' URL param Serializer.toShip(ship, $p.code); // Populate components from 'code' URL param
$scope.code = $p.code; $scope.code = $p.code;
@@ -10,7 +11,7 @@ angular.module('app').controller('OutfitController', ['$rootScope','$scope', '$s
} }
$scope.buildName = $p.bn; $scope.buildName = $p.bn;
$rootScope.title = ship.name + $scope.buildName? ' - ' + $scope.buildName: ''; $rootScope.title = ship.name + ($scope.buildName? ' - ' + $scope.buildName: '');
$scope.ship = ship; $scope.ship = ship;
$scope.pp = ship.common[0]; // Power Plant $scope.pp = ship.common[0]; // Power Plant
$scope.th = ship.common[1]; // Thruster $scope.th = ship.common[1]; // Thruster
@@ -23,11 +24,17 @@ angular.module('app').controller('OutfitController', ['$rootScope','$scope', '$s
$scope.internal = ship.internal; $scope.internal = ship.internal;
$scope.availCS = Components.forShip(ship.id); $scope.availCS = Components.forShip(ship.id);
$scope.selectedSlot = null; $scope.selectedSlot = null;
$scope.lastSaveCode = Persist.getBuild(ship.id, $scope.buildName); $scope.savedCode = Persist.getBuild(ship.id, $scope.buildName);
// for debugging // for debugging
window.myScope = $scope; window.myScope = $scope;
/**
* 'Opens' a select for component selection.
*
* @param {[type]} e The event object
* @param {[type]} slot The slot that is being 'opened' for selection
*/
$scope.selectSlot = function(e, slot) { $scope.selectSlot = function(e, slot) {
e.stopPropagation(); e.stopPropagation();
if ($scope.selectedSlot == slot) { if ($scope.selectedSlot == slot) {
@@ -37,6 +44,14 @@ angular.module('app').controller('OutfitController', ['$rootScope','$scope', '$s
} }
}; };
/**
* Updates the ships build with the selected component for the
* specified slot. Prevents the click event from propagation.
*
* @param {string} type Shorthand key/string for identifying the slot & component type
* @param {[type]} slot The slot object belonging to the ship instance
* @param {[type]} e The event object
*/
$scope.select = function(type, slot, e) { $scope.select = function(type, slot, e) {
e.stopPropagation(); e.stopPropagation();
if (e.srcElement.id) { if (e.srcElement.id) {
@@ -54,7 +69,6 @@ angular.module('app').controller('OutfitController', ['$rootScope','$scope', '$s
$scope.selectedSlot = null; $scope.selectedSlot = null;
$scope.code = Serializer.fromShip(ship); $scope.code = Serializer.fromShip(ship);
$state.go('outfit', {shipId: ship.id, code: $scope.code, bn: $scope.buildName}, {location:'replace', notify:false}); $state.go('outfit', {shipId: ship.id, code: $scope.code, bn: $scope.buildName}, {location:'replace', notify:false});
$scope.canSave = true;
} }
} }
@@ -62,21 +76,28 @@ angular.module('app').controller('OutfitController', ['$rootScope','$scope', '$s
* Reload the build from the last save. * Reload the build from the last save.
*/ */
$scope.reloadBuild = function() { $scope.reloadBuild = function() {
if ($scope.buildName && $scope.lastSaveCode) { if ($scope.buildName && $scope.savedCode) {
Serializer.toShip(ship, $scope.lastSaveCode); // Repopulate with components from last save Serializer.toShip(ship, $scope.savedCode); // Repopulate with components from last save
$scope.code = $scope.lastSaveCode; $scope.code = $scope.savedCode;
$state.go('outfit', {shipId: ship.id, code: $scope.lastSaveCode, bn: $scope.buildName}, {location:'replace', notify:false}); $state.go('outfit', {shipId: ship.id, code: $scope.savedCode, bn: $scope.buildName}, {location:'replace', notify:false});
} }
}; };
/**
* Save the current build. Will replace the saved build if there is one
* for this ship & with the exact name.
*/
$scope.saveBuild = function() { $scope.saveBuild = function() {
if ($scope.code && $scope.code != $scope.lastSaveCode) { if($scope.code != $scope.savedCode) {
Persist.saveBuild(ship.id, $scope.buildName, $scope.code); Persist.saveBuild(ship.id, $scope.buildName, $scope.code);
$scope.lastSaveCode = $scope.code; $scope.savedCode = $scope.code;
$rootScope.$broadcast('buildSaved', ship.id, $scope.buildName, $scope.code);
} }
} }
/**
* Permanently delete the current build and redirect/reload this controller
* with the 'factory' build of the current ship.
*/
$scope.deleteBuild = function() { $scope.deleteBuild = function() {
Persist.deleteBuild(ship.id, $scope.buildName); Persist.deleteBuild(ship.id, $scope.buildName);
$rootScope.$broadcast('buildDeleted', $scope.saveName, ship.id); $rootScope.$broadcast('buildDeleted', $scope.saveName, ship.id);
@@ -84,17 +105,20 @@ angular.module('app').controller('OutfitController', ['$rootScope','$scope', '$s
} }
$rootScope.$on('keyup', function (e, keyEvent) { $rootScope.$on('keyup', function (e, keyEvent) {
if(keyEvent.keyCode == 27) { // on Escape // CTRL + S or CMD + S will override the default and save the build is possible
$scope.selectedSlot = null; if (keyEvent.keycode == 83 && keyEvent.ctrlKey) {
$scope.$apply();
}
else if(keyEvent.keycode == 83 && keyEvent.ctrlKey){ // CTRL + S
e.preventDefault(); e.preventDefault();
$scope.saveBuild(); $scope.saveBuild();
} }
}); });
$rootScope.$on('bgClicked', function (e, keyEvent) { // Hide any open menu/slot/etc if escape key is pressed
$rootScope.$on('escape', function (e, keyEvent) {
$scope.selectedSlot = null;
$scope.$apply();
});
// Hide any open menu/slot/etc if the background is clicked
$rootScope.$on('close', function (e, keyEvent) {
$scope.selectedSlot = null; $scope.selectedSlot = null;
}); });

View File

@@ -1,4 +1,3 @@
angular.module('app') angular.module('app').controller('ShipyardController', ['$rootScope', function ($rootScope) {
.controller('ShipyardController', ['$rootScope', function ($rootScope) {
$rootScope.title = 'Coriolis - Shipyard'; $rootScope.title = 'Coriolis - Shipyard';
}]); }]);

View File

@@ -0,0 +1,37 @@
angular.module('app').directive('shipyardHeader', ['$rootScope', 'Persist', function ($rootScope, Persist) {
return {
restrict: 'E',
templateUrl: 'views/_header.html',
scope: true,
link: function (scope) {
scope.openedMenu = null;
scope.ships = DB.ships;
scope.allBuilds = Persist.builds;
scope.bs = Persist.state;
console.log(scope);
$rootScope.$on('$stateChangeStart',function(){
scope.openedMenu = null;
});
$rootScope.$on('close', function (e, keyEvent) {
scope.openedMenu = null;
});
scope.openMenu = function (menu) {
if(menu == scope.openedMenu) {
scope.openedMenu = null;
return;
}
if (menu == 'b' && !scope.bs.hasBuilds) {
scope.openedMenu = null;
return;
}
scope.openedMenu = menu;
};
}
};
}]);

View File

@@ -1,13 +0,0 @@
angular.module('app').directive('shipyardMenu', function () {
return {
restrict: 'E',
templateUrl: 'views/menu.html',
link: function () {
// TODO: Saved Ships: load, save, save as, delete, export
// TODO: Links: github, forum, etc
}
};
});

View File

@@ -1,3 +1,6 @@
/**
* [description]
*/
angular.module('app').service('Persist', ['lodash', function (_) { angular.module('app').service('Persist', ['lodash', function (_) {
var LS_KEY = 'builds'; var LS_KEY = 'builds';
@@ -9,6 +12,9 @@ angular.module('app').service('Persist', ['lodash', function (_) {
this.builds = {}; this.builds = {};
} }
this.state = {
hasBuilds: Object.keys(this.builds).length > 0
}
/** /**
* Persist a ship build in local storage. * Persist a ship build in local storage.
* *
@@ -22,7 +28,9 @@ angular.module('app').service('Persist', ['lodash', function (_) {
} }
this.builds[shipId][name] = code; this.builds[shipId][name] = code;
localStorage.setItem(LS_KEY, angular.toJson(this.builds)); // Persist updated build collection to localstorage this.state.hasBuilds = true;
// Persist updated build collection to localstorage
localStorage.setItem(LS_KEY, angular.toJson(this.builds));
} }
/** /**
@@ -48,11 +56,15 @@ angular.module('app').service('Persist', ['lodash', function (_) {
* @param {string} name The name of the build * @param {string} name The name of the build
*/ */
this.deleteBuild = function (shipId, name) { this.deleteBuild = function (shipId, name) {
delete build[shipId][name]; if(this.builds[shipId][name]) {
if (Object.keys(build[shipId]).length == 0) { delete this.builds[shipId][name];
delete build[shipId]; if (Object.keys(this.builds[shipId]).length == 0) {
delete this.builds[shipId];
this.state.hasBuilds = Object.keys(this.builds).length > 0;
}
// Persist updated build collection to localstorage
localStorage.setItem(LS_KEY, angular.toJson(this.builds));
} }
} }
}]);
}]);

View File

@@ -3,8 +3,10 @@
* information or behavoir in Elite Dangerous. * information or behavoir in Elite Dangerous.
* *
* This file contains values and functions that can be reused across the app. * This file contains values and functions that can be reused across the app.
*
* @requires ngLodash is a dependency of this module.
*/ */
angular.module('shipyard', []) angular.module('shipyard', ['ngLodash'])
.value('commonArray', [ .value('commonArray', [
'Power Plant', 'Power Plant',
'Thrusters', 'Thrusters',
@@ -67,42 +69,39 @@ angular.module('shipyard', [])
'Large', 'Large',
'Huge' 'Huge'
]) ])
.factory('calcJumpRange', function() { /**
/** * Calculate the maximum single jump range based on mass and a specific FSD
* Calculate the maximum single jump range based on mass and a specific FSD *
* @param {number} mass Mass of a ship: laden, unlanden, partially laden, etc * @param {number} mass Mass of a ship: laden, unlanden, partially laden, etc
* @param {object} fsd The FDS object/component with maxfuel, fuelmul, fuelpower, optmass * @param {object} fsd The FDS object/component with maxfuel, fuelmul, fuelpower, optmass
* @param {number} fuel Optional - The fuel consumed during the jump (must be less than the drives max fuel per jump) * @param {number} fuel Optional - The fuel consumed during the jump (must be less than the drives max fuel per jump)
* @return {number} Distance in Light Years * @return {number} Distance in Light Years
*/ */
return function(mass, fsd, fuel) { .value('calcJumpRange', function(mass, fsd, fuel) {
return Math.pow(Math.min(fuel || Infinity, fsd.maxfuel) / fsd.fuelmul, 1 / fsd.fuelpower ) * fsd.optmass / mass; return Math.pow(Math.min(fuel || Infinity, fsd.maxfuel) / fsd.fuelmul, 1 / fsd.fuelpower ) * fsd.optmass / mass;
};
}) })
.factory('calcShieldStrength', function() { /**
/** * Calculate the a ships shield strength based on mass, shield generator and shield boosters used.
* Calculate the a ships shield strength based on mass, shield generator and shield boosters used. *
* * @private
* @private * @param {number} mass Current mass of the ship
* @param {number} mass Current mass of the ship * @param {number} shields Base Shield strength MJ for ship
* @param {number} shields Base Shield strength MJ for ship * @param {object} sg The shield generator used
* @param {object} sg The shield generator used * @param {number} multiplier Shield multiplier for ship (1 + shield boosters if any)
* @param {number} multiplier Shield multiplier for ship (1 + shield boosters if any) * @return {number} Approximate shield strengh in MJ
* @return {number} Approximate shield strengh in MJ */
*/ .value('calcShieldStrength', function (mass, shields, sg, multiplier) {
return function (mass, shields, sg, multiplier) { if (!sg) {
if (!sg) { return 0;
return 0;
}
if (mass <= sg.minmass) {
return shields * multiplier * sg.minmul;
}
if (mass < sg.optmass) {
return shields * multiplier * (sg.minmul + (mass - sg.minmass) / (sg.optmass - sg.minmass) * (sg.optmul - sg.minmul));
}
if (mass < sg.maxmass) {
return shields * multiplier * (sg.optmul + (mass - sg.optmass) / (sg.maxmass - sg.optmass) * (sg.maxmul - sg.optmul));
}
return shields * multiplier * sg.maxmul;
} }
if (mass <= sg.minmass) {
return shields * multiplier * sg.minmul;
}
if (mass < sg.optmass) {
return shields * multiplier * (sg.minmul + (mass - sg.minmass) / (sg.optmass - sg.minmass) * (sg.optmul - sg.minmul));
}
if (mass < sg.maxmass) {
return shields * multiplier * (sg.optmul + (mass - sg.optmass) / (sg.maxmass - sg.optmass) * (sg.maxmul - sg.optmul));
}
return shields * multiplier * sg.maxmul;
}); });

View File

@@ -2,14 +2,15 @@
@import 'fonts'; @import 'fonts';
@import 'utilities'; @import 'utilities';
@import 'icons'; @import 'icons';
@import 'header';
@import 'shipyard'; @import 'shipyard';
@import 'list'; @import 'list';
@import 'slot'; @import 'slot';
@import 'ship'; @import 'outfit';
@import 'select'; @import 'select';
@import 'charts'; @import 'charts';
@import 'meters'; @import 'meters';
@import 'error';
html, body { html, body {
@@ -65,44 +66,19 @@ body {
clear: both; clear: both;
} }
header { a, a:visited {
background-color: @bg; color: @fg;
margin: 0;
height: 55px;
line-height: 55px;
font-family: @fTitle;
vertical-align: middle;
a {
vertical-align: middle;
color: @warning;
&:visited {
color: @warning;
}
&:hover {
color: teal;
}
}
.title {
font-size: 1.3em;
display: inline-block;
margin:0px;
text-transform: uppercase;
}
} }
footer { footer {
font-size: 0.3em; font-size: 0.6em;
color: #999; color: #999;
padding: 10px 0; padding: 10px 0;
width: 100%; width: 100%;
overflow: hidden; overflow: hidden;
} }
header, footer { footer {
.right { .right {
float: right; float: right;
text-align: right; text-align: right;

View File

@@ -10,10 +10,10 @@
@disabled: #888; @disabled: #888;
@primary-disabled: darken(@primary, @disabledDarken); @primary-disabled: darken(@primary, @disabledDarken);
@secondary-disabled: darken(@primary, @disabledDarken); @secondary-disabled: darken(@secondary, @disabledDarken);
@warning-disabled: darken(@primary, @disabledDarken); @warning-disabled: darken(@warning, @disabledDarken);
@bgBlack: rgba(0,0,0,0.6); @bgBlack: rgba(0,0,0,0.9);
@primary-bg: fadeout(darken(@primary, 45%), 30%); @primary-bg: fadeout(darken(@primary, 45%), 30%);
@secondary-bg: fadeout(darken(@secondary, @bgDarken), @bgTransparency); // Brown background @secondary-bg: fadeout(darken(@secondary, @bgDarken), @bgTransparency); // Brown background

10
app/less/error.less Normal file
View File

@@ -0,0 +1,10 @@
.error {
width: 50%;
margin: 10% auto;
text-align: center;
small {
color: @primary-disabled;
}
}

85
app/less/header.less Normal file
View File

@@ -0,0 +1,85 @@
header {
background-color: @bg;
margin: 0;
padding: 0 1em;
height: 4em;
line-height: 4em;
font-family: @fTitle;
vertical-align: middle;
position: relative;
z-index: 2;
.user-select-none();
.menu {
position: relative;
z-index: 1;
cursor: default;
}
.menu-header {
height: 100%;
z-index: 2;
padding : 0 1em;
cursor: pointer;
color: @warning;
&.disabled {
color: @warning-disabled;
cursor: default;
&:hover {
background-color: transparent;
}
}
&:hover, &.selected {
background-color: @bgBlack;
}
}
.menu-list {
width: 200%;
font-family: @fStandard;
position: absolute;
padding: 0 1em 1em 0;
overflow: hidden;
background-color: @bgBlack;
font-size: 0.8em;
}
ul {
margin: 0;
padding: 0;
margin-top: 0.5em;
line-height: 2em;
}
li {
list-style: none;
margin-left: 1em;
line-height: 1.1em;
}
a {
vertical-align: middle;
color: @warning;
text-decoration: none;
white-space: nowrap;
&:visited {
color: @warning;
}
&:hover {
color: teal;
}
&.active {
color: @primary;
}
}
.title {
font-size: 1.3em;
display: inline-block;
margin:0px;
text-transform: uppercase;
}
}

View File

@@ -1,15 +1,24 @@
#overview { #overview {
margin: 0px auto;
text-align: center;
h1 { h1 {
font-family: @fTitle;
margin: 5px 0; margin: 5px 0;
color: @primary;
float: left;
} }
}
div { #build {
display: inline-block; float: right;
margin: 0 5px; line-height: 2em;
input {
background: @primary-bg;
color: @fg;
border: none;
font-size: 0.8em;
line-height: 2em;
text-transform: uppercase;
} }
} }

View File

@@ -2,7 +2,6 @@
.slot-group { .slot-group {
float: left; float: left;
margin: 0 5px; margin: 0 5px;
background-color: @bgBlack;
.user-select-none(); .user-select-none();
cursor: default; cursor: default;

21
app/views/_header.html Normal file
View File

@@ -0,0 +1,21 @@
<header>
<div class="l" style="margin-right: 2em;"><a ui-sref="shipyard" class="logo shipyard"></a></div>
<div class="l menu">
<div class="menu-header" ng-class="{selected: openedMenu=='b', disabled: !bs.hasBuilds}" ng-click="openMenu('b')">Builds</div>
<div class="menu-list" ng-if="openedMenu=='b'">
<ul class="left" ng-repeat="(shipId,builds) in allBuilds">
{{ships[shipId].properties.name}}
<li ng-repeat="(name, build) in builds">
<a ui-sref-active="active" ui-sref="outfit({shipId:shipId, code:build, bn:name})" ng-bind="name"></a>
</li>
</ul>
</div>
</div>
<div class="r">
<a class="logo github" href="https://github.com/cmmcleod/ed-shipyard" target="_blank" title="Shipyard Github Project"></a>
<a class="logo reddit" href="#" target="_blank" title="Reddit Thread"></a>
</div>
</header>

View File

@@ -1,11 +0,0 @@
<header>
<div class="left">
<a ui-sref="shipyard" class="logo shipyard"></a>
</div>
<div class="right">
<a class="logo github" href="https://github.com/cmmcleod/ed-shipyard" target="_blank" title="Shipyard Github Project"></a>
<a class="logo reddit" href="#" target="_blank" title="Reddit Thread"></a>
</div>
</header>

View File

@@ -1,12 +1,14 @@
<div class="error">
<h1>
<span ng-if="msgPre">{{msgPre}}</span>
<small ng-if="msgHighlight">{{msgHighlight}}</small>
<span ng-if="msgPost">{{msgPost}}</span>
</h1>
<!-- TODO: add awesome relevant SVG based on code /-->
<div> <p ng-if="path" ng-bind="path"></p>
<h1>Error {{type}}</h1> <p ng-if="type" ng-bind="type"></p>
<h2 ng-bind="message"></h2>
<p ng-if="path" ng-bind="path"></p>
</div> </div>
<!-- TODO: formatting /-->
<!-- TODO: add awesome relevant SVG based on code /-->
<!-- TODO: Add github issue link /--> <!-- TODO: Add github issue link /-->

View File

@@ -124,16 +124,16 @@
</div> </div>
</div> </div>
<div id="build">
<h1 ng-bind="ship.name"></h1>
<input ng-model="buildName" placeholder="Build Name" />
<button ng-click="saveBuild()" ng-disabled="code == lastSaveCode">Save</button>
<button ng-click="reloadBuild()" ng-disabled="!lastSaveCode || code == lastSaveCode">Reload</button>
<button ui-sref="outfit({shipId: ship.id,code:null})" ng-disabled="!code">Clear</button>
<button ng-click="deleteBuild()" ng-disabled="!lastSaveCode">Delete</button>
</div>
<div id="summary"> <div id="summary">
<div id="overview" class="list">
<h1 ng-bind="ship.name"></h1>
<div id="build">
<input ng-model="buildName" placeholder="Enter Build Name" />
<button ng-click="saveBuild()" ng-disabled="code == savedCode">Save</button>
<button ng-click="reloadBuild()" ng-disabled="!savedCode || code == savedCode">Reload</button>
<button ui-sref="outfit({shipId: ship.id,code:null})" ng-disabled="!code">Clear</button>
</div>
</div>
<div class="list"> <div class="list">
<div class="header">Maneuverability</div> <div class="header">Maneuverability</div>
<div class="summary"> <div class="summary">

View File

@@ -25,7 +25,7 @@
"dependencies": { "dependencies": {
"d3": "~3.5.5", "d3": "~3.5.5",
"ng-lodash": "~0.2.0", "ng-lodash": "~0.2.0",
"angular-ui-router": "0.2.14" "angular-ui-router": "^0.2.14"
}, },
"overrides": {} "overrides": {}
} }