account recovery and inital status stuff
This commit is contained in:
parent
4b087cb98b
commit
acbce08e49
11 changed files with 370 additions and 92 deletions
|
@ -169,7 +169,11 @@ class Contextmenu<x, y> {
|
|||
if (Contextmenu.currentmenu !== "") {
|
||||
Contextmenu.currentmenu.remove();
|
||||
}
|
||||
div.style.top = y + "px";
|
||||
if (y > 0) {
|
||||
div.style.top = y + "px";
|
||||
} else {
|
||||
div.style.bottom = y * -1 + "px";
|
||||
}
|
||||
div.style.left = x + "px";
|
||||
document.body.appendChild(div);
|
||||
Contextmenu.keepOnScreen(div);
|
||||
|
|
|
@ -8,8 +8,8 @@ import {File} from "./file.js";
|
|||
import {I18n} from "./i18n.js";
|
||||
(async () => {
|
||||
await I18n.done;
|
||||
const users = getBulkUsers();
|
||||
if (!users.currentuser) {
|
||||
|
||||
if (!Localuser.users.currentuser) {
|
||||
window.location.href = "/login.html";
|
||||
return;
|
||||
}
|
||||
|
@ -26,94 +26,27 @@ import {I18n} from "./i18n.js";
|
|||
}
|
||||
}
|
||||
I18n;
|
||||
function showAccountSwitcher(): void {
|
||||
const table = document.createElement("div");
|
||||
table.classList.add("flexttb", "accountSwitcher");
|
||||
|
||||
for (const user of Object.values(users.users)) {
|
||||
const specialUser = user as Specialuser;
|
||||
const userInfo = document.createElement("div");
|
||||
userInfo.classList.add("flexltr", "switchtable");
|
||||
|
||||
const pfp = document.createElement("img");
|
||||
pfp.src = specialUser.pfpsrc;
|
||||
pfp.classList.add("pfp");
|
||||
userInfo.append(pfp);
|
||||
|
||||
const userDiv = document.createElement("div");
|
||||
userDiv.classList.add("userinfo");
|
||||
userDiv.textContent = specialUser.username;
|
||||
userDiv.append(document.createElement("br"));
|
||||
|
||||
const span = document.createElement("span");
|
||||
span.textContent = specialUser.serverurls.wellknown
|
||||
.replace("https://", "")
|
||||
.replace("http://", "");
|
||||
span.classList.add("serverURL");
|
||||
userDiv.append(span);
|
||||
|
||||
userInfo.append(userDiv);
|
||||
table.append(userInfo);
|
||||
|
||||
userInfo.addEventListener("click", () => {
|
||||
thisUser.unload();
|
||||
thisUser.swapped = true;
|
||||
const loading = document.getElementById("loading") as HTMLDivElement;
|
||||
loading.classList.remove("doneloading");
|
||||
loading.classList.add("loading");
|
||||
|
||||
thisUser = new Localuser(specialUser);
|
||||
users.currentuser = specialUser.uid;
|
||||
sessionStorage.setItem("currentuser", specialUser.uid);
|
||||
localStorage.setItem("userinfos", JSON.stringify(users));
|
||||
|
||||
thisUser.initwebsocket().then(() => {
|
||||
thisUser.loaduser();
|
||||
thisUser.init();
|
||||
loading.classList.add("doneloading");
|
||||
loading.classList.remove("loading");
|
||||
console.log("done loading");
|
||||
});
|
||||
|
||||
userInfo.remove();
|
||||
});
|
||||
}
|
||||
|
||||
const switchAccountDiv = document.createElement("div");
|
||||
switchAccountDiv.classList.add("switchtable");
|
||||
switchAccountDiv.textContent = I18n.getTranslation("switchAccounts");
|
||||
switchAccountDiv.addEventListener("click", () => {
|
||||
window.location.href = "/login.html";
|
||||
});
|
||||
table.append(switchAccountDiv);
|
||||
|
||||
if (Contextmenu.currentmenu) {
|
||||
Contextmenu.currentmenu.remove();
|
||||
}
|
||||
Contextmenu.currentmenu = table;
|
||||
document.body.append(table);
|
||||
}
|
||||
|
||||
const userInfoElement = document.getElementById("userinfo") as HTMLDivElement;
|
||||
userInfoElement.addEventListener("click", (event) => {
|
||||
event.stopImmediatePropagation();
|
||||
showAccountSwitcher();
|
||||
const rect = userInfoElement.getBoundingClientRect();
|
||||
Localuser.userMenu.makemenu(rect.x, rect.top - 10 - window.innerHeight, thisUser);
|
||||
});
|
||||
|
||||
const switchAccountsElement = document.getElementById("switchaccounts") as HTMLDivElement;
|
||||
switchAccountsElement.addEventListener("click", (event) => {
|
||||
event.stopImmediatePropagation();
|
||||
showAccountSwitcher();
|
||||
Localuser.showAccountSwitcher(thisUser);
|
||||
});
|
||||
|
||||
let thisUser: Localuser;
|
||||
try {
|
||||
const current = sessionStorage.getItem("currentuser") || users.currentuser;
|
||||
console.log(users.users, current);
|
||||
if (!users.users[current]) {
|
||||
const current = sessionStorage.getItem("currentuser") || Localuser.users.currentuser;
|
||||
if (!Localuser.users.users[current]) {
|
||||
window.location.href = "/login";
|
||||
}
|
||||
thisUser = new Localuser(users.users[current]);
|
||||
thisUser = new Localuser(Localuser.users.users[current]);
|
||||
thisUser.initwebsocket().then(() => {
|
||||
thisUser.loaduser();
|
||||
thisUser.init();
|
||||
|
|
|
@ -3,7 +3,7 @@ import {Channel} from "./channel.js";
|
|||
import {Direct} from "./direct.js";
|
||||
import {AVoice} from "./audio/voice.js";
|
||||
import {User} from "./user.js";
|
||||
import {getapiurls, SW} from "./utils/utils.js";
|
||||
import {getapiurls, getBulkUsers, SW} from "./utils/utils.js";
|
||||
import {getBulkInfo, setTheme, Specialuser} from "./utils/utils.js";
|
||||
import {
|
||||
channeljson,
|
||||
|
@ -30,6 +30,7 @@ import {Play} from "./audio/play.js";
|
|||
import {Message} from "./message.js";
|
||||
import {badgeArr} from "./Dbadges.js";
|
||||
import {Rights} from "./rights.js";
|
||||
import {Contextmenu} from "./contextmenu.js";
|
||||
|
||||
const wsCodesRetry = new Set([4000, 4001, 4002, 4003, 4005, 4007, 4008, 4009]);
|
||||
|
||||
|
@ -75,6 +76,146 @@ class Localuser {
|
|||
set perminfo(e) {
|
||||
this.userinfo.localuserStore = e;
|
||||
}
|
||||
static users = getBulkUsers();
|
||||
static showAccountSwitcher(thisUser: Localuser): void {
|
||||
const table = document.createElement("div");
|
||||
table.classList.add("flexttb", "accountSwitcher");
|
||||
|
||||
for (const user of Object.values(this.users.users)) {
|
||||
const specialUser = user as Specialuser;
|
||||
const userInfo = document.createElement("div");
|
||||
userInfo.classList.add("flexltr", "switchtable");
|
||||
|
||||
const pfp = document.createElement("img");
|
||||
pfp.src = specialUser.pfpsrc;
|
||||
pfp.classList.add("pfp");
|
||||
userInfo.append(pfp);
|
||||
|
||||
const userDiv = document.createElement("div");
|
||||
userDiv.classList.add("userinfo");
|
||||
userDiv.textContent = specialUser.username;
|
||||
userDiv.append(document.createElement("br"));
|
||||
|
||||
const span = document.createElement("span");
|
||||
span.textContent = specialUser.serverurls.wellknown
|
||||
.replace("https://", "")
|
||||
.replace("http://", "");
|
||||
span.classList.add("serverURL");
|
||||
userDiv.append(span);
|
||||
|
||||
userInfo.append(userDiv);
|
||||
table.append(userInfo);
|
||||
|
||||
userInfo.addEventListener("click", () => {
|
||||
thisUser.unload();
|
||||
thisUser.swapped = true;
|
||||
const loading = document.getElementById("loading") as HTMLDivElement;
|
||||
loading.classList.remove("doneloading");
|
||||
loading.classList.add("loading");
|
||||
|
||||
thisUser = new Localuser(specialUser);
|
||||
Localuser.users.currentuser = specialUser.uid;
|
||||
sessionStorage.setItem("currentuser", specialUser.uid);
|
||||
localStorage.setItem("userinfos", JSON.stringify(Localuser.users));
|
||||
|
||||
thisUser.initwebsocket().then(() => {
|
||||
thisUser.loaduser();
|
||||
thisUser.init();
|
||||
loading.classList.add("doneloading");
|
||||
loading.classList.remove("loading");
|
||||
console.log("done loading");
|
||||
});
|
||||
|
||||
userInfo.remove();
|
||||
});
|
||||
}
|
||||
|
||||
const switchAccountDiv = document.createElement("div");
|
||||
switchAccountDiv.classList.add("switchtable");
|
||||
switchAccountDiv.textContent = I18n.getTranslation("switchAccounts");
|
||||
switchAccountDiv.addEventListener("click", () => {
|
||||
window.location.href = "/login.html";
|
||||
});
|
||||
table.append(switchAccountDiv);
|
||||
|
||||
if (Contextmenu.currentmenu) {
|
||||
Contextmenu.currentmenu.remove();
|
||||
}
|
||||
Contextmenu.currentmenu = table;
|
||||
document.body.append(table);
|
||||
}
|
||||
static userMenu = this.generateUserMenu();
|
||||
static generateUserMenu() {
|
||||
const menu = new Contextmenu<Localuser, void>("");
|
||||
menu.addButton(
|
||||
() => I18n.localuser.addStatus(),
|
||||
function () {
|
||||
const d = new Dialog(I18n.localuser.status());
|
||||
const opt = d.float.options.addForm(
|
||||
"",
|
||||
() => {
|
||||
const status = cust.value;
|
||||
sessionStorage.setItem("cstatus", JSON.stringify({text: status}));
|
||||
//this.user.setstatus(status);
|
||||
d.hide();
|
||||
},
|
||||
{
|
||||
fetchURL: this.info.api + "/users/@me/settings",
|
||||
method: "PATCH",
|
||||
headers: this.headers,
|
||||
},
|
||||
);
|
||||
opt.addText(I18n.localuser.customStatusWarn());
|
||||
opt.addPreprocessor((obj) => {
|
||||
if ("custom_status" in obj) {
|
||||
obj.custom_status = {text: obj.custom_status};
|
||||
}
|
||||
});
|
||||
const cust = opt.addTextInput(I18n.localuser.status(), "custom_status", {});
|
||||
d.show();
|
||||
},
|
||||
);
|
||||
menu.addButton(
|
||||
() => I18n.localuser.status(),
|
||||
function () {
|
||||
const d = new Dialog(I18n.localuser.status());
|
||||
const opt = d.float.options;
|
||||
const selection = ["online", "invisible", "dnd", "idle"] as const;
|
||||
opt.addText(I18n.localuser.statusWarn());
|
||||
const smap = selection.map((_) => I18n.user[_]());
|
||||
let index = selection.indexOf(
|
||||
sessionStorage.getItem("status") as "online" | "invisible" | "dnd" | "idle",
|
||||
);
|
||||
if (index === -1) {
|
||||
index = 0;
|
||||
}
|
||||
opt
|
||||
.addSelect("", () => {}, smap, {
|
||||
defaultIndex: index,
|
||||
})
|
||||
.watchForChange(async (i) => {
|
||||
const status = selection[i];
|
||||
await fetch(this.info.api + "/users/@me/settings", {
|
||||
body: JSON.stringify({
|
||||
status,
|
||||
}),
|
||||
headers: this.headers,
|
||||
method: "PATCH",
|
||||
});
|
||||
sessionStorage.setItem("status", status);
|
||||
this.user.setstatus(status);
|
||||
});
|
||||
d.show();
|
||||
},
|
||||
);
|
||||
menu.addButton(
|
||||
() => I18n.switchAccounts(),
|
||||
function () {
|
||||
Localuser.showAccountSwitcher(this);
|
||||
},
|
||||
);
|
||||
return menu;
|
||||
}
|
||||
constructor(userinfo: Specialuser | -1) {
|
||||
Play.playURL("/audio/sounds.jasf").then((_) => {
|
||||
this.play = _;
|
||||
|
@ -104,7 +245,7 @@ class Localuser {
|
|||
this.guilds = [];
|
||||
this.guildids = new Map();
|
||||
this.user = new User(ready.d.user, this);
|
||||
this.user.setstatus("online");
|
||||
this.user.setstatus(sessionStorage.getItem("status") || "online");
|
||||
this.resume_gateway_url = ready.d.resume_gateway_url;
|
||||
this.session_id = ready.d.session_id;
|
||||
|
||||
|
@ -240,7 +381,7 @@ class Localuser {
|
|||
},
|
||||
compress: Boolean(DecompressionStream),
|
||||
presence: {
|
||||
status: "online",
|
||||
status: sessionStorage.getItem("status") || "online",
|
||||
since: null, //new Date().getTime()
|
||||
activities: [],
|
||||
afk: false,
|
||||
|
@ -756,13 +897,13 @@ class Localuser {
|
|||
for (const [role, list] of elms) {
|
||||
members.forEach((member) => {
|
||||
if (role === "offline") {
|
||||
if (member.user.getStatus() === "offline") {
|
||||
if (member.user.getStatus() === "offline" || member.user.getStatus() === "invisible") {
|
||||
list.push(member);
|
||||
members.delete(member);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (member.user.getStatus() === "offline") {
|
||||
if (member.user.getStatus() === "offline" || member.user.getStatus() === "invisible") {
|
||||
return;
|
||||
}
|
||||
if (role !== "online" && member.hasRole(role.id)) {
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
<button type="submit" id="loginButton">Login</button>
|
||||
</form>
|
||||
<a href="/register.html" id="switch">Don't have an account?</a>
|
||||
<div id="recover"></div>
|
||||
</div>
|
||||
<datalist id="instances"></datalist>
|
||||
<script src="/login.js" type="module"></script>
|
||||
|
|
|
@ -2,9 +2,35 @@ import {getBulkInfo, Specialuser} from "./utils/utils.js";
|
|||
import {I18n} from "./i18n.js";
|
||||
import {Dialog, FormError} from "./settings.js";
|
||||
import {checkInstance} from "./utils/utils.js";
|
||||
|
||||
function generateRecArea() {
|
||||
const recover = document.getElementById("recover");
|
||||
if (!recover) return;
|
||||
const can = localStorage.getItem("canRecover");
|
||||
if (can) {
|
||||
const a = document.createElement("a");
|
||||
a.textContent = I18n.login.recover();
|
||||
a.href = "/reset";
|
||||
recover.append(a);
|
||||
}
|
||||
}
|
||||
checkInstance.alt = async (e) => {
|
||||
const recover = document.getElementById("recover");
|
||||
if (!recover) return;
|
||||
recover.innerHTML = "";
|
||||
try {
|
||||
const json = (await (await fetch(e.api + "/policies/instance/config")).json()) as {
|
||||
can_recover_account: boolean;
|
||||
};
|
||||
if (!json || !json.can_recover_account) throw Error("can't recover account");
|
||||
localStorage.setItem("canRecover", "true");
|
||||
generateRecArea();
|
||||
} catch {
|
||||
localStorage.removeItem("canRecover");
|
||||
generateRecArea();
|
||||
}
|
||||
};
|
||||
await I18n.done;
|
||||
|
||||
generateRecArea();
|
||||
(async () => {
|
||||
await I18n.done;
|
||||
const instanceField = document.getElementById("instanceField");
|
||||
|
|
119
src/webpage/recover.ts
Normal file
119
src/webpage/recover.ts
Normal file
|
@ -0,0 +1,119 @@
|
|||
import {I18n} from "./i18n.js";
|
||||
import {adduser} from "./login.js";
|
||||
import {Dialog, FormError} from "./settings.js";
|
||||
await I18n.done;
|
||||
const info = JSON.parse(localStorage.getItem("instanceinfo") as string);
|
||||
|
||||
function makeMenu2(email: string | void) {
|
||||
const d2 = new Dialog(I18n.login.recovery());
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
};
|
||||
const opt = d2.float.options.addForm(
|
||||
"",
|
||||
async (obj) => {
|
||||
const serverurls = JSON.parse(localStorage.getItem("instanceinfo") as string);
|
||||
|
||||
if ("token" in obj && typeof obj.token === "string") {
|
||||
if (email === undefined) {
|
||||
const user = await (
|
||||
await fetch(serverurls.api + "/users/@me", {
|
||||
headers: {
|
||||
Authorization: obj.token,
|
||||
},
|
||||
})
|
||||
).json();
|
||||
if ("email" in user && typeof user.email === "string") {
|
||||
email = user.email;
|
||||
} else {
|
||||
throw new Error("stupid");
|
||||
}
|
||||
}
|
||||
const username = email;
|
||||
adduser({
|
||||
serverurls,
|
||||
email: username,
|
||||
token: obj.token,
|
||||
}).username = username;
|
||||
}
|
||||
},
|
||||
{
|
||||
fetchURL: info.api + "/auth/reset",
|
||||
method: "POST",
|
||||
headers,
|
||||
},
|
||||
);
|
||||
if (email !== undefined) {
|
||||
opt.addTextInput(I18n.login.pasteInfo(), "token");
|
||||
}
|
||||
opt.addTextInput(I18n.login.newPassword(), "password", {password: true});
|
||||
const p2 = opt.addTextInput(I18n.login.enterPAgain(), "password2", {password: true});
|
||||
opt.addPreprocessor((e) => {
|
||||
const obj = e as unknown as {password: string; password2?: string; token?: string};
|
||||
const token = obj.token || window.location.href;
|
||||
if (URL.canParse(token)) {
|
||||
obj.token = new URLSearchParams(token.split("#")[1]).get("token") as string;
|
||||
}
|
||||
|
||||
if (obj.password !== obj.password2) {
|
||||
throw new FormError(p2, I18n.localuser.PasswordsNoMatch());
|
||||
}
|
||||
delete obj.password2;
|
||||
});
|
||||
d2.show(false);
|
||||
}
|
||||
function makeMenu1() {
|
||||
const d = new Dialog(I18n.login.recovery());
|
||||
let area: HTMLElement | undefined = undefined;
|
||||
const opt = d.float.options.addForm(
|
||||
"",
|
||||
(e) => {
|
||||
if (Object.keys(e).length === 0) {
|
||||
d.hide();
|
||||
makeMenu2(email.value);
|
||||
} else if ("captcha_sitekey" in e && typeof e.captcha_sitekey === "string") {
|
||||
if (area) {
|
||||
eval("hcaptcha.reset()");
|
||||
} else {
|
||||
area = document.createElement("div");
|
||||
opt.addHTMLArea(area);
|
||||
const capty = document.createElement("div");
|
||||
capty.classList.add("h-captcha");
|
||||
|
||||
capty.setAttribute("data-sitekey", e.captcha_sitekey);
|
||||
const script = document.createElement("script");
|
||||
script.src = "https://js.hcaptcha.com/1/api.js";
|
||||
area.append(script);
|
||||
area.append(capty);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
fetchURL: info.api + "/auth/forgot",
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
);
|
||||
const email = opt.addTextInput(I18n.htmlPages.emailField(), "login");
|
||||
opt.addPreprocessor((e) => {
|
||||
if (area) {
|
||||
try {
|
||||
//@ts-expect-error
|
||||
e.captcha_key = area.children[1].children[1].value;
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
d.show(false);
|
||||
}
|
||||
if (
|
||||
window.location.href.split("#").length == 2 &&
|
||||
new URLSearchParams(window.location.href.split("#")[1]).has("token")
|
||||
) {
|
||||
makeMenu2();
|
||||
} else {
|
||||
makeMenu1();
|
||||
}
|
27
src/webpage/reset.html
Normal file
27
src/webpage/reset.html
Normal file
|
@ -0,0 +1,27 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Jank Client</title>
|
||||
<meta content="Jank Client" property="og:title" />
|
||||
<meta content="A spacebar client that has DMs, replying and more" property="og:description" />
|
||||
<meta content="/logo.webp" property="og:image" />
|
||||
<meta content="#4b458c" data-react-helmet="true" name="theme-color" />
|
||||
<link href="/style.css" rel="stylesheet" />
|
||||
<link href="/themes.css" rel="stylesheet" id="lightcss" />
|
||||
<style>
|
||||
body.no-theme {
|
||||
background: #16191b;
|
||||
}
|
||||
@media (prefers-color-scheme: light) {
|
||||
body.no-theme {
|
||||
background: #9397bd;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="no-theme">
|
||||
<script src="/recover.js" type="module"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -351,7 +351,7 @@ class SelectInput implements OptionsElement<number> {
|
|||
readonly label: string;
|
||||
readonly owner: Options;
|
||||
readonly onSubmit: (str: number) => void;
|
||||
options: string[];
|
||||
options: readonly string[];
|
||||
index: number;
|
||||
select!: WeakRef<HTMLSelectElement>;
|
||||
radio: boolean;
|
||||
|
@ -361,7 +361,7 @@ class SelectInput implements OptionsElement<number> {
|
|||
constructor(
|
||||
label: string,
|
||||
onSubmit: (str: number) => void,
|
||||
options: string[],
|
||||
options: readonly string[],
|
||||
owner: Options,
|
||||
{defaultIndex = 0, radio = false} = {},
|
||||
) {
|
||||
|
@ -619,7 +619,7 @@ class Dialog {
|
|||
constructor(name: string, {ltr = false, noSubmit = true} = {}) {
|
||||
this.float = new Float(name, {ltr, noSubmit});
|
||||
}
|
||||
show() {
|
||||
show(hideOnClick = true) {
|
||||
const background = document.createElement("div");
|
||||
background.classList.add("background");
|
||||
const center = this.float.generateHTML();
|
||||
|
@ -632,7 +632,9 @@ class Dialog {
|
|||
document.body.append(background);
|
||||
this.background = new WeakRef(background);
|
||||
background.onclick = (_) => {
|
||||
background.remove();
|
||||
if (hideOnClick) {
|
||||
background.remove();
|
||||
}
|
||||
};
|
||||
}
|
||||
hide() {
|
||||
|
@ -738,7 +740,7 @@ class Options implements OptionsElement<void> {
|
|||
addSelect(
|
||||
label: string,
|
||||
onSubmit: (str: number) => void,
|
||||
selections: string[],
|
||||
selections: readonly string[],
|
||||
{defaultIndex = 0, radio = false} = {},
|
||||
) {
|
||||
const select = new SelectInput(label, onSubmit, selections, this, {
|
||||
|
|
|
@ -124,6 +124,9 @@ class User extends SnowFlake {
|
|||
return this.status && this.status != "offline";
|
||||
}
|
||||
setstatus(status: string): void {
|
||||
if (this.id === this.localuser.user.id) {
|
||||
console.warn(status);
|
||||
}
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
|
@ -482,6 +485,7 @@ class User extends SnowFlake {
|
|||
status.classList.add("statusDiv");
|
||||
switch (await this.getStatus()) {
|
||||
case "offline":
|
||||
case "invisible":
|
||||
status.classList.add("offlinestatus");
|
||||
break;
|
||||
case "online":
|
||||
|
|
|
@ -614,7 +614,7 @@ const checkInstance = Object.assign(
|
|||
verify!.textContent = I18n.getTranslation("login.allGood");
|
||||
loginButton.disabled = false;
|
||||
if (checkInstance.alt) {
|
||||
checkInstance.alt();
|
||||
checkInstance.alt(instanceinfo);
|
||||
}
|
||||
setTimeout((_: any) => {
|
||||
console.log(verify!.textContent);
|
||||
|
@ -630,7 +630,16 @@ const checkInstance = Object.assign(
|
|||
loginButton.disabled = true;
|
||||
}
|
||||
},
|
||||
{} as {alt?: Function},
|
||||
{} as {
|
||||
alt?: (e: {
|
||||
wellknown: string;
|
||||
api: string;
|
||||
cdn: string;
|
||||
gateway: string;
|
||||
login: string;
|
||||
value: string;
|
||||
}) => void;
|
||||
},
|
||||
);
|
||||
export {checkInstance};
|
||||
export function getInstances() {
|
||||
|
|
|
@ -295,6 +295,10 @@
|
|||
"save": "Save changes"
|
||||
},
|
||||
"localuser": {
|
||||
"addStatus": "Add status",
|
||||
"status": "Status",
|
||||
"statusWarn": "Spacebar has bugs with this feature and will only update after a refresh, and will often not respect it",
|
||||
"customStatusWarn": "Spacebar does not support custom status being displayed at this time so while it'll accept the status, it will not do anything with it",
|
||||
"settings": "Settings",
|
||||
"userSettings": "User Settings",
|
||||
"themesAndSounds": "Themes & Sounds",
|
||||
|
@ -331,7 +335,7 @@
|
|||
"changePassword": "Change password",
|
||||
"oldPassword:": "Old password:",
|
||||
"newPassword:": "New password:",
|
||||
"PasswordsNoMatch": "Password don't match",
|
||||
"PasswordsNoMatch": "Passwords don't match",
|
||||
"disableConnection": "This connection has been disabled server-side",
|
||||
"devPortal": "Developer Portal",
|
||||
"createApp": "Create application",
|
||||
|
@ -455,6 +459,9 @@
|
|||
"copyId": "Copy user ID",
|
||||
"online": "Online",
|
||||
"offline": "Offline",
|
||||
"invisible": "Invisible",
|
||||
"dnd": "Do Not Disturb",
|
||||
"idle": "Idle",
|
||||
"message": "Message user",
|
||||
"block": "Block user",
|
||||
"unblock": "Unblock user",
|
||||
|
@ -471,7 +478,12 @@
|
|||
"checking": "Checking Instance",
|
||||
"allGood": "All good",
|
||||
"invalid": "Invalid Instance, try again",
|
||||
"waiting": "Waiting to check Instance"
|
||||
"waiting": "Waiting to check Instance",
|
||||
"recover": "Forgot password?",
|
||||
"pasteInfo": "Paste the recovery URL here:",
|
||||
"newPassword": "New password:",
|
||||
"enterPAgain": "Enter new password again:",
|
||||
"recovery": "Forgotten password"
|
||||
},
|
||||
"member": {
|
||||
"kick": "Kick $1 from $2",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue