Committing so I don't lose work.

This commit is contained in:
PeekabooSteam 2023-02-21 15:38:38 +00:00
parent 853af46483
commit 093ab75e8f
24 changed files with 1062 additions and 57 deletions

View File

@ -21,9 +21,11 @@
},
"devDependencies": {
"@types/gtag.js": "^0.0.12",
"@types/sortablejs": "^1.15.0",
"browserify": "^17.0.0",
"concurrently": "^7.6.0",
"nodemon": "^2.0.20",
"sortablejs": "^1.15.0",
"tsify": "^5.0.4",
"typescript": "^4.9.4",
"watchify": "^4.0.0"
@ -48,6 +50,12 @@
"@types/geojson": "*"
}
},
"node_modules/@types/sortablejs": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/@types/sortablejs/-/sortablejs-1.15.0.tgz",
"integrity": "sha512-qrhtM7M41EhH4tZQTNw2/RJkxllBx3reiJpTbgWCM2Dx0U1sZ6LwKp9lfNln9uqE26ZMKUaPEYaD4rzvOWYtZw==",
"dev": true
},
"node_modules/abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
@ -2621,6 +2629,12 @@
"semver": "bin/semver.js"
}
},
"node_modules/sortablejs": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.0.tgz",
"integrity": "sha512-bv9qgVMjUMf89wAvM6AxVvS/4MX3sPeN0+agqShejLU5z5GX4C75ow1O2e5k4L6XItUyAK3gH6AxSbXrOM5e8w==",
"dev": true
},
"node_modules/source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
@ -3248,6 +3262,12 @@
"@types/geojson": "*"
}
},
"@types/sortablejs": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/@types/sortablejs/-/sortablejs-1.15.0.tgz",
"integrity": "sha512-qrhtM7M41EhH4tZQTNw2/RJkxllBx3reiJpTbgWCM2Dx0U1sZ6LwKp9lfNln9uqE26ZMKUaPEYaD4rzvOWYtZw==",
"dev": true
},
"abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
@ -5329,6 +5349,12 @@
}
}
},
"sortablejs": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.0.tgz",
"integrity": "sha512-bv9qgVMjUMf89wAvM6AxVvS/4MX3sPeN0+agqShejLU5z5GX4C75ow1O2e5k4L6XItUyAK3gH6AxSbXrOM5e8w==",
"dev": true
},
"source-map": {
"version": "0.5.7",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",

View File

@ -23,9 +23,11 @@
},
"devDependencies": {
"@types/gtag.js": "^0.0.12",
"@types/sortablejs": "^1.15.0",
"browserify": "^17.0.0",
"concurrently": "^7.6.0",
"nodemon": "^2.0.20",
"sortablejs": "^1.15.0",
"tsify": "^5.0.4",
"typescript": "^4.9.4",
"watchify": "^4.0.0"

View File

@ -0,0 +1,27 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="64.000000pt" height="64.000000pt" viewBox="0 0 64.000000 64.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,64.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M285 590 c-11 -12 -31 -20 -51 -20 -23 0 -37 -6 -44 -20 -6 -11 -17
-20 -25 -20 -7 0 -16 -4 -20 -10 -10 -16 14 -174 28 -185 7 -5 16 -18 20 -27
3 -10 16 -18 27 -18 13 0 20 -7 20 -20 0 -11 5 -20 10 -20 6 0 10 -43 10 -110
l0 -110 60 0 60 0 0 110 c0 67 4 110 10 110 6 0 10 9 10 20 0 13 7 20 20 20
11 0 24 8 27 18 4 9 13 22 20 27 14 11 38 169 28 185 -4 6 -13 10 -20 10 -8 0
-19 9 -25 20 -7 14 -21 20 -44 20 -20 0 -40 8 -51 20 -10 11 -26 20 -35 20 -9
0 -25 -9 -35 -20z m60 -10 c4 -6 -7 -10 -25 -10 -18 0 -29 4 -25 10 3 6 15 10
25 10 10 0 22 -4 25 -10z m90 -40 c4 -6 -37 -10 -115 -10 -78 0 -119 4 -115
10 4 6 53 10 115 10 62 0 111 -4 115 -10z m-205 -110 c0 -78 -1 -80 -24 -80
-22 0 -25 5 -31 48 -3 26 -8 62 -11 80 -5 31 -4 32 31 32 l35 0 0 -80z m80 0
l0 -80 -30 0 -30 0 0 80 0 80 30 0 30 0 0 -80z m80 0 l0 -80 -30 0 -30 0 0 80
0 80 30 0 30 0 0 -80z m86 48 c-3 -18 -8 -54 -11 -80 -6 -43 -9 -48 -31 -48
-23 0 -24 2 -24 80 l0 80 35 0 c35 0 36 -1 31 -32z m-46 -158 c0 -6 -43 -10
-110 -10 -67 0 -110 4 -110 10 0 6 43 10 110 10 67 0 110 -4 110 -10z m-50
-40 c0 -6 -27 -10 -60 -10 -33 0 -60 4 -60 10 0 6 27 10 60 10 33 0 60 -4 60
-10z m-20 -130 l0 -100 -40 0 -40 0 0 100 0 100 40 0 40 0 0 -100z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,21 @@
<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
width="96.000000pt" height="96.000000pt" viewBox="0 0 96.000000 96.000000"
preserveAspectRatio="xMidYMid meet">
<g transform="translate(0.000000,96.000000) scale(0.100000,-0.100000)"
fill="#000000" stroke="none">
<path d="M411 846 c-77 -78 -70 -86 69 -86 139 0 146 8 69 86 -29 30 -60 54
-69 54 -9 0 -40 -24 -69 -54z"/>
<path d="M132 668 c-16 -16 -15 -43 2 -57 9 -8 110 -11 351 -9 309 3 339 4
349 21 8 12 8 22 0 35 -10 16 -40 17 -350 20 -256 2 -343 -1 -352 -10z"/>
<path d="M132 508 c-16 -16 -15 -43 2 -57 9 -8 110 -11 351 -9 309 3 339 4
349 21 8 12 8 22 0 35 -10 16 -40 17 -350 20 -256 2 -343 -1 -352 -10z"/>
<path d="M132 348 c-16 -16 -15 -43 2 -57 9 -8 110 -11 351 -9 309 3 339 4
349 21 8 12 8 22 0 35 -10 16 -40 17 -350 20 -256 2 -343 -1 -352 -10z"/>
<path d="M363 184 c-7 -18 92 -124 117 -124 25 0 124 106 117 124 -9 24 -225
24 -234 0z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1,211 @@
/*** Control panel ***/
#atc-control-panel {
align-self: flex-end;
background: white;
border-radius: 10px;
display:flex;
margin: 0 0 50px 100px;
padding:5px;
position: absolute;
z-index: 9999;
}
.atc-tool {
align-self: center;
border-radius: 10px;
display:none;
justify-self: center;
padding: 10px;
position: absolute;
z-index: 9999;
}
.atc-enabled .atc-tool {
display:flex;
}
#atc-flight-list {
flex-direction: column;
}
#atc-flight-list table {
color:white;
}
#atc-flight-list table td {
padding:0 10px;
text-align: center;
}
#atc-flight-list table td:first-of-type {
text-align: left;
}
#atc-flight-list table tr[data-status='checkedIn'] td {
background-color:goldenrod;
}
#atc-flight-list table tr[data-status='readyToTaxi'] td {
background-color:darkgreen;
}
#atc-flight-list table button {
background-color: #666;
border:1px solid white;
color:white;
font-weight: bold;
margin:2px 0;
}
.atc-strip-board {
align-self: center;
display:flex;
justify-self: center;
position: absolute;
z-index: 9999 ;
}
.atc-strip-board-header {
display:none;
}
.atc-strip-board-strips {
display:flex;
flex-direction: column;
}
.atc-strip-board-strip {
display:flex;
flex-direction: row;
}
/*
.atc-strip-board-header {
background:black;
color:white;
display:none;
justify-content: right;
}
.atc-strip-board {
display:flex;
flex-direction: column;
row-gap: 5px;
}
.atc-strip-board-strips {
display:flex;
flex-direction: column;
padding:10px;
row-gap: 5px;
}
.atc-strip-board-strips > div {
align-items: center;
color:white;
column-gap: 2px;
display: flex;
flex-direction: row;
padding: 5px;
}
.atc-strip-board-header > div, .atc-strip-board-strips > div > div {
text-align: center;
width: 75px;
}
.atc-strip-board-header > .name {
width:150px;
}
.atc-strip-board-header > div, .atc-strip-board-strips > div > div {
text-align: center;
width: 75px;
}
.atc-strip-board-strips > div > .name {
text-align: left;
width:150px;
}
.atc-strip-board-strips > div {
align-items: center;
column-gap: 5px;
display: flex;
flex-direction: row;
font-size:12px;
font-weight: 600;
padding: 5px;
row-gap: 5px;
}
/*
.atc-strip-board-header, .atc-strip-board-strips > div {
align-items: center;
background:#FFF3;
color:white;
column-gap: 5px;
display: flex;
flex-direction: row;
font-size:12px;
font-weight: 600;
padding: 5px;
row-gap: 5px;
}
.atc-strip-board-header {
background:black;
color:white;
display:none;
justify-content: right;
}
.atc-strip-board-strips > div {
border-bottom:1px solid black;
}
.atc-strip-board-header > div, .atc-strip-board-strips > div > div {
text-align: center;
width: 75px;
}
.atc-strip-board-header > .name {
width:150px;
}
.atc-strip-board-strips > div > .handle {
background: black;
border-radius: 50%;
cursor:grab;
height:10px;
width:10px;
}
.atc-strip-board-strips > div > .name {
text-align: left;
width:150px;
}
.atc-strip-board-strips > div > .warning {
background:red;
color: white;
font-weight: bold;
}
.atc-strip-board-strips > div > .link-warning {
border: 1px solid red;
color: red;
font-weight: bold;
}
*/

