mirror of
https://github.com/dscalzi/HeliosLauncher.git
synced 2024-12-22 11:42:14 -08:00
Added UI and implementation for the account settings tab.
Features: * Add a new account. * Switch accounts. * Log out of an account. Also added a cancel button to the login UI which is only shown when a user is adding an account. In that case, the operation should be and is cancellable.
This commit is contained in:
parent
2dcbb45bdb
commit
91c842dd40
@ -387,6 +387,68 @@ body, button {
|
||||
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;
|
||||
@ -816,6 +878,7 @@ body, button {
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
/* Main settings container. */
|
||||
#settingsContainer {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
@ -823,6 +886,7 @@ body, button {
|
||||
background: rgba(0, 0, 0, 0.50);
|
||||
}
|
||||
|
||||
/* Left hand side of the settings UI, for navigation. */
|
||||
#settingsContainerLeft {
|
||||
height: 100%;
|
||||
width: 25%;
|
||||
@ -830,20 +894,22 @@ body, button {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Settings navigation container. */
|
||||
#settingsNavContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* Navigation header styles. */
|
||||
#settingsNavHeader {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#settingsNavHeaderText {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
/* Navigation items outer container. */
|
||||
#settingsNavItemsContainer {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
@ -852,11 +918,13 @@ body, button {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* Navigation items content container. */
|
||||
#settingsNavItemsContent {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
/* Navigation item shared styles. */
|
||||
.settingsNavItem {
|
||||
background: none;
|
||||
border: none;
|
||||
@ -880,23 +948,36 @@ body, button {
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
/* Right hand side of the settings container, for tabs. */
|
||||
#settingsContainerRight {
|
||||
height: 100%;
|
||||
width: 75%;
|
||||
padding: 5% 0%;
|
||||
padding-top: 5%;
|
||||
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);
|
||||
}
|
||||
|
||||
/* Tab header shared styles. */
|
||||
.settingsTabHeader {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.settingsTabHeaderText {
|
||||
font-size: 20px;
|
||||
font-family: 'Avenir Medium';
|
||||
@ -905,6 +986,163 @@ body, button {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* * *
|
||||
* Settings View (Account Tab)
|
||||
* * */
|
||||
|
||||
/* Add account button styles. */
|
||||
#settingsAddAccountContainer {
|
||||
margin-top: 20px;
|
||||
}
|
||||
#settingsAddAccount {
|
||||
background: rgba(0, 0, 0, 0.25);
|
||||
border: 1px solid rgba(126, 126, 126, 0.57);
|
||||
border-radius: 3px;
|
||||
height: 50px;
|
||||
width: 75%;
|
||||
text-align: left;
|
||||
padding: 0px 50px;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
transition: 0.25s ease;
|
||||
}
|
||||
#settingsAddAccount:hover,
|
||||
#settingsAddAccount:focus {
|
||||
background: rgba(54, 54, 54, 0.25);
|
||||
text-shadow: 0px 0px 20px white;
|
||||
}
|
||||
|
||||
/* Settings auth accounts header. */
|
||||
#settingsCurrentAccountsHeader {
|
||||
margin: 20px 0px;
|
||||
}
|
||||
#settingsCurrentAccountsHeaderText {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
width: 75%;
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* Landing View (Structural Styles) *
|
||||
|
@ -116,6 +116,7 @@ document.getElementById('launch_button').addEventListener('click', function(e){
|
||||
|
||||
// Bind settings button
|
||||
document.getElementById('settingsMediaButton').onclick = (e) => {
|
||||
prepareSettings()
|
||||
switchView(getCurrentView(), VIEWS.settings)
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,8 @@ 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')
|
||||
@ -139,6 +141,7 @@ function loginLoading(v){
|
||||
*/
|
||||
function formDisabled(v){
|
||||
loginDisabled(v)
|
||||
loginCancelButton.disabled = v
|
||||
loginUsername.disabled = v
|
||||
loginPassword.disabled = v
|
||||
if(v){
|
||||
@ -215,6 +218,23 @@ function resolveError(err){
|
||||
}
|
||||
}
|
||||
|
||||
let loginViewOnSuccess = VIEWS.landing
|
||||
let loginViewOnCancel = VIEWS.settings
|
||||
|
||||
function loginCancelEnabled(val){
|
||||
if(val){
|
||||
$(loginCancelContainer).show()
|
||||
} else {
|
||||
$(loginCancelContainer).hide()
|
||||
}
|
||||
}
|
||||
|
||||
loginCancelButton.onclick = (e) => {
|
||||
switchView(getCurrentView(), loginViewOnCancel, 500, 500, () => {
|
||||
loginCancelEnabled(false)
|
||||
})
|
||||
}
|
||||
|
||||
// Disable default form behavior.
|
||||
loginForm.onsubmit = () => { return false }
|
||||
|
||||
@ -233,7 +253,13 @@ loginButton.addEventListener('click', () => {
|
||||
$('.checkmark').toggle()
|
||||
//console.log(value)
|
||||
setTimeout(() => {
|
||||
switchView(VIEWS.login, VIEWS.landing, 500, 500, () => {
|
||||
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.
|
||||
loginUsername.value = ''
|
||||
loginPassword.value = ''
|
||||
$('.circle-loader').toggleClass('load-complete')
|
||||
|
@ -1,5 +1,15 @@
|
||||
const settingsAddAccount = document.getElementById('settingsAddAccount')
|
||||
const settingsCurrentAccounts = document.getElementById('settingsCurrentAccounts')
|
||||
|
||||
/**
|
||||
* General Settings Functions
|
||||
*/
|
||||
|
||||
let selectedTab = 'settingsTabAccount'
|
||||
|
||||
/**
|
||||
* Bind functionality for the settings navigation items.
|
||||
*/
|
||||
function setupSettingsTabs(){
|
||||
Array.from(document.getElementsByClassName('settingsNavItem')).map((val) => {
|
||||
val.onclick = (e) => {
|
||||
@ -22,4 +32,148 @@ function setupSettingsTabs(){
|
||||
})
|
||||
}
|
||||
|
||||
setupSettingsTabs()
|
||||
/**
|
||||
* Account Management Tab
|
||||
*/
|
||||
|
||||
// Bind the add account button.
|
||||
settingsAddAccount.onclick = (e) => {
|
||||
switchView(getCurrentView(), VIEWS.login, 500, 500, () => {
|
||||
loginViewOnCancel = VIEWS.settings
|
||||
loginViewOnSuccess = VIEWS.settings
|
||||
loginCancelEnabled(true)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind functionality for the account selection buttons. If another account
|
||||
* is selected, the UI of the previously selected account will be updated.
|
||||
*/
|
||||
function bindAuthAccountSelect(){
|
||||
Array.from(document.getElementsByClassName('settingsAuthAccountSelect')).map((val) => {
|
||||
val.onclick = (e) => {
|
||||
if(val.hasAttribute('selected')){
|
||||
return
|
||||
}
|
||||
const selectBtns = document.getElementsByClassName('settingsAuthAccountSelect')
|
||||
for(let i=0; i<selectBtns.length; i++){
|
||||
if(selectBtns[i].hasAttribute('selected')){
|
||||
selectBtns[i].removeAttribute('selected')
|
||||
selectBtns[i].innerHTML = 'Select Account'
|
||||
}
|
||||
}
|
||||
val.setAttribute('selected', '')
|
||||
val.innerHTML = 'Selected Account ✔'
|
||||
ConfigManager.setSelectedAccount(val.closest('.settingsAuthAccount').getAttribute('uuid'))
|
||||
ConfigManager.save()
|
||||
updateSelectedAccount(ConfigManager.getSelectedAccount())
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind functionality for the log out button. If the logged out account was
|
||||
* the selected account, another account will be selected and the UI will
|
||||
* be updated accordingly.
|
||||
*/
|
||||
function bindAuthAccountLogOut(){
|
||||
Array.from(document.getElementsByClassName('settingsAuthAccountLogOut')).map((val) => {
|
||||
val.onclick = (e) => {
|
||||
const parent = val.closest('.settingsAuthAccount')
|
||||
const uuid = parent.getAttribute('uuid')
|
||||
const prevSelAcc = ConfigManager.getSelectedAccount()
|
||||
AuthManager.removeAccount(uuid).then(() => {
|
||||
if(uuid === prevSelAcc.uuid){
|
||||
const selAcc = ConfigManager.getSelectedAccount()
|
||||
refreshAuthAccountSelected(selAcc.uuid)
|
||||
updateSelectedAccount(selAcc)
|
||||
}
|
||||
})
|
||||
$(parent).fadeOut(250, () => {
|
||||
parent.remove()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Refreshes the status of the selected account on the auth account
|
||||
* elements.
|
||||
*
|
||||
* @param {string} uuid The UUID of the new selected account.
|
||||
*/
|
||||
function refreshAuthAccountSelected(uuid){
|
||||
Array.from(document.getElementsByClassName('settingsAuthAccount')).map((val) => {
|
||||
const selBtn = val.getElementsByClassName('settingsAuthAccountSelect')[0]
|
||||
if(uuid === val.getAttribute('uuid')){
|
||||
selBtn.setAttribute('selected', '')
|
||||
selBtn.innerHTML = 'Selected Account ✔'
|
||||
} else {
|
||||
if(selBtn.hasAttribute('selected')){
|
||||
selBtn.removeAttribute('selected')
|
||||
}
|
||||
selBtn.innerHTML = 'Select Account'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Add auth account elements for each one stored in the authentication database.
|
||||
*/
|
||||
function populateAuthAccounts(){
|
||||
const authAccounts = ConfigManager.getAuthAccounts()
|
||||
const authKeys = Object.keys(authAccounts)
|
||||
const selectedUUID = ConfigManager.getSelectedAccount().uuid
|
||||
|
||||
let authAccountStr = ``
|
||||
|
||||
authKeys.map((val) => {
|
||||
const acc = authAccounts[val]
|
||||
authAccountStr += `<div class="settingsAuthAccount" uuid="${acc.uuid}">
|
||||
<div class="settingsAuthAccountLeft">
|
||||
<img class="settingsAuthAccountImage" alt="${acc.displayName}" src="https://crafatar.com/renders/body/${acc.uuid}?scale=3&default=MHF_Steve&overlay">
|
||||
</div>
|
||||
<div class="settingsAuthAccountRight">
|
||||
<div class="settingsAuthAccountDetails">
|
||||
<div class="settingsAuthAccountDetailPane">
|
||||
<div class="settingsAuthAccountDetailTitle">Username</div>
|
||||
<div class="settingsAuthAccountDetailValue">${acc.displayName}</div>
|
||||
</div>
|
||||
<div class="settingsAuthAccountDetailPane">
|
||||
<div class="settingsAuthAccountDetailTitle">${acc.displayName === acc.username ? 'UUID' : 'Email'}</div>
|
||||
<div class="settingsAuthAccountDetailValue">${acc.displayName === acc.username ? acc.uuid : acc.username}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="settingsAuthAccountActions">
|
||||
<button class="settingsAuthAccountSelect" ${selectedUUID === acc.uuid ? 'selected>Selected Account ✔' : '>Select Account'}</button>
|
||||
<div class="settingsAuthAccountWrapper">
|
||||
<button class="settingsAuthAccountLogOut">Log Out</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>`
|
||||
})
|
||||
|
||||
settingsCurrentAccounts.innerHTML = authAccountStr
|
||||
}
|
||||
|
||||
function prepareAccountsTab() {
|
||||
populateAuthAccounts()
|
||||
bindAuthAccountSelect()
|
||||
bindAuthAccountLogOut()
|
||||
}
|
||||
|
||||
/**
|
||||
* Settings preparation functions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Prepare the entire settings UI.
|
||||
*/
|
||||
function prepareSettings() {
|
||||
setupSettingsTabs()
|
||||
prepareAccountsTab()
|
||||
}
|
||||
|
||||
// Prepare the settings UI on startup.
|
||||
prepareSettings()
|
@ -145,6 +145,7 @@ async function validateSelectedAccount(){
|
||||
setOverlayHandler(() => {
|
||||
document.getElementById('loginUsername').value = selectedAcc.username
|
||||
validateEmail(selectedAcc.username)
|
||||
loginViewOnSuccess = getCurrentView()
|
||||
switchView(getCurrentView(), VIEWS.login)
|
||||
toggleOverlay(false)
|
||||
})
|
||||
|
@ -1,4 +1,10 @@
|
||||
<div id="loginContainer" style="display: none;">
|
||||
<div id="loginCancelContainer" style="display: none;">
|
||||
<button id="loginCancelButton">
|
||||
<div id="loginCancelIcon">X</div>
|
||||
<span id="loginCancelText">Cancel</span>
|
||||
</button>
|
||||
</div>
|
||||
<div id="loginContent">
|
||||
<form id="loginForm">
|
||||
<img id="loginImageSeal" src="assets/images/WesterosSealCircle.png"/>
|
||||
|
@ -20,6 +20,17 @@
|
||||
<span class="settingsTabHeaderText">Account Settings</span>
|
||||
<span class="settingsTabHeaderDesc">Add new accounts or manage existing ones.</span>
|
||||
</div>
|
||||
<div id="settingsAddAccountContainer">
|
||||
<button id="settingsAddAccount">
|
||||
<span id="settingsAddAccountText">+ Add Account</span>
|
||||
</button>
|
||||
</div>
|
||||
<div id="settingsCurrentAccountsHeader">
|
||||
<span id="settingsCurrentAccountsHeaderText">Current Accounts</span>
|
||||
</div>
|
||||
<div id="settingsCurrentAccounts">
|
||||
<!-- Auth accounts populated here. -->
|
||||
</div>
|
||||
</div>
|
||||
<div id="settingsTabMinecraft" class="settingsTab" style="display: none;">
|
||||
<div class="settingsTabHeader">
|
||||
|
Loading…
Reference in New Issue
Block a user