Add cool animations and placeholder pfps
This commit is contained in:
parent
8402564b28
commit
e0c044a894
13 changed files with 624 additions and 204 deletions
|
|
@ -36,5 +36,13 @@
|
||||||
"passwords.not.match": "Passwords do not match",
|
"passwords.not.match": "Passwords do not match",
|
||||||
"password.cant.empty": "Password cannot be empty",
|
"password.cant.empty": "Password cannot be empty",
|
||||||
"username.cant.empty": "Username cannot be empty",
|
"username.cant.empty": "Username cannot be empty",
|
||||||
"bad.request": "Bad request"
|
"bad.request": "Bad request",
|
||||||
|
|
||||||
|
"letters": "letters",
|
||||||
|
"numbers": "numbers",
|
||||||
|
"underscores": "underscores",
|
||||||
|
|
||||||
|
"loading.connecting": "Connecting...",
|
||||||
|
"loading.loading": "Loading...",
|
||||||
|
"loading.done": "Ready!"
|
||||||
}
|
}
|
||||||
|
|
@ -8,11 +8,18 @@
|
||||||
<link rel="icon" type="image/svg+xml" href="favicon.svg">
|
<link rel="icon" type="image/svg+xml" href="favicon.svg">
|
||||||
</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;">
|
||||||
<sidebar>
|
<sidebar>
|
||||||
<sidebarelement id="sidebar-home">
|
<sidebarelement id="sidebar-home">
|
||||||
<indicator class="active">
|
<indicator class="active">
|
||||||
</indicator>
|
</indicator>
|
||||||
<button class="icon-button" aria-label="Homepage">
|
<button class="icon-button" aria-label="Homepage" 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"
|
||||||
|
|
@ -25,11 +32,10 @@
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</sidebarelement>
|
</sidebarelement>
|
||||||
<hr>
|
|
||||||
<sidebarelement id="sidebar-add">
|
<sidebarelement id="sidebar-add">
|
||||||
<indicator>
|
<indicator>
|
||||||
</indicator>
|
</indicator>
|
||||||
<button class="icon-button" aria-label="Add space">
|
<button class="icon-button" aria-label="Add space" 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>
|
||||||
|
|
@ -38,6 +44,21 @@
|
||||||
</button>
|
</button>
|
||||||
</sidebarelement>
|
</sidebarelement>
|
||||||
<hr>
|
<hr>
|
||||||
|
<hr class="bottom-element">
|
||||||
|
<sidebarelement id="sidebar-inbox">
|
||||||
|
<indicator>
|
||||||
|
</indicator>
|
||||||
|
<button class="icon-button" aria-label="Inbox" onclick="gotoSideInboxPopup()">
|
||||||
|
<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>
|
||||||
|
</sidebarelement>
|
||||||
|
<sidebarelement id="sidebar-profile">
|
||||||
|
<indicator>
|
||||||
|
</indicator>
|
||||||
|
<button class="icon-button" aria-label="Profile" onclick="gotoInbox()">
|
||||||
|
<img id="sidebar-pfp">
|
||||||
|
</button>
|
||||||
|
</sidebarelement>
|
||||||
</sidebar>
|
</sidebar>
|
||||||
|
|
||||||
<sidebar class="second" id="roomsbar">
|
<sidebar class="second" id="roomsbar">
|
||||||
|
|
@ -93,12 +114,13 @@
|
||||||
</roomcontent>
|
</roomcontent>
|
||||||
<sidebar class="second" id="roomdetailsbar" style="display: none;">
|
<sidebar class="second" id="roomdetailsbar" style="display: none;">
|
||||||
</sidebar>
|
</sidebar>
|
||||||
|
</main>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
<script src="main.js"></script>
|
<script src="main.js"></script>
|
||||||
<script>
|
<script>
|
||||||
async function start() {
|
async function start() {
|
||||||
|
updateLoadingStatus("loading.loading");
|
||||||
try {
|
try {
|
||||||
if (host != null)
|
if (host != null)
|
||||||
{
|
{
|
||||||
|
|
@ -109,6 +131,8 @@
|
||||||
await updateProtocolAndUrl(window.location.hostname);
|
await updateProtocolAndUrl(window.location.hostname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sidebarPfp.src = await getAvatarUrl(username);
|
||||||
|
|
||||||
showAction("Authenticating...", "startauth");
|
showAction("Authenticating...", "startauth");
|
||||||
let res = await Auth(username, password);
|
let res = await Auth(username, password);
|
||||||
clearAction("startauth");
|
clearAction("startauth");
|
||||||
|
|
@ -119,6 +143,8 @@
|
||||||
await delay(2000);
|
await delay(2000);
|
||||||
window.location.href = "login/index.html";
|
window.location.href = "login/index.html";
|
||||||
}
|
}
|
||||||
|
updateLoadingStatus("loading.done");
|
||||||
|
await loadingFadeOut();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
clearAction("startauth");
|
clearAction("startauth");
|
||||||
showBlahNotification("error:auth.failed.redirect.to.login");
|
showBlahNotification("error:auth.failed.redirect.to.login");
|
||||||
|
|
@ -159,6 +185,9 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
start();
|
async function createGroup() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<script src="userscript.js"></script>
|
<script src="userscript.js"></script>
|
||||||
|
|
@ -478,6 +478,5 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loginHostChanged();
|
|
||||||
</script>
|
</script>
|
||||||
<script src="../userscript.js"></script>
|
<script src="../userscript.js"></script>
|
||||||
|
|
@ -24,7 +24,7 @@ var url = `${prot}//${window.location.hostname}/_larpix`;
|
||||||
var params = new URLSearchParams(window.location.search);
|
var params = new URLSearchParams(window.location.search);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
var loadingStatus = document.getElementById("loadingstatus");
|
||||||
|
|
||||||
var collapseDmsBtn = document.getElementById("collapse-dms");
|
var collapseDmsBtn = document.getElementById("collapse-dms");
|
||||||
var collapseGroupsBtn = document.getElementById("collapse-groups");
|
var collapseGroupsBtn = document.getElementById("collapse-groups");
|
||||||
|
|
@ -49,6 +49,21 @@ try {
|
||||||
|
|
||||||
var roomContentBar = roomContent.children[0];
|
var roomContentBar = roomContent.children[0];
|
||||||
|
|
||||||
|
var roomTopBar = document.getElementsByTagName("roomtopbar")[1];
|
||||||
|
|
||||||
|
var sidebarProfile = document.getElementById("sidebar-profile");
|
||||||
|
var sidebarProfileButton = sidebarProfile.children.item(1);
|
||||||
|
var sidebarProfileIndicator = sidebarProfile.children.item(0);
|
||||||
|
|
||||||
|
var sidebarPfp = sidebarProfileButton.children.item(0);
|
||||||
|
|
||||||
|
|
||||||
|
var sidebarInbox = document.getElementById("sidebar-inbox");
|
||||||
|
var sidebarInboxButton = sidebarInbox.children.item(1);
|
||||||
|
var sidebarInboxIndicator = sidebarInbox.children.item(0);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -439,6 +454,103 @@ async function hashSHA3_512(input) {
|
||||||
return hashHex;
|
return hashHex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//placeholder pfp
|
||||||
|
function getInitials(name) {
|
||||||
|
const cleanName = (name || "").trim();
|
||||||
|
|
||||||
|
//name empty
|
||||||
|
if (!cleanName) return "";
|
||||||
|
|
||||||
|
const parts = cleanName.split(/\s+/);
|
||||||
|
|
||||||
|
//at least 2 words
|
||||||
|
if (parts.length >= 2) {
|
||||||
|
const firstInitial = parts[0][0];
|
||||||
|
const secondInitial = parts[parts.length - 1][0]; //from last word
|
||||||
|
return (firstInitial + secondInitial).toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
//only 1 word with 1 letter
|
||||||
|
const word = parts[0];
|
||||||
|
if (word.length === 1) {
|
||||||
|
return word.toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
//1 word at least 2 letters
|
||||||
|
return word.substring(0, 2).toUpperCase();
|
||||||
|
}
|
||||||
|
function stringToColor(str) {
|
||||||
|
let hash = 0;
|
||||||
|
for (let i = 0; i < str.length; i++) {
|
||||||
|
hash = str.charCodeAt(i) + ((hash << 5) - hash);
|
||||||
|
}
|
||||||
|
const h = Math.abs(hash) % 360;
|
||||||
|
const s = 50;
|
||||||
|
const l = 65;
|
||||||
|
|
||||||
|
return `hsl(${h}, ${s}%, ${l}%)`;
|
||||||
|
}
|
||||||
|
function createAvatarSvg(name, size = 512) {
|
||||||
|
const initials = getInitials(name);
|
||||||
|
const color = stringToColor(name);
|
||||||
|
|
||||||
|
const svg = `
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 ${size} ${size}">
|
||||||
|
<rect width="100%" height="100%" fill="${color}" />
|
||||||
|
<text
|
||||||
|
x="50%"
|
||||||
|
y="50%"
|
||||||
|
fill="white"
|
||||||
|
font-family="Nunito"
|
||||||
|
font-size="${size * 0.45}"
|
||||||
|
text-anchor="middle"
|
||||||
|
dy=".35em">
|
||||||
|
${initials}
|
||||||
|
</text>
|
||||||
|
</svg>
|
||||||
|
`.trim();
|
||||||
|
return `data:image/svg+xml;utf8,${encodeURIComponent(svg)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getAvatarUrl(username)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
let pfpUrl = `${url}/user/storage/public/getentry?u=${username}&e=larp.profile.pfp`;
|
||||||
|
if ((await fetchAsync(pfpUrl)) == "")
|
||||||
|
{
|
||||||
|
throw Error();
|
||||||
|
}
|
||||||
|
return pfpUrl;
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
return createAvatarSvg(username);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateLoadingStatus(message) {
|
||||||
|
loadingStatus.innerHTML = processBlah(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadingFadeOut() {
|
||||||
|
let loadingScreen = document.querySelector("loading");
|
||||||
|
let mainScreen = document.querySelector("main");
|
||||||
|
|
||||||
|
mainScreen.style.transform = "scale(0.85)";
|
||||||
|
mainScreen.style.opacity = "0";
|
||||||
|
|
||||||
|
loadingScreen.style.transform = "scale(0.85)";
|
||||||
|
loadingScreen.style.opacity = "0";
|
||||||
|
await delay(200);
|
||||||
|
loadingScreen.style.display = "none";
|
||||||
|
mainScreen.style.display = "";
|
||||||
|
await delay(200);
|
||||||
|
mainScreen.style.transform = "";
|
||||||
|
mainScreen.style.opacity = "";
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
var blah;
|
var blah;
|
||||||
|
|
||||||
async function initBlahs() {
|
async function initBlahs() {
|
||||||
|
|
@ -457,6 +569,10 @@ async function initBlahs() {
|
||||||
|
|
||||||
function processBlah(blahmessage) {
|
function processBlah(blahmessage) {
|
||||||
try {
|
try {
|
||||||
|
if (!blahmessage.includes(":")) {
|
||||||
|
blahmessage = `:${blahmessage}`;
|
||||||
|
}
|
||||||
|
|
||||||
let split = blahmessage.split(":");
|
let split = blahmessage.split(":");
|
||||||
let values = [];
|
let values = [];
|
||||||
try {
|
try {
|
||||||
|
|
@ -468,9 +584,8 @@ function processBlah(blahmessage) {
|
||||||
|
|
||||||
let valueslist = "";
|
let valueslist = "";
|
||||||
for (let i = 0; i < values.length; i++) {
|
for (let i = 0; i < values.length; i++) {
|
||||||
let value = values[i];
|
let value = processBlah(values[i]);
|
||||||
valueslist+=`${values[i]}, `;
|
valueslist+=`${value}, `;
|
||||||
processBlah(value);
|
|
||||||
|
|
||||||
message = message.replaceAll(`{${i}}`, value);
|
message = message.replaceAll(`{${i}}`, value);
|
||||||
}
|
}
|
||||||
|
|
@ -479,7 +594,6 @@ function processBlah(blahmessage) {
|
||||||
|
|
||||||
message = message.replaceAll('{all}', valueslist);
|
message = message.replaceAll('{all}', valueslist);
|
||||||
}
|
}
|
||||||
|
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
catch (e)
|
catch (e)
|
||||||
|
|
@ -505,6 +619,8 @@ async function mainJS() {
|
||||||
if (localStorage.getItem('lang') != null) {
|
if (localStorage.getItem('lang') != null) {
|
||||||
lang = localStorage.getItem('lang');
|
lang = localStorage.getItem('lang');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await start();
|
||||||
}
|
}
|
||||||
username = localStorage.getItem('username');
|
username = localStorage.getItem('username');
|
||||||
password = localStorage.getItem('password');
|
password = localStorage.getItem('password');
|
||||||
|
|
@ -518,7 +634,14 @@ collapseGroupsBtn.addEventListener("click", () => {
|
||||||
collapseGroupsBtn.classList.toggle("collapsed");
|
collapseGroupsBtn.classList.toggle("collapsed");
|
||||||
});
|
});
|
||||||
|
|
||||||
addDmBtn.addEventListener("click", () => {
|
addDmBtn.addEventListener("click", async () => {
|
||||||
|
roomContentMain.style.transform = "scale(0.85)";
|
||||||
|
roomContentMain.style.opacity = "0";
|
||||||
|
await delay(200);
|
||||||
|
|
||||||
|
roomTopBar.innerHTML = "Invite to dm";
|
||||||
|
roomDetailsBar.style.display = "none";
|
||||||
|
|
||||||
roomContentMain.innerHTML =
|
roomContentMain.innerHTML =
|
||||||
`
|
`
|
||||||
<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;">
|
||||||
|
|
@ -528,7 +651,7 @@ addDmBtn.addEventListener("click", () => {
|
||||||
<br>
|
<br>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<label for="addchat-username">Username</label>
|
<label for="addchat-username">Username</label>
|
||||||
<input type="text" id="addchat-username" placeholder="@username:serverhost" class="forminput">
|
<input type="text" id="addchat-username" placeholder="username:serverhost" class="forminput">
|
||||||
</div>
|
</div>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<button class="submit-button" onclick="addDm()">
|
<button class="submit-button" onclick="addDm()">
|
||||||
|
|
@ -536,10 +659,38 @@ addDmBtn.addEventListener("click", () => {
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`
|
`;
|
||||||
|
roomContentMain.style.transform = "";
|
||||||
|
roomContentMain.style.opacity = "";
|
||||||
});
|
});
|
||||||
addGroupBtn.addEventListener("click", () => {
|
addGroupBtn.addEventListener("click", async () => {
|
||||||
|
roomContentMain.style.transform = "scale(0.85)";
|
||||||
|
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 = "";
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -557,3 +708,55 @@ sidebarAddButton.addEventListener("mouseleave", () => {
|
||||||
sidebarAddIndicator.classList.remove("hover");
|
sidebarAddIndicator.classList.remove("hover");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
sidebarProfileButton.addEventListener("mouseenter", () => {
|
||||||
|
sidebarProfileIndicator.classList.add("hover");
|
||||||
|
});
|
||||||
|
sidebarProfileButton.addEventListener("mouseleave", () => {
|
||||||
|
sidebarProfileIndicator.classList.remove("hover");
|
||||||
|
});
|
||||||
|
|
||||||
|
sidebarInboxButton.addEventListener("mouseenter", () => {
|
||||||
|
sidebarInboxIndicator.classList.add("hover");
|
||||||
|
});
|
||||||
|
sidebarInboxButton.addEventListener("mouseleave", () => {
|
||||||
|
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() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,9 +40,16 @@ html {
|
||||||
body {
|
body {
|
||||||
padding-top: env(safe-area-inset-top);
|
padding-top: env(safe-area-inset-top);
|
||||||
background-color: var(--main-bg-color);
|
background-color: var(--main-bg-color);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
main, loading, body {
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 100dvh;
|
height: 100dvh;
|
||||||
overflow: hidden;
|
}
|
||||||
|
loading {
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
* {
|
* {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
|
|
@ -68,6 +75,11 @@ button, input {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
border: var(--border-width) solid var(--light-border-color);
|
border: var(--border-width) solid var(--light-border-color);
|
||||||
|
|
||||||
|
backface-visibility: hidden;
|
||||||
|
transform: translateZ(0);
|
||||||
|
will-change: transform;
|
||||||
|
transform-origin: center center;
|
||||||
}
|
}
|
||||||
input {
|
input {
|
||||||
padding-left: calc(var(--button-margin) * 2);
|
padding-left: calc(var(--button-margin) * 2);
|
||||||
|
|
@ -120,11 +132,16 @@ indicator.active {
|
||||||
height: var(--icon-button-height);
|
height: var(--icon-button-height);
|
||||||
width: var(--icon-button-height);
|
width: var(--icon-button-height);
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
.icon-button svg {
|
.icon-button svg {
|
||||||
width: var(--icon-button-size);
|
width: var(--icon-button-size);
|
||||||
height: var(--icon-button-size);
|
height: var(--icon-button-size);
|
||||||
}
|
}
|
||||||
|
.icon-button img {
|
||||||
|
width: calc(var(--icon-button-height) - (var(--border-width) * 2));
|
||||||
|
height: calc(var(--icon-button-height) - (var(--border-width) * 2));
|
||||||
|
}
|
||||||
button:hover, input:hover {
|
button:hover, input:hover {
|
||||||
background-color: rgba(255, 255, 255, 0.1);
|
background-color: rgba(255, 255, 255, 0.1);
|
||||||
}
|
}
|
||||||
|
|
@ -341,3 +358,8 @@ herotitle {
|
||||||
.submit-button:hover {
|
.submit-button:hover {
|
||||||
background-color: rgba(255, 255, 255, 0.5);
|
background-color: rgba(255, 255, 255, 0.5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.bottom-element {
|
||||||
|
margin-top: auto;
|
||||||
|
}
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
BIN
icons/icon.png
BIN
icons/icon.png
Binary file not shown.
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
|
@ -36,5 +36,13 @@
|
||||||
"passwords.not.match": "Passwords do not match",
|
"passwords.not.match": "Passwords do not match",
|
||||||
"password.cant.empty": "Password cannot be empty",
|
"password.cant.empty": "Password cannot be empty",
|
||||||
"username.cant.empty": "Username cannot be empty",
|
"username.cant.empty": "Username cannot be empty",
|
||||||
"bad.request": "Bad request"
|
"bad.request": "Bad request",
|
||||||
|
|
||||||
|
"letters": "letters",
|
||||||
|
"numbers": "numbers",
|
||||||
|
"underscores": "underscores",
|
||||||
|
|
||||||
|
"loading.connecting": "Connecting...",
|
||||||
|
"loading.loading": "Loading...",
|
||||||
|
"loading.done": "Ready!"
|
||||||
}
|
}
|
||||||
|
|
@ -8,6 +8,13 @@
|
||||||
<link rel="icon" type="image/svg+xml" href="favicon.svg">
|
<link rel="icon" type="image/svg+xml" href="favicon.svg">
|
||||||
</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;">
|
||||||
<sidebar>
|
<sidebar>
|
||||||
<sidebarelement id="sidebar-home">
|
<sidebarelement id="sidebar-home">
|
||||||
<indicator class="active">
|
<indicator class="active">
|
||||||
|
|
@ -25,7 +32,6 @@
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</sidebarelement>
|
</sidebarelement>
|
||||||
<hr>
|
|
||||||
<sidebarelement id="sidebar-add">
|
<sidebarelement id="sidebar-add">
|
||||||
<indicator>
|
<indicator>
|
||||||
</indicator>
|
</indicator>
|
||||||
|
|
@ -38,11 +44,19 @@
|
||||||
</button>
|
</button>
|
||||||
</sidebarelement>
|
</sidebarelement>
|
||||||
<hr>
|
<hr>
|
||||||
<sidebarelement id="sidebar-profile" class="bottom-element">
|
<hr class="bottom-element">
|
||||||
|
<sidebarelement id="sidebar-inbox">
|
||||||
<indicator>
|
<indicator>
|
||||||
</indicator>
|
</indicator>
|
||||||
<button class="icon-button" aria-label="Profile" onclick="gotoSideProfilePopup()">
|
<button class="icon-button" aria-label="Inbox" onclick="gotoSideInboxPopup()">
|
||||||
<img id="sidebar-pfp" src="./pfpexamp.png">
|
<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>
|
||||||
|
</sidebarelement>
|
||||||
|
<sidebarelement id="sidebar-profile">
|
||||||
|
<indicator>
|
||||||
|
</indicator>
|
||||||
|
<button class="icon-button" aria-label="Profile" onclick="gotoInbox()">
|
||||||
|
<img id="sidebar-pfp">
|
||||||
</button>
|
</button>
|
||||||
</sidebarelement>
|
</sidebarelement>
|
||||||
</sidebar>
|
</sidebar>
|
||||||
|
|
@ -100,12 +114,13 @@
|
||||||
</roomcontent>
|
</roomcontent>
|
||||||
<sidebar class="second" id="roomdetailsbar" style="display: none;">
|
<sidebar class="second" id="roomdetailsbar" style="display: none;">
|
||||||
</sidebar>
|
</sidebar>
|
||||||
|
</main>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
<script src="main.js"></script>
|
<script src="main.js"></script>
|
||||||
<script>
|
<script>
|
||||||
async function start() {
|
async function start() {
|
||||||
|
updateLoadingStatus("loading.loading");
|
||||||
try {
|
try {
|
||||||
if (host != null)
|
if (host != null)
|
||||||
{
|
{
|
||||||
|
|
@ -116,6 +131,8 @@
|
||||||
await updateProtocolAndUrl(window.location.hostname);
|
await updateProtocolAndUrl(window.location.hostname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sidebarPfp.src = await getAvatarUrl(username);
|
||||||
|
|
||||||
showAction("Authenticating...", "startauth");
|
showAction("Authenticating...", "startauth");
|
||||||
let res = await Auth(username, password);
|
let res = await Auth(username, password);
|
||||||
clearAction("startauth");
|
clearAction("startauth");
|
||||||
|
|
@ -126,6 +143,8 @@
|
||||||
await delay(2000);
|
await delay(2000);
|
||||||
window.location.href = "login/index.html";
|
window.location.href = "login/index.html";
|
||||||
}
|
}
|
||||||
|
updateLoadingStatus("loading.done");
|
||||||
|
await loadingFadeOut();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
clearAction("startauth");
|
clearAction("startauth");
|
||||||
showBlahNotification("error:auth.failed.redirect.to.login");
|
showBlahNotification("error:auth.failed.redirect.to.login");
|
||||||
|
|
@ -170,6 +189,5 @@
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
start();
|
|
||||||
</script>
|
</script>
|
||||||
<script src="userscript.js"></script>
|
<script src="userscript.js"></script>
|
||||||
|
|
@ -478,6 +478,5 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loginHostChanged();
|
|
||||||
</script>
|
</script>
|
||||||
<script src="../userscript.js"></script>
|
<script src="../userscript.js"></script>
|
||||||
143
webroot/main.js
143
webroot/main.js
|
|
@ -24,7 +24,7 @@ var url = `${prot}//${window.location.hostname}/_larpix`;
|
||||||
var params = new URLSearchParams(window.location.search);
|
var params = new URLSearchParams(window.location.search);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
var loadingStatus = document.getElementById("loadingstatus");
|
||||||
|
|
||||||
var collapseDmsBtn = document.getElementById("collapse-dms");
|
var collapseDmsBtn = document.getElementById("collapse-dms");
|
||||||
var collapseGroupsBtn = document.getElementById("collapse-groups");
|
var collapseGroupsBtn = document.getElementById("collapse-groups");
|
||||||
|
|
@ -55,6 +55,9 @@ try {
|
||||||
var sidebarProfileButton = sidebarProfile.children.item(1);
|
var sidebarProfileButton = sidebarProfile.children.item(1);
|
||||||
var sidebarProfileIndicator = sidebarProfile.children.item(0);
|
var sidebarProfileIndicator = sidebarProfile.children.item(0);
|
||||||
|
|
||||||
|
var sidebarPfp = sidebarProfileButton.children.item(0);
|
||||||
|
|
||||||
|
|
||||||
var sidebarInbox = document.getElementById("sidebar-inbox");
|
var sidebarInbox = document.getElementById("sidebar-inbox");
|
||||||
var sidebarInboxButton = sidebarInbox.children.item(1);
|
var sidebarInboxButton = sidebarInbox.children.item(1);
|
||||||
var sidebarInboxIndicator = sidebarInbox.children.item(0);
|
var sidebarInboxIndicator = sidebarInbox.children.item(0);
|
||||||
|
|
@ -451,6 +454,103 @@ async function hashSHA3_512(input) {
|
||||||
return hashHex;
|
return hashHex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//placeholder pfp
|
||||||
|
function getInitials(name) {
|
||||||
|
const cleanName = (name || "").trim();
|
||||||
|
|
||||||
|
//name empty
|
||||||
|
if (!cleanName) return "";
|
||||||
|
|
||||||
|
const parts = cleanName.split(/\s+/);
|
||||||
|
|
||||||
|
//at least 2 words
|
||||||
|
if (parts.length >= 2) {
|
||||||
|
const firstInitial = parts[0][0];
|
||||||
|
const secondInitial = parts[parts.length - 1][0]; //from last word
|
||||||
|
return (firstInitial + secondInitial).toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
//only 1 word with 1 letter
|
||||||
|
const word = parts[0];
|
||||||
|
if (word.length === 1) {
|
||||||
|
return word.toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
//1 word at least 2 letters
|
||||||
|
return word.substring(0, 2).toUpperCase();
|
||||||
|
}
|
||||||
|
function stringToColor(str) {
|
||||||
|
let hash = 0;
|
||||||
|
for (let i = 0; i < str.length; i++) {
|
||||||
|
hash = str.charCodeAt(i) + ((hash << 5) - hash);
|
||||||
|
}
|
||||||
|
const h = Math.abs(hash) % 360;
|
||||||
|
const s = 50;
|
||||||
|
const l = 65;
|
||||||
|
|
||||||
|
return `hsl(${h}, ${s}%, ${l}%)`;
|
||||||
|
}
|
||||||
|
function createAvatarSvg(name, size = 512) {
|
||||||
|
const initials = getInitials(name);
|
||||||
|
const color = stringToColor(name);
|
||||||
|
|
||||||
|
const svg = `
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 ${size} ${size}">
|
||||||
|
<rect width="100%" height="100%" fill="${color}" />
|
||||||
|
<text
|
||||||
|
x="50%"
|
||||||
|
y="50%"
|
||||||
|
fill="white"
|
||||||
|
font-family="Nunito"
|
||||||
|
font-size="${size * 0.45}"
|
||||||
|
text-anchor="middle"
|
||||||
|
dy=".35em">
|
||||||
|
${initials}
|
||||||
|
</text>
|
||||||
|
</svg>
|
||||||
|
`.trim();
|
||||||
|
return `data:image/svg+xml;utf8,${encodeURIComponent(svg)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getAvatarUrl(username)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
let pfpUrl = `${url}/user/storage/public/getentry?u=${username}&e=larp.profile.pfp`;
|
||||||
|
if ((await fetchAsync(pfpUrl)) == "")
|
||||||
|
{
|
||||||
|
throw Error();
|
||||||
|
}
|
||||||
|
return pfpUrl;
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
return createAvatarSvg(username);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateLoadingStatus(message) {
|
||||||
|
loadingStatus.innerHTML = processBlah(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadingFadeOut() {
|
||||||
|
let loadingScreen = document.querySelector("loading");
|
||||||
|
let mainScreen = document.querySelector("main");
|
||||||
|
|
||||||
|
mainScreen.style.transform = "scale(0.85)";
|
||||||
|
mainScreen.style.opacity = "0";
|
||||||
|
|
||||||
|
loadingScreen.style.transform = "scale(0.85)";
|
||||||
|
loadingScreen.style.opacity = "0";
|
||||||
|
await delay(200);
|
||||||
|
loadingScreen.style.display = "none";
|
||||||
|
mainScreen.style.display = "";
|
||||||
|
await delay(200);
|
||||||
|
mainScreen.style.transform = "";
|
||||||
|
mainScreen.style.opacity = "";
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
var blah;
|
var blah;
|
||||||
|
|
||||||
async function initBlahs() {
|
async function initBlahs() {
|
||||||
|
|
@ -469,6 +569,10 @@ async function initBlahs() {
|
||||||
|
|
||||||
function processBlah(blahmessage) {
|
function processBlah(blahmessage) {
|
||||||
try {
|
try {
|
||||||
|
if (!blahmessage.includes(":")) {
|
||||||
|
blahmessage = `:${blahmessage}`;
|
||||||
|
}
|
||||||
|
|
||||||
let split = blahmessage.split(":");
|
let split = blahmessage.split(":");
|
||||||
let values = [];
|
let values = [];
|
||||||
try {
|
try {
|
||||||
|
|
@ -480,9 +584,8 @@ function processBlah(blahmessage) {
|
||||||
|
|
||||||
let valueslist = "";
|
let valueslist = "";
|
||||||
for (let i = 0; i < values.length; i++) {
|
for (let i = 0; i < values.length; i++) {
|
||||||
let value = values[i];
|
let value = processBlah(values[i]);
|
||||||
valueslist+=`${values[i]}, `;
|
valueslist+=`${value}, `;
|
||||||
processBlah(value);
|
|
||||||
|
|
||||||
message = message.replaceAll(`{${i}}`, value);
|
message = message.replaceAll(`{${i}}`, value);
|
||||||
}
|
}
|
||||||
|
|
@ -491,7 +594,6 @@ function processBlah(blahmessage) {
|
||||||
|
|
||||||
message = message.replaceAll('{all}', valueslist);
|
message = message.replaceAll('{all}', valueslist);
|
||||||
}
|
}
|
||||||
|
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
catch (e)
|
catch (e)
|
||||||
|
|
@ -517,6 +619,8 @@ async function mainJS() {
|
||||||
if (localStorage.getItem('lang') != null) {
|
if (localStorage.getItem('lang') != null) {
|
||||||
lang = localStorage.getItem('lang');
|
lang = localStorage.getItem('lang');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await start();
|
||||||
}
|
}
|
||||||
username = localStorage.getItem('username');
|
username = localStorage.getItem('username');
|
||||||
password = localStorage.getItem('password');
|
password = localStorage.getItem('password');
|
||||||
|
|
@ -530,9 +634,14 @@ collapseGroupsBtn.addEventListener("click", () => {
|
||||||
collapseGroupsBtn.classList.toggle("collapsed");
|
collapseGroupsBtn.classList.toggle("collapsed");
|
||||||
});
|
});
|
||||||
|
|
||||||
addDmBtn.addEventListener("click", () => {
|
addDmBtn.addEventListener("click", async () => {
|
||||||
|
roomContentMain.style.transform = "scale(0.85)";
|
||||||
|
roomContentMain.style.opacity = "0";
|
||||||
|
await delay(200);
|
||||||
|
|
||||||
roomTopBar.innerHTML = "Invite to dm";
|
roomTopBar.innerHTML = "Invite to dm";
|
||||||
roomDetailsBar.style.display = "none";
|
roomDetailsBar.style.display = "none";
|
||||||
|
|
||||||
roomContentMain.innerHTML =
|
roomContentMain.innerHTML =
|
||||||
`
|
`
|
||||||
<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;">
|
||||||
|
|
@ -551,10 +660,17 @@ addDmBtn.addEventListener("click", () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
roomContentMain.style.transform = "";
|
||||||
|
roomContentMain.style.opacity = "";
|
||||||
});
|
});
|
||||||
addGroupBtn.addEventListener("click", () => {
|
addGroupBtn.addEventListener("click", async () => {
|
||||||
|
roomContentMain.style.transform = "scale(0.85)";
|
||||||
|
roomContentMain.style.opacity = "0";
|
||||||
|
await delay(200);
|
||||||
|
|
||||||
roomTopBar.innerHTML = "Create group";
|
roomTopBar.innerHTML = "Create group";
|
||||||
roomDetailsBar.style.display = "none";
|
roomDetailsBar.style.display = "none";
|
||||||
|
|
||||||
roomContentMain.innerHTML =
|
roomContentMain.innerHTML =
|
||||||
`
|
`
|
||||||
<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;">
|
||||||
|
|
@ -573,6 +689,8 @@ addGroupBtn.addEventListener("click", () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
roomContentMain.style.transform = "";
|
||||||
|
roomContentMain.style.opacity = "";
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -608,7 +726,14 @@ sidebarInboxButton.addEventListener("mouseleave", () => {
|
||||||
function gotoSideProfilePopup() {
|
function gotoSideProfilePopup() {
|
||||||
|
|
||||||
}
|
}
|
||||||
function gotoCreateSpace() {
|
function gotoInbox() {
|
||||||
|
|
||||||
|
}
|
||||||
|
async function gotoCreateSpace() {
|
||||||
|
roomContentMain.style.transform = "scale(0.85)";
|
||||||
|
roomContentMain.style.opacity = "0";
|
||||||
|
await delay(200);
|
||||||
|
|
||||||
roomTopBar.innerHTML = "Create space";
|
roomTopBar.innerHTML = "Create space";
|
||||||
roomDetailsBar.style.display = "none";
|
roomDetailsBar.style.display = "none";
|
||||||
roomContentMain.innerHTML =
|
roomContentMain.innerHTML =
|
||||||
|
|
@ -629,6 +754,8 @@ function gotoCreateSpace() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
roomContentMain.style.transform = "";
|
||||||
|
roomContentMain.style.opacity = "";
|
||||||
}
|
}
|
||||||
function gotoHome() {
|
function gotoHome() {
|
||||||
|
|
||||||
|
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.6 KiB |
|
|
@ -40,9 +40,16 @@ html {
|
||||||
body {
|
body {
|
||||||
padding-top: env(safe-area-inset-top);
|
padding-top: env(safe-area-inset-top);
|
||||||
background-color: var(--main-bg-color);
|
background-color: var(--main-bg-color);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
main, loading, body {
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 100dvh;
|
height: 100dvh;
|
||||||
overflow: hidden;
|
}
|
||||||
|
loading {
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
* {
|
* {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue