Add landing account menu
Some checks failed
Build / release (macos-latest) (push) Has been cancelled
Build / release (ubuntu-latest) (push) Has been cancelled
Build / release (windows-latest) (push) Has been cancelled
Windows Smoke Test / windows-smoke (push) Has been cancelled

This commit is contained in:
2026-05-04 14:27:09 +09:00
parent de47cb219a
commit f6f716acd0
6 changed files with 169 additions and 50 deletions

View File

@@ -2955,19 +2955,36 @@ input:checked + .toggleSwitchSlider:before {
flex-direction: column;
position: relative;
top: 50px;
align-items: flex-start;
align-items: flex-end;
height: calc(100% - 50px);
}
/* Right hand user content container. */
#user_content {
display: flex;
align-items: center;
flex-direction: column;
align-items: flex-end;
justify-content: center;
gap: 10px;
box-sizing: border-box;
position: relative;
}
#avatarMenuButton {
padding: 0;
border: none;
background: none;
cursor: pointer;
}
#avatarMenuButton:focus {
outline: none;
}
#avatarMenuButton:disabled {
cursor: default;
}
/* User profile avatar container. */
#avatarContainer {
border-radius: 50%;
@@ -2981,47 +2998,44 @@ input:checked + .toggleSwitchSlider:before {
position: relative;
background-position: center;
background-repeat: no-repeat;
background-size: contain;
background-size: cover;
}
/* Avatar edit overlay. */
#avatarOverlay {
opacity: 0;
position: absolute;
z-index: 1;
#avatarMenuButton:hover #avatarContainer,
#avatarMenuButton[aria-expanded="true"] #avatarContainer,
#avatarMenuButton:focus #avatarContainer {
border-color: #f1c15a;
box-shadow: 0px 0px 18px 0px rgba(241, 193, 90, 0.55);
}
#accountMenu {
min-width: 190px;
padding: 14px;
border-radius: 16px;
border: 1px solid rgba(255, 255, 255, 0.08);
background: rgba(10, 10, 10, 0.9);
backdrop-filter: blur(12px);
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);
flex-direction: column;
align-items: stretch;
gap: 12px;
box-shadow: 0 18px 40px rgba(0, 0, 0, 0.28);
}
/* 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;
#accountMenu[hidden] {
display: none;
}
#accountMenuName {
font-size: 13px;
font-weight: 800;
letter-spacing: 0.04em;
color: #ffffff;
text-align: right;
-webkit-user-select: initial;
}
#accountMenuLogoutButton {
width: 100%;
}
/* Social media icon content container. */

View File

@@ -1,6 +1,7 @@
/**
* Script for landing.ejs
*/
(() => {
// Requirements
const { URL } = require('url')
const {
@@ -28,6 +29,7 @@ const {
} = require('helios-core/java')
// Internal Requirements
const AuthManager = require('./assets/js/authmanager')
const DiscordWrapper = require('./assets/js/discordwrapper')
const ProcessBuilder = require('./assets/js/processbuilder')
@@ -38,10 +40,79 @@ const launch_progress = document.getElementById('launch_progress')
const launch_progress_label = document.getElementById('launch_progress_label')
const launch_details_text = document.getElementById('launch_details_text')
const server_selection_button = document.getElementById('server_selection_button')
const user_text = document.getElementById('user_text')
const avatarMenuButton = document.getElementById('avatarMenuButton')
const avatarContainer = document.getElementById('avatarContainer')
const accountMenu = document.getElementById('accountMenu')
const accountMenuName = document.getElementById('accountMenuName')
const accountMenuLogoutButton = document.getElementById('accountMenuLogoutButton')
const loggerLanding = LoggerUtil.getLogger('Landing')
function setAccountMenuOpen(open){
if(open && ConfigManager.getSelectedAccount() == null){
return
}
avatarMenuButton.setAttribute('aria-expanded', open ? 'true' : 'false')
if(open){
accountMenu.removeAttribute('hidden')
} else {
accountMenu.setAttribute('hidden', '')
}
}
function showAccountError(message){
if(typeof setOverlayContent === 'function'){
setOverlayContent(
Lang.queryJS('settings.msftLogout.errorTitle'),
message,
Lang.queryJS('landing.launch.okay')
)
setOverlayHandler(() => toggleOverlay(false))
toggleOverlay(true)
}
}
async function logoutSelectedAccount(){
const selectedAccount = ConfigManager.getSelectedAccount()
if(selectedAccount == null){
return
}
const accountCount = Object.keys(ConfigManager.getAuthAccounts()).length
accountMenuLogoutButton.disabled = true
try {
if(selectedAccount.type === 'microsoft'){
await AuthManager.removeMicrosoftAccount(selectedAccount.uuid)
} else {
await AuthManager.removeMojangAccount(selectedAccount.uuid)
}
setAccountMenuOpen(false)
const nextAccount = ConfigManager.getSelectedAccount()
if(nextAccount != null){
updateSelectedAccount(nextAccount)
validateSelectedAccount()
} else if(accountCount === 1){
updateSelectedAccount(null)
loginOptionsCancelEnabled(false)
loginOptionsViewOnLoginSuccess = VIEWS.landing
loginOptionsViewOnLoginCancel = VIEWS.loginOptions
switchView(getCurrentView(), VIEWS.loginOptions)
}
} catch (error) {
console.error(error)
const message = selectedAccount.type === 'microsoft'
? Lang.queryJS('settings.msftLogout.errorMessage')
: Lang.queryJS('landing.selectedAccount.logoutFailed')
showAccountError(message)
} finally {
accountMenuLogoutButton.disabled = false
}
}
/* Launch Progress Wrapper Functions */
/**
@@ -147,13 +218,24 @@ document.getElementById('landingInstallButton').onclick = async () => {
switchView(getCurrentView(), VIEWS.install)
}
// Bind avatar overlay button.
document.getElementById('avatarOverlay').onclick = async e => {
await prepareSettings()
switchView(getCurrentView(), VIEWS.settings, 500, 500, () => {
settingsNavItemListener(document.getElementById('settingsNavAccount'), false)
avatarMenuButton.addEventListener('click', (e) => {
e.stopPropagation()
setAccountMenuOpen(accountMenu.hasAttribute('hidden'))
})
accountMenu.addEventListener('click', (e) => {
e.stopPropagation()
})
accountMenuLogoutButton.addEventListener('click', async () => {
await logoutSelectedAccount()
})
document.addEventListener('click', () => {
if(!accountMenu.hasAttribute('hidden')){
setAccountMenuOpen(false)
}
})
// Bind selected account
function updateSelectedAccount(authUser){
@@ -163,10 +245,16 @@ function updateSelectedAccount(authUser){
username = authUser.displayName
}
if(authUser.uuid != null){
document.getElementById('avatarContainer').style.backgroundImage = `url('https://mc-heads.net/body/${authUser.uuid}/right')`
avatarContainer.style.backgroundImage = `url('https://mc-heads.net/avatar/${authUser.uuid}/64')`
}
} else {
avatarContainer.style.backgroundImage = `url('assets/images/Icon.png')`
}
accountMenuName.textContent = username
avatarMenuButton.disabled = authUser == null
if(authUser == null){
setAccountMenuOpen(false)
}
user_text.innerHTML = username
}
updateSelectedAccount(ConfigManager.getSelectedAccount())
@@ -1038,3 +1126,9 @@ async function loadNews(){
return await promise
}
window.updateSelectedAccount = updateSelectedAccount
window.updateSelectedServer = updateSelectedServer
window.refreshServerStatus = refreshServerStatus
window.initNews = initNews
})()

View File

@@ -1,6 +1,10 @@
// Requirements
const os = require('os')
const semver = require('semver')
const {
validateSelectedJvm,
ensureJavaDirIsRoot
} = require('helios-core/java')
const DropinModUtil = require('./assets/js/dropinmodutil')
const { MSFT_OPCODE, MSFT_REPLY_TYPE, MSFT_ERROR } = require('./assets/js/ipcconstants')

View File

@@ -2,6 +2,7 @@
updateAvailableTooltip = "Update Available"
usernamePlaceholder = "Username"
usernameEditButton = "Edit"
accountMenuLogout = "Log Out"
settingsTooltip = "Settings"
serverStatus = "SERVER"
serverStatusPlaceholder = "OFFLINE"
@@ -161,6 +162,7 @@ okay = "Okay"
[js.landing.selectedAccount]
noAccountSelected = "No Account Selected"
logoutFailed = "Failed to log out of the selected account. Please try again."
[js.landing.selectedServer]
noSelection = "No Server Selected"

View File

@@ -2,6 +2,7 @@
updateAvailableTooltip = "업데이트 가능"
usernamePlaceholder = "사용자 이름"
usernameEditButton = "편집"
accountMenuLogout = "로그아웃"
settingsTooltip = "설정"
serverStatus = "서버"
serverStatusPlaceholder = "오프라인"
@@ -161,6 +162,7 @@ okay = "확인"
[js.landing.selectedAccount]
noAccountSelected = "선택된 계정 없음"
logoutFailed = "계정을 로그아웃하지 못했습니다. 다시 시도해 주세요."
[js.landing.selectedServer]
noSelection = "선택된 서버 없음"

View File

@@ -15,9 +15,12 @@
<div id="right">
<div id="rightContainer">
<div id="user_content">
<span id="user_text"><%- lang('landing.usernamePlaceholder') %></span>
<div id="avatarContainer">
<button id="avatarOverlay"><%- lang('landing.usernameEditButton') %></button>
<button id="avatarMenuButton" type="button" aria-haspopup="true" aria-expanded="false">
<div id="avatarContainer"></div>
</button>
<div id="accountMenu" hidden>
<span id="accountMenuName"><%- lang('landing.usernamePlaceholder') %></span>
<button id="accountMenuLogoutButton" class="launcherGhostButton"><%- lang('landing.accountMenuLogout') %></button>
</div>
</div>
<div id="mediaContent">