(WiP) Unit spawn menu

This commit is contained in:
dpassoni 2023-03-09 17:55:35 +01:00
parent 70c73aa3a9
commit 406e515fa6
14 changed files with 707 additions and 408 deletions

View File

@ -6,6 +6,10 @@
position: relative;
}
#aircraft-spawn-menu {
height: 191px;
}
.ol-contextmenu {
display: flex;
flex-direction: column;
@ -42,18 +46,42 @@
text-align: left;
}
.ol-contextmenu>ul::-webkit-scrollbar {
width: 10px;
}
.ol-contextmenu>ul::-webkit-scrollbar-track {
background-color: transparent;
border-radius: 100px;
.ol-contextmenu>div:nth-child(2){
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
row-gap: 5px;
}
.ol-contextmenu>ul::-webkit-scrollbar-thumb {
background-color: white;
border-radius: 100px;
opacity: 0.8;
margin-top: 10px;
.ol-contextmenu .ol-select-container{
width: 100%;
flex:0 0 auto;
align-self: stretch;
}
#deploy-unit-button {
width: 100%;
text-align: center;
}
#unit-spawn-aircraft {
background-image: var( --spawn-aircraft-url );
}
#unit-spawn-ground {
background-image: var( --spawn-ground-url );
}
#unit-spawn button {
border: none;
height: 32px;
width: 32px;
}
#unit-spawn button:not(:hover){
background-color: transparent !important;
}

View File

@ -5,40 +5,40 @@
/* Variables definitions */
:root {
--accent-green : #8bff63;
--accent-light-blue : #5ca7ff;
--background-grey : #3d4651;
--background-offwhite : #f2f2f3;
--background-steel : #202831;
--primary-blue : #247be2;
--primary-grey : #CFD9E8;
--primary-red : #ff5858;
--secondary-blue-outline : #082e44;
--secondary-dark-steel : #181e25;
--secondary-gunmetal-grey : #2f2f2f;
--secondary-light-grey : #797e83;
--secondary-neutral : #111111;
--secondary-red-outline : #262222;
--secondary-yellow : #ffd46893;
--nav-text : #ECECEC;
--accent-green: #8bff63;
--accent-light-blue: #5ca7ff;
--background-grey: #3d4651;
--background-offwhite: #f2f2f3;
--background-steel: #202831;
--primary-blue: #247be2;
--primary-grey: #CFD9E8;
--primary-red: #ff5858;
--secondary-blue-outline: #082e44;
--secondary-dark-steel: #181e25;
--secondary-gunmetal-grey: #2f2f2f;
--secondary-light-grey: #797e83;
--secondary-neutral: #111111;
--secondary-red-outline: #262222;
--secondary-yellow: #ffd46893;
--nav-text: #ECECEC;
--ol-select-secondary : #545F6C;
--border-radius-xs : 2px;
--border-radius-sm : 5px;
--border-radius-md : 10px;
--border-radius-lg : 15px;
--font-weight-bolder : 600;
--ol-select-secondary: #545F6C;
--border-radius-xs: 2px;
--border-radius-sm: 5px;
--border-radius-md: 10px;
--border-radius-lg: 15px;
--font-weight-bolder: 600;
}
* {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
* {
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
@ -48,25 +48,25 @@ html {
button {
background-color:var(--background-steel);
border:1px solid var( --background-steel );
border-radius: var( --border-radius-sm );
color:whitesmoke;
cursor:pointer;
font-weight: var( --font-weight-bolder );
padding:8px;
background-color: var(--background-steel);
border: 1px solid var(--background-steel);
border-radius: var(--border-radius-sm);
color: whitesmoke;
cursor: pointer;
font-weight: var(--font-weight-bolder);
padding: 8px;
}
button[disabled="disabled"] {
color: var( --highlight-color );
cursor:not-allowed;
color: var(--highlight-color);
cursor: not-allowed;
}
.pill {
border-radius: var( --border-radius-sm );
padding:2px 6px;
width:fit-content;
border-radius: var(--border-radius-sm);
padding: 2px 6px;
width: fit-content;
}
@ -75,248 +75,282 @@ button[disabled="disabled"] {
background-color: var(--background-steel);
border-radius: 15px;
box-shadow: 0px 2px 5px #000A;
color:white;
color: white;
font-size: 12px;
height:fit-content;
padding:10px;
width:fit-content;
height: fit-content;
padding: 10px;
width: fit-content;
}
.ol-panel hr {
background-color: var( --secondary-light-grey );
border:none;
height:1px;
margin:20px 0;
width:100%;
background-color: var(--secondary-light-grey);
border: none;
height: 1px;
margin: 20px 0;
width: 100%;
}
.ol-panel-padding-lg {
padding:24px 30px;
padding: 24px 30px;
}
.ol-select-container {
width: 100%;
}
.ol-select {
color: var( --nav-text );
position: relative;
color: var(--nav-text);
}
.ol-select > .ol-select-value {
.ol-select>.ol-select-value {
align-content: center;
box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25);
cursor:pointer;
display:flex;
cursor: pointer;
display: flex;
justify-content: left;
text-align: center;
white-space: nowrap;
width: 100%;
}
.ol-select:not(.ol-select-image)>.ol-select-value {
align-items: center;
background-color: var(--background-grey);
border-radius: var(--border-radius-sm);
padding: 1em;
width: 100%;
padding-left: 20px;
padding-right: 30px;
overflow: hidden;
text-overflow: ellipsis;
}
.ol-select:not(.ol-select-image)>.ol-select-value svg {
margin-right: 10px;
}
.ol-select:not(.ol-select-image)>.ol-select-value:after {
position: absolute;
content: url("/themes/olympus/images/chevron-down.svg");
right: 10px;
}
.ol-select>.ol-select-options {
position: absolute;
overflow: hidden;
max-height: 0;
translate: 0 -2px;
z-index: 1000;
}
.ol-select.ol-select-image>.ol-select-options {
position: absolute;
}
.ol-select.is-open>.ol-select-options {
max-height: fit-content;
overflow: visible;
overflow-y: auto;
padding: 8px 0;
max-height: 300px;
min-width: 100%;
}
.ol-select>.ol-select-options>div {
background-color: var(--background-grey);
box-shadow: 0 4px 4px rgba(0, 0, 0, 0.25);
display: flex;
justify-content: left;
padding: 6px 25px;
width: 100%;
}
.ol-select>.ol-select-options>div:first-of-type {
border-top-left-radius: var(--border-radius-md);
border-top-right-radius: var(--border-radius-md);
padding-top: 16px;
}
.ol-select>.ol-select-options>div:last-of-type {
border-bottom-left-radius: var(--border-radius-md);
border-bottom-right-radius: var(--border-radius-md);
padding-bottom: 16px;
}
.ol-select>.ol-select-options div hr {
background-color: white;
height: 1px;
width: 100%;
}
.ol-select>.ol-select-options div button {
background-color: transparent;
border: none;
border-radius: 0;
font-size: 14px;
font-weight: normal;
padding: 6px 2px;
text-align: left;
white-space: nowrap;
width: fit-content;
}
.ol-select:not( .ol-select-image ) > .ol-select-value {
align-items: center;
background-color: var( --background-grey );
border-radius: var( --border-radius-sm );
justify-content: center;
padding:1em;
width:100%;
}
.ol-select:not( .ol-select-image ) > .ol-select-value svg {
margin-right: 10px;
}
.ol-select:not( .ol-select-image ) > .ol-select-value:after {
content: url( "/themes/olympus/images/chevron-down.svg" );
margin-left:10px;
}
.ol-select > .ol-select-options {
overflow:hidden;
max-height: 0;
translate:0 -2px;
}
.ol-select.ol-select-image > .ol-select-options {
position:absolute;
}
.ol-select.is-open > .ol-select-options {
max-height: fit-content;
overflow: visible;
padding:8px 0;
}
.ol-select > .ol-select-options > div {
background-color: var( --background-grey );
box-shadow: 0 4px 4px rgba(0, 0, 0, 0.25);
display:flex;
justify-content: left;
padding:6px 25px;
width:100%;
}
.ol-select > .ol-select-options > div:first-of-type {
border-top-left-radius: var( --border-radius-md );
border-top-right-radius: var( --border-radius-md );
padding-top:16px;
}
.ol-select > .ol-select-options > div:last-of-type {
border-bottom-left-radius: var( --border-radius-md );
border-bottom-right-radius: var( --border-radius-md );
padding-bottom:16px;
}
.ol-select > .ol-select-options div hr {
background-color: white;
height:1px;
width:100%;
}
.ol-select > .ol-select-options div button {
background-color: transparent;
border:none;
border-radius: 0;
font-size:14px;
font-weight: normal;
padding:6px 2px;
text-align: left;
white-space: nowrap;
width:fit-content;
}
.ol-select > .ol-select-options > div button:hover {
.ol-select>.ol-select-options>div button:hover {
text-decoration: underline;
}
.ol-select>.ol-select-options::-webkit-scrollbar {
width: 10px;
}
.ol-select>.ol-select-options::-webkit-scrollbar-track {
background-color: transparent;
border-radius: 100px;
}
.ol-select>.ol-select-options::-webkit-scrollbar-thumb {
background-color: white;
border-radius: 100px;
opacity: 0.8;
margin-top: 10px;
}
.ol-panel-list {
border-radius: var( --border-radius-sm );
border-radius: var(--border-radius-sm);
display: flex;
flex-direction: column;
height: fit-content;
height: fit-content;
row-gap: 5px;
text-align: center;
width: fit-content;
text-align: center;
width: fit-content;
}
.ol-panel-list .list-item {
border-radius: var( --border-radius-md );
display:flex;
border-radius: var(--border-radius-md);
display: flex;
justify-content: space-between;
padding: 6px 10px;
padding: 6px 10px;
}
.ol-panel-list.sortable > .sortable-item {
.ol-panel-list.sortable>.sortable-item {
align-items: center;
column-gap: 5px;
display:flex;
display: flex;
flex-direction: row;
}
.ol-panel-list.sortable > .sortable-item > .handle {
cursor:grab;
filter:invert(100);
.ol-panel-list.sortable>.sortable-item>.handle {
cursor: grab;
filter: invert(100);
}
.ol-panel-list.sortable > .sortable-item > .handle img {
.ol-panel-list.sortable>.sortable-item>.handle img {
max-width: 16px;
}
.ol-panel-board {
display:flex;
display: flex;
flex-direction: row;
justify-content: space-evenly;
}
.ol-panel-board > .panel-section {
.ol-panel-board>.panel-section {
border-right: 1px solid #555;
padding:10px;
padding: 10px;
}
.ol-panel-board > .panel-section:last-of-type {
.ol-panel-board>.panel-section:last-of-type {
border-right-width: 0;
}
.ol-panel-board h1, .ol-panel-board h2 {
font-weight: var( --font-weight-bolder );
.ol-panel-board h1,
.ol-panel-board h2 {
font-weight: var(--font-weight-bolder);
margin: 0;
padding:0 0 5px 0;
padding: 0 0 5px 0;
}
.ol-panel-board h2 {
font-size:14px;
font-size: 14px;
}
h1, h2, h3, h4, h5, h6 {
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 0px;
}
h1 {
font-size:36px;
font-size: 36px;
font-weight: 800;
}
h2 {
font-size:24px;
font-size: 24px;
font-weight: bold;
}
h3 {
font-size:18px;
font-size: 18px;
font-weight: bold;
}
h4 {
font-size:14px;
font-size: 14px;
font-weight: normal;
}
button.ol-button-warning {
border: 1px solid var( --primary-red );
color: var( --primary-red );
border: 1px solid var(--primary-red);
color: var(--primary-red);
}
nav.ol-panel {
column-gap: 20px;
display:flex;
display: flex;
flex-direction: row;
height:58px;
height: 58px;
}
nav.ol-panel > :last-child {
margin-right:5px;
nav.ol-panel> :last-child {
margin-right: 5px;
}
.ol-panel .ol-group {
column-gap: 10px;
display:flex;
display: flex;
flex-direction: row;
flex-wrap:nowrap;
flex-wrap: nowrap;
}
.ol-panel .ol-group {
border-radius: var( --border-radius-sm );
.ol-panel .ol-group {
border-radius: var(--border-radius-sm);
}
.ol-panel .ol-group-button-toggle {
align-items: center;
column-gap: 15px;
display:flex;
display: flex;
flex-wrap: nowrap;
white-space: nowrap;
width:fit-content;
width: fit-content;
}
.ol-panel .ol-group-button-toggle button {
align-items: center;
background-image: url( "/themes/olympus/images/check_square.svg");
background-image: url("/themes/olympus/images/check_square.svg");
background-position: 5px 50%;
background-repeat: no-repeat;
border:0;
border: 0;
text-indent: 15px;
}
@ -324,46 +358,47 @@ nav.ol-panel > :last-child {
.highlight-primary {
background-color: var(--secondary-light-grey);
background-color: var(--secondary-light-grey);
}
.highlight-bluefor {
background-color: var(--primary-blue);
color: var(--background-steel )
background-color: var(--primary-blue);
color: var(--background-steel)
}
.highlight-redfor {
background-color: var(--primary-red);
background-color: var(--primary-red);
}
.highlight-neutral {
background-color: var(--primary-grey);
background-color: var(--primary-grey);
color: var(--secondary-gunmetal-grey)
}
.accent-green {
color: var(--accent-green);
font-weight: var( --font-weight-bolder );
font-weight: var(--font-weight-bolder);
}
.accent-light-blue {
color: var(--accent-light-blue);
font-weight: var( --font-weight-bolder );
font-weight: var(--font-weight-bolder);
}
.accent-bluefor {
color: var(--primary-blue);
font-weight: var( --font-weight-bolder );
font-weight: var(--font-weight-bolder);
}
.accent-redfor {
color: var(--primary-red);
font-weight: var( --font-weight-bolder );
font-weight: var(--font-weight-bolder);
}
.accent-neutral {
color: var( --primary-grey );
font-weight: var( --font-weight-bolder );
color: var(--primary-grey);
font-weight: var(--font-weight-bolder);
}
@ -391,32 +426,32 @@ nav.ol-panel > :last-child {
column-gap: 2px;
}
.data-row>*:nth-child(2){
.data-row>*:nth-child(2) {
width: 100px;
}
.data-row>*:last-child{
.data-row>*:last-child {
width: 30px;
text-align: right;
}
.data-row>.icon-small{
.data-row>.icon-small {
margin: 2px;
}
.slider-container {
width: 100%;
width: 100%;
}
.slider {
width: 100%;
-webkit-appearance: none;
-webkit-appearance: none;
appearance: none;
height: 2px;
background: #d3d3d3;
outline: none;
opacity: 0.7;
-webkit-transition: .2s;
height: 2px;
background: #d3d3d3;
outline: none;
opacity: 0.7;
-webkit-transition: .2s;
transition: opacity .2s;
margin-top: 10px;
margin-bottom: 10px;
@ -431,20 +466,20 @@ nav.ol-panel > :last-child {
appearance: none;
width: 20px;
height: 20px;
background: gray;
cursor: pointer;
background: gray;
cursor: pointer;
border-radius: 999px;
}
.active .slider::-webkit-slider-thumb {
background: #5ca7ff;
background: #5ca7ff;
}
.slider::-moz-range-thumb {
width: 20px;
width: 20px;
height: 20px;
background: gray;
cursor: pointer;
background: gray;
cursor: pointer;
border-radius: 999px;
}
@ -458,20 +493,20 @@ nav.ol-panel > :last-child {
}
.ol-measure-box {
position: absolute;
padding-left: 0.5em;
padding-right: 0.5em;
padding-top: 0.2em;
padding-bottom: 0.2em;
background-color: var(--background-steel);
border-radius: 999px;
width: fit-content;
height: fit-content;
text-align: center;
color: var(--primary-grey);
position: absolute;
padding-left: 0.5em;
padding-right: 0.5em;
padding-top: 0.2em;
padding-bottom: 0.2em;
background-color: var(--background-steel);
border-radius: 999px;
width: fit-content;
height: fit-content;
text-align: center;
color: var(--primary-grey);
font-size: 12px;
z-index: 2000;
font-weight: var(--font-weight-bolder);
z-index: 2000;
font-weight: var(--font-weight-bolder);
}
@ -483,44 +518,44 @@ nav.ol-panel > :last-child {
#unit-info-panel #unit-identification {
align-items: center;
display:flex;
margin-bottom:11px;
display: flex;
margin-bottom: 11px;
}
#unit-info-panel #unit-identification .unit {
height:28px;
margin-right:6px;
width:28px;
height: 28px;
margin-right: 6px;
width: 28px;
}
#unit-info-panel #unit-identification .unit .unit-marker {
background-size: 28px 28px;
height:28px;
width:28px;
height: 28px;
width: 28px;
}
#unit-info-panel #unit-identification .unit .unit-short-label {
font-size:12px;
font-size: 12px;
}
#unit-info-panel #unit-identification #unit-name {
background-color:transparent;
border:none;
color:white;
font-size:16px;
font-weight: var( --font-weight-bolder );
outline:none;
background-color: transparent;
border: none;
color: white;
font-size: 16px;
font-weight: var(--font-weight-bolder);
outline: none;
overflow: hidden;
white-space: nowrap;
width: 150px;
}
#edit-unit-name {
background-image: url( "/images/buttons/edit.svg" );
background-image: url("/images/buttons/edit.svg");
background-repeat: no-repeat;
height:14px;
margin-left:10px;
width:15px;
height: 14px;
margin-left: 10px;
width: 15px;
}
@ -530,54 +565,95 @@ nav.ol-panel > :last-child {
}
#unit-visibility-control button {
border:none;
height:32px;
width:32px;
border: none;
height: 32px;
width: 32px;
}
#unit-visibility-control-aircraft {
background-image: var( --visibility-control-aircraft-visible-url );
background-image: var(--visibility-control-aircraft-visible-url);
}
body[data-hide-aircraft] #unit-visibility-control-aircraft {
background-image: var( --visibility-control-aircraft-hidden-url );
background-image: var(--visibility-control-aircraft-hidden-url);
}
#unit-visibility-control-ground {
background-image: var( --visibility-control-ground-visible-url );
background-image: var(--visibility-control-ground-visible-url);
}
body[data-hide-ground] #unit-visibility-control-ground {
background-image: var( --visibility-control-ground-hidden-url );
background-image: var(--visibility-control-ground-hidden-url);
}
#unit-visibility-control-sam {
background-image: var( --visibility-control-sam-visible-url );
background-image: var(--visibility-control-sam-visible-url);
}
body[data-hide-sam] #unit-visibility-control-sam {
background-image: var( --visibility-control-sam-hidden-url );
background-image: var(--visibility-control-sam-hidden-url);
}
#unit-visibility-control-threat {
background-image: var( --visibility-control-threat-visible-url );
background-image: var(--visibility-control-threat-visible-url);
}
body[data-hide-threat] #unit-visibility-control-threat {
background-image: var( --visibility-control-threat-hidden-url );
background-image: var(--visibility-control-threat-hidden-url);
}
#unit-visibility-control-naval {
background-image: var( --visibility-control-naval-visible-url );
background-image: var(--visibility-control-naval-visible-url);
}
body[data-hide-naval] #unit-visibility-control-naval {
background-image: var( --visibility-control-naval-hidden-url );
background-image: var(--visibility-control-naval-hidden-url);
}
[data-hide-blue] #coalition-visibility-control #coalition-visibility-control-blue,
[data-hide-red] #coalition-visibility-control #coalition-visibility-control-red,
[data-hide-neutral] #coalition-visibility-control #coalition-visibility-control-neutral {
background-image:none;
}
background-image: none;
}
.toggle {
--width: 40px;
--height: calc(var(--width) / 2);
--border-radius: calc(var(--height) / 2);
display: inline-block;
cursor: pointer;
}
.toggle-input {
display: none;
}
.toggle-fill {
position: relative;
width: var(--width);
height: var(--height);
border-radius: var(--border-radius);
transition: background-color 0.2s;
}
.toggle-fill::after {
content: "";
position: absolute;
top: 2;
left: 2;
height: calc(var(--height) - 4px);
width: calc(var(--height) - 4px);
background-color: #ffffff;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.25);
border-radius: var(--border-radius);
transition: transform 0.2s;
}
.toggle-input:checked ~ .toggle-fill::after {
transform: translateX(var(--height));
}
[data-coalition=blue] {background-color: var(--primary-blue) !important}
[data-coalition=red] {background-color:var(--primary-red)!important}

View File

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
inkscape:version="1.0 (4035a4fb49, 2020-05-01)"
sodipodi:docname="spawn_aircraft.svg"
id="svg8"
version="1.1"
fill="none"
viewBox="0 0 32 32"
height="32"
width="32">
<metadata
id="metadata14">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs12" />
<sodipodi:namedview
inkscape:current-layer="svg8"
inkscape:window-maximized="1"
inkscape:window-y="-8"
inkscape:window-x="-8"
inkscape:cy="22.261162"
inkscape:cx="31.929932"
inkscape:zoom="18.782524"
showgrid="false"
id="namedview10"
inkscape:window-height="1017"
inkscape:window-width="1920"
inkscape:pageshadow="2"
inkscape:pageopacity="0"
guidetolerance="10"
gridtolerance="10"
objecttolerance="10"
borderopacity="1"
bordercolor="#666666"
pagecolor="#ffffff" />
<rect
style="fill:none"
id="rect2"
fill="white"
rx="7.5"
height="31"
width="31"
y="0.5"
x="0.5" />
<path
style="fill:#ffffff;fill-opacity:1"
id="path4"
fill="#202831"
d="M21.3047 14C22.2344 14 23.875 14.793 23.875 15.75C23.875 16.7344 22.2344 17.5 21.3047 17.5H18.1055L15.3711 22.3125C15.207 22.5859 14.9062 22.75 14.6055 22.75H13.0742C12.7734 22.75 12.5547 22.4766 12.6367 22.2031L13.9766 17.5H11.1875L9.98438 19.0859C9.90234 19.1953 9.79297 19.25 9.65625 19.25H8.50781C8.28906 19.25 8.125 19.0859 8.125 18.8672C8.125 18.8398 8.125 18.8125 8.125 18.7852L9 15.75L8.125 12.7422C8.125 12.7148 8.125 12.6875 8.125 12.6328C8.125 12.4414 8.28906 12.25 8.50781 12.25H9.65625C9.79297 12.25 9.90234 12.332 9.98438 12.4414L11.1875 14H13.9766L12.6367 9.32422C12.5547 9.05078 12.7734 8.75 13.0742 8.75H14.6055C14.9062 8.75 15.207 8.94141 15.3711 9.21484L18.1055 14H21.3047Z" />
<rect
style="fill:none;stroke:none"
id="rect6"
stroke="white"
rx="7.5"
height="31"
width="31"
y="0.5"
x="0.5" />
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.6 KiB

