forked from olcxjas-softworks/LarpixClient
Compatibility tweaks
- Fix (i hope all) electron issues - Add complete blah support - Add userscript
This commit is contained in:
parent
588d55abf8
commit
7ff648ba3a
19 changed files with 478 additions and 576 deletions
40
android/app/src/main/assets/public/blah/en-us.json
Normal file
40
android/app/src/main/assets/public/blah/en-us.json
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"user.not.found": "User not found",
|
||||
"cant.invite.urself": "You can't invite yourself",
|
||||
"user.already.invited": "You have already invited this user",
|
||||
"user.invited": "User invited successfully",
|
||||
"cant.create.dm.without.invitation": "You can't create a dm without invitation",
|
||||
"dm.begin.notice": "At the beginning of a DM, you should always verify that the person you're talking to is the intended recipient",
|
||||
"failed.accept.dm": "Failed to accept DM",
|
||||
"dm.accepted": "DM accepted",
|
||||
"no.invite.found": "You can't create a dm without invitation",
|
||||
"unknown.error": "Unknown error",
|
||||
"account.creation.request.expired": "Account creation request expired. Try again",
|
||||
"invalid.username": "Invalid username: {0}",
|
||||
"invalid.password": "Invalid password: {0}",
|
||||
"incorrect.captcha": "Incorrect captcha. Try again",
|
||||
"username.taken": "This username is already taken",
|
||||
"accounts.slots.full": "You can't create a new account because all ids are used. Try again later",
|
||||
"registration.disabled": "Registration disabled",
|
||||
"account.created": "Account created successfully",
|
||||
"password.changed": "Password changed successfully",
|
||||
"keys.updated": "Keys updated successfully",
|
||||
"unknown.request": "Unknown request: {0}",
|
||||
"login.successful": "Login successful",
|
||||
"username.length": "Username must be {0} characters long",
|
||||
"username.conditions.allowed": "Username can only include {all}",
|
||||
"password.not.hashed.properly": "Password is not hashed properly",
|
||||
"invalid.username.or.password": "Invalid username or password",
|
||||
"account.not.exist": "Account with this name doesn't exist",
|
||||
"invalid.nonce": "Invalid nonce. Try again",
|
||||
"username.changed": "Username changed successfully",
|
||||
"auth.failed.redirect.to.login": "Failed to auth. Redirecting to login...",
|
||||
"dm.refresh.failed": "Failed to refresh dms",
|
||||
"chat.add.failed": "Failed to add chat",
|
||||
"something.wrong.mayb.pass": "Something went wrong... (probably wrong password)",
|
||||
"something.wrong": "Something went wrong...",
|
||||
"passwords.not.match": "Passwords do not match",
|
||||
"password.cant.empty": "Password cannot be empty",
|
||||
"username.cant.empty": "Username cannot be empty",
|
||||
"bad.request": "Bad request"
|
||||
}
|
||||
|
|
@ -84,14 +84,14 @@
|
|||
Splash
|
||||
</roomtopbar>
|
||||
<roomcontent2>
|
||||
<div style="display: flex;justify-content: center;align-items: center;height:100%;flex-direction: column;">
|
||||
<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">
|
||||
<herotitle>Welcome to Miarven</herotitle>
|
||||
<p>First Larpix client. <span class="aqua">v<span class="clientver aqua">1.0</span></span></p>
|
||||
</div>
|
||||
</roomcontent2>
|
||||
</roomcontent>
|
||||
<sidebar class="second hidden" id="roomdetailsbar" style="display: none;">
|
||||
<sidebar class="second" id="roomdetailsbar" style="display: none;">
|
||||
</sidebar>
|
||||
|
||||
</body>
|
||||
|
|
@ -100,21 +100,28 @@
|
|||
<script>
|
||||
async function start() {
|
||||
try {
|
||||
|
||||
if (host != null)
|
||||
{
|
||||
await updateProtocolAndUrl(host);
|
||||
}
|
||||
else
|
||||
{
|
||||
await updateProtocolAndUrl(window.location.hostname);
|
||||
}
|
||||
|
||||
showAction("Authenticating...", "startauth");
|
||||
let res = await Auth(username, password);
|
||||
clearAction("startauth");
|
||||
if (res == "Login successful") {
|
||||
if (res.startsWith("success:")) {
|
||||
await refreshDms();
|
||||
} else {
|
||||
showNotification("Failed to auth. Redirecting to login...", "error", 3500);
|
||||
showBlahNotification("error:auth.failed.redirect.to.login");
|
||||
await delay(2000);
|
||||
window.location.href = "login/index.html";
|
||||
}
|
||||
} catch (e) {
|
||||
clearAction("startauth");
|
||||
showNotification("Failed to auth. Redirecting to login...", "error", 3500);
|
||||
showBlahNotification("error:auth.failed.redirect.to.login");
|
||||
await delay(2000);
|
||||
window.location.href = "login/index.html";
|
||||
}
|
||||
|
|
@ -131,9 +138,27 @@
|
|||
}
|
||||
catch (e) {
|
||||
clearAction("dmrefresh");
|
||||
showNotification("Failed to refresh dms", "error", 3500);
|
||||
showBlahNotification("error:dm.refresh.failed");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
async function addDm() {
|
||||
try {
|
||||
showAction("Adding...", "dmadd");
|
||||
let res = await fetchEncrypted("user/dm/invite", document.getElementById("addchat-username").value);
|
||||
console.log(res);
|
||||
let ressplit = res.split(":");
|
||||
clearAction("dmadd");
|
||||
showBlahNotification(res);
|
||||
}
|
||||
catch (e) {
|
||||
console.log(e);
|
||||
clearAction("dmadd");
|
||||
showBlahNotification("error:chat.add.failed");
|
||||
}
|
||||
}
|
||||
|
||||
start();
|
||||
</script>
|
||||
</script>
|
||||
<script src="userscript.js"></script>
|
||||
|
|
@ -264,11 +264,10 @@
|
|||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
<script src="../main.js"></script>
|
||||
<script>
|
||||
document.getElementById("reg-host").value = window.location.hostname;
|
||||
document.getElementById("login-host").value = window.location.hostname;
|
||||
|
||||
const container = document.getElementById('auth-container');
|
||||
|
||||
|
|
@ -311,13 +310,12 @@
|
|||
formLogin.addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
try {
|
||||
url = `${window.location.protocol}//${loginHost.value}/_larpix`;
|
||||
|
||||
let res = await Auth(loginUsername.value, loginPassword.value);
|
||||
|
||||
if (res == "Login successful")
|
||||
if (res.startsWith("success:"))
|
||||
{
|
||||
showNotification(res, "success", 3500);
|
||||
showBlahNotification(res);
|
||||
await delay(1000);
|
||||
localStorage.setItem("username", loginUsername.value);
|
||||
localStorage.setItem("password", loginPassword.value);
|
||||
|
|
@ -327,12 +325,12 @@
|
|||
}
|
||||
else
|
||||
{
|
||||
showNotification(res, "error", 3500);
|
||||
showBlahNotification(res);
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
showNotification("Something went wrong... (probably wrong password)", "error", 3500);
|
||||
showBlahNotification("error:something.wrong.mayb.pass");
|
||||
container.className = 'auth-container';
|
||||
}
|
||||
});
|
||||
|
|
@ -342,21 +340,21 @@
|
|||
try {
|
||||
captchaCode.value = "";
|
||||
regKeyInput.value = "";
|
||||
|
||||
url = `${window.location.protocol}//${registerHost.value}/_larpix`;
|
||||
|
||||
|
||||
|
||||
if (!registerUsername.value || registerUsername.value.trim() === '') {
|
||||
showNotification("Username cannot be empty", "error");
|
||||
showBlahNotification("error:username.cant.empty");
|
||||
container.className = 'auth-container show-register';
|
||||
return;
|
||||
}
|
||||
if (!registerPassword.value || registerPassword.value.trim() === '') {
|
||||
showNotification("Password cannot be empty", "error");
|
||||
showBlahNotification("error:password.cant.empty");
|
||||
container.className = 'auth-container show-register';
|
||||
return;
|
||||
}
|
||||
if (registerPassword.value != registerPasswordConfirm.value) {
|
||||
showNotification("Passwords do not match", "error");
|
||||
showBlahNotification("error:passwords.not.match");
|
||||
container.className = 'auth-container show-register';
|
||||
return;
|
||||
}
|
||||
|
|
@ -388,13 +386,13 @@
|
|||
if (res.length > 64 || res.length <= 1) {
|
||||
throw new Error();
|
||||
}
|
||||
showNotification(res, "error", 3500);
|
||||
showBlahNotification(res);
|
||||
container.className = 'auth-container show-register';
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
showNotification("Something went wrong...", "error", 3500);
|
||||
showBlahNotification("error:something.wrong");
|
||||
container.className = 'auth-container show-register';
|
||||
}
|
||||
});
|
||||
|
|
@ -414,11 +412,8 @@
|
|||
if (res.length > 64 || res.length <= 1) {
|
||||
throw new Error();
|
||||
}
|
||||
if (res.toLowerCase().includes("incorrect")) {
|
||||
showNotification(res, "error", 3500);
|
||||
container.className = 'auth-container show-register';
|
||||
} else if (res.toLowerCase().includes("created")) {
|
||||
showNotification(res, "success", 3500);
|
||||
if (res.startsWith("success")) {
|
||||
showBlahNotification(res);
|
||||
await delay(1000);
|
||||
localStorage.setItem("username", registerUsername.value);
|
||||
localStorage.setItem("password", registerPassword.value);
|
||||
|
|
@ -427,12 +422,12 @@
|
|||
window.location.href = "../";
|
||||
|
||||
} else {
|
||||
showNotification(res, "info", 3500);
|
||||
showBlahNotification(res);
|
||||
container.className = 'auth-container show-register';
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
showNotification("Something went wrong...", "error", 3500);
|
||||
showBlahNotification("error:something.wrong");
|
||||
container.className = 'auth-container show-register';
|
||||
}
|
||||
});
|
||||
|
|
@ -450,6 +445,7 @@
|
|||
async function updateLoginForm(host)
|
||||
{
|
||||
try {
|
||||
await updateProtocolAndUrl(host);
|
||||
let serverInfo = await getServerInfo(host);
|
||||
if (serverInfo["registration"] == "disabled")
|
||||
{
|
||||
|
|
@ -484,5 +480,4 @@
|
|||
|
||||
loginHostChanged();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
<script src="../userscript.js"></script>
|
||||
|
|
@ -1,49 +1,74 @@
|
|||
console.log(window.location.protocol);
|
||||
var prot = window.location.protocol;
|
||||
|
||||
var url = `${window.location.protocol}//${window.location.hostname}/_larpix`;
|
||||
async function updateProtocolAndUrl(host)
|
||||
{
|
||||
prot = window.location.protocol == "miarven:" ? "http:" : window.location.protocol;
|
||||
if (prot == "http:") {
|
||||
try {
|
||||
JSON.parse(await fetchAsync(`${prot}//${host}/_larpix/serverinfo`));
|
||||
}
|
||||
catch (error) {
|
||||
try {
|
||||
JSON.parse(await fetchAsync(`https://${host}/_larpix/serverinfo`));
|
||||
prot = "https:";
|
||||
}
|
||||
catch (error) {}
|
||||
}
|
||||
}
|
||||
url = `${prot}//${host}/_larpix`;
|
||||
}
|
||||
|
||||
console.log(prot);
|
||||
|
||||
var url = `${prot}//${window.location.hostname}/_larpix`;
|
||||
var params = new URLSearchParams(window.location.search);
|
||||
|
||||
const collapseDmsBtn = document.getElementById("collapse-dms");
|
||||
const collapseGroupsBtn = document.getElementById("collapse-groups");
|
||||
try {
|
||||
|
||||
const addDmBtn = document.getElementById("add-dm-btn");
|
||||
const addGroupBtn = document.getElementById("add-group-btn");
|
||||
|
||||
const sidebarHome = document.getElementById("sidebar-home");
|
||||
const sidebarHomeButton = sidebarHome.children.item(1);
|
||||
const sidebarHomeIndicator = sidebarHome.children.item(0);
|
||||
var collapseDmsBtn = document.getElementById("collapse-dms");
|
||||
var collapseGroupsBtn = document.getElementById("collapse-groups");
|
||||
|
||||
const sidebarAdd = document.getElementById("sidebar-add");
|
||||
const sidebarAddButton = sidebarAdd.children.item(1);
|
||||
const sidebarAddIndicator = sidebarAdd.children.item(0);
|
||||
var addDmBtn = document.getElementById("add-dm-btn");
|
||||
var addGroupBtn = document.getElementById("add-group-btn");
|
||||
|
||||
const roomDetailsBar = document.getElementById("roomdetailsbar");
|
||||
const roomContent = document.getElementsByTagName("roomcontent")[0];
|
||||
const roomsBar = document.getElementById("roomsbar");
|
||||
const sideBar = document.getElementsByTagName("sidebar")[0];
|
||||
var sidebarHome = document.getElementById("sidebar-home");
|
||||
var sidebarHomeButton = sidebarHome.children.item(1);
|
||||
var sidebarHomeIndicator = sidebarHome.children.item(0);
|
||||
|
||||
const roomContentMain = document.getElementsByTagName("roomcontent2")[0];
|
||||
var sidebarAdd = document.getElementById("sidebar-add");
|
||||
var sidebarAddButton = sidebarAdd.children.item(1);
|
||||
var sidebarAddIndicator = sidebarAdd.children.item(0);
|
||||
|
||||
const roomContentBar = roomContent.children[0];
|
||||
var roomDetailsBar = document.getElementById("roomdetailsbar");
|
||||
var roomContent = document.getElementsByTagName("roomcontent")[0];
|
||||
var roomsBar = document.getElementById("roomsbar");
|
||||
var sideBar = document.getElementsByTagName("sidebar")[0];
|
||||
|
||||
var roomContentMain = document.getElementsByTagName("roomcontent2")[0];
|
||||
|
||||
var roomContentBar = roomContent.children[0];
|
||||
|
||||
} catch (e) {
|
||||
}
|
||||
|
||||
|
||||
function delay(time) {
|
||||
return new Promise(resolve => setTimeout(resolve, time));
|
||||
}
|
||||
|
||||
async function packetEncPass(pass, key, username) {
|
||||
return await encryptWithNonce(pass, key, getNonce(username, key));
|
||||
}
|
||||
|
||||
async function getNonce(username, key) {
|
||||
|
||||
|
||||
let nonce;
|
||||
let fetchRes = await (await fetch(`${url}/nextnonce?u=${username}`)).text();
|
||||
|
||||
try {
|
||||
nonce = await decryptString(fetchRes, key);
|
||||
}
|
||||
catch(err) {
|
||||
} catch (err) {
|
||||
nonce = await decryptString(fetchRes, "");
|
||||
}
|
||||
return nonce;
|
||||
|
|
@ -83,12 +108,13 @@ function keyDataFromServerJson(jsonFromServer) {
|
|||
return [p, g, pubServer, data.idKey]
|
||||
}
|
||||
|
||||
function base64ToUint8(base64) {
|
||||
function base64ToUint8(base64) {
|
||||
return Uint8Array.from(atob(base64), c => c.charCodeAt(0));
|
||||
}
|
||||
|
||||
function uint8ToBase64(uint8) {
|
||||
return fixBase64Padding(btoa(String.fromCharCode(...uint8)));
|
||||
}
|
||||
}
|
||||
|
||||
async function encrypt(plainText, keyBytes) {
|
||||
const iv = window.crypto.getRandomValues(new Uint8Array(16));
|
||||
|
|
@ -241,10 +267,10 @@ async function fetchPostEnc(url, value) {
|
|||
|
||||
async function fetchAsync(url) {
|
||||
let response = await fetch(url, {
|
||||
method: "GET",
|
||||
method: "GET",
|
||||
credentials: "omit"
|
||||
});
|
||||
|
||||
|
||||
let data = await response.text();
|
||||
return data;
|
||||
}
|
||||
|
|
@ -262,15 +288,13 @@ async function fetchAsyncWAuth(url) {
|
|||
return data;
|
||||
}
|
||||
|
||||
async function getServerInfo(host){
|
||||
console.log(`${window.location.protocol}//${host}/_larpix/serverinfo`)
|
||||
return JSON.parse(await fetchAsync(`${window.location.protocol}//${host}/_larpix/serverinfo`));
|
||||
async function getServerInfo(host) {
|
||||
console.log(`${prot}//${host}/_larpix/serverinfo`)
|
||||
return JSON.parse(await fetchAsync(`${prot}//${host}/_larpix/serverinfo`));
|
||||
}
|
||||
|
||||
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}`, {
|
||||
method: "GET",
|
||||
credentials: "omit",
|
||||
|
|
@ -285,16 +309,14 @@ async function Auth(username, password) {
|
|||
}
|
||||
|
||||
|
||||
async function fetchEncrypted(request, body)
|
||||
{
|
||||
async function fetchEncrypted(request, body) {
|
||||
|
||||
let nonce = await getNonce(username, passwordHash);
|
||||
|
||||
|
||||
let response = await fetch(`${url}/encryptedrequest?u=${username}`, {
|
||||
method: "POST",
|
||||
credentials: "omit",
|
||||
body: await encryptWithNonce(
|
||||
|
||||
JSON.stringify({
|
||||
string1: request,
|
||||
string2: body
|
||||
|
|
@ -334,6 +356,15 @@ function fixBase64Padding(base64String) {
|
|||
return str;
|
||||
}
|
||||
|
||||
function showBlahNotification(blahmessage, duration = 3500) {
|
||||
try {
|
||||
let split = blahmessage.split(":");
|
||||
showNotification(processBlah(blahmessage), split[0], duration);
|
||||
} catch (e) {
|
||||
showNotification(blahmessage, "info", duration);
|
||||
}
|
||||
}
|
||||
|
||||
function showNotification(message, type = 'info', duration = 3500) {
|
||||
let container = document.getElementById('notification-container');
|
||||
if (!container) {
|
||||
|
|
@ -385,40 +416,99 @@ function showAction(message, actionid) {
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
function clearAction(actionid) {
|
||||
const notifications = document.querySelectorAll(`[id="notification-${actionid}"]`);
|
||||
|
||||
let notif = document.getElementById(`notification-${actionid}`);
|
||||
notif.classList.remove('show');
|
||||
notifications.forEach(notif => {
|
||||
notif.classList.remove('show');
|
||||
|
||||
notif.addEventListener('transitionend', () => {
|
||||
notif.remove();
|
||||
notif.addEventListener('transitionend', () => {
|
||||
notif.remove();
|
||||
}, { once: true });
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async function hashSHA3_512(input) {
|
||||
const encoder = new TextEncoder();
|
||||
const data = encoder.encode(input);
|
||||
const data = encoder.encode(input);
|
||||
const hashBuffer = await crypto.subtle.digest('SHA-512', data); //-3 kiedys xddddddddddddddddd
|
||||
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
||||
const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
return hashHex;
|
||||
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
||||
const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
|
||||
return hashHex;
|
||||
}
|
||||
|
||||
var blah;
|
||||
|
||||
async function initBlahs() {
|
||||
lang = lang.toLowerCase();
|
||||
let res;
|
||||
|
||||
let path = window.location.pathname.replace("/login/index.html", "/");
|
||||
|
||||
try { //try user lang first
|
||||
res = await fetchAsync(`${path}blah/${lang}.json`);
|
||||
} catch (e) { //fallback to en-us
|
||||
res = await fetchAsync(`${path}blah/en-us.json`);
|
||||
}
|
||||
blah = JSON.parse(res);
|
||||
}
|
||||
|
||||
function processBlah(blahmessage) {
|
||||
try {
|
||||
let split = blahmessage.split(":");
|
||||
let values = [];
|
||||
try {
|
||||
values = split[2].split(";");
|
||||
} catch (e) {
|
||||
}
|
||||
|
||||
let message = blah[split[1]];
|
||||
|
||||
let valueslist = "";
|
||||
for (let i = 0; i < values.length; i++) {
|
||||
let value = values[i];
|
||||
valueslist+=`${values[i]}, `;
|
||||
processBlah(value);
|
||||
|
||||
message = message.replaceAll(`{${i}}`, value);
|
||||
}
|
||||
valueslist = valueslist.slice(0, -2);
|
||||
if (message.includes('{all}')) {
|
||||
|
||||
message = message.replaceAll('{all}', valueslist);
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
catch (e)
|
||||
{
|
||||
return blahmessage;
|
||||
}
|
||||
}
|
||||
|
||||
function getLang() {
|
||||
return (navigator.language || navigator.languages[0]);
|
||||
}
|
||||
|
||||
var password = "";
|
||||
var username = "";
|
||||
var passwordHash = "";
|
||||
var host = "";
|
||||
async function mainJS()
|
||||
{
|
||||
username = localStorage.getItem('username');
|
||||
password = localStorage.getItem('password');
|
||||
host = localStorage.getItem('host');
|
||||
var lang = getLang();
|
||||
|
||||
async function mainJS() {
|
||||
await initBlahs();
|
||||
|
||||
passwordHash = await hashSHA3_512(password);
|
||||
url = `${window.location.protocol}//${host}/_larpix`;
|
||||
if (localStorage.getItem('lang') != null) {
|
||||
lang = localStorage.getItem('lang');
|
||||
}
|
||||
}
|
||||
username = localStorage.getItem('username');
|
||||
password = localStorage.getItem('password');
|
||||
host = localStorage.getItem('host');
|
||||
mainJS();
|
||||
|
||||
collapseDmsBtn.addEventListener("click", () => {
|
||||
|
|
@ -429,9 +519,9 @@ collapseGroupsBtn.addEventListener("click", () => {
|
|||
});
|
||||
|
||||
addDmBtn.addEventListener("click", () => {
|
||||
roomContentMain.innerHTML =
|
||||
roomContentMain.innerHTML =
|
||||
`
|
||||
<div style="display: flex;justify-content: center;align-items: center;height:100%;flex-direction: column;">
|
||||
<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>
|
||||
|
|
@ -441,7 +531,7 @@ addDmBtn.addEventListener("click", () => {
|
|||
<input type="text" id="addchat-username" placeholder="@username:serverhost" class="forminput">
|
||||
</div>
|
||||
<div class="input-group">
|
||||
<button class="submit-button">
|
||||
<button class="submit-button" onclick="addDm()">
|
||||
Add chat
|
||||
</button>
|
||||
</div>
|
||||
|
|
@ -449,9 +539,8 @@ addDmBtn.addEventListener("click", () => {
|
|||
`
|
||||
});
|
||||
addGroupBtn.addEventListener("click", () => {
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
sidebarHomeButton.addEventListener("mouseenter", () => {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,10 @@
|
|||
--big-red: rgb(202 0 0);
|
||||
--big-green: rgb(25 189 0);
|
||||
}
|
||||
*:focus {
|
||||
outline: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
.red {
|
||||
color: var(--big-red);
|
||||
}
|
||||
|
|
@ -303,11 +307,12 @@ herotitle {
|
|||
|
||||
|
||||
.input-group {
|
||||
text-align: left;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.2rem;
|
||||
|
||||
width: 80%;
|
||||
width: 90%;
|
||||
max-width: 30rem;
|
||||
}
|
||||
|
||||
|
|
|
|||
4
android/app/src/main/assets/public/userscript.js
Normal file
4
android/app/src/main/assets/public/userscript.js
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
//write your custom deployment scripts here
|
||||
|
||||
loginHost.value = "olcxja.ovh";
|
||||
loginHostChanged();
|
||||
Loading…
Add table
Add a link
Reference in a new issue