View File

@ -0,0 +1,106 @@
/* Variables definitions */
:root {
--active-coalition-color: var(--blue-coalition-color);
--background-color-dark: #202831;
--background-color-light: #AAA;
--blue-coalition-color: #247be2;
--highlight-color: #FFF5;
--neutral-coalition-color: whitesmoke;
--neutral-coalition-text: #202831;
--red-coalition-color: #f32121;
--text-color: white;
--title-color: #d3e9ff;
}
* {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
html {
font-family: 'Open Sans', sans-serif;
}
.ol-panel {
background-color: var(--background-color-dark);
border-radius: 15px;
box-shadow: 0px 2px 5px #000A;
color:white;
font-size: 12px;
height:fit-content;
padding:10px;
width:fit-content;
}
.ol-panel-list {
display: flex;
flex-direction: column;
height: fit-content;
row-gap: 5px;
text-align: center;
width: fit-content;
border-radius: 5px;
}
.ol-panel-list .list-item {
border-radius: 10px;
display:flex;
justify-content: space-between;
padding: 6px 10px;
}
.ol-panel-list.sortable > .sortable-item {
align-items: center;
column-gap: 5px;
display:flex;
flex-direction: row;
}
.ol-panel-list.sortable > .sortable-item > .handle {
cursor:grab;
filter:invert(100);
}
.ol-panel-list.sortable > .sortable-item > .handle img {
max-width: 16px;
}
.ol-panel-info {
display:flex;
flex-direction: row;
justify-content: space-evenly;
}
.ol-panel-info > .panel-section {
border-right: 1px solid #555;
padding:10px;
}
.ol-panel-info > .panel-section:last-of-type {
border-right-width: 0;
}
.highlight-primary {
background-color: var(--highlight-color);
}
.highlight-bluefor {
background-color: var(--blue-coalition-color);
}
.highlight-redfor {
background-color: var(--red-coalition-color);
}
.highlight-neutral {
background-color: var(--neutral-coalition-color);
color: var(--neutral-coalition-text)
}

View File

@ -16,6 +16,7 @@
@import url("mouseinfopanel.css");
@import url( "aic.css" );
@import url( "atc.css" );
@import url("layout.css");
@ -36,7 +37,7 @@
* {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
box-sizing: border-box;
}
html {

View File

@ -0,0 +1,54 @@
body {
background-color:#eaeaea;
}
#content-wrapper {
row-gap: 5px;
display: flex;
flex-direction: column;
flex-wrap: wrap;
height:100%;
width:100%;
}
section {
column-gap: 20px;
display:flex;
flex-direction: row;
}
.section-header {
font-size:125%;
font-weight: bold;
margin-bottom: 1vh;
}
.content {
background:white;
border-radius: 10px;
height:fit-content;
margin-bottom:4vh;
padding:20px;
width:fit-content;
}
.content-header {
color:#666;
letter-spacing:1px;
margin-bottom: 1vh;
}
.content-body {
column-gap: 20px;
display:flex;
flex-direction: row;
}
.caption {
margin:2vh 0 1vh 0;
}
#paragraph {
max-width: 750px;
}

181
client/public/uikit.html Normal file
View File

@ -0,0 +1,181 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>Olympus UI Kit</title>
<link rel="stylesheet" type="text/css" href="stylesheets/olympus.css" />
<link rel="stylesheet" type="text/css" href="stylesheets/uikit.css" />
</head>
<body>
<div id="content-wrapper">
<h1>Olympus UI Kit</h1>
<div class="section-header">Typeography</div>
<section>
<div class="content">
<div class="content-header">Headings</div>
<div class="content-body">
<div class="example">
<h1>h1 | open sans | 32px</h1>
<h2>h2 | open sans | 24px</h2>
<h3>h3 | open sans | 18.72px</h3>
<h4>h4 | open sans | 16px</h4>
<h5>h5 | open sans | 13.28px</h5>
<h6>h6 | open sans | 10.72px</h6>
</div>
</div>
</div>
<div id="paragraph" class="content">
<div class="content-header">Paragraph</div>
<div class="content-body">
<div class="example">
<div class="caption">Plain</div>
<p>Nullam iaculis nisi sed mi tincidunt pretium blandit tempus urna. Vestibulum non ex vitae massa tristique auctor. Praesent orci justo, porttitor pellentesque convallis non, commodo at augue.</p>
</div>
<div class="example">
<div class="caption">In a panel</div>
<div class="ol-panel">
<p>Donec nibh est, fringilla sed pharetra eu, varius vel sem. Aliquam ac libero leo. Sed consectetur enim aliquam dui pellentesque luctus. Pellentesque vel iaculis quam.</p>
</div>
</div>
</div>
</div>
</section>
<div class="section-header">.ol-panel</div>
<section>
<div class="content">
<div class="content-header">Plain panel</div>
<div class="content-body">
<div class="example">
<div class="ol-panel">
Disconnected
</div>
</div>
</div>
</div>
<div class="content">
<div class="content-header">Panel list</div>
<div class="content-body">
<div class="example">
<div class="caption">Basic list</div>
<div class="ol-panel">
<div class="ol-panel-list">
<div class="list-item">List item 1</div>
<div class="list-item">List item 2</div>
<div class="list-item">List item 3</div>
</div>
</div>
</div>
<div class="example">
<div class="caption">List with .highlight-primary</div>
<div class="ol-panel">
<div class="ol-panel-list">
<div class="list-item highlight-primary">List item with highlight-primary</div>
<div class="list-item highlight-bluefor">List item with highlight-bluefor</div>
<div class="list-item highlight-redfor">List item with highlight-redfor</div>
<div class="list-item highlight-neutral">List item with highlight-neutral</div>
</div>
</div>
</div>
<div class="example">
<div class="caption">Sortable list</div>
<div class="ol-panel">
<div class="ol-panel-list sortable">
<div class="sortable-item">
<div class="handle"><img src="images/buttons/reorder.svg" /></div>
<div class="list-item">List item 1</div>
</div>
<div class="sortable-item">
<div class="handle"><img src="images/buttons/reorder.svg" /></div>
<div class="list-item">List item 2</div>
</div>
<div class="sortable-item">
<div class="handle"><img src="images/buttons/reorder.svg" /></div>
<div class="list-item">List item 3</div>
</div>
</div>
<!-- JavaScript: new Sortable( element:HTMLElement, [ options:object ]) -->
</div>
</div>
</div>
</div>
<div class="content">
<div class="content-header">.ol-panel > .ol-panel-info</div>
<div class="content-body">
<div class="example">
<div class="ol-panel">
<div class="ol-panel-info">
<div class="panel-section">
Info panel number 1
</div>
<div class="panel-section">
Info panel number 2
</div>
<div class="panel-section">
Info panel number 3
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
</body>
</html>