View File

@ -162,4 +162,10 @@
--unit-building-marker-neutral-url: url( "/themes/olympus/images/icon_building_neutral.svg" );
--unit-building-marker-red-url: url( "/themes/olympus/images/icon_building_red.svg" );
/*** Context menu ***/
--spawn-aircraft-url: url( "/themes/olympus/images/spawn_aircraft.svg" );
--spawn-ground-url: url( "/themes/olympus/images/spawn_ground.svg" );
}

View File

@ -1,41 +1,63 @@
import { LatLng } from "leaflet";
import { getActiveCoalition, setActiveCoalition } from "..";
import { ContextMenuOption } from "../@types/dom";
import { ClickEvent } from "../map/map";
import { spawnAircraft } from "../server/server";
import { aircraftDatabase } from "../units/aircraftdatabase";
import { Dropdown } from "./dropdown";
export interface SpawnOptions {
role: string;
type: string;
latlng: LatLng;
coalition: string;
loadout: string | null;
airbaseName: string | null;
}
export class ContextMenu {
#container: HTMLElement | null;
#latlng: LatLng = new LatLng(0, 0);
#aircraftRoleDropdown: Dropdown;
#aircraftTypeDropdown: Dropdown;
#aircraftLoadoutDropdown: Dropdown;
//#unitsNumberDropdown: Dropdown;
#spawnOptions: SpawnOptions = {role: "", type: "", latlng: this.#latlng, loadout: null, coalition: "blue", airbaseName: null};
constructor(id: string,) {
this.#container = document.getElementById(id);
this.#container?.querySelector("#switch")?.addEventListener('change', (e) => this.#onSwitch(e))
this.#container?.querySelector("#context-menu-switch")?.addEventListener('change', (e) => this.#onSwitch(e));
this.#aircraftRoleDropdown = new Dropdown("role-options", (role: string) => this.#setAircraftRole(role), aircraftDatabase.getRoles());
this.#aircraftTypeDropdown = new Dropdown("aircraft-options", (type: string) => this.#setAircraftType(type));
this.#aircraftLoadoutDropdown = new Dropdown("loadout-options", (loadout: string) => this.#setAircraftLoadout(loadout));
//this.#unitsNumberDropdown = new Dropdown("#units-options", this.#setAircraftType, [""]);
document.addEventListener("contextMenuShow", (e: any) => {
this.#container?.querySelector("#aircraft-spawn-menu")?.classList.toggle("hide", e.detail.unitType !== "aircraft");
})
document.addEventListener("contextMenuDeployAircraft", () => {
this.hide();
this.#spawnOptions.coalition = getActiveCoalition();
if (this.#spawnOptions)
spawnAircraft(this.#spawnOptions);
})
this.hide();
}
show(x: number, y: number, title: string, options: ContextMenuOption[], showCoalition: boolean) {
show(x: number, y: number, latlng: LatLng) {
this.#spawnOptions.latlng = latlng;
this.#container?.classList.toggle("hide", false);
this.#container?.querySelector("#list")?.replaceChildren(...options.map((option: ContextMenuOption) => {
var li = document.createElement("li");
var button = document.createElement("button");
button.textContent = option.tooltip;
li.appendChild(button);
button.addEventListener("click", (e: MouseEvent) => option.callback((e.target as HTMLButtonElement).innerText));
return button;
}));
this.#container?.querySelector("#switch")?.classList.toggle("hide", !showCoalition);
if (this.#container != null && options.length >= 1) {
var titleDiv = this.#container.querySelector("#title");
if (titleDiv)
titleDiv.textContent = title;
if (x - this.#container.offsetWidth / 2 + this.#container.offsetWidth < window.innerWidth)
this.#container.style.left = x - this.#container.offsetWidth / 2 + "px";
if (this.#container != null) {
if (x + this.#container.offsetWidth < window.innerWidth)
this.#container.style.left = x + "px";
else
this.#container.style.left = window.innerWidth - this.#container.offsetWidth + "px";
if (y - 20 + this.#container.offsetHeight < window.innerHeight)
this.#container.style.top = y - 20 + "px";
if (y + this.#container.offsetHeight < window.innerHeight)
this.#container.style.top = y + "px";
else
this.#container.style.top = window.innerHeight - this.#container.offsetHeight + "px";
}
@ -47,10 +69,43 @@ export class ContextMenu {
#onSwitch(e: any) {
if (this.#container != null) {
if (e.currentTarget.checked)
if (e.srcElement.checked)
setActiveCoalition("red");
else
setActiveCoalition("blue");
}
}
#setAircraftRole(role: string)
{
if (this.#spawnOptions != null)
{
this.#spawnOptions.role = role;
this.#aircraftTypeDropdown.setOptions(aircraftDatabase.getLabelsByRole(role));
}
}
#setAircraftType(type: string)
{
if (this.#spawnOptions != null)
{
this.#spawnOptions.type = type;
this.#aircraftLoadoutDropdown.setOptions(aircraftDatabase.getLoadoutNamesByRole(type, this.#spawnOptions.role));
}
}
#setAircraftLoadout(loadoutName: string)
{
if (this.#spawnOptions != null)
{
var loadout = aircraftDatabase.getLoadoutsByName(this.#spawnOptions.type, loadoutName);
if (loadout)
this.#spawnOptions.loadout = loadout.code;
}
}
#setUnitsNumber(unitsNumber: string)
{
}
}

View File

@ -0,0 +1,32 @@
export class Dropdown {
#element: HTMLElement;
#options: HTMLElement;
#value: HTMLElement;
#callback: CallableFunction;
constructor(ID: string, callback: CallableFunction, options: string[] | null = null)
{
this.#element = <HTMLElement>document.getElementById(ID);
var element = this.#element;
this.#options = <HTMLElement>this.#element.querySelector(".ol-select-options");
this.#value = <HTMLElement>this.#element.querySelector(".ol-select-value");
this.#callback = callback;
if (options != null)
this.setOptions(options);
}
setOptions(options: string[])
{
this.#options.replaceChildren(...options.map((option: string) => {
var div = document.createElement("div");
var button = document.createElement("button");
button.textContent = option;
div.appendChild(button);
button.addEventListener("click", (e: MouseEvent) => {
this.#value.innerText = option;
this.#callback(option);
});
return div;
}));
}
}

View File

@ -248,6 +248,7 @@ export function getConnectionStatusPanel() {
export function setActiveCoalition(newActiveCoalition: string) {
activeCoalition = newActiveCoalition;
document.querySelectorAll('[data-coalition]').forEach((element: any) => {element.setAttribute("data-coalition", activeCoalition)});
}
export function getActiveCoalition() {

View File

@ -5,6 +5,7 @@ import { aircraftDatabase } from "../units/aircraftdatabase";
import { unitTypes } from "../units/unittypes";
import { BoxSelect } from "./boxselect";
import { ContextMenuOption } from "../@types/dom";
import { SpawnOptions } from "../controls/contextmenu";
export const IDLE = "IDLE";
export const MOVE_UNIT = "MOVE_UNIT";
@ -116,10 +117,10 @@ export class Map extends L.Map {
}
/* Context Menu */
showContextMenu(e: ClickEvent | SpawnEvent, title: string, options: ContextMenuOption[], showCoalition: boolean = false) {
var x = e.x;
var y = e.y;
getContextMenu()?.show(x, y, title, options, showCoalition);
showContextMenu(e: any, spawnOptions: SpawnOptions | null = null) {
var x = e.originalEvent.x;
var y = e.originalEvent.y;
getContextMenu()?.show(x, y, e.latlng);
document.dispatchEvent(new CustomEvent("mapContextMenu"));
}
@ -139,7 +140,7 @@ export class Map extends L.Map {
/* Spawn from air base */
spawnFromAirbase(e: SpawnEvent)
{
this.#aircraftSpawnMenu(e);
//this.#aircraftSpawnMenu(e);
}
/* Event handlers */
@ -164,15 +165,8 @@ export class Map extends L.Map {
#onContextMenu(e: any) {
this.hideContextMenu();
if (this.#state === IDLE) {
var spawnEvent: SpawnEvent = {x: e.originalEvent.x, y: e.originalEvent.y, latlng: e.latlng, airbaseName: null, coalitionID: null};
if (this.#state == IDLE) {
var options = [
{ "tooltip": "Spawn air unit", "src": "spawnAir.png", "callback": () => this.#aircraftSpawnMenu(spawnEvent) },
{ "tooltip": "Spawn ground unit", "src": "spawnGround.png", "callback": () => this.#groundUnitSpawnMenu(spawnEvent) },
{ "tooltip": "Smoke", "src": "spawnSmoke.png", "callback": () => this.#smokeSpawnMenu(spawnEvent) },
//{ "tooltip": "Explosion", "src": "spawnExplosion.png", "callback": () => this.#explosionSpawnMenu(e) }
]
this.showContextMenu(spawnEvent, "Action", options, false);
this.showContextMenu(e);
}
}
else if (this.#state === MOVE_UNIT) {
@ -215,99 +209,4 @@ export class Map extends L.Map {
this.#lastMousePosition.x = e.originalEvent.x;
this.#lastMousePosition.y = e.originalEvent.y;
}
/* Spawning menus */
#aircraftSpawnMenu(e: SpawnEvent) {
var options = [
{ 'coalition': true, 'tooltip': 'CAP', 'src': 'spawnCAP.png', 'callback': () => this.#selectAircraft(e, "cap") },
{ 'coalition': true, 'tooltip': 'CAS', 'src': 'spawnCAS.png', 'callback': () => this.#selectAircraft(e, "cas") },
{ 'coalition': true, 'tooltip': 'Strike', 'src': 'spawnStrike.png', 'callback': () => this.#selectAircraft(e, "strike") },
{ 'coalition': true, 'tooltip': 'Recce', 'src': 'spawnStrike.png', 'callback': () => this.#selectAircraft(e, "reconnaissance") },
{ 'coalition': true, 'tooltip': 'Tanker', 'src': 'spawnTanker.png', 'callback': () => this.#selectAircraft(e, "tanker") },
{ 'coalition': true, 'tooltip': 'AWACS', 'src': 'spawnAWACS.png', 'callback': () => this.#selectAircraft(e, "awacs") },
{ 'coalition': true, 'tooltip': 'Drone', 'src': 'spawnDrone.png', 'callback': () => this.#selectAircraft(e, "drone") },
{ 'coalition': true, 'tooltip': 'Transport', 'src': 'spawnTransport.png', 'callback': () => this.#selectAircraft(e, "transport") },
]
if (e.airbaseName != null)
this.showContextMenu(e, "Spawn at " + e.airbaseName, options, true);
else
this.showContextMenu(e, "Spawn air unit", options, true);
}
#groundUnitSpawnMenu(e: SpawnEvent) {
var options = [
{'coalition': true, 'tooltip': 'Howitzer', 'src': 'spawnHowitzer.png', 'callback': () => this.#selectGroundUnit(e, "Howitzers")},
{'coalition': true, 'tooltip': 'SAM', 'src': 'spawnSAM.png', 'callback': () => this.#selectGroundUnit(e, "SAM")},
{'coalition': true, 'tooltip': 'IFV', 'src': 'spawnIFV.png', 'callback': () => this.#selectGroundUnit(e, "IFV")},
{'coalition': true, 'tooltip': 'Tank', 'src': 'spawnTank.png', 'callback': () => this.#selectGroundUnit(e, "Tanks")},
{'coalition': true, 'tooltip': 'MLRS', 'src': 'spawnMLRS.png', 'callback': () => this.#selectGroundUnit(e, "MLRS")},
{'coalition': true, 'tooltip': 'Radar', 'src': 'spawnRadar.png', 'callback': () => this.#selectGroundUnit(e, "Radar")},
{'coalition': true, 'tooltip': 'Unarmed', 'src': 'spawnUnarmed.png', 'callback': () => this.#selectGroundUnit(e, "Unarmed")}
]
this.showContextMenu(e, "Spawn ground unit", options, true);
}
#smokeSpawnMenu(e: SpawnEvent) {
this.hideContextMenu();
var options = [
{'tooltip': 'Red smoke', 'src': 'spawnSmoke.png', 'callback': () => {this.hideContextMenu(); spawnSmoke('red', e.latlng)}, 'tint': 'red'},
{'tooltip': 'White smoke', 'src': 'spawnSmoke.png', 'callback': () => {this.hideContextMenu(); spawnSmoke('white', e.latlng)}, 'tint': 'white'},
{'tooltip': 'Blue smoke', 'src': 'spawnSmoke.png', 'callback': () => {this.hideContextMenu(); spawnSmoke('blue', e.latlng)}, 'tint': 'blue'},
{'tooltip': 'Green smoke', 'src': 'spawnSmoke.png', 'callback': () => {this.hideContextMenu(); spawnSmoke('green', e.latlng)}, 'tint': 'green'},
{'tooltip': 'Orange smoke', 'src': 'spawnSmoke.png', 'callback': () => {this.hideContextMenu(); spawnSmoke('orange', e.latlng)}, 'tint': 'orange'},
]
this.showContextMenu(e, "Spawn smoke", options, false);
}
#explosionSpawnMenu(e: SpawnEvent) {
}
/* Show unit selection for air units */
#selectAircraft(e: SpawnEvent, role: string) {
this.hideContextMenu();
var options = aircraftDatabase.getLabelsByRole(role);
this.showContextMenu(e, "Select aircraft",
options.map((option: string) => {
return {tooltip: option, src: "", callback: (label: string) => {
this.hideContextMenu();
var name = aircraftDatabase.getNameByLabel(label);
if (name != null)
this.#unitSelectPayload(e, name, role);
}}}), true);
}
/* Show weapon selection for air units */
#unitSelectPayload(e: SpawnEvent, unitType: string, role: string) {
this.hideContextMenu();
var options = aircraftDatabase.getLoadoutNamesByRole(unitType, role);
//options = payloadNames[unitType]
if (options != undefined && options.length > 0) {
options.sort();
this.showContextMenu({x: e.x, y: e.y, latlng: e.latlng}, "Select loadout",
options.map((option: string) => {
return {tooltip: option, src: "", callback: (loadoutName: string) => {
this.hideContextMenu();
var loadout = aircraftDatabase.getLoadoutsByName(unitType, loadoutName);
spawnAircraft(unitType, e.latlng, getActiveCoalition(), loadout != null? loadout.code: "", e.airbaseName);
}}}), true);
}
else {
spawnAircraft(unitType, e.latlng, getActiveCoalition());
}
}
/* Show unit selection for ground units */
#selectGroundUnit(e: any, group: string)
{
this.hideContextMenu();
var options = unitTypes.vehicles[group];
options.sort();
this.showContextMenu(e, "Select ground unit",
options.map((option: string) => {
return {tooltip: option, src: "", callback: (unitType: string) => {
this.hideContextMenu();
spawnGroundUnit(unitType, e.latlng, getActiveCoalition());
}}}), true);
}
}

View File

@ -84,9 +84,9 @@ export class MissionHandler
else
options = ["Spawn unit"];
getMap().showContextMenu(e.originalEvent, e.sourceTarget.getName(),
options.map((option) => {return {tooltip: option, src: "", callback: (label: string) => {this.#onAirbaseOptionSelection(e, label)}}}, false)
)
//getMap().showContextMenu(e.originalEvent, e.sourceTarget.getName(),
// options.map((option) => {return {tooltip: option, src: "", callback: (label: string) => {this.#onAirbaseOptionSelection(e, label)}}}, false)
//)
}
#onAirbaseOptionSelection(e: any, option: string) {

View File

@ -1,5 +1,6 @@
import * as L from 'leaflet'
import { setConnected } from '..';
import { SpawnOptions } from '../controls/contextmenu';
/* Edit here to change server address */
const REST_ADDRESS = "http://localhost:30000/olympus";
@ -69,8 +70,8 @@ export function spawnGroundUnit(type: string, latlng: L.LatLng, coalition: strin
POST(data, () => { });
}
export function spawnAircraft(type: string, latlng: L.LatLng, coalition: string, payloadName: string | null = null, airbaseName: string | null = null) {
var command = { "type": type, "location": latlng, "coalition": coalition, "payloadName": payloadName != null? payloadName: "", "airbaseName": airbaseName != null? airbaseName: ""};
export function spawnAircraft(spawnOptions: SpawnOptions) {
var command = { "type": spawnOptions.type, "location": spawnOptions.latlng, "coalition": spawnOptions.coalition, "payloadName": spawnOptions.loadout != null? spawnOptions.loadout: "", "airbaseName": spawnOptions.airbaseName != null? spawnOptions.airbaseName: ""};
var data = { "spawnAir": command }
POST(data, () => { });
}

View File

@ -290,7 +290,7 @@ export class Unit extends Marker {
'Attack',
'Follow'
]
getMap().showContextMenu(e.originalEvent, "Action: " + this.getData().unitName, options.map((option: string) => {return {tooltip: option, src: "", callback: (action: string) => this.#executeAction(action)}}));
//getMap().showContextMenu(e.originalEvent, "Action: " + this.getData().unitName, options.map((option: string) => {return {tooltip: option, src: "", callback: (action: string) => this.#executeAction(action)}}));
}
#executeAction(action: string) {

View File

@ -6,6 +6,24 @@ export class UnitDatabase {
}
getRoles()
{
var roles: string[] = [];
for (let unit in this.units)
{
for (let loadout of this.units[unit].loadouts)
{
for (let role of loadout.roles)
{
role = role.toUpperCase();
if (role !== "" && !roles.includes(role))
roles.push(role);
}
}
}
return roles;
}
getLabelsByRole(role: string)
{
var units = [];
@ -13,7 +31,7 @@ export class UnitDatabase {
{
for (let loadout of this.units[unit].loadouts)
{
if (loadout.roles.includes(role))
if (loadout.roles.includes(role) || loadout.roles.includes(role.toLowerCase()))
{
units.push(this.units[unit].label)
break;
@ -28,7 +46,7 @@ export class UnitDatabase {
var loadouts = [];
for (let loadout of this.units[unit].loadouts)
{
if (loadout.roles.includes(role) || loadout.roles.includes(""))
if (loadout.roles.includes(role) || loadout.roles.includes(role.toLowerCase()) || loadout.roles.includes(""))
{
loadouts.push(loadout.name)
}

View File

@ -1,19 +1,44 @@
<div id="contextmenu" class="ol-contextmenu">
<div class="ol-panel">
<div id="title"> Title </div>
<div id="switch">
<input type="checkbox">
<label id="context-menu-switch" class="toggle" for="context-menu-toggle">
<input class="toggle-input" name="" type="checkbox" id="context-menu-toggle">
<div data-coalition="blue" class="toggle-fill"></div>
</label>
<div id="unit-spawn" class="ol-group">
<button data-coalition="blue" id="unit-spawn-aircraft" title="Spawn aircraft" data-on-click="contextMenuShow"
data-on-click-params='{ "unitType": "aircraft" }'></button>
<button data-coalition="blue" id="unit-spawn-ground" title="Spawn ground unit" data-on-click="contextMenuShow"
data-on-click-params='{ "unitType": "ground" }'></button>
</div>
</div>
<ul id="list" class="ol-panel ol-scroll">
<li><button>Option A</button></li>
<li><button>Option B</button></li>
<li><button>Option C</button></li>
<li><button>Option D</button></li>
<li><button>Option D</button></li>
<li><button>Option D</button></li>
<li><button>Option D</button></li>
<li><button>Option D</button></li>
<li><button>Option D</button></li>
</ul>
<div id="aircraft-spawn-menu" class="ol-panel hide">
<div class="ol-select-container">
<div id="role-options" class="ol-select">
<div class="ol-select-value">Aircraft role</div>
<div class="ol-select-options">
<!-- This is where all the aircraft roles buttons will be shown-->
</div>
</div>
</div>
<div class="ol-select-container">
<div id="aircraft-options" class="ol-select">
<div class="ol-select-value">Aircraft type</div>
<div class="ol-select-options">
<div>Select role first</div>
<!-- This is where all the aircraft types buttons will be shown-->
</div>
</div>
</div>
<div class="ol-select-container">
<div id="loadout-options" class="ol-select">
<div class="ol-select-value">Loadout</div>
<div class="ol-select-options">
<div>Select type first</div>
<!-- This is where all the aircraft loadouts buttons will be shown-->
</div>
</div>
</div>
<button id="deploy-unit-button" title="" data-coalition="blue" data-on-click="contextMenuDeployUnit">Deploy units</button>
</div>
</div>