From a4204d1f07d29668c60cb33e8682565eb31d6a2c Mon Sep 17 00:00:00 2001 From: cyber-dream Date: Sat, 30 Jul 2022 16:07:51 +0300 Subject: [PATCH] initial-offline login --- app/app.ejs | 109 +- app/assets/css/launcher.css | 8023 +++++++++++++------------ app/assets/distribution.json | 298 + app/assets/js/authmanager.js | 5 + app/assets/js/configmanager.js | 11 + app/assets/js/distromanager.js | 3 +- app/assets/js/scripts/landing.js | 5 +- app/assets/js/scripts/login.js | 476 +- app/assets/js/scripts/loginOffline.js | 30 + app/assets/js/scripts/loginOptions.js | 95 +- app/assets/js/scripts/uibinder.js | 901 +-- app/loginOffline.ejs | 25 + app/loginOptions.ejs | 71 +- 13 files changed, 5258 insertions(+), 4794 deletions(-) create mode 100644 app/assets/distribution.json create mode 100644 app/assets/js/scripts/loginOffline.js create mode 100644 app/loginOffline.ejs diff --git a/app/app.ejs b/app/app.ejs index e829fa1..7f4657d 100644 --- a/app/app.ejs +++ b/app/app.ejs @@ -1,55 +1,56 @@ - - - - Helios Launcher - - - - - - - <%- include('frame') %> -
- <%- include('welcome') %> - <%- include('login') %> - <%- include('waiting') %> - <%- include('loginOptions') %> - <%- include('settings') %> - <%- include('landing') %> -
- <%- include('overlay') %> -
-
-
- - -
-
-
- - + + + + Helios Launcher + + + + + + + <%- include('frame') %> +
+ <%- include('welcome') %> + <%- include('login') %> + <%- include('loginOffline') %> + <%- include('waiting') %> + <%- include('loginOptions') %> + <%- include('settings') %> + <%- include('landing') %> +
+ <%- include('overlay') %> +
+
+
+ + +
+
+
+ + \ No newline at end of file diff --git a/app/assets/css/launcher.css b/app/assets/css/launcher.css index e67984e..d42722d 100644 --- a/app/assets/css/launcher.css +++ b/app/assets/css/launcher.css @@ -1,3967 +1,4058 @@ -/* Github Code Highlighting. */ -@import "../../../node_modules/github-syntax-dark/lib/github-dark.css"; - -/******************************************************************************* - * * - * Fonts * - * * - ******************************************************************************/ - -@font-face { - font-family: 'Avenir Book'; - src: url('../fonts/Avenir-Book.ttf'); -} - -@font-face { - font-family: 'Avenir Medium'; - src: url('../fonts/Avenir-Medium.ttf'); -} - -@font-face { - font-family: 'Ringbearer'; - src: url('../fonts/Ringbearer.ttf'); -} - -/******************************************************************************* - * * - * Element Styles * - * * - ******************************************************************************/ - -/* Reset body, html, and div presets. */ -body, html, div { - margin: 0px; - padding: 0px; -} - -/* Reset p presets. */ -p { - -webkit-margin-before: 0em; - -webkit-margin-after: 0em; -} - -/* Set default font and color. */ -body, button { - font-family: 'Avenir Book'; - color: white; -} - -/*body { - background: url('./../images/backgrounds/0.jpg') no-repeat center center fixed; - background-size: cover; -}*/ - -/******************************************************************************* - * * - * Frame Styles (frame.ejs) * - * * - ******************************************************************************/ - -/* Frame Bar */ -#frameBar { - position: relative; - z-index: 100; - display: flex; - flex-direction: column; - transition: background-color 1s ease; - /*background-color: rgba(0, 0, 0, 0.5);*/ - -webkit-user-select: none; -} - -/* Undraggable region on the top of the frame. */ -#frameResizableTop { - height: 2px; - width: 100%; - -webkit-app-region: no-drag; -} - -/* Flexbox to wrap the main frame content. */ -#frameMain { - display: flex; - height: 20px -} - -/* Undraggable region on the left and right of the frame. */ -.frameResizableVert { - width: 2px; - -webkit-app-region: no-drag; -} - -/* Main frame content for windows. */ -#frameContentWin { - display: flex; - justify-content: space-between; - width: 100%; - -webkit-app-region: drag; -} - -/* Main frame content for darwin. */ -#frameContentDarwin { - display: flex; - justify-content: flex-start; - align-items: center; - width: 100%; - -webkit-app-region: drag; -} - -/* Frame logo (windows only). */ -#frameTitleDock { - padding: 0px 10px; -} -#frameTitleText { - font-size: 14px; - font-family: 'Avenir Medium'; - letter-spacing: 0.5px; -} - -/* Windows frame button dock. */ -#frameButtonDockWin { - -webkit-app-region: no-drag !important; - position: relative; - top: -2px; - right: -2px; - height: 22px; -} -#frameButtonDockWin > .frameButton:not(:first-child) { - margin-left: -4px; -} - -/* Darwin frame button dock: NaN; */ -#frameButtonDockDarwin { - -webkit-app-region: no-drag !important; - position: relative; - top: -1px; - right: -1px; -} - -/* Windows Frame Button Styles. */ -.frameButton { - background: none; - border: none; - height: 22px; - width: 39px; - cursor: pointer; -} -.frameButton:hover, -.frameButton:focus { - background: rgba(189, 189, 189, 0.43); -} -.frameButton:active { - background: rgba(156, 156, 156, 0.43); -} -.frameButton:focus { - outline: 0px; -} - -/* Close button is red. */ -#frameButton_close:hover, -#frameButton_close:focus { - background: rgba(255, 53, 53, 0.61) !important; -} -#frameButton_close:active { - background: rgba(235, 0, 0, 0.61) !important; -} - -/* Darwin Frame Button Styles. */ -.frameButtonDarwin { - height: 12px; - width: 12px; - border-radius: 50%; - border: 0px; - margin-left: 5px; - -webkit-app-region: no-drag !important; - cursor: pointer; -} -.frameButtonDarwin:focus { - outline: 0px; -} - -#frameButtonDarwin_close { - background-color: #e74c32; -} -#frameButtonDarwin_close:hover, -#frameButtonDarwin_close:focus { - background-color: #FF9A8A; -} -#frameButtonDarwin_close:active { - background-color: #ff8d7b; -} - -#frameButtonDarwin_minimize { - background-color: #fed045; -} -#frameButtonDarwin_minimize:hover, -#frameButtonDarwin_minimize:focus { - background-color: #FFE9A9; -} -#frameButtonDarwin_minimize:active { - background-color: #ffde7b; -} - -#frameButtonDarwin_restoredown { - background-color: #96e734; -} -#frameButtonDarwin_restoredown:hover, -#frameButtonDarwin_restoredown:focus { - background-color: #D6FFA6; -} -#frameButtonDarwin_restoredown:active { - background-color: #bfff76; -} - -/******************************************************************************* - * * - * Welcome View (welcome.ejs) * - * * - ******************************************************************************/ - -#welcomeContainer { - position: relative; - display: flex; - justify-content: center; - align-items: center; - height: 100%; - width: 100%; - background: rgba(0, 0, 0, 0.50); -} - -#welcomeContent { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - width: 50%; - top: -10%; - position: relative; -} - -/* -.cloudDiv { - position: absolute; - height: 100%; - width: 100%; - display: flex; - flex-direction: column; -} - -.cloudTop { - height: 50%; - width: 100%; - background-image: url('../images/cloudTrans.png'); - animation: clouds1 80s linear infinite; - background-size: cover; -} - -.cloudBottom { - height: 50%; - width: 100%; - background-image: url('../images/cloudTrans2.png'); - animation: clouds2 70s linear infinite; - background-size: cover; -} - -@keyframes clouds1 { - to { - background-position: 200%; - } -} -@keyframes clouds2 { - to { - background-position: 230%; - } -} -*/ - -#welcomeImageSeal { - border-radius: 50%; - border: 2px solid #cad7e1; - background: rgba(1, 2, 1, 0.5); - height: 125px; - width: 125px; - box-shadow: 0px 0px 10px 0px rgb(0, 0, 0); - margin-bottom: 5%; - margin-top: 10%; -} - -#welcomeHeader { - font-family: 'Avenir Medium'; - text-align: center; - color: white; - margin-bottom: 25px; - letter-spacing: 1px; - font-size: 20px; - text-shadow: white 0px 0px 0px; -} - -#welcomeDescription { - text-align: justify; - font-size: 13px; - font-weight: 100; - text-shadow: rgba(255, 255, 255, 0.75) 0px 0px 20px -} - -#welcomeDescCTA { - text-align: center; - font-size: 14px; - font-weight: 100; - text-shadow: rgba(255, 255, 255, 0.75) 0px 0px 20px -} - -/* Login button styles. */ -#welcomeButton { - background: none; - font-weight: bold; - letter-spacing: 2px; - border: none; - padding: 15px 5px; - margin: 10px 0px; - cursor: pointer; - position: relative; - right: -20px; - transition: 0.5s ease; - margin-top: 5%; - margin-bottom: -5%; -} -#welcomeButton:disabled { - color: rgba(255, 255, 255, 0.75); - pointer-events: none; -} -#welcomeButton:hover, -#welcomeButton:focus { - text-shadow: 0px 0px 20px #fff; - outline: none; -} -#welcomeButton:active { - color: #c7c7c7; - text-shadow: 0px 0px 20px #c7c7c7; -} -#welcomeSVG { - -webkit-transform: translate3d(0, 0, 0); - overflow: visible; - transform: rotate(90deg); - margin-left: 20px; - transition: 0.25s ease; - width: 20px; - height: 20px; -} -#welcomeButton:hover #welcomeSVG, -#welcomeButton:focus #welcomeSVG { - -webkit-filter: drop-shadow(0px 0px 2px #fff); -} -#welcomeButton:active #welcomeSVG .arrowLine { - stroke: #c7c7c7; -} -#welcomeButton:active #welcomeSVG { - -webkit-filter: drop-shadow(0px 0px 2px #c7c7c7); -} -#welcomeButton:disabled #welcomeSVG .arrowLine { - stroke: rgba(255, 255, 255, 0.75); -} - -#welcomeButtonContent { - display: flex; - align-items: center; -} - -/******************************************************************************* - * * - * Login View (login.ejs) * - * * - ******************************************************************************/ - -/* Styles for dimmer login span. */ -.loginSpanDim { - font-size: 12px; - color: #848484; - font-weight: bold; -} - -/* Main login container. */ -#loginContainer { - position: relative; - display: flex; - justify-content: center; - align-items: center; - height: 100%; - width: 100%; - transition: filter 0.25s ease; - background: rgba(0, 0, 0, 0.50); -} - -/* Login cancel button styles. */ -#loginCancelContainer { - position: absolute; - top: 5%; - right: 5%; -} - -/* Login cancel button styles. */ -#loginCancelButton { - background: none; - border: none; - outline: none; - cursor: pointer; - transition: 0.25s ease; -} -#loginCancelButton:hover #loginCancelIcon, -#loginCancelButton:hover #loginCancelText, -#loginCancelButton:focus #loginCancelIcon, -#loginCancelButton:focus #loginCancelText { - text-shadow: 0px 0px 20px white; -} -#loginCancelButton:hover #loginCancelIcon, -#loginCancelButton:focus #loginCancelIcon { - box-shadow: 0px 0px 20px white; -} -#loginCancelButton:active #loginCancelIcon, -#loginCancelButton:active #loginCancelText { - text-shadow: 0px 0px 20px rgba(255, 255, 255, 0.75); - color: rgba(255, 255, 255, 0.75); - border-color: rgba(255, 255, 255, 0.75); -} -#loginCancelButton:active #loginCancelIcon { - box-shadow: 0px 0px 20px rgba(255, 255, 255, 0.75); -} -#loginCancelButton:disabled { - pointer-events: none; -} -#loginCancelButton:disabled #loginCancelIcon, -#loginCancelButton:disabled #loginCancelText { - color: rgba(255, 255, 255, 0.75); - border-color: rgba(255, 255, 255, 0.75); -} - -/* The X in a circle icon for the cancel button. */ -#loginCancelIcon { - border-radius: 50%; - border: 1px solid white; - box-sizing: border-box; - height: 30px; - width: 30px; - font-size: 19px; - line-height: 30px; - margin: 0 auto; - margin-bottom: 5px; - transition: 0.25s ease; -} -/* Text for the login cancel button. */ -#loginCancelText { - font-size: 15px; - transition: 0.25s ease; -} - -/* Login content wrapper. */ -#loginContent { - display: flex; - justify-content: center; - align-items: center; - height: 100%; - padding: 0px 25px; -} - -/* Login form. */ -#loginForm { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; -} - -/* Login form anchor styles. */ -#loginForm a { - font-size: 12px; - color: #848484; - font-weight: bold; - text-decoration: none; - transition: 0.25s ease; -} -#loginForm a:hover, -#loginForm a:focus { - color: #a2a2a2; - outline: none; -} -#loginForm a:active { - color: #8b8b8b; -} - -/* Logo on login form. */ -#loginImageSeal { - border-radius: 50%; - border: 2px solid #cad7e1; - background: rgba(1, 2, 1, 0.5); - height: 125px; - width: 125px; - box-shadow: 0px 0px 10px 0px rgb(0, 0, 0); - margin-bottom: 20px; -} - -/* Header on login view. */ -#loginSubheader { - font-family: 'Avenir Medium'; - margin-bottom: 25px; - font-size: 12px; - letter-spacing: 1px; - font-weight: bold; -} - -/* Container to organize login field elements. */ -.loginFieldContainer { - position: relative; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; -} - -/* SVG icons on the login view. */ -.loginSVG { - fill: #fff; - height: 20px; - width: 20px; -} - -/* Span which displays errors related to login field content. */ -.loginErrorSpan { - font-family: 'Avenir Medium'; - font-weight: bold; - font-size: 8px; - color: #ff1b0c; - width: 100%; - text-align: right; - position: absolute; - top: 7px; - opacity: 0; - transition: 0.25s ease; -} - -.shake { - animation: shake 0.82s cubic-bezier(.36,.07,.19,.97) both; -} - -@keyframes shake { - 10%, 90% { - transform: translate3d(-1px, 0, 0); - } - - 20%, 80% { - transform: translate3d(2px, 0, 0); - } - - 30%, 50%, 70% { - transform: translate3d(-4px, 0, 0); - } - - 40%, 60% { - transform: translate3d(4px, 0, 0); - } -} - -/* Login text input styles. */ -.loginField { - font-family: 'Avenir Book'; - background: none; - border-width: 1.5px 0px 0px 0px; - border-style: solid; - width: 250px; - margin-bottom: 20px; - border-color: #fff; - color: rgba(255, 255, 255, 0.75); - font-weight: bold; - text-align: center; - box-sizing: border-box; - padding: 7.5px; - font-size: 10px; - letter-spacing: 1px; -} -.loginField:focus { - outline: none; -} -.loginField:disabled { - color: rgba(255, 255, 255, 0.50); -} -.loginField::-webkit-input-placeholder { - color: rgba(255, 255, 255, 0.75); - font-size: 10px; - letter-spacing: 1px; - text-align: center; - font-weight: bold; -} -.loginField:focus::-webkit-input-placeholder { - color: transparent; -} - -/* Add spacing between password field and options bar. */ -#labelPassword { - margin-bottom: 13px; -} - -/* Container which contains the forgot and remember options. */ -#loginOptions { - display: flex; - justify-content: space-between; - width: 100%; -} - -/* Remember option text. */ -#loginRememberText { - padding-right: 10px; - transition: 0.25s ease; -} - -/* Login button styles. */ -#loginButton { - background: none; - font-weight: bold; - letter-spacing: 2px; - border: none; - padding: 15px 5px; - margin: 10px 0px; - cursor: pointer; - position: relative; - right: -20px; - transition: 0.5s ease; -} -#loginButton:disabled { - color: rgba(255, 255, 255, 0.75); - pointer-events: none; -} -#loginButton[loading] { - color: #fff; -} -#loginButton:hover, -#loginButton:focus { - text-shadow: 0px 0px 20px #fff; - outline: none; -} -#loginButton:active { - color: #c7c7c7; - text-shadow: 0px 0px 20px #c7c7c7; -} -#loginSVG { - -webkit-transform: translate3d(0, 0, 0); - overflow: visible; - transform: rotate(90deg); - margin-left: 20px; - transition: 0.25s ease; - width: 20px; - height: 20px; -} -#loginButton:hover #loginSVG, -#loginButton:focus #loginSVG { - -webkit-filter: drop-shadow(0px 0px 2px #fff); -} -#loginButton:active #loginSVG .arrowLine { - stroke: #c7c7c7; -} -#loginButton:active #loginSVG { - -webkit-filter: drop-shadow(0px 0px 2px #c7c7c7); -} -#loginButton:disabled #loginSVG .arrowLine { - stroke: rgba(255, 255, 255, 0.75); -} - -#loginButtonContent { - display: flex; - align-items: center; -} - -#loginButton .circle-loader, -#loginButton[loading] #loginSVG { - display: none; -} -#loginButton[loading] .circle-loader, -#loginButton #loginSVG { - display: initial; -} - - -.circle-loader { - margin-left: 20px; - border: 2px solid rgba(255, 255, 255, 0.5); - border-left-color: #ffffff; - animation-name: loader-spin; - animation-duration: 1s; - animation-iteration-count: infinite; - animation-timing-function: linear; - position: relative; - display: inline-block; - vertical-align: top; - border-radius: 50%; - width: 16px; - height: 16px; -} -.load-complete { - animation: none; - border-color: #ffffff; - transition: border 500ms ease-out; -} -.checkmark { - display: none; -} -.checkmark.draw:after { - animation-duration: 800ms; - animation-timing-function: ease; - animation-name: checkmark; - transform: scaleX(-1) rotate(135deg); -} -.checkmark:after { - opacity: 1; - height: 8px; - width: 4px; - transform-origin: left top; - border-right: 2px solid #ffffff; - border-top: 2px solid #ffffff; - content: ''; - left: 2px; - top: 8px; - position: absolute; -} -@keyframes loader-spin { - 0% { - transform: rotate(0deg); - } - 100% { - transform: rotate(360deg); - } -} -@keyframes checkmark { - 0% { - height: 0; - width: 0; - opacity: 1; - } - 20% { - height: 0; - width: 4px; - opacity: 1; - } - 40% { - height: 8px; - width: 4px; - opacity: 1; - } - 100% { - height: 8px; - width: 4px; - opacity: 1; - } -} - - - -/*.spinningCircle { - margin-left: 20px; - height: 16px; - width: 16px; - border-radius: 50%; - border: 2px solid rgba(255,255,255,0); - border-top-color: #ffffff; - border-right-color: #ffffff; - border-left-color: rgba(255, 255, 255, 0.50); - border-bottom-color: rgba(255, 255, 255, 0.50); - animation: single2 4s infinite linear; -} - -@keyframes single2 { - 0% { - transform: rotate(0deg); - } - 100% { - transform: rotate(720deg); - } -}*/ - -/* Disclaimer container. */ -#loginDisclaimer { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; -} - -/* Add spacing between register anchor and disclaimer. */ -#loginRegisterSpan { - margin-bottom: 5px; -} - -/* Disclaimer text styles. */ -.loginDisclaimerText { - font-size: 7px; - color: #848484; - font-weight: bold; - text-align: center; -} - -/* * * -* Login View | Custom Checkbox -* * */ - -/* Checkbox container. */ -#checkmarkContainer { - display: flex; - justify-content: flex-end; - align-items: center; - position: relative; - cursor: pointer; - font-size: 22px; - -webkit-user-select: none; -} - -/* Hide the default checkbox. */ -#checkmarkContainer input { - opacity: 0; - cursor: pointer; - position: absolute; -} - -/* Create a custom checkbox. */ -.loginCheckmark { - position: relative; - height: 10px; - width: 10px; - border: 1px solid #848484; - border-radius: 1px; - background: none; - transition: 0.25s ease; -} -/* On hover and focus, add a grey border color. */ -#checkmarkContainer:hover input ~ *, -#checkmarkContainer input:focus ~ * { - color: #a2a2a2; - border-color: #a2a2a2; -} -/* On keydown, darken the checkbox a bit. */ -#checkmarkContainer input:active ~ *:not(#loginRememberText) { - color: #8d8d8d; - border-color: #8d8d8d; -} -#checkmarkContainer[disabled] { - pointer-events: none; -} -/* For checked -> #checkmarkContainer input:checked ~ * */ -/* Create the checkmark/indicator (hidden when not checked). */ -.loginCheckmark:after { - content: ""; - display: none; -} -/* Show the checkmark when checked. */ -#checkmarkContainer input:checked ~ .loginCheckmark:after { - display: block; -} -/* Style the checkmark/indicator. */ -#checkmarkContainer .loginCheckmark:after { - position: absolute; - left: 3.5px; - top: 0.5px; - width: 2px; - height: 6px; - border: solid #a2a2a2; - border-width: 0 2px 2px 0; - transform: rotate(45deg); -} - -/* -#login_filter { - height: calc(100% - 22px); - width: 100%; - z-index: 9000; - position: absolute; - filter: blur(8px) contrast(0.9) brightness(1.0); - background: url('./../images/backgrounds/0.jpg') no-repeat center center fixed; - transform: scale(1.2); - background-size: cover; -} -*/ - -/******************************************************************************* - * * - * Waiting View (waiting.ejs) * - * * - ******************************************************************************/ - -#waitingContainer { - position: relative; - display: flex; - justify-content: center; - align-items: center; - height: 100%; - width: 100%; - transition: filter 0.25s ease; - background: rgba(0, 0, 0, 0.50); -} - -#waitingContent { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - width: 50%; - top: -10%; - position: relative; -} - -.waitingSpinner:before { - transform: rotateX(60deg) rotateY(45deg) rotateZ(45deg); - animation: 750ms rotateBefore infinite linear reverse; -} -.waitingSpinner:after { - transform: rotateX(240deg) rotateY(45deg) rotateZ(45deg); - animation: 750ms rotateAfter infinite linear; -} -.waitingSpinner:before, -.waitingSpinner:after { - box-sizing: border-box; - content: ''; - display: block; - position: fixed; - top: calc(50% - 5em); - /* left: 50%; */ - margin-top: -5em; - margin-left: -5em; - width: 10em; - height: 10em; - transform-style: preserve-3d; - transform-origin: 50%; - transform: rotateY(50%); - perspective-origin: 50% 50%; - perspective: 340px; - background-size: 10em 10em; - background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+Cjxzdmcgd2lkdGg9IjI2NnB4IiBoZWlnaHQ9IjI5N3B4IiB2aWV3Qm94PSIwIDAgMjY2IDI5NyIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWxuczpza2V0Y2g9Imh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaC9ucyI+CiAgICA8dGl0bGU+c3Bpbm5lcjwvdGl0bGU+CiAgICA8ZGVzY3JpcHRpb24+Q3JlYXRlZCB3aXRoIFNrZXRjaCAoaHR0cDovL3d3dy5ib2hlbWlhbmNvZGluZy5jb20vc2tldGNoKTwvZGVzY3JpcHRpb24+CiAgICA8ZGVmcz48L2RlZnM+CiAgICA8ZyBpZD0iUGFnZS0xIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiBza2V0Y2g6dHlwZT0iTVNQYWdlIj4KICAgICAgICA8cGF0aCBkPSJNMTcxLjUwNzgxMywzLjI1MDAwMDM4IEMyMjYuMjA4MTgzLDEyLjg1NzcxMTEgMjk3LjExMjcyMiw3MS40OTEyODIzIDI1MC44OTU1OTksMTA4LjQxMDE1NSBDMjE2LjU4MjAyNCwxMzUuODIwMzEgMTg2LjUyODQwNSw5Ny4wNjI0OTY0IDE1Ni44MDA3NzQsODUuNzczNDM0NiBDMTI3LjA3MzE0Myw3NC40ODQzNzIxIDc2Ljg4ODQ2MzIsODQuMjE2MTQ2MiA2MC4xMjg5MDY1LDEwOC40MTAxNTMgQy0xNS45ODA0Njg1LDIxOC4yODEyNDcgMTQ1LjI3NzM0NCwyOTYuNjY3OTY4IDE0NS4yNzczNDQsMjk2LjY2Nzk2OCBDMTQ1LjI3NzM0NCwyOTYuNjY3OTY4IC0yNS40NDkyMTg3LDI1Ny4yNDIxOTggMy4zOTg0Mzc1LDEwOC40MTAxNTUgQzE2LjMwNzA2NjEsNDEuODExNDE3NCA4NC43Mjc1ODI5LC0xMS45OTIyOTg1IDE3MS41MDc4MTMsMy4yNTAwMDAzOCBaIiBpZD0iUGF0aC0xIiBmaWxsPSIjZmZmZmZmIiBza2V0Y2g6dHlwZT0iTVNTaGFwZUdyb3VwIj48L3BhdGg+CiAgICA8L2c+Cjwvc3ZnPg==); -} - -#waitingTextContainer { - position: fixed; - top: 50%; -} - -@keyframes rotateBefore { - from { - transform: rotateX(60deg) rotateY(45deg) rotateZ(0deg); - } - to { - transform: rotateX(60deg) rotateY(45deg) rotateZ(-360deg); - } -} - -@keyframes rotateAfter { - from { - transform: rotateX(240deg) rotateY(45deg) rotateZ(0deg); - } - to { - transform: rotateX(240deg) rotateY(45deg) rotateZ(360deg); - } -} - -/******************************************************************************* - * * - * Login Options View (loginOptions.ejs) * - * * - ******************************************************************************/ - -#loginOptionsContainer { - position: relative; - display: flex; - justify-content: center; - align-items: center; - height: 100%; - width: 100%; - transition: filter 0.25s ease; - background: rgba(0, 0, 0, 0.50); -} - -#loginOptionsContent { - border-radius: 3px; - position: relative; - top: -5%; -} - -.loginOptionsMainContent { - display: flex; - flex-direction: column; - align-items: center; -} - -.loginOptionActions { - display: flex; - flex-direction: column; - row-gap: 10px; -} - -.loginOptionButtonContainer { - width: 16em; -} - -.loginOptionButton { - background: rgba(0, 0, 0, 0.25); - border: 1px solid rgba(126, 126, 126, 0.57); - border-radius: 3px; - height: 50px; - width: 100%; - text-align: left; - padding: 0px 25px; - cursor: pointer; - outline: none; - transition: 0.25s ease; - display: flex; - align-items: center; - column-gap: 5px; -} -.loginOptionButton:hover, -.loginOptionButton:focus { - background: rgba(54, 54, 54, 0.25); - text-shadow: 0px 0px 20px white; -} - -#loginOptionCancelContainer { - position: absolute; - bottom: -100px; -} - -#loginOptionCancelButton { - background: none; - border: none; - padding: 2px 0px; - font-size: 16px; - font-weight: bold; - color: lightgrey; - cursor: pointer; - outline: none; - transition: 0.25s ease; -} -#loginOptionCancelButton:hover, -#loginOptionCancelButton:focus { - text-shadow: 0px 0px 20px lightgrey; -} -#loginOptionCancelButton:active { - text-shadow: 0px 0px 20px rgba(211, 211, 211, 0.75); - color: rgba(211, 211, 211, 0.75); -} -#loginOptionCancelButton:disabled { - color: rgba(211, 211, 211, 0.75); - pointer-events: none; -} - - -/******************************************************************************* - * * - * Settings View (sttings.ejs) * - * * - ******************************************************************************/ - -/* Main settings container. */ -#settingsContainer { - position: relative; - height: 100%; - display: flex; - background-color: rgba(0, 0, 0, 0.50); - transition: background-color 0.25s cubic-bezier(.02, .01, .47, 1); -} - -/* Drop shadow displayed when content is scrolled out of view. */ -#settingsContainer:before { - content: ''; - background: linear-gradient(rgba(0, 0, 0, 0.25), transparent); - width: 100%; - height: 5px; - position: absolute; - opacity: 0; - transition: opacity 0.25s ease; -} -#settingsContainer[scrolled]:before { - opacity: 1; -} - -/* Left hand side of the settings UI, for navigation. */ -#settingsContainerLeft { - padding-top: 4%; - height: 100%; - width: 25%; - box-sizing: border-box; -} - -/* Settings navigation container. */ -#settingsNavContainer { - height: 100%; - display: flex; - flex-direction: column; -} - -/* Navigation header styles. */ -#settingsNavHeader { - height: 15%; - display: flex; - justify-content: center; -} -#settingsNavHeaderText { - font-size: 20px; -} - -/* Navigation items outer container. */ -#settingsNavItemsContainer { - height: 85%; - display: flex; - justify-content: center; - box-sizing: border-box; -} - -/* Navigation items content container. */ -#settingsNavItemsContent { - height: 100%; - display: flex; - flex-direction: column; - position: relative; -} - -/* Navigation item shared styles. */ -.settingsNavItem { - background: none; - border: none; - text-align: left; - margin: 5px 0px; - padding: 0px 20px; - color: grey; - cursor: pointer; - outline: none; - transition: 0.25s ease; -} -.settingsNavItem:hover, -.settingsNavItem:focus { - color: #c1c1c1; - text-shadow: 0px 0px 20px #c1c1c1; -} -.settingsNavItem[selected] { - cursor: default; - color: white; - text-shadow: none; -} - -/* Div to add some space between nav items. */ -.settingsNavSpacer { - height: 25px; -} - -/* Content container for the done button. */ -#settingsNavContentBottom { - position: absolute; - top: 65%; -} - -/* Settings navigational divider. */ -.settingsNavDivider { - width: 75%; - height: 1px; - background: rgba(126, 126, 126, 0.57); - margin-left: auto; - margin-bottom: 25px; -} - -/* Settings done button styles. */ -#settingsNavDone { - background: none; - border: none; - text-align: left; - margin: 5px 0px; - padding: 0px 20px; - color: white; - cursor: pointer; - outline: none; - transition: 0.25s ease; -} -#settingsNavDone:hover, -#settingsNavDone:focus { - text-shadow: 0px 0px 20px white, 0px 0px 20px white, 0px 0px 20px white; -} -#settingsNavDone:active { - text-shadow: 0px 0px 20px rgba(255, 255, 255, 0.75), 0px 0px 20px rgba(255, 255, 255, 0.75), 0px 0px 20px rgba(255, 255, 255, 0.75); - color: rgba(255, 255, 255, 0.75); -} -#settingsNavDone:disabled { - color: rgba(255, 255, 255, 0.75); - pointer-events: none; -} - -/* Right hand side of the settings container, for tabs. */ -#settingsContainerRight { - height: 100%; - width: 75%; - box-sizing: border-box; -} - -/* Settings tab shared styles. */ -.settingsTab { - width: 100%; - height: 100%; - overflow-y: auto; -} -.settingsTab::-webkit-scrollbar { - width: 2px; -} -.settingsTab::-webkit-scrollbar-track { - display: none; -} -.settingsTab::-webkit-scrollbar-thumb { - border-radius: 10px; - box-shadow: inset 0 0 10px rgba(255, 255, 255, 0.50); -} - -/* Add spacing to the top of each settings tab. */ -.settingsTab > *:first-child { - margin-top: 5%; -} - -/* Add spacing to the bottom of each settings tab. */ -.settingsTab > *:last-child { - margin-bottom: 20%; -} - -/* Tab header shared styles. */ -.settingsTabHeader { - display: flex; - flex-direction: column; - margin-bottom: 20px; -} -.settingsTabHeaderText { - font-size: 20px; - font-family: 'Avenir Medium'; -} -.settingsTabHeaderDesc { - font-size: 12px; -} - -/* Remove spin button from number inputs. */ -#settingsContainer input[type=number]::-webkit-inner-spin-button { - -webkit-appearance: none; -} - -/* Default styles for text/number inputs. */ -#settingsContainer input[type=number], -#settingsContainer input[type=text] { - color: white; - background: rgba(0, 0, 0, 0.25); - border-radius: 3px; - border: 1px solid rgba(126, 126, 126, 0.57); - font-family: 'Avenir Book'; - transition: 0.25s ease; -} -#settingsContainer input[type=number]:focus, -#settingsContainer input[type=text]:focus { - outline: none; - border-color: rgba(126, 126, 126, 0.87); -} -#settingsContainer input[type=number][error] { - border-color: rgb(255, 27, 12); - background: rgba(236, 0, 0, 0.25); - color: rgb(255, 27, 12); -} - -/* Styles for a generic settings entry. */ -.settingsFieldContainer { - display: flex; - align-items: center; - justify-content: space-between; - padding: 20px 0px; - width: 75%; - border-bottom: 1px solid rgba(255, 255, 255, 0.50); -} -.settingsFieldLeft { - display: flex; - flex-direction: column; -} -.settingsFieldTitle { - font-size: 14px; - font-family: 'Avenir Medium'; - color: rgba(255, 255, 255, 0.95); -} -.settingsFieldDesc { - font-size: 12px; - color: rgba(255, 255, 255, .95); - margin-top: 5px; -} -.settingsDivider { - height: 1px; - width: 75%; - background: rgba(255, 255, 255, 0.25); -} - -/* Toggle Switch */ -.toggleSwitch { - position: relative; - display: inline-block; - width: 40px; - height: 20px; - border-radius: 50px; - box-sizing: border-box; -} -.toggleSwitch input { - display:none; -} -.toggleSwitchSlider { - position: absolute; - cursor: pointer; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: rgba(255, 255, 255, 0.35); - transition: .4s; - border-radius: 50px; - border: 1px solid rgba(126, 126, 126, 0.57); -} -.toggleSwitchSlider:before { - position: absolute; - content: ""; - height: 13px; - width: 16px; - left: 3px; - bottom: 3px; - background-color: white; - box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.75); - border-radius: 50px; - transition: .4s; -} -input:checked + .toggleSwitchSlider { - background-color: rgb(31, 140, 11); - /* box-shadow: inset 2px 1px 20px black; */ - border: 1px solid rgb(31, 140, 11); -} -input:checked + .toggleSwitchSlider:before { - transform: translateX(15px); -} - -/* Range Slider styles. */ -.rangeSlider { - width: 35%; - height: 5px; - margin: 15px 0px; - background: grey; - border-radius: 3px; - position: relative; -} -.rangeSliderBar { - position: absolute; - background: #8be88b; - width: 50%; - height: 5px; - border-radius: 3px 0px 0px 3px; - transition: background 0.25s ease; -} -.rangeSliderTrack { - position: absolute; - top: -7.5px; - width: 7px; - height: 20px; - background: white; - border-radius: 3px; - left: 50%; - cursor: ew-resize; -} - -/* File selectors */ - -/* Main container for File selectors. */ -.settingsFileSelContainer { - display: flex; - flex-direction: column; - border-bottom: 1px solid rgba(255, 255, 255, 0.50); - margin-bottom: 20px; - margin-top: 20px; - width: 75%; -} - -/* File selector title. */ -.settingsFileSelTitle { - margin-bottom: 10px; -} - -/* Wrapper container for the actionable elements. */ -.settingsFileSelActions { - display: flex; - width: 90%; -} - -/* File selector icon settings. */ -.settingsFileSelIcon { - display: flex; - align-items: center; - background: rgba(126, 126, 126, 0.57); - border-radius: 3px 0px 0px 3px; - padding: 5px; - transition: 0.25s ease; -} -.settingsFileSelSVG { - width: 20px; - height: 20px; - fill: white; -} - -/* Disabled text field which stores the selected file path. */ -.settingsFileSelVal { - border-radius: 0px !important; - width: 100%; - padding: 5px 10px; - font-size: 12px; - height: 30px; -} - -/* File selection button. */ -.settingsFileSelButton { - border: 0px; - border-radius: 0px 3px 3px 0px; - font-size: 12px; - padding: 0px 5px; - cursor: pointer; - background: rgba(126, 126, 126, 0.57); - transition: 0.25s ease; - white-space: nowrap; - outline: none; -} -.settingsFileSelButton:hover, -.settingsFileSelButton:focus { - text-shadow: 0px 0px 20px white; -} -.settingsFileSelButton:active { - text-shadow: 0px 0px 20px rgba(255, 255, 255, 0.75); - color: rgba(255, 255, 255, 0.75); -} - -/* Description for the file selector. */ -.settingsFileSelDesc { - font-size: 10px; - margin: 20px 0px; - color: lightgrey; - width: 89%; -} -.settingsFileSelDesc strong { - font-family: 'Avenir Medium'; -} - -/* * * -* Settings View (Account Tab) -* * */ - -.settingsAuthAccountTypeContainer { - display: flex; - width: 75%; - flex-direction: column; -} - -.settingsAuthAccountTypeHeader { - display: flex; - align-items: center; - width: 100%; - justify-content: space-between; - padding: 10px 0px; - border-bottom: 1px solid #ffffff85; - margin-bottom: 30px; -} - -.settingsAuthAccountTypeHeaderLeft { - display: flex; - column-gap: 5px; -} - -/* Settings add account button styles. */ -.settingsAddAuthAccount { - background: none; - border: none; - text-align: left; - padding: 2px 0px; - color: white; - cursor: pointer; - outline: none; - transition: 0.25s ease; -} -.settingsAddAuthAccount:hover, -.settingsAddAuthAccount:focus { - text-shadow: 0px 0px 20px white, 0px 0px 20px white, 0px 0px 20px white; -} -.settingsAddAuthAccount:active { - text-shadow: 0px 0px 20px rgba(255, 255, 255, 0.75), 0px 0px 20px rgba(255, 255, 255, 0.75), 0px 0px 20px rgba(255, 255, 255, 0.75); - color: rgba(255, 255, 255, 0.75); -} -.settingsAddAuthAccount:disabled { - color: rgba(255, 255, 255, 0.75); - pointer-events: none; -} - -/* Auth account list container styles. */ -.settingsCurrentAccounts { - margin-bottom: 5%; -} -.settingsCurrentAccounts > .settingsAuthAccount:not(:last-child) { - margin-bottom: 10px; -} -.settingsCurrentAccounts > .settingsAuthAccount:not(:first-child) { - margin-top: 10px; -} - -/* Auth account shared styles. */ -.settingsAuthAccount { - display: flex; - background: rgba(0, 0, 0, 0.25); - border-radius: 3px; - border: 1px solid rgba(126, 126, 126, 0.57); -} - -/* Left hand side of an auth account element, for the skin image. */ -.settingsAuthAccountLeft { - padding: 5px 5px 5px 20px; -} - -/* Image of the auth account's skin. */ -.settingsAuthAccountImage { - height: 115px; -} - -/* Right hand side of the auth account, for info + actions. */ -.settingsAuthAccountRight { - display: flex; - width: 100%; -} - -/* Account details container. */ -.settingsAuthAccountDetails { - display: flex; - flex-direction: column; - justify-content: center; - margin-left: 20px; - width: 100%; -} -.settingsAuthAccountDetails > *:not(:last-child) { - margin-bottom: 20px; -} - -/* Account detail element styles. */ -.settingsAuthAccountDetailPane { - display: flex; - flex-direction: column; -} -.settingsAuthAccountDetailTitle { - font-size: 12px; - color: grey; - font-weight: bold; - font-family: 'Avenir Medium'; -} -.settingsAuthAccountDetailValue { - font-size: 14px; - -webkit-user-select: initial; -} - -/* Account actions container. */ -.settingsAuthAccountActions { - display: flex; - flex-direction: column; - justify-content: space-between; - align-items: flex-end; - padding: 10px; -} - -/* Account select button shared styles. */ -.settingsAuthAccountSelect { - opacity: 0; - border: none; - white-space: nowrap; - background: none; - font-family: 'Avenir Medium'; - outline: none; - transition: 0.25s ease; -} -.settingsAuthAccountSelect:hover:not([selected]), -.settingsAuthAccountSelect:focus:not([selected]) { - text-shadow: 0px 0px 20px white, 0px 0px 20px white; - cursor: pointer; -} -.settingsAuthAccount:hover .settingsAuthAccountSelect:not([selected]), -.settingsAuthAccountSelect[selected] { - opacity: 1; -} -.settingsAuthAccountSelect[selected] { - pointer-events: none; -} - -/* Account logout button shared styles. */ -.settingsAuthAccountLogOut { - opacity: 0; - border: 1px solid rgb(241, 55, 55); - color: rgb(241, 55, 55); - background: none; - font-size: 12px; - border-radius: 3px; - font-family: 'Avenir Medium'; - transition: 0.25s ease; - cursor: pointer; - outline: none; -} -.settingsAuthAccountLogOut:hover, -.settingsAuthAccountLogOut:focus { - box-shadow: 0px 0px 20px rgb(241, 55, 55); - background: rgba(241, 55, 55, 0.25); -} -.settingsAuthAccountLogOut:active { - box-shadow: 0px 0px 20px rgb(185, 47, 47); - background: rgba(185, 47, 47, 0.25); - border: 1px solid rgb(185, 47, 47); - color: rgb(185, 47, 47); -} -.settingsAuthAccount:hover .settingsAuthAccountLogOut { - opacity: 1; -} - -/* * * -* Settings View (Minecraft Tab) -* * */ - -/* Game resolution UI elements. */ -#settingsGameResolutionContainer { - display: flex; - flex-direction: column; - padding-bottom: 20px; - border-bottom: 1px solid rgba(255, 255, 255, 0.50); - width: 75%; -} -#settingsGameResolutionContent { - display: flex; - align-items: center; - padding-top: 10px; -} -#settingsGameResolutionCross { - color: grey; - padding: 0px 15px; -} -#settingsGameWidth, -#settingsGameHeight { - padding: 7.5px 5px; - width: 75px; -} - -/* * * -* Settings View (Mods Tab) -* * */ - -/* Selected server content container */ -#settingsSelServContainer { - background: rgba(0, 0, 0, 0.25); - width: 75%; - border-radius: 3px; - display: flex; - justify-content: space-between; - margin: 15px 0px; -} - -/* Div which will be populated with the selected server's information. */ -#settingsSelServContent { - display: flex; - align-items: center; - justify-content: flex-start; - padding: 5px 0px; -} - -/* Wrapper container for the switch server button. */ -#settingsSwitchServerContainer { - display: flex; - align-items: center; - padding: 15px; -} - -/* Button to switch server configurations on the mods tab. */ -#settingsSwitchServerButton { - opacity: 0; - border: 1px solid rgb(255, 255, 255); - color: rgb(255, 255, 255); - background: none; - font-size: 12px; - border-radius: 3px; - font-family: 'Avenir Medium'; - transition: 0.25s ease; - cursor: pointer; - outline: none; -} -#settingsSwitchServerButton:hover, -#settingsSwitchServerButton:focus { - box-shadow: 0px 0px 20px rgb(255, 255, 255); - background: rgba(255, 255, 255, 0.25); -} -#settingsSwitchServerButton:active { - box-shadow: 0px 0px 20px rgb(187, 187, 187); - background: rgba(187, 187, 187, 0.25); - border: 1px solid rgb(187, 187, 187); - color: rgb(187, 187, 187); -} -#settingsSelServContainer:hover #settingsSwitchServerButton { - opacity: 1; -} - -/* Main content container for the mod elements. */ -#settingsModsContainer { - width: 75%; -} - -/* Mod sub-container header text. */ -.settingsModsHeader { - padding-bottom: 10px; - border-bottom: 1px solid rgba(255, 255, 255, 0.5); - margin-bottom: 10px; -} - -/* Mod elements sub-containers. */ -#settingsReqModsContainer, -#settingsOptModsContainer, -#settingsDropinModsContainer { - padding-bottom: 25px; -} - -/* Main content containers for mod elements. */ -#settingsReqModsContent, -#settingsOptModsContent, -#settingsDropinModsContent { - font-size: 12px; - background: rgba(0, 0, 0, 0.25); - border-radius: 3px; - color: white; -} - -/* Mod elements. */ -.settingsMod, -.settingsDropinMod { - padding: 10px; -} -.settingsSubMod { - padding: 10px 0px 10px 15px; - margin-left: 20px; - border-left: 1px solid rgba(255, 255, 255, 0.5); -} - -/* Main content container for mod element information. */ -.settingsModContent { - display: flex; - align-items: center; - justify-content: space-between; - transition: opacity 0.25s ease; -} - -/* Wrapper container for the left side of a mod element. */ -.settingsModMainWrapper { - display: flex; - align-items: center; -} - -/* Mod enabled/disabled status. */ -.settingsModStatus { - width: 7px; - height: 7px; - border-radius: 50%; - background-color: #c32625; - margin-right: 15px; - transition: 0.25s ease; -} - -/* Mod details container. */ -.settingsModDetails { - display: flex; - flex-direction: column; -} - -/* The version of the mod. */ -.settingsModVersion { - color: grey; - font-size: 10px; -} - -/* Disabled toggleswitch for required mods. */ -.toggleSwitch[reqmod] { - filter: grayscale(49%) brightness(60%); - pointer-events: none; -} - -/* Set the status color of an enabled mod. */ -.settingsBaseMod[enabled] > .settingsModContent > .settingsModMainWrapper > .settingsModStatus { - background-color: rgb(165, 195, 37); -} - -/* Add opacity to submods of a disabled mod. */ -.settingsBaseMod:not([enabled]) > .settingsSubModContainer .settingsModContent { - opacity: 0.5; -} - -/* Curve the left border for submods. */ -.settingsSubModContainer > .settingsSubMod:first-child { - border-top-left-radius: 10px; -} -.settingsSubModContainer > .settingsSubMod:last-child { - border-bottom-left-radius: 10px; -} -.settingsSubModContainer > .settingsSubMod:only-child { - border-top-left-radius: 10px; - border-bottom-left-radius: 10px; -} - -/* Wrapper container for all submods. */ -.settingsSubModContainer { - margin-top: 10px; -} - -/* Button to open the mods folder for drop-in mods. */ -#settingsDropinFileSystemButton { - background: rgba(0, 0, 0, 0.25); - border: 1px solid rgba(126, 126, 126, 0.57); - border-radius: 3px; - height: 50px; - width: 100%; - text-align: left; - padding: 0px 50px; - cursor: pointer; - outline: none; - transition: 0.25s ease; - margin-bottom: 10px; -} -#settingsDropinFileSystemButton:hover, -#settingsDropinFileSystemButton:focus, -#settingsDropinFileSystemButton[drag] { - background: rgba(54, 54, 54, 0.25); - text-shadow: 0px 0px 20px white; -} -/* Refresh instructions on the file system button. */ -#settingsDropinRefreshNote { - font-size: 10px; - pointer-events: none; -} - -/* Button to remove drop-in mods. */ -.settingsDropinRemoveButton { - background: none; - border: none; - font-size: 10px; - text-align: left; - padding: 0px; - color: #c32625; - font-weight: bold; - cursor: pointer; - outline: none; - transition: 0.25s ease; -} -.settingsDropinRemoveButton:hover, -.settingsDropinRemoveButton:focus { - text-shadow: 0px 0px 20px #c32625, 0px 0px 20px #c32625, 0px 0px 20px #c32625; -} -.settingsDropinRemoveButton:active { - color: #9b1f1f; - text-shadow: 0px 0px 20px #9b1f1f, 0px 0px 20px #9b1f1f, 0px 0px 20px #9b1f1f; -} - -/* Shaderpack settings description. */ -#settingsShaderpackDesc { - font-size: 10px; - margin: 10px 0px; - color: lightgrey; - font-weight: bold; - width: 89%; -} - -/* Wrapper container. */ -#settingsShaderpackWrapper { - display: flex; -} - -/* Button to add shaderpacks. */ -#settingsShaderpackButton { - background: rgba(0, 0, 0, 0.25); - border: 1px solid rgba(126, 126, 126, 0.57); - border-radius: 3px; - cursor: pointer; - outline: none; - transition: 0.25s ease; - font-size: 14px; - padding: 6px 11px; - margin-right: 5px; -} -#settingsShaderpackButton:hover, -#settingsShaderpackButton:focus, -#settingsShaderpackButton[drag] { - background: rgba(54, 54, 54, 0.25); - text-shadow: 0px 0px 20px white; -} - -/* Main select container. */ -.settingsSelectContainer { - position: relative; - width: 50%; -} - -/* Div which displays the selected option. */ -.settingsSelectSelected { - border-radius: 3px; - border-width: 1px; - font-size: 14px; - padding: 6px 16px; -} - -/* Style the arrow inside the select element. */ -.settingsSelectSelected:after { - position: absolute; - content: ""; - top: calc(50% - 3px); - right: 10px; - width: 0; - height: 0; - border: 6px solid transparent; - border-color: rgba(126, 126, 126, 0.57) transparent transparent transparent; -} - -/* Point the arrow upwards when the select box is open (active). */ -.settingsSelectSelected.select-arrow-active:after { - border-color: transparent transparent rgba(126, 126, 126, 0.57) transparent; - top: 7px; -} -.settingsSelectSelected.select-arrow-active { - border-radius: 3px 3px 0px 0px; -} - -/* Options content container. */ -.settingsSelectOptions { - position: absolute; - top: 100%; - left: 0; - right: 0; - z-index: 99; - max-height: 300%; - overflow-y: scroll; - border: 1px solid rgba(126, 126, 126, 0.57); - border-top: none; - border-radius: 0px 0px 3px 3px; -} -/* Hide the items when the select box is closed. */ -.settingsSelectOptions[hidden] { - display: none; -} -.settingsSelectOptions::-webkit-scrollbar { - width: 2px; -} -.settingsSelectOptions::-webkit-scrollbar-track { - display: none; -} -.settingsSelectOptions::-webkit-scrollbar-thumb { - border-radius: 10px; - box-shadow: inset 0 0 10px rgba(255, 255, 255, 0.50); -} - -/* Shared styles between options and selection div. */ -.settingsSelectOptions div, -.settingsSelectSelected { - background: rgba(0, 0, 0, 0.25); - border-style: solid; - border-color: rgba(126, 126, 126, 0.57); - color: #ffffff; - cursor: pointer; -} -.settingsSelectOptions div { - border-width: 0px 0px 1px 0px; - font-size: 12px; - padding: 4px 16px; -} -.settingsSelectOptions div:last-child { - border-bottom: none; -} - -/* Hover + selected styles. */ -.settingsSelectOptions div:hover, .settingsSelectOptions div[selected] { - background-color: rgba(255, 255, 255, 0.25) !important; -} - -/* * * -* Settings View (Java Tab) -* * */ - -/* Style links on the Java tab. */ -#settingsTabJava a, -.settingsChangelogText a { - color: rgba(202, 202, 202, 0.75); - transition: 0.25s ease; - outline: none; -} -#settingsTabJava a:hover, -#settingsTabJava a:focus, -.settingsChangelogText a:hover, -.settingsChangelogText a:focus { - color: rgba(255, 255, 255, 0.75); -} -#settingsTabJava a:active, -.settingsChangelogText a:active { - color: rgba(165, 165, 165, 0.75); -} - -/* Main container for memory management. */ -#settingsMemoryContainer { - width: 75%; - display: flex; - flex-direction: column; - border-bottom: 1px solid rgba(255, 255, 255, 0.50); - margin-bottom: 20px; -} - -/* Memory management title. */ -#settingsMemoryTitle { - margin-bottom: 10px; - padding-bottom: 5px; - border-bottom: 1px solid rgba(255, 255, 255, 0.5); -} - -/* Memory management content. */ -#settingsMemoryContent { - display: flex; - justify-content: space-between; - width: 100%; -} -#settingsMemoryContentLeft { - width: 69%; -} -#settingsMemoryContentRight { - display: flex; - align-items: center; - margin-right: 10%; -} - -/* Header for memory sliders. */ -.settingsMemoryHeader { - font-size: 14px; -} - -/* Wrapper container for a memory slider and label. */ -.settingsMemoryActionContainer { - display: flex; - align-items: center; - justify-content: space-between; -} - -/* Label which displays a memory slider's value. */ -.settingsMemoryLabel { - font-size: 14px; - margin-right: 2%; -} - -/* Range sliders for min and max memory settings. */ -#settingsMaxRAMRange, -#settingsMinRAMRange { - width: 85%; -} - -/* Memory status elements. */ -#settingsMemoryStatus { - display: flex; - flex-direction: column; -} -#settingsMemoryStatus > .settingsMemoryStatusContainer:not(:last-child){ - margin-bottom: 50%; -} -.settingsMemoryStatusContainer { - display: flex; - flex-direction: column; - align-items: center; -} -.settingsMemoryStatusTitle { - font-size: 12px; - color: grey; - font-weight: bold; -} -.settingsMemoryStatusValue { - color: lightgrey; - font-size: 16px; -} - -/* Description for memory management. */ -#settingsMemoryDesc { - font-size: 10px; - margin: 20px 0px; - color: lightgrey; - font-weight: bold; -} - -/* Status text which displays details on the selected executable. */ -#settingsJavaExecDetails { - font-weight: bold; - color: grey; - font-size: 12px; -} - -/* Main container for the JVM options setting. */ -#settingsJVMOptsContainer { - width: 75%; -} - -/* JVM options title. */ -#settingsJVMOptsTitle { - margin-bottom: 10px; -} - -/* Wrapper container for the actionable elements. */ -#settingsJVMOptsContent { - display: flex; - width: 90%; -} - -/* Text field to input the JVM options. */ -#settingsJVMOptsVal { - border-radius: 0px 3px 3px 0px !important; - width: 100%; - padding: 5px 10px; - font-size: 12px; -} -#settingsJVMOptsContent:focus-within > .settingsJavaIcon { - background: rgba(126, 126, 126, 0.87); -} - -/* Description for the JVM options setting. */ -#settingsJVMOptsDesc { - font-size: 10px; - margin: 20px 0px; - color: lightgrey; - font-weight: bold; - width: 89%; -} - -/* * * -* Settings View (Launcher Tab) -* * */ - -/* Tailored style for the data directory header. */ -#settingsDataDirTitle { - margin-bottom: 10px; -} - -/* * * -* Settings View (About Tab) -* * */ - -/* Main about content container. */ -#settingsAboutCurrentContainer { - display: flex; - flex-direction: column; - background: rgba(0, 0, 0, 0.25); - border: 1px solid rgba(126, 126, 126, 0.57); - border-radius: 3px; - width: 75%; - margin-bottom: 20px; -} - -/* About content. */ -#settingsAboutCurrentContent { - display: flex; - flex-direction: column; - padding: 15px; -} - -/* About header elements. */ -#settingsAboutCurrentHeadline { - display: flex; - align-items: center; - padding-bottom: 5px; - border-bottom: 1px solid rgba(126, 126, 126, 0.57); -} -#settingsAboutLogo { - width: 30px; - height: 30px; - padding: 5px; -} -#settingsAboutTitle { - font-size: 23px; - padding-left: 10px; -} - -/* Current version container. */ -#settingsAboutCurrentVersion { - display: flex; - align-items: center; - padding-top: 10px; -} - -/* Checkmark next to the version information. */ -#settingsAboutCurrentVersionCheck { - border-radius: 50%; - background: #23aa23; - text-align: center; - font-weight: bold; - margin: 11px 12px; - color: white; - height: 15px; - width: 15px; - font-size: 12px; - line-height: 17px; -} - -/* Current version details container. */ -#settingsAboutCurrentVersionDetails { - margin-left: 10px; -} - -/* Release type text. */ -#settingsAboutCurrentVersionTitle { - font-size: 12px; - font-family: 'Avenir Medium'; - color: #23aa23; - font-weight: bold; -} - -/* Current version text. */ -#settingsAboutCurrentVersionLine { - font-size: 10px; - color: grey; - font-weight: bold; -} - -/* About information links. */ -#settingsAboutButtons { - display: flex; - padding: 0px 15px; - margin-bottom: 5px; -} -.settingsAboutButton { - background: none; - border: none; - font-size: 10px; - color: grey; - padding: 0px 5px; - transition: 0.25s ease; - outline: none; - text-decoration: none; -} -.settingsAboutButton:hover, -.settingsAboutButton:focus { - color: rgb(165, 165, 165); -} -.settingsAboutButton:active { - color: rgba(124, 124, 124, 0.75); -} - -/* Main changelog container. */ -.settingsChangelogContainer { - display: flex; - flex-direction: column; - background: rgba(0, 0, 0, 0.25); - border: 1px solid rgba(126, 126, 126, 0.57); - border-radius: 3px; - width: 75%; - margin-bottom: 20px; -} - -/* Changelog content container. */ -.settingsChangelogContent { - display: flex; - flex-direction: column; - padding: 15px; -} - -/* Changelog header container. */ -.settingsChangelogHeadline { - padding-bottom: 10px; - margin-bottom: 10px; - border-bottom: 1px solid rgba(126, 126, 126, 0.57); -} -/* Changelog header label. */ -.settingsChangelogLabel { - font-size: 12px; - color: grey; - font-weight: bold; -} - -/* Changelog text content container. */ -.settingsChangelogText { - font-size: 12px; -} - -/* Styles for the changelog elements. */ -.settingsChangelogText p { - margin-bottom: 16px; - line-height: 1.5; -} -.settingsChangelogText blockquote { - border-left: 0.25em solid rgba(126, 126, 126, 0.95); - margin: 0px; - padding: 0 0 0 1em; - color: rgba(255, 255, 255, 0.85); -} -.settingsChangelogText code { - padding: 0.1em 0.4em; - font-size: 85%; - background-color: rgba(255, 255, 255, 0.25); - color: white; - border-radius: 3px; - font-family: 'Avenir Book'; -} -.settingsChangelogText li+li { - margin-top: .25em; -} -.settingsChangelogText a.commit-link { - font-weight: 400; - color: #ffffff; - text-decoration: none; -} -.settingsChangelogText a.commit-link:hover { - text-decoration: underline !important; - text-decoration-color: black; -} -.settingsChangelogText tt { - padding: 0.1em 0.4em; - font-size: 86%; - background-color: white; - border-radius: 3px; - color: black; - font-weight: bold; -} -.settingsChangelogText a.commit-link:hover tt { - text-decoration: underline; - text-decoration-color: black; -} -.settingsChangelogText .highlight { - background: rgba(0, 0, 0, 0.30); - user-select: initial; - padding: 5px 10px; -} -.settingsChangelogText .highlight pre { - margin: 0px; -} - -/* Container for the changelog button. */ -.settingsChangelogActions { - padding: 0px 15px 5px 15px; -} - -/* Open changelog on GitHub. */ -.settingsChangelogButton { - padding: 0px; -} - -/* * * -* Settings View (Updates Tab) -* * */ - -/* Main about content container. */ -#settingsUpdateStatusContainer { - display: flex; - flex-direction: column; - background: rgba(0, 0, 0, 0.25); - border: 1px solid rgba(126, 126, 126, 0.57); - border-radius: 3px; - width: 75%; - margin-bottom: 20px; -} - -/* Update content. */ -#settingsUpdateStatusContent { - display: flex; - flex-direction: column; - padding: 15px; -} - -/* Update header elements. */ -#settingsUpdateStatusHeadline { - display: flex; - align-items: center; - padding-bottom: 5px; - border-bottom: 1px solid rgba(126, 126, 126, 0.57); -} -#settingsUpdateTitle { - font-size: 16px; - padding-left: 10px; - font-weight: bold; -} - -/* Update version container. */ -#settingsUpdateVersion { - display: flex; - align-items: center; - padding: 10px 0px; - border-bottom: 1px solid rgba(126, 126, 126, 0.57); -} - -/* Checkmark next to the version information. */ -#settingsUpdateVersionCheck { - border-radius: 50%; - background: #23aa23; - text-align: center; - font-weight: bold; - margin: 11px 12px; - color: white; - height: 15px; - width: 15px; - font-size: 12px; - line-height: 17px; -} - -/* Update version details container. */ -#settingsUpdateVersionDetails { - margin-left: 10px; -} - -/* Release type text. */ -#settingsUpdateVersionTitle { - font-size: 12px; - font-family: 'Avenir Medium'; - color: #23aa23; - font-weight: bold; -} - -/* Current version text. */ -#settingsUpdateVersionLine { - font-size: 10px; - color: grey; - font-weight: bold; -} - -/* Update action container. */ -#settingsUpdateActionContainer { - padding-top: 10px; - font-size: 14px; - font-weight: bold; -} - -/* Update action button styles. */ -#settingsUpdateActionButton { - display: flex; - flex-direction: column; - padding-left: 10px; - background: none; - border: none; - font-size: 14px; - font-weight: bold; - cursor: pointer; - outline: none; - text-align: left; - transition: 0.25s ease; -} -#settingsUpdateActionButton:hover, -#settingsUpdateActionButton:focus { - text-shadow: 0px 0px 20px white, 0px 0px 20px white, 0px 0px 20px white; -} -#settingsUpdateActionButton:active { - text-shadow: 0px 0px 20px #c7c7c7, 0px 0px 20px #c7c7c7, 0px 0px 20px #c7c7c7; - color: #c7c7c7; -} -#settingsUpdateActionButton:disabled { - pointer-events: none; -} - -/******************************************************************************* - * * - * Landing View (Structural Styles) * - * * - ******************************************************************************/ - -/* Main content container. */ -#landingContainer { - height: 100%; - position: relative; - transition: background 2s ease; - overflow-y: hidden; -} - -/* Upper content container. */ -#landingContainer > #upper { - position: relative; - transition: top 2s ease; - top: 0px; - height: 77%; - display: flex; -} -#landingContainer > #upper > #left { - display: inline-flex; - width: 15%; - height: 100%; - justify-content: flex-end; -} -#landingContainer > #upper > #content { - display: inline-flex; - width: 70%; - height: 100%; -} -#landingContainer > #upper > #right { - display: inline-flex; - width: 15%; - height: 100%; -} - -/* Lower content container. */ -#landingContainer > #lower { - height: 23%; - display: flex; - background: linear-gradient(to top, rgba(0, 0, 0, 0.75), rgba(0, 0, 0, 0)); -} -#landingContainer > #lower > #left { - position: relative; - transition: top 2s ease; - top: 0px; - height: 100%; - width: 33%; - display: inline-flex; - justify-content: center; -} -#landingContainer > #lower > #left #content { - position: relative; - top: 25px; - display: inline-flex; - line-height: 24px; - left: 50px; -} -#landingContainer > #lower > #center { - position: relative; - transition: top 2s ease; - top: 0px; - height: 100%; - width: 34%; - display: inline-flex; - justify-content: center; -} -#landingContainer > #lower > #center #content { - position: relative; - z-index: 500; - transition: top 2s ease; - top: 10px; -} -#landingContainer > #lower > #right { - position: relative; - transition: top 2s ease; - top: 0px; - height: 100%; - width: 33%; - display: inline-flex; -} - -/******************************************************************************* - * * - * Landing View (News Styles) * - * * - ******************************************************************************/ - -/* Main container. */ -#newsContainer { - position: absolute; - top: 100%; - height: 100%; - width: 100%; - transition: top 2s ease; - display: flex; - align-items: flex-end; - justify-content: center; -} - -/* News content container. */ -#newsContent { - height: 82vh; - width: 100%; - display: flex; - -webkit-user-select: initial; - position: relative; -} - -/* Drop shadow displayed when content is scrolled out of view. */ -#newsContent:before { - content: ''; - background: linear-gradient(rgba(0, 0, 0, 0.25), transparent); - width: 100%; - height: 5px; - position: absolute; - opacity: 0; - transition: opacity 0.25s ease; -} -#newsContent[scrolled]:before { - opacity: 1; -} - -/* News article status container (left). */ -#newsStatusContainer { - width: calc(30% - 60px); - height: calc(100% - 30px); - padding: 15px 15px 15px 45px; - display: flex; - flex-direction: column; - justify-content: space-between; - position: relative; -} - -/* News status content. */ -#newsStatusContent { - display: flex; - flex-direction: column; - align-items: flex-end; -} - -/* News title wrapper. */ -#newsTitleContainer { - display: flex; - max-width: 90%; -} - -/* News article title styles. */ -#newsArticleTitle { - font-size: 18px; - font-weight: bold; - font-family: 'Avenir Medium'; - color: white; - text-decoration: none; - transition: 0.25s ease; - outline: none; - text-align: right; -} -#newsArticleTitle:hover, -#newsArticleTitle:focus { - text-shadow: 0px 0px 20px white; -} -#newsArticleTitle:active { - color: #c7c7c7; - text-shadow: 0px 0px 20px #c7c7c7; -} - -/* News meta container. */ -#newsMetaContainer { - display: flex; - flex-direction: column; -} - -/* Date and author wrappers. */ -#newsArticleDateWrapper, -#newsArticleAuthorWrapper { - display: flex; - justify-content: flex-end; -} - -/* Date and author shared styles. */ -#newsArticleDate, -#newsArticleAuthor { - display: inline-block; - font-size: 10px; - padding: 0px 5px; - font-weight: bold; - border-radius: 2px; -} - -/* Date styles. */ -#newsArticleDate { - background: white; - color: black; - margin-top: 5px; -} - -/* Author styles. */ -#newsArticleAuthor { - background: #a02d2a; -} - -/* News article comments styles. */ -#newsArticleComments { - margin-top: 5px; - display: inline-block; - font-size: 10px; - color: #ffffff; - text-decoration: none; - transition: 0.25s ease; - outline: none; - text-align: right; -} -#newsArticleComments:focus, -#newsArticleComments:hover { - color: #e0e0e0; -} -#newsArticleComments:active { - color: #c7c7c7; -} - -/* Article content container (right). */ -#newsArticleContainer { - width: calc(100% - 25px); - height: 100%; - margin: 0px 0px 0px 25px; -} - -/* Article content styles. */ -#newsArticleContentScrollable { - font-size: 12px; - overflow-y: scroll; - height: 100%; - padding: 0px 15px 0px 15px; -} -#newsArticleContentScrollable img, -#newsArticleContentScrollable iframe { - max-width: 95%; - display: block; - margin: 0 auto; -} -#newsArticleContentScrollable a { - color: rgba(202, 202, 202, 0.75); - transition: 0.25s ease; - outline: none; -} -#newsArticleContentScrollable a:hover, -#newsArticleContentScrollable a:focus { - color: rgba(255, 255, 255, 0.75); -} -#newsArticleContentScrollable a:active { - color: rgba(165, 165, 165, 0.75); -} -#newsArticleContentScrollable::-webkit-scrollbar { - width: 2px; -} -#newsArticleContentScrollable::-webkit-scrollbar-track { - display: none; -} -#newsArticleContentScrollable::-webkit-scrollbar-thumb { - border-radius: 10px; - box-shadow: inset 0 0 10px rgba(255, 255, 255, 0.50); -} -.bbCodeSpoilerButton { - background: none; - border: none; - outline: none; - cursor: pointer; - font-size: 16px; - transition: 0.25s ease; - width: 100%; - border-bottom: 1px solid white; - padding-bottom: 15px; -} -.bbCodeSpoilerButton:hover, -.bbCodeSpoilerButton:focus { - text-shadow: 0px 0px 20px #ffffff, 0px 0px 20px #ffffff, 0px 0px 20px #ffffff; -} -.bbCodeSpoilerButton:active { - color: #c7c7c7; - text-shadow: 0px 0px 20px #c7c7c7, 0px 0px 20px #c7c7c7, 0px 0px 20px #c7c7c7; -} -.bbCodeSpoilerText { - display: none; - padding: 15px 0px; - border-bottom: 1px solid white; -} - - -#newsArticleContentWrapper { - width: 80%; -} - -.newsArticleSpacerTop { - height: 15px; -} - -/* Div to add spacing at the end of a news article. */ -.newsArticleSpacerBot { - height: 30px; -} - -/* News navigation container. */ -#newsNavigationContainer { - display: flex; - justify-content: center; - align-items: center; - margin-bottom: 10px; - -webkit-user-select: none; - position: absolute; - bottom: 15px; - right: 0px; -} - -/* Navigation status span. */ -#newsNavigationStatus { - font-size: 12px; - margin: 0px 15px; -} - -/* Left and right navigation button styles. */ -#newsNavigateLeft, -#newsNavigateRight { - background: none; - border: none; - outline: none; - height: 20px; - cursor: pointer; -} -#newsNavigateLeft:hover #newsNavigationLeftSVG, -#newsNavigateLeft:focus #newsNavigationLeftSVG, -#newsNavigateRight:hover #newsNavigationRightSVG, -#newsNavigateRight:focus #newsNavigationRightSVG { - -webkit-filter: drop-shadow(0px 0px 2px #fff); -} -#newsNavigateLeft:active #newsNavigationLeftSVG .arrowLine, -#newsNavigateRight:active #newsNavigationRightSVG .arrowLine { - stroke: #c7c7c7; -} -#newsNavigateLeft:active #newsNavigationLeftSVG, -#newsNavigateRight:active #newsNavigationRightSVG { - -webkit-filter: drop-shadow(0px 0px 2px #c7c7c7); -} -#newsNavigateLeft:disabled #newsNavigationLeftSVG .arrowLine, -#newsNavigateRight:disabled #newsNavigationRightSVG .arrowLine { - stroke: rgba(255, 255, 255, 0.75); -} -#newsNavigationLeftSVG { - transform: rotate(-90deg); - width: 15px; -} -#newsNavigationRightSVG { - transform: rotate(90deg); - width: 15px; -} - -/* News error (message) container. */ -#newsErrorContainer { - height: 100%; - display: flex; - align-items: center; - flex-direction: column; - justify-content: center; -} -#newsErrorFailed { - display: flex; - align-items: center; - flex-direction: column; - justify-content: center; -} - -/* News error content (message). */ -.newsErrorContent { - font-size: 20px; -} -#newsErrorLoading { - display: flex; - width: 168.92px; -} -#nELoadSpan { - white-space: pre; -} -/* News error retry button styles. */ -#newsErrorRetry { - font-size: 12px; - font-weight: bold; - cursor: pointer; - background: none; - border: none; - outline: none; - transition: 0.25s ease; -} -#newsErrorRetry:focus, -#newsErrorRetry:hover { - text-shadow: 0px 0px 20px white; -} -#newsErrorRetry:active { - color: #c7c7c7; - text-shadow: 0px 0px 20px #c7c7c7; -} - -/******************************************************************************* - * * - * Landing View (Top Styles) * - * * - ******************************************************************************/ - -/* * * -* Landing View (Top Styles) | Left Content -* * */ - -/* Logo image. */ -#image_seal { - height: 70px; - width: auto; - position: relative; - border: 2px solid white; - box-sizing: border-box; - border-radius: 50%; -} - -/* Logo container styles. */ -#image_seal_container { - position: relative; - height: 70px; - width: 70px; - border-radius: 50%; - margin-top: 50px; -} - -/* Logo container styles w/ update. */ -#image_seal_container[update]{ - cursor: pointer -} -#image_seal_container[update]:before, -#image_seal_container[update]:after { - cursor: pointer; - position: absolute; - content: ''; - height: 100%; - width: 100%; - top: 0%; - left: 0%; - border-radius: 50%; - box-shadow: 0 0 15px #43c628; - animation: glow-grow 4s ease-out infinite; - background: rgba(0, 0, 0, 0.15); -} -#image_seal_container[update]:before { - animation-delay: 2s; -} - -/* Update available tooltip styles. */ -#updateAvailableTooltip { - cursor: pointer; - visibility: hidden; - opacity: 0; - width: 100px; - height: 15px; - background-color: rgb(0, 0, 0); - color: #fff; - text-align: center; - border-radius: 4px; - padding: 2px; - position: absolute; - z-index: 1; - top: 115%; - left: -17.5px; - font-family: 'Avenir Medium'; - font-size: 12px; - transition: visibility 0s linear 0.25s, opacity 0.25s ease; -} -#updateAvailableTooltip::after { - content: " "; - position: absolute; - left: 50%; - bottom: 100%; - margin-left: -5px; - border-width: 5px; - border-style: solid; - border-color: transparent transparent rgb(0, 0, 0) transparent; -} -#image_seal_container[update]:hover #updateAvailableTooltip { - visibility: visible; - opacity: 1; - transition-delay: 0s; -} - -/* Update available animation. */ -@keyframes glow-grow { - 0% { - opacity: 0; - transform: scale(1); - } - 80% { - opacity: 1; - } - 100% { - transform: scale(1.5); - opacity: 0; - } -} - -/* * * -* Landing View (Bottom Styles) | Right Content -* * */ - -/* Wrapper container for top, right content. */ -#rightContainer { - display: flex; - flex-direction: column; - position: relative; - top: 50px; - align-items: flex-start; - height: calc(100% - 50px); -} - -/* Right hand user content container. */ -#user_content { - display: flex; - align-items: center; - justify-content: center; - box-sizing: border-box; - position: relative; -} - -/* User profile avatar container. */ -#avatarContainer { - border-radius: 50%; - border: 2px solid #cad7e1; - box-sizing: border-box; - background: rgba(1, 2, 1, 0.5); - height: 70px; - width: 70px; - box-shadow: 0px 0px 10px 0px rgb(0, 0, 0); - overflow: hidden; - position: relative; - background-position: center; - background-repeat: no-repeat; - background-size: contain; -} - -/* Avatar edit overlay. */ -#avatarOverlay { - opacity: 0; - position: absolute; - z-index: 1; - display: flex; - justify-content: center; - align-items: center; - transition: 0.25s ease; - font-weight: bold; - letter-spacing: 2px; - background-color: rgba(0, 0, 0, 0.35); - -webkit-user-select: none; - border: none; - cursor: pointer; - width: 100%; - height: 100%; - border-radius: 50%; -} -#avatarOverlay:hover, -#avatarOverlay:focus { - opacity: 1; -} -#avatarOverlay:active { - background-color: rgba(0, 0, 0, 0.45); -} - -/* User profile name text. */ -#user_text { - font-size: 12px; - min-width: 135px; - font-weight: 900; - letter-spacing: 1px; - text-shadow: 0px 0px 20px black; - position: absolute; - right: 95px; - text-align: right; - -webkit-user-select: initial; -} - -/* Social media icon content container. */ -#mediaContent { - position: relative; - display: flex; - flex-direction: column; - margin-top: 25px; - height: calc(100% - 95px); - width: 70px; - align-items: center; -} - -/* Social Media Icon division containers. */ -#internalMedia, #externalMedia { - display: flex; - flex-direction: column; -} - -/* Container object which wraps an icon to ensure fluid transitions. */ -.mediaContainer { - display: flex; - justify-content: center; - align-items: center; - height: 27px; -} - -/* Divider bar between the external and internal icons. */ -.mediaDivider { - height: 1px; - width: 14px; - background: rgb(255, 255, 255); - margin: 10px 0px; -} - -/* Social media icon shared styles. */ -.mediaSVG { - fill: #ffffff; - height: 12px; - transition: 0.25s ease; - cursor: pointer; - height: 12px; - width: 25px; -} -.mediaSVG:hover, -.mediaURL:focus .mediaSVG, -.mediaSVG:active { - height: 20px; -} - -/* Social media URL shared styles. */ -.mediaURL { - outline: none; -} - -/* Internal media button shared styles. */ -.mediaButton { - background: none; - border: none; - padding: 0px; - display: flex; - align-items: center; - outline: none; -} - -#settingsMediaContainer { - position: relative; -} - -/* Settings icon colors. */ -#settingsSVG { - stroke: #ffffff; - height: 15px; -} -.mediaButton:hover #settingsSVG, -.mediaButton:focus #settingsSVG, -.mediaButton:active #settingsSVG { - height: 23px; -} - -/* Settings tooltip styles. */ -#settingsTooltip { - visibility: hidden; - opacity: 0; - width: 75px; - height: 20px; - background-color: rgba(0, 0, 0, 0.75); - text-align: center; - border-radius: 4px; - position: absolute; - z-index: 1; - right: 130%; - font-size: 12px; - line-height: 20px; - transition: visibility 0s linear 0.25s, opacity 0.25s ease; -} -#settingsTooltip::after { - content: " "; - position: absolute; - top: 50%; - left: 100%; - margin-top: -5px; - border-width: 5px; - border-style: solid; - border-color: transparent transparent transparent rgba(0, 0, 0, 0.75); -} -.mediaButton:hover #settingsTooltip, -.mediaButton:focus #settingsTooltip, -.mediaButton:active #settingsTooltip { - visibility: visible; - opacity: 1; - transition-delay:0s; -} - -/* Twitter icon colors. */ -#twitterSVG:hover, -#twitterURL:focus #twitterSVG { - fill: #1da1f2; -} -#twitterSVG:active { - fill: #1b8dd4; -} - -/* Instagram icon colors. */ -#instagramSVG:hover, -#instagramURL:focus #instagramSVG { - fill: url('#instaFill') - /*fill: radial-gradient(circle at 30% 107%, #fdf497 0%, #fdf497 5%, #fd5949 45%, #d6249f 60%, #285AEB 90%); */ -} -#instagramSVG:active { - fill: url('#instaFill') -} - -/* Youtube icon colors. */ -#youtubeSVG:hover, -#youtubeURL:focus #youtubeSVG { - fill: #f00; -} -#youtubeSVG:active { - fill: #ea0202; -} - -/* Discord icon colors. */ -#discordSVG:hover, -#discordURL:focus #discordSVG { - fill: #7288d9; -} -#discordSVG:active { - fill: #657ac4; -} - -/******************************************************************************* - * * - * Landing View (Bottom Styles) * - * * - ******************************************************************************/ - -/* Style for a general label on the bottom of the landing view. */ -.bot_label { - font-size: 9px; - letter-spacing: 1px; - font-weight: bold; - text-shadow: 0px 0px 0px #bebcbb; -} - -/* Divider used on the bottom of the landing view. */ -.bot_divider { - height: 25px; - width: 2px; - background: rgba(107, 105, 105, 0.7); - margin-left: 20px; - margin-right: 20px; -} - -/* * * -* Landing View (Bottom Styles) | Left Content -* * */ - -/* Maintains maximum width on the status bar. */ -#server_status_wrapper { - display: inline-flex; - width: 75px; -} - -/* Span which displays the player count of the selected server. */ -#player_count { - color: #949494; - font-size: 8px; - font-weight: 900; - text-shadow: 0px 0px 20px #949494; - margin-left: 10px; -} - -/* Wrapper container for the mojang status bar. */ -#mojangStatusWrapper { - position: relative; - display: flex; - cursor: pointer; -} - -/* Icon which displays the status of the mojang services. */ -#mojang_status_icon { - font-size: 30px; - color: #848484; - margin-left: 15px; - font-family: 'sans-serif'; -} - -/* Tooltip which displays more details about the mojang statuses. */ -#mojangStatusTooltip { - position: absolute; - visibility: hidden; - opacity: 0; - width: 145px; - min-height: 150px; - background-color: rgba(0, 0, 0, 0.75); - color: #fff; - border-radius: 4px; - padding: 5px 10px; - z-index: 1; - font-family: 'Avenir Medium'; - font-size: 12px; - transition: visibility 0s linear 0.25s, opacity 0.25s ease; - bottom: calc(100% + 15px); - transform: translateX(-50%); - margin-left: 50%; - box-shadow: 0px 0px 20px rgb(0, 0, 0); - cursor: default; -} -#mojangStatusTooltip:after { - content: " "; - position: absolute; - left: 50%; - top: 100%; - margin-left: -5px; - border-width: 5px; - border-style: solid; - border-color: rgba(0, 0, 0, 0.75) transparent transparent transparent; -} -#mojangStatusWrapper:hover #mojangStatusTooltip { - visibility: visible; - opacity: 1; - transition-delay: 0s; -} - -/* Tooltip title for the mojang statuses. */ -#mojangStatusTooltipTitle { - width: 100%; - text-align: center; - margin-bottom: 5px; - letter-spacing: 1px; -} - -/* Wrapper container for the non essential services title. */ -#mojangStatusNEContainer { - display: flex; - align-items: center; - margin: 10px 0px; -} - -/* White bar which surrounds the non essential service title. */ -.mojangStatusNEBar { - height: 1px; - width: 100%; - background: white; -} - -/* Non essential service title text. */ -#mojangStatusNETitle { - font-size: 10px; - padding: 0px 3px; - text-align: center; - letter-spacing: 1px; -} - -/* Wrapper container for mojang service information. */ -.mojangStatusContainer { - display: flex; -} - -/* Displays the name of the mojang service. */ -.mojangStatusName { - width: 100%; - font-size: 10px; - letter-spacing: 1px; - line-height: 12px; - padding: 6px 0px; -} - -/* Displays the status of the mojang service. */ -.mojangStatusIcon { - margin-right: 10px; - font-size: 18.5px; - color: #848484; -} - -/* * * -* Landing View (Bottom Styles) | Center Content -* * */ - -/* Button which opens the news view. */ -#newsButton { - background: none; - border: none; - cursor: pointer; - outline: none; -} -#newsButton:hover #newsButtonText, -#newsButton:focus #newsButtonText { - text-shadow: 0px 0px 20px #fff, 0px 0px 20px #fff; -} -#newsButton:active { - color: #c7c7c7; - text-shadow: 0px 0px 20px #c7c7c7, 0px 0px 20px #c7c7c7; -} - -#newsButton:hover #newsButtonSVG, -#newsButton:focus #newsButtonSVG { - -webkit-filter: drop-shadow(0px 0px 2px #fff); -} -#newsButton:active #newsButtonSVG .arrowLine { - stroke: #c7c7c7; -} -#newsButton:active #newsButtonSVG { - -webkit-filter: drop-shadow(0px 0px 2px #c7c7c7); -} -#newsButton:disabled #newsButtonSVG .arrowLine { - stroke: rgba(255, 255, 255, 0.75); -} - -/* Icon which indicates there is new news. */ -#newsButtonAlert { - width: 5px; - height: 5px; - position: absolute; - border-radius: 50%; - background: red; - right: -1px; - top: 50%; -} - -/* Arrow image which floats above the news button. */ -#newsButtonSVG { - height: 11px; - margin-left: -2px; - transition: 0.25s ease; -} - -/* Span which contains the news button text. */ -#newsButtonText { - color: white; - font-weight: 900; - letter-spacing: 2px; - text-shadow: 0px 0px 0px #bebcbb; - font-size: 11px; - line-height: 30px; - display: flex; - transition: 0.25s ease; -} - -/* * * -* Landing View (Bottom Styles) | Right Content -* * */ - -/* Main launch content container. */ -#landingContainer > #lower > #right #launch_content { - position: relative; - top: 25px; - display: inline-flex; -} - -/* The launch button. */ -#launch_button { - background: none; - border: none; - cursor: pointer; - font-weight: 900; - letter-spacing: 2px; - text-shadow: 0px 0px 0px #bebcbb; - font-size: 20px; - padding: 0px; - transition: 0.25s ease; - outline: none; -} -#launch_button:hover, -#launch_button:focus { - text-shadow: 0px 0px 20px #fff, 0px 0px 20px #fff; -} -#launch_button:active { - color: #c7c7c7; - text-shadow: 0px 0px 20px #c7c7c7, 0px 0px 20px #c7c7c7; -} -#launch_button:disabled { - color: #c7c7c7; - cursor: default; - pointer-events: none; -} - -/* Launch details main container, hidden until launch processing begins. */ -#launch_details { - position: relative; - top: 25px; - display: none; -} - -/* Left side of launch details container, displays percentage and a divider. */ -#launch_details_left { - display: flex; -} - -/* Span which displays percentage complete. */ -#launch_progress_label { - font-weight: 900; - letter-spacing: 1px; - text-shadow: 0px 0px 0px #bebcbb; - font-size: 20px; - min-width: 53.21px; - max-width: 53.21px; - text-align: right; -} - -/* Right side of launch details container, displays progress bar and details. */ -#launch_details_right { - display: flex; - flex-direction: column; - justify-content: center; -} - -/* Button which opens the server selection view. */ -#server_selection_button { - background: none; - border: none; - outline: none; - cursor: pointer; - line-height: 24px; - padding: 0px; - transition: 0.25s ease; -} -#server_selection_button:hover, -#server_selection_button:focus { - text-shadow: 0px 0px 20px #fff, 0px 0px 20px #fff, 0px 0px 20px #fff; -} -#server_selection_button:active { - color: #c7c7c7; - text-shadow: 0px 0px 20px #c7c7c7, 0px 0px 20px #c7c7c7, 0px 0px 20px #c7c7c7; -} - -/* Progress bar styles. */ -#launch_progress[value] { - height: 3px; - width: 265px; - -webkit-appearance: none; -} -#launch_progress[value]::-webkit-progress-bar { - background-color: transparent; -} -#launch_progress[value]::-webkit-progress-value { - background-color: #fff; -} - -/* Span which displays information about the status of the launch process. */ -#launch_details_text { - font-size: 11px; - text-overflow: ellipsis; - white-space: nowrap; - overflow: hidden; -} - -/******************************************************************************* - * * - * Overlay View (overlay.ejs) * - * * - ******************************************************************************/ - -/* * * -* Overlay View (Main Content) -* * */ - -/* Overlay container, placed over the main div. */ -#overlayContainer { - position: absolute; - z-index: 500; - top: 22px; - display: flex; - align-items: center; - justify-content: center; - width: 100%; - height: calc(100% - 22px); - background: rgba(0, 0, 0, 0.50); -} - -/* Main overlay content. */ -#overlayContent { - position: relative; - display: flex; - flex-direction: column; - align-items: center; - /*justify-content: space-between;*/ - width: 300px; - /*height: 35%;*/ - box-sizing: border-box; - padding: 15px 0px; - /* background-color: #424242; */ - text-align: center; -} - -/* Main overlay content anchor styles. */ -#overlayContent a, -#overlayDismiss { - color: rgba(202, 202, 202, 0.75); - transition: 0.25s ease; -} -#overlayContent a:hover, -#overlayContent a:focus, -#overlayDismiss:focus { - color: rgba(255, 255, 255, 0.75); -} -#overlayContent a:active, -#overlayDismiss:active { - color: rgba(165, 165, 165, 0.75); -} - -/* Add spacing between overlay content elements. */ -#overlayContent > *:first-child { - margin-top: 0px !important; -} -#overlayContent > *:last-child { - margin-bottom: 0px !important; -} -#overlayContent > * { - margin: 8px 0px; -} - -/* Overlay title styles. */ -#overlayTitle { - font-family: 'Avenir Medium'; - font-size: 20px; - font-weight: bold; - letter-spacing: 1px; - -webkit-user-select: initial; -} - -/* Overlay description styles. */ -#overlayDesc { - font-size: 12px; - font-weight: bold; - -webkit-user-select: initial; -} - -/* Div which contains action buttons. */ -#overlayActionContainer { - display: flex; - flex-direction: column; - justify-content: center; -} - -/* Overlay acknowledge button styles. */ -#overlayAcknowledge { - background: none; - border: 1px solid #ffffff; - color: white; - font-family: 'Avenir Medium'; - font-weight: bold; - border-radius: 2px; - padding: 0px 8.1px; - cursor: pointer; - transition: 0.25s ease; -} -#overlayAcknowledge:hover, -#overlayAcknowledge:focus { - box-shadow: 0px 0px 10px 0px #fff; - outline: none; -} -#overlayAcknowledge:active { - border-color: rgba(255, 255, 255, 0.75); - color: rgba(255, 255, 255, 0.75); -} - -/* Overlay dismiss option styles. */ -#overlayDismiss { - font-weight: bold; - font-size: 10px; - text-decoration: none; - padding-top: 2.5px; - background: none; - border: none; - outline: none; - cursor: pointer; -} -#overlayDismiss:hover { - color: rgba(255, 255, 255, 0.75); -} -#overlayDismiss:active { - color: rgba(165, 165, 165, 0.75); -} - -/* * * -* Overlay View (Server + Account Selection Content) -* * */ - -/* Server selection content container. */ -#serverSelectContent, -#accountSelectContent { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - height: 75%; -} - -/* Server selection header. */ -#serverSelectHeader, -#accountSelectHeader { - font-family: 'Avenir Medium'; - font-size: 20px; - font-weight: bold; - color: #fff; - margin-bottom: 25px; -} - -/* Wrapper div for the list of available servers. */ -#serverSelectList, -#accountSelectList { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - max-height: 65%; - min-height: 40%; -} - -/* Scrollable div which lists the available servers. */ -#serverSelectListScrollable, -#accountSelectListScrollable { - padding: 0px 5px; - overflow-y: scroll; -} -#serverSelectListScrollable::-webkit-scrollbar, -#accountSelectListScrollable::-webkit-scrollbar { - width: 2px; -} -#serverSelectListScrollable::-webkit-scrollbar-track, -#accountSelectListScrollable::-webkit-scrollbar-track { - display: none; -} -#serverSelectListScrollable::-webkit-scrollbar-thumb, -#accountSelectListScrollable::-webkit-scrollbar-thumb { - border-radius: 10px; - box-shadow: inset 0 0 10px rgba(255, 255, 255, 0.50); -} - -/* Content container for a server listing. */ -.serverListing { - border: none; - padding: 0px; - width: 375px; - min-height: 60px; - display: flex; - justify-content: flex-start; - align-items: center; - opacity: 0.6; - transition: 0.25s ease; - cursor: pointer; - position: relative; - background: rgba(131, 131, 131, 0.25); -} -.serverListing[selected] { - cursor: default; - opacity: 1.0; -} -.serverListing:hover, -.serverListing:focus { - outline: none; - opacity: 1.0; -} - -.accountListing { - color: white; - border: 1px solid rgba(126, 126, 126, 0.57); - border-radius: 3px; - padding: 5px 45px; - width: 250px; - display: flex; - justify-content: flex-start; - align-items: center; - opacity: 0.6; - transition: 0.25s ease; - cursor: pointer; - position: relative; - background: rgba(0, 0, 0, 0.25); -} -.accountListing[selected] { - cursor: default; - opacity: 1.0; -} -.accountListing:hover, -.accountListing:focus { - outline: none; - opacity: 1.0; -} - -.accountListingName { - display: flex; - height: 100%; - width: 100%; - padding-left: 10px; -} - -/* Add spacing between server listings. */ -#serverSelectListScrollable > .serverListing:not(:first-child):not(:last-child), -#accountSelectListScrollable > .accountListing:not(:first-child):not(:last-child) { - margin: 5px 0px; -} -#serverSelectListScrollable > .serverListing:first-child, -#accountSelectListScrollable > .accountListing:first-child { - margin-bottom: 5px; -} -#serverSelectListScrollable > .serverListing:last-child, -#accountSelectListScrollable > .accountListing:last-child { - margin-top: 5px; -} - -/* Server listing image. */ -.serverListingImg { - margin: 0px 10px 0px 5px; - border: 1px solid #fff; - height: 50px; - width: 50px; -} - -/* Content container for the server listing's details. */ -.serverListingDetails { - display: flex; - flex-direction: column; - align-items: flex-start; - justify-content: space-between; - height: 50px; -} - -/* The name of the server listing. */ -.serverListingName { - font-size: 14px; - font-weight: bold; -} - -/* Description for the server listing. */ -.serverListingDescription { - font-size: 10px; - line-height: 10px; - font-weight: bold; -} - -/* Content container for the server listing's information. */ -.serverListingInfo { - width: 100%; - display: flex; - justify-content: flex-start; -} - -/* The minecraft version of the server listing. */ -.serverListingVersion { - font-size: 10px; - text-align: center; - display: flex; - justify-content: center; - align-items: center; - line-height: 12px; - height: 12px; - border-radius: 2px; - background: rgba(31, 140, 11, 0.8); - padding: 0px 2px; -} - -/* The revision version of the server's manifest. */ -.serverListingRevision { - color: #969696; - font-size: 10px; - line-height: 12px; - padding: 0px 5px; -} - -/* Star which indicates the default (main) server. */ -.serverListingStarWrapper { - display: flex; - align-items: center; - cursor: pointer; - height: 12px; - position: relative; -} -/* Tooltip which displays when hovering over the star. */ -.serverListingStarTooltip { - visibility: hidden; - opacity: 0; - width: 65px; - background-color: rgba(0, 0, 0, 0.40); - text-align: center; - border-radius: 4px; - position: absolute; - z-index: 1; - left: 130%; - font-size: 10px; - transition: visibility 0s linear 0.25s, opacity 0.25s ease; -} -.serverListingStarTooltip::after { - content: " "; - position: absolute; - top: 50%; - right: 100%; /* To the left of the tooltip */ - margin-top: -5px; - border-width: 5px; - border-style: solid; - border-color: transparent rgba(0, 0, 0, 0.40) transparent transparent; -} -.serverListingStarWrapper:hover .serverListingStarTooltip { - visibility: visible; - opacity: 1; - transition-delay:0s; -} - -/* Content container which contains the server select actions. */ -#serverSelectActions, -#accountSelectActions { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - margin-top: 25px; -} - -/* Server selection confirm button styles. */ -#serverSelectConfirm, -#accountSelectConfirm { - background: none; - border: 1px solid #ffffff; - color: white; - font-family: 'Avenir Medium'; - font-weight: bold; - border-radius: 2px; - padding: 0px 8.1px; - cursor: pointer; - transition: 0.25s ease; - min-height: 20.67px; -} -#serverSelectConfirm:hover, -#serverSelectConfirm:focus, -#accountSelectConfirm:hover, -#accountSelectConfirm:focus { - box-shadow: 0px 0px 10px 0px #fff; - outline: none; -} -#serverSelectConfirm:active, -#accountSelectConfirm:active { - border-color: rgba(255, 255, 255, 0.75); - color: rgba(255, 255, 255, 0.75); -} - -/* Server selection cancel button styles. */ -#serverSelectCancel, -#accountSelectCancel { - font-weight: bold; - font-size: 10px; - text-decoration: none; - padding-top: 2.5px; - color: rgba(202, 202, 202, 0.75); - transition: 0.25s ease; - background: none; - border: none; - outline: none; - cursor: pointer; -} -#serverSelectCancel:hover, -#serverSelectCancel:focus, -#accountSelectCancel:hover, -#accountSelectCancel:focus { - color: rgba(255, 255, 255, 0.75); -} -#serverSelectCancel:active, -#accountSelectCancel:active { - color: rgba(165, 165, 165, 0.75); -} - -/******************************************************************************* - * * - * Loading Element (app.ejs) * - * * - ******************************************************************************/ - -/* Loading container, placed above everything. */ -#loadingContainer { - position: absolute; - z-index: 400; - display: flex; - align-items: center; - justify-content: center; - width: 100%; - height: calc(100% - 22px); -} - -/* Loading content container. */ -#loadingContent { - position: relative; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; -} - -/* Spinner container. */ -#loadSpinnerContainer { - position: relative; - display: flex; - align-items: center; - justify-content: center; -} - -/* Stationary image for the spinner. */ -#loadCenterImage { - position: absolute; - width: 277px; - height: auto; -} - -/* Rotating image for the spinner. */ -#loadSpinnerImage { - width: 280px; - height: auto; - z-index: 400; -} - -/* Rotating animation for the spinner. */ -@keyframes rotating { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} - -/* Class which is applied when the spinner image is spinning. */ -.rotating { - animation: rotating 10s linear infinite; +/* Github Code Highlighting. */ +@import "../../../node_modules/github-syntax-dark/lib/github-dark.css"; + +/******************************************************************************* + * * + * Fonts * + * * + ******************************************************************************/ + +@font-face { + font-family: 'Avenir Book'; + src: url('../fonts/Avenir-Book.ttf'); +} + +@font-face { + font-family: 'Avenir Medium'; + src: url('../fonts/Avenir-Medium.ttf'); +} + +@font-face { + font-family: 'Ringbearer'; + src: url('../fonts/Ringbearer.ttf'); +} + +/******************************************************************************* + * * + * Element Styles * + * * + ******************************************************************************/ + +/* Reset body, html, and div presets. */ +body, html, div { + margin: 0px; + padding: 0px; +} + +/* Reset p presets. */ +p { + -webkit-margin-before: 0em; + -webkit-margin-after: 0em; +} + +/* Set default font and color. */ +body, button { + font-family: 'Avenir Book'; + color: white; +} + +/*body { + background: url('./../images/backgrounds/0.jpg') no-repeat center center fixed; + background-size: cover; +}*/ + +/******************************************************************************* + * * + * Frame Styles (frame.ejs) * + * * + ******************************************************************************/ + +/* Frame Bar */ +#frameBar { + position: relative; + z-index: 100; + display: flex; + flex-direction: column; + transition: background-color 1s ease; + /*background-color: rgba(0, 0, 0, 0.5);*/ + -webkit-user-select: none; +} + +/* Undraggable region on the top of the frame. */ +#frameResizableTop { + height: 2px; + width: 100%; + -webkit-app-region: no-drag; +} + +/* Flexbox to wrap the main frame content. */ +#frameMain { + display: flex; + height: 20px +} + +/* Undraggable region on the left and right of the frame. */ +.frameResizableVert { + width: 2px; + -webkit-app-region: no-drag; +} + +/* Main frame content for windows. */ +#frameContentWin { + display: flex; + justify-content: space-between; + width: 100%; + -webkit-app-region: drag; +} + +/* Main frame content for darwin. */ +#frameContentDarwin { + display: flex; + justify-content: flex-start; + align-items: center; + width: 100%; + -webkit-app-region: drag; +} + +/* Frame logo (windows only). */ +#frameTitleDock { + padding: 0px 10px; +} +#frameTitleText { + font-size: 14px; + font-family: 'Avenir Medium'; + letter-spacing: 0.5px; +} + +/* Windows frame button dock. */ +#frameButtonDockWin { + -webkit-app-region: no-drag !important; + position: relative; + top: -2px; + right: -2px; + height: 22px; +} +#frameButtonDockWin > .frameButton:not(:first-child) { + margin-left: -4px; +} + +/* Darwin frame button dock: NaN; */ +#frameButtonDockDarwin { + -webkit-app-region: no-drag !important; + position: relative; + top: -1px; + right: -1px; +} + +/* Windows Frame Button Styles. */ +.frameButton { + background: none; + border: none; + height: 22px; + width: 39px; + cursor: pointer; +} +.frameButton:hover, +.frameButton:focus { + background: rgba(189, 189, 189, 0.43); +} +.frameButton:active { + background: rgba(156, 156, 156, 0.43); +} +.frameButton:focus { + outline: 0px; +} + +/* Close button is red. */ +#frameButton_close:hover, +#frameButton_close:focus { + background: rgba(255, 53, 53, 0.61) !important; +} +#frameButton_close:active { + background: rgba(235, 0, 0, 0.61) !important; +} + +/* Darwin Frame Button Styles. */ +.frameButtonDarwin { + height: 12px; + width: 12px; + border-radius: 50%; + border: 0px; + margin-left: 5px; + -webkit-app-region: no-drag !important; + cursor: pointer; +} +.frameButtonDarwin:focus { + outline: 0px; +} + +#frameButtonDarwin_close { + background-color: #e74c32; +} +#frameButtonDarwin_close:hover, +#frameButtonDarwin_close:focus { + background-color: #FF9A8A; +} +#frameButtonDarwin_close:active { + background-color: #ff8d7b; +} + +#frameButtonDarwin_minimize { + background-color: #fed045; +} +#frameButtonDarwin_minimize:hover, +#frameButtonDarwin_minimize:focus { + background-color: #FFE9A9; +} +#frameButtonDarwin_minimize:active { + background-color: #ffde7b; +} + +#frameButtonDarwin_restoredown { + background-color: #96e734; +} +#frameButtonDarwin_restoredown:hover, +#frameButtonDarwin_restoredown:focus { + background-color: #D6FFA6; +} +#frameButtonDarwin_restoredown:active { + background-color: #bfff76; +} + +/******************************************************************************* + * * + * Welcome View (welcome.ejs) * + * * + ******************************************************************************/ + +#welcomeContainer { + position: relative; + display: flex; + justify-content: center; + align-items: center; + height: 100%; + width: 100%; + background: rgba(0, 0, 0, 0.50); +} + +#welcomeContent { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: 50%; + top: -10%; + position: relative; +} + +/* +.cloudDiv { + position: absolute; + height: 100%; + width: 100%; + display: flex; + flex-direction: column; +} + +.cloudTop { + height: 50%; + width: 100%; + background-image: url('../images/cloudTrans.png'); + animation: clouds1 80s linear infinite; + background-size: cover; +} + +.cloudBottom { + height: 50%; + width: 100%; + background-image: url('../images/cloudTrans2.png'); + animation: clouds2 70s linear infinite; + background-size: cover; +} + +@keyframes clouds1 { + to { + background-position: 200%; + } +} +@keyframes clouds2 { + to { + background-position: 230%; + } +} +*/ + +#welcomeImageSeal { + border-radius: 50%; + border: 2px solid #cad7e1; + background: rgba(1, 2, 1, 0.5); + height: 125px; + width: 125px; + box-shadow: 0px 0px 10px 0px rgb(0, 0, 0); + margin-bottom: 5%; + margin-top: 10%; +} + +#welcomeHeader { + font-family: 'Avenir Medium'; + text-align: center; + color: white; + margin-bottom: 25px; + letter-spacing: 1px; + font-size: 20px; + text-shadow: white 0px 0px 0px; +} + +#welcomeDescription { + text-align: justify; + font-size: 13px; + font-weight: 100; + text-shadow: rgba(255, 255, 255, 0.75) 0px 0px 20px +} + +#welcomeDescCTA { + text-align: center; + font-size: 14px; + font-weight: 100; + text-shadow: rgba(255, 255, 255, 0.75) 0px 0px 20px +} + +/* Login button styles. */ +#welcomeButton { + background: none; + font-weight: bold; + letter-spacing: 2px; + border: none; + padding: 15px 5px; + margin: 10px 0px; + cursor: pointer; + position: relative; + right: -20px; + transition: 0.5s ease; + margin-top: 5%; + margin-bottom: -5%; +} +#welcomeButton:disabled { + color: rgba(255, 255, 255, 0.75); + pointer-events: none; +} +#welcomeButton:hover, +#welcomeButton:focus { + text-shadow: 0px 0px 20px #fff; + outline: none; +} +#welcomeButton:active { + color: #c7c7c7; + text-shadow: 0px 0px 20px #c7c7c7; +} +#welcomeSVG { + -webkit-transform: translate3d(0, 0, 0); + overflow: visible; + transform: rotate(90deg); + margin-left: 20px; + transition: 0.25s ease; + width: 20px; + height: 20px; +} +#welcomeButton:hover #welcomeSVG, +#welcomeButton:focus #welcomeSVG { + -webkit-filter: drop-shadow(0px 0px 2px #fff); +} +#welcomeButton:active #welcomeSVG .arrowLine { + stroke: #c7c7c7; +} +#welcomeButton:active #welcomeSVG { + -webkit-filter: drop-shadow(0px 0px 2px #c7c7c7); +} +#welcomeButton:disabled #welcomeSVG .arrowLine { + stroke: rgba(255, 255, 255, 0.75); +} + +#welcomeButtonContent { + display: flex; + align-items: center; +} + +/******************************************************************************* + * * + * Login View (login.ejs) * + * * + ******************************************************************************/ + +/* Styles for dimmer login span. */ +.loginSpanDim { + font-size: 12px; + color: #848484; + font-weight: bold; +} + +/* Main login container. */ +#loginContainer { + position: relative; + display: flex; + justify-content: center; + align-items: center; + height: 100%; + width: 100%; + transition: filter 0.25s ease; + background: rgba(0, 0, 0, 0.50); +} + +/* Login cancel button styles. */ +#loginCancelContainer { + position: absolute; + top: 5%; + right: 5%; +} + +/* Login cancel button styles. */ +#loginCancelButton { + background: none; + border: none; + outline: none; + cursor: pointer; + transition: 0.25s ease; +} +#loginCancelButton:hover #loginCancelIcon, +#loginCancelButton:hover #loginCancelText, +#loginCancelButton:focus #loginCancelIcon, +#loginCancelButton:focus #loginCancelText { + text-shadow: 0px 0px 20px white; +} +#loginCancelButton:hover #loginCancelIcon, +#loginCancelButton:focus #loginCancelIcon { + box-shadow: 0px 0px 20px white; +} +#loginCancelButton:active #loginCancelIcon, +#loginCancelButton:active #loginCancelText { + text-shadow: 0px 0px 20px rgba(255, 255, 255, 0.75); + color: rgba(255, 255, 255, 0.75); + border-color: rgba(255, 255, 255, 0.75); +} +#loginCancelButton:active #loginCancelIcon { + box-shadow: 0px 0px 20px rgba(255, 255, 255, 0.75); +} +#loginCancelButton:disabled { + pointer-events: none; +} +#loginCancelButton:disabled #loginCancelIcon, +#loginCancelButton:disabled #loginCancelText { + color: rgba(255, 255, 255, 0.75); + border-color: rgba(255, 255, 255, 0.75); +} + +/* The X in a circle icon for the cancel button. */ +#loginCancelIcon { + border-radius: 50%; + border: 1px solid white; + box-sizing: border-box; + height: 30px; + width: 30px; + font-size: 19px; + line-height: 30px; + margin: 0 auto; + margin-bottom: 5px; + transition: 0.25s ease; +} +/* Text for the login cancel button. */ +#loginCancelText { + font-size: 15px; + transition: 0.25s ease; +} + +/* Login content wrapper. */ +#loginContent { + display: flex; + justify-content: center; + align-items: center; + height: 100%; + padding: 0px 25px; +} + +/* Login form. */ +#loginForm { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +/* Login form anchor styles. */ +#loginForm a { + font-size: 12px; + color: #848484; + font-weight: bold; + text-decoration: none; + transition: 0.25s ease; +} +#loginForm a:hover, +#loginForm a:focus { + color: #a2a2a2; + outline: none; +} +#loginForm a:active { + color: #8b8b8b; +} + +/* Login Offline form. */ +#loginOfflineForm { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +/* Login form anchor styles. */ +#loginOfflineForm a { + font-size: 12px; + color: #848484; + font-weight: bold; + text-decoration: none; + transition: 0.25s ease; +} +#loginOfflineForm a:hover, +#loginOfflineForm a:focus { + color: #a2a2a2; + outline: none; +} +#loginOfflineForm a:active { + color: #8b8b8b; +} + +/* Logo on login form. */ +#loginImageSeal { + border-radius: 50%; + border: 2px solid #cad7e1; + background: rgba(1, 2, 1, 0.5); + height: 125px; + width: 125px; + box-shadow: 0px 0px 10px 0px rgb(0, 0, 0); + margin-bottom: 20px; +} + +/* Header on login view. */ +#loginSubheader { + font-family: 'Avenir Medium'; + margin-bottom: 25px; + font-size: 12px; + letter-spacing: 1px; + font-weight: bold; +} + +/* Container to organize login field elements. */ +.loginFieldContainer { + position: relative; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +/* SVG icons on the login view. */ +.loginSVG { + fill: #fff; + height: 20px; + width: 20px; +} + +/* Span which displays errors related to login field content. */ +.loginErrorSpan { + font-family: 'Avenir Medium'; + font-weight: bold; + font-size: 8px; + color: #ff1b0c; + width: 100%; + text-align: right; + position: absolute; + top: 7px; + opacity: 0; + transition: 0.25s ease; +} + +.shake { + animation: shake 0.82s cubic-bezier(.36,.07,.19,.97) both; +} + +@keyframes shake { + 10%, 90% { + transform: translate3d(-1px, 0, 0); + } + + 20%, 80% { + transform: translate3d(2px, 0, 0); + } + + 30%, 50%, 70% { + transform: translate3d(-4px, 0, 0); + } + + 40%, 60% { + transform: translate3d(4px, 0, 0); + } +} + +/* Login text input styles. */ +.loginField { + font-family: 'Avenir Book'; + background: none; + border-width: 1.5px 0px 0px 0px; + border-style: solid; + width: 250px; + margin-bottom: 20px; + border-color: #fff; + color: rgba(255, 255, 255, 0.75); + font-weight: bold; + text-align: center; + box-sizing: border-box; + padding: 7.5px; + font-size: 10px; + letter-spacing: 1px; +} +.loginField:focus { + outline: none; +} +.loginField:disabled { + color: rgba(255, 255, 255, 0.50); +} +.loginField::-webkit-input-placeholder { + color: rgba(255, 255, 255, 0.75); + font-size: 10px; + letter-spacing: 1px; + text-align: center; + font-weight: bold; +} +.loginField:focus::-webkit-input-placeholder { + color: transparent; +} + +/* Add spacing between password field and options bar. */ +#labelPassword { + margin-bottom: 13px; +} + +/* Container which contains the forgot and remember options. */ +#loginOptions { + display: flex; + justify-content: space-between; + width: 100%; +} + +/* Remember option text. */ +#loginRememberText { + padding-right: 10px; + transition: 0.25s ease; +} + +/* Login button styles. */ +#loginButton { + background: none; + font-weight: bold; + letter-spacing: 2px; + border: none; + padding: 15px 5px; + margin: 10px 0px; + cursor: pointer; + position: relative; + right: -20px; + transition: 0.5s ease; +} +#loginButton:disabled { + color: rgba(255, 255, 255, 0.75); + pointer-events: none; +} +#loginButton[loading] { + color: #fff; +} +#loginButton:hover, +#loginButton:focus { + text-shadow: 0px 0px 20px #fff; + outline: none; +} +#loginButton:active { + color: #c7c7c7; + text-shadow: 0px 0px 20px #c7c7c7; +} +#loginSVG { + -webkit-transform: translate3d(0, 0, 0); + overflow: visible; + transform: rotate(90deg); + margin-left: 20px; + transition: 0.25s ease; + width: 20px; + height: 20px; +} +#loginButton:hover #loginSVG, +#loginButton:focus #loginSVG { + -webkit-filter: drop-shadow(0px 0px 2px #fff); +} +#loginButton:active #loginSVG .arrowLine { + stroke: #c7c7c7; +} +#loginButton:active #loginSVG { + -webkit-filter: drop-shadow(0px 0px 2px #c7c7c7); +} +#loginButton:disabled #loginSVG .arrowLine { + stroke: rgba(255, 255, 255, 0.75); +} + +#loginButtonContent { + display: flex; + align-items: center; +} + +#loginButton .circle-loader, +#loginButton[loading] #loginSVG { + display: none; +} +#loginButton[loading] .circle-loader, +#loginButton #loginSVG { + display: initial; +} + +/* Login Offline button styles. */ +#loginOfflineButton { + background: none; + font-weight: bold; + letter-spacing: 2px; + border: none; + padding: 15px 5px; + margin: 10px 0px; + cursor: pointer; + position: relative; + right: -20px; + transition: 0.5s ease; +} +#loginOfflineButton:disabled { + color: rgba(255, 255, 255, 0.75); + pointer-events: none; +} +#loginOfflineButton[loading] { + color: #fff; +} +#loginOfflineButton:hover, +#loginOfflineButton:focus { + text-shadow: 0px 0px 20px #fff; + outline: none; +} +#loginOfflineButton:active { + color: #c7c7c7; + text-shadow: 0px 0px 20px #c7c7c7; +} +#loginOfflineSVG { + -webkit-transform: translate3d(0, 0, 0); + overflow: visible; + transform: rotate(90deg); + margin-left: 20px; + transition: 0.25s ease; + width: 20px; + height: 20px; +} +#loginOfflineButton:hover #loginOfflineSVG, +#loginOfflineButton:focus #loginOfflineSVG { + -webkit-filter: drop-shadow(0px 0px 2px #fff); +} +#loginOfflineButton:active #loginOfflineSVG .arrowLine { + stroke: #c7c7c7; +} +#loginOfflineButton:active #loginOfflineSVG { + -webkit-filter: drop-shadow(0px 0px 2px #c7c7c7); +} +#loginOfflineButton:disabled #loginOfflineSVG .arrowLine { + stroke: rgba(255, 255, 255, 0.75); +} + +#loginOfflineButtonContent { + display: flex; + align-items: center; +} + +#loginOfflineButton .circle-loader, +#loginOfflineButton[loading] #loginOfflineSVG { + display: none; +} +#loginOfflineButton[loading] .circle-loader, +#loginOfflineButton #loginOfflineSVG { + display: initial; +} + + +.circle-loader { + margin-left: 20px; + border: 2px solid rgba(255, 255, 255, 0.5); + border-left-color: #ffffff; + animation-name: loader-spin; + animation-duration: 1s; + animation-iteration-count: infinite; + animation-timing-function: linear; + position: relative; + display: inline-block; + vertical-align: top; + border-radius: 50%; + width: 16px; + height: 16px; +} +.load-complete { + animation: none; + border-color: #ffffff; + transition: border 500ms ease-out; +} +.checkmark { + display: none; +} +.checkmark.draw:after { + animation-duration: 800ms; + animation-timing-function: ease; + animation-name: checkmark; + transform: scaleX(-1) rotate(135deg); +} +.checkmark:after { + opacity: 1; + height: 8px; + width: 4px; + transform-origin: left top; + border-right: 2px solid #ffffff; + border-top: 2px solid #ffffff; + content: ''; + left: 2px; + top: 8px; + position: absolute; +} +@keyframes loader-spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} +@keyframes checkmark { + 0% { + height: 0; + width: 0; + opacity: 1; + } + 20% { + height: 0; + width: 4px; + opacity: 1; + } + 40% { + height: 8px; + width: 4px; + opacity: 1; + } + 100% { + height: 8px; + width: 4px; + opacity: 1; + } +} + + + +/*.spinningCircle { + margin-left: 20px; + height: 16px; + width: 16px; + border-radius: 50%; + border: 2px solid rgba(255,255,255,0); + border-top-color: #ffffff; + border-right-color: #ffffff; + border-left-color: rgba(255, 255, 255, 0.50); + border-bottom-color: rgba(255, 255, 255, 0.50); + animation: single2 4s infinite linear; +} + +@keyframes single2 { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(720deg); + } +}*/ + +/* Disclaimer container. */ +#loginDisclaimer { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; +} + +/* Add spacing between register anchor and disclaimer. */ +#loginRegisterSpan { + margin-bottom: 5px; +} + +/* Disclaimer text styles. */ +.loginDisclaimerText { + font-size: 7px; + color: #848484; + font-weight: bold; + text-align: center; +} + +/* * * +* Login View | Custom Checkbox +* * */ + +/* Checkbox container. */ +#checkmarkContainer { + display: flex; + justify-content: flex-end; + align-items: center; + position: relative; + cursor: pointer; + font-size: 22px; + -webkit-user-select: none; +} + +/* Hide the default checkbox. */ +#checkmarkContainer input { + opacity: 0; + cursor: pointer; + position: absolute; +} + +/* Create a custom checkbox. */ +.loginCheckmark { + position: relative; + height: 10px; + width: 10px; + border: 1px solid #848484; + border-radius: 1px; + background: none; + transition: 0.25s ease; +} +/* On hover and focus, add a grey border color. */ +#checkmarkContainer:hover input ~ *, +#checkmarkContainer input:focus ~ * { + color: #a2a2a2; + border-color: #a2a2a2; +} +/* On keydown, darken the checkbox a bit. */ +#checkmarkContainer input:active ~ *:not(#loginRememberText) { + color: #8d8d8d; + border-color: #8d8d8d; +} +#checkmarkContainer[disabled] { + pointer-events: none; +} +/* For checked -> #checkmarkContainer input:checked ~ * */ +/* Create the checkmark/indicator (hidden when not checked). */ +.loginCheckmark:after { + content: ""; + display: none; +} +/* Show the checkmark when checked. */ +#checkmarkContainer input:checked ~ .loginCheckmark:after { + display: block; +} +/* Style the checkmark/indicator. */ +#checkmarkContainer .loginCheckmark:after { + position: absolute; + left: 3.5px; + top: 0.5px; + width: 2px; + height: 6px; + border: solid #a2a2a2; + border-width: 0 2px 2px 0; + transform: rotate(45deg); +} + +/* +#login_filter { + height: calc(100% - 22px); + width: 100%; + z-index: 9000; + position: absolute; + filter: blur(8px) contrast(0.9) brightness(1.0); + background: url('./../images/backgrounds/0.jpg') no-repeat center center fixed; + transform: scale(1.2); + background-size: cover; +} +*/ + +/******************************************************************************* + * * + * Waiting View (waiting.ejs) * + * * + ******************************************************************************/ + +#waitingContainer { + position: relative; + display: flex; + justify-content: center; + align-items: center; + height: 100%; + width: 100%; + transition: filter 0.25s ease; + background: rgba(0, 0, 0, 0.50); +} + +#waitingContent { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: 50%; + top: -10%; + position: relative; +} + +.waitingSpinner:before { + transform: rotateX(60deg) rotateY(45deg) rotateZ(45deg); + animation: 750ms rotateBefore infinite linear reverse; +} +.waitingSpinner:after { + transform: rotateX(240deg) rotateY(45deg) rotateZ(45deg); + animation: 750ms rotateAfter infinite linear; +} +.waitingSpinner:before, +.waitingSpinner:after { + box-sizing: border-box; + content: ''; + display: block; + position: fixed; + top: calc(50% - 5em); + /* left: 50%; */ + margin-top: -5em; + margin-left: -5em; + width: 10em; + height: 10em; + transform-style: preserve-3d; + transform-origin: 50%; + transform: rotateY(50%); + perspective-origin: 50% 50%; + perspective: 340px; + background-size: 10em 10em; + background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+Cjxzdmcgd2lkdGg9IjI2NnB4IiBoZWlnaHQ9IjI5N3B4IiB2aWV3Qm94PSIwIDAgMjY2IDI5NyIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWxuczpza2V0Y2g9Imh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaC9ucyI+CiAgICA8dGl0bGU+c3Bpbm5lcjwvdGl0bGU+CiAgICA8ZGVzY3JpcHRpb24+Q3JlYXRlZCB3aXRoIFNrZXRjaCAoaHR0cDovL3d3dy5ib2hlbWlhbmNvZGluZy5jb20vc2tldGNoKTwvZGVzY3JpcHRpb24+CiAgICA8ZGVmcz48L2RlZnM+CiAgICA8ZyBpZD0iUGFnZS0xIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiBza2V0Y2g6dHlwZT0iTVNQYWdlIj4KICAgICAgICA8cGF0aCBkPSJNMTcxLjUwNzgxMywzLjI1MDAwMDM4IEMyMjYuMjA4MTgzLDEyLjg1NzcxMTEgMjk3LjExMjcyMiw3MS40OTEyODIzIDI1MC44OTU1OTksMTA4LjQxMDE1NSBDMjE2LjU4MjAyNCwxMzUuODIwMzEgMTg2LjUyODQwNSw5Ny4wNjI0OTY0IDE1Ni44MDA3NzQsODUuNzczNDM0NiBDMTI3LjA3MzE0Myw3NC40ODQzNzIxIDc2Ljg4ODQ2MzIsODQuMjE2MTQ2MiA2MC4xMjg5MDY1LDEwOC40MTAxNTMgQy0xNS45ODA0Njg1LDIxOC4yODEyNDcgMTQ1LjI3NzM0NCwyOTYuNjY3OTY4IDE0NS4yNzczNDQsMjk2LjY2Nzk2OCBDMTQ1LjI3NzM0NCwyOTYuNjY3OTY4IC0yNS40NDkyMTg3LDI1Ny4yNDIxOTggMy4zOTg0Mzc1LDEwOC40MTAxNTUgQzE2LjMwNzA2NjEsNDEuODExNDE3NCA4NC43Mjc1ODI5LC0xMS45OTIyOTg1IDE3MS41MDc4MTMsMy4yNTAwMDAzOCBaIiBpZD0iUGF0aC0xIiBmaWxsPSIjZmZmZmZmIiBza2V0Y2g6dHlwZT0iTVNTaGFwZUdyb3VwIj48L3BhdGg+CiAgICA8L2c+Cjwvc3ZnPg==); +} + +#waitingTextContainer { + position: fixed; + top: 50%; +} + +@keyframes rotateBefore { + from { + transform: rotateX(60deg) rotateY(45deg) rotateZ(0deg); + } + to { + transform: rotateX(60deg) rotateY(45deg) rotateZ(-360deg); + } +} + +@keyframes rotateAfter { + from { + transform: rotateX(240deg) rotateY(45deg) rotateZ(0deg); + } + to { + transform: rotateX(240deg) rotateY(45deg) rotateZ(360deg); + } +} + +/******************************************************************************* + * * + * Login Options View (loginOptions.ejs) * + * * + ******************************************************************************/ + +#loginOptionsContainer { + position: relative; + display: flex; + justify-content: center; + align-items: center; + height: 100%; + width: 100%; + transition: filter 0.25s ease; + background: rgba(0, 0, 0, 0.50); +} + +#loginOptionsContent { + border-radius: 3px; + position: relative; + top: -5%; +} + +.loginOptionsMainContent { + display: flex; + flex-direction: column; + align-items: center; +} + +.loginOptionActions { + display: flex; + flex-direction: column; + row-gap: 10px; +} + +.loginOptionButtonContainer { + width: 16em; +} + +.loginOptionButton { + background: rgba(0, 0, 0, 0.25); + border: 1px solid rgba(126, 126, 126, 0.57); + border-radius: 3px; + height: 50px; + width: 100%; + text-align: left; + padding: 0px 25px; + cursor: pointer; + outline: none; + transition: 0.25s ease; + display: flex; + align-items: center; + column-gap: 5px; +} +.loginOptionButton:hover, +.loginOptionButton:focus { + background: rgba(54, 54, 54, 0.25); + text-shadow: 0px 0px 20px white; +} + +#loginOptionCancelContainer { + position: absolute; + bottom: -100px; +} + +#loginOptionCancelButton { + background: none; + border: none; + padding: 2px 0px; + font-size: 16px; + font-weight: bold; + color: lightgrey; + cursor: pointer; + outline: none; + transition: 0.25s ease; +} +#loginOptionCancelButton:hover, +#loginOptionCancelButton:focus { + text-shadow: 0px 0px 20px lightgrey; +} +#loginOptionCancelButton:active { + text-shadow: 0px 0px 20px rgba(211, 211, 211, 0.75); + color: rgba(211, 211, 211, 0.75); +} +#loginOptionCancelButton:disabled { + color: rgba(211, 211, 211, 0.75); + pointer-events: none; +} + + +/******************************************************************************* + * * + * Settings View (sttings.ejs) * + * * + ******************************************************************************/ + +/* Main settings container. */ +#settingsContainer { + position: relative; + height: 100%; + display: flex; + background-color: rgba(0, 0, 0, 0.50); + transition: background-color 0.25s cubic-bezier(.02, .01, .47, 1); +} + +/* Drop shadow displayed when content is scrolled out of view. */ +#settingsContainer:before { + content: ''; + background: linear-gradient(rgba(0, 0, 0, 0.25), transparent); + width: 100%; + height: 5px; + position: absolute; + opacity: 0; + transition: opacity 0.25s ease; +} +#settingsContainer[scrolled]:before { + opacity: 1; +} + +/* Left hand side of the settings UI, for navigation. */ +#settingsContainerLeft { + padding-top: 4%; + height: 100%; + width: 25%; + box-sizing: border-box; +} + +/* Settings navigation container. */ +#settingsNavContainer { + height: 100%; + display: flex; + flex-direction: column; +} + +/* Navigation header styles. */ +#settingsNavHeader { + height: 15%; + display: flex; + justify-content: center; +} +#settingsNavHeaderText { + font-size: 20px; +} + +/* Navigation items outer container. */ +#settingsNavItemsContainer { + height: 85%; + display: flex; + justify-content: center; + box-sizing: border-box; +} + +/* Navigation items content container. */ +#settingsNavItemsContent { + height: 100%; + display: flex; + flex-direction: column; + position: relative; +} + +/* Navigation item shared styles. */ +.settingsNavItem { + background: none; + border: none; + text-align: left; + margin: 5px 0px; + padding: 0px 20px; + color: grey; + cursor: pointer; + outline: none; + transition: 0.25s ease; +} +.settingsNavItem:hover, +.settingsNavItem:focus { + color: #c1c1c1; + text-shadow: 0px 0px 20px #c1c1c1; +} +.settingsNavItem[selected] { + cursor: default; + color: white; + text-shadow: none; +} + +/* Div to add some space between nav items. */ +.settingsNavSpacer { + height: 25px; +} + +/* Content container for the done button. */ +#settingsNavContentBottom { + position: absolute; + top: 65%; +} + +/* Settings navigational divider. */ +.settingsNavDivider { + width: 75%; + height: 1px; + background: rgba(126, 126, 126, 0.57); + margin-left: auto; + margin-bottom: 25px; +} + +/* Settings done button styles. */ +#settingsNavDone { + background: none; + border: none; + text-align: left; + margin: 5px 0px; + padding: 0px 20px; + color: white; + cursor: pointer; + outline: none; + transition: 0.25s ease; +} +#settingsNavDone:hover, +#settingsNavDone:focus { + text-shadow: 0px 0px 20px white, 0px 0px 20px white, 0px 0px 20px white; +} +#settingsNavDone:active { + text-shadow: 0px 0px 20px rgba(255, 255, 255, 0.75), 0px 0px 20px rgba(255, 255, 255, 0.75), 0px 0px 20px rgba(255, 255, 255, 0.75); + color: rgba(255, 255, 255, 0.75); +} +#settingsNavDone:disabled { + color: rgba(255, 255, 255, 0.75); + pointer-events: none; +} + +/* Right hand side of the settings container, for tabs. */ +#settingsContainerRight { + height: 100%; + width: 75%; + box-sizing: border-box; +} + +/* Settings tab shared styles. */ +.settingsTab { + width: 100%; + height: 100%; + overflow-y: auto; +} +.settingsTab::-webkit-scrollbar { + width: 2px; +} +.settingsTab::-webkit-scrollbar-track { + display: none; +} +.settingsTab::-webkit-scrollbar-thumb { + border-radius: 10px; + box-shadow: inset 0 0 10px rgba(255, 255, 255, 0.50); +} + +/* Add spacing to the top of each settings tab. */ +.settingsTab > *:first-child { + margin-top: 5%; +} + +/* Add spacing to the bottom of each settings tab. */ +.settingsTab > *:last-child { + margin-bottom: 20%; +} + +/* Tab header shared styles. */ +.settingsTabHeader { + display: flex; + flex-direction: column; + margin-bottom: 20px; +} +.settingsTabHeaderText { + font-size: 20px; + font-family: 'Avenir Medium'; +} +.settingsTabHeaderDesc { + font-size: 12px; +} + +/* Remove spin button from number inputs. */ +#settingsContainer input[type=number]::-webkit-inner-spin-button { + -webkit-appearance: none; +} + +/* Default styles for text/number inputs. */ +#settingsContainer input[type=number], +#settingsContainer input[type=text] { + color: white; + background: rgba(0, 0, 0, 0.25); + border-radius: 3px; + border: 1px solid rgba(126, 126, 126, 0.57); + font-family: 'Avenir Book'; + transition: 0.25s ease; +} +#settingsContainer input[type=number]:focus, +#settingsContainer input[type=text]:focus { + outline: none; + border-color: rgba(126, 126, 126, 0.87); +} +#settingsContainer input[type=number][error] { + border-color: rgb(255, 27, 12); + background: rgba(236, 0, 0, 0.25); + color: rgb(255, 27, 12); +} + +/* Styles for a generic settings entry. */ +.settingsFieldContainer { + display: flex; + align-items: center; + justify-content: space-between; + padding: 20px 0px; + width: 75%; + border-bottom: 1px solid rgba(255, 255, 255, 0.50); +} +.settingsFieldLeft { + display: flex; + flex-direction: column; +} +.settingsFieldTitle { + font-size: 14px; + font-family: 'Avenir Medium'; + color: rgba(255, 255, 255, 0.95); +} +.settingsFieldDesc { + font-size: 12px; + color: rgba(255, 255, 255, .95); + margin-top: 5px; +} +.settingsDivider { + height: 1px; + width: 75%; + background: rgba(255, 255, 255, 0.25); +} + +/* Toggle Switch */ +.toggleSwitch { + position: relative; + display: inline-block; + width: 40px; + height: 20px; + border-radius: 50px; + box-sizing: border-box; +} +.toggleSwitch input { + display:none; +} +.toggleSwitchSlider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(255, 255, 255, 0.35); + transition: .4s; + border-radius: 50px; + border: 1px solid rgba(126, 126, 126, 0.57); +} +.toggleSwitchSlider:before { + position: absolute; + content: ""; + height: 13px; + width: 16px; + left: 3px; + bottom: 3px; + background-color: white; + box-shadow: 0px 1px 2px 0px rgba(0, 0, 0, 0.75); + border-radius: 50px; + transition: .4s; +} +input:checked + .toggleSwitchSlider { + background-color: rgb(31, 140, 11); + /* box-shadow: inset 2px 1px 20px black; */ + border: 1px solid rgb(31, 140, 11); +} +input:checked + .toggleSwitchSlider:before { + transform: translateX(15px); +} + +/* Range Slider styles. */ +.rangeSlider { + width: 35%; + height: 5px; + margin: 15px 0px; + background: grey; + border-radius: 3px; + position: relative; +} +.rangeSliderBar { + position: absolute; + background: #8be88b; + width: 50%; + height: 5px; + border-radius: 3px 0px 0px 3px; + transition: background 0.25s ease; +} +.rangeSliderTrack { + position: absolute; + top: -7.5px; + width: 7px; + height: 20px; + background: white; + border-radius: 3px; + left: 50%; + cursor: ew-resize; +} + +/* File selectors */ + +/* Main container for File selectors. */ +.settingsFileSelContainer { + display: flex; + flex-direction: column; + border-bottom: 1px solid rgba(255, 255, 255, 0.50); + margin-bottom: 20px; + margin-top: 20px; + width: 75%; +} + +/* File selector title. */ +.settingsFileSelTitle { + margin-bottom: 10px; +} + +/* Wrapper container for the actionable elements. */ +.settingsFileSelActions { + display: flex; + width: 90%; +} + +/* File selector icon settings. */ +.settingsFileSelIcon { + display: flex; + align-items: center; + background: rgba(126, 126, 126, 0.57); + border-radius: 3px 0px 0px 3px; + padding: 5px; + transition: 0.25s ease; +} +.settingsFileSelSVG { + width: 20px; + height: 20px; + fill: white; +} + +/* Disabled text field which stores the selected file path. */ +.settingsFileSelVal { + border-radius: 0px !important; + width: 100%; + padding: 5px 10px; + font-size: 12px; + height: 30px; +} + +/* File selection button. */ +.settingsFileSelButton { + border: 0px; + border-radius: 0px 3px 3px 0px; + font-size: 12px; + padding: 0px 5px; + cursor: pointer; + background: rgba(126, 126, 126, 0.57); + transition: 0.25s ease; + white-space: nowrap; + outline: none; +} +.settingsFileSelButton:hover, +.settingsFileSelButton:focus { + text-shadow: 0px 0px 20px white; +} +.settingsFileSelButton:active { + text-shadow: 0px 0px 20px rgba(255, 255, 255, 0.75); + color: rgba(255, 255, 255, 0.75); +} + +/* Description for the file selector. */ +.settingsFileSelDesc { + font-size: 10px; + margin: 20px 0px; + color: lightgrey; + width: 89%; +} +.settingsFileSelDesc strong { + font-family: 'Avenir Medium'; +} + +/* * * +* Settings View (Account Tab) +* * */ + +.settingsAuthAccountTypeContainer { + display: flex; + width: 75%; + flex-direction: column; +} + +.settingsAuthAccountTypeHeader { + display: flex; + align-items: center; + width: 100%; + justify-content: space-between; + padding: 10px 0px; + border-bottom: 1px solid #ffffff85; + margin-bottom: 30px; +} + +.settingsAuthAccountTypeHeaderLeft { + display: flex; + column-gap: 5px; +} + +/* Settings add account button styles. */ +.settingsAddAuthAccount { + background: none; + border: none; + text-align: left; + padding: 2px 0px; + color: white; + cursor: pointer; + outline: none; + transition: 0.25s ease; +} +.settingsAddAuthAccount:hover, +.settingsAddAuthAccount:focus { + text-shadow: 0px 0px 20px white, 0px 0px 20px white, 0px 0px 20px white; +} +.settingsAddAuthAccount:active { + text-shadow: 0px 0px 20px rgba(255, 255, 255, 0.75), 0px 0px 20px rgba(255, 255, 255, 0.75), 0px 0px 20px rgba(255, 255, 255, 0.75); + color: rgba(255, 255, 255, 0.75); +} +.settingsAddAuthAccount:disabled { + color: rgba(255, 255, 255, 0.75); + pointer-events: none; +} + +/* Auth account list container styles. */ +.settingsCurrentAccounts { + margin-bottom: 5%; +} +.settingsCurrentAccounts > .settingsAuthAccount:not(:last-child) { + margin-bottom: 10px; +} +.settingsCurrentAccounts > .settingsAuthAccount:not(:first-child) { + margin-top: 10px; +} + +/* Auth account shared styles. */ +.settingsAuthAccount { + display: flex; + background: rgba(0, 0, 0, 0.25); + border-radius: 3px; + border: 1px solid rgba(126, 126, 126, 0.57); +} + +/* Left hand side of an auth account element, for the skin image. */ +.settingsAuthAccountLeft { + padding: 5px 5px 5px 20px; +} + +/* Image of the auth account's skin. */ +.settingsAuthAccountImage { + height: 115px; +} + +/* Right hand side of the auth account, for info + actions. */ +.settingsAuthAccountRight { + display: flex; + width: 100%; +} + +/* Account details container. */ +.settingsAuthAccountDetails { + display: flex; + flex-direction: column; + justify-content: center; + margin-left: 20px; + width: 100%; +} +.settingsAuthAccountDetails > *:not(:last-child) { + margin-bottom: 20px; +} + +/* Account detail element styles. */ +.settingsAuthAccountDetailPane { + display: flex; + flex-direction: column; +} +.settingsAuthAccountDetailTitle { + font-size: 12px; + color: grey; + font-weight: bold; + font-family: 'Avenir Medium'; +} +.settingsAuthAccountDetailValue { + font-size: 14px; + -webkit-user-select: initial; +} + +/* Account actions container. */ +.settingsAuthAccountActions { + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: flex-end; + padding: 10px; +} + +/* Account select button shared styles. */ +.settingsAuthAccountSelect { + opacity: 0; + border: none; + white-space: nowrap; + background: none; + font-family: 'Avenir Medium'; + outline: none; + transition: 0.25s ease; +} +.settingsAuthAccountSelect:hover:not([selected]), +.settingsAuthAccountSelect:focus:not([selected]) { + text-shadow: 0px 0px 20px white, 0px 0px 20px white; + cursor: pointer; +} +.settingsAuthAccount:hover .settingsAuthAccountSelect:not([selected]), +.settingsAuthAccountSelect[selected] { + opacity: 1; +} +.settingsAuthAccountSelect[selected] { + pointer-events: none; +} + +/* Account logout button shared styles. */ +.settingsAuthAccountLogOut { + opacity: 0; + border: 1px solid rgb(241, 55, 55); + color: rgb(241, 55, 55); + background: none; + font-size: 12px; + border-radius: 3px; + font-family: 'Avenir Medium'; + transition: 0.25s ease; + cursor: pointer; + outline: none; +} +.settingsAuthAccountLogOut:hover, +.settingsAuthAccountLogOut:focus { + box-shadow: 0px 0px 20px rgb(241, 55, 55); + background: rgba(241, 55, 55, 0.25); +} +.settingsAuthAccountLogOut:active { + box-shadow: 0px 0px 20px rgb(185, 47, 47); + background: rgba(185, 47, 47, 0.25); + border: 1px solid rgb(185, 47, 47); + color: rgb(185, 47, 47); +} +.settingsAuthAccount:hover .settingsAuthAccountLogOut { + opacity: 1; +} + +/* * * +* Settings View (Minecraft Tab) +* * */ + +/* Game resolution UI elements. */ +#settingsGameResolutionContainer { + display: flex; + flex-direction: column; + padding-bottom: 20px; + border-bottom: 1px solid rgba(255, 255, 255, 0.50); + width: 75%; +} +#settingsGameResolutionContent { + display: flex; + align-items: center; + padding-top: 10px; +} +#settingsGameResolutionCross { + color: grey; + padding: 0px 15px; +} +#settingsGameWidth, +#settingsGameHeight { + padding: 7.5px 5px; + width: 75px; +} + +/* * * +* Settings View (Mods Tab) +* * */ + +/* Selected server content container */ +#settingsSelServContainer { + background: rgba(0, 0, 0, 0.25); + width: 75%; + border-radius: 3px; + display: flex; + justify-content: space-between; + margin: 15px 0px; +} + +/* Div which will be populated with the selected server's information. */ +#settingsSelServContent { + display: flex; + align-items: center; + justify-content: flex-start; + padding: 5px 0px; +} + +/* Wrapper container for the switch server button. */ +#settingsSwitchServerContainer { + display: flex; + align-items: center; + padding: 15px; +} + +/* Button to switch server configurations on the mods tab. */ +#settingsSwitchServerButton { + opacity: 0; + border: 1px solid rgb(255, 255, 255); + color: rgb(255, 255, 255); + background: none; + font-size: 12px; + border-radius: 3px; + font-family: 'Avenir Medium'; + transition: 0.25s ease; + cursor: pointer; + outline: none; +} +#settingsSwitchServerButton:hover, +#settingsSwitchServerButton:focus { + box-shadow: 0px 0px 20px rgb(255, 255, 255); + background: rgba(255, 255, 255, 0.25); +} +#settingsSwitchServerButton:active { + box-shadow: 0px 0px 20px rgb(187, 187, 187); + background: rgba(187, 187, 187, 0.25); + border: 1px solid rgb(187, 187, 187); + color: rgb(187, 187, 187); +} +#settingsSelServContainer:hover #settingsSwitchServerButton { + opacity: 1; +} + +/* Main content container for the mod elements. */ +#settingsModsContainer { + width: 75%; +} + +/* Mod sub-container header text. */ +.settingsModsHeader { + padding-bottom: 10px; + border-bottom: 1px solid rgba(255, 255, 255, 0.5); + margin-bottom: 10px; +} + +/* Mod elements sub-containers. */ +#settingsReqModsContainer, +#settingsOptModsContainer, +#settingsDropinModsContainer { + padding-bottom: 25px; +} + +/* Main content containers for mod elements. */ +#settingsReqModsContent, +#settingsOptModsContent, +#settingsDropinModsContent { + font-size: 12px; + background: rgba(0, 0, 0, 0.25); + border-radius: 3px; + color: white; +} + +/* Mod elements. */ +.settingsMod, +.settingsDropinMod { + padding: 10px; +} +.settingsSubMod { + padding: 10px 0px 10px 15px; + margin-left: 20px; + border-left: 1px solid rgba(255, 255, 255, 0.5); +} + +/* Main content container for mod element information. */ +.settingsModContent { + display: flex; + align-items: center; + justify-content: space-between; + transition: opacity 0.25s ease; +} + +/* Wrapper container for the left side of a mod element. */ +.settingsModMainWrapper { + display: flex; + align-items: center; +} + +/* Mod enabled/disabled status. */ +.settingsModStatus { + width: 7px; + height: 7px; + border-radius: 50%; + background-color: #c32625; + margin-right: 15px; + transition: 0.25s ease; +} + +/* Mod details container. */ +.settingsModDetails { + display: flex; + flex-direction: column; +} + +/* The version of the mod. */ +.settingsModVersion { + color: grey; + font-size: 10px; +} + +/* Disabled toggleswitch for required mods. */ +.toggleSwitch[reqmod] { + filter: grayscale(49%) brightness(60%); + pointer-events: none; +} + +/* Set the status color of an enabled mod. */ +.settingsBaseMod[enabled] > .settingsModContent > .settingsModMainWrapper > .settingsModStatus { + background-color: rgb(165, 195, 37); +} + +/* Add opacity to submods of a disabled mod. */ +.settingsBaseMod:not([enabled]) > .settingsSubModContainer .settingsModContent { + opacity: 0.5; +} + +/* Curve the left border for submods. */ +.settingsSubModContainer > .settingsSubMod:first-child { + border-top-left-radius: 10px; +} +.settingsSubModContainer > .settingsSubMod:last-child { + border-bottom-left-radius: 10px; +} +.settingsSubModContainer > .settingsSubMod:only-child { + border-top-left-radius: 10px; + border-bottom-left-radius: 10px; +} + +/* Wrapper container for all submods. */ +.settingsSubModContainer { + margin-top: 10px; +} + +/* Button to open the mods folder for drop-in mods. */ +#settingsDropinFileSystemButton { + background: rgba(0, 0, 0, 0.25); + border: 1px solid rgba(126, 126, 126, 0.57); + border-radius: 3px; + height: 50px; + width: 100%; + text-align: left; + padding: 0px 50px; + cursor: pointer; + outline: none; + transition: 0.25s ease; + margin-bottom: 10px; +} +#settingsDropinFileSystemButton:hover, +#settingsDropinFileSystemButton:focus, +#settingsDropinFileSystemButton[drag] { + background: rgba(54, 54, 54, 0.25); + text-shadow: 0px 0px 20px white; +} +/* Refresh instructions on the file system button. */ +#settingsDropinRefreshNote { + font-size: 10px; + pointer-events: none; +} + +/* Button to remove drop-in mods. */ +.settingsDropinRemoveButton { + background: none; + border: none; + font-size: 10px; + text-align: left; + padding: 0px; + color: #c32625; + font-weight: bold; + cursor: pointer; + outline: none; + transition: 0.25s ease; +} +.settingsDropinRemoveButton:hover, +.settingsDropinRemoveButton:focus { + text-shadow: 0px 0px 20px #c32625, 0px 0px 20px #c32625, 0px 0px 20px #c32625; +} +.settingsDropinRemoveButton:active { + color: #9b1f1f; + text-shadow: 0px 0px 20px #9b1f1f, 0px 0px 20px #9b1f1f, 0px 0px 20px #9b1f1f; +} + +/* Shaderpack settings description. */ +#settingsShaderpackDesc { + font-size: 10px; + margin: 10px 0px; + color: lightgrey; + font-weight: bold; + width: 89%; +} + +/* Wrapper container. */ +#settingsShaderpackWrapper { + display: flex; +} + +/* Button to add shaderpacks. */ +#settingsShaderpackButton { + background: rgba(0, 0, 0, 0.25); + border: 1px solid rgba(126, 126, 126, 0.57); + border-radius: 3px; + cursor: pointer; + outline: none; + transition: 0.25s ease; + font-size: 14px; + padding: 6px 11px; + margin-right: 5px; +} +#settingsShaderpackButton:hover, +#settingsShaderpackButton:focus, +#settingsShaderpackButton[drag] { + background: rgba(54, 54, 54, 0.25); + text-shadow: 0px 0px 20px white; +} + +/* Main select container. */ +.settingsSelectContainer { + position: relative; + width: 50%; +} + +/* Div which displays the selected option. */ +.settingsSelectSelected { + border-radius: 3px; + border-width: 1px; + font-size: 14px; + padding: 6px 16px; +} + +/* Style the arrow inside the select element. */ +.settingsSelectSelected:after { + position: absolute; + content: ""; + top: calc(50% - 3px); + right: 10px; + width: 0; + height: 0; + border: 6px solid transparent; + border-color: rgba(126, 126, 126, 0.57) transparent transparent transparent; +} + +/* Point the arrow upwards when the select box is open (active). */ +.settingsSelectSelected.select-arrow-active:after { + border-color: transparent transparent rgba(126, 126, 126, 0.57) transparent; + top: 7px; +} +.settingsSelectSelected.select-arrow-active { + border-radius: 3px 3px 0px 0px; +} + +/* Options content container. */ +.settingsSelectOptions { + position: absolute; + top: 100%; + left: 0; + right: 0; + z-index: 99; + max-height: 300%; + overflow-y: scroll; + border: 1px solid rgba(126, 126, 126, 0.57); + border-top: none; + border-radius: 0px 0px 3px 3px; +} +/* Hide the items when the select box is closed. */ +.settingsSelectOptions[hidden] { + display: none; +} +.settingsSelectOptions::-webkit-scrollbar { + width: 2px; +} +.settingsSelectOptions::-webkit-scrollbar-track { + display: none; +} +.settingsSelectOptions::-webkit-scrollbar-thumb { + border-radius: 10px; + box-shadow: inset 0 0 10px rgba(255, 255, 255, 0.50); +} + +/* Shared styles between options and selection div. */ +.settingsSelectOptions div, +.settingsSelectSelected { + background: rgba(0, 0, 0, 0.25); + border-style: solid; + border-color: rgba(126, 126, 126, 0.57); + color: #ffffff; + cursor: pointer; +} +.settingsSelectOptions div { + border-width: 0px 0px 1px 0px; + font-size: 12px; + padding: 4px 16px; +} +.settingsSelectOptions div:last-child { + border-bottom: none; +} + +/* Hover + selected styles. */ +.settingsSelectOptions div:hover, .settingsSelectOptions div[selected] { + background-color: rgba(255, 255, 255, 0.25) !important; +} + +/* * * +* Settings View (Java Tab) +* * */ + +/* Style links on the Java tab. */ +#settingsTabJava a, +.settingsChangelogText a { + color: rgba(202, 202, 202, 0.75); + transition: 0.25s ease; + outline: none; +} +#settingsTabJava a:hover, +#settingsTabJava a:focus, +.settingsChangelogText a:hover, +.settingsChangelogText a:focus { + color: rgba(255, 255, 255, 0.75); +} +#settingsTabJava a:active, +.settingsChangelogText a:active { + color: rgba(165, 165, 165, 0.75); +} + +/* Main container for memory management. */ +#settingsMemoryContainer { + width: 75%; + display: flex; + flex-direction: column; + border-bottom: 1px solid rgba(255, 255, 255, 0.50); + margin-bottom: 20px; +} + +/* Memory management title. */ +#settingsMemoryTitle { + margin-bottom: 10px; + padding-bottom: 5px; + border-bottom: 1px solid rgba(255, 255, 255, 0.5); +} + +/* Memory management content. */ +#settingsMemoryContent { + display: flex; + justify-content: space-between; + width: 100%; +} +#settingsMemoryContentLeft { + width: 69%; +} +#settingsMemoryContentRight { + display: flex; + align-items: center; + margin-right: 10%; +} + +/* Header for memory sliders. */ +.settingsMemoryHeader { + font-size: 14px; +} + +/* Wrapper container for a memory slider and label. */ +.settingsMemoryActionContainer { + display: flex; + align-items: center; + justify-content: space-between; +} + +/* Label which displays a memory slider's value. */ +.settingsMemoryLabel { + font-size: 14px; + margin-right: 2%; +} + +/* Range sliders for min and max memory settings. */ +#settingsMaxRAMRange, +#settingsMinRAMRange { + width: 85%; +} + +/* Memory status elements. */ +#settingsMemoryStatus { + display: flex; + flex-direction: column; +} +#settingsMemoryStatus > .settingsMemoryStatusContainer:not(:last-child){ + margin-bottom: 50%; +} +.settingsMemoryStatusContainer { + display: flex; + flex-direction: column; + align-items: center; +} +.settingsMemoryStatusTitle { + font-size: 12px; + color: grey; + font-weight: bold; +} +.settingsMemoryStatusValue { + color: lightgrey; + font-size: 16px; +} + +/* Description for memory management. */ +#settingsMemoryDesc { + font-size: 10px; + margin: 20px 0px; + color: lightgrey; + font-weight: bold; +} + +/* Status text which displays details on the selected executable. */ +#settingsJavaExecDetails { + font-weight: bold; + color: grey; + font-size: 12px; +} + +/* Main container for the JVM options setting. */ +#settingsJVMOptsContainer { + width: 75%; +} + +/* JVM options title. */ +#settingsJVMOptsTitle { + margin-bottom: 10px; +} + +/* Wrapper container for the actionable elements. */ +#settingsJVMOptsContent { + display: flex; + width: 90%; +} + +/* Text field to input the JVM options. */ +#settingsJVMOptsVal { + border-radius: 0px 3px 3px 0px !important; + width: 100%; + padding: 5px 10px; + font-size: 12px; +} +#settingsJVMOptsContent:focus-within > .settingsJavaIcon { + background: rgba(126, 126, 126, 0.87); +} + +/* Description for the JVM options setting. */ +#settingsJVMOptsDesc { + font-size: 10px; + margin: 20px 0px; + color: lightgrey; + font-weight: bold; + width: 89%; +} + +/* * * +* Settings View (Launcher Tab) +* * */ + +/* Tailored style for the data directory header. */ +#settingsDataDirTitle { + margin-bottom: 10px; +} + +/* * * +* Settings View (About Tab) +* * */ + +/* Main about content container. */ +#settingsAboutCurrentContainer { + display: flex; + flex-direction: column; + background: rgba(0, 0, 0, 0.25); + border: 1px solid rgba(126, 126, 126, 0.57); + border-radius: 3px; + width: 75%; + margin-bottom: 20px; +} + +/* About content. */ +#settingsAboutCurrentContent { + display: flex; + flex-direction: column; + padding: 15px; +} + +/* About header elements. */ +#settingsAboutCurrentHeadline { + display: flex; + align-items: center; + padding-bottom: 5px; + border-bottom: 1px solid rgba(126, 126, 126, 0.57); +} +#settingsAboutLogo { + width: 30px; + height: 30px; + padding: 5px; +} +#settingsAboutTitle { + font-size: 23px; + padding-left: 10px; +} + +/* Current version container. */ +#settingsAboutCurrentVersion { + display: flex; + align-items: center; + padding-top: 10px; +} + +/* Checkmark next to the version information. */ +#settingsAboutCurrentVersionCheck { + border-radius: 50%; + background: #23aa23; + text-align: center; + font-weight: bold; + margin: 11px 12px; + color: white; + height: 15px; + width: 15px; + font-size: 12px; + line-height: 17px; +} + +/* Current version details container. */ +#settingsAboutCurrentVersionDetails { + margin-left: 10px; +} + +/* Release type text. */ +#settingsAboutCurrentVersionTitle { + font-size: 12px; + font-family: 'Avenir Medium'; + color: #23aa23; + font-weight: bold; +} + +/* Current version text. */ +#settingsAboutCurrentVersionLine { + font-size: 10px; + color: grey; + font-weight: bold; +} + +/* About information links. */ +#settingsAboutButtons { + display: flex; + padding: 0px 15px; + margin-bottom: 5px; +} +.settingsAboutButton { + background: none; + border: none; + font-size: 10px; + color: grey; + padding: 0px 5px; + transition: 0.25s ease; + outline: none; + text-decoration: none; +} +.settingsAboutButton:hover, +.settingsAboutButton:focus { + color: rgb(165, 165, 165); +} +.settingsAboutButton:active { + color: rgba(124, 124, 124, 0.75); +} + +/* Main changelog container. */ +.settingsChangelogContainer { + display: flex; + flex-direction: column; + background: rgba(0, 0, 0, 0.25); + border: 1px solid rgba(126, 126, 126, 0.57); + border-radius: 3px; + width: 75%; + margin-bottom: 20px; +} + +/* Changelog content container. */ +.settingsChangelogContent { + display: flex; + flex-direction: column; + padding: 15px; +} + +/* Changelog header container. */ +.settingsChangelogHeadline { + padding-bottom: 10px; + margin-bottom: 10px; + border-bottom: 1px solid rgba(126, 126, 126, 0.57); +} +/* Changelog header label. */ +.settingsChangelogLabel { + font-size: 12px; + color: grey; + font-weight: bold; +} + +/* Changelog text content container. */ +.settingsChangelogText { + font-size: 12px; +} + +/* Styles for the changelog elements. */ +.settingsChangelogText p { + margin-bottom: 16px; + line-height: 1.5; +} +.settingsChangelogText blockquote { + border-left: 0.25em solid rgba(126, 126, 126, 0.95); + margin: 0px; + padding: 0 0 0 1em; + color: rgba(255, 255, 255, 0.85); +} +.settingsChangelogText code { + padding: 0.1em 0.4em; + font-size: 85%; + background-color: rgba(255, 255, 255, 0.25); + color: white; + border-radius: 3px; + font-family: 'Avenir Book'; +} +.settingsChangelogText li+li { + margin-top: .25em; +} +.settingsChangelogText a.commit-link { + font-weight: 400; + color: #ffffff; + text-decoration: none; +} +.settingsChangelogText a.commit-link:hover { + text-decoration: underline !important; + text-decoration-color: black; +} +.settingsChangelogText tt { + padding: 0.1em 0.4em; + font-size: 86%; + background-color: white; + border-radius: 3px; + color: black; + font-weight: bold; +} +.settingsChangelogText a.commit-link:hover tt { + text-decoration: underline; + text-decoration-color: black; +} +.settingsChangelogText .highlight { + background: rgba(0, 0, 0, 0.30); + user-select: initial; + padding: 5px 10px; +} +.settingsChangelogText .highlight pre { + margin: 0px; +} + +/* Container for the changelog button. */ +.settingsChangelogActions { + padding: 0px 15px 5px 15px; +} + +/* Open changelog on GitHub. */ +.settingsChangelogButton { + padding: 0px; +} + +/* * * +* Settings View (Updates Tab) +* * */ + +/* Main about content container. */ +#settingsUpdateStatusContainer { + display: flex; + flex-direction: column; + background: rgba(0, 0, 0, 0.25); + border: 1px solid rgba(126, 126, 126, 0.57); + border-radius: 3px; + width: 75%; + margin-bottom: 20px; +} + +/* Update content. */ +#settingsUpdateStatusContent { + display: flex; + flex-direction: column; + padding: 15px; +} + +/* Update header elements. */ +#settingsUpdateStatusHeadline { + display: flex; + align-items: center; + padding-bottom: 5px; + border-bottom: 1px solid rgba(126, 126, 126, 0.57); +} +#settingsUpdateTitle { + font-size: 16px; + padding-left: 10px; + font-weight: bold; +} + +/* Update version container. */ +#settingsUpdateVersion { + display: flex; + align-items: center; + padding: 10px 0px; + border-bottom: 1px solid rgba(126, 126, 126, 0.57); +} + +/* Checkmark next to the version information. */ +#settingsUpdateVersionCheck { + border-radius: 50%; + background: #23aa23; + text-align: center; + font-weight: bold; + margin: 11px 12px; + color: white; + height: 15px; + width: 15px; + font-size: 12px; + line-height: 17px; +} + +/* Update version details container. */ +#settingsUpdateVersionDetails { + margin-left: 10px; +} + +/* Release type text. */ +#settingsUpdateVersionTitle { + font-size: 12px; + font-family: 'Avenir Medium'; + color: #23aa23; + font-weight: bold; +} + +/* Current version text. */ +#settingsUpdateVersionLine { + font-size: 10px; + color: grey; + font-weight: bold; +} + +/* Update action container. */ +#settingsUpdateActionContainer { + padding-top: 10px; + font-size: 14px; + font-weight: bold; +} + +/* Update action button styles. */ +#settingsUpdateActionButton { + display: flex; + flex-direction: column; + padding-left: 10px; + background: none; + border: none; + font-size: 14px; + font-weight: bold; + cursor: pointer; + outline: none; + text-align: left; + transition: 0.25s ease; +} +#settingsUpdateActionButton:hover, +#settingsUpdateActionButton:focus { + text-shadow: 0px 0px 20px white, 0px 0px 20px white, 0px 0px 20px white; +} +#settingsUpdateActionButton:active { + text-shadow: 0px 0px 20px #c7c7c7, 0px 0px 20px #c7c7c7, 0px 0px 20px #c7c7c7; + color: #c7c7c7; +} +#settingsUpdateActionButton:disabled { + pointer-events: none; +} + +/******************************************************************************* + * * + * Landing View (Structural Styles) * + * * + ******************************************************************************/ + +/* Main content container. */ +#landingContainer { + height: 100%; + position: relative; + transition: background 2s ease; + overflow-y: hidden; +} + +/* Upper content container. */ +#landingContainer > #upper { + position: relative; + transition: top 2s ease; + top: 0px; + height: 77%; + display: flex; +} +#landingContainer > #upper > #left { + display: inline-flex; + width: 15%; + height: 100%; + justify-content: flex-end; +} +#landingContainer > #upper > #content { + display: inline-flex; + width: 70%; + height: 100%; +} +#landingContainer > #upper > #right { + display: inline-flex; + width: 15%; + height: 100%; +} + +/* Lower content container. */ +#landingContainer > #lower { + height: 23%; + display: flex; + background: linear-gradient(to top, rgba(0, 0, 0, 0.75), rgba(0, 0, 0, 0)); +} +#landingContainer > #lower > #left { + position: relative; + transition: top 2s ease; + top: 0px; + height: 100%; + width: 33%; + display: inline-flex; + justify-content: center; +} +#landingContainer > #lower > #left #content { + position: relative; + top: 25px; + display: inline-flex; + line-height: 24px; + left: 50px; +} +#landingContainer > #lower > #center { + position: relative; + transition: top 2s ease; + top: 0px; + height: 100%; + width: 34%; + display: inline-flex; + justify-content: center; +} +#landingContainer > #lower > #center #content { + position: relative; + z-index: 500; + transition: top 2s ease; + top: 10px; +} +#landingContainer > #lower > #right { + position: relative; + transition: top 2s ease; + top: 0px; + height: 100%; + width: 33%; + display: inline-flex; +} + +/******************************************************************************* + * * + * Landing View (News Styles) * + * * + ******************************************************************************/ + +/* Main container. */ +#newsContainer { + position: absolute; + top: 100%; + height: 100%; + width: 100%; + transition: top 2s ease; + display: flex; + align-items: flex-end; + justify-content: center; +} + +/* News content container. */ +#newsContent { + height: 82vh; + width: 100%; + display: flex; + -webkit-user-select: initial; + position: relative; +} + +/* Drop shadow displayed when content is scrolled out of view. */ +#newsContent:before { + content: ''; + background: linear-gradient(rgba(0, 0, 0, 0.25), transparent); + width: 100%; + height: 5px; + position: absolute; + opacity: 0; + transition: opacity 0.25s ease; +} +#newsContent[scrolled]:before { + opacity: 1; +} + +/* News article status container (left). */ +#newsStatusContainer { + width: calc(30% - 60px); + height: calc(100% - 30px); + padding: 15px 15px 15px 45px; + display: flex; + flex-direction: column; + justify-content: space-between; + position: relative; +} + +/* News status content. */ +#newsStatusContent { + display: flex; + flex-direction: column; + align-items: flex-end; +} + +/* News title wrapper. */ +#newsTitleContainer { + display: flex; + max-width: 90%; +} + +/* News article title styles. */ +#newsArticleTitle { + font-size: 18px; + font-weight: bold; + font-family: 'Avenir Medium'; + color: white; + text-decoration: none; + transition: 0.25s ease; + outline: none; + text-align: right; +} +#newsArticleTitle:hover, +#newsArticleTitle:focus { + text-shadow: 0px 0px 20px white; +} +#newsArticleTitle:active { + color: #c7c7c7; + text-shadow: 0px 0px 20px #c7c7c7; +} + +/* News meta container. */ +#newsMetaContainer { + display: flex; + flex-direction: column; +} + +/* Date and author wrappers. */ +#newsArticleDateWrapper, +#newsArticleAuthorWrapper { + display: flex; + justify-content: flex-end; +} + +/* Date and author shared styles. */ +#newsArticleDate, +#newsArticleAuthor { + display: inline-block; + font-size: 10px; + padding: 0px 5px; + font-weight: bold; + border-radius: 2px; +} + +/* Date styles. */ +#newsArticleDate { + background: white; + color: black; + margin-top: 5px; +} + +/* Author styles. */ +#newsArticleAuthor { + background: #a02d2a; +} + +/* News article comments styles. */ +#newsArticleComments { + margin-top: 5px; + display: inline-block; + font-size: 10px; + color: #ffffff; + text-decoration: none; + transition: 0.25s ease; + outline: none; + text-align: right; +} +#newsArticleComments:focus, +#newsArticleComments:hover { + color: #e0e0e0; +} +#newsArticleComments:active { + color: #c7c7c7; +} + +/* Article content container (right). */ +#newsArticleContainer { + width: calc(100% - 25px); + height: 100%; + margin: 0px 0px 0px 25px; +} + +/* Article content styles. */ +#newsArticleContentScrollable { + font-size: 12px; + overflow-y: scroll; + height: 100%; + padding: 0px 15px 0px 15px; +} +#newsArticleContentScrollable img, +#newsArticleContentScrollable iframe { + max-width: 95%; + display: block; + margin: 0 auto; +} +#newsArticleContentScrollable a { + color: rgba(202, 202, 202, 0.75); + transition: 0.25s ease; + outline: none; +} +#newsArticleContentScrollable a:hover, +#newsArticleContentScrollable a:focus { + color: rgba(255, 255, 255, 0.75); +} +#newsArticleContentScrollable a:active { + color: rgba(165, 165, 165, 0.75); +} +#newsArticleContentScrollable::-webkit-scrollbar { + width: 2px; +} +#newsArticleContentScrollable::-webkit-scrollbar-track { + display: none; +} +#newsArticleContentScrollable::-webkit-scrollbar-thumb { + border-radius: 10px; + box-shadow: inset 0 0 10px rgba(255, 255, 255, 0.50); +} +.bbCodeSpoilerButton { + background: none; + border: none; + outline: none; + cursor: pointer; + font-size: 16px; + transition: 0.25s ease; + width: 100%; + border-bottom: 1px solid white; + padding-bottom: 15px; +} +.bbCodeSpoilerButton:hover, +.bbCodeSpoilerButton:focus { + text-shadow: 0px 0px 20px #ffffff, 0px 0px 20px #ffffff, 0px 0px 20px #ffffff; +} +.bbCodeSpoilerButton:active { + color: #c7c7c7; + text-shadow: 0px 0px 20px #c7c7c7, 0px 0px 20px #c7c7c7, 0px 0px 20px #c7c7c7; +} +.bbCodeSpoilerText { + display: none; + padding: 15px 0px; + border-bottom: 1px solid white; +} + + +#newsArticleContentWrapper { + width: 80%; +} + +.newsArticleSpacerTop { + height: 15px; +} + +/* Div to add spacing at the end of a news article. */ +.newsArticleSpacerBot { + height: 30px; +} + +/* News navigation container. */ +#newsNavigationContainer { + display: flex; + justify-content: center; + align-items: center; + margin-bottom: 10px; + -webkit-user-select: none; + position: absolute; + bottom: 15px; + right: 0px; +} + +/* Navigation status span. */ +#newsNavigationStatus { + font-size: 12px; + margin: 0px 15px; +} + +/* Left and right navigation button styles. */ +#newsNavigateLeft, +#newsNavigateRight { + background: none; + border: none; + outline: none; + height: 20px; + cursor: pointer; +} +#newsNavigateLeft:hover #newsNavigationLeftSVG, +#newsNavigateLeft:focus #newsNavigationLeftSVG, +#newsNavigateRight:hover #newsNavigationRightSVG, +#newsNavigateRight:focus #newsNavigationRightSVG { + -webkit-filter: drop-shadow(0px 0px 2px #fff); +} +#newsNavigateLeft:active #newsNavigationLeftSVG .arrowLine, +#newsNavigateRight:active #newsNavigationRightSVG .arrowLine { + stroke: #c7c7c7; +} +#newsNavigateLeft:active #newsNavigationLeftSVG, +#newsNavigateRight:active #newsNavigationRightSVG { + -webkit-filter: drop-shadow(0px 0px 2px #c7c7c7); +} +#newsNavigateLeft:disabled #newsNavigationLeftSVG .arrowLine, +#newsNavigateRight:disabled #newsNavigationRightSVG .arrowLine { + stroke: rgba(255, 255, 255, 0.75); +} +#newsNavigationLeftSVG { + transform: rotate(-90deg); + width: 15px; +} +#newsNavigationRightSVG { + transform: rotate(90deg); + width: 15px; +} + +/* News error (message) container. */ +#newsErrorContainer { + height: 100%; + display: flex; + align-items: center; + flex-direction: column; + justify-content: center; +} +#newsErrorFailed { + display: flex; + align-items: center; + flex-direction: column; + justify-content: center; +} + +/* News error content (message). */ +.newsErrorContent { + font-size: 20px; +} +#newsErrorLoading { + display: flex; + width: 168.92px; +} +#nELoadSpan { + white-space: pre; +} +/* News error retry button styles. */ +#newsErrorRetry { + font-size: 12px; + font-weight: bold; + cursor: pointer; + background: none; + border: none; + outline: none; + transition: 0.25s ease; +} +#newsErrorRetry:focus, +#newsErrorRetry:hover { + text-shadow: 0px 0px 20px white; +} +#newsErrorRetry:active { + color: #c7c7c7; + text-shadow: 0px 0px 20px #c7c7c7; +} + +/******************************************************************************* + * * + * Landing View (Top Styles) * + * * + ******************************************************************************/ + +/* * * +* Landing View (Top Styles) | Left Content +* * */ + +/* Logo image. */ +#image_seal { + height: 70px; + width: auto; + position: relative; + border: 2px solid white; + box-sizing: border-box; + border-radius: 50%; +} + +/* Logo container styles. */ +#image_seal_container { + position: relative; + height: 70px; + width: 70px; + border-radius: 50%; + margin-top: 50px; +} + +/* Logo container styles w/ update. */ +#image_seal_container[update]{ + cursor: pointer +} +#image_seal_container[update]:before, +#image_seal_container[update]:after { + cursor: pointer; + position: absolute; + content: ''; + height: 100%; + width: 100%; + top: 0%; + left: 0%; + border-radius: 50%; + box-shadow: 0 0 15px #43c628; + animation: glow-grow 4s ease-out infinite; + background: rgba(0, 0, 0, 0.15); +} +#image_seal_container[update]:before { + animation-delay: 2s; +} + +/* Update available tooltip styles. */ +#updateAvailableTooltip { + cursor: pointer; + visibility: hidden; + opacity: 0; + width: 100px; + height: 15px; + background-color: rgb(0, 0, 0); + color: #fff; + text-align: center; + border-radius: 4px; + padding: 2px; + position: absolute; + z-index: 1; + top: 115%; + left: -17.5px; + font-family: 'Avenir Medium'; + font-size: 12px; + transition: visibility 0s linear 0.25s, opacity 0.25s ease; +} +#updateAvailableTooltip::after { + content: " "; + position: absolute; + left: 50%; + bottom: 100%; + margin-left: -5px; + border-width: 5px; + border-style: solid; + border-color: transparent transparent rgb(0, 0, 0) transparent; +} +#image_seal_container[update]:hover #updateAvailableTooltip { + visibility: visible; + opacity: 1; + transition-delay: 0s; +} + +/* Update available animation. */ +@keyframes glow-grow { + 0% { + opacity: 0; + transform: scale(1); + } + 80% { + opacity: 1; + } + 100% { + transform: scale(1.5); + opacity: 0; + } +} + +/* * * +* Landing View (Bottom Styles) | Right Content +* * */ + +/* Wrapper container for top, right content. */ +#rightContainer { + display: flex; + flex-direction: column; + position: relative; + top: 50px; + align-items: flex-start; + height: calc(100% - 50px); +} + +/* Right hand user content container. */ +#user_content { + display: flex; + align-items: center; + justify-content: center; + box-sizing: border-box; + position: relative; +} + +/* User profile avatar container. */ +#avatarContainer { + border-radius: 50%; + border: 2px solid #cad7e1; + box-sizing: border-box; + background: rgba(1, 2, 1, 0.5); + height: 70px; + width: 70px; + box-shadow: 0px 0px 10px 0px rgb(0, 0, 0); + overflow: hidden; + position: relative; + background-position: center; + background-repeat: no-repeat; + background-size: contain; +} + +/* Avatar edit overlay. */ +#avatarOverlay { + opacity: 0; + position: absolute; + z-index: 1; + display: flex; + justify-content: center; + align-items: center; + transition: 0.25s ease; + font-weight: bold; + letter-spacing: 2px; + background-color: rgba(0, 0, 0, 0.35); + -webkit-user-select: none; + border: none; + cursor: pointer; + width: 100%; + height: 100%; + border-radius: 50%; +} +#avatarOverlay:hover, +#avatarOverlay:focus { + opacity: 1; +} +#avatarOverlay:active { + background-color: rgba(0, 0, 0, 0.45); +} + +/* User profile name text. */ +#user_text { + font-size: 12px; + min-width: 135px; + font-weight: 900; + letter-spacing: 1px; + text-shadow: 0px 0px 20px black; + position: absolute; + right: 95px; + text-align: right; + -webkit-user-select: initial; +} + +/* Social media icon content container. */ +#mediaContent { + position: relative; + display: flex; + flex-direction: column; + margin-top: 25px; + height: calc(100% - 95px); + width: 70px; + align-items: center; +} + +/* Social Media Icon division containers. */ +#internalMedia, #externalMedia { + display: flex; + flex-direction: column; +} + +/* Container object which wraps an icon to ensure fluid transitions. */ +.mediaContainer { + display: flex; + justify-content: center; + align-items: center; + height: 27px; +} + +/* Divider bar between the external and internal icons. */ +.mediaDivider { + height: 1px; + width: 14px; + background: rgb(255, 255, 255); + margin: 10px 0px; +} + +/* Social media icon shared styles. */ +.mediaSVG { + fill: #ffffff; + height: 12px; + transition: 0.25s ease; + cursor: pointer; + height: 12px; + width: 25px; +} +.mediaSVG:hover, +.mediaURL:focus .mediaSVG, +.mediaSVG:active { + height: 20px; +} + +/* Social media URL shared styles. */ +.mediaURL { + outline: none; +} + +/* Internal media button shared styles. */ +.mediaButton { + background: none; + border: none; + padding: 0px; + display: flex; + align-items: center; + outline: none; +} + +#settingsMediaContainer { + position: relative; +} + +/* Settings icon colors. */ +#settingsSVG { + stroke: #ffffff; + height: 15px; +} +.mediaButton:hover #settingsSVG, +.mediaButton:focus #settingsSVG, +.mediaButton:active #settingsSVG { + height: 23px; +} + +/* Settings tooltip styles. */ +#settingsTooltip { + visibility: hidden; + opacity: 0; + width: 75px; + height: 20px; + background-color: rgba(0, 0, 0, 0.75); + text-align: center; + border-radius: 4px; + position: absolute; + z-index: 1; + right: 130%; + font-size: 12px; + line-height: 20px; + transition: visibility 0s linear 0.25s, opacity 0.25s ease; +} +#settingsTooltip::after { + content: " "; + position: absolute; + top: 50%; + left: 100%; + margin-top: -5px; + border-width: 5px; + border-style: solid; + border-color: transparent transparent transparent rgba(0, 0, 0, 0.75); +} +.mediaButton:hover #settingsTooltip, +.mediaButton:focus #settingsTooltip, +.mediaButton:active #settingsTooltip { + visibility: visible; + opacity: 1; + transition-delay:0s; +} + +/* Twitter icon colors. */ +#twitterSVG:hover, +#twitterURL:focus #twitterSVG { + fill: #1da1f2; +} +#twitterSVG:active { + fill: #1b8dd4; +} + +/* Instagram icon colors. */ +#instagramSVG:hover, +#instagramURL:focus #instagramSVG { + fill: url('#instaFill') + /*fill: radial-gradient(circle at 30% 107%, #fdf497 0%, #fdf497 5%, #fd5949 45%, #d6249f 60%, #285AEB 90%); */ +} +#instagramSVG:active { + fill: url('#instaFill') +} + +/* Youtube icon colors. */ +#youtubeSVG:hover, +#youtubeURL:focus #youtubeSVG { + fill: #f00; +} +#youtubeSVG:active { + fill: #ea0202; +} + +/* Discord icon colors. */ +#discordSVG:hover, +#discordURL:focus #discordSVG { + fill: #7288d9; +} +#discordSVG:active { + fill: #657ac4; +} + +/******************************************************************************* + * * + * Landing View (Bottom Styles) * + * * + ******************************************************************************/ + +/* Style for a general label on the bottom of the landing view. */ +.bot_label { + font-size: 9px; + letter-spacing: 1px; + font-weight: bold; + text-shadow: 0px 0px 0px #bebcbb; +} + +/* Divider used on the bottom of the landing view. */ +.bot_divider { + height: 25px; + width: 2px; + background: rgba(107, 105, 105, 0.7); + margin-left: 20px; + margin-right: 20px; +} + +/* * * +* Landing View (Bottom Styles) | Left Content +* * */ + +/* Maintains maximum width on the status bar. */ +#server_status_wrapper { + display: inline-flex; + width: 75px; +} + +/* Span which displays the player count of the selected server. */ +#player_count { + color: #949494; + font-size: 8px; + font-weight: 900; + text-shadow: 0px 0px 20px #949494; + margin-left: 10px; +} + +/* Wrapper container for the mojang status bar. */ +#mojangStatusWrapper { + position: relative; + display: flex; + cursor: pointer; +} + +/* Icon which displays the status of the mojang services. */ +#mojang_status_icon { + font-size: 30px; + color: #848484; + margin-left: 15px; + font-family: 'sans-serif'; +} + +/* Tooltip which displays more details about the mojang statuses. */ +#mojangStatusTooltip { + position: absolute; + visibility: hidden; + opacity: 0; + width: 145px; + min-height: 150px; + background-color: rgba(0, 0, 0, 0.75); + color: #fff; + border-radius: 4px; + padding: 5px 10px; + z-index: 1; + font-family: 'Avenir Medium'; + font-size: 12px; + transition: visibility 0s linear 0.25s, opacity 0.25s ease; + bottom: calc(100% + 15px); + transform: translateX(-50%); + margin-left: 50%; + box-shadow: 0px 0px 20px rgb(0, 0, 0); + cursor: default; +} +#mojangStatusTooltip:after { + content: " "; + position: absolute; + left: 50%; + top: 100%; + margin-left: -5px; + border-width: 5px; + border-style: solid; + border-color: rgba(0, 0, 0, 0.75) transparent transparent transparent; +} +#mojangStatusWrapper:hover #mojangStatusTooltip { + visibility: visible; + opacity: 1; + transition-delay: 0s; +} + +/* Tooltip title for the mojang statuses. */ +#mojangStatusTooltipTitle { + width: 100%; + text-align: center; + margin-bottom: 5px; + letter-spacing: 1px; +} + +/* Wrapper container for the non essential services title. */ +#mojangStatusNEContainer { + display: flex; + align-items: center; + margin: 10px 0px; +} + +/* White bar which surrounds the non essential service title. */ +.mojangStatusNEBar { + height: 1px; + width: 100%; + background: white; +} + +/* Non essential service title text. */ +#mojangStatusNETitle { + font-size: 10px; + padding: 0px 3px; + text-align: center; + letter-spacing: 1px; +} + +/* Wrapper container for mojang service information. */ +.mojangStatusContainer { + display: flex; +} + +/* Displays the name of the mojang service. */ +.mojangStatusName { + width: 100%; + font-size: 10px; + letter-spacing: 1px; + line-height: 12px; + padding: 6px 0px; +} + +/* Displays the status of the mojang service. */ +.mojangStatusIcon { + margin-right: 10px; + font-size: 18.5px; + color: #848484; +} + +/* * * +* Landing View (Bottom Styles) | Center Content +* * */ + +/* Button which opens the news view. */ +#newsButton { + background: none; + border: none; + cursor: pointer; + outline: none; +} +#newsButton:hover #newsButtonText, +#newsButton:focus #newsButtonText { + text-shadow: 0px 0px 20px #fff, 0px 0px 20px #fff; +} +#newsButton:active { + color: #c7c7c7; + text-shadow: 0px 0px 20px #c7c7c7, 0px 0px 20px #c7c7c7; +} + +#newsButton:hover #newsButtonSVG, +#newsButton:focus #newsButtonSVG { + -webkit-filter: drop-shadow(0px 0px 2px #fff); +} +#newsButton:active #newsButtonSVG .arrowLine { + stroke: #c7c7c7; +} +#newsButton:active #newsButtonSVG { + -webkit-filter: drop-shadow(0px 0px 2px #c7c7c7); +} +#newsButton:disabled #newsButtonSVG .arrowLine { + stroke: rgba(255, 255, 255, 0.75); +} + +/* Icon which indicates there is new news. */ +#newsButtonAlert { + width: 5px; + height: 5px; + position: absolute; + border-radius: 50%; + background: red; + right: -1px; + top: 50%; +} + +/* Arrow image which floats above the news button. */ +#newsButtonSVG { + height: 11px; + margin-left: -2px; + transition: 0.25s ease; +} + +/* Span which contains the news button text. */ +#newsButtonText { + color: white; + font-weight: 900; + letter-spacing: 2px; + text-shadow: 0px 0px 0px #bebcbb; + font-size: 11px; + line-height: 30px; + display: flex; + transition: 0.25s ease; +} + +/* * * +* Landing View (Bottom Styles) | Right Content +* * */ + +/* Main launch content container. */ +#landingContainer > #lower > #right #launch_content { + position: relative; + top: 25px; + display: inline-flex; +} + +/* The launch button. */ +#launch_button { + background: none; + border: none; + cursor: pointer; + font-weight: 900; + letter-spacing: 2px; + text-shadow: 0px 0px 0px #bebcbb; + font-size: 20px; + padding: 0px; + transition: 0.25s ease; + outline: none; +} +#launch_button:hover, +#launch_button:focus { + text-shadow: 0px 0px 20px #fff, 0px 0px 20px #fff; +} +#launch_button:active { + color: #c7c7c7; + text-shadow: 0px 0px 20px #c7c7c7, 0px 0px 20px #c7c7c7; +} +#launch_button:disabled { + color: #c7c7c7; + cursor: default; + pointer-events: none; +} + +/* Launch details main container, hidden until launch processing begins. */ +#launch_details { + position: relative; + top: 25px; + display: none; +} + +/* Left side of launch details container, displays percentage and a divider. */ +#launch_details_left { + display: flex; +} + +/* Span which displays percentage complete. */ +#launch_progress_label { + font-weight: 900; + letter-spacing: 1px; + text-shadow: 0px 0px 0px #bebcbb; + font-size: 20px; + min-width: 53.21px; + max-width: 53.21px; + text-align: right; +} + +/* Right side of launch details container, displays progress bar and details. */ +#launch_details_right { + display: flex; + flex-direction: column; + justify-content: center; +} + +/* Button which opens the server selection view. */ +#server_selection_button { + background: none; + border: none; + outline: none; + cursor: pointer; + line-height: 24px; + padding: 0px; + transition: 0.25s ease; +} +#server_selection_button:hover, +#server_selection_button:focus { + text-shadow: 0px 0px 20px #fff, 0px 0px 20px #fff, 0px 0px 20px #fff; +} +#server_selection_button:active { + color: #c7c7c7; + text-shadow: 0px 0px 20px #c7c7c7, 0px 0px 20px #c7c7c7, 0px 0px 20px #c7c7c7; +} + +/* Progress bar styles. */ +#launch_progress[value] { + height: 3px; + width: 265px; + -webkit-appearance: none; +} +#launch_progress[value]::-webkit-progress-bar { + background-color: transparent; +} +#launch_progress[value]::-webkit-progress-value { + background-color: #fff; +} + +/* Span which displays information about the status of the launch process. */ +#launch_details_text { + font-size: 11px; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; +} + +/******************************************************************************* + * * + * Overlay View (overlay.ejs) * + * * + ******************************************************************************/ + +/* * * +* Overlay View (Main Content) +* * */ + +/* Overlay container, placed over the main div. */ +#overlayContainer { + position: absolute; + z-index: 500; + top: 22px; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: calc(100% - 22px); + background: rgba(0, 0, 0, 0.50); +} + +/* Main overlay content. */ +#overlayContent { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + /*justify-content: space-between;*/ + width: 300px; + /*height: 35%;*/ + box-sizing: border-box; + padding: 15px 0px; + /* background-color: #424242; */ + text-align: center; +} + +/* Main overlay content anchor styles. */ +#overlayContent a, +#overlayDismiss { + color: rgba(202, 202, 202, 0.75); + transition: 0.25s ease; +} +#overlayContent a:hover, +#overlayContent a:focus, +#overlayDismiss:focus { + color: rgba(255, 255, 255, 0.75); +} +#overlayContent a:active, +#overlayDismiss:active { + color: rgba(165, 165, 165, 0.75); +} + +/* Add spacing between overlay content elements. */ +#overlayContent > *:first-child { + margin-top: 0px !important; +} +#overlayContent > *:last-child { + margin-bottom: 0px !important; +} +#overlayContent > * { + margin: 8px 0px; +} + +/* Overlay title styles. */ +#overlayTitle { + font-family: 'Avenir Medium'; + font-size: 20px; + font-weight: bold; + letter-spacing: 1px; + -webkit-user-select: initial; +} + +/* Overlay description styles. */ +#overlayDesc { + font-size: 12px; + font-weight: bold; + -webkit-user-select: initial; +} + +/* Div which contains action buttons. */ +#overlayActionContainer { + display: flex; + flex-direction: column; + justify-content: center; +} + +/* Overlay acknowledge button styles. */ +#overlayAcknowledge { + background: none; + border: 1px solid #ffffff; + color: white; + font-family: 'Avenir Medium'; + font-weight: bold; + border-radius: 2px; + padding: 0px 8.1px; + cursor: pointer; + transition: 0.25s ease; +} +#overlayAcknowledge:hover, +#overlayAcknowledge:focus { + box-shadow: 0px 0px 10px 0px #fff; + outline: none; +} +#overlayAcknowledge:active { + border-color: rgba(255, 255, 255, 0.75); + color: rgba(255, 255, 255, 0.75); +} + +/* Overlay dismiss option styles. */ +#overlayDismiss { + font-weight: bold; + font-size: 10px; + text-decoration: none; + padding-top: 2.5px; + background: none; + border: none; + outline: none; + cursor: pointer; +} +#overlayDismiss:hover { + color: rgba(255, 255, 255, 0.75); +} +#overlayDismiss:active { + color: rgba(165, 165, 165, 0.75); +} + +/* * * +* Overlay View (Server + Account Selection Content) +* * */ + +/* Server selection content container. */ +#serverSelectContent, +#accountSelectContent { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + height: 75%; +} + +/* Server selection header. */ +#serverSelectHeader, +#accountSelectHeader { + font-family: 'Avenir Medium'; + font-size: 20px; + font-weight: bold; + color: #fff; + margin-bottom: 25px; +} + +/* Wrapper div for the list of available servers. */ +#serverSelectList, +#accountSelectList { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + max-height: 65%; + min-height: 40%; +} + +/* Scrollable div which lists the available servers. */ +#serverSelectListScrollable, +#accountSelectListScrollable { + padding: 0px 5px; + overflow-y: scroll; +} +#serverSelectListScrollable::-webkit-scrollbar, +#accountSelectListScrollable::-webkit-scrollbar { + width: 2px; +} +#serverSelectListScrollable::-webkit-scrollbar-track, +#accountSelectListScrollable::-webkit-scrollbar-track { + display: none; +} +#serverSelectListScrollable::-webkit-scrollbar-thumb, +#accountSelectListScrollable::-webkit-scrollbar-thumb { + border-radius: 10px; + box-shadow: inset 0 0 10px rgba(255, 255, 255, 0.50); +} + +/* Content container for a server listing. */ +.serverListing { + border: none; + padding: 0px; + width: 375px; + min-height: 60px; + display: flex; + justify-content: flex-start; + align-items: center; + opacity: 0.6; + transition: 0.25s ease; + cursor: pointer; + position: relative; + background: rgba(131, 131, 131, 0.25); +} +.serverListing[selected] { + cursor: default; + opacity: 1.0; +} +.serverListing:hover, +.serverListing:focus { + outline: none; + opacity: 1.0; +} + +.accountListing { + color: white; + border: 1px solid rgba(126, 126, 126, 0.57); + border-radius: 3px; + padding: 5px 45px; + width: 250px; + display: flex; + justify-content: flex-start; + align-items: center; + opacity: 0.6; + transition: 0.25s ease; + cursor: pointer; + position: relative; + background: rgba(0, 0, 0, 0.25); +} +.accountListing[selected] { + cursor: default; + opacity: 1.0; +} +.accountListing:hover, +.accountListing:focus { + outline: none; + opacity: 1.0; +} + +.accountListingName { + display: flex; + height: 100%; + width: 100%; + padding-left: 10px; +} + +/* Add spacing between server listings. */ +#serverSelectListScrollable > .serverListing:not(:first-child):not(:last-child), +#accountSelectListScrollable > .accountListing:not(:first-child):not(:last-child) { + margin: 5px 0px; +} +#serverSelectListScrollable > .serverListing:first-child, +#accountSelectListScrollable > .accountListing:first-child { + margin-bottom: 5px; +} +#serverSelectListScrollable > .serverListing:last-child, +#accountSelectListScrollable > .accountListing:last-child { + margin-top: 5px; +} + +/* Server listing image. */ +.serverListingImg { + margin: 0px 10px 0px 5px; + border: 1px solid #fff; + height: 50px; + width: 50px; +} + +/* Content container for the server listing's details. */ +.serverListingDetails { + display: flex; + flex-direction: column; + align-items: flex-start; + justify-content: space-between; + height: 50px; +} + +/* The name of the server listing. */ +.serverListingName { + font-size: 14px; + font-weight: bold; +} + +/* Description for the server listing. */ +.serverListingDescription { + font-size: 10px; + line-height: 10px; + font-weight: bold; +} + +/* Content container for the server listing's information. */ +.serverListingInfo { + width: 100%; + display: flex; + justify-content: flex-start; +} + +/* The minecraft version of the server listing. */ +.serverListingVersion { + font-size: 10px; + text-align: center; + display: flex; + justify-content: center; + align-items: center; + line-height: 12px; + height: 12px; + border-radius: 2px; + background: rgba(31, 140, 11, 0.8); + padding: 0px 2px; +} + +/* The revision version of the server's manifest. */ +.serverListingRevision { + color: #969696; + font-size: 10px; + line-height: 12px; + padding: 0px 5px; +} + +/* Star which indicates the default (main) server. */ +.serverListingStarWrapper { + display: flex; + align-items: center; + cursor: pointer; + height: 12px; + position: relative; +} +/* Tooltip which displays when hovering over the star. */ +.serverListingStarTooltip { + visibility: hidden; + opacity: 0; + width: 65px; + background-color: rgba(0, 0, 0, 0.40); + text-align: center; + border-radius: 4px; + position: absolute; + z-index: 1; + left: 130%; + font-size: 10px; + transition: visibility 0s linear 0.25s, opacity 0.25s ease; +} +.serverListingStarTooltip::after { + content: " "; + position: absolute; + top: 50%; + right: 100%; /* To the left of the tooltip */ + margin-top: -5px; + border-width: 5px; + border-style: solid; + border-color: transparent rgba(0, 0, 0, 0.40) transparent transparent; +} +.serverListingStarWrapper:hover .serverListingStarTooltip { + visibility: visible; + opacity: 1; + transition-delay:0s; +} + +/* Content container which contains the server select actions. */ +#serverSelectActions, +#accountSelectActions { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + margin-top: 25px; +} + +/* Server selection confirm button styles. */ +#serverSelectConfirm, +#accountSelectConfirm { + background: none; + border: 1px solid #ffffff; + color: white; + font-family: 'Avenir Medium'; + font-weight: bold; + border-radius: 2px; + padding: 0px 8.1px; + cursor: pointer; + transition: 0.25s ease; + min-height: 20.67px; +} +#serverSelectConfirm:hover, +#serverSelectConfirm:focus, +#accountSelectConfirm:hover, +#accountSelectConfirm:focus { + box-shadow: 0px 0px 10px 0px #fff; + outline: none; +} +#serverSelectConfirm:active, +#accountSelectConfirm:active { + border-color: rgba(255, 255, 255, 0.75); + color: rgba(255, 255, 255, 0.75); +} + +/* Server selection cancel button styles. */ +#serverSelectCancel, +#accountSelectCancel { + font-weight: bold; + font-size: 10px; + text-decoration: none; + padding-top: 2.5px; + color: rgba(202, 202, 202, 0.75); + transition: 0.25s ease; + background: none; + border: none; + outline: none; + cursor: pointer; +} +#serverSelectCancel:hover, +#serverSelectCancel:focus, +#accountSelectCancel:hover, +#accountSelectCancel:focus { + color: rgba(255, 255, 255, 0.75); +} +#serverSelectCancel:active, +#accountSelectCancel:active { + color: rgba(165, 165, 165, 0.75); +} + +/******************************************************************************* + * * + * Loading Element (app.ejs) * + * * + ******************************************************************************/ + +/* Loading container, placed above everything. */ +#loadingContainer { + position: absolute; + z-index: 400; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: calc(100% - 22px); +} + +/* Loading content container. */ +#loadingContent { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + +/* Spinner container. */ +#loadSpinnerContainer { + position: relative; + display: flex; + align-items: center; + justify-content: center; +} + +/* Stationary image for the spinner. */ +#loadCenterImage { + position: absolute; + width: 277px; + height: auto; +} + +/* Rotating image for the spinner. */ +#loadSpinnerImage { + width: 280px; + height: auto; + z-index: 400; +} + +/* Rotating animation for the spinner. */ +@keyframes rotating { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + +/* Class which is applied when the spinner image is spinning. */ +.rotating { + animation: rotating 10s linear infinite; } \ No newline at end of file diff --git a/app/assets/distribution.json b/app/assets/distribution.json new file mode 100644 index 0000000..ca4fd16 --- /dev/null +++ b/app/assets/distribution.json @@ -0,0 +1,298 @@ +{ + "version": "1.0.0", + "discord": { + "clientId": "385581240906022916", + "smallImageText": "WesterosCraft", + "smallImageKey": "seal-circle" + }, + "java": { + "oracle": "http://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads-2133155.html" + }, + "rss": "https://westeroscraft.com/articles/index.rss", + "servers": [ + { + "id": "SkirdaTesting-1.12.2", + "name": "Skirda Test Server", + "description": "Сплошные баги блять", + "icon": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/server-prod.png", + "version": "4.6.5", + "address": "192.168.88.228:35012", + "minecraftVersion": "1.12.2", + "discord": { + "shortId": "Skirda Minecraft Server", + "largeImageText": "Skirda 1.12.2 Minecraft Server", + "largeImageKey": "skirda-testing" + }, + "mainServer": false, + "autoconnect": true, + "modules": [ + { + "id": "net.minecraftforge:forge:1.12.2-14.23.5.2847", + "name": "Minecraft Forge", + "type": "ForgeHosted", + "artifact": { + "size": 4884700, + "MD5": "90734a5a713e24902d24c45c15caa42c", + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/forge-1.12.2-14.23.5.2847-universal.jar" + }, + "subModules": [ + { + "id": "net.minecraft:launchwrapper:1.12", + "name": "Mojang (LaunchWrapper)", + "type": "Library", + "artifact": { + "size": 32999, + "MD5": "934b2d91c7c5be4a49577c9e6b40e8da", + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/launchwrapper-1.12.jar" + } + }, + { + "id": "org.ow2.asm:asm-all:5.2", + "name": "Mojang (ASM)", + "type": "Library", + "artifact": { + "size": 247787, + "MD5": "f5ad16c7f0338b541978b0430d51dc83", + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/asm-all-5.2.jar" + } + }, + { + "id": "jline:jline:2.13", + "name": "Mojang (jline)", + "type": "Library", + "artifact": { + "size": 248566, + "MD5": "f251ba666cccb260ff7215b2cbeee8d4", + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/jline-2.13.jar" + } + }, + { + "id": "org.scala-lang:scala-library:2.11.1@jar.pack.xz", + "name": "Minecraft Forge (scala-library)", + "type": "Library", + "artifact": { + "size": 1474672, + "MD5": "379c15c4f724421c6d5d7aecedaf87a6", + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-library-2.11.1.jar.pack.xz" + } + }, + { + "id": "org.scala-lang:scala-compiler:2.11.1@jar.pack.xz", + "name": "Minecraft Forge (scala-compiler)", + "type": "Library", + "artifact": { + "size": 3076920, + "MD5": "7d89e952f2d5c74577310cd2c28e3f20", + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-compiler-2.11.1.jar.pack.xz" + } + }, + { + "id": "org.scala-lang:scala-actors-migration_2.11:1.1.0@jar.pack.xz", + "name": "Minecraft Forge (scala-actors-migration)", + "type": "Library", + "artifact": { + "size": 21324, + "MD5": "04e3428b2600ace33c7ae2bf1f6c0a4c", + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-actors-migration_2.11-1.1.0.jar.pack.xz" + } + }, + { + "id": "org.scala-lang.plugins:scala-continuations-library_2.11:1.0.2@jar.pack.xz", + "name": "Minecraft Forge (scala-continuations-library)", + "type": "Library", + "artifact": { + "size": 7956, + "MD5": "ed9b1d27aba8ac4090a3749c4dfc895a", + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-continuations-library_2.11-1.0.2.jar.pack.xz" + } + }, + { + "id": "org.scala-lang.plugins:scala-continuations-plugin_2.11.1:1.0.2@jar.pack.xz", + "name": "Minecraft Forge (scala-continuations-plugin)", + "type": "Library", + "artifact": { + "size": 46140, + "MD5": "a8232db22a72a981de6b1399eb86dff7", + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-continuations-plugin_2.11.1-1.0.2.jar.pack.xz" + } + }, + { + "id": "org.scala-lang:scala-parser-combinators_2.11:1.0.1@jar.pack.xz", + "name": "Minecraft Forge (scala-parser-combinators)", + "type": "Library", + "artifact": { + "size": 85568, + "MD5": "2e50a7df17680daadacca69f07f8a16d", + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-parser-combinators_2.11-1.0.1.jar.pack.xz" + } + }, + { + "id": "org.scala-lang:scala-reflect:2.11.1@jar.pack.xz", + "name": "Minecraft Forge (scala-reflect)", + "type": "Library", + "artifact": { + "size": 1070312, + "MD5": "84e5dc81c10e2bd74c579c9d0332fdd9", + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-reflect-2.11.1.jar.pack.xz" + } + }, + { + "id": "org.scala-lang:scala-swing_2.11:1.0.1", + "name": "Minecraft Forge (scala-swing)", + "type": "Library", + "artifact": { + "size": 736795, + "MD5": "1d360289e697022a3f57abaad344b28f", + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-swing_2.11-1.0.1.jar" + } + }, + { + "id": "org.scala-lang:scala-xml_2.11:1.0.2@jar.pack.xz", + "name": "Minecraft Forge (scala-xml)", + "type": "Library", + "artifact": { + "size": 217812, + "MD5": "cc891b094a4c32dedc56bfefe9b072ff", + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-xml_2.11-1.0.2.jar.pack.xz" + } + }, + { + "id": "com.typesafe.akka:akka-actor_2.11:2.3.3@jar.pack.xz", + "name": "Minecraft Forge (akka-actor)", + "type": "Library", + "artifact": { + "size": 746612, + "MD5": "25cb22c3078e9fb3f7a861c912924862", + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/akka-actor_2.11-2.3.3.jar.pack.xz" + } + }, + { + "id": "com.typesafe:config:1.2.1@jar.pack.xz", + "name": "Minecraft Forge (typesafe-config)", + "type": "Library", + "artifact": { + "size": 56636, + "MD5": "10ec4ccabc4e68aac9cf87165ead5d7d", + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/config-1.2.1.jar.pack.xz" + } + }, + { + "id": "lzma:lzma:0.0.1", + "name": "Mojang (LZMA)", + "type": "Library", + "artifact": { + "size": 5762, + "MD5": "a3e3c3186e41c4a1a3027ba2bb23cdc6", + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/lzma-0.0.1.jar" + } + }, + { + "id": "net.sf.trove4j:trove4j:3.0.3", + "name": "Trove4J", + "type": "Library", + "artifact": { + "size": 2523218, + "MD5": "8fc4d4e0129244f9fd39650c5f30feb2", + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/trove4j-3.0.3.jar" + } + }, + { + "id": "java3d:vecmath:1.5.2", + "name": "Vecmath", + "type": "Library", + "artifact": { + "size": 318956, + "MD5": "e5d2b7f46c4800a32f62ce75676a5710", + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/vecmath-1.5.2.jar" + } + }, + { + "id": "net.sf.jopt-simple:jopt-simple:5.0.3", + "name": "Jopt-simple", + "type": "Library", + "artifact": { + "size": 78175, + "MD5": "0a5ec84e23df9d7cfb4063bc55f2744c", + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/jopt-simple-5.0.3.jar" + } + }, + { + "id": "org.apache.maven:maven-artifact:3.5.3", + "name": "maven-artifact", + "type": "Library", + "artifact": { + "size": 54961, + "MD5": "7741ebf29690ee7d9dde9cf4376347fc", + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/maven-artifact-3.5.3.jar" + } + }, + { + "id": "net.minecraftforge:MercuriusUpdater:1.12.2", + "name": "MercuriusUpdater", + "type": "Library", + "artifact": { + "size": 15098, + "MD5": "6eb9e61097bee3103a2fdc42746b76a4", + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/MercuriusUpdater-1.12.2.jar" + } + } + ] + }, + { + "id": "net.optifine:optifine:1.12.2_HD_U_F5", + "name": "Optifine", + "type": "ForgeMod", + "artifact": { + "size": 2598821, + "MD5": "043ac1db6f7441ea4cf31bcb621aff0b", + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/prod-1.12.2/mods/OptiFine.jar" + } + }, + { + "id": "mezz:jei:1.12.2-4.14.3.242", + "name": "JustEnoughItems", + "type": "ForgeMod", + "artifact": { + "size": 620682, + "MD5": "ae6d0e6e873ef6c20f41097dc7fee8c6", + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/prod-1.12.2/mods/jei.jar" + } + }, + { + "id": "xaeros:minimap:1.12.2-20.15.0", + "name": "XaerosMinimap", + "type": "ForgeMod", + "required": { + "value": false + }, + "artifact": { + "size": 528849, + "MD5": "cc12cfe20febd1404345f5339e522cda", + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/prod-1.12.2/mods/Xaeros_Minimap.jar" + } + }, + { + "id": "options.txt", + "name": "Default Client Options", + "type": "File", + "artifact": { + "size": 1973, + "path": "options.txt", + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/options-1.12.2.txt" + } + }, + { + "id": "servers.dat", + "name": "Saved Client Servers", + "type": "File", + "artifact": { + "size": 84, + "MD5": "71d99e229d7d2b8d2a6423e46832a4b8", + "path": "servers.dat", + "url": "http://mc.westeroscraft.com/WesterosCraftLauncher/prod-1.12.2/servers.dat" + } + } + ] + } + ] +} \ No newline at end of file diff --git a/app/assets/js/authmanager.js b/app/assets/js/authmanager.js index 3f43144..03b3a22 100644 --- a/app/assets/js/authmanager.js +++ b/app/assets/js/authmanager.js @@ -15,6 +15,7 @@ const { RestResponseStatus } = require('helios-core/common') const { MojangRestAPI, mojangErrorDisplayable, MojangErrorCode } = require('helios-core/mojang') const { MicrosoftAuth, microsoftErrorDisplayable, MicrosoftErrorCode } = require('helios-core/microsoft') const { AZURE_CLIENT_ID } = require('./ipcconstants') +const { async } = require('node-stream-zip') const log = LoggerUtil.getLogger('AuthManager') @@ -57,6 +58,10 @@ exports.addMojangAccount = async function(username, password) { } } +exports.addOfflineAccount = async function(usernameOffline){ + ConfigManager.addOfflineAccount('0456456413213', '-', "Megatraher") +} + const AUTH_MODE = { FULL: 0, MS_REFRESH: 1, MC_REFRESH: 2 } /** diff --git a/app/assets/js/configmanager.js b/app/assets/js/configmanager.js index 3dff950..4814de6 100644 --- a/app/assets/js/configmanager.js +++ b/app/assets/js/configmanager.js @@ -353,6 +353,17 @@ exports.addMojangAuthAccount = function(uuid, accessToken, username, displayName return config.authenticationDatabase[uuid] } +exports.addOfflineAccount = function(uuid, accessToken, usernameOffline){ + config.selectedAccount = uuid + config.authenticationDatabase[uuid] = { + type: 'offline', + accessToken, + username: usernameOffline.trim(), + uuid: uuid.trim(), + displayName: usernameOffline.trim() + } + return config.authenticationDatabase[uuid] +} /** * Update the tokens of an authenticated microsoft account. * diff --git a/app/assets/js/distromanager.js b/app/assets/js/distromanager.js index 90a2ab8..7b2bd4d 100644 --- a/app/assets/js/distromanager.js +++ b/app/assets/js/distromanager.js @@ -537,7 +537,8 @@ exports.pullRemote = function(){ return exports.pullLocal() } return new Promise((resolve, reject) => { - const distroURL = 'http://mc.westeroscraft.com/WesterosCraftLauncher/distribution.json' + //const distroURL = 'http://mc.westeroscraft.com/WesterosCraftLauncher/distribution.json' + const distroURL = "http://192.168.88.228:45789/distr.json" //const distroURL = 'https://gist.githubusercontent.com/dscalzi/53b1ba7a11d26a5c353f9d5ae484b71b/raw/' const opts = { url: distroURL, diff --git a/app/assets/js/scripts/landing.js b/app/assets/js/scripts/landing.js index c15896c..3407fbc 100644 --- a/app/assets/js/scripts/landing.js +++ b/app/assets/js/scripts/landing.js @@ -108,6 +108,7 @@ document.getElementById('launch_button').addEventListener('click', function(e){ } }) + // Bind settings button document.getElementById('settingsMediaButton').onclick = (e) => { prepareSettings() @@ -484,12 +485,12 @@ function dlAsync(login = true){ // Login parameter is temporary for debug purposes. Allows testing the validation/downloads without // launching the game. - if(login) { + /* if(login) { if(ConfigManager.getSelectedAccount() == null){ loggerLanding.error('You must be logged into an account.') return } - } + }*/ setLaunchDetails('Please wait..') toggleLaunchArea(true) diff --git a/app/assets/js/scripts/login.js b/app/assets/js/scripts/login.js index 724f09c..34bf526 100644 --- a/app/assets/js/scripts/login.js +++ b/app/assets/js/scripts/login.js @@ -1,239 +1,239 @@ -/** - * Script for login.ejs - */ -// Validation Regexes. -const validUsername = /^[a-zA-Z0-9_]{1,16}$/ -const basicEmail = /^\S+@\S+\.\S+$/ -//const validEmail = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i - -// Login Elements -const loginCancelContainer = document.getElementById('loginCancelContainer') -const loginCancelButton = document.getElementById('loginCancelButton') -const loginEmailError = document.getElementById('loginEmailError') -const loginUsername = document.getElementById('loginUsername') -const loginPasswordError = document.getElementById('loginPasswordError') -const loginPassword = document.getElementById('loginPassword') -const checkmarkContainer = document.getElementById('checkmarkContainer') -const loginRememberOption = document.getElementById('loginRememberOption') -const loginButton = document.getElementById('loginButton') -const loginForm = document.getElementById('loginForm') - -// Control variables. -let lu = false, lp = false - -const loggerLogin = LoggerUtil1('%c[Login]', 'color: #000668; font-weight: bold') - - -/** - * Show a login error. - * - * @param {HTMLElement} element The element on which to display the error. - * @param {string} value The error text. - */ -function showError(element, value){ - element.innerHTML = value - element.style.opacity = 1 -} - -/** - * Shake a login error to add emphasis. - * - * @param {HTMLElement} element The element to shake. - */ -function shakeError(element){ - if(element.style.opacity == 1){ - element.classList.remove('shake') - void element.offsetWidth - element.classList.add('shake') - } -} - -/** - * Validate that an email field is neither empty nor invalid. - * - * @param {string} value The email value. - */ -function validateEmail(value){ - if(value){ - if(!basicEmail.test(value) && !validUsername.test(value)){ - showError(loginEmailError, Lang.queryJS('login.error.invalidValue')) - loginDisabled(true) - lu = false - } else { - loginEmailError.style.opacity = 0 - lu = true - if(lp){ - loginDisabled(false) - } - } - } else { - lu = false - showError(loginEmailError, Lang.queryJS('login.error.requiredValue')) - loginDisabled(true) - } -} - -/** - * Validate that the password field is not empty. - * - * @param {string} value The password value. - */ -function validatePassword(value){ - if(value){ - loginPasswordError.style.opacity = 0 - lp = true - if(lu){ - loginDisabled(false) - } - } else { - lp = false - showError(loginPasswordError, Lang.queryJS('login.error.invalidValue')) - loginDisabled(true) - } -} - -// Emphasize errors with shake when focus is lost. -loginUsername.addEventListener('focusout', (e) => { - validateEmail(e.target.value) - shakeError(loginEmailError) -}) -loginPassword.addEventListener('focusout', (e) => { - validatePassword(e.target.value) - shakeError(loginPasswordError) -}) - -// Validate input for each field. -loginUsername.addEventListener('input', (e) => { - validateEmail(e.target.value) -}) -loginPassword.addEventListener('input', (e) => { - validatePassword(e.target.value) -}) - -/** - * Enable or disable the login button. - * - * @param {boolean} v True to enable, false to disable. - */ -function loginDisabled(v){ - if(loginButton.disabled !== v){ - loginButton.disabled = v - } -} - -/** - * Enable or disable loading elements. - * - * @param {boolean} v True to enable, false to disable. - */ -function loginLoading(v){ - if(v){ - loginButton.setAttribute('loading', v) - loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.login'), Lang.queryJS('login.loggingIn')) - } else { - loginButton.removeAttribute('loading') - loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.loggingIn'), Lang.queryJS('login.login')) - } -} - -/** - * Enable or disable login form. - * - * @param {boolean} v True to enable, false to disable. - */ -function formDisabled(v){ - loginDisabled(v) - loginCancelButton.disabled = v - loginUsername.disabled = v - loginPassword.disabled = v - if(v){ - checkmarkContainer.setAttribute('disabled', v) - } else { - checkmarkContainer.removeAttribute('disabled') - } - loginRememberOption.disabled = v -} - -let loginViewOnSuccess = VIEWS.landing -let loginViewOnCancel = VIEWS.settings -let loginViewCancelHandler - -function loginCancelEnabled(val){ - if(val){ - $(loginCancelContainer).show() - } else { - $(loginCancelContainer).hide() - } -} - -loginCancelButton.onclick = (e) => { - switchView(getCurrentView(), loginViewOnCancel, 500, 500, () => { - loginUsername.value = '' - loginPassword.value = '' - loginCancelEnabled(false) - if(loginViewCancelHandler != null){ - loginViewCancelHandler() - loginViewCancelHandler = null - } - }) -} - -// Disable default form behavior. -loginForm.onsubmit = () => { return false } - -// Bind login button behavior. -loginButton.addEventListener('click', () => { - // Disable form. - formDisabled(true) - - // Show loading stuff. - loginLoading(true) - - AuthManager.addMojangAccount(loginUsername.value, loginPassword.value).then((value) => { - updateSelectedAccount(value) - loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.loggingIn'), Lang.queryJS('login.success')) - $('.circle-loader').toggleClass('load-complete') - $('.checkmark').toggle() - setTimeout(() => { - switchView(VIEWS.login, loginViewOnSuccess, 500, 500, () => { - // Temporary workaround - if(loginViewOnSuccess === VIEWS.settings){ - prepareSettings() - } - loginViewOnSuccess = VIEWS.landing // Reset this for good measure. - loginCancelEnabled(false) // Reset this for good measure. - loginViewCancelHandler = null // Reset this for good measure. - loginUsername.value = '' - loginPassword.value = '' - $('.circle-loader').toggleClass('load-complete') - $('.checkmark').toggle() - loginLoading(false) - loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.success'), Lang.queryJS('login.login')) - formDisabled(false) - }) - }, 1000) - }).catch((displayableError) => { - loginLoading(false) - - let actualDisplayableError - if(isDisplayableError(displayableError)) { - msftLoginLogger.error('Error while logging in.', displayableError) - actualDisplayableError = displayableError - } else { - // Uh oh. - msftLoginLogger.error('Unhandled error during login.', displayableError) - actualDisplayableError = { - title: 'Unknown Error During Login', - desc: 'An unknown error has occurred. Please see the console for details.' - } - } - - setOverlayContent(actualDisplayableError.title, actualDisplayableError.desc, Lang.queryJS('login.tryAgain')) - setOverlayHandler(() => { - formDisabled(false) - toggleOverlay(false) - }) - toggleOverlay(true) - }) - +/** + * Script for login.ejs + */ +// Validation Regexes. +const validUsername = /^[a-zA-Z0-9_]{1,16}$/ +const basicEmail = /^\S+@\S+\.\S+$/ +//const validEmail = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i + +// Login Elements +const loginCancelContainer = document.getElementById('loginCancelContainer') +const loginCancelButton = document.getElementById('loginCancelButton') +const loginEmailError = document.getElementById('loginEmailError') +const loginUsername = document.getElementById('loginUsername') +const loginPasswordError = document.getElementById('loginPasswordError') +const loginPassword = document.getElementById('loginPassword') +const checkmarkContainer = document.getElementById('checkmarkContainer') +const loginRememberOption = document.getElementById('loginRememberOption') +const loginButton = document.getElementById('loginButton') +const loginForm = document.getElementById('loginForm') + +// Control variables. +let lu = false, lp = false + +const loggerLogin = LoggerUtil1('%c[Login]', 'color: #000668; font-weight: bold') + + +/** + * Show a login error. + * + * @param {HTMLElement} element The element on which to display the error. + * @param {string} value The error text. + */ +function showError(element, value){ + element.innerHTML = value + element.style.opacity = 1 +} + +/** + * Shake a login error to add emphasis. + * + * @param {HTMLElement} element The element to shake. + */ +function shakeError(element){ + if(element.style.opacity == 1){ + element.classList.remove('shake') + void element.offsetWidth + element.classList.add('shake') + } +} + +/** + * Validate that an email field is neither empty nor invalid. + * + * @param {string} value The email value. + */ +function validateEmail(value){ + if(value){ + if(!basicEmail.test(value) && !validUsername.test(value)){ + showError(loginEmailError, Lang.queryJS('login.error.invalidValue')) + loginDisabled(true) + lu = false + } else { + loginEmailError.style.opacity = 0 + lu = true + if(lp){ + loginDisabled(false) + } + } + } else { + lu = false + showError(loginEmailError, Lang.queryJS('login.error.requiredValue')) + loginDisabled(true) + } +} + +/** + * Validate that the password field is not empty. + * + * @param {string} value The password value. + */ +function validatePassword(value){ + if(value){ + loginPasswordError.style.opacity = 0 + lp = true + if(lu){ + loginDisabled(false) + } + } else { + lp = false + showError(loginPasswordError, Lang.queryJS('login.error.invalidValue')) + loginDisabled(true) + } +} + +// Emphasize errors with shake when focus is lost. +loginUsername.addEventListener('focusout', (e) => { + validateEmail(e.target.value) + shakeError(loginEmailError) +}) +loginPassword.addEventListener('focusout', (e) => { + validatePassword(e.target.value) + shakeError(loginPasswordError) +}) + +// Validate input for each field. +loginUsername.addEventListener('input', (e) => { + validateEmail(e.target.value) +}) +loginPassword.addEventListener('input', (e) => { + validatePassword(e.target.value) +}) + +/** + * Enable or disable the login button. + * + * @param {boolean} v True to enable, false to disable. + */ +function loginDisabled(v){ + if(loginButton.disabled !== v){ + loginButton.disabled = v + } +} + +/** + * Enable or disable loading elements. + * + * @param {boolean} v True to enable, false to disable. + */ +function loginLoading(v){ + if(v){ + loginButton.setAttribute('loading', v) + loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.login'), Lang.queryJS('login.loggingIn')) + } else { + loginButton.removeAttribute('loading') + loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.loggingIn'), Lang.queryJS('login.login')) + } +} + +/** + * Enable or disable login form. + * + * @param {boolean} v True to enable, false to disable. + */ +function formDisabled(v){ + loginDisabled(v) + loginCancelButton.disabled = v + loginUsername.disabled = v + loginPassword.disabled = v + if(v){ + checkmarkContainer.setAttribute('disabled', v) + } else { + checkmarkContainer.removeAttribute('disabled') + } + loginRememberOption.disabled = v +} + +let loginViewOnSuccess = VIEWS.landing +let loginViewOnCancel = VIEWS.settings +let loginViewCancelHandler + +function loginCancelEnabled(val){ + if(val){ + $(loginCancelContainer).show() + } else { + $(loginCancelContainer).hide() + } +} + +loginCancelButton.onclick = (e) => { + switchView(getCurrentView(), loginViewOnCancel, 500, 500, () => { + loginUsername.value = '' + loginPassword.value = '' + loginCancelEnabled(false) + if(loginViewCancelHandler != null){ + loginViewCancelHandler() + loginViewCancelHandler = null + } + }) +} + +// Disable default form behavior. +loginForm.onsubmit = () => { return false } + +// Bind login button behavior. +loginButton.addEventListener('click', () => { + // Disable form. + formDisabled(true) + + // Show loading stuff. + loginLoading(true) + + AuthManager.addMojangAccount(loginUsername.value, loginPassword.value).then((value) => { + updateSelectedAccount(value) + loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.loggingIn'), Lang.queryJS('login.success')) + $('.circle-loader').toggleClass('load-complete') + $('.checkmark').toggle() + setTimeout(() => { + switchView(VIEWS.login, loginViewOnSuccess, 500, 500, () => { + // Temporary workaround + if(loginViewOnSuccess === VIEWS.settings){ + prepareSettings() + } + loginViewOnSuccess = VIEWS.landing // Reset this for good measure. + loginCancelEnabled(false) // Reset this for good measure. + loginViewCancelHandler = null // Reset this for good measure. + loginUsername.value = '' + loginPassword.value = '' + $('.circle-loader').toggleClass('load-complete') + $('.checkmark').toggle() + loginLoading(false) + loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.success'), Lang.queryJS('login.login')) + formDisabled(false) + }) + }, 1000) + }).catch((displayableError) => { + loginLoading(false) + + let actualDisplayableError + if(isDisplayableError(displayableError)) { + msftLoginLogger.error('Error while logging in.', displayableError) + actualDisplayableError = displayableError + } else { + // Uh oh. + msftLoginLogger.error('Unhandled error during login.', displayableError) + actualDisplayableError = { + title: 'Unknown Error During Login', + desc: 'An unknown error has occurred. Please see the console for details.' + } + } + + setOverlayContent(actualDisplayableError.title, actualDisplayableError.desc, Lang.queryJS('login.tryAgain')) + setOverlayHandler(() => { + formDisabled(false) + toggleOverlay(false) + }) + toggleOverlay(true) + }) + }) \ No newline at end of file diff --git a/app/assets/js/scripts/loginOffline.js b/app/assets/js/scripts/loginOffline.js new file mode 100644 index 0000000..dc3446f --- /dev/null +++ b/app/assets/js/scripts/loginOffline.js @@ -0,0 +1,30 @@ +const loggerOfflineLogin = LoggerUtil1('%c[LoginOffline]', 'color: #000668; font-weight: bold') + +const loginOfflineButton = document.getElementById('loginOfflineButton') + +function loginOfflineDisabled(v){ + if(loginOfflineButton.disabled !== v){ + loginOfflineButton.disabled = v + } +} + +function formOfflineDisabled(v){ + loginOfflineDisabled(v) + //loginCancelButton.disabled = v + loginOfflineUsername.disabled = v + /*loginPassword.disabled = v + if(v){ + checkmarkContainer.setAttribute('disabled', v) + } else { + checkmarkContainer.removeAttribute('disabled') + } + loginRememberOption.disabled = v*/ +} + +loginOfflineButton.addEventListener('click', () => { + + formOfflineDisabled(true) + AuthManager.addOfflineAccount(loginOfflineUsername.value).then((value) =>{ + switchView(VIEWS.loginOffline, VIEWS.landing, 500, 500) + }) +}) \ No newline at end of file diff --git a/app/assets/js/scripts/loginOptions.js b/app/assets/js/scripts/loginOptions.js index cdb1bc8..e62abe9 100644 --- a/app/assets/js/scripts/loginOptions.js +++ b/app/assets/js/scripts/loginOptions.js @@ -1,50 +1,45 @@ -const loginOptionsCancelContainer = document.getElementById('loginOptionCancelContainer') -const loginOptionMicrosoft = document.getElementById('loginOptionMicrosoft') -const loginOptionMojang = document.getElementById('loginOptionMojang') -const loginOptionsCancelButton = document.getElementById('loginOptionCancelButton') - -let loginOptionsCancellable = false - -let loginOptionsViewOnLoginSuccess -let loginOptionsViewOnLoginCancel -let loginOptionsViewOnCancel -let loginOptionsViewCancelHandler - -function loginOptionsCancelEnabled(val){ - if(val){ - $(loginOptionsCancelContainer).show() - } else { - $(loginOptionsCancelContainer).hide() - } -} - -loginOptionMicrosoft.onclick = (e) => { - switchView(getCurrentView(), VIEWS.waiting, 500, 500, () => { - ipcRenderer.send( - MSFT_OPCODE.OPEN_LOGIN, - loginOptionsViewOnLoginSuccess, - loginOptionsViewOnLoginCancel - ) - }) -} - -loginOptionMojang.onclick = (e) => { - switchView(getCurrentView(), VIEWS.login, 500, 500, () => { - loginViewOnSuccess = loginOptionsViewOnLoginSuccess - loginViewOnCancel = loginOptionsViewOnLoginCancel - loginCancelEnabled(true) - }) -} - -loginOptionsCancelButton.onclick = (e) => { - switchView(getCurrentView(), loginOptionsViewOnCancel, 500, 500, () => { - // Clear login values (Mojang login) - // No cleanup needed for Microsoft. - loginUsername.value = '' - loginPassword.value = '' - if(loginOptionsViewCancelHandler != null){ - loginOptionsViewCancelHandler() - loginOptionsViewCancelHandler = null - } - }) -} \ No newline at end of file +const loginOptionsCancelContainer = document.getElementById('loginOptionCancelContainer') +const loginOptionMicrosoft = document.getElementById('loginOptionMicrosoft') +const loginOptionMojang = document.getElementById('loginOptionMojang') +const loginOptionsCancelButton = document.getElementById('loginOptionCancelButton') + +let loginOptionsCancellable = true + +let loginOptionsViewOnLoginSuccess +let loginOptionsViewOnLoginCancel +let loginOptionsViewOnCancel +let loginOptionsViewCancelHandler + +function loginOptionsCancelEnabled(val){ + if(val){ + $(loginOptionsCancelContainer).show() + } else { + $(loginOptionsCancelContainer).hide() + } +} + +loginOptionMicrosoft.onclick = (e) => { + switchView(getCurrentView(), VIEWS.waiting, 500, 500, () => { + ipcRenderer.send( + MSFT_OPCODE.OPEN_LOGIN, + loginOptionsViewOnLoginSuccess, + loginOptionsViewOnLoginCancel + ) + }) +} + +loginOptionMojang.onclick = (e) => { + switchView(getCurrentView(), VIEWS.login, 500, 500, () => { + loginViewOnSuccess = loginOptionsViewOnLoginSuccess + loginViewOnCancel = loginOptionsViewOnLoginCancel + loginCancelEnabled(true) + }) +} + +loginOptionOffline.onclick = (e) => { + switchView(getCurrentView(), VIEWS.loginOffline, 500, 500, () => { + loginViewOnSuccess = loginOptionsViewOnLoginSuccess + loginViewOnCancel = loginOptionsViewOnLoginCancel + loginCancelEnabled(true) + }) +} diff --git a/app/assets/js/scripts/uibinder.js b/app/assets/js/scripts/uibinder.js index d338514..d7b8d7b 100644 --- a/app/assets/js/scripts/uibinder.js +++ b/app/assets/js/scripts/uibinder.js @@ -1,450 +1,451 @@ -/** - * Initialize UI functions which depend on internal modules. - * Loaded after core UI functions are initialized in uicore.js. - */ -// Requirements -const path = require('path') - -const AuthManager = require('./assets/js/authmanager') -const ConfigManager = require('./assets/js/configmanager') -const DistroManager = require('./assets/js/distromanager') -const Lang = require('./assets/js/langloader') - -let rscShouldLoad = false -let fatalStartupError = false - -// Mapping of each view to their container IDs. -const VIEWS = { - landing: '#landingContainer', - loginOptions: '#loginOptionsContainer', - login: '#loginContainer', - settings: '#settingsContainer', - welcome: '#welcomeContainer', - waiting: '#waitingContainer' -} - -// The currently shown view container. -let currentView - -/** - * Switch launcher views. - * - * @param {string} current The ID of the current view container. - * @param {*} next The ID of the next view container. - * @param {*} currentFadeTime Optional. The fade out time for the current view. - * @param {*} nextFadeTime Optional. The fade in time for the next view. - * @param {*} onCurrentFade Optional. Callback function to execute when the current - * view fades out. - * @param {*} onNextFade Optional. Callback function to execute when the next view - * fades in. - */ -function switchView(current, next, currentFadeTime = 500, nextFadeTime = 500, onCurrentFade = () => {}, onNextFade = () => {}){ - currentView = next - $(`${current}`).fadeOut(currentFadeTime, () => { - onCurrentFade() - $(`${next}`).fadeIn(nextFadeTime, () => { - onNextFade() - }) - }) -} - -/** - * Get the currently shown view container. - * - * @returns {string} The currently shown view container. - */ -function getCurrentView(){ - return currentView -} - -function showMainUI(data){ - - if(!isDev){ - loggerAutoUpdater.log('Initializing..') - ipcRenderer.send('autoUpdateAction', 'initAutoUpdater', ConfigManager.getAllowPrerelease()) - } - - prepareSettings(true) - updateSelectedServer(data.getServer(ConfigManager.getSelectedServer())) - refreshServerStatus() - setTimeout(() => { - document.getElementById('frameBar').style.backgroundColor = 'rgba(0, 0, 0, 0.5)' - document.body.style.backgroundImage = `url('assets/images/backgrounds/${document.body.getAttribute('bkid')}.jpg')` - $('#main').show() - - const isLoggedIn = Object.keys(ConfigManager.getAuthAccounts()).length > 0 - - // If this is enabled in a development environment we'll get ratelimited. - // The relaunch frequency is usually far too high. - if(!isDev && isLoggedIn){ - validateSelectedAccount() - } - - if(ConfigManager.isFirstLaunch()){ - currentView = VIEWS.welcome - $(VIEWS.welcome).fadeIn(1000) - } else { - if(isLoggedIn){ - currentView = VIEWS.landing - $(VIEWS.landing).fadeIn(1000) - } else { - loginOptionsCancelEnabled(false) - loginOptionsViewOnLoginSuccess = VIEWS.landing - loginOptionsViewOnLoginCancel = VIEWS.loginOptions - currentView = VIEWS.loginOptions - $(VIEWS.loginOptions).fadeIn(1000) - } - } - - setTimeout(() => { - $('#loadingContainer').fadeOut(500, () => { - $('#loadSpinnerImage').removeClass('rotating') - }) - }, 250) - - }, 750) - // Disable tabbing to the news container. - initNews().then(() => { - $('#newsContainer *').attr('tabindex', '-1') - }) -} - -function showFatalStartupError(){ - setTimeout(() => { - $('#loadingContainer').fadeOut(250, () => { - document.getElementById('overlayContainer').style.background = 'none' - setOverlayContent( - 'Fatal Error: Unable to Load Distribution Index', - 'A connection could not be established to our servers to download the distribution index. No local copies were available to load.

The distribution index is an essential file which provides the latest server information. The launcher is unable to start without it. Ensure you are connected to the internet and relaunch the application.', - 'Close' - ) - setOverlayHandler(() => { - const window = remote.getCurrentWindow() - window.close() - }) - toggleOverlay(true) - }) - }, 750) -} - -/** - * Common functions to perform after refreshing the distro index. - * - * @param {Object} data The distro index object. - */ -function onDistroRefresh(data){ - updateSelectedServer(data.getServer(ConfigManager.getSelectedServer())) - refreshServerStatus() - initNews() - syncModConfigurations(data) -} - -/** - * Sync the mod configurations with the distro index. - * - * @param {Object} data The distro index object. - */ -function syncModConfigurations(data){ - - const syncedCfgs = [] - - for(let serv of data.getServers()){ - - const id = serv.getID() - const mdls = serv.getModules() - const cfg = ConfigManager.getModConfiguration(id) - - if(cfg != null){ - - const modsOld = cfg.mods - const mods = {} - - for(let mdl of mdls){ - const type = mdl.getType() - - if(type === DistroManager.Types.ForgeMod || type === DistroManager.Types.LiteMod || type === DistroManager.Types.LiteLoader){ - if(!mdl.getRequired().isRequired()){ - const mdlID = mdl.getVersionlessID() - if(modsOld[mdlID] == null){ - mods[mdlID] = scanOptionalSubModules(mdl.getSubModules(), mdl) - } else { - mods[mdlID] = mergeModConfiguration(modsOld[mdlID], scanOptionalSubModules(mdl.getSubModules(), mdl), false) - } - } else { - if(mdl.hasSubModules()){ - const mdlID = mdl.getVersionlessID() - const v = scanOptionalSubModules(mdl.getSubModules(), mdl) - if(typeof v === 'object'){ - if(modsOld[mdlID] == null){ - mods[mdlID] = v - } else { - mods[mdlID] = mergeModConfiguration(modsOld[mdlID], v, true) - } - } - } - } - } - } - - syncedCfgs.push({ - id, - mods - }) - - } else { - - const mods = {} - - for(let mdl of mdls){ - const type = mdl.getType() - if(type === DistroManager.Types.ForgeMod || type === DistroManager.Types.LiteMod || type === DistroManager.Types.LiteLoader){ - if(!mdl.getRequired().isRequired()){ - mods[mdl.getVersionlessID()] = scanOptionalSubModules(mdl.getSubModules(), mdl) - } else { - if(mdl.hasSubModules()){ - const v = scanOptionalSubModules(mdl.getSubModules(), mdl) - if(typeof v === 'object'){ - mods[mdl.getVersionlessID()] = v - } - } - } - } - } - - syncedCfgs.push({ - id, - mods - }) - - } - } - - ConfigManager.setModConfigurations(syncedCfgs) - ConfigManager.save() -} - -/** - * Recursively scan for optional sub modules. If none are found, - * this function returns a boolean. If optional sub modules do exist, - * a recursive configuration object is returned. - * - * @returns {boolean | Object} The resolved mod configuration. - */ -function scanOptionalSubModules(mdls, origin){ - if(mdls != null){ - const mods = {} - - for(let mdl of mdls){ - const type = mdl.getType() - // Optional types. - if(type === DistroManager.Types.ForgeMod || type === DistroManager.Types.LiteMod || type === DistroManager.Types.LiteLoader){ - // It is optional. - if(!mdl.getRequired().isRequired()){ - mods[mdl.getVersionlessID()] = scanOptionalSubModules(mdl.getSubModules(), mdl) - } else { - if(mdl.hasSubModules()){ - const v = scanOptionalSubModules(mdl.getSubModules(), mdl) - if(typeof v === 'object'){ - mods[mdl.getVersionlessID()] = v - } - } - } - } - } - - if(Object.keys(mods).length > 0){ - const ret = { - mods - } - if(!origin.getRequired().isRequired()){ - ret.value = origin.getRequired().isDefault() - } - return ret - } - } - return origin.getRequired().isDefault() -} - -/** - * Recursively merge an old configuration into a new configuration. - * - * @param {boolean | Object} o The old configuration value. - * @param {boolean | Object} n The new configuration value. - * @param {boolean} nReq If the new value is a required mod. - * - * @returns {boolean | Object} The merged configuration. - */ -function mergeModConfiguration(o, n, nReq = false){ - if(typeof o === 'boolean'){ - if(typeof n === 'boolean') return o - else if(typeof n === 'object'){ - if(!nReq){ - n.value = o - } - return n - } - } else if(typeof o === 'object'){ - if(typeof n === 'boolean') return typeof o.value !== 'undefined' ? o.value : true - else if(typeof n === 'object'){ - if(!nReq){ - n.value = typeof o.value !== 'undefined' ? o.value : true - } - - const newMods = Object.keys(n.mods) - for(let i=0; i${selectedAcc.displayName}. Please ${accLen > 0 ? 'select another account or ' : ''} login again.`, - 'Login', - 'Select Another Account' - ) - setOverlayHandler(() => { - - const isMicrosoft = selectedAcc.type === 'microsoft' - - if(isMicrosoft) { - // Empty for now - } else { - // Mojang - // For convenience, pre-populate the username of the account. - document.getElementById('loginUsername').value = selectedAcc.username - validateEmail(selectedAcc.username) - } - - loginOptionsViewOnLoginSuccess = getCurrentView() - loginOptionsViewOnLoginCancel = VIEWS.loginOptions - - if(accLen > 0) { - loginOptionsViewOnCancel = getCurrentView() - loginOptionsViewCancelHandler = () => { - if(isMicrosoft) { - ConfigManager.addMicrosoftAuthAccount( - selectedAcc.uuid, - selectedAcc.accessToken, - selectedAcc.username, - selectedAcc.expiresAt, - selectedAcc.microsoft.access_token, - selectedAcc.microsoft.refresh_token, - selectedAcc.microsoft.expires_at - ) - } else { - ConfigManager.addMojangAuthAccount(selectedAcc.uuid, selectedAcc.accessToken, selectedAcc.username, selectedAcc.displayName) - } - ConfigManager.save() - validateSelectedAccount() - } - loginOptionsCancelEnabled(true) - } else { - loginOptionsCancelEnabled(false) - } - toggleOverlay(false) - switchView(getCurrentView(), VIEWS.loginOptions) - }) - setDismissHandler(() => { - if(accLen > 1){ - prepareAccountSelectionList() - $('#overlayContent').fadeOut(250, () => { - bindOverlayKeys(true, 'accountSelectContent', true) - $('#accountSelectContent').fadeIn(250) - }) - } else { - const accountsObj = ConfigManager.getAuthAccounts() - const accounts = Array.from(Object.keys(accountsObj), v => accountsObj[v]) - // This function validates the account switch. - setSelectedAccount(accounts[0].uuid) - toggleOverlay(false) - } - }) - toggleOverlay(true, accLen > 0) - } else { - return true - } - } else { - return true - } -} - -/** - * Temporary function to update the selected account along - * with the relevent UI elements. - * - * @param {string} uuid The UUID of the account. - */ -function setSelectedAccount(uuid){ - const authAcc = ConfigManager.setSelectedAccount(uuid) - ConfigManager.save() - updateSelectedAccount(authAcc) - validateSelectedAccount() -} - -// Synchronous Listener -document.addEventListener('readystatechange', function(){ - - if (document.readyState === 'interactive' || document.readyState === 'complete'){ - if(rscShouldLoad){ - rscShouldLoad = false - if(!fatalStartupError){ - const data = DistroManager.getDistribution() - showMainUI(data) - } else { - showFatalStartupError() - } - } - } - -}, false) - -// Actions that must be performed after the distribution index is downloaded. -ipcRenderer.on('distributionIndexDone', (event, res) => { - if(res) { - const data = DistroManager.getDistribution() - syncModConfigurations(data) - if(document.readyState === 'interactive' || document.readyState === 'complete'){ - showMainUI(data) - } else { - rscShouldLoad = true - } - } else { - fatalStartupError = true - if(document.readyState === 'interactive' || document.readyState === 'complete'){ - showFatalStartupError() - } else { - rscShouldLoad = true - } - } -}) +/** + * Initialize UI functions which depend on internal modules. + * Loaded after core UI functions are initialized in uicore.js. + */ +// Requirements +const path = require('path') + +const AuthManager = require('./assets/js/authmanager') +const ConfigManager = require('./assets/js/configmanager') +const DistroManager = require('./assets/js/distromanager') +const Lang = require('./assets/js/langloader') + +let rscShouldLoad = false +let fatalStartupError = false + +// Mapping of each view to their container IDs. +const VIEWS = { + landing: '#landingContainer', + loginOptions: '#loginOptionsContainer', + login: '#loginContainer', + loginOffline: '#loginOfflineContainer', + settings: '#settingsContainer', + welcome: '#welcomeContainer', + waiting: '#waitingContainer' +} + +// The currently shown view container. +let currentView + +/** + * Switch launcher views. + * + * @param {string} current The ID of the current view container. + * @param {*} next The ID of the next view container. + * @param {*} currentFadeTime Optional. The fade out time for the current view. + * @param {*} nextFadeTime Optional. The fade in time for the next view. + * @param {*} onCurrentFade Optional. Callback function to execute when the current + * view fades out. + * @param {*} onNextFade Optional. Callback function to execute when the next view + * fades in. + */ +function switchView(current, next, currentFadeTime = 500, nextFadeTime = 500, onCurrentFade = () => {}, onNextFade = () => {}){ + currentView = next + $(`${current}`).fadeOut(currentFadeTime, () => { + onCurrentFade() + $(`${next}`).fadeIn(nextFadeTime, () => { + onNextFade() + }) + }) +} + +/** + * Get the currently shown view container. + * + * @returns {string} The currently shown view container. + */ +function getCurrentView(){ + return currentView +} + +function showMainUI(data){ + + if(!isDev){ + loggerAutoUpdater.log('Initializing..') + ipcRenderer.send('autoUpdateAction', 'initAutoUpdater', ConfigManager.getAllowPrerelease()) + } + + prepareSettings(true) + updateSelectedServer(data.getServer(ConfigManager.getSelectedServer())) + refreshServerStatus() + setTimeout(() => { + document.getElementById('frameBar').style.backgroundColor = 'rgba(0, 0, 0, 0.5)' + document.body.style.backgroundImage = `url('assets/images/backgrounds/${document.body.getAttribute('bkid')}.jpg')` + $('#main').show() + + const isLoggedIn = Object.keys(ConfigManager.getAuthAccounts()).length > 0 + + // If this is enabled in a development environment we'll get ratelimited. + // The relaunch frequency is usually far too high. + if(!isDev && isLoggedIn){ + validateSelectedAccount() + } + + if(ConfigManager.isFirstLaunch()){ + currentView = VIEWS.welcome + $(VIEWS.welcome).fadeIn(1000) + } else { + if(isLoggedIn){ + currentView = VIEWS.landing + $(VIEWS.landing).fadeIn(1000) + } else { + loginOptionsCancelEnabled(false) + loginOptionsViewOnLoginSuccess = VIEWS.landing + loginOptionsViewOnLoginCancel = VIEWS.loginOptions + currentView = VIEWS.loginOptions + $(VIEWS.loginOptions).fadeIn(1000) + } + } + + setTimeout(() => { + $('#loadingContainer').fadeOut(500, () => { + $('#loadSpinnerImage').removeClass('rotating') + }) + }, 250) + + }, 750) + // Disable tabbing to the news container. + initNews().then(() => { + $('#newsContainer *').attr('tabindex', '-1') + }) +} + +function showFatalStartupError(){ + setTimeout(() => { + $('#loadingContainer').fadeOut(250, () => { + document.getElementById('overlayContainer').style.background = 'none' + setOverlayContent( + 'Fatal Error: Unable to Load Distribution Index', + 'A connection could not be established to our servers to download the distribution index. No local copies were available to load.

The distribution index is an essential file which provides the latest server information. The launcher is unable to start without it. Ensure you are connected to the internet and relaunch the application.', + 'Close' + ) + setOverlayHandler(() => { + const window = remote.getCurrentWindow() + window.close() + }) + toggleOverlay(true) + }) + }, 750) +} + +/** + * Common functions to perform after refreshing the distro index. + * + * @param {Object} data The distro index object. + */ +function onDistroRefresh(data){ + updateSelectedServer(data.getServer(ConfigManager.getSelectedServer())) + refreshServerStatus() + initNews() + syncModConfigurations(data) +} + +/** + * Sync the mod configurations with the distro index. + * + * @param {Object} data The distro index object. + */ +function syncModConfigurations(data){ + + const syncedCfgs = [] + + for(let serv of data.getServers()){ + + const id = serv.getID() + const mdls = serv.getModules() + const cfg = ConfigManager.getModConfiguration(id) + + if(cfg != null){ + + const modsOld = cfg.mods + const mods = {} + + for(let mdl of mdls){ + const type = mdl.getType() + + if(type === DistroManager.Types.ForgeMod || type === DistroManager.Types.LiteMod || type === DistroManager.Types.LiteLoader){ + if(!mdl.getRequired().isRequired()){ + const mdlID = mdl.getVersionlessID() + if(modsOld[mdlID] == null){ + mods[mdlID] = scanOptionalSubModules(mdl.getSubModules(), mdl) + } else { + mods[mdlID] = mergeModConfiguration(modsOld[mdlID], scanOptionalSubModules(mdl.getSubModules(), mdl), false) + } + } else { + if(mdl.hasSubModules()){ + const mdlID = mdl.getVersionlessID() + const v = scanOptionalSubModules(mdl.getSubModules(), mdl) + if(typeof v === 'object'){ + if(modsOld[mdlID] == null){ + mods[mdlID] = v + } else { + mods[mdlID] = mergeModConfiguration(modsOld[mdlID], v, true) + } + } + } + } + } + } + + syncedCfgs.push({ + id, + mods + }) + + } else { + + const mods = {} + + for(let mdl of mdls){ + const type = mdl.getType() + if(type === DistroManager.Types.ForgeMod || type === DistroManager.Types.LiteMod || type === DistroManager.Types.LiteLoader){ + if(!mdl.getRequired().isRequired()){ + mods[mdl.getVersionlessID()] = scanOptionalSubModules(mdl.getSubModules(), mdl) + } else { + if(mdl.hasSubModules()){ + const v = scanOptionalSubModules(mdl.getSubModules(), mdl) + if(typeof v === 'object'){ + mods[mdl.getVersionlessID()] = v + } + } + } + } + } + + syncedCfgs.push({ + id, + mods + }) + + } + } + + ConfigManager.setModConfigurations(syncedCfgs) + ConfigManager.save() +} + +/** + * Recursively scan for optional sub modules. If none are found, + * this function returns a boolean. If optional sub modules do exist, + * a recursive configuration object is returned. + * + * @returns {boolean | Object} The resolved mod configuration. + */ +function scanOptionalSubModules(mdls, origin){ + if(mdls != null){ + const mods = {} + + for(let mdl of mdls){ + const type = mdl.getType() + // Optional types. + if(type === DistroManager.Types.ForgeMod || type === DistroManager.Types.LiteMod || type === DistroManager.Types.LiteLoader){ + // It is optional. + if(!mdl.getRequired().isRequired()){ + mods[mdl.getVersionlessID()] = scanOptionalSubModules(mdl.getSubModules(), mdl) + } else { + if(mdl.hasSubModules()){ + const v = scanOptionalSubModules(mdl.getSubModules(), mdl) + if(typeof v === 'object'){ + mods[mdl.getVersionlessID()] = v + } + } + } + } + } + + if(Object.keys(mods).length > 0){ + const ret = { + mods + } + if(!origin.getRequired().isRequired()){ + ret.value = origin.getRequired().isDefault() + } + return ret + } + } + return origin.getRequired().isDefault() +} + +/** + * Recursively merge an old configuration into a new configuration. + * + * @param {boolean | Object} o The old configuration value. + * @param {boolean | Object} n The new configuration value. + * @param {boolean} nReq If the new value is a required mod. + * + * @returns {boolean | Object} The merged configuration. + */ +function mergeModConfiguration(o, n, nReq = false){ + if(typeof o === 'boolean'){ + if(typeof n === 'boolean') return o + else if(typeof n === 'object'){ + if(!nReq){ + n.value = o + } + return n + } + } else if(typeof o === 'object'){ + if(typeof n === 'boolean') return typeof o.value !== 'undefined' ? o.value : true + else if(typeof n === 'object'){ + if(!nReq){ + n.value = typeof o.value !== 'undefined' ? o.value : true + } + + const newMods = Object.keys(n.mods) + for(let i=0; i${selectedAcc.displayName}. Please ${accLen > 0 ? 'select another account or ' : ''} login again.`, + 'Login', + 'Select Another Account' + ) + setOverlayHandler(() => { + + const isMicrosoft = selectedAcc.type === 'microsoft' + + if(isMicrosoft) { + // Empty for now + } else { + // Mojang + // For convenience, pre-populate the username of the account. + document.getElementById('loginUsername').value = selectedAcc.username + validateEmail(selectedAcc.username) + } + + loginOptionsViewOnLoginSuccess = getCurrentView() + loginOptionsViewOnLoginCancel = VIEWS.loginOptions + + if(accLen > 0) { + loginOptionsViewOnCancel = getCurrentView() + loginOptionsViewCancelHandler = () => { + if(isMicrosoft) { + ConfigManager.addMicrosoftAuthAccount( + selectedAcc.uuid, + selectedAcc.accessToken, + selectedAcc.username, + selectedAcc.expiresAt, + selectedAcc.microsoft.access_token, + selectedAcc.microsoft.refresh_token, + selectedAcc.microsoft.expires_at + ) + } else { + ConfigManager.addMojangAuthAccount(selectedAcc.uuid, selectedAcc.accessToken, selectedAcc.username, selectedAcc.displayName) + } + ConfigManager.save() + validateSelectedAccount() + } + loginOptionsCancelEnabled(true) + } else { + loginOptionsCancelEnabled(false) + } + toggleOverlay(false) + switchView(getCurrentView(), VIEWS.loginOptions) + }) + setDismissHandler(() => { + if(accLen > 1){ + prepareAccountSelectionList() + $('#overlayContent').fadeOut(250, () => { + bindOverlayKeys(true, 'accountSelectContent', true) + $('#accountSelectContent').fadeIn(250) + }) + } else { + const accountsObj = ConfigManager.getAuthAccounts() + const accounts = Array.from(Object.keys(accountsObj), v => accountsObj[v]) + // This function validates the account switch. + setSelectedAccount(accounts[0].uuid) + toggleOverlay(false) + } + }) + toggleOverlay(true, accLen > 0) + } else { + return true + } + } else { + return true + } +} + +/** + * Temporary function to update the selected account along + * with the relevent UI elements. + * + * @param {string} uuid The UUID of the account. + */ +function setSelectedAccount(uuid){ + const authAcc = ConfigManager.setSelectedAccount(uuid) + ConfigManager.save() + updateSelectedAccount(authAcc) + validateSelectedAccount() +} + +// Synchronous Listener +document.addEventListener('readystatechange', function(){ + + if (document.readyState === 'interactive' || document.readyState === 'complete'){ + if(rscShouldLoad){ + rscShouldLoad = false + if(!fatalStartupError){ + const data = DistroManager.getDistribution() + showMainUI(data) + } else { + showFatalStartupError() + } + } + } + +}, false) + +// Actions that must be performed after the distribution index is downloaded. +ipcRenderer.on('distributionIndexDone', (event, res) => { + if(res) { + const data = DistroManager.getDistribution() + syncModConfigurations(data) + if(document.readyState === 'interactive' || document.readyState === 'complete'){ + showMainUI(data) + } else { + rscShouldLoad = true + } + } else { + fatalStartupError = true + if(document.readyState === 'interactive' || document.readyState === 'complete'){ + showFatalStartupError() + } else { + rscShouldLoad = true + } + } +}) diff --git a/app/loginOffline.ejs b/app/loginOffline.ejs new file mode 100644 index 0000000..0adfbbf --- /dev/null +++ b/app/loginOffline.ejs @@ -0,0 +1,25 @@ + \ No newline at end of file diff --git a/app/loginOptions.ejs b/app/loginOptions.ejs index 36af37e..effbaf9 100644 --- a/app/loginOptions.ejs +++ b/app/loginOptions.ejs @@ -1,34 +1,39 @@ -