Add profile context menu & test profile popup
All checks were successful
Android Build / publish (push) Successful in 53s
Linux Build / publish (push) Successful in 52s

This commit is contained in:
olcxja 2026-06-19 20:04:23 +02:00
commit 516bdf5186
12 changed files with 602 additions and 14 deletions

View file

@ -1411,6 +1411,10 @@ if (App) {
}
function popstate() {
if (isProfileOpen) {
closeProfile();
return;
}
if (!mainScreen.classList.contains('mobile-content') && !mainScreen.classList.contains('mobile-details')) {
history.back();
if (App) {
@ -1421,8 +1425,108 @@ function popstate() {
}
function gotoSideProfilePopup() {
sidebarProfileButton.addEventListener("click", (e) => {
e.stopPropagation();
history.pushState({trap: true}, "", location.href);
if (fixedContextMenu.classList.contains("show")) {
fixedContextMenu.classList.remove("show");
if (typeof clearContextMenuStyles === "function") clearContextMenuStyles();
setActiveSidebarIndicator(currentMainIndicator);
} else {
setActiveSidebarIndicator(sidebarProfileIndicator, true);
const rect = sidebarProfileButton.getBoundingClientRect();
showFixedContextMenu({top: rect.top, right: rect.right, bottom: rect.bottom, left: rect.left}, profileContextMenu);
}
});
function logout() {
localStorage.clear();
window.location.href = "login/index.html";
}
function gotoSettings() {
if (fixedContextMenu.classList.contains("show")) {
fixedContextMenu.classList.remove("show");
if (typeof clearContextMenuStyles === "function") clearContextMenuStyles();
setActiveSidebarIndicator(currentMainIndicator);
}
}
let isProfileOpen = false;
async function openProfile(accountId) {
if (fixedContextMenu.classList.contains("show")) {
fixedContextMenu.classList.remove("show");
if (typeof clearContextMenuStyles === "function") clearContextMenuStyles();
setActiveSidebarIndicator(currentMainIndicator);
}
let popupContainer = document.getElementById("profile-popup-container");
let popupInner = document.getElementById("profile-popup-inner");
//show loading
popupInner.innerHTML = '<div style="display: flex; justify-content: center; align-items: center; height: 100%;"><p>Loading profile...</p></div>';
popupContainer.style.display = "flex";
//force reflow
popupContainer.offsetHeight;
popupContainer.classList.add("show");
isProfileOpen = true;
try {
if (!accountId) accountId = window.id; //var fallback
let nameWithHost = await fetchAsync(`${url}/idtoname?id=${accountId}`);
if (nameWithHost.startsWith("error:")) nameWithHost = accountId; //api fallback
let nameParts = nameWithHost.split(":");
let profileName = nameParts[0] || accountId;
let profileHost = nameParts.slice(1).join(":") || host;
let pfpUrl = await getAvatarUrl(accountId, nameWithHost);
let bannerUrl = `${url}/user/storage/public/getentry?id=${accountId}&e=larp.profile.banner`;
let bannerHtml = `<img src="${bannerUrl}" class="profile-banner" onerror="this.outerHTML='<div class=\\'profile-banner\\'></div>'">`;
let bio = await fetchAsync(`${url}/user/storage/public/getentry?id=${accountId}&e=larp.profile.bio`);
if (bio.startsWith("error:")) bio = "";
let bioHtml = bio && bio.trim() !== "" ? `<div class="profile-bio">${bio.replace(/</g, "&lt;").replace(/>/g, "&gt;")}</div>` : "";
let isOwnProfile = accountId === id;
let actionBtnHtml = isOwnProfile ?
`<button class="profile-action-btn">Edit Profile</button>` :
`<button class="profile-action-btn">Open DM</button>`;
popupInner.innerHTML = `
${bannerHtml}
<div class="profile-avatar-container">
<img src="${pfpUrl}" class="profile-avatar">
</div>
<div class="profile-info">
<div>
<div class="profile-name">${profileName}</div>
<div class="profile-id-host">${profileName}:${profileHost} (${accountId})</div>
</div>
${bioHtml}
${actionBtnHtml}
</div>
`;
} catch (e) {
popupInner.innerHTML = '<div style="display: flex; justify-content: center; align-items: center; height: 100%;"><p>Failed to load profile.</p></div>';
console.error(e);
}
}
function closeProfile() {
let popupContainer = document.getElementById("profile-popup-container");
popupContainer.classList.remove("show");
isProfileOpen = false;
setTimeout(() => {
popupContainer.style.display = "none";
}, 300);
}
function setActiveRoombarItem(itemId) {
@ -1820,7 +1924,7 @@ async function renderDms(res) {
let dms = parsed.dms || {};
let dmEntries = Object.entries(dms);
// Sort by timestamp descending
//Sort by timestamp descending
dmEntries.sort((a, b) => (parseInt(b[1].string2) || 0) - (parseInt(a[1].string2) || 0));
let html = "";