Implement more wizard page, result page still wip
@ -1,142 +1,89 @@
|
||||
<style>
|
||||
#manager-connections .option {
|
||||
background-color: var(--background);
|
||||
border: 1px solid var(--offwhite);
|
||||
width: 220px;
|
||||
height: 60px;
|
||||
color: var(--offwhite);
|
||||
display: flex;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
padding-left: 15px;
|
||||
align-items: center;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
background-color: transparent;
|
||||
color: var(--offwhite);
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#manager-connections .option:hover {
|
||||
color: var(--background);
|
||||
background-color: var(--offwhite);
|
||||
}
|
||||
|
||||
#manager-connections .buttons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 15px;
|
||||
}
|
||||
|
||||
#manager-connections .success,
|
||||
#manager-connections .error {
|
||||
#connections-page .success,
|
||||
#connections-page .error {
|
||||
position: absolute;
|
||||
left: 420px;
|
||||
left: 320px;
|
||||
display: flex;
|
||||
width: 150px;
|
||||
column-gap: 8px;
|
||||
}
|
||||
|
||||
#manager-connections .success {
|
||||
#connections-page .success {
|
||||
content: url("./icons/check-solid-green.svg");
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
#manager-connections .error img {
|
||||
#connections-page .error img {
|
||||
content: url("./icons/triangle-exclamation-solid.svg");
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
#manager-connections .error span {
|
||||
#connections-page .error span {
|
||||
font-weight: 600;
|
||||
font-size: 12px;
|
||||
color: var(--red);
|
||||
height: fit-content;
|
||||
}
|
||||
</style>
|
||||
<div id="manager-connections">
|
||||
<div class="step-summary">
|
||||
<div class="blue <%= singleInstance? 'hide': '' %>"><%= install? 'User path': 'Instance selection' %></div>
|
||||
<div class="blue">Type of install</div>
|
||||
<div class="white">Ports and address</div>
|
||||
<div class="empty">Passwords</div>
|
||||
<div class="empty"> <%= install? 'Install': 'Update' %></div>
|
||||
<div id="connections-page">
|
||||
<div class="instructions">
|
||||
<div class="step">
|
||||
Step 3 of 4
|
||||
</div>
|
||||
<div class="title">
|
||||
Manually set Olympus port and address settings
|
||||
</div>
|
||||
<div class="note">
|
||||
Please note: you may be required to allow these ports through your firewall and modem/router via port
|
||||
forwarding. <br>
|
||||
Otherwise, others may not be able to connect to Olympus.
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<% if (selectAutoOrManual) { %>
|
||||
<div class="instructions">
|
||||
<span>
|
||||
Do you want to set port and address settings manually?
|
||||
</span>
|
||||
<span>
|
||||
We can auto setup ports and addresses for you, or you can set the manually. <br>
|
||||
If you don't have an understanding of how Olympus works, we recommend the auto option.
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="buttons">
|
||||
<div class="option button auto">
|
||||
Auto apply settings
|
||||
<div class="wizard-inputs">
|
||||
<div class="input-group client-port">
|
||||
<span>Client port
|
||||
<img src="./icons/circle-info-solid.svg"
|
||||
title="This port is used to allow access to Olympus.
|
||||
Be sure to allow this port through your firewall if you want people to connect remotely">
|
||||
</span>
|
||||
<div>
|
||||
<input type="number" min="1024" max="65535" value="<%= activeInstance[" clientPort"] %>">
|
||||
<img class="success hide">
|
||||
<div class="error hide">
|
||||
<img> <span>Port already in use</span>
|
||||
</div>
|
||||
<div class="option button manual">
|
||||
Manually set options
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<% } else { %>
|
||||
<div class="instructions">
|
||||
<span>
|
||||
Enter the ports and address to use.
|
||||
</span>
|
||||
<span>
|
||||
Select client and backend ports, making sure they are free to use with the provided check. <br>
|
||||
Unless you want to support direct API calls to the backend, you can keep the address to localhost even for dedicated servers.
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="input-group client-port">
|
||||
<span>Client port
|
||||
<img src="./icons/circle-info-solid.svg" title="This port is used to allow access to Olympus. Be sure to allow this port through your firewall if you want people to connect remotely">
|
||||
</span>
|
||||
<div>
|
||||
<input type="number" min="1024" max="65535" value="<%= activeInstance["clientPort"] %>">
|
||||
<img class="success hide">
|
||||
<div class="error hide">
|
||||
<img> <span>Port already in use</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group backend-port">
|
||||
<span>Backend port
|
||||
<img src="./icons/circle-info-solid.svg" title="This port is used to allow access to Olympus. Be sure to allow this port through your firewall if you want people to connect remotely.">
|
||||
</span>
|
||||
<div>
|
||||
<input type="number" min="1024" max="65535" value="<%= activeInstance["backendPort"] %>">
|
||||
<img class="success hide">
|
||||
<div class="error hide">
|
||||
<img> <span>Port already in use</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group backend-address">
|
||||
<span>Backend address
|
||||
<img src="./icons/circle-info-solid.svg" title="This is the backend address Olympus will listen on. Unless you know what you are doing, leave it as localhost, even for dedicated server installations.">
|
||||
</span>
|
||||
<input type="text" value="<%= activeInstance["backendAddress"] %>">
|
||||
</div>
|
||||
<% } %>
|
||||
<div class="buttons-footer">
|
||||
<div class="button back">
|
||||
Back
|
||||
</div>
|
||||
<div class="button next">
|
||||
Next
|
||||
</div>
|
||||
</div>
|
||||
<div class="button cancel">
|
||||
<%= install? "Cancel installation": "Cancel editing" %>
|
||||
<div class="input-group backend-port">
|
||||
<span>Backend port
|
||||
<img src="./icons/circle-info-solid.svg"
|
||||
title="This port is used by Olympus to communicate with DCS.
|
||||
You only need to allow it through your firewall if you enable direct API connection">
|
||||
</span>
|
||||
<div>
|
||||
<input type="number" min="1024" max="65535" value="<%= activeInstance[" backendPort"] %>"
|
||||
onchange="signal('onBackendPortChanged', this.value)">
|
||||
<img class="success hide">
|
||||
<div class="error hide">
|
||||
<img> <span>Port already in use</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-group backend-address">
|
||||
<span onclick="signal('onEnableAPIClicked')">
|
||||
<div class="checkbox"></div> Enable direct backend API connection
|
||||
<img src="./icons/circle-info-solid.svg"
|
||||
title="Allows services to connect to Olympus directly.
|
||||
This is NOT NEEDED for normal Olympus operation, even for dedicated servers.
|
||||
Leave it unchecked if in doubt.">
|
||||
</span>
|
||||
</div>
|
||||
<div class="note warning">
|
||||
Note: if you enable direct backend API connection, you will be required to run DCS as admin or run the netsh
|
||||
command for others to connect. Leave unchecked if you don't know what this is. <br>See the Olympus
|
||||
documentation for more details.
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
25
manager/ejs/connectionsType.ejs
Normal file
@ -0,0 +1,25 @@
|
||||
<style>
|
||||
|
||||
</style>
|
||||
<div>
|
||||
<div class="instructions">
|
||||
<div class="step">
|
||||
Step 2 of 4
|
||||
</div>
|
||||
<div class="title">
|
||||
Do you want to set port and address settings?
|
||||
</div>
|
||||
<div class="description">
|
||||
We can automatically set port and address settings for you, or you can set them manually. <br>
|
||||
If you don't have a good understanding of how Olympus works, we recommend the <i>auto apply settings</i> option.
|
||||
</div>
|
||||
</div>
|
||||
<div class="wizard-inputs">
|
||||
<div class="button radio auto selected" onclick="signal('onConnectionsTypeClicked', 'auto')">
|
||||
Auto apply settings
|
||||
</div>
|
||||
<div class="button radio manual" onclick="signal('onConnectionsTypeClicked', 'manual')">
|
||||
Manually set
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -1,51 +1,37 @@
|
||||
<style>
|
||||
|
||||
</style>
|
||||
<div id="manager-passwords">
|
||||
<div class="step-summary">
|
||||
<div class="blue <%= singleInstance? 'hide': '' %>"><%= install? 'User path': 'Instance selection' %></div>
|
||||
<div class="blue">Type of install</div>
|
||||
<div class="blue">Ports and address</div>
|
||||
<div class="white">Passwords</div>
|
||||
<div class="empty"> <%= install? 'Install': 'Update' %></div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="instructions">
|
||||
<span>
|
||||
Enter your passwords to access Olympus
|
||||
</span>
|
||||
<span>
|
||||
When logging into Olympus, these passwords will let you access the different roles. Gamemaster is the default.
|
||||
</span>
|
||||
</div>
|
||||
|
||||
</style>
|
||||
<div id="passwords-page">
|
||||
<div class="instructions">
|
||||
<div class="step">
|
||||
Step 4 of 4
|
||||
</div>
|
||||
<div class="title">
|
||||
Enter your passwords for Olympus
|
||||
</div>
|
||||
<div class="description">
|
||||
When logging into Olympus, these passwords will let you access the different roles. <br>
|
||||
Game Master is the default and is used as a global commander. The other two are used as a part of the RTS mode.
|
||||
</div>
|
||||
</div>
|
||||
<div class="wizard-inputs">
|
||||
<div class="input-group game-master">
|
||||
<span>Game Master Password<img src="./icons/circle-info-solid.svg" title="This password is used to access Olympus as Game Master with full privileges.">
|
||||
<span>Game Master Password<img src="./icons/circle-info-solid.svg"
|
||||
title="This password is used to access Olympus as Game Master with full privileges.">
|
||||
</span>
|
||||
<input type="password" minlength="8">
|
||||
</div>
|
||||
<div class="input-group blue-commander">
|
||||
<span>Blue Commander Password<img src="./icons/circle-info-solid.svg" title="This password is used to access Olympus as blue coalition Commander.">
|
||||
<span>Blue Commander Password<img src="./icons/circle-info-solid.svg"
|
||||
title="This password is used to access Olympus as blue coalition Commander.">
|
||||
</span>
|
||||
<input type="password" minlength="8">
|
||||
</div>
|
||||
<div class="input-group red-commander">
|
||||
<span>Red Commander Password<img src="./icons/circle-info-solid.svg" title="This password is used to access Olympus as red coalition Commander.">
|
||||
<span>Red Commander Password<img src="./icons/circle-info-solid.svg"
|
||||
title="This password is used to access Olympus as red coalition Commander.">
|
||||
</span>
|
||||
<input type="password" minlength="8">
|
||||
</div>
|
||||
<div class="buttons-footer">
|
||||
<div class="button back">
|
||||
Back
|
||||
</div>
|
||||
<div class="button next">
|
||||
Next
|
||||
</div>
|
||||
</div>
|
||||
<% if (!singleInstance) { %>
|
||||
<div class="button cancel">
|
||||
<%= install? "Cancel installation": "Cancel editing" %>
|
||||
</div>
|
||||
<% } %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,146 +1,128 @@
|
||||
<style>
|
||||
#manager-result .content {
|
||||
width: 100% !important;
|
||||
}
|
||||
|
||||
#manager-result img.success {
|
||||
content: url("./icons/check-solid-green.svg");
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
#result-page {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 30px;
|
||||
padding: 60px 120px;
|
||||
}
|
||||
|
||||
#manager-result img.error {
|
||||
content: url("./icons/triangle-exclamation-solid.svg");
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
#result-page .result-summary {
|
||||
padding: 25px 15px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 10px;
|
||||
}
|
||||
|
||||
#manager-result img.wait {
|
||||
content: url("./icons/spinner-solid.svg");
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
animation: rotate 2s linear infinite;
|
||||
}
|
||||
|
||||
#manager-result .summary {
|
||||
font-weight: 600;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
#manager-result .summary.success {
|
||||
color: var(--green);
|
||||
}
|
||||
|
||||
#manager-result .summary.error {
|
||||
color: var(--red);
|
||||
}
|
||||
|
||||
#manager-result .info {
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
color: var(--offwhite);
|
||||
}
|
||||
|
||||
#manager-result .step {
|
||||
#result-page .result-summary .title {
|
||||
font-weight: bold;
|
||||
font-size: 15px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#result-page .result-summary .title img {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
#result-page .result-summary .description {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
#result-page .result-summary.wait{
|
||||
color: var(--offwhite);
|
||||
column-gap: 10px;
|
||||
border: 1px solid var(--offwhite);
|
||||
}
|
||||
|
||||
#manager-result .result {
|
||||
cursor: pointer;
|
||||
background-color: var(--darkgray);
|
||||
border-left: 5px solid var(--blue);
|
||||
width: 100%;
|
||||
height: 80px;
|
||||
color: white;
|
||||
#result-page .result-summary.success{
|
||||
color: var(--background-color);
|
||||
background-color: var(--green);
|
||||
}
|
||||
|
||||
#result-page .result-summary.error{
|
||||
color: var(--background-color);
|
||||
background-color: var(--red);
|
||||
}
|
||||
|
||||
#result-page .usage-instructions {
|
||||
background-color: var(--background-usage);
|
||||
border-radius: 10px;
|
||||
display: flex;
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
padding-left: 15px;
|
||||
flex-direction: row;
|
||||
column-gap: 25px;
|
||||
align-items: center;
|
||||
border-radius: 5px;
|
||||
width: 500px;
|
||||
padding: 25px;
|
||||
}
|
||||
|
||||
#manager-result .result>img {
|
||||
margin-left: 5px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
#manager-result .result>div {
|
||||
#result-page .usage-instructions>div {
|
||||
color: var(--offwhite);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 5px;
|
||||
}
|
||||
|
||||
#manager-result .result>div>span:nth-child(1) {
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
#manager-result .result>div>span:nth-child(2) {
|
||||
display: flex;
|
||||
column-gap: 10px;
|
||||
justify-content: center;
|
||||
justify-items: center;
|
||||
align-items: start;
|
||||
font-size: 13px;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
#result-page .usage-instructions>div>img {
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
#result-page .usage-instructions>img {
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
}
|
||||
</style>
|
||||
<div id="manager-result">
|
||||
<div class="content">
|
||||
<div class="step hook <%= !install? 'hide': '' %>">
|
||||
Installing hook scripts<img class="wait"><img class="success hide"><img class="error hide">
|
||||
</div>
|
||||
<div class="step mod <%= !install? 'hide': '' %>">
|
||||
Installing mod folder<img class="wait"><img class="success hide"><img class="error hide">
|
||||
</div>
|
||||
<div class="step json <%= !install? 'hide': '' %>">
|
||||
Installing configuration file<img class="wait"><img class="success hide"><img class="error hide">
|
||||
</div>
|
||||
<div class="step config">
|
||||
Applying configuration<img class="wait"><img class="success hide"><img class="error hide">
|
||||
</div>
|
||||
<div class="step shortcuts <%= !install? 'hide': '' %>">
|
||||
Creating shortcuts<img class="wait"><img class="success hide"><img class="error hide">
|
||||
</div>
|
||||
|
||||
<div class="summary success hide">
|
||||
Olympus successfully installed in the following DCS instance
|
||||
</div>
|
||||
|
||||
<div class="summary error hide">
|
||||
An error has occurred while installing Olympus
|
||||
</div>
|
||||
|
||||
<div class="info success hide">
|
||||
You may now start DCS and use Olympus either with the shortcuts or the "View and manage instances" entry in the
|
||||
main menu.
|
||||
</div>
|
||||
|
||||
<div class="info error hide">
|
||||
Please make sure DCS is not currently being executed. Check <%= logLocation %> for more info.
|
||||
</div>
|
||||
|
||||
<div class="result">
|
||||
<img class="wait"><img class="success hide"><img class="error hide">
|
||||
<div id="result-page">
|
||||
<div class="result-summary wait">
|
||||
<div class="title"><img src="./icons/spinner-solid.svg">Please wait while Olympus is being added to <i><%= activeInstance["name"] %></i></div>
|
||||
</div>
|
||||
<div class="result-summary success">
|
||||
<div class="title"><img src="./icons/check-solid-background.svg">Olympus successfully added to <i><%= activeInstance["name"] %></i></div>
|
||||
<div class="description">See the <b>DCS Olympus Wiki</b> for more information on how to use Olympus and for troubleshooting issues. You may now close the installer.</div>
|
||||
</div>
|
||||
<div class="result-summary error">
|
||||
<div class="title"><img src="./icons/triangle-exclamation-solid-background.svg">An error occurred while adding Olympus to <i><%= activeInstance["name"] %></i></div>
|
||||
<div class="description">See the manager log located in TODO for more information.</div>
|
||||
</div>
|
||||
<div>
|
||||
How to launch Olympus
|
||||
</div>
|
||||
<div>
|
||||
To launch Olympus, there are shortcuts available in the DCS Olympus folder under Saved Games.
|
||||
</div>
|
||||
<div class="usage-instructions">
|
||||
<div>
|
||||
<img src="./icons/server-solid.svg">
|
||||
<div>
|
||||
<span>
|
||||
<%= activeInstance.name %>
|
||||
</span>
|
||||
<span><img src="./icons/folder-open-solid.svg">
|
||||
<%= activeInstance.folder %>
|
||||
</span>
|
||||
Launch the Olympus Server via the shortcut in DCS Olympus / Saved Games.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="buttons-footer">
|
||||
<div class="button back">
|
||||
Back to main menu
|
||||
<img src="./icons/arrow-right-solid.svg">
|
||||
<div>
|
||||
<img src="./icons/chrome.svg">
|
||||
<div>
|
||||
Visit http://localhost:3000 in a web browser (Google Chrome recommended).
|
||||
</div>
|
||||
</div>
|
||||
<img src="./icons/arrow-right-solid.svg">
|
||||
<div>
|
||||
<img src="./icons/gamepad-solid.svg">
|
||||
<div>
|
||||
Launch DCS, load a mission and unpause the game. Enjoy!
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
Alternatively, you can run the Olympus Client instead to replace the first two steps above.
|
||||
</div>
|
||||
|
||||
<div class="buttons-footer">
|
||||
<div class="button return">
|
||||
Return to main menu
|
||||
</div>
|
||||
<div class="button close">
|
||||
Close manager
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -1,23 +1,25 @@
|
||||
<style>
|
||||
|
||||
</style>
|
||||
<div class="instructions">
|
||||
<div class="step">
|
||||
Step 1 of 4
|
||||
<div>
|
||||
<div class="instructions">
|
||||
<div class="step">
|
||||
Step 1 of 4
|
||||
</div>
|
||||
<div class="title">
|
||||
Do you want to add Olympus for singleplayer or multiplayer?
|
||||
</div>
|
||||
<div class="description">
|
||||
Select singleplayer if you only want to play locally on your own computer. <br>
|
||||
Select multiplayer if you want Olympus to be useable over the internet from a different computer, or this instance is a dedicated server.
|
||||
</div>
|
||||
</div>
|
||||
<div class="title">
|
||||
Do you want to add Olympus for singleplayer or multiplayer?
|
||||
</div>
|
||||
<div class="description">
|
||||
Select singleplayer if you only want to play locally on your own computer. <br>
|
||||
Select multiplayer if you want Olympus to be useable over the internet from a different computer, or this instance is a dedicated server.
|
||||
</div>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<div class="button">
|
||||
Singleplayer
|
||||
</div>
|
||||
<div class="button">
|
||||
Multiplayer
|
||||
<div class="wizard-inputs">
|
||||
<div class="button radio singleplayer selected" onclick="signal('onInstallTypeClicked', 'singleplayer')">
|
||||
Singleplayer
|
||||
</div>
|
||||
<div class="button radio multiplayer" onclick="signal('onInstallTypeClicked', 'multiplayer')">
|
||||
Multiplayer
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
flex-direction: column;
|
||||
row-gap: 20px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
@ -13,11 +13,20 @@
|
||||
}
|
||||
|
||||
.instructions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 15px;
|
||||
color: var(--offwhite);
|
||||
}
|
||||
|
||||
.instructions .step {
|
||||
font-size: 14px;
|
||||
color: var(--lightgray);
|
||||
}
|
||||
|
||||
.instructions .description {
|
||||
font-size: 14px;
|
||||
color: var(--lightgray);
|
||||
}
|
||||
|
||||
.instructions .title {
|
||||
@ -25,7 +34,7 @@
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.content {
|
||||
.content > div {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
@ -34,6 +43,32 @@
|
||||
align-items: start;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.wizard-inputs {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 10px;
|
||||
}
|
||||
|
||||
.wizard-page .button.radio {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.note {
|
||||
width: 100%;
|
||||
background-color: var(--background-note);
|
||||
color: var(--offwhite);
|
||||
border-left: 5px solid var(--offwhite);
|
||||
font-size: 14px;
|
||||
padding: 15px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.warning {
|
||||
background-color: var(--background-warning);
|
||||
border-left: 5px solid var(--orange);
|
||||
}
|
||||
|
||||
</style>
|
||||
<div class="wizard-page">
|
||||
<div class="cancel" style="font-size: 14px; font-weight: 600; color: var(--offwhite); display: flex; align-items: center; column-gap: 10px;">
|
||||
@ -43,10 +78,10 @@
|
||||
|
||||
</div>
|
||||
<div class="buttons-footer">
|
||||
<div class="button back" style="color: var(--offwhite); background-color: var(--background); border: 1px solid var(--offwhite);">
|
||||
<div class="button back" style="color: var(--offwhite); background-color: var(--background); border: 1px solid var(--offwhite);" onclick="signal('onBackClicked')">
|
||||
Back
|
||||
</div>
|
||||
<div class="button next" style="color: var(--background); background-color: var(--offwhite);">
|
||||
<div class="button next" style="color: var(--background); background-color: var(--offwhite);" onclick="signal('onNextClicked')">
|
||||
Next
|
||||
</div>
|
||||
</div>
|
||||
|
||||
1
manager/icons/arrow-right-solid.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="16" width="14" viewBox="0 0 448 512"><!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path fill="#F2F2F2" d="M438.6 278.6c12.5-12.5 12.5-32.8 0-45.3l-160-160c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L338.8 224 32 224c-17.7 0-32 14.3-32 32s14.3 32 32 32l306.7 0L233.4 393.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l160-160z"/></svg>
|
||||
|
After Width: | Height: | Size: 490 B |
1
manager/icons/check-solid-background.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="16" width="14" viewBox="0 0 448 512"><!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2023 Fonticons, Inc.--><path fill="#181e25" d="M438.6 105.4c12.5 12.5 12.5 32.8 0 45.3l-256 256c-12.5 12.5-32.8 12.5-45.3 0l-128-128c-12.5-12.5-12.5-32.8 0-45.3s32.8-12.5 45.3 0L160 338.7 393.4 105.4c12.5-12.5 32.8-12.5 45.3 0z"/></svg>
|
||||
|
After Width: | Height: | Size: 449 B |
1
manager/icons/chrome.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16" viewBox="0 0 512 512"><!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path fill="#F2F2F2" d="M0 256C0 209.4 12.5 165.6 34.3 127.1L144.1 318.3C166 357.5 207.9 384 256 384C270.3 384 283.1 381.7 296.8 377.4L220.5 509.6C95.9 492.3 0 385.3 0 256zM365.1 321.6C377.4 302.4 384 279.1 384 256C384 217.8 367.2 183.5 340.7 160H493.4C505.4 189.6 512 222.1 512 256C512 397.4 397.4 511.1 256 512L365.1 321.6zM477.8 128H256C193.1 128 142.3 172.1 130.5 230.7L54.2 98.5C101 38.5 174 0 256 0C350.8 0 433.5 51.5 477.8 128V128zM168 256C168 207.4 207.4 168 256 168C304.6 168 344 207.4 344 256C344 304.6 304.6 344 256 344C207.4 344 168 304.6 168 256z"/></svg>
|
||||
|
After Width: | Height: | Size: 804 B |
1
manager/icons/gamepad-solid.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="16" width="20" viewBox="0 0 640 512"><!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path fill="#F2F2F2" d="M192 64C86 64 0 150 0 256S86 448 192 448H448c106 0 192-86 192-192s-86-192-192-192H192zM496 168a40 40 0 1 1 0 80 40 40 0 1 1 0-80zM392 304a40 40 0 1 1 80 0 40 40 0 1 1 -80 0zM168 200c0-13.3 10.7-24 24-24s24 10.7 24 24v32h32c13.3 0 24 10.7 24 24s-10.7 24-24 24H216v32c0 13.3-10.7 24-24 24s-24-10.7-24-24V280H136c-13.3 0-24-10.7-24-24s10.7-24 24-24h32V200z"/></svg>
|
||||
|
After Width: | Height: | Size: 622 B |
@ -1 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16" viewBox="0 0 512 512"><!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2023 Fonticons, Inc.--><path opacity="1" fill="#F2F2F2" d="M64 32C28.7 32 0 60.7 0 96v64c0 35.3 28.7 64 64 64H448c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64zm280 72a24 24 0 1 1 0 48 24 24 0 1 1 0-48zm48 24a24 24 0 1 1 48 0 24 24 0 1 1 -48 0zM64 288c-35.3 0-64 28.7-64 64v64c0 35.3 28.7 64 64 64H448c35.3 0 64-28.7 64-64V352c0-35.3-28.7-64-64-64H64zm280 72a24 24 0 1 1 0 48 24 24 0 1 1 0-48zm56 24a24 24 0 1 1 48 0 24 24 0 1 1 -48 0z"/></svg>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16" viewBox="0 0 512 512"><!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path fill="#F2F2F2" d="M64 32C28.7 32 0 60.7 0 96v64c0 35.3 28.7 64 64 64H448c35.3 0 64-28.7 64-64V96c0-35.3-28.7-64-64-64H64zm280 72a24 24 0 1 1 0 48 24 24 0 1 1 0-48zm48 24a24 24 0 1 1 48 0 24 24 0 1 1 -48 0zM64 288c-35.3 0-64 28.7-64 64v64c0 35.3 28.7 64 64 64H448c35.3 0 64-28.7 64-64V352c0-35.3-28.7-64-64-64H64zm280 72a24 24 0 1 1 0 48 24 24 0 1 1 0-48zm56 24a24 24 0 1 1 48 0 24 24 0 1 1 -48 0z"/></svg>
|
||||
|
Before Width: | Height: | Size: 659 B After Width: | Height: | Size: 647 B |
1
manager/icons/triangle-exclamation-solid-background.svg
Normal file
@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16" viewBox="0 0 512 512"><!--!Font Awesome Free 6.5.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2023 Fonticons, Inc.--><path opacity="1" fill="#181e25" d="M256 32c14.2 0 27.3 7.5 34.5 19.8l216 368c7.3 12.4 7.3 27.7 .2 40.1S486.3 480 472 480H40c-14.3 0-27.6-7.7-34.7-20.1s-7-27.8 .2-40.1l216-368C228.7 39.5 241.8 32 256 32zm0 128c-13.3 0-24 10.7-24 24V296c0 13.3 10.7 24 24 24s24-10.7 24-24V184c0-13.3-10.7-24-24-24zm32 224a32 32 0 1 0 -64 0 32 32 0 1 0 64 0z"/></svg>
|
||||
|
After Width: | Height: | Size: 584 B |
@ -8,7 +8,7 @@ const { checkPort, fetchWithTimeout } = require('./net')
|
||||
const dircompare = require('dir-compare');
|
||||
const { spawn } = require('child_process');
|
||||
const find = require('find-process');
|
||||
const { uninstallInstance } = require('./filesystem')
|
||||
const { uninstallInstance, installHooks, installMod, installJSON, applyConfiguration, installShortCuts } = require('./filesystem')
|
||||
const { showErrorPopup, showConfirmPopup } = require('./popup')
|
||||
const { logger } = require("./filesystem")
|
||||
|
||||
@ -79,6 +79,8 @@ class DCSInstance {
|
||||
missionTime = "";
|
||||
load = 0;
|
||||
fps = 0;
|
||||
installationType = 'singleplayer';
|
||||
connectionsType = 'auto';
|
||||
|
||||
constructor(folder) {
|
||||
this.folder = folder;
|
||||
@ -146,7 +148,7 @@ class DCSInstance {
|
||||
*/
|
||||
async setBackendPort(newPort) {
|
||||
if (await this.checkBackendPort(newPort)) {
|
||||
logger.log(`Instance ${this.folder} client port set to ${newPort}`)
|
||||
logger.log(`Instance ${this.folder} backend port set to ${newPort}`)
|
||||
this.backendPort = newPort;
|
||||
return true;
|
||||
}
|
||||
@ -236,6 +238,7 @@ class DCSInstance {
|
||||
} else {
|
||||
logger.log(`Port ${port} currently in use`);
|
||||
}
|
||||
logger.log(`Port ${port} is free`);
|
||||
res(portFree);
|
||||
})
|
||||
})
|
||||
@ -340,6 +343,48 @@ class DCSInstance {
|
||||
})
|
||||
}
|
||||
|
||||
/* Install this instance */
|
||||
install() {
|
||||
installHooks(getManager().getActiveInstance().folder).then(
|
||||
() => {
|
||||
},
|
||||
(err) => {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
).then(() => installMod(getManager().getActiveInstance().folder, getManager().getActiveInstance().name)).then(
|
||||
() => {
|
||||
},
|
||||
(err) => {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
).then(() => installJSON(getManager().getActiveInstance().folder)).then(
|
||||
() => {
|
||||
},
|
||||
(err) => {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
).then(() => applyConfiguration(getManager().getActiveInstance().folder, getManager().getActiveInstance())).then(
|
||||
() => {
|
||||
},
|
||||
(err) => {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
).then(() => installShortCuts(getManager().getActiveInstance().folder, getManager().getActiveInstance().name)).then(
|
||||
() => {
|
||||
},
|
||||
(err) => {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
).then(
|
||||
() => {
|
||||
//getManager().resultPage.getElement()
|
||||
},
|
||||
() => {
|
||||
//getManager().resultPage.getElement()
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/* Uninstall this instance */
|
||||
uninstall() {
|
||||
showConfirmPopup("<div style='font-size: 18px; max-width: 100%'> Are you sure you want to remove Olympus? </div> If you click Accept, the Olympus mod will be removed from your DCS installation.", () =>
|
||||
@ -353,7 +398,8 @@ class DCSInstance {
|
||||
location.reload();
|
||||
});
|
||||
}
|
||||
));
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -15,37 +15,40 @@ class Manager {
|
||||
configLoaded: false
|
||||
};
|
||||
|
||||
activePage = null;
|
||||
welcomePage = null;
|
||||
folderPage = null;
|
||||
typePage = null;
|
||||
connectionsTypePage = null;
|
||||
connectionsPage = null;
|
||||
passwordsPage = null;
|
||||
resultPage = null;
|
||||
instancesPage = null;
|
||||
|
||||
constructor() {
|
||||
console.log("constructor")
|
||||
document.addEventListener("signal", (ev) => {
|
||||
const callback = ev.detail.callback;
|
||||
const params = ev.detail.params;
|
||||
const params = JSON.stringify(ev.detail.params);
|
||||
try {
|
||||
eval(`this.${callback}(${params})`)
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async start() {
|
||||
/* Check if the options file exists */
|
||||
if (fs.existsSync("options.json")) {
|
||||
/* Load the options from the json file */
|
||||
try {
|
||||
this.options = {...this.options, ...JSON.parse(fs.readFileSync("options.json"))};
|
||||
this.options = { ...this.options, ...JSON.parse(fs.readFileSync("options.json")) };
|
||||
this.options.configLoaded = true;
|
||||
} catch (e) {
|
||||
logger.error(`An error occurred while reading the options.json file: ${e}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.options.configLoaded) {
|
||||
/* Hide the loading page */
|
||||
@ -82,9 +85,9 @@ class Manager {
|
||||
return instance.installed && instance.error;
|
||||
})).then(
|
||||
() => { location.reload() },
|
||||
(err) => {
|
||||
(err) => {
|
||||
logger.error(err);
|
||||
showErrorPopup(`An error occurred while trying to fix your installations. Please reinstall Olympus manually. <br><br> You can find more info in ${path.join(__dirname, "..", "manager.log")}`);
|
||||
showErrorPopup(`An error occurred while trying to fix your installations. Please reinstall Olympus manually. <br><br> You can find more info in ${path.join(__dirname, "..", "manager.log")}`);
|
||||
}
|
||||
)
|
||||
})
|
||||
@ -101,13 +104,14 @@ class Manager {
|
||||
|
||||
/* Create all the HTML pages */
|
||||
this.menuPage = new ManagerPage(this, "./ejs/menu.ejs");
|
||||
this.folderPage = new WizardPage(this, "./ejs/installation.ejs");
|
||||
this.typePage = new WizardPage(this, "./ejs/type.ejs");
|
||||
//this.connectionsPage = new ConnectionsPage(this);
|
||||
//this.passwordsPage = new PasswordsPage(this);
|
||||
//this.resultPage = new ResultPage(this);
|
||||
this.folderPage = new WizardPage(this, "./ejs/installation.ejs");
|
||||
this.typePage = new WizardPage(this, "./ejs/type.ejs");
|
||||
this.connectionsTypePage = new WizardPage(this, "./ejs/connectionsType.ejs");
|
||||
this.connectionsPage = new WizardPage(this, "./ejs/connections.ejs");
|
||||
this.passwordsPage = new WizardPage(this, "./ejs/passwords.ejs");
|
||||
this.resultPage = new ManagerPage(this, "./ejs/result.ejs");
|
||||
//this.instancesPage = new InstancesPage(this);
|
||||
|
||||
|
||||
if (this.options.mode === "basic") {
|
||||
/* In basic mode no dashboard is shown */
|
||||
this.menuPage.show();
|
||||
@ -124,7 +128,7 @@ class Manager {
|
||||
|
||||
createOptionsFile(mode) {
|
||||
try {
|
||||
fs.writeFileSync("options.json", JSON.stringify({mode: mode}));
|
||||
fs.writeFileSync("options.json", JSON.stringify({ mode: mode }));
|
||||
location.reload();
|
||||
} catch (e) {
|
||||
showErrorPopup(`A critical error occurred, check ${this.options.logLocation} for more info.`)
|
||||
@ -155,26 +159,26 @@ class Manager {
|
||||
/* When the install button is clicked go the installation page */
|
||||
onInstallClicked() {
|
||||
this.options.install = true;
|
||||
|
||||
|
||||
if (this.options.singleInstance) {
|
||||
this.options.activeInstance = this.options.instances[0];
|
||||
|
||||
/* Show the type selection page */
|
||||
if (!this.options.activeInstance.installed) {
|
||||
this.menuPage.hide();
|
||||
this.typePage.show(this.menuPage);
|
||||
this.typePage.show();
|
||||
} else {
|
||||
showConfirmPopup("<div style='font-size: 18px; max-width: 100%'> Olympus is already installed in this instance! </div> If you click Accept, it will be installed again and all changes, e.g. custom databases or mods support, will be lost. Are you sure you want to continue?",
|
||||
() => {
|
||||
this.menuPage.hide();
|
||||
this.typePage.show(this.menuPage);
|
||||
this.typePage.show();
|
||||
}
|
||||
)
|
||||
}
|
||||
} else {
|
||||
/* Show the folder selection page */
|
||||
this.menuPage.hide();
|
||||
this.folderPage.show(this.menuPage);
|
||||
this.folderPage.show();
|
||||
}
|
||||
}
|
||||
|
||||
@ -182,16 +186,115 @@ class Manager {
|
||||
onEditClicked() {
|
||||
this.hide();
|
||||
this.options.install = false;
|
||||
|
||||
|
||||
if (this.options.singleInstance) {
|
||||
this.options.activeInstance = this.options.instances[0];
|
||||
this.typePage.show(this);
|
||||
this.typePage.show();
|
||||
} else {
|
||||
this.folderPage.show(this);
|
||||
this.folderPage.show();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* When the installation type is selected */
|
||||
onInstallTypeClicked(type) {
|
||||
this.typePage.getElement().querySelector(`.singleplayer`).classList.toggle("selected", type === 'singleplayer');
|
||||
this.typePage.getElement().querySelector(`.multiplayer`).classList.toggle("selected", type === 'multiplayer');
|
||||
if (this.options.activeInstance)
|
||||
this.options.activeInstance.installationType = type;
|
||||
else
|
||||
showErrorPopup("A critical error has occurred. Please restart the Manager.")
|
||||
}
|
||||
|
||||
/* When the connections type is selected */
|
||||
onConnectionsTypeClicked(type) {
|
||||
this.connectionsTypePage.getElement().querySelector(`.auto`).classList.toggle("selected", type === 'auto');
|
||||
this.connectionsTypePage.getElement().querySelector(`.manual`).classList.toggle("selected", type === 'manual');
|
||||
if (this.options.activeInstance)
|
||||
this.options.activeInstance.connectionsType = type;
|
||||
else
|
||||
showErrorPopup("A critical error has occurred. Please restart the Manager.")
|
||||
}
|
||||
|
||||
/* When the back button of a wizard page is clicked */
|
||||
onBackClicked() {
|
||||
this.activePage.hide();
|
||||
this.activePage.previousPage.show();
|
||||
}
|
||||
|
||||
/* When the next button of a wizard page is clicked */
|
||||
onNextClicked() {
|
||||
this.activePage.hide();
|
||||
|
||||
/* Choose which page to show depending on the active page */
|
||||
if (this.activePage == this.typePage) {
|
||||
this.connectionsTypePage.show();
|
||||
} else if (this.activePage == this.connectionsTypePage) {
|
||||
if (this.options.activeInstance) {
|
||||
if (this.options.activeInstance.connectionsType === 'auto') {
|
||||
this.passwordsPage.show();
|
||||
}
|
||||
else {
|
||||
this.connectionsPage.show();
|
||||
this.setPort('client', this.options.activeInstance.clientPort);
|
||||
this.setPort('backend', this.options.activeInstance.backendPort);
|
||||
this.connectionsPage.getElement().querySelector(".backend-address .checkbox").classList.toggle("checked", this.options.activeInstance.backendAddress === '*')
|
||||
}
|
||||
} else {
|
||||
showErrorPopup("A critical error has occurred. Please restart the Manager.")
|
||||
}
|
||||
} else if (this.activePage == this.connectionsPage) {
|
||||
this.passwordsPage.show();
|
||||
} else if (this.activePage == this.passwordsPage) {
|
||||
if (this.options.activeInstance) {
|
||||
this.options.activeInstance.install();
|
||||
this.resultPage.show();
|
||||
} else {
|
||||
showErrorPopup("A critical error has occurred. Please restart the Manager.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* When the client port input value is changed */
|
||||
onClientPortChanged(value) {
|
||||
this.setPort('client', Number(value));
|
||||
}
|
||||
|
||||
/* When the backend port input value is changed */
|
||||
onBackendPortChanged(value) {
|
||||
this.setPort('backend', Number(value));
|
||||
}
|
||||
|
||||
/* When the "Enable API connection" checkbox is clicked */
|
||||
onEnableAPIClicked() {
|
||||
if (this.options.activeInstance) {
|
||||
if (this.options.activeInstance.backendAddress === 'localhost') {
|
||||
this.options.activeInstance.backendAddress = '*';
|
||||
} else {
|
||||
this.options.activeInstance.backendAddress = 'localhost';
|
||||
}
|
||||
this.connectionsPage.getElement().querySelector(".backend-address .checkbox").classList.toggle("checked", this.options.activeInstance.backendAddress === '*')
|
||||
} else {
|
||||
showErrorPopup("A critical error has occurred. Please restart the Manager.")
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the selected port to the dcs instance */
|
||||
async setPort(port, value) {
|
||||
var success;
|
||||
if (port === 'client')
|
||||
success = await this.options.activeInstance.setClientPort(value);
|
||||
else
|
||||
success = await this.options.activeInstance.setBackendPort(value);
|
||||
|
||||
var successEls = this.connectionsPage.getElement().querySelector(`.${port}-port`).querySelectorAll(".success");
|
||||
for (let i = 0; i < successEls.length; i++) {
|
||||
successEls[i].classList.toggle("hide", !success);
|
||||
}
|
||||
var errorEls = this.connectionsPage.getElement().querySelector(`.${port}-port`).querySelectorAll(".error");
|
||||
for (let i = 0; i < errorEls.length; i++) {
|
||||
errorEls[i].classList.toggle("hide", success);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Manager;
|
||||
@ -1,12 +1,12 @@
|
||||
var manager = null;
|
||||
/* TODO: find a better solution without using the window object to persist the manager singleton */
|
||||
|
||||
function getManager() {
|
||||
if (manager) {
|
||||
return manager;
|
||||
if (window.manager) {
|
||||
return window.manager;
|
||||
} else {
|
||||
const Manager = require("./manager");
|
||||
manager = new Manager();
|
||||
return manager;
|
||||
window.manager = new Manager();
|
||||
return window.manager;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -31,8 +31,8 @@ class ManagerPage {
|
||||
|
||||
this.element.classList.remove("hide");
|
||||
|
||||
if (previousPage !== undefined)
|
||||
this.previousPage = previousPage;
|
||||
this.previousPage = this.manager.activePage;
|
||||
this.manager.activePage = this;
|
||||
}
|
||||
|
||||
hide() {
|
||||
|
||||
@ -10,8 +10,8 @@ process.env['PATH'] = process.env['PATH'] + "%WINDIR%\\System32;"
|
||||
|
||||
function createWindow() {
|
||||
const window = new electronBrowserWindow({
|
||||
width: 1500,
|
||||
height: 850,
|
||||
width: 1200,
|
||||
height: 750,
|
||||
frame: false,
|
||||
resizable: true,
|
||||
maximizable: true,
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
echo D|xcopy /Y /S /E .\icons ..\package\manager\icons
|
||||
echo D|xcopy /Y /S /E .\ejs ..\package\manager\ejs
|
||||
echo D|xcopy /Y /S /E .\javascripts ..\package\manager\javascripts
|
||||
echo D|xcopy /Y /S /E .\stylesheets ..\package\manager\stylesheets
|
||||
|
||||
echo F|xcopy /Y /I .\*.* ..\package\manager
|
||||
xcopy /Y /S /E .\icons ..\package\manager\icons
|
||||
xcopy /Y /S /E .\ejs ..\package\manager\ejs
|
||||
xcopy /Y /S /E .\javascripts ..\package\manager\javascripts
|
||||
xcopy /Y /S /E .\stylesheets ..\package\manager\stylesheets
|
||||
xcopy /Y /I .\*.* ..\package\manager
|
||||
|
||||
cd ..
|
||||
call node .\scripts\node\set_version_text.js
|
||||
@ -3,14 +3,18 @@
|
||||
--background-dark: #13181f;
|
||||
--background-light: #202831;
|
||||
--background-disabled: #212A34;
|
||||
--background-note: #2C3540;
|
||||
--background-warning: #3D3322;
|
||||
--background-usage: #28313A;
|
||||
--offwhite: #F2F2F2;
|
||||
--offwhite-transparent: #F2F2F255;
|
||||
--blue: #247be2;
|
||||
--red: #FF5858;
|
||||
--green: #8bff63;
|
||||
--green: #8BFF63;
|
||||
--lightgray: #cfd9e8;
|
||||
--gray: #989898;
|
||||
--darkgray: #3d4651;
|
||||
--orange: #FF7B42;
|
||||
}
|
||||
|
||||
* {
|
||||
@ -36,7 +40,7 @@ body {
|
||||
display: block;
|
||||
-webkit-user-select: none;
|
||||
-webkit-app-region: drag;
|
||||
height: 20px;
|
||||
height: 30px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: end;
|
||||
@ -197,6 +201,24 @@ body {
|
||||
column-gap: 10px;
|
||||
}
|
||||
|
||||
.button.radio {
|
||||
border: 1px solid var(--offwhite);
|
||||
color: var(--offwhite);
|
||||
}
|
||||
|
||||
.button.radio::before {
|
||||
content: "";
|
||||
display: block;
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border: 1px solid var(--offwhite);
|
||||
border-radius: 999px;
|
||||
}
|
||||
|
||||
.button.radio.selected::before {
|
||||
background-color: var(--offwhite);
|
||||
}
|
||||
|
||||
.close-popup {
|
||||
color: var(--offwhite);
|
||||
background-color: var(--blue);
|
||||
@ -214,7 +236,7 @@ input {
|
||||
font-size: 13px;
|
||||
padding: 3px 10px;
|
||||
border-radius: 5px;
|
||||
text-align: center;
|
||||
text-align: left;
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
@ -288,7 +310,7 @@ input {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 5px;
|
||||
align-items: center;
|
||||
align-items: start;
|
||||
position: relative;
|
||||
width: 500px;
|
||||
}
|
||||
@ -317,10 +339,6 @@ input {
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.instructions {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.divider {
|
||||
border-top: 0px solid transparent !important;
|
||||
border-bottom: 1px solid var(--offwhite) !important;
|
||||
@ -392,3 +410,22 @@ input {
|
||||
border-top-left-radius: 0px;
|
||||
border-top-right-radius: 0px;
|
||||
}
|
||||
|
||||
.checkbox {
|
||||
position: relative;
|
||||
height: 15px;
|
||||
width: 15px;
|
||||
border: 1px solid var(--offwhite);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.checkbox.checked::after {
|
||||
display: block;
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 3px;
|
||||
width: 8px;
|
||||
transform: translate(1px, -1px) rotate(-45deg);
|
||||
border-left: 2px solid var(--offwhite);
|
||||
border-bottom: 2px solid var(--offwhite);
|
||||
}
|
||||
|
||||