View File

@ -0,0 +1,77 @@
export interface FeatureSwitchInterface {
"enabled": boolean,
"label": string,
"name": string,
"options"?: object,
"removeArtifactsIfDisabled"?: boolean
}
class FeatureSwitch {
enabled;
label;
name;
removeArtifactsIfDisabled = true;
constructor( config:FeatureSwitchInterface ) {
this.enabled = config.enabled;
this.label = config.label;
this.name = config.name;
}
isEnabled() {
return this.enabled;
}
}
export class FeatureSwitches {
#featureSwitches:FeatureSwitch[] = [
new FeatureSwitch({
"enabled": false,
"label": "AIC",
"name": "aic"
}),
new FeatureSwitch({
"enabled": false,
"label": "ATC",
"name": "atc",
"options": {
"key": "value"
}
})
];
constructor() {
this.#removeArtifacts();
}
getSwitch( switchName:string ) {
return this.#featureSwitches.find( featureSwitch => featureSwitch.name === switchName );
}
#removeArtifacts() {
for ( const featureSwitch of this.#featureSwitches ) {
if ( !featureSwitch.isEnabled() && featureSwitch.removeArtifactsIfDisabled !== false ) {
document.querySelectorAll( "[data-feature-switch='" + featureSwitch.name + "']" ).forEach( el => el.remove() );
}
}
}
}

View File

@ -0,0 +1,35 @@
export abstract class ToggleableFeature {
#status:boolean = false;
constructor( defaultStatus:boolean ) {
this.#status = defaultStatus;
this.onStatusUpdate();
}
getStatus() : boolean {
return this.#status;
}
protected onStatusUpdate() {}
toggleStatus( force?:boolean ) : void {
if ( force ) {
this.#status = force;
} else {
this.#status = !this.#status;
}
this.onStatusUpdate();
}
}

View File

@ -1,12 +1,11 @@
import { ToggleableFeature } from "../ToggleableFeature";
import { AICFormation_Azimuth } from "./AICFormation/Azimuth";
import { AICFormation_Range } from "./AICFormation/Range";
import { AICFormation_Single } from "./AICFormation/Single";
import { AICFormationDescriptorSection } from "./AICFormationDescriptorSection";
export class AIC {
#status:boolean = true;
export class AIC extends ToggleableFeature {
#formations = [
@ -18,8 +17,10 @@ export class AIC {
constructor() {
super( false );
this.#onStatusUpdate();
this.onStatusUpdate();
// This feels kind of dirty
let $aicFormationList = document.getElementById( "aic-formation-list" );
@ -80,30 +81,10 @@ export class AIC {
}
getStatus() {
return this.#status;
}
#onStatusUpdate() {
const status:boolean = this.getStatus();
onStatusUpdate() {
// Update the DOM
document.body.classList.toggle( "aic-enabled", status );
}
toggleStatus(force?:boolean) {
if ( force ) {
this.#status = force;
} else {
this.#status = !this.#status;
}
this.#onStatusUpdate();
document.body.classList.toggle( "aic-enabled", this.getStatus() );
}

87
client/src/atc/ATC.ts Normal file
View File

@ -0,0 +1,87 @@
import { ToggleableFeature } from "../ToggleableFeature";
import Sortable from 'sortablejs';
import { ATCFLightList } from "./FlightList";
export class ATC extends ToggleableFeature {
constructor() {
super( true );
//this.#generateFlightList();
let $list = document.getElementById( "atc-strip-board-arrivals" );
if ( $list instanceof HTMLElement ) {
Sortable.create( $list, {
"handle": ".handle"
});
}
}
#generateFlightList() {
const flightList = new ATCFLightList();
const flights:any = flightList.getFlights( true );
const $tbody = document.getElementById( "atc-flight-list-table-body" );
if ( $tbody instanceof HTMLElement ) {
if ( flights.length > 0 ) {
let flight:any = {};
let $button, i;
for ( [ i, flight ] of flights.entries() ) {
const $row = document.createElement( "tr" );
$row.dataset.status = flight.status
let $td = document.createElement( "td" );
$td.innerText = flight.name;
$row.appendChild( $td );
$td = document.createElement( "td" );
$td.innerText = flight.takeOffTime;
$row.appendChild( $td );
$td = document.createElement( "td" );
$td.innerText = "00:0" + ( 5 + i );
$row.appendChild( $td );
$td = document.createElement( "td" );
$td.innerText = flight.status;
$row.appendChild( $td );
$td = document.createElement( "td" );
$button = document.createElement( "button" );
$button.innerText = "...";
$td.appendChild( $button );
$row.appendChild( $td );
$tbody.appendChild( $row );
}
}
}
}
protected onStatusUpdate(): void {
document.body.classList.toggle( "atc-enabled", this.getStatus() );
}
}

View File

@ -1,14 +0,0 @@
export interface ATCAPIInterface {
get: CallableFunction
}
export abstract class ATCAPI {
constructor() {
}
}

View File

@ -0,0 +1,7 @@
export abstract class ATCMockAPI {
constructor() {}
generateMockData() {}
}

View File

@ -0,0 +1,40 @@
import { ATCMockAPI } from "../ATCMockAPI";
export class ATCMockAPI_Flights extends ATCMockAPI {
generateMockData() {
let data = [];
const statuses = [ "unknown", "checkedIn", "readyToTaxi" ]
for ( const [ i, flightName ] of [ "Shark", "Whale", "Dolphin" ].entries() ) {
data.push({
"name": flightName,
"status": statuses[ i ],
"takeOffTime": "18:0" + i
});
}
localStorage.setItem( "flightList", JSON.stringify( data ) );
}
get( generateMockDataIfEmpty?:boolean ) : object {
generateMockDataIfEmpty = generateMockDataIfEmpty || false;
let data = localStorage.getItem( "flightList" ) || "[]";
if ( data === "[]" && generateMockDataIfEmpty ) {
this.generateMockData();
}
return JSON.parse( data );
}
}

View File

@ -0,0 +1,18 @@
import { ATCMockAPI_Flights } from "./ATCMockAPI/Flights";
export class ATCFLightList {
constructor() {
}
getFlights( generateMockDataIfEmpty?:boolean ) {
let api = new ATCMockAPI_Flights();
return api.get( generateMockDataIfEmpty );
}
}

View File

@ -14,6 +14,8 @@ import { Slider } from "./controls/slider";
import { AIC } from "./aic/AIC";
import { VisibilityControlPanel } from "./panels/visibilitycontrolpanel";
import { ATC } from "./atc/ATC";
import { FeatureSwitches } from "./FeatureSwitches";
/* TODO: should this be a class? */
var map: Map;
@ -41,13 +43,22 @@ var aic: AIC;
var aicToggleButton: Button;
var aicHelpButton: Button;
var atc: ATC;
var atcToggleButton: Button;
var altitudeSlider: Slider;
var airspeedSlider: Slider;
var connected: boolean;
var activeCoalition: string;
var featureSwitches;
function setup() {
featureSwitches = new FeatureSwitches();
/* Initialize */
map = new Map('map-container');
unitsManager = new UnitsManager();
@ -63,9 +74,6 @@ function setup() {
mouseInfoPanel = new MouseInfoPanel("mouse-info-panel");
visibilityControlPanel = new VisibilityControlPanel("visibility-control-panel");
scenarioDropdown = new Dropdown("scenario-dropdown", ["Caucasus", "Syria", "Marianas", "Nevada", "South Atlantic", "The channel"], () => { });
mapSourceDropdown = new Dropdown("map-source-dropdown", map.getLayers(), (option: string) => map.setLayer(option));
missionData = new MissionData();
/* Unit control buttons */
@ -79,15 +87,20 @@ function setup() {
airspeedSlider = new Slider("airspeed-slider", 0, 100, "kts", (value: number) => getUnitsManager().selectedUnitsSetSpeed(value / 1.94384));
/* AIC */
aic = new AIC();
aicToggleButton = new Button( "toggle-aic-button", ["images/buttons/radar.svg"], () => {
aic.toggleStatus();
});
let aicFeatureSwitch = featureSwitches.getSwitch( "aic" );
aicHelpButton = new Button( "aic-help-button", [ "images/buttons/question-mark.svg" ], () => {
aic.toggleHelp();
});
if ( aicFeatureSwitch?.isEnabled() ) {
aic = new AIC();
aicToggleButton = new Button( "toggle-aic-button", ["images/buttons/radar.svg"], () => {
aic.toggleStatus();
});
aicHelpButton = new Button( "aic-help-button", [ "images/buttons/question-mark.svg" ], () => {
aic.toggleHelp();
});
}
/* Generic clicks */
@ -104,6 +117,22 @@ function setup() {
});
/*** ATC ***/
let atcFeatureSwitch = featureSwitches.getSwitch( "atc" );
if ( atcFeatureSwitch?.isEnabled() ) {
atc = new ATC();
atcToggleButton = new Button( "atc-toggle-button", [ "images/buttons/atc.svg" ], () => {
atc.toggleStatus();
} );
}
/* Default values */
activeCoalition = "blue";
connected = false;

View File

@ -1,9 +1,9 @@
<div class="ol-panel aic-panel" id="aic-control-panel">
<div class="ol-panel aic-panel" id="aic-control-panel" data-feature-switch="aic">
<div class="olympus-button" id="toggle-aic-button"></div>
<div class="olympus-button" id="aic-help-button"></div>
</div>
<div id="aic-help" class="olympus-dialog hide">
<div id="aic-help" class="olympus-dialog hide" data-feature-switch="aic">
<div class="olympus-dialog-close">&times;</div>
<div class="olympus-dialog-header">AIC Help</div>
<div class="olympus-dialog-content">

View File

@ -1,4 +1,4 @@
<div id="aic-callsign-panel" class="aic-panel">
<div id="aic-callsign-panel" class="aic-panel" data-feature-switch="aic">
<div class="aic-panel">
<h2>My callsign</h2>
@ -8,7 +8,7 @@
</div>
<div id="aic-toolbox" class="aic-panel">
<div id="aic-toolbox" class="aic-panel" data-feature-switch="aic">
<div id="aic-control-type" class="aic-toolbox-panel">
<h2>Control</h2>

105
client/views/atc.ejs Normal file
View File

@ -0,0 +1,105 @@
<div id="atc-control-panel" data-feature-switch="atc">
<div class="ol-button" id="atc-toggle-button"></div>
</div>
<div id="atc-flight-list" class="atc-tool hide" data-feature-switch="atc">
<table>
<thead>
<tr>
<th>Flight</th>
<th>T/O</th>
<th>TTG</th>
<th>Status</th>
<th> </th>
</tr>
</thead>
<tbody id="atc-flight-list-table-body"></tbody>
</table>
</div>
<div class="atc-strip-board" data-feature-switch="atc">
<div class="atc-strip-board-header">
<div class="name">Name</div>
<div class="bearing-range">BR</div>
<div class="target-altitude">t. Alt</div>
<div class="current-altitude">Alt</div>
<div class="target-speed">t. Spd</div>
<div class="current-speed">Speed</div>
<div class="runway">RWY</div>
<div class="line">Line</div>
</div>
<div id="atc-strip-board-arrivals" class="atc-strip-board-strips ol-panel">
<div class="atc-strip-board-strip">
<div class="handle"></div>
<div class="rectangular-container">
<div class="name">Shark 3</div>
<div class="bearing-range">250 / 28</div>
<div class="target-altitude">-</div>
<div class="current-altitude">10000</div>
<div class="target-speed">-</div>
<div class="current-speed">421</div>
<div class="runway">-</div>
<div class="line">-</div>
</div>
</div>
<div class="atc-strip-board-strip">
<div class="handle"></div>
<div class="rectangular-container">
<div class="name">Shark 2</div>
<div class="bearing-range">250 / 24</div>
<div class="target-altitude">6000</div>
<div class="current-altitude">6000</div>
<div class="target-speed">-</div>
<div class="current-speed">400</div>
<div class="runway">-</div>
<div class="line">-</div>
</div>
</div>
<div class="atc-strip-board-strip">
<div class="handle"></div>
<div class="rectangular-container">
<div class="name">Shark 1</div>
<div class="bearing-range link-warning">262 / 12</div>
<div class="target-altitude">5000</div>
<div class="current-altitude">5100</div>
<div class="target-speed">-</div>
<div class="current-speed">367</div>
<div class="runway warning">-</div>
<div class="line">-</div>
</div>
</div>
<div class="atc-strip-board-strip">
<div class="handle"></div>
<div class="rectangular-container">
<div class="name">Dolphin 1</div>
<div class="bearing-range">250 / 4</div>
<div class="target-altitude link-warning">3000</div>
<div class="current-altitude warning">4100</div>
<div class="target-speed">-</div>
<div class="current-speed">511</div>
<div class="runway">25L</div>
<div class="line">2nd</div>
</div>
</div>
<div class="atc-strip-board-strip">
<div class="handle"></div>
<div class="rectangular-container">
<div class="name">Whale 1</div>
<div class="bearing-range">070 / 2</div>
<div class="target-altitude">1500</div>
<div class="current-altitude">1650</div>
<div class="target-speed link-warning">350</div>
<div class="current-speed warning">312</div>
<div class="runway">25L</div>
<div class="line">1st</div>
</div>
</div>
</div>
</div>

View File

@ -31,9 +31,12 @@
<%- include('visibilitycontrolpanel.ejs') %>
<%- include('connectionstatuspanel.ejs') %>
<%- include('mouseinfopanel.ejs') %>
<%- include('aiccontrolpanel.ejs') %>
<%- include('aicformationpanel.ejs') %>
<%- include( 'atc.ejs' ) %>
<script src="javascripts/bundle.js"></script>
</body>

9
package-lock.json generated
View File

@ -6,7 +6,8 @@
"": {
"devDependencies": {
"chai": "^4.3.7",
"mocha": "^10.2.0"
"mocha": "^10.2.0",
"sortablejs": "^1.15.0"
}
},
"node_modules/ansi-colors": {
@ -827,6 +828,12 @@
"randombytes": "^2.1.0"
}
},
"node_modules/sortablejs": {
"version": "1.15.0",
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.15.0.tgz",
"integrity": "sha512-bv9qgVMjUMf89wAvM6AxVvS/4MX3sPeN0+agqShejLU5z5GX4C75ow1O2e5k4L6XItUyAK3gH6AxSbXrOM5e8w==",
"dev": true
},
"node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",

View File

@ -1,6 +1,7 @@
{
"devDependencies": {
"chai": "^4.3.7",
"mocha": "^10.2.0"
"mocha": "^10.2.0",
"sortablejs": "^1.15.0"
}
}