add blahs for whole ui

This commit is contained in:
olcxja 2026-05-14 21:05:10 +02:00
commit 7ca3832286
14 changed files with 646 additions and 438 deletions

File diff suppressed because one or more lines are too long

View file

@ -3,7 +3,7 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover"> <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<title>Larpix Client</title> <title>Miarven</title>
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="style.css">
<link rel="icon" type="image/svg+xml" href="favicon.svg"> <link rel="icon" type="image/svg+xml" href="favicon.svg">
</head> </head>
@ -19,7 +19,7 @@
<sidebarelement id="sidebar-home"> <sidebarelement id="sidebar-home">
<indicator class="active"> <indicator class="active">
</indicator> </indicator>
<button class="icon-button" aria-label="Homepage" onclick="gotoHome()"> <button class="icon-button" onclick="gotoHome()">
<svg viewBox="-1 -1 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg viewBox="-1 -1 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path <path
d="M1 6V15H6V11C6 9.89543 6.89543 9 8 9C9.10457 9 10 9.89543 10 11V15H15V6L8 0L1 6Z" d="M1 6V15H6V11C6 9.89543 6.89543 9 8 9C9.10457 9 10 9.89543 10 11V15H15V6L8 0L1 6Z"
@ -35,7 +35,7 @@
<sidebarelement id="sidebar-add"> <sidebarelement id="sidebar-add">
<indicator> <indicator>
</indicator> </indicator>
<button class="icon-button" aria-label="Add space" onclick="gotoCreateSpace()"> <button class="icon-button" onclick="gotoCreateSpace()">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="12" y1="5" x2="12" y2="19"></line> <line x1="12" y1="5" x2="12" y2="19"></line>
@ -48,14 +48,14 @@
<sidebarelement id="sidebar-inbox"> <sidebarelement id="sidebar-inbox">
<indicator> <indicator>
</indicator> </indicator>
<button class="icon-button" aria-label="Inbox" onclick="gotoInbox()"> <button class="icon-button" onclick="gotoInbox()">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="currentColor"><path d="M216-144q-29 0-50.5-21.5T144-216v-528q0-29.7 21.5-50.85Q187-816 216-816h528q29.7 0 50.85 21.15Q816-773.7 816-744v528q0 29-21.15 50.5T744-144H216Zm0-72h528v-144H632q-23 43-63.5 69.5T480-264q-49 0-89.5-26T328-360H216v144Zm332-148q28-28 28-68h168v-312H216v312h168q0 40 28 68t68 28q40 0 68-28ZM216-216h528-528Z"/></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="currentColor"><path d="M216-144q-29 0-50.5-21.5T144-216v-528q0-29.7 21.5-50.85Q187-816 216-816h528q29.7 0 50.85 21.15Q816-773.7 816-744v528q0 29-21.15 50.5T744-144H216Zm0-72h528v-144H632q-23 43-63.5 69.5T480-264q-49 0-89.5-26T328-360H216v144Zm332-148q28-28 28-68h168v-312H216v312h168q0 40 28 68t68 28q40 0 68-28ZM216-216h528-528Z"/></svg>
</button> </button>
</sidebarelement> </sidebarelement>
<sidebarelement id="sidebar-profile"> <sidebarelement id="sidebar-profile">
<indicator> <indicator>
</indicator> </indicator>
<button class="icon-button" aria-label="Profile" onclick="gotoSideProfilePopup()"> <button class="icon-button" onclick="gotoSideProfilePopup()">
<img id="sidebar-pfp"> <img id="sidebar-pfp">
</button> </button>
</sidebarelement> </sidebarelement>
@ -63,17 +63,17 @@
<sidebar class="second" id="roomsbar"> <sidebar class="second" id="roomsbar">
<roomtopbar> <roomtopbar>
Home <blah>title.home</blah>
</roomtopbar> </roomtopbar>
<div class="sidebar-section-header"> <div class="sidebar-section-header">
<button class="collapse-text-button" id="collapse-dms"> <button class="collapse-text-button" id="collapse-dms">
<span>Direct messages</span> <span><blah>title.dms</blah></span>
<svg class="chevron" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" <svg class="chevron" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="6 9 12 15 18 9"></polyline> <polyline points="6 9 12 15 18 9"></polyline>
</svg> </svg>
</button> </button>
<button class="add-action-button" aria-label="Add Direct Message" id="add-dm-btn"> <button class="add-action-button" id="add-dm-btn">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="12" y1="5" x2="12" y2="19"></line> <line x1="12" y1="5" x2="12" y2="19"></line>
@ -84,13 +84,13 @@
<div class="sidebar-section-header"> <div class="sidebar-section-header">
<button class="collapse-text-button" id="collapse-groups"> <button class="collapse-text-button" id="collapse-groups">
<span>Groups</span> <span><blah>title.groups</blah></span>
<svg class="chevron" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" <svg class="chevron" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="6 9 12 15 18 9"></polyline> <polyline points="6 9 12 15 18 9"></polyline>
</svg> </svg>
</button> </button>
<button class="add-action-button" aria-label="Add Group" id="add-group-btn"> <button class="add-action-button" id="add-group-btn">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="12" y1="5" x2="12" y2="19"></line> <line x1="12" y1="5" x2="12" y2="19"></line>
@ -102,13 +102,13 @@
<roomcontent> <roomcontent>
<roomtopbar> <roomtopbar>
Splash <blah>title.splash</blah>
</roomtopbar> </roomtopbar>
<roomcontent2> <roomcontent2>
<div style="display: flex;justify-content: center;align-items: center;height:100%;flex-direction: column;text-align: center;"> <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"> <img src="favicon.svg" style="width: 6rem">
<herotitle>Welcome to Miarven</herotitle> <herotitle><blah>title.welcome.splash</blah></herotitle>
<p>First Larpix client. <span class="aqua">v<span class="clientver aqua">1.0</span></span></p> <p><blah>desc.welcome.splash</blah>. <span class="aqua">v<span class="clientver aqua">1.0</span></span></p>
</div> </div>
</roomcontent2> </roomcontent2>
</roomcontent> </roomcontent>
@ -117,7 +117,7 @@
</main> </main>
</body> </body>
</html> </html>
<script src="main.js"></script> <script src="screens.js"></script>
<script> <script>
async function start() { async function start() {
updateLoadingStatus("loading.loading"); updateLoadingStatus("loading.loading");
@ -190,4 +190,5 @@
} }
</script> </script>
<script src="main.js"></script>
<script src="userscript.js"></script> <script src="userscript.js"></script>

View file

@ -3,7 +3,7 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover"> <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<title>Larpix - Authentication</title> <title>Miarven - Login</title>
<link rel="stylesheet" href="../style.css"> <link rel="stylesheet" href="../style.css">
<link rel="icon" type="image/svg+xml" href="../favicon.svg"> <link rel="icon" type="image/svg+xml" href="../favicon.svg">
<style> <style>
@ -11,7 +11,7 @@
font-size: max(17px, calc(100vw / 100)); font-size: max(17px, calc(100vw / 100));
} }
body { body, main {
justify-content: center; justify-content: center;
align-items: center; align-items: center;
background-color: var(--main-bg-color); background-color: var(--main-bg-color);
@ -153,117 +153,118 @@
</style> </style>
</head> </head>
<body> <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;">
<div class="auth-card">
<div class="auth-container" id="auth-container">
<div class="auth-card"> <div class="auth-box" id="login-box">
<div class="auth-container" id="auth-container"> <div class="auth-header">
<h1>Larpix</h1>
<p><blah>title.sign.in.to</blah></p>
</div>
<div class="auth-box" id="login-box"> <form id="form-login">
<div class="auth-header"> <div class="input-group">
<h1>Larpix</h1> <label for="login-host"><blah>title.server.host</blah></label>
<p>Sign in to your larpix instance.</p> <input type="text" id="login-host" placeholder="example.com" autocomplete="url" onchange="loginHostChanged()">
</div> <p class="mininote serverstatus"><blah>loading.connecting</blah></p>
</div>
<form id="form-login"> <div class="input-group">
<div class="input-group"> <label for="login-username"><blah>title.username</blah></label>
<label for="login-host">Server Host</label> <input type="text" id="login-username" placeholder="{blah(placeholder.username)}" autocomplete="username">
<input type="text" id="login-host" placeholder="example.com" autocomplete="url" onchange="loginHostChanged()"> </div>
<p class="mininote serverstatus">Connecting...</p>
<div class="input-group">
<label for="login-password"><blah>title.password</blah></label>
<input type="password" id="login-password" placeholder="••••••••" autocomplete="current-password">
</div>
<button type="submit" class="submit-button blah">title.sign.in</button>
</form>
<div class="footer-links">
<span class="footer-link-toggle" id="to-register">
<blah>title.new.here.?</blah> <strong class="blah">title.create.an.account</strong>
</span>
</div>
</div> </div>
<div class="input-group"> <div class="auth-box" id="register-box">
<label for="login-username">Username</label> <div class="auth-header">
<input type="text" id="login-username" placeholder="username" autocomplete="username"> <h1><blah>join.larpix</blah></h1>
<p><blah>title.create.new.account</blah></p>
</div>
<form id="form-register">
<div class="input-group">
<label for="reg-host"><blah>title.server.host</blah></label>
<input type="text" id="reg-host" placeholder="example.com" autocomplete="url" onchange="regHostChanged()">
<p class="mininote serverstatus"><blah>loading.connecting</blah></p>
</div>
<div class="input-group">
<label for="reg-username"><blah>title.username</blah></label>
<input type="text" id="reg-username" placeholder="{blah(placeholder.username)}" autocomplete="username">
</div>
<div class="input-group">
<label for="reg-password"><blah>title.password</blah></label>
<input type="password" id="reg-password" placeholder="••••••••" autocomplete="new-password">
<p class="red mininote"><blah>notice.use.strong.pass</blah></p>
</div>
<div class="input-group">
<label for="reg-confirm"><blah>title.confirm.password</blah></label>
<input type="password" id="reg-confirm" placeholder="••••••••" autocomplete="new-password">
</div>
<button type="submit" class="submit-button blah" id="register-button">title.sign.up</button>
</form>
<div class="footer-links">
<span class="footer-link-toggle" id="to-login">
<blah>title.already.registered.?</blah> <strong class="blah">title.back.to.login</strong>
</span>
</div>
</div> </div>
<div class="input-group"> <div class="auth-box" id="captcha-box">
<label for="login-password">Password</label> <div class="auth-header">
<input type="password" id="login-password" placeholder="••••••••" autocomplete="current-password"> <h1><blah>title.verify</blah></h1>
</div> <p><blah>title.captcha.desc</blah></p>
</div>
<div class="captcha-img">
<img src="" alt="Captcha" id="captcha-image">
</div>
<form id="form-captcha">
<div class="input-group">
<label for="captcha-input"><blah>title.captcha.code</blah></label>
<input type="text" id="captcha-input" placeholder="{blah(placeholder.captcha.code)}" autocomplete="off">
<button type="submit" class="submit-button"> </div>
Sign In <div class="input-group" id="regkey-group">
</button> <label for="regkey-input"><blah>title.invitation.code</blah></label>
</form> <input type="text" id="regkey-input" placeholder="{blah(placeholder.invitation.code)}" autocomplete="off">
</div>
<div class="footer-links"> <button type="submit" class="submit-button blah">title.verify</button>
<span class="footer-link-toggle" id="to-register"> </form>
New here? <strong>Create an account</strong> <div class="footer-links">
<span class="footer-link-toggle" id="back-to-reg">
<strong class="blah">title.back.to.register</strong>
</span> </span>
</div>
</div>
</div> </div>
</div> </div>
</main>
<div class="auth-box" id="register-box">
<div class="auth-header">
<h1>Join Larpix</h1>
<p>Create new larpix account.</p>
</div>
<form id="form-register">
<div class="input-group">
<label for="reg-host">Server Host</label>
<input type="text" id="reg-host" placeholder="example.com" autocomplete="url" onchange="regHostChanged()">
<p class="mininote serverstatus">Connecting...</p>
</div>
<div class="input-group">
<label for="reg-username">Username</label>
<input type="text" id="reg-username" placeholder="Choose username" autocomplete="username">
</div>
<div class="input-group">
<label for="reg-password">Password</label>
<input type="password" id="reg-password" placeholder="Create password" autocomplete="new-password">
<p class="red mininote">Remember to use a strong password! It will be used to encrypt your keys</p>
</div>
<div class="input-group">
<label for="reg-confirm">Confirm Password</label>
<input type="password" id="reg-confirm" placeholder="Repeat password" autocomplete="new-password">
</div>
<button type="submit" class="submit-button" id="register-button">
Sign Up
</button>
</form>
<div class="footer-links">
<span class="footer-link-toggle" id="to-login">
Already a member? <strong>Back to Login</strong>
</span>
</div>
</div>
<div class="auth-box" id="captcha-box">
<div class="auth-header">
<h1>Verify</h1>
<p>Prove you are a human.</p>
</div>
<div class="captcha-img">
<img src="" alt="Captcha" id="captcha-image">
</div>
<form id="form-captcha">
<div class="input-group">
<label for="captcha-input">Captcha code</label>
<input type="text" id="captcha-input" placeholder="Captcha code" autocomplete="off">
</div>
<div class="input-group" id="regkey-group">
<label for="regkey-input">Invitation code</label>
<input type="text" id="regkey-input" placeholder="Invitation code" autocomplete="off">
</div>
<button type="submit" class="submit-button">
Verify
</button>
</form>
<div class="footer-links">
<span class="footer-link-toggle" id="back-to-reg">
<strong>Back to registration</strong>
</span>
</div>
</div>
</div>
</div>
</body> </body>
</html> </html>
<script src="../main.js"></script> <script src="../main.js"></script>
@ -294,6 +295,16 @@
const registerButton = document.getElementById("register-button"); const registerButton = document.getElementById("register-button");
const regKeyGroup = document.getElementById("regkey-group"); const regKeyGroup = document.getElementById("regkey-group");
async function start() {
updateLoadingStatus("loading.loading");
//
updateLoadingStatus("loading.done");
await loadingFadeOut();
}
toRegister.addEventListener('click', () => { toRegister.addEventListener('click', () => {
container.className = 'auth-container show-register'; container.className = 'auth-container show-register';
}); });
@ -316,11 +327,13 @@
if (res.startsWith("success:")) if (res.startsWith("success:"))
{ {
showBlahNotification(res); showBlahNotification(res);
await delay(1000); await delay(800);
localStorage.setItem("username", loginUsername.value); localStorage.setItem("username", loginUsername.value);
localStorage.setItem("password", loginPassword.value); localStorage.setItem("password", loginPassword.value);
localStorage.setItem("host", loginHost.value); localStorage.setItem("host", loginHost.value);
await loadingFadeIn();
window.location.href = "../"; window.location.href = "../";
} }
else else

View file

@ -24,6 +24,9 @@ var url = `${prot}//${window.location.hostname}/_larpix`;
var params = new URLSearchParams(window.location.search); var params = new URLSearchParams(window.location.search);
try { try {
var loadingScreen = document.querySelector("loading");
var mainScreen = document.querySelector("main");
var loadingStatus = document.getElementById("loadingstatus"); var loadingStatus = document.getElementById("loadingstatus");
var collapseDmsBtn = document.getElementById("collapse-dms"); var collapseDmsBtn = document.getElementById("collapse-dms");
@ -256,7 +259,6 @@ async function decryptString(base64Text, passphrase) {
async function fetchPost(url, value) { async function fetchPost(url, value) {
let response = await fetch(url, { let response = await fetch(url, {
method: "POST", method: "POST",
credentials: "omit",
body: value, body: value,
headers: { headers: {
"secret": await encryptWithNonce(passwordHash, passwordHash, await getNonce(username, passwordHash)) "secret": await encryptWithNonce(passwordHash, passwordHash, await getNonce(username, passwordHash))
@ -270,7 +272,6 @@ async function fetchPostEnc(url, value) {
let nonce = await getNonce(username, passwordHash); let nonce = await getNonce(username, passwordHash);
let response = await fetch(url, { let response = await fetch(url, {
method: "POST", method: "POST",
credentials: "omit",
body: await encryptWithNonce(value, passwordHash, nonce), body: await encryptWithNonce(value, passwordHash, nonce),
headers: { headers: {
"secret": await encryptWithNonce(passwordHash, passwordHash, nonce) "secret": await encryptWithNonce(passwordHash, passwordHash, nonce)
@ -283,7 +284,6 @@ async function fetchPostEnc(url, value) {
async function fetchAsync(url) { async function fetchAsync(url) {
let response = await fetch(url, { let response = await fetch(url, {
method: "GET", method: "GET",
credentials: "omit"
}); });
let data = await response.text(); let data = await response.text();
@ -293,7 +293,6 @@ async function fetchAsync(url) {
async function fetchAsyncWAuth(url) { async function fetchAsyncWAuth(url) {
let response = await fetch(url, { let response = await fetch(url, {
method: "GET", method: "GET",
credentials: "omit",
headers: { headers: {
"secret": await encryptWithNonce(passwordHash, passwordHash, await getNonce(username, passwordHash)) "secret": await encryptWithNonce(passwordHash, passwordHash, await getNonce(username, passwordHash))
} }
@ -312,7 +311,6 @@ async function Auth(username, password) {
let passwordHash = await hashSHA3_512(password); let passwordHash = await hashSHA3_512(password);
let response = await fetch(`${url}/auth?u=${username}`, { let response = await fetch(`${url}/auth?u=${username}`, {
method: "GET", method: "GET",
credentials: "omit",
headers: { headers: {
"secret": await encryptWithNonce(passwordHash, passwordHash, await getNonce(username, passwordHash)) "secret": await encryptWithNonce(passwordHash, passwordHash, await getNonce(username, passwordHash))
} }
@ -330,7 +328,6 @@ async function fetchEncrypted(request, body) {
let response = await fetch(`${url}/encryptedrequest?u=${username}`, { let response = await fetch(`${url}/encryptedrequest?u=${username}`, {
method: "POST", method: "POST",
credentials: "omit",
body: await encryptWithNonce( body: await encryptWithNonce(
JSON.stringify({ JSON.stringify({
string1: request, string1: request,
@ -532,8 +529,6 @@ function updateLoadingStatus(message) {
} }
async function loadingFadeOut() { async function loadingFadeOut() {
let loadingScreen = document.querySelector("loading");
let mainScreen = document.querySelector("main");
mainScreen.style.transform = "scale(0.85)"; mainScreen.style.transform = "scale(0.85)";
mainScreen.style.opacity = "0"; mainScreen.style.opacity = "0";
@ -546,8 +541,20 @@ async function loadingFadeOut() {
await delay(200); await delay(200);
mainScreen.style.transform = ""; mainScreen.style.transform = "";
mainScreen.style.opacity = ""; mainScreen.style.opacity = "";
}
async function loadingFadeIn() {
loadingScreen.style.transform = "scale(0.85)";
loadingScreen.style.opacity = "0";
mainScreen.style.transform = "scale(0.85)";
mainScreen.style.opacity = "0";
await delay(200);
mainScreen.style.display = "none";
loadingScreen.style.display = "";
await delay(200);
loadingScreen.style.transform = "";
loadingScreen.style.opacity = "";
} }
@ -565,6 +572,25 @@ async function initBlahs() {
res = await fetchAsync(`${path}blah/en-us.json`); res = await fetchAsync(`${path}blah/en-us.json`);
} }
blah = JSON.parse(res); blah = JSON.parse(res);
let blahTags = document.getElementsByTagName("blah");
for (let i = 0; i < blahTags.length; i++) {
blahTags[i].innerHTML = processBlah(blahTags[i].innerHTML);
}
blahTags = document.getElementsByClassName("blah");
for (let i = 0; i < blahTags.length; i++) {
blahTags[i].innerHTML = processBlah(blahTags[i].innerHTML);
}
let placeholders = document.querySelectorAll("[placeholder]");
for (let i = 0; i < placeholders.length; i++) {
if (placeholders[i].placeholder.startsWith("{blah("))
{
let value = placeholders[i].placeholder.split("{blah(")[1].split(")}")[0];
placeholders[i].placeholder = processBlah(value);
}
}
} }
function processBlah(blahmessage) { function processBlah(blahmessage) {
@ -634,65 +660,69 @@ collapseGroupsBtn.addEventListener("click", () => {
collapseGroupsBtn.classList.toggle("collapsed"); collapseGroupsBtn.classList.toggle("collapsed");
}); });
addDmBtn.addEventListener("click", async () => {
//Invite to dm, addDmScreen, false
async function switchRoomContent(title, content, showRoomBar)
{
roomContentMain.style.transform = "scale(0.85)"; roomContentMain.style.transform = "scale(0.85)";
roomContentMain.style.opacity = "0"; roomContentMain.style.opacity = "0";
await delay(200); await delay(200);
roomTopBar.innerHTML = "Invite to dm"; roomTopBar.innerHTML = processBlah(title);
roomDetailsBar.style.display = "none"; roomDetailsBar.style.display = showRoomBar ? "flex" : "none";
//content blah parsing
let parser = new DOMParser();
let doc = parser.parseFromString(content, "text/html");
let blahTags = doc.getElementsByTagName("blah");
for (let i = 0; i < blahTags.length; i++) {
blahTags[i].innerHTML = processBlah(blahTags[i].innerHTML);
}
blahTags = doc.getElementsByClassName("blah");
for (let i = 0; i < blahTags.length; i++) {
blahTags[i].innerHTML = processBlah(blahTags[i].innerHTML);
}
let placeholders = doc.querySelectorAll("[placeholder]");
for (let i = 0; i < placeholders.length; i++) {
if (placeholders[i].placeholder.startsWith("{blah("))
{
let value = placeholders[i].placeholder.split("{blah(")[1].split(")}")[0];
placeholders[i].placeholder = processBlah(value);
}
}
roomContentMain.innerHTML = doc.body.innerHTML;
roomContentMain.innerHTML =
`
<div style="display: flex;justify-content: center;align-items: center;height:100%;flex-direction: column;text-align: center;">
<svg xmlns="http://www.w3.org/2000/svg" width="3rem" viewBox="0 -960 960 960" fill="var(--text-color)"><path d="M120-160v-600q0-33 23.5-56.5T200-840h480q33 0 56.5 23.5T760-760v203q-10-2-20-2.5t-20-.5q-10 0-20 .5t-20 2.5v-203H200v400h283q-2 10-2.5 20t-.5 20q0 10 .5 20t2.5 20H240L120-160Zm160-440h320v-80H280v80Zm0 160h200v-80H280v80Zm400 280v-120H560v-80h120v-120h80v120h120v80H760v120h-80ZM200-360v-400 400Z"/></svg>
<herotitle>Add Chat</herotitle>
<p>Add a private, encrypted chat by entering a username</p>
<br>
<div class="input-group">
<label for="addchat-username">Username</label>
<input type="text" id="addchat-username" placeholder="username:serverhost" class="forminput">
</div>
<div class="input-group">
<button class="submit-button" onclick="addDm()">
Add chat
</button>
</div>
</div>
`;
roomContentMain.style.transform = ""; roomContentMain.style.transform = "";
roomContentMain.style.opacity = ""; roomContentMain.style.opacity = "";
}
addDmBtn.addEventListener("click", async () => {
switchRoomContent("title.create.dm", addDmScreen, false);
}); });
addGroupBtn.addEventListener("click", async () => { addGroupBtn.addEventListener("click", async () => {
roomContentMain.style.transform = "scale(0.85)"; switchRoomContent("title.create.group", createGroupScreen, false);
roomContentMain.style.opacity = "0";
await delay(200);
roomTopBar.innerHTML = "Create group";
roomDetailsBar.style.display = "none";
roomContentMain.innerHTML =
`
<div style="display: flex;justify-content: center;align-items: center;height:100%;flex-direction: column;text-align: center;">
<svg xmlns="http://www.w3.org/2000/svg" width="3rem" viewBox="0 -960 960 960" fill="var(--text-color)"><path d="M500-482q29-32 44.5-73t15.5-85q0-44-15.5-85T500-798q60 8 100 53t40 105q0 60-40 105t-100 53Zm220 322v-120q0-36-16-68.5T662-406q51 18 94.5 46.5T800-280v120h-80Zm80-280v-80h-80v-80h80v-80h80v80h80v80h-80v80h-80Zm-593-87q-47-47-47-113t47-113q47-47 113-47t113 47q47 47 47 113t-47 113q-47 47-113 47t-113-47ZM0-160v-112q0-34 17.5-62.5T64-378q62-31 126-46.5T320-440q66 0 130 15.5T576-378q29 15 46.5 43.5T640-272v112H0Zm320-400q33 0 56.5-23.5T400-640q0-33-23.5-56.5T320-720q-33 0-56.5 23.5T240-640q0 33 23.5 56.5T320-560ZM80-240h480v-32q0-11-5.5-20T540-306q-54-27-109-40.5T320-360q-56 0-111 13.5T100-306q-9 5-14.5 14T80-272v32Zm240-400Zm0 400Z"/></svg>
<herotitle>Create Group</herotitle>
<p>Create a private, encrypted group</p>
<br>
<div class="input-group">
<label for="creategroup-name">Name</label>
<input type="text" id="creategroup-name" placeholder="My group" class="forminput">
</div>
<div class="input-group">
<button class="submit-button" onclick="createGroup()">
Create group
</button>
</div>
</div>
`;
roomContentMain.style.transform = "";
roomContentMain.style.opacity = "";
}); });
function gotoSideProfilePopup() {
}
function gotoInbox() {
}
async function gotoCreateSpace() {
switchRoomContent("title.create.space", createSpaceScreen, false);
}
function gotoHome() {
}
/* replaced with css /* replaced with css
sidebarHomeButton.addEventListener("mouseenter", () => { sidebarHomeButton.addEventListener("mouseenter", () => {
sidebarHomeIndicator.classList.add("hover"); sidebarHomeIndicator.classList.add("hover");
@ -722,41 +752,3 @@ sidebarInboxButton.addEventListener("mouseleave", () => {
sidebarInboxIndicator.classList.remove("hover"); sidebarInboxIndicator.classList.remove("hover");
}); });
*/ */
function gotoSideProfilePopup() {
}
function gotoInbox() {
}
async function gotoCreateSpace() {
roomContentMain.style.transform = "scale(0.85)";
roomContentMain.style.opacity = "0";
await delay(200);
roomTopBar.innerHTML = "Create space";
roomDetailsBar.style.display = "none";
roomContentMain.innerHTML =
`
<div style="display: flex;justify-content: center;align-items: center;height:100%;flex-direction: column;text-align: center;">
<svg xmlns="http://www.w3.org/2000/svg" width="3rem" viewBox="0 -960 960 960" fill="var(--text-color)"><path d="M80-120v-720h400v160h400v320h-80v-240H480v80h80v80h-80v80h80v80h-80v80h160v80H80Zm80-80h80v-80h-80v80Zm0-160h80v-80h-80v80Zm0-160h80v-80h-80v80Zm0-160h80v-80h-80v80Zm160 480h80v-80h-80v80Zm0-160h80v-80h-80v80Zm0-160h80v-80h-80v80Zm0-160h80v-80h-80v80ZM800-40v-80h-80v-80h80v-80h80v80h80v80h-80v80h-80ZM640-440v-80h80v80h-80Zm0 160v-80h80v80h-80Z"/></svg>
<herotitle>Create Space</herotitle>
<p>Create a space for your community</p>
<br>
<div class="input-group">
<label for="addgroup-name">Name</label>
<input type="text" id="createspace-name" placeholder="My space" class="forminput">
</div>
<div class="input-group">
<button class="submit-button" onclick="createGroup()">
Create space
</button>
</div>
</div>
`;
roomContentMain.style.transform = "";
roomContentMain.style.opacity = "";
}
function gotoHome() {
}

View file

@ -0,0 +1,47 @@
var addDmScreen = `
<div style="display: flex;justify-content: center;align-items: center;height:100%;flex-direction: column;text-align: center;">
<svg xmlns="http://www.w3.org/2000/svg" width="3rem" viewBox="0 -960 960 960" fill="var(--text-color)"><path d="M120-160v-600q0-33 23.5-56.5T200-840h480q33 0 56.5 23.5T760-760v203q-10-2-20-2.5t-20-.5q-10 0-20 .5t-20 2.5v-203H200v400h283q-2 10-2.5 20t-.5 20q0 10 .5 20t2.5 20H240L120-160Zm160-440h320v-80H280v80Zm0 160h200v-80H280v80Zm400 280v-120H560v-80h120v-120h80v120h120v80H760v120h-80ZM200-360v-400 400Z"/></svg>
<herotitle><blah>title.add.chat</blah></herotitle>
<p><blah>desc.add.chat</blah></p>
<br>
<div class="input-group">
<label for="addchat-username"><blah>title.username</blah></label>
<input type="text" id="addchat-username" placeholder="name@example.com" class="forminput">
</div>
<div class="input-group">
<button class="submit-button blah" onclick="addDm()">title.add.chat</button>
</div>
</div>
`
var createGroupScreen = `
<div style="display: flex;justify-content: center;align-items: center;height:100%;flex-direction: column;text-align: center;">
<svg xmlns="http://www.w3.org/2000/svg" width="3rem" viewBox="0 -960 960 960" fill="var(--text-color)"><path d="M500-482q29-32 44.5-73t15.5-85q0-44-15.5-85T500-798q60 8 100 53t40 105q0 60-40 105t-100 53Zm220 322v-120q0-36-16-68.5T662-406q51 18 94.5 46.5T800-280v120h-80Zm80-280v-80h-80v-80h80v-80h80v80h80v80h-80v80h-80Zm-593-87q-47-47-47-113t47-113q47-47 113-47t113 47q47 47 47 113t-47 113q-47 47-113 47t-113-47ZM0-160v-112q0-34 17.5-62.5T64-378q62-31 126-46.5T320-440q66 0 130 15.5T576-378q29 15 46.5 43.5T640-272v112H0Zm320-400q33 0 56.5-23.5T400-640q0-33-23.5-56.5T320-720q-33 0-56.5 23.5T240-640q0 33 23.5 56.5T320-560ZM80-240h480v-32q0-11-5.5-20T540-306q-54-27-109-40.5T320-360q-56 0-111 13.5T100-306q-9 5-14.5 14T80-272v32Zm240-400Zm0 400Z"/></svg>
<herotitle><blah>title.create.group</blah></herotitle>
<p><blah>desc.create.group</blah></p>
<br>
<div class="input-group">
<label for="creategroup-name"><blah>title.name</blah></label>
<input type="text" id="creategroup-name" placeholder="{blah(placeholder.create.group.input)}" class="forminput">
</div>
<div class="input-group">
<button class="submit-button blah" onclick="createGroup()">title.create.group</button>
</div>
</div>
`;
var createSpaceScreen = `
<div style="display: flex;justify-content: center;align-items: center;height:100%;flex-direction: column;text-align: center;">
<svg xmlns="http://www.w3.org/2000/svg" width="3rem" viewBox="0 -960 960 960" fill="var(--text-color)"><path d="M80-120v-720h400v160h400v320h-80v-240H480v80h80v80h-80v80h80v80h-80v80h160v80H80Zm80-80h80v-80h-80v80Zm0-160h80v-80h-80v80Zm0-160h80v-80h-80v80Zm0-160h80v-80h-80v80Zm160 480h80v-80h-80v80Zm0-160h80v-80h-80v80Zm0-160h80v-80h-80v80Zm0-160h80v-80h-80v80ZM800-40v-80h-80v-80h80v-80h80v80h80v80h-80v80h-80ZM640-440v-80h80v80h-80Zm0 160v-80h80v80h-80Z"/></svg>
<herotitle><blah>title.create.space</blah></herotitle>
<p><blah>desc.create.space</blah></p>
<br>
<div class="input-group">
<label for="addgroup-name"><blah>title.name</blah></label>
<input type="text" id="createspace-name" placeholder="{blah(placeholder.create.space.input)}" class="forminput">
</div>
<div class="input-group">
<button class="submit-button blah" onclick="createGroup()">title.create.space</button>
</div>
</div>
`;

View file

@ -392,3 +392,11 @@ sidebarelement:has(.icon-button:active) indicator:not(.active) {
border-radius: 0.8rem; border-radius: 0.8rem;
transform: translateY(calc( ( var(--icon-button-height) + (var(--button-margin) * 2) ) / 2 - 0.6rem)); transform: translateY(calc( ( var(--icon-button-height) + (var(--button-margin) * 2) ) / 2 - 0.6rem));
} }
blah {
all: inherit;
padding: 0;
margin: 0;
display: inline;
opacity: 1;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Before After
Before After

File diff suppressed because one or more lines are too long

View file

@ -3,7 +3,7 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover"> <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<title>Larpix Client</title> <title>Miarven</title>
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="style.css">
<link rel="icon" type="image/svg+xml" href="favicon.svg"> <link rel="icon" type="image/svg+xml" href="favicon.svg">
</head> </head>
@ -19,7 +19,7 @@
<sidebarelement id="sidebar-home"> <sidebarelement id="sidebar-home">
<indicator class="active"> <indicator class="active">
</indicator> </indicator>
<button class="icon-button" aria-label="Homepage" onclick="gotoHome()"> <button class="icon-button" onclick="gotoHome()">
<svg viewBox="-1 -1 18 18" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg viewBox="-1 -1 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path <path
d="M1 6V15H6V11C6 9.89543 6.89543 9 8 9C9.10457 9 10 9.89543 10 11V15H15V6L8 0L1 6Z" d="M1 6V15H6V11C6 9.89543 6.89543 9 8 9C9.10457 9 10 9.89543 10 11V15H15V6L8 0L1 6Z"
@ -35,7 +35,7 @@
<sidebarelement id="sidebar-add"> <sidebarelement id="sidebar-add">
<indicator> <indicator>
</indicator> </indicator>
<button class="icon-button" aria-label="Add space" onclick="gotoCreateSpace()"> <button class="icon-button" onclick="gotoCreateSpace()">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="12" y1="5" x2="12" y2="19"></line> <line x1="12" y1="5" x2="12" y2="19"></line>
@ -48,14 +48,14 @@
<sidebarelement id="sidebar-inbox"> <sidebarelement id="sidebar-inbox">
<indicator> <indicator>
</indicator> </indicator>
<button class="icon-button" aria-label="Inbox" onclick="gotoInbox()"> <button class="icon-button" onclick="gotoInbox()">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="currentColor"><path d="M216-144q-29 0-50.5-21.5T144-216v-528q0-29.7 21.5-50.85Q187-816 216-816h528q29.7 0 50.85 21.15Q816-773.7 816-744v528q0 29-21.15 50.5T744-144H216Zm0-72h528v-144H632q-23 43-63.5 69.5T480-264q-49 0-89.5-26T328-360H216v144Zm332-148q28-28 28-68h168v-312H216v312h168q0 40 28 68t68 28q40 0 68-28ZM216-216h528-528Z"/></svg> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -960 960 960" fill="currentColor"><path d="M216-144q-29 0-50.5-21.5T144-216v-528q0-29.7 21.5-50.85Q187-816 216-816h528q29.7 0 50.85 21.15Q816-773.7 816-744v528q0 29-21.15 50.5T744-144H216Zm0-72h528v-144H632q-23 43-63.5 69.5T480-264q-49 0-89.5-26T328-360H216v144Zm332-148q28-28 28-68h168v-312H216v312h168q0 40 28 68t68 28q40 0 68-28ZM216-216h528-528Z"/></svg>
</button> </button>
</sidebarelement> </sidebarelement>
<sidebarelement id="sidebar-profile"> <sidebarelement id="sidebar-profile">
<indicator> <indicator>
</indicator> </indicator>
<button class="icon-button" aria-label="Profile" onclick="gotoSideProfilePopup()"> <button class="icon-button" onclick="gotoSideProfilePopup()">
<img id="sidebar-pfp"> <img id="sidebar-pfp">
</button> </button>
</sidebarelement> </sidebarelement>
@ -63,17 +63,17 @@
<sidebar class="second" id="roomsbar"> <sidebar class="second" id="roomsbar">
<roomtopbar> <roomtopbar>
Home <blah>title.home</blah>
</roomtopbar> </roomtopbar>
<div class="sidebar-section-header"> <div class="sidebar-section-header">
<button class="collapse-text-button" id="collapse-dms"> <button class="collapse-text-button" id="collapse-dms">
<span>Direct messages</span> <span><blah>title.dms</blah></span>
<svg class="chevron" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" <svg class="chevron" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="6 9 12 15 18 9"></polyline> <polyline points="6 9 12 15 18 9"></polyline>
</svg> </svg>
</button> </button>
<button class="add-action-button" aria-label="Add Direct Message" id="add-dm-btn"> <button class="add-action-button" id="add-dm-btn">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="12" y1="5" x2="12" y2="19"></line> <line x1="12" y1="5" x2="12" y2="19"></line>
@ -84,13 +84,13 @@
<div class="sidebar-section-header"> <div class="sidebar-section-header">
<button class="collapse-text-button" id="collapse-groups"> <button class="collapse-text-button" id="collapse-groups">
<span>Groups</span> <span><blah>title.groups</blah></span>
<svg class="chevron" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" <svg class="chevron" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none"
stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polyline points="6 9 12 15 18 9"></polyline> <polyline points="6 9 12 15 18 9"></polyline>
</svg> </svg>
</button> </button>
<button class="add-action-button" aria-label="Add Group" id="add-group-btn"> <button class="add-action-button" id="add-group-btn">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor"
stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="12" y1="5" x2="12" y2="19"></line> <line x1="12" y1="5" x2="12" y2="19"></line>
@ -102,13 +102,13 @@
<roomcontent> <roomcontent>
<roomtopbar> <roomtopbar>
Splash <blah>title.splash</blah>
</roomtopbar> </roomtopbar>
<roomcontent2> <roomcontent2>
<div style="display: flex;justify-content: center;align-items: center;height:100%;flex-direction: column;text-align: center;"> <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"> <img src="favicon.svg" style="width: 6rem">
<herotitle>Welcome to Miarven</herotitle> <herotitle><blah>title.welcome.splash</blah></herotitle>
<p>First Larpix client. <span class="aqua">v<span class="clientver aqua">1.0</span></span></p> <p><blah>desc.welcome.splash</blah>. <span class="aqua">v<span class="clientver aqua">1.0</span></span></p>
</div> </div>
</roomcontent2> </roomcontent2>
</roomcontent> </roomcontent>
@ -117,7 +117,7 @@
</main> </main>
</body> </body>
</html> </html>
<script src="main.js"></script> <script src="screens.js"></script>
<script> <script>
async function start() { async function start() {
updateLoadingStatus("loading.loading"); updateLoadingStatus("loading.loading");
@ -190,4 +190,5 @@
} }
</script> </script>
<script src="main.js"></script>
<script src="userscript.js"></script> <script src="userscript.js"></script>

View file

@ -3,7 +3,7 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover"> <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
<title>Larpix - Authentication</title> <title>Miarven - Login</title>
<link rel="stylesheet" href="../style.css"> <link rel="stylesheet" href="../style.css">
<link rel="icon" type="image/svg+xml" href="../favicon.svg"> <link rel="icon" type="image/svg+xml" href="../favicon.svg">
<style> <style>
@ -11,7 +11,7 @@
font-size: max(17px, calc(100vw / 100)); font-size: max(17px, calc(100vw / 100));
} }
body { body, main {
justify-content: center; justify-content: center;
align-items: center; align-items: center;
background-color: var(--main-bg-color); background-color: var(--main-bg-color);
@ -153,117 +153,118 @@
</style> </style>
</head> </head>
<body> <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;">
<div class="auth-card">
<div class="auth-container" id="auth-container">
<div class="auth-card"> <div class="auth-box" id="login-box">
<div class="auth-container" id="auth-container"> <div class="auth-header">
<h1>Larpix</h1>
<p><blah>title.sign.in.to</blah></p>
</div>
<div class="auth-box" id="login-box"> <form id="form-login">
<div class="auth-header"> <div class="input-group">
<h1>Larpix</h1> <label for="login-host"><blah>title.server.host</blah></label>
<p>Sign in to your larpix instance.</p> <input type="text" id="login-host" placeholder="example.com" autocomplete="url" onchange="loginHostChanged()">
</div> <p class="mininote serverstatus"><blah>loading.connecting</blah></p>
</div>
<form id="form-login"> <div class="input-group">
<div class="input-group"> <label for="login-username"><blah>title.username</blah></label>
<label for="login-host">Server Host</label> <input type="text" id="login-username" placeholder="{blah(placeholder.username)}" autocomplete="username">
<input type="text" id="login-host" placeholder="example.com" autocomplete="url" onchange="loginHostChanged()"> </div>
<p class="mininote serverstatus">Connecting...</p>
<div class="input-group">
<label for="login-password"><blah>title.password</blah></label>
<input type="password" id="login-password" placeholder="••••••••" autocomplete="current-password">
</div>
<button type="submit" class="submit-button blah">title.sign.in</button>
</form>
<div class="footer-links">
<span class="footer-link-toggle" id="to-register">
<blah>title.new.here.?</blah> <strong class="blah">title.create.an.account</strong>
</span>
</div>
</div> </div>
<div class="input-group"> <div class="auth-box" id="register-box">
<label for="login-username">Username</label> <div class="auth-header">
<input type="text" id="login-username" placeholder="username" autocomplete="username"> <h1><blah>join.larpix</blah></h1>
<p><blah>title.create.new.account</blah></p>
</div>
<form id="form-register">
<div class="input-group">
<label for="reg-host"><blah>title.server.host</blah></label>
<input type="text" id="reg-host" placeholder="example.com" autocomplete="url" onchange="regHostChanged()">
<p class="mininote serverstatus"><blah>loading.connecting</blah></p>
</div>
<div class="input-group">
<label for="reg-username"><blah>title.username</blah></label>
<input type="text" id="reg-username" placeholder="{blah(placeholder.username)}" autocomplete="username">
</div>
<div class="input-group">
<label for="reg-password"><blah>title.password</blah></label>
<input type="password" id="reg-password" placeholder="••••••••" autocomplete="new-password">
<p class="red mininote"><blah>notice.use.strong.pass</blah></p>
</div>
<div class="input-group">
<label for="reg-confirm"><blah>title.confirm.password</blah></label>
<input type="password" id="reg-confirm" placeholder="••••••••" autocomplete="new-password">
</div>
<button type="submit" class="submit-button blah" id="register-button">title.sign.up</button>
</form>
<div class="footer-links">
<span class="footer-link-toggle" id="to-login">
<blah>title.already.registered.?</blah> <strong class="blah">title.back.to.login</strong>
</span>
</div>
</div> </div>
<div class="input-group"> <div class="auth-box" id="captcha-box">
<label for="login-password">Password</label> <div class="auth-header">
<input type="password" id="login-password" placeholder="••••••••" autocomplete="current-password"> <h1><blah>title.verify</blah></h1>
</div> <p><blah>title.captcha.desc</blah></p>
</div>
<div class="captcha-img">
<img src="" alt="Captcha" id="captcha-image">
</div>
<form id="form-captcha">
<div class="input-group">
<label for="captcha-input"><blah>title.captcha.code</blah></label>
<input type="text" id="captcha-input" placeholder="{blah(placeholder.captcha.code)}" autocomplete="off">
<button type="submit" class="submit-button"> </div>
Sign In <div class="input-group" id="regkey-group">
</button> <label for="regkey-input"><blah>title.invitation.code</blah></label>
</form> <input type="text" id="regkey-input" placeholder="{blah(placeholder.invitation.code)}" autocomplete="off">
</div>
<div class="footer-links"> <button type="submit" class="submit-button blah">title.verify</button>
<span class="footer-link-toggle" id="to-register"> </form>
New here? <strong>Create an account</strong> <div class="footer-links">
<span class="footer-link-toggle" id="back-to-reg">
<strong class="blah">title.back.to.register</strong>
</span> </span>
</div>
</div>
</div> </div>
</div> </div>
</main>
<div class="auth-box" id="register-box">
<div class="auth-header">
<h1>Join Larpix</h1>
<p>Create new larpix account.</p>
</div>
<form id="form-register">
<div class="input-group">
<label for="reg-host">Server Host</label>
<input type="text" id="reg-host" placeholder="example.com" autocomplete="url" onchange="regHostChanged()">
<p class="mininote serverstatus">Connecting...</p>
</div>
<div class="input-group">
<label for="reg-username">Username</label>
<input type="text" id="reg-username" placeholder="Choose username" autocomplete="username">
</div>
<div class="input-group">
<label for="reg-password">Password</label>
<input type="password" id="reg-password" placeholder="Create password" autocomplete="new-password">
<p class="red mininote">Remember to use a strong password! It will be used to encrypt your keys</p>
</div>
<div class="input-group">
<label for="reg-confirm">Confirm Password</label>
<input type="password" id="reg-confirm" placeholder="Repeat password" autocomplete="new-password">
</div>
<button type="submit" class="submit-button" id="register-button">
Sign Up
</button>
</form>
<div class="footer-links">
<span class="footer-link-toggle" id="to-login">
Already a member? <strong>Back to Login</strong>
</span>
</div>
</div>
<div class="auth-box" id="captcha-box">
<div class="auth-header">
<h1>Verify</h1>
<p>Prove you are a human.</p>
</div>
<div class="captcha-img">
<img src="" alt="Captcha" id="captcha-image">
</div>
<form id="form-captcha">
<div class="input-group">
<label for="captcha-input">Captcha code</label>
<input type="text" id="captcha-input" placeholder="Captcha code" autocomplete="off">
</div>
<div class="input-group" id="regkey-group">
<label for="regkey-input">Invitation code</label>
<input type="text" id="regkey-input" placeholder="Invitation code" autocomplete="off">
</div>
<button type="submit" class="submit-button">
Verify
</button>
</form>
<div class="footer-links">
<span class="footer-link-toggle" id="back-to-reg">
<strong>Back to registration</strong>
</span>
</div>
</div>
</div>
</div>
</body> </body>
</html> </html>
<script src="../main.js"></script> <script src="../main.js"></script>
@ -294,6 +295,16 @@
const registerButton = document.getElementById("register-button"); const registerButton = document.getElementById("register-button");
const regKeyGroup = document.getElementById("regkey-group"); const regKeyGroup = document.getElementById("regkey-group");
async function start() {
updateLoadingStatus("loading.loading");
//
updateLoadingStatus("loading.done");
await loadingFadeOut();
}
toRegister.addEventListener('click', () => { toRegister.addEventListener('click', () => {
container.className = 'auth-container show-register'; container.className = 'auth-container show-register';
}); });
@ -316,11 +327,13 @@
if (res.startsWith("success:")) if (res.startsWith("success:"))
{ {
showBlahNotification(res); showBlahNotification(res);
await delay(1000); await delay(800);
localStorage.setItem("username", loginUsername.value); localStorage.setItem("username", loginUsername.value);
localStorage.setItem("password", loginPassword.value); localStorage.setItem("password", loginPassword.value);
localStorage.setItem("host", loginHost.value); localStorage.setItem("host", loginHost.value);
await loadingFadeIn();
window.location.href = "../"; window.location.href = "../";
} }
else else

View file

@ -24,6 +24,9 @@ var url = `${prot}//${window.location.hostname}/_larpix`;
var params = new URLSearchParams(window.location.search); var params = new URLSearchParams(window.location.search);
try { try {
var loadingScreen = document.querySelector("loading");
var mainScreen = document.querySelector("main");
var loadingStatus = document.getElementById("loadingstatus"); var loadingStatus = document.getElementById("loadingstatus");
var collapseDmsBtn = document.getElementById("collapse-dms"); var collapseDmsBtn = document.getElementById("collapse-dms");
@ -256,7 +259,6 @@ async function decryptString(base64Text, passphrase) {
async function fetchPost(url, value) { async function fetchPost(url, value) {
let response = await fetch(url, { let response = await fetch(url, {
method: "POST", method: "POST",
credentials: "omit",
body: value, body: value,
headers: { headers: {
"secret": await encryptWithNonce(passwordHash, passwordHash, await getNonce(username, passwordHash)) "secret": await encryptWithNonce(passwordHash, passwordHash, await getNonce(username, passwordHash))
@ -270,7 +272,6 @@ async function fetchPostEnc(url, value) {
let nonce = await getNonce(username, passwordHash); let nonce = await getNonce(username, passwordHash);
let response = await fetch(url, { let response = await fetch(url, {
method: "POST", method: "POST",
credentials: "omit",
body: await encryptWithNonce(value, passwordHash, nonce), body: await encryptWithNonce(value, passwordHash, nonce),
headers: { headers: {
"secret": await encryptWithNonce(passwordHash, passwordHash, nonce) "secret": await encryptWithNonce(passwordHash, passwordHash, nonce)
@ -283,7 +284,6 @@ async function fetchPostEnc(url, value) {
async function fetchAsync(url) { async function fetchAsync(url) {
let response = await fetch(url, { let response = await fetch(url, {
method: "GET", method: "GET",
credentials: "omit"
}); });
let data = await response.text(); let data = await response.text();
@ -293,7 +293,6 @@ async function fetchAsync(url) {
async function fetchAsyncWAuth(url) { async function fetchAsyncWAuth(url) {
let response = await fetch(url, { let response = await fetch(url, {
method: "GET", method: "GET",
credentials: "omit",
headers: { headers: {
"secret": await encryptWithNonce(passwordHash, passwordHash, await getNonce(username, passwordHash)) "secret": await encryptWithNonce(passwordHash, passwordHash, await getNonce(username, passwordHash))
} }
@ -312,7 +311,6 @@ async function Auth(username, password) {
let passwordHash = await hashSHA3_512(password); let passwordHash = await hashSHA3_512(password);
let response = await fetch(`${url}/auth?u=${username}`, { let response = await fetch(`${url}/auth?u=${username}`, {
method: "GET", method: "GET",
credentials: "omit",
headers: { headers: {
"secret": await encryptWithNonce(passwordHash, passwordHash, await getNonce(username, passwordHash)) "secret": await encryptWithNonce(passwordHash, passwordHash, await getNonce(username, passwordHash))
} }
@ -330,7 +328,6 @@ async function fetchEncrypted(request, body) {
let response = await fetch(`${url}/encryptedrequest?u=${username}`, { let response = await fetch(`${url}/encryptedrequest?u=${username}`, {
method: "POST", method: "POST",
credentials: "omit",
body: await encryptWithNonce( body: await encryptWithNonce(
JSON.stringify({ JSON.stringify({
string1: request, string1: request,
@ -532,8 +529,6 @@ function updateLoadingStatus(message) {
} }
async function loadingFadeOut() { async function loadingFadeOut() {
let loadingScreen = document.querySelector("loading");
let mainScreen = document.querySelector("main");
mainScreen.style.transform = "scale(0.85)"; mainScreen.style.transform = "scale(0.85)";
mainScreen.style.opacity = "0"; mainScreen.style.opacity = "0";
@ -546,8 +541,20 @@ async function loadingFadeOut() {
await delay(200); await delay(200);
mainScreen.style.transform = ""; mainScreen.style.transform = "";
mainScreen.style.opacity = ""; mainScreen.style.opacity = "";
}
async function loadingFadeIn() {
loadingScreen.style.transform = "scale(0.85)";
loadingScreen.style.opacity = "0";
mainScreen.style.transform = "scale(0.85)";
mainScreen.style.opacity = "0";
await delay(200);
mainScreen.style.display = "none";
loadingScreen.style.display = "";
await delay(200);
loadingScreen.style.transform = "";
loadingScreen.style.opacity = "";
} }
@ -565,6 +572,25 @@ async function initBlahs() {
res = await fetchAsync(`${path}blah/en-us.json`); res = await fetchAsync(`${path}blah/en-us.json`);
} }
blah = JSON.parse(res); blah = JSON.parse(res);
let blahTags = document.getElementsByTagName("blah");
for (let i = 0; i < blahTags.length; i++) {
blahTags[i].innerHTML = processBlah(blahTags[i].innerHTML);
}
blahTags = document.getElementsByClassName("blah");
for (let i = 0; i < blahTags.length; i++) {
blahTags[i].innerHTML = processBlah(blahTags[i].innerHTML);
}
let placeholders = document.querySelectorAll("[placeholder]");
for (let i = 0; i < placeholders.length; i++) {
if (placeholders[i].placeholder.startsWith("{blah("))
{
let value = placeholders[i].placeholder.split("{blah(")[1].split(")}")[0];
placeholders[i].placeholder = processBlah(value);
}
}
} }
function processBlah(blahmessage) { function processBlah(blahmessage) {
@ -634,65 +660,69 @@ collapseGroupsBtn.addEventListener("click", () => {
collapseGroupsBtn.classList.toggle("collapsed"); collapseGroupsBtn.classList.toggle("collapsed");
}); });
addDmBtn.addEventListener("click", async () => {
//Invite to dm, addDmScreen, false
async function switchRoomContent(title, content, showRoomBar)
{
roomContentMain.style.transform = "scale(0.85)"; roomContentMain.style.transform = "scale(0.85)";
roomContentMain.style.opacity = "0"; roomContentMain.style.opacity = "0";
await delay(200); await delay(200);
roomTopBar.innerHTML = "Invite to dm"; roomTopBar.innerHTML = processBlah(title);
roomDetailsBar.style.display = "none"; roomDetailsBar.style.display = showRoomBar ? "flex" : "none";
//content blah parsing
let parser = new DOMParser();
let doc = parser.parseFromString(content, "text/html");
let blahTags = doc.getElementsByTagName("blah");
for (let i = 0; i < blahTags.length; i++) {
blahTags[i].innerHTML = processBlah(blahTags[i].innerHTML);
}
blahTags = doc.getElementsByClassName("blah");
for (let i = 0; i < blahTags.length; i++) {
blahTags[i].innerHTML = processBlah(blahTags[i].innerHTML);
}
let placeholders = doc.querySelectorAll("[placeholder]");
for (let i = 0; i < placeholders.length; i++) {
if (placeholders[i].placeholder.startsWith("{blah("))
{
let value = placeholders[i].placeholder.split("{blah(")[1].split(")}")[0];
placeholders[i].placeholder = processBlah(value);
}
}
roomContentMain.innerHTML = doc.body.innerHTML;
roomContentMain.innerHTML =
`
<div style="display: flex;justify-content: center;align-items: center;height:100%;flex-direction: column;text-align: center;">
<svg xmlns="http://www.w3.org/2000/svg" width="3rem" viewBox="0 -960 960 960" fill="var(--text-color)"><path d="M120-160v-600q0-33 23.5-56.5T200-840h480q33 0 56.5 23.5T760-760v203q-10-2-20-2.5t-20-.5q-10 0-20 .5t-20 2.5v-203H200v400h283q-2 10-2.5 20t-.5 20q0 10 .5 20t2.5 20H240L120-160Zm160-440h320v-80H280v80Zm0 160h200v-80H280v80Zm400 280v-120H560v-80h120v-120h80v120h120v80H760v120h-80ZM200-360v-400 400Z"/></svg>
<herotitle>Add Chat</herotitle>
<p>Add a private, encrypted chat by entering a username</p>
<br>
<div class="input-group">
<label for="addchat-username">Username</label>
<input type="text" id="addchat-username" placeholder="username:serverhost" class="forminput">
</div>
<div class="input-group">
<button class="submit-button" onclick="addDm()">
Add chat
</button>
</div>
</div>
`;
roomContentMain.style.transform = ""; roomContentMain.style.transform = "";
roomContentMain.style.opacity = ""; roomContentMain.style.opacity = "";
}
addDmBtn.addEventListener("click", async () => {
switchRoomContent("title.create.dm", addDmScreen, false);
}); });
addGroupBtn.addEventListener("click", async () => { addGroupBtn.addEventListener("click", async () => {
roomContentMain.style.transform = "scale(0.85)"; switchRoomContent("title.create.group", createGroupScreen, false);
roomContentMain.style.opacity = "0";
await delay(200);
roomTopBar.innerHTML = "Create group";
roomDetailsBar.style.display = "none";
roomContentMain.innerHTML =
`
<div style="display: flex;justify-content: center;align-items: center;height:100%;flex-direction: column;text-align: center;">
<svg xmlns="http://www.w3.org/2000/svg" width="3rem" viewBox="0 -960 960 960" fill="var(--text-color)"><path d="M500-482q29-32 44.5-73t15.5-85q0-44-15.5-85T500-798q60 8 100 53t40 105q0 60-40 105t-100 53Zm220 322v-120q0-36-16-68.5T662-406q51 18 94.5 46.5T800-280v120h-80Zm80-280v-80h-80v-80h80v-80h80v80h80v80h-80v80h-80Zm-593-87q-47-47-47-113t47-113q47-47 113-47t113 47q47 47 47 113t-47 113q-47 47-113 47t-113-47ZM0-160v-112q0-34 17.5-62.5T64-378q62-31 126-46.5T320-440q66 0 130 15.5T576-378q29 15 46.5 43.5T640-272v112H0Zm320-400q33 0 56.5-23.5T400-640q0-33-23.5-56.5T320-720q-33 0-56.5 23.5T240-640q0 33 23.5 56.5T320-560ZM80-240h480v-32q0-11-5.5-20T540-306q-54-27-109-40.5T320-360q-56 0-111 13.5T100-306q-9 5-14.5 14T80-272v32Zm240-400Zm0 400Z"/></svg>
<herotitle>Create Group</herotitle>
<p>Create a private, encrypted group</p>
<br>
<div class="input-group">
<label for="creategroup-name">Name</label>
<input type="text" id="creategroup-name" placeholder="My group" class="forminput">
</div>
<div class="input-group">
<button class="submit-button" onclick="createGroup()">
Create group
</button>
</div>
</div>
`;
roomContentMain.style.transform = "";
roomContentMain.style.opacity = "";
}); });
function gotoSideProfilePopup() {
}
function gotoInbox() {
}
async function gotoCreateSpace() {
switchRoomContent("title.create.space", createSpaceScreen, false);
}
function gotoHome() {
}
/* replaced with css /* replaced with css
sidebarHomeButton.addEventListener("mouseenter", () => { sidebarHomeButton.addEventListener("mouseenter", () => {
sidebarHomeIndicator.classList.add("hover"); sidebarHomeIndicator.classList.add("hover");
@ -722,41 +752,3 @@ sidebarInboxButton.addEventListener("mouseleave", () => {
sidebarInboxIndicator.classList.remove("hover"); sidebarInboxIndicator.classList.remove("hover");
}); });
*/ */
function gotoSideProfilePopup() {
}
function gotoInbox() {
}
async function gotoCreateSpace() {
roomContentMain.style.transform = "scale(0.85)";
roomContentMain.style.opacity = "0";
await delay(200);
roomTopBar.innerHTML = "Create space";
roomDetailsBar.style.display = "none";
roomContentMain.innerHTML =
`
<div style="display: flex;justify-content: center;align-items: center;height:100%;flex-direction: column;text-align: center;">
<svg xmlns="http://www.w3.org/2000/svg" width="3rem" viewBox="0 -960 960 960" fill="var(--text-color)"><path d="M80-120v-720h400v160h400v320h-80v-240H480v80h80v80h-80v80h80v80h-80v80h160v80H80Zm80-80h80v-80h-80v80Zm0-160h80v-80h-80v80Zm0-160h80v-80h-80v80Zm0-160h80v-80h-80v80Zm160 480h80v-80h-80v80Zm0-160h80v-80h-80v80Zm0-160h80v-80h-80v80Zm0-160h80v-80h-80v80ZM800-40v-80h-80v-80h80v-80h80v80h80v80h-80v80h-80ZM640-440v-80h80v80h-80Zm0 160v-80h80v80h-80Z"/></svg>
<herotitle>Create Space</herotitle>
<p>Create a space for your community</p>
<br>
<div class="input-group">
<label for="addgroup-name">Name</label>
<input type="text" id="createspace-name" placeholder="My space" class="forminput">
</div>
<div class="input-group">
<button class="submit-button" onclick="createGroup()">
Create space
</button>
</div>
</div>
`;
roomContentMain.style.transform = "";
roomContentMain.style.opacity = "";
}
function gotoHome() {
}

47
webroot/screens.js Normal file
View file

@ -0,0 +1,47 @@
var addDmScreen = `
<div style="display: flex;justify-content: center;align-items: center;height:100%;flex-direction: column;text-align: center;">
<svg xmlns="http://www.w3.org/2000/svg" width="3rem" viewBox="0 -960 960 960" fill="var(--text-color)"><path d="M120-160v-600q0-33 23.5-56.5T200-840h480q33 0 56.5 23.5T760-760v203q-10-2-20-2.5t-20-.5q-10 0-20 .5t-20 2.5v-203H200v400h283q-2 10-2.5 20t-.5 20q0 10 .5 20t2.5 20H240L120-160Zm160-440h320v-80H280v80Zm0 160h200v-80H280v80Zm400 280v-120H560v-80h120v-120h80v120h120v80H760v120h-80ZM200-360v-400 400Z"/></svg>
<herotitle><blah>title.add.chat</blah></herotitle>
<p><blah>desc.add.chat</blah></p>
<br>
<div class="input-group">
<label for="addchat-username"><blah>title.username</blah></label>
<input type="text" id="addchat-username" placeholder="name@example.com" class="forminput">
</div>
<div class="input-group">
<button class="submit-button blah" onclick="addDm()">title.add.chat</button>
</div>
</div>
`
var createGroupScreen = `
<div style="display: flex;justify-content: center;align-items: center;height:100%;flex-direction: column;text-align: center;">
<svg xmlns="http://www.w3.org/2000/svg" width="3rem" viewBox="0 -960 960 960" fill="var(--text-color)"><path d="M500-482q29-32 44.5-73t15.5-85q0-44-15.5-85T500-798q60 8 100 53t40 105q0 60-40 105t-100 53Zm220 322v-120q0-36-16-68.5T662-406q51 18 94.5 46.5T800-280v120h-80Zm80-280v-80h-80v-80h80v-80h80v80h80v80h-80v80h-80Zm-593-87q-47-47-47-113t47-113q47-47 113-47t113 47q47 47 47 113t-47 113q-47 47-113 47t-113-47ZM0-160v-112q0-34 17.5-62.5T64-378q62-31 126-46.5T320-440q66 0 130 15.5T576-378q29 15 46.5 43.5T640-272v112H0Zm320-400q33 0 56.5-23.5T400-640q0-33-23.5-56.5T320-720q-33 0-56.5 23.5T240-640q0 33 23.5 56.5T320-560ZM80-240h480v-32q0-11-5.5-20T540-306q-54-27-109-40.5T320-360q-56 0-111 13.5T100-306q-9 5-14.5 14T80-272v32Zm240-400Zm0 400Z"/></svg>
<herotitle><blah>title.create.group</blah></herotitle>
<p><blah>desc.create.group</blah></p>
<br>
<div class="input-group">
<label for="creategroup-name"><blah>title.name</blah></label>
<input type="text" id="creategroup-name" placeholder="{blah(placeholder.create.group.input)}" class="forminput">
</div>
<div class="input-group">
<button class="submit-button blah" onclick="createGroup()">title.create.group</button>
</div>
</div>
`;
var createSpaceScreen = `
<div style="display: flex;justify-content: center;align-items: center;height:100%;flex-direction: column;text-align: center;">
<svg xmlns="http://www.w3.org/2000/svg" width="3rem" viewBox="0 -960 960 960" fill="var(--text-color)"><path d="M80-120v-720h400v160h400v320h-80v-240H480v80h80v80h-80v80h80v80h-80v80h160v80H80Zm80-80h80v-80h-80v80Zm0-160h80v-80h-80v80Zm0-160h80v-80h-80v80Zm0-160h80v-80h-80v80Zm160 480h80v-80h-80v80Zm0-160h80v-80h-80v80Zm0-160h80v-80h-80v80Zm0-160h80v-80h-80v80ZM800-40v-80h-80v-80h80v-80h80v80h80v80h-80v80h-80ZM640-440v-80h80v80h-80Zm0 160v-80h80v80h-80Z"/></svg>
<herotitle><blah>title.create.space</blah></herotitle>
<p><blah>desc.create.space</blah></p>
<br>
<div class="input-group">
<label for="addgroup-name"><blah>title.name</blah></label>
<input type="text" id="createspace-name" placeholder="{blah(placeholder.create.space.input)}" class="forminput">
</div>
<div class="input-group">
<button class="submit-button blah" onclick="createGroup()">title.create.space</button>
</div>
</div>
`;

View file

@ -392,3 +392,11 @@ sidebarelement:has(.icon-button:active) indicator:not(.active) {
border-radius: 0.8rem; border-radius: 0.8rem;
transform: translateY(calc( ( var(--icon-button-height) + (var(--button-margin) * 2) ) / 2 - 0.6rem)); transform: translateY(calc( ( var(--icon-button-height) + (var(--button-margin) * 2) ) / 2 - 0.6rem));
} }
blah {
all: inherit;
padding: 0;
margin: 0;
display: inline;
opacity: 1;
}