LarpixClient/webroot/index.html
olcxja 5a04288e96
All checks were successful
Android Build / publish (push) Successful in 32s
Linux Build / publish (push) Successful in 57s
update deps & add version sync
2026-08-22 09:33:12 +02:00

283 lines
No EOL
11 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<title>Miarven</title>
<link rel="stylesheet" href="style.css">
<link rel="icon" type="image/svg+xml" href="favicon.svg">
<script src="crypto-pq.js"></script>
<!-- debug
<script src="https://cdn.jsdelivr.net/npm/eruda"></script>
<script>eruda.init();</script> -->
<script src="icons.js"></script>
</head>
<body>
<loading>
<div style="display: flex;justify-content: center;align-items: center;height:100%;flex-direction: column;text-align: center;">
<img src="favicon.svg" style="width: 6rem">
<p id="loadingstatus"></p>
</div>
</loading>
<main style="display: none;">
<sidebar>
<sidebarelement id="sidebar-home">
<indicator class="active">
</indicator>
<button class="icon-button" onclick="gotoHome()">
<script>
document.currentScript.insertAdjacentHTML('beforebegin', ICONS.home());
document.currentScript.remove();
</script>
</button>
</sidebarelement>
<sidebarelement id="sidebar-add">
<indicator>
</indicator>
<button class="icon-button">
<script>
document.currentScript.insertAdjacentHTML('beforebegin', ICONS.plus());
document.currentScript.remove();
</script>
</button>
</sidebarelement>
<hr>
<hr class="bottom-element">
<sidebarelement id="sidebar-inbox">
<indicator>
</indicator>
<button class="icon-button" onclick="gotoInbox()">
<script>
document.currentScript.insertAdjacentHTML('beforebegin', ICONS.inbox());
document.currentScript.remove();
</script>
</button>
</sidebarelement>
<sidebarelement id="sidebar-profile">
<indicator>
</indicator>
<button class="icon-button">
<img id="sidebar-pfp">
</button>
</sidebarelement>
</sidebar>
<sidebar class="second" id="roomsbar">
<roomtopbar>
<inherit style="display: flex;"></inherit>
</roomtopbar>
<roomcontent2>
</roomcontent2>
</sidebar>
<roomcontent>
<roomtopbar>
<inherit style="display: flex;"></inherit>
</roomtopbar>
<roomcontent2>
</roomcontent2>
</roomcontent>
<sidebar class="second" id="roomdetailsbar" style="display: none;">
<roomtopbar>
<inherit style="display: flex;"></inherit>
</roomtopbar>
<roomcontent2>
</roomcontent2>
</sidebar>
</main>
<div id="fixed-context-menu" class="context-menu">
</div>
<div id="profile-popup-container" class="profile-popup-container" style="display: none;">
<div class="profile-popup-bg" onclick="closeProfile()"></div>
<div class="profile-popup-content">
<button class="profile-popup-close-btn" onclick="closeProfile()">
<script>
document.currentScript.insertAdjacentHTML('beforebegin', ICONS.close());
document.currentScript.remove();
</script>
</button>
<div id="profile-popup-inner"></div>
</div>
</div>
<div id="cropper-popup-container" class="profile-popup-container" style="z-index: 9999;">
<div class="profile-popup-bg" onclick="closeCropper()"></div>
<div class="profile-popup-content" style="max-width: 40rem; padding: 2rem; display: flex; flex-direction: column; align-items: center; gap: 1rem; height: auto;">
<h2><blah>title.crop.image</blah></h2>
<div id="cropper-viewport-container" style="position: relative; overflow: hidden; background: #000; width: 100%; max-width: 30rem; border-radius: 0.8rem; border: var(--border-width) solid rgba(255,255,255,0.2);">
<img id="cropper-image" src="" style="position: absolute; transform-origin: 0 0; cursor: move;">
</div>
<div style="display: flex; gap: 1rem; margin-top: 1rem; width: 100%; max-width: 30rem;">
<button class="submit-button blah" style="background: rgba(255,255,255,0.1); color: var(--text-color); flex: 1;" onclick="closeCropper()">action.cancel</button>
<button class="submit-button blah" style="flex: 1;" onclick="confirmCropper()">action.save</button>
</div>
</div>
</div>
<div id="generic-popup-container" class="profile-popup-container" style="display: none; z-index: 9999;">
<div class="profile-popup-bg" onclick="closeGenericPopup()"></div>
<div class="profile-popup-content popup-auto-height">
<button class="profile-popup-close-btn" onclick="closeGenericPopup()">
<script>
document.currentScript.insertAdjacentHTML('beforebegin', ICONS.close());
document.currentScript.remove();
</script>
</button>
<div id="generic-popup-inner" style="padding: 2rem; display: flex; flex-direction: column; align-items: center; gap: 1rem; width: 100%; box-sizing: border-box;">
</div>
</div>
</div>
</body>
</html>
<script src="version.js"></script>
<script src="screens.js"></script>
<script>
async function start() {
updateLoadingStatus("loading.loading");
try {
if (host != null)
{
await updateProtocolAndUrl(host);
}
else
{
await updateProtocolAndUrl(window.location.hostname);
}
let localIdRes = await fetchAsync(`${url}/nametoid?u=${username}`);
let localId = localIdRes.trim();
sidebarPfp.src = await getAvatarUrl(localId, `${username}:${host}`);
showAction("action.auth", "startauth");
let res = await Auth(username, password);
clearAction("startauth");
if (res.startsWith("success:")) {
try {
await ensureUserKeys();
} catch (e) {
//if fails continue loading encryption may be broken
console.error(e);
}
gotoHome();
} else {
showBlahNotification("error:auth.failed.redirect.to.login");
await delay(2000);
window.location.href = "login/index.html";
}
updateLoadingStatus("loading.done");
await loadingFadeOut();
} catch (e) {
clearAction("startauth");
showBlahNotification("error:auth.failed.redirect.to.login");
await delay(2000);
window.location.href = "login/index.html";
}
}
async function refreshDms(waittime = 0, showLoading = true) {
try {
if (showLoading) showAction("action.dm.fetch", "dmrefresh");
await delay(waittime);
if (window.cachedDms && typeof renderDms === 'function') {
await renderDms(window.cachedDms);
}
let res = await fetchEncrypted("user/dm/list");
window.cachedDms = res;
if (typeof renderDms === 'function') {
await renderDms(res);
}
if (showLoading) clearAction("dmrefresh");
}
catch (e) {
if (showLoading) clearAction("dmrefresh");
showBlahNotification("error:dm.refresh.failed");
}
}
async function addDm() {
try {
showAction("action.dm.adding", "dmadd");
let username = document.getElementById("addchat-username").value;
let idRes = await fetchAsync(`${url}/nametoid?u=${username}`);
if (idRes.startsWith("error") || idRes.trim() === "0" || idRes.trim() === "") {
clearAction("dmadd");
showBlahNotification("error:user.not.found");
return;
}
let targetId = idRes.trim();
let res = await fetchEncrypted("user/dm/invite", targetId);
clearAction("dmadd");
showBlahNotification(res);
}
catch (e) {
console.log(e);
clearAction("dmadd");
showBlahNotification("error:chat.add.failed");
}
}
async function refreshGroups(waittime = 0, showLoading = true) {
try {
if (showLoading) showAction("action.group.fetch", "grouprefresh");
await delay(waittime);
if (window.cachedGroups && typeof renderGroups === 'function') {
await renderGroups(window.cachedGroups);
}
let res = await fetchEncrypted("user/group/list");
window.cachedGroups = res;
if (typeof renderGroups === 'function') {
await renderGroups(res);
}
if (showLoading) clearAction("grouprefresh");
}
catch (e) {
if (showLoading) clearAction("grouprefresh");
showBlahNotification("error:group.refresh.failed");
}
}
async function createGroup() {
try {
let groupName = document.getElementById("creategroup-name").value;
if (!groupName || groupName.trim() === "") {
showBlahNotification("error:group.name.empty");
return;
}
showAction("action.group.creating", "group.action");
await ensureUserKeys();
const roomKey = randomRoomKey256Chars();
const selfWrapped = await wrapRoomKeyForSelf(roomKey);
let historyVisible = document.getElementById("creategroup-history") ? document.getElementById("creategroup-history").checked.toString() : "false";
let payload = JSON.stringify({
string1: groupName,
string2: selfWrapped,
string3: historyVisible
});
let res = await fetchEncrypted("group/create", payload);
clearAction("group.action");
if (res.startsWith("success:")) {
showBlahNotification("success:group.created");
await refreshGroups(200, false);
} else {
showBlahNotification(res || "error:something.wrong");
}
} catch (e) {
clearAction("group.action");
showBlahNotification("error:something.wrong");
console.error(e);
}
}
</script>
<script src="gifuct.js"></script>
<script src="main.js"></script>
<script src="userscript.js"></